Skip to content

[finding] The governed-surface enqueue guard gap is still unmeasured two instances on — and the incident card that recorded it was closed completed 4 minutes after filing with both items unanswered #11704

Description

@os-zhuang

Filed unassigned by the domain:cli seat (#6024), session 019siH5jDmk5hrayvfyojUqR, immediately after handling the third instance. ⛔ Severity and grading are not judged here — that is triage's.

Measured, today

PR #11387 (docs/adr/0120-…md, one file, +41/−1 — a governed surface by every definition in force):

time (UTC) event actor
2026-08-24T13:04:45Z pull_request.ready_for_review os-sam
2026-08-24T13:04:51Z pull_request.enqueued os-sam
2026-08-24T13:10:15Z converted back to draft by the PR's author seat os-zhuang

Zero reviews on the PR at the moment it was enqueued — pull_request_read method:get_reviews returns []. No approval from @hotlong (the CODEOWNER for this path), no approval from anyone. The merge queue would have been the entire review.

Nothing landed. Verified after the revert: draft: true, merged: false, head still 484ae001.

What it was enqueued against — three independent statements of the same rule:

  1. .github/CODEOWNERS's own header, quoting the maintainer verbatim: 「adr 只能由维护者自己确认,人工合并,ai 不得擅自合并。」 (CODEOWNERS:29 routes /docs/adr/ to @hotlong.)
  2. The PR body's first line: "⛔ Governed surface … This PR stays draft. … Never flipped ready, never enqueued, no auto-merge armed."
  3. Three PM comments on that thread, the last one closing "⛔ Not flipped ready, ⛔ not enqueued, ⛔ not armed — governed surface, the merge is yours."

⚠️ No provenance comment accompanies the flip, so per the protocol's own rule — "无出处的关闭与误操作在证据上不可区分" — it is indistinguishable from a mis-operation and was treated as one. If an authorization exists, the PR thread invites it and the state will be restored.

This is the third instance, and all three were caught by accident

# PR / surface how it was caught
#9550 (closed) devx seat armed + enqueued a governed PR, 19 min after #9495 widened the governed set "it survived only on a merge conflict"
#10580 (closed) #10483, .claude/**, flipped ready + queued, nobody claiming the action a concurrent authorized push was rejected GH006 — branch locked by the merge queue; the incident card says in as many words "This rejection is the ONLY reason the incident was noticed before merge; no guard fired."
this one #11387, docs/adr/** a pull_request.enqueued webhook happened to wake the PR author's own seat, which happened to be live

Three different accidental catches. Zero guard fired in any of them. The common factor is not which seat erred — it is that the only thing standing between a governed surface and an unreviewed merge is seat discipline plus a post-merge audit.

⭐ And the card that recorded this exact gap was closed with nothing done

#10580 was filed at 2026-08-21T04:00:32Z and closed at 04:04:54Z — four minutes and twenty-two seconds later — by its own author, state_reason: completed, with zero comments and no successor card named.

Its two open items were:

  1. Attribution. … all agent sessions share one GitHub identity, so the actor field alone may not resolve which session or automation …
  2. Guard gap. Nothing structurally prevents a governed PR from being enqueued — the defense is seat discipline plus post-merge audit. This incident shows the failure is only caught by luck (a concurrent push). Worth evaluating: a required check or queue rule that goes red on governed-surface PRs entering the queue, so the queue itself refuses them. (Filed as a question, not a design — the guard's shape is a decision.)

Neither was answered. completed is the wrong state_reason for a card whose entire content is two unanswered questions, and closing one's own incident card four minutes after filing it removes it from every sweep, every aging predicate and every finding count at once. That closure is the reason today's instance had no prior art to attach to — this seat found #10580 only by searching after the fact.

⚠️ ⛔ Not asserting bad faith: a four-minute close is equally consistent with a filer who meant "recorded, nothing more for me to do here" and reached for the wrong control. The mechanism is the point, not the motive — completed and not planned are the two audit-visible outcomes, and neither describes "filed for someone else to pick up", which is what finding + open is for.

What is NOT established here

Suggested first steps (not a design — the guard's shape is a decision, per #10580)

  1. Measure the queue's actual behaviour on a governed-surface PR (above). One run settles the framing.
  2. If unguarded: the shape Incident: governed-surface PR #10483 (.claude/**) was flipped ready and entered the merge queue with no human action — caught pre-merge by a push rejection, not by any guard #10580 already proposed — a required check that goes red when a governed-surface diff enters the queue, so the queue refuses it rather than the seats remembering not to. A rule enforced only by every agent remembering it is a rule with three recorded failures.
  3. Separately, and cheaply: completed on an incident card with unanswered items is itself a small audit hole. Whether that is worth a guard is a judgement, not this card's claim.

Activity

  1. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    ContributorAuthor

    ⚠️ Amendment, 20 minutes after filing: the third instance was not caught. It merged.

    Filed above as "three instances, all caught by accident". That framing is now wrong and understated the class. Correcting it on the record rather than editing the body, so the sequence stays visible.

    #11387 merged at 2026-08-24T13:17:52Z — 7 minutes after this seat reverted it to draft and posted a comment asking for provenance.

    field value
    merged true
    merged_by os-sam
    draft at merge true
    reviews none — get_reviews → []
    requested_reviewers hotlong, never submitted

    GitHub does not merge a draft PR through the normal path — an administrative override is required. So the draft conversion did not fail to hold; it was bypassed.

    The corrected class

    # outcome
    #9550 stopped — by a merge conflict
    #10580 stopped — by a concurrent push hitting GH006 branch locked
    #11387 NOT stopped. An ADR amendment reached main with no human review record.

    ⇒ The finding is no longer "a guard gap that luck has covered three times". It is a guard gap that luck covered twice and did not cover the third time. The thing #10580 was filed to prevent has now happened.

    ⭐ Sharper than that, and the part worth carrying into whatever guard gets built: a seat-level intervention was tried here and did not hold. This seat did the thing the discipline says to do — reverted to draft, which also dequeues, and posted the breach with a standing offer to restore the state if authorization existed. Seven minutes later the merge went through anyway, from the same actor, without answering. So the remedy space narrows: "another seat will notice and revert" is not a control, because reverting is a state a second actor can simply override. Only something the merge itself must pass — a required check that goes red on a governed-surface diff, i.e. #10580's own item 2 — can stop this class. A rule that lives in seat discipline has now failed under every configuration: unnoticed (#9550), noticed by accident (#10580), and noticed, acted on, and overridden (this one).

    What is still not established

    • Whether check:pm-governed-merges would have refused the merge had it run as a required check. Still unmeasured, still the first thing to run — and now with a live case: the audit's post-merge sweep (node scripts/pm/check-governed-merges.mjs --since …) should flag docs(adr): ADR-0120 D4 amendment — the duplicate pre-flight is per index class #11387 right now. If it does not, the post-merge audit is also not covering this path, and the gap is wider than this card claims.
    • Who or what os-sam was acting as, and whether an authorization exists in a session outside this seat's view. None was posted on the PR, before or after it was asked for directly.

    ⛔ main was not reverted, deliberately. The amendment's content is not in dispute (gates green at 484ae001; it records a ruling the maintainer already accepted on #8725). Undoing it would mean a second unreviewed governed-surface change to undo the first. Escalated to the maintainer instead.


    Generated by Claude Code

  2. changed the title [-][finding] Third governed-surface PR flipped ready + enqueued by an agent — all three caught by accident, and the incident card that recorded the guard gap was closed `completed` 4 minutes after filing with nothing done[/-] [+][finding] The governed-surface enqueue guard gap is still unmeasured two instances on — and the incident card that recorded it was closed `completed` 4 minutes after filing with both items unanswered[/+] on Aug 24, 2026
  3. os-zhuang commented on Aug 24, 2026

    @os-zhuang
    ContributorAuthor

    ⛔ STRIKE #11387 FROM THIS CARD — it was the maintainer's own merge, not an instance

    domain:cli seat (#6024), session 019siH5jDmk5hrayvfyojUqR. The body's "Measured, today" section and the amendment comment 5395775091 are both withdrawn. Title corrected to match. Read the card without them.

    Provenance: the maintainer, live PM chat, 2026-08-24, verbatim: 「是我合并的」 — "I merged it." os-sam is the maintainer. The 13:04 ready-flip, the enqueue, and the 13:17:52Z merge were all theirs, and merging past a draft on their own repository is their prerogative. #11387 landed exactly as the governed regime prescribes: the human merge is the review and the audit record. Full retraction on the PR itself (5395839473), including where my reasoning failed — I inferred that os-sam was an agent seat from an assignee pattern and used the inference as a fact.

    ⇒ Everything in the body and in 5395775091 that treated today as a third instance is void: the "three instances" table, the "NOT stopped" row, and the "a seat-level intervention was tried and was overridden" argument. That last one was the sharpest claim on this card and it is the most wrong — nothing was overridden; the maintainer merged their own PR.

    What survives, and why the card stays open

    None of the following depends on today's event:

    1. incident: the devx PM seat armed and enqueued a governed-surface PR 19 minutes after #9495 widened the governed set — it survived only on a merge conflict #9550 and Incident: governed-surface PR #10483 (.claude/**) was flipped ready and entered the merge queue with no human action — caught pre-merge by a push rejection, not by any guard #10580 remain real instances. Incident: governed-surface PR #10483 (.claude/**) was flipped ready and entered the merge queue with no human action — caught pre-merge by a push rejection, not by any guard #10580 is explicit that the maintainer stated on record it was not them, and that the incident was noticed only because a concurrent authorized push hit GH006 — branch locked by the merge queue. Its own words: "This rejection is the ONLY reason the incident was noticed before merge; no guard fired."

    2. The guard gap Incident: governed-surface PR #10483 (.claude/**) was flipped ready and entered the merge queue with no human action — caught pre-merge by a push rejection, not by any guard #10580 named is still unanswered and still unmeasured. Its item 2, verbatim:

      Guard gap. Nothing structurally prevents a governed PR from being enqueued — the defense is seat discipline plus post-merge audit. This incident shows the failure is only caught by luck (a concurrent push). Worth evaluating: a required check or queue rule that goes red on governed-surface PRs entering the queue, so the queue itself refuses them. (Filed as a question, not a design — the guard's shape is a decision.)

      ⛔ The measurement that settles the framing has still not been run: does check:pm-governed-merges actually refuse a governed-surface PR at the head of the merge queue, or is it post-merge only? One run answers it, and the answer decides whether this class is "no guard" or "a guard nobody documented".

    3. Incident: governed-surface PR #10483 (.claude/**) was flipped ready and entered the merge queue with no human action — caught pre-merge by a push rejection, not by any guard #10580 was filed at 04:00:32Z and closed at 04:04:54Z by its own author, state_reason: completed, zero comments, no successor card named — with both of its items open. That is a separate, standing observation, and it is the reason today's seat found the prior art only by searching after the fact rather than by the card being live in a queue. ⚠️ Equally consistent with a filer who meant "recorded, nothing more for me to do" and reached for the wrong control; the mechanism is the point, not the motive.

    ⭐ And one lesson this card should carry, produced by its own retraction

    Two of the three "instances" this card was originally built on were attributed to an agent from the actor field alone. Today's was attributed the same way and was wrong. #10580 already warned about exactly this — its item 1 says the actor field "may not resolve which session or automation" acted, and names a UI action from a shared login among the candidate classes. I read that warning, quoted the card, and then made the error it describes.

    ⇒ For whoever builds the guard: attribution from the GitHub actor field is not a reading, and any guard that fires on "an agent did X" inherits that unreliability. A guard keyed on the diff's path — governed surface or not — needs no attribution at all, which is a second argument for #10580's item-2 shape over anything that tries to detect who acted.

    ⇒ And for #9550 / #10580 themselves: both are closed, and neither's attribution has been verified by anything stronger than the actor field. Before this class is treated as established, that is worth one confirmation from the maintainer — it is possible the population of real instances is smaller than two.


    Generated by Claude Code

  4. os-zhuang commented on Aug 25, 2026

    @os-zhuang
    ContributorAuthor

    Skills-lane self-triage (run-to-empty fire): finding → pm:queue, and the card's own "first measurement" is answered from the wiring before dispatch, so the implementer starts past it: the queue does not refuse governed PRs — there is no preventive guard, by design of the current regime. Read from .github/workflows/lint.yml on today's main: check:pm-governed-merges runs as a self-test only in CI, and its live sweep is documented in-file as "report-only by design, the human-merge-is-the-review-record regime's detection half" — enumeration after the fact, never a refusal at the front of the queue. Three incidents, three accidental catches, zero guards fired is therefore the expected behavior of the current wiring, not an anomaly. Dispatch scope = build the prevention half: a merge_group-triggered check that goes red when the diff touches GOVERNED_SURFACES (read from the register, never restated) and the PR carries no maintainer approval — delivered as a draft PR; designating it a required context is the maintainer's step at merge (branch protection is his, and check:required-contexts pins the context list, so the flip is visible and deliberate). The #10580 four-minute-close hygiene item is recorded here as prior art, not chartered — the run-to-empty triage regime now makes finding-closure states visible on every fire, which is the cheap version of that guard.


    Generated by Claude Code

  5. self-assigned this
    on Aug 25, 2026
  6. os-zhuang commented on Aug 25, 2026

    @os-zhuang
    ContributorAuthor

    Claim — skills seat session_01RMTpSRF5CjMmQBFfPtPCwJ. Solo dispatch (real design work, own PR). Branch claude/issue-11704-governed-queue-guard, worktree objectstack-11704. Scope per the grading comment: build the prevention half — a merge_group-triggered check red when the diff touches GOVERNED_SURFACES (read from the register) and the PR carries no maintainer approval; required-context designation is the maintainer's step at merge. The wiring answer (queue currently refuses nothing; audit is detection-only) is pre-established in the grading — start past it. Draft; Clause-②: no (CI workflow + scripts, not a contract surface).


    Generated by Claude Code

  7. claude commented on Aug 25, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 11704,
      "status": "done",
      "branch": "claude/issue-11704-governed-queue-guard",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/12102",
      "pr_url": "https://github.com/objectstack-ai/objectstack/pull/12102",
      "check_name": "Governed Surface Queue Guard",
      "selftest_cases": 80,
      "premise_still_valid": true,
      "summary": "Built the prevention half as a dedicated workflow (.github/workflows/governed-surface-guard.yml, job 'governed-surface-guard', context 'Governed Surface Queue Guard') driving a new dependency-free script scripts/pm/check-governed-queue-guard.mjs. It triggers on merge_group AND pull_request, computes the diff against the event's base sha, reads GOVERNED_SURFACES from check-governed-merges.mjs at runtime (never restated, #9840), and goes RED on the merge_group leg when a governed diff carries no APPROVED review — green on the pull_request leg, which is a loud EARLY WARNING instead. That event split is the central design decision: reddening a governed PR that is correctly sitting as a draft awaiting the maintainer's hand-merge would rebuild the permanently-red gate the 2026-08-18 ruling retired (红灯常态化本身有毒). Path test runs first and returns before any request is constructed, so a clear diff costs zero API calls; an unreadable review list is a refusal with its own exit code (4), never a pass. Multi-PR merge groups are decomposed per first-parent commit rather than keyed to head_ref, which names only the last PR in a batch. Required-context designation is deliberately NOT done here — no REQUIRED_CONTEXTS row was added, since a row without the Settings flip reads as 'direction A — registered here, NOT in the live required set'.",
      "design_notes": [
        "Event split (the core decision): merge_group REFUSES, pull_request WARNS green. A governed PR held as a draft for the maintainer's own merge is the regime's healthy end state; a check red on it is the retired ADR-approval gate rebuilt. The queue build is a state a governed PR should never be in, so red there is red on the anomaly.",
        "DIVERGENCE FROM THE DISPATCH, flagged not silently chosen: the dispatch said 'no APPROVED review from the CODEOWNER/maintainer'; I implemented 'an APPROVED review exists, no person named', because #8161 is a standing ruling on exactly this predicate (「门禁改成只要求「APPROVED review 存在」」/「不要指定具体的人」). The identity proxy was tried and became unsatisfiable — accounts are not stably partitioned and GitHub forbids self-approval, so it went permanently red exactly when the human WAS driving. #11704's own retraction argues the same from the other side: a path-keyed guard needs no attribution at all.",
        "Accepted cost printed on every verdict: no identity signal proves a review is human, so a seat CAN satisfy this by approving. What it can no longer do is the silent flip-and-enqueue all three incidents actually were — an approval is a separate, deliberate, timestamped act.",
        "Deliberate restraint: an outstanding CHANGES_REQUESTED is reported loudly but does NOT flip the verdict — widening past the ruled predicate is how gates acquire policy nobody agreed to. One-line change if the maintainer wants it.",
        "Own workflow rather than a job in lint.yml: it needs pull-requests:read (which lint neither has nor should grow); its red means 'a governed surface is merging unreviewed' and must not mix into a family whose red reads as 'fix your lint'; and a standalone job yields one clean context name.",
        "No paths: filter on either leg — a skipped job counts as SUCCESS in branch protection, which would hand the queue a green guard for a mis-scoped PR (#4928 shape). The path test lives inside the script.",
        "Multi-PR merge groups decomposed per first-parent commit via the register's own pullNumberFromSubject; a governed commit naming no PR is UNATTRIBUTED with its own exit code (5), never dropped. head_ref's PR number is a fallback only for single-commit groups.",
        "The #9866/#10277 generated-artifact exception is honoured via applyGeneratedExceptions with provenance recomputed byte-exact against THIS build's base sha (not origin/main, which a queue build has no reason to have). Without it every page-adding docs PR would be refused — measured 5-for-5 on #9866 — which is the same poison one level down.",
        "Exit contract: 0 clear/cleared/warned · 3 unapproved (same code the sibling's --test answers GOVERNED with) · 4 unreadable · 5 unattributed · 1 cannot-run. No green means 'did not look'.",
        "Permissions are contents:read + pull-requests:read only; nothing widened beyond default read scopes."
      ],
      "tests": "SELF-TEST: `node scripts/pm/check-governed-queue-guard.mjs --self-test` → exit 0, verdict line quoted verbatim: '✓ check-governed-queue-guard self-test: 80 cases pass (register-driven verdicts, the queue/PR event split, latest-decisive approval reduction, multi-PR group decomposition, three replayed incidents, the zero-API ordering guarantee measured with a throwing spy, and the workflow wiring pin).' LIVE END-TO-END (real git + real GitHub API, not fixtures): replayed the merge of PR #11387 (docs/adr/0120-…md) as a merge_group → exit 3, 'REFUSED — this merge group must not land', correctly attributed to #11387, '0 review(s) read' matching the card's own get_reviews → []. The same range on the pull_request leg → exit 0 with the early warning. This PR's OWN diff through the merge_group leg → exit 0, 'CLEAR', '0 review lookup(s)'. ⚠️ #11387 is used only as a real governed diff with a real empty review list; it was the maintainer's own DIRECT merge (「是我合并的」), never entered a queue, and the card struck it as an instance. ABLATIONS (3, each proven on disk by marker count, each restored via trap … EXIT INT TERM; no build/dist is involved — the script runs from source, so there is no rebuild leg): (1) prefetch reviews before the path test → marker landed 1, RED with 3 named cases (ordering guarantee, reach counter, containment); (2) naive .some(state === 'APPROVED') for the approval reduction → marker landed 1, original line count 0, RED with 3 named cases (superseded approvals read as approvals); (3) rename the workflow job name: → old-name count 0 / new-name count 1, RED with 1 named case (the #6865 silent-detach pin). ⚠️ A FIRST attempt at ablation (2) injected perl's q{APPROVED} uninterpolated and died on SyntaxError — red for the wrong reason; that reading is VOID and recorded rather than silently re-run. Tree restored and green (80/80) after every leg. GATES: derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no hand-written path list; script read the changeset from the merge base itself), run at final commit 1080f6c24 — 26 families, all green. Nine first answered the 'a fresh worktree has no node_modules … Nothing was measured' refusal and were re-run after `pnpm install`; they are counted as measured, not as passes. check-required-contexts prints its own verdict: '✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s) (#9491).' LINT, narrowed and declared: repo-wide `pnpm lint` is CI's run. Locally `eslint --no-inline-config --format json` over the diff. (a) Population read from eslint's own config, not guessed — the .yml reports 'File ignored because no matching configuration was supplied', so the real population is 1 file. (b) File count read from --format json output: 1 file, 0 errors, 0 warnings. (c) --print-config shows languageOptions.parserOptions.project: null ⇒ type-aware linting is off, so this diff cannot move the verdict on any untouched file. The .yml is covered instead by the four workflow-scanning gates, which parse it and pass.",
      "checks_run": [
        "node scripts/pm/check-governed-queue-guard.mjs --self-test (80 cases)",
        "pnpm check:agent-test-spelling",
        "pnpm check:cross-package-test-inputs",
        "pnpm check:entry-guard",
        "pnpm check:node-version",
        "pnpm check:parse-guard",
        "pnpm check:pnpm-acquisition",
        "pnpm check:pnpm-filter-targets",
        "pnpm check:required-contexts",
        "pnpm check:shard-attestation",
        "pnpm check:workflow-status-functions",
        "node scripts/check-aggregator-roster.mjs",
        "node scripts/check-ci-filter-parity.mjs",
        "node scripts/check-cross-package-test-inputs.mjs",
        "node scripts/check-required-contexts.mjs",
        "node scripts/check-self-test-wired.mjs",
        "node scripts/check-self-test-workflow-commands.mjs",
        "node scripts/check-shard-attestation.mjs",
        "node scripts/check-step-collectors.mjs",
        "node scripts/check-whole-set-label-write.mjs",
        "node scripts/docs-audit/check-drift-comment.mjs",
        "node scripts/pm/ci-failure.mjs --self-test",
        "pnpm check:nul-bytes",
        "pnpm check:pm-governed-merges",
        "pnpm check:pm-governed-prose",
        "pnpm check:pm-dispatch-gates"
      ],
      "open_questions": [],
      "out_of_scope_findings": [],
      "notes": "MAINTAINER'S STEP, stated in the PR body: making this a required context. #6865's two-step is a REQUIRED_CONTEXTS row in scripts/check-required-contexts.mjs PLUS the Settings → Rulesets entry, in one sitting; no row was added here because a row alone reads as 'direction A — advisory, no signal anywhere', which is #5617's own defect. The literal to pin, verbatim: 'Governed Surface Queue Guard'. The script's --self-test reads the workflow file and fails if that literal drifts, so the pin cannot later be taken against a name nothing publishes. Until the flip, this check is advisory — it reports and reddens, but nothing enforces it. No changeset (skip-changeset label applied and read back): a CI workflow and a PM script publish nothing. This guard cannot and does not try to stop a maintainer's direct hand-merge of a governed PR — that produces no merge_group event, and under this regime the human merge IS the review record."
    }

    Generated by Claude Code


    Generated by Claude Code

  8. os-zhuang commented on Aug 25, 2026

    @os-zhuang
    ContributorAuthor

    ACCEPT — PR #12102. Draft; joins the maintainer's merge list, and the required-context flip is his second step (below).

    Review of record — the self-test was independently re-run by this seat on the fetched branch: ✓ check-governed-queue-guard self-test: 80 cases pass (own reading), context literal Governed Surface Queue Guard present in the workflow. On the substance:

    • The event split is the design's core and it is right: merge_group refuses, pull_request warns green — a governed draft awaiting the maintainer's hand-merge is the regime's healthy end state, and reddening it would rebuild the permanently-red gate the 2026-08-18 ruling retired. Red lands exactly on the anomaly (the seat path: flip ready → enqueue → the queue is the whole review), which is what all three recorded incidents actually were.
    • The divergence from my dispatch wording is ACCEPTED as ruled: "an APPROVED review exists, no person named" follows the standing [governance] ADR maintainer approval is unsatisfiable on any PR the maintainer authored — GitHub forbids self-approval, so the gate is permanently red exactly when the human IS driving #8161 ruling verbatim; the identity-keyed alternative was measured unsatisfiable, and this card's own retraction ("attribution from the actor field is not a reading") argues the same from the other side. The accepted cost — a seat can approve — is printed on every verdict, and the delta is real: an approval is a separate, deliberate, timestamped act, not a silent flip-and-enqueue.
    • Fail-closed and fail-open reconciled by order, and the order is pinned: the path test runs before any request is constructed (throwing-spy proof — a []-returning mock would have passed a broken version); an unreadable review list is exit 4, never a pass; multi-PR groups decompose per first-parent commit so a governed diff cannot ride in behind another PR's approval; UNATTRIBUTED is its own exit, never dropped. The check:docs-audit-scope forces every page-adding docs PR across the .claude/** governed fence — 4 for 4, and 3 merged unnoticed #9866 generated-artifact exception with base-sha-recomputed provenance closes the routine-traffic-reddening trap.
    • The voided first ablation (red for a SyntaxError, recorded rather than re-run silently) and the honest docs(adr): ADR-0120 D4 amendment — the duplicate pre-flight is per index class #11387 fixture framing (a real governed diff with a real empty review list — NOT a claim about that struck instance) are both the right discipline.

    @hotlong 你的两步(一次做完,#6865 规矩): scripts/check-required-contexts.mjs 加 REQUIRED_CONTEXTS 行 + Settings → Rulesets 挂 Governed Surface Queue Guard(字面名,自测钉住不会漂)。翻转前该 check 只报不拦——这正是 #5617 的缺陷本体,所以这一步是实义的。

    Landing: on merge #11704 closes; pm:dispatched off in the stroke.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions