test: round-2 coverage hardening (edge, runtime, generative consensus) + edge reconnect fix#9
Merged
Merged
Conversation
Adds tests/consensusProperties.test.ts: a property-based suite that runs many randomized iterations against a fresh LocalTransport book cluster (3- and 5-node), driving valid randomized book commands through the current leader and periodically crashing/restarting nodes to force re-elections. After the cluster heals it asserts the Raft safety invariants: state convergence across live nodes, committed-log agreement up to the shared commit index, and determinism (replaying the committed command sequence into a fresh state machine reproduces the converged state). Randomness is a hand-rolled seeded mulberry32 PRNG (no new deps); each iteration prints its seed and SEED=<n> replays a single case for reproducibility. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
…ches
Add focused unit tests for under-tested runtime files, hitting their
uncovered error/edge branches without duplicating the existing suites:
- canonicalUnit: 'throw' vs 'drop' undefined modes, nested structures,
key-order independence.
- shardRouterUnit: empty-shard guard, out-of-range RangeError,
NoShardLeaderError rejection, collectMetrics with a leaderless shard
(driven by fake ShardNode stubs, no clusters/timers).
- keyedModuleUnit: name/command validation, reserved __ names, strict
vs { strict: false } lint paths.
- projectionUnit: defineProjection name/init/on/queries validation.
All four target files reach 100% stmt/branch/func/line coverage.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Add explicit coverageReporters (text-summary + text + lcov) and a CI step that uploads coverage/ per Node matrix leg, so reviewers can inspect per-PR coverage (lcov.info + HTML report) without rerunning locally. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Tooling parks git worktrees under .claude/, each a full copy of this suite; without this, `jest` globs into them and multiplies test discovery. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Claude Code parks agent worktrees and local state under .claude/; it should never be committed. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
…/keyedModule/projection
Add tests/edgeStreamSource.test.ts driving HttpStreamSource against a stub Node http SSE server (snapshot->entry->caughtup ordering, multi-chunk frames, malformed/comment/unknown frames, clean-end and abrupt-reset disconnects, non-200/401-403 statuses, https routing, and the close() teardown contract), plus EventSourceStreamSource via an injected in-memory EventSource double (URL/token building, open/snapshot/entry/caughtup dispatch, bad-payload onError, error self-close + suppression, close() idempotency, missing-ctor throw, and global-EventSource fallback). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
HttpStreamSource only listened for res 'end' and req 'error'. An abrupt mid-stream socket reset (RST / socket.destroy) makes Node emit 'aborted'/'close' on the response WITHOUT 'end', so the drop was swallowed and the replica silently stalled instead of reconnecting. Listen for 'aborted'/'close' too, collapsing all termination paths to a single onError via a streamDone guard (and a no-op after an intentional close()). Surfaced by the new tests/edgeStreamSource.test.ts coverage; the abrupt-reset test now asserts the single onError fires. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Only retry NotLeaderError / 'node stopped' (the genuine churn transients) in the submit loop; rethrow any other error so a real regression surfaces instead of degrading into a low-commit run. Bump the per-test timeout to 45s for slow-CI headroom. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
After the follow-up tests (edge stream sources, runtime units, generative consensus suite), coverage is ~90.4/76.7/90.7/92.3. Raise the global floor to 88/74/88/90 to lock the gains in. Documents why a single global bucket is used rather than per-path floors (jest subtracts glob-matched files from global). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Per review: send the 401/403 and non-200 onError calls through fail() too, so "exactly one terminal onError ever" is a single uniform invariant (and a late close on the drained response can't double-fire). Note the aborted/close redundancy is intentional belt-and-suspenders across Node versions. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
Dev-only, not in the default test/CI gate: `yarn test:mutation` runs Stryker scoped (via coverageAnalysis perTest) to a small pure module by default, reusing jest.config.js. Measures test effectiveness, not just reach — the initial canonical.ts run scored ~94% and surfaced a few survivable mutants in the 'drop'-mode branch. ADR-0024 documents the dev-only exception to ADR-0013; Stryker output is git-ignored. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_0159Rma834V7wPgft7fzoFtg
naveed949
marked this pull request as ready for review
June 23, 2026 04:51
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Follow-up to #8, working through the "what's next" list. Built with parallel implementer + reviewer agents in isolated git worktrees (3 implementers, 3 reviewers), then integrated here. Suite grew 273 → 347 tests; coverage 90.4% stmt / 76.7% branch / 90.7% func / 92.3% line (up from 88.5/73.4/89.7/90.5).
What's included
tests/edgeStreamSource.test.ts, 19 tests) —HttpStreamSourceagainst a stub SSE server +EventSourceStreamSourcevia an injected double: frame parsing, split frames, malformed payloads, auth/non-200, all termination paths.httpStreamSource75→100% stmt,eventSourceStreamSource80→100% stmt.src/edge/httpStreamSource.ts): an abrupt socket reset emitsaborted/close(notend), which the source ignored — soEdgeReplicasilently stalled instead of reconnecting. Now surfaced as a singleonErrorvia astreamDone/closedguard (all termination paths routed through onefail()).tests/runtime/{canonical,shardRouter,keyedModule,projection}Unit.test.ts) — drove those four files to 100% statements and branches (from 76/74/78/64%).tests/consensusProperties.test.ts) — seeded mulberry32 (no new deps) randomized command streams + leader-crash churn over LocalTransport clusters, asserting the Raft safety triple: state convergence, committed-log agreement up to the shared commit index, and replay determinism. Reproducible viaSEED=<n>; verified to exercise real re-elections and that assertions are sensitive (not vacuous)..claude/worktrees and.claude/is git-ignored.yarn test:mutation, Stryker) — dev-only, not in the CI gate, scoped to a small module by default (ADR-0024 documents the dev-only exception to ADR-0013). Initialcanonical.tsrun scored ~94%, surfacing a few survivable mutants — test-strength signal coverage alone can't give.Reviewer notes addressed
NotLeaderError/'node stopped'(real regressions now surface), +timeout headroom.Known gap (intentional)
The 2s
READ_BARRIER_TIMEOUTbranch remains unit-untested —lastAppliedadvances beforeapply(), so the only trigger is a racy partition of a lagging follower mid-ReadIndex. Forcing it cleanly needs a test-onlysrcseam; adjacent fail-closed paths are already covered. Documented indocs/TEST_COVERAGE.md.Test plan
tsc --noEmitclean;yarn test347/347 green;yarn test:coveragepasses thresholds on the new floor;yarn test:mutationruns Stryker (~94% on the scoped module). Generative suite verified stable across repeated runs.🤖 Generated with Claude Code