Skip to content

feat(frontend): the design system renders, islands boot, admin pages register, one row per id - #91

Merged
sebyx07 merged 1 commit into
mainfrom
feat/ui-runtime-entity-components
Aug 15, 2026
Merged

feat(frontend): the design system renders, islands boot, admin pages register, one row per id#91
sebyx07 merged 1 commit into
mainfrom
feat/ui-runtime-entity-components

Conversation

@sebyx07

@sebyx07 sebyx07 commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Five slices, four agents, all from the same audit of five production codebases. Each found the problem was worse than reported, and three found a shipped API broken on its first line — none of which the read-only audit could see, because each only surfaces when something calls it.

ui — the throw was protecting nothing

setSolidRuntime had zero call sites outside this package's own tests, and 24 components (not 23 — eight call solid() directly, which patching useUi() alone would have left broken) could not render server-side. The demo says so in its own source: two auth pages hand-rolled the same field block twice and had already drifted.

Then the deeper finding: registering the real solid-js and rendering Ctx.Provider through the inert factory, the child still read the default. Solid's context needs an owner and an inert tree is walked outside every owner — so UiProvider has always been a server-side no-op and the throw guarded nothing.

The obvious fix was rejected. Falling back to defaultUiContext() would render every server-side <DateTime> in UTC and every <Money> in USD, silently, for every app. Instead useUi() off-DOM returns an ambient context reading locale and zone off core's existing request ALS — no new store, because i18n and time already project those. The probe is "is reactivity possible here", not "am I a server": a DOM with no runtime still throws, because that is the theme-toggle-does-nothing bug.

render + clihydrate was a promise with no referent

IslandDirective, emitIslandAttributes, hydrateRuntime, RouteEntry.islands and routeJsBytes all shipped, and nothing ever constructed or populated any of them. render-static.ts:55 even carried a fix: telling authors to "move the request-dependent part into an island" — naming a mechanism the framework could not express.

island({ src, props }) is a factory over the route's existing hydrate: the route says when, the island says which module. defineRoute gains no key, because a second way to say "this route hydrates" is what axiom 1 forbids.

src is a string, not an import. There is no edge from the page to the island for a bundler or the surface-boundary walk to follow, so a static page's graph cannot grow the island's dependencies — structural, not policed. Props are gated: declared, JSON-only, 4kb — <Modal {...post} /> fails and names email and passwordHash, every column the spread would have shipped.

Wired end to end through both paths from one table — x dev and serve.ts — deliberately, because a seam that works in dev and not in the image is the same failure one release later. Proof from the emitted artifact: one data-x-entry, and the static page next door emits no <script> at all with jsBytes: 0.

And a live budget bug in each layer: routeJsBytes filtered by entry.islands, which nothing populated; measureDocumentJs weighed <script src> tags while an island is reached by import(). A page was charged for the hydration runtime and never for the code it boots.

adminadminRoutes() was dead on arrival

It emitted defineRoute({ render: 'spa' }) with no policy, which render's own assertModeShape refuses — so every call threw X_ROUTE_MODE_INVALID. Published, advertised in README.md:61, no test file, no consumer anywhere.

pages: now registers a custom screen, and the guard cannot be omitted, by four independent locks: refused at declaration when permissions is empty; the frame's admin:read composed in front of the declared one; adminRouteConfig writes the defineRoute call so the author never does; and the router is handed a wrapped component, with AdminPageProps.ctx required so the raw one cannot even be called. Nav is closed too — an unlinkable page was visible to everyone.

The escape hatch is the main event: of treasury's 70 ActiveAdmin files, 28 reach for Arbre or register_page and hold 55% of the LOC, and 20 of 70 are bespoke ops screens rather than model CRUD.

Also names the strength that was undocumented: there is no Arbre analogue and there will not be one. Every renderer is ordinary TSX importing @ultimat3/ui, the generated pieces are individually exported so a table can be lifted out of its page — which ActiveAdmin cannot do — and an admin route is an ordinary route.

realtime — the local store was write-only

Two live queries overlapping on one row held two copies of it, which the thesis table has called "a bug the framework should make unrepresentable" since before it shipped. Fixed by lifting the identity map out of the tier-3 local store so both tiers share one, keyed (entity, id)posts/7 and users/7 are two rows, and a slug primary key makes that collision plausible rather than theoretical.

The larger bug the test exposed: useLive never read the local store at all. store.apply() wrote MemoryLocalStore and nothing anywhere read it, so a mutator's optimistic local(tx, input) twin was invisible in every live query until the server round-tripped a patch.

Membership and identity are separate — Ember's own split — because sharing one Map<table, Map<id, Row>> means rolling back an optimistic insert deletes a row the server had since sent to another window. A write merges columns rather than replacing the row, since two queries may project different columns.

SnapshotFrame carries entity, and PROTOCOL_VERSION is deliberately not bumped: the field is additive and readable in both directions, so bumping would refuse every in-flight client on a rolling deploy in exchange for nothing. The package rule now says the version guards incompatibility, not novelty.

Also

Two framework i18n keys were structurally unreachable: ui.error and ui.theme are leaves under branches (ui.error.code, ui.theme.light), and a catalog is authored nested where a name is a leaf or a branch, never both — so <ThemeToggle>'s aria-label rendered ⟦ui.theme⟧. Renamed, and the whole ui.* namespace now ships in en.json; it was absent entirely.

x g island and x g admin:page, both in FIXTURE_GENERATORS so the scaffold gate compiles them. cmd-generate.ts had reached exactly 500 lines — passing with zero headroom — and is split.

Gate

bun run verify14 of 17 passed, 3 skipped. Reference-app gate: every pin holds. 328 error codes. Every new test written failure-case-first and run red; the ui table was re-run with the fix reverted to prove 26 of 28 cases fail.

Owed, and named rather than left silent: neither tracked app exercises an island yet, so the seam is not proven against real app code in the app gate. x g island <name> --at apps/web/site/<route> writes the first half.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…register, one row per id

Five slices, four agents, all from the same audit. Each found the problem was
worse than reported, and three found a shipped API that was broken on its first
line — none of which a read-only audit could see, because each only surfaces
when something calls it.

ui — the throw was protecting nothing
--------------------------------------
setSolidRuntime had zero call sites outside this package's own tests, and 24
components (not 23 — eight call solid() directly for signals, which patching
useUi() alone would have left broken) could not render server-side at all. The
demo says so in its own source: two auth pages hand-rolled the same field block
twice and had already drifted.

Then the deeper finding: registering the real solid-js and rendering
Ctx.Provider through the inert factory, the child STILL read the default. Solid's
context needs an owner and an inert tree is walked outside every owner — so
UiProvider has always been a no-op on the server, and the throw guarded nothing.

Rejected the obvious fix. Falling back to defaultUiContext() would render every
server-side <DateTime> in UTC and every <Money> in USD, silently, for every app —
the exact degradation this repo keeps closing. Instead useUi() off-DOM returns an
ambient context reading locale and zone off core's existing request ALS; no new
store, because i18n and time already project those. The probe is "is reactivity
possible here", not "am I a server": a DOM with no runtime still throws, because
that is the theme-toggle-does-nothing bug.

UiProvider now refuses on the server rather than silently dropping its props —
it is the one thing an inert runtime cannot honour.

render + cli — hydrate was a promise with no referent
------------------------------------------------------
IslandDirective, emitIslandAttributes, hydrateRuntime, RouteEntry.islands and
routeJsBytes all shipped, and NOTHING ever constructed or populated any of them.
render-static.ts:55 even carried a fix: telling authors to "move the
request-dependent part into an island" — naming a mechanism the framework could
not express.

island({ src, props }) is a factory over the route's existing `hydrate`; the
route says WHEN, the island says WHICH module. defineRoute gains no key, because
a second way to say "this route hydrates" is what axiom 1 forbids.

`src` is a string, not an import. There is no edge from the page to the island
for a bundler or the surface-boundary walk to follow, so a static page's graph
cannot grow the island's dependencies — structural, not policed. Props are gated:
declared, JSON-only, 4kb; <Modal {...post} /> fails and NAMES email and
passwordHash, every column the spread would have shipped.

Wired end to end, both paths from one table — x dev and serve.ts, deliberately,
because a seam that works in dev and not in the image is the same failure one
release later. Proof from the emitted artifact: one data-x-entry, the static page
next door emits no <script> at all and reports jsBytes 0.

And a live budget bug in each layer: routeJsBytes filtered by entry.islands,
which nothing populated, and measureDocumentJs weighed <script src> tags while an
island is reached by import() — so a page was charged for the hydration runtime
and never for the code it boots. Both now charge the chunk, and an oversized
island fails naming the island.

admin — adminRoutes() was dead on arrival
------------------------------------------
adminRouteConfig emitted defineRoute({ render: 'spa' }) with no policy, which
render's own assertModeShape refuses — so every call threw X_ROUTE_MODE_INVALID.
Published, advertised in README.md:61, no test file, no consumer anywhere. That
is why it went unnoticed.

pages: now registers a custom screen, and the guard cannot be omitted, by four
independent locks: refused at declaration when permissions is empty; the frame's
admin:read composed in front of the declared one; adminRouteConfig writes the
defineRoute call so the author never does; and the router is handed a wrapped
component, with AdminPageProps.ctx required so the raw one cannot even be called.
Nav is closed too — an unlinkable page was visible to everyone.

The escape hatch is the main event, not a corner case: of treasury's 70
ActiveAdmin files, 28 reach for Arbre or register_page and hold 55% of the LOC,
and 20 of 70 are bespoke ops screens rather than model CRUD.

Named the strength that was undocumented: there is no Arbre analogue and there
will not be one. Every renderer is ordinary TSX importing @ultimat3/ui, the
generated pieces are individually exported so a table can be lifted out of its
page — which ActiveAdmin cannot do — and an admin route is an ordinary route.

realtime — the local store was write-only
-------------------------------------------
Two live queries overlapping on one row held two copies of it, which the thesis
table has called a bug the framework should make unrepresentable since before it
shipped. Fixed by lifting the identity map out of the tier-3 local store so both
tiers share one, keyed (entity, id) — posts/7 and users/7 are two rows, and a
slug primary key makes that collision plausible rather than theoretical.

The larger bug the test exposed: useLive never read the local store AT ALL.
store.apply() wrote MemoryLocalStore and nothing anywhere read it, so a mutator's
optimistic local(tx, input) twin was invisible in every live query until the
server round-tripped a patch.

Membership and identity are separate — Ember's own split — because sharing one
Map<table, Map<id, Row>> means rolling back an optimistic insert deletes a row
the server had since sent to another window. A write merges columns rather than
replacing the row, since two queries may project different columns and a narrower
snapshot must not blank what a wider one renders.

SnapshotFrame carries `entity`, and PROTOCOL_VERSION is deliberately NOT bumped:
the field is additive and readable both directions, so bumping would refuse every
in-flight client on a rolling deploy in exchange for nothing. The package rule now
says the version guards incompatibility, not novelty.

Also
----
Two framework i18n keys were structurally unreachable: `ui.error` and `ui.theme`
are leaves under branches (`ui.error.code`, `ui.theme.light`), and a catalog is
authored nested where a name is a leaf or a branch, never both — so ThemeToggle's
aria-label rendered ⟦ui.theme⟧. Renamed to ui.error.title and ui.theme.label, and
the whole ui.* namespace now ships in en.json; it was absent entirely.

x g island and x g admin:page, both in FIXTURE_GENERATORS so the scaffold gate
compiles them. cmd-generate.ts had reached exactly 500 lines — passing with zero
headroom — and is split.

New codes (5): X_ADMIN_PAGE_UNGUARDED, X_ADMIN_PAGE_PATH_INVALID,
X_ISLAND_INVALID, X_ISLAND_PROPS_INVALID, X_ISLAND_NOT_HYDRATED. The CLI borrows
X_ISLAND_INVALID rather than twinning it.

Gate: bun run verify 14/17, 3 skipped. Reference-app gate: every pin holds.
328 error codes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3fb3ea2a-ad2e-4414-9767-8e0e848fa2ac

📥 Commits

Reviewing files that changed from the base of the PR and between d4d946b and 94d65f2.

📒 Files selected for processing (86)
  • docs/idea/00-thesis.md
  • framework.manifest.json
  • packages/admin/CLAUDE.md
  • packages/admin/README.md
  • packages/admin/src/admin.ts
  • packages/admin/src/errors.ts
  • packages/admin/src/index.ts
  • packages/admin/src/nav.ts
  • packages/admin/src/page-guard.tsx
  • packages/admin/src/pages.test.ts
  • packages/admin/src/pages.ts
  • packages/admin/src/routes.ts
  • packages/cli/CLAUDE.md
  • packages/cli/README.md
  • packages/cli/src/app-load.ts
  • packages/cli/src/budgets.ts
  • packages/cli/src/cmd-dev.ts
  • packages/cli/src/cmd-generate.ts
  • packages/cli/src/dev-render.ts
  • packages/cli/src/error-codes.ts
  • packages/cli/src/errors.ts
  • packages/cli/src/generate-kinds.ts
  • packages/cli/src/island-bundle.test.ts
  • packages/cli/src/island-bundle.ts
  • packages/cli/src/island-routes.test.ts
  • packages/cli/src/island-routes.ts
  • packages/cli/src/mcp-errors.ts
  • packages/cli/src/prerender.test.ts
  • packages/cli/src/prerender.ts
  • packages/cli/src/scaffold-fixture.ts
  • packages/cli/src/serve.ts
  • packages/cli/src/templates/admin-page.ts
  • packages/cli/src/templates/index.ts
  • packages/cli/src/templates/island.test.ts
  • packages/cli/src/templates/island.ts
  • packages/i18n/src/catalogs/en.json
  • packages/i18n/src/framework.ts
  • packages/realtime/CLAUDE.md
  • packages/realtime/README.md
  • packages/realtime/src/apply-patches.test.ts
  • packages/realtime/src/apply-patches.ts
  • packages/realtime/src/client-frames.ts
  • packages/realtime/src/client.ts
  • packages/realtime/src/hooks-fixture.ts
  • packages/realtime/src/hooks-identity.test.ts
  • packages/realtime/src/hooks.test.ts
  • packages/realtime/src/identity-map.test.ts
  • packages/realtime/src/identity-map.ts
  • packages/realtime/src/index.ts
  • packages/realtime/src/live-definition.test.ts
  • packages/realtime/src/live-definition.ts
  • packages/realtime/src/live-query.ts
  • packages/realtime/src/live-rows.test.ts
  • packages/realtime/src/live-rows.ts
  • packages/realtime/src/local-store.test.ts
  • packages/realtime/src/local-store.ts
  • packages/realtime/src/sync-protocol.test.ts
  • packages/realtime/src/sync-protocol.ts
  • packages/render/CLAUDE.md
  • packages/render/README.md
  • packages/render/src/errors.ts
  • packages/render/src/hydrate.ts
  • packages/render/src/index.ts
  • packages/render/src/island-collector.ts
  • packages/render/src/island-props.ts
  • packages/render/src/island.test.ts
  • packages/render/src/island.ts
  • packages/render/src/islands.ts
  • packages/render/src/render-html.ts
  • packages/render/src/type-pins.ts
  • packages/ui/CLAUDE.md
  • packages/ui/README.md
  • packages/ui/src/errors.ts
  • packages/ui/src/i18n-keys.ts
  • packages/ui/src/index.ts
  • packages/ui/src/theme/context.test.ts
  • packages/ui/src/theme/context.ts
  • packages/ui/src/theme/inert-render.test.ts
  • packages/ui/src/theme/inert-runtime.test.ts
  • packages/ui/src/theme/inert-runtime.ts
  • packages/ui/src/theme/provider.tsx
  • packages/ui/src/theme/solid-adapter.test.ts
  • packages/ui/src/theme/solid-adapter.ts
  • wiki/CLI-Reference.md
  • wiki/Error-Codes.md
  • wiki/Realtime.md

Comment @coderabbitai help to get the list of available commands.

