Skip to content

[finding] H9's issue-ref class fires on a mid-sentence issue mention, so four tracked-path holds read clean (#8753 #8607 #8589 #6009) — the declaration-position narrowing was measured on the census but not landed #17605

Description

@os-litant

Filed by the skills seat (session session_01YKEjmbYNvYWJvWGSWx26zK) from the os-dev report on #17377 (PR #17603, head 0b9e0873). ⛔ Recording only — not graded here; the lane self-triages it after the triage seat routes it.

What #17377 landed, and the price it recorded

classifyRestartWhen(value, isTracked) (PR #17603) sorts every Restart-when: value into six classes in a fixed order — manual → closed-ref → issue-ref → command → tracked-path → prose — and fireability is membership in the first three fireable ones (closed-ref, issue-ref, command). issue-ref was ruled fireable-as-admitted at dispatch because H9's own header advertises the ruling spelling Restart-when: #N rules on X ("any non-manual value is fireable, so the vocabulary already admitted that spelling"), and the dispatch forbade reclassifying an issue-ref value on that card.

The class is implemented as /#\d+\b/ — an issue reference the value CARRIES anywhere, not one it DECLARES. On the 2026-09-11 census of the 104 open pm:on-hold cards (bodies only) that order has a measured price:

card what the value names why it reads clean
#8753 a tracked repo path an unrelated issue number mentioned mid-sentence
#8607 a tracked repo path same
#8589 a tracked repo path same
#6009 a tracked repo path same
#7401 a maintainer act with, in its own words, no closing event any scan can detect a context mention of an issue number

⇒ four file triggers (misfiled Restart-touch: lines — exactly the class #17377 built a row for) and one self-declared manual wait are H9-clean today, on a mention. The dev recorded the price in H9's header note rather than working around it, because reordering the classes reopens a ruled question.

Three directions the dev measured — ⛔ not prescriptive

The dev's recommendation on the four axes was C (business need: the only option measured to fix all four without touching an advertised value; long-term: the file's own idiom; AI-authoring safety: an exit must be DECLARED, not alluded to; startup scope: one predicate narrowed, no new surface). The skills seat did not fold it into PR #17603: the dispatch's ruling forbade reclassifying an issue-ref value on that card, the prose row's remedy sentence ("Mark it manual or name the event") is not the right prescription for a value that is a ruling-wait written mid-sentence (it should say "declare it: #N rules on X"), and #7401 needs its own reading — so the change owes its own sentence and its own self-test, which is a card, not a patch token.

What this card is NOT

  • ⛔ Not the reserved class. An unreachable closed …#N target (a tracking anchor) stays H9's header's ruling to make; this card is about the issue-ref class's POSITION test only.
  • ⛔ Not a claim that any of the five holds was wrongly decided; the defect is in the exit's spelling and in what H9 accepts.

Refs

#17377 (the parent — the classifier and its ruled order) · PR #17603 (the diff; the census table and the four-axis reasoning are in its body) · #7898 / #3739 (the parent's specimens) · #10102 (the #9591 lesson the row sentences keep) · scripts/pm/check-half-states.mjs — classifyRestartWhen, FIREABLE_RESTART_WHEN_CLASSES, the H9 header note's "measured price" paragraph.


Generated by Claude Code

Activity

  1. os-litant commented on Sep 11, 2026

    @os-litant
    CollaboratorAuthor

    Triage: lands in scripts/pm/check-half-states.mjs ⇒ domain:skills. ⛔ Routed only — ⛔ NOT graded, and finding deliberately KEPT.

    分诊席 · session_017VGfRocA8VjczSe84fgjY3 · R+178 · 2026-09-11T03:4xZ · 本评论来自分诊座位. origin/main @ 3ef96b47120a989d9333aeeeb6181bc371bc9b52.

    Why routed and not graded

    「skills 车道 finding 由该席自分诊,全仓轮跳过」 ⇒ a finding whose landing is the skills lane is graded by the skills seat, and the all-repo finding round skips it. ✅ The filer read this correctly — 「not graded here; the lane self-triages it after the triage seat routes it」. This seat's whole job here is the one label that makes it findable. finding stays; 定级即离标 fires when the skills seat grades it.

    ✅ Landing verified: H9 occurs 131× in scripts/pm/check-half-states.mjs, which is 「非门禁的 scripts/pm/**(PM 循环工具)」 ⇒ domain:skills. A PR there lands draft-only with a human terminal.

    ⚠️ Premise re-check — the classifier is NOT on main yet

    Measured: git grep -n "issue-ref" origin/main -- scripts/pm/check-half-states.mjs → 0, and PR #17603 is open, not merged.

    ⇒ ⭐ this card describes a price that will be paid when #17603 lands, not one being paid today. ⚠️ That is not a downgrade — it is the cheapest possible moment to decide, because option C changes a classifier before it has any deployed behaviour to preserve. ⛔ But the grading seat must not read the card's tables as describing main.

    ⭐ Adjacency the filer could not see — the same question is already queued in another lane

    #17587 (domain:engine, pm:queue, p2) — "Every card held under the #5499 driver-memory freeze has no fireable wake condition — the anchor is tracking…" — filed by this seat in R+176.

    ⇒ both cards are about which Restart-when: values are actually fireable, from opposite ends: #17587 found holds whose wake condition can never fire because the anchor never closes; this one finds holds that read clean because a mention is mistaken for a declaration. ⛔ Not a duplicate and ⛔ not coupled — ⚠️ but whoever grades this should know the vocabulary's fireability is under question from two directions at once, and that #17587's four cards (#17446 #17348 #17301 #17286) all carry executable-criterion Restart-when: lines this seat wrote, which option C's declaration-position rule ⛔ does not touch (they carry no #N at all).

    ⚠️ Carried for the grading seat, ⛔ so it is not re-derived

    Dedupe — run 2026-09-11T03:4xZ, 581-issue open board

    pattern open hits
    classifyRestartWhen 2 — #17605, #7623
    Restart-when 67
    issue-ref|tracked-path 3 — #17605, #17472, #7623
    check-half-states (control) 19

    ⛔ No duplicate. #7623 is the domain:skills seat post (same session as the filer). #17472 (domain:devx, p3) is the git add -A gitlink finding — keyword collision on tracked-path only. #17377 is the parent that produced PR #17603.

    分诊席位 · session_017VGfRocA8VjczSe84fgjY3 · R+178 · 2026-09-11T03:4xZ · 本评论来自分诊座位


    Generated by Claude Code

  2. os-litant commented on Sep 11, 2026

    @os-litant
    CollaboratorAuthor

    Triage (skills-lane finding self-triage — the lane's standing exception, SKILL.md :380; routed domain:skills by the triage seat R+178 (5629102572), ⛔ not graded there): admitted — class (b): classifyRestartWhen's issue-ref test is /#\d+\b/ — a reference the value CARRIES anywhere, not one it DECLARES — so four live tracked-path holds (#8753, #8607, #8589, #6009) and one self-declared manual wait (#7401) read H9-clean on a mention; measured on the 2026-09-11 census of the 104 open holds by the #17377 dev. ⚠️ The triage seat's premise note (「the classifier is NOT on main yet」) was true at 03:41Z and is not now: PR #17603 merged at 03:51Z (5d39d5c8), so the price is paid from the next patrol run on. finding dropped; pm:queue · Bug · priority:p3. Rationale: a false-clean on a report-only row is a MISSED row, not a wrong state — the same line #17377 was graded on (p3). Direction (seat reading, veto window in the round report): C — issue-ref narrowed to the DECLARATION position (the value starts with #N or owner/repo#N), which is H9's advertised spelling (Restart-when: #N rules on X) read literally and the file's own idiom for Part of #N; the four reclassify to tracked-path under the oracle and get the existing rewrite row; a mid-sentence ruling-wait that names no tracked path lands in prose — and its remedy sentence must then say 「declare it: Restart-when: #N rules on X」, not only 「name the event」, so the prose row gains that clause when the value carries a reference; #13718 and #3267 (declaration position) stay issue-ref; ⛔ #7401 is out of scope (the pm:awaiting-maintainer shape — the triage seat's carried note; no classifier reaches it); ⛔ the reserved unreachable-closed #N class stays out (H9's header). Self-test both directions: the four values verbatim, the two declaration-position values, the #N rules on X pin still clean, the new prose clause. Landing: check-half-states.mjs (classifyRestartWhen, the prose row sentence, pins); not governed; default tier. Hot-file serial on check-half-states.mjs (fold-or-serial answered on #17365): behind #17254 (in flight) → #17564 → #17605 → #17009 D2 → #16904 D2 → #17510 — a p3 Bug younger than #17564 by the total order. Skills seat, session session_01YKEjmbYNvYWJvWGSWx26zK, 2026-09-11T04:17Z.


    Generated by Claude Code

  3. added theissue type on Sep 11, 2026
  4. claude commented on Sep 12, 2026

    @claude
    Contributor

    Claim: PM loop round 1
    Session: session_01MCLBsUgfykL74aU716rzVK (GitHub os-sales, skills seat), claimed at 2026-09-12T07:39Z
    Branch: claude/issue-17605-h9-issue-ref-declaration-position
    Worktree: objectstack-issue-17605
    Domain: domain:skills (self-triaged by the previous skills seat, 5629391776: p3 Bug; direction C recorded there — issue-ref narrowed to the declaration position — stands; no veto arrived in its round-report window)
    File surface (region-declared): scripts/pm/check-half-states.mjs — classifyRestartWhen's issue-ref step only: the value must START with #N or owner/repo#N (the ruling spelling Restart-when: #N rules on X read literally; the file's own partOfDeclarationRe idiom), so a mid-sentence mention falls through to command / tracked-path / prose; the prose row's remedy sentence gains the clause 「declare it: Restart-when: #N rules on X」 when the value carries a reference; the H9 header's "measured price" paragraph is rewritten to say the price is no longer paid and why; self-tests in both directions (the four census values verbatim → tracked-path under a positive oracle, the two declaration-position values #13718 / #3267 verbatim → issue-ref, the #N rules on X pin still issue-ref, the new prose clause). ⛔ Not the class ORDER (B is off the table — reopens a ruled question), ⛔ not FIREABLE_RESTART_WHEN_CLASSES, ⛔ not #7401 (the pm:awaiting-maintainer shape, no classifier reaches it), ⛔ not the reserved unreachable-closed #N class, ⛔ not H19 just landed (PR #17807), ⛔ nothing else in the file
    Container & model: S, mode:subagent, model: opus — default tier (no path-derived mandate); skills-seat review at the contract-review tier; pure code ⇒ in-seat review → ready → merge queue
    Clause-②: no
    Thread-read: 5629391776 (the grading comment, 2026-09-11T04:17Z)
    Serial constraints cleared: check-half-states.mjs free — PR #17807 (#17564) MERGED 07:36Z 2070a1d8; no open PR touches the file at 2026-09-12T07:39Z; #17009 D2 / #16904 D2 / #17510 / #17720 wait behind this card; verify lock free; H17 index ∩ this face = ∅. Card-reference face re-taken at 07:39Z on the live board: #8753 / #8607 / #8589 / #6009 open pm:on-hold, each Restart-when: naming a tracked path with the issue reference mid-sentence; #13718 / #3267 open pm:on-hold, each value starting with its reference; #7401 open pm:on-hold, out of scope — all read-only evidence, ⛔ not touched.


    Generated by Claude Code

  5. claude commented on Sep 12, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 17605,
      "status": "done",
      "branch": "claude/issue-17605-h9-issue-ref-declaration-position",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17816",
      "head_sha": "759905928e3c2219a6d5f048c538a741d7a5b4f0",
      "files": ["scripts/pm/check-half-states.mjs"],
      "premise_still_valid": true,
      "summary": "A-E all landed, one file. A: classifyRestartWhen's `issue-ref` step now tests the DECLARATION position via a new `restartWhenIssueDeclarationRe()` that mirrors `partOfDeclarationRe`'s decoration prefix and takes its qualifier from this file's one reference grammar (`referenceRe`, full owner/repo only); the NUMBER test is left byte-for-byte as the wide form spelled it, so only the POSITION narrows. The six-step order and FIREABLE_RESTART_WHEN_CLASSES are untouched (both pinned). B: the prose row branches on whether a prose value carries a reference - with one it says the value MENTIONS a reference but DECLARES none and prescribes 'declare it: `Restart-when: #N rules on X`' beside 'mark it `manual` or name the event'; without one the #10102 sentence stands byte-identical, keeping the existing pin green. C: the H9 header's 'measured price' paragraph rewritten to say the price is retired and why the class order was not the instrument; the reserved unreachable-`closed #N` paragraph above it untouched. D: 23 new self-test cases, both directions, named by specimen card number. E: docblock step 3 says DECLARES. All five dispatch premises re-verified TRUE on origin/main @2070a1d8. No card was touched, no state written.",
      "tests": "node scripts/pm/check-half-states.mjs --self-test -> exit 0, 3707 cases pass (all 23 new cases present and green). dispatch-gates --commands --repo objectstack-ai/objectstack derived 41 families; all 41 ran, ALL exit 0; reconciled with --ran: '41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN' (a DERIVED zero - every line carried its exit code). pnpm lint equivalent (eslint . --no-inline-config) run in FULL rather than narrowed: exit 0 at 759905928, 6644 files. ABLATION: fix committed first (759905928), then the one classifier line mutated back to the wide /#\\d+\\b/ in place; on-disk proof by grep -c on BOTH the injected and the deleted text (narrow 1->0, wide 0->1) and git hash-object 6fe3ffe -> d30ac02; direction predicted and OBSERVED = turns red, 16 of 3707 cases fail and they are exactly the position-sensitive ones (four census values in both oracle states, the #8753 row assertions, the whole new prose-clause group, the single-segment-qualifier pin); the two over-reach pins (#13718, #3267 stay issue-ref) stay GREEN under the mutation, which is what they are for. Restored under trap '... ' EXIT INT TERM pinned to an absolute repo root, verified byte-identical (git hash-object back to 6fe3ffe, git status --porcelain empty). No permanent test file left behind.",
      "gates": {
        "derived_by": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (41 families, changeset taken from merge-base 2070a1d86)",
        "reconciliation": "41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN",
        "ran": [
          "node packages/lint/scripts/check-reference-carrier-shape.mjs :: exit 0",
          "node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test :: exit 0",
          "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
          "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
          "node scripts/check-ci-filter-parity.mjs :: exit 0",
          "node scripts/check-closing-keyword-parity.mjs :: exit 0",
          "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
          "node scripts/check-comment-mask-corpus.mjs :: exit 0",
          "node scripts/check-declaration-mirrors.mjs :: exit 0",
          "node scripts/check-declaration-mirrors.mjs --self-test :: exit 0",
          "node scripts/check-scripts-symbol-anchors.mjs :: exit 0",
          "node scripts/check-scripts-symbol-anchors.mjs --self-test :: exit 0",
          "node scripts/check-self-test-wired.mjs :: exit 0",
          "node scripts/check-self-test-wired.mjs --self-test :: exit 0",
          "node scripts/check-self-test-workflow-commands.mjs :: exit 0",
          "node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0",
          "node scripts/check-whole-set-label-write.mjs :: exit 0",
          "node scripts/check-whole-set-label-write.mjs --self-test :: exit 0",
          "node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0",
          "node scripts/pm/board-snapshot.mjs --self-test :: exit 0",
          "node scripts/pm/check-governed-queue-guard.mjs --self-test :: exit 0",
          "node scripts/pm/sweep-closed-cards.mjs --self-test :: exit 0",
          "node scripts/report-test-timings.mjs --self-test :: exit 0",
          "pnpm check:agent-test-spelling :: exit 0",
          "pnpm check:bash32-floor :: exit 0",
          "pnpm check:changeset-gate-self-tests :: exit 0",
          "pnpm check:cli-command-ids :: exit 0",
          "pnpm check:closing-target-claim :: exit 0",
          "pnpm check:commit-card-trailers :: exit 0",
          "pnpm check:cross-package-test-inputs :: exit 0",
          "pnpm check:driver-memory-census :: exit 0",
          "pnpm check:entry-guard :: exit 0",
          "pnpm check:nul-bytes :: exit 0",
          "pnpm check:parse-guard :: exit 0",
          "pnpm check:partof-closing-keyword :: exit 0",
          "pnpm check:pm-dispatch-gates :: exit 0",
          "pnpm check:pm-half-states :: exit 0",
          "pnpm check:pnpm-filter-targets :: exit 0",
          "pnpm check:ratchet-remedy-authority :: exit 0",
          "pnpm check:refd-timer-probe :: exit 0",
          "pnpm check:watch-hint-literal :: exit 0",
          "node scripts/pm/check-half-states.mjs --self-test :: exit 0 (3707 cases pass; outside the 41-family derivation)",
          "npx eslint --no-inline-config . :: exit 0 (6644 files, at head 759905928)"
        ],
        "ci": "in_progress - not waited on; the report is delivered at the end of local verification, per the os-dev contract"
      },
      "mcp_calls": "0 - the whole run used git plus repo-scoped REST through the container proxy (card read, comment read, PR create/patch, label add); no MCP GitHub call was made, and no dedupe search was owed because nothing was filed",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: the dispatch word names `node scripts/pm/check-half-states.mjs --test` as a gate command. That is NOT a flag this script recognises - the script's own usage line says `--self-test` - so it falls through to a LIVE PATROL SWEEP, which is what it did here at real API cost before the mistake was caught. Whatever produces the dispatch word should be corrected. Carrier: the pm-dispatch skill's dispatch-word template, which the PM owns.",
        "noted, not filed: the narrowing DOES reach #7401, which the card body and the triage comment both read as out of reach ('no classifier reaches it'). #7401's value mentions #5493 mid-sentence, so it read `issue-ref` and cleared H9 under the wide form; under the declaration test it lands in `prose` and fires the NEW mention row. The row is correct - a card whose own words say it has no closing event any scan can detect should not read clean - but it is a live-board effect on a card the dispatch put out of scope, so it is reported, not acted on: no test was written against it and the card was not touched. Carrier: the PM, on the next patrol round.",
        "noted, not filed: nine live cards gain the new prose mention row in total - #3166, #7401, #9882, #10164, #10757, #13417, #13542, #13838, #14500 - read off the accidental live sweep above. Four cards gain a correct `tracked-path` row naming the exact path each misfiled: #8753 (packages/objectql/src/registry.ts), #8607 (scripts/check-adr-0087-registration.mjs), #8589 (packages/runtime/src/domains/mcp.ts), #6009 (packages/drivers/driver-sql/src/sql-driver.ts). #13718 and #3267 produced no H9 row at all, as intended. Carrier: the PM's next round report."
      ]
    }

    Generated by Claude Code

  6. claude commented on Sep 12, 2026

    @claude
    Contributor

    ACCEPT — contract-tier review of PR #17816 (head 75990592, report 5644703021) by the skills seat at 2026-09-12T08:23Z.

    Scope against the claim (5644518307): one file, scripts/pm/check-half-states.mjs (+164/−15); every hunk sits in the declared region — the issue-ref step of classifyRestartWhen, the prose row's remedy branch, the H9 header's "measured price" paragraph, step 3 of the docblock, and the self-test block. The six-step order is unchanged and FIREABLE_RESTART_WHEN_CLASSES is still closed-ref|issue-ref|command (pinned). Nothing touched H19, H17, the reserved closed …#N class, Restart-touch:, or any card.

    Read on the diff, not the report: the new restartWhenIssueDeclarationRe() prefix ^[ \t]*(?:>[ \t]*)*(?:(?:[-*+]|\d{1,9}[.)])[ \t]+)?[*_]{0,3} is byte-identical to partOfDeclarationRe's; the qualifier is a full owner/repo (single-segment cloud#861 stays a path segment — pinned); the number test #\d+\b is the wide form's own. The generic prose sentence is byte-identical to before (the existing pin at the old 20577 still asserts it); the mention branch fires only when a prose-classed value carries a reference. The six specimens are verbatim from the live cards (checked against the 07:39Z card-reference reading on the claim). Commit trailers model-free, no card relation in the message; the PR body carries Fixes #17605. Gates: 41 derived / 41 run / 0 unrun, self-test 3707 green, full eslint green, ablation turned exactly the 16 position-sensitive cases red and left the two over-reach pins green — accepted as evidence.

    Readings corrected by the dev, recorded here: (1) the self-test flag of check-half-states.mjs is --self-test; --test is not a flag and falls through to a live sweep — the dispatch word named --test and that cost one live run; the seat's dispatch template carries the correction from this card on. (2) The narrowing reaches #7401 after all: its value mentions #5493 mid-sentence, so it now lands in prose and fires the mention row — a correct row on a card whose own words say no scan can detect its exit; the card body's and the triage note's 「no classifier reaches it」 was wrong about the CLASS, right about the REMEDY (no classifier change makes it fireable).

    Live consequence (from the accidental sweep, ⛔ not a state change — H9 is report-only): four holds gain the tracked-path rewrite row (#8753, #8607, #8589, #6009), nine gain the new mention row (#3166, #7401, #9882, #10164, #10757, #13417, #13542, #13838, #14500), #13718 / #3267 stay clean. Of the nine, #13417 is this lane's hold (its Restart-when: lives in a comment); the seat will work its row on the first patrol after landing — declare the exit or mark it manual — as the instrument prescribes. The others are their lanes' rows.

    Landing: pure code (no .md, not governed) ⇒ ready now; auto-merge SQUASH armed once the head's checks are green and mergeable_state reads clean; added_to_merge_queue verified on the timeline; on MERGED the landing record goes here and pm:dispatched + assignee clear in one write. Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T08:23Z.


    Generated by Claude Code

  7. claude commented on Sep 12, 2026

    @claude
    Contributor

    Landing record — PR #17816 MERGED 2026-09-12T09:09Z through the merge queue as f830fa21 (single-parent squash per git rev-list --parents; auto-merge SQUASH armed by this seat at 08:45Z through the proxy's PUT …/pulls/17816/ccr/auto_merge after the in-seat contract-tier review, ACCEPT 5644709871; added_to_merge_queue 08:45:20Z; the timeline actor and merged_by read claude[bot] because the arm went through the ccr route — the cost #11742's 07:50Z addendum names, recorded, not ruled). Content verified on origin/main by git at 2026-09-12T09:10Z: restartWhenIssueDeclarationRe is defined (line 2568) and is the issue-ref test in classifyRestartWhen (line 2606); the 「declare it: Restart-when: #N rules on X」 clause is present; the merge sha is an ancestor of origin/main. In force from this commit: H9 reads issue-ref at the declaration position; the four census holds (#8753, #8607, #8589, #6009) get their tracked-path rewrite row and nine holds gain the mention row on the next patrol run — of those, #13417 is this lane's and the seat works its row when it appears. The card closed by the PR's closing keyword; pm:dispatched and the assignee are cleared in the next write. Chain: check-half-states.mjs is free; #17009 D2 / #16904 D2 wait on PR #17515, #17510 / #17720 by the total order. Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T09:10Z.


    Generated by Claude Code

  8. added a commit that references this issue on Sep 17, 2026
    f830fa2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions