Repository navigation
Conversation
EvidenceBase: Local gate: New regression tests ( Base/head proof: disposable checkout at base with only the behavioral change reverted → all 6 tests fail for the intended reasons (no ceiling, no reasons, no env override); at head all 6 pass. Focused suites at head: startup-budget + startup-race 31 passed; lifecycle + ensuring + explicit-lifecycle 77 passed; registration-owner + daemon-entrypoint + help 79 passed. Existing lifecycle/startup-race tests keep their meaning (15 s budget pinned via Live route proof: |
|
Size Report
Startup median (7 runs, lower is better):
|
There was a problem hiding this comment.
All reported issues were addressed across 8 files
You’re at about 98% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Integration Tests failed at This is a PR defect, not a known CI flake. I assigned a lifecycle fix with red/green verification through the three failing integration tests. The leak oracle stays active. I did not rerun CI. The preview comment needs no action. The Size report shows +3.2 kB unpacked. The independent review must assess whether a smaller design can meet #3782. Review and repair are in progress; the PR is not ready. |
|
I checked all six cubic claims against
The current Apex repair worker now owns these items with the integration cleanup defect. This keeps one editor on the PR. Independent review continues. Threads remain open until a verified fix or assessment is posted. |
|
Independent review of The current repair worker owns these findings with the integration cleanup defect. It must also split the startup responsibility from The reviewer treats the long gap between phases as a risk, not a demonstrated defect. Completed-phase markers can improve observability. A heartbeat must not make stuck work appear to progress. The reviewer ran 270 daemon-client tests and the focused registration, entrypoint, close, and help suites. They passed at the reviewed head. This does not replace the failed Integration Tests lane. A new independent review and CI pass are required after repair. The PR remains not ready. |
…ts owner
The integration leak oracle failed because every daemon appended its
startup phase markers to one shared `daemon-startup-phases.jsonl` beside
the registration and nothing retired that file, so any completed launch
left state-dir residue the strict oracle names as a stray entry.
Ownership now follows the file name: each launch writes only to
`daemon-startup-phases-<pid>.jsonl` through
`resolveDaemonStartupPhasesPath(stateDir, pid)`. The writing daemon
removes its file once it has registered; the launching client removes it
once that process's exit is joined (in `retireStartupAttempt`, after the
exit is observed, never before); and each new registration-lock owner
sweeps the files of provably dead pids next to the shutdown-report
removal. A live pid's file is always kept, so a concurrent or replaced
launch can neither add to, hide behind, nor delete another launch's
evidence, and the client no longer needs `spawnedAtMs` to attribute
markers to its own launch.
Along the protocol boundary:
- `recordDaemonStartupMarker` takes an optional `reportFailure` callback
so producers surface a refused append on stderr (the daemon log tail
the waiting client already ships as failure evidence) instead of
swallowing it; the append stays non-fatal and a crash-truncated final
line is separated so it cannot glue two records together.
- The phase list gains real completed boundaries, `composition-loaded`
and `recovery-finished`, and no heartbeats, so silence still means a
stalled startup and progress extends the stall window exactly as far
as the work took.
- The launch-exit join drops its redundant `.catch(() => {})`: the
`runCmdDetachedMonitored` owner resolves the promise on error and
exit, so it never rejects.
- Startup code splits out of `daemon-client-lifecycle.ts` into
`daemon-client-startup.ts` (budget, wait loop, marker refresh, hints),
keeping both modules under the 1000-line tripwire; importers attach
and ensure point at the owning module directly.
Regression coverage: the budget suite now pins per-launch attribution,
including a fresh daemon producing its own markers while an earlier
launch's leftover file is swept at the new registration, and a new
protocol suite pins the per-pid paths, the dead-pid sweep, removal
idempotence, and the write-failure seam.
Refs #3782, #3791
The documented reasons overclaimed. `startup-ceiling` said "progressing, not registered before the ceiling", but the ceiling is reached by a daemon that is merely alive: a progressing one is only ever stopped by a ceiling above the stall window, so the promise was unverifiable from the client's evidence. `startup-stalled` named a 60 s window without saying that `AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS` does not change it, so raising the ceiling looked like a fix for silence. Both the CLI help and the configuration table now describe the two reasons as what they are, and the env var is specified as a positive integer number of milliseconds. Refs #3791
Follow-up: the Integration Tests leak failure on this PR is fixed (a2c6e74)Cause. The daemon wrote its #3782 startup phase markers to a single shared Fix — ownership follows the file name. Each launch writes only Red→green. Review threads.
Also in this push. Startup code split out of |
There was a problem hiding this comment.
All reported issues were addressed across 12 files (changes from recent commits).
You’re at about 98% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
The lifecycle and startup module headers only narrate each file's role, which AGENTS.md reserves for public APIs, tool directives, and constraints code cannot show. The split is owned by the imports and the file names. Fixes review thread PRRT_kwDORFGHaM6tkpef on #3791.
…or it The shared emit-startup-markers flag file applied to every later fixture in the same state dir, so the stale-history cleaner inherited the request, wrote its own live marker, and the sweep assertion raced it. The request is now a typed per-child option bound into that child's entry script, and readiness waits use a per-pid file so a stale registration-held from an earlier child cannot shortcut the await. Fixes review thread PRRT_kwDORFGHaM6tkpeV on #3791.
… exit A launch that exited busy, unproven, or lost the registration to a contending winner returned its retry, error, or winner handoff without joining its exact exited child, so the child's pid-named phase file sat in the state dir until some later registration sweep. Every terminal child outcome now joins the child first and removes only that child's own file, the same ownership rule a retired startup follows; the current winner's registration and record are untouched. Regression tests write markers at the real pre-acquisition producer seam (new emitStartupMarkerBeforeAcquisition fixture option) and pin the residue rule on the retry, winner-attach, and unproven-exit paths: red at the prior head, green with the fix. Fixes review thread PRRT_kwDORFGHaM6tkpec on #3791.
The per-pid file names its writer, not its lifetime: if client and daemon of an old launch both died before either cleanup ran and the host reused the pid, the old record survived under the new writer's name, the sweep skipped it as live, and the earliest-per-phase reader mixed two lifetimes into one observation. The producer now claims its own record (claimDaemonStartupPhasesFile) before its first marker, so stale same-pid content can neither mask nor extend the fresh startup's progress. A refused claim follows the marker contract: reported, never fatal. The test child repeats the real producer sequence against its own pid, which no outside test can arrange. Addresses review finding R2-1 on #3791.
describeStartupPhaseTimings builds a Record<string, number> that always starts at spawned: 0; the intersection cast asserted what the literal already showed. No caller branched on it. Addresses review finding R2-2 on #3791.
There was a problem hiding this comment.
All reported issues were addressed across 12 files (changes from recent commits).
You’re at about 98% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Repairs at head Causes & fixes
Validation: Threads: peV/pec/pev fixed+resolved; marker-unavailable j3DD stays open — stall retirement still applies when the marker channel is unobservable; no exemption claimed. Pending: full CI at this head (Integration Tests, Coverage, native, device lanes are GitHub-owned), and the independent review of a2c6..62a09. Not ready for merge. |
|
Coverage failed at This is a PR regression, not a coverage-percentage failure or a known flake. The active repair worker will reproduce the tests with the same CI base and correct the import boundary. The budgets and assertions remain unchanged. I did not request a rerun. The PR remains not ready. |
registeredDaemonFixtureArgs rewrote one shared dist/src/internal/ daemon.js per construction, so a second build could replace the script before an earlier launched child loaded it, silently applying the wrong per-child marker switches and registration fields. Each construction now writes a unique fixture-entries/<uuid>/dist/src/internal/daemon.js: the per-launch directory keeps the daemon entry path shape the retirement identity checks require, and cleanup still removes the state dir. A regression test builds both arg sets before launching either child and proves child 1 executes its own switches while child 2 exits busy: red on the shared path, green per-launch. Fixes review thread PRRT_kwDORFGHaM6tk7ed on #3791.
The split moved the helpers next to the runtime but left a static edge, so both daemon entries evaluated one more module and 12-15 more top-level statements than the merge-base (Coverage lane red: 3 eager-closure-budgets failures at OUTPUT_ECONOMY_BASE=4a8abed7b9). startDaemonRuntime now loads them through a function-scoped await import at its first use point, the loading shape the gate prescribes; composition, publication, flush, and shutdown order are unchanged and the source-order guards still read them from this module. Red at 62a09bd (3 failures), green here: 846/846. Addresses the eager-closure failure reported at 62a09bd on #3791.
|
Repairs at head Causes & fixes
Validation: Threads: tk7ed fixed+resolved; peV/pec/pef fixed (replies at Pending: CI at this head (Coverage/Integration/native/device GitHub-owned) and independent review of the two new commits. Not ready for merge. |
|
At 62a09bd, one defect remains in the startup wait. When another live daemon holds the lock and has not published yet, the client waits to the ceiling and reports the wrong reason. In Not blocking, and you can take or leave each: the production marker emitters in Coverage failed at 62a09bd, likely because On the open threads: the two cubic-dev-ai P2 threads do not apply, so please resolve them. The first is #3791 (comment): Before merge, please make every wait that reaches the ceiling with a live startup pending report 'startup-ceiling' and add the failing-on-head test. Then get Coverage green at the head, and attach the measurement #3782 rule 3 asks for. That is the 'Preflight iOS runner through public CLI' step log from a run at this head, after |
The prepare step's daemon_startup diagnostic is not a cold-startup measurement: the CLI's ensured transport finishes ensureDaemon before sendToDaemon's timer wraps the attach connect, so the timer only sees an attach. Time the public ensureDaemon() directly after clean:daemon and record phase, durationMs, started, and pid, so the record counts as cold only when started is true. The prepare command keeps its original semantics and attaches to the same daemon. Corrects the measurement assumption behind 62a09bd on #3791; the cold-startup CI evidence for #3782 is still missing until a run reports this record with started:true.
|
CI measurement correction at head Cause: the prepare step's Fix: after Local proof (isolated temp state dir): cold run Validation: Pending: one iOS CI run here reporting |
|
Independent review found no actionable findings in I reviewed the workflow-only change I verified receipt |
|
Required checks pass at The raw iOS job log records a fresh public SDK start after {"phase":"daemon_cold_startup","durationMs":324,"started":true,"pid":60517}This is one successful CI sample. It does not establish the maximum startup time on overloaded hosts. The CLI diagnostic measured an attach after startup, so it cannot supply this cold-start evidence. The maintainer review identifies one remaining defect. If our contender exits busy while a verified live winner still starts, the deadline can produce The PR remains not ready until the repair, independent review, exact-head gate, and new-head CI pass. No merge requested. |
Repair: live startup at the ceiling reports
|
There was a problem hiding this comment.
All reported issues were addressed across 12 files (changes from recent commits).
You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
The code now looks good at 8ccb661, and both findings from the earlier review (#3791 (comment)) are fixed. CI shows 20 checks with none failing, and I know of no conflicts. I did not run the suite myself. Could you also show a cold start that goes past 60 s between recorded phases and still succeeds, with the phase markers in the output, so we know the progress-aware budget works on the slow path? The CI cold-start log from the iOS job covers only the fast path. Not blocking: the headline test in daemon-client-startup-budget.test.ts only rewrites Could the startup progress records live in their own daemon-contracts module, such as The two earlier inline threads on the |
A client killed a healthy daemon that was still starting: the local startup used one 15 s wall-clock deadline, and a timeout never retried. On an overloaded host that is a failed run before any work starts (#3782, failure class #3342). - startLocalDaemon now waits while the spawned daemon stays alive, up to a 120 s ceiling; AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS overrides it for the CLI, MCP, and Node client alike. - The daemon records startup phase markers (modules-loaded, lock-acquired, listening, registered) with timestamps in daemon-startup-phases.jsonl beside its registration. A live daemon that publishes no marker for 60 s is retired as stalled; one that keeps progressing is waited for to the ceiling. - Failure details carry reason (startup-exited, startup-stalled, startup-ceiling), the observed phase timings, and the effective startupTimeoutMs. Each reason has its own hint. - help commands documents the variable and the three reasons.
…ts owner
The integration leak oracle failed because every daemon appended its
startup phase markers to one shared `daemon-startup-phases.jsonl` beside
the registration and nothing retired that file, so any completed launch
left state-dir residue the strict oracle names as a stray entry.
Ownership now follows the file name: each launch writes only to
`daemon-startup-phases-<pid>.jsonl` through
`resolveDaemonStartupPhasesPath(stateDir, pid)`. The writing daemon
removes its file once it has registered; the launching client removes it
once that process's exit is joined (in `retireStartupAttempt`, after the
exit is observed, never before); and each new registration-lock owner
sweeps the files of provably dead pids next to the shutdown-report
removal. A live pid's file is always kept, so a concurrent or replaced
launch can neither add to, hide behind, nor delete another launch's
evidence, and the client no longer needs `spawnedAtMs` to attribute
markers to its own launch.
Along the protocol boundary:
- `recordDaemonStartupMarker` takes an optional `reportFailure` callback
so producers surface a refused append on stderr (the daemon log tail
the waiting client already ships as failure evidence) instead of
swallowing it; the append stays non-fatal and a crash-truncated final
line is separated so it cannot glue two records together.
- The phase list gains real completed boundaries, `composition-loaded`
and `recovery-finished`, and no heartbeats, so silence still means a
stalled startup and progress extends the stall window exactly as far
as the work took.
- The launch-exit join drops its redundant `.catch(() => {})`: the
`runCmdDetachedMonitored` owner resolves the promise on error and
exit, so it never rejects.
- Startup code splits out of `daemon-client-lifecycle.ts` into
`daemon-client-startup.ts` (budget, wait loop, marker refresh, hints),
keeping both modules under the 1000-line tripwire; importers attach
and ensure point at the owning module directly.
Regression coverage: the budget suite now pins per-launch attribution,
including a fresh daemon producing its own markers while an earlier
launch's leftover file is swept at the new registration, and a new
protocol suite pins the per-pid paths, the dead-pid sweep, removal
idempotence, and the write-failure seam.
Refs #3782, #3791
The documented reasons overclaimed. `startup-ceiling` said "progressing, not registered before the ceiling", but the ceiling is reached by a daemon that is merely alive: a progressing one is only ever stopped by a ceiling above the stall window, so the promise was unverifiable from the client's evidence. `startup-stalled` named a 60 s window without saying that `AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS` does not change it, so raising the ceiling looked like a fix for silence. Both the CLI help and the configuration table now describe the two reasons as what they are, and the env var is specified as a positive integer number of milliseconds. Refs #3791
The lifecycle and startup module headers only narrate each file's role, which AGENTS.md reserves for public APIs, tool directives, and constraints code cannot show. The split is owned by the imports and the file names. Fixes review thread PRRT_kwDORFGHaM6tkpef on #3791.
…or it The shared emit-startup-markers flag file applied to every later fixture in the same state dir, so the stale-history cleaner inherited the request, wrote its own live marker, and the sweep assertion raced it. The request is now a typed per-child option bound into that child's entry script, and readiness waits use a per-pid file so a stale registration-held from an earlier child cannot shortcut the await. Fixes review thread PRRT_kwDORFGHaM6tkpeV on #3791.
… exit A launch that exited busy, unproven, or lost the registration to a contending winner returned its retry, error, or winner handoff without joining its exact exited child, so the child's pid-named phase file sat in the state dir until some later registration sweep. Every terminal child outcome now joins the child first and removes only that child's own file, the same ownership rule a retired startup follows; the current winner's registration and record are untouched. Regression tests write markers at the real pre-acquisition producer seam (new emitStartupMarkerBeforeAcquisition fixture option) and pin the residue rule on the retry, winner-attach, and unproven-exit paths: red at the prior head, green with the fix. Fixes review thread PRRT_kwDORFGHaM6tkpec on #3791.
The per-pid file names its writer, not its lifetime: if client and daemon of an old launch both died before either cleanup ran and the host reused the pid, the old record survived under the new writer's name, the sweep skipped it as live, and the earliest-per-phase reader mixed two lifetimes into one observation. The producer now claims its own record (claimDaemonStartupPhasesFile) before its first marker, so stale same-pid content can neither mask nor extend the fresh startup's progress. A refused claim follows the marker contract: reported, never fatal. The test child repeats the real producer sequence against its own pid, which no outside test can arrange. Addresses review finding R2-1 on #3791.
…n out of the runtime Code ownership allows no exception: behavior was added to a module over 1000 lines, so the module is split at its existing boundary first. flushDaemonStartupDiagnostics, emitDaemonDiagnostic, finishDaemonRegistration, and armDaemonMetadataLossWatch form the daemon-log diagnostic and registration-completion edge the runtime already treats as one unit; they move with their callers updated, no behavior change. daemon-runtime.ts is back under the limit.
describeStartupPhaseTimings builds a Record<string, number> that always starts at spawned: 0; the intersection cast asserted what the literal already showed. No caller branched on it. Addresses review finding R2-2 on #3791.
registeredDaemonFixtureArgs rewrote one shared dist/src/internal/ daemon.js per construction, so a second build could replace the script before an earlier launched child loaded it, silently applying the wrong per-child marker switches and registration fields. Each construction now writes a unique fixture-entries/<uuid>/dist/src/internal/daemon.js: the per-launch directory keeps the daemon entry path shape the retirement identity checks require, and cleanup still removes the state dir. A regression test builds both arg sets before launching either child and proves child 1 executes its own switches while child 2 exits busy: red on the shared path, green per-launch. Fixes review thread PRRT_kwDORFGHaM6tk7ed on #3791.
The split moved the helpers next to the runtime but left a static edge, so both daemon entries evaluated one more module and 12-15 more top-level statements than the merge-base (Coverage lane red: 3 eager-closure-budgets failures at OUTPUT_ECONOMY_BASE=4a8abed7b9). startDaemonRuntime now loads them through a function-scoped await import at its first use point, the loading shape the gate prescribes; composition, publication, flush, and shutdown order are unchanged and the source-order guards still read them from this module. Red at 62a09bd (3 failures), green here: 846/846. Addresses the eager-closure failure reported at 62a09bd on #3791.
The prepare step's daemon_startup diagnostic is not a cold-startup measurement: the CLI's ensured transport finishes ensureDaemon before sendToDaemon's timer wraps the attach connect, so the timer only sees an attach. Time the public ensureDaemon() directly after clean:daemon and record phase, durationMs, started, and pid, so the record counts as cold only when started is true. The prepare command keeps its original semantics and attaches to the same daemon. Corrects the measurement assumption behind 62a09bd on #3791; the cold-startup CI evidence for #3782 is still missing until a run reports this record with started:true.
…at the deadline When the launched contender exited busy while another live daemon held the registration and deferred publication, the wait loop ended in an unlabeled 'timeout' result that mapped to startup-exited with the generic hint. Any deadline with a live startup still pending, this client's launch or a verified live lock owner, now reports startup-ceiling with the effective ceiling and the overload hint; startup-exited stays reserved for a real exit or no live startup. Remove the 'timeout' wait kind so the unlabeled state cannot exist and add the sendToDaemon-boundary regressions for both outcomes. Also compress this PR's narration and duplicate test setup to keep the gross diff within one coherent change, and add the Unreleased changelog entry for the startup budget, the stall window, and the three reasons.
…nd pid identity At an expired deadline, a delivered child exit is authoritative for the lifetime it watched, so it outranks an unobserved liveness probe of a pid that may have been reused. Unobserved, the launch's recorded birth time must prove the pid changed hands before it counts as a live startup; an unavailable identity stays fail-closed. Extracted classifyExpiredDaemonStartup keeps the wait loop within its complexity thresholds. The budget test pins liveness of its fabricated pids at the process seam instead of trusting the host, and the winner-sweep race coverage is deduplicated into the joined contender test.
…ore the marker sweep owner Both facts were stated incompletely against the code: - resolveDaemonStartupTimeoutMs runs only inside startLocalDaemon, so AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS is validated only when a client must start a daemon. A client that attaches to or reuses a running daemon never reads the variable. CHANGELOG, cli-help, and the configuration guide now say so; the guide already named INVALID_ARGS. - The startup-marker ownership comment dropped the registration owner's sweep of provably dead pids, which sweepDeadDaemonStartupPhasesFiles still performs at each new registration lock acquisition. Addresses review threads r4305110030 and r4305299946 on #3791. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The startup split moved observeLocalDaemon out of daemon-client-lifecycle.ts, so the host test's lifecycle-module mock no longer stopped the ensure path and the CLI-run case fell through to the real observation. Mock the seam the subject imports it from now. Drop two narration comments the assertions already state. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The per-pid startup phase file has its own record format, writer, reader and dead-pid sweep, so it no longer belongs inside the registration owner the review pointed at (#3791). The declarations move verbatim into daemon-contracts/daemon-startup-phases.ts beside daemon-shutdown-report and the suffix-named markers test follows them as daemon-startup-phases.test.ts. Registration acquisition imports only sweepDeadDaemonStartupPhasesFiles; the runtime, the daemon entry, the client wait and the fixture import the record owner directly, with no re-export shim (unreleased surface). The daemon entry must write its earliest modules-loaded marker at module load, so the eager-closure gate gets one APPROVED_CLOSURE_ADDITIONS row naming the new module; the entry pays for the record it writes first. Addresses review 6248815887 item 1 on #3791. Refs #3782, #3791
Importers attach to daemon-contracts/daemon-startup-phases directly; daemon-registration-owner keeps only the sweep call at acquisition. src/daemon.ts captures its host environment once and resolves the phases path from the same env and cwd startDaemonRuntime resolves its state dir from, so a relative AGENT_DEVICE_STATE_DIR cannot land the earliest markers beside a different directory than the registration (the module top-level second resolveDaemonPaths(process.env) is gone), and the modules-loaded marker stays the first thing recorded. Addresses review 6248815887 items 1 and 2 on #3791. Refs #3782, #3791
The headline slow-start test rewrote lock-acquired repeatedly; the reader keeps each phase's earliest timestamp, so those writes never advanced progress and the run spanned only 20 s against the 60 s stall window. It now schedules four distinct phases (modules-loaded, composition-loaded, lock-acquired, recovery-finished) across 70 s of virtual time under a 150 s ceiling and asserts the wait survived on observed successive progress. With the marker read removed, the same scenario fails as startup-stalled at the 60 s window (verified with a throwaway stub, not committed), so the test is credibly red without the progress rule. Addresses review 6248815887 item 3 on #3791. Refs #3782, #3791
8ccb661 to
d22edfe
Compare
|
Round-8 repair pushed at Review responses: (1) phase records moved to Both prior inline threads remain resolved. Exact-head gate |
|
Rebased and pushed at The review follow-up separates startup records into The revised test advances four distinct phases across 80 seconds of virtual time. Disabling marker reads makes it fail. A gap beyond 60 seconds without progress intentionally stalls. This unit result does not prove a real slow-host cold start. The prior 330 ms CI sample remains evidence only for The exact-commit gate passed ( Gross diff: 1,827 added and 673 removed lines across 22 files. The PR is not ready yet. |
|
Independent review at I accepted two low-severity corrections:
The worker will also remove one introduced blank line in the changelog. One small repair round is active. The reviewer independently ran the 80-second virtual test and made it fail with marker reads disabled. It also reproduced the HarmonyOS test's host-environment failure and its pass with the three SDK variables unset. The relevant files match the base. Real slow-host cold-start evidence remains unavailable. The virtual test is unit evidence. CI and review of the repaired head remain required. |
…prove the default ceiling The help and configuration docs claimed only a progressing daemon reaches a ceiling above the stall window. On the contended path this client's launch exits busy and the wait runs on the exit branch, where the stall check never runs, so a live startup owned by another client reaches the ceiling with no observed progress. Qualify the clause to this client's own launch, matching the CHANGELOG definition. The no-marker budget test stubbed 120000 instead of unsetting the variable, so it never proved the default. Unset it (stubEnv with undefined) so the resolved ceiling is the unoverridden default even on a host that exports the variable. Also drop a stray blank line in the Unreleased list.
|
Round-8 fixes at
Gate: |
|
Independent review is complete at I compared the four-file repair with reviewed head The prior independent review verified the rebase, owner extraction, host environment, smaller design, and 80-second virtual progress test. Those code paths are unchanged by this repair. The default test also fails when the default changes to Receipt CI at this head is still required. Real slow-host cold-start evidence remains unavailable; the 80-second result is unit evidence. The 60-second window without progress is unchanged. |
Summary
Closes #3782. Startup previously killed healthy daemons after 15 seconds on loaded hosts (#3342). CLI, MCP, and Node now share a 120-second ceiling and a 60-second window without progress.
The setting requires positive integer milliseconds. Invalid values fail with
INVALID_ARGSbefore spawn, only when a daemon must start. Attach and reuse ignore it. Typed reasons distinguishstartup-exited,startup-stalled, andstartup-ceiling. A live competing startup is preserved. One startup-record module owns the format, writer, reader, and sweep. Scope: 22 files, 1,827 added and 673 removed lines.Validation
Head
0295ee5f23; base0fb25c474a. Repairs: the ceiling prose is scoped to the client's own launch (another client's live startup can reach the ceiling without observed progress), the no-marker budget test unsets the variable instead of stubbing 120000 so the default ceiling is proven against host overrides, and a stray CHANGELOG blank line is gone. Same 22 files, gross 2,500.Receipt
run-Q4YXDqpassed:exactCommit=true,checkoutChanged=false; 36 checks passed, 25 skipped, 2 deduplicated. Host HarmonyOS SDK variables were unset (env -u DEVECO_SDK_HOME -u HDC_SDK_PATH -u HARMONYOS_COMMAND_LINE_TOOLS); that hdc test is unchanged here and fails only with those exports present. Independent review is complete. No findings remain. CI is pending.The headline test advances four distinct phases across 80 seconds of virtual time under a 150-second ceiling; disabling marker reads makes it fail. This is unit evidence; the CI cold start measured 330 ms at
8ccb661. No real slow-host result beyond 60 s is claimed.