Skip to content

fix(spec)!: a single-brace token in a translated flow screen title is refused, like the description beside it (#22627) - #22673

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-22627-screen-title-text-slot-judge
Oct 10, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-22627-screen-title-text-slot-judge

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22627

Clause-②: no (narrowing)

What changed

The flow engine picks three translated templates in the run's locale and renders each through renderTextSlot, the {{ }} dialect: a screen's heading (title), its body text (description), and a refusing end node's message (maintainer ruling A on #22507, implemented by PR #22626 at d25b187203). The description and message translation leaves ran the one text-slot judge, textSlotTemplateRefusal. The flows.FLOW.screens.NODE_ID.title leaf was a bare z.string(). So title: 'Welcome, {name}' parsed, and the heading showed Welcome, {name}.

  • packages/spec/src/system/translation.zod.ts. One package-internal leaf factory, flowTextSlotTranslation, runs the judge. title, description and refusals.NODE_ID.message all use it, so one judge covers the three by construction, and the two spelled-out copies of the superRefine are gone. It is a factory, so each slot keeps its own schema node as before. No new export. The flows docblock's ⚠️ paragraph that recorded the gap now says both screen keys are judged, and the title leaf's comment says so too. The .describe() strings are unchanged: the heading's already called it a {{ }} template.
  • Pins in translation.test.ts, beside the description pins.
    • Refused: {name} in a translated title, at the key's path, through TranslationDataSchema and TranslationItemSchema. The message starts with TEXT_SLOT_TEMPLATE_REFUSAL and names {{ name }}.
    • Control: Welcome, {{ record.name }} and '' are accepted.
    • Family: every key in FLOW_SCREEN_COPY_KEYS, plus the refusal message, refuses {name}. A floor stops an emptied key list from passing.
    • Refusal is asserted by the stable prefix and the double-brace spelling, never by remedy wording, so PR feat(spec,service-automation)!: refuse the date macros in flow value slots with their CEL string form (#19939 pass 3) #22635's rewrite of the judge's remedies does not flip these pins.
  • ADR-0087. New D3 semantic entry translation-flow-screen-title-text-slot-refused (protocol 18) in its own file, plus the regenerated migrations/registry.ts. PR feat(spec,service-automation)!: refuse the date macros in flow value slots with their CEL string form (#19939 pass 3) #22635's 18.flow-text-slot-single-brace-refused.ts is not touched.
  • packages/spec/dropped-refinements.baseline.json. The judge reaches the runtime and not the published JSON Schema, like its two siblings. The 8 schemas that carry the flows face now name the new flows.valueType.screens.valueType.title site, and droppedRefinementSites goes from 696 to 704. The ledger is hand-edited, and the build printed the corrected entries.
  • Changeset .changeset/22627-flow-screen-title-translation-text-slot.md: @objectstack/spec: minor. It is BREAKING (an accept-set narrowing) under the launch-window convention, and it carries the FROM → TO.

No other generated artifact moved: check:generated reported all 15 artifacts up to date against the rebuilt dist, both before and after the merge.

The dispatch's premises, measured

  1. The gap was real on main. At 86da194919, title was z.string().optional(), description ran the judge in a superRefine, and the ⚠️ paragraph recorded the gap.
  2. Reach is 0 on the base. A tsx walker loaded the four bundles that carry a screens group, the only four under examples/** and packages/**: examples/app-crm crm.translation.ts, examples/app-showcase translations/index.ts, and examples/app-todo ja-JP.ts / zh-CN.ts. It judged every flows.F.screens.N.title string with textSlotTemplateRefusal: 8 judged, 0 refused. The positive control, the same walker over messages strings, judged 48 and refused 2. Both are crm.activity.due_today ({count}, en and zh-CN). No fixture or bundle flips.
  3. The empty string stays accepted. textSlotTemplateRefusal('') answers undefined, measured. It is pinned for title here, beside the existing description and message pins.
  4. ADR-0087: an entry is owed. This contradicts the triage claim. check-adr-0087-registration.mjs --base origin/main refused not-required (no-migration-prescription) because the changeset carries a FROM → TO table (evidence from-to-label). A breaking narrowing owes the upgrader that rewrite, so the disposition is registered, now green: [BREAKING+clause-②-narrowing] registered translation-flow-screen-title-text-slot-refused (new here).
  5. PR feat(spec,service-automation)!: refuse the date macros in flow value slots with their CEL string form (#19939 pass 3) #22635. Its diff of flow-text-slot-template.ts (head 3c97f71067) rewrites the date-macro remedy and the module docblock. It does not touch TEXT_SLOT_TEMPLATE_REFUSAL or the plain-path "Write X as Y" remedy, and the pins rely on nothing else.
  6. Consumers. Each package below was run against a rebuilt @objectstack/spec dist. Results are in the tests table.

Ablation (expected direction: red; observed: red)

node scripts/ablation-replace.mjs ran on the committed fix (d3723c736). It replaced the anchor title: flowTextSlotTranslation().optional().describe( with title: z.string().optional().describe(. The anchor count went from 1 to 0, and the blob from 62144f762132 to 14fb1e3e3d4f. Then vitest run src/system/translation.test.ts ran: 2 failed | 150 passed. The failures are exactly the two title pins, the refusal pin and the family pin. The accept-control stayed green, as it should. Restore check: blob 62144f762132 equals HEAD, and git diff HEAD is empty. The test imports ./translation.zod from source, so no dist rebuild was involved.

Tests and gates

The head is 327c0cc2fb: the fix plus a merge of origin/main at 5fb1746611, done with scripts/pm/os-regen-merge.sh. That merge brought in PR #22635's judge edits. The regenerated registry.ts came out byte-identical, check:generated reported all 15 artifacts current, and the branch delta against origin/main is exactly this PR's 6 files.

Before the merge (cf08a125a): a full consumer sweep against a rebuilt dist.

package command result
@objectstack/spec vitest run --project local (the package's pnpm test) 642 files, 19152 passed, 1 todo
@objectstack/spec vitest run --project repo (not part of pnpm test; run anyway) 54 files, 915 passed
@objectstack/spec pnpm typecheck exit 0 (translation.test.ts is in the tsconfig.test.json program, with no debt entry)
@objectstack/lint vitest run, the whole package, including validate-translation-references.test.ts 134 files, 6122 passed
@objectstack/service-automation vitest run, the whole package, including screen-copy-translation.test.ts 183 files, 2300 passed
@objectstack/cli vitest run --project unit i18n: every unit-tier file whose path names i18n, including i18n-flow-screen-coverage, i18n-flow-refusal-coverage and i18n-extract 26 files, 330 passed
@objectstack/downstream-contract vitest run 3 files, 31 passed

After the merge (327c0cc2fb).

package command result
@objectstack/spec vitest run --project local, then pnpm typecheck 642 files, 19175 passed, 1 todo; typecheck exit 0
@objectstack/lint vitest run src/validate-translation-references 1 file, 164 passed
@objectstack/service-automation screen-copy-translation.test.ts + builtin/text-slot-template.test.ts 2 files, 32 passed
@objectstack/cli vitest run --project unit i18n 26 files, 330 passed
@objectstack/downstream-contract vitest run 3 files, 31 passed

Other checks.

  • CLI integration tier. Left to CI: this diff touches no CLI file and no spawn entry. Three i18n files are in that tier: i18n-extract-check-dry-run, -check-json and -companion-orphan.
  • Reach after the merge. Re-measured at 327c0cc2fb with the judge as it now stands: 8 screen headings judged, 0 refused. The control refused 2 of 48 messages.
  • Gates.
    • node scripts/pm/dispatch-gates.mjs --commands (no paths) derived the same 92 commands before and after the merge. All 92 were run at 327c0cc2fb, and all 92 exited 0.
    • --ran reconciliation: 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero with every exit code recorded.
    • The first run, at cf08a125a, had three PREREQUISITE NOT MET refusals (exit 3), which measure nothing: a shallow clone missing check-plugin-teardown-shape's pinned fixture commit, and unbuilt packages for check:dual-build-cjs-loads and check:i18n-walk-parity. All three were re-run green once their inputs existed.
  • The families the PM named are all in that set.
    • Repo scripts: check-adr-0087-registration, check-changeset-no-major, check-closing-keyword-parity, check-spec-docblock-symbol-anchors and docs-audit/check-affected-docs.
    • The spec package's checks: check:api-surface, check:authorable-surface, check:docs, check:liveness, check:strictness-ledger, check:export-origins and check:objectui-pin-citations.
    • Root checks: check:i18n-walk-parity, check:doc-authoring, check:issue-citations and check:spec-parsed-alias.

Acceptance notes

  • The A screen flow's select options and screen description have no key in the flows translation face — the zh-CN intake wizard translates its labels and placeholders and keeps its options and body text in English (17.7.0) #22507 changeset still says the opposite, in the same release. .changeset/22507-screen-copy-engine-pick-spec.md (PR feat(i18n): the engine translates a screen's title and description in the run's locale #22626, unreleased) ends with "A translated screen title is not judged by the text-slot rule yet". This PR's changeset carries the repo's usual sentence for that case ("An earlier entry in this release says …; that describes the face before this change"). The other file was outside this card's file surface, so it was not edited. If deleting that last bullet reads better in the compiled CHANGELOG, it is a one-line follow-up.
  • The engine docblock still hedges. AutomationEngine.renderFlowTextSlot in packages/services/service-automation/src/engine.ts says the single brace is refused "for the keys that judge covers". That is still true, and the judge now covers all three keys, so the hedge could go. Not edited (outside the surface).
  • A translated heading is judged even when it stands in for the node label. When a screen declares no config.title, the heading falls back to node.label, which is plain text and never judged on the source. Its translation is still judged, because the engine renders whatever it picks through renderTextSlot. The docblock says so.
  • The prose docs are already correct. The content/docs/ui/translations.mdx flows bullets already say a translation keeps the holes of the text it translates, and nothing there is made false. The generated references/system/translation.mdx did not move.

Generated by Claude Code

…lot judge (#22627)

The engine picks a translated screen title in the run's locale and renders it
through renderTextSlot, like the description and the refusing end message
beside it, but only those two were judged: a single-brace {name} in a
translated heading parsed and was drawn as literal text. The three
engine-picked template leaves now share one leaf, flowTextSlotTranslation,
which runs textSlotTemplateRefusal; an empty string stays accepted.

Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK
Co-authored-by: Claude <noreply@anthropic.com>
…tle translation

The narrowing's changeset carries its FROM -> TO, so the ADR-0087 gate
refuses a not-required disposition; the D3 semantic entry
translation-flow-screen-title-text-slot-refused records it, and the
registry is regenerated.

Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK
Co-authored-by: Claude <noreply@anthropic.com>
…d-refinements ledger

The text-slot judge on a translated screen title reaches the runtime and not
the published JSON Schema, like its description and refusal-message
siblings; the eight schemas that carry the flows face name the site.

Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

3 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/dropped-refinements.baseline.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/dropped-refinements.baseline.json) — pages documenting those are invisible to this run
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 139 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 243dd3c6256673dc1a56f9419be03c397129f825 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 967cf2fadf12ff4d3fa0f43c1854701a99cffb4c — the merge of head 9c3733f39b37bf9805ef4558c87474da9b01d316 into base 243dd3c6256673dc1a56f9419be03c397129f825, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 967cf2fadf12ff4d3fa0f43c1854701a99cffb4c && git checkout 967cf2fadf12ff4d3fa0f43c1854701a99cffb4c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 243dd3c6256673dc1a56f9419be03c397129f825 9c3733f39b37bf9805ef4558c87474da9b01d316 && git checkout -B drift-repro 243dd3c6256673dc1a56f9419be03c397129f825 && git merge --no-ff 9c3733f39b37bf9805ef4558c87474da9b01d316

node scripts/docs-audit/affected-docs.mjs --json 243dd3c6256673dc1a56f9419be03c397129f825

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

…reen-title-text-slot-judge

# Conflicts:
#	packages/spec/dropped-refinements.baseline.json
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 9c3733f39b37bf9805ef4558c87474da9b01d316
Local-runs: none

PR #22673 for card #22627, branch claude/issue-22627-screen-title-text-slot-judge. The head is a merge of origin/main 243dd3c625 into 327c0cc2fb; the net delta against main is the PR's 6 files (216 insertions, 39 deletions). Inputs read: the card body and all 5 comments (triage 6094869470, unlock 6095432757, claim 6095600078, the two os-dev-reports 6096446823 and 6098004242), the governing ruling 6093472708 on #22507, the PR body, the REST file list, the diff against main, the 35 check-runs on the head, and files at origin/main and at the head through git show. Nothing was built, run or re-run.

① Derived judgments

  1. Accept-set change, one leaf: flows.FLOW.screens.NODE_ID.title narrows — right. On main the leaf is z.string().optional(); at the head it is flowTextSlotTranslation().optional(), a superRefine over the one judge textSlotTemplateRefusal. That judge has two arms at the head (singleBraceRefusal and unboundRootHoleRefusal), so the leaf now refuses a single-brace {token} (the card's defect) and a {{ }} hole over a $ root the engine does not bind (the arm stock changeset 22477 gave the judge). The ruling and the triage direction say the ONE judge and ⛔ not a second one, so the second arm riding along is by design, and the changeset's "What is refused" names both arms, so the narrowing is declared at its true width. The empty string stays accepted (pinned). The .describe() string of the leaf is unchanged. The narrowing reaches every door that embeds the shape: TranslationDataSchema, TranslationItemSchema (the metadata-item door, pinned), PlatformTranslationDataSchema, and the manifest and API schemas that embed them — the eight schemas the ledger names.
  2. description and refusals.NODE_ID.message: no accept-set change — right. The factory is the inline superRefine moved, same judge, same custom issue, same .optional().describe(...) chain. A refactor with no contract movement; the family pin (FLOW_SCREEN_COPY_KEYS plus message, with a floor) holds all three on the one judge.
  3. Public surface: nothing new reaches it — right. flowTextSlotTranslation is a module-level const, not exported, and its docblock says why. The test's imports (TEXT_SLOT_TEMPLATE_REFUSAL, FLOW_SCREEN_COPY_KEYS, TranslationItemSchema) already exist at main. The leaf's TS type does not move (superRefine keeps ZodString, so the leaf is ZodOptional of ZodString before and after). packages/spec/api-surface/** and export-origins/** are not in the file list, and git diff --name-only origin/main...head over those two directories is empty. Lint & Repo Gates, Build Core and the four Type Check runs are green on the head.
  4. Published JSON Schema projection — right. A superRefine is dropped by z.toJSONSchema, so the published JSON Schema (gitignored, generated at publish) keeps its shape and the committed record of the gap is dropped-refinements.baseline.json. Read at the head: 223 schemas carry sites, 701 sites in all, 8 of them the new ...screens.valueType.title site (Manifest, GetTranslationsResponse, the options[1].manifest form, PlatformTranslationBundle, PlatformTranslationData, TranslationBundle, TranslationData, TranslationItem); at main the same read gives 223, 693, 0. The totals block at the head says 223 and 701, so the merge round's hand resolution of the conflicting totals is verified by count, not taken on the dev's word.
  5. ADR-0087 ledger — right. A D3 semantic entry translation-flow-screen-title-text-slot-refused under protocol 18 (PROTOCOL_VERSION is 18.0.0 at the head; the entry sits in step18), with no D2 conversion: a single-brace heading always drew as literal text on every route, so only the translator can say whether a hole was meant, which is ADR-0087's "cannot be converted; it goes to D3" case. The registry.ts diff is exactly that one entry inserted in id order between translation-component-submit-label-retired and translation-per-app-settings-platform-only; the dev reports gen:migration-registry byte-identical in both rounds, and the gate's registered disposition requires the id to resolve at the head AND be new in the diff, which it is. PR feat(spec,service-automation)!: refuse the date macros in flow value slots with their CEL string form (#19939 pass 3) #22635's 18.flow-text-slot-single-brace-refused.ts is untouched.
  6. Gap prose closed, nothing made false — right. The ⚠️ paragraph recording the gap in the flows docblock is replaced; a grep of the head for "not judged" / "unjudged" finds no residue for this key in packages/spec/src, content/docs or the liveness ledger; content/docs/ui/translations.mdx already says both screen keys are {{ }} templates the server renders. No generated reference moved (none in the file list; the dev reports check:generated 15 of 15 current in both rounds).
  7. Reach — consistent. The dev measured 8 translated headings judged, 0 refused, at both bases, with a positive control refusing 2 of 48 messages. A read of the four bundle files at the head finds no title: value carrying a single brace. Test Core 6 of 6 and the consumer suites are green, so no fixture flips.
  8. Governed surface — none. None of the 6 paths is a GOVERNED_SURFACES row; Governed Surface Queue Guard is green. The PR is a draft awaiting this record under the claim's own protocol (a contract-face narrowing is reviewed at this tier before enqueue), not under Tier S.
  9. Check-runs on the head: 32 success, 3 skipped, 0 failure. The three skipped are Build Docs, Console Pin Gate and the opt-in Packed-tarball smoke, all path-gated by the filter job; no export is removed or renamed and resolveFlowScreenTitle is untouched, so the pin gate has nothing this diff could redden. Check Changeset, Spec property liveness, Lint & Repo Gates, the Type Check family, Test Core and the Dogfood gates are all green.
  10. Branch history — clean. Five commits, linear from 86da194919 with two merges of origin/main (5fb1746611, then 243dd3c625); the PR's commit list matches the branch; no amend or force push; the head equals the PR head. Commit trailers are AGENTS.md's model-free pair.

② Semver level

  • The changeset matches what the diff publishes. .changeset/22627-flow-screen-title-translation-text-slot.md grades @objectstack/spec only, and packages/spec is the only published package the diff moves. It carries the BREAKING banner, the FROM → TO table, the one-line fix, the measured reach, the ledger paragraph, and exactly one ADR-0087 marker (registered translation-flow-screen-title-text-slot-refused). No tombstone is owed: no key is removed or renamed.
  • Clause-②: no (narrowing) is right, in the PR body and the changeset alike. Clause ② is "a new key on a published payload"; this PR adds none (the title key predates it), so no is the truthful value, and (narrowing) is the arm that makes it BREAKING under the closed pair. The card body and the triage spelled yes (narrowing); the claim, which binds, spelled no (narrowing), and the PR follows the claim and the truth. The guard's LEVEL axis reads no as not-declared and stands down; Check Changeset is green on the head.
  • minor with a BREAKING section, in pre mode — right. scripts/check-changeset-no-major.mjs's header states the launch-window convention: a breaking change ships as minor, the level is not the carrier, and the carriers are the BREAKING banner plus the ADR-0087 disposition, both present here. Its RC exemption says that while .changeset/pre.json reads mode: pre (it does, tag next) the guard stands aside for a major; that ADMITS major, it does not demand it, and the workflow's WHICH LEVEL prose says the same. The pending stock on main at 243dd3c625 is split: spec accept-set narrowings graded minor with a BREAKING banner (13458, the 15206/15207 set, 21898, 21982, 22054, 22088, 22114, 22149, 22343, 22443, 22470, 22477, 22568, 5082, 9139) and graded major (11509, the 19939 set, 22110, 22158, 22491, 22502, 22565). The nearest sibling, 22477-flow-text-slot-dollar-root-refused — the $-root arm of this very judge — is minor, no (narrowing), BREAKING. And the line's version is already decided: 22080-v18-line-opens and 22130-protocol-18 carry @objectstack/spec: major, the fixed group takes the highest bump, so the next release is 18.0.0-next.N whatever this changeset grades; the level here carries no information, exactly as the header says of the window. Observation, not a finding: the stock carries two banner wordings for one convention ("under the launch-window convention" here and in 22477; "as major on the v18 line" in 11509). That is a stock-wide inconsistency for the maintainer to settle once, not this PR's defect.

③ Boundary flags

Open questions: none in either report. Every flag answered below; nothing escalates.

Report 1 (6096446823), out-of-scope findings.

  • .changeset/22507-screen-copy-engine-pick-spec.md's last bullet ("A translated screen title is not judged by the text-slot rule yet") becomes false in the same release. Answered, not blocking. The dev's changeset carries the counter-sentence "An earlier entry in this release says …; that describes the face before this change", which is the shape two entries in the pending stock already use (22428-field-existence-every-spelling, 22481-attached-block-served-rows), so the compiled CHANGELOG reads correctly in order. The cleaner outcome is deleting that one bullet; it is outside the card's file surface, and the dev rightly noted it in the Acceptance notes rather than widening scope (Prime Directive chore: version packages #10). The seat may fold the one-line deletion into this PR before enqueue, or leave it to a follow-up; neither changes this verdict.
  • AutomationEngine.renderFlowTextSlot's docblock hedge "for the keys that judge covers". Answered, not blocking. Read at main: the sentence stays true (the judge now covers every key the engine picks), so the hedge is cosmetic residue, outside the surface; no issue is owed.

Report 1, deviations.

  • ADR-0087 D3 entry added after check-adr-0087-registration refused not-required (no-migration-prescription). Right, and pre-authorised: the claim's file surface says "Only if check-adr-0087-registration demands one". The gate refuses no-migration-prescription on a changeset whose own body carries a FROM → TO, and AGENTS.md requires that FROM → TO on every breaking changeset, so registered was the only honest disposition; the triage's "ADR-0087 not required" was a prediction the gate overturned by measurement.
  • Clause-②: no (narrowing) against the card's yes (narrowing). Right; judged in ②.
  • Attribution trailers: AGENTS.md's model-free pair over the harness reminder. Right; the commits carry Claude-Session: plus Co-authored-by: Claude, the PR body ends with the session URL. Not a contract matter.
  • A never-pushed probe commit reset with git reset --soft onto the branch's own pushed commit. Verified: the pushed history is the five commits above, no amend, no force push.
  • One pinned fixture commit fetched into the shared object store; the spec repo tier and a --re-measure turbo build run in the worktree. Process only; objects without refs and a local run leave nothing in the diff.
  • origin/main merged before the PR opened. Fine; the delta against main is the PR's 6 files.

Report 2 (6098004242), the merge round.

  • Head 9c3733f39b is a merge, not a rebase. Verified: parents 327c0cc2fb and 243dd3c625.
  • dropped-refinements.baseline.json totals resolved by counting the merged body. Verified by an independent count at the head: 223 schemas, 701 sites, all 8 title sites present (①.4).
  • registry.ts auto-merged and regenerated byte-identical. Consistent with the diff, which holds exactly the one new entry; Build Core and Lint & Repo Gates are green on the head.
  • The full 92-command gate battery is NOT MEASURED at 9c3733f39b. Answered by the head's check-runs: 32 success, 0 failure (①.9); the families the claim named are all green there.
  • Worktree re-created; two-step merge as the script prescribes. Process only.

Implemented-by: claude/issue-22627-screen-title-text-slot-judge
Reviewed-by: session_016njDy8ozy9B9Ns5Y8kAWEK

VERDICT: PASS


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 protocol:system size/m tests tooling

Projects

None yet

2 participants