Skip to content

Harden occurrence pipeline, strengthen type design#33

Merged
yairfalse merged 2 commits into
mainfrom
fix/review-findings
Mar 3, 2026
Merged

Harden occurrence pipeline, strengthen type design#33
yairfalse merged 2 commits into
mainfrom
fix/review-findings

Conversation

@yairfalse
Copy link
Copy Markdown
Collaborator

Summary

  • Fix silent data loss in occurrence pipeline: Replace overbroad rescue with explicit error handling — Occurrence.new failures raise with diagnostics, persist/2 errors are logged, all LogEmitter return values are checked
  • Strengthen type invariants: Add @enforce_keys to Result and Events, narrow strategy from atom() to :direct | :canary | :blue_green, add Result.rolledback/5 factory, define NodeKind.t() type
  • Close test gaps: Fix conditional if File.exists? assertion in integration test, add build_entity edge case tests, persist error path test, clean up leaked emitter processes

What was found

Four review agents (code reviewer, silent failure hunter, type design analyzer, test coverage analyzer) identified 17 issues ranging from critical silent data loss to minor type narrowing. All addressed in this PR.

Test plan

  • 265 tests passing, 0 failures (+5 new tests)
  • mix compile --warnings-as-errors clean
  • mix format --check-formatted clean
  • mix credo — no new issues (pre-existing Logger metadata warnings only)
  • Sykli pre-commit: all 5 tasks green

🤖 Generated with Claude Code

Replace overbroad rescue in generate_occurrence with explicit error
handling for each failure mode (Occurrence.new, persist, LogEmitter).
Add @enforce_keys to Result and Events, narrow strategy type from
atom() to :direct | :canary | :blue_green, add Result.rolledback/5
factory, add NodeKind.t() type, and fix start_log_emitter typespec.

Remove unreachable execute_strategy fallback, add emit_status_log
catch-all, check all LogEmitter return values, and log disabled
emitter events at debug level.

Fix conditional assertion in integration test, add tests for
build_entity edge cases, persist error path, and Result enforce_keys.
Clean up leaked emitter processes in OccurrenceLogTest.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 hardens the deployment occurrence pipeline and tightens type invariants across deploy results, events, and graph nodes, while adding tests to cover edge cases and prior silent-failure paths.

Changes:

  • Replace overbroad exception handling around occurrence generation with explicit error handling and improved diagnostics/logging.
  • Strengthen type invariants via @enforce_keys, narrower strategy types, a rolledback/5 result constructor, and a dedicated NodeKind.t() type.
  • Expand test coverage for malformed resource inputs, occurrence persistence failure paths, integration assertions, and emitter process cleanup.

Reviewed changes

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

Show a summary per file
File Description
test/nopea/occurrence_test.exs Adds edge-case tests for entity building and a persist error-path test.
test/nopea/occurrence_log_test.exs Ensures emitter processes are stopped on test exit to prevent leaks.
test/nopea/deploy_integration_test.exs Makes occurrence-file assertion unconditional to avoid silent pass.
test/nopea/deploy/result_test.exs Adds tests for rolledback/5 and @enforce_keys behavior.
lib/nopea/occurrence.ex Makes Occurrence.new/… failure explicit (raise) and widens start_log_emitter/1 spec to include error tuples.
lib/nopea/graph/node_kind.ex Introduces NodeKind.t() as a constrained type.
lib/nopea/graph/node.ex Narrows Node.kind type to NodeKind.t().
lib/nopea/events/emitter.ex Logs a debug message when emission is ignored due to disabled emitter.
lib/nopea/events.ex Adds @enforce_keys to event struct for stronger invariants.
lib/nopea/deploy/spec.ex Narrows Spec.strategy type to the constrained Result.strategy().
lib/nopea/deploy/result.ex Adds strategy type, enforces required keys, and adds rolledback/5 constructor.
lib/nopea/deploy.ex Improves occurrence persistence handling and checks LogEmitter return values with explicit logging.

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

Comment thread lib/nopea/graph/node.ex
id: String.t(),
name: String.t(),
kind: atom(),
kind: NodeKind.t(),
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Node.t/0 now narrows kind to NodeKind.t(), but new/3 is still spec’d as taking atom() and is only guarded by is_atom(kind) (with a runtime NodeKind.valid?/1 check). To keep the public types consistent for Dialyzer/docs, update @spec new/3 (and ideally the guard) to accept NodeKind.t() rather than atom().

Copilot uses AI. Check for mistakes.
Align the @SPEC with the struct type — new/3 accepts NodeKind.t(),
not atom(). Addresses Copilot review comment on PR #33.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yairfalse yairfalse merged commit 8d12b2c into main Mar 3, 2026
0 of 2 checks passed
@yairfalse yairfalse deleted the fix/review-findings branch March 3, 2026 02:53
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