Skip to content

chore(spec): register the admin-platform-admin-standing dogfood proof tag, and red the drift that let it accumulate - #12549

Merged
huangyiirene merged 3 commits into
mainfrom
claude/issue-12216-proof-tag-registry
Aug 26, 2026
Merged

chore(spec): register the admin-platform-admin-standing dogfood proof tag, and red the drift that let it accumulate#12549
huangyiirene merged 3 commits into
mainfrom
claude/issue-12216-proof-tag-registry

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

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).

Producerpackages/qa/dogfood/test/admin-platform-admin-standing.dogfood.test.ts
declares // @proof: admin-platform-admin-standing at 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 tag
is already registered. No registered id is within a typo of it (admin-credential-lifecycle
and admin-route-nonadmin-refusal are 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 the
platform-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.

Registrypackages/spec/scripts/liveness/proof-registry.mts has no entry for it, so
KNOWN_PROOF_IDS does not contain it and check:liveness reported it as an orphan tag.

⇒ the registry lagged the dogfood tree. The tag is registered, unbound, with a
blockedReason rather than a manufactured binding: platform-admin standing is the ADR-0068 D2
identity resolution evaluated inside the auth plugin's route gate (runtime principal
resolution, no authorable metadata key whose live status it gates), and it is a breadth guard
over a derived route population besides — the admin-route-nonadmin-refusal /
permission-model-zoo shape, where binding any single ledger entry would misrepresent both
what 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. orphanProofs was
populated by scanOrphanProofs() and printed as a , but it was absent from the failed
condition
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 time
does not close a class whose signal nothing fails on.

The second commit adds report.orphanProofs.length (greater than zero) to the failed
condition, 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 (commit 846750d)
  • packages/spec/scripts/liveness/check-liveness.mts — the class gate (commit b884d56)

No producer-side edit: the drift was registry-side. proof-registry.test.ts needed no change —
its unbound classes record an honest blockedReason invariant covers the new entry
automatically, and BOUND_PROOF_PATHS is unchanged because the entry is unbound (its pinned
key list would have had to change had it bound anything).

No changeset

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"]scripts/ is
not published, so nothing in this diff reaches a consumer. skip-changeset applied and
confirmed by read-back (labels now ["size/s","skip-changeset"]).

Verification — all at head b884d56

check verdict line
pnpm --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.ts Test Files 2 passed (2) · Tests 62 passed (62)
pnpm --filter @objectstack/spec typecheck check:test-typecheck: OK — and tsc -p tsconfig.scripts.json --listFiles confirms both edited .mts files are in the program (2 hits), so this is a measurement, not a green over unread source
pnpm lint (full repo, eslint . --no-inline-config) exit 0 — no narrowing, no declaration owed
pnpm check:nul-bytes OK (scanned 6921 text file(s) … no raw ASCII control bytes)
bare-root-worklist --self-test, check:pm-dispatch-gates exit 0 — the two convention-triggered families a gate-script edit incurs
check: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-docs all exit 0

Gate family derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
against 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), mutation
proved on disk before the reading (git hash-object moved 51066bf…11f6368…, marker
grep -c 1 → 0), then check:liveness re-run:

ABLATED-EXIT=1
✗ 1 unregistered dogfood proof tag(s) — add to proof-registry.mts:

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 and
not an artifact of the registration. Restore proved by observation, not exit code: blob back to
51066bf…, marker back to 1, git diff HEAD empty and git status --porcelain empty (index
clean too — no MM from the checkout-from-ref). No build or dist/ is involved: check:liveness
runs tsx directly over the .mts sources.

Instrument disclosures

  1. node scripts/check-dev-prereqs.mjs exits 1 here, reporting The workspace is not built
    67 of 67 workspace packages
    missing a dist/ entry point. That is a prerequisite not met
    in 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-file
    scripts-only change. Recorded as NOT MEASURED rather than reported as a failure. CI builds
    before it runs.
  2. Labelling took the declared fallback. The additive labels endpoint answered
    403 GitHub access is not enabled for this session from this seat, so the label went through
    the 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. An
    earlier 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.
  3. A platform body mutation was caught on read-back: the first revision contained an
    angle-bracketed placeholder in the ablation command, and the sanitizer removed it after
    storage, leaving git checkout --. Respelled as BASE-COMMIT above rather than left to read
    as a command with a missing argument.

Generated by Claude Code

@github-actions

github-actions Bot commented Aug 26, 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 52a98238876fd5183ff087ce6cca1adb195a9636packageMentionDocs.

@huangyiirene huangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tooling labels Aug 26, 2026 — with Claude

Copy link
Copy Markdown
Collaborator Author

PM review — ACCEPT (session_01E5LFCYBJ3q2s6yW6oMLxwy, domain:spec seat R7, contract review performed at the review tier as the compensating control for an opus-built PR).

Contract verdict: Clause-② re-checked against the real diff — still no on both limbs. Scripts-only; the published @objectstack/spec surface is untouched (the files whitelist argument in the body is correct — scripts/ never ships). The one behaviour that does move is repo-CI's own accept/reject (orphan proof tags now red), which is exactly what the card's class needed.

Both commits kept, including the gate commit b884d56:

  • Registration 846750d is the honest shape: bound:false with a blockedReason that names what the proof guards instead (ADR-0068 D2 principal resolution + derived-population breadth guard) rather than a manufactured binding. Drift-direction evidence (producer names itself, its sibling, and no registered id within a typo) is the read-both-sides work the triage asked for.
  • The gate flip is the load-bearing half: [finding] check:liveness warns on 11 unregistered dogfood proof tags — proof-registry.mts lags the dogfood test tree #10773's repair registered instances while orphanProofs stayed absent from the failed condition — the recurrence mechanism this card itself is an instance of. Zero-census start, ablation-proved warn→red direction (base tree with the same orphan exits 0), one line of condition in the same gate family. That satisfies the tiny-and-same-surface bar for including rather than proposing, and the commit split preserved my option to drop it — declined.
  • Surface note for the record: check-liveness.mts extends the claim comment's named file but stays inside the dispatched packages/spec/scripts/liveness/** surface; no in-flight overlap (docs content: the 38 generated reference pages still render two <h1> — the heading comes from a spec JSDoc header via build-docs.ts #12249 touches build-docs/check-docs-single-h1 only).

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 b884d56, then ready-flip + auto-merge, queue-entry verified by ls-remote.


Generated by Claude Code

@huangyiirene
huangyiirene marked this pull request as ready for review August 26, 2026 10:13
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 26, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32957180001 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/6) — 失败步骤: Run this shard's tests

    @objectstack/lint:test:  FAIL  src/lint-startup-registry-verdict.corpus.test.ts [ src/lint-startup-registry-verdict.corpus.test.ts ]
      ↳ 失败原因: @objectstack/lint:test: Error: ENOENT: no such file or directory, stat '/home/runner/work/objectstack/objectstack/packages/platform-objects/tsup.config.bundled_akw7tdc8uzr.mjs'
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

跨 PR 相同签名(24h,按失败测试文件聚合):

  • src/lint-startup-registry-verdict.corpus.test.ts — 24h 窗口内只有本 PR 撞到过,暂不汇总(再有一个不同 PR 撞到就会自动开汇总 issue)。
  • ⚠️ 24h 评论账本没读完(超过 5 页仍未读到窗口尽头),所以上面的「不同 PR 数」是下界,不是全量。

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 0 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@huangyiirene
huangyiirene enabled auto-merge August 26, 2026 10:41
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 26, 2026
Merged via the queue into main with commit b566f83 Aug 26, 2026
34 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-12216-proof-tag-registry branch August 26, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] unregistered dogfood proof tag admin-platform-admin-standing — pre-existing check:liveness warning, recurrence of #10773's class

2 participants