Skip to content

ci(timing gates): the two timing steps report-only on every event, schedule included — the per-package wall ceiling and the shard drift stay readings, never a red (#22949 ruling E, item 1) #23058

Closed

Description

@objectstack-fleet

Protects: Test Core on main's hourly schedule run (the full battery under objectstack#22998), red three of four hours since C2 on a measurement of runner load; and every seat that reads a main-red as a package regression.

Filed by the director seat (summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB) on the maintainer's word 「22949 同意」 (2026-10-12) to this seat's letter E on #22949 (the ruling record is the newest Ruling: comment there). Filing gate ③: maintainer-directed. ⛔ Not a claim. .github/workflows/** is governed in this repository as of #23048 (in flight) and by the round's posture: the PR stays a draft until a GOVERNED_APPROVERS member approves it.

What to build

  1. scripts/partition-test-shards.mjs / scripts/check-test-suite-ceilings.mjs: the grading mode becomes report-only on every event (TIMING_GRADED_EVENT removed or set so that no event grades; timingGateMode returns report for every event and still refuses a missing --event, the dev picks the spelling whose self-test is the clearest); a package over its ceiling or a shard past its drift bound prints the same table and one ::warning:: annotation and exits 0 on schedule too. A refusal (a malformed table or raise record, a missing --event) stays red everywhere (ACCEPT 6119677604's decision).
  2. .github/workflows/ci.yml: the two steps ("Check this shard's timing drift" :1136, "Check the per-package suite-duration ceilings" :1563) keep their names, their --event "$GITHUB_EVENT_NAME" and the ⛔ at :1076 (no if:, no continue-on-error); their comments say why no event grades (this ruling).
  3. The headers of both scripts carry the ruling URL and the diagnosis in two sentences (density, not code). Untouched: the formula, CEILING_FLOOR_SECONDS, RULED_CEILING_RAISES, the dataset, the refresh lane (E2 is its own card).
  4. Self-tests: every event → report; the existing graded-mode cases become the report-mode cases; the refusal cases unchanged.

Acceptance

  • check-test-suite-ceilings.mjs --self-test and partition-test-shards.mjs --self-test exit 0; the parity checkers named in ACCEPT 6119677604 green unchanged; the first hourly schedule run on main after landing: the two steps green with their ::warning:: annotations where a package is over; hourly full run: red on main (CI) #23007 closed on the ruling.

Related: #22949 (ruling E) · #22998 · #16468 · #22917 · #23007 · E2 (the refresh diff card, filed in the same act).

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · the director seat dispatching on the maintainer's words, verbatim 「22949 同意」 (ruling E, 6125775640) and the standing order 「三仓的 ci 优化卡你负责派发」 (this seat's session, 2026-10-12T14:22Z)
    Session: session_01LqNgdPZB2Jnr5HpGbaqLeB
    Account: os-zhuang
    Branch: claude/issue-23058-timing-gates-report-only
    Worktree: objectstack-issue-23058
    Domain: domain:devx
    Seat: domain:devx#9
    File surface: scripts/partition-test-shards.mjs and scripts/check-test-suite-ceilings.mjs (the grading mode and their self-tests and headers), .github/workflows/ci.yml (the comments of the two timing steps only: "Check this shard's timing drift" and "Check the per-package suite-duration ceilings"); ⛔ not the formula, CEILING_FLOOR_SECONDS, RULED_CEILING_RAISES, the dataset scripts/test-shard-timings.json or the refresh lane (E2, its own card), ⛔ no if: / continue-on-error on the steps (ci.yml:1076's ⛔), ⛔ not lint.yml (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: sonnet (the floor: a grading-mode switch with existing self-tests; the diagnosis is on the card and in the ruling). Tier H posture: .github/workflows/** (the round's posture; objectstack#23048 is queued for the register row): the PR stays a draft until a GOVERNED_APPROVERS member approves it.
    Clause-②: no
    Responsibility: Test Core's two timing steps (ci.yml:1136, :1563) | no existing path grades a timing baseline at the density it was measured; the ruling takes the red away | every hourly schedule run on main red on busy hours (3 of 4 since C2), and every seat that reads that red as a regression
    Thread-read: 6125775640
    Ruling-ref: #22949 ruling E 6125775640 (the maintainer's word verbatim 「22949 同意」), C2 6119186511 (the prior ruling it extends), ACCEPT 6119677604 (the refusal-stays-red decision), objectstack#22998 (timing gates report-only)
    Serial constraints cleared: no in-flight claim in this repository declares these files (PR #23043 merged; #23044 and #23048 queued); E2 (the refresh diff, filed in the same act) edits scripts/measure-test-shard-timings.mjs and the refresh workflow only. Merge origin/main before opening the PR.

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23058,
      "status": "done",
      "branch": "claude/issue-23058-timing-gates-report-only",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23063",
      "session": "session_01LqNgdPZB2Jnr5HpGbaqLeB",
      "premise_still_valid": true,
      "summary": "Both timing steps of Test Core are report-only on every event, schedule included: a package over its ceiling or a shard past its drift bound prints the same table, raises ::warning:: annotations and exits 0, while a refusal (missing --event, malformed table or raise record, unparseable dataset or summary) still exits 1 on every event. TIMING_GRADED_EVENT is removed and timingGateMode returns report for every non-empty event and throws on a missing one; the exit-1 and ::error:: branches are deleted with it. Headers of both scripts carry the ruling URL and the two-sentence diagnosis, the ci.yml step comments say why no event grades with the ruling URL, and the graded-mode self-test cases became report-mode cases. Draft PR 23063 is open on head 81970584, assignee os-zhuang, label skip-changeset, body read back byte-identical; CI was still running at report time.",
      "spelling": "TIMING_GRADED_EVENT removed outright, not set to a value no event matches. A never-matching constant would keep an exit-1 branch and an ::error:: annotation that nothing can reach, which reads as a switch somebody may flip; with the constant gone the self-test says the rule as one line (every event reads report, including schedule and one the list never heard of), the sweep case fails if any tier on any event exits non-zero or raises ::error::, and grading a timing again is a new ruling and a new edit. timingGateMode keeps its name and its refusal, as the ruling and ACCEPT 6119677604 name them.",
      "files_changed": [
        "scripts/partition-test-shards.mjs (+157/-119): TIMING_GRADED_EVENT removed, timingGateMode/timingModeNote report-only, renderDriftVerdict single DRIFT path, header with ruling URL and diagnosis, drift battery rewritten (8 cases, same floor)",
        "scripts/check-test-suite-ceilings.mjs (+158/-138): import without TIMING_GRADED_EVENT, renderCeilingVerdict single OVER path (REFUSED still exit 1), RED_STATUSES/red renamed OVER_STATUSES/overs, header and exit-code section rewritten, graded cases converted, last battery rewritten (8 cases, same floor; 58 cases across 9 batteries)",
        ".github/workflows/ci.yml (+60/-38): comments only; step names, --event \"$GITHUB_EVENT_NAME\", if: and continue-on-error of both steps byte-identical (no non-comment line changed)"
      ],
      "gates": {
        "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, run at head 81970584 after merging origin/main (derived set identical before and after the merge): 59 commands plus pnpm check:doc-authoring added by me; every exit code recorded before any pipe",
        "green_exit_0": "56 of 60, including node scripts/check-test-suite-ceilings.mjs --self-test, node scripts/partition-test-shards.mjs --self-test, check:self-test-workflow-commands, check:step-collectors, check:workflow-status-functions, check:required-contexts, check:aggregator-roster, check:ratchet-remedy-authority, check:stall-guard-budget, check:stall-guard-headroom, check:workflow-step-name-quoting, check:shard-attestation, check:nul-bytes, check:pm-dispatch-gates, check:entry-guard, check:doc-authoring",
        "not_measured_exit_3": "pnpm check:dts-closure, pnpm check:dual-build-cjs-loads, pnpm check:lean-entry-closure, pnpm check:sourcemap-no-sources-content: PREREQUISITE NOT MET (no dist/ in a fresh worktree). Build Core family, derived only because ci.yml is on that job's path filter; this diff changes no package, so no dist/ content can differ; Build Core builds the closure and runs them. Not a red, not a pass.",
        "reconcile": "dispatch-gates --ran: 59 derived, 55 run, 4 NOT-MEASURED, 0 UNRUN, exit 0",
        "pr_ci_at_report_time": "in progress on head 81970584 (Lint, Type Check, Test Core 1-6, Build Core, Governed Surface Queue Guard running; filter, Check Changeset, claim and closing-target gates success). Not awaited, per the contract; the PM reads Lint & Repo Gates, TypeScript Type Check and Test Core with the two steps' tables."
      },
      "tests": "At head 81970584. ceilings --self-test: self-test OK (58 cases across 9 batteries), exit 0. partition --self-test: self-test OK (72 measured packages, 74 shard items, 6 shards, max/mean 1.00x), exit 0. CLI ceilings on a fixture (live dataset, @objectstack/client ceiling 179.74 s, run 209 s): --event schedule, merge_group, pull_request, push, workflow_dispatch each exit 0 with exactly one ::warning:: and no ::error::; no --event exit 1 with the refusal; a fixture within its ceiling exit 0, no annotation. CLI drift on fixtures (client predicted 111.17 s): 180 s DRIFT, 150 s WARN, 100 s OK each exit 0 on all five events, one ::warning:: for DRIFT and WARN, none for OK; no --event exit 1. Ablation (fix committed first, scripts/ablation-replace.mjs wrap mode, mutation proved on disk by anchor count and blob hash, restore proved by blob equal to HEAD and empty git diff HEAD): (1) ceilings OVER return exitCode event === 'schedule' ? 1 : 0 turned its self-test red (over: exit 1, verdict OVER); (2) partition DRIFT return the same turned its self-test red (a DRIFT rendered DRIFT exit 1); (3) timingGateMode returning grade for schedule turned it red (schedule read a mode other than report). Direction red in all three, the common case; scripts are source .mjs with no build, so no dist step applies. No package changed: pnpm test and pnpm typecheck not applicable. Local verification ran no repo-wide eslint.",
      "mcp_calls": "0",
      "api_writes": "3 REST writes through the fleet-write relay as objectstack-fleet[bot] (3 dispatches): (1) pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls (draft forced) then POST /issues/23063/assignees, read back 9339 bytes sent, 9339 stored, identical; (2) label-write labels_add, POST /issues/23063/labels with skip-changeset, read back matches the target (ci/cd and size/l are the labelers'); (3) this os-dev-report comment, POST /issues/23058/comments. Plus 4 git pushes (not REST): the empty-branch probe, scripts, ci.yml comments, the origin/main merge. REST reads were GETs through gh api (card, comments, rulings, PR, check runs). OS_PM_WRITE_HOURLY_MAX=80 set on every scripts/pm call; no write-pace refusal. Worktree objectstack-issue-23058 removed without --force after the final push.",
      "deviations": [
        "One comment outside the claim's declared surface changed: the ci.yml aggregator note near the ceilings step (about line 1470) called the ceilings step 'the one step here that DOES red the job, on purpose: it is a gate'. This PR makes that false, so it now says the step reds only on a refusal. Still comments only; no non-comment line of ci.yml changed.",
        "Merged origin/main into the branch before opening the PR (the claim asked for it); two incoming commits, no overlap with this diff, no os-regen deferral. The whole gate union was re-run at the merged head 81970584 and the derived set was identical.",
        "Added pnpm check:doc-authoring to the derived list (runtime strings changed) and renamed RED_STATUSES/red to OVER_STATUSES/overs in the ceilings renderer, because nothing is red there any more. Neither is in the dispatch text.",
        "Four dist-reading gates are NOT MEASURED (exit 3), declared as a narrowing above; CI's Build Core owns them.",
        "Commit trailers are the model-free pair (Claude-Session, Co-authored-by Claude) from the contract, not the harness reminder's model-bearing Co-Authored-By trailer."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: E2 (objectstack#23059, the refresh lane's seat), noted, not filed. .github/workflows/shard-timings-refresh.yml (about line 688) tells the refresh PR reader that a package over its held ceiling in the window means 'the brake fired on main'. After this ruling the ceiling is a reading, so the 'brake' wording is stale copy in the bot PR body. E2 edits that workflow and the measure script; I did not touch either (the claim excludes them).",
        "carrier: none, noted, not filed. A missing --event still surfaces as an uncaught throw with a stack trace in both scripts (the cosmetic ACCEPT 6119677604 recorded as non-blocking); only the message text changed here. CI always passes the event.",
        "carrier: this PR's reviewer, noted, not filed. Comments in partition-test-shards.mjs above the new block still call the DRIFT bound 'the red' (they carry the 1.5x measurement); one sentence in the new block says it is the upper warning tier since this ruling, and the self-test battery key 'drift warning tier under the red' is unchanged so the pinned roster does not move."
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23063 (draft, head 81970584) · director seat dispatching on the maintainer's order, 2026-10-12T15:06Z

    Checked on GitHub, not on the report's say-so:

    • PR shape: exists, draft, base main (merge-base 0cbfb7c3, origin/main merged in as the claim asked), body line 1 Fixes #23058 (the only closing keyword), Clause-②: no, assignee os-zhuang, labels ci/cd, size/l, skip-changeset; 3 files, +375/−295, three commits.
    • Diff read, ci.yml: no non-comment line changed (the diff's added and removed lines minus comment and blank lines: empty), so the step names, --event "$GITHUB_EVENT_NAME" and the ⛔ at :1076 (no if:, no continue-on-error) stand; the ruling URL sits at both steps (lines 1094 and 1557); the aggregator-note rewrite is a comment.
    • Diff read, partition-test-shards.mjs: TIMING_GRADED_EVENT is gone (one comment names it, line 239); timingGateMode throws on a missing or empty event and returns report for every other (lines 242–251); renderDriftVerdict exits 0 on DRIFT, WARN and OK (lines 1200, 1218, 1233); the 1.3x and 1.5x constants untouched (the one non-comment diff line near them changes the word "red" to "DRIFT" in a message); the header carries the ruling URL (line 209) and the two-sentence diagnosis (line 220).
    • Diff read, check-test-suite-ceilings.mjs: renderCeilingVerdict keeps REFUSED at exit 1 (line 413) and exits 0 on OVER (line 512) and ok; CEILING_FLOOR_SECONDS and RULED_CEILING_RAISES are byte-identical to the base; the header carries the ruling URL (line 46) and the diagnosis (line 56); RED_STATUSES → OVER_STATUSES has no reference outside the file at the head.
    • Gates on the head 81970584, read at this act: green: Lint · ESLint, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Lint · CI, release & engine gates, Lint · docs & code guards, Lint · repo & tooling gates, Type Check · workspace, · source gates, · consumer gates, Build Core, Test Core 2/6–6/6, Check Changeset, Check PR Size; still running: Test Core (1/6), Build Docs, Lint · scoped · query-options erasure and the three aggregators. Nothing red; landing waits for all green. The dev's local union, exits quoted: 59 derived + check:doc-authoring added, 56 exit 0, 4 exit 3 NOT MEASURED (the dist-reading gates of Build Core's family; Build Core green on the head covers them), --ran 0 UNRUN; both self-tests OK (58 cases across 9 batteries; 72 packages, 6 shards); CLI fixtures: a package over its ceiling exits 0 with one ::warning:: on all five events, no --event exits 1; drift DRIFT/WARN/OK exit 0 on all five events; three ablations red in the predicted direction (restore proven).
    • Tier and review face: check-governed-merges.mjs --pr 23063 finds no register row (670 lines ≤ 3000); the round's Tier H posture for .github/workflows/** is the maintainer's word, so the PR stays a draft until a GOVERNED_APPROVERS member approves, then the seat readies and arms the queue (「这些pr 你为什么不自己合并,都要等我」). Contract review: none of the three faces is touched (Clause-②: no, no packages/spec/src/**, no governed rules text) → the seat's own reading, no second agent.
    • The spelling, accepted with the dev's reason: TIMING_GRADED_EVENT removed rather than set to a never-matching value, because a dead exit-1 branch with its ::error:: reads as a switch; grading a timing again is a new ruling and a new edit. timingGateMode keeps the name and the refusal ACCEPT 6119677604 named.
    • Deviations accepted: the aggregator-note comment (it called the ceilings step a gate that reds the job, which this PR makes false); check:doc-authoring added to the derived set; the RED_STATUSES/red rename; origin/main merged before the PR. Writes: 3 relay strokes (pr_create, label-write, the report) and 4 pushes; mcp_calls 0.
    • Out-of-scope findings, routed: the refresh workflow's "the brake fired on main" wording (shard-timings-refresh.yml about line 688) is stale under ruling E and sits on E2's surface → relayed to the ci(refresh lane): each test-timing refresh diffs the window's per-package weights against the previous dataset — a package up 25 % or more, or a file over the 10 s budget, is a filed card for its lane, never a red build (#22949 ruling E, items 2–3) #23059 dev by the seat in this act; the uncaught throw on a missing --event (cosmetic, recorded non-blocking at 6119677604) and the "the red" wording above the new block in partition-test-shards.mjs (the 1.5x measurement's comments; the self-test key unchanged) stay as they are.

    Landing: on all checks green and the maintainer's Approve, the seat readies the PR and arms the queue. The card's acceptance is read by the seat after merge: the first hourly schedule run on main shows both timing steps green, with ::warning:: annotations where a package is over its ceiling; until E2 (#23059) lands, a real slowdown is visible as that annotation only. This card stays pm:dispatched until the landing record.

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    LANDED — PR #23063 is MERGED (2026-10-12T21:55Z, approved by the maintainer, review 5496220027 on head 81970584, readied and enqueued by hand; merge commit 56986e9d) and read in place on origin/main 56986e9d. Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-12T21:56Z.

    probe on origin/main want got
    TIMING_GRADED_EVENT outside comments in scripts/ and .github/ 0 0
    timingGateMode returns report (and still throws on a missing event) 1 return 1
    renderCeilingVerdict: REFUSED exit 1, OVER exit 0 both both
    CEILING_FLOOR_SECONDS, RULED_CEILING_RAISES byte-identical to the base 0cbfb7c3 identical identical
    ci.yml: the ruling URL at both timing steps 2 2
  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Acceptance reading on #23058: the first hourly schedule run on main after the landing (run 38314183560, 22:01–22:23Z, main d0f1c5bf, with both E1 56986e9d and E2 d0f1c5bf in it), read on the jobs API by the director seat, 2026-10-12T22:35Z.

    step job conclusion
    Check this shard's timing drift Test Core (1/6) … (6/6) success ×6
    Check the per-package suite-duration ceilings Test Core (the aggregator) success
    Test Core (the required context) success
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxpriority:p1High: required for production / M2tooling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions