Skip to content

[finding] 分片腿的任务哈希仍不携带上游闭包 —— #19271 的 --force 修好的是「执行」,根因是「哈希」,而恒真的绕过是一条不会再报警的电线 #19278

Closed

Description

@os-try-charles

Path: none | #18671 的根因仍在,被恒真 --force 遮住 | 不会再报警

由 domain:devx 执行席(座位贴 #6023)在复核 PR #19271(卡 #18671 第二飞行)时立。⛔ 裸立:priority: 与 domain: 留空,定级与路由归分诊。

已修好的是「执行」,没修好的是「哈希」

PR #19271 给 Test Core 的分片腿加了 --force,于是一个受影响的分片一定会执行,⛔ 不再被缓存重放(卡 #18671,裁定 (A),机制 --only)。

⚠️ 但那条腿的任务哈希仍然不携带上游闭包:--only 把依赖任务摘出运行,于是哈希只剩包自身文件加 turbo.json 里手写的 $TURBO_ROOT$ 输入。⇒ 这一类缺陷的根因仍在,现在被一个恒真的 --force 压住。一个恒真的绕过是一条永远不会再报警的电线。

形状最对的修法(第二飞行实测,三选一里最便宜的那条,⛔ 当时出不了那张卡的面)

把分片值改成由 task 声明的 env 携带,从而根本不需要 --only:

  • packages/cli/vitest.config.ts 里 test: { shard: process.env.OS_TEST_SHARD } —— ⚠️ 需要这一步的原因是实测的:vitest 4.1.11 不读 VITEST_SHARD;
  • turbo.json 的 test task 的 env 里加 OS_TEST_SHARD;
  • 之后分片腿可以去掉 --only(也就不再需要 --force)。

实测代价对比(turbo 2.10.10,@objectstack/cli 真实规模,第二飞行,⛔ 本席未重跑):

形状 --dry=json 计划
现状(--only) 1 个任务
去掉 --only、保留 passthrough 60 个任务,60 全 MISS(实测闭包重执行 5m11.262s,同闭包哈希不动时 60ms FULL TURBO)
本卡这条(env 携带分片) 60 个任务,57 HIT / 3 MISS

⇒ 它既让任务执行,又让哈希诚实,而且是三条里最便宜的。

⛔ 为什么当时不做

#18671 第二飞行的文件面是 .github/workflows/ci.yml + turbo.json,而本条需要 packages/cli/vitest.config.ts。施工席报告而未越界,派发席确认这是对的。

验收(⛔ 不规定实现)

  1. 受影响的分片仍然执行 —— 与 [finding] 图说 @objectstack/cli#test 该被 spec 的改动波及,#17914 那次运行却说它是缓存重放、从未执行 —— 这才是让红落进 main 的那一环,而它至今没有卡 #18671 同一条判据。
  2. ⭐ 哈希要真的动:上游源码一改,分片腿的任务哈希必须变。⚠️ turbo ls --affected 的读数不钉 TURBO_SCM_BASE 一律作废(干净树也读回 76 个包,[finding] 图说 @objectstack/cli#test 该被 spec 的改动波及,#17914 那次运行却说它是缓存重放、从未执行 —— 这才是让红落进 main 的那一环,而它至今没有卡 #18671 卡面实测)。
  3. --force 若在本卡里被去掉,必须证明去掉之后缺陷不回来(即第 2 条成立),⛔ 不得只凭「不再需要」。

Refs:#18671 · PR #19271

domain:devx 执行席 · 座位贴 #6023


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Claim: takeover by the maintainer's order (a single card, run from the vacant domain:spec seat 2 as a registered stay-behind)
    Session: session_014EJ1ED8X4MMrT18BhVx4tx
    Account: os-tesla (the card's assignee from this act)
    Branch: claude/issue-19278-shard-hash-carries-closure
    Worktree: objectstack-issue-19278
    Domain: domain:devx
    Seat: domain:spec#2. The seat post #18549 reads ⏳ vacant and registers this one card as this session's stay-behind item. The maintainer named the card; it is not a lane selection.
    File surface:

    • .github/workflows/ci.yml: the Test Core file-level slice leg (about :797, --only --force … -- "--shard=$SLICE") and its comment block.
    • turbo.json: the test task's env.
    • The vitest.config.ts of each package that the slice leg can slice (packages/cli/vitest.config.ts named by the card; any other package scripts/partition-test-shards.mjs slices, measured first).
    • One test or self-test that pins the hash moving.
    • Nothing wider (stop on breach; explain in the report).
      Container & model: M, mode:subagent, model: opus (dispatch-gates --tier for these paths: no path-derived mandate).
      Clause-②: no (CI caching and test sharding; no contract accept or reject moves)
      Thread-read: none
      Serial constraints cleared: read at 2026-09-30T07:22Z against origin/main 96e724475c, over the 10 open PRs. None touches .github/workflows/ci.yml, turbo.json, a package vitest.config.ts or scripts/partition-test-shards.mjs.

    The thread: the card's counter says 1 comment, but the REST and MCP comment reads both return none, so Thread-read is none.

    Premise, re-read on main today: the slice leg still runs pnpm turbo run test "--filter=$PKG" --only --force … -- "--shard=$SLICE" (ci.yml about :797). Its own comment block says: "What --force does NOT do is make the hash honest. It stays blind to the closure." turbo.json's test task declares env: ["OS_TEST_TIERS"] and no shard variable.

    The card's acceptance governs (⛔ not an implementation prescription):

    1. An affected slice still executes.
    2. The slice leg's task hash moves when upstream source changes.
    3. If --force goes, prove that the defect does not come back.

    Provenance (whose instruction / verbatim / where): the maintainer, in this session's chat (session_014EJ1ED8X4MMrT18BhVx4tx): 「19278 什么情况,你接手」.


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 19278,
      "status": "blocked",
      "branch": "claude/issue-19278-shard-hash-carries-closure",
      "pr": null,
      "session": "session_014EJ1ED8X4MMrT18BhVx4tx (the dispatching session; this run is its subagent)",
      "premise_still_valid": true,
      "summary": "Premise holds on origin/main 96e724475c: the slice leg's cli#test hash does not move for an upstream source change (a8cb3b6e48265376 before and after a packages/spec/src/ui/view.zod.ts edit). The in-surface fix is built, pushed and measured on all three acceptance lines: turbo.json declares OS_TEST_SHARD on the test task (generic and @objectstack/cli#test), packages/cli/vitest.config.ts reads it into vitest's shard, the Test Core slice leg runs `env OS_TEST_SHARD=$SLICE pnpm turbo run test --filter=$PKG ...` with no passthrough, no --only and no --force, and partition-test-shards --self-test gains a battery that fails a sliceable package whose turbo task or vitest config does not carry the variable. I STOPPED at the file surface, per the dispatch, because dropping the passthrough breaks a consumer the card and the dispatch did not name: turbo records the slice only in the run summary's `cliArguments`, and scripts/measure-test-shard-timings.mjs (samplesFromSummary via sliceOfCliArguments, which also feeds report-test-timings.mjs and --check-drift) reassembles slices from exactly that field. On a real post-change summary it returns `samples {cli: 118.073s}, slices []`, so the next timings refresh would write one slice's window as cli's WHOLE cost: the #16173 defect that reader's own header forbids. No PR is opened, because landing this branch as it stands would plant that silent corruption; branch head 276b3591d8.",
      "blocker": "Needs the PM to widen the claim's file surface by: (1) scripts/measure-test-shard-timings.mjs, so samplesFromSummary also identifies an env-carried slice. turbo writes the value as `OS_TEST_SHARD=` followed by the sha256 hex of the value in the task's environmentVariables.configured (measured: sha256 of `1/16` is ece2d97a69030356..., the same digest the real summary carries), so the reader can match it against the k/n candidates, keeping the cliArguments path for the nightly-tiers workflow, which still slices by passthrough. Plus its --self-test cases, including a digest that matches no candidate, which must be refused loudly and never read as a whole-package sample. (2) Comment-only lines that become false: scripts/report-test-timings.mjs header lines about 116 ('with a --shard=k/n passthrough') and about 267 ('the slice leg runs with --only'), and the ci.yml closure-build step's opening paragraph (about line 559: 'so that the sharded run in the next step can be --only'). With that widening the rest of the work is already on the branch.",
      "tests": "All readings are on worktree /home/user/objectstack-issue-19278, turbo 2.10.10, vitest 4.1.11, with a private --cache-dir for every turbo run. Wall-clock figures are SHARED-BOX seconds taken under scripts/pm/os-verify-lock.sh. (1) Behaviour, final config shape, 6 fixed cli files, `pnpm exec vitest run --maxWorkers=2 --reporter=json`: OS_TEST_SHARD unset gives 6 files / 105 tests. 1/2 gives 3 files / 46 tests. 2/2 gives the OTHER 3 files / 59 tests: disjoint, union = the 6, 46+59 = 105. OS_TEST_SHARD=1/2 with CLI --shard=2/2 gives the 2/2 set (the CLI wins, because vitest merges CLI options over the config's test block). The cli config has two inline projects, so this also shows config-level shard is honoured under projects. (2) Typecheck: `pnpm --filter @objectstack/cli typecheck` exit 0; check:test-typecheck OK, 3 files / 28 errors / 6 pinned signatures held (unchanged), vitest.config.ts 0 errors. A literal `test: { shard: ... }` measured TS2769 ('shard' does not exist in type 'InlineConfig'), hence the typed spread. (3) cli unit tier, OS_TEST_SHARD unset: `pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2` gives Test Files 236 passed (236), Tests 3365 passed (3365), 393.34s, lock VERDICT command-exit 0. The integration tier is declared to CI: the diff touches no integration file and no spawn entry. (4) Pin ablations, each through scripts/ablation-replace.mjs (anchor hits 1 then 0, blob moved, restored to the HEAD blob, git diff HEAD empty). A: drop OS_TEST_SHARD from turbo.json tasks['@objectstack/cli#test'].env. The self-test exits 1 naming that entry, and turbo itself then resolves cli#test env to ['OS_TEST_TIERS'] with configured [] although the generic test task still declares it, confirming a package-specific task REPLACES the generic one. B: delete the config's spread line. The self-test exits 1 with 'packages/cli/vitest.config.ts never reads OS_TEST_SHARD'. Both restored; self-test green again, 141ms wall. (5) Published surface: packages/cli files is [dist, README.md, CHANGELOG.md]; grep of the built dist for OS_TEST_SHARD finds 0 files, with a positive control (the one-shot-exit symbol) finding 2. So there is no changeset: nothing published moves.",
      "gates": "Derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at 276b3591d8, change set 4 paths vs merge base 96e724475c: 86 commands. Each was run sequentially with its exit code captured before any pipe: 85 exit 0 on the first pass. check:dual-build-cjs-loads exited 3, PREREQUISITE NOT MET (9 packages outside cli's closure had no dist), so it was not read as a pass. Those 9 were built (42 tasks, 33 cached, 45.6s) and the real `pnpm check:dual-build-cjs-loads` was re-run: exit 0. Reconciled with `--ran` on a record carrying exit codes: '86 derived famil(ies) accounted for, 86 run, 0 NOT-MEASURED (a DERIVED zero, all 86 recorded an exit code and none of them is 3)'. The ones the dispatch named: check-ci-filter-parity (and its --self-test) exit 0, 'all 187 declared cross-package glob(s) (134 unique) are covered'. check:turbo-task-graph exit 0. check:stall-guard-budget and check:stall-guard-headroom exit 0. check:shard-attestation exit 0. check:cross-package-test-inputs exit 0. check:tier-file-adoption exit 0. partition-test-shards --self-test exit 0 (its verdict line reads 'self-test OK', over 70 measured packages and 71 shard items). check:nul-bytes exit 0 (9417 files, no raw control bytes). check:pm-dispatch-gates exit 0 in 1049s on this box, above the 536-712s prediction. ⚠ This gate union ran on 276b3591d8. The branch will move when the widening lands, so the union is owed again on the new head.",
      "measurements": {
        "before_plans": "Old leg, `turbo run test --filter=@objectstack/cli --only --force --dry=json -- --shard=1/2`: 1 task. On origin/main 96e724475c the cli#test hash is a8cb3b6e48265376, and it is IDENTICAL after a packages/spec/src/ui/view.zod.ts edit (the defect, reproduced). Controls move: a file inside cli (src/utils/one-shot-exit.ts) gives 6cf4881373490413, and a declared TURBO_ROOT input of the task (packages/spec/src/system/translation.zod.ts) gives 65c4aa7a29e02a8b. Passthrough contamination, same plan: plain vs `-- --shard=1/2` has 0 of 62 hashes identical, and the plain-vs-plain control has 62 of 62.",
        "after_plans": "New leg, `OS_TEST_SHARD=1/2 turbo run test --filter=@objectstack/cli --dry=json`: 62 tasks. Plain vs OS_TEST_SHARD=1/2: 61 of 62 identical; the 1 changed is cli#test. 1/2 vs 2/2: only cli#test differs. `turbo run build --filter=@objectstack/cli` (the CI closure-build step) vs this plan: 61 of 61 build hashes identical, so the closure replays.",
        "hash_moves_proof": "New leg cli#test, --dry=json, with a transient one-line marker proven on disk (count 0 to 1, blob moved off HEAD) and restored under a trap (blob equals HEAD, git diff HEAD empty). Clean: 1ee03ac2f26389a6. packages/spec/src/ui/view.zod.ts: 04eabd0b5a9db364, MOVES. packages/types/src/env.ts: 4b15652b8c493471, MOVES. packages/cli/src/utils/one-shot-exit.ts: f2d2d4ccd3e235c3, MOVES. Lit control, packages/connectors/connector-slack/src/connector-slack-plugin.ts (a package outside cli's closure and not a declared input): 1ee03ac2f26389a6, UNMOVED. Old leg on the same tree: d5e7ec263710fe59 for clean, the view.zod.ts edit and the connector-slack edit alike.",
        "execution_proof": "Real turbo runs on cli, slice 1/16 for time (the replay decision is turbo's hash comparison and does not depend on k/n), VITEST_MAX_WORKERS=2, --concurrency=2. Clean tree: the new leg's first run is `cache miss, executing 60253d0474a35b68`, 60 tasks, 59 cached, 19 test files passed, 1m58.382s. The second run is `cache hit, replaying logs 60253d0474a35b68`, 60 of 60 cached, 104ms FULL TURBO: a legitimate replay, since nothing moved. The old leg without --force seeds `cache miss, executing e5e4dcfe362d59a6`. Then packages/client/src/index.ts was edited (a cli dependency that no TURBO_ROOT input of cli#test names; marker 0 to 1, blob cabb6e00 to 392a6a37) and the closure was rebuilt the way CI's step does it (59 tasks, 57 cached, client#build and cli#build executed, 25.2s). Old leg, no --force: `cache hit, replaying logs e5e4dcfe362d59a6`, 69ms FULL TURBO, i.e. NOT RUN (#18671 reproduced). Old leg with --force, which is main today: `cache bypass, force executing e5e4dcfe362d59a6`, the same blind hash, run only because forced. New leg, no --force: `cache miss, executing 0b12ed4c0b1637ce`, 59 of 60 cached, 19 files passed, 1m48.433s, i.e. RUNS because the hash moved (acceptances 1 and 3). Restored: blob equals HEAD, git diff HEAD empty. ⚠ These runs used the intermediate config spelling (a helper binding spread into test). The final commit spells the same key and value inline at the use site. Turbo's decision does not read the config text, and vitest honouring the final shape is re-proven in tests (1).",
        "cost": "Plans against the cache a passthrough-free closure build filled (cold build: 59 tasks, 0 cached, 7m6.732s at --concurrency=2 on the shared box; the control re-run gives 59 of 59 cached, 252ms FULL TURBO). Old leg: 1 task, 1 MISS. Drop --only but keep the passthrough: 62 tasks, 62 MISS. New leg: 62 tasks, 59 HIT / 3 MISS, the 3 being cli#test plus console#build and refd-timer-testkit#build, which declare no build script and never execute. The card's 60 / 57-3 figures are now 62 / 59-3 because the closure grew by two packages. Expected CI wall for the slice leg is the cli slice itself plus about a second of replay for 59 builds: the same test cost --force already pays, and no closure rebuild. One-time landing cost: adding OS_TEST_SHARD to the generic test env moves the hashes of 52 test tasks (175 of 227 workspace tasks unchanged), and any turbo.json edit makes all 80 packages affected anyway (TURBO_SCM_BASE=96e724475c gives 80; the null control TURBO_SCM_BASE=HEAD on the clean tree gives 0)."
      },
      "line_budget": "Diff vs merge base 96e724475c: 4 files, +294 / -72 = 366 changed lines, against the 5000 human-merge threshold. .github/workflows/ci.yml +64/-67 (the leg's comment block is rewritten, net -3). packages/cli/vitest.config.ts +33/-1. scripts/partition-test-shards.mjs +195/-2. turbo.json +2/-2. No governed surface and no skills/** are touched.",
      "deviations": [
        "Mechanism hypothesis 1, partly falsified: the literal `test: { shard: process.env.OS_TEST_SHARD }` fails cli's test-layer typecheck (TS2769; vitest declares shard on its CLI-options type, not on InlineConfig). vitest.config.ts has no ledger row, so check:test-typecheck would red. Implemented as a spread of `{ shard: process.env.OS_TEST_SHARD }` that `satisfies` a Pick of `TestUserConfig` narrowed to `shard` (spelled in words here because the GitHub sanitizer eats angle-bracket fragments), typed against the type vitest/node exports. That the runtime honours it is measured, not assumed. It rests on vitest merging the whole test block with the CLI options (`deepMerge(configDefaults, test, cliOptions)` in 4.1.11). If an upgrade stopped doing so, both slices would run the whole suite: a superset, costly but not a correctness loss, and nothing pins it.",
        "Mechanism hypothesis 5, the card's 57 HIT / 3 MISS: re-measured today as 59 HIT / 3 MISS out of 62, because the closure grew.",
        "The added pin is the config-coverage one (hypothesis 2), placed as a battery of partition-test-shards --self-test (roster +1, SELF_TEST_BATTERY_FLOOR 9 to 10). It runs in lint.yml's existing 'Shard partitioner self-test' step, so no new gate or job. It is a SPELLING check in the check-tier-file-adoption idiom, and it says so. The 'hash moves' pin is deliberately NOT added, because it is #19279's scope (open, unclaimed).",
        "ci.yml: besides the leg and its comment block, the item-split paragraph of the same step (about line 678) is rewritten. It justified a separate slice invocation by the passthrough, and would otherwise be false. I read it as part of the slice leg's comment. The closure-build step's paragraph (about line 559) is NOT edited; it is listed in the blocker instead.",
        "One line of the rewritten ci.yml comment block overruns the block's wrap width ('main-seeded entry ... Run 34746808828 did: it replayed'). It is cosmetic and left for the continuation, which edits that block anyway to add the timings-reader sentence. Re-running the 86-gate union (1049s of it one gate) for a comment reflow on a blocked branch was not worth it.",
        "The first local commit carried the harness's model-named Co-Authored-By trailer. It was amended to the model-free pair before any push, so nothing with a model identifier reached the remote (check:commit-card-trailers passed on both pushes).",
        "Execution proof uses slice 1/16 and the intermediate config spelling; see measurements.execution_proof."
      ],
      "files_changed": [
        "turbo.json: OS_TEST_SHARD added to tasks.test.env and tasks['@objectstack/cli#test'].env",
        "packages/cli/vitest.config.ts: the typed OS_TEST_SHARD spread in the root test block, plus the header section explaining it",
        ".github/workflows/ci.yml: the Test Core slice leg becomes `set -- env \"OS_TEST_SHARD=$SLICE\" pnpm turbo run test \"--filter=$PKG\" --concurrency=4 --summarize --log-order=stream`, with its comment block rewritten and run 34746808828 kept; the item-split paragraph is updated",
        "scripts/partition-test-shards.mjs: SLICE_ENV, judgeSliceWiring(), sliceWiringProblems(), and a 9-case self-test battery"
      ],
      "mcp_calls": "0",
      "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/19278/comments (this os-dev-report, through scripts/pm/post-stamped.mjs). Also 2 git pushes of the branch, which are not REST writes. No pr_create and no label-write, because no PR was opened.",
      "open_questions": [
        {
          "question": "The honest-hash shape moves the slice from turbo's passthrough (recorded in run-summary cliArguments) to a task env (recorded only as a sha256 digest in environmentVariables.configured). The timings reader identifies slices from cliArguments alone. How should this land?",
          "options": [
            "A. Widen this claim to scripts/measure-test-shard-timings.mjs (samplesFromSummary resolves the OS_TEST_SHARD digest against k/n candidates, keeps the cliArguments path, and refuses an unmatched digest loudly), plus its self-test and the three comment-only lines named in `blocker`, all in this one PR.",
            "B. Land the in-surface change now and file the reader as a follow-up card. That opens a window in which a timings refresh silently records one slice as cli's whole cost.",
            "C. Keep the passthrough and give up the honest hash. That fails acceptance 2, and the leg keeps its constant --force."
          ],
          "recommendation": "A. Real business need: scripts/test-shard-timings.json is the partitioner's only weight input and is refreshed from exactly these CI summaries, so the reader is a live consumer, measured, not hypothetical. Long-term soundness: the producer changes its carrier, so the reader moves in the same change (contract-first; one carrier, one reader), rather than being patched later. Guarding against AI error: B leaves a silent half-weight that reads right and is wrong, the exact class that goes unnoticed. No sprawl: A adds no gate, no job and no new surface, only one reader and its self-test; C buys nothing and keeps the alarmless bypass. All four axes point the same way."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: named real producer: the ci.yml Dogfood job's sharded test step, which feeds the required context 'Dogfood Regression Gate' · evidence: that step runs `pnpm turbo run test --filter=@objectstack/dogfood --only --log-order=stream -- --shard=k/3` with NO --force. --dry=json on origin/main 96e724475c shows dogfood#test at a11cf066bff49638, IDENTICAL after a packages/objectql/src/index.ts edit (objectql is not among dogfood#test's declared TURBO_ROOT inputs), while the plain leg moves 99bff506f6402576 to bd50678598c1f3ef and an in-package control (packages/qa/dogfood/vitest.config.ts) moves to 4156855690741fe6. The job restores a main-seeded turbo cache through prefix restore-keys and saves on push, so a PR whose only change is undeclared upstream source (objectql, core, spec outside automation/ and data/, ...) can have dogfood#test replayed green: #18671's mechanism in a required gate, with no --force covering it. This is a dry-run hash reading, not a replay executed in CI. The same fix shape applies (env carrier, the dogfood config read, the dogfood#test env). Recommend its own card linked to #19278 and #19279 rather than widening this one · dedupe words: dogfood --only shard replay; Dogfood Regression Gate cache replay; dogfood#test hash closure; --only hash blind",
        "carrier: 承接者:无 · noted, not filed. .github/workflows/test-nightly-tiers.yml (about line 282) slices cli by a `-- --shard=$SLICE` passthrough without --only, so each nightly slice re-hashes and rebuilds its whole build closure. That is a cost, not a correctness gap (its hash stays honest). It keeps feeding sliceOfCliArguments correctly, which is why reader option A must keep the cliArguments path."
      ],
      "acceptance_notes_for_the_pr": [
        "The config-level shard key is typed through vitest's CLI-options type. If a vitest upgrade stops merging the test block into the CLI options, both slices silently run the whole suite (superset: cost, not correctness). The partitioner battery is a spelling check and cannot see that.",
        "Landing moves the hashes of 52 test tasks once (every task on the generic test definition plus cli#test). Any turbo.json edit already makes all 80 packages affected on the landing PR.",
        "check-test-completeness and report-test-timings now also receive the slice leg's replayed build-task log lines. Both key on test and test:repo tasks and drop build-prefixed lines, exactly as they already do for the whole-package leg."
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Scope amendment to claim 5906267088 — the file surface widens to the timings reader, answering the dev's open question with A · session session_014EJ1ED8X4MMrT18BhVx4tx (os-tesla) · 2026-09-30T08:46Z

    ⛔ Not a new claim. The branch, worktree and identity are unchanged.

    Why (the dev's report 5907562928, read against the branch at 276b3591d8):

    Ruling (PM scope, not escalated): A. The producer and its one reader change in the same PR. Landing the in-surface half first (B) would leave a silent, plausible-looking wrong weight. Keeping the passthrough (C) fails acceptance 2.

    Added to the file surface:

    • scripts/measure-test-shard-timings.mjs:
      • samplesFromSummary also recognises a slice carried in OS_TEST_SHARD, by matching the environmentVariables.configured digest against the possible k/n values;
      • it keeps the cliArguments path, which the nightly-tiers workflow still uses;
      • it gains self-test cases, including a digest that matches no candidate, which must fail loudly and ⛔ never read as a whole-package sample.
    • scripts/report-test-timings.mjs, comment text only: the header at about :116 and about :267, which the change makes false.
    • .github/workflows/ci.yml, comment text only: the closure-build step's opening paragraph at about :559.
    • Nothing wider. ⛔ No new gate or job.

    Also from the report, not in this card: the Dogfood job's sharded step has the same --only passthrough shape without --force. It is filed separately, bare, for triage.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Release and handover: #19278, mid-flight, stopped on the maintainer's order · session session_014EJ1ED8X4MMrT18BhVx4tx (os-tesla) · 2026-09-30T08:53Z

    Release: session_014EJ1ED8X4MMrT18BhVx4tx (claim 5906267088, amended 5907599025) · cause: the maintainer stopped the work and signed this session off · destination: pm:queue. pm:dispatched and the assignee os-tesla come off in this act. The next seat claims it through the full protocol and continues the branch.

    • Provenance (whose instruction / verbatim / where): the maintainer, in this session's chat: 「停了吧,你下班,让下一任接手」.

    State of the branch claude/issue-19278-shard-hash-carries-closure (no PR is open):

    • Remote head 9df0b71851, on 276b3591d8, which is on origin/main 96e724475c.
      • 276b3591d8 is round 1, measured in 5907562928. The slice leg runs env OS_TEST_SHARD=$SLICE pnpm turbo run test --filter=$PKG …, with no passthrough, no --only and no --force. turbo.json declares OS_TEST_SHARD on test and on @objectstack/cli#test. packages/cli/vitest.config.ts reads it. partition-test-shards --self-test gains a slice-wiring battery (ablated, per the report).
      • 9df0b71851 is round 2, under the amendment. measure-test-shard-timings.mjs reads an OS_TEST_SHARD slice back from the summary's env digest, and keeps the cliArguments path. The three false comment passages are rewritten (report-test-timings.mjs, and the ci.yml closure-build step). partition-test-shards.mjs changed too (7 lines).
    • NOT done in round 2 (the dev was stopped mid-ablation):
      • the ablation proof of the reader's new self-test cases, including the unmatched-digest case that must fail loudly;
      • feeding a real new-leg summary through the reader, report-test-timings.mjs and --check-drift;
      • a merge of origin/main (a local merge commit was never pushed; redo it);
      • the full dispatch-gates --commands re-run on the final head;
      • the PR. Its body is sketched in the amendment, and the three Acceptance notes are in 5907562928.

    Still owed after the PR: an at-tier contract record on the landing head (the director's reminder 5904102495 on #18549), then the gated landing.

    The worktree /home/user/objectstack-issue-19278 in that container is clean, at a local, unpushed aa688f81c4 (the merge). Rely on the remote branch, not on it.

    Related, filed separately: #20820, the Dogfood gate's shard leg with the same --only passthrough shape and no --force.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Addendum to the handover note 5907712578: the branch now has a draft PR, #20824, head 9df0b71851, opened on the maintainer's word so the work is visible and CI runs on it · session session_014EJ1ED8X4MMrT18BhVx4tx · 2026-09-30T09:11Z

    • It says Part of #19278 and lists the five remaining steps in its body, the same as the handover note.
    • ⛔ Not ready, and not to be enqueued, until those steps are done and an at-tier record names the landing head.
    • The card stays in pm:queue, unassigned. The next seat claims the card and continues this PR's branch.
    • Provenance: the maintainer, in this session's chat: 「开一个草稿 PR」.

    Generated by Claude Code

  6. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Claim: maintainer direct dispatch, taking over the released card and its draft PR #20824 (continuing the handover 5907712578 + addendum 5908021217)
    Session: session_01TdiauJaVCHuj45EzZGUxHh
    Account: huangyiirene (the card's assignee from this act)
    Branch: claude/issue-19278-shard-hash-carries-closure (continued; the remote head at claim is 9df0b71851, PR #20824)
    Worktree: objectstack-issue-19278 (a fresh one in this container, from the remote branch; the previous container's unpushed aa688f81c4 is not relied on)
    Domain: domain:devx
    Seat: domain:devx#2 (objectstack-ai/objectui#10917, round R4, a maintainer direct dispatch whose scope this order extends by this one card)
    File surface: exactly PR #20824's six paths, i.e. the amended surface of 5907599025:

    • .github/workflows/ci.yml (the Test Core slice leg and the closure-build comment);
    • turbo.json (OS_TEST_SHARD on test and @objectstack/cli#test);
    • packages/cli/vitest.config.ts;
    • scripts/partition-test-shards.mjs;
    • scripts/measure-test-shard-timings.mjs;
    • scripts/report-test-timings.mjs (comment text only).
    • Plus whatever a merge of origin/main brings in. Nothing wider (stop on breach; explain in the report). [finding] The required Dogfood Regression Gate shard step runs --only with a --shard passthrough and no --force, so its dogfood#test hash ignores upstream changes and a main-seeded cache can replay it green #20820 (the Dogfood shard leg) stays out.
      Container & model: M, mode:subagent, model: opus. dispatch-gates --tier over the six paths: no path-derived mandate, so the default applies.
      Clause-②: no. CI caching and test sharding; no contract accept or reject moves. None of the five review faces is touched, so the contract review is this seat's in-seat same-form record on the landing head (contract-review.md), which the handover also asks for.
      Thread-read: 5908021217
      Serial constraints cleared: read at 2026-09-30T09:17Z against origin/main 79114850f, over the 13 other open objectstack PRs. None touches ci.yml, turbo.json, any vitest.config.ts, or the three scripts/*test-shard* / report-test-timings files.

    Provenance (whose instruction / verbatim / where): the maintainer, in this session's chat (session_01TdiauJaVCHuj45EzZGUxHh): 「objectstack 20824 你也接手处理完」.

    What continues: the remaining steps 1–4 of the handover note, done by a dev on the pushed head. Step 5 is this seat's: the same-form record on the landing head, then the gated landing, with Part of → Fixes #19278. The card's acceptance governs, as the first claim quoted: an affected slice executes; the slice hash moves on an upstream edit; with --force gone, the defect is proven not to return.

  7. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 19278,
      "status": "done",
      "branch": "claude/issue-19278-shard-hash-carries-closure",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/20824",
      "session": "session_01TdiauJaVCHuj45EzZGUxHh (dispatch session; this run is its subagent)",
      "premise_still_valid": true,
      "final_head": "e00136407d04e3b2871b30a9c6463a2f9f108f6c (pushed; git ls-remote confirms)",
      "summary": "Handover steps 1-4 are done on the existing branch, with no force-push, rebase or amend. (1) All 10 cases of the reader's env-carried-slice self-test battery were ablated through scripts/ablation-replace.mjs under a trap. Nine mutations were used, each read twice: the real --self-test (every mutation exits 1) and an instrumented harness that lists every red case. Every case goes red under at least one mutation, and the unmatched-digest case goes red under A0 and A4. One finding was folded in as a comment fix (099e5ff641): the battery comment claimed every case fails when the digest path is dropped, but cases 3, 7 and 8 are controls that pass either way. H1 holds: no code defect. (2) Real new-leg summaries (cli slices 1/2 and 2/2, the leg's own command shape, produced locally because the Actions artifact blob host answers 403 here) go through the pipeline correctly. The reader returns cli = 1217.05 s summed from the two slices, where origin/main's reader gives 608.52 s. report-test-timings reports all 2 slices as complete and labels a lone slice as a PART. --check-drift predicts one slice's share, 229.1 s. A real summary with a flipped digest fails loudly in the reader and in --check-drift (both exit 1) and is a stated problem in the report tool, which is never read as a whole sample. (3) origin/main was merged twice as merge commits: 810d42b69c, then 4b45afaed5 after dispatch-gates flagged the first derivation stale. There were no conflicts, and main touched none of the six paths (H2 holds). (4) On the final head e00136407, dispatch-gates reports 89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN. Acceptance 2 was re-proved by dry-run hashes (the new leg moves for spec, types, cli and client edits and stays for a connector-slack control). Acceptances 1 and 3 were re-proved by executed runs without --force: after an undeclared upstream edit the new leg executes, while the old --only leg replays, and it replayed across the real second merge too. The PR body was rewritten through the relay: Fixes #19278, the evidence for steps 1-4, and the contract-record line. It was read back byte-identical (15892 bytes), the PR is still draft, and auto-merge is not armed. The Changeset disposition is skip-changeset (H3 holds), and the seat applies it. The PM relay's Shard Timings Refresh red is root-caused to an intermittently stale GitHub run listing, not to this diff.",
      "tests": "All on /home/user/objectstack-issue-19278. Every heavy run went through os-verify-lock (slot issue-19278), and every lock verdict line reads command-exit 0 except where noted. Turbo runs used a private --cache-dir. STEP 1 ABLATION, reader blob 453a072feedb at 099e5ff641 = e00136407 (also measured on cb42313d89e6 at 9df0b71851, same result). Each ablation-replace leg printed 'ok mutation landed: anchor 1 -> 0, blob 453a072feedb -> X', then 'ok restored: blob == HEAD and git diff HEAD is empty', and afterwards git status --porcelain was empty. Control: the instrumented harness with no mutation shows 0 reds and exit 0. Mutations, each with the real self-test's exit and the env-battery cases red: A0 digest path dropped (const fromEnv = null): exit 1, cases 1,2,4,5,6,9,10. A1 return fromArgs only: exit 1, cases 1,2,10. A2 samplesFromSummary default sliced = {}: exit 1, case 2. A3 return fromEnv only: exit 1, case 3 plus old-battery cases 29,31,34,35,36,37,40,41,42,43. A4 throw replaced by return null: exit 1, cases 4,5,6. A5 unsliced package returns null: exit 1, case 5. A6 empty-value guard deleted: exit 1, case 7. A7 find without the OS_TEST_SHARD= prefix: exit 1, case 8. A8 disagreement check if (false): exit 1, case 9. After the ablations: measure-test-shard-timings self-test OK. STEP 2 REAL SUMMARIES at 95b97ef2e (the six paths and every packages/cli file are identical to the final head), command OS_TEST_TIERS=queue VITEST_MAX_WORKERS=2 env OS_TEST_SHARD=k/2 pnpm turbo run test --filter=@objectstack/cli --concurrency=2 --summarize --log-order=stream --cache-dir=PRIVATE. Closure build: 59 tasks, 6m24.7s. Slice 1/2: 'cache miss, executing 90ddc44dcc24b458', 60 tasks, 59 cached, 152 files, 2069 passed and 1 skipped, 10m44.6s; the summary has cliArguments [] and configured [OS_TEST_SHARD=d939926f... (sha256 of 1/2), OS_TEST_TIERS=00b109cf...]. Slice 2/2: 'cache miss, executing 52f80464736e668b', 151 files, 1865 passed, 9m32.7s. CI corroboration: Test Core (6/6) on 9df0b71851, job 109819361192, log via MCP: '@objectstack/cli:test: cache miss, executing 874a69822b22ac22', Tasks 60, Cached 59, 151 files, 1865 tests. Pipeline: measure --run local-19278 s1 s2 --out scratch gives exit 0 and packages {@objectstack/cli: 1217.05} (644.411 + 572.636). origin/main 810d42b69c's reader on the same files gives slices [] and buildDataset cli 608.52 (the #16173 defect). report-test-timings --capture x2 then --merge: cli 1217.05, 'all 2 slices', complete true, 303 of 303 file lines. With one capture only: 'slice 1/2 — PART, not a total', where origin/main prints 644.41 with no note. partition-test-shards --check-drift s1 s2: 'predicted 229.1s, measured 644.4s', DRIFT 2.81x, exit 1 (the shared box is about 2.7x slower than CI). origin/main's --check-drift: 'predicted 458.1s', OK 1.41x (a slice compared against the whole package). Perturbed digest (first hex digit of slice 1/2's OS_TEST_SHARD flipped): measure exit 1, 'matches no slice the partitioner can emit for it (1/2, 2/2). Refusing to read the window as a whole-package sample', no dataset written. --check-drift exit 1, same refusal. report-test-timings capture exit 0 by design, with the refusal under Problems and cli shown as 'slice 2/2 — PART, not a total' (complete false). STEP 4 ACCEPTANCE ON e00136407, cli#test --dry=json, each edit planted and restored by ablation-replace. New leg (OS_TEST_SHARD=1/2) clean 5fe85e3cd60398b1. view.zod.ts f57477faa9b85239, env.ts b64907aa07f030ad, one-shot-exit.ts 123e600f94cc13c8, client/src/index.ts 32e74945bc85d7e1: all MOVE. connector-slack control 5fe85e3cd60398b1: STILL. Old leg (--only --force -- --shard=1/2) d26a68b9c44aac59 for clean, spec, types, client and control alike; it moves only for the in-cli edit (297d412288a9c65b). New-leg plan: 62 tasks, 59 HIT / 3 MISS; closure build hashes are 61 of 61 equal to turbo run build --filter=@objectstack/cli. The same probe on 099e5ff641 gave new-leg clean 6a3fe12522c74bb9, so the second merge moved it, while the old leg stayed d26a68b9c44aac59. Executed, slice 1/16, OS_TEST_TIERS=queue, no --force anywhere. The new leg on the unchanged tree seeded 'cache miss, executing 8cc2f107d21814cf' (19 files, 1m42.1s), then replayed 'cache hit, replaying logs 8cc2f107d21814cf' in 86ms. The old --only leg on the unchanged final tree gave 'cache hit, replaying logs dc666be1735ca19a', an entry written on 099e5ff641 before the second merge's upstream changes: the defect, reproduced by a real merge. Planted edit in packages/client/src/index.ts (blob cabb6e00308f to 2ab5bc398aea), then the CI closure rebuild: client#build and cli#build executed, 57 of 59 cached. Old leg: 'cache hit, replaying logs dc666be1735ca19a', 118ms, NOT RUN. New leg: 'cache miss, executing 61f0a4c75daa610c', 19 files passed, 1m38.1s. Restored: blob-head equals blob-disk cabb6e00308f, final git status empty. The same sequence on 099e5ff641 with the partition value 1/2: clean replay 90ddc44dcc24b458, then after the edit 'cache miss, executing 2df7b9311ca50a57', 152 files, 2069 passed and 1 skipped, 10m22.8s. OTHER: pnpm --filter @objectstack/cli typecheck exit 0 (check:test-typecheck OK, 3 files / 28 errors / 6 signatures held). pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 at e00136407: 237 files, 3370 tests passed, 496.3s. The integration tier was not re-run on the final head: the full queue-tier suite, both tiers across the two slices (303 files), ran at 95b97ef2e, whose cli files are identical, and CI's Test Core on e00136407 is success. node scripts/check-test-completeness.mjs --self-test OK (it imports the partitioner). eslint narrowing at e00136407: population read from eslint's own config (isPathIgnored false for all 4 changed lintable files); --format json count 4 files, 0 errors, 0 warnings; invariance: the config sets no parserOptions.project and no projectService (0 hits) and says it never enables type-aware linting, so this diff cannot move a verdict on an untouched file. check:nul-bytes OK (9435 files).",
      "gates": "At e00136407: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack. Its stderr said the tree was 2 commits behind origin/main 22e584c9d and none of those commits touched what the derivation reads. Change set: 6 paths against merge base 4b45afaed. 89 commands. Each was run as printed, with the exit code captured before any pipe. First pass: 87 exit 0. check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET, 9 packages outside cli's closure had no dist). check:pm-dispatch-gates ran detached. The 9 packages were built (42 tasks, 33 cached, 49.6s) and pnpm check:dual-build-cjs-loads re-run: exit 0. The other dist readers were re-run on the fuller tree (check:dts-closure, check:lean-entry-closure, check:published-files, check:sourcemap-no-sources-content): all exit 0. check:pm-dispatch-gates: exit 0, 'dispatch-gates self-test: 1976 cases pass', 1058.8s. Reconciled: '✓ dispatch-gates --ran: 89 derived famil(ies) accounted for — 89 run, 0 NOT-MEASURED (a DERIVED zero — all 89 recorded an exit code and none of them is 3)', and 'Run reconciliation — 89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN'. NOT MEASURED, outside the 89 and named by the derivation: 9 families that take a value from the workflow, so they cannot run locally because their argv or env has no value outside CI. They are check-shard-attestation --emit for test, dogfood and dogfood-verify; check-shard-attestation --verify for Test Core and Dogfood Regression Gate; check-test-completeness on dogfood.log and on test-core.log; check-issue-citations --census; check-required-contexts --verify-required-set. The 13 pending-changeset families do not apply (no changeset; disposition skip-changeset). The 7 path-scheduled CI jobs and their 38 steps are CI's own. CI on e00136407: CI success (all jobs, including every Test Core shard, Dogfood Regression Gate, Build Core and Temporal Conformance), Lint & Type Check success, Governed Surface Guard success, and all closing and claim guards success, including the re-run after the body edit. PR Automation failed at Check Changeset 'Require a changeset (or the skip-changeset label)', awaiting the seat's label; a second PR Automation run started by the body edit was in_progress at 10:51Z. Shard Timings Refresh failed (run 36701198568); see the refresh_check field.",
      "refresh_check": "Shard Timings Refresh, job 'Regenerate the shard-timings dataset', on e00136407: FAILURE (run 36701198568, job 109840789692). This is its final verdict on the final head, because nothing was pushed after it. The step 'Choose a green, uncensored, un-replayed run' refused with exit 1, 'candidates existed and none was eligible'. Root cause, measured: the GitHub run-listing API served a stale index for ci.yml schedule runs. The diff is not the cause. (a) The lane's inputs are byte-identical between the green 099e5ff641 and the red e00136407: git diff over scripts/ci/, .github/workflows/shard-timings-refresh.yml and scripts/measure-test-shard-timings.mjs prints nothing, and the selector imports only import-prerequisite.mjs and invoked-as.mjs. (b) Reproduced locally at 10:22Z: NODE_USE_ENV_PROXY=1 node scripts/ci/select-shard-timings-run.mjs --candidates --limit 24 exited 1, rejecting 24 of 24 runs as 'run summary artifact(s) 1-of-6 ... 6-of-6 are missing or expired', with the newest candidate 36324387456 at 2026-09-27T14:00:48Z. (c) GET /repos/objectstack-ai/objectstack/actions/workflows/ci.yml/runs?event=schedule&branch=main&status=completed&per_page=5 returned total_count 70 and newest 2026-09-27T14:00:48Z, and about a minute later returned total_count 512 and newest 36699807760 at 2026-09-30T10:01:15Z. Run 36693380342 (schedule, 09:01Z, success, six run-summary artifacts expiring 2026-10-01) exists throughout, and the green refresh at 09:59Z (job 109835317504) used exactly that run. (d) Re-running the selector at 10:23:55Z, 10:24:20Z and 10:24:45Z gave exit 0 each time, with 36699807760 and 36693380342 ELIGIBLE. The check was not re-run to green. Separately, the green runs' dry-run logs show the partitioner self-test red on the REGENERATED dataset ('slice derivation: UNSLICED, @objectstack/cli at 1231.52s ... now fits under 1.3x on its own'). That comes from main's scheduled summaries read through the unchanged cliArguments path. It is main-side state, and the lane reports it by design (PARTITIONER_EXIT=1 does not red the job).",
      "changeset": "Disposition: skip-changeset. The seat applies the label; this run made no label writes. Proof: presence, 0 .changeset/*.md added against merge base 4b45afaed5. node scripts/check-empty-changeset.mjs --base origin/main: exit 0, '0 declaring changeset(s) added' and no foreign changeset modified or deleted. node scripts/check-changeset-no-major.mjs --base origin/main: exit 0, no major bump. Published bytes: packages/cli files are [dist, README.md, CHANGELOG.md], and tsconfig.build.json includes only src, so vitest.config.ts is test configuration. Built cli dist + README + CHANGELOG: OS_TEST_SHARD in 0 files; positive control exitOneShotCommand in 6 files; no vitest.config* in dist. The other paths are CI config, the root turbo.json, and scripts of the root package (private: true). Check Changeset on e00136407 fails only at 'Require a changeset (or the skip-changeset label)', which confirms H3: it lacks a disposition and does not misread paths.",
      "mcp_calls": "4 — mcp__github__get_job_logs x4 (read only): job 109819361192 three times (Test Core 6/6 on 9df0b71851, widening the tail), job 109835317504 once (the green Shard Timings Refresh at 09:59Z). No MCP write tool.",
      "api_writes": "2 — (1) PATCH /repos/objectstack-ai/objectstack/issues/20824 (body only), through the fleet-write relay (scripts/pm/with-fleet.sh --via dispatch; request fw-20260930T105041Z-6a5892, relay run 36704884148, success; its read-back and a REST read-back both found 15892 bytes sent and 15892 stored, identical). (2) POST /repos/objectstack-ai/objectstack/issues/19278/comments, this os-dev-report, through scripts/pm/post-stamped.mjs. Also 3 git pushes of the branch (95b97ef2e, 099e5ff64, e00136407; fast-forward, not REST). No pr_create, no label-write, no assignee write. REST reads were GETs of the issue, comments, PR, runs, jobs and artifacts. One artifact download was refused by the proxy (blob host, 403).",
      "deviations": [
        "Second merge of origin/main (4b45afaed5) beyond the one the dispatch named. dispatch-gates flagged the derivation on 099e5ff641 as STALE because main had changed scripts/pm/fleet-write/dispatch.mjs, a file the derivation reads. Every step-4 proof was then re-run on the new head.",
        "First hash-probe attempt on 099e5ff641 was a no-op: the replacement contained the anchor, so ablation-replace refused (anchor 1 -> 1) and the plans never ran with an edit. Its readings were voided (kept aside as accept/hash-noop-attempt1). The replacement was changed so the anchor drops, and the probe re-ran.",
        "Local turbo shape versus ci.yml: --concurrency=2 (not 4), VITEST_MAX_WORKERS=2 and a private --cache-dir, per the resource rules. None of these enters a task hash or the summary's slice fields. The final-head execution proof used slice 1/16 for time; the partition value 1/2 was executed on 099e5ff641 and 95b97ef2e.",
        "Round-1 PR-body table corrected: its row said the old leg is unchanged for an upstream edit in spec / types / cli. An edit inside cli moves the old leg too (297d412288a9c65b), so the row now splits spec/types from cli.",
        "PR assignee is empty while the card's is huangyiirene. The PR was opened by another session, and the dispatch forbids label writes, which carry the PR assignee, so it is left for the seat.",
        "Attribution: commits carry the model-free trailer pair that AGENTS.md prescribes and that the pre-push hook enforces, not the harness reminder's model-named Co-Authored-By. PR body edit: no footer was sent (the edit-side prescription). Attribution is a prose line naming both sessions, which replaces the previous harness block for session_014EJ1ED8X4MMrT18BhVx4tx."
      ],
      "files_changed": [
        "scripts/measure-test-shard-timings.mjs: the env-carried-slice battery comment (099e5ff641, comment only)",
        "merge commits 95b97ef2e and e00136407 (origin/main 810d42b69c and 4b45afaed5); the PR's delta against main is still exactly the six paths, +536 / -95"
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: public door = the Shard Timings Refresh check on PR #20824 at e00136407 (run 36701198568) answered red 'candidates existed and none was eligible' while eligible scheduled runs existed (36699807760 at 10:01Z and 36693380342 at 09:01Z, both with six unexpired run-summary artifacts). Reproduced locally at 10:22Z and gone at 10:23Z · evidence: the refresh_check field. GET actions/workflows/ci.yml/runs with event=schedule, branch=main and status=completed intermittently returns a stale index (total_count 70, newest 2026-09-27T14:00Z) instead of the live one (total_count 512). select-shard-timings-run reads that listing once, and its leg-2 refusal text ('every one was censored, failed, or has lost its run-summary artifacts') then points a reader at the hourly trigger or the retention window. It can red any PR touching the lane's three paths, and the Monday schedule too, for a cause outside the repo. A possible shape: when every candidate is past the 1-day retention, cross-check the newest scheduled run before refusing, or refuse as NOT MEASURED; that is the seat's call · dedupe words: shard-timings-refresh stale run listing; select-shard-timings-run no eligible run; candidates existed and none was eligible; workflow runs listing total_count",
        "carrier: 承接者:无 · noted, not filed. Dry-runs of the refresh lane regenerate the dataset from main's 09:01Z scheduled run, and on that dataset the partitioner self-test goes red: 'slice derivation: UNSLICED, @objectstack/cli at 1231.52s is 1232s against a 1188s mean and now fits under 1.3x on its own ... Re-derive the slice count (or retire it)'. The next real refresh PR will carry this red by design. It is main-side state (the summaries carry cliArguments slices, read by the unchanged path), not this diff."
      ]
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Landing record: PR #20824 merged through the queue at 2026-09-30T11:33:41Z, as 30839063b56181e396ddd3065cab47e6d884dc66. domain:devx seat 2 (objectstack-ai/objectui#10917), session_01TdiauJaVCHuj45EzZGUxHh, closing this card at 2026-09-30T11:34Z.

    • Reviewed head = landed head. The seat review 5909822071 (ACCEPT) read e00136407, and nothing was pushed after it. The queue built merge group pr-20824-1741c5dc on that head, and every check there passed: 24 success, then the last 2 finished, 0 red.
    • Delivered:
      • Test Core's file-level slice leg carries its slice in the task-declared OS_TEST_SHARD, with no --only, no --force and no passthrough.
      • So the slice's task hash now carries its build closure.
      • The dev report 5909748208 measured the card's acceptance on the final head: (1) an affected slice executes; (2) the hash moves on upstream edits in spec, types, cli and client, and stays put for a control; (3) with --force gone, the defect does not return.
      • The one reader, measure-test-shard-timings.mjs, reads the env-carried slice back from the summary digest, and refuses an unmatched digest loudly.
    • No contract-review record was owed. The PR touches no review face and says Clause-②: no; the reasoning is in the review.
    • Carried, not filed (carrier: 承接者:无; neither passes the filing gate's reach:):
      1. select-shard-timings-run reads GitHub's ci.yml schedule-run listing once. The listing intermittently serves a stale index (measured by the dev: total_count 70, newest 09-27, against the live 512), and the selector then refuses with "candidates existed and none was eligible". It cost this PR one re-run. Dedupe words: shard-timings-refresh stale run listing, candidates existed and none was eligible.
      2. On a dataset regenerated from main's scheduled summaries, the partitioner's self-test reads cli as fitting UNSLICED under 1.3x. That is main-side state, which the next real refresh PR will carry by design.
    • Out of scope, filed earlier: [finding] The required Dogfood Regression Gate shard step runs --only with a --shard passthrough and no --force, so its dogfood#test hash ignores upstream changes and a main-seeded cache can replay it green #20820, the Dogfood shard leg with the same --only passthrough shape.
    • State: pm:dispatched stripped, closed completed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions