Skip to content

feat(serve): add recurring pattern detection endpoint (GH-318)#371

Merged
fagemx merged 2 commits intomainfrom
feat/318-pattern-detection
Mar 27, 2026
Merged

feat(serve): add recurring pattern detection endpoint (GH-318)#371
fagemx merged 2 commits intomainfrom
feat/318-pattern-detection

Conversation

@fagemx
Copy link
Copy Markdown
Owner

@fagemx fagemx commented Mar 27, 2026

Summary

  • Add GET /api/patterns endpoint for detecting recurring governance patterns in village decisions
  • Implement detect_village_patterns() in edda-ledger with three SQL-based pattern types: recurring decisions, chief repeated actions, and rollback trends
  • Include trend direction detection for rollback patterns (comparing first half vs second half of window)

API

GET /api/patterns?village_id=xxx&lookback_days=7&min_occurrences=3

Returns PatternDetectionResult with detected patterns array.

Files Changed

File Change
crates/edda-ledger/src/sqlite_store.rs Add pattern types + detect_village_patterns() + 5 tests
crates/edda-ledger/src/ledger.rs Delegation method
crates/edda-serve/src/lib.rs Route + handler + 2 HTTP tests

Test plan

  • 5 ledger unit tests (recurring, chief, rollback, below-threshold, empty village)
  • 2 HTTP endpoint tests (success path, missing village_id 400)
  • cargo fmt --check passes
  • cargo clippy -p edda-ledger -p edda-serve --all-targets passes
  • No regressions in affected crates

Closes #318

🤖 Generated with Claude Code

@fagemx
Copy link
Copy Markdown
Owner Author

fagemx commented Mar 27, 2026

Code Review: PR #371 (Round 1)

Summary

Adds GET /api/patterns endpoint for detecting recurring governance patterns in village decisions. Three SQL-based pattern types are implemented: recurring decisions, chief repeated actions, and rollback trends. Overall solid implementation with good test coverage.

Key Findings

Critical Issues (P0)

None.

High Priority (P1)

  1. Dead code in detect_trend_direction (sqlite_store.rs:3440-3454)

    • after_date and last_date are computed but never meaningfully used. The else branch at line 3453 is unreachable when dates.len() >= 2 (which is the guard at line 3436), so sorted.get(mid) will always return Some. The let _ = (after_date, last_date) is just suppressing unused-variable warnings. Should be cleaned up.
  2. New types not re-exported from edda-ledger/src/lib.rs (line 21-24)

    • DetectedPattern, PatternType, and PatternDetectionResult are pub in sqlite_store.rs but not re-exported in lib.rs, unlike peer types (BundleRow, DecisionRow, ChainEntry, etc.). The serve code uses edda_ledger::sqlite_store::PatternDetectionResult instead of edda_ledger::PatternDetectionResult. Inconsistent with project conventions.
  3. Trend direction logic bias with duplicate dates

    • When all rollback dates fall on the same day (common in burst scenarios), detect_trend_direction reports true (trending up) because first_half=0 and second_half=N. This is technically correct per the comparison operator (< vs >= on midpoint), but semantically misleading — "trending up" should mean the frequency is increasing over time, not that events are concentrated. Consider returning false when all dates are equal.

Testing Review

Coverage

  • 5 ledger unit tests covering all three pattern types, below-threshold, and empty village -- good
  • 2 HTTP endpoint tests (success path, 400 for missing village_id) -- good
  • No unit test for detect_trend_direction edge cases (same day, single date, truly trending dates)

Convention Compliance

  • Tests follow project patterns: real SQLite, tempfile, inline #[test]
  • Serde attributes follow skip_serializing_if convention
  • Error handling uses ? propagation correctly

Testing Verdict: Adequate

Verdict: Changes Requested

Fixing P1 issues and will re-review.


Round 1 of automated review-fix loop

@fagemx
Copy link
Copy Markdown
Owner Author

fagemx commented Mar 27, 2026

Code Review: PR #371 (Round 2) — LGTM 🎉

All P0 and P1 issues have been resolved.

Summary

The pattern detection endpoint is well-implemented with clean SQL queries, proper error handling, and good test coverage (5 ledger + 2 HTTP = 7 tests). Fixes applied in round 2:

  • Dead code removed: Unused after_date/last_date variables and unreachable else branch cleaned from detect_trend_direction
  • Types re-exported: DetectedPattern, PatternType, PatternDetectionResult now available via edda_ledger:: (consistent with BundleRow, DecisionRow, etc.)
  • Trend logic improved: Same-day rollback bursts no longer report as "trending up"

All 256 tests pass (159 ledger + 97 serve), clippy clean, fmt clean.

Verdict: LGTM ✅

No critical or high-priority issues remaining. This PR is ready for merge.


Completed after 2 round(s) of automated review-fix loop

fagemx and others added 2 commits March 27, 2026 12:28
Add GET /api/patterns endpoint to detect recurring governance patterns
within a village's decisions. Three pattern types are detected:
- recurring_decision: same key changed >= N times in window
- chief_repeated_action: same authority+key >= N times
- rollback_trend: supersession chains with trend direction

Query params: village_id (required), lookback_days (default 7, max 90),
min_occurrences (default 3, min 2).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rn types

- Remove dead code (unused after_date/last_date and unreachable else branch)
- Return false for duplicate dates (burst != trend)
- Re-export DetectedPattern, PatternType, PatternDetectionResult from lib.rs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fagemx fagemx force-pushed the feat/318-pattern-detection branch from b6f05f0 to 768df4b Compare March 27, 2026 04:29
@fagemx fagemx merged commit 0ee21c2 into main Mar 27, 2026
7 checks passed
@fagemx fagemx deleted the feat/318-pattern-detection branch March 27, 2026 04:38
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.

feat(analysis): add recurring pattern detection for governance events

1 participant