Skip to content

refactor(spec,skills): gen:react-blocks emits one artifact — the markdown rendering is the single AI-facing output - #15257

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14559-react-blocks-single-rendering
Sep 4, 2026
Merged

refactor(spec,skills): gen:react-blocks emits one artifact — the markdown rendering is the single AI-facing output#15257
os-zhuang merged 2 commits into
mainfrom
claude/issue-14559-react-blocks-single-rendering

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #14559

gen:react-blocks wrote the same table twice. It now writes it once: skills/objectstack-ui/references/react-blocks.md is the single AI-facing rendering, and the machine-readable JSON twin is deleted.

The ruling this executes

Maintainer ruling on #14296 item 3 = A (director relay 5507419465, 2026-09-02, 「其他同意」), carried by the seam card: the generator stops emitting skills/objectstack-ui/contracts/react-blocks.contract.json; the file is deleted; skills/objectstack-ui/references/react-blocks.md is the single AI-facing output. Not re-decided here. Option C of the same item (moving evals/ out of the published tree) is not this PR.

Premise, re-verified at the base (96b4af88)

Measured before the first edit, not assumed:

Claim Reading
One generator emits both check:react-blocks at base: react-blocks contract: 4 blocks → …contract.json + …react-blocks.md
Same four blocks, same prop counts JSON ObjectForm:34 ListView:20 ObjectChart:18 Block:1 · markdown table rows ObjectForm:34 ListView:20 ObjectChart:18 Block:1
Same note string the JSON note appears byte-identically in the markdown body (md.includes(json.note)true)
Same prop names per block every JSON prop name present in the matching markdown section → true
Zero in-repo consumers of the JSON git grep react-blocks.contract.json = 12 hits, all of them names: the generator, the register rows repaired below, one skill-body link, ADR-0082, and two history files (packages/spec/CHANGELOG.md, an existing changeset). No code reads the file.
Zero consumers in objectui at origin/main 24e027e9, git grep react-blocks.contract.json is empty; the only neighbour is prose in scripts/check-governed-queue-guard.mjs:106

The premise holds in full.

Reverse verification, in the card's order

Step Command Exit The gate's own line
1. base, two artifacts pnpm --filter @objectstack/spec check:react-blocks 0 ✅ 2 generated files in sync with packages/spec
2. JSON deleted, generator untouched same 1 + skills/objectstack-ui/contracts/react-blocks.contract.json (missing — spec adds it)
3. generator change landed same 0 ✅ 1 generated files in sync with packages/spec

Step 2 is the one that matters: the deletion is real, and the sync gate is what sees it. Write mode agrees — gen:react-blocks prints ✅ Generated 1 files and leaves the tree clean, so the markdown is byte-identical before and after (git status reports no change to it at any step).

The seven moving parts

  • 1. Generatorpackages/spec/scripts/build-react-blocks-contract.ts: OUT_JSON and its emit() are gone, so --check compares the markdown alone. version and source were the JSON envelope's own fields and went with it; the markdown states its provenance in the frontmatter description it emits. Script names unchanged (gen:react-blocks / check:react-blocks). The header records the retirement so nothing reinstates a second output by habit.
  • 2. Sync gatecheck:react-blocks verifies one artifact (reading 3 above). Nothing about the gate's wiring changed; it is the same --check on the same sink.
  • 3. .gitattributes — the contracts/react-blocks.contract.json merge=os-regen row is dropped, the references/react-blocks.md row kept, and the "both halves of the react-blocks contract" comment corrected to name one artifact and one row. pnpm check:merge-driver exit 0.
  • 4. AGENTS.mdno edit; reported rather than invented. The row reads | The react-blocks contract | check:react-blocks | gen:react-blocks |: three cells naming a surface, its gate and its generator, and no artifact path at all — there is no artifact list in it to narrow. The prose above it ("packages/spec has eight checked-in generated artifacts, each with its own CI gate") counts gates, one per table entry, and check:react-blocks is still exactly one of the eight. Every cell stays true, so an edit here could only add text to a governed file for no gain.
  • 5. Ratchet self-testscripts/check-skills-token-ratchet.mjs: the genContract boundary fixture now points at skills/objectstack-ui/references/react-blocks.md (still a real generator-owned path on this tree, still routing to register row spec-react-blocks), the pinned excluded set drops the JSON, and both prose comments are corrected. Self-test 64 cases pass; the gate itself is green with the generator-owned population at 10 files, down from 11.
  • 6. ADR-0082 — the sentence naming both renderings now names one, with a correction parenthetical in the form this ADR already uses for its other corrections. The chain diagram needed no change: it already reads spec zod schema ──gen──► react-blocks.md, one rendering, and always has.
  • 7. check:skill-refs / check:skill-docs / check:skill-identifier-liveness — verified, not assumed. Neither reference generator enumerates the JSON (check:skill-refs declares 9 outputs, all _index.md; check:skill-docs in sync). The liveness gate's Leg 1 population went 47 published files to 46, matching the one deletion exactly.

