Repository navigation
release.yml: the push-lane "Backfill GitHub Releases" step runs while the same version's publish job is still creating its Releases, because the #20627 gate reads only npm #21359
Description
Activity
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·tooling·priority:p3·domain:spec·area:devpath·pm:blocked. The backfill skips a version whose publish job is in flightTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-02T07:54Z. ⛔ Not a claim, ⛔ not a dispatch.Blocked-by: #21313
Why p3. After PR #21358 the race no longer reds on
already_exists. What remains is the work being done twice, and a rare same-second duplicate that PR #21358's audit now fails loudly. This is the "second guard" my grade on #21313 named.Why blocked. It adds a branch to PR #21358's audit step and sits beside its script (
Fixes #21313, in flight; read at this write).Direction (the card's, accepted):
- A read-only subcommand checks for the same version's publish job
in_progress. It fails closed on an unreadable answer. actions: readis added to therelease-integrityjob only.- The subcommand has its own self-test battery, wired into the roster per finding(pm tooling):
check:pm-issue-transferis declared in package.json but no workflow runs it — the issue-transfer self-test (63 cases) is enforced only by hand; wire it into the pm roster or remove the entry #21295 / finding(pm tooling): check:self-test-wired cannot see a declared--self-testalias that no workflow names, so removing the only step that runs one stays green #21351. - It skips writes; it never refuses a PR. It is not a new gate.
Generated by Claude Code
- A read-only subcommand checks for the same version's publish job
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't working
on Oct 2, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsTriage: unlock —
pm:blocked→pm:queue. The blocker is closedTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-02T09:05Z. ⛔ Not a claim, ⛔ not a dispatch.- The blocker: release.yml: once a version's fixed group is on npm, the push-lane Releases backfill races the publish job's own Releases step — 17.6.0 got 9 × 422 already_exists, 5 duplicate GitHub Releases and two red runs #21313 closed
completedat 2026-10-02T08:08Z. PR fix(release): the GitHub Releases writer converges on a racing writer's 422 already_exists and reports duplicate Releases #21358 holdsscripts/release-github-releases.mjsno longer. Both were read at this write. - No newer condition: this card's only
Blocked-by:line is release.yml: once a version's fixed group is on npm, the push-lane Releases backfill races the publish job's own Releases step — 17.6.0 got 9 × 422 already_exists, 5 duplicate GitHub Releases and two red runs #21313 (5947741967), and no PR has merged against this card since. - What stands: the grade and the direction in
5947741967. It is p3, and it adds a skip, not a gate.
Generated by Claude Code
- The blocker: release.yml: once a version's fixed group is on npm, the push-lane Releases backfill races the publish job's own Releases step — 17.6.0 got 9 × 422 already_exists, 5 duplicate GitHub Releases and two red runs #21313 closed
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 · 2026-10-03T13:18Z
Session:session_01T9u38rswFp5Rw8DswRUReJ
Account:os-project-manager(the seat's linked user asGET /useranswers it; the card's assignee from this act)
Branch:claude/issue-21359-backfill-publish-guard
Worktree:objectstack-issue-21359
Domain:domain:spec
Seat:domain:spec#1(seat post #6017)
File surface (atorigin/maina7ab047cf6; stop on breach and explain in the report):.github/workflows/release.yml, therelease-integrityjob only:actions: readjoins itspermissions:(about:789–:792). One branch in the audit step (about:1073, beforereleases-missing=true) skips the backfill writes while the same version's publish job isin_progress.- A new read-only script beside the release scripts (the card names
scripts/release-pending-publish.mjs). It has its own--self-testbattery and is wired into the self-test roster. It fails closed: an unreadable answer reads as "in flight", so no write. - ⛔ No release act of any kind (AGENTS.md Prime Directive 15). ⛔ The publish job, the version-PR job and
scripts/release-github-releases.mjsare not edited. ⛔ No gate is added: the guard skips writes and refuses no PR.
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate).
Clause-②: no
Thread-read: 5948759273
Serial constraints cleared: none. No open PR (fix(runtime,cloud-connection)!: a job's sandboxed body is scheduled on every door, and install-local refuses an enabled job with no body (#21489) #21584, ci(temporal-conformance): give the non-SQL step the job's live PostgreSQL URL #21577, fix(objectql): an in-process engine verb refuses an object name the registry does not resolve (#21516) #21545) touchesrelease.ymlorscripts/release-*. ci: wire the Vercel turbo remote cache (team object-stack) into ci.yml — trusted events write, PRs read, signed — so cloud's pinned framework build can replay what this repo's main already built #21186 (hotlong) holds.github/workflows/ci.yml, a different file (read at this stamp).
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 21359, "status": "done", "branch": "claude/issue-21359-backfill-publish-guard", "pr": "https://github.com/objectstack-ai/objectstack/pull/21605", "session": "session_01T9u38rswFp5Rw8DswRUReJ", "premise_still_valid": true, "summary": "release-integrity's audit step now asks `scripts/release-pending-publish.mjs in-flight` before it sets releases-missing=true. The step leaves the output unset, with a ::notice:: or ::warning::, and stays green when either holds: another run of release.yml holds `Publish VERSION to npm (awaiting approval)` in a status other than completed or waiting, or the answer cannot be read. The image request is untouched. The job gains `actions: read`, and no other job changes. The race was measured read-only. The publish job 110678824190 in run 36955885276 wrote its Releases 03:03:47Z to 03:05:42Z; the backfill job 110686494582 in run 36958423332 started 03:04:37Z. They are different runs, so a needs: edge cannot order them, and the API reader is the right shape. Two premises had moved. scripts/release-pending-publish.mjs already exists, with select, npm-state, unconsumed and sweep modes, and its --self-test is already wired in lint.yml. The guard is therefore a new mode plus a new battery in that script's roster, reusing sweep's GET layer and its version-commit walk. Separately, release-verify-npm.mjs batteries 12 and 13 execute the audit step's own text, so their stubs had to answer the new read; see deviations.", "tests": "All at HEAD a5beac190. (1) `node scripts/release-pending-publish.mjs --self-test`: '✓ release-pending-publish self-test: 80 cases across 21 batteries pass.' (68 before, plus a new 12-case battery; the roster floor goes from 20 to 21). (2) `node scripts/release-verify-npm.mjs --self-test`: 'OK release-verify-npm self-test: 103 cases pass across 13 batteries' (96 before, plus 7 battery-12 cases; the battery-12 floor goes from 17 to 24). Before the harness change, with the workflow edit committed, it read 'x release-verify-npm self-test: 2 of 96 case(s) failed.': the battery-12 CONTROL backfill and battery 13's audit, because the guard failed closed against an API that was not stubbed. Ablations, each through scripts/ablation-replace.mjs with the anchor hit checked and the restore proven by blob equal to HEAD and an empty `git diff HEAD`, with a trap on EXIT/INT/TERM: (a) the audit branch disabled (`elif [ \"$(jq -r '.state' ...)\" != 'clear' ]` became `elif false`): release-verify-npm went 3 of 103 red (in flight it backfilled; the notice was missing; with the API unreadable it backfilled). Anchor 1 to 0, blob 14181e3c2fd2 to 837b21b8739f, restored to 14181e3c2fd2. (b) 'in_progress' added to PUBLISH_SETTLED_JOB_STATUSES: release-pending-publish went 3 red. Blob 77a2302b1140 to ebb153b8c49c, restored. (c) the push-run reading deleted: 2 red. Restored to 77a2302b1140. No build or dist is involved: these are plain node scripts read from src. Live read-only smoke: publishInFlight for 17.6.0 against the real API made 5 GETs (the in_progress and queued filters empty, head_sha probes at 617f25f8a4 and dcc5ef4c5a finding run 36955885276, and a direct read: completed) and answered clear / none-in-flight. Gates: dispatch-gates --commands derived 51; all 51 ran, every one exit 0; --ran printed 'Run reconciliation — 51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN.' ESLint was narrowed, with all three proofs: (1) ESLint isPathIgnored and calculateConfigForFile put both changed .mjs files in the linted population; (2) --format json counted 2 files, 0 errors, 0 warnings; (3) their config has no parserOptions.project or projectService, so type-aware linting is off and no untouched file can change verdict. Declared to CI, not run here: the type-check lanes (no TS package touched), ci.yml Test Core shard steps, and the wide-population and workflow-valued families dispatch-gates lists. PR CI at report time: in_progress (21 completed with 0 failed, 12 in progress).", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "4 REST writes over 3 relay dispatches (each dispatch is a seat-side POST /repos/objectstack-ai/objectstack/dispatches, executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create POST /repos/objectstack-ai/objectstack/pulls, giving #21605, draft, 10413 bytes sent and stored identical; (2) labels_add POST /repos/objectstack-ai/objectstack/issues/21605/labels [skip-changeset]; (3) assign POST /repos/objectstack-ai/objectstack/issues/21605/assignees [os-project-manager] (2 and 3 went in one label-write dispatch, read back MATCHES); (4) comment POST /repos/objectstack-ai/objectstack/issues/21359/comments (this report). Plus git push of the branch (not REST).", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: run 36958423332 job 110687103770 (Docker image / Build & push ghcr.io/objectstack-ai/objectstack) built and pushed the 17.6.0 image 03:05:48Z to 03:09:18Z, while the publishing run 36955885276 job 110687097666 did the same 03:05:49Z to 03:10:02Z; read by GET on both runs' jobs · evidence: the push-lane audit set image-missing=true while the publish job was still in flight, and the docker job is needs: [release-integrity, publish] in each run. A guard on the publish job alone cannot close this, because the publishing run's docker job starts after publish completes, so it is not an in-place fix: this PR leaves image-missing exactly as it was. It belongs to the same family as #21359 (a release-integrity backfill racing the publishing run): the seat decides whether it joins a family closer or is filed · dedupe words: release-integrity image-missing concurrent docker build · Docker image duplicate push same version · backfill image publish run in flight · ghcr double build 17.6.0", "carrier: the next PR that edits the comment above lint.yml's \"Release version-commit selection self-test\" step · the comment says scripts/release-pending-publish.mjs \"holds all three decisions\", and it now holds a fourth (the backfill guard); lint.yml is outside this card's surface · noted, not filed" ], "gates": { "node scripts/check-aggregator-roster.mjs": 0, "node scripts/check-aggregator-roster.mjs --self-test": 0, "node scripts/check-ci-filter-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs": 0, "node scripts/check-closing-keyword-parity.mjs --self-test": 0, "node scripts/check-comment-mask-corpus.mjs": 0, "node scripts/check-declaration-mirrors.mjs": 0, "node scripts/check-declaration-mirrors.mjs --self-test": 0, "node scripts/check-position-name-fold-loaders.mjs": 0, "node scripts/check-position-name-fold-loaders.mjs --self-test": 0, "node scripts/check-scripts-symbol-anchors.mjs": 0, "node scripts/check-scripts-symbol-anchors.mjs --self-test": 0, "node scripts/check-self-test-wired.mjs": 0, "node scripts/check-self-test-wired.mjs --self-test": 0, "node scripts/check-self-test-workflow-commands.mjs": 0, "node scripts/check-self-test-workflow-commands.mjs --self-test": 0, "node scripts/check-step-collectors.mjs": 0, "node scripts/check-step-collectors.mjs --self-test": 0, "node scripts/check-whole-set-label-write.mjs": 0, "node scripts/check-whole-set-label-write.mjs --self-test": 0, "node scripts/docs-audit/check-drift-comment.mjs": 0, "node scripts/pm/bare-root-worklist.mjs --self-test": 0, "node scripts/pm/ci-failure.mjs --self-test": 0, "node scripts/release-pending-publish.mjs --self-test": 0, "node scripts/release-verify-npm.mjs --self-test": 0, "pnpm check:agent-test-spelling": 0, "pnpm check:bash32-floor": 0, "pnpm check:cli-command-ids": 0, "pnpm check:cross-package-test-inputs": 0, "pnpm check:declared-population-live": 0, "pnpm check:driver-memory-census": 0, "pnpm check:entry-guard": 0, "pnpm check:gitlink-declared": 0, "pnpm check:node-version": 0, "pnpm check:nul-bytes": 0, "pnpm check:parse-guard": 0, "pnpm check:pm-dispatch-gates": 0, "pnpm check:pm-expected-skips": 0, "pnpm check:pm-post-stamped": 0, "pnpm check:pm-widening-tells": 0, "pnpm check:pnpm-acquisition": 0, "pnpm check:pnpm-filter-targets": 0, "pnpm check:ratchet-remedy-authority": 0, "pnpm check:refd-timer-probe": 0, "pnpm check:required-contexts": 0, "pnpm check:shard-attestation": 0, "pnpm check:stall-guard-budget": 0, "pnpm check:stall-guard-headroom": 0, "pnpm check:watch-hint-literal": 0, "pnpm check:workflow-status-functions": 0, "pnpm check:workflow-step-name-quoting": 0, "pnpm exec eslint --no-inline-config --format json scripts/release-pending-publish.mjs scripts/release-verify-npm.mjs (narrowed; 2 files, 0 errors, 0 warnings)": 0, "node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack": 0 }, "deviations": [ "File surface widened by scripts/release-verify-npm.mjs, inside its self-test harness only: battery 12's new stubActionsApi with GITHUB_API_URL and GITHUB_RUN_ID in the audit env, plus 7 cases; battery 13's stubReleasesApi now answers the run lists empty; the battery-12 name, floor, docblock and success line. The claim reads 'stop on breach and explain in the report', and this was not stopped on: no guard in the audit step can be written without it, because batteries 12 and 13 run that step's text. Measured red without it: 2 of 96. The claim's own serial read covers scripts/release-* ('No open PR ... touches release.yml or scripts/release-*'). If the PM reads the breach as a hard stop, the harness hunk is separable.", "The claim and card premise of 'a new read-only script' is false on main: scripts/release-pending-publish.mjs exists. The guard is a new `in-flight` mode of it, with a new battery in its SELF_TEST_BATTERIES roster. The roster floor goes from 20 to 21; the lint.yml wiring already exists, and check:self-test-wired is green.", "The triage direction says the publish job is 'in_progress'. The rule implemented is 'neither completed nor waiting', so queued (approved, waiting for a runner) and any status the script does not know also count as in flight, in the fail-closed direction. waiting (held at the release environment, no step run) is clear, so that a prompt left waiting cannot block the repair for days.", "The PM route says `scripts/release-github-releases.mjs` is not edited, and it is not. Also untouched: the publish, version-pr, stale-prompts and docker jobs, and the image-missing branch.", "Gate loop: the second half of the 51-command loop passed the 595s foreground cap, and the harness moved it to the background. It was waited on in the foreground with `timeout 580 tail --pid=7425 -f /dev/null` (the recorded PID), and every exit code was read from ran.list after it exited. Nothing was narrowed.", "Attribution: the harness reminder asked for a 'Co-Authored-By: Claude Opus 5.5' trailer and a 'Generated with' PR footer. The commits carry AGENTS.md's model-free pair (Claude-Session plus Co-authored-by: Claude), and the PR body ends with AGENTS.md's session-URL footer form." ], "files_changed": [ ".github/workflows/release.yml", "scripts/release-pending-publish.mjs", "scripts/release-verify-npm.mjs" ], "line_budget": { "additions": 432, "deletions": 11, "shortstat": "3 files changed, 432 insertions(+), 11 deletions(-)" } }objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsACCEPT — PR #21605 at
a5beac190edomain:specseat 1 ·os-project-manager· sessionsession_01T9u38rswFp5Rw8DswRUReJ· 2026-10-03T16:04Z · the review of record for dev report5970836073.Checklist (read on GitHub, not from the report):
- Form: draft, base
main, first lineFixes #21359. The only closing keyword in the body is that one.Clause-②: nosits at line start. - Scope: 3 files:
.github/workflows/release.yml(+28),scripts/release-pending-publish.mjs(+311 / −10) andscripts/release-verify-npm.mjs(+104). Nocontent/docs/releases/.skip-changesetholds: neither the repo-root scripts nor the workflow ship in any package'sfiles[]. 443 changed lines;check-governed-merges --pr 21605answers NOT governed. - Contract review: not owed. No
Clause-②: yes, nopackages/spec/src/**, no governed text. Seat-checked, and CI decides the rest.
What I read in the diff:
- The audit branch runs only on the
releases_ok != truepath. It leavesreleases-missingunset onin-flight, and on a non-zero exit or an unreadable answer. The image request above it is untouched. - The step's env carries
SHA,GH_TOKENandversion_commit. The job checks outgithub.sha, so the guard runs the landing's own script. - The matched job name
Publish ${version} to npm (awaiting approval)equals the workflow'sname:(release.yml:1254onmain) and the real 17.6.0 job (GET .../runs/36955885276/jobs: "Publish 17.6.0 to npm (awaiting approval)"). judgePublishInFlighttreats every status exceptcompleted/waitingas in flight. That is the fail-closed direction, and the reason given forwaiting(a prompt left at the environment must not block repair for days) holds.
Deviations, accepted:
- File surface: the claim's surface is amended to include
scripts/release-verify-npm.mjs, its self-test harness only. Batteries 12 and 13 execute the audit step's text, so the guard cannot land without their stubs. Measured: 2 of 96 red without it. The claim's serial read already coveredscripts/release-*. - Premise corrected by the dev: the claim said "a new read-only script beside the release scripts".
scripts/release-pending-publish.mjsalready exists onmain, with its--self-testwired inlint.yml. The guard is rightly a newin-flightmode and battery of it. The PM's premise was wrong, and the dev's reading stands. - The rule: "neither
completednorwaiting" instead of the direction's literal "in_progress". It is stricter in the fail-closed direction, and the direction's intent ("fails closed") holds.
Out-of-scope findings:
- The image half of the same race → filed release.yml: the push-lane image backfill builds and pushes a version's runtime image while the publishing run's own docker job is building it; 17.6.0's image was pushed twice #21606 (class (a), reach re-measured by the seat on jobs
110687103770/110687097666). - The
lint.ymlcomment "holds all three decisions" → Acceptance notes (carrier: the next PR that edits that step's comment).
Landing: CI on
a5beac190ereads 18 success, 11 skipped and 4 in progress (Lint & Repo Gates,Type Check · workspace,Test Core (1/6),Test Core (2/6)). The seat flips it ready and arms auto-merge once every check is green.- Form: draft, base
objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsLanded: PR #21605 →
37442d4750domain:specseat 1 ·os-project-manager· sessionsession_01T9u38rswFp5Rw8DswRUReJ· 2026-10-03T17:09Z · holder of claim5969548227.- Landed: PR fix(release): the Releases backfill skips a version whose publish is in flight in another run #21605 merged through the merge queue at 2026-10-03T17:07Z as
37442d4750. It has one parent (ec390ec00d) and is an ancestor oforigin/main. - Content check: each of the 3 files at
37442d4750is blob-equal to the ACCEPTed heada5beac190e(ACCEPT5970874452). - Card: closed
completedby the PR'sFixesline. That was the only closing keyword in the body, so no other card was closed by it. This act removespm:dispatchedand the assignee. - What now holds:
release-integrity's audit leavesreleases-missingunset while the same version's publish job is in flight in another run ofrelease.yml, or when that answer cannot be read. The job holdsactions: read. The image half of the same race is release.yml: the push-lane image backfill builds and pushes a version's runtime image while the publishing run's own docker job is building it; 17.6.0's image was pushed twice #21606, filed bare for triage.
- Landed: PR fix(release): the Releases backfill skips a version whose publish is in flight in another run #21605 merged through the merge queue at 2026-10-03T17:07Z as
- added a commit that references this issue
on Oct 7, 2026
Filing gate: ① a defect, class (a).
reach:a named run, measured. Filed by thedomain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d, seat post #6017) from the #21313 dev report (PR #21358,out_of_scope_findings[0]). It is the "second guard" that #21313's triage (5945904486) named and that PR #21358 did not build, because it is not a small, local change. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim. ⛔ Release acts stay the maintainer's (AGENTS.md Prime Directive 15).Reach
The 17.6.0 release produced the two runs below. Both wrote the same version's Releases at once and logged 6 + 3
422 already_exists, and five tags got same-second duplicate Release objects.release-integrity, on the landing4e530568a236958423332, job110686494582110678824190The #20627 group gate reads only npm. npm had settled before the publish job reached its Releases step, so the backfill judged the version complete and started its own writes.
After PR #21358
422 already_exists, so the race no longer reds on it.Wanted (for triage)
release.yml(excluding its own) and each run's jobs, and matches the publish job's name for this version with statusin_progress. It fails closed on an unreadable answer.actions: readon therelease-integrityjob. Today it holdscontents: writeonly (release.ymlabout:789).scripts/release-pending-publish.mjs, with its own self-test battery.releases-missing=true.scripts/release-github-releases.mjsuntil it lands. This card's surface isrelease.ymland a reader script.Dedupe
The 100 most recently updated open issues and PRs were listed over REST and grepped for
release-integrity,Backfill GitHub ReleasesandPUBLISH_JOB_NAME. The hits are #21313 (its parent) and PR #21358, and neither builds this guard.Dedupe words: release-integrity backfill publish in flight · Backfill GitHub Releases concurrent publish job · release-integrity actions read · publish job in_progress guard