@sebyx07
sebyx07 merged commit 14eb84b into main Aug 15, 2026
5 checks passed
@sebyx07
sebyx07 deleted the feat/ui-runtime-entity-components branch August 15, 2026 16:13
sebyx07 added a commit that referenced this pull request Aug 15, 2026
…sland is one line (#92)

* feat(harness): .claude ships with x new, x docs answers offline, an island is one line

Four slices. Two of them deleted a design I had specced, because checking beat
assuming again.

.claude/ ships with x new — 9 files, 18.9kb
--------------------------------------------
All five audited repos built one independently: 24,249 lines of agent-facing
markdown, written five times. x new shipped none, so a scaffolded app inherited
nothing.

/feature is 5,001 bytes against this repo's 18,727 — the hive coordination, the
PR splitting and the npm release are framework-monorepo concerns, not an app's.
Subagents are scoped by BOUNDARY, never by role, and the boundary is not "one per
app directory" as the audit assumed: resourceFiles puts the whole vertical slice
in one apps/web/app/<feature>/, so that cut would hand one agent everything. The
real lines are the app's own import direction — data -> server -> web — plus
`shape`, read-only, which decides whether to build at all before there is a
boundary to hold.

No new-model/new-route/new-service commands: every one is `x g <kind>` already,
and a slash command wrapping a shipped command is a second path that drifts. A
test asserts none exists.

No size budget, no X_CLAUDE_BUDGET_* code, nothing gated. A ceiling on an app's
own markdown is the framework policing the user's docs, and how big your .claude/
is, is your convention. Nothing reaches outside the project directory either — a
test asserts every path starts with .claude/ and holds no `..` or `~`.

The scoped-typecheck hook I had specced twice does NOT exist and never will:
cmd-verify.ts:1-4 says narrowing the gate "would make 'green' mean whatever the
caller chose". So the one hook is biome on the edited file, with the reason
written down. Every `x …` a template names is asserted to exist, planned commands
excluded — a planned command is not a fix.

x docs — and the payload I specced was wrong
---------------------------------------------
I asked for a generated docs.json per package. Verifying the premise inverted the
conclusion: Bun runs TypeScript directly, so the published artifact IS the source
and every doc is already inside the installed tarball. A docs.json would be a
second copy of bytes the install already has, and the second copy is the one that
drifts.

So `x docs "<question>"` reads the installed source at query time. 66ms scan +
16ms search over 906 entries across 29 packages; 0.69s end to end against `x
errors list`'s 2.2s, because it reads files instead of importing 27 packages.

The doc unit was measured, not assumed. JSDoc above a public export covers 42.3%
— job(), the flagship, has none, so ranking on JSDoc would have missed it. File
header comments, which the conventions already mandate, cover 99.8%. That is the
index.

Two bugs its own tests caught: the tokenizer lowercased before splitting
camelCase, so nextRetry never split — the one case it existed for; and a
one-token-of-five match was returned in the same shape as a real answer. An agent
cannot see that difference, and a confident irrelevant answer is worse than none
because it stops the search. An entry now has to cover half the question.

CLAUDE.md is added to all 29 files arrays: +333kb, +5.8%. It was required to
exist by workspace-checks.ts and thrown away at publish.

islands and admin pages, proven in the apps
--------------------------------------------
PR #91 shipped both and admitted neither was exercised by real app code.

examples/dummy's /pricing now carries a Talk to sales island. Measured: /pricing
1894 bytes (875-byte chunk + 1019-byte interaction runtime), / next door still 0.
Everything on screen is server-rendered inside the wrapper — a real <form
method="post"> — so the enquiry sends with scripting off; only three post-click
strings cross as props.

The demo's admin ops page moved to pages:, deleting a hand-written defineRoute, a
hand-written policy line, a hand-written permission branch and a raw <a href>.
That anchor was the one sidebar link no permission filtered: it rendered for
anyone who could open the dashboard, pointing at a page they would be refused.

an island is now the whole declaration
---------------------------------------
island() could not be used in JSX at all — TS2786. solid's JSX.Element is a type
ALIAS and therefore unaugmentable, and the framework's own island tests all call
h(Modal, …), never JSX, which is why it was never exercised. IslandNode now
extends Array<never>: ArrayElement is the union's only object-shaped member, so
it satisfies the configured JSX.Element structurally without render importing
solid-js. render-html's unwrap tests isIslandNode BEFORE Array.isArray, or the
generic branch renders '' and drops the island silently.

And the ceremony is down to one line. A route carrying an island derives
hydrate: 'interaction' and its budget from the surface baseline (site 4kb, app
18kb) — the two facts the framework can work out are no longer two lines to
forget. Explicit always wins. Per-island strategy was rejected: RouteDescriptor
.hydrate is one field read by sw.js, the web manifest and x routes, and two
islands with different timings would leave it with no true answer.

props stays explicit. It is the only thing between <Modal {...post} /> and a
passwordHash in the client bundle, and no default recovers that.

RouteEntry.islands was `input.islands ?? []` and nothing has ever passed islands
— so routeJsBytes' "what registration declared" half has read [] on every route
in the framework's history.

x g admin:page gains --at; it wrote to a hardcoded directory.

Debt named, not hidden
-----------------------
- cmd-generate.ts writes x.manifest.json after ANY generator run, creating one in
  an app that never had it, and prints a line report.written does not count.
- A named import from @ultimat3/action pulls 36.1kb minified through the barrel
  into core; naming.ts's "pure string math without importing a byte of server
  code" is true of the function and false of the import. 40x the island.
- SURFACE_SPECS.site.mayImportTypes is ['shared'] but checkSurfaceBoundary only
  classifies value edges, so a site/ page type-importing from api/ passes.

Gate: bun run verify 14/17, 3 skipped. Reference-app gate: every pin holds; the
typecheck pin drops 138 -> 137 because the TS2786 class is fixed. 328 codes, no
new ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review — a decorative rate limit, a lost redirect, an ambient date

Nineteen findings. Two premises were wrong and the agents said so; three fixes
uncovered something bigger than the finding.

the rate limit was not what the review said, and worse than it looks
--------------------------------------------------------------------
The review called the demo's public contactSales an unthrottled open relay. It
is not: pipeline.ts:235 runs rate-limit on every route by default, keyed
contactSales|ip:<addr>, so it sat on the default bucket at 120 burst / 2 per
second per IP. A page's read allowance on a mail endpoint is the wrong shape, but
it is not a relay.

Declaring rateLimit: { limit: 5, windowMs: 600_000 } fixed the published
contract — openapi.json stops advertising "unlimited" on a public mail endpoint.

But proving that surfaced a framework gap: an action's rateLimit is DECORATIVE.
toRoute (packages/action/src/http.ts:85) sets meta.rateLimit = <actionName>, so
the limiter looks up a bucket literally named contactSales; defineConfig has no
http block, dev-roles.ts and serve.ts pass no rateLimit to defineHttpConfig, and
nothing derives a bucket from the action's declared numbers. They reach the
OpenAPI spec and stop. An author who writes limit: 5 gets 120. Named at the
declaration and in the PR body rather than papered over; the fix is cross-package
and belongs in its own slice.

x docs lost the redirect on the one query most likely to be a typo
-------------------------------------------------------------------
`x docs "X_DB_DRIFT"` ranked FIVE prose files above the redirect, on the words
"db" and "drift" — contradicting the contract in the command's own file header.
And a mistyped code got no redirect at all, so the query most likely to be wrong
had no path to the command that would have suggested the right one. The code
query now resolves before any scan, which also skips 81ms of work for a question
that was never about documentation.

The duplicate-heading finding was accepted on a different ground than the one
cited: all 58 shipped READMEs have zero slug collisions today, but DocEntry.topic's
own JSDoc promises ids are unique within a package and the code did not hold it.
Code contradicting its own documented invariant is worth four lines.

an ambient date in the scaffolded /planx
-----------------------------------------
The template told the agent to run `date +%F` — the host shell's ambient zone, so
two machines produce two plan dates for one instant. It is also the one rule this
repo enforces hardest: no date formatted without an explicit IANA timeZone,
anywhere. Replaced with a named-zone Bun one-liner, deliberately NOT added to the
permission allowlist, because `bun -e` is arbitrary code execution and one prompt
per plan is the right price.

The scaffolded README claimed "nothing here reaches outside this directory" while
the PostToolUse hook runs biome --write over any edited file. Both halves were
wrong. The containment claim is load-bearing and stayed, corrected to
"repository"; the hook is now disclosed in three places as the bundle's one
component that WRITES, with a test that fails if the disclosure disappears.

the rest
--------
- The island test template put its header comment below the imports, so every
  scaffolded island test shipped in violation of the header rule.
- X_ISLAND_NOT_HYDRATED has a THIRD cause the wiki did not name —
  islandWithoutCollector, which is the host's wiring rather than the author's page.
- A receipt's idempotency key held only email + message, while the template reads
  plan, currency and locale — so the same question about team/USD and business/EUR
  deduped and the second visitor silently got nothing.
- A test dereferenced JSON.parse output through `as`, so a shape change threw a
  TypeError instead of failing by name; now unknown + a schema parse, with a test
  proving the guard is not decoration.
- node: imports carry their why-comments; measurements carry their date and their
  denominators.

Gate: bun run verify 14/17, 3 skipped. Reference-app gate: every pin holds.
328 error codes, none new.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

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.

1 participant