feat(platform-checklist): carry implementation STATUS in the ledger — status: planned for capabilities the definition requires and the platform does not yet verify - #19161
Conversation
… `status: planned` An area item gains `status: planned` — a capability the North Star's definition requires that the platform does not yet verify. The ledger could record only what already works, so a capability gap had nowhere to live: the backlog sweep had nothing to point a `Path:` at, and the platform's implementation status lived in nobody's head. `planned` relaxes exactly the three fields that cannot honestly exist before the capability does — `since` (null, or the TARGET release), `steps` (none until it is implementable) and `acceptance` (no oracle to consult) — and adds one: `personas`, which is knowable the day the gap is found and is what makes the gap readable to the next sweep. The load-bearing half is the capability-coverage ratchet: a planned item is a legal map target and carries ZERO coverage, so a kind whose only items are planned is UNMAPPED. Otherwise `planned` would be the cheapest way to green an untested kind and the ratchet would measure intentions instead of tests. Both directions are pinned on fixtures in a new self-test battery, because the live ledger carries zero planned items and cannot tell a working rule from a deleted one. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
…UNNER/README/skills The selector resolves one selector against two pools: the runnable one it has always returned, and the planned one it now reports beside it. A planned id must never reach a runner (whatever verdict came back would be about nothing), but dropping it silently would answer 'nothing here' about an area whose gap the ledger is deliberately carrying. `pnpm gen:checklist-status` is the 平台功能清单 + 实现状态 view: per-area active/planned counts and every planned id, plus `--out <dir>` rendering the wiki page set — one index and one page per area, planned first. Published on a schedule to the wiki, never committed: a generated page in the tree is a third artifact to keep fresh whose stale copy reads exactly as authoritative as a current one. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
…isposition and classify its battery Two ledgers the new generator and its self-test battery owe a row in, each found by its own gate rather than by inspection: - `scripts/regen-artifacts.mjs`: `gen:checklist-status` writes NOTHING into this repository, so 'discard both sides and re-run the generator' is not a question that arises. Recorded as NOT_DRIVER_MANAGED with `untracked: true` rather than omitted, because the refused alternative — a committed STATUS.md paired with a check — is exactly the routed-artifact shape a reader assumes. Owner is the ROOT manifest: the accounting is keyed per (owner, script). - `scripts/pm/dispatch-gates.mjs`: `selfTestPlannedStatus` is a genuine battery, so its fixtures SHOULD be masked away from watch-hint extraction. The docblock's TOTAL / GENUINE / distinct-spelling counts are pinned against the table and move with the row. Its two UNPINNED neighbours (the corpus totals) were already stale on origin/main at 253/223 against a measured 273/243; restated to the freshly measured 275/244 so the paragraph's own arithmetic (244 + 31 = 275) stays true rather than being broken by this row. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
Contract review — Tier S landing credentialServed-tier: Isolated at-tier reviewer, own worktrees, shared checkout untouched. Tier re-derived independently and agrees with the seat: VERDICT: FAIL ⭐ One blocking finding, and it is one line of prose. Everything substantive measured PASS-grade — the relaxation not leaking to ⛔ F1 — BLOCKING — a dangling
|
| probe | result |
|---|---|
pnpm check:adr-anchors at head |
exit 1 — 2 failures of 106: 「ADR-0136 is cited by 1 file(s) but names no record under docs/adr/」 |
same on origin/main 8b8258d910 |
exit 0 |
git grep ADR-0136 on origin/main |
0 hits — the line is this PR's |
highest record under docs/adr/ |
0135-identity-and-access-architecture.md |
CI Lint & Repo Gates (job 105819264481) |
FAILURE, step 10 pnpm check:adr-anchors exit 1 · never_ran=169 failed=1 ran=8 declared=179 |
⇒ Lint & Repo Gates is one of the seven required contexts. A ## Contract review record is a credential for the CURRENT head, and this head cannot land, so a PASS here would be a credential for nothing.
⭐ Provenance, and it is not the dev's invention: the CARD ITSELF carries the citation. #19157's body says 「(the ADR-0136 lesson; …)」 and the dev copied it. A bare ADR-NNNN resolves against this repo's registry; if a sibling repo's decision is meant, the gate's own remedy text names the cloud ADR-0136 / ObjectUI ADR-0136 spelling. Whether such a record exists in objectstack-ai/cloud is NOT MEASURED — no cloud checkout here.
check:adr-anchors sits among dispatch-gates's 「43 undetermined (their sources name no path at all)」 families — outside the 43 it DERIVES for these paths. The dev's 「43 derived / 43 accounted / 0 UNRUN」 was reproduced exactly and is true of that instrument. ⇒ this is an instrument-reach fact, not dishonesty. But 「every check is green」 is a landing precondition the PR body itself states, and it is false at this head.
F3 — noted by the reviewer; ⭐ the seat is CARRYING it into the same push
The reviewer ran the ablations the PR said were not owed, and the answer is two-sided:
- The dev is RIGHT that no ablation was needed to prove the SHIPPED behaviour — the fixture-driven live runs prove the binding works today, in both directions and in the leak direction.
- The dev is WRONG as a DURABILITY claim. The PR body says 「the real data cannot distinguish a working ratchet rule from a deleted one … pinned on fixtures in the self-test」. That holds for the function, ⛔ not for its binding into the walk:
| ablation | result |
|---|---|
A2 — coverage call site reverted to the pre-PR loop, coverageEntryProblems never called |
--self-test exit 0, 207 assertions; live gate on a planned-only kind exit 0 |
A3 — the statusFieldProblems(item) call dropped from the item walk |
--self-test exit 0, 207; live gate on an ACTIVE item with since: null and no steps exit 0 |
| A1 guard · A4 selector · A5/A6 gen · A7 floor | all exit 1 ✓ — the function-level pins do fire |
⇒ a severed call site leaves the self-test 207/207 green, the live ledger green, and even a planned-only fixture green. ⛔ The seat is not letting that ship as a noted item: this PR's whole subject is a ratchet, and a ratchet whose binding nothing pins is the shape this lane refuses. The remedy pattern already lives in this file — the line-citation limb pins its binding by a source read driven on and off. Carry it in the same push; the file is already open and this is not widening.
Other noted findings, all to carry
- F2 — a planned item whose
sincenames a PAST release passes silently (fixturesince: "v1"→ exit 0).RELEASE_REis shape-only and the ledger holds no release timeline, so the README/PR-body phrase 「never a release that already shipped without it」 is authoring guidance the code cannot enforce, and nothing pins it either way. ⇒ per PD chore: version packages #10 「keep the claim as narrow as the enforcement」: narrow the wording, or add a floor. Not coverage-defeating (bearing stays 0). - F4 — a hand-typed
264in the new self-test prose (assertion label and success line). Prose only, no output derives from it, ⛔ but it reads false on the 265th item and nothing pins it — the same rotdispatch-gates.mjs's own docblock warns about. The status command's numbers are derived (with the fixture on the tree it printed 「264 active · 1 planned」). - F5 — the docblock arithmetic is right and the edit was forced, not creep: census re-derived at three trees, head reads 275 / 244 / 31 / 28, and 275 = 244 + 31 ✓, with 「the remaining 31」 pinned in the same sentence as the unpinned 253/223 where 253 − 223 = 30 ≠ 31.
⚠️ On the untouched sentence the reviewer corrects both the author and itself: accidental rows are 11 over SIX files — so 「in any of the six files」 is correct, 「Neutralising each of the ten」 is stale, and the dev's own report saying 「eleven rows across SEVEN files」 has the seven wrong. All of it was already stale at the merge base and none is pinned ⇒ ⛔ leaving it untouched here is right; the next accidental row is the carrier. - F6 — the README links the workflow file (absent on PR A's tree) and the wiki page (absent until PR B's first run): dangling between the two landings by the declared ordering.
Check Documentation Linksis success, so no gate reds. - F7 — PR B's own
pull_requesttrigger runspnpm gen:checklist-statuson PR B's tree, where the script is absent ⇒ that check fails until PR A lands or PR B rebases onto it.
⭐ Ordering CONFIRMED from four independent sources
PR B's body 「land the ledger PR first」 · PR A's body 「deliberately not a close」 · the card's closed_by_pull_requests listing only #19162 · the workflow's own lines. And measured rather than argued: on the base tree without PR A, pnpm gen:checklist-status exits 254 (Command "gen:checklist-status" not found), and the workflow captures code=$? with no pipe and re-exits it ⇒ PR B landed first fails loudly, exactly as its body claims.
NOT MEASURED, declared
- The final exit code of the ledger-row ablation battery — its decisive assertion had already gone red and was captured (case 194,
unlisted: …::selfTestPlannedStatus), but the 1866-case / ~700 s battery was still running at handback. ⇒ it will exit non-zero; the exit code itself is not a reading I hold. check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:sourcemap-no-sources-content,@objectstack/lint check:doc-formula-expressions— exit 3, no closure build in the worktree, and the diff touches no package source.- The 169 CI gates that never ran on this head, because CI stopped at F1.
- PR B's
workflow_dispatch/ wiki publish (environmental — the wiki must exist; ⭐ the file refuses rather than skips, which is checkable from the workflow source without running it) and PR B's check runs. - Whether
ADR-0136exists inobjectstack-ai/cloud.
Zeros, each with its reach
0 leak (one item, five mutations; the walk applies the same status-keyed predicate to all 264, so it generalises by construction — outside: fields this PR does not touch) · 0 derivation drift (38 of 8988 tracked paths, 178 families identical at both trees — outside: the other 8950) · 0 bin/exports escapes (70 published manifests — outside: a build script copying a root file into a package's dist) · 0 UNRUN (the 43 DERIVED families only — ⛔ check:adr-anchors sits outside that reach, and it is RED).
⛔ The PR stays a draft and ⛔ does not enter the queue. ⛔ needs:contract-review comes off all three carriers (#19157, #19161, #19162) in one stroke, as a concluded review does whether it passed or failed — ⛔ this is NOT a strip and NOT a green light; this record is what blocks the landing. It is re-hung when the new head arrives.
Implemented-by: claude/issue-19157-checklist-planned-status
Reviewed-by: session_01AmH9bKvGoLjiY86Q4Z3og2
Generated by Claude Code
…l sites, narrow the `since` claim Four findings from the Tier S contract review, carried in one push. F1 (BLOCKING) — `docs/qa/platform-checklist/README.md` cited `ADR-0136`, which names no record under `docs/adr/` (the registry stops at 0135). A bare `ADR-NNNN` resolves against THIS repo, so `check:adr-anchors` exited 1 and took the required `Lint & Repo Gates` context with it, leaving 169 gates never run. The citation came from the card body and was copied; the fix is still owed here. ⛔ No number is invented and nothing is allowlisted: the lesson is stated self-containedly instead, which is what a rule in this tree owes anyway. F3 — the two rules ride on two call sites that nothing pinned. Both were severed and measured: `--self-test` stayed at 207/207 green, the live gate stayed green, and a fixture kind whose ONLY item is planned stayed green. A pure function's battery cannot see whether anything calls it, and the subject here IS a ratchet, so an unpinned binding is a ratchet that switches off without a number moving. `statusBindingProblems` reads this file's own source and is driven ON and OFF over one text, the way the line-citation limb below already pins its binding. The first draft of it shipped a decoy — its severing needles were plain string literals the predicate matched instead of the real call sites, so both OFF legs read as passes. The OFF legs caught it; the predicate now demands EXACTLY ONE occurrence and the needles arrive in halves. F2 — `since` is checked for SHAPE only. This ledger holds no release timeline, so a planned item targeting an already-shipped release passes. The README, the refusal message and the docblock now say that, and two rows pin the limit in the direction it deliberately does not go. F4 — the hand-typed `264` in the self-test prose is derived from the ledger. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
Contract review — Tier S landing credential, scoped re-reviewServed-tier: VERDICT: FAIL — one blocking finding. F1, F2, F4 and the whole regression surface measured PASS-grade. ⛔ F3 — BLOCKING — it is a SPELLING pin, ⛔ not a BINDING pinWhat is genuinely real.
⛔ And it is defeated by the most ordinary severing gesture there is. Every row below left
⭐ The dev's own docblock names 「a commented-out draft」 as the decoy threat — and the comment-out IS that draft, at count 1. What it refuses, correctly (fails closed — brittle but documented): a double space, a line break inside the ⭐ The seat's call on which tier to demand — stated rather than left openThe reviewer measured two tiers and handed the choice to the seat. Take the MINIMUM tier, and make the residual DISCLOSED rather than implied.
VERIFIEDF1 — PASS. F2 — PASS on the tree. A five-spelling whole-tree sweep finds the only in-surface hits now reading 「Only the SHAPE is checked … no release timeline … an authoring error no gate here can see」. F4 — PASS, one noted: the literal readings that remain ( F5 — PASS. ⭐ No assertion was weakened or deleted, established by predicate-level extraction at both heads: the 19 rows the extractor parses are byte-identical, and the diff is additions only. The one touched pre-existing row had its label string become a template literal with the predicate unchanged. 217 − 207 = 10 = the ten new rows. Skill budgets did not move (the delta touches no
|
…urce, and disclose what it still cannot see F3, third pass. The pin demanded exactly one occurrence of each call site and counted RAW source, so the most ordinary severing gesture there is walked straight past it: commenting the call out IN PLACE left the commented line as the one occurrence, and `--self-test` stayed at 217/217 with the live gate at 264 active. The nastier variant did the same while inverting behaviour — comment the `mappedCount` gate out, add an ungated increment below it, and a kind mapped only to planned items is counted as covered on the OK line. The remedy is one line: `maskComments`, already imported in this file and already used twice in it, applied before counting. Masking also settles the decoy rule in the only consistent direction — a copy inside a comment is neither a call site nor a decoy, so it must neither satisfy the count nor inflate it. ⛔ And the claim is narrowed to the enforcement, which is the part that is not optional. This is a TEXT pin. It answers "is this call site still written, in live code, exactly once?" and it is NOT proof the call executes: shadowing, a call moved into a never-called helper, and a call left under a dead branch all keep the spelling intact and this pin reports nothing. The docblock says so and G12 asserts it, so nobody reads a green G1 as more than it is. Closing those needs the walk driven over a fixture ledger — a root knob or the walk factored into a callable — which is not built here by the seat's scope call. G9–G11 keep the mask: reverting it to a raw count reds those three rows and nothing else. The OFF legs' first-occurrence anchoring is noted where they are written. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
Contract review — Tier S landing credentialServed-tier: VERDICT: PASS ⛔ Blocking findings: none. Six noted prose/citation imprecisions, ⛔ none of which makes a docblock claim false on the tree. Scope: the delta ⭐ The mask is the whole difference — identical attacks, green at base, red at head
⇒ the two attacks that defeated the previous head are closed, and the base control proves it is the mask that closed them. ⭐ META-ABLATION — the rows are the mask's pins, ⛔ not decorationReverting ⭐ The disclosure is ACCURATE in both directions
⇒ all three named forms are genuinely unseeable, and ⛔ nothing the list names is in fact seen — the disclosure neither under- nor over-claims on its own members. G12 is something a test can fail on, ⛔ not prose: adding a row that claims to see shadowing reds exactly G12 (1 failure) on both instruments. And the floor bites — dropping G12 reds with 「reported 41 assertions but its floor is 42」. ⭐ Both of the dev's self-reports against itself — CONFIRMED
Regression on the delta217 → 221 assertions, battery 38 → 42, floor raised to 42 and it bites. ⛔ No assertion weakened or deleted: the
|
Part of #19157 — the ledger half (scope items 1–6).
Clause-②: yes (widening)
⛔ Merging this PR is deliberately not a close of that card. Scope item 7 — the scheduled workflow that publishes the human reading entry — is a separate draft on
claude/issue-19157-checklist-status-workflow, human-merged because the seat token lacks theworkflowscope. That half is what is left open here.The problem
docs/qa/platform-checklist/areas/*.jsonheld 264 items, every onestatus: active: the ledger recorded only capabilities that already work. So a missing piece of a listed capability had nowhere to live — the backlog sweep had nothing to point aPath:at, and the platform's implementation status lived in nobody's head. The North Star's definition line (「做出来的是什么」…「缺任何一样就不是这个应用」) makes such a piece a requirement, which is why it belongs on this ledger rather than in a second document that would drift against it with no gate able to say which is wrong.One ledger, one id space, one more status.
What changed
status: "planned"— the definition requires the capability and the platform does not yet implement or verify it. It relaxes exactly the three fields that cannot honestly exist before the capability does, and adds one that can:sincenull(no target release chosen) or a TARGET release. ⛔ Only the SHAPE is checked — this ledger holds no release timeline, so naming a release that already shipped is an authoring error no gate here can see. ⭐ Corrected by the seat: an earlier revision of this row promised 「never one that already shipped without it」, which described a check the code does not perform (PD #10 — keep the claim as narrow as the enforcement).stepsacceptancepersonasEverything else (
id,title,priority,surface,revision,history) is judged exactly as before, and the 264 live items are untouched.A planned item never runs.
scripts/checklist-select.mjsnow resolves one selector against two pools. The runnable pool is unchanged; the planned pool is reported beside it and handed to no runner. Dropping planned items silently was the alternative and is wrong in the other direction — a selector would answer "nothing here" about an area whose gap the ledger is deliberately carrying.A planned item is not coverage — this is the load-bearing half. It is a legal
coverage.jsonmap target, which is where a capability-gap card points, and it contributes zero: a kind whose only items are planned is reported UNMAPPED. Otherwiseplannedbecomes the cheapest way to green an untested kind, and 「凡是有的能力, 都要测试」 quietly becomes 「都要打算测试」.pnpm gen:checklist-statusis the 「平台功能清单 + 实现状态」 view: per-area active/planned counts, every planned id, and — with--out DIR— the wiki page set (one index, one page per area, planned first). Nothing downstream types a number; the pages carry them because the command produces them.RUNNER.md, README.md and the two internal skills carry the same three rules, each in the place its reader is already looking.
Measured, not asserted
Both coverage directions were driven end to end against a real fixture area file (a temporary
i18n.rtl-mirroringplanned item plus acoverage.jsonedit, restored afterwards —git diff HEADempty and both blob hashes equal to HEAD's):Direction A — the kind is still mapped by active items, planned listed beside them: GREEN
Direction B — the kind's ONLY item is planned: RED
The selector on that area — reported as planned, runs nothing for it
The runnable JSON that a runner fans out over carried the five active ids and not the planned one.
The status command on the current tree
Both numbers are read off the command. Index counts equal each area page's own (
P12in the generator's battery pins that equality rather than a second count of the same thing).Both directions are pinned on fixtures, in a battery declared in the roster with its floor — the live ledger carries zero planned items and is expected to for a while, so the real data cannot distinguish a working ratchet rule from a deleted one.
--self-testat 207/207 green, the live gate green, and even a planned-only fixture kind green.statusBindingProblemsnow pins both call sites by reading this file's own source, driven ON and OFF — the pattern the line-citation limb beside it already uses. All four severings now exit 1 on both instruments; two of the four were double-green before this pin existed.⛔ And that pin has a limit which is stated rather than implied (
## ⛔ WHAT THIS PIN CANNOT SEE): it reads comment-masked source, so it catches the text-visible severings — deletion, comment-out, a decoy copy — and ⛔ cannot see shadowing, a dead helper or a dead branch, which are semantic. ⭐ It is not proof the call executes. The behavioural tier that would be — driving the real walk over a fixture ledger — was deliberately not built here: it needs a root knob forAREAS_DIRor the walk factored into a callable, and the seat scoped that out rather than widen this PR at its third review.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsand reconciled with--ran: 43 derived families, 43 accounted for, 0 UNRUN.check:adr-anchorssits amongdispatch-gates's 43 UNDETERMINED families — outside the 43 this derivation covers — and an earlier head of this PR reddened it while the reconciliation above read clean. ⭐ The green asserted here is read from the PR's actual check runs: at 2026-09-19T04:18:24Z, 34 runs — 30 success, 4 skipped, 0 not-green, all seven required contexts success.⛔ And one more reach fact that changes what CI green MEANS here:
lint.ymlrecords thatcheck:platform-checklistis by maintainer decision NOT wired into CI — PR CI runs only a static watchdog-workflow pin, and the gate itself runs onmaindaily. ⇒Lint & Repo Gatessuccess says nothing about this PR's self-test, here or on any future head. The local runs above are its only reading.check:platform-checklist(207-assertion self-test + the live gate),check:doc-authoring,check:pm-skill-ratchet,check:pm-skill-id-lint,check:skill-frame-sync,check:merge-driver,check:pm-dispatch-gates(1866 cases),check:self-test-wired,check:declared-population-live,check:nul-bytes,check:pm-governed-merges,check:cross-package-test-inputs,check:parse-guard,check:turbo-task-graphand the rest of the derived set.check:merge-driver(the new generator owed a merge disposition) andcheck:pm-dispatch-gates(the new battery owed aCOMPOUND_ANCHOR_LEDGERrow).PREREQUISITE NOT MET, which is that gate's own distinct code for "nothing was swept": no closure build exists in this worktree, and this diff touches no package source at all, so there was nothing for a build to produce.check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:sourcemap-no-sources-content,@objectstack/lint check:doc-formula-expressions. ⛔ Read as neither a pass nor a finding; CI builds fresh and measures them there. Every exit code above was captured before any pipe.Skill budgets, both at their ceilings with the added rules paid for in the same edit:
checklist-test234 → 238 (ceiling 238),checklist-author53 → 62 (ceiling 62). No ceiling raised, no line bought by re-wrapping.⛔ Landing — Tier S, and the record comes first
.claude/**is on the governed register and is Tier S: this PR lands on a contract-tier review of record on this thread (Served-tier: CONTRACT_REVIEW_TIERplus a PASS verdict) and then the merge queue. ⛔ Not a human merge, and ⛔ never the queue without that record.docs/qa/**andscripts/**are not governed, and no hunk lands on a Tier H path —AGENTS.md,CLAUDE.md,docs/adr/**,docs/NORTH-STAR.mdand publishedskills/**are all untouched. Scope item 6 anticipated the one way that could change: the North Star's 「账本」 sentence stands as written, and nothing here required a pointer inAGENTS.mdto name the status axis, so the tier is S and not H.skip-changeset: this diff publishes nothing. Measured rather than assumed — the ten changed paths are.claude/**,docs/qa/**,scripts/**and the private rootpackage.json, none of which lives under any workspace package directory, so none can appear in any package'sfiles[]. Positive control: the same method finds 70 published packages that DO declarefiles[].Acceptance notes
scripts/pm/dispatch-gates.mjs's anchor-census docblock carried two unpinned corpus totals that were already stale onorigin/main: it claimed 253 matches / 223 bare against a measured 273 / 243. They are unpinned, so nothing reddened. This PR restates them to the freshly measured 275 / 244 because its own new row moves the pinned third number (30 → 31) and244 + 31 = 275has to stay true; leaving them would have broken the paragraph's arithmetic. Disclosed rather than folded in silently.planneditems appear neither in(judged/total)nor as a sixth counts bucket, becausescripts/qa/qa-rollup.mjsparses that vocabulary strictly and a planned item was never a judgeable unit of a run. RUNNER.md now says so where a runner would otherwise guess.维护者速读(草稿)
改了什么 —— 测试清单账本多了一个状态
planned:平台「按定义应该有、但还没做出来或还没验证」的能力,从此在账本里有地方放,有 id 可指。配套一条命令pnpm gen:checklist-status打印每个区的 active / planned 数字。为什么改 —— 之前账本只记已经能用的东西,于是 backlog 扫出来的「能力缺口」卡无处可指,只能靠人记着;平台实现到哪一步这件事没有任何地方写着。另立一份功能清单会和账本互相漂移,而且没有任何闸门能说哪份是错的 —— 所以加在同一份账本上,不新开文档。
风险与代价(含回滚) —— 最大的风险是
planned被当成覆盖用:只要有人把「打算测」算成「测了」,整个覆盖棘轮就从「有的能力都测了」变成「有的能力都打算测」。这条被钉死在两个方向上(只有 planned 项的种类仍报 UNMAPPED),并且是在夹具上钉的,因为真实账本现在一个 planned 项都没有。回滚代价很低:整个改动是新增状态 + 新增命令,现有 264 项的判定一字未动,撤回即回到今天的行为。席位意见 ——
你要做的 —— 这是 Tier S:需要本 PR 线程上一条契约档复核记录(
Served-tier: CONTRACT_REVIEW_TIER+ PASS),然后才走合并队列,⛔ 不是人工直接合。另外,item 7 的工作流是另一张单独的 draft,要你手动合(座位令牌没有workflow权限),建议先合这一张、再合那一张。Generated by Claude Code
Generated by Claude Code