Skip to content

[Decision] Does published skills/** text fall under clause ②'s CONTENT limb? A false skill line changes what the contract promises without touching a contract file #13588

Closed

Description

@claude

[Decision] Does published skills/** text fall under clause ②'s CONTENT limb? — today nothing but a seat's judgement routes it to contract review

Provenance. Raised by the os-dev agent on #13539 as its option C, and forwarded — ⛔ not adjudicated — by the domain:devx seat (post #6023, session session_01Pk26oZ12t5N1hwGW1m1MgC), R33. Filed separately so it does not die inside a closed card.

The one-line problem

A false published-skill line changes what the contract PROMISES without touching a contract file.

Clause ② has two limbs: a PATH limb (packages/spec/src/**) and a CONTENT limb (changes contract accept/reject behaviour or widens the public surface). Published skill text under skills/** is customer-reachable documentation of the contract. It can state that an operator means one thing when the drivers implement another — which is precisely what #13539 found and fixed — while touching zero contract files.

⇒ the PATH limb cannot see it, and whether the CONTENT limb reaches it has never been ruled.

The concrete instance that raised it

On #13539 the dev measured, honestly and against itself, that neither limb fires on its own two PRs: zero packages/spec/** paths, and no Clause-2: yes declaration in the dispatch. It attached needs:contract-review anyway — riding the card's standing determination, which had been made for a packages/spec JSDoc site fenced out of its scope — and ⛔ self-cleared nothing. Correct on both counts, and it left the question standing rather than resolving it by convenience.

四维分析

1 — 实际业务需求。 这是客户今天就会撞上的面。#13539 的两处 published skill 文本教的是「$exists 测键是否存在」,而三个 driver 实现的全是「有没有值(!= null)」。⇒ 一个照着 skill 写查询的客户会得到与文档相反的结果,而没有任何门禁会红。这不是理论风险,是已发生并已修的实例。

2 — 平台长远合理性。 契约的权威文本与契约的描述文本正在分叉治理:前者有 PATH 肢兜底,后者只靠某个座位当天恰好想到。⭐ 关键不对称:skills/** 已经是受管面(人工合并),所以它已经被认为足够重要到不许 AI 自行落地 —— 但它不触发契约复审。⇒ 「重要到要人工合并」与「不重要到不必过契约复审」这两个判断同时成立,至少有一个是错的。

3 — 避免 AI 写代码犯错。 ⛔ 最大的风险是扩面过宽:若把「任何提到契约的文本」都拉进条款②,复审队列会被 4 个纯算子清单、拼写修正和格式改动淹没,而复审是稀缺的人工资源 —— 淹没一条通道等于关掉它。#13539 的实测正好给了收窄的形状:10 处 content/docs 命中里,只有 3 处作出语义主张,4 处是无主张的算子清单。⇒ 判据应当是「是否作出可证伪的语义主张」,不是「是否提到契约」。

4 — 创业阶段不扩散需求。 便宜的出口存在且不必新建机制:published skills/** 里作出算子语义主张的改动 ⇒ 挂 needs:contract-review,复用现有标签与现有复审链,⛔ 不新增状态、不新增 sweep、不新增门禁。若判定不值得,那也要明写「published skill 文本不属条款②」,让下一个座位不必再猜一次。

三条候选,⛔ 本席不裁

⚠️ A 与 C 不互斥,很可能应当同时采纳:C 抓已知措辞,A 兜住新措辞。

⚠️ 与 #13557 的分界 —— 邻卡,⛔ 不是重复

#13557 问的是何时挂:2026-08-28 对 #12887 的裁定废止了预挂,标签只在可复审增量存在时挂载,而两日内复发 9 例(其中就包括本卡引出的 #13539 本身,由总监席于 2026-08-31 摘除)。它的根因假设是 SOP 文本把「判定」与「挂载」两个动作写在了同一笔。

本卡问的是是否属于:published skills/** 文本根本上算不算 CONTENT 肢。两者正交 ——
#13557 即使完全修好,本卡的面仍然没有任何机制把它路由进复审;本卡即使裁 B(明确排除),
#13557 的时序缺陷照旧存在。

⭐ 值得注意的是本卡的实例同时验证了 #13557 的修法方向:#13539 的 dev 在开 PR 的同一笔重挂了标签(正是 9 例摘除评论共同注明的「PR 存在的同笔即重挂」),⇒ 时序这一半按裁定执行是可行的;卡住的是适用性这一半,而那正是本卡。

⛔ 本席的边界

本席不代裁:这是协议形状问题(条款②覆盖面),按人工地板归维护者。上面的建议是建议,不是裁决。

Refs: #13539(引出本卡的实例,含实现层证据)· #13582(词表棘轮路径)· #13531(filter-logic-conformance.ts 的陈旧格,domain:spec 在飞)


Generated by Claude Code

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 31, 2026
  2. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    ⚖️ RULED — 维护者,2026-08-31,第 6 场总监席决裁批 #12,verbatim「同意」(采本席推荐)

    裁定:A + C 同取,B 弃。

    席位边界(裁不派):录裁 + 转 pm:queue,同笔摘 needs-user-decision;派发归 domain:skills 车道。裁决入本场追认摘要表。


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 31, 2026
  4. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    ⚖️ RULED — 维护者,2026-08-31,第 6 场总监席决裁批 #12,verbatim「同意」(采本席推荐;裁定评论迟于标签转移补录,裁定时点以批回为准)

    裁定:采 A + C 同取(不互斥),B 弃。

    席位边界(裁不派):录裁 + pm:queue(标签已转);技能文本半归 skills 车道(governed draft + 人工合并),棘轮半纯代码直行。裁决入本场追认摘要表。


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 31, 2026
  6. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    Claim: PM loop round 1
    Session: session_01EnE7G31tqbxN1rqpQmzurT
    Branch: claude/issue-13588-clause2-content-limb (half C, if split as ruled, rides claude/issue-13588-role-word-ratchet — one card, up to two PRs per 批 #12's 执行落点)
    Worktree: objectstack-issue-13588
    Domain: domain:skills
    File surface: .claude/skills/pm-dispatch/references/contract-review.md (half A — the ruled single source; ⛔ NOT SKILL.md) + scripts/check-role-word.mjs and its word/baseline table (half C) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — half A is a references/**-only governance face (opus construction per the 2026-08-20 narrowing; this seat reviews at contract-review tier at ACCEPT), half C is gate-script code; per this hour's dispatch-gates.mjs --tier posture no path-derived mandate applies to either face, and SKILL.md (fable-mandated) is explicitly out of scope.
    Clause-②: no — process/SOP text and a lint-gate word addition; no contract accept/reject behavior change, no public-surface widening.
    Serial constraints cleared: references/contract-review.md face FREE per seat post #7623 (audit #13597 Phase-3 re-locks are downstream, check-skill-line-ratchet.mjs last); zero open PRs touch either face (open-PR listing read this hour); in-flight siblings #13717 (skills/objectstack-query/**), #13663 (.claude/hooks/**) and ui#6977 (objectui) are disjoint — no read-coupling.


    Generated by Claude Code

  7. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    Claim: os-dev subagent, dispatched for 批 #12's A + C halves — separate from the PM's claim above, not a second seat.

    Session: session_01EnE7G31tqbxN1rqpQmzurT (mode:subagent; a subagent shares the dispatching session's id, so this claim is distinguished by role and branch rather than by id)
    Worktree: objectstack-issue-13588 (cut from origin/main @ cc837dbf)

    Branches:

    File surface actually touched (half A): .claude/skills/pm-dispatch/references/contract-review.md (the ruled single source) and the CEILINGS entry for that file in scripts/pm/check-skill-line-ratchet.mjs — the ceiling raise the ruled addition costs. ⛔ .claude/skills/pm-dispatch/SKILL.md NOT touched, per the scope fence.

    Assignee left as the PM set it; ⛔ nothing on the assignee field written by this subagent.


    Generated by Claude Code

  8. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    os-dev-report

    {
      "issue": 13588,
      "status": "needs_decision",
      "branch": "claude/issue-13588-clause2-content-limb (half A, pushed at b812c180). Half C branch claude/issue-13588-role-word-ratchet was NOT created — see open_questions.",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13746",
      "premise_still_valid": false,
      "summary": "Half A is DONE and shipped as draft PR #13746: the 批 #12 criterion (published skills/** changes making a FALSIFIABLE operator/contract semantic claim fall under clause ②'s CONTENT limb; criterion is 可证伪的语义主张, NOT 提到契约) is recorded as a three-line bullet at the head of 载体纪律 in .claude/skills/pm-dispatch/references/contract-review.md, the ruled single source, with the 10-hits/3-claims yardstick and the dated provenance. That file sits at a line ratchet of 48 with headroom 0, so the addition cost a ceiling raise to 51 in scripts/pm/check-skill-line-ratchet.mjs; the ruling is quoted in the PR body as that gate's own discipline requires, and the CEILINGS comment carries the measurement showing neither in-place payment was available (moving narrative out is impossible in the references file itself; absorbing 332 bytes into 577 bytes of slack across 41 lines means re-wrapping the whole file, which is banned funding; the only remaining payment was deleting a ruled clause, refused on the state-machine.md precedent). ⛔ SKILL.md was NOT touched. Half C is NOT delivered: the PM mechanism assumption 'extend check-role-word.mjs the same shape / add a word' was tested against the tree and is FALSE, and the work it actually requires is verbatim the already-triaged build of open card #13582 in another lane. premise_still_valid is false for that half only — the ADJUDICATION stands untouched; what is falsified is the mechanism premise 批 #12 inherited from the card's own option-C text, 「加一个词即可覆盖本类」, which #13582 itself already contradicts in writing.",
      "tests": "All readings at worktree objectstack-issue-13588, cut from origin/main @ cc837dbf; gate union re-run AFTER the final commit, at head b812c180 (git rev-parse --short HEAD). Gate families derived from the REAL diff, never a hand-written path list: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` → 20 commands harvested with --commands. Each run with its exit code captured BEFORE any pipe (cmd redirected to a file, then EXIT=$?). RESULT at b812c180: 19 exit 0, 1 NOT MEASURED. Green include check:pm-skill-ratchet, check:pm-skill-id-lint, check:skill-frame-sync, check:doc-authoring, check:agent-test-spelling, check:pm-governed-merges, check:pm-dispatch-gates, check:parse-guard, check:entry-guard, check:watch-hint-literal, check:pnpm-filter-targets, check:cli-command-ids, check:bash32-floor, check:cross-package-test-inputs, check:doc-formula-expressions, check-ci-filter-parity, check-cross-package-test-inputs, check-shard-attestation, bare-root-worklist --self-test. NOT MEASURED: `node scripts/check-test-completeness.mjs` exit 3, its own text 'PREREQUISITE NOT MET ... ⛔ It is not a red, and there is nothing here to fix' — it grades a saved turbo test log only CI produces; recorded as NOT MEASURED, not green and not red. Two gates first returned PREREQUISITE NOT MET for a missing build and were made real rather than reported as red: `pnpm exec turbo run build --filter=@objectstack/formula` then `--filter=@objectstack/lint` (both exit 0, under the shared verify lock), after which check:doc-formula-expressions is exit 0. Gate verdict lines quoted from the gate itself, not from $?: '✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/contract-review.md is 51 lines (ceiling 51; headroom 0).' and '✓ ... widest table row is 0 bytes (pin 0; headroom 0).'; before the edit the same gate printed the file at 48 lines (ceiling 48). Standing rule for any edit: `pnpm check:nul-bytes` exit 0 — 'check-nul-bytes: OK (scanned 7572 text file(s) -- 7572 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)'. Because the diff edits a GATE SCRIPT, that script's own suite was run beyond the derived family: check-skill-line-ratchet --self-test exit 0 (it has no separate .test.ts), plus the three gates that git grep shows read it by name — check:pm-dispatch-gates exit 0, node scripts/check-published-list-mirrors.mjs exit 0, node scripts/check-skills-token-ratchet.mjs exit 0 ('✓ 38 authored bundle file(s) within their ceilings'). No ablation was run: nothing here is a new gate needing a can-it-fail proof. DECLARED NARROWING: the post-commit union re-run was executed WITHOUT the shared verify lock after a first attempt was killed at the ~10-minute foreground cap (exit 143) while queued behind another holder; the lock's own VERDICT banner states it does not exclude `check:*` gates anyway, so holding it buys nothing for these light node gates. Heavy commands (both turbo builds) did go through the lock. Half C: no code was written, so no test evidence is claimed for it — only the measurements in open_questions.",
      "mcp_calls": "9 — create_pull_request 1, issue_read get_labels 1 (failed loudly on a PR number, the documented routing signal), pull_request_read 4 (body/label read, compare read-back, get_status, delayed re-confirmation), issue_write 1 (label union write), add_issue_comment 2 (claim + this report). All issue and card BODY reads for #13588, #13582, #13539 and #13646 went through the zero-quota public-repo payload channel, not MCP.",
      "open_questions": [
        {
          "question": "Half C (the vocabulary ratchet) cannot land as 'add a word to check-role-word.mjs'. MEASURED on origin/main @ cc837dbf: `const WORD = /\\brole(?:s)?\\b/gi` is a single module-level regex; the ledger scripts/role-word-baseline.json is a flat {path: count} map of ONE word's per-file counts (43 keys); the remedy strings are registered by ledger PATH in scripts/check-ratchet-remedy-authority.mjs, whose own self-test pins the exact role-word remedy string. #13582 already states this verbatim — 'What it does not have is a second word: WORD is a single module-level regex, so a second term is a change to its shape rather than a row in a table' — and its triage already RULED the build: 造成一张表,不是第二条硬编码正则. Worse for the 'one word' framing, the ruled matcher there is a CO-OCCURRENCE rule (『$exists 与 field exists / existence check / key presence / MongoDB $exists 的共现』), a shape countMatches(text) does not have at all. So half C's real work IS #13582's whole build, in the domain:devx lane, on a p2 card that is already filed, triaged and queued. How should it land?",
          "options": [
            "A — Dispatch it as #13582, its own card, using the build direction its triage already ruled and the three constraints it already records (registration + self-test + workflow entry + baseline; the baseline MUST admit objectstack-formula's has(record.foo) as genuine key existence; shrink-only). Note its scheduling hold is now falsifiable: the hold says it must wait for a .github/workflows/lint.yml slot behind #13646 and PR #13584, but check:role-word is ALREADY registered (package.json:56, .github/workflows/lint.yml:1757), so an in-place extension needs NO new workflow entry and contends with nothing. #13646 is still OPEN, and that no longer blocks this.",
            "B — Build it now under #13588 as PR-C, duplicating #13582's scope from the skills lane and leaving the PM a duplicate open card to reconcile.",
            "C — Widen the existing WORD regex with an alternation (a second hardcoded regex). Explicitly ruled against on #13582, and it corrupts the diagnostics: two unrelated words would share one per-file count, so the gate's own messages ('role-word count improved 4 → 3', 'add it to scripts/role-word-baseline.json') become false for half the hits."
          ],
          "recommendation": "A, on all four axes. REAL BUSINESS NEED: real but narrower than the card assumes — a shrink-only ratchet blocks only NEW occurrences, and #13539's defect was PR #13529 making PRE-EXISTING prose false, which no ratchet can catch; the pull is 'prevent re-introduction', and it is the same pull under A or B, so this axis does not pick B. LONG-TERM SOUNDNESS: the ruled matcher is a co-occurrence rule and the ledger is per-word; doing that properly means per-word ledgers and per-word remedies, which is A's ruled table. It also keeps two subjects apart — ADR-0090 D3 reserved vocabulary versus operator-semantics truth — the exact split #13582's triage used to route the gate to devx by SUBJECT. AI-ERROR-PROOFING: A and B enforce identically for authors; C is strictly worse because the remedy text an AI author acts on would name the wrong ledger. STARTUP SCOPE DISCIPLINE: decisive — A costs nothing new (the card is filed, triaged, ruled and queued, and its blocker is measured away above), while B pays for the same build twice. One measurement to carry into whoever takes it, so it is not re-derived: current live hits in the gate's roots (content/docs + skills, generated references/ excluded) are — NoSQL 9 hits / 7 files, of which skills has exactly 1 (a column header 'SQL / NoSQL' at skills/objectstack-query/SKILL.md:154); MongoDB 120+ hits / 34 files, mostly legitimate driver documentation and therefore unusable as a pin; presence-phrasing (key presence|field existence|existence check|field exists|key exists) 14 hits / 13 files, including the must-stay-green skills/objectstack-formula/SKILL.md:110 and :119. All six #13539 sites read correctly today. ⚠️ CAUTION the dispatch's own note gets backwards: baselining current hits does make the gate green today, but this ratchet ALSO fails when a baselined count DECREASES ('ratchet DOWN: run --update'), so pinning a word with live hits in skills/objectstack-query/** couples the gate to in-flight #13717, whose sweep would drop that hit and turn it red. The presence-phrasing candidate avoids that face entirely; NoSQL does not."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED, handed to the PM to file or fold in — discoverability gap left open by half A. The 双肢 definition itself lives in .claude/skills/pm-dispatch/SKILL.md (out of scope, fable-mandated face), and its clause-② gate paragraph routes readers to references/contract-review.md for only three named topics — 载体纪律、资格与归属、降档保险丝 — applicability is not one of them. The ruled criterion IS reachable in practice, because its operative half is an attach rule and 载体纪律 is where an attaching seat lands, which is why the fence was not tripped and PR #13746 stands. But a seat consulting only SKILL.md's 双肢 paragraph will not see the skills/** face named. Closing it needs a one-line SKILL.md edit under that file's own ratchet — reported, not taken, per the scope fence.",
        "NOT FILED, observation for #13582's taker — the scheduling hold recorded on #13582 ('⏸ Held behind #13646 — both need a .github/workflows/lint.yml entry') rests on a premise that does not hold for an in-place extension of check-role-word.mjs: that gate is already registered at package.json:56 and .github/workflows/lint.yml:1757, so extending it adds no workflow entry and contends with neither #13646 nor PR #13584. Recording it here rather than editing another card's hold."
      ]
    }

    Generated by Claude Code

  9. huangyiirene commented on Aug 31, 2026

    @huangyiirene
    Collaborator

    Disposition + ACCEPT (half A) — PR #13746; half C discharged to #13582 per the ruling's own path

    Half A — ACCEPT. Diff verified against GitHub: references/contract-review.md +3 lines at the head of 载体纪律 carrying exactly 批 #12's criterion, its explicit negative (⛔ not 「提到契约」; operator lists/spelling/format don't trigger), the 10-hits/3-claims yardstick, dated provenance, and the two-guarantees-stack note — no scope creep; SKILL.md untouched, fence held. The ratchet raise 48→51 in check-skill-line-ratchet.mjs follows that file's own state-machine.md precedent form with the in-place-payment impossibility measured (577 bytes of slack across 41 lines ⇒ absorbing 332 bytes means whole-file re-wrap, which is banned funding; the only other payment was deleting a ruled clause, refused). The raise is carried by the ruled addition itself — 批 #12 ordered the sentence, and the ruling is quoted verbatim in the PR body per the gate's discipline — and since the PR is governed references/** md, the maintainer's own merge is the human eye on the raise; it is flagged in the round report rather than slipped through. Review ran at contract tier per the governance-face compensation rule (fuse read this session: last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER). Gates 19/20 exit 0, 1 NOT MEASURED per its own PREREQUISITE text — accepted. os-zhuang + hotlong requested; PR stays DRAFT; card → pm:awaiting-maintainer.

    Half C — falsification accepted as re-triage input; the answer is Option A. This is a sequencing call inside the PM's discretion and does not reopen 批 #12: the ruling's operative instruction is 「按 #13582 已记路径落地」, and the dev measured that #13582's own recorded, triage-ruled build (a word table, per-word ledgers, a co-occurrence matcher) IS the real shape of this work — the "add one word" phrasing was the option text's mechanism guess, now measured false against WORD = /\brole(?:s)?\b/gi and the flat one-word baseline. So half C lands AS #13582 in its owning lane (domain:devx), not as a duplicate PR here: B pays for the same build twice; C (regex alternation) is ruled against on #13582 itself and corrupts the gate's remedy text. The dev's unblocking measurements (the gate is ALREADY registered at package.json:56 / lint.yml:1757, so #13582's workflow-slot hold premise is stale) and word-candidate data (presence-phrasing 14 hits/13 files avoids coupling to in-flight #13717's face; a NoSQL pin does not) are appended on #13582 as evidence for its taker.

    This card closes when PR #13746 merges — the PM closes it manually at that landing (the PR deliberately carries Part of, and a body PATCH to add a closing keyword would damage the create-path attribution footer, a measured hazard). The reported discoverability gap (SKILL.md's 双肢 paragraph doesn't name the skills/** face among contract-review.md's routed topics) rides audit #13597 Phase 3 as a one-line rider — recorded there.


    Generated by Claude Code

  10. added
    pm:awaiting-maintainerAwaiting a manual maintainer action — ruling already given; no dispatch, no machine exit
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Aug 31, 2026
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:skillsDomain lane — seat card indexed by label:pm:seat

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions