feat(decisions): durable decision log + overridable tracker receipts - #3
Merged
Conversation
BEFLOW-12 — harden the decision log against concurrent writers: - Add atomic append() to the RunStoreFs contract; LocalNdjsonSink.emit now does a single O_APPEND write instead of read-modify-write, so two runs racing on decisions.ndjson can no longer clobber each other's events. - Add readDecisionEvents() that recovers from a torn trailing line without dropping earlier valid events. BEFLOW-9 — surface every governed decision as a receipt comment: - New TrackerCommentSink (behind the existing DecisionSink contract) and CompositeSink pairing the durable NDJSON log with a best-effort tracker comment; ordered [local, tracker] so the audit write lands first. - Receipt body is a user-overridable prompt template (decision-receipt.md) riding the existing prompts.dir cascade — not a forced format. - Gated by decisions.comment (default on); tracker and template failures are logged, never fatal. Tests enforce the fixes: a spy proving emit never read-then-writes, a cross-process O_APPEND no-loss test, torn-line recovery, and receipt render/override/gating coverage.
- comment readDecisionEvents as the durable read path consumed by predictive preflight (BEFLOW-18) so the not-yet-wired export reads as staged foundation, not dead code - rename the single-process sink test to state what it verifies (two instances accumulate, never clobber); real concurrency is the cross-process test below it - isDecisionEvent: drop the per-line shallow-copy allocation in favor of in-operator narrowing
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.
What
Two related changes to beflow's decision-sink layer (BEFLOW-10 governance roadmap), both behind the existing
DecisionSinkcontract — no schema change.BEFLOW-12 — durable decision log
The decision log is beflow's audit record; it must survive concurrent runs.
LocalNdjsonSink.emitused unlocked read-modify-write, so two runs racing ondecisions.ndjsoncould clobber each other's events.append()to theRunStoreFscontract;emitnow does a single O_APPEND write.readDecisionEvents()that recovers from a torn/partial trailing line without dropping earlier valid events.BEFLOW-9 (PR1 slice) — surface decisions as tracker receipts
TrackerCommentSink+CompositeSinkpairing the durable NDJSON log with a best-effort tracker comment, ordered[local, tracker]so the audit write lands first.decision-receipt.md) riding the existingprompts.dircascade — not a forced format.decisions.comment(default on). Tracker and template failures are logged, never fatal.Tests
The tests enforce the fixes rather than just smoke them:
emitnever read-then-writes (fails against the old code),bun run check(oxfmt + oxlint + tsc + bun test): 1036 pass / 0 fail.Not in this PR
Receipt-aware gate evaluation (using the receipt to influence allow/block) remains open on BEFLOW-9 as follow-up.