Skip to content

feat: structural diffs for definition migration hooks (friction #5)#28

Merged
ehabterra merged 2 commits into
mainfrom
fingerprint-diff
Jul 15, 2026
Merged

feat: structural diffs for definition migration hooks (friction #5)#28
ehabterra merged 2 commits into
mainfrom
fingerprint-diff

Conversation

@ehabterra

Copy link
Copy Markdown
Owner

Summary

Friction log #5 — the migration hook could only see two opaque fingerprint hashes, so hosts approved every definition upgrade blindly, unable to distinguish "new transition added" from "place renamed". Now the mismatch says what changed.

Mechanism: every save stamps a compact definition shape — sorted place names plus a short hash of each transition's structural record (the same fields the fingerprint covers) — under the reserved __workflow_def_shape context key (a few hundred bytes; stripped on load like the fingerprint). On a mismatch, the handler receives a DefinitionMismatch:

  • WorkflowID, StoredFingerprint, CurrentFingerprint
  • Diff *DefinitionDiff — places and transitions added / removed / changed, by name. A renamed place reads as remove+add with its referencing transitions marked changed — exactly the shape a reviewer needs.
  • Diff.Additive() makes "new structure only, approve mechanically" a one-line policy; Diff == nil for state saved by pre-shape versions ("no information", not "no change").

⚠️ Breaking (pre-1.0): DefinitionMigrationFunc is now func(ctx context.Context, mm workflow.DefinitionMismatch) error. The fingerprint hash itself is unchanged (Fingerprint() refactored to share the per-transition record with the shape).

Dogfood proof: approval is now a policy instead of blind trust — additive changes pass mechanically (logged with the diff), non-additive expense-net changes are refused loudly, the payment net's anchor removal keeps its explicit migratePaymentAnchor migration, and nil-diff state approves with the loader's place validation as backstop.

Tests: additive add (place+transition, asserted through the hook), removal + guard change (non-additive, by name), rename shape with exact String() output, nil diff for pre-shape rows, reserved-key leak checks.

Roadmap milestone

Post-M5 friction-log-driven feature #5 — with it, every library item in the friction log's ranked list is shipped.

Checklist

  • gofmt -s -l . prints nothing
  • go vet ./... passes
  • go test -race ./... passes (root + examples, run serialized)
  • CHANGELOG.md updated under [Unreleased] (Added + Breaking)
  • Docs/examples only describe behavior the engine can actually execute

🤖 Generated with Claude Code

The migration hook could only see two opaque fingerprint hashes, so hosts
approved every definition upgrade blindly — unable to distinguish "new
transition added" from "place renamed". Now the mismatch says WHAT changed:

- every save stamps a compact definition SHAPE (sorted place names + a
  short hash of each transition's structural record — the same fields the
  fingerprint covers) under the reserved __workflow_def_shape context key,
  stripped on load like the fingerprint
- on mismatch the handler receives a DefinitionMismatch: workflow ID, both
  fingerprints, and a DefinitionDiff — places/transitions added, removed,
  changed, by name; a renamed place reads as remove+add with referencing
  transitions marked changed; Diff.Additive() is the one-line "new
  structure only" policy; Diff is nil for pre-shape state (no information,
  not no change)
- BREAKING: DefinitionMigrationFunc now takes (ctx, DefinitionMismatch)
  instead of (ctx, id, stored, current) — pre-1.0, documented in CHANGELOG
- Fingerprint() refactored to share the per-transition record with the
  shape (hash unchanged)
- dogfood: the hook's approval is now a policy — additive changes pass
  mechanically, non-additive expense-net changes are refused loudly, the
  payment net's anchor removal keeps its explicit migration, and nil-diff
  (pre-shape) state is approved with the loader's place validation as
  backstop
- tests: additive add, removal+guard-change, rename shape (+String()),
  nil diff for pre-shape rows, reserved-key leak checks

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@ehabterra, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 37b5c82e-8154-4182-97d5-da0e608cbf19

📥 Commits

Reviewing files that changed from the base of the PR and between 506b664 and 7753a00.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • definition.go
  • diff.go
  • diff_test.go
  • docs/roadmap/FRICTION.md
  • examples/expense_approval/README.md
  • examples/expense_approval/app.go
  • m3_test.go
  • manager.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fingerprint-diff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CI's staticcheck flags dereferencing d after `d := mm.Diff; if d == nil {
t.Fatal }` — it doesn't credit t.Fatal as terminating in this shape. Check
mm.Diff first, assign after, matching the sibling tests it doesn't flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.61702% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.29%. Comparing base (506b664) to head (7753a00).

Files with missing lines Patch % Lines
manager.go 77.77% 2 Missing and 2 partials ⚠️
diff.go 96.29% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #28      +/-   ##
==========================================
+ Coverage   80.89%   81.29%   +0.40%     
==========================================
  Files          29       30       +1     
  Lines        3057     3128      +71     
==========================================
+ Hits         2473     2543      +70     
  Misses        366      366              
- Partials      218      219       +1     
Files with missing lines Coverage Δ
definition.go 100.00% <100.00%> (ø)
diff.go 96.29% <96.29%> (ø)
manager.go 84.87% <77.77%> (+0.16%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ehabterra
ehabterra merged commit f03268d into main Jul 15, 2026
6 checks passed
@ehabterra
ehabterra deleted the fingerprint-diff branch July 15, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant