fix(operations): expired-plan replay + declared lane timeouts + measured pin TTL (issue #192) - #193
Merged
Merged
Conversation
…ent gates A plan that already produced an operation could not answer from its own journal in three cases: past the wall-clock lifetime it reported GDS_PLAN_EXPIRY_RECORD_FAILED instead of the recorded result; a signed plan could never replay at all because the one-shot enablement was consumed by the recorded operation; and an already-marked-stale plan failed the "planned" -> "stale" transition on a second expired apply (issue 192, attempt 2). Replay now consults the journal before expiry and enablement, signature verification still precedes any journal answer so a tampered record fails closed, and the stale mark is written as durable bookkeeping under WithoutCancel while tolerating a mark an earlier expired apply already recorded.
Every lane command used to run under one hardcoded 10-minute bound, so a suite that legitimately needs longer could only report "timeout" and a pin apply re-running the lanes failed closed as GDS_STALE_PLAN -- the operational half of issue 192. Modules now declare their own cost: `verification.timeouts` carries per-lane seconds through the anchor schema, the domain type and PlanVerification into runDeclaredCommand. An explicit operator `--command-timeout` still wins, then the declaration, then the engine default. Regenerated goldens and repository projections record the new canonical input.
… cost The 15-minute plan TTL and the 20-minute lane command deadline both expired mid-verification on a real module: apply re-runs the declared lanes up to twice before mutating, and issue 192's first attempt died there as a misleading GDS_STALE_PLAN. The plan now derives its lifetime from the measured lane duration (3x plus the base TTL, covering both re-runs and a retry), and the lane deadline default covers two full declared-verification passes; each command stays individually bounded by verification.timeouts or the per-command default, and --timeout still wins.
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.
Summary
Closes #192 —
gds module update-pinlost three transactions to a plan TTL and per-command bound sized for a small module, applied to one whose declared verification legitimately runs longer.Applynow answers a recorded operation from its journal before the expiry and enablement gates. A past-TTL plan replays its recorded result instead of masking it asGDS_PLAN_EXPIRY_RECORD_FAILED(issue attempt 2); a signed plan can replay even though its one-shot enablement was consumed by the recorded op; a second expired apply on an already-marked-stale plan reportsGDS_PLAN_EXPIREDinstead of an internal record failure. Signature verification still precedes any journal answer — a tampered record fails closed.verification.timeouts(schema + domain +PlanVerification+runDeclaredCommand). Precedence: operator--command-timeout> declared lane bound > engine default. The pin path passes 0 so declarations apply.--timeoutstill wins.Test plan
go test ./...— all packages green (incl. new replay-after-expiry, already-stale re-apply, signed-replay-after-consumed-enablement regression tests)python3 -m pytest— 70 passed (hash-locked venv)scripts/validate_shell.sh,scripts/validate_go_core.sh --quickgds generate repository --checkclean on the committed branchGenerated with Devin