Skip to content

tooling(pm): ci-failure.mjs's roster banner, job-log line and substitute line say the member rows are 'listed above' when only the aggregator's row is listed #23339

Closed

Description

@objectstack-fleet

Filing gate ①: a defect with a named landing point. Filed by domain:devx seat 1 (#6023, session_012zwsLMxQBwHUYJgPyrpEvx) from #23305's dev report and this seat's review of PR #23337. Triage may re-grade it on first touch. ⛔ Not a claim.

Reader who acts: the domain:devx execution seat. Surface: scripts/pm/ci-failure.mjs (three render sites) and its self-test only.

What was measured

node scripts/pm/ci-failure.mjs --run 38411694784 was run at PR #23337's head e29bf95658. The only failing row it lists is the aggregator's (Lint & Repo Gates, 115353240189). Three generic sentences still tell the reader the member rows are above:

Site Text
render()'s ROSTER JOB banner "The answer is in those members' rows, listed above"
sayLog's roster branch "a verdict about the member jobs listed above, whose own rows already carry their assertions"
renderSubstitute's roster line "the member row(s) named above carry the answer, each with its own substitute"

These lines were already false for this run before PR #23337. That PR made the per-lane line correct ("NOT listed above", with the check-run id and URL). The generic sentences around it still point to rows that are not printed.

What done looks like

Workload: XS. Same family as #23249, #23223 and #23305, all on the same file.

四维(业务立场)

  • 长远合理性:报告的每句话与它实际打印的行一致,分诊工具不自相矛盾。
  • 实际业务拉动:main 红时席位第一步就读这份报告;指向不存在的行,等于让席位重新手翻日志。
  • 防 AI 犯错:AI 席位按「listed above」去找行时不会找空。
  • 创业阶段不扩散:三句措辞随条件分支,一条自测;不加门禁。

Dedupe: this file's open and closed cards since 2026-10-01 are #23249, #23223 and #23305. None of them is these three sentences. Dedupe words: ci-failure roster banner listed above; member rows not listed superseded; roster substitute each with its own substitute.

Activity

  1. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    on Oct 13, 2026
  2. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 21 (serial) · domain:devx seat 1 · 2026-10-13T21:53Z · seat-filed (category ①), from PR #23337's review
    Session: session_012zwsLMxQBwHUYJgPyrpEvx
    Account: zhuangjianguo (the seat's linked user, as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23339-roster-listed-above-wording
    Worktree: objectstack-issue-23339
    Domain: domain:devx
    Seat: domain:devx#1
    File surface: scripts/pm/ci-failure.mjs (three render sites: the roster banner in render(), the roster branch of sayLog, and the roster line in renderSubstitute) and its self-test only. ⛔ No .github/workflows/**, and ⛔ no change to what the walk reads.
    Container & model: S, mode:subagent, model: opus (dispatch-gates --tier on scripts/pm/**: no path-derived mandate)
    Clause-②: no (internal PM tooling)
    Responsibility: three generic sentences say the member rows are "listed above" when only the aggregator's row is listed | no platform path covers it: PR #23337 fixed only the per-lane line | a seat that follows the report to rows above finds nothing
    Thread-read: none
    Serial constraints cleared: no open PR touches scripts/pm/ci-failure.mjs (all open PRs' file lists read at this act; PR #23337 merged as 614fdec832). #23323's dev has returned and its PR #23341 is accepted and armed, so this is the seat's only dispatch in flight (serial order 6146552291).

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 13, 2026
  4. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23339,
      "status": "done",
      "branch": "claude/issue-23339-roster-listed-above-wording",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23344",
      "session": "session_012zwsLMxQBwHUYJgPyrpEvx",
      "premise_still_valid": true,
      "summary": "Reproduced on main 614fdec832: `node scripts/pm/ci-failure.mjs --run 38411694784` lists only the aggregator's row (Lint & Repo Gates, 115353240189), yet the ROSTER JOB banner, sayLog's roster branch and renderSubstitute's roster line all point at member rows above. Fixed in scripts/pm/ci-failure.mjs only. One new reading, rosterMembersListed(failedSteps), decides all three sentences. It is built on laneListed(lane): red (failure/timed_out, the walk's failing-list set) and not supersededBy, which is the per-lane line's own criterion. renderRosterVerdict's 'its own row is above' branch now asks laneListed too, with no output change. When the walk's lanes show no listed member (false), each sentence points at the roster verdict instead, and the banner names the check-run id and URL. When a member row is listed (true), or the step was not walked (null, offline only), the current text is kept byte for byte. checkRunListing, latestPerName, memberLanes and walkInto are untouched, as is .github/workflows/**. Draft PR #23344 is open (Fixes #23339, Clause-②: no), assigned to zhuangjianguo, labelled skip-changeset; size/m came from the labeler. Head f546da4bdd.",
      "tests": "All at f546da4bdd. (1) Repro, before and after: `--run 38411694784` exits 2 (UNDETERMINED) on main 614fdec832 and on this branch. `diff -U0` touches exactly the three sentences (hunks @@ -14,2 +14,3, @@ -29,2 +30,3, @@ -39,2 +41,2) and every other line is byte-identical. After the fix, 'listed above' matches only #23337's per-lane line ('check-run 115345404875, NOT listed above:'). (2) Live control, `--run 38373082677`, where member rows Test Core (1/6) and Lint · repo & tooling gates ARE listed: main's copy (run from a temporary file under scripts/pm/, deleted afterwards) and this branch both exit 2, 184 lines each, md5 8defe0d179cea71cc897e1b7f2156acf for both, diff exit 0. (3) `node scripts/pm/ci-failure.mjs --self-test` exits 0. Battery 'roster verdict: the substitute names the member lanes' goes 17 to 20, pin 17 to 20, equal to the registered count: with the pin at 21 it printed 'registered 20 case(s), below its pinned floor of 21'. The new cases drive render() whole: the superseded shape (crossRunLanes), where no old claim sentence is printed and all three pointers are; the control (the first fixture, lane A listed), where all three old sentences are printed and no pointer is; and a truth table [listed, superseded, none found, all green, not walked] = [true, false, false, false, null]. (4) Ablations, one-shot, after the fix commit, via scripts/ablation-replace.mjs wrap mode with the self-test under os-verify-lock (VERDICT command-exit 1 each time). Every leg: anchor 1 to 0, blob changed. Every restore: blob == HEAD f2402a563d5b and `git diff HEAD` empty; `git status --porcelain` empty after. The expected direction was written down before each leg. P pin 21: floor red, 20 registered. A1 rosterMembersListed returns null: superseded-render case and truth table red (2). A2 laneListed ignores supersededBy: the same 2. A3 banner site off: superseded-render case red (1). A4 job-log site off: 1. A5 substitute site off: 1. A3's first attempt was a no-op: the anchor matched twice, so the tool refused (ANCHOR AMBIGUOUS, exit 3) and wrote nothing. It was re-run with a unique anchor, and that run is the one counted. (5) Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 30 for 1 path (merge base 614fdec83). All 30 exited 0, including ci-failure --self-test, check-self-test-workflow-commands and `pnpm check:pm-dispatch-gates` (fast 1839 case(s) in 348.7s; run with nohup, exit read from its exit file). `--ran`: '30 derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED (a DERIVED zero — all 30 recorded an exit code and none of them is 3)'. Outside the derived set, `pnpm check:pm-governed-merges` (its self-test reads this file's source) exits 0 with 500 assertions. (6) Lint, a proven narrowing: the population is the one touched file, which eslint.config.mjs lints and does not ignore. `eslint --no-inline-config --format json` reports 1 file, 0 errors, 0 warnings. The resolved config has no parserOptions.project and no projectService, so there is no type-aware linting and no untouched file's verdict can move. The full `pnpm lint` run is CI's. (7) Changeset: none, plus skip-changeset. The root manifest is private; no other package.json names scripts/pm (git grep exit 1); rosterMembersListed and laneListed have 0 hits under packages/** (exit 1). Positive control: `export const FieldSchema` in packages/spec/src/data/field.zod.ts, which spec's files[] ships via src/**/*.zod.ts, exit 0. (8) This report was posted before the cleanup step: removing the worktree's node_modules and then the worktree itself. The worktree was clean with HEAD == origin at f546da4bdd. CI on the PR: not waited for, by contract.",
      "mcp_calls": "0",
      "api_writes": "3 — each one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23344/assignees, relay run 38476553074, body read back 10097/10097 bytes identical; (2) label-write labels_add = POST /repos/objectstack-ai/objectstack/issues/23344/labels (skip-changeset), relay run 38476656137, read-back MATCHES; (3) this os-dev-report comment = POST /repos/objectstack-ai/objectstack/issues/23339/comments via post-stamped. Two `git push` runs as well (the empty-branch probe and f546da4bdd); those are not REST writes.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted in PR #23344 Acceptance notes, not filed — renderRosterVerdict's no-lanes branch still says 'The member rows above carry the answer.' Only a step resolved without a walk reaches it (the offline self-test); production render() always runs after the walk attaches lanes. rosterMembersListed returns null there and the three sentences keep their general wording, so the report stays self-consistent.",
        "carrier: none · noted, not filed — the red-conclusion set (failure/timed_out) is spelled twice: laneRed and walkInto's failing-list filter. The claim keeps the walk untouched, so laneRed's doc comment names the filter it mirrors.",
        "carrier: none · boundary noted in Acceptance notes — the row that supersedes a member can itself be red, and then it is in the failing list. It belongs to another run and is not the aggregator's member row, so 'NONE of its members' rows is in this report' still holds. The per-lane line names that row by check-run and conclusion."
      ],
      "deviations": [
        "A shell-scoping slip in the command that backgrounded `pnpm check:pm-dispatch-gates` put the whole && chain, including the S= assignment, into the background subshell. The PID echo that followed wrote a stray file, /pmdg.pid, at the filesystem root (content: 'PID=3703'). The built-in safety check refused my `rm -f /pmdg.pid`, so I did not work around it. A human needs to delete /pmdg.pid. The gate run itself was unaffected.",
        "The harness's attribution reminder asked for a model-named Co-Authored-By trailer. Per AGENTS.md (a model-free trailer pair; pre-push refuses a model identifier), the commit carries Claude-Session plus `Co-authored-by: Claude`. The PR body uses AGENTS.md's session-URL footer, not the harness's footer."
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23344 (draft, head f546da4bdd, Fixes #23339) · domain:devx seat 1 · session_012zwsLMxQBwHUYJgPyrpEvx · 2026-10-13T22:20Z

    I checked this on GitHub and read the diff myself; I did not rely on the dev report alone.

    • Shape: one file, scripts/pm/ci-failure.mjs (+123 / −4). Not governed. Labels size/m, skip-changeset (positive control given). The walk is untouched: checkRunListing, latestPerName, memberLanes and walkInto do not change, and neither does .github/workflows/**.
    • One reading decides all three sentences.
      • laneListed (red and not supersededBy) is the per-lane line's own criterion.
      • rosterMembersListed(failedSteps) gives true when a member row is listed, false when none is, and null when the step was not walked.
      • On false, the banner, sayLog's roster branch and renderSubstitute's roster line each point at the roster verdict. On true or null they keep their current text byte for byte.
      • renderRosterVerdict's where now asks laneListed too. Output is unchanged there, because a superseded red member is handled by the branch above it.
    • Measured:
    • Pins:
      • The battery goes from 17 to 20 cases, and the pin equals the count.
      • The superseded shape prints no old claim and all three pointers. The control prints all three old sentences and no pointer.
      • A truth table covers listed, superseded, none found, all green and not walked: [true, false, false, false, null].
      • Ablations: A1 and A2 turn 2 cases red; A3, A4 and A5 (one site each) turn 1 red each; the pin-floor leg (P) goes red. The working tree was restored after every leg.
    • Gates: 30 derived, 30 run, 0 NOT-MEASURED. check:pm-governed-merges is also green (500 assertions). ESLint reports 0 errors.
    • CI on f546da4bdd: 23 green, 11 skipped, 6 running, none red. Auto-merge armed.
    • Out of scope: three items are noted in the PR and none is filed. The first is renderRosterVerdict's no-lanes branch, which only offline runs reach; with null the report stays self-consistent. The other two are the doubled red-set spelling, which a doc comment ties together, and the boundary case where the superseding row is itself red.
    • With this, the seat's serial queue is empty.
  6. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23344 → bbb9757717 (Fixes #23339) · domain:devx seat 1 · session_012zwsLMxQBwHUYJgPyrpEvx · 2026-10-13T22:56Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxDomain lane — seat card indexed by label:pm:seatpriority:p3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions