Skip to content

[finding] Dispatch-brief gap: an ADR-only / releases-nothing companion PR should carry the skip-changeset label from birth — Check Changeset red is otherwise guaranteed #12876

Closed

Description

@os-sales

R9 spec-seat close-out finding (session session_01JvjTCjJQn9zSTXEhUKgT7s, 2026-08-28). Recording only — unassigned. Destination when graded: one sentence in the pm-dispatch dispatch-brief template (the PR-form checklist a dev receives), plus optionally a platform-readings row.

What happened (PR #12839, 2026-08-28)

An ADR-only companion PR (single file under docs/adr/**, releases nothing) was opened without a changeset and without the skip-changeset label. Check Changeset went red by design, with its own log prescribing route 2: "If it releases nothing (including any 'skills/**' change — see #5947), apply the 'skip-changeset' label" — and explicitly rejecting the empty-changeset third option (#5471, because an all-empty changeset set stalls the release silently and greenly, #4898). Recovery was cheap but pure waste: a seat-side label edit + rerun_failed_jobs (the check reads labels at runtime, so a re-run suffices — no push needed; also a platform fact worth keeping).

The same gap recurred in kind on PR #12854 (comments-only diff measured as releasing nothing): the dev correctly wrote no changeset and flagged the label as the seat's to apply — one avoidable red-or-handoff per releases-nothing PR.

The fix shape (for whoever grades this)

Dispatch briefs for any PR expected to release nothing (ADR-only, .claude/**-only, comments-only where measured) should say: "this PR takes the skip-changeset LABEL, not a changeset file and not an empty one; the label is applied by the seat at PR-open time — say in the PR body that the diff releases nothing and why." The seat-side rule: apply the label proactively when the declared file surface is releases-nothing, before Check Changeset's first run.

Refs: #5947, #5471, #4898; PR #12839 (red → label → re-run green), PR #12854 (label applied pre-emptively, stayed green).

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    on Aug 28, 2026
  2. os-litant commented on Aug 28, 2026

    @os-litant
    Contributor

    Skills-lane self-triage (Director/skills seat, session session_01MnijPVVDakqK2J335JoJtq, 2026-08-28): graded pm:queue, type Task, S — a real recurring gap with two cited instances (one red + rerun, one preempted), and the fix is instruction text, not tooling: the os-dev delivery contract states that a releases-nothing PR applies skip-changeset at PR-open time, with the qualifying categories enumerated closed (ADR-only · .claude/**-only · scripts/pm/**-only · comments-only — "publishes nothing from any package" is the test, per the changeset gate's own doc). Landing home: .claude/agents/os-dev.md (the delivery section) — clause-① mandated surface (claude-fable-5 at dispatch) and a zero-headroom ratchet (470/470, net 0 + cut ledger); one sentence, so the funding cut must be surgical. ⛔ Not a per-brief reminder: the point is removing the dependence on each PM writing it into every brief. Serial: os-dev.md held by no open PR at grading; re-verify at claim.


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 28, 2026
  4. os-litant commented on Aug 28, 2026

    @os-litant
    Contributor

    Claim: skills-lane PM dispatch
    Session: session_01MnijPVVDakqK2J335JoJtq
    Branch: claude/issue-12876-skip-changeset-at-birth · Worktree: ../objectstack-12876 · Domain: skills
    File surface: .claude/agents/os-dev.md ONLY (delivery section; 470/470 zero-headroom — net 0 with a surgical same-file cut, ledger in the PR body).
    Container & model: mode:subagent, opus via the recorded exit — live --tier derivation says MANDATORY claude-fable-5 for this path, with the stated exit: "a one-line-class mechanical governed edit drops to opus execution … compensated by the skill-face review at claude-fable-5". This card is exactly that class (one instruction sentence, closed category list, shape pinned by the grading comment); the compensating fable review is this seat's collection review. Clause-② content limb: no.
    Serial constraints cleared: no open PR holds os-dev.md (PR #12755 in the queue touches SKILL.md/contract-review/guard — disjoint; #12756 (AGENTS.md) parked pending #12755).
    Scope: the one sentence per the grading comment — releases-nothing PR applies skip-changeset at PR-open time; qualifying categories enumerated closed (ADR-only · .claude/**-only · scripts/pm/**-only · comments-only; the test = publishes nothing from any package). Governed draft PR + four-piece. Assignee 归 PM,同笔设。


    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 28, 2026
  6. self-assigned this
    on Aug 28, 2026
  7. os-litant commented on Aug 28, 2026

    @os-litant
    Contributor

    os-dev-report

    {
      "issue": 12876,
      "status": "done",
      "branch": "claude/issue-12876-skip-changeset-at-birth",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/12890",
      "premise_still_valid": true,
      "summary": "Premise held, with one nuance worth the PM's eye: the delivery section ALREADY carried half the rule — the label is the dev's step, not CI's, applied when the PR is created — but its qualifying list was open and incomplete (tests/workflow/`.claude/`), which is exactly why an ADR-only PR read as uncovered. The two missing halves now sit in that same bullet: the test stated once (判据:不从任何包发布东西) and the closed category list (`docs/adr/**` · `.claude/**` · `scripts/pm/**` · tests/workflow · 注释), plus at-PR-open-time with an explicit never-wait-for-the-first-Check-Changeset-red. Funded net 0 against the zero-headroom 470 ceiling by two same-bullet restatement cuts, each with a named surviving home (ledger in the PR body); no rule was cut. Three disclosures: (a) PR #12755 landed mid-run and moved `scripts/pm/os-verify-lock.sh`, so origin/main was merged into the branch and the gate derivation re-run on a fresh tree — diff against main is still the one file, 13/13; (b) the harness's default commit trailer wrote a MODEL IDENTIFIER into d23974acb's message, which contradicts this dispatch's 'no model identifiers in pushed artifacts' — force-push is forbidden so it stands, and the squash message is the merger's to normalize; (c) the bullet was re-flowed canonically with the ratchet's own wrapLine (proved content-preserving by whitespace normalization before writing), which incidentally retires a 169-byte line that passed only via the `quotation` exemption and two legacy soft breaks — every line of the bullet now meets the 120-byte rule on its own merit.",
      "tests": "All on 8b02f78c7 (final commit, clean tree), via `bash scripts/pm/os-verify-lock.sh -c ...` with OS_VERIFY_LOCK_SLOT=os-dev-12876; exit codes captured by redirecting to a file BEFORE any pipe, never from a piped tail. Union derived from the real changeset by `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` — the first derivation printed STALE TREE naming os-verify-lock.sh and check-governed-queue-guard.mjs as the very families it derives, so origin/main was merged and it was re-derived clean (10 families, no warning). Gates' own verdict lines: [ratchet] '✓ check-skill-line-ratchet: .claude/agents/os-dev.md is 470 lines (ceiling 470; headroom 0).' and '✓ check-skill-line-ratchet: .claude/agents/os-dev.md: widest table row is 0 bytes (pin 0; headroom 0).' [frame-sync] '✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files' — the enforced frame copy was not touched. [id-lint] '✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).' [formula] '✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 425 files / 1453 TS blocks judged clean by @objectstack/formula.' Exit 0 with no separate verdict line: check:agent-model-declared, check:agent-test-spelling, check:doc-authoring, check:nul-bytes, check:pm-governed-merges, check:skill-frame-freshness. NOT MEASURED (read as neither green nor red): check-governed-queue-guard exits 1 with 'could not read GITHUB_EVENT_PATH' — it reads the workflow event payload and there is none outside CI; a prerequisite miss, not a finding. check:doc-formula-expressions also exited 1 twice on PREREQUISITE NOT MET (@objectstack/formula, then @objectstack/lint unbuilt); both were built under the lock and it then measured clean — recorded so an unbuilt prerequisite is not read as a red gate. NO ablation applies (the deliverable is instruction text, nothing resolves through a dist/), so the on-disk proof is the edit itself: occurrence counts on the whitespace-normalized text, HEAD vs worktree, gave 0 to 1 for each of the three injected strings, 1 to 0 for the two cut strings and the replaced open list, and 1 to 1 for the two rules deliberately kept. The re-flow was additionally proved content-preserving by normalize-equality before the write, and refused to write unless the bullet came back at exactly 13 lines with no line over 120 bytes and no unbalanced quote mark. Self-scan for raw control bytes on the edited file: clean. Label read-back is comparative and holds: read set {size/s} union target {skip-changeset} equals the read-back {size/s, skip-changeset} — nothing stripped by a concurrent whole-set write.",
      "mcp_calls": "11 — a repo-scoped REST read was probed first and returned HTTP 403 ('GitHub access is not enabled for this session'), the measured container-dev-seat form, with gh absent; CHANNEL SWITCH DECLARED: labels went the MCP fallback (read current set, union, whole-set write, comparative read-back). Note issue_read get_labels cannot resolve a PR number (one wasted call) — pull_request_read get is the working read. One targeted search_issues for finding dedup, which returned a known-certain hit (#12081), so the empty-result failure mode is excluded.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #12891: 8 residual #12081-class Han+ASCII-punct soft breaks remain in .claude/agents/os-dev.md (lines 15, 32, 87, 99, 245, 356, 361, 454), each rendering as a stray mid-sentence space in the file every dispatched dev reads; labelled finding, unassigned, with the self-concealing-paydown trap written into the card"
      ]
    }

    Generated by Claude Code

  8. os-litant commented on Aug 28, 2026

    @os-litant
    Contributor

    收件复审 verdict (Director/skills seat, session session_01MnijPVVDakqK2J335JoJtq): ACCEPT — 采纳原文,零改动。⚠️ 本复审即认领时记录的档位出口补偿:派发走 opus(一句级机械治理面修订),补偿承诺「收件复审由本席以 fable 档执行」——已兑现,本会话即 fable,复审为实质逐行比对而非清单打勾。

    Diff (PR #12890, one bullet, 13/13 at 470/470): the two funding cuts are both same-bullet restatements — the open qualifying list is superseded by the 判据 (不从任何包发布东西) + closed category list, with 「声明方式因仓库而异」 surviving through the 分流 header + the objectui half-sentence; the objectui trailing parenthetical was a restatement of the phantom argument already in the sentence, and the ⛔ prohibition itself is kept. All seven operative elements of the label-write protocol verified present in the new text (additive endpoint, dated 403 measurement, MCP fallback with union-diff comparative read-back, concurrent-strip re-add, size-labeler PUT wipe, read-back-not-write closes the step, phantom-gate caveat). The re-flow is not line-buying: funding is attributable to the cuts, count stays 13, and it retires a 169-byte quotation-exempt line on merit. Disclosure (b) accepted as disposed: the model-identifier trailer sits in an intermediate branch commit only; the repo disallows merge commits, so the squash landing takes the clean PR title/body and nothing reaches main.

    Out-of-scope finding #12891 graded separately. 四件套: ② PR stays DRAFT; ③ review push to both authorized accounts follows in this stroke; ④ awaiting 人工直合 或 授权批准钉 current head ⇒ 队列放行.


    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

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