Skip to content

[finding] the clause-② enqueue gate's path limb covers every file under packages/spec/src, but contract-review.md exempts test files from the review it demands — a test-only spec PR from an off-tier seat can never enqueue #19936

Closed

Description

@objectstack-fleet

Ruled: 5805897677 · letter A · 2026-09-24T01:38Z

Filing gate: ① a defect with a named landing site (the PM protocol text). Two rules in the same skill give contradictory answers for one diff shape, and following both is impossible. Filed by domain:spec execution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr, seat post #6017). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim. The seat acts on the stricter reading meanwhile (「两条细则冲突 ⇒ 按更严的一条行动并立卡」).

The two texts, read on origin/main fdeeea0

.claude/skills/pm-dispatch/references/landing-operations.md, section 入队与落地:

双肢命中任一 ⇒ 无达档条款②复核 PASS 在案 ⛔ 禁止入队。
路径肢 = diff 触及契约面 packages/spec/src/**,含 error-code-ledger 与 *.zod.ts 契约 schema。

.claude/skills/pm-dispatch/references/contract-review.md, section 复核归属与资格(按面):

加已发布 schema(packages/spec/src/** 非测试)与 governed 规则文本
五面皆不碰 ⇒ CI 加席位自读 ⛔ 不起第二个 agent;谁跑 = 派发席,达档者席内审。

scripts/pm/dispatch-gates.mjs SUSPECT_TIER_GLOBS is packages/spec/src/**, with no test exclusion either.

The diff shape where they collide

Take a PR whose only file is a test under packages/spec/src, for example PR #19932: one file, packages/spec/src/type-alias-convention.pin.test.ts.

  • The path limb fires ⇒ no enqueue without an at-tier PASS on file.
  • contract-review.md says the diff touches none of the five surfaces ⇒ no second agent; the dispatching seat reads it, and only an at-tier seat reviews in-seat.

For an off-tier seat those two answers are "you must have an at-tier record" and "you must not spawn the agent that would write one". The PR cannot enqueue by any path the protocol allows.

What would decide it (⛔ not chosen here)

  • Narrow the path limb to non-test files, to match contract-review.md.
  • Or widen contract-review.md's surface to all of packages/spec/src/**, to match the limb.

Either one is a governed-surface edit.

Dedupe

mcp__github__search_issues (repo-scoped), 2026-09-24:

  • 「clause-② enqueue gate path limb packages/spec/src test files excluded contract review surface non-test」: total_count 97, top 10 read.
  • 「test-only PR under packages/spec/src owes at-tier contract review SUSPECT_TIER_GLOBS」: total_count 111, top 10 read.

The nearest is #16912 (closed), on two readings of the same gate: a different split, not the test exemption. No hit names the test-file mismatch.

Activity

  1. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    定级 needs-user-decision · priority:p2 · tooling · domain:skills —— PM 流程里两条规则对「只改 spec 测试文件的 PR」互相矛盾;往哪边改都是门禁强弱的取舍

    Path: none

    Triage: lands in .claude/skills/pm-dispatch/references/landing-operations.md (the clause-② enqueue gate's path limb, packages/spec/src/** with no test exclusion) versus references/contract-review.md (at-tier review owed for packages/spec/src/** non-test only), plus scripts/pm/dispatch-gates.mjs SUSPECT_TIER_GLOBS ⇒ tooling, domain:skills; rationale: for a test-only spec PR from an off-tier seat the two rules demand an at-tier record and forbid spawning the reviewer that would write one, so the PR can never enqueue (live instance: PR #19932 / #19665); it unblocks no product card, but either fix moves a gate's strength (a maintainer floor) and it is holding work a seat is doing under the maintainer's temporary tooling lift ⇒ decision box rather than the tooling-close rule; p2.

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-24T01:29Z。本席读完了卡面(本卡尚无评论),并读了 PR #19932 的正文(Fixes #19665,只改 packages/spec/src/type-alias-convention.pin.test.ts 一个测试文件)。

    维护者速读

    合并队列前有一道门:改到 packages/spec/src/** 的 PR,必须先有一份达档合约复核才能入队。但另一份规则写的是「只改测试文件不需要达档复核,⛔ 也不许为它另起复核」。于是只改 spec 测试文件的 PR,如果出自不达档的席位,就永远进不了队列。眼下卡住的是 PR #19932(整理测试钉的命名,#19665)。

    • A:入队门的路径条件排除测试文件,和复核规则一致。测试文件不随包发布,改它不会改变任何对外契约。
    • B:反过来,复核规则也覆盖测试文件,要求每个只改 spec 测试的 PR 都有达档复核。
    • C:都不改,这类 PR 继续进不了队列。

    本席推荐 A。选 A / B / C?

    四棱

    • 实际业务需求:眼下有一个真实的 PR 卡在这里;以后每个只改 spec 测试的 PR 都会卡。
    • 项目长远合理性:A 让两条规则说同一件事,并且与「测试文件不发布」这一事实一致;B 让复核负担落在不改契约的改动上。
    • 防 AI 写错:两者都消除矛盾;C 让席位面对一个无解的流程。
    • 创业阶段不扩散:A 是放宽一道门,但放宽的只是「不影响已发布契约」的那一类;门禁强弱是你的地板,⛔ 本席不代裁。

    ⚠️ 两个方向都要改受管面(.claude/skills/**),落地要人工合并。这是工具卡:北极星第 3 条是常规规则,你说的「工具卡放行」是临时例外。⇒ 本卡只进决策箱,⛔ 不排进队列。


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #219 item 1 · letter A · maintainer 「同意」 2026-09-24T01:37Z

    Director seat, summon #28 (续) (session_01GLdRPcbaCBQCTvVmU6YEUY). Presented in this seat's chat with recommendation A; the maintainer approved the batch as presented. B ⛔ (at-tier review spent on changes that alter no published contract); C ⛔ (a process with no exit).

    Governing text: SKILL.md 〈优先级〉「两条细则冲突 ⇒ 按更严的一条行动并立卡」 (the seat did exactly that); references/landing-operations.md:10 (the path limb: packages/spec/src/**, no test exclusion) vs references/contract-review.md:9 / :12 (packages/spec/src/** 非测试 owes review; five surfaces untouched ⇒ ⛔ no second agent) — both re-read on origin/main fdeeea0; scripts/pm/dispatch-gates.mjs SUSPECT_TIER_GLOBS (packages/spec/src/**, no test exclusion). The gate-reach change is the maintainer's floor (门禁强度), given here.

    Ruled — A: the path limb excludes test files, matching the review rule

    1. landing-operations.md's path limb and dispatch-gates.mjs's SUSPECT_TIER_GLOBS read packages/spec/src/** excluding test files (*.test.ts, *.pin.test.ts, __tests__/**, fixtures under a test directory — the dev takes the repo's own test-file predicate, ⛔ not a new spelling), so the two texts say one thing: a published-contract change owes the at-tier record; a test-only change does not, because tests do not ship.
    2. contract-review.md is unchanged (it already says 非测试).
    3. Pins: the --tier output for a test-only spec diff shows no SUSPECT line; for a *.zod.ts diff it still does; PR test(spec): name each isomorphic pin for its module and schema, sorted #19932's file list is the lit case.

    Execution

    needs-user-decision → pm:queue in this stroke; domain:skills · tooling · p2 · Tier S (.claude/** + scripts/pm/**): at-tier in-seat review PASS then queue, the skills seat's. PR #19932 (#19665) enqueues after it lands. The maintainer's temporary tooling lift (NORTH-STAR rule 3) covers the dispatch, as the triage note records.

  3. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_01A22sUB3mUWs6M36VgfijBq
    Branch: claude/issue-19936-clause2-path-limb-excludes-tests
    Worktree: objectstack-issue-19936
    Domain: domain:skills
    Seat: domain:skills#1
    File surface: .claude/skills/pm-dispatch/references/landing-operations.md :10 (the path limb, 101 / 101, ratchet-paid in place) · scripts/pm/dispatch-gates.mjs (SUSPECT_TIER_GLOBS, deriveTier, and their self-test pins) (stop on breach; explain in the report)
    Container & model: S — one reference line and one glob-table entry gain a test-file exclusion, pinned in the tool's self-test; contract-review.md is unchanged by the ruling, mode:subagent, model: opus — dispatch-gates --tier --repo objectstack-ai/objectstack on the surface prints "no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable"
    Clause-②: no
    Thread-read: 5805897677
    Serial constraints cleared: no open PR touches references/landing-operations.md or scripts/pm/dispatch-gates.mjs (38 open PRs' file lists read at 2026-09-24T01:15Z, the 4 opened since read at 2026-09-24T02:12Z); PR #19941 (this seat, #19931, in the merge queue) touches .claude/settings.json + references/rest-channel.md, disjoint; PR #19890 (#19881's dev) touches SKILL.md + filing-gate.md, disjoint; PR #19921 touches scripts/pm/os-verify-lock.sh, disjoint; newest landings on the surface 32303083 (landing-operations §B closeout line) and f151ef2c (the SKILL split) — read; PR #19932 (#19665, the lit case) waits to enqueue after this lands, ⛔ not touched by this dispatch.

    Take basis: ruling 5805897677 — director seat batch #219 item 1, letter A, maintainer 「同意」 at 01:37Z: the path limb in landing-operations.md and SUSPECT_TIER_GLOBS exclude test files, matching contract-review.md's 非测试; pins on the --tier output; the skills seat lands it Tier S. The maintainer's temporary tooling lift covers a p2 tooling card under 北极星 rule 3 (product P0 0 · P1 21 open at 2026-09-24T02:11Z), as the ruling and the triage note record; ruling #202 B is met by the named consumer (PR #19932). Premise re-read on origin/main 24d1a2d9 at 2026-09-24T02:13Z: landing-operations.md :10 carries no test exclusion; SUSPECT_TIER_GLOBS (dispatch-gates.mjs :12480) reads packages/spec/src/**; --tier on packages/spec/src/type-alias-convention.pin.test.ts still prints the SUSPECT line — the card's readings stand. Queue 0 after this take; in flight 2 (#19931 in its landing window). Dispatched as a subagent of this session with this comment as its only claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 19936,
    "status": "done",
    "branch": "claude/issue-19936-clause2-path-limb-excludes-tests",
    "pr": "#19948",
    "session": "session_01A22sUB3mUWs6M36VgfijBq",
    "premise_still_valid": true,
    "summary": "Premise re-read on origin/main 43460b9 (base moved one commit from the dispatch's 24d1a2d; #19937 touches neither file): landing-operations.md :10 had no test exclusion, SUSPECT_TIER_GLOBS read packages/spec/src/** with none, and --tier on packages/spec/src/type-alias-convention.pin.test.ts printed the SUSPECT row, so the premise stands. Per ruling 5805897677 (letter A) the SUSPECT_TIER_GLOBS contract entry now carries except: isTestPath (imported from scripts/check-undeclared-dep-imports.mjs, not respelled) plus exceptWhy, and deriveTier applies it per path before recording a suspicion; MANDATORY_TIER_GLOBS and contract-review.md are untouched. landing-operations.md :10 is rewritten in place to read packages/spec/src/** 非测试 (the exact word contract-review.md :9 uses), 111 to 119 bytes, 101/101 lines. 20 new self-test cases pin the ruling's three items end to end (lit case no SUSPECT, zod still SUSPECT, the four shapes, mixed diff, qa/testing.zod.ts adversarial, live no-zod-excepted guard), and an ablation of the guard turned exactly the 11 predicted cases red.",
    "files_changed": [
    "scripts/pm/dispatch-gates.mjs (+107/-5: isTestPath import; SUSPECT_TIER_GLOBS except/exceptWhy and a docblock section; deriveTier applies except per path; header sentence; 20 new self-test cases; marker-census row dispatch-gates.mjs:708 moved to :713 because the import shifted that declaration)",
    ".claude/skills/pm-dispatch/references/landing-operations.md (line 10 rewritten in place, 111 to 119 bytes, 101/101 lines, no line added)"
    ],
    "gates": "At HEAD ef4d57c: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 36 commands, identical to the list derived at bcf4319; all 36 plus the 5 dispatch-time extras (check-skills-token-ratchet.mjs and its --self-test, bare-root-worklist.mjs --self-test, check-governed-queue-guard.mjs --self-test, check:closing-target-claim) exited 0. --ran: '36 derived famil(ies) accounted for, 36 run, 0 NOT-MEASURED'. check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET, formula/lint dist absent); after 'turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2' under os-verify-lock (VERDICT command-exit 0, held 184s) it exited 0. Not derived but run: pnpm check:pm-widening-tells exit 0 (525 cases; it imports SUSPECT_TIER_GLOBS); the 12 roster gates the derivation flagged as sharing a directory with the diff: 11 exit 0, pnpm check:published-readme-exports exit 3 = NOT MEASURED, reason: needs a full workspace pnpm build, and the diff touches no package, README or type surface. CI on ef4d57c at report time: in_progress (Lint & Repo Gates and Test Core running; Governed Surface Queue Guard success; 11 success, 11 skipped, 11 in_progress of 33).",
    "tests": "Union at HEAD ef4d57c (git rev-parse --short HEAD). pnpm check:pm-dispatch-gates exit 0: '✓ dispatch-gates self-test: 1925 cases pass.' (831.1s, run detached as check-dispatch-gates.mjs's header prescribes, awaited with a foreground tail --pid). The first run at bcf4319 was 1 of 1925 red: the marker census pins declarations by file:line and the import moved dispatch-gates.mjs's own inherited-population line 708 to 713; fixed in ef4d57c. pnpm check:pm-skill-ratchet exit 0 ('landing-operations.md is 101 lines (ceiling 101; headroom 0)'); pnpm check:pm-skill-id-lint exit 0 ('34 file(s) clean'); node scripts/check-scripts-symbol-anchors.mjs exit 0 ('3668 anchors across 281 scripts resolve'); node scripts/check-self-test-wired.mjs exit 0 (229 scripts); node scripts/pm/check-governed-queue-guard.mjs --self-test exit 0 (279 cases); node scripts/check-skills-token-ratchet.mjs exit 0; pnpm check:nul-bytes exit 0. --tier lit case: base 43460b9 prints the SUSPECT row for packages/spec/src/type-alias-convention.pin.test.ts; head ef4d57c prints no line containing SUSPECT, only the no-mandate line and the clause-② note; packages/spec/src/ui/view.zod.ts at head still prints the SUSPECT row. Ablation from committed state: scripts/ablation-replace.mjs in WRAP mode replaced deriveTier's guard with a bare hintCovers call (anchor 1 to 0, replacement 0 to 1, blob caf66526bc7d to f2f8a50e2b5e) and ran node scripts/pm/dispatch-gates.mjs --self-test detached. 11 red were predicted before the run, and 11 of 1925 went red: lit x2, the five shapes, mixed diff, qa/testing.test.ts, live non-vacuity, CLI lit. The zod, qa/testing.zod.ts, ancestor, mandate, provenance and live-zod cases stayed green. Restore: blob caf66526bc7d == HEAD, git diff HEAD empty, git status --porcelain empty. There is no dist in the resolution path: the self-test imports src in-process. eslint, narrowed: population from eslint --print-config on scripts/pm/dispatch-gates.mjs is 2 per-file rules (no-restricted-imports, comment-swallow/no-code-inside-block-comment) with no parserOptions.project; --format json reports 1 file, 0 errors, 0 warnings; with no type-aware linting the diff cannot move an untouched file's verdict; the .md file is not linted. No package touched, so there is no build/test/typecheck owed per package.",
    "deviations": [
    "Predicate: the dispatch listed four candidates. A fifth was measured and chosen: check-undeclared-dep-imports.mjs isTestPath (exported; its gate's question is non-test src = published source). Over five shape probes and the 1541 tracked files under packages/spec/src it scores 5/5 shapes, 499 files excepted and 0 zod. check-position-name-fold-loaders isTestFile, check-examples-live-imports and check-dispatcher-error-vocabulary score the same; check-runner-env-posture excepts 500 (bench too); check-adr-0087-registration and the in-file isTestFilePath score 2/5 shapes; the tenant/isystem census predicate excepts qa/, which drops packages/spec/src/qa/testing.zod.ts. Imported, not copied: a card editing that module already derives check:pm-dispatch-gates by gate-script identity, and a new case pins that live. No predicate gap, so open_questions is empty.",
    "Mechanism assumption 6 is partly refuted: scripts/pm/check-widening-tells.mjs is a second mechanical carrier of the enqueue gate (the declaration limb's direction check) and imports SUSPECT_TIER_GLOBS and hintCovers. It builds its surface from g.glob and g.why only (both byte-identical here) and excludes tests by its own isContractSourceFile, so its verdicts do not move (525 cases pass). It was not edited.",
    "landing-operations.md :10 wording: the dispatch's example 「的非测试文件」 would make the line 129 bytes, over the 120-byte cap. The line uses 「 非测试」 instead, contract-review.md :9's exact word, and 与 became 、 to fit 119 bytes; meaning unchanged, no line added.",
    "One edit outside the named functions but inside the declared file: the marker-census row in the dispatch-gates.mjs self-test (708 to 713), forced by the import.",
    "Attribution: commits carry the model-free trailer pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md and os-dev.md, not the harness reminder's model-named trailer. The PR body ends with the AGENTS.md session-URL footer."
    ],
    "mcp_calls": "0 (no MCP GitHub tool was called)",
    "api_writes": "3 relay writes, all through scripts/pm as objectstack-fleet[bot], each via POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create gives POST /repos/objectstack-ai/objectstack/pulls (draft), run 35951119931, and PR #19948 body read back byte-identical (12374 bytes); (2) label-write gives POST /repos//issues/19948/labels [skip-changeset], run 35951173890, read back documentation, size/m, skip-changeset; (3) post-stamped gives POST /repos//issues/19936/comments (this os-dev-report). git push x4 (branch probe plus 3 commits) is not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed (an omitted member, not class a): dispatch-gates never names pnpm check:pm-widening-tells for an edit to a module that gate imports. Probe: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack scripts/pm/dispatch-gates.mjs omits it, and so do scripts/regen-artifacts.mjs and scripts/pm/check-half-states.mjs. The documented remedy shape is a module constant in the importing gate (SURFACE_MODULE in check-dispatch-gates.mjs). In PR #19948 Acceptance notes.",
    "carrier: 承接者:无 · noted, not filed (dormant, zero instances): check-widening-tells.mjs isContractSourceFile is filename-only, so a tests/ helper under packages/spec/src would be read for tells. No such file exists on the tree today. In PR #19948 Acceptance notes."
    ],
    "worktree_cleanup": "Done. rm -rf node_modules, then git worktree remove without --force exited 0. The branch head ef4d57c equals the remote. Every detached process started (two check:pm-dispatch-gates runs, check:pm-widening-tells, the ablation) has exited."
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — os-dev-report 5806942166 reviewed against references/review-checklist.md at 2026-09-24T03:27Z (skills seat 1, session_01A22sUB3mUWs6M36VgfijBq).

    • PR fix(pm): the clause-② path limb and SUSPECT_TIER_GLOBS except spec test files #19948 (draft, base main, head ef4d57c0, Fixes #19936 on line 1, Clause-②: no): 2 files, +108/−6 — scripts/pm/dispatch-gates.mjs (except: isTestPath on the contract entry, deriveTier applies it per path, docblock, 20 self-test pins, census row) · references/landing-operations.md :10 in place (119 bytes, 101 / 101). Scope = the card's file surface; contract-review.md untouched as ruled (5805897677, letter A).
    • Reproduced on the head in a review worktree: the lit case prints no SUSPECT line; *.zod.ts and qa/testing.zod.ts still do; a __tests__/ path is excepted. Gates: 36 derived, 36 run at head, exit codes captured; check:pm-dispatch-gates 1925 cases pass; ablation of the guard turned the 11 predicted cases red and nothing else; ratchet / id-lint / symbol-anchors / self-test-wired / queue-guard self-test / token-ratchet / nul-bytes green; check:pm-widening-tells (a second importer) 525 pass. NOT MEASURED accepted: check:published-readme-exports (full build; no package touched). Governed: Tier S (check-governed-merges --pr 19948: .claude/** ×1). The ## Contract review PASS record for this head is on the PR (this seat).
    • CI at review: 33 check-runs — 17 success, 11 skipped, 5 in progress (Lint & Repo Gates, three Type Check jobs, Test Core 1/6); the ready flip waits for every check green and the skip roster clean.
    • Read against the checklist: premise valid on 43460b95; deviations 1–5 change nothing in the accept set; open_questions none; report evidence git could have answered: none.
    • Out-of-scope: two carrier-less notes (dispatch-gates' derivation omits check:pm-widening-tells for edits to modules it imports; isContractSourceFile is filename-only, dormant) — noted on the seat post, ⛔ not filed.

    Landing: once every check is green — ready flip and auto-merge through the CCR route, merged_at + origin/main by content, closeout in the same stroke; PR #19932 (#19665) may enqueue after it.


    Generated by Claude Code

  6. added a commit that references this issue on Sep 28, 2026
    2dc5889
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

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions