Skip to content

Commit 551139b

Browse files
pm(half-states): H65 reads the tier DECLARATION, not the ASCII string Tier: (#18672)
Fixes #18547 Clause-②: no — `scripts/pm/**` is shipped by no package. Re-judged from the actual diff, measured below, not inherited from the dispatch. ## The row asked one question and answered a different one H65 reports, of a triage round artefact, that it «names NO tier at all — so the two-tier rule … is satisfied by SILENCE here». Its predicate was an ASCII literal: ``` export const H65_TIER_LINE = /^[ \t]*Tier:[ \t]*(\S*)/m; export const H65_TIER_KEY = /Tier:/; ``` The live specimen — objectstack#6015 comment `5706306387` — **does** name its tier, on its headline, as a `·`-delimited field: `**层:小时层(增量)**`. The row reported it as silence because the seat wrote it in Chinese, and one sweep took 46 rows from that one miss. Re-measured on this branch's tree: the English word `Tier` in any casing appears nowhere in `.claude/skills/pm-dispatch/SKILL.md` or `references/dispatch-runbook.md`. The only clause is 「选层按 fire 时刻,⛔ 不用计数器;简报写明本轮跑的层」 — it requires the tier to be **written** and prescribes no spelling. So the repair is in the predicate. ⛔ No `.claude/` path is touched. ## The repair, and the property it preserves A second spelling, closed exactly as the first one is: - **closed key** — 「层」 plus a colon (ASCII or full-width), nothing else; - **closed word set** — 「小时层」/「每日层」, the runbook's own two names, resolving onto the same `hourly`/`daily` pair. Any other word is `unknown-tier`, exactly as `Tier: full` is; - **a declaration slot, never prose** — the start of a line, or immediately after a 「·」 field separator, which is the marker headline's own field idiom. A mention inside a sentence is not a declaration and keeps the verdict it has today; - **the same blockquote refusal** — a quoted line is this artefact repeating another one. One asymmetry is deliberate and named in the source: a leading `**` stays refused on the English line (`**Tier:** daily` is unchanged) and is accepted on the Chinese field, because the measured artefact writes every headline field in bold and refusing it would re-file the same false positive one layer down. ## Verdict table — every fixture, BEFORE and AFTER BEFORE = `origin/main` at `14d25441`; AFTER = this branch. Produced by importing both module copies into one process. | fixture | BEFORE (origin/main 14d2544) | AFTER (this branch) | |---|---|---| | LIVE objectstack#6015 comment 5706306387 (whole body, verbatim) | `absent` | `clean` **CHANGED** | | LIVE headline only | `absent` | `clean` **CHANGED** | | measured tier-less round-open marker (MARKER65) | `absent` | `absent` | | measured round close (CLOSE65) | `absent` | `absent` | | measured stand-down brief (BRIEF65) | `absent` | `absent` | | marker + `Tier: hourly (since ...)` | `clean` | `clean` | | marker + `Tier: daily (first fire of the day)` | `clean` | `clean` | | marker + `Tier: full` | `unknown-tier [full]` | `unknown-tier [full]` | | marker + `Tier: 全量` | `unknown-tier [全量]` | `unknown-tier [全量]` | | marker + `**Tier:** daily` | `not-at-line-start` | `not-at-line-start` | | marker + `> Tier: daily (...)` | `not-at-line-start` | `not-at-line-start` | | marker + mid-paragraph English `Tier: daily` | `not-at-line-start` | `not-at-line-start` | | marker + CN line `层:每日层(当日首 fire)` | `absent` | `clean` **CHANGED** | | marker + CN line, full-width colon | `absent` | `clean` **CHANGED** | | marker + CN line indented | `absent` | `clean` **CHANGED** | | marker + CN PROSE mid-sentence | `absent` | `absent` | | marker + CN prose on a line that has a `·` elsewhere | `absent` | `absent` | | marker + BLOCKQUOTED CN declaration | `absent` | `absent` | | marker + CN dialect `层:全量层` | `absent` | `unknown-tier [全量层]` **CHANGED** | | marker + bare `层:` | `absent` | `unknown-tier [(nothing)]` **CHANGED** | | marker + `层` with no key punctuation | `absent` | `absent` | | marker + a different key `本轮:小时层(增量)` | `absent` | `absent` | | non-artefact prose carrying a CN declaration | `clean` | `clean` | | CN declaration inside a FENCED block | `absent` | `absent` | Seven rows move; the other seventeen are unchanged, and five of those seventeen are the firing controls. - **Rows 1–2**: the card's own defect. The live marker stops being reported as silence, with the tier VALUE extracted (`hourly`), not merely "not silent". - **Rows 13–15**: the same, for the line-start and full-width-colon spellings. - **Rows 19–20**: a Chinese declaration carrying an off-spec word, and a bare key naming nothing, move from `absent` to `unknown-tier`. **Both still fire.** The reclassification is the honest half: reporting 「层:全量层」 as "names NO tier at all" would be the same false statement one layer down. The row now echoes the key it actually read, so a Chinese finding no longer claims a `Tier:` line the artefact does not carry. ## Firing controls — what must STILL fire | control | verdict | |---|---| | the three measured tier-less specimens (marker, round close, stand-down brief) | `absent`, unchanged | | a Chinese tier mention mid-sentence, in prose | `absent` — today's verdict, KEPT and pinned | | …with a 「·」 elsewhere on the same line | `absent` | | a blockquoted Chinese declaration | `absent` | | a quoted HEADLINE carrying a 「·」 tier field | `absent` | | 「层」 with no key punctuation | `absent` | | a different key carrying the same word (`本轮:小时层`) | `absent` | | every English verdict: clean / `unknown-tier` / `not-at-line-start` | unchanged | ## Ablation ledger Each leg: mutate through an anchor that must hit, prove on disk, run the battery, restore, prove the restore byte-identical against the HEAD blob with an empty `git diff HEAD`. All four went through `scripts/ablation-replace.mjs` (wrap mode, EXIT/INT/TERM trap). | # | mutation | battery | what it proves | |---|---|---|---| | A1 | drop the declaration-slot anchor (`(?:^\|·)` becomes optional) | **RED** — 2 cases | the slot rule is what refuses prose; without it a mid-sentence mention clears the duty | | A2 | open the Chinese word set (`startsWith` becomes always-true) | **RED** — 5 cases | the word set is genuinely closed | | A3 | delete the blockquote skip | **RED** — 1 case | the quoted-headline refusal is live | | A4 | always label the key as the Chinese one | **RED** — 1 case | the row names the key it actually read | A3 is worth the reviewer's eye: the **first** version of it came back **GREEN**. The blockquote case that existed then (`> 层:每日层…`) is carried by the slot rule, not by the skip — `> ` is not indentation, so the line-start branch never reaches the key. The control was vacuous. The case that can actually fail is a quoted **headline**, where the field branch does reach the key; it is now pinned beside the first one with a comment saying why they must not be merged. Restore proof for every leg, from the tool's own output: `blob after restore == blob at HEAD` and `git diff HEAD` empty. ## The self-test battery floor goes UP Probed, not assumed: ``` BEFORE 4583 cases pass. Batteries: H66 released queue card 183/172, H19 judged-set founding 37/34. AFTER 4629 cases pass. Batteries: H66 … 183/172, H19 … 37/34, H65 tier declaration spelling 46/42. ``` `SELF_TEST_BATTERY_FLOOR` 2 → 3. The new battery is where the firing controls live, on the H19 battery's stated grounds: a widening with no live control beside it is how a repair becomes a silencer. ⛔ No floor lowered, no case deleted, no other H-row touched. ## Counts, each with a firing control `git diff BASE HEAD -- scripts/pm/check-half-states.mjs | grep -c TERM` reads **0** for each control term while that term is present in the file — so the count is a control, not a coincidence. | claim | measurement | firing control (present in file, **0** in diff) | |---|---|---| | exactly one file changed | `git diff --stat 14d2544 HEAD` → `1 file changed, 246 insertions(+), 10 deletions(-)` | — | | ⛔ no other H-row touched | the file names **67** distinct `H<row>` ids; added/removed diff lines name **3**: `H65` (the subject), plus `H19`/`H66` in one prose line naming the two existing batteries | `H44_ROUND_OPEN_MARKER` 12/**0** · `PM_SWEEP_CLOSED_FLOOR` 17/**0** · `h19BlockOutlivedBlocker` 33/**0** | | ⛔ H65's own window/population untouched | only the tier predicate, its row text and the battery moved | `h65NewestPagePlan` 24/**0** · `h65IsTriageSeatPost` 15/**0** · `H65_COMMENTS_PAGE_SIZE` 7/**0** | | ⛔ the English word set is untouched | the new word set is a separate constant | `H65_TIER_WORDS ` 1/**0** (the declaration line itself) | | ⛔ no control bytes | `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` → no match; `pnpm check:nul-bytes` exit 0 | — | | ⛔ no `.claude/` path in the diff | `git diff --name-only 14d2544 HEAD` → one path, `scripts/pm/check-half-states.mjs` | — | ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` against head `5745ec5b3` (the tool takes its own change set from the merge base; it printed `objectstack-ai/objectstack` and the commit on stderr). 38 commands. All 38 run, exit codes recorded before any pipe, reconciled with `--ran`. ``` ✓ 37 of 38 commands run in a recorded loop, exit code captured BEFORE any pipe — all exit 0. ✓ pnpm check:pm-dispatch-gates — detached, waited on a recorded PID — exit 0, `1746 cases pass`, 826.3s on this box ✓ dispatch-gates --ran: 38 derived famil(ies) accounted for — 38 run, 0 NOT-MEASURED, 0 UNRUN ``` Highlights: `check:pm-half-states` (this file's own gate) exit 0 · `check:nul-bytes` exit 0 · `check:self-test-wired` exit 0 · `check:scripts-symbol-anchors` exit 0 · `check:changeset-no-major --base origin/main` exit 0 · `check:commit-card-trailers` exit 0. Outside the derived 38 and named as such by the tool, not silently dropped: 48 artifact-roster families (a list of files that already exist can never contain one added tomorrow), 11 declared-wide-population families, 5 families taking a value from the workflow, 1 CI-measured-only family, 1 path-scheduled CI job, and the 10 pending-changeset families that do not apply to a `skip-changeset` PR. CI runs the farm. ## Changeset: `skip-changeset`, measured One criterion: does anything **published** move? Every tracked manifest was scanned for a non-private `files[]` entry covering the changed path. ``` CHANGED scripts/pm/check-half-states.mjs -> NOT SHIPPED by any package files[] CONTROL packages/lint/CHANGELOG.md -> @objectstack/lint (packages/lint/package.json files[] "CHANGELOG.md") CONTROL packages/lint/package.json -> NOT SHIPPED by any package files[] manifests scanned: 83 ``` The control lights, so the negative is a reading rather than a silent miss. `skip-changeset` applied additively and read back. ## What the PM's full sweep will see A change in total row count is expected and is explainable row by row: 1. Any triage round artefact whose tier is declared in Chinese **leaves** the H65 population. On the live carrier that is the whole of the 46-row block the card measured. 2. An artefact carrying a Chinese key with an off-spec word or no word **stays**, with its reason moving `absent` → `unknown-tier` and its text naming `层:` instead of `Tier:`. 3. Every H65 row's remedy sentence now names both spellings and the 「·」 field slot, so row **text** differs on every H65 row even where the verdict does not. Nothing else in the file moved. ## Acceptance notes - `noted, not filed:` `H65_TIER_LINE`'s `/m` flag scans the whole body while the artefact shape is judged on the headline alone, so an English `Tier:` line anywhere in a long marker clears it. That is pre-existing, deliberate per the row's header, and untouched here. Carrier: the next PR to touch H65's window rules. - `noted, not filed:` this repo's editing tools normalise full-width CJK punctuation to ASCII on write, and unicode escapes in a Bash argument are decoded before the shell sees them. Both were caught here by on-disk byte probes, and one of them had already produced a phantom test case (a "full-width colon" fixture that carried an ASCII one). Carrier: none — recorded here because the probe, not the exit code, is what caught it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent f32f480 commit 551139b

1 file changed

Lines changed: 246 additions & 10 deletions

File tree

0 commit comments

Comments
 (0)