The four references the card omits — each answered

Reference Answer
scripts/regen-artifacts.mjs Repaired. The REGEN_ARTIFACTS entry for the JSON is dropped and the markdown entry kept, so regen-artifacts still knows this generator by one row. Its "both halves" comment is corrected in the same edit. check:merge-driver reconciles this table against .gitattributes, and both moved together — exit 0.
scripts/pm/check-governed-merges.mjs Repaired, in three places, not one. The spec-react-blocks candidate alternation loses the JSON branch. Two more sites named the path and would have gone stale silently: REGISTER_SAMPLES (the one real path per row, itself asserted to be matched by its row) and the self-test case that pinned both outputs. The pinning case now asserts the single output, and a new case asserts the retired path is no longer a register member — a candidate that still matched a deleted path would hand it a recompute nothing can satisfy. --self-test 246 assertions, exit 0; --test on this PR's eight paths returns exit 3 (GOVERNED, see below).
skills/objectstack-ui/rules/pages.md Repaired, one line. The blockquote's dead link to the JSON becomes "the block→schema index in @objectstack/spec" — which is also what the generator actually reads, where the old line implied the markdown was generated from the JSON. Net 0 lines (448 to 448) and −9 tokens (5,501 to 5,492 against a 5,501 ceiling). No other body change.
objectui scripts/check-governed-queue-guard.mjs:106 Read; no edit needed, and none made. At origin/main 24e027e9 the line is prose inside a comment explaining why the register half of the upstream mechanism was not ported: "skills/ carries no generator output (no references/_index.md, no react-blocks contract)". It is a statement about objectui's own tree, it does not name the JSON path, and it stays true after this change — the react-blocks contract still exists upstream, as one artifact. Nothing in objectui reads the deleted file (git grep react-blocks.contract.json there is empty).

Measurements

base 96b4af88 head d76ab048 delta
Published skill bundle, total tokens 156,787 151,426 −5,361 (−3.4%)
— the deleted JSON 5,352 tokens / 559 lines −5,352
rules/pages.md 5,501 tokens / 448 lines 5,492 / 448 −9 / ±0
Generator-owned files in the bundle 11 10 −1
Published files (liveness Leg 1 population) 47 46 −1
Artifacts check:react-blocks verifies 2 1 −1
Ratcheted (authored) subtotal unchanged path set 139,948 / 157,650 untouched

Token counts are the ratchet's own countTokens, applied to the base blobs and the head files, so the two columns are the same instrument.

Gates

Derived after the last commit from the real change set — node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no path arguments, at d76ab048: 64 commands, change set exactly the eight paths below. All 64 run, 63 exit 0.

The one that did not is pnpm check:dual-build-cjs-loads, which exited 3 — its own PREREQUISITE-NOT-MET code, printing "this gate reads built output, and some package has no dist/ … ⛔ This is NOT a pass: nothing was measured." Its self-test passed (93 cases) on this tree; only its corpus half is unmeasured, and satisfying it needs a full 102-package build, which is the repo-wide run CI owns. It cannot be moved by this diff: zero of the eight changed paths lie under any package's src/ (git diff --name-only merge-base HEAD -- 'packages/*/src/**' 'packages/*/*/src/**' is empty), and packages/spec/scripts/** is not published or compiled — npm pack --dry-run on packages/spec lists 2,086 files, 0 of them under scripts/. Recorded as NOT MEASURED, never as green.

pnpm lint (repo-wide eslint . --no-inline-config, no narrowing) exit 0. node scripts/pm/check-governed-merges.mjs --test on these paths: exit 3, ⛔ GOVERNEDdocs/adr/** ×1 and skills/** ×2.

Landing

This PR stays DRAFT for a human merge. AGENTS.md turned out not to need an edit, so the governed surfaces here are docs/adr/** and skills/** — two of three, which changes nothing about the route. No seat flips it ready, enqueues it, or arms auto-merge. Review requested from os-zhuang and hotlong; a human merge is the review record.

skip-changeset, and the reason is measured. Nothing this PR touches is published by any package. packages/spec's files whitelist is dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json — no scripts/, confirmed against the real tarball (0 of 2,086 entries under scripts/), and check:published-files states the whitelist "admits no test, test-harness config or build script". skills/ sits in no workspace package and appears in no package's files. So this PR releases nothing and the label is the honest declaration; an empty changeset would be a real input to changesets/action and buys nothing the label does not. The existing .changeset/skill-catalog-projected-issue-ids.md mentions the JSON in prose — that is history and is deliberately untouched.

Files

packages/spec/scripts/build-react-blocks-contract.ts · skills/objectstack-ui/contracts/react-blocks.contract.json (deleted) · .gitattributes · scripts/regen-artifacts.mjs · scripts/pm/check-governed-merges.mjs · scripts/check-skills-token-ratchet.mjs · docs/adr/0082-react-component-contract-governance.md · skills/objectstack-ui/rules/pages.md


Generated by Claude Code

os-justin and others added 2 commits September 4, 2026 06:56
…down is the single AI-facing rendering

The generator wrote the same table twice: a machine-readable JSON rendering
(5,352 tokens) and a markdown one (3,153 tokens) — same four blocks, same prop
counts, byte-identical `note`. The JSON had zero consumers in this repo beyond
the register rows that named it, and zero in objectui. It is retired: the
writer is dropped, the file is deleted, `--check` verifies one artifact, and
every reference that named the path moves with it — the merge-driver row and
its comment, the regeneration orchestrator entry, the governed-merge register's
candidate and its self-test fixtures, the skills token ratchet's boundary
fixture and pinned exclusion set, ADR-0082, and the one skill-body link.

Measured: the published skill bundle drops from 156,787 to 151,426 tokens
(-5,361, -3.4%); the generator-owned population goes 11 files to 10 and the
published-file population 47 to 46.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2oQebDDxYKfWZusyd8GXk
@github-actions github-actions Bot added the size/l label Sep 4, 2026
@os-justin os-justin added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026 — with Claude
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 97bcd99e1f71c58a14b3b4f7f57559dc031a7b42packageMentionDocs.

Copy link
Copy Markdown
Collaborator Author

Seat review: ACCEPT — review of record on #14559 (comment 5537286881), domain:spec seat, 2026-09-04T07:36Z.

Governed surface (docs/adr/**, skills/**; check-governed-merges --test exit 3 on the eight paths) ⇒ this PR stays draft. No agent seat flips it ready, enqueues it, or arms auto-merge; a human merge is the review record. Review requested from os-zhuang and hotlong.

For the human merger, what to read:

  • docs/adr/0082-react-component-contract-governance.md:39 — one sentence now names one rendering, plus a correction parenthetical in the ADR's own style (:87 already read one rendering, unchanged).
  • skills/objectstack-ui/rules/pages.md:194 — one line, the dead link retargeted; 448 → 448 lines, 5,501 → 5,492 tokens under a 5,501 ceiling.
  • The deleted JSON has no reader: git grep -n react-blocks.contract.json origin/main at 97bcd99e returns names only (generator, .gitattributes, ADR, changelog/changeset history, ratchet fixtures, queue-guard register rows, regen-artifacts, pages.md); objectui 24e027e9 returns nothing. Every one of those name sites is repaired in this diff or is history.
  • skip-changeset is measured: packages/spec publishes no scripts/, and skills/ is in no package.

CI on d76ab048 at 07:31Z: 15 completed checks green, the long jobs still running; merge when the required checks report on this head.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

2 participants