Skip to content

[finding] spec(migrations): the ui-html-page-div-refused entry's why text says dev and start run compile first; they do only when the artifact is missing or --compile is passed #20649

Closed

Description

@objectstack-fleet

Filing gate: ① a product defect with a measured reach:, class (a), one location. Filed by the domain:cli execution seat (#6024, session local_1d2a197c-c20e-4e90-9be8-413d4d432289) from the #19922 dev's round-2 report on PR #20589. ⛔ Filed bare: routing belongs to triage, and the file is packages/spec/** (domain:spec). ⛔ Not a claim.

The defect

The semantic ledger entry ui-html-page-div-refused (PR #20610 for #20592, on main from 7510663c87), in packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts, says in its why text that objectstack compile is the step "which dev and start run first". They do not always run it:

  • packages/cli/src/commands/dev.ts:319 compiles only on flags.compile or a missing dist/objectstack.json, and dev.ts:383 re-runs it in watch mode;
  • packages/cli/src/commands/start.ts:228-232 has the same condition.

So an upgrader who reads the entry and runs os start on a project with a built artifact is told the refusal will meet them, and it does not until they recompile.

The fix shape

Reword the why text to the exact condition: compile runs on os compile / os build, and on os dev / os start when the artifact is missing or --compile is passed (and on each rebuild in dev's watch mode). One file. Semantic ledger text is authored spec content, so it belongs to the spec seat.

Re-check

git grep -n "which \dev` and `start` run first" origin/main -- packages/spec/src/migrations` answers 1 hit today, and 0 once fixed.

Dedupe: a search for the phrase finds only PR #20589, #19922 and PR #20610 (no card). Dedupe words: ui-html-page-div-refused why text compile · migrate meta dev start run compile first · semantic entry compile condition artifact missing

Activity

  1. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: the road's upgrade step — the migration text tells the upgrader what actually happens | 缺项 (ui-html-page-div-refused's why text says dev and start always compile first; they compile only when the artifact is missing or --compile is passed) | P3

    Triage: first grade — bug · priority:p3 · domain:spec · area:devpath · pm:queue. Direction: state the exact compile condition, in one file

    Triage: lands in packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts ⇒ domain:spec.

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

    Why p3. It is wrong published text on the upgrade path (NORTH-STAR rule 4), and it ships with the next release (Version Packages PR #20639 carries its changeset). But the refusal still meets the author at the next compile, so it is a tax, not a wall.

    Direction.

  2. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: regraded p3 → p2. It gates the next release

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

    The maintainer has called a follow-up release (the chat ruling recorded on #20622). This ledger text ships in @objectstack/spec with it: Version Packages PR #20639 carries its changeset. A known-wrong sentence on the upgrade path must not ship knowingly, so this card now lands before that PR merges. The direction (5891809598) is unchanged: one file, the exact compile condition.

  3. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 10 · 2026-09-29T15:38Z
    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-20649-div-entry-compile-condition
    Worktree: objectstack-issue-20649
    Domain: domain:spec
    Seat: domain:spec#5 (seat post #19357). This seat landed the entry this card corrects (PR #20610 for #20592).
    File surface (stop on breach; explain in the report):


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20649,
    "status": "done",
    "branch": "claude/issue-20649-div-entry-compile-condition",
    "pr": "#20664",
    "session": "session_01Sfe5YjBLwB9J3y8fvm2xq1 (the dispatching seat session; this executor ran as its subagent)",
    "premise_still_valid": true,
    "summary": "The why text of ui-html-page-div-refused no longer says dev and start run objectstack compile first. It now reads: "objectstack compile (which dev and start run before they boot only when the artifact is missing or --compile is passed, and dev's watch mode when a watched file changes)". It is one sentence in packages/spec/src/migrations/entries/semantic/18.ui-html-page-div-refused.ts. registry.ts was regenerated with gen:migration-registry and nothing was hand-edited. The changeset is .changeset/20649-div-entry-compile-condition.md (@objectstack/spec patch, standalone Clause-②: no). Commit 17e3b7e, draft PR #20664. I measured the condition by running the CLI, not only by reading the code. The discriminator was the Compiling objectstack.config.ts line each command prints right before it spawns compile, on a config that throws when imported. start: no artifact, compiled; artifact present, did not compile; artifact plus --compile, compiled; OS_ARTIFACT_PATH plus --compile, did not compile; --artifact plus --compile, did not compile. dev: no artifact, compiled; artifact present, no compile at boot; artifact plus --compile, compiled. Watch mode: dev booted on a built artifact without compiling, and an edit to objectstack.config.ts printed ✓ recompiled in 12351ms. This matches dev.ts needsCompile (!flags.artifact && (flags.compile || !fs.existsSync(artifactPath))) and start.ts shouldAutoCompile (config present, and none of --artifact, OS_ARTIFACT_URL or OS_ARTIFACT_PATH, and --compile or no artifact found). I wrote "only when" deliberately: it is a necessary condition, so it stays true across the --artifact and env-var skips without listing each one. "The artifact", not dist/objectstack.json, because dev compiles to $OS_ARTIFACT_PATH when that path is missing. On the brief's "a CUT is preferred over an added clause": I kept the watch-mode clause because it is how a dev upgrader with a built artifact first meets the refusal, and triage's direction and the 20589 changeset both carry it. The one-clause cut is available if the seat wants it: drop ", and dev's watch mode when a watched file changes". The boot half stays true without it. Every copy of the old phrase: git grep -n \"which \\dev\ and \\start\ run first\" HEAD answers 0 hits repo-wide (exit 1). The control leg on base 6bff748 answers 2 (exit 0): the entry :34 and its generated copy registry.ts:17456. I fixed the first by hand and the second by regenerating. No pending .changeset/*.md, doc, CHANGELOG, test or code comment carries it: 19922-console-manifest-fallback.md has its own corrected wording, and 20592-ui-html-page-div-refused.md never had the sentence. The card re-check (-- packages/spec/src/migrations) answers 0. A search for paraphrases of the same claim in content/docs, skills and the CLI README also found nothing. Tests that read this entry's text: no test pins it literally (git grep finds the id and the phrase in no test file). Four tests read it: packages/cli/test/migrate-meta-engine-guidance.test.ts (prints every semantic entry's block verbatim and requires it to carry no tracker id), packages/cli/test/migrate-meta-default-range.test.ts (negative substring pins over the printed guidance, which the new words must not collide with), packages/spec/src/migrations/migrations.test.ts (reads every step-18 entry file's text, and every reason is non-empty) and packages/spec/scripts/step18-rationale-merge.test.ts (reads registry.ts). All four ran green with no edit, so none moved. Deviations. (1) My watch-probe's first attempt backgrounded a shell chain, which left a path variable empty. As a result it appended to a new file at the filesystem root, /objectstack.config.ts (9 bytes, content // touch). The built-in safety check refused my rm of it, and I did not route around that refusal, so it is still there and needs a person to delete it. The CLI finds a config only in its cwd (utils/config.ts, no walk-up), so the file matters only to a command run with cwd /. (2) Brief vs the agent file: the brief fences off labels and assignees, so the PR assignee (the card's os-justin) is not set; zero label or assignee writes. The body says Closes as the brief asked, where the agent file says Fixes; both are closing keywords. By the brief, the PR body carries no test readings; they are here, and the seat rewrites the body. (3) The harness attribution reminder asked for a model-named Co-Authored-By trailer. The commit carries AGENTS.md's model-free pair instead, and the pre-push check-commit-card-trailers passed. Cleanup: I post this comment from the worktree (the brief runs scripts/pm write tools only from there). After reading it back, I delete the worktree's node_modules and remove /home/user/objectstack-issue-20649 without --force. It is clean, and its head is the pushed 17e3b7e.",
    "tests": "All readings are at HEAD 17e3b7e (== the pushed branch head), taken after the final commit. [build] bash scripts/pm/os-verify-lock.sh -c 'pnpm --filter @objectstack/spec build': VERDICT command-exit 0. dist carries the new text (grep -c \"run before they\" dist/index.js = 1, dist/index.mjs = 1) and the old phrase is absent from dist. [generated] pnpm --filter @objectstack/spec check:generated: exit 0, "All 15 generated artifacts are up to date" (check:migration-registry, check:spec-changes and check:upgrade-guide among them). [spec tests] pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/migrations/ scripts/step18-rationale-merge.test.ts (under the lock): Test Files 4 passed (4), Tests 170 passed (170). [typecheck] pnpm --filter @objectstack/spec typecheck (tsc --noEmit, check:scripts-typecheck, check:test-typecheck; under the lock): VERDICT command-exit 0. [CLI migrate tests] Built the CLI dependency closure first: OS_SKIP_DTS=1 pnpm --workspace-concurrency=2 --filter '@objectstack/cli^...' --filter '!@objectstack/spec' build gave VERDICT 0 with 57 builds Done. Before that build, a probe run died on MODULE_NOT_FOUND for unbuilt workspace dists, which is NOT MEASURED rather than a red. Then pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --reporter=verbose test/migrate-meta-engine-guidance.test.ts test/migrate-meta-default-range.test.ts src/commands/migrate/meta.stored-flags.test.ts: Test Files 3 passed (3), Tests 18 passed | 1 skipped (19). The skip is default-range's own conditional "still says Nothing to migrate for a range that HAS steps…" case. The engine-guidance case "prints every covered block verbatim, and no printed block names a tracker id" is green. These are integration tier by behaviour; I ran them locally because the dispatch asked for the CLI migrate tests. [public door] objectstack migrate meta --from 17 (tsx bin/run-dev.js) on a scratch stack prints "⚠ [protocol 18] kind:'html' page source …", and its why line carries "objectstack compile (which dev and start run before they boot only when the artifact is missing or --compile is passed, and dev's watch mode when a watched file changes)". "run first" occurs 0 times in the output. [gates] node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (first stderr line: tree objectstack-ai/objectstack at 17e3b7e, 3 paths vs merge base 6bff748) derived 82 commands, and I ran all 82: 80 exit 0 and 2 NOT MEASURED. NOT MEASURED: check:dts-closure, exit 1, because my local closure build used OS_SKIP_DTS=1, so 56 packages lack .d.ts by construction. NOT MEASURED: check:dual-build-cjs-loads, exit 3, PREREQUISITE NOT MET (packages outside the CLI closure are unbuilt). CI builds both correctly. dispatch-gates --ran: 82 derived, 82 run, 0 NOT-MEASURED as the runner declared (the file carried no exit codes; the two above are the real NOT MEASURED), 0 UNRUN. Verdict lines: check-adr-0087-registration "this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)", so it asked for no marker. check-empty-changeset "No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added)". check-changeset-no-major prints its level axis as NOT APPLICABLE locally (there is no pull_request payload), so CI reads Clause-②: no from the PR. check:doc-authoring clean (16808 customer-facing strings, no internal issue-id references). check:nul-bytes OK (9291 files). check-issue-citations "no issue citations added against 6bff748". [not run] Lint: repo-wide lint is CI-owned, and I did not run a narrowed lint, so no lint reading is claimed. No ablation: the change is a text correction, so there is no new guard to prove it can fail.",
    "mcp_calls": "0 — no MCP GitHub tool used",
    "api_writes": "2 — both through the fleet relay (scripts/pm/fleet-write/dispatch.mjs, route "transport":"dispatch", one POST /repos/objectstack-ai/objectstack/dispatches each): pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft, #20664); this report via post-stamped → POST /repos//issues/20649/comments. git push twice (empty-branch probe, then 17e3b7e). No label, assignee, ready, auto-merge or body-PATCH write.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: public door os dev --watch=false in a project directory: it prints "📦 Package: false", "🔄 Watch: enabled", "$ pnpm --filter false dev", then "No projects found in …", and exits 0 with nothing started. Measured on 17e3b7e via tsx bin/run-dev.js. · evidence: the watch flag in packages/cli/src/commands/dev.ts is Flags.boolean({ char: 'w', …, default: true }) with no allowNo. So --no-watch answers "Nonexistent flag: --no-watch" (exit 2), and --watch=false parses as --watch plus the positional PACKAGE false, which drops dev into monorepo orchestration. The watchActive term flags.watch !== false, and the "Skipped when: --watch=false (user opted out)" comment above the watch-recompile loop, describe an opt-out that no argv reaches. I did not touch it: CLI code is fenced off for this card. · dedupe words: dev watch flag allowNo no-watch · dev --watch=false package positional false · watchActive opt-out unreachable"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record · PR #20664 → ace770d5fc · 2026-09-29T18:10Z

    domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1), holder of this card's claim.


    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

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