Repository navigation
Description
Filing-gate category: ③ maintainer-directed. The maintainer, in the devx project thread on 2026-10-27 (08:22Z), after the 18.2.0 release diagnosis: 「立卡,包括。」 (the card offered there: make the publish log carry npm's own answer, so the next "reported published, not on npm" can be diagnosed). It is also a ① tooling defect with a measured run: a red release run on a publish that turned out complete.
What happened (18.2.0, measured)
- Release 40458210871, job 122037220985, publish approved at the
releaseenvironment 06:05Z, version commit27f38ada. changeset publishlisted@object-ui/console@18.2.0under "Successfully published" at 06:16:41Z and pushed its tag at 06:16:55Z.@changesets/cli3.0.3 counts a package as published whenpnpm publishexits 0 (dist/getPublishPlan.mjs, pnpm branch), and it prints none of pnpm's or npm's output.- The other 109 packages were readable 06:15:55Z–06:25:19Z (npm
time).@object-ui/consolestayed 404 (/@object-ui/console/18.2.0), andscripts/release-verify-npm.mjsfailed at 06:52:58Z after 39 rounds over its 2100 s budget: "publish ran but 1 of 110 package(s) are still not readable … @object-ui/console@18.2.0 — not on the registry". The Releases, ADR-0087 D4 asset, dist-tag and Docker steps were skipped. - The maintainer dispatched the repair, Release 40464600678 (
force: true), approved 07:09Z. npm's owntimefor@object-ui/console@18.2.0is 07:11:04.711Z, four minutes before that run's publish step started (07:15:42Z). So the first upload was not lost: npm made it readable about 55 minutes afterpnpm publishreturned. The repair only re-ran the verification and the skipped steps. - Size:
@object-ui/console@18.2.0is 45.7 MB unpacked, 2418 files (18.1.0: 35.3 MB, 2311).@objectstack/console@18.2.0(46.8 MB, 2416 files) was readable inside the normal window, so size alone does not explain it. - Precedent: release-verify-npm: the 15-minute read-back budget is shorter than the 18.0.0 publish took to settle (
@objectstack/console, 42 MB, readable at +16m22s), so a complete publish read red and skipped its Releases, D4 asset and image #24888 (closed) had the same shape on 18.0.0 (@objectstack/console, 42 MB, readable at +16m22s), which raised the budget from 15 to 35 minutes. This time the lag was longer than the raised budget.
Why it matters
The cost of a lag like this is a red release run, a force dispatch, a second human approval at release, and about an hour before the GitHub Releases and the image exist. The bigger cost is that nobody can tell lag from loss: the log says "not on the registry" for both, and the only fix the message offers is the force repair. Had npm actually dropped the tarball, the same log would have read the same way.
Ask (the dev decides the shape)
- Keep npm's own answer for each package.
pnpm publishalready gets a response from the registry, butchangeset publishthrows it away. The publish step should keep it, as a per-package result the verifier can read, so a missing package is named as "npm accepted it (status, id)" or "npm refused it". One possible shape: publish with--json/ a reporter that keeps stdout, or a per-packagenpm viewof the version'sdist.integrityagainst the packed tarball. - When the budget runs out on a package that npm accepted,
release-verify-npm.mjsshould say so ("accepted by npm, not yet readable after Ns: registry lag") and give the next step for that case (re-run the verification or the backfill later). It must still fail closed: an unreadable package is red, never a warning. - Measure before re-tuning the budget: record the per-package spread for 18.0.0, 18.1.0 and 18.2.0 from npm
timein the script header, the way fix(release): the post-publish npm check races the registry and only ever looks at 1 of 69 packages — it red-flagged a release that had fully succeeded #15321 and release-verify-npm: the 15-minute read-back budget is shorter than the 18.0.0 publish took to settle (@objectstack/console, 42 MB, readable at +16m22s), so a complete publish read red and skipped its Releases, D4 asset and image #24888 did. A bigger budget alone is not the ask.
Scope
scripts/release-publish.sh, scripts/release-verify-npm.mjs and its self-test, maybe .github/workflows/release.yml (the publish step). The workflow is the one job that publishes, so read its header gating notes before touching it. ⛔ No change to who may publish or to the release environment gating.
Reader: the devx execution seat, on its next candidate pick (domain:devx, tooling).
Dedupe: searched objectstack issues for "changeset publish reports success but package not on npm registry, log npm publish response" and "release-verify-npm partial publish" (15 hits, open and closed). Nearest: #24888 (closed, same symptom on 18.0.0, budget raise), #15321 (closed, verifier race), #26552 (open, the duplicate-Release false red on the same repair run, a different defect). No open card covers this.
Business rationale: whoever approves a release learns whether it shipped from this one log. A log that cannot tell "npm is slow" from "npm lost a package" costs that person an hour and a second approval every time the biggest tarball lags.
Clause-②: no
Metadata-protocol: none
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
tooling·priority:p2·domain:devx·area:devpath·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T08:55Z⛔ Not a claim, ⛔ not a dispatch.
@objectstack/console, 42 MB, readable at +16m22s), so a complete publish read red and skipped its Releases, D4 asset and image #24888 precedent). Lands inscripts/release-verify-npm.mjsand the publish step's logging. ⛔ Prime Directive 15: the PR changes tooling only. No seat re-runs or dispatchesrelease.yml.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 3 · 2026-10-27T10:58Z
Session:
session_01JQwxbaFpnMwgpCgneKe2qSAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-ervpst(platform exception: this seat's container pushes only its ownclaude/project-thread-*branch; its previous PR #26610 merged)Worktree:
objectstack-issue-26558Domain:
domain:devxSeat:
domain:devx#1File surface:
scripts/release-verify-npm.mjsand its self-test,scripts/release-publish.sh;.github/workflows/release.yml(the publish step only) only if the per-package npm answer cannot be kept without it, and then the PR is Tier H (governed); ⛔ no change to who may publish or to thereleaseenvironment gating (stop on breach)Container & model: M,
mode:subagent(in-seat and serial instead of a card thread: the account's 7-day usage readsallowed_warning, so the seat opens no new card thread, coordinator.md §六),model: default(dispatch-gates --tier: "no path-derived mandate … default opus"; the ceiling tier is out of quota for this account, quota exemption),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
scripts/release-verify-npm.mjs+ the publish step (this repo's release tooling) | no platform path keeps npm's per-package answer today (@changesets/cli3.0.3 prints none of it, per the card) | every release approver reads this log; reached on 18.2.0 (run 40458210871)Thread-read: 6437674284
Premise: holds (no commit to
scripts/release-verify-npm.mjsor.github/workflows/release.ymlon origin/main since the card was filed,git logsince 08:00 UTC today, read at c739de7)Serial constraints cleared: none (no open PR touches
scripts/release-publish.sh,scripts/release-verify-npm.mjsor.github/workflows/release.yml, read over all 8 open PRs' file lists; no other devx seat is seated)Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26558, "status": "done", "branch": "claude/project-thread-ervpst", "pr": "https://github.com/objectstack-ai/objectstack/pull/26650", "session": "session_01JQwxbaFpnMwgpCgneKe2qS", "premise_still_valid": true, "summary": "Mechanism measured, not assumed: @changesets/cli 3.0.3 (installed dist/getPublishPlan.mjs, pnpm branch) returns result 'published' on pnpm publish exit 0 and discards stdout/stderr; pnpm 10.31.0 delegates the upload to npm publish (runNpm publish --ignore-scripts TARBALL), and npm 10.9 writes a debug log per run with the argv, 'http fetch PUT STATUS URL Nms', 'error code' and 'verbose exit'. scripts/release-publish.sh now points npm's logs-dir at a per-job record under RUNNER_TEMP (path named once by release-verify-npm.mjs --start-npm-record), lifts logs-max off 10, and prints npm's answer per package (--npm-answers) after changeset publish, before exiting on a failed publish or pushing tags. release-verify-npm.mjs reads the record only after the budget is spent and tags each missing package: accepted (registry lag, still red, next step --probe then the force backfill), refused (npm code + summary), never sent, not uploaded, or record missing ('cannot tell lag from loss'); the exit code stays 1 in every case. Budget unchanged at 35 min with the 18.0.0/18.1.0/18.2.0 per-package npm time spread recorded in the header and the reason (the 18.2.0 tail would need ~115 min under the 2.11x margin, inside a 120-min job). release.yml not touched (not Tier H); no change to who may publish or the release environment gating.", "tests": "node scripts/release-verify-npm.mjs --self-test at 3981356b: exit 0, 'OK release-verify-npm self-test: 164 cases pass across 16 batteries'. New battery 15 (25 cases): log parse for accepted/refused/not-sent/non-publish/ambiguous, credential scrub, acceptance-wins, absent record, per-package report; main() on the 18.2.0 shape: accepted -> exit 1 + '(npm accepted it: registry lag)' + no 'Repair:' line, refused -> exit 1 + '(npm refused it: E403)' + force repair, no record -> exit 1 + 'cannot tell lag from loss'; and the REAL pnpm publish -> npm 10 chain against a 127.0.0.1 stub registry (200 and 403), parsed back as PUT 200 accepted and PUT 403 E403 refused. New battery 16 (8 cases): release-publish.sh with stub changeset/git: record dir + logs_max handed to npm, stale record emptied, globalconfig still unset, per-package line printed, tags pushed once after publish; failed publish -> exit 1, answers printed, no tag push. Also: npx eslint --no-inline-config scripts/release-verify-npm.mjs exit 0; bash -n scripts/release-publish.sh exit 0; node scripts/release-dist-tags.mjs --self-test exit 0. No ablation: scripts are outside the ablation rule.", "gates": "Local at 3981356b: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 31; all 31 ran, every one exit 0 (30 captured as exit codes; pnpm check:pm-dispatch-gates ran detached under nohup and its verdict line reads 'dispatch-gates self-test (fast tier): 1935 cases pass'). --ran reconciliation: 'dispatch-gates --ran: 31 derived famil(ies) accounted for, 31 run, 0 NOT-MEASURED', exit 0. CI on PR 26650 head 3981356b at report time: 24 check-runs, 15 in_progress, 7 skipped, 2 success, 0 failed: in_progress is the honest value.", "dogfood_battery": "n/a: no '!' in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 relay writes: pr_create (fleet-write run 40496432145, PR 26650, body 9201 bytes sent = stored, assignee os-warren, label skip-changeset read back) and this os-dev-report comment via post-stamped.mjs. Plus 2 git pushes of claude/project-thread-ervpst (not REST). Reads: REST GETs only (issue, comments, actions runs/jobs, git tags, PR, check-runs) and public npm registry metadata.", "open_questions": [], "out_of_scope_findings": [ "carrier: none. Noted, not filed: the publish step's comment in .github/workflows/release.yml still says the verifier retries 'for 15 minutes' (the budget has been 35 since the 18.0.0 raise). Comment drift in a governed file, no runtime effect.", "carrier: none. Noted, not filed: the Actions job-log blob host (productionresultssa8.blob.core.windows.net) is denied by this container's egress policy, so the 18.1.0/18.2.0 verification start instants were read as the annotated tags' tagger dates (T0) instead of from the job logs." ], "measured_spreads": "npm time minus T0 (tagger date of the version's annotated tags): 18.0.0 (73 pkgs, T0 12:41:28Z) p50 +1m22s, p90 +3m52s, max @objectstack/console +16m31s; 18.1.0 (73, T0 09:02:22Z) p50 +0m48s, p90 +2m53s, max @objectstack/spec +9m34s; 18.2.0 (110, T0 06:16:43Z) p50 +1m13s, p90 +3m18s, max @object-ui/console +54m22s, next @objectstack/console +8m36s.", "deviations": [ "dispatch-gates refused a stale tree after origin/main moved (03e898c1), so origin/main was merged into the branch (merge commit 3981356b, no force push) and the gates re-derived and ran there.", "pnpm check:pm-dispatch-gates ran detached (its header's instruction); its exit code was not captured as $? and is recorded as 0 from the gate's own verdict line.", "Battery 15 spawns the real pnpm publish / npm publish against a 127.0.0.1 stub registry in a sealed environment (no inherited registry, token or npm config). Nothing reaches npmjs. It pins npm's log format the parse depends on." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26558, "status": "done", "round": "rework 1 (addendum to os-dev-report 6440815967)", "branch": "claude/project-thread-ervpst", "pr": "https://github.com/objectstack-ai/objectstack/pull/26650", "head": "1dbf832b", "session": "session_01JQwxbaFpnMwgpCgneKe2qS", "cause_measured": "Reproduced CI's shape here: corepack enable --install-directory TMPBIN, COREPACK_HOME=TMPSTORE, corepack install from the repo root (pnpm 10.31.0 into the store), TMPBIN first on PATH. On 3981356b, node scripts/release-verify-npm.mjs --self-test exits 1 with 4 failed cases, all battery 15's REAL npm cases. The first shows the Corepack error, and the records read 'no-upload'. In the sealed env (no COREPACK_HOME, fresh HOME) and a fixture package.json without packageManager, the shim requests https://registry.npmjs.org/pnpm/latest ('Error when performing the request to .../pnpm/latest'), so pnpm publish never reaches the stub npm. A second fact surfaced while fixing: this container's pnpm is not Corepack. /opt/node-tools pnpm is 10.28.0, and it switches to the pinned 10.31.0 from ~/.local/share/pnpm/.tools. So the earlier local green ran pnpm 10.28.0 in the fixture, not the pin.", "fix": "Battery 15 only (scripts/release-verify-npm.mjs). Each fixture package.json carries the root package.json's packageManager, read at run time and never retyped. The sealed env keeps every COREPACK_* variable and the caller's PNPM_HOME (default per platform), and still drops any inherited registry, token and npm config (fresh HOME, its own .npmrc). A new first case asserts that pnpm --version in the sealed env equals the pinned version, and its failure text names the pin, the pnpm output and that every REAL npm case below fails for that reason. Nothing is skipped or made conditional. If pnpm is absent, the spawn fails and the case is red. Floor for battery 15 goes from 25 to 26 cases.", "tests": "On 5632173f plus the merge 1dbf832b: under the Corepack shim, self-test exit 0, 'OK release-verify-npm self-test: 165 cases pass across 16 batteries', and the TMPSTORE still holds only pnpm 10.31.0 (no latest added). Under this container's non-Corepack pnpm, exit 0 with 165 cases. Before the fix, on 3981356b under the shim: exit 1, 4 of 164 failed (above). Intermediate measurement: turning off pnpm's self-switching made the new case red with 'pnpm --version exit 0: 10.28.0', which showed the case catches a wrong pnpm. npx eslint --no-inline-config scripts/release-verify-npm.mjs exit 0.", "gates": "On 1dbf832b: dispatch-gates --commands derived 31, the same list as round 0. All 31 ran with exit 0. pnpm check:pm-dispatch-gates ran detached with its exit captured: EXIT=0, 1935 cases pass. --ran: '31 derived famil(ies) accounted for, 31 run, 0 NOT-MEASURED', exit 0. CI: not read yet for the new head.", "merge": "origin/main 498e8f40 merged as merge commit 1dbf832b, no force push. The 3-dot diff shows main touched neither script.", "mcp_calls": "0", "api_writes": "1 relay write this round (this addendum via post-stamped.mjs), plus 1 git push. Reads: REST GET only.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
ACCEPT → PR #26650 comment 6441254696 ·
domain:devx#1· head1dbf832bef· 2026-10-27T11:55Z. One REWORK round (battery 15 under a Corepack shim, addendum 6441222070). Readied and auto-merge armed through the relay; the card closes on merge byFixes #26558.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Landed: PR #26650 merged 2026-10-27T12:14Z as
4b7dbc44c8(merge queue, one pass), head1dbf832bef= the ACCEPTed head (6441254696). Card closed byFixes #26558;pm:dispatchedremoved ·domain:devx#1· 2026-10-27T12:16Z. The first release after this merge is the first live reading of the per-package npm answers.Generated by Claude Code