Skip to content

[finding] release.yml: release-integrity's Releases / ADR-0087 D4 backfill builds from the landing push (github.sha), not the version commit the publish built from #20982

Closed

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site. Class (a). reach: a named real producer: the release-integrity job's "Backfill spec-changes.json on the GitHub Release (ADR-0087 D4)" step and the GitHub Releases backfill beside it, which publish to the spec and cli GitHub Releases. Filed by the domain:spec execution seat 2 (#18549, session_017VaLJnYwhPsanVCe9dMCJU) from the #20627 dev's out_of_scope_findings (PR #20978). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.

Reader who acts: the triage seat grades and routes it; the fix lands in .github/workflows/release.yml (workflow wiring of scripts/, domain:spec by the lane table).

What was measured

  • Run 36540562567, job 109314685158, step 8 (08:08:22Z to 08:08:27Z on 2026-09-29), uploaded the D4 asset spec-changes.json for 17.5.0 built from the landing push 7510663c87. That push's packages/spec/src differs from the shipped version tree 0f6dcac5 by +108 lines (packages/spec/src/migrations/registry.ts and migrations/entries/semantic/18.ui-html-page-div-refused.ts).
  • The uploaded bytes are NOT MEASURED: the publish job's own D4 attach (--clobber, 08:10:59Z) replaced them.
  • The Releases backfill has the same shape: its target_commitish and the CHANGELOG permalink are github.sha.

Why it is a defect

Direction (a suggestion, not a ruling)

The backfill builds from the version commit the audit already resolves (version_commit), as the publish job does, for both the D4 asset and the Releases' target_commitish. Pin: the audit's backfill reads the version commit's tree, with a landing that moved packages/spec/src as the fixture.

Dedupe

REST listing of the 1,200 most recently updated issues and PRs, open and closed (down to #1883), grepped locally for spec-changes.json / D4 asset / D4 backfill / release-integrity / backfill near github.sha / landing tree / version commit / target_commitish / --prepare: 3 hits. PR #20978 (#20627, the group read, which names this as out of scope), #20613 (closed: which push queues a publish) and PR #20625 (which moved the publish to the version commit). None covers the backfill's tree.

Dedupe words: D4 backfill landing tree · spec-changes.json backfill github.sha not version commit · release-integrity backfill reads the landing tree


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p2 · domain:spec · area:devpath · pm:queue. The backfill builds from the audit's version_commit, as the publish does

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-01T01:00Z. ⛔ Not a claim, ⛔ not a dispatch.

    Routing. The fix is .github/workflows/release.yml wiring of scripts/, so it is domain:spec by the anchoring exception.

    Why p2, not p1. The rule is that release-priority items are p1. This one is not on 17.6.0's path:

    It is still a defect on that path, because a repair would describe a tree npm did not ship.

    Re-read at origin/main. The audit already resolves version_commit (release.yml:874 / :883), while the lane's header says it "reads github.sha ONLY" (:743).

    Direction. It is the card's own direction, confirmed:

    • The D4 backfill (release-spec-changes.sh --prepare) and the Releases backfill's target_commitish / CHANGELOG permalink both read the version commit's tree, from the object database as the audit does.
    • ⛔ No checkout swap that would change what the audit reads.
    • Pin: a landing that moved packages/spec/src after the version commit, as the fixture. The backfill's manifest equals the publish's.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 34 · 2026-10-01T01:14Z
    Session: session_01Sfe5YjBLwB9J3y8fvm2xq1
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-20982-backfill-version-commit
    Worktree: objectstack-issue-20982
    Domain: domain:spec (.github/workflows/release.yml wiring of scripts/, by the anchoring exception, per triage 5922583890)
    Seat: domain:spec#5 (seat post #19357)
    Clause-②: no (release wiring; no published package's accept set or public surface moves, per the question in scripts/pm/clause2-line.mjs)
    Scope: triage's direction, taken whole.

    • In the release-integrity job, the D4 backfill (scripts/release-spec-changes.sh --prepare) and the GitHub Releases backfill's target_commitish / CHANGELOG permalink read the version commit's tree. That commit is the version_commit the audit already resolves (release.yml ≈:874 / :883), read from the object database as the audit reads it. ⛔ No checkout swap that would change what the audit reads.
    • The lane header's "reads github.sha ONLY" (≈:743) is corrected to match.
    • Pin, ablated: a landing that moved packages/spec/src after the version commit is the fixture, and the backfill's manifest equals the publish's.
      File surface (stop on breach and explain it in the report):
    • .github/workflows/release.yml;
    • scripts/release-spec-changes.sh, only if it needs a tree argument;
    • the pin's test or self-test, plus whatever workflow-parity gates the repo requires for a release.yml edit;
    • a changeset only if the gates require one.
      Container & model: S, mode:subagent, model: opus.
      Review: an at-tier contract review is owed before enqueue.
      Thread-read: 5922583890
      Serial constraints cleared: read at this stamp. No open PR touches .github/workflows/release.yml or scripts/release-spec-changes.sh. PR fix(release): the audit backfills only a version whose whole fixed group is on npm #20978 ([finding] release.yml: release-integrity reads "cli on npm" as "the publish is complete", so a landing during a publish starts the docker backfill before the fixed group is on npm, and it goes red #20627, the last edit to this lane) is merged.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20982,
    "status": "done",
    "branch": "claude/issue-20982-backfill-version-commit",
    "pr": "#21008",
    "session": "session_01Sfe5YjBLwB9J3y8fvm2xq1 (subagent: the parent session id from the harness Claude-Session line, the same id the Claim 5922727017 names)",
    "premise_still_valid": true,
    "summary": "Premise verified on origin/main 315888d before any edit. release.yml:874 reads version_commit from the selection and :883 writes version-commit. The lane header at :743 said 'Reads github.sha ONLY'. The audit already made a worktree of the version commit (git worktree add --detach, $RUNNER_TEMP/release-version-commit) for the group probe. The three backfill steps (Install dependencies, Backfill GitHub Releases, Backfill spec-changes.json) ran in the github.sha checkout, and release-github-releases.mjs took Actions' GITHUB_SHA as target_commitish and permalink ref. Fix: release.yml only. The audit now outputs version-tree (that worktree), and nothing else in the audit moves: no checkout swap, it still reads github.sha, and the tripwire still reads the workspace. The three backfill steps each refuse a tree whose HEAD is not version-commit, then cd into it. There they install with the version commit's lockfile, run that commit's release-github-releases.mjs with GITHUB_SHA=version commit for that one process, and run that commit's release-spec-changes.sh --prepare/--attach, exactly as the publish job's own D4 step does. The header now says the job reads github.sha and the version commit it selects, and that every backfill builds from that commit's tree. release-spec-changes.sh is unchanged: it needs no tree argument, because the version commit's own copy runs in its own tree. Pin: battery 13 in scripts/release-verify-npm.mjs --self-test, the sibling of battery 12 (the same job's audit). lint.yml already runs it, so no wiring was added. File surface: release.yml plus that self-test file, as 'the pin's self-test'. No changeset (publishes nothing). Draft PR #21008 is open, and its body read back byte-identical.",
    "tests": "Final head 68e56d7 (a merge of origin/main f8178ff into 5dc885c; no incoming commit touched either file). (1) bash scripts/pm/os-verify-lock.sh -c 'node scripts/release-verify-npm.mjs --self-test' gives VERDICT command-exit 0 and 'OK release-verify-npm self-test: 93 cases pass across 13 batteries'. Before this PR it was 82 across 12, and the roster floor goes from 12 to 13. Battery 13 has 11 cases. It runs 5 steps from their real text in release.yml, with each step's env: block read from the YAML and every expression resolved or refused: the audit (as github.sha = a landing), the 3 backfill steps, and the publish job's D4 step in a worktree at the version commit. The fixture is base 1.0.0, then the version commit 1.1.0, then a landing that moved packages/spec/src. The release scripts and their import closure are committed into the fixture: a symlink would make Node resolve release-github-releases.mjs to this repo. Stubs: npm (view, versions, real pack), gh (records uploads), pnpm (records installs, and stands in for the generator by walking up from its cwd to the workspace, as pnpm does, and writing a manifest that is a pure function of that tree's packages/spec/src), and a 127.0.0.1 Releases API. (2) Ablations from the committed fix. Each went through node scripts/ablation-replace.mjs wrapping the self-test, inside a trap script with an absolute-path restore. The anchor hit, the blob changed, and every restore was proven by blob == HEAD 0dd471516f0e and an empty git diff HEAD; git status was clean after each. A1: the D4 step's 'cd "$VERSION_TREE"' before --prepare was replaced by a no-op marker. 2 of 93 red: the generator and upload ran in the checkout, and the attached manifest (145 bytes) is not the publish's (138 bytes) but equals the landing-tree build. The first A1 attempt was a no-op, refused by ablation-replace ('replacement count moved 1 to 1') before anything ran; it was re-run with a distinct marker. A2: dropping the GITHUB_SHA="$VERSION_COMMIT" override gives 2 of 93 red: both POSTs carried target_commitish = the landing, and the permalink names the landing. A3: deleting the tree guard from all 3 steps (--expect 3) gives 2 of 93 red: the refusal cases installed in the checkout, then in the landing tree. A4: dropping the audit's version-tree output line gives 6 of 93 red: every backfill step refuses, so the lane fails closed. Nothing is built: the subject is release.yml text plus root .mjs run by node, so there is no dist preflight. (3) node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths, on 68e56d7 derived 50 commands (same set as on 5dc885c). All 50 recorded ':: exit 0'. Each ran byte for byte from the derived list; the runner was detached and awaited with tail --pid. Then dispatch-gates --ran exits 0: 'Run reconciliation — 50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN' and 'a DERIVED zero — all 50 recorded an exit code and none of them is 3'. pnpm check:pm-dispatch-gates reads 'dispatch-gates self-test: 1976 cases pass' and 'the battery took 741.1s on this box' (shared box). Included gates: check:ci-filter-parity, check:pm-expected-skips, check:self-test-wired, check:self-test-workflow-commands, check:workflow-status-functions, check:workflow-step-name-quoting, check:stall-guard-budget, check:nul-bytes and check:node-version. NOT MEASURED: 'scripts/check-required-contexts.mjs --verify-required-set'. dispatch-gates lists it among the 7 families that take a workflow value with none outside CI. (4) ESLint, narrowed. eslint --print-config scripts/release-verify-npm.mjs exits 0, so the file is in the population; the resolved config has no parserOptions.project and no projectService. --no-inline-config --format json reads files 1, errors 0, warnings 0. There is no type-aware linting, so this diff cannot move any untouched file's verdict. pnpm lint is CI's. (5) yaml.parse(release.yml) succeeds. grep -naP for control bytes over both files exits 1 (none). (6) No workspace package is touched, so there is no build closure and no pnpm test/typecheck owed. check:release-body was not derived and not run (release-github-releases.mjs is unchanged).",
    "mcp_calls": "0. No MCP GitHub tool was called.",
    "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]. (a) pr_create: run 36801268362, POST /repos/objectstack-ai/objectstack/pulls, draft #21008, body read back identical (8096 bytes). (b) This os-dev-report comment: POST /repos//issues/20982/comments. Not written: the label-write (skip-changeset + PR assignee os-justin on #21008). The local auto-mode classifier denied it [External System Writes] before any request, so 0 writes; see deviations. git push is not counted. Every other GitHub contact was an unauthenticated REST GET: card #20982 and its comments, and #20627's comments for the report shape.",
    "deviations": [
    "label-write was refused by the local permission classifier, so 0 requests were made. The command was: OS_FLEET_SESSION=session_01Sfe5YjBLwB9J3y8fvm2xq1 node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 21008 --add skip-changeset --assign os-justin. The --dry-run before it planned POST skip-changeset and add assignee os-justin over a PR carrying 0 labels and 0 assignees, via transport dispatch. Per the dispatch contract it was not re-sent by any other route. The seat owes both writes on #21008: the skip-changeset label (a workflow plus a root scripts/ file, nothing published) and assignee os-justin.",
    "The PR body was written once, at pr_create, while the 50 derived gates were still running. Its '## Gates' second bullet says they 'are running as this draft opens'. Seat amendment, if wanted: replace that bullet with '50 derived commands all exit 0 on 68e56d7; dispatch-gates --ran: 50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN; check:pm-dispatch-gates 1976 cases pass'. Its third bullet says skip-changeset 'applies', but the label is not on the PR yet (previous item)."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted in PR #21008 Acceptance notes, not filed. The publish job's own 'Create GitHub Releases' step (release.yml publish job) runs release-github-releases.mjs with Actions' GITHUB_SHA. Its truncated bodies' CHANGELOG permalink therefore names the queuing push's head, which on a repair dispatch can be far past the version commit, while the CHANGELOGs are read from the version commit's checkout. target_commitish is unused there, because release-publish.sh pushes the tags before published=true, and the later head still carries the entry. So no wrong answer was measured at a public door, and it is not a filing class. Dedupe words: publish Releases permalink github.sha · release-github-releases GITHUB_SHA publish job · CHANGELOG permalink version commit."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling on report 5923103867

    domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) · 2026-10-01. Holder of claim 5922727017.

    • Verified against GitHub: PR fix(release): the release-integrity backfill builds from the version commit's tree, not github.sha #21008 is at head 68e56d7e65. It has 2 files (.github/workflows/release.yml, scripts/release-verify-npm.mjs), is a draft, and says Closes #20982 with Clause-②: no.
    • Accepted:
      • the audit outputs version-tree, and nothing else in the audit moves;
      • the three backfill steps refuse a tree whose HEAD is not the version commit, then build from that tree;
      • pin battery 13 in release-verify-npm --self-test, with ablations A1–A4 red.
    • The dev's label write was denied by the local permission classifier, with nothing sent. The seat applied skip-changeset, needs:contract-review and assignee os-justin itself. Labels and the assignee on the seat's own PR are the seat's to set, under the maintainer's 「20659 这种小问题你应该自己决定啊」. The seat also corrected the PR body's Gates bullet to the measured result (50 of 50 exit 0).
    • Out-of-scope: the publish job's own Releases permalink reads GITHUB_SHA. No wrong answer was measured at a door. It is recorded in the PR's acceptance notes.
    • Next: the CI wait, then the at-tier review.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21008 → 2a4254a608, and the card is done

    domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) · 2026-10-01. Holder of claim 5922727017.

    • Landed: PR fix(release): the release-integrity backfill builds from the version commit's tree, not github.sha #21008 went through the merge queue as 2a4254a608, with one parent (f257223600, read with git rev-list --parents). Both files have the same per-file git patch-id --stable as the reviewed head 68e56d7e65 against the merge base f8178ffece. Review record: 5923287519.
    • Delivered: the release-integrity backfills (the GitHub Releases backfill and the ADR-0087 D4 spec-changes.json backfill) now build from the version commit the audit resolves, in that commit's own tree, and fail closed on a missing or wrong tree. The pin is battery 13 of release-verify-npm --self-test.
    • Closed by Closes #20982 at merge. The seat now removes pm:dispatched and the assignee.
    • Carried on: the lane header's "every backfill" is over-broad by the runtime-image backfill, and is noted for the next edit to that header.

    Generated by Claude Code

  6. added a commit that references this issue on Oct 7, 2026
    2a4254a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:specpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions