fix(web): say why a zoom level rendered as another one - #133
Closed
lex00 wants to merge 1 commit into
Closed
Conversation
Closes #131. Four of six zoom levels rendered as one of the other two with nothing on screen saying so. Stepping through them showed the same picture repeatedly, which reads as a broken picker — that is how it was reported. Each fallback is correct and stays. COMPOSITES is RESOURCES plus overlaid component-dependency edges, so no component graph means no edges and the same picture. RUNTIME descends to owner-referenced children, and an estate whose children live in AWS rather than the cluster has none. LOGICAL is a cloud-topology lens (#74) and nests kinds a Kubernetes estate does not declare. What was not defensible is that a limited view and a working view were indistinguishable. The server now reports what it fell back to and the SPA renders it above the graph: composites no component dependencies to overlay — this is the resources graph runtime no owner-referenced children observed — this is the resources graph logical logical kept 1 of 11 resources — it is a cloud-topology lens, and the rest are kinds it does not nest (behold#74) A note, not an error card: nothing failed. The composites catch also stops being bare. It swallowed every failure identically, so an unavailable component DAG and a genuinely empty one produced the same silence; they now produce different notes. logicalDegraded() stays quiet when the projection kept most of the graph. A note on every logical view is noise, and noise is how a real signal stops being read. The runtime check counts nodes across attachRuntimeContainment rather than looking for a marker: the tier's job is to bring children in, so "did it add any" is the question, and it survives however they come to be tagged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TCV5kwB1jdnWH9if9ZbNXq
This was referenced Aug 5, 2026
lex00
added a commit
that referenced
this pull request
Aug 5, 2026
…t it is empty (#140) Ported from #133, which had this and #139 -- the version I merged -- did not. Recording that plainly: #133 was open first and I implemented #131 without checking, so the better reading of this one case shipped second. #139 noted logical only when it projected zero nodes. The quiet failure is the partial one: a lens that keeps 1 of 11 renders a plausible-looking diagram of almost nothing, which reads as "this is your estate" rather than "no data". Empty at least reads as absence. `logicalKept` is #133's function under a different name, threshold and message intact. Its reasoning is kept verbatim because it is the right reasoning: a note on every logical view would be noise, and noise is how a real signal stops being read. The `* 3` cut-off is a judgement call and is better argued with than inherited. Both call sites now count before projecting, so the note can say what was dropped. Callers that cannot count keep the empty-only check -- notesFor takes the input count as optional and prefers it when present. Verified against a live pure-k8s estate: logical projected nothing from 11 resources -- it is a cloud-topology lens, and this estate declares none of the kinds it nests (behold#74) against #139's flatter "logical is an AWS projection -- no AWS resources in this estate". The count is the part that tells you it looked at something. 462 tests (7 new), tsc and build clean. Claude-Session: https://claude.ai/code/session_012n8PKN49z8c6jZVA9QYwvk Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Superseded, and not on its own merits — recording what happened. This was open first. I implemented #131 without checking for an existing PR, merged it as #139, and put this branch into conflict. That was avoidable and I should have looked. Everything here is now on
#140's commit and PR both say where it came from. The One thing #139 added that this did not: a note for an estate with nodes and no edges, which is the flat-row case (fountain-ops#84). Closing as superseded rather than stale. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #131. Separate from #132 (the on-screen picker) — that one is a design call, this one is a straight bug.
The problem
Four of six zoom levels rendered as one of the other two, silently:
20edb39120edb391cdfcb2f834916166composites and resources byte-identical; with an env, runtime and attributes likewise. Reproduces on this repo's own
example-k8s, so it is not a property of the project being viewed.Every fallback is correct and stays
What is not defensible is that a limited view and a working view were indistinguishable. The server reports what it fell back to; the SPA renders it above the graph as a note, not an error card, because nothing failed.
Verified against a live mixed-substrate estate (k3d + floci + the KubeMicroVM operator, 11 resources):
That last line matters as much as the others — the level that is not degraded stays quiet.
Two details worth review
The composites
catch {}stops being bare. It swallowed every failure identically, so an unavailable component DAG and a genuinely empty one were the same silence. They now say different things.logicalDegraded()is quiet when the projection kept most of the graph (after * 3 >= before). A note on every logical view would be noise, and noise is how a real signal stops being read. The threshold is a judgement call and I would rather it were argued with than inherited.The runtime check counts nodes across
attachRuntimeContainmentrather than probing for a marker — the tier's job is to bring children in, so "did it add any" is the actual question, and it survives however those children come to be tagged.Testing
npx tsc --noEmitclean;npm test433 passing across 33 files. Behaviour verified by querying every level against the live estate above, including the negative case.