Skip to content

Nested drilldown: N-depth bundles, recursive descend, zoom-dive, recursive-by-default repository maps - #1

Merged
Cagatay342 merged 30 commits into
mainfrom
feat/nested-drilldown
Sep 13, 2026
Merged

Nested drilldown: N-depth bundles, recursive descend, zoom-dive, recursive-by-default repository maps#1
Cagatay342 merged 30 commits into
mainfrom
feat/nested-drilldown

Conversation

@Cagatay342

Copy link
Copy Markdown
Owner

Summary

  • Stacks on upstream PR feat: stable identity map — ownership sidecar, archify locate, drilldown bundles tt-a1i/archify#367 (identity map; included here because it is not on main yet).
  • Bundles: max_depth 2–8, tree validation, ownership sidecar chain generalized past one hop.
  • Viewer: recursive descend in place, breadcrumb, Escape/Backspace ladder, session/requestId protocol, depth-scaled ascend settle.
  • Camera: cursor/pinch-anchored wheel and pinch zoom, onChange, minZoomOut.
  • Dive (viewer/dive.js, opt-in Z): zoom a drilldown node past 2.5× → 250 ms dwell → descend; two zoom-outs at 1× ascend; redive lock; allowed in Presentation, blocked only while a guided story plays.
  • Skill: SKILL.md "Repository maps: recursive drilldown bundles" — whole-repository maps default to an outside-in bundle with a per-component decomposition test, parallel children, archify bundle <dir>.
  • READMEs and landing pages install from this fork; generated artifacts rebuilt (archify.zip, examples, gallery, showcase GIF).

Test plan

  • npm run check:viewer, check:validators at every viewer/schema commit
  • drilldown / dive / wheel / bundle browser tests in real Chrome (CDP)
  • README budget, package and showcase gates
  • Pilot: AIWorkspace docs/diagrams/nested/ (3 levels, bundle --check 10/10)
  • Known environmental failures (also at base cc1b33a): update-notifier timing tests, motion-governor-browser hang.

🤖 Generated with Claude Code

tt-a1i and others added 30 commits September 9, 2026 03:50
Add a component ownership sidecar (<stem>.ownership.json, validated by
ownership.schema.json) and a pure-computation `archify locate` command
that classifies every path in a git range as touched / uncovered /
ambiguous / excluded and every component as touched / untouched / stale.

- No LLM, no inference, no map edits; ambiguity is reported, never
  resolved by implicit glob precedence. `--lint` turns ambiguity into an
  authoring-time failure and reports uncovered as advisory only.
- Receipt (locate-receipt.schema.json) is deterministic: stable code
  point sort, no timestamps, no absolute paths, 40-char SHAs, sha256 of
  map and sidecar. Two runs are byte-identical.
- Renames via `git diff --name-status -M -z`; both sides recorded and a
  moved_between_components fact emitted when owners differ.
- `--facts` attaches import-edge observations; endpoints outside any
  component are `componentId: null`, never dropped.
- When the map itself changed in the range, `archify compare` runs as a
  child process under <out>/compare/ and is linked from mapDelta; the
  locate exit code is independent of the comparison.
- Delta `navigation` field group classifies a changed `drilldown` target
  as `navigation-changed` rather than `changed` or `moved`.
- SVG annotation helpers extracted from architecture-delta.mjs into
  delta/svg-annotate.mjs and shared with the locate HTML.

Tests: archify/test/{locate,locate-glob,locate-html,locate-bundle,
ownership,architecture-delta,generate-validators}.test.mjs. Full suite
1170 tests / 1133 pass / 0 fail / 37 skipped on Node 26; Node 22 package
gates 18 pass. check:validators clean.
…iewer

Add `archify bundle <dir> [--check]`: one entry diagram plus up to twelve
same-directory children of any diagram type, bound by manifest.json
(bundle.schema.json) using diagram ids and two sha256 digests
(spec_sha256 for the runtime handshake, artifact_sha256 for offline
validation). Depth is fixed at two; each level keeps the 12-node cap.

- Architecture components may declare an optional `drilldown: <child id>`
  (schema addition, pending maintainer sign-off). The renderer draws the
  mark into the SVG so it survives canonical export.
- Viewer descends in place: parent SVG is hidden, never transformed;
  breadcrumb + 96px silhouette; child opens in a same-directory iframe;
  Esc/Backspace/breadcrumb ascend and restore scroll. Parent geometry is
  unchanged by construction (drilldown-browser.test.mjs verifies pixels).
- Handshake: hello/ack over postMessage with unconditional event.source
  check and shape validation; id/sha mismatch, unsafe filename, or a
  1200 ms timeout shows an explicit stale card (built with textContent,
  strings via i18n) instead of rendering the child.
- validateBundle runs derived-count checks (manifest schema first,
  fail-closed), including the shared child-ownership subset rule from
  locate/ownership.mjs. Required <entryId>.ownership.json; no directory
  order dependence.
- Locate projection pass-through: `locate --bundle` embeds component and
  child node states; parent chip "N FILES TOUCHED INSIDE" hidden at zero;
  stale gets a distinct non-green treatment.
- Bundle render flags are parsed once at the renderer CLI entry and
  passed explicitly; svgRootAttrs no longer reads process.argv.
- Drilldown runtime exposed as pure functions on Archify.drilldown and
  unit-tested in node:vm; CI webm-artifact job runs the Chrome test.

Tests: bundle-{schema,manifest,validate,ownership}, drilldown-{mark,
viewer,stale,locate,browser}, svg-root-attrs, cli, i18n. Full suite
1170 / 1133 pass / 0 fail; Chrome tests 12/12; actionlint clean except
pre-existing SC2016 in release.yml.
…eriments

- docs/decisions/identity-map-2026-09-09.md: drilldown contract, ownership
  sidecar spec, locate receipt format, diagnostic codes, "what we do not
  do", E1/E3 raw numbers, PR tt-a1i#269/tt-a1i#281 gap assessment, schema changes
  pending sign-off, code-vs-draft divergences, open questions. Every
  decision cites path:line.
- E3 (100-commit replay of a hand-written self-map): 9/100 commits needed
  a map edit, 0 ambiguous, uncovered returns to 0; sources line anchors
  decayed 68.7% over the same range. E1: 8/50 fix commits structural
  (16%), supporting "orientation", not defect-finding, wording.
- docs/cases/archify-self/: ten-component self-map, two children
  (architecture + workflow), sidecars, manifest, receipts for PR tt-a1i#256 and
  PR tt-a1i#352 (regenerable; only receipts are kept), README with commands.
- archify/references/{locate,drilldown-bundles}.md; SKILL.md fast path
  unchanged. CHANGELOG entry; one-clause ROADMAP note that the diagram
  diff stance still holds.
archify/assets/template.html gained the drilldown runtime and locate
projection styles, so every artifact that embeds the template is
rebuilt per CONTRIBUTING:

- archify.zip via scripts/build-zip.sh on Node 22.23.2
  (1,959,997 bytes, +82,567 vs origin/main)
- packaged and root examples/*.html goldens, checkout-platform-delta
  html + receipt (compare embeds two explorers)
- docs/gallery via scripts/build-gallery.mjs (11 artifacts / 99 checks)
- docs/cases/mco-runtime.architecture.html and
  experiments/mco-showcase/mco-runtime.html (byte-repro against mco
  @ 9f1a1cf)
- docs/assets/archify-live-proof.{gif,json}: readme-showcase.test.mjs
  pins the gallery artifact sha256 into the receipt, forcing the rebuild

No SVG geometry changes in any golden; diffs are viewer chrome only.
CI's headless Chrome caught a refit on ascend: the first implementation
hid the entry SVG with display:none, so it left layout, the adaptive
reader re-measured the canvas as overflowing on reveal and shrank
--archify-reader-width from 1376px to 960px, scaling every node box by
0.691. Reproduced at 1440x900 with the test's 240px canvas pinch.

The entry SVG now stays in flow with visibility:hidden while the child
is overlaid, and the reader/viewer-chrome measurers are frozen while
data-drilldown-level is set, so no fit runs at all. drilldown-browser
asserts pixel-identical node boxes at 1440x900 and 800x600 with a child
taller than the parent canvas.

Decision record §3.7 and the drilldown reference describe the mechanism
and why. Goldens, gallery, MCO artifacts and README GIF rebuilt for the
template change. npm test: 1170 / 1133 pass / 0 fail / 37 skipped.
Generalize drilldown bundles from a fixed two-level parent/child pair to a
tree of arbitrary depth (2-8): any diagram in the bundle may declare its own
drilldown, max_depth is computed from the tree, ownership sidecars bind to
whichever diagram a drilldown row names as parent, and excluded globs
accumulate down the full chain. Adds bundle-depth and locate-bundle-depth
test coverage plus the deep-checkout fixtures.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Viewer now reads a bundle's full tree instead of only its first level:
a non-leaf child offers the same Descend control and drilldown mark for its
own components, so a diagram can be descended into a second and third time
(iframe inside iframe). A parent hands its child a scoped subtree of the
manifest inside the existing handshake hello; every navigation
request/reply (hello ack, escape, breadcrumb, ascend) carries a session
number (and ascend messages a request id) so a delayed or superseded
ack/escape/breadcrumb update is ignored — the Locate projection message
carries no session at all, since it is not part of this handshake. The
breadcrumb is drawn once at the root as the full chain to whichever level
is deepest; Esc/Backspace close exactly one level from wherever focus is,
and a breadcrumb rung's click ascends directly to that depth via the new
ascendTo/closeInnermost/escapeToParent API. Readiness
(data-drilldown-state="open") is now gated only on a successful handshake
ack.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A nested child still renders its own full page chrome (header, page
padding) inside its shrinking iframe box; the toolbar/legend column
.header's padding-right normally reserves is already hidden while nested,
so it is pure waste here. Four html[data-bundle-nested="true"] rules
reclaim that space. Pure CSS, no behavior change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd + nested CSS)

Rebuild archify.zip, the five bundled examples (default root and ../examples),
the checkout-platform-delta compare artifact/receipt, the docs gallery, and the
README showcase GIF from PR1's own head (bundle N-depth + recursive descend +
nested-chrome CSS only — no camera/dive bytes yet). Excludes docs/cases/
archify-self and docs/cases/mco-runtime.*/experiments/mco-showcase, which need
checkouts not available here and are not reproduced in this run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Viewer now zooms continuously between 1x and 3x around the pointer
(mouse wheel, Ctrl+wheel trackpad pinch) or the two-finger touch pinch
midpoint, alongside the existing +/-/0 controls. viewer-camera.js adds
zoomAt(nextScale, clientX, clientY, { snap }) anchored on a caller-supplied
point via svgOrigin(); a gesture that cannot change scale (1x floor) leaves
page scrolling alone and emits minZoomOut instead. Pinch pointer capture is
held for the gesture's lifetime, drags are scoped to the pointer that
started them, and a third touch during an active pinch cannot start a new
drag. onChange/offChange subscribe to every apply() with a transitioning
flag that settles on transitionend or a 200ms fallback; on/off cover
minZoomOut and gesture events. viewer-wheel-browser.test.mjs covers wheel/
pinch/minZoomOut end to end in a real Chrome; its checks wait for the
transform to stay stable for a 260ms minimum before asserting on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A new Archify.dive (viewer/dive.js) lets a reader turn manual zoom itself
into drilldown navigation. Off by default (localStorage['archify-dive'],
toggled by Z or a .diagram-nav button shown only when the current diagram
has a drilldown row). The precise trigger: manual camera mode (never a
semantic Focus/Guided/Radar reveal), scale >= 2.5, no
prefers-reduced-motion, not the mobile-contained wide-diagram mode, none of
Route Probe / Semantic Lens / Presentation active (Intent Trace is
deliberately excluded from this blocking list — its own "active" node is
just a 90ms fine-pointer hover preview, true almost the whole time a real
mouse hovers the node being wheel-zoomed), no redive lock, rearmed, and no
descent already open or mid-handshake; once eligible, a candidate node gets
a visible 250ms dwell (a ring on the node plus a status line) before
calling the existing Archify.drilldown.descend. The dwell is cancelled by
any camera movement beyond a small epsilon (0.004 scale, 0.5px x/y) versus
where it started, or by losing eligibility for any other reason, on either
the transitioning or settled onChange notification.

Inside a nested child, two zoom-out gestures at the 1x floor with distinct
(source, gestureId) pairs within 600ms ascend one level the same way a
breadcrumb click does. After an ascend, a redive lock and a separate
`rearmed` flag both go false; a new dwell needs both cleared. The lock
clears on a fresh pointerdown/keydown anywhere in the document, or on a
gesture 'start' once the document has gone >=400ms (GESTURE_SILENCE_MS)
without any gesture activity at all — time-based and document-local,
deliberately not a comparison of gesture ids, since the ascend-triggering
gesture happened in a different document with its own id space. `rearmed`
only flips back to true once the camera is later seen at scale < 2.5 on a
settled snapshot, i.e. the reader has zoomed back out past the dive
threshold at least once since the ascend.

viewer-camera.js is unchanged by this feature; export/print/SVG bytes are
unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rebuild archify.zip, the five bundled examples (default root and
../examples), the checkout-platform-delta compare artifact/receipt, the
docs gallery, and the README showcase GIF now that camera gestures and
dive are in the template, on top of PR1's own rebuild. Same
docs/cases/archify-self and docs/cases/mco-runtime.*/experiments/
mco-showcase exclusion as commit 4 (needs checkouts not available here).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ream drafts

Working documents behind the feat/nested-drilldown branch: the phase plan,
the Sonnet implementation briefs and reports for phases 0-5 and the commit
split, the Codex astra second-opinion reviews for every phase, the Faz 5
acceptance evidence, and the upstream drafts (PR1/PR2 descriptions, the
issue tt-a1i#280 comment, the commit plan). Multi-MB test transcript logs are
ignored, not committed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… plays

Presentation only hides chrome and puts the diagram on stage; a reader
zooming a drilldown node by hand there is exactly the audience dive is
for. The blocker that made Presentation an exclusive mode is replaced
by `Archify.guidedViews.isPlaying()`: a playing guided story (whose
semantic camera already never dives) is the genuinely incompatible
surface. Route Probe and Semantic Lens blockers, the Intent Trace
exclusion, and the redive lock are unchanged.

`viewer/README.md` (dive contract eligibility list) and the CHANGELOG
bullet state the new blocking set; `archify/assets/template.html`
regenerated (`check:viewer` clean; drilldown-dive-browser and
generate-viewer tests 290/290).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same file set and commands as the PR2 rebuild: render:examples (both
roots, plus examples/web-app.html rendered directly), the checkout
compare artifact + receipt, build:gallery, build:readme-showcase and
scripts/build-zip.sh. Gates: release-package-gates, readme-showcase,
architecture-delta and generate-viewer tests 323/323 (2 skipped).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…dles

SKILL.md gains "Repository maps: recursive drilldown bundles": a
whole-repository/system request defaults to a bundle authored
outside-in — survey the repo, write the level-0 candidate at once,
then run a decomposition test per architecture component (several
distinct internal parts, own request path, own stores/boundaries, and
inlining would break the twelve-node cap), recurse through
architecture children only (other types are leaves, 2–8 total levels),
author independent children in parallel as fresh work from their own
source evidence, deliver each diagram, then `archify bundle <dir>` as
the single sanctioned re-render of delivered HTML, browser evidence on
the final entry, and a tree report with stopping decisions. The
reference's "When to use it" points back at the section. CHANGELOG
bullet; archify.zip rebuilt (SKILL.md and the reference are packaged).

Codex astra review: DÜZELTMEYLE KABUL, all six findings applied
(narrow single-diagram exception, leaf/recursion rule, source survey
before schema reading, deliver-vs-bundle re-render exception, softened
file:// claim, lighter report duty).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…; install from this fork

All three READMEs and the landing pages now install from
`Cagatay342/archify` (`npx skills add Cagatay342/archify -g`, the
explicit Cursor command, `skills use`) and the quick-start repository
prompt asks for a nested drilldown bundle, with one line on the
outside-in default. The temporary fork blockquote is gone. Kept within
the README budget tests (≤295 lines, ≤2085 words, mirrors identical);
`cursor-onboarding.test.mjs`'s install constant follows the fork.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Cagatay342
Cagatay342 merged commit 7713f2a into main Sep 13, 2026
@Cagatay342
Cagatay342 deleted the feat/nested-drilldown branch September 13, 2026 14:51
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.

2 participants