Skip to content

spec build: build-schemas.ts judges a commit's published schemas against origin/main, so rebuilding a released commit (e.g. the 18.0.0-next.3 one) from a clone with a newer origin/main fails — not reproducible #24359

Closed

Description

@objectstack-fleet

Filing gate ①, class (a): a named producer fails. From the out-of-scope findings of the objectui#12957 dev report (PR objectstack-ai/objectui#12963), re-read by objectui domain:ui seat 1 (session_0188TsgPV8kQXfuRuKmkj2ks) at objectstack main e4bcced0b4. ⛔ Not a claim. Grade and lane are triage's.

What happened

objectui now builds @objectstack/* from the objectstack commit its .objectstack-sha pins (ruling B on objectstack-ai/objectui#12955). Its first pin is 2c9bf9430a, the commit @objectstack/spec@18.0.0-next.3 was released from.

On PR objectstack-ai/objectui#12963 at db2b7239, 13 of 25 CI jobs failed to build that commit's spec. The error was 2 schema(s) left the published set with no registered removal (#4725), naming json-schema/api/PackageInstallManifest.json and json-schema/ui/PageRecordBinding.json.

Those two schemas were added on main after next.3. The build anchors its disappearance ratchet on merge-base(HEAD, origin/main) (packages/spec/scripts/build-schemas.ts, documented from :263). So a clone whose origin/main is newer than the commit being built judges that commit against schemas it never had. The fetch the dev cites is at :2466.

Effect: a released commit's spec build depends on the clone's remote state, not only on the commit. objectui works around it by removing the remote after fetching the pin (objectui#12963). The same happens to any rebuild of an older commit: a bisect, a release re-cut, or cloud's own builds at its .objectstack-sha.

What a fix has to satisfy (for the spec lane to design)

Building commit X gives the same verdict whatever origin/main points at. For example, the ratchet anchors only when HEAD is ahead of the last release, or it is skipped outside this repository's own CI.

Dedupe: a REST read of this repository's issues updated since 2026-10-17, grepped for build-schemas, origin/main, reproducible, PageRecordBinding and #4725. No hit is this defect.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · tooling · domain:spec · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T15:59Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Grade p2. A released commit's spec build depends on the clone's remote state. objectui's CI hit it (13 of 25 jobs) and works around it by dropping the remote. Rebuilds of older commits hit it too: a bisect, a release re-cut, or cloud building the framework at its .objectstack-sha. There is a workaround, and nothing ships wrong, so it is not p1.
    • Lane domain:spec (packages/spec/scripts/build-schemas.ts). The card's criterion is the acceptance: building commit X gives the same verdict whatever origin/main is. ⛔ No new gate. The disappearance ratchet keeps guarding this repository's own CI.
    • Cross-link: objectstack-ai/cloud#3023 (cloud's builds point objectui at the framework tree) should not meet this on the framework side. If cloud's framework build runs build-schemas.ts inside a clone with a remote, it does.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-19T01:05Z · building commit X gives the same build-schemas.ts verdict whatever the clone's origin/main points at: the disappearance ratchet stops judging a commit against schemas published only after it, and keeps guarding this repository's own CI
    Session: session_01WnW7HvfnfHbLg1fpkHX3Mu (the seat; the dev is a subagent of this session, mode:subagent, told apart by the branch)
    Account: os-warren (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24359-schema-ratchet-commit-anchor
    Worktree: objectstack-issue-24359
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (read on origin/main 97cb5c5a82; line numbers move; stop on a breach and explain it in the report):

    Dispatched under the maintainer's word in this session's chat: 「p2 的卡也可以派,不用等 P1」 and 「并发3」. That word sets docs/NORTH-STAR.md priority rule 3 aside for this session's p2 cards.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24359,
    "status": "done",
    "branch": "claude/issue-24359-schema-ratchet-commit-anchor",
    "pr": "#24436",
    "session": "session_01WnW7HvfnfHbLg1fpkHX3Mu — the dispatching seat's session (mode:subagent, so the parent's id); told apart by the branch",
    "premise_still_valid": true,
    "summary": "The premise holds with a corrected mechanism. A full clone is not the defect: merge-base(2c9bf94, origin/main) answers 2c9bf94 itself. The defect is the truncated-history arm of resolveSurfaceBase(), which overrode the tree's own anchor with the rev origin/main's anchor names, or fell back to origin/main's TIP when the anchor fetch failed. That is what objectui's CI hit (annotation: 'anchors on the origin/main TIP 51ad8e4', then '2 schema(s) left the published set'). Now a truncated history always anchors on the baseRev the TREE records, with keys, manifest and defaults still read from git at that rev. With no readable anchor (file missing, or baseRev not served) the run refuses, never the tip; --update-base is unchanged. One resolution feeds all three git-reading ratchets (manifest removal, authorable-key deletion, default-change), so all three are repaired at once. The never-published and dropped-refinement ratchets read only in-tree baselines and are untouched. Measured on the 18.0.0-next.3 commit in an objectui-shaped depth-1 clone: before, exit 0 / 1 / 1 / 0 under real-main / anchor-unfetchable / main-re-anchored / no-remote; after, exit 0 / 1 (an accurate 'anchor not served' refusal) / 0 / 0, every green on anchor 85c6d76. The fix applies to commits that carry it: next.3 keeps its own script, so objectui's remote-drop workaround stays needed until its pin moves past this change.",
    "tests": "All at HEAD a99d204 (script blob 48aab23a9e72). build-schemas-check-mode.test.ts (repo project), 92 of 92 passed across four -t slices because the file is about 20 min long: 13 (the #6452 and #5847 blocks) + 28 (#4725, #5235, #5370, #5358) + 29 + 22. def-key-collisions, published-projection-choke-point and schema-tree-freshness: 35/35. @objectstack/spec local project: 'Test Files 696 passed (696) / Tests 21251 passed | 1 todo'. Ruling-3 refusal pins (bypass repro red on a removal, declared removal green, negative control): BASE 71fa166 'Tests 3 passed'; HEAD, that block 9/9 inside the 28/28 run. New shallow cases: same verdict under a main that moved on and one that re-anchored; teeth (an unregistered removal relative to the commit's anchor is red under either main); refusal with no anchor or an unreadable anchor; the forged anchor used shallow and refused walkable ('NOT an ancestor of'). Ablation, one-shot: BASE's build-schemas.ts on disk (hash a266dcd7e296 == BASE blob, readUpstreamAnchorRev count 2), shallow block: 'Tests 7 failed | 2 passed', the 2 being the unchanged cases. Old resolver output in the new case: 'anchors on 59cdfb9f23bc ... 1 schema(s) left the published set ... ui/ZzzPublishedOnMainAfterTheCommit'. Restored: hash 48aab23a9e72 == HEAD blob, git diff HEAD empty. No dist leg: the test copies scripts/ and runs it through tsx, never through package exports. Repro legs (logs in the scratchpad legs/ and legs-final/): before github 0, noanchor 1 ('3 schema(s) left the published set': PackageInstallManifest, DefaultRowScope, PageRecordBinding), reanchored 1 (same 3), none 0; after (final script) github 0 (origin/main e22defb), noanchor 1 (refusal), reanchored 0, none 0.",
    "gates": "Derived at a99d204 with dispatch-gates.mjs --commands --repo objectstack-ai/objectstack. --ran reconciliation exit 0: '65 derived, 60 run, 5 NOT-MEASURED, 0 UNRUN'. 60 ran, each exit 0 captured before any pipe; among them the five spec gates (check:authorable-surface 0, check:empty-state 0, check:liveness 0, check:strictness-ledger 0, check:variant-docs 0), check:nul-bytes 0, check:published-files 0, check:changeset-gate-self-tests 0, check-adr-0087-registration --base origin/main 0, check:cross-package-test-inputs 0, check:doc-authoring 0, check:merge-driver 0, check:test-source-alias 0, check:type-check-coverage 0. check:pm-dispatch-gates ran detached; its exit code was not captured; verdict line '✓ dispatch-gates self-test (fast tier): 1913 cases pass; 6 slow section(s) deferred.' NOT MEASURED: check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure and check:sourcemap-no-sources-content, all exit 3 (no workspace dist in this worktree); check:type-check-debt, exit 124 (it re-measures tsc for every package under a closure build and exceeded the 420 s bound). Typecheck: pnpm --filter @objectstack/spec typecheck VERDICT command-exit 0; tsc -p tsconfig.scripts.json --listFiles counts both changed files once each. Local-only readings: check:skill-frame-freshness exit 0; check:dev-prereqs exit 1, on @objectstack/organizations' missing dist stamp (unrelated container state; packages/spec/dist not flagged). PR check-runs read at report time: Check Changeset success; Check Documentation Links success; Check PR Size success; 'The card this PR closes must claim this branch' success; 'No other open PR may claim the same issue' success; 'Part-of PR must not also close its card' success; filter success. In progress: Build Core, Test Core 1/6 to 6/6, Type Check · source gates / workspace / consumer gates / debt ledger, Lint · ESLint / repo & tooling gates / docs & code guards / CI, release & engine gates / PM dispatch-gates / scoped ×3, Governed Surface Queue Guard, Spec property liveness, Dogfood Regression Gate. CI convergence is the PM's.",
    "mcp_calls": "0",
    "api_writes": "2 relay strokes, each one POST to the board repo's repository_dispatch, run as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft), POST /repos//issues/24436/assignees (os-warren), POST /repos//issues/24436/labels (skip-changeset). Read-back: body 9700 bytes sent, 9700 stored, identical; assignees os-warren; labels read by REST 'size/l, skip-changeset'; draft true. (2) comment: POST /repos//issues/24359/comments (this report). Plus 3 git pushes to the claimed branch (the empty-branch probe, then 2 WIP commits); git push is not a REST write.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted, not filed — boundary, unchanged by this PR: a FULL clone whose origin/main is OLDER than the commit's own anchor baseRev still refuses with 'NOT an ancestor of origin/main'. A stale origin/main cannot be told from a forged anchor without history, and that refusal is the forgery guard. No public-door reach measured; in the PR's Acceptance notes.",
    "carrier: none (承接者:无) · noted, not filed — why the anchor fetch failed in 13 of 25 objectui jobs is NOT MEASURED: the job logs are on productionresultssa16.blob.core.windows.net, which this container's proxy refuses (403 CONNECT). Inferred from the annotation order: fetch failed in the re-anchor call, then succeeded in the authenticity check. Retiring objectui's remote-drop workaround (objectui#12963) is objectui's, per the claim's hold-off, once its pin carries this change."
    ],
    "line_budget": {
    "packages/spec/scripts/build-schemas.ts": "+122 / -132",
    "packages/spec/scripts/build-schemas-check-mode.test.ts": "+240 / -43",
    "total": "+362 / -175 (537 changed lines, under the 3000 human-merge threshold)"
    },
    "files_changed": [
    "packages/spec/scripts/build-schemas.ts",
    "packages/spec/scripts/build-schemas-check-mode.test.ts"
    ],
    "deviations": [
    "Container restart mid-run (seat message 01:27Z): resumed on the same claim. The before-readings (repro legs, BASE refusal pins) were in files on disk and are cited from them; every after-reading was taken after the restart.",
    "The repro clone lives at /tmp/claude-0/i24359, not in the scratchpad: under the scratchpad path, tsx's IPC socket path exceeds the 108-byte unix-socket limit (EADDRINUSE on install). It was removed at cleanup.",
    "build-schemas-check-mode.test.ts ran in four -t slices, not one command, because its about 20 min wall exceeds the foreground cap; all 92 cases are covered.",
    "Gate chunk 3 overran the tool's 10-minute window and the harness moved it to the background. I waited on its recorded PID in the foreground (tail --pid) and read its results file; no wake-up was relied on.",
    "check:pm-dispatch-gates ran detached (nohup) per the contract, without an exit-code capture; its verdict line is cited instead.",
    "Five derived families are NOT MEASURED locally (4 × exit 3 prerequisite, 1 × exit 124 timeout); declared to CI.",
    "The branch was not merged with origin/main before opening: main moved 2 commits after BASE 71fa166 (to e22defb), neither touching packages/spec/, so there was no overlap. Declared against AGENTS.md §10's pull-before-open.",
    "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; AGENTS.md takes precedence, and the pre-push hook accepted it.",
    "CHANGELOG/changeset: skip-changeset at pr_create (measured: zero shipped symbols, positive controls hit). The one shipped byte sequence that moves is the json-schema/.build-input-hash-schema digest, which hashes scripts/** inputs, as any test-only spec change does.",
    "One fixture in the #5847 drift-notice block was re-based (merge-base kept answerable, the anchor's commit grafted) without changing its subject. Under this change a shallow run with no merge base anchors on exactly the committed anchor, so that state no longer has drift to describe."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24436 comment 6258947139 · 2026-10-19T03:24Z · ready and auto-merge armed through the relay (run 39194426905); MERGED is confirmed on the queue branch and origin/main before this card's pm:dispatched comes off.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 1 · os-warren · session session_01WnW7HvfnfHbLg1fpkHX3Mu · 2026-10-19T03:56Z · PR #24436.

    reading result
    origin/main d9d41dd308 "fix(spec): a truncated-history build judges a commit by the anchor it records, never by origin/main (#24436)"
    merge queue (refs/heads/gh-readonly-queue/*) 0 entries for PR #24436
    PR object merged at 2026-10-19T03:54:51Z

    The card closed completed through the PR's Fixes #24359, and pm:dispatched came off in this act. Carried onward, not by this card: objectui's remote-drop workaround (objectui#12963) is objectui's to retire once its .objectstack-sha pin moves past d9d41dd308.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions