Repository navigation
cli(dev): the watch opt-out the code checks for is unreachable — watch has no allowNo, so --no-watch is refused and --watch=false boots nothing and exits 0 #20681
Description
Activity
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsPath: the author's loop —
os dev's documented opt-out works | 缺项 (watchhas noallowNo, so--no-watchis refused and--watch=falseparses as a package namedfalse, starts nothing and exits 0) | P3Triage: first grade —
bug·priority:p3·domain:cli·area:devpath·pm:queue. Direction (triage's call):allowNo: true, so--no-watchis the spellingTriage: lands in
packages/cli/src/commands/dev.ts(:187) ⇒domain:cli.Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-29T18:05Z. ⛔ Not a claim, ⛔ not a dispatch.Direction.
- The
watchflag getsallowNo: true, as three sibling flags in the same command already do. The code'swatchActivecheck and its comment already expect an opt-out. - The comment's "--watch=false" becomes "--no-watch".
--watch=falseshould not silently boot nothing. Since oclif readsfalseas the positional package, the seat checks whether a positional that names no workspace package can fail loudly (non-zero, naming the value) instead of exiting 0. If that is a larger change, report it on this card.- Pins:
os dev --no-watchstarts with watch off;os devkeeps it on.
- The
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingand removed
on Sep 29, 2026 objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 of the
domain:cliseat's sessionsession_01VvcEokUG1tvVxkceYfR5XB(batch3):priority:p3, the next card by the lane's full order (aBug, the oldest dispatchable p3)
Session:session_01VvcEokUG1tvVxkceYfR5XB
Account:huangyiirene
Branch:claude/issue-20681-dev-no-watch
Worktree:objectstack-issue-20681
Domain:domain:cli
Seat:domain:cli#1
File surface:packages/cli/src/commands/dev.ts: thewatchflag declaration (allowNo: true), the watch-loop comment ("--watch=false" becomes "--no-watch"), and, if it stays small, the positionalPACKAGEcheck, so that a value naming no workspace package fails loudly instead of exiting 0.- A pin file under
packages/cli/test/. .changeset/20681-*.mdfor@objectstack/cli.- If a loud positional check needs more than
dev.ts, the dev ships theallowNohalf and reports the rest on this card (triage5895852973: "If that is a larger change, report it on this card").
Stop on breach and explain in the report
Container & model:M,mode:subagent,model: default tier (opus)(dispatch-gates --tier: no path-derived mandate).
Clause-②: no
Clause-② reading: the flag describes watch as the default, and the command's own code carries the off branch (watchActive, and the loop comment).--no-watchmakes that declared opt-out reachable, which is pulling back to declared behaviour, not a new capability. A loud refusal of a positional that names no package narrows a silent no-op. Neither widens a published contract. The at-tier review re-reads this line against the real diff.
Thread-read: 5895852973
Serial constraints cleared:No open PR touches packages/cli (file lists of all open PRs read in this act; PR #20801 landed as d2b188fb). The blocked cards #20620 and #20583 are not on dev.ts. No other card of this lane is on dev.ts.Taken 2026-09-30T09:30Z,
maind2b188fb.
Generated by Claude Code
objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 20681,
"status": "done",
"branch": "claude/issue-20681-dev-no-watch",
"pr": "#20839",
"session": "session_01VvcEokUG1tvVxkceYfR5XB",
"premise_still_valid": true,
"summary": "Both halves were delivered in packages/cli/src/commands/dev.ts. The only other files are one pin and one changeset. (1)watchgetsallowNo: true.os dev --no-watchnow boots with the watch-recompile loop off, and bareos devkeeps it on. The loop's decision is extracted as the exporteddevWatchActive, and the loop comment now says --no-watch. (2) The monorepo command passes pnpm--fail-if-no-match. A PACKAGE that selects nothing (for examplefalse, which is what--watch=falseparses to) now exits 1, and the failure line names the value. Before, it exited 0. pnpm owns the filter grammar, so dev.ts does not re-read the workspace. (3) New, because (1) makes it reachable:--no-watchin monorepo orchestration mode is refused with exit 1 and names the flag, instead of printing 'Watch: enabled'. That argv was a Nonexistent-flag exit 2 before, so no run that used to work is newly refused. PM hypothesis readings, at BASE 73155fe: H1 confirmed. The sibling allowNo flags are at :206 :212 :261 and watch is at :187. content/docs and packages/cli/README.md have 0 hits for --no-watch/--watch; the control, allowNo in dev.ts, has 3. H2 reproduced exactly: exit 2, then Package: false / Watch: enabled / pnpm --filter false dev / No projects found, exit 0. H3: dev.ts consumes PACKAGE only aspnpm --filter PKG devvia execSync. Judging 'names no workspace package' in the CLI would re-implement pnpm's filter grammar (globs, ./dir, ...pkg), so pnpm decides. According to pnpm's CHANGELOG at v10.31.0 the flag arrived in pnpm 8.13.1. This was measured on 10.31.0 only. H4: no oclif manifest to regenerate: package.json has oclif.manifest null, there is no oclif.manifest.json, and files[] is dist, README.md and CHANGELOG.md.",
"tests": "Heads: every test, gate and lint result below is on c36db55 except the pin and the ablations, which ran on fcf4f78. The only later commit adds the changeset .md. PIN:pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/dev-no-watch.pin.test.tsgave 'Test Files 1 passed (1) / Tests 8 passed (8)'. The pin is in the integration tier because it spawns (vitest-tiers fired childProcess, entryBasename, tsxBin). ABLATION: three legs through scripts/ablation-replace.mjs in WRAP mode. The subject resolves via src (a relative import plus tsx over run-dev.js), so no dist is involved and no rebuild was needed. Every restore printed 'ok restored: blob == HEAD (02c1c4bb1d8e) and git diff HEAD is empty'. A, --fail-if-no-match dropped: 'ok mutation landed: anchor 1 -> 0, blob 02c1c4bb1d8e -> 2195d30b5f4f' gave 2 failed / 6 passed ('expected +0 to be 1'; expected '' to match the value). The first try at A was a NO-OP: the tool refused it with 'the replacement count moved 1 -> 1' because the replacement was a substring of the anchor, and no test ran. It was re-run with the disjoint replacement --filter=PKG. B, the orchestration refusal disabled: blob -> 8aa89fa2f3d7 gave 2 failed / 6 passed ('expected +0 to be 1'; 'not to contain DEV-SCRIPT-RAN'). C, watch without allowNo: blob -> ff4c7ee5f149 gave 2 failed / 6 passed (the parse throws; 'expected 2 to be 1'). All three turned red, as predicted. UNIT:pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2gave 'Test Files 2 failed | 235 passed (237) / Tests 3341 passed | 29 skipped'. Both failures were prerequisite refusals: 'packages/cli is not built (./dist/index.js is absent)' in published-subpath-console.pin and published-subpath-hook-body.pin. Afterpnpm --filter @objectstack/cli buildthose two gave 'Test Files 2 passed (2) / Tests 29 passed (29)'. TYPECHECK:pnpm --filter @objectstack/cli typecheckexited 0, with 'check:test-typecheck: OK ... 3 file(s) / 28 error(s)'. That is the ledger's existing figure, and the new test is inside the tsconfig.test.json program. INTEGRATION TIER beyond the pin: declared to CI, because the diff touches no integration-tier file other than the new pin, and no spawn entry. E2E BY HAND: the no-watch app-todo boot printed 'Server is ready' and no watching line. The control boot printed 'watching objectstack.config.ts, src'. The matching-filter control (os dev @objectstack/verify) ran tsc -w until the timeout (exit 124). LINT:pnpm lintexited 0 at c36db55 ('VERDICT command-exit 0').",
"mcp_calls": "0 — no MCP GitHub tool was called; reads were REST GETs, writes went through the scripts/pm relay",
"api_writes": "3 — each one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (#20839, draft, read-back 6974 bytes identical); (2) label-write assign -> POST /repos//issues/20839/assignees (huangyiirene, read-back MATCHES); (3) this os-dev-report -> POST /repos//issues/20681/comments. git push is not a REST write and is not counted",
"open_questions": [
{
"question": "The claim carries 'Clause-②: no'. It does not carry the (narrowing) arm, and this PR copies it verbatim. Two behaviours move toward refusal. First,os dev PKGwhose filter selects nothing used to exit 0 having started nothing, and now exits 1. Second, monorepo mode now needs pnpm 8.13.1 or later for--fail-if-no-match. Does the at-tier review keep the bareno, or re-grade itno (narrowing)(BREAKING)?",
"options": [
"A: keep bare 'Clause-②: no' with the cli patch. The refused runs were silent no-ops, and pnpm 8.13.1 dates from 2023.",
"B: re-grade as 'no (narrowing)'. That makes the changeset minor with a breaking marker, and it needs an ADR-0087 disposition line."
],
"recommendation": "A. On the business-need axis, the only run newly refused on a current pnpm is one that started nothing and reported success. That is the defect this card fixes, not a contract anyone relies on. On the long-term axis, pnpm stays the one owner of its filter grammar. On the AI-error axis, a loud exit 1 naming the value is what stops an agent from reading--watch=falseas success. On the scope axis, a breaking grade would add a migration section for a no-op population. The pnpm-version floor is stated in the changeset either way."
}
],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed — content/docs/deployment/cli.mdx, the os dev options table, omits -w/--[no-]watch, --[no-]restart, --log-level, --preset, --admin-email and --admin-password. Pre-existing, no pin enumerates that table, and it is outside the claim's file surface. In the PR's Acceptance notes.",
"carrier: none (承接者:无) · noted, not filed, unmeasured — monorepo orchestration mode forwards none of dev's other flags (--port, --fresh, --ui, --artifact with a PACKAGE) and says nothing about dropping them. This PR refuses only --no-watch, the flag it made reachable. In the PR's Acceptance notes."
],
"gates": "dispatch-gates --repo objectstack-ai/objectstack --commands (no paths) at c36db55 derived 63 commands. The dispatch snapshot had 49; the new families are adr-0087-registration, empty-changeset, release-rehearsal-clone self-test, cli-test-child-env, engine-double-contract, objectql-double-limit, objectui-changeset, pm-changeset-deadline-census, query-options-erasure and others that the committed diff adds. 63/63 exited 0. check:dual-build-cjs-loads and check:i18n-coverage first exited 3 with PREREQUISITE NOT MET (unbuilt packages) and exited 0 on re-run once those dists existed. The--ranfile carries per-line exit codes and read 'Run reconciliation — 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN' ('a DERIVED zero'). check:nul-bytes exited 0, and a manual control-byte scan of the 3 files found no hits. pnpm lint (full, not narrowed) exited 0 at c36db55. PR CI at 10:50Z: in_progress, 31 check runs (11 success, 3 skipped, 17 in_progress); not awaited.",
"deviations": [
"Added the orchestration-mode --no-watch refusal. It is not in the triage text. Making --no-watch reachable (triage point 1) would otherwise have printed 'Watch: enabled' under it and run the watchers, so it is must-fix under 'the round's change makes it false'. It stays inside dev.ts, which is in the claimed surface.",
"Extracted the watchActive expression into the exported devWatchActive, so the pin drives the real decision with oclif's parse. This is a small refactor inside dev.ts.",
"The first try at ablation leg A was a no-op (the tool refused it; no tests ran). It is declared and was re-run with a disjoint replacement.",
"The harness moved gate chunk 43-63 to the background after the 600 s foreground window. I waited on its PID in the foreground (tail --pid) and read its results file. Nothing was left running.",
"Commit trailers use the dispatch's model-free pair, and the PR body uses the AGENTS.md session-URL footer. The harness attribution reminder asked for a model-named Co-Authored-By and a different PR footer; neither was used, per AGENTS.md.",
"Answered the PM status probe with one SendMessage line, then continued.",
"Cleanup: dev servers were all stopped (killed by their own timeouts, no leftovers in ps). node_modules was removed, andgit worktree remove ../objectstack-issue-20681exited 0 without --force."
],
"files_changed": [
"packages/cli/src/commands/dev.ts",
"packages/cli/test/dev-no-watch.pin.test.ts",
".changeset/20681-dev-no-watch.md"
]
}objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsACCEPT: PR #20839 at
c36db550(os dev --no-watchreaches the watch opt-out; a PACKAGE that selects nothing fails loudly)domain:cliseat ·session_01VvcEokUG1tvVxkceYfR5XB· 2026-09-30T11:38Z- Contract review of record:
5910400468on the PR,CONTRACT_REVIEW_TIER, headc36db550, PASS. It answers the dev's open question: bareClause-②: nowithpatch(option A).- A PACKAGE that selects nothing was never inside the door's declared value set ("Package name or filter pattern"; start development mode). Refusing it pulls the door back to its contract, the pattern of PR fix(runtime,metadata-protocol): the /automation write doors keep the packaged-base lock the /meta door keeps (#20679) #20817.
- The new pnpm 8.13.1 floor sits below every pnpm the repo has declared.
- Seat verification on adoption, at merge-base
73155fedc:- the root
packageManagerispnpm@10.31.0; @objectstack/cli'sexportsmap is closed to.,./console,./hook-bodyand./package.json;packages/cli/src/index.tsre-exports onlydefault as DevCommandfrom./commands/dev.js.- So the new named export
devWatchActivedoes not reach the published surface.
- the root
- Checklist:
- Draft, base
main, first lineFixes #20681, andClause-②: noat line start. No other closing keyword. - 3 files, +257 / −4, all in the claim's surface:
packages/cli/src/commands/dev.ts, one pin and one changeset. - Changeset:
@objectstack/clipatch. check-governed-merges --pr 20839: NOT governed, 261 changed lines.- 34 check-run names on the head: 31 success and 3 skipped (path-filtered or opt-in).
- Draft, base
- Deviations: seven, each answered in the record. The one behavioural addition, refusing
--no-watchin monorepo orchestration mode, refuses only argv that was an exit-2 parse error before, and it stays indev.ts. - Out-of-scope findings and the record's escalations:
- The
os devoptions table incontent/docs/deployment/cli.mdxomits--[no-]watch,--[no-]restart,--log-leveland--preset: not filed. It is pre-existing, and the page promises less than the CLI delivers. No one is editing that page, so the filing gate names no reader who acts. oclif's--helprenders--[no-]watch. Acceptance notes. - Monorepo orchestration mode forwards none of dev's other flags: unmeasured, so not filed. The filing gate asks for a measured reach first. Acceptance notes.
- The changeset's "Monorepo mode now needs pnpm 8.13.1 or later" is broader than the diff: the flag is passed only with a PACKAGE. It errs in the conservative direction, and a prose edit would move the head, so it stays. Acceptance notes.
- A pnpm below the floor fails loudly, but without naming the floor. Declaring shell-out floors mechanically is a repo-wide question, not this card's. Noted, not filed.
- The
- Next: land through the queue. At the merge, the seat closes this card if the
Fixesdoes not, and removespm:dispatched.
Generated by Claude Code
- Contract review of record:
objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsLanded: PR #20839 →
c90f9fb6e2(os dev --no-watchturns watch off; a PACKAGE matching nothing fails loudly)domain:cliseat ·session_01VvcEokUG1tvVxkceYfR5XB· 2026-09-30T11:59Z- Landing reading:
c90f9fb6e21809430db13371d8929a21e6787a8dis onorigin/mainas a single-parent squash over688ddef3c. Content:git diff --statof the PR headc36db550againstc90f9fb6over the PR's 3 files is empty.packages/cli/src/commands/dev.tsonorigin/mainnamesfail-if-no-matchon 2 lines, against 0 at the parent. - Queue note: the head's third-party
Vercelstatus stayedpending("deploying") from 10:03Z. On the other heads today it resolved to "Canceled by Ignored Build Step" within a minute. It is not a required context, and the queue took and merged the PR regardless. - Closure: the merge did not close this card by itself (the same reading as the other queue merges today). The seat closes it as
completedand removespm:dispatchedin the same act.
Generated by Claude Code
- Landing reading:
- added a commit that references this issue
on Oct 7, 2026
What.
packages/cli/src/commands/dev.tsdeclareswatch: Flags.boolean({ char: 'w', description: 'Enable watch mode (default)', default: true })with noallowNo(:187onmain). Three other flags in the same command do setallowNo: true. The code downstream expects an opt-out:watchActiveisflags.watch !== false && …(:383);:699-700).No argv reaches that opt-out.
Measured. The #20649 dev (report on #20649, out-of-scope finding) ran
tsx bin/run-dev.jsat17e3b7eadb:os dev --no-watchanswers "Nonexistent flag: --no-watch" and exits 2.os dev --watch=false, in a project directory, parses as--watchplus the positional PACKAGEfalse. It prints "📦 Package: false", "🔄 Watch: enabled" and "$ pnpm --filter false dev", then "No projects found in …". It exits 0 with nothing started.domain:specseat 5 re-read the flag declaration, thepackagepositional (:183),watchActiveand the comment onmainat6c11ef9ecb. It did not re-run the CLI.Reach. This is the public
objectstack devcommand. A user who wants to turn watch mode off gets either a refusal or a silent no-op that exits 0.Open. Whether to add
allowNo: true, which makes--no-watchthe spelling, or to drop the opt-out text and term. This card does not choose.Filed by
domain:specseat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) from the #20649 dev report. It is unlabelled, for triage; the file ispackages/cli/**.Dedupe words:
dev watch flag allowNo no-watch·dev --watch=false package positional false·watchActive opt-out unreachable