Two follow-ups surfaced during the Coral cross-review of PR #175 (gov-vote handler).
1. Per-handler idempotency review template
PR #175 documents in `gov_vote.go` that the engine's crash-rehydration path is safe specifically because MsgVote is chain-idempotent (last-write-wins on `(proposalID, voter)`). Future sign-tx handlers — MsgSend, MsgWithdrawDelegatorReward, MsgDelegate, etc. — do NOT have chain-side idempotency. Copying the gov-vote pattern blindly would double-spend on crash-after-broadcast.
Action when the next non-idempotent sign-tx handler ships:
- Persist a "broadcast-attempted, txHash=H" marker to SQLite before calling `BroadcastSync`
- On rehydration, `QueryTx(H)` first — if found, treat handler as completed; only re-broadcast if the chain has no record
- Add a per-handler doc comment matching the gov-vote template stating which idempotency guarantee applies
When to do this: when the next sign-tx handler (likely gov-submit-proposal #163-C or a staking task) is proposed — not as a speculative refactor. The pre-broadcast marker has its own failure window (between hash compute and the SQLite write) so it deserves real design.
2. `TaskResult.Output` engine extension
`TaskResult` currently exposes only `Status`/`Error`/timestamps. Sign-tx handlers' structured output (`txHash`, `height`, `sequence`, `inclusionStatus`, etc.) is logged but not returned via the engine's task-result surface. Operators must grep the sidecar logs or chain by memo (`taskID=`) for tx outcome.
Acceptable for MVP because:
- The chain is the genuine source of truth
- The memo carries the task UUID for forensic correlation
- Adding `Output any` is a one-way door: storage schema change, `/tasks/{id}` JSON contract change, every other handler suddenly nullable-output
When to do this: when a second sign-tx handler ships and the demand for structured output is concrete (not speculative). At that point design the `Output` shape against two real consumers rather than over-engineering for one.
References
Two follow-ups surfaced during the Coral cross-review of PR #175 (gov-vote handler).
1. Per-handler idempotency review template
PR #175 documents in `gov_vote.go` that the engine's crash-rehydration path is safe specifically because MsgVote is chain-idempotent (last-write-wins on `(proposalID, voter)`). Future sign-tx handlers — MsgSend, MsgWithdrawDelegatorReward, MsgDelegate, etc. — do NOT have chain-side idempotency. Copying the gov-vote pattern blindly would double-spend on crash-after-broadcast.
Action when the next non-idempotent sign-tx handler ships:
When to do this: when the next sign-tx handler (likely gov-submit-proposal #163-C or a staking task) is proposed — not as a speculative refactor. The pre-broadcast marker has its own failure window (between hash compute and the SQLite write) so it deserves real design.
2. `TaskResult.Output` engine extension
`TaskResult` currently exposes only `Status`/`Error`/timestamps. Sign-tx handlers' structured output (`txHash`, `height`, `sequence`, `inclusionStatus`, etc.) is logged but not returned via the engine's task-result surface. Operators must grep the sidecar logs or chain by memo (`taskID=`) for tx outcome.
Acceptable for MVP because:
When to do this: when a second sign-tx handler ships and the demand for structured output is concrete (not speculative). At that point design the `Output` shape against two real consumers rather than over-engineering for one.
References