@bongos/core 1.19.468 → 1.19.470
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +94 -44
- package/docs/adr/0227-a-task-network-map-is-refused-the-goal-graph-is-the-map.md +169 -0
- package/docs/adr/README.md +1 -0
- package/docs/copy-inventory.md +42 -50
- package/docs/copy-registry.json +167 -271
- package/docs/file-map.md +5 -1
- package/docs/module-api-changelog.md +4 -0
- package/docs/research/task-network-map/a-every-task-p2.png +0 -0
- package/docs/research/task-network-map/a-every-task-p40.png +0 -0
- package/docs/research/task-network-map/b-dependency-forest-p2.png +0 -0
- package/docs/research/task-network-map/b-dependency-forest-p40.png +0 -0
- package/docs/research/task-network-map/c-goals-p2.png +0 -0
- package/docs/research/task-network-map/c-goals-p40.png +0 -0
- package/docs/research/task-network-map/d-joined-by-goal.png +0 -0
- package/docs/research/task-network-map-readability.md +191 -0
- package/modules/hall-ui/public/atlas.css +96 -88
- package/modules/hall-ui/public/atlas.html +43 -20
- package/modules/hall-ui/public/atlas.js +118 -20
- package/modules/hall-ui/public/atlas.states.json +52 -1
- package/modules/hall-ui/public/modules.css +67 -86
- package/modules/hall-ui/public/modules.html +46 -35
- package/modules/hall-ui/public/modules.js +195 -103
- package/modules/hall-ui/public/modules.states.json +48 -1
- package/modules/hall-ui/public/people.css +3 -2
- package/modules/hall-ui/public/people.html +2 -2
- package/modules/hall-ui/public/people.js +5 -4
- package/modules/hall-ui/public/people.states.json +1 -1
- package/modules/hall-ui/public/settings.js +1 -1
- package/modules/hall-ui/public/style.css +12 -11
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/spike-task-map.js +730 -0
- package/src/bongos/serve-internal.js +20 -8
- package/src/module-api.js +1 -1
- package/tests/hall_catalog_world.mjs +181 -0
- package/tests/hall_page_gate_map.mjs +4 -2
- package/tests/hall_reading_world.mjs +2 -2
- package/tests/hall_roster_world.mjs +40 -12
- package/tests/spike_task_map.mjs +0 -0
- package/modules/hall-ui/public/scouting.html +0 -69
- package/modules/hall-ui/public/scouting.states.json +0 -59
package/docs/file-map.md
CHANGED
|
@@ -68,6 +68,9 @@
|
|
|
68
68
|
│ │ ├── overnight-builder.md ← (#358) operator runbook for the autonomous overnight session-runner
|
|
69
69
|
│ │ ├── builder-box-lifecycle.md ← (#598/ADR 0031) operator runbook: provision/park/wake/deprovision dev boxes, the two sweeps, config env, going-live steps
|
|
70
70
|
│ │ └── managed-settings-remote-control.md ← (#599/ADR 0031 §1, #760/ADR 0038) operator+builder guide: distribute the locked Claude Desktop SSH config; the browser web-terminal (ttyd + Cloudflare Tunnel) on-ramp
|
|
71
|
+
│ ├── research/ ← investigations that answer a question rather than record a decision (an ADR) or a procedure (a recipe)
|
|
72
|
+
│ │ ├── task-network-map-readability.md ← (task 1003282, goal 1000072) the spike verdict: a node-link map of ~1,357 tasks is unreadable at every dependency density — 59–97% isolated dots, and the dense fix overplots 84% of them into the 40-node goal graph. Build the goal graph + a per-goal dependency forest; measure the real density with `--from` first
|
|
73
|
+
│ │ └── task-network-map/ ← the figures that verdict argues from, rendered by scripts/gds/spike-task-map.js — regenerate, never hand-edit
|
|
71
74
|
│ ├── reviews/ ← temporary audit/review docs (e.g. claude-md-audit-V3.R86.md)
|
|
72
75
|
│ ├── session-logs/ ← one file per session, named YYYY-MM-DD-<slug>.md (CLAUDE.md §13 indexes them)
|
|
73
76
|
│ └── session-log-archive.md ← compressed older session-log prose
|
|
@@ -127,7 +130,7 @@
|
|
|
127
130
|
│ ├── sessions/ ← CORE-DOMAIN carve (BV1.R82, default-on): the session_records corpus + data plane (upload, cross-builder search/deep-dive), the BFG read-the-room scorer, session-pulse/stale-claim helpers. Registers no port — reached via HTTP POST to its own /sessions route; resolves the economy `reward` port for the cost-plus token reward. CLAUDE.md, module.json, routes/sessions.js, bfg.js, pulse.js.
|
|
128
131
|
│ ├── autonomy/ ← CORE-DOMAIN carve (BV1.R83, default-on): the MAS autonomy surfaces — the $0 deterministic autonomy gate (System 3, inert until armed), the conductor/architect CLIs, and the in-process routine timers (incl. the weekly peer-vote-tally poller). Registers no port; resolves the lifecycle `tallyPeerVotes` doorway. CLAUDE.md, module.json, routes/autonomy.js, autonomy.js.
|
|
129
132
|
│ ├── status-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R84, default-on): the public status dashboard at status.<apex>, moved from public-status/. NO routes/db/port — declares contributes.webSurfaces:[{host:"status.",dir:"public"}], served by the loader web-surface seam (moduleWebSurfaces → serve-internal). CLAUDE.md, module.json, public/{index.html,status.js,style.css,cursors/,snapshots/}.
|
|
130
|
-
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,harbor,gate,pair,settings,ranks,sessions,primer,diagrams,atlas,...}.{html,js},cursors/,chime.wav. Three ARCHETYPE sheets sit beside the per-page ones: `record.css` (the task + idea records, task 1003305), `room.css` (the READING ROOMS — the primer + the diagrams index, task 1003306: the reading measure and rhythm, the table of contents, the progress hairline and the framed figure diagram-viewer.js upgrades on both pages) and `oversight.css` (the OVERSIGHT family — government, watch, harbor, gate, task 1003469: the row, the figure band inside a panel, the group head, the inline form, the grant toggle and the shared confirm modal; named oversight because the vocabulary wall bans "governance" on the government surface). A page sheet then holds only what one page has and the others do not — `primer.css` the acknowledge gate, `diagrams.css` the legend strip, `gate.css` the hold reasons and file chips, `watch.css` the severities, the report reader and the grade trend, `people.css` the directory's identity cell (task 1003470
|
|
133
|
+
│ ├── hall-ui/ ← CORE-DOMAIN WEB-SURFACE carve (BV1.R85, default-on): the authenticated builders' hall at builders.<apex>, moved from public-builders/ (~13k LOC, the largest). NO routes/db/port — declares contributes.webSurfaces:[{host:"builders.",dir:"public"}] for discovery, but UNLIKE status-ui keeps its DEDICATED serving block in serve-internal (the /builders shim + canonical redirects + citizen/Archon page gates + asset-stamping + hall-widget injection), partitioned out of the generic web-surface loop and served from BUILDERS_DIR. CLAUDE.md, module.json, public/{index.html,builders.js,style.css,work,watch,harbor,gate,pair,settings,ranks,sessions,primer,diagrams,atlas,...}.{html,js},cursors/,chime.wav. Three ARCHETYPE sheets sit beside the per-page ones: `record.css` (the task + idea records, task 1003305), `room.css` (the READING ROOMS — the primer + the diagrams index, task 1003306: the reading measure and rhythm, the table of contents, the progress hairline and the framed figure diagram-viewer.js upgrades on both pages) and `oversight.css` (the OVERSIGHT family — government, watch, harbor, gate, task 1003469: the row, the figure band inside a panel, the group head, the inline form, the grant toggle and the shared confirm modal; named oversight because the vocabulary wall bans "governance" on the government surface). A page sheet then holds only what one page has and the others do not — `primer.css` the acknowledge gate, `diagrams.css` the legend strip, `gate.css` the hold reasons and file chips, `watch.css` the severities, the report reader and the grade trend, `people.css` the directory's identity cell (task 1003470 made the legacy door `/scouting` ship the same body and script as `/people`; task 1003440 then deleted the door — `scouting.html` and `scouting.states.json` are gone and the URL 301s to `/people`).
|
|
131
134
|
│ ├── lifecycle/ ← CORE-DOMAIN carve (BV1.R86, default-on): the build state machine — tasks · claims · versions · done-when · goals · dependencies · claim→ship→grade→credit · github-push + merge-lock + conflict-resolve + publish-reconciler. The LAST, most-coupled carve; registers the `lifecycle` kernel port (createTask, classifyTaskKind, tallyPeerVotes, work-tracking reads). CLAUDE.md, module.json, routes/{tasks,claims,versions,done-when,goals,dependencies,gate-approvals,analytics}.js, lifecycle.js, github-push.js, merge-lock.js, conflict-resolve.js, publish-reconciler.js, task-visuals.js + task-visual-db.js + routes/visuals.js (the optional ship-time visual, task 1003109 — the route file is NOT named task-*.js on purpose; see the module CLAUDE.md).
|
|
132
135
|
│ ├── copy-desk/ ← CORE-DOMAIN module (task 1003113 / R02 of goal 1000074, default-on): the COPY half of the design contract — ADR 0081 gave design TOKENS a repo-owned source of truth, text had none. Owns the FLAG (anyone in any role marks a string or a whole surface as needing an artist's attention, with a reason required in BOTH the route and a CHECK constraint) and the QUEUE an artist reads it from. READS R01's committed registry (docs/copy-registry.json, generated by scripts/gds/copy-inventory.js) and never writes it. NO LIVE CMS is the hard non-goal: no column here could hold replacement text, and copy_no_cms.mjs pins that. Key is `copy-desk`, not `copy` — the branding contract already owns a `copy` block, so the bare word reds the "core carries no module code" fitness check. CLAUDE.md, module.json, registry.js, flags.js, routes/copy-desk.js, migrations/copy_desk_001_flags.sql, tests/{copy_flags,copy_queue,copy_no_cms}.mjs. Its hall surface lives with hall-ui (public/copy-desk.{html,js,css}), per the one-key-per-web-surface precedent.
|
|
133
136
|
│ ├── ui-design/ ← CORE-DOMAIN module (task 1003324 / ADR 0197, default-on): the design capability every builder on every instance gets — ships METHOD, never a world. Absorbs ADR 0081's layer: adapters/{claude-design,figma}/index.js (moved from src/ui/adapters/), scripts/{design-sync,figma-design-sync,validate-design}.js (moved from scripts/gds/, which keeps thin shims), docs/design-contract.md (moved from docs/). Declaration-only: contributes.skills design (the /design playbook, new) + design-sync + figma-design-sync; no routes/port/migrations, so disabling it touches no served surface. CLAUDE.md separates the platform FLOORS (the Fifteen Rule, the dark twins, no page :root, the 24px floor, AA in both modes, the kill switch) from the instance's WORLD (its packs + DESIGN.md). kit/ (task 1003320) is the look-before-you-ship kit: lib.js (the floors, the states/probes contracts, the action + expectation vocabularies, the WCAG maths, the stub spawner), serve.js (any surface through the doorway's real transforms + fixtures/), render.js (states × 1440/390/320 × dark/light, audited), probe.js (PASS/FAIL contracts), check-mock.js (platform rules + the instance's DESIGN.md taste bans, then the detector), tells.js (task 1003329 / ADR 0223: the anti-pattern detector as two tiers — floors FAIL, craft tells WARN, kit-ignore waivers per file; the rendered twins live in lib.js factsInPage), contrast.js + png.js; a page's <page>.states.json / <page>.probes.json sit BESIDE the surface (modules/public-landing/public/, modules/hall-ui/public/). Recipe: docs/recipes/ui-look-before-you-ship.md. skills/ (task 1003321 / ADR 0198) is the vendoring policy: policy.json (licence allowlist, verdicts that may land, sidecar fields, preamble markers), PREAMBLE.md (the platform preamble every vendored SKILL.md opens with), README.md (the roster — both origins scanned dangerous on 2026-08-28, landed as rebuild specs; nothing vendored — and the landing recipe); a landable copy goes under skills/vendor/<name>/ with PROVENANCE.md + LICENSE and is materialised into an instance's .claude/skills/ by claude-materialize.js step 1b. skills/<name>/ (task 1003325 / ADR 0220) are the in-house rebuilds from the specs, first-party and counted: design-taste-frontend (the default taste skill), design-taste-frontend-v1 (the earlier generation, kept distinct), high-end-visual-design (the polish pass), redesign-existing-projects (the in-place upgrade); each opens with the same preamble and carries a "Rebuilt from" section instead of a sidecar. impeccable/ (task 1003326 / ADR 0221) is the design-craft method as ONE skill with sub-commands: SKILL.md (the router, the menu, the craft floor, the bounded finish) + reference/<sub-command>.md (eighteen playbooks, one loaded per request); no hooks, no bypass agent, no telemetry, no live server. image-to-code/, imagegen-frontend-web/, imagegen-frontend-mobile/, brandkit/ (task 1003328 / ADR 0222) are the image family under the hero-only rule: plates and hero objects only, the pair (JPEG dark plate + WebP alpha cutout) with a <file>.json sidecar beside each, through the instance's art pipeline key; the grove specimen's styles/grove/assets/ is the worked example. styles/ (task 1003323 / ADR 0219) is the style library: <name>/pack.json (the theme.ui overlay, exactly the fifteen) + DESIGN.md (the look's derived recipes, thirteen in lockstep with the pack) + mock.html (the specimen); chrome-world (pinned to the neutral pack), expedition, grove; STYLE=<name> on the kit lays a look over the instance's pack through GDS_BRANDING_FILE; tests/ui_design_styles.mjs runs the world/cosmos/hall token suites once per alternate (UI_DESIGN_PACK). config/design-tokens.* + design-sources.json STAY in config/ as the host boundary; public-landing keeps its own key (first customer, not owner).
|
|
@@ -159,6 +162,7 @@
|
|
|
159
162
|
│ ├── next-number.js ← deterministic next-free ADR + migration number from origin/main ∪ local working tree; supersedes the drift-prone claim-time DB counter (V4.R26, [#964](https://example.com/builders#/task/964)). `node scripts/gds/next-number.js [--json]`
|
|
160
163
|
│ ├── gen-repo-map.js ← Path B (ADR 0063, [#1224](https://example.com/builders#/task/1224)): zero-dep, deterministic symbol-skeleton generator → docs/repo-map.md + the generated factual block in each nested CLAUDE.md; ranks exported symbols by reference frequency. `--check` = CI gate; regenerated on deploy by ship.js regenerateRepoMap()
|
|
161
164
|
│ ├── gen-file-map.js ← ADR 0066 ([#1276](https://example.com/builders#/task/1276)): generates the `.claude/skills/` + `.claude/scheduled-tasks/` sections of docs/file-map.md from disk; per-entry notes come from docs/file-map.notes.json; `--check` fails on drift OR a skill/routine with no note (CI gate via fitness.js); regenerated on deploy by ship.js regenerateFileMap()
|
|
165
|
+
│ ├── spike-task-map.js ← (task 1003282, goal 1000072) the task-network-map spike harness: builds a ~1,357-task graph across a swept dependency density, lays it out for real (<redacted> + Barnes-Hut), counts what decides readability (isolated nodes, components, distinguishable marks / overplot, crossings, ink budget, payload) and renders PNGs with a hand-rolled encoder. Zero deps, no DB. `--from <tasks.json>` measures the REAL corpus instead of the model. Verdict: docs/research/task-network-map-readability.md
|
|
162
166
|
│ ├── fitness.js ← Path C (ADR 0062 §9, [#1225](https://example.com/builders#/task/1225)): architecture fitness functions — core↔host import boundary (zero grandfathered exceptions as of R52/#1191), CLAUDE.md budget + nested-doc presence (ADR 0061), no route bypasses rank checks (reuses route-rank-check), repo-map freshness. Enforced in CI via tests/fitness.mjs (the `unit` gate). `node scripts/gds/fitness.js`
|
|
163
167
|
│ ├── ship.js ← resolve claim as shipped, award credits (`/builder-ship`); also uploads a secret-scrubbed session digest to the corpus (6D.1, ADR 0027); on a dev box runs the sandbox-first review gate before resolving (#927, ADR 0046)
|
|
164
168
|
│ ├── ship-visual.js ← the OPTIONAL `--visual <image> [--visual-alt "…"]` leg of a ship (task 1003109): screens the file BEFORE the claim resolves (bad input costs no claim), uploads it AFTER (a failed picture never fails a ship)
|
|
@@ -1373,5 +1373,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1373
1373
|
landed since 1.19.466 with no explicit bump. run 33638703282. (task 1002620)
|
|
1374
1374
|
1.19.468 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1375
1375
|
landed since 1.19.467 with no explicit bump. run 33640370009. (task 1002620)
|
|
1376
|
+
1.19.469 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1377
|
+
landed since 1.19.468 with no explicit bump. run 33643388774. (task 1002620)
|
|
1378
|
+
1.19.470 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1379
|
+
landed since 1.19.469 with no explicit bump. run 33644371734. (task 1002620)
|
|
1376
1380
|
---------------------------------------------------------------------------
|
|
1377
1381
|
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Can a network map of ~1,357 tasks be read? — the spike
|
|
2
|
+
|
|
3
|
+
- **Task:** [1003282](https://cloudbongos.com/builders#/task/1003282) · goal 1000072 (Human legibility)
|
|
4
|
+
- **Date:** 2026-08-28
|
|
5
|
+
- **Harness:** [`scripts/gds/spike-task-map.js`](../../scripts/gds/spike-task-map.js) — no dependencies, no network, no DB. Re-run with `node scripts/gds/spike-task-map.js`.
|
|
6
|
+
- **Figures:** [`docs/research/task-network-map/`](task-network-map/) — rendered by the harness, not drawn by hand.
|
|
7
|
+
|
|
8
|
+
## The answer
|
|
9
|
+
|
|
10
|
+
**No — not as a map of tasks, at any dependency density, and the obvious fix makes it
|
|
11
|
+
worse.** What *is* readable is the forty-node **goal** graph as the entry point, with a
|
|
12
|
+
per-goal **dependency forest** as the drill-down. That second view is 3–40% of the
|
|
13
|
+
corpus, never 100%, and that is the finding rather than a compromise: the tasks it
|
|
14
|
+
leaves out are the ones with nothing to connect them to.
|
|
15
|
+
|
|
16
|
+
The map worth building is therefore **not** "the task graph, zoomed out". It is the
|
|
17
|
+
goal graph, drawn once, with a task-level view that opens *inside* a goal.
|
|
18
|
+
|
|
19
|
+
## How it was measured
|
|
20
|
+
|
|
21
|
+
The house rule for questions of this shape was set by this goal's own shipped criterion
|
|
22
|
+
`legibility-sort-and-staleness`: *"~1,357 tasks on BONGOS-V1 alone. A view that does not
|
|
23
|
+
survive that number is not a solution"* — answered in `tests/goal_sort_staleness.mjs` by
|
|
24
|
+
**executing** the board pipeline over a corpus that size. A network map is the same
|
|
25
|
+
question one dimension harder, so it got the same treatment: build the graph, lay it out
|
|
26
|
+
with a real Fruchterman–Reingold pass (Barnes–Hut quadtree, θ=0.8 — the approximation
|
|
27
|
+
d3-force uses), draw it to a real raster, and count.
|
|
28
|
+
|
|
29
|
+
**The dependency density is swept, not guessed.** How many tasks actually declare a
|
|
30
|
+
`task_dependencies` row is a fact of the live DB, which this environment cannot reach.
|
|
31
|
+
Rather than assume one number, the harness sweeps p ∈ {2, 5, 10, 20, 40}% — the share of
|
|
32
|
+
tasks declaring at least one dependency — and reports where each conclusion would flip.
|
|
33
|
+
Every conclusion below holds across the whole range, which is why the missing fact does
|
|
34
|
+
not change the verdict. Point the harness at a real dump to replace every number here
|
|
35
|
+
with a measured one:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node scripts/gds/spike-task-map.js --from tasks.json # a GET /tasks?include=deps dump
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Four views of the same corpus, all at 1280×720 (a laptop viewport with the hall's chrome
|
|
42
|
+
removed — quoting a 4K desktop would flatter the result for a screen most readers do not
|
|
43
|
+
have):
|
|
44
|
+
|
|
45
|
+
| | view | what it is |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| **A** | every task | the literal reading of "a network map of 1,300 tasks" |
|
|
48
|
+
| **B** | tasks with a dependency | A with the unconnected nodes swept off |
|
|
49
|
+
| **C** | goals | one node per goal, cross-goal dependencies aggregated |
|
|
50
|
+
| **D** | tasks joined by goal | the obvious second attempt, once A turns out to be sparse |
|
|
51
|
+
|
|
52
|
+
## The numbers
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
density view nodes edges isol% comps marks lost% cross pitch label? ms KB
|
|
56
|
+
------------------------------------------------------------------------------------------------------------------------
|
|
57
|
+
p=2% every task 1357 21 97.2 1336 1355 0.1 0 26.1px NO 861 6
|
|
58
|
+
p=2% tasks with a dependency 38 21 0 17 38 0 0 155.7px yes 34 0
|
|
59
|
+
p=2% goals 40 5 80 35 40 0 0 151.8px yes 54 0
|
|
60
|
+
any tasks joined by goal 1357 22341 0 40 222 83.6 1492927~ 26.1px NO 1003 232
|
|
61
|
+
p=5% every task 1357 44 94.1 1313 1352 0.4 1 26.1px NO 855 6
|
|
62
|
+
p=5% tasks with a dependency 80 44 0 36 80 0 1 107.3px yes 24 1
|
|
63
|
+
p=5% goals 40 7 72.5 33 40 0 2 151.8px yes 8 0
|
|
64
|
+
p=10% every task 1357 81 89.7 1277 1351 0.4 2 26.1px NO 818 6
|
|
65
|
+
p=10% tasks with a dependency 140 81 0 60 140 0 2 81.1px yes 54 1
|
|
66
|
+
p=10% goals 40 13 52.5 27 40 0 2 151.8px yes 9 0
|
|
67
|
+
p=20% every task 1357 168 79.2 1189 1336 1.5 5 26.1px NO 884 7
|
|
68
|
+
p=20% tasks with a dependency 282 168 0 114 282 0 8 57.2px yes 143 3
|
|
69
|
+
p=20% goals 40 31 22.5 12 40 0 12 151.8px yes 9 0
|
|
70
|
+
p=40% every task 1357 351 59.5 1006 1320 2.7 33 26.1px NO 897 9
|
|
71
|
+
p=40% tasks with a dependency 549 351 0 198 549 0 30 41px NO 325 6
|
|
72
|
+
p=40% goals 40 50 2.5 2 40 0 44 151.8px yes 10 0
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`marks` = distinct 7px cells any node lands in — what a reader can actually tell apart.
|
|
76
|
+
`lost%` = share of nodes overplotting a mark another node already owns.
|
|
77
|
+
`pitch` = √(canvas area ÷ nodes), the square each node owns. `label?` asks whether that
|
|
78
|
+
square is as wide as a six-character label (48px).
|
|
79
|
+
|
|
80
|
+
## What each row says
|
|
81
|
+
|
|
82
|
+
### A — "every task" is confetti, not a hairball
|
|
83
|
+
|
|
84
|
+
This is the surprise, and it is the whole result. A 1,357-node graph is *expected* to
|
|
85
|
+
fail as a tangle: too many edges, too many crossings, one illegible ball of yarn. It
|
|
86
|
+
fails the other way. **59.5% to 97.2% of tasks have no dependency at all**, so the
|
|
87
|
+
picture is 1,006–1,336 separate components — overwhelmingly single dots — and **33
|
|
88
|
+
crossings at the densest end**, which is nothing.
|
|
89
|
+
|
|
90
|
+

|
|
91
|
+
|
|
92
|
+
That disc of 1,320 distinguishable dots with a few three-node chains in the middle is
|
|
93
|
+
the *best* case in the sweep. Two things follow, and neither is fixable by drawing
|
|
94
|
+
better:
|
|
95
|
+
|
|
96
|
+
- **A force layout is arranging nothing.** It has no opinion about where a thousand
|
|
97
|
+
unconnected islands go, so their positions carry no information. Every dot's location
|
|
98
|
+
is an accident of the seed. A reader who infers anything from proximity here is being
|
|
99
|
+
misled by the renderer.
|
|
100
|
+
- **Labels never fit.** 26.1px of pitch against the 48px a six-character label needs —
|
|
101
|
+
and that is the *average*, before clustering. So the map cannot say which task any dot
|
|
102
|
+
is, which means the only way to read it is to hover 1,357 times.
|
|
103
|
+
|
|
104
|
+
Sparse-and-disconnected is a *different failure* from dense-and-tangled, and it needs a
|
|
105
|
+
different answer. You cannot declutter your way out of it; there is no clutter.
|
|
106
|
+
|
|
107
|
+
### D — making it dense draws the goal graph, badly
|
|
108
|
+
|
|
109
|
+
The natural next move once A turns out sparse: connect tasks by something that actually
|
|
110
|
+
relates them. Shared goal is the obvious candidate, and it is the one a "task network"
|
|
111
|
+
would reach for.
|
|
112
|
+
|
|
113
|
+

|
|
114
|
+
|
|
115
|
+
Forty dots. **22,341 edges, ~1.49 million crossings, 232 KB of graph, a full second of
|
|
116
|
+
layout — and 83.6% of the nodes overplot, leaving 222 marks that read as forty.** Each
|
|
117
|
+
goal is a clique, so each clique contracts to a blob smaller than the dot used to draw
|
|
118
|
+
it, and every edge inside it is sub-pixel.
|
|
119
|
+
|
|
120
|
+
The dense view spends three orders of magnitude more edges to draw, illegibly, the
|
|
121
|
+
picture that view C draws legibly with fifty. That is not a tuning problem. It is the
|
|
122
|
+
data saying that at this scale the only structure the eye can extract from 1,357 tasks
|
|
123
|
+
**is** the forty goals.
|
|
124
|
+
|
|
125
|
+
### C — the goal graph is readable, everywhere in the sweep
|
|
126
|
+
|
|
127
|
+

|
|
128
|
+
|
|
129
|
+
Forty nodes, 5–50 edges, zero overplot, 151.8px of pitch — three times what a label
|
|
130
|
+
needs — and it stays readable at every density measured. It is also the view the system
|
|
131
|
+
already computes: `modules/lifecycle/goal-rollup.js` produces one row per goal in
|
|
132
|
+
Postgres precisely because the browser could not hold the task corpus (5,229,455 bytes
|
|
133
|
+
for ~1,400 tasks, measured 2026-08-25). **The readable map is the one whose data layer
|
|
134
|
+
already exists.**
|
|
135
|
+
|
|
136
|
+
At low density it has its own honest weakness — 80% of goals are isolated at p=2%,
|
|
137
|
+
because cross-goal dependencies are what draw its edges. A goal graph with no edges is a
|
|
138
|
+
legend, not a map. Which side of that line the live corpus falls on is the one number
|
|
139
|
+
worth measuring before building.
|
|
140
|
+
|
|
141
|
+
### B — the dependency forest is the drill-down
|
|
142
|
+
|
|
143
|
+

|
|
144
|
+
|
|
145
|
+
Sweeping the isolated nodes off A leaves 38–549 nodes and zero overplot, readable with
|
|
146
|
+
labels up to p=20% and as unlabelled dots beyond. This is the task-level view that
|
|
147
|
+
works, and it works *because* it does not try to show every task.
|
|
148
|
+
|
|
149
|
+
Note what it costs: at p=40% it still fails the label test (41px pitch), so even the
|
|
150
|
+
forest wants scoping. Per goal it is 1–14 nodes — comfortably readable, and the natural
|
|
151
|
+
thing to open when someone clicks a goal in C.
|
|
152
|
+
|
|
153
|
+
## What to build, if anything
|
|
154
|
+
|
|
155
|
+
1. **The goal graph (C) as the map.** Forty nodes, edges = cross-goal dependencies,
|
|
156
|
+
weight = task count, colour = the ADR 0192 category the goals already carry. Its data
|
|
157
|
+
is one `goalRollups` query plus a cross-goal dependency count; the payload is bytes,
|
|
158
|
+
not megabytes.
|
|
159
|
+
2. **The dependency forest (B), scoped to one goal, as the drill-down.** Not a zoom of a
|
|
160
|
+
global map — a separate, small query answered when a goal is opened.
|
|
161
|
+
3. **Never view A, and never view D.** Not as a default, not as an "advanced" toggle.
|
|
162
|
+
A shows a thousand dots whose positions are noise; D shows forty dots and calls it a
|
|
163
|
+
thousand. Both invite a reader to believe they are seeing structure that is not there,
|
|
164
|
+
which is a worse outcome than no map — this goal is about legibility, and a confident
|
|
165
|
+
picture of nothing is the opposite of it.
|
|
166
|
+
|
|
167
|
+
**Before any of it is built, measure the real density**, with `--from`. Two numbers
|
|
168
|
+
decide the shape: the share of tasks carrying a dependency (does B have anything in it?)
|
|
169
|
+
and the share of dependencies that cross a goal boundary (does C have any edges?). If
|
|
170
|
+
cross-goal dependencies are near zero, C is forty disconnected dots and the honest
|
|
171
|
+
deliverable is a grid of goal cards, not a graph — which the hall's Goals page already
|
|
172
|
+
is. **That is a real possible outcome of this spike, and it would mean the right amount
|
|
173
|
+
of new map to build is none.**
|
|
174
|
+
|
|
175
|
+
## Caveats, stated plainly
|
|
176
|
+
|
|
177
|
+
- **The corpus is synthetic.** The live DB is unreachable from the environment this ran
|
|
178
|
+
in, so the harness sweeps a plausible range instead of measuring one truth. The sweep
|
|
179
|
+
is what makes the verdict robust — every conclusion above holds from p=2% to p=40% —
|
|
180
|
+
but the *specific* numbers are model output, not observation. Re-run with `--from`.
|
|
181
|
+
- **The goal count (40) and the 85% within-goal edge preference are modelled**, from the
|
|
182
|
+
repo's own record of ~38 open goals on BONGOS-V1 (`scripts/gds/goal-names.js`) and from
|
|
183
|
+
how dependencies are declared in practice. A very different real distribution would
|
|
184
|
+
change C's edge count — not A's isolation, which is bounded by p by construction.
|
|
185
|
+
- **`marks` is a proxy for legibility, not legibility.** It counts what is
|
|
186
|
+
*distinguishable*, not what is *understandable*; a map can clear it and still say
|
|
187
|
+
nothing. It is used here only to make overplotting a number, which is the one thing
|
|
188
|
+
looking at a picture reliably fails to do.
|
|
189
|
+
- **The layout is one algorithm.** A hierarchical or Sugiyama-style layout would draw
|
|
190
|
+
view B's chains better than a force pass does. It would not change A (there is nothing
|
|
191
|
+
to lay out) or D (the overplotting is arithmetic, not layout).
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
/* atlas.css —
|
|
2
|
-
|
|
3
|
-
the
|
|
4
|
-
|
|
1
|
+
/* atlas.css — the Repo Atlas SCENE (task 1737 amending ADR 0094's styling
|
|
2
|
+
clause; re-skinned in task 1003307; redesigned in task 1003472, goal 1000081).
|
|
3
|
+
The chrome around the scene — the panel, the view switch, the caption, the
|
|
4
|
+
detail card, the island index, the foot — is the shell's and the oversight
|
|
5
|
+
family's, so this sheet holds only what the map has that no other page does:
|
|
6
|
+
the nine semantic colours, the scene box, the detail card's placement, the
|
|
7
|
+
legend swatches and the node/edge states.
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
(
|
|
13
|
-
|
|
14
|
-
the
|
|
9
|
+
What 1003472 removed, and why: the page's own hairline + accent wash on the
|
|
10
|
+
panel (the panel is the shell's .scroll now, on the owner's standing decision
|
|
11
|
+
that the transparent edge stands — task 1003470 closed that question);
|
|
12
|
+
.ab-modes, a segmented box that was a third toggle grammar beside the shell's
|
|
13
|
+
tab strip; .ab-chip, an accent pill saying "live" on a map whose foot already
|
|
14
|
+
says when it was drawn; the glass hint pill floating over the scene; the two
|
|
15
|
+
box-shadows (the detail card and the empty card — the world draws depth with
|
|
16
|
+
hairlines); and the 5.5s pulse on the hub's glow, which read as a status dot
|
|
17
|
+
(the world's ambient floor is 20s). */
|
|
15
18
|
.atlas-page{
|
|
16
19
|
/* THE SEMANTIC MAP PALETTE — the sanctioned exception, alongside the shell's
|
|
17
20
|
status vocabulary. ADR 0094's invariant is that a pack's colours must never
|
|
@@ -26,28 +29,19 @@
|
|
|
26
29
|
/* Pure white with alpha as an ambient wash — the Fifteen Rule's one legal
|
|
27
30
|
literal shape (a scrim, a mask or a halo). */
|
|
28
31
|
--ab-ambient: rgba(255,255,255,.5);
|
|
29
|
-
/*
|
|
30
|
-
already holds a second hue for exactly this: --sea, which the hall otherwise
|
|
32
|
+
/* The hub's glow: the world's second hue, --sea, which the hall otherwise
|
|
31
33
|
never spends. */
|
|
32
34
|
--ab-glow: color-mix(in srgb, var(--sea) 30%, var(--bg-card));
|
|
33
|
-
/* The badge fills
|
|
34
|
-
|
|
35
|
-
modes (tests/hall_tokens.mjs), so they are that vocabulary now — which is
|
|
36
|
-
also why this rule needs no dark block for them any more. */
|
|
35
|
+
/* The in-scene badge fills are the four-state vocabulary the shell already
|
|
36
|
+
measures on both grounds in both modes (tests/hall_tokens.mjs). */
|
|
37
37
|
--ab-b-good-bg:var(--ok-weak); --ab-b-good-fg:var(--ok);
|
|
38
38
|
--ab-b-warn-bg:var(--warn-weak); --ab-b-warn-fg:var(--warn);
|
|
39
39
|
--ab-b-danger-bg:var(--danger-weak); --ab-b-danger-fg:var(--danger);
|
|
40
40
|
--ab-b-info-bg:var(--info-weak); --ab-b-info-fg:var(--info);
|
|
41
|
-
color:var(--ink);
|
|
42
|
-
border:var(--line) solid var(--rule-soft); border-radius:var(--radius);
|
|
43
|
-
background:
|
|
44
|
-
radial-gradient(ellipse 70% 55% at 50% 46%, color-mix(in srgb, var(--accent) 4%, transparent), transparent 70%),
|
|
45
|
-
var(--bg-card);
|
|
46
41
|
}
|
|
47
|
-
/* The dark twin,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
values are left (task 1003307). */
|
|
42
|
+
/* The dark twin, written twice and byte-identical — that rule does not bend.
|
|
43
|
+
Only the two genuinely scene-level values flip here; the badge pairs flip
|
|
44
|
+
themselves as the status vocabulary. */
|
|
51
45
|
html[data-theme="dark"] .atlas-page{
|
|
52
46
|
--ab-ambient: rgba(255,255,255,.03);
|
|
53
47
|
--ab-glow: color-mix(in srgb, var(--sea) 55%, var(--bg));
|
|
@@ -58,69 +52,83 @@ html[data-theme="dark"] .atlas-page{
|
|
|
58
52
|
--ab-glow: color-mix(in srgb, var(--sea) 55%, var(--bg));
|
|
59
53
|
}
|
|
60
54
|
}
|
|
61
|
-
.atlas-page *{box-sizing:border-box}
|
|
62
|
-
.atlas-page button{font:inherit}
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.ab-
|
|
69
|
-
|
|
70
|
-
.ab-
|
|
71
|
-
.ab-modes button.active{background:var(--accent-tint); color:var(--accent-ink)}
|
|
72
|
-
.ab-modes button:focus-visible{outline:2px solid var(--accent); outline-offset:-2px}
|
|
56
|
+
/* The view switch sits under the heading with the strip's own rule; the
|
|
57
|
+
caption under it is the shell's lede, so the map's blurb takes the measure
|
|
58
|
+
every other panel's lede takes. The sub line is the caption's faint second
|
|
59
|
+
line: what the map was counted from. */
|
|
60
|
+
.ab-views{ margin: 4px 0 14px; }
|
|
61
|
+
.ab-caption{ margin-bottom: 4px; }
|
|
62
|
+
.ab-caption .sub{ display:block; margin-top:4px; font-size:12.5px; color:var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
73
63
|
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
/* The scene: the SVG at its natural aspect, the detail card and the empty
|
|
65
|
+
state positioned inside it. */
|
|
66
|
+
.ab-scene{ position:relative; width:100%; padding:6px 0 0; }
|
|
67
|
+
.ab-scene svg{ display:block; width:100%; height:auto; }
|
|
68
|
+
.ab-hint{ margin: 6px 0 0; }
|
|
69
|
+
/* The empty state flows in the scene's place (the SVG is hidden then), so a
|
|
70
|
+
phone is not handed 300px of ground under a map that is not there. */
|
|
71
|
+
.ab-empty{ display:none; justify-content:center; text-align:center; padding:40px 20px; }
|
|
72
|
+
.ab-empty.show{ display:flex; }
|
|
73
|
+
.ab-empty__state{ max-width: var(--measure); }
|
|
74
|
+
.ab-empty__state p b{ display:block; margin-bottom:4px; font-weight:500; color:var(--ink); }
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.ab-
|
|
82
|
-
.ab-
|
|
83
|
-
.ab-
|
|
84
|
-
box-shadow:var(--shadow-pop)}
|
|
85
|
-
.ab-empty h2{margin:0 0 8px; font-size:16px; font-weight:650}
|
|
86
|
-
.ab-empty p{margin:0; font-size:13.5px; line-height:1.55; color:var(--ink-soft)}
|
|
76
|
+
/* The legend: the nine colours with their meaning, in the fact voice. The
|
|
77
|
+
swatch is a semantic colour, so it is the one thing on the page that is not
|
|
78
|
+
a token. */
|
|
79
|
+
.ab-legend{ display:flex; flex-wrap:wrap; gap:8px 18px; padding:10px 0 0; font-size:12.5px; color:var(--ink-soft); }
|
|
80
|
+
.ab-legend .lg{ display:flex; align-items:center; gap:7px; }
|
|
81
|
+
.ab-legend .sw{ width:12px; height:12px; border-radius:3px; }
|
|
82
|
+
.ab-legend .ln{ width:18px; border-top:3px solid; }
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.
|
|
92
|
-
.
|
|
84
|
+
/* The island index: the family's dense rows under a collapsible head. The
|
|
85
|
+
row's title is a disclosure button; the detail it opens is the same panel
|
|
86
|
+
the map's popup shows, laid inline under the row so a phone reads it in
|
|
87
|
+
place. Hovering a row lights the island on the map, the way hovering the
|
|
88
|
+
island does. */
|
|
89
|
+
.ab-index{ margin: var(--sp-md) 0 0; padding-top: 10px; border-top: var(--line) solid var(--rule); }
|
|
90
|
+
.ab-index > summary{ padding: 0 0 10px; border-bottom: var(--line) solid var(--rule); }
|
|
91
|
+
.ab-index[open] > summary{ margin-bottom: 0; }
|
|
92
|
+
.ab-index .kit-collapse__body{ margin-top: 0; }
|
|
93
|
+
.ab-ix__t{ font: inherit; background:none; border:0; padding:2px 4px; margin:-2px -4px; text-align:left; cursor:pointer; }
|
|
94
|
+
.ab-ix__t:hover{ color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
|
|
95
|
+
.ab-ix__t[aria-expanded="true"]{ color: var(--ink); }
|
|
96
|
+
.ab-ix__body{ margin: 10px 0 4px; max-width: var(--measure); }
|
|
97
|
+
.ab-ix__body .ab-ptitle{ display:none; }
|
|
98
|
+
/* The island's colour, drawn as a 10px square before the title so the index
|
|
99
|
+
and the map share one language. */
|
|
100
|
+
.ab-ix__sw{ display:inline-block; width:10px; height:10px; border-radius:2px; margin-right:9px; vertical-align: 1px; }
|
|
101
|
+
.ab-ix__sw--ghost{ background:transparent !important; border:1.5px dashed currentColor; opacity:.6; }
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
.ab-popup
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
.ab-
|
|
102
|
-
|
|
103
|
-
.ab-ppath{font-family: var(--font-mono); font-size:11.5px; color:var(--ink-
|
|
104
|
-
.ab-pdesc{font-size:
|
|
105
|
-
.ab-prow{margin-top:
|
|
106
|
-
.ab-chips{display:flex; flex-wrap:wrap; gap:6px; margin-top:6px}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
.ab-
|
|
110
|
-
.ab-b-good{background:var(--ab-b-good-bg); color:var(--ab-b-good-fg)} .ab-b-warn{background:var(--ab-b-warn-bg); color:var(--ab-b-warn-fg)}
|
|
111
|
-
.ab-b-danger{background:var(--ab-b-danger-bg); color:var(--ab-b-danger-fg)} .ab-b-info{background:var(--ab-b-info-bg); color:var(--ab-b-info-fg)}
|
|
103
|
+
/* The detail card: a --bg-card panel closed by one rule hairline and no shadow
|
|
104
|
+
(the family's .ov-modal, positioned over the scene). */
|
|
105
|
+
.ab-popup{ position:absolute; z-index:6; width:320px; max-width:92%; background:var(--bg-card);
|
|
106
|
+
border:var(--line) solid var(--rule); border-radius:var(--radius); padding:16px 18px; display:none; }
|
|
107
|
+
.ab-popup.show{ display:block; }
|
|
108
|
+
.ab-popup-close{ position:absolute; top:10px; right:10px; display:inline-flex; align-items:center; justify-content:center;
|
|
109
|
+
width:28px; height:28px; cursor:pointer; border:0; border-radius:var(--radius-pill); background:transparent; color:var(--ink-faint); }
|
|
110
|
+
.ab-popup-close:hover{ color:var(--ink); background:var(--glass); }
|
|
111
|
+
.ab-ptitle{ font-weight:500; font-size:15px; letter-spacing:-0.01em; display:flex; align-items:center; gap:8px; flex-wrap:wrap; line-height:1.3; padding-right:28px; color:var(--ink); }
|
|
112
|
+
.ab-ppath{ font-family: var(--font-mono); font-size:11.5px; color:var(--ink-faint); margin-top:4px; overflow-wrap:anywhere; }
|
|
113
|
+
.ab-pdesc{ font-size:13px; line-height:1.55; margin:10px 0 0; color:var(--ink-soft); }
|
|
114
|
+
.ab-prow{ margin-top:12px; font-family:var(--label-face); font-size:var(--label-size); letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink-faint); }
|
|
115
|
+
.ab-chips{ display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
|
|
116
|
+
/* A neighbour is a door: the chip is a button that opens that island. */
|
|
117
|
+
button.ab-jump{ font:inherit; font-family:var(--font-mono); font-size:11px; cursor:pointer; background:none; }
|
|
118
|
+
button.ab-jump:hover{ color:var(--accent-ink); border-color:var(--accent-ink); }
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
.ab-node
|
|
115
|
-
.ab-node text
|
|
116
|
-
.ab-node text.ab-
|
|
117
|
-
|
|
118
|
-
svg.focus .ab-node
|
|
119
|
-
.ab-
|
|
120
|
-
|
|
121
|
-
svg.focus .ab-edge
|
|
122
|
-
.ab-edge.lit{
|
|
123
|
-
.ab-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@
|
|
120
|
+
/* ---- the scene's own states: nodes, edges, the lit set, the hub's glow ---- */
|
|
121
|
+
.ab-node{ cursor:pointer; transition:opacity .18s; }
|
|
122
|
+
.ab-node text{ font-family:var(--font-body); paint-order:stroke; stroke:var(--ab-label-halo); stroke-width:3px; stroke-linejoin:round; fill:var(--ab-label-ink); }
|
|
123
|
+
.ab-node text.ab-sub{ fill:var(--ink-faint); }
|
|
124
|
+
.ab-node text.ab-badge-text{ stroke:none; paint-order:normal; }
|
|
125
|
+
svg.focus .ab-node{ opacity:.18; }
|
|
126
|
+
svg.focus .ab-node.lit{ opacity:1; }
|
|
127
|
+
.ab-edge{ fill:none; opacity:.18; transition:opacity .18s; }
|
|
128
|
+
svg.focus .ab-edge{ opacity:.04; }
|
|
129
|
+
svg.focus .ab-edge.lit{ opacity:1; }
|
|
130
|
+
.ab-edge.lit{ filter:url(#abglow); }
|
|
131
|
+
/* The hub breathes at the world's ambient floor, not as a pulse. */
|
|
132
|
+
.ab-sun-glow{ animation:abbreathe 24s ease-in-out infinite; }
|
|
133
|
+
@keyframes abbreathe{ 0%,100%{opacity:.45} 50%{opacity:.75} }
|
|
134
|
+
@media (prefers-reduced-motion: reduce){ .atlas-page *{ transition:none!important; animation:none!important; } }
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
12
|
+
<!-- task 1003472: the island index under the map is a run of oversight rows,
|
|
13
|
+
and the detail panel's facts are the family's lines, so the family sheet
|
|
14
|
+
loads first and atlas.css holds only the scene. -->
|
|
15
|
+
<link rel="stylesheet" href="/builders/oversight.css">
|
|
12
16
|
<link rel="stylesheet" href="/builders/atlas.css">
|
|
13
17
|
</head>
|
|
14
18
|
<body data-page="atlas" data-page-title="Repo Atlas">
|
|
@@ -24,42 +28,61 @@
|
|
|
24
28
|
board's label voice gives it one without competing with the map. -->
|
|
25
29
|
<div class="page-head page-head--board">
|
|
26
30
|
<h1 class="page-head__h">Repo atlas</h1>
|
|
27
|
-
<p class="page-head__sub">A self-drawing map of the codebase: what each module is, and what depends on it.</p>
|
|
31
|
+
<p class="page-head__sub">A self-drawing map of the codebase: what each module is, and what depends on it. Redrawn from the code on every deploy.</p>
|
|
28
32
|
</div>
|
|
29
33
|
|
|
30
34
|
<main id="hall-main">
|
|
31
|
-
<!-- The atlas
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
<!-- The atlas is NOT a list page: it is an SVG scene with a view switch,
|
|
36
|
+
a caption, a legend and a detail panel. task 1003472 put its CHROME
|
|
37
|
+
in the shell's dialect — the panel is the shell's .scroll, the view
|
|
38
|
+
switch its tab strip, the detail panel a hairline --bg-card card —
|
|
39
|
+
and added the island INDEX under the map: every island as a row a
|
|
40
|
+
keyboard or a phone can open, since the map itself is a hover scene
|
|
41
|
+
that was unreadable at 390px and unreachable without a mouse. Only
|
|
42
|
+
the semantic node/edge palette stays instance-independent, so a
|
|
43
|
+
pack can never scramble the map's colour-coded meaning (ADR 0094). -->
|
|
44
|
+
<section class="scroll atlas-page" aria-labelledby="atlas-h">
|
|
45
|
+
<h2 id="atlas-h" class="scroll__h">The map</h2>
|
|
46
|
+
<div class="kit-tabs ab-views" role="tablist" aria-label="Map view">
|
|
47
|
+
<button type="button" class="setup__tab" role="tab" data-view="context" aria-selected="true">Context layer</button>
|
|
48
|
+
<button type="button" class="setup__tab" role="tab" data-view="modules" aria-selected="false">Module truth</button>
|
|
41
49
|
</div>
|
|
42
50
|
|
|
43
|
-
<p class="ab-caption" id="caption">Loading the map…</p>
|
|
51
|
+
<p class="scroll__lede ab-caption" id="caption">Loading the map…</p>
|
|
44
52
|
|
|
45
53
|
<div class="ab-scene" id="scene">
|
|
46
54
|
<svg id="svg" role="img" aria-label="Isometric map of the repository"></svg>
|
|
47
|
-
<div class="ab-hint">Hover an island to light its links · click one for details</div>
|
|
48
55
|
<div class="ab-popup" id="popup" role="dialog" aria-label="Codebase detail">
|
|
49
|
-
<button class="ab-popup-close" id="popupClose" aria-label="Close"
|
|
56
|
+
<button type="button" class="ab-popup-close" id="popupClose" aria-label="Close">
|
|
57
|
+
<svg viewBox="0 0 12 12" width="12" height="12" aria-hidden="true" focusable="false"><path d="M2 2l8 8M10 2l-8 8" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
|
|
58
|
+
</button>
|
|
50
59
|
<div id="popupBody"></div>
|
|
51
60
|
</div>
|
|
52
61
|
<div class="ab-empty" id="empty">
|
|
53
|
-
<div class="
|
|
54
|
-
<
|
|
55
|
-
<p>The Repo Atlas regenerates itself on the server every time code ships. It looks like it hasn’t been generated on this deploy yet — check back after the next deploy.</p>
|
|
62
|
+
<div class="empty-state ab-empty__state">
|
|
63
|
+
<p><b>The map is being drawn.</b> The atlas regenerates itself on the server every time code ships; it has not been generated on this deploy yet. Check back after the next deploy.</p>
|
|
56
64
|
</div>
|
|
57
65
|
</div>
|
|
58
66
|
</div>
|
|
59
67
|
|
|
68
|
+
<p class="ab-hint ov-foot" id="hint">Hover an island to light its links, click one for its details, or open it from the index below.</p>
|
|
60
69
|
<div class="ab-legend" id="legend"></div>
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
|
|
71
|
+
<!-- The island index (task 1003472): the same islands as rows. Closed
|
|
72
|
+
on a desktop, where the map is the read; opened by atlas.js on a
|
|
73
|
+
phone, where the index is. -->
|
|
74
|
+
<details class="kit-collapse ab-index" id="ab-index">
|
|
75
|
+
<summary class="kit-collapse__summary">
|
|
76
|
+
<span class="ov-group__name">Island index</span>
|
|
77
|
+
<span class="ov-group__n" id="ab-index-n"></span>
|
|
78
|
+
</summary>
|
|
79
|
+
<div class="kit-collapse__body">
|
|
80
|
+
<ul class="ov-rows" id="ab-index-rows"></ul>
|
|
81
|
+
</div>
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
<p class="ov-foot" id="foot"></p>
|
|
85
|
+
</section>
|
|
63
86
|
</main>
|
|
64
87
|
<footer class="app-foot" id="app-foot"></footer>
|
|
65
88
|
</div>
|
|
@@ -71,6 +94,6 @@
|
|
|
71
94
|
<script src="/builders/shell.js?v=2026-07-02-shell1"></script>
|
|
72
95
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
73
96
|
<script src="/builders/palette.js" defer></script>
|
|
74
|
-
<script src="/builders/atlas.js?v=2026-
|
|
97
|
+
<script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
|
|
75
98
|
</body>
|
|
76
99
|
</html>
|