Skip to content

docs(pm-dispatch): timestamped readings are the first construct-shaped fix; record the remediation-shape ranking beside it - #14784

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-12911-timestamped-readings
Sep 3, 2026
Merged

docs(pm-dispatch): timestamped readings are the first construct-shaped fix; record the remediation-shape ranking beside it#14784
os-project-manager merged 1 commit into
mainfrom
claude/issue-12911-timestamped-readings

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes #12911

Governed surface (.claude/**) — DRAFT, human merge only; never flipped ready, never queued, never armed. Review requests are the dispatching seat's step, not this flight's.

The ruling, verbatim and untranslated

Director seat, summon #8, 2026-09-02 (comment 5507671383 on the card). Provenance: maintainer, live PM chat with the director seat, replying to decision batch #4 in which this card was item 3. Verbatim reply:

13973 帮我综合分析,并参考主流平台的方案,并给我解释为什么不能都用日期类型。其他同意

「其他同意」 adopts B + A. The ruled text, verbatim:

  • B (construct-shaped, lands first in the same PR): every board / tree / queue reading a PM seat states — in a claim, a dispatch order, a review, a round report, a seat-post segment — carries the moment it was taken (UTC timestamp, and the ref or tip where the reading is of a tree). A reading without its timestamp is malformed, not current: the reader treats it as untaken. This changes what gets typed, not what has to be recalled, which is the discriminator this card measured.
  • A (the meta-rule, recorded beside B): when a PM-side failure is recorded, the amendment prefers, in order: (a) remove the construct that permits the error; (b) make the correct form the only one the protocol spells; (c) add a check the PM must remember. (c) is what recurred; (a) is what held. Option C (mechanise all four instruments) and D (do nothing) are not taken; the three remaining instruments (fence derivation, census/grep, loop refill) are not mechanised in this ruling — measure B's effect first.

Nothing is re-decided here. C and D stay refused; the other three instruments stay un-mechanised (that non-action is recorded on the card, not in the skill text — the skill carries rules, not history).

What landed — .claude/skills/pm-dispatch/SKILL.md only

One bullet in 「平台读数纪律」 grew by six continuation lines; no existing line was changed, moved or re-wrapped (git diff --stat: 1 file, 6 insertions, 0 deletions).

Where and why there. B is folded into the existing reading-validity bullet — 「零命中必须用确定存在的邻近词反查, 否则零命中不成立」 — because it has exactly the same shape: a condition under which a reading is not a reading. A zero without a control does not hold; a reading without its timestamp is malformed. One rule, stated once, in the file's own register; no new bullet.

Before (origin/main 224f8ea4, L163–L165 — the whole bullet):

- **零命中必须用确定存在的邻近词反查**,
  否则零命中不成立;仓不可达同理,⛔ 不因「查不了」
  当「查过了干净」—— 在 issue 上贴出给对应座位的现成命令,等读数回贴再派。

After (3612bd4e1, L163–L171; L163–L165 byte-identical, L166–L171 new):

- **零命中必须用确定存在的邻近词反查**,
  否则零命中不成立;仓不可达同理,⛔ 不因「查不了」
  当「查过了干净」—— 在 issue 上贴出给对应座位的现成命令,等读数回贴再派。
  **同为成立条件 —— 板面/树/队列读数自带取数时刻**(维护者 2026-09-02 裁「其他同意」):
  写进认领、派发令、复核、轮次报告、座位贴段落的读数恒带 UTC 时间戳
  (形如 `2026-09-03T00:21Z`),树读数另带 ref 或 tip;无时间戳的读数是格式错误不是现值,
  读者按未取处理 —— 改的是键入什么,不是要记住什么。**PM 侧失效的修法按序取**:
  (a) 删掉容许出错的构造 → (b) 让正确形态成为协议唯一拼写 → (c) 加一条要记住的检查;
  (c) 型屡复发、(a) 型守住 —— 占位符禁令与本条取数时刻皆 (a) 型。
  • B = L166–L169 (first clause). The five reading sites the ruling names, in the file's order of use (认领 · 派发令 · 复核 · 轮次报告 · 座位贴段落); UTC timestamp with one spelled example so the correct form is the only one the protocol spells (the (b)-shaped half, at zero extra lines); ref or tip for tree readings; the malformed-not-current reading rule; the discriminator sentence.
  • A = L169 (second clause)–L171. The (a) → (b) → (c) ranking, the measurement (「(c) 型屡复发、(a) 型守住」), and the two worked (a)-shaped examples the file now carries: the placeholder ban at L150–L153 (unchanged; see finding 1) and this bullet.

Line arithmetic, from the gate's own verdict lines (pnpm check:pm-skill-ratchet):

lines ceiling headroom widest table row
before, origin/main 224f8ea4 ✓ … SKILL.md is 989 lines (ceiling 1005; headroom 16). 1005 16 642 bytes (pin 642; headroom 0)
after, 3612bd4e1 ✓ … SKILL.md is 995 lines (ceiling 1005; headroom 10). 1005 10 642 bytes (pin 642; headroom 0)

Spent: 6 of 16. Paid by deletion: none — I looked for a restatement beside the landing site to delete and found none. Each of the neighbouring bullets' load-bearing phrases is single-sited in this file (维护者中止 ×1 at L173, 聚合读数 ×1 at L170, 共享检出 ×1 at L162, 对向事实 ×1 at L181, pin 反转 ×1 at L182, 邻近词 ×1 at L163); 查重 appears 8× but every other occurrence is a pointer or a different rule (cross-repo shadow check, sub-issue channel), not a restatement of the L176 立单前查重 rule. So the six lines come from headroom, and no #13597-style Phase-2 cut was started. ⛔ No re-wrap as payment: the diff is insertions only. ⛔ No ceiling raise. The first attempt at these lines was 126–133 bytes wide and the ratchet's length rule went red on L166–L169 (4 line(s) over the 120-byte budget); only the six NEW lines were re-wrapped to ≤118 bytes — that is wrapping my own text, not paying with the file's.

Verification facts, as the ruling asked

(1) Did #11901's construct-removal ever reach persistent skill text? — Yes. It landed 2026-08-25, three days before the card.

The triage comment (2026-08-28) concluded 「#11901 的那次「construct-removal」没有落进任何持久指令文本」 from a zero on the single spelling the card's re-check used (绝对路径). That zero is real but measures the wrong spelling. Searched on origin/main 224f8ea4 across .claude/skills/pm-dispatch/** and .claude/agents/os-dev.md (git grep -c -F, summed hits; every zero has a positive control beside it):

spelling hits reading
绝对路径 0 the card's own re-check — a true zero, wrong spelling
angle-bracket / angle bracket / placeholder / spell it in words 0 English spellings of the #11901 triage note never entered the Chinese-register files
尖括号 12 SKILL.md L150PM 写进 GitHub 的文本 ⛔ 不用尖括号路径占位符, 改写成「后跟显式路径」的说法 … 不产生这个构造才是修法, 回读只是兜底」; os-dev.md L356; platform-readings.md ×10
占位 6 os-dev.md L357 「尖括号形状片段一律改占位词拼写」; platform-readings.md L248, L253 「运算符用词拼出,或占位词定义一次」; SKILL.md L150; landing-operations.md L79 (unrelated sense)
angle-bracket path-placeholder tokens (the literal word path in angle brackets) 9 all reader-facing command templates (git show origin/main: + path, git checkout HEAD -- + path …), the same four the triage already classified as not the construct — plus os-dev.md's ablation recipes
positive controls domain: 44 · 路径 68 · Blocked-by: 26 the paths are readable; the zeros above are measurements

Dating (the clone was shallow — 242 commits, graft at 873ff0f — so git log -S first reported the graft boundary; deepened twice to 2,320 commits, oldest 2026-08-17): git log -S'尖括号路径占位符' -- .claude/skills/pm-dispatch/SKILL.mdde98599, 2026-08-25 09:16Z, PR #12086 「SKILL.md discipline pack — six scoped protocol amendments」 — the PR through which #11901 reached CLOSED/COMPLETED (the card's closedByPullRequestsReferences names exactly that PR). os-dev.md's 占位词 spelling: 04600d9, 2026-08-26 (PR #12440). platform-readings' 用词拼出: same 2026-08-26 commit, widened 2026-08-29 (47fd377).

So the #11901 triage note (os-zhuang, 2026-08-25 05:14Z: 「PM-authored text does not use angle-bracket path placeholders; spell "followed by the explicit path" in words — because it removes the construct instead of adding a check; plus the narrow read-back rule as the backstop」) was delivered in full, four hours later, to SKILL.md L150–L153 — construct-removal as the fix and read-back as the backstop, in those words. The card's discriminator sample stands: the (a)-shaped fix that held is also the one that reached persistent text. The triage's weakening (「若那次修复其实只是一个席位在会话内的习惯 …」) does not apply. Not landed here: the rule already exists; the new text only cites it as the sibling (a)-shaped example (「占位符禁令」).

(2) B's boilerplate cost — light: ≤1 % on claims and dispatch orders, ≈2–5 % on round reports; the round report is the heaviest site.

Reading sites the protocol prescribes, enumerated from SKILL.md at 3612bd4e1:

site where prescribed readings per artifact (typical)
claim comment L541–L549 template: Serial constraints cleared: (in-flight/board), Container & model: tier from dispatch-gates --tier output (tree) 2
dispatch order L626–L653: 「清单、路径、行号在派发那一刻从树上取」 (tree), same-day churn line (tree), 在飞重叠拦截 (board), stale-premise check 三面 L481–L495 (tree + board) 3–6
review / ACCEPT L705–L724: get_files path face, gate-job conclusions, 「抽查读数」 2–4
round report L800–L812: five health indicators (可派发库存 · 决策箱 · finding 数与中位年龄 · 裸卡数与中位年龄 · 发版阻塞) + governed 合并审计 + UNRECOGNISED line 5–8
seat-post segment L285–L300 四段现值 at round boundary; the 开轮标记 (session ID + fire 时刻) and 收班简报 timestamp (L333 anchor) are already timestamped by existing protocol ≤4, two already stamped

Per-reading cost: a UTC stamp 2026-09-03T00:21Z is 17 bytes; a tree reading adds a ref/tip such as origin/main 224f8ea4 (≈21 bytes) — ≤ ~40 bytes per reading, plus one date -u per reading pass (most inputs already carry their own time: git --date, updated_at, check-run timestamps).

Measured on this card's own artifacts: the dispatch order for this flight (~5,400 chars) states 2 stampable readings (the origin/main line count — which carried neither stamp nor tip — and the claim-state board reading; the third, the triage's zero, is carried by that comment's own timestamp) → ≈55 bytes, ≈1 %. The claim comment 5518388833 (~2,400 chars) states 1 (the two sibling PRs merged, face free) → 17 bytes, <1 %. A round report with 8 readings pays ≈300 bytes on a multi-KB report, ≈2–5 %. Honest caveat: the byte cost is small; the real cost is that the stamp must be taken at read time — which is precisely the construct the ruling wants, since a reading typed without one is now visibly malformed instead of silently stale.

Gates (every exit captured by redirect before any pipe; each gate's own verdict line quoted)

All at HEAD 3612bd4e1, the final commit; the union was derived AFTER the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no hand-fed paths; stderr: gate list derived from the tree of 'objectstack-ai/objectstack' at commit 3612bd4e1 … change set derived from git — 1 path(s) vs merge base 224f8ea4a). Union = check:doc-formula-expressions (lint pkg) · check:agent-test-spelling · check:doc-authoring · check:pm-governed-merges · check:pm-governed-prose · check:pm-skill-id-lint · check:pm-skill-ratchet · check:skill-frame-sync. Four of the union were not in the dispatch list and were run in addition; four of the dispatch list are not in the union and were run anyway.

gate exit verdict line
check:pm-skill-ratchet (+ --self-test) 0 ✓ check-skill-line-ratchet self-test: 111 cases pass. · ✓ … SKILL.md: widest table row is 642 bytes (pin 642; headroom 0). · ✓ … SKILL.md is 995 lines (ceiling 1005; headroom 10).
check:pm-skill-id-lint 0 ✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
check:skill-frame-sync 0 ✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files
check:skill-frame-freshness 0 ✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now).
check:pm-dispatch-gates 0 self-test suite green (last line ✓ a valueless run record refuses, and its message does not name the OTHER flag)
check:pm-governed-merges 0 --self-test green (exit 0, no ✗)
check:corpus-claim-drift 0 exit 0, no ✗
check:nul-bytes 0 exit 0, no ✗
check:agent-test-spelling (union) 0 ✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare -- token(s) …
check:doc-authoring (union) 0 ✓ doc authoring guard: 46 published skill files clean — no internal issue-id references. (+3 more ✓ lines)
check:pm-governed-prose (union) 0 ✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
check:doc-formula-expressions (union, @objectstack/lint) 0 (after building @objectstack/spec, @objectstack/formula, @objectstack/lint under the lock; the first two runs were exit 3 PREREQUISITE NOT MET, recorded as NOT MEASURED, never as a flake) ✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 426 files / 1365 TS blocks judged clean by @objectstack/formula. · ✓ … (spec TSDoc): 9 @example(s) judged clean across 1120 packages/spec/src files … · ✓ … (field-level *When): 14 predicate(s) … judged clean; 6 skipped as undeterminable.

Deviation, declared: the ratchet and the @objectstack/formula build ran under scripts/pm/os-verify-lock.sh (slot issue-12911); the batch of seven check:* gates queued under the same lock was killed at the platform's 10-minute foreground cap (exit 143, after 3 of 7 had already returned 0), so the check:* gates were re-run unlocked at HEAD. The lock's own --status text classifies check:* gate scripts as unlocked sibling work it never excludes, and os-dev.md's lock rule names build/test; this is the declared narrowing, not a skipped gate.

Premise checks

  • premise_falsetriage comment 5453234724: 「pm-dispatch: the PM tells every dev to read its comment body back, and never does so itself — 2 of 5 dispatch orders in one round shipped a truncated restore command #11901 的那次「construct-removal」没有落进任何持久指令文本」 — false on its own date; see finding (1). The card's re-check zero on 绝对路径 holds as a zero; it never held as evidence.
  • Held: the dispatch's measurement 「989 lines against ceiling 1005 (headroom 16), widest-table-row pin 642」 — matched by the gate's verdict line before writing.
  • Held: 「the seat has already claimed the card」 — claim comment 5518388833 (branch claude/issue-12911-timestamped-readings, this session); assignee and labels untouched by this flight.
  • Held: skip-changeset applies — nothing is published from any package; the diff is .claude/** only.

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…d fix; record the remediation-shape ranking beside it

Every board / tree / queue reading a PM seat states — in a claim, a dispatch
order, a review, a round report, a seat-post segment — carries the UTC moment
it was taken (and the ref or tip when the reading is of a tree). A reading
without its timestamp is malformed, not current: the reader treats it as
untaken. Folded into the reading-validity bullet of 平台读数纪律 beside the
zero-hit control rule, which has the same shape.

Recorded beside it: when a PM-side failure is recorded, the amendment prefers
(a) remove the construct that permits the error, then (b) make the correct
form the only one the protocol spells, then (c) add a check the PM must
remember — (c) recurred, (a) held.

Maintainer ruling 2026-09-02, verbatim: 「其他同意」 (adopting B + A).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:33
@os-zhuang
os-zhuang enabled auto-merge September 3, 2026 02:33
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710779173 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test:  FAIL   integration  test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
      ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 49 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33711768020 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test:  FAIL   integration  test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
      ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 51 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 3, 2026
@os-project-manager
os-project-manager added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit 1596b4c Sep 3, 2026
31 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-12911-timestamped-readings branch September 3, 2026 09:56
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

4 participants