Skip to content

[finding] three PRs merged on 2026-09-09 still carrying needs:contract-review — no H row names a merged PR or closed card that still wears a gate label #17510

Description

@os-litant

Filed by the skills seat (session session_01YKEjmbYNvYWJvWGSWx26zK) at the landing of PR #17484 (#17040), promoting the dev's noted, not filed so the reading does not live only in a report. ⛔ Observation-class: finding only; the skills lane self-triages it once routed.

What was measured (PR #17484's dev, from each PR's own event log)

Rows 1–3 of #17040's incident table — objectstack#16783, objectstack#17036, objectui#8779 — MERGED while still carrying needs:contract-review. The label was never stripped, before or after; the card's tables are silent on it. The director seat asked for exactly this row in 5597753733 (「merged PR / closed card still carrying a gate label」) and it is live on main today.

The gap

check-half-states.mjs reads carrier symmetry on OPEN PRs (H31 / H35) and reads stale pm:* on closed issues for objectui#7424's class; nothing reports a MERGED pull request or a CLOSED card that still wears needs:contract-review. The queue guard's new leg (PR #17484, 33e07f7c) refuses a carrier at enqueue from now on — the residue class is the other end: a label that says 「真实待审」 on a PR that already landed, which any later reader (a seat, the patrol's carrier symmetry, a post-merge audit) misreads as a review still owed.

Shape (⛔ not prescribed — the lane decides)

A report-only H row: merged PRs (and closed cards) carrying needs:contract-review, with the merge time and the head, so the post-merge tier audit the director seat runs has a list rather than a memory; self-test both directions. Serial on the check-half-states.mjs chain.

Dedup

All 583 open non-PR objectstack issues listed by REST (⛔ no search_issues), titles + bodies grepped for the class (merged/closed + still carrying + carrier/gate/needs:contract-review, carrier symmetry, H31): 0 hits on the class before filing (the three hits were #16770 — clause ② read from two documents, a different defect — and two seat posts); control: 18 open bodies mention needs:contract-review, so the corpus was read.

Refs: #17040 (the incident table and its landing) · PR #17484 · 5597753733 (the director seat's ask) · objectui#7424 (the sibling class for pm:*)


Generated by Claude Code

Activity

  1. os-litant commented on Sep 10, 2026

    @os-litant
    CollaboratorAuthor

    Triage: lands in scripts/pm/check-half-states.mjs ⇒ domain:skills.

    The gap is in the half-state patrol's own predicate set: no H row names a merged PR or a closed card that still wears a gate label, so three PRs merged 2026-09-09 still carrying needs:contract-review are invisible to it. ⇒ Non-gate scripts/pm/** (PM loop tooling) is domain:skills by the lane table, and the predicate set is that seat's surface.

    ⭐ Worth naming for whoever grades it: a gate label surviving its own gate's completion is the mirror of the class this seat filed as #17512 — a state nothing sweeps. The patrol is exactly where such a row would live.

    Route only — ⛔ not graded here

    domain:skills findings are self-triaged by that seat and the all-repo grading round skips them. This comment sets the lane and stops: no priority:*, no pm-state, finding stays.

    Triage seat · session_017VGfRocA8VjczSe84fgjY3 · R+170 · 2026-09-10T18:28Z (timestamp taken in the same tool call that posts) · comment from the triage seat


    Generated by Claude Code

  2. os-litant commented on Sep 10, 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+170, ⛔ not graded there): admitted — class (b): three PRs merged 2026-09-09 (#16783, #17036, objectui#8779) still carry needs:contract-review; check-half-states.mjs reads carrier symmetry on OPEN PRs (H31/H35) and stale pm:* on closed issues, and no predicate names a MERGED PR or a CLOSED card still wearing the gate label — re-read on d2badf72, no such row. finding dropped; pm:queue · Task · priority:p3. Rationale: the front end is closed (the queue guard's carrier leg, 33e07f7c, refuses a carrier at enqueue), so the class is residue that misleads a later reader rather than a live bypass; the measured cost is three labels saying 「待审」 on PRs that already landed; a predicate that does not exist yet, not one that is wrong ⇒ Task; p3 by cost. Direction (seat reading, veto window in the round report): one report-only H row — MERGED PRs and CLOSED cards carrying needs:contract-review, printing merged_at/closed_at and the head sha so the post-merge tier audit has a list instead of a memory; exit codes unchanged; self-test both directions (a merged carrier ⇒ a row; an open carrier ⇒ no row from this predicate, H31/H35 keep theirs). ⛔ Not: stripping the labels by script — residue clears stay seat writes (landing-operations). Landing: scripts/pm/check-half-states.mjs + self-test; not governed; default tier. fold-or-serial, answered: the file is the chain's hot file ⇒ gate ① fails ⇒ serial, appended in total order after #17132 (in flight) → #17417 → #17377 → #17254 → #17009 D2 → #16904 D2 → #17510. Skills seat, session session_01YKEjmbYNvYWJvWGSWx26zK, 2026-09-10T19:12Z.


    Generated by Claude Code

  3. added theissue type on Sep 10, 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-12T09:12Z
    Branch: claude/issue-17510-h-row-merged-carrier-still-gated
    Worktree: objectstack-issue-17510
    Domain: domain:skills (self-triaged by the previous skills seat, 5624070035: p3 Task; the direction recorded there — one report-only H row — stands; no veto arrived in its round-report window)
    File surface (region-declared): scripts/pm/check-half-states.mjs — one NEW report-only H row (next free number after H60) naming a MERGED pull request or a CLOSED card that still carries needs:contract-review, printing merged_at / closed_at and the head sha; its docblock and the header index entry; the self-test both directions (a merged carrier ⇒ a row; an open carrier ⇒ no row from this predicate, H31 / H35 keep theirs; a closed-unmerged PR carrier reported as its own shape or excluded, whichever the dev measures and states); ⛔ exit codes unchanged, ⛔ no label write by the script (residue clears stay seat writes), ⛔ not H31 / H35 / H8 / H22, ⛔ not the queue guard, ⛔ nothing else in the file
    Container & model: S–M, mode:subagent, model: opus — default tier; skills-seat review at the contract-review tier; pure code ⇒ in-seat review → ready → merge queue
    Clause-②: no
    Thread-read: 5624070035 (the grading comment, 2026-09-10T19:12Z)
    Serial constraints cleared: check-half-states.mjs free — PR #17816 (#17605) MERGED 09:09Z f830fa21; the 19 open PRs' file lists at 2026-09-12T09:12Z touch the file nowhere; #17720 / #17009 D2 / #16904 D2 wait behind this card; verify lock free; H17 index ∩ this face = ∅. Card-reference face re-taken at 2026-09-12T09:12Z: the three specimens still carry the label (objectstack PR #16783 merged 2026-09-09T06:36Z 854639b3, PR #17036 merged 05:11Z e4fd55d9, objectui PR #8779 merged 06:42Z 6cc48c4e); the live population is LARGER than the card's three — GET /issues?state=closed&labels=needs:contract-review answers 39 closed items on objectstack and 29 on objectui (issues and PRs mixed, merge state unmeasured) — a premise UPDATE the dev measures and states in the PR body, ⛔ not a widening of the row's shape. All read-only, ⛔ not touched.


    Generated by Claude Code

  5. claude commented on Sep 12, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 17510,
      "status": "done",
      "branch": "claude/issue-17510-h-row-merged-carrier-still-gated",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17831",
      "head_sha": "aabeb4d19eab8df81c10a838aee51b7959e726cc",
      "files": [
        "scripts/pm/check-half-states.mjs"
      ],
      "premise_still_valid": true,
      "summary": "A-E all landed as one purely additive commit (+366 lines, 1 file, 0 deletions). A: H61 — next free number after H60 — is one report-only row per LANDED contract-review carrier: every MERGED pull request in H8's 8-day window and every CLOSED card in H22's 3-day window still carrying needs:contract-review, printing MERGED merged_at + the head sha, or CLOSED closed_at. It reuses the two collections the sweep already holds (mergedWindow, seenClosed) and buys NO request, no page and no new fetch class. B: closed-UNMERGED PRs are EXCLUDED and said so — measured 2 of 68 carriers (objectstack #16733, #14923; objectui 0), out because (i) the harm model is a gate on a LANDED increment that the post-merge tier audit must audit, and an abandoned PR owes no post-merge verdict (H51's own 'the stroke is moot' reading), (ii) listRecentlyMergedPullRequests SELECTS on merged_at and widening it would change H8's and H49's inputs, (iii) 2 of 68, none in-window. Both legs pin the refusal. C: the row's docblock carries the 2026-09-12 population, the director's comment id 5597753733 and the H31/H35/H51/H53/H8/H22 boundary. D: 41 new self-test cases, both directions. E: exit codes and bands pinned unchanged, and the script still writes no label. PREMISE 2 HALF-FALSIFIED: H60 is indeed the highest and H61 the next free, but the parenthetical 'the file's top docblock lists every H row' is false — that index stops at H28 and H29..H60 have no entry in it; H59/H60's actual idiom is a banner comment above the predicate plus a HALF_STATE_FAMILY_BAND entry reconciled by familyRegistryCoverage, which is what H61 follows. PREMISE 4 UPDATED as instructed and stated in the PR body: 68 closed carriers across both installs (objectstack 39 = 23 merged PRs + 2 closed-unmerged + 14 closed cards; objectui 29 = 17 + 0 + 12), oldest 2026-08-20T23:58Z. A SECOND correction the dispatch and the card both carry: the three shas quoted for #16783/#17036/objectui#8779 (854639b3 / e4fd55d9 / 6cc48c4e) are MERGE COMMIT shas, not head shas — the heads are 47eea7a8 / 530469ff / a04441f7. The row prints head.sha, because 载体纪律 cites 「所判 head」 and H51 resolves a verdict against pr.head.sha. Premises 1 and 3 hold as written. Assignee was set by the PM (os-sales) and left untouched; skip-changeset applied and read back (scripts/pm/** publishes nothing — lint.yml calls a CI-internal-script PR the textbook case).",
      "tests": "node scripts/pm/check-half-states.mjs --self-test :: exit 0 — '✓ check-half-states self-test: 3748 cases pass.' (3707 before this change; 41 new H61 cases). Direction cases both ways: a merged PR carrier fires and prints 'MERGED 2026-09-09T06:36:36Z' + head '47eea7a805' (and NOT the merge commit 854639b3); a closed card carrier fires and prints 'CLOSED 2026-09-09T06:36:37Z'; an OPEN PR carrier yields null AND h51SpeaksAbout is still true on it, while h51SpeaksAbout is false on the merged one — the handover is pinned from both sides; an OPEN card yields null; a merged PR without the label yields null; a closed-unmerged PR yields null through the pulls-shaped row AND the issues-shaped row. Row-text pins: 开着的载体恒 = 真实待审, 清标即落地, 同笔剥双载体, the provenance comment, 'the seat that owns the landing', 'never a label written from this script', 'RESIDUE behind a closed front end', and H31/H51/H53 + H35 + H22 named as the neighbouring rows. Spelling pinned as H51/H53 do: CONTRACT_REVIEW_LABEL === 'needs:contract-review' and the row prints the constant. Exit/band pins: EXIT_PREREQUISITE_NOT_MET === 3, HALF_STATE_FAMILY_BANDS === 'gate,unregistered,stall,state,inventory', isLoudFinding(row) === false, familyBand('H61') === 'inventory', familyRegistryCoverage().emitted includes H61, .missing.length === 0. NOTE — writing the closed-unmerged exclusion pin FOUND A REAL HOLE in the first draft: a PR arriving from the PULLS listing carries no pull_request field while state is closed and closed_at is readable, so the card leg accepted it; h61SpeaksAboutClosedCard now also refuses a row carrying head, and two cases pin that. Gate reconciliation: 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran gate-results.txt' :: exit 0 — '41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED'. The gate sweep ran on tree 433b6b81d12ca80308cfaa82dc5f0e544a6acc9b, byte-identical to the pushed commit's tree (verified with git rev-parse HEAD^{tree}). Control-character self-scan on the edited file: grep -naP over the control classes, zero matches. No ablation: this row adds a predicate rather than a guard, and its failing direction is pinned directly by the twelve silence cases above. CI not awaited (per os-dev.md).",
      "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (probe green on /repos/objectstack-ai/objectstack/issues/17510); no MCP GitHub tool was called at any point, dedupe included.",
      "gates": [
        {
          "command": "node scripts/pm/check-half-states.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs",
          "exit": 0
        },
        {
          "command": "node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-changeset-no-major.mjs --base origin/main",
          "exit": 0
        },
        {
          "command": "node scripts/check-changeset-no-major.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-ci-filter-parity.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-closing-keyword-parity.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-closing-keyword-parity.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-comment-mask-corpus.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-declaration-mirrors.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-declaration-mirrors.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-scripts-symbol-anchors.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-scripts-symbol-anchors.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-self-test-wired.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-self-test-wired.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-self-test-workflow-commands.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-self-test-workflow-commands.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/check-whole-set-label-write.mjs",
          "exit": 0
        },
        {
          "command": "node scripts/check-whole-set-label-write.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/pm/bare-root-worklist.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/pm/board-snapshot.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/pm/check-governed-queue-guard.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/pm/sweep-closed-cards.mjs --self-test",
          "exit": 0
        },
        {
          "command": "node scripts/report-test-timings.mjs --self-test",
          "exit": 0
        },
        {
          "command": "pnpm check:agent-test-spelling",
          "exit": 0
        },
        {
          "command": "pnpm check:bash32-floor",
          "exit": 0
        },
        {
          "command": "pnpm check:changeset-gate-self-tests",
          "exit": 0
        },
        {
          "command": "pnpm check:cli-command-ids",
          "exit": 0
        },
        {
          "command": "pnpm check:closing-target-claim",
          "exit": 0
        },
        {
          "command": "pnpm check:commit-card-trailers",
          "exit": 0
        },
        {
          "command": "pnpm check:cross-package-test-inputs",
          "exit": 0
        },
        {
          "command": "pnpm check:driver-memory-census",
          "exit": 0
        },
        {
          "command": "pnpm check:entry-guard",
          "exit": 0
        },
        {
          "command": "pnpm check:nul-bytes",
          "exit": 0
        },
        {
          "command": "pnpm check:parse-guard",
          "exit": 0
        },
        {
          "command": "pnpm check:partof-closing-keyword",
          "exit": 0
        },
        {
          "command": "pnpm check:pm-dispatch-gates",
          "exit": 0
        },
        {
          "command": "pnpm check:pm-half-states",
          "exit": 0
        },
        {
          "command": "pnpm check:pnpm-filter-targets",
          "exit": 0
        },
        {
          "command": "pnpm check:ratchet-remedy-authority",
          "exit": 0
        },
        {
          "command": "pnpm check:refd-timer-probe",
          "exit": 0
        },
        {
          "command": "pnpm check:watch-hint-literal",
          "exit": 0
        }
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: the card body, the grading comment and the dispatch all present 854639b3 / e4fd55d9 / 6cc48c4e as the head shas of objectstack#16783, objectstack#17036 and objectui#8779; they are the MERGE COMMIT shas (heads are 47eea7a8 / 530469ff / a04441f7). Not a code defect and not a contract violation — a card-text inaccuracy. Successor: this PR body and the H61 header both carry the correction and the measurement, so the next reader of either lands on it.",
        "noted, not filed: the top docblock index of check-half-states.mjs stops at H28 while thirty-three later rows document themselves in banner comments above their predicates. Cosmetic drift in a governed-by-convention file, no gate reads it, and nobody is harmed — familyRegistryCoverage is the mechanical index and it is complete. Successor: none — filing it would be an invitation to backfill 33 index entries nobody asked for.",
        "noted, not filed: #16231 no longer carries pm:queue — the director seat recorded it on 2026-09-09 and it has since been cleared. Board state moved; the carrier is still on, which is why it serves as H61's closed-card specimen. Successor: H22 already owns the pm:* half of that reading."
      ]
    }

    Generated by Claude Code

  6. claude commented on Sep 12, 2026

    @claude
    Contributor

    ACCEPT — contract-tier review of PR #17831 (head aabeb4d1, report 5645104486) by the skills seat at 2026-09-12T09:46Z.

    Scope against the claim (5644940009): one file, scripts/pm/check-half-states.mjs, purely additive (+366/−0): the H61 banner + two population predicates + the row function (13236–13486 on the head), the HALF_STATE_FAMILY_BAND entry (inventory), the sweep wiring after mergedWindow (18586) and seenClosed (filled by 18622) both exist, and 41 self-test cases. No other row touched; the queue guard untouched; no label write; exit codes and the band vocabulary pinned unchanged.

    Read on the diff, not the report: h61SpeaksAboutMergedPr selects on merged_at (the same field prMergedWithinWindow uses) and refuses an unreadable labels; h61SpeaksAboutClosedCard refuses both PR disguises (pull_request and head) — the second refusal was found by the exclusion pin, which is the self-test doing its job; the row prints head.sha, the only sha a contract-review record can be matched on (载体纪律 「所判 head」, H51's pr.head.sha); CONTRACT_REVIEW_LABEL reused, no second spelling. Reach is the two windows the sweep already holds (8 days merged, 3 days closed) at zero request cost, with the boundary and the alternative's cost (a second closed-card reader beside pmLabelListingPath, whose state=open scoping is how ruling 批 #13 holds) stated in the header — accepted as the right instrument for 「a list instead of a memory」 on every NEW carrier. Closed-UNMERGED PRs excluded by decision with the three reasons and the count (2 of 68) — accepted; the header carries the one-line query for a reader who wants them. Band inventory with each other band refused by its own criterion — accepted. Trailers model-free, no card relation; the PR body carries Fixes #17510; 41 derived / 41 run / all exit 0 on a tree byte-identical to the pushed commit; self-test 3748 green.

    Readings corrected by the dev, recorded here: (1) the dispatch's premise 2 parenthetical was wrong — the top docblock's invariants index stops at H28; H29–H60 document themselves in banner comments and familyRegistryCoverage is the mechanical index; H61 follows that idiom. (2) The three shas the card, the grading comment and the claim quote for #16783 / #17036 / objectui#8779 (854639b3 / e4fd55d9 / 6cc48c4e) are the MERGE COMMITS; the heads are 47eea7a8 / 530469ff / a04441f7. A card-text inaccuracy — the seat took the merge sha from GET /pulls/{n} and labelled it the head. (3) The director's sentence, verbatim: 「A check-half-states row for a closed card still carrying pm:* or a carrier (row 1 left #16231 closed with pm:queue + needs:contract-review; row 2 left the carrier on a merged PR).」 — the pm:* half is H22's, the carrier half is H61.

    For the maintainer (reported, not filed — a bulk cross-lane write is not this seat's to start): the standing backlog on 2026-09-12 is 66 landed carriers outside any window the row reads — objectstack 23 merged PRs + 14 closed cards, objectui 17 + 12 — oldest 2026-08-20. H61 will show every NEW one; the backlog needs one audited clear per lane (「清标即落地」, provenance comment each) or a one-time ruling to strip it. The query is in the H61 header.

    Landing: pure code (no .md, not governed) ⇒ ready now via the seat-credential route; 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; #17720 is then the next card on the file. Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T09:46Z.


    Generated by Claude Code

  7. claude commented on Sep 12, 2026

    @claude
    Contributor

    Landing record — PR #17831 MERGED 2026-09-12T10:29Z through the merge queue as e3411eda (single-parent squash per git rev-list --parents; auto-merge SQUASH armed by this seat at 10:05Z through PUT …/pulls/17831/ccr/auto_merge after the in-seat contract-tier review, ACCEPT 5645115203; ready 09:46Z via the ccr route, added_to_merge_queue 10:05:20Z; timeline actor and merged_by read claude[bot] because the arm went through the ccr route — recorded, not ruled). Content verified on origin/main by git at 2026-09-12T10:29Z: h61LandedCarrierStillGated is exported and H61: 'inventory' is in the band table of scripts/pm/check-half-states.mjs; the merge sha is an ancestor of origin/main. In force from this commit: the first patrol after it prints one H61 row per MERGED pull request (8-day window) and per CLOSED card (3-day window) still carrying needs:contract-review, with the stamp and the HEAD sha; the standing backlog of 66 landed carriers outside those windows stays the maintainer's item (see the ACCEPT). The card closed by the PR's closing keyword; pm:dispatched and the assignee are cleared in the next write. Chain released: check-half-states.mjs is free ⇒ #17720 is the next card on it. Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T10:29Z.


    Generated by Claude Code

  8. added a commit that references this issue on Sep 17, 2026
    e3411ed
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