feat(test): stateful lifecycle replay for the contract matrix (#218 stage 2) - #309
Conversation
🦋 Changeset detectedLatest commit: 54557e6 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54557e6d28
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| client.setNotificationHandler('notifications/progress', (notification) => { | ||
| if (notification.params.progressToken === progressToken && !settled) liveProgress += 1; | ||
| }); |
There was a problem hiding this comment.
Preserve the caller's progress notification handler
When a lifecycle fixture runs against the caller-owned packed session, each transition replaces the client's existing notifications/progress handler, and the final replacement remains installed after runPackedContractMatrix returns. A caller that registered a progress listener and then reuses the still-open session will silently stop receiving progress because the retained closure only counts the last lifecycle token while unsettled. Collect lifecycle progress without permanently overwriting the caller's handler, or restore/compose the handler when replay finishes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Summary
Stage 2 of the #218 contract matrix: stateful lifecycle replay across both existing boundaries, riding the single packed journey.
ContractRouteFixture.lifecycle: a project-supplied deterministic transition driver walks one tool throughunknown → queued → running → first-progress → repeated-progress → terminalover the matrix's one open client connection; the framework owns transport, phase order, per-phase structured-content/rendered-output validation, per-phase additive/closed compat probing, and module-backed serialized round-trips where the boundary can load route modules (honestnot-applicableat packed, stage-1 reasoning).notifications/progressreceived before settlement; a fixture that stops emitting progress fails thelive-progress-before-terminalcheck (negative test included).lifecycleroute-harness tool (mounteddefineState, workspace-durable):state-journal(sequential events accumulate),state-notice(declared notice observable at terminal),state-idempotency(same idempotency key replays without double-apply, same revision),state-budget(a commit pastmaxEventBytesfails typedbudget-exceededat the commit boundary with revision unchanged).restart-durability: a caller-owned same-storerestartcallback (in-memory reopens the same sqlite store; packed reuses the existing packed journey's process restart — no second pack/build). Without a callback the check is honestlynot-applicable.Deferred (recorded on #218): state-lifetime catalog /
WarmRuntimeIdentityidentity assertions depend on #269; restart proves same-artifact same-store durability, not artifact-rebuild replay (stage 4 / #179 territory).Gates (local, rebased on 0560c75)
pnpm build·pnpm typecheck·pnpm lint(0/0) ·pnpm test:unit(2568 passed; one unrelatednative-claude-contract5s timeout under full-suite load, passes in isolation) ·pnpm test:route-unit(24) ·pnpm test:projection(58) ·pnpm test:packed(26 passed / 1 skipped) — packed journey unchanged in count, extended in assertions.