Skip to content

[finding] settings lock 1: no gate pins permissions.deny to the MCP write-tool roster the charter's ACCEPT refusal names — declared vs enforced is reconciled by hand #18281

Description

@claude

Filed by the domain:skills execution PM seat, session session_01HZfg2AwVX191qCizp88gQr, at 2026-09-15T07:16Z, from the #18218 dev's out_of_scope_findings (report 5676241066). #18218 itself was one hand reconciliation: SKILL.md :98 / :602 declared update_pull_request closed while permissions.deny did not carry it, and nothing red.

The gap (measured by the #18218 dev on 681317c3)

What is asked (⛔ not asserted — the skills seat grades)

One gate (scripts/pm/check-settings-deny-roster.mjs with a --self-test, wired through check-self-test-wired.mjs and package.json, in the derived family for .claude/settings.json): read permissions.deny and assert that every mcp__github__* tool the charter classes as a content or enqueue write is present, with the roster declared ONCE (the gate's constant) and the prose lines pointing at it, not restating it. Which tools belong in the enqueue class is the maintainer's call on the decision card filed beside this one; the gate pins whatever roster stands.

Serial: scripts/pm/** + package.json + the wired ledger — free; touches no governed .md unless the prose must point at the constant (then rules layer). Grading (stand-in triage while the triage seat is VACANT): p3 · Task · pm:queue · domain:skills.


Generated by Claude Code

Activity

  1. added theissue type on Sep 15, 2026
  2. claude commented on Sep 15, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01HZfg2AwVX191qCizp88gQr (skills seat; claimed at 2026-09-15T07:44Z)
    Branch: claude/issue-18281-settings-deny-roster-gate
    Worktree: objectstack-issue-18281
    Domain: domain:skills
    File surface: scripts/pm/check-settings-deny-roster.mjs (new, with --self-test), package.json (one script line), .github/workflows/lint.yml (one step in Lint & Repo Gates), scripts/check-self-test-wired.mjs ledger entry if the wiring gate needs one, and the gate's own ROOT_DIR_WATCH_HINTS declaration so dispatch-gates.mjs derives it for .claude/settings.json (stop on breach; explain in the report — ⛔ no edit to .claude/**, the prose pointer lines are a later rules-layer card)
    Container & model: S, mode:subagent, model: default tier — dispatch-gates.mjs --tier names no mandate for scripts/pm/**, package.json or workflows; seat review at CONTRACT_REVIEW_TIER
    Clause-②: no
    Thread-read: none (the card carries no comment at claim time)
    Serial constraints cleared: scripts/pm/** free (PR #18279 touches check-skill-line-ratchet.mjs only); no open PR holds package.json's script block or the lint workflow's gate steps; batch 1/3 (PR #18279 is ACCEPTED and landing, no dev in flight); the roster the gate pins is the one on origin/main after PR #18276 lands (15 entries) — the gate reads the file, so it stays correct whichever way #18282 is ruled


    Generated by Claude Code

  3. claude commented on Sep 15, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 18281,
      "status": "done",
      "branch": "claude/issue-18281-settings-deny-roster-gate",
      "worktree": "/home/user/objectstack-issue-18281",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18285",
      "head_sha": "834621592533a62a6ba9ae7006b58740db059f05",
      "premise_still_valid": true,
      "summary": "One gate now holds `permissions.deny` in `.claude/settings.json` equal to the charter's content-write roster, declared once as CONTENT_WRITE_TOOLS in scripts/pm/check-settings-deny-roster.mjs. Both directions are asserted over the mcp__github__ namespace and only it: a roster tool missing from deny is red, and a denied mcp__github__ tool the roster does not declare is red as roster drift. The gate is wired through one package.json script line and one Lint & Repo Gates step, and its ROOT_DIR_WATCH_HINTS declaration puts it on the dispatch brief for any card editing the settings file. Nothing under .claude/** was edited and no changeset is owed.",
      "files_changed": [
        {
          "path": "scripts/pm/check-settings-deny-roster.mjs",
          "what": "NEW, 517 lines. The gate: the 15-tool roster declared once; denyList/verdict/rosterProblems/settingsPathFromArgv as pure exported functions; a --settings PATH flag; a --self-test with 32 cases over 7 declared batteries and a battery floor; exit codes 0/1/2/3 with 3 = PREREQUISITE NOT MET naming the path; ROOT_DIR_WATCH_HINTS declared as a literal array naming the one file it opens."
        },
        {
          "path": "package.json",
          "what": "one line: check:pm-settings-deny-roster = node ... --self-test && node ..., the form its check:pm-* neighbours use, placed beside check:pm-governed-prose."
        },
        {
          "path": ".github/workflows/lint.yml",
          "what": "one step in Lint & Repo Gates after 'Governed-surface prose pin': name quoted ('Settings deny-roster pin (#18281)'), run: pnpm check:pm-settings-deny-roster, no if:, no paths filter, with a comment saying why."
        }
      ],
      "gates": [
        {
          "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-aggregator-roster.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-aggregator-roster.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-ci-filter-parity.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-closing-keyword-parity.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-closing-keyword-parity.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-comment-mask-corpus.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-declaration-mirrors.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-declaration-mirrors.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-merged-branch-reaper-outcome.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-merged-branch-reaper-outcome.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-position-name-fold-loaders.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-position-name-fold-loaders.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-scripts-symbol-anchors.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-scripts-symbol-anchors.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-self-test-wired.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-self-test-wired.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-self-test-workflow-commands.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-self-test-workflow-commands.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-step-collectors.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-step-collectors.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-whole-set-label-write.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/check-whole-set-label-write.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/ci/scheduled-full-run.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/docs-audit/check-drift-comment.mjs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/pm/bare-root-worklist.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/pm/ci-failure.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "node scripts/report-test-timings.mjs --self-test",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:agent-test-spelling",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:bash32-floor",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:cli-command-ids",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:cross-package-test-inputs",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:declared-population-live",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:driver-memory-census",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:dts-closure",
          "exit": 3,
          "note": "NOT MEASURED (exit 3, PREREQUISITE NOT MET): reads built dist/, and this fresh worktree has none. Diff touches no package source."
        },
        {
          "command": "pnpm check:dual-build-cjs-loads",
          "exit": 3,
          "note": "NOT MEASURED (exit 3): same prerequisite — 96+ packages have no dist/ in this worktree."
        },
        {
          "command": "pnpm check:entry-guard",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:lean-entry-closure",
          "exit": 3,
          "note": "NOT MEASURED (exit 3): loads built entry points; self-test 22 cases passed first."
        },
        {
          "command": "pnpm check:manifest-repository-directory",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:merge-driver",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:node-version",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:nul-bytes",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:parse-guard",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:pm-settings-deny-roster",
          "exit": 1,
          "note": "THE LIVE READING, RED BY EXACTLY ONE NAME: self-test 32 cases pass, then the gate reds on `.claude/settings.json` not denying mcp__github__update_pull_request. That is the measured gap this gate exists to catch (PR #18276 has not landed), not a defect in this change. The roster was not shrunk and the settings entry was not added here."
        },
        {
          "command": "pnpm check:pm-widening-tells",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:pnpm-acquisition",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:pnpm-filter-targets",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:ratchet-remedy-authority",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:refd-timer-probe",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:required-contexts",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:select-gate-families",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:shard-attestation",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:sourcemap-no-sources-content",
          "exit": 3,
          "note": "NOT MEASURED (exit 3): reads built sourcemaps."
        },
        {
          "command": "pnpm check:stall-guard-budget",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:stall-guard-headroom",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:turbo-task-graph",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:type-check-coverage",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:type-check-debt",
          "exit": 3,
          "note": "NOT MEASURED (exit 3): --re-measure refuses without the built closure; check:type-check-coverage (same script, no --re-measure) ran green."
        },
        {
          "command": "pnpm check:watch-hint-literal",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:workflow-status-functions",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:workflow-step-name-quoting",
          "exit": 0,
          "note": "green"
        },
        {
          "command": "pnpm check:pm-dispatch-gates",
          "exit": 0,
          "note": "derived because this PR adds a gate source. Run detached per the dispatch (setsid nohup + tail --pid), 447.4s. Exit read from the two printed verdict lines ('check:pm-dispatch-gates --self-test: the exit contract holds in all three directions' and 'dispatch-gates self-test: 1730 cases pass') plus the absence of pnpm's ELIFECYCLE line — a detached run leaves no $? to capture."
        },
        {
          "command": "node scripts/pm/check-settings-deny-roster.mjs --self-test",
          "exit": 0,
          "note": "32 cases across 7 declared batteries (battery roster + floor idiom); fixtures only, no network."
        },
        {
          "command": "node scripts/pm/check-settings-deny-roster.mjs --settings SCRATCH/settings-with-18276.json",
          "exit": 0,
          "note": "THE GREEN READING: `.claude/settings.json` taken with `git show 79ee821e:.claude/settings.json` from origin/claude/issue-18218-deny-update-pull-request into a scratch path outside the tree. Prints '15 content-write tool(s) declared = enforced ... (15 mcp__github__ deny entr(ies), 0 outside this gate's population and ignored)'."
        },
        {
          "command": "node scripts/pm/check-settings-deny-roster.mjs --settings SCRATCH/settings-drift.json",
          "exit": 1,
          "note": "drift direction, end to end on a scratch copy with mcp__github__enable_pr_auto_merge appended: reds with the roster-drift wording. No tree file mutated."
        },
        {
          "command": "node scripts/pm/check-settings-deny-roster.mjs --settings SCRATCH/nope.json",
          "exit": 3,
          "note": "PREREQUISITE NOT MET path, naming the file."
        },
        {
          "command": "node --stack-size=4000 node_modules/eslint/bin/eslint.js scripts/pm/check-settings-deny-roster.mjs",
          "exit": 0,
          "note": "0 errors, 0 warnings; --format json reports 1 file linted. Narrowing declared: eslint.config.mjs enables no type-aware linting for this population (no parserOptions.project), so this diff cannot move the verdict on a file it does not touch; the repo-wide sweep is CI’s."
        },
        {
          "command": "node scripts/pm/dispatch-gates.mjs --commands .claude/settings.json",
          "exit": 0,
          "note": "DERIVATION PROOF: 13 command(s), 6 matched by path, including pnpm check:pm-settings-deny-roster. Same invocation on the merge base derived 12 command(s), 5 matched by path."
        },
        {
          "command": "node scripts/pm/dispatch-gates.mjs --ran SCRATCH/ran.list",
          "exit": 0,
          "note": "VERDICT LINE: ✓ dispatch-gates --ran: 63 derived famil(ies) accounted for — 58 run, 5 NOT-MEASURED (5 DERIVED from a recorded exit 3). 0 UNRUN."
        }
      ],
      "assumptions_verified": [
        {
          "assumption": "the roster of 15 is the charter's content-write class",
          "verdict": "true, with one qualification stated rather than smoothed",
          "evidence": "`.claude/settings.json` on origin/main (fe0ae5c1) carries exactly 14 mcp__github__ deny entries, and PR #18276's hunk (79ee821e) adds mcp__github__update_pull_request as the 15th, in position 3 — the roster is those 15, no more and no fewer. QUALIFICATION: no surface in the tree ENUMERATES that class; SKILL.md's ACCEPT refusal names it by pointing at the deny list, which is precisely the hand reconciliation this card is about. So the roster's authority is the settings file plus PR #18276, and the gate's constant is now the first enumeration of it anywhere. The enqueue pair is out (rest-channel.md still names MCP update_pull_request and enable_pr_auto_merge as a fallback channel; #18282 carries the maintainer's decision)."
        },
        {
          "assumption": "nothing else reads the deny list's membership",
          "verdict": "true",
          "evidence": "`git grep -n 'permissions\\.deny' -- scripts/` returns two hits, both inside comments (check-skill-line-ratchet.mjs, label-write.mjs). Of the 8 files under scripts/ and .claude/hooks that name settings.json, none reads the deny array: check-harness-current.mjs declares it as a PATH for harness freshness; guard-main-checkout*.sh and guard-governed-enqueue.selftest.sh grep for hook registration and the two enqueue matchers; check-governed-merges.mjs classifies the path; check-doc-authoring.mjs exempts it. `git grep -l mcp__github__` outside the settings file: guard-governed-enqueue.sh (a case over two enqueue tool names, its own mechanism, not a read of deny), its self-test, platform-readings.md (prose) and check-half-states.mjs (prose about transports). Reverting the #18218 entry still moves zero diagnostics anywhere but in the new gate."
        },
        {
          "assumption": "ROOT_DIR_WATCH_HINTS makes dispatch-gates derive the gate for .claude/settings.json",
          "verdict": "true, measured both sides",
          "evidence": "`node scripts/pm/dispatch-gates.mjs --commands .claude/settings.json` on the merge base 9fa9955a: 12 command(s), 5 matched by path, no such gate. On this branch at 83462159: 13 command(s), 6 matched by path, `pnpm check:pm-settings-deny-roster` listed. check:watch-hint-literal and check:declared-population-live both green, so the declaration is a literal the extractor admits and its population reaches the tree."
        },
        {
          "assumption": "PR #18276 has not landed, so the live gate reads red by exactly one name",
          "verdict": "true at report time",
          "evidence": "GET /pulls/18276 -> state open, draft true, merged false. origin/main at fe0ae5c1 still carries 14 deny entries. The live run names exactly mcp__github__update_pull_request and nothing else."
        },
        {
          "assumption": "check-self-test-wired.mjs needs a ledger entry for the new script",
          "verdict": "false — the condition did not fire",
          "evidence": "`node scripts/check-self-test-wired.mjs` and its --self-test are both green with no edit: the new script is named by a workflow step through the root package.json alias, and that alias runs its --self-test, which is exactly what the gate asks for. SELF_TEST_RUN_OTHERWISE was not touched."
        }
      ],
      "deviations": [
        "scripts/check-self-test-wired.mjs was NOT edited. The dispatch made it conditional ('only if its ledger needs an entry'); the gate is green as shipped (see assumptions_verified), so the condition did not fire.",
        "The gate gained a `--settings PATH` flag, which the dispatch offered as acceptable. It is what makes the green reading of PR #18276's hunk reproducible without mutating any tree file.",
        "ROOT_DIR_WATCH_HINTS here names ONE FILE (.claude/settings.json) rather than a directory subtree, under the name the dispatch and the claim comment both specified. `.claude/**` would place this gate on every agent/hook card, which the derivation's own docs call a fabricated lead; the single-file spelling under this name follows check-tenant-audit-census.mjs, and the exact-file population idiom follows check-tenant-chokepoint.mjs. A docblock on the constant says so.",
        "The workflow step name is quoted AND carries the card number, per the dispatch and the repo's step-name style; check:workflow-step-name-quoting is green either way.",
        "pnpm check:pm-dispatch-gates ran detached as instructed, so its exit code is read from its two printed verdict lines and the absence of pnpm's ELIFECYCLE line rather than from a captured $?. Stated rather than presented as a captured code.",
        "Five derived families are recorded NOT MEASURED (exit 3, build prerequisite) instead of being made green by a full `pnpm build`: this diff touches no package source and no dist/, and a full build in a shared container is exactly the heavy serial work the resource discipline reserves. CI builds before those steps."
      ],
      "out_of_scope_findings": [
        "noted, not filed: `.claude/skills/pm-dispatch/references/rest-channel.md` still names MCP `update_pull_request` as a fallback channel while the charter's ACCEPT refusal treats it as shut. Carrier: PR #18276 already edits that exact line, so it is that PR's to settle, not a new card.",
        "noted, not filed: `.claude/hooks/guard-governed-enqueue.sh` hard-codes `mcp__github__enable_pr_auto_merge` and `mcp__github__merge_pull_request` in a case arm — a second enumeration of tool names in the tree. It answers a different question (blocking the enqueue act) and carries its own self-test, so it is not drift against this roster; whether the two enumerations should meet is downstream of #18282. Carrier: whoever lands #18282.",
        "noted, not filed: the charter enumerates the content-write class nowhere in prose — it points at the deny list. The prose lines that should now point at CONTENT_WRITE_TOOLS (SKILL.md and rest-channel.md) are the rules-layer card the dispatch already reserved. Carrier: that card."
      ],
      "open_questions": [],
      "mcp_calls": "0 — no MCP GitHub tool was called in this run, read or write. Every GitHub read and write went through the REST proxy with curl and $GITHUB_TOKEN, or through scripts/pm/label-write.mjs.",
      "api_writes": "3 REST proxy writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR 18285); POST /repos/objectstack-ai/objectstack/issues/18285/labels (skip-changeset, through scripts/pm/label-write.mjs, HTTP 200, read-back step 4 MATCHES the target: size/l, skip-changeset); POST /repos/objectstack-ai/objectstack/issues/18281/comments (this report). Plus 2 git pushes on the feature branch (empty-branch route probe, then the one commit). No PATCH of any body, no MCP write tool.",
      "session": "session_01HZfg2AwVX191qCizp88gQr — the harness-stamped id of the dispatching skills seat. A subagent has no own session_01... id, so this is the parent's, as the report contract prescribes.",
      "timings": "worktree + pnpm install --offline --frozen-lockfile 4.9s; 62 derived families run serially in 4 foreground batches, 208s total (longest: check-comment-mask-corpus 49s, check-self-test-workflow-commands 33s); pnpm check:pm-dispatch-gates 447.4s detached; dispatch-gates derivations ~13s each. No verify-lock slot was taken — check:* gates do not route through it.",
      "tests": "The gate's own instrument is its --self-test (32 cases, 7 batteries, fixtures only). Both live readings recorded above: red by one name on this tree, green on PR #18276's settings hunk. The drift direction and the exit-3 prerequisite path were each exercised end to end on scratch copies. Full derived union reconciled: 63 derived, 58 run, 5 NOT MEASURED, 0 unrun. No ablation of a tree file was performed and none is owed: the gate is new, its failure is demonstrated by the live red and by the scratch-copy drift run, and no existing gate's rule was changed."
    }

    Generated by Claude Code

  4. claude commented on Sep 15, 2026

    @claude
    ContributorAuthor

    ACCEPT (serial — lands after PR #18276) — skills seat, session session_01HZfg2AwVX191qCizp88gQr, 2026-09-15T08:15Z. Report 5676927844 on PR #18285 (head 83462159) reviewed by the checklist: files changed = the claim's surface (the new gate, one package.json line, one quoted lint.yml step; check-self-test-wired.mjs untouched because its condition did not fire, seat-verified); Fixes #18281 alone beside a closing keyword; skip-changeset read back; mcp_calls 0 — every write through the REST proxy or label-write.mjs; gates 63 / 58 / 5 NOT MEASURED (build prerequisites) / 0 unrun by --ran, battery 447.4 s detached; the seat's re-run on a detached worktree of the head reproduced every reading (record 5676984841 on the PR names each): self-test 32, live RED by exactly update_pull_request, GREEN over PR #18276's settings file, drift RED, missing-file exit 3, ESLint 0, step quoting, self-test wiring, required-contexts, watch-hint, declared-population, derivation proof. Deviations (6) answered one by one in the record. Out of scope routed: the enqueue-pair enumeration in guard-governed-enqueue.sh waits on #18282; the prose pointers are the reserved rules-layer card. The PR stays DRAFT with one known red (Lint & Repo Gates at the new step, by design) until PR #18276 lands; then the seat merges origin/main, reads CI green, flips ready through the CCR route and arms auto-merge SQUASH. The card stays pm:dispatched until the landing.


    Generated by Claude Code

  5. claude commented on Sep 15, 2026

    @claude
    ContributorAuthor

    Landed — skills seat, session session_01HZfg2AwVX191qCizp88gQr, 2026-09-15T16:08Z. PR #18285 (reviewed head 83462159, merge head 95c82a53) merged by the queue as 52c1a8c4af411ce759158bd938474903d42dc6b2 (single-parent squash per git rev-list --parents) at 2026-09-15T16:07Z — the merged_at instant, carried identically by the merged and removed_from_merge_queue timeline events. Readings at 2026-09-15T16:08Z: git log origin/main carries (#18285); the queue ref refs/heads/gh-readonly-queue/main/pr-18285-* is gone from origin; the removed_from_merge_queue event is on the timeline. Non-governed landing: record 5676984841 PASS, ACCEPT on this card at 2026-09-15T08:15Z, provenance 5683278669 on the PR; serial behind PR #18276 (the deny), which landed at 2026-09-15T15:14Z; the seat merged origin/main in through update-branch at 2026-09-15T15:16Z, read CI green on the merge head, flipped it ready through the CCR route and armed auto-merge SQUASH at 2026-09-15T15:43Z. Now on origin/main: scripts/pm/check-settings-deny-roster.mjs pins .claude/settings.json's permissions.deny to the charter's 15-name MCP content-write roster in both directions (a roster name missing from deny and a mcp__github__ deny entry the roster does not declare are each a FINDING), wired as a Lint & Repo Gates step and as pnpm check:pm-settings-deny-roster. Residue (pm:dispatched, assignee) stripped through label-write.mjs and read back.


    Generated by Claude Code

  6. added 3 commits that reference this issue on Sep 17, 2026
    52c1a8c
    ceb6b5f
    37af653
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions