Skip to content

feat(queen): one spec corpus for every tab of /game - #1206

Merged
gHashTag merged 2 commits into
mainfrom
feat/queen-spec-sync
Oct 1, 2026
Merged

gHashTag merged 2 commits into
mainfrom
feat/queen-spec-sync

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

The owner's report: the specs were not in sync across the tabs of https://app.t27.ai/game. This makes every Queen tab read one spec corpus from one store. A contract now holds them equal on every tab of the built page.

Measured on t27.ai first.

  • Every tab happened to print 1577, because one scan wrote every file.
  • The shell and the Spec Explorer frame each fetched the 1.8 MB manifest.
  • The comb and the hero block each fetched the universe atlas.
  • The SPECS rung read a sixth file, ladder.specs.
  • A tab switch dropped spec=, the comb's spec stayed local, and the Explorer ignored the world chosen in the shell.

Nothing stated that two tabs were showing one corpus.

Before → after, on the built page (check:queen-spec-sync --browser):

before after
tabs reporting a corpus version 0 14 of 14: gHashTag/t27@2e4093d33/1577 (shell root, 6 SPECS rungs, the Explorer frame and its list)
manifest fetches, shell + Explorer frame 2 1
atlas holders inside the Queen 2 (comb, hero) 1 store
world= in the shell → Explorer ignored narrowed to the comb's count (tri-net: 113)
spec= across a tab switch dropped kept
{
  "version": 1,
  "head_sha": "9af298948b7121e5f48a21d62e67586a62bf4123",
  "summary": "Every Queen tab now reads one spec corpus from one store, src/lib/queenCorpus.ts. It is fetched once for the shell and its Explorer frame, and each tab says which corpus it shows. A new contract checks the files, the source, the store, the address and all 14 tabs of the built page. Each of those checks is also fed a broken fixture that must fail.",
  "changes": [
    "Added src/lib/queenCorpus.ts, one store for the manifest, atlas, modules and foundation. Each part is fetched once per window tree, because the Explorer frame adopts the shell's registry. The wire is tried first and the vendored file is the fallback. Each part reports its source and generatedAt, and the manifest's identity is its commit plus the SHA-256 of its bytes.",
    "Added src/lib/queenCorpusCheck.ts, a pure definition of one corpus. The manifest, the universe atlas, the shared core and the five spec-* ladders must agree on the count, on the manifest bytes they were built from, and world by world.",
    "Rewired the shell, the Specs directive, the hero block, the comb, the universe view, the compiler driver and the Spec Explorer onto the store. The SPECS rung now prints the store's count.",
    "The address now carries the selection: a tab switch keeps spec= and world=, and the comb writes the spec it opens. world= in the shell narrows the Explorer frame, which shows a world chip.",
    "The shell root and the Explorer root carry data-spec-count, data-corpus-version and data-corpus-source.",
    "Added qa/queen-spec-sync-contract.mjs as check:queen-spec-sync, with negative fixtures, and wired both its pure and --browser modes into Website checks.",
    "t27-world-scan.yml now dispatches pr-blog-report.yml for the refresh PR it opens, because a GITHUB_TOKEN event starts no workflow and #1176 sat BLOCKED. The discovery audit allows that one dispatch and nothing else."
  ],
  "tests": [
    {
      "command": "npm run check:queen-spec-sync -- --browser --no-build",
      "status": "passed",
      "result": "27 checks pass. All 14 tabs report gHashTag/t27@2e4093d33/1577 across 22 readings, the manifest is read once between the shell and the frame, and world=ghashtag/tri-net lists 113. The negative fixtures (stale ladder, foreign atlas, comb world mismatch, rogue fetch, a tab reading 1576, a whole run on a stale public/ that exits 1) are all reported.",
      "evidence": "apps/website/qa/queen-spec-sync-contract.mjs; local BrowserOS headless run"
    },
    {
      "command": "node qa/queen-embed-address-contract.mjs --no-build",
      "status": "passed",
      "result": "25 checks pass: deep links, picks, reload, Back, language and cross-Explorer links still keep the address and the frame on one card.",
      "evidence": "apps/website/qa/queen-embed-address-contract.mjs"
    },
    {
      "command": "every pure npm run step of .github/workflows/website-checks.yml (34 steps)",
      "status": "passed",
      "result": "All exit 0, including typecheck:ratchet (no file worsened), check:discovery, check:spec-catalog, check:queen-atlas, check:shared-core, check:queen-spec-mirrors, check:queen-catalog and check:subpath-urls.",
      "evidence": "local run, each exit code read directly rather than through a pipe"
    },
    {
      "command": "npx vite build",
      "status": "passed",
      "result": "Production build completed with the existing large-chunk warning.",
      "evidence": "local npx vite build in the task worktree, exit code read directly; dist/ served to the browser contracts above"
    }
  ],
  "limitations": [
    "The vendored corpus is still the 1577-spec snapshot at t27 2e4093d33. The 1737-spec refresh is bot PR #1176 and lands separately once its work report is dispatched.",
    "The comb's spec selection flows one way, from the comb to the address to the Explorer. The comb does not open a spec from the address on arrival, so the default spec= of the Specs tab does not pop a card open.",
    "QUEEN_API has no public-manifest or public-atlas route, so those two parts come from the vendored file, and modules and foundation fall back to it while the wire returns 404.",
    "The outer /game shell is another repository and iframes this Queen, so the store spans the Queen and its Explorer frame, not the outer shell."
  ],
  "tags": [
    "Engineering",
    "Verification",
    "Queen"
  ],
  "blog": {
    "title": "Fourteen tabs, one corpus",
    "summary": "The Queen's tabs printed the same spec count only because one scan wrote every file. They now read one store, say which corpus they show, and a contract proves it on every tab.",
    "outline": [
      "What the owner saw: tabs that could disagree. What was measured: five holders of the corpus, two copies of the manifest, and a selection lost on every tab switch.",
      "One store per window tree: the Explorer frame adopts the shell's registry, and every part carries its source, time and manifest hash.",
      "A contract that has been seen to fail: stale ladders, foreign atlases, rogue fetches and a whole stale public/ tree must each be reported, before 14 real tabs are read in Chrome."
    ]
  }
}

🤖 Generated with Claude Code

The owner's report: the specs were not in sync across the tabs of /game.
Measured on t27.ai first: every tab happened to print 1577, because one
scan wrote every file -- but the shell and the Spec Explorer frame each
fetched the 1.8 MB manifest, the comb and the hero block each fetched the
atlas, the SPECS rung read a sixth file, a tab switch dropped spec=, the
comb's spec stayed local, and the Explorer ignored the world chosen in the
shell. Nothing said two tabs were showing one corpus.

- src/lib/queenCorpus.ts: one store for manifest, atlas, modules and
  foundation. Fetched once per window tree (the Explorer frame adopts the
  shell's registry), the wire first and the vendored file as fallback, each
  part saying its source and when it was generated; the manifest's identity
  is its commit and the SHA-256 of its bytes. Every tab reads it.
- src/lib/queenCorpusCheck.ts: what "one corpus" means, as a pure function:
  manifest, atlas, shared core and the five spec-* ladders agree on count,
  on the manifest bytes they were built from, and world by world.
- The address: a tab switch keeps spec= (and world=), the comb writes the
  spec it opens, and world= in the shell narrows the Explorer frame.
- Shell root and Explorer root stamp data-spec-count / data-corpus-version.
- qa/queen-spec-sync-contract.mjs (check:queen-spec-sync): files, source,
  store and address, each fed a broken fixture that must fail; --browser
  reads all 14 tabs of the built page. Wired into Website checks.
- t27-world-scan.yml: the refresh PR it opens never got its required
  "T27 work report" (a GITHUB_TOKEN event starts no workflow), so #1176
  (1737 specs) sat BLOCKED. It now dispatches pr-blog-report.yml for it;
  the discovery audit allows that dispatch and nothing else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the status:in-progress 🔵 Agent working label Oct 1, 2026
The CI runner's Chrome cannot start its sandbox; the other Queen browser
contracts pass --no-sandbox --disable-dev-shm-usage on linux, and this one
now does too (it exited 2, 'Chrome never announced a debugging port').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag merged commit ce91da6 into main Oct 1, 2026
28 of 32 checks passed
@github-actions github-actions Bot added status:completed Done and removed status:in-progress 🔵 Agent working labels Oct 1, 2026
github-actions Bot added a commit that referenced this pull request Oct 1, 2026
feat(queen): one spec corpus for every tab of /game (#1206)

* feat(queen): one spec corpus for every tab of /game

The owner's report: the specs were not in sync across the tabs of /game.
Measured on t27.ai first: every tab happened to print 1577, because one
scan wrote every file -- but the shell and the Spec Explorer frame each
fetched the 1.8 MB manifest, the comb and the hero block each fetched the
atlas, the SPECS rung read a sixth file, a tab switch dropped spec=, the
comb's spec stayed local, and the Explorer ignored the world chosen in the
shell. Nothing said two tabs were showing one corpus.

- src/lib/queenCorpus.ts: one store for manifest, atlas, modules and
  foundation. Fetched once per window tree (the Explorer frame adopts the
  shell's registry), the wire first and the vendored file as fallback, each
  part saying its source and when it was generated; the manifest's identity
  is its commit and the SHA-256 of its bytes. Every tab reads it.
- src/lib/queenCorpusCheck.ts: what "one corpus" means, as a pure function:
  manifest, atlas, shared core and the five spec-* ladders agree on count,
  on the manifest bytes they were built from, and world by world.
- The address: a tab switch keeps spec= (and world=), the comb writes the
  spec it opens, and world= in the shell narrows the Explorer frame.
- Shell root and Explorer root stamp data-spec-count / data-corpus-version.
- qa/queen-spec-sync-contract.mjs (check:queen-spec-sync): files, source,
  store and address, each fed a broken fixture that must fail; --browser
  reads all 14 tabs of the built page. Wired into Website checks.
- t27-world-scan.yml: the refresh PR it opens never got its required
  "T27 work report" (a GITHUB_TOKEN event starts no workflow), so #1176
  (1737 specs) sat BLOCKED. It now dispatches pr-blog-report.yml for it;
  the discovery audit allows that dispatch and nothing else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(qa): spec-sync browser mode starts Chrome on a Linux runner

The CI runner's Chrome cannot start its sandbox; the other Queen browser
contracts pass --no-sandbox --disable-dev-shm-usage on linux, and this one
now does too (it exited 2, 'Chrome never announced a debugging port').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag added a commit that referenced this pull request Oct 3, 2026
…#1206

On the runner, with Chrome finally launching, the contract failed honestly:
"page never became ready - selected unit NO". Since #1206 the comb on
#/queen is the shared catalog (QueenCatalogHive), and the old CONTEXT panel
with .queen27-context-unit-text is not mounted there at all. The contract
waited for an element of the previous design; nobody saw, because nothing
ran it.

- Ready means the catalog layer ([data-catalog-map]) or, for an engine
  without the catalog, the legacy panel.
- A pick is the text of .queen-catalog-detail. The catalog flies the camera
  to what was tapped, so between taps the contract closes the detail, as a
  person would.
- No Chrome is NOT MEASURED (rc 2), not a silent exit 0.
- A failure names what the page showed (width, media query, hash) and which
  cells were picked.

Local run (chrome-headless-shell 1208): PASS, 13 distinct cells, a drag
picked nothing. queen-dead-api: PASS, 8 sizes x 2 views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag added a commit that referenced this pull request Oct 3, 2026
* fix(queen): two red contracts on main -- an honest stat, a dash too tall, a starved page

- viewport --dead-api: #stat-research counts the .t27 corpus index, which ships
  with the page (#1058), so 52% with the API refused is true; drop it from the
  bare-zero probe.
- the sectors strip's placeholder dash kept the panel's padding: 35px in a
  29px strip, an undeclared scroller at 1440x900. It takes the rows' metrics.
- touch: a probe that gets no answer in 20 s is NOT MEASURED (rc 2, with the
  load average), and not-ready names the missing part.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(website): run the Queen touch and dead-API contracts on every site PR

Both were only ever run by hand, so both went red on main unseen. The dead-API
step goes last because it rebuilds dist/ against a refused address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(qa): launch the touch contract's Chrome with the Linux flags every other contract uses

On the ubuntu runner Chrome never announced a debugging port without
--no-sandbox and --disable-dev-shm-usage, and the contract threw away its
stderr, so the log said only 'no port'. The error now carries Chrome's tail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(qa): the touch contract taps the shared catalog the comb became in #1206

On the runner, with Chrome finally launching, the contract failed honestly:
"page never became ready - selected unit NO". Since #1206 the comb on
#/queen is the shared catalog (QueenCatalogHive), and the old CONTEXT panel
with .queen27-context-unit-text is not mounted there at all. The contract
waited for an element of the previous design; nobody saw, because nothing
ran it.

- Ready means the catalog layer ([data-catalog-map]) or, for an engine
  without the catalog, the legacy panel.
- A pick is the text of .queen-catalog-detail. The catalog flies the camera
  to what was tapped, so between taps the contract closes the detail, as a
  person would.
- No Chrome is NOT MEASURED (rc 2), not a silent exit 0.
- A failure names what the page showed (width, media query, hash) and which
  cells were picked.

Local run (chrome-headless-shell 1208): PASS, 13 distinct cells, a drag
picked nothing. queen-dead-api: PASS, 8 sizes x 2 views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Oct 3, 2026
fix(queen): two red contracts on main, and CI that runs them (#1247)

* fix(queen): two red contracts on main -- an honest stat, a dash too tall, a starved page

- viewport --dead-api: #stat-research counts the .t27 corpus index, which ships
  with the page (#1058), so 52% with the API refused is true; drop it from the
  bare-zero probe.
- the sectors strip's placeholder dash kept the panel's padding: 35px in a
  29px strip, an undeclared scroller at 1440x900. It takes the rows' metrics.
- touch: a probe that gets no answer in 20 s is NOT MEASURED (rc 2, with the
  load average), and not-ready names the missing part.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(website): run the Queen touch and dead-API contracts on every site PR

Both were only ever run by hand, so both went red on main unseen. The dead-API
step goes last because it rebuilds dist/ against a refused address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(qa): launch the touch contract's Chrome with the Linux flags every other contract uses

On the ubuntu runner Chrome never announced a debugging port without
--no-sandbox and --disable-dev-shm-usage, and the contract threw away its
stderr, so the log said only 'no port'. The error now carries Chrome's tail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(qa): the touch contract taps the shared catalog the comb became in #1206

On the runner, with Chrome finally launching, the contract failed honestly:
"page never became ready - selected unit NO". Since #1206 the comb on
#/queen is the shared catalog (QueenCatalogHive), and the old CONTEXT panel
with .queen27-context-unit-text is not mounted there at all. The contract
waited for an element of the previous design; nobody saw, because nothing
ran it.

- Ready means the catalog layer ([data-catalog-map]) or, for an engine
  without the catalog, the legacy panel.
- A pick is the text of .queen-catalog-detail. The catalog flies the camera
  to what was tapped, so between taps the contract closes the detail, as a
  person would.
- No Chrome is NOT MEASURED (rc 2), not a silent exit 0.
- A failure names what the page showed (width, media query, hash) and which
  cells were picked.

Local run (chrome-headless-shell 1208): PASS, 13 distinct cells, a drag
picked nothing. queen-dead-api: PASS, 8 sizes x 2 views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag added a commit that referenced this pull request Oct 4, 2026
… in CI (#1352)

check:queen-honesty was FAIL (3) on main because its pins pointed at code
that has since moved:

- the round decision line (`decisionLine`) went with the command rail's
  second round button in 9316e9e. The pin now holds the popover that
  survived: the verb on its own line, then {decisionInfo} first and the
  skip count after;
- H-C1 required Queen.tsx to name queen/foundation.json, but #1206 moved
  every corpus read into lib/queenCorpus.ts, and spec-sync rule B refuses
  that name anywhere else. The pin now holds what Queen.tsx still decides:
  - the foundation comes from the store, with the server's route as the
    wire;
  - only the board's own repository is kept;
  - the viewport shows count@date:source.
  The store's order is pointed to (spec-sync rule C), not restated;
- yellow coverage now reads useCorpus("manifest") rather than a fetch.

Negative controls: seven mutations of a mirrored Queen.tsx each fail with
exactly the intended pin, and the unmutated mirror passes.

website-checks.yml now runs the contract. No workflow had run it since
#897 (2026-09-04).

Closes #1351

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Oct 4, 2026
qa(queen): re-home the three stale honesty pins, and run the contract in CI (#1352)

check:queen-honesty was FAIL (3) on main because its pins pointed at code
that has since moved:

- the round decision line (`decisionLine`) went with the command rail's
  second round button in 9316e9e. The pin now holds the popover that
  survived: the verb on its own line, then {decisionInfo} first and the
  skip count after;
- H-C1 required Queen.tsx to name queen/foundation.json, but #1206 moved
  every corpus read into lib/queenCorpus.ts, and spec-sync rule B refuses
  that name anywhere else. The pin now holds what Queen.tsx still decides:
  - the foundation comes from the store, with the server's route as the
    wire;
  - only the board's own repository is kept;
  - the viewport shows count@date:source.
  The store's order is pointed to (spec-sync rule C), not restated;
- yellow coverage now reads useCorpus("manifest") rather than a fetch.

Negative controls: seven mutations of a mirrored Queen.tsx each fail with
exactly the intended pin, and the unmutated mirror passes.

website-checks.yml now runs the contract. No workflow had run it since
#897 (2026-09-04).

Closes #1351

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant