Skip to content

test: cover null-action guard and isolate explanation test fixtures#81

Merged
jayzalowitz merged 1 commit into
mainfrom
jayzalowitz/test-polish
Apr 26, 2026
Merged

test: cover null-action guard and isolate explanation test fixtures#81
jayzalowitz merged 1 commit into
mainfrom
jayzalowitz/test-polish

Conversation

@jayzalowitz

Copy link
Copy Markdown
Owner

Summary

Two follow-ups surfaced during the post-merge review of #78:

  • Cover the unreachable `!action` guard. `assertValidExecutionInputs(null, ...)` was added in test(safety): lock policy-check-blocks-execution invariant #78 but had no test (TypeScript guarantees the branch is unreachable in practice). Defensive code on a safety boundary deserves a test so future refactors can't silently delete it.
  • Isolate explanation test fixtures. Seven describe blocks in `explanation-generator.test.ts` shared a single `InMemoryExplanationRepo` declared at `describe` scope. `repo.saved` accumulated across `it()` calls. No current assertion notices, but a future "save called once" test would inherit cross-contamination. Converted to per-test `beforeEach`.

The larger gaps from #78 (e2e tests, partial-block leak in `whatWouldIDo`, blocked-by-policy ExplanationRecord persistence) are tracked separately in #80.

Test plan

  • `pnpm --filter @skytwin/execution-router test` — 67/67 (was 66, +1)
  • `pnpm --filter @skytwin/explanations test` — 30/30 (same count, now isolated)
  • `pnpm test` (full repo) — all turbo tasks succeed
  • `pnpm lint` — clean

🤖 Generated with Claude Code

Two follow-ups from the post-merge review of #78:

- Add the missing test for assertValidExecutionInputs(null, ...). The
  branch is unreachable via TypeScript, but defensive code on a safety
  boundary deserves a test so future refactors can't silently delete it.
- Convert the seven shared-fixture describe blocks in
  explanation-generator.test.ts from module-level const to per-test
  beforeEach. Saved records no longer accumulate across it() calls in
  the same describe, so future "save called once" assertions won't
  inherit cross-contamination.

Net new tests: +1. Existing tests still 30/30 explanations, now
67/67 execution-router.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 26, 2026 21:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens test reliability around safety-boundary invariants and eliminates cross-test state contamination in explanation generator unit tests.

Changes:

  • Adds a unit test covering the defensive “null CandidateAction” guard in ExecutionRouter.executeWithRouting.
  • Refactors multiple ExplanationGenerator test suites to use per-test setup (beforeEach) instead of sharing a single in-memory repo instance across it() calls.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/explanations/src/tests/explanation-generator.test.ts Switches shared repo/gen instances to beforeEach initialization to prevent fixture state leakage across tests.
packages/execution-router/src/tests/execution-router.test.ts Adds coverage for the unreachable-in-practice null-action invariant guard in executeWithRouting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const assessment = makeRiskAssessment();
await expect(
router.executeWithRouting(null as unknown as CandidateAction, assessment, 'user-1'),
).rejects.toThrow(/without a CandidateAction/);

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test title says it throws an InvariantViolationError, but the assertion only matches the error message regex. Consider also asserting the thrown error is an instance of InvariantViolationError (or using rejects.toThrow(InvariantViolationError)), so the test can’t pass due to some other unexpected error with a similar message.

Suggested change
).rejects.toThrow(/without a CandidateAction/);
).rejects.toBeInstanceOf(InvariantViolationError);

Copilot uses AI. Check for mistakes.
@jayzalowitz jayzalowitz merged commit 85f25ee into main Apr 26, 2026
12 checks passed
@jayzalowitz jayzalowitz deleted the jayzalowitz/test-polish branch April 26, 2026 21:21
jayzalowitz added a commit that referenced this pull request Apr 27, 2026
…h work (#87)

Captures eight PRs (#77, #78, #79, #81, #82, #83, #84, #85, #86) under
an [Unreleased] section. No code changes — pure documentation.

Bumping VERSION + cutting a tag is left as a separate decision so the
release moment stays explicit.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants