chore(spec): register the admin-platform-admin-standing dogfood proof tag, and red the drift that let it accumulate - #12549
Conversation
📓 Docs Drift CheckNothing 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
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
|
PM review — ACCEPT ( Contract verdict: Clause-② re-checked against the real diff — still no on both limbs. Scripts-only; the published Both commits kept, including the gate commit
Instrument disclosures (prereqs-not-met on unbuilt worktree recorded as NOT MEASURED; 403 label fallback with read-back; sanitizer mutation caught and respelled) are the discipline we keep — noted. Landing: waiting for every check green on Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32957180001 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes #12216
Which side drifted: the REGISTRY
Decided by reading both sides rather than assuming, because the card admitted either
direction (register the tag, or correct a producer misspelling).
Producer —
packages/qa/dogfood/test/admin-platform-admin-standing.dogfood.test.tsdeclares
// @proof: admin-platform-admin-standingat line 113. The tag is not a typo:the file names itself, its tag and its sibling consistently, and it explicitly cites that
sibling —
admin-route-nonadmin-refusal.dogfood.test.ts— as a different file whose tagis already registered. No registered id is within a typo of it (
admin-credential-lifecycleand
admin-route-nonadmin-refusalare the two nearest, and both belong to real, distinct,already-registered proof files). The producer is a substantial deliberate proof: it pins the
dual of the sibling's assertion over the same derived
/admin/route population, with theplatform-admin standing control asserted first and per-route payloads chosen so the vendor's
pre-auth body validation cannot stand in for an authorization answer.
Registry —
packages/spec/scripts/liveness/proof-registry.mtshas no entry for it, soKNOWN_PROOF_IDSdoes not contain it andcheck:livenessreported it as an orphan tag.⇒ the registry lagged the dogfood tree. The tag is registered, unbound, with a
blockedReasonrather than a manufactured binding: platform-admin standing is the ADR-0068 D2identity resolution evaluated inside the auth plugin's route gate (runtime principal
resolution, no authorable metadata key whose
livestatus it gates), and it is a breadth guardover a derived route population besides — the
admin-route-nonadmin-refusal/permission-model-zooshape, where binding any single ledger entry would misrepresent bothwhat the proof covers and what that entry is proven by.
The #10773 class gate — included, not merely proposed
The card asked whether #10773's repair left the class un-gated. It did.
orphanProofswaspopulated by
scanOrphanProofs()and printed as a⚠, but it was absent from thefailedcondition in
check-liveness.mts— so registration drift could never turn the gate red.That is the whole mechanism of the recurrence: the warning reported 13 tags, PR #10934 (for
#10773) registered the 11 that existed then, a 12th arrived with the next dogfood proof, and
#12216 was written off the same
⚠line as #10773. Registering instances one round at a timedoes not close a class whose signal nothing fails on.
The second commit adds
report.orphanProofs.length(greater than zero) to thefailedcondition, upgrades the
⚠to✗with remediation guidance (including the explicit"registered-and-honestly-unbound is a first-class outcome; ⛔ do not bind a proof to a property
it does not author"), and names the new invariant in the success line.
Justification for including rather than proposing (the triage's default was propose): the
change is one line of condition plus its guidance text, in the same directory and the same
gate family as the card's own fix, and it adds no new validation surface. The census that
licenses it is this PR's own arithmetic — after the registration the orphan list is at zero,
so the gate starts green and only a genuinely NEW unregistered tag can red it. That is the same
"a check that starts at zero can be red" reasoning the
keyMention*half was switched on under,which sits three lines above it in the same condition.
It is a separate commit (
b884d56) on purpose: if the PM prefers the propose-only route,dropping that one commit leaves the card's registration fix intact and complete.
Files touched
packages/spec/scripts/liveness/proof-registry.mts— the registry entry (commit846750d)packages/spec/scripts/liveness/check-liveness.mts— the class gate (commitb884d56)No producer-side edit: the drift was registry-side.
proof-registry.test.tsneeded no change —its
unbound classes record an honest blockedReasoninvariant covers the new entryautomatically, and
BOUND_PROOF_PATHSis unchanged because the entry is unbound (its pinnedkey list would have had to change had it bound anything).
No changeset
packages/spec'sfileswhitelist is["dist","json-schema","liveness","prompts","llms.txt", "README.md","src/**/*.zod.ts","CHANGELOG.md","api-surface","spec-changes.json"]—scripts/isnot published, so nothing in this diff reaches a consumer.
skip-changesetapplied andconfirmed by read-back (labels now
["size/s","skip-changeset"]).Verification — all at head
b884d56pnpm --filter @objectstack/spec check:liveness✓ every governed-type property … every dogfood @proof: tag on disk is registered in proof-registry.mts …(orphan list empty)vitest run scripts/liveness/proof-registry.test.ts scripts/liveness/check-liveness.test.tsTest Files 2 passed (2)·Tests 62 passed (62)pnpm --filter @objectstack/spec typecheckcheck:test-typecheck: OK— andtsc -p tsconfig.scripts.json --listFilesconfirms both edited.mtsfiles are in the program (2 hits), so this is a measurement, not a green over unread sourcepnpm lint(full repo,eslint . --no-inline-config)pnpm check:nul-bytesOK (scanned 6921 text file(s) … no raw ASCII control bytes)bare-root-worklist --self-test,check:pm-dispatch-gatescheck:empty-state,check:strictness-ledger,check:variant-docs,check:merge-driver,check:page-declaration-shape,check:pm-governed-merges,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check-comment-mask-adoption,check-plugin-teardown-shape,docs-audit/check-affected-docsGate family derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackagainst the real changeset, not from the dispatch brief's list.
Reverse verification — the gate flip is load-bearing
Ablation: the registry entry removed (
git checkout BASE-COMMIT -- proof-registry.mts), mutationproved on disk before the reading (
git hash-objectmoved51066bf…→11f6368…, markergrep -c1 → 0), thencheck:livenessre-run:The same tree at the base commit — same orphan tag present, gate flip absent — exited 0
with
⚠ 1 unregistered dogfood proof tag(s). So the direction is a genuine warn→red flip andnot an artifact of the registration. Restore proved by observation, not exit code: blob back to
51066bf…, marker back to 1,git diff HEADempty andgit status --porcelainempty (indexclean too — no
MMfrom the checkout-from-ref). No build ordist/is involved:check:livenessruns
tsxdirectly over the.mtssources.Instrument disclosures
node scripts/check-dev-prereqs.mjsexits 1 here, reportingThe workspace is not built—67 of 67 workspace packages missing a
dist/entry point. That is a prerequisite not metin a fresh never-built worktree (AGENTS.md §9's first row), not a measurement of this diff:
the verdict is about whether
dist/exists at all and cannot be moved by a two-filescripts-only change. Recorded as NOT MEASURED rather than reported as a failure. CI builds
before it runs.
403 GitHub access is not enabled for this sessionfrom this seat, so the label went throughthe read → union → whole-set write path instead: labels read as
["size/s"](size-labeler),written back as the union
["size/s","skip-changeset"], and confirmed by read-back. Anearlier revision of this body said the label could not be applied — that was written between
the 403 and the successful fallback, and is corrected here rather than left standing.
angle-bracketed placeholder in the ablation command, and the sanitizer removed it after
storage, leaving
git checkout --. Respelled asBASE-COMMITabove rather than left to readas a command with a missing argument.
Generated by Claude Code