fix: make failed public follow-ups deliverable - #67
Merged
Merged
Conversation
… for any expected type A promised-final obligation whose required work relation ends failed was accepted but never became deliverable: relationLanded/isPublicFollowupReady only treated `failed` as terminal when expected_final.type was failure-outcome, so a pr-merged or report-ready promise whose work failed (or was parked, which has no typed outcome) got stuck in pending-work with no supported path to deliver the owed public reply. relationLanded now treats a failed relation as terminal and deliverable for any expected type, reusing the same failure-deliverable safety check already enforced at accept time (validateWorkEventContract), so the existing consume -> ready -> deliver path works unchanged and the honest text is the accepted failed event's public_safe_outcome.
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.
Intent
"yes" - approving option A for this tasks-axi problem:
In tasks-axi public-followup, a promised-final obligation whose required work relation ends failed (for example a parked or failed task on an expected pr-merged or report-ready final) is accepted as a failed relation but never becomes deliverable: relationLanded/isPublicFollowupReady treat failed as terminal only when the expected type is failure-outcome, and beginDelivery refuses pending-work, so the owed public reply is stuck with no supported path (hit on a real obligation; the operator had to post manually and waive).
Reproduction evidence (real scripts, tasks-axi 0.2.5): seed a pr-merged promised-final bound to a work relation, emit a failed outcome for that work (error_code deliverable), consume, then deliver. Observed: consume prints no "ready" line; delivery state stays pending-work; the relation reads {"state":"failed","last":"failed"}; deliver exits 1 with "obligation ... is still waiting on its bound work; nothing to deliver yet"; nothing is posted. "Parked" has no typed outcome (work outcome types are pr-merged, report-ready, local-main, failed, superseded), so a parked lane can only report failed.
Option A: a failed required relation is terminal and deliverable for any expected type, using the accepted failed event's public_safe_outcome as the honest text, so the existing consume -> ready -> deliver path works unchanged. Add regression tests in tasks-axi.
What Changed
pending-workobligations affected by the old readiness rule toreadyduring normalization while preserving validation for other stale states.Risk Assessment
✅ Low: The change is narrowly scoped, preserves legacy validation outside the authorized migration, and covers both the end-to-end failure path and persisted-record upgrade behavior.
Testing
Targeted public-followup tests passed, and live CLI scenarios confirmed failed pr-merged and report-ready relations become deliverable using their public-safe outcomes, legacy pending-work records self-heal, and unrelated stale pending-work records still fail closed.
Evidence: Failed pr-merged relation through completed delivery
Source: Failed pr-merged relation through completed delivery
Evidence: Legacy state upgrade and stale-state rejection boundary
Source: Legacy state upgrade and stale-state rejection boundary
Evidence: Failed report-ready relation becomes deliverable
Source: Failed report-ready relation becomes deliverable
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed (2) ✅
src/public-followup.ts:1445- The new readiness rule makes previously valid 0.2.5 records unreadable. A non-failure promise with a failed relation was persisted as delivery.state="pending-work"; after upgrading, relationLanded returns true, then normalization rejects that same record as stale at src/public-followup.ts:1107. Because backlog parsing normalizes metadata, ready, duplicate event consumption, and delivery all fail before they can repair the state. The regression at test/commands/public-followup.test.ts:406 only creates the event under the new implementation, so it does not cover the persisted failing sequence. Preserve or migrate the formerly valid pending-work representation so existing obligations can reach ready and delivery.🔧 Fix applied.
2 errors still open:
src/public-followup.ts:1445- The new readiness rule makes previously valid 0.2.5 records unreadable. A non-failure promise with a failed relation was persisted as delivery.state="pending-work"; after upgrading, relationLanded returns true, then normalization rejects that same record as stale at src/public-followup.ts:1107. Because backlog parsing normalizes metadata, ready, duplicate event consumption, and delivery all fail before they can repair the state. The regression at test/commands/public-followup.test.ts:406 only creates the event under the new implementation, so it does not cover the persisted failing sequence. Preserve or migrate the formerly valid pending-work representation so existing obligations can reach ready and delivery.src/public-followup.ts:1107- The round 1 fix self-heals everypending-workrecord for which readiness derives true, rather than only the authorized pre-fix shape with a failed relation. For example, a hand-edited record containing a normally landed matching event but staledelivery.state="pending-work"now silently becomes ready instead of failing closed, masking drift that was never produced by the old failed-relation rule. Narrow this branch to readiness attributable to the newly accepted non-failure expected type plus failed relation transition; retain validation for other pending-work/ready mismatches.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
pnpm exec vitest run test/commands/public-followup.test.ts test/public-followup.test.tsLive CLI: add, bind, consume a failed pr-merged relation, query ready, begin delivery, and record deliveryLive CLI: consume a failed report-ready relation, query ready, and begin deliveryLive CLI: read a simulated 0.2.5 failed relation persisted as pending-work, then begin deliveryLive CLI adversarial check: read a landed relation hand-edited to pending-work and verify VALIDATION_ERROR with exit 2✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.