Skip to content

AGENTS.md's governed-surface section contradicts the shipped guard: it lists skills/** as NOT governed and asserts no mechanical backstop exists #6975

Description

@os-sam

Filed by the domain:ui execution seat. Surfaced by the dev on card #5704 (PR #6974) as an out-of-scope finding; it could not file it itself (GitHub search hit this seat's rate limit mid-task). I re-measured every claim below against the bytes on origin/main = fd8dacecc322e886986d86fdea8ddf139834241e before filing — none of it is forwarded phrasing.

Two contradictions, both checkable

AGENTS.md §"⛔ 受管面(governed surface):agent 起草,人类合并" (line 360 onward) and scripts/check-governed-queue-guard.mjs disagree about what the governed surface is and about whether it is enforced.

1. skills/** — the doc says not governed, the guard says governed

AGENTS.md:371 heads its list with "本仓的受管面 —— 四项" (four items). The shipped guard ships five:

// scripts/check-governed-queue-guard.mjs
export const GOVERNED_SURFACES = Object.freeze([
  Object.freeze({ id: 'adr',            prefix: 'docs/adr/', glob: 'docs/adr/**', what: 'architecture decision records' }),
  Object.freeze({ id: 'claude-tree',    prefix: '.claude/',  glob: '.claude/**',  what: 'the agent instruction tree (skills, hooks, settings)' }),
  Object.freeze({ id: 'skills-catalog', prefix: 'skills/',   glob: 'skills/**',   what: 'the published skills catalog' }),
  Object.freeze({ id: 'agents-md',      exact: 'AGENTS.md',  glob: 'AGENTS.md',   what: 'the repo-root agent instruction file' }),
  Object.freeze({ id: 'claude-md',      exact: 'CLAUDE.md',  glob: 'CLAUDE.md',   what: 'the repo-root Claude instruction file' }),
]);

The count difference is exactly skills-catalog, and AGENTS.md:378 does not merely omit it — it rules the opposite way, in the ruling text's own words (quoted verbatim, untranslated):

  • skills/**(仓根,发布给使用者的那棵,如 skills/objectui/)—— 不在受管面上,按普通代码 PR 走:CI 全绿就照上面的常规路径自行入队合并。

Gloss: repo-root skills/** is not on the governed surface, and an agent should take the ordinary path — CI green, self-enqueue, merge.

2. The doc says no mechanical backstop exists; one is shipped and wired

AGENTS.md:392, verbatim:

本仓没有任何机械兜底,这一段就是全部。 … 受管面上没有 required check、没有钩子 … 本段没点名的兜底工具,就是不存在的工具;哪天本仓真有了检测,它会写在这里。

Gloss: this repo has no mechanical backstop at all, this section is the whole of it; there is no required check and no hook on the governed surface; a backstop tool not named in this section is a tool that does not exist.

But .github/workflows/governed-surface-guard.yml exists and is wired on two legs — pull_request: (line 24) and merge_group: (line 42) — and its own header states which leg does the work:

merge_group is the leg that REFUSES: the queue build is the last thing between a speculative merge and main, and it is the path #6183 took. pull_request is an EARLY WARNING that deliberately exits 0 …

The guard's header dates its mandate: objectui#6596, maintainer ruling 2026-08-27. AGENTS.md's section quotes a ruling of 2026-08-18. The guard's ruling is the later of the two, and the doc was never brought forward to it.

What in that paragraph still holds — do not over-correct

One claim at AGENTS.md:392 is still true and must survive the fix: this repo has no CODEOWNERS. Verified — .github/CODEOWNERS, CODEOWNERS, and docs/CODEOWNERS all absent. The stale parts are "no required check / no hook" and the closing "a tool not named here does not exist", not the CODEOWNERS sentence.

The failure mode this creates

An agent that follows AGENTS.md:378 literally on a skills/**-only PR does exactly what the line tells it to: waits for CI green, flips the PR ready, enqueues. The merge_group leg then refuses — so the trap costs a rejected queue build plus a ready-flip that, per the guard header's account of #6183, converting back to draft did not cleanly undo.

This is not hypothetical for the current batch: PR #6974 (card #5704) is a skills/**-only change. It stayed draft only because that dev read the guard source instead of trusting AGENTS.md's literal text. An agent doing the reverse — trusting the instruction file, which is the documented thing to do — walks into the refusal.

Proposed remedy

Sync AGENTS.md to the shipped mechanism: correct line 378 to place repo-root skills/** on the governed surface, correct the count at line 371 (four to five), and rewrite line 392 to name scripts/check-governed-queue-guard.mjs and .github/workflows/governed-surface-guard.yml as the backstop that now exists — while keeping the CODEOWNERS sentence, which is still accurate.

This PR edits AGENTS.md, which is itself a governed surface. It must be drafted and left as a draft for a human to merge — never marked ready, never enqueued, never auto-merged. GOVERNED_APPROVERS are os-zhuang and hotlong.

Note for the maintainer

I am not treating the direction of the fix as settled by me. The reading above — that the 2026-08-27 ruling behind the guard supersedes the 2026-08-18 ruling quoted in AGENTS.md — is the only reading consistent with both artifacts, but the governed-surface definition is the maintainer's to state. If the intent was instead that repo-root skills/** stay ungoverned, then the fix is in the guard's GOVERNED_SURFACES, not in the doc, and this card should be re-pointed there.


Seat session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpm:dispatchedpriority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions