refactor(cli): centralize process lifecycle#2171
Conversation
57ef434 to
a24f174
Compare
2b8ae85 to
f941ffb
Compare
34ec519 to
53132dd
Compare
f941ffb to
35f4007
Compare
53132dd to
df7dfef
Compare
165f2e1 to
7fe2537
Compare
df7dfef to
608548d
Compare
7fe2537 to
eb0930b
Compare
b3ce98b to
f593708
Compare
0b30fbc to
e2cd043
Compare
f593708 to
6408d4b
Compare
e2cd043 to
fad0f25
Compare
d9d9868 to
53fee32
Compare
|
Fixed the fresh-head lifecycle CI failures on
Fresh exact-head CI is running. |
miguel-heygen
left a comment
There was a problem hiding this comment.
The process-ownership refactor is structurally sound and the focused lifecycle/usage/ownership tests pass, but one blocking telemetry regression remains.
Verdict: REQUEST_CHANGES
Reasoning: Exact-head command failures are reported twice, which corrupts the cli_error signal this path is meant to preserve.
-- Magi
|
Addressed Magi’s P1 on exact head
Validated locally: focused command-failure/CLI-boundary tests, CLI ownership check, typecheck, full lint, and full CLI suite (2,075 passed; 2 skipped). Fresh exact-head CI is running. |
1 similar comment
|
Addressed Magi’s P1 on exact head
Validated locally: focused command-failure/CLI-boundary tests, CLI ownership check, typecheck, full lint, and full CLI suite (2,075 passed; 2 skipped). Fresh exact-head CI is running. |
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head 73d3b4e1f491e5211a960bac86fbb674909be7ad against live main (6ad738b580adf157393fde02351af64669c9fbc5).
Audited: packages/cli/src/cli.ts, utils/commandResult.ts, utils/command-failure-tracking.ts and their focused tests, recursive usage resolution, and the AST ownership checker. I mechanically checked the command migration for remaining direct process.exit / process.exitCode writes. Trusting: the individual command bodies beyond their lifecycle substitutions, backed by the green exact-head CLI/full CI matrix.
The central result contract is a strong boundary: commandResult.ts:60-85 cleanly separates fatal signals, non-fatal exit status, and root-owned forced termination. The recursive wrapper also preserves leaf unknown-flag validation while propagating the original failure unchanged (command-failure-tracking.ts:34-70).
blocker — packages/cli/src/cli.ts:450: await the sole failure reporter before finalizing telemetry. reportCommandFailure() is async because it lazy-imports telemetry/events.js before enqueuing the cli_error (packages/cli/src/utils/command-failure-tracking.ts:80-83), but the new executable-boundary call drops its promise. Control immediately reaches finalizeCli() at line 460, which flushes the queue and marks finalized = true; if the lazy import settles afterward, the error is queued after the only async flush and the exit fallback returns early because the CLI is already finalized. The prior wrapper explicitly awaited this operation for exactly that reason. This can turn the fixed duplicate signal into an intermittently missing signal, especially for fast failures such as unknown flags. Please await reportCommandFailure(command, error) and add a boundary test that defers the reporter and proves flush/finalization happens only after the error is enqueued; the current source-count assertion proves one call site, not delivery ordering.
All exact-head required checks are green, and the focused ownership/result/wrapper tests pass; they do not exercise this ordering.
Verdict: REQUEST CHANGES
Reasoning: The duplicate reporter is removed, but the remaining sole reporter is not awaited before the one-shot telemetry flush, so cli_error delivery is still not reliable.
— Magi
|
Fixed Magi’s telemetry-ordering P1 on exact head
Validated locally: targeted lifecycle test; CLI typecheck; process-ownership gate; full lint; full CLI suite (2,076 passed; 2 skipped); P1-file formatting and diff checks. The repository-wide format check remains blocked only by the preserved unrelated |
Fallow audit reportFound 21 findings. Duplication (12)
Health (8)
Suppressions (1)
Generated by fallow. |
miguel-heygen
left a comment
There was a problem hiding this comment.
Exact-head re-review at a9338a4e0f91b8482fe32bef50018209c29ce031.
Audited: the complete two-file delta from the previously reviewed 73d3b4e1f head (packages/cli/src/cli.ts and the new packages/cli/src/cli.lifecycle.test.ts), plus exact-head required CI. Trusting: the restacked 76-file lifecycle migration previously reviewed; its tree is unchanged apart from this focused fix.
The telemetry-ordering P1 is resolved. executeCli() now awaits the sole lazy reportCommandFailure() call before entering finalizeCli(), so the final flush cannot run before cli_error is queued. The regression deliberately stalls the telemetry-events import, proves no flush occurs while reporting is blocked, then verifies cli_error precedes flush; this covers the asynchronous failure mode rather than merely counting source call sites.
All 8 required exact-head checks are green: Build, Test, runtime contract, Typecheck, regression, Windows tests/render, and semantic title. The non-required Fallow audit reports inherited stack findings outside this two-file delta.
Verdict: APPROVED — the blocker is fixed with direct lifecycle-ordering coverage and exact-head CI proof.
— Magi

What
Centralize CLI process termination and error signaling at the executable boundary.
Why
Command handlers wrote process.exit/process.exitCode directly, which made cleanup, telemetry finalization, testing, and machine-readable errors inconsistent.
How
Introduce CommandResult, CliUsageError, CliRuntimeError, and CliResultSignal. Route termination through cli.ts, preserve finalizers, and enforce ownership with an AST-based repository check.
Test plan