You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Automatic map creation must yield to user work and recover consistently across readiness changes, retries, process replacement, and shutdown.
Summary and scope
Add the complete bootstrap and user-input coordinator over the durable store: evidence-first turn generation, FIFO input, readiness and completion correlation, preemption, and recovery. Server activation follows in the next stack increment.
Emit recovery metadata only after its state commits, avoiding contradictory duplicate lifecycle events. Injection failure retains the correct retryable recovery state.
How this increment fits
The complete bootstrap state machine is tested as one unit over part 5 storage and part 4 input delivery. Server activation and old-path removal stay together in part 7.
Stack and review boundary
Part 06 of 15 in the Agent Map review stack; review this increment against its predecessor.
Root checks ran against c3023e9e643e21ccc503969243666faa081e3462. The final head changes only README terminology or commit ancestry; a complete tracked-file comparison confirms identical executable source and build inputs. The terminology gate was rerun on d10f6055f0d6c7336a46593c304cecfbddf0ef9c.
Regression coverage: FIFO user input, initial-input precedence, readiness and completion correlation, durable recovery, preemption, failed injection, and shutdown fencing.
See part 15 for integrated browser, native CLI, and Mac journey validation. The checks above were run independently on this PR’s own commit.
Linux tests run with ordinary user filesystem permissions; the sandbox's extra ambient capabilities are dropped. Hosted CI and automated review are separate from these recorded local results.
Compatibility and release impact
Compatibility: Internal coordinator groundwork. Existing server startup remains active until the next increment.
No secrets, credentials, private user data, or unsanitized logs are included.
This PR does not publicly disclose a suspected vulnerability.
AI assistance
Codex assembled the implementation, addressed reproduced defects, supplied tests and documentation, inspected the diff, and ran the checks above. Reviews are handled by hosted PR automation.
Checklist
Read CONTRIBUTING.md; implementation follows the requested 15-PR split.
Description reflects this PR's actual predecessor-relative diff.
Relevant tests accompany the changed behavior.
Root build, typecheck, lint, and test evidence matches the final implementation; any documentation-only update is identified above.
Release/documentation treatment is explained above.
Scope reviewed: .changeset/bootstrap-coordinator.md, packages/harness/src/core/project-bootstrap.ts, packages/harness/src/core/project-bootstrap.test.ts. No frontend files in the diff, so the component-hygiene
section does not apply. No confidentiality leaks found: no third-party company names, business arrangements,
private hostnames, or internal links in any prose surface; SAP-#### in the legacyStateRoot JSDoc matches
existing repo convention (packages/tools/**, packages/tools/CHANGELOG.md). Test fixtures are excluded from
the tarball by tsconfig.build.json.
Findings
1. Boot recovery emits an error code that contradicts the state it just persisted — project-bootstrap.ts:1524
In register()'s boot-recovery branch, the persisted classification is chosen at :1493:
but the lifecycle event at :1524 is hardcoded to errorCode: "delivery_timeout", retryable: false, and it is
gated on !shouldRetry — which additionally requires session.ready && session.status === "running".
Failure scenario: process is killed mid-attempt with the attempt at phase claimed/not-submitted
(bootstrap.status === "generating" on disk), retryCount < MAX_RETRIES, no queued inputs. On restart the
session is restored but not yet ready (readiness arrives later via onSessionStatus), so shouldRetry is
false. The durable state and session.projectBootstrap say injection_failed / retryable: true, while the
emitted project_bootstrap.failed says delivery_timeout / retryable: false. Any onEvent consumer —
analytics, and whatever surfaces the retry affordance — records a non-retryable delivery timeout for a state
that is retryable and is in fact retried moments later when readiness lands. Not covered by the suite: no test
asserts the lifecycle event for this branch (the injection_failed tests at :1411/:1570 all go through mode: "created" / explicit retry()).
Fix: derive the emitted errorCode/retryable from state.metadata.bootstrap rather than restating them.
2. Same block emits terminal lifecycle events before persist() — project-bootstrap.ts:1514-1533
The skipped and failed emits at :1514 and :1524 run before await this.persist(session.id, state) at :1549. Everywhere else this file is strict about the opposite order and says so in comments
("Release only after the terminal/non-replayable state is durable", :1055; commitTerminalPreemption's
copy-on-write note at :2571).
Failure scenario: the queue-file write fails during boot registration. Consumers have already been told the
bootstrap was skipped/failed for a transition that never committed, and persist()'s fallback path then
emits a second, different project_bootstrap.failed with persistence_failed for the same attempt. On the
next boot the state is re-read as generating and the whole branch — including the emits — runs again.
Fix: move both emits below the persist() call, as commitBootstrapFailureTransition and commitPendingBootstrapFailureTransition already do.
3. Changeset advertises a feature no consumer can reach — .changeset/bootstrap-coordinator.md
Stage the complete bootstrap and user-input coordinator with recovery, FIFO delivery, and shutdown handling.
Automatic bootstrap remains inactive until server integration.
This compiles into packages/harness/CHANGELOG.md and ships in the npm tarball permanently. Nothing imports project-bootstrap.ts (grep: only its own test), it is not re-exported from src/index.ts, and the PR states
activation lands in slot 7 — so an npm consumer reading this line will look for "recovery, FIFO delivery, and
shutdown handling" and find no API, no flag, and no behavior change. "until server integration" is internal
stack sequencing that means nothing outside this repo.
patch is the right level (no reachable surface changes). Rewrite the body for the consumer, e.g. "Internal
groundwork for automatic Agent Map bootstrap. No user-facing change in this release." — and let the release
that activates it carry the feature description.
Nits
project-bootstrap.ts:101 — legacyStateRoot is introduced already @deprecated. If it is only ever set by
internal callers, drop it from the public options type rather than shipping a deprecated option at birth.
Verdict
Request changes: fix the contradictory lifecycle event (1) and the emit-before-persist ordering (2) — both are
in the same ~40-line boot-recovery block — and rewrite the changeset body (3) before this merges, since that
text cannot be retracted after publish.
All three findings from the previous round are fixed, with tests. No new findings.
(1) contradictory lifecycle event — fixed. The recovery emit now derives errorCode/retryable/reason from the committed state.metadata.bootstrap (project-bootstrap.ts:1530-1551); covered by the new claimed/not-submitted cases asserting injection_failed / retryable: true.
(2) emit-before-persist — fixed. Both emits moved below await this.persist(...) (:1529); persist() throws on a failed commit, so nothing is published for an uncommitted transition. The new storage-failure test asserts exactly one persistence_failed event and eventsBeforeCommit is empty in the success test.
(3) changeset — fixed..changeset/bootstrap-coordinator.md now reads as internal groundwork with no user-facing change; patch still correct. No confidentiality issues in the new text.
Not fixed (carried nit, non-blocking)
project-bootstrap.ts:102 — legacyStateRoot still ships @deprecated at birth. The class is not exported from src/index.ts, so this is internal-only; leaving it is fine.
New nits (one line each, non-blocking)
project-bootstrap.ts:1528 — the comment "A failed commit publishes its own persistence failure instead" holds for the failed classification but not the skipped one: isTerminal() is true for skipped, so persist()'s catch emits nothing and just throws. Silence is the right behavior (disk still says generating, so the next boot re-runs recovery) — the comment just overstates.
The persistence_failed event raised from that path carries no attemptId (project-bootstrap-store.ts:1202, only set when the previous bootstrap was generating), so a consumer correlating terminal events per attempt gets an uncorrelated failure for boot recovery.
Verdict
Approve — the push resolved everything raised in round 1; remaining items are non-blocking nits.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Primary change type
Problem and motivation
Automatic map creation must yield to user work and recover consistently across readiness changes, retries, process replacement, and shutdown.
Summary and scope
Add the complete bootstrap and user-input coordinator over the durable store: evidence-first turn generation, FIFO input, readiness and completion correlation, preemption, and recovery. Server activation follows in the next stack increment.
Emit recovery metadata only after its state commits, avoiding contradictory duplicate lifecycle events. Injection failure retains the correct retryable recovery state.
How this increment fits
The complete bootstrap state machine is tested as one unit over part 5 storage and part 4 input delivery. Server activation and old-path removal stay together in part 7.
Stack and review boundary
d10f6055f0d6c7336a46593c304cecfbddf0ef9c; 7,556 changed lines across 3 files, counting additions and deletions including tests.fix/studio-onboarding-followups.Related work
Agent Map checkpoint SAP-3147; relevant work SAP-3148. This packaging follows the maintainer-approved 15-PR split.
Validation
Root checks ran against
c3023e9e643e21ccc503969243666faa081e3462. The final head changes only README terminology or commit ancestry; a complete tracked-file comparison confirms identical executable source and build inputs. The terminology gate was rerun ond10f6055f0d6c7336a46593c304cecfbddf0ef9c.Tests and documentation
Regression coverage: FIFO user input, initial-input precedence, readiness and completion correlation, durable recovery, preemption, failed injection, and shutdown fencing.
See part 15 for integrated browser, native CLI, and Mac journey validation. The checks above were run independently on this PR’s own commit.
Linux tests run with ordinary user filesystem permissions; the sandbox's extra ambient capabilities are dropped. Hosted CI and automated review are separate from these recorded local results.
Compatibility and release impact
.changeset/bootstrap-coordinator.mdSecurity
AI assistance
Checklist