Skip to content

fix: a zoom level that cannot render says so, instead of looking stuck - #139

Merged
lex00 merged 1 commit into
mainfrom
fix/zoom-says-when-it-cannot-render
Aug 5, 2026
Merged

fix: a zoom level that cannot render says so, instead of looking stuck#139
lex00 merged 1 commit into
mainfrom
fix/zoom-says-when-it-cannot-render

Conversation

@lex00

@lex00 lex00 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes #131.

Four of the six zoom levels can legitimately render empty, or identically to the level below, and none of them said which. Someone stepping through the picker saw the same picture repeatedly and reported the control as stuck. The views were right; the silence was not.

Nothing here becomes an error

logical on a k8s estate is correctly empty (#74 — the projection's headline kinds are literal AWS::*). composites with no component ownership is correctly the resource graph (#138). These are captioned, not fixed, because there is nothing wrong with them to fix.

Deliberately not a RouteError: those replace the canvas with a card and exist for a view that could not be produced at all. These were produced and are honest — they need a caption, not an error screen.

How it works

src/zoom-notes.ts is pure and reads the finished IR, so a note describes what was actually rendered rather than what the request asked for. The SPA never infers a note; it only displays meta.note.

Composites needs one extra input — how many component edges attached — because that is not recoverable from the IR afterwards: an estate can have zero edges either way (fountain-ops#84). addCompositeDepsCounted reports it, and the silent catch that swallowed a missing component DAG now records the zero instead of shrugging:

         } catch {
-          /* component DAG unavailable — leave composites as-is */
+          /* component DAG unavailable — leave composites as-is, and say so */
+          compositeEdgesAttached = 0;
         }

The second note

Orthogonal to the zoom: a graph with nodes and no edges lays out as a single flat row, which reads as a broken renderer rather than as an accurate picture of a project that declares no references. components and logical are exempt — both lay themselves out (waves, nested boxes), so edge count is not a meaningful judgement of either.

Verified against a live estate

fountain-ops on k3d, pure k8s, serve --env local:

  zoom         nodes edges  note
  logical        0n  0e   logical is an AWS projection — no AWS resources in this estate
  components     5n  4e   (no note)
  composites    11n  0e   no component ownership to join — showing the resource graph
                          unchanged · no edges — nothing in this estate references anything else
  resources     11n  0e   no edges — nothing in this estate references anything else
  attributes    11n  0e   no edges — nothing in this estate references anything else
  runtime       15n  0e   no edges — nothing in this estate references anything else

components stays silent because it renders what it promises — which is the control case that proves the notes are conditional rather than decorative.

just check: tsc clean, 455 tests pass (15 new), build clean.

Scope

This resolves the reported symptom without waiting on any of the projections it describes — #138, #74, chant#1489 and chant#1493 all remain open and all now announce themselves in the UI instead of looking like a dead control.

🤖 Generated with Claude Code

https://claude.ai/code/session_012n8PKN49z8c6jZVA9QYwvk

#131)

Four of the six levels can legitimately render empty, or identically to the
level below, and none of them said which. Someone stepping through the picker
saw the same picture repeatedly and reported the control as broken. That is the
defect: the views were right, the silence was not.

None of these become errors. `logical` on a k8s estate is correctly empty (#74
-- the projection's headline kinds are literal AWS::*), and `composites` with
no component ownership is correctly the resource graph. They are captioned, not
fixed, because there is nothing wrong with them to fix.

src/zoom-notes.ts is pure and reads the FINISHED IR, so a note describes what
was actually rendered rather than what the request asked for. Composites needs
one extra input -- how many component edges attached -- because that is not
recoverable from the IR afterwards: an estate can have zero edges either way
(fountain-ops#84). addCompositeDepsCounted reports it; the silent catch that
swallowed a missing component DAG now records the zero instead of shrugging.

The second note is orthogonal to the zoom. A graph with nodes and no edges lays
out as one flat row, which reads as a broken renderer rather than as an
accurate picture of a project that declares no references. `components` and
`logical` are exempt -- both lay themselves out, so edge count is not a
judgement of either.

Deliberately not a RouteError: those replace the canvas with a card and are for
a view that could not be produced. These were produced and are honest.

Verified against a live pure-k8s estate (fountain-ops on k3d):

  logical      0n  0e   logical is an AWS projection -- no AWS resources in this estate
  components   5n  4e   (no note)
  composites  11n  0e   no component ownership to join -- showing the resource graph
                        unchanged | no edges -- nothing references anything else
  resources   11n  0e   no edges -- nothing in this estate references anything else
  runtime     15n  0e   no edges -- nothing in this estate references anything else

Closes #131

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012n8PKN49z8c6jZVA9QYwvk
@lex00
lex00 merged commit 176987b into main Aug 5, 2026
1 check passed
@lex00
lex00 deleted the fix/zoom-says-when-it-cannot-render branch August 5, 2026 04:17
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A zoom level that cannot render falls back to another one silently, so the picker looks broken

1 participant