Repository navigation
Description
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Blocked-by: #30799
Filing gate ③, a task the maintainer directed: on #29466's snapshot lane, the maintainer chose option A on a decision card at 2026-11-06T05:41Z, a daily scheduled preflight that stops at the approval (ruling record 6677910954). ⛔ Not a claim.
Ruling-ref: 6677910954
Business reason. main lands about a hundred PRs a day, so a fix is ready for app repos every day. Today the lane waits for a human to dispatch it. With a daily start, the only human act left is the one click that matters, the approval at environment: release.
Reader who acts. The domain:devx seat. One Tier H PR touching docs/adr/0125-release-approval-gate-replaces-the-typed-version.md and .github/workflows/release.yml, plus whatever pins and self-tests read them. This card waits on the lane PR #30799.
What the change does (bound by the ruling)
- A
scheduletrigger starts the snapshot lane's preflight once a day: the commit at distance zero, the RC-cycle read (selected commit and main's tip), the debut rule, and the dry run, all exactly as asnapshot_nextdispatch. - When the preflight passes, the snapshot job waits at
environment: release, and it publishes only on the maintainer's approval. ⛔ Prime Directive 15 is unchanged: no seat dispatches the lane or approves its deployment. - An unapproved run is not an error and is not swept. The next day's run supersedes it.
- The
scheduleevent runs no stable job.release-integrity, the full-battery gate,publish,version-pr,dockerandstale-promptsread the schedule the way they readsnapshot_next, by strictly subtractiveif:edits. - Everything else in the 2026-11-05 amendment stands:
nextonly, neverlatest, no debut, workspace only, no tag, no Release, no Version Packages PR touch.
Acceptance
- ADR-0125 gains a short amendment (or a dated note on the 2026-11-05 amendment, in the house shape) that admits the scheduled start. It quotes the sentence it replaces ("no
scheduleand nopushcan start it") and names the ruling. The ADR part is drafted on Fable at xhigh, and the PR gets a complete Fable review before merge (maintainer rule, 2026-10-25). release.ymlhas thescheduletrigger. The cron hour is chosen after the nightly full battery, and the choice is argued in a comment.- A preflight refusal on the scheduled run is visible: a red run with its reason in the summary. A refusal is expected while
@objectstack/service-pushhas no npm version. - The self-tests pin it: a scheduled run starts only the snapshot jobs, and a stable dispatch or push never does.
- The release-channels row in
docs/releases-maintenance.mdsays the snapshot is proposed daily by schedule and published on approval. - Tier H hand-off after ACCEPT, contract review PASS and the Fable review.
Dedupe (open AND closed): is:issue "snapshot_next schedule" → 1 hit (#30591), is:issue "daily next snapshot" → 40 hits, is:issue "snapshot schedule next" → 243 hits. None but #30591/#30590 is about the snapshot lane, and neither schedules it.
Activity
objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Unblock ·
pm:blocked→pm:queue· 2026-11-06T06:03Z. ⛔ Not a claim.Blocked-by: #30799is merged as14917871b8. The snapshot lane, with itssnapshot_nextinput, preflight and approval-held job, is onmain.release.yml's snapshot jobs or ADR-0125.objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Claim: PM loop round 1
Session:
session_017ihL2ebbZkr2QAEG1x7UC8Account:
marchtianBranch:
claude/issue-30832-snapshot-daily-scheduleWorktree:
objectstack-issue-30832Domain:
domain:devxSeat:
domain:devx#2Ruling-ref: 6677910954
Direct dispatch: 田騏 (maintainer), in the project thread on a decision card, 2026-11-06T05:41:01Z, chose 「每天定时预检,停在批准」 on 「next 快照要不要改成每天定时发?」. He raised the lane's ceiling to 3 the same minute, with 「devx 车道并发加到3」 (05:42:29Z).
File surface:
docs/adr/0125-release-approval-gate-replaces-the-typed-version.md(a dated amendment admitting the scheduled start, replacing "noscheduleand nopushcan start it" for the snapshot preflight only),.github/workflows/release.yml(ascheduletrigger that starts the snapshot preflight; strictly subtractiveif:edits so a scheduled run starts no stable job),scripts/ci/snapshot-next.mjswiring pins and self-test, the release-channels row indocs/releases-maintenance.md, and whatever pin or self-test a gate derives from those files. ⛔ The approval atenvironment: releasestays a human act (Prime Directive 15 unchanged); ⛔ neverlatest.Container & model:
M,mode:subagent,model: CONTRACT_REVIEW_TIER,effort: xhigh, reason: maintainer ruling 2026-10-25 「adr 这种任务都需要 fable extra」 (the ADR part is drafted at Fable xhigh; complete Fable review before merge)Clause-②: no
Metadata-protocol: none
Responsibility: n/a — ADR text + release wiring (Tier H, governed); an independent complete Fable review before ACCEPT, then hand-off to os-zhuang + hotlong
Thread-read: 6678236253
Premise: holds.
origin/mainb6182249c3carries the snapshot lane (#30799, merged14917871b8) onworkflow_dispatchonly, and ADR-0125's 2026-11-05 amendment forbids aschedulestart.Serial constraints cleared:
Blocked-by: #30799merged and released in 6678236253; #30591 ispm:on-holdawaiting service-push's debut, with no edit in flight; no open PR touches the lane or ADR-0125.objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
os-dev-report
Card #30832 · draft PR #30862 at head
a4bb83b2a43f105f98a0324d581d571697300fce· 2026-11-06T07:12Z{ "change": "release.yml fires a second cron on its one `schedule:` (`17 1 * * *`, beside the 6-hourly `0 */6 * * *`); the two clocks are told apart by `github.event.schedule`, as fleet-patrols.yml does. The daily cron starts `snapshot-next-preflight` alone (the unchanged dispatch preflight; on a schedule the summary says the clock started it and that a refusal is the expected daily red until `@objectstack/service-push` debuts); on a pass `snapshot-next` waits at `environment: release` as before. `version-pr` now names its own cron (strictly subtractive); every stable job plus `stale-prompts` is skipped on the daily cron. New job `snapshot-next-supersede` (needs the preflight, `success() && <daily cron>`, `actions: write`) runs `snapshot-next.mjs supersede`, which cancels only an OLDER `schedule` run whose snapshot job is still `waiting` at `release` — never a dispatch, a started job, a stable prompt or the calling run; an unanswered read defers to tomorrow (exit 0, warning). `cancel-in-progress` stays false. ADR-0125 gains `## Amendment (2026-11-06, #30832)` in the house shape plus dated pointer callouts at D1/D4/D5 and the three replaced 2026-11-05 sentences; D1-D6 and earlier amendments untouched. docs/releases-maintenance.md row: proposed daily by schedule, published on approval (own commit). Pins: snapshot-next.mjs `declaredCrons`/`guardClock`, clock + supersede pins in `snapshotWiring`, three new batteries (floor 13→16, 123 cases/16 batteries); fleet-write `jobsStartedBy` gains a `schedule` argument and its release.yml pins evaluate each cron (340 cases/17 batteries). Draft PR, `skip-changeset`.", "ruling_lines_mapped": { "1_schedule_starts_the_preflight_once_a_day_exactly_the_dispatch_preflight": { "adr": "Amendment (2026-11-06) › What the ruling binds › 1; pointer callout under 2026-11-05 bound line 2 replacing \"no `schedule` and no `push` can start it\"; callout under the \"Dispatch-only, and exclusive\" requirement; callout under the ⛔ \"never reachable from `push` or `schedule`\"", "workflow": "release.yml `on: schedule:` second cron `'17 1 * * *'` with the argued comment; `snapshot-next-preflight` `if:` schedule arm `(github.event_name == 'schedule' && github.event.schedule == '17 1 * * *')` beside the unchanged dispatch arm; steps unchanged but for the schedule-only `Note the scheduled start` summary step and the event-aware `started` line; `version-pr` `if:` names `'0 */6 * * *'`" }, "2_on_a_pass_the_snapshot_job_waits_at_environment_release_and_publishes_only_on_approval": { "adr": "Amendment (2026-11-06) › What the ruling binds › 2; D1 and D4 pointer callouts (no scheduled run reaches the stable publish job or the repair lane)", "workflow": "`snapshot-next` `if:` `success() && ((schedule arm) || (dispatch arm))`; `environment: release`, group `release-snapshot-next-<ref>`, permissions and steps unchanged; the `Guard the approved snapshot` summary line is event-aware" }, "3_an_unapproved_run_is_the_system_working_the_next_days_run_supersedes_it_the_stable_sweep_untouched": { "adr": "Amendment (2026-11-06) › What the ruling binds › 3 (the narrow reading of \"supersedes\"); D5 pointer callout; What the lane must satisfy › \"Supersede, narrowly\"; What does not change › stale-prompts and release-pending-publish.mjs untouched", "workflow": "new job `snapshot-next-supersede` at the end of release.yml (needs [snapshot-next-preflight]; `success() && (github.event_name == 'schedule' && github.event.schedule == '17 1 * * *')`; actions: write, contents: read; one call `node scripts/ci/snapshot-next.mjs supersede --workflow release.yml`); `snapshot-next`'s concurrency comment says why `cancel-in-progress: true` is wrong; `stale-prompts` not touched (its `if:` already excludes schedule); scripts/release-pending-publish.mjs not touched" }, "4_everything_else_in_the_2026-11-05_amendment_stands_option_B_not_chosen": { "adr": "Amendment (2026-11-06) › Status (\"Option B … was not chosen\"), › What the ruling binds › 4, › What does not change", "workflow": "no stable job's `if:` widened: `release-integrity`, `full-battery`, `publish`, `docker`, `stale-prompts` already exclude schedule, `version-pr` now excludes the daily cron; `snapshotWiring` and fleet-write pins: daily cron → preflight alone, mayRun snapshot-next + supersede, every other job skipped; bookkeeping cron → version-pr alone" } }, "cron_derivation": "The preflight reads the nightly full battery (ci.yml and lint.yml, cron `0 0 * * *`). Measured over 2026-10-31..11-06 from the scheduled runs, the later of the two nightly runs finished at 00:52:03, 00:51:31, 00:33:28, 00:41:20, 00:47:45, 00:34:31, 00:28:03Z (range 00:28–00:52). `17 1 * * *` = 01:17Z leaves 25 min past the slowest finish observed; 01:17Z is 09:17 Beijing (UTC+8), the maintainer's morning, so the prompt is read the morning it is proposed; `:17` keeps off the `:00` crowd GitHub queues worst; a late battery costs freshness, never correctness (the preflight picks the newest commit whose battery is green ON it). The seat's increment proposes exactly 09:17 Beijing, which is what is built. Argued in the `schedule:` comment, marked landing detail 1.", "gates": { "derived_by": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (67 commands, derived after the one origin/main merge)", "results": "67 run; 66 exit 0 at first run; `pnpm --filter @objectstack/lint run check:doc-formula-expressions` exit 3 (missing build prerequisite), rebuilt with `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` and rerun to exit 0; every `CMD :: exit N` recorded before any pipe, full list in the PR body", "reconciliation": "node scripts/pm/dispatch-gates.mjs --ran ran-final.txt --repo objectstack-ai/objectstack :: exit 0 — 67 derived, 67 run, 0 NOT-MEASURED, 0 UNRUN", "self_tests": "snapshot-next.mjs --self-test: 123 cases / 16 batteries (was 89 / 13); fleet-write/validate.mjs --self-test: 340 cases / 17 batteries; scheduled-full-run.mjs --self-test OK; release-pending-publish.mjs --self-test 146 cases / 35 batteries; check-nul-bytes OK; release.yml parses as YAML with the two crons and nine jobs" }, "files_changed": [ ".github/workflows/release.yml", "docs/adr/0125-release-approval-gate-replaces-the-typed-version.md", "docs/releases-maintenance.md", "scripts/ci/snapshot-next.mjs", "scripts/pm/fleet-write/validate.mjs" ], "deviations": [ "The order's 'preflight refusal on schedule is a red run' is built as ordered; the seat's increment says this may become a quiet skip — kept red, alternative spelled at the one place (landing detail 3).", "The supersede is a new job plus a new `supersede` mode in snapshot-next.mjs rather than a concurrency setting: `cancel-in-progress: true` would cancel a snapshot approved minutes before the next tick mid-publish, so the newer run replaces only an older WAITING scheduled prompt. The order asked for a justified decision here; this is it, and it is deletable whole (landing detail 2).", "The supersede job installs the workspace (setup-workspace) because snapshot-next.mjs imports `semver`; the stable sweep needs no install. A few minutes a day.", "open_questions is non-empty on the seat's instruction (five landing details to confirm); check-half-states H52 reads a non-empty array on a `pm:dispatched` card without `needs-user-decision` — the seat's call, I label nothing.", "The ADR amendment carries a closing section 'Landing details being confirmed — this draft's reading' so the five are in one place in the record too; it is rewritten or removed by the second increment before the PR leaves draft." ], "open_questions": [ { "n": 1, "question": "The run time: 09:17 Beijing = 01:17Z (replaces 'the hour after the nightly')", "implemented": "`17 1 * * *` under `schedule:` and in the three `if:`s (snapshot-next-preflight, snapshot-next, snapshot-next-supersede); comment argues it from the measured nightly finishes; marker `[#30832 landing detail 1 of 5]` at the cron. Change = four string sites; the self-test refuses a mismatch and a non-daily cron." }, { "n": 2, "question": "Yesterday's unapproved prompt is replaced by the new run, not left waiting", "implemented": "Replaced: job `snapshot-next-supersede` + `snapshot-next.mjs supersede` cancel only an older `schedule` run whose snapshot job is `waiting` at `release`. If 'left waiting': delete the job (end of release.yml) and the `supersede`-named pins/batteries. If a dispatch should also be replaced: one refusal (`run.event !== 'schedule'`) in `judgeSnapshotPrompts`. Marker at the job's comment." }, { "n": 3, "question": "A preflight refusal is a quiet skip, not a red run", "implemented": "Red run (the order's default) with the reason in the step summary and a schedule-only 'expected daily red' note. Quiet-skip alternative spelled in the lane header: the refusing steps exit 0 on `schedule` for a measured refusal (EXIT_FINDINGS), set output `refused=true`, `snapshot-next`'s `if:` reads it; NOT MEASURED (exit 3) stays red. Marker in the lane header." }, { "n": 4, "question": "A real failure, as opposed to a refusal, opens a card", "implemented": "Not built. The place is named in the lane header: a `failure()` step at the end of the preflight on `schedule` only, filing through a dependency-free filer like scripts/ci/scheduled-full-run-card.mjs, keyed on exit 3 (NOT MEASURED) so a debut-rule refusal never files. Marker in the lane header." }, { "n": 5, "question": "Only an ADR amendment, no other doc rewrites", "implemented": "ADR amendment + one isolated commit `docs(releases): …` touching the `next` snapshot row and the one schedule sentence of docs/releases-maintenance.md (the order and the card's acceptance ask for the row). If confirmed as 'ADR only', drop that commit." } ], "mcp_calls": [], "api_writes": [ "git push -u origin claude/issue-30832-snapshot-daily-schedule (a4bb83b2a43f105f98a0324d581d571697300fce)", "fleet-write relay pr_create → draft PR #30862 (labels: skip-changeset)", "post-stamped.mjs --comment=30832 (this os-dev-report)" ], "filed_issues": [] }ci(release): the daily next snapshot skips quietly, reads the stable …
objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
os-dev-report
Card #30832 · round 2 (delta to report 6679395057) · draft PR #30862 at head
5fe2149385301e15afcde5fe15d33f4d6434ff49· 2026-11-06T12:52Z{ "change": "Round 2 lands the five landing details the maintainer confirmed at 2026-11-06 11:32Z (「同意」 on the five-point list; ruling 6677910954 unchanged). (1) Time `17 1 * * *` and (2) the supersede stand as built; the UNCONFIRMED markers are removed and the comments cite the confirmation. (3) Quiet skip, schedule only: five expected refusals -- same-commit, rc-cycle, debut, no-green-commit, stable-lane -- each conclude as a GREEN run with nothing queued and no card (a ::notice and a step-summary section). The switch is one schedule-only expression on the preflight job's three refusing calls (`${{ github.event_name == 'schedule' && ' --quiet-skip' || '' }}`) plus the select step's own EVENT_NAME test; `proposalVerdict` in snapshot-next.mjs is the one place kinds, flag and exit code meet. The preflight job records `refusal`/`reason` outputs; `snapshot-next` and `snapshot-next-supersede` require `refusal == ''`. A dispatch keeps the loud refusal (exit 1, same outputs, no card). New checks on both starts: the same-commit check (`record-commit --commit` writes gitHead into every manifest after the version step, `guard --commit` reads it back from every packed manifest, `preflight --commit` reads the anchor's `next` version document on npm; passes through while `next` is no snapshot; a snapshot recording no commit is refused as unexpected) and the stable lane (`stable-lane --workflow release.yml`, release-pending-publish.mjs's collectWaitingRuns + collectPublishRuns, PUBLISH_JOB_NAME / PUBLISH_SETTLED_JOB_STATUSES, non-GET refused structurally, unread = NOT MEASURED). (4) Card: new job `snapshot-next-card` (needs preflight + snapshot-next, always() && arms && ((preflight failed && refusal == '') || snapshot failed), contents: read + issues: write) files/refreshes ONE fixed-title card through the full-run card's own filer (`snapshotCardStep` -> `fileOrRefreshCard`; identity, case and body in scheduled-full-run.mjs) on an unexpected refusal or a publish failure after the approval; body gives reason, run link, candidate commit, version reached, and the partial-publish rule (fresh complete snapshot, never a republish, never latest). Success and quiet skips file nothing. (5) Text: ADR-0125's 2026-11-06 amendment states the ruled behaviour (quiet skips, card, 'no schedule can publish', old proposal replaced by new, PD15 unchanged, trial readings), the 'Landing details being confirmed' section and every marker removed, the red-run requirement replaced; release.yml header re-pinned (stable publish never reachable from schedule + the preflight exception); fleet-write validate.mjs reads ten jobs; the docs/releases-maintenance.md row commit kept and the row updated. origin/main merged once more (26c965cb8f); every derived gate re-run on the final diff; PR body rewritten through the relay issue_patch.", "ruling_lines_mapped": { "1_schedule_starts_the_preflight_once_a_day_exactly_the_dispatch_preflight": { "adr": "Amendment (2026-11-06) › What the ruling binds › 1 (now also names the two checks added on both starts and that only the CONCLUSION of an expected refusal differs by event); the bound-line-2 callout now reads 'no `schedule` can publish; `push` cannot start it'", "workflow": "release.yml `schedule:` cron `'17 1 * * *'` (comment cites the 11:32Z confirmation, item 1); `snapshot-next-preflight` unchanged arms; the same steps on either start, the refusing ones carrying QUIET_SKIP_EXPRESSION; new step `stable-lane` and `--commit` on the preflight call" }, "2_on_a_pass_the_snapshot_job_waits_at_environment_release_and_publishes_only_on_approval": { "adr": "Amendment (2026-11-06) › What the ruling binds › 2; › What stays forbidden › 'No `schedule` can publish'", "workflow": "`snapshot-next` `if:` `success() && needs.snapshot-next-preflight.outputs.refusal == '' && (arms)`; environment: release unchanged; post-approval preflight `--commit` (loud, no --quiet-skip); `record-commit` between the version step and the guard; `guard --commit`; new `version` output" }, "3_an_unapproved_run_is_the_system_working_the_next_days_run_supersedes_it_the_stable_sweep_untouched": { "adr": "Amendment (2026-11-06) › What the ruling binds › 3; › What the lane must satisfy › 'Supersede, narrowly (landing detail 2, as built)'", "workflow": "`snapshot-next-supersede` `if:` gains `needs.snapshot-next-preflight.outputs.refusal == ''` (a quiet skip leaves yesterday's prompt standing); marker 2 replaced by the confirmation; `stale-prompts` and release-pending-publish.mjs untouched (the stable-lane check only IMPORTS its readers)" }, "4_everything_else_in_the_2026-11-05_amendment_stands_option_B_not_chosen": { "adr": "Amendment (2026-11-06) › Status; › What does not change; ⛔ PD15 unchanged stated in the Status paragraph", "workflow": "no stable job's `if:` touched; the card job holds issues: write and contents: read only; snapshotWiring + fleet-write pins: snapshot cron -> preflight alone, mayRun snapshot-next + card + supersede, every stable job skipped" }, "landing_details_11_32Z": { "1_time": "as built; marker removed; `schedule:` comment names the four `if:` sites", "2_supersede": "as built; marker removed; `if:` reads the verdict", "3_quiet_skip": "ADR › What the lane must satisfy › 'The quiet skip (landing detail 3)'; release.yml lane header 'THE FIVE LANDING DETAILS' item 3; snapshot-next.mjs header 'The quiet skip', `proposalVerdict`, `writeStepOutputs`, `sameCommitRefusal`, `readPublishedCommit`, `recordCommit`, `judgeStableLane`, `readStableLane`, `stableLane`; select step classification in release.yml", "4_notification": "ADR › 'The card (landing detail 4)'; release.yml `snapshot-next-card`; scheduled-full-run.mjs `snapshotCardIdentity`/`snapshotCardCase`/`renderSnapshotCardBody`/`SNAPSHOT_EXPECTED_REFUSALS`; scheduled-full-run-card.mjs `snapshotCardStep`", "5_text": "ADR amendment rewritten (Status, What it replaces, bound line 1, requirements, Trial readings, What stays forbidden; 'Landing details being confirmed' removed); release.yml header paragraph; validate.mjs pins; docs/releases-maintenance.md row" } }, "cron_derivation": "Unchanged from round 1: `17 1 * * *` = 01:17Z = 09:17 Beijing, 25 min past the slowest nightly finish measured over 2026-10-31..11-06 (00:28-00:52Z); confirmed as item 1 of the 11:32Z list, every day of the week.", "gates": { "derived_by": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 5fe2149385 (after the second origin/main merge): 68 commands, 7 paths vs merge base 26c965cb8", "results": "68 run, every one exit 0 at first run (no exit 3, no rebuild needed); each CMD :: exit N recorded before any pipe; the first runner was stopped at its background time limit after 44 and the remaining 24 were run from the derived list, so every family carries one recorded exit; full list in the PR body", "reconciliation": "node scripts/pm/dispatch-gates.mjs --ran ran-final.txt --repo objectstack-ai/objectstack :: exit 0 -- 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN", "self_tests": "snapshot-next.mjs --self-test: 178 cases / 21 batteries (was 123 / 16; new: the same-commit check 10, the stable lane 10, the quiet skip 14, record-commit 4, release.yml quiet skip and card 17); scheduled-full-run.mjs OK (snapshot card battery 13); scheduled-full-run-card.mjs 13 cases; fleet-write/validate.mjs 340 / 17; release-pending-publish.mjs 146 / 35; release.yml parses with ten jobs; check-workflow-status-functions / context-availability / step-name-quoting / self-test-workflow-commands OK" }, "files_changed": [ ".github/workflows/release.yml", "docs/adr/0125-release-approval-gate-replaces-the-typed-version.md", "docs/releases-maintenance.md", "scripts/ci/scheduled-full-run-card.mjs", "scripts/ci/scheduled-full-run.mjs", "scripts/ci/snapshot-next.mjs", "scripts/pm/fleet-write/validate.mjs" ], "deviations": [ "The card also files when the snapshot job fails AFTER the approval but BEFORE the publish (post-approval preflight, build or guard): the list's case is 'publish failure after approval incl. half-finished'; a job the maintainer approved that delivered nothing is read as that case, and the card says 'the version step did not run: nothing reached npm' so the reader is not misled. Stated in the PR body, not decided against the list.", "A `next` snapshot on npm that records NO gitHead (not cut by this lane) is an UNEXPECTED refusal (`same-commit-unrecorded`), not a pass-through: the list's pass-through is for 'nothing on next' before the first snapshot, and this case is an incident. Stated in the PR body.", "The `--quiet-skip` switch is also honoured by `dry-run` (an expected preflight refusal found there skips quietly too; a guard problem never does) so the three refusing calls of the preflight job read one way.", "The snapshot job gained a `version` output and the card an `SNAPSHOT_CARD_VERSION` env so the publish-failure card can say whether anything may be on npm -- one field beyond the list's 'reason, run link, candidate commit'.", "The merge commits (round 1's a4bb83b2a4 and this round's 5fe2149385) carry git's default message without the trailer pair, as round 1 did." ], "open_questions": [], "mcp_calls": [], "api_writes": [ "git push -u origin claude/issue-30832-snapshot-daily-schedule (5fe2149385301e15afcde5fe15d33f4d6434ff49)", "fleet-write relay issue_patch -> PR #30862 body rewritten (request fw-20261106T125105Z-67e46d, run 42220830381 success, read-back 18632 bytes identical)", "post-stamped.mjs --comment=30832 (this os-dev-report)" ], "filed_issues": [] }ci(release): the select step's dispatch branch records its expected r…
docs(adr): ADR-0125's 2026-11-06 amendment names what the quiet skip …
objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
os-dev-report
Card #30832 · round 3 (delta to report 6685251006, after the complete review 6685551244 of 5fe2149: FAIL on one must-fix) · draft PR #30862 at head
e4c7785c5aa732d361ccb580635af7d0ae603087· 2026-11-06T14:02Z{ "change": "Round 3 takes the review's must-fix and should-fixes 2 to 5 (the seat's round-3 list); the docs/releases-maintenance.md row is kept. M1: the select step's DISPATCH branch (no fully green commit on main) wrote `reason` alone and exited 1, so `snapshot-next-card` read the loud expected refusal as UNEXPECTED (a failed preflight with an empty `refusal`) and filed a false p1 card; the branch now records `refusal=no-green-commit` like the schedule branch, and `snapshotWiring` pins the classification by event and each branch's echo on its own (a firing case per branch asserts the other branch's finding stays silent). S2: the preflight detached to the selected commit and ran every snapshot-next.mjs mode off THAT tree, whose copy predates this PR (no `stable-lane`, `--quiet-skip`, `--commit`, `record-commit`), and the snapshot job did the same from its checkout -- the first daily runs after the merge would have gone red and filed a false card. Both jobs now take `scripts/` off `GITHUB_SHA` (`git archive`) into `${RUNNER_TEMP}/lane-tooling` before the tree moves (the preflight before its detach, the snapshot job before its install), link the tree's node_modules beside it (the script imports `semver`), set `SNAPSHOT_NEXT_ROOT: ${{ github.workspace }}` in the job env (read by the new `laneRoot`), and call `node \"${RUNNER_TEMP}/lane-tooling/scripts/ci/snapshot-next.mjs\" <mode>` alone; the build, the publish script, release-spec-changes.sh and release-verify-npm.mjs stay the selected tree's own; the supersede job reads main's checkout and takes nothing. Pinned: the take exactly once and before the detach / the install, the link, the env, a call before the take, and any call off the tree; one self-test case loads the copy from a temp dir through a linked node_modules and reads the tree from the env, writing nothing into it. S3: the ADR sentence 'The quiet skip replaces this record's earlier reading of a scheduled refusal as a red run' now names what it replaces (the lane's first draft on #30832 and the card's acceptance line) and says the merged 2026-11-05 amendment, dispatch-only, carried no such reading. S4: 'Trial readings for the #29466 report' is marked in its heading and opening sentence as this record's reading, not the ruling's. S5: `dryRun()`'s early returns (dirty tree, missing changeset binary, and the version step failing) record `reason=` as the catch path does; a new battery drives each on a scratch repository. The ADR also gains one requirement bullet stating where the lane's checks run from and that the stable lane's 'Known edges' reading is untouched. origin/main merged twice (33043bd8a2, then 616311c126); every derived gate re-run on the final diff; PR body rewritten through the relay issue_patch.", "ruling_lines_mapped": { "1_schedule_starts_the_preflight_once_a_day_exactly_the_dispatch_preflight": { "adr": "Amendment (2026-11-06) › What the ruling binds › 1 (unchanged this round); › What the lane must satisfy › new bullet 'The lane's checks run from the workflow's own commit'", "workflow": "release.yml `snapshot-next-preflight`: job env `SNAPSHOT_NEXT_ROOT`, new step 'Take the lane's tooling from the workflow's own commit' before the select step, every snapshot-next.mjs call from the copy; the same steps on either start" }, "2_on_a_pass_the_snapshot_job_waits_at_environment_release_and_publishes_only_on_approval": { "adr": "Amendment (2026-11-06) › What the ruling binds › 2; › What stays forbidden › 'No `schedule` can publish' (unchanged this round)", "workflow": "`snapshot-next`: job env `SNAPSHOT_NEXT_ROOT`, the take step after its checkout and before the install, post-approval preflight / record-commit / guard / verify from the copy; `if:` unchanged" }, "3_an_unapproved_run_is_the_system_working_the_next_days_run_supersedes_it_the_stable_sweep_untouched": { "adr": "unchanged this round", "workflow": "`snapshot-next-supersede` unchanged; it runs main's own checkout (GITHUB_SHA) and takes no copy" }, "4_everything_else_in_the_2026-11-05_amendment_stands_option_B_not_chosen": { "adr": "unchanged this round", "workflow": "no stable job touched; the card job unchanged -- its first case (`preflight failed && refusal == ''`) now never meets an expected dispatch refusal, because every expected kind records `refusal` on both starts (M1 closed the one shell branch that did not)" }, "landing_details_11_32Z": { "1_time": "unchanged", "2_supersede": "unchanged", "3_quiet_skip": "release.yml select step: both branches record `refusal=no-green-commit` (schedule exit 0, dispatch exit 1); outputs comment re-worded (`refusal` is recorded on BOTH starts); snapshot-next.mjs header 'The quiet skip' says so; `dryRun` early returns record `reason`; ADR 'The quiet skip' sentence re-worded (S3)", "4_notification": "no change to the card; the false-card path on a dispatch's no-green-commit refusal is closed by M1, the false-card path on an old tree's script by S2", "5_text": "ADR: S3 sentence, S4 heading + opening sentence, one new requirement bullet for the tooling; release.yml comments (outputs, select step, the two take steps, 'From here on the tree is the selected commit'); snapshot-next.mjs header section 'Where the tooling runs from' and the SNAPSHOT_NEXT_ROOT usage line; docs/releases-maintenance.md untouched this round (row kept)" } }, "cron_derivation": "Unchanged: `17 1 * * *` = 01:17Z = 09:17 Beijing, confirmed as item 1 of the 11:32Z list.", "gates": { "derived_by": "node scripts/pm/dispatch-gates.mjs --commands at e4c7785c5a (after the third origin/main merge): 68 commands (the same 68 as round 2), 7 paths vs merge base 616311c12 (origin/main merged twice this round: 33043bd8a2, then 616311c126)", "results": "68 run, every one exit 0 at first run (no exit 3, no rebuild); each CMD :: exit N recorded before any pipe; one runner, the maximum background budget, finished in one pass; full list in the PR body. origin/main moved again (6ddf827236) while the gates ran: not re-merged a third time, since a fourth merge would start the same race over; the landing merge resolves it", "reconciliation": "node scripts/pm/dispatch-gates.mjs --ran gates-exit.txt --repo objectstack-ai/objectstack :: exit 0 -- 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN", "self_tests": "snapshot-next.mjs --self-test: 191 cases / 23 batteries (round 2: 178 / 21; new: 'dry-run: every early return records its reason' 3, 'release.yml: the lane's tooling runs from the workflow's own commit' 6, four more cases in 'release.yml: the quiet skip and the card' now 20); scheduled-full-run.mjs OK; scheduled-full-run-card.mjs 13 cases; fleet-write/validate.mjs 340 / 17; release-pending-publish.mjs 146 / 35; release.yml parses with ten jobs and both snapshot jobs carry the env; check-workflow-status-functions / context-availability / step-name-quoting / self-test-workflow-commands OK; eslint clean" }, "files_changed": [ ".github/workflows/release.yml", "docs/adr/0125-release-approval-gate-replaces-the-typed-version.md", "scripts/ci/snapshot-next.mjs" ], "deviations": [ "S5 is taken one step wider than written: the version step's own failure (exit 1, not 3) is the third early return of `dryRun()` and had the same gap, so it records `reason` too.", "S2's shape is the seat's first suggestion (the copy to `$RUNNER_TEMP` before the detach), applied to the snapshot job as well, since its post-approval preflight, `record-commit` and `guard --commit` ran off the selected tree with the same gap; the node_modules link and the `SNAPSHOT_NEXT_ROOT` env are what the copy needs to load (`semver`) and to read the checkout rather than its own directory. The build, publish script and read-back stay the selected tree's own.", "The ADR gains one requirement bullet for S2 (where the checks run from), beyond S3 and S4: the stable lane reads the opposite way ('Known edges': the version commit's own tooling), and leaving the two lanes' readings unrecorded side by side seemed worse than one sentence. Easy to drop if the seat reads it as overreach.", "The merge commits 943fc6da72 and e4c7785c5a carry git's default message without the trailer pair, as the earlier merges did." ], "open_questions": [], "mcp_calls": [], "api_writes": [ "git push origin claude/issue-30832-snapshot-daily-schedule (e4c7785c5aa732d361ccb580635af7d0ae603087)", "fleet-write relay issue_patch -> PR #30862 body rewritten (request fw-20261106T140136Z-712aaa, run 42230286396 success, read-back 24653 bytes identical)", "post-stamped.mjs --comment=30832 (this os-dev-report)" ], "filed_issues": [] }objectstack-fleet commentedon Nov 6, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Paused · 2026-11-06T14:17Z ·
pm:dispatched→pm:on-hold, on the maintainer's order to pause this card.Where it stands:
e4c7785c5aonclaude/issue-30832-snapshot-daily-schedule, with nothing left uncommitted.e4c7785c5ais a PASS, posted on the PR.Not done yet: the seat ACCEPT and the Tier H hand-off (marking it ready, asking os-zhuang and hotlong to review,
needs-user-decision). That hand-off is where it resumes. The PR stays a draft until then.The card stays assigned to
domain:devx#2, and the slot is released.Restart-when: the maintainer resumes this card. Then re-read the head's checks, write the ACCEPT, and do the Tier H hand-off.