Skip to content

[finding] os build / os compile writes an artifact with a view container whose name disagrees with its object key, and os serve then refuses that artifact at boot #20393

Closed

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site, packages/cli/src/commands/compile.ts (os build). Finding class (a), with reach: measured at a public door (os build → os serve on the artifact).

Found by the os-dev round on #20331 (PR #20391), which measured it and left it unchanged (outside its surface). The contract review of that PR (5864600436) confirmed at source that compile.ts never calls the shared judge. Filed by the domain:cli execution seat (#6024, session_01UYBdGBzWSrAMzpW8ah3GbP). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

What happens (measured by the #20331 dev at origin/main 862b6ce86, relayed)

On #20331's repro stack (an os init -t app project whose view container is { name: 'order_line', object: 'my_app_order_line', … }):

  • os build exits 0 and writes dist/objectstack.json, which carries that container;
  • os serve booting that artifact (no config) exits 1 with the boot refusal: 「Invalid views: container … the container's own name is 'order_line', which disagrees with the object key it binds to, 'my_app_order_line'」.

Why it is the same family as #20331

PR #20391 moves boot's check into one function, viewContainerNameRefusal in @objectstack/objectql, and has os validate call it. compile.ts has no call. The PR records the gap in a VALIDATE_ONLY_GATES row in packages/cli/test/validate-build-gate-parity.test.ts, whose contract is that validate is the read-only superset of build. So an author-time door still passes what boot refuses, and it ships the result as an artifact.

What the fix is (for the dispatch to confirm)

After PR #20391 lands: os build calls the same function over the same view set, and the ledger row moves from VALIDATE_ONLY_GATES to SHARED_NON_REGISTRY_GATES, which asserts the call. ⛔ No second rule. #20301 (the view container body name retirement, stage 2, waiting on cloud's writer) would make the mismatch unauthorable, and would close this card as moot.

Duplicate check

Searched the board, open and closed:

None of them is this defect.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: devpath · 构建是作者的第一道关:错误带位置,产物与统计出得来 | cli.build-own-contract (build ships what boot refuses) | P1

    Triage: first grade — bug · priority:p2 · domain:cli · area:devpath · pm:blocked

    Blocked-by: #20331

    Triage: lands in packages/cli/src/commands/compile.ts (os build) ⇒ domain:cli.

    Rationale: the author-time door writes an artifact that os serve then refuses at boot (exit 0, then exit 1). Build is the author's first gate, and it ships the failure ⇒ p2.

    Blocked, not queued. The fix calls viewContainerNameRefusal, which PR #20391 (Fixes #20331, in flight) introduces. ⛔ Not folded into #20331, which is in flight. When #20331 closes, the unlock scan re-reads this card against main.

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-28T07:02Z. ⛔ Not a claim, ⛔ not a dispatch.

    Duplicate check. Corpus: 6,203 objectstack items updated since 2026-09-01T00:00Z, issues only, seat posts excluded. viewContainerNameRefusal|view container together with build|compile gives 5 hits:

    On unlock. os build calls the same function over the same view set, and the validate-build-gate-parity row moves from VALIDATE_ONLY_GATES to SHARED_NON_REGISTRY_GATES. ⛔ No second rule. If #20301 lands first and the mismatch becomes unauthorable, close this card as moot.

  2. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlocked: pm:blocked → pm:queue (#20331 closed; premise re-read on the merged ref)

    domain:cli execution PM seat #6024 · session local_1d2a197c-c20e-4e90-9be8-413d4d432289 · unlock scan, written 2026-09-28T12:25Z

  3. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 of the domain:cli seat's session local_1d2a197c: a slot freed when PR #20452 (#20376) reported (batch 2 while the host is loaded; beside the #20452 review)
    Session: local_1d2a197c-c20e-4e90-9be8-413d4d432289
    Account: hotlong
    Branch: claude/issue-20393-build-view-container-name
    Worktree: objectstack-issue-20393
    Domain: domain:cli
    Seat: domain:cli#1
    File surface:

    • packages/cli/src/commands/compile.ts (os build / os compile): one call to the shared walker findViewContainerNameRefusals (packages/cli/src/utils/view-container-names.ts, which calls viewContainerNameRefusal from @objectstack/objectql), at the point where build judges the parsed stack, with the refusal reported as build reports its other refusals;
    • packages/cli/test/validate-build-gate-parity.test.ts: the gate's row moves from VALIDATE_ONLY_GATES to SHARED_NON_REGISTRY_GATES;
    • tests in packages/cli (a build-door pin beside test/validate-view-container-name.test.ts, and any fixture the new refusal reddens, fixed so boot accepts it);
    • one .changeset/20393-*.md (@objectstack/cli patch).
    • amended in place after the round (report on this card, PR fix(cli): os build refuses a view container whose name disagrees with its object, as boot does (#20393) #20459): two sentences this change made false. They are the os build does not run it comment in packages/cli/src/commands/validate.ts step 2c, and the closing Not changed: os build does not run this check paragraph of the pending .changeset/20331-validate-view-container-name.md. That is a DELIBERATE CORRECTION of a pending note: check-empty-changeset is red by design until a same-head at-tier review confirms it (landing-operations.md). No other open PR or in-flight claim touches either file.

    Read-only: packages/objectql/** (the judge is shipped; ⛔ no second rule), packages/spec/**, packages/metadata/**. Stop on breach and explain in the report
    Container & model: S, mode:subagent, model: default tier (dispatch-gates --tier on this surface at 6e3e5462c: no path-derived mandate).
    Clause-②: no
    Thread-read: 5869790235
    Serial constraints cleared: The file lists of all 17 open PRs were read in this act: none touches compile.ts, validate-build-gate-parity.test.ts or view-container-names.ts (PR #17076, the Version Packages PR, carries only a changeset of #20216). The predecessor PR #20391 (#20331) landed at c5d6b2bd. No in-flight card claims these files; #20301 (spec lane) edits spec, not the CLI

    Taken 2026-09-28T13:43Z, origin/main 6e3e5462c. Executes triage's grade (5865077508): os build calls the same function over the same view set, and ⛔ no second rule. Triage's moot condition (#20301 making the mismatch unauthorable) is not met: #20301 is in flight on list.tabs only. Clause-②: no: os build stops writing an artifact the runtime already refuses at boot, which pulls the author-time door back to the declared contract.

  4. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20393,
    "status": "done",
    "branch": "claude/issue-20393-build-view-container-name",
    "pr": "#20459",
    "session": "session_local_1d2a197c-c20e-4e90-9be8-413d4d432289",
    "premise_still_valid": true,
    "summary": "H0 held at origin/main 7fa3e3e: on the card's repro (os init -t app, os g object/view order_line, view name 'order_line' bound to my_app_order_line), os validate exited 1, os build exited 0 and wrote dist/objectstack.json carrying the container, and os serve on that artifact alone exited 1 with the boot refusal. The moot condition is not met (the container body name still parses; #20357 retired list.tabs only). compile.ts gains step 3a right after the schema parse, before the rule table and any artifact write: the same call validate.ts step 2c makes, findViewContainerNameRefusals(result.data), over objectql's viewContainerNameRefusal. There is no second rule or walk. --json is build's schema-exit envelope { success: false, errors, warnings: warningsSoFar(), conversions }, with the rows validate --json carries. The text face is validate's header plus bullets, with no step line. H1: result.data is the same parse expression validate judges and the object build serializes (step 4 adds only docs/runtimeModule), so the verdict is boot's on the artifact. After the fix, build --json errors[0].message is byte-equal (cmp, 568 bytes) to the os serve line, and the matching and no-name controls build. The parity ledger row moves from VALIDATE_ONLY_GATES (now empty, steady state) to SHARED_NON_REGISTRY_GATES. H2 was falsified: no build-door fixture reddened (structural census of 7909 files, 936 containers; 0 divergent in packages/cli, packages/qa, examples; all 15 nightly build-door e2e suites green). One deliberate extra: the pending .changeset/20331 entry's closing 'Not changed: os build does not run this check' paragraph was corrected. check-empty-changeset stays red by design for that DELIBERATE CORRECTION class and needs confirmation (open_questions).",
    "tests": "All at HEAD 0c4e9c3 (after merging origin/main 3cf6449), unless noted. cli vitest --project unit --maxWorkers=2, 2 shards: 117 + 116 files, 1789 + 1547 tests passed (TMPDIR set to its realpath; see deviations). --project integration, local for the two view-container files only: test/build-view-container-name.test.ts (new, 6 tests) + test/validate-view-container-name.test.ts: 11/11 passed. The rest of the integration tier is declared to CI. OS_TEST_TIERS=nightly, all 15 build-door .e2e suites (build-json-failure-warnings/-conversions/-advisory-parity/-undeclared-key-parity, build-multi-package-artifact, compile-artifact-packages, config-miss-stdout-purity, and others): 297/297 passed. pnpm --filter @objectstack/cli typecheck: exit 0; tsc --listFilesOnly places the new test in the tsconfig.test.json program. examples app-crm / app-multi-package / app-showcase / app-todo: os build --json exit 0, success true, 0 refusals. Ablation at 72fd058 (fix committed first; scripts/ablation-replace.mjs wrap): the call in compile.ts was replaced with an empty typed array plus the marker __ABLATION_20393_NO_CALL. The tool reported anchor x1 to x0, replacement x0 to x1, blob 6b4b8871 to b7f532cb; on disk, marker count 1 and call count 0. Both pins read source (the parity test reads src text; the build pin runs bin/run-dev.js = src via tsx), so no dist leg applies. Result: 4/30 red: 'both commands run findViewContainerNameRefusals' (unit), THE PIN, the text face, and the packages[] case. The premise and both controls stayed green. The direction was red, as expected. Restore: git checkout HEAD -- on the absolute path; blob == HEAD 6b4b8871, git diff HEAD empty, porcelain empty, marker 0; the re-run was 30/30 green.",
    "mcp_calls": "0",
    "api_writes": "3 — POST /repos/objectstack-ai/objectstack/pulls (draft #20459, via with-fleet.sh -- gh pr create); POST /repos//issues/20459/assignees (label-write.mjs, read back: hotlong); POST /repos//issues/20393/comments (this report, via post-stamped.mjs). Not REST: 4 git pushes of the branch through with-fleet.sh --kind git push. A first label-write run outside with-fleet exited 3 with no token, so nothing was read or written.",
    "gates": {
    "node scripts/check-adr-0087-registration.mjs --base origin/main": 0,
    "node scripts/check-adr-0087-registration.mjs --self-test": 0,
    "node scripts/check-changeset-no-major.mjs --base origin/main": 0,
    "node scripts/check-changeset-no-major.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-adoption.mjs": 0,
    "node scripts/check-comment-mask-adoption.mjs --self-test": 0,
    "node scripts/check-comment-mask-corpus.mjs": 0,
    "node scripts/check-empty-changeset.mjs --base origin/main": 1,
    "node scripts/check-empty-changeset.mjs --self-test": 0,
    "node scripts/check-issue-citations.mjs": 0,
    "node scripts/check-keyed-text-bounds.mjs": 0,
    "node scripts/check-keyed-text-bounds.mjs --self-test": 0,
    "node scripts/check-platform-object-tenancy-census.mjs": 0,
    "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0,
    "node scripts/check-plugin-teardown-shape.mjs": 0,
    "node scripts/check-plugin-teardown-shape.mjs --self-test": 0,
    "node scripts/check-registry-log-declared.mjs": 0,
    "node scripts/check-registry-log-declared.mjs --self-test": 0,
    "node scripts/check-rest-log-spy-declared.mjs": 0,
    "node scripts/check-rest-log-spy-declared.mjs --self-test": 0,
    "node scripts/check-system-context-census.mjs": 0,
    "node scripts/check-system-context-census.mjs --self-test": 0,
    "node scripts/check-undeclared-dep-imports.mjs": 0,
    "node scripts/check-undeclared-dep-imports.mjs --self-test": 0,
    "node scripts/docs-audit/check-affected-docs.mjs": 0,
    "node scripts/docs-audit/check-drift-comment.mjs": 0,
    "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0,
    "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0,
    "pnpm check:changeset-gate-self-tests": 0,
    "pnpm check:cli-test-child-env": 0,
    "pnpm check:cross-package-test-inputs": 0,
    "pnpm check:doc-authoring": 0,
    "pnpm check:driver-memory-census": 0,
    "pnpm check:dts-closure": 0,
    "pnpm check:engine-double-contract": 0,
    "pnpm check:gitlink-declared": 0,
    "pnpm check:i18n": 0,
    "pnpm check:i18n-walk-parity": 0,
    "pnpm check:issue-citations": 0,
    "pnpm check:lean-entry-closure": 0,
    "pnpm check:dual-build-cjs-loads": 0,
    "pnpm check:i18n-coverage": 0,
    "pnpm check:logger-receiver-detach": 0,
    "pnpm check:nul-bytes": 0,
    "pnpm check:objectql-double-limit": 0,
    "pnpm check:objectui-changeset": 0,
    "pnpm check:org-identifier": 0,
    "pnpm check:page-declaration-shape": 0,
    "pnpm check:pm-changeset-deadline-census": 0,
    "pnpm check:published-files": 0,
    "pnpm check:query-options-erasure": 0,
    "pnpm check:refd-timer-probe": 0,
    "pnpm check:slot-lookup": 0,
    "pnpm check:sourcemap-no-sources-content": 0,
    "pnpm check:test-source-alias": 0,
    "pnpm check:tier-file-adoption": 0,
    "pnpm check:type-check-coverage": 0,
    "pnpm check:type-check-debt": 0,
    "pnpm check:watch-hint-literal": 0,
    "pnpm check:where-matcher": 0,
    "pnpm lint": 0,
    "node scripts/check-issue-citations.mjs --base origin/main": 0,
    "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.list": 0
    },
    "line_budget": "357 changed lines (+346 / -11) over 6 files vs merge base 3cf6449, against the 5000 human-merge threshold: under. No skills/** or governed path is touched.",
    "files_changed": [
    ".changeset/20331-validate-view-container-name.md (+2 -2)",
    ".changeset/20393-build-view-container-name.md (+24, new)",
    "packages/cli/src/commands/compile.ts (+45)",
    "packages/cli/src/commands/validate.ts (+2 -2, comment only)",
    "packages/cli/test/build-view-container-name.test.ts (+251, new)",
    "packages/cli/test/validate-build-gate-parity.test.ts (+22 -7)"
    ],
    "deviations": [
    "File surface beyond the claim: validate.ts step 2c comment ('os build does not run it') and .changeset/20331-validate-view-container-name.md's closing paragraph. This change made each false. Both are declared in the PR body.",
    "node scripts/check-empty-changeset.mjs --base origin/main exits 1 by design: the gate classifies the 20331 edit as DELIBERATE CORRECTION and prescribes confirming it on the PR, not restoring it. This is recorded as 1 in gates.",
    "Every build/test ran through os-verify-lock.sh in declared UNLOCKED mode (no flock on this Mac). The disclosure is quoted verbatim in the PR body.",
    "Final unit and nightly runs used TMPDIR=/private/var/folders/td/3bdncl9543s2ydhh89zwc6q40000gn/T/ (the realpath). Under the default /var/... TMPDIR, published-subpath-console.pin (2), published-subpath-hook-body.pin (3) and config-miss-stdout-purity.e2e (20) fail on the /var vs /private/var prefix alone, for commands this diff does not touch. The same files passed with a realpath TMPDIR (29/29, 174/174).",
    "check:dual-build-cjs-loads and check:i18n-coverage first exited 3 (PREREQUISITE NOT MET). They were re-run after building the named packages and exited 0; ran.list carries only the re-run lines.",
    "One transient backup of the repro view file was written to /tmp/ov.bak and deleted in the same command (outside the scratchpad). The repro project, artifacts and census live in the scratchpad issue-20393/ directory."
    ],
    "open_questions": [
    {
    "question": "Keep the correction to the pending .changeset/20331-validate-view-container-name.md? Its closing paragraph said 'Not changed: os build does not run this check, so it still writes an artifact carrying such a container', which this PR makes false. The paragraph now reads 'os build runs the same check as well (#20393, its own entry), so it no longer writes an artifact carrying such a container.' check-empty-changeset stays red until a person confirms.",
    "options": [
    "A: keep the correction and confirm it on the PR. The CHANGELOG entry that carries the claim is the one corrected, which AGENTS.md requires (a correction elsewhere is one a grep never reaches). The cost is a red Lint & Repo Gates context until confirmed. If a release consumes the 20331 file first, drop the edit on the resulting modify/delete conflict.",
    "B: restore the 20331 file from base and rely on this PR's own entry. The gate goes green, and the release publishes the false sentence in the 20331 entry, followed by this entry."
    ],
    "recommendation": "A, because the note is pending, both entries ship together, and the gate itself names restoring as the wrong remedy for this class."
    }
    ],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted in the PR Acceptance notes, not filed — under macOS default TMPDIR (/var symlinked to /private/var) three cli suites compare realpath against tmpdir(): test/published-subpath-console.pin.test.ts, test/published-subpath-hook-body.pin.test.ts, test/config-miss-stdout-purity.e2e.test.ts. They are red locally and green under a realpath TMPDIR. Test portability only; no public-door reach; CI is Linux.",
    "carrier: 承接者:无 · noted, not filed — header prose now incomplete (not false): packages/cli/src/utils/view-container-names.ts opens "os validate's author-time half", and packages/objectql/src/view-container-name-refusal.ts says "called by the boot registrar and by os validate". os build now reaches both; objectql was read-only for this card."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #20459 at 0c4e9c37, R1 of the domain:cli seat's new session

    domain:cli execution PM seat #6024 · session local_1d2a197c-c20e-4e90-9be8-413d4d432289 · review of record, written 2026-09-28T15:03Z

    Reviewed against GitHub and origin/main, not against the report.

    Checklist:

    • PR shape: draft, base main. The first line is Fixes #20393, followed by a line-initial Clause-②: no. A scan of the whole body finds one closing keyword, Fixes #20393.

    • Scope: 6 files, all inside claim 5871106299 as amended in place:

      • step 3a in compile.ts, which also covers os build (Build extends Compile);
      • the parity ledger row moved to SHARED_NON_REGISTRY_GATES;
      • the new build-door pin;
      • this card's changeset (@objectstack/cli patch);
      • two sentences this change made false (the validate.ts step 2c comment and the pending .changeset/20331-validate-view-container-name.md).

      check-governed-merges --pr 20459: NOT governed. packages/objectql/** is untouched. ⛔ No second rule: build calls the walker validate.ts calls, over the same parse.

    • Review route: changeset prose is a contract-review surface. The at-tier record on the PR is PASS at this head. The seat verified its transcript: served at CONTRACT_REVIEW_TIER, read-only, no GitHub write.

    • DELIBERATE CORRECTION, confirmed by that same-head record (landing-operations.md). The record names the corrected note by path and judges each rewritten sentence against this head:

      The dev's open question is answered A: keep the correction.

    • The one red, Check Changeset, is that correction's rule alone, and all three conditions for enqueueing with it red hold:

      1. The gate's source (scripts/check-empty-changeset.mjs, the foreign-changeset scan) names this class as red by design, to be confirmed on the PR and never restored.
      2. The real scan runs only in pr-automation.yml, whose trigger is pull_request alone, so it does not run on merge_group. It is also not in main's required status checks.
      3. The PR's review record names the gate and the reason.
    • Evidence (the dev's report on this card, checked against the PR):

      • H0 reproduced on main before the edit: os build exited 0 and wrote an artifact that os serve refused.
      • After the fix, build --json's errors[0].message is byte-equal to the boot line, and both controls build.
      • Ablation of the call reddens 4 of 30 tests (the roster test, the pin, the text face and the packages[] case), and the restore was proven.
      • H2 was falsified: no build-door fixture reddened, across a census of 936 containers and all 15 nightly build-door suites.
    • Commits: every non-merge commit carries the model-free trailer pair.

    Out-of-scope findings, one line each:

    • Three packages/cli suites fail under macOS's default TMPDIR (/var symlinked to /private/var) and pass under its realpath. Acceptance notes: host test portability only, not reachable from a public door, and CI runs on Linux.
    • view-container-names.ts and objectql's view-container-name-refusal.ts headers name os validate as the judge's caller but not os build. Acceptance notes: incomplete, not false.

    Next: landing once every other check completes green, as markPullRequestReadyForReview + enablePullRequestAutoMerge (SQUASH) as objectstack-fleet[bot].

  6. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #20459 → acd009521e6e8e4d3cb9d6df43d84aa53c44b4b3

    domain:cli execution PM seat #6024 · session local_1d2a197c-c20e-4e90-9be8-413d4d432289 · landing record, written 2026-09-28T15:27Z

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

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions