Skip to content

docs(pm): label writes re-read current labels in the same action — stale snapshots are invalid snapshots (#9226) - #9238

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-9226-label-write-reread
Aug 17, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-9226-label-write-reread

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #9226

Main deliverable — references/platform-readings.md (in-place, line-neutral)

The issue_write labels whole-set-replace trap line is rewritten in place (no new lines). Core increment per the card: 写标签前同一动作内重读现值合并 —— 隔轮/隔小时的旧读数视为无效快照. All pre-existing elements are preserved: whole-set replace (not append), the silent-stripping consequence, true append via REST POST /issues/{n}/labels, and the post-write read-back. Rationale (from the card): the old wording pinned read-then-union but not the freshness of the read — a reading taken early in a round plus a write 80 minutes later satisfied it literally while bypassing it semantically; post-write read-back cannot catch this class, so the only effective defense is compressing the read-write window to seconds.

Piggyback (scope-addendum comment on #9226) — landed, not dropped

SKILL.md review section (the skill-surface ACCEPT 三件套, item ①) now states that the review seat for clause-① skill-surface PRs must itself run at the contract-review tier, referenced via the dispatch-gates constant CONTRACT_REVIEW_TIER — no model name written, single source preserved. Funded line-neutrally by extending the existing line (long-line precedent in the file: lines up to 492 chars); no re-wrap, no new line.

Line budget (ratchet, read on the spot)

file before after ceiling
.claude/skills/pm-dispatch/references/platform-readings.md 133 133 134
.claude/skills/pm-dispatch/SKILL.md 682 682 682

Tier derivation (verbatim, node scripts/pm/dispatch-gates.mjs --tier on the changed paths)

Model tier — MANDATORY: claude-fable-5 (derived from the file surface, not recalled).
  - .claude/skills/pm-dispatch/SKILL.md ⇢ '.claude/skills/pm-dispatch/**' — clause ① of the model-tiering ruling: a card editing the PM dispatch skill is fable-mandatory, references included — the skill is the lane's own operating protocol and a wrong edit propagates to every later dispatch
  - .claude/skills/pm-dispatch/references/platform-readings.md ⇢ '.claude/skills/pm-dispatch/**' — clause ① of the model-tiering ruling: a card editing the PM dispatch skill is fable-mandatory, references included — the skill is the lane's own operating protocol and a wrong edit propagates to every later dispatch
  The only exit is the measured quota exemption (fable unavailable ⇒ opus, never lower), recorded with its reason in the claim comment's `Container & model` line.
  Clause ② is NOT reachable from paths: a card that changes contract accept/reject behaviour or widens the public surface is fable-mandatory too, judged from the card CONTENT. This line is a FLOOR, never a clearance.

Verification — gate union re-run after the final commit, at 0627eed38

doc-authoring: PASS
doc-formula-expressions: PASS
pm-skill-id-lint: PASS
pm-skill-ratchet: PASS
skill-frame-sync: PASS
nul-bytes: PASS
union at HEAD: 0627eed38

Gate families re-derived from the actual changed paths (node scripts/pm/dispatch-gates.mjs on the two files): the five families above, matching the dispatch expectation; no additions beyond the derived set. .claude/-only change — releases nothing; skip-changeset applied.

This is a skill-surface PR (.claude/skills/**): draft, awaiting a human merge — never ready/queue/auto-merge.


Generated by Claude Code

… — stale snapshots are invalid (#9226)

In-place, line-neutral rewrite of the issue_write labels whole-set-replace
trap line in platform-readings.md: the freshness of the read is now pinned
(re-read current values within the same action; a reading from an earlier
round/hour is an invalid snapshot). Piggyback per the scope-addendum comment:
SKILL.md review section now states that the review seat for clause-1
skill-surface PRs must itself run at the contract-review tier, referenced
via the dispatch-gates CONTRACT_REVIEW_TIER constant (no model name).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TNzEetykdh7ceZGwuAPLq
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 17, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 17, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 17, 2026 11:50
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 17, 2026
Merged via the queue into main with commit 862eb14 Aug 17, 2026
23 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-9226-label-write-reread branch August 17, 2026 13:15
os-zhuang pushed a commit that referenced this pull request Aug 17, 2026
…9395)

Implements the maintainer ruling on #9319 decision 2 (2026-08-17): the
`ADR maintainer approval` gate's path predicate extends to
`.claude/skills/**`, so Prime Directive #14's human-merge reservation is
machine-enforced on the lane's own protocol surface rather than declared.

- the single ADR prefix becomes a GOVERNED_SURFACES table: identical pass
  conditions (an APPROVED standing + no armed auto-merge), distinct failure
  wording, each surface naming its own rule;
- the #8012 armed-auto-merge clause reaches the new path class identically,
  with its own emptiness proof (identical reviews, opposite verdicts);
- one path hit governs the whole PR -- a mixed diff is never judged by
  proportion, pinned by comparing a 1-of-4 verdict with a 1-of-1 one;
- the report renderer is pure, so the "each surface names its own rule"
  requirement is asserted on the text an operator actually reads;
- PR #9238 -- the skills-only PR the merge queue landed with zero reviews --
  joins the historical replay fixtures as a real capture, pinned RED.

The workflow needed no trigger change: it carries no `paths` filter (a path
filter would skip the whole workflow and hang the queue on a required context
that never reports), and #9238 already produced a completed `ADR maintainer
approval` check run through the clean path.

No existing check is weakened: every prior assertion still runs, and the
self-test goes from 66 to 96 assertions.

Fixes #9395
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 23, 2026
…bjectstack-ai#9395) (objectstack-ai#9407)

Implements the maintainer ruling on objectstack-ai#9319 decision 2 (2026-08-17): the
`ADR maintainer approval` gate's path predicate extends to
`.claude/skills/**`, so Prime Directive objectstack-ai#14's human-merge reservation is
machine-enforced on the lane's own protocol surface rather than declared.

- the single ADR prefix becomes a GOVERNED_SURFACES table: identical pass
  conditions (an APPROVED standing + no armed auto-merge), distinct failure
  wording, each surface naming its own rule;
- the objectstack-ai#8012 armed-auto-merge clause reaches the new path class identically,
  with its own emptiness proof (identical reviews, opposite verdicts);
- one path hit governs the whole PR -- a mixed diff is never judged by
  proportion, pinned by comparing a 1-of-4 verdict with a 1-of-1 one;
- the report renderer is pure, so the "each surface names its own rule"
  requirement is asserted on the text an operator actually reads;
- PR objectstack-ai#9238 -- the skills-only PR the merge queue landed with zero reviews --
  joins the historical replay fixtures as a real capture, pinned RED.

The workflow needed no trigger change: it carries no `paths` filter (a path
filter would skip the whole workflow and hang the queue on a required context
that never reports), and objectstack-ai#9238 already produced a completed `ADR maintainer
approval` check run through the clean path.

No existing check is weakened: every prior assertion still runs, and the
self-test goes from 66 to 96 assertions.

Fixes objectstack-ai#9395

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
…he pre-ruling landing (objectstack-ai#18148)

Fixes objectstack-ai#18083

`scripts/pm/check-governed-queue-guard.mjs` decides on an authorized
APPROVED review and has
since the 2026-09-04 predicate landed. What had not moved was the text a
seat is told to
consult: the docblock called a draft awaiting the maintainer's own merge
the regime's terminal
state, and the printed remedy's preferred option told a seat to take the
PR out of the queue
"and leave the merge to the maintainer". Since the charter chain landed
(PR objectstack-ai#18018 `9489e2c0`,
PR objectstack-ai#18038 `c185d087`, PR objectstack-ai#18051 `137eb00e`) the rule is ruling C — issue
objectstack-ai#17971, maintainer
2026-09-13, verbatim and untranslated:

> C. approve 后不管后续改动都由席位落地:

So the narration under-permitted: it told a seat not to do the thing the
rule now says it
should do once an authorized approval is on record.

## What moved

Wording only. ⛔ No decision branch changed — `entrySatisfied`, the
approval reduction, the
tier split and every exit code are untouched. Anchored by content, not
by line number.

1. **Docblock, the "why the PR leg must not redden" paragraph.** The
healthy resting state is
now a draft *waiting for an authorized approval*, in the landed rule's
own words from
`.claude/skills/pm-dispatch/references/landing-operations.md`: 「四件套留
draft 等人批,⛔ 不翻正式不入队;获授权批准后认领席落地。」
2. **Docblock, a new paragraph for what happens after the approval** —
ruling C, quoted
verbatim, plus `SKILL.md`'s operational half: 「席位落地 =
过落地前检、清标、ready、auto-merge,踢出/变基同法。」
The seat's ready → enqueue is now stated as the correct next act there
rather than a violation.
3. **Docblock, the "this guard cannot stop a direct merge" paragraph.**
The direct merge is now
the OTHER landing rather than the only one — `references/core-rules.md`:
「受管面由维护者人合或授权批准后席位落地」.
   The objectstack-ai#11387 measurement it cites is kept verbatim as history.
4. **The `pull_request` leg's EARLY WARNING rendering.** The ⛔ list
(flip ready / enqueue / arm
auto-merge) is now explicitly conditional — "while no authorized
APPROVED review is on
record", with AGENTS.md Prime Directive objectstack-ai#14's own "lift only for that
approval" — and a new
   ✅ line says what a seat DOES do after the approval.
5. **The `merge_group` refusal remedy.** Steps 1 → 2 are now an order
rather than a menu:
out of the queue first, then the authorized approval, and the CLAIMING
SEAT lands it from
there. The unapproved direct merge (人工直合) is kept as the landing that PR
still has.
6. **Two internal comments** that restated the same pre-ruling shape:
the tier-default
asymmetry cost (was "costs one hand merge") and the exit-code precedence
note.

The references tier is untouched and still says the in-seat review of
record lands it: remedy
option 3 renders byte-for-byte as before, and both of its pins (offered
on a references-only
refusal, withheld on a rules-layer one) still pass.

## Acceptance readings

Taken on `a2e4cd7d9`, in the worktree, against merge base `a90a9f267`.

**The two pre-ruling phrases, in the narration and the printed text: N →
0.**

| reading | before | after |
|---|---|---|
| `git grep -c -E 'leave the merge to the maintainer\|human merge IS the
review record'` | 2 | 2 |
| … of those, hits in narration or printed remedy | 2 | **0** |
| … of those, hits inside the self-test pin that FORBIDS them | 0 | 2 |

Both remaining hits are the new negative assertion itself — a comment
and the regex literal in
`⛔
a-refusal-never-tells-a-seat-to-leave-the-merge-to-the-maintainer-nor-calls-that-merge-the-record`.
A pin has to name what it forbids; neither is text the guard ever
prints.

**The landed phrase: 0 → 5** (`git grep -c 'CLAIMING SEAT
lands\|claiming seat lands'`).

**Every hit of the pre-ruling wording enumerated** (`git grep -n -E
'hand merge|human merge|leave the merge|人工合'`),
6 before → 4 after, and each remaining one accounted for:

- `:44` 「人工合并即人工审核」 (docblock) — **moved**.
- `:52` "the human merge IS the review record" (docblock) — **moved**.
- `:536` "costs one hand merge" (tier-default comment) — **moved**, now
"costs one authorized approval".
- `:1171` 「人工合并即人工审核」 (EARLY WARNING rendering) — **moved**.
- `:1242` "leave the merge to the maintainer. A human merge" (remedy) —
**moved**.
- `:2010` (was `:1983`) the `objectstack-ai#9319` replay fixture's name, quoting PR
objectstack-ai#9238's own body: "a .claude/skills PR whose own body said 'awaiting a
human merge'" — **stays**. It is a historical measurement naming what
that PR said in 2026; rewriting it would falsify the fixture.
- `:2429`, `:2436`, `:2468` — **new**, the three negative pins (two
English phrases, one 人工合并即人工审核).

**Self-test:** `node scripts/pm/check-governed-queue-guard.mjs
--self-test` :: exit 0,
**233 cases before → 238 after** (5 added, none removed, no battery
floor lowered).

**Diff surface:** `git diff --stat a90a9f2` names exactly one file,
`scripts/pm/check-governed-queue-guard.mjs`, 104 insertions / 32
deletions. `origin/main`
advanced under this worktree during the run (`a90a9f267` → `739ab526d`,
a shared-ref hazard
AGENTS.md names), so the anchor above is the merge base, not the moving
ref.

**Governed?** No — `node scripts/pm/check-governed-merges.mjs --test
scripts/pm/check-governed-queue-guard.mjs`
:: exit 0, "NOT governed — ordinary queue landing applies". This PR is
opened as a draft and the
seat lands it; nothing here flips ready or arms anything on its own.

## Reverse verification — the new pins can actually fail

One-shot, from the committed state, with a `trap … EXIT INT TERM`
restoring absolute paths.
Predicted direction: **turns red**.

- HEAD blob `f7938efe94a20f34a3c1e6f07e2aaca393f16a47`.
- Mutation: the remedy's step-2 line rewritten back to the pre-ruling
wording. On-disk
observation, anchored on both texts: landed anchor 1 → **0**, injected
stale phrase 0 → **1**;
blob `87b912dbc8acaf5af5d02fb86cc06eb2bcffd986` ≠ HEAD blob, so it
reached disk.
- Mutated leg: `--self-test` :: **exit 1**, `✗ 2 of 238 case(s) failed`
— exactly

`a-refusal-orders-the-remedy-DRAFT-then-the-authorized-APPROVAL-then-the-CLAIMING-SEAT-lands-it`
and `⛔
a-refusal-never-tells-a-seat-to-leave-the-merge-to-the-maintainer-nor-calls-that-merge-the-record`.
- Restore leg: `git checkout HEAD -- FILE` → blob back to `f7938efe…`
(byte-identical),
`git diff HEAD` empty, `git status --porcelain` empty, anchor restored
1, injected 0.
- Restored leg: `--self-test` :: exit 0, 238 cases pass.

## Gates

Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`
(no paths, three-dot against merge base `a90a9f267`) — **33 commands,
all run in the
foreground, every exit code captured before any pipe, all `exit 0`.**
Reconciled:

```
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RAN_FILE
Run reconciliation — 33 derived, 33 run, 0 NOT-MEASURED, 0 UNRUN.
✓ 33 derived famil(ies) accounted for — a DERIVED zero — all 33 recorded an exit code and none of them is 3.
```

Including `node scripts/pm/check-governed-queue-guard.mjs --self-test`
:: exit 0 and
`pnpm check:nul-bytes` :: exit 0. `pnpm check:pm-governed-merges` ::
exit 0 was run too, though
the derivation does **not** place it for this path — it is a
`--self-test`-only checker-health
family here, so its green grades that checker's fixtures, not this diff.

Control characters: `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` over
the changed file — no hits.

No changeset: `scripts/pm/**` ships in no package's `files[]`, so this
publishes nothing — the
`skip-changeset` label carries it.

## Acceptance notes

Two observations outside this card's one-file surface, noted and not
filed (this seat's write
budget for the round is the branch push, this PR, the label and one
report comment):

- `scripts/pm/check-governed-merges.mjs` :140 and
`scripts/check-required-contexts.mjs` :288
both still say "a human merge IS the review record" for a governed PR.
Neither is wrong —
it is one of the two terminals the charter names 「终局两条:人工直合即审核记录;授权批准 ⇒
席位落地。」 —
but neither mentions the second one. That is an omission rather than a
contradiction, so it is
not the class this card is. Issue objectstack-ai#18083 fences the first file off from
this PR by name.
- `.claude/hooks/guard-governed-enqueue.sh` :548 was checked and is
already ruling-C shaped
(its steps read draft → wait for the approval → "Then enqueue"), so it
needed nothing.

_Generated by [Claude
Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_

---
_Generated by [Claude
Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

技能卡:标签写前同动作内重读——陈旧快照整组回写陷阱行收紧(行中性)

2 participants