feat: add retained managed-epoch reference execution - #16
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 06c810909d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (sourceEpoch == -1L) { | ||
| return lineage.authoredInitialBlueId(); | ||
| } |
There was a problem hiding this comment.
Read the current representation during selector preflight
When an indirect cyclic-component rebind changes a lineage's authoritative currentBlueId without adding an epoch, its last retainedStates() entry still contains the immutable revision BlueId. A ManagedEpochSelector that explicitly selects that current epoch and authoritative BlueId is therefore rejected during operation submission with MANAGED_EPOCH_SELECTOR_STATE_MISMATCH, even though ManagedOccurrenceResolver.blueIdAt explicitly supports this same current-epoch selection. Check lineage.currentEpoch() and return lineage.currentBlueId() before scanning retained states.
Useful? React with 👍 / 👎.
| diagnostic, | ||
| drained.managedEpochApplications().stream() | ||
| .map(SdkDrainResultMapper | ||
| ::managedEpochApplicationReceipt) | ||
| .toList(), | ||
| drained.managedEpochApplicationAttempts().stream() |
There was a problem hiding this comment.
Include managed application gas in drain statistics
When a drain performs managed-epoch work without completing a journal entry, such as drainManagedEpochApplication, entries is empty and aggregateDrainStats reports zero gas even though the newly attached managed attempt contains a complete ClosureProcessResult with nonzero totalGas and the receipt may report a committed transition. Mixed journal/managed drains similarly undercount gas. Fold the managed application attempts' processor results into ProcessingStats before constructing the result.
Useful? React with 👍 / 👎.
| boolean remainingWork = activeCatchUp || !journalQuiescent; | ||
| boolean budgetExhausted = committedTransitions | ||
| >= limits.maxCommittedProcessTransitions() | ||
| || selectedEntries >= limits.maxSelectedEntries(); | ||
| boolean quiescent = !remainingWork; | ||
| boolean paused = remainingWork && budgetExhausted; |
There was a problem hiding this comment.
Report terminal managed failures as blocked
When the last permitted selection produces a terminal managed evidence or publication failure, the plan's due row is removed and its barrier becomes durably BLOCKED, but selectedEntries also reaches the budget. This calculation consequently returns paused=true and blocked=false—notably from the one-selection targeted managed drain—even though no deterministic work remains and the next processing selection is NONE. Distinguish runnable remaining work from an active blocked barrier before letting budget exhaustion select the paused state.
Useful? React with 👍 / 👎.
| if (!selected.equals(selectionsByPath.keySet())) { | ||
| LinkedHashSet<String> missing = new LinkedHashSet<>( | ||
| selectionsByPath.keySet()); | ||
| missing.removeAll(selected); | ||
| LinkedHashSet<String> unexpected = new LinkedHashSet<>(selected); | ||
| unexpected.removeAll(selectionsByPath.keySet()); | ||
| throw new IllegalArgumentException( | ||
| "MANAGED_EPOCH_SELECTOR_PATH_MISMATCH: missing=" | ||
| + missing + ", unexpected=" + unexpected); |
There was a problem hiding this comment.
Make an unused selector a terminal operation failure
If a submitted selector names a syntactically valid path but the selected handler never produces a managed-occurrence demand for that path, Contracts can complete its attempt and this check throws IllegalArgumentException. The exception occurs before ContractsRootFeederWindow.record, so the appended journal entry remains nonterminal and every subsequent drain retries and throws on the same entry, preventing the contiguous processing frontier from advancing. Reject the path before append when possible, or publish a terminal non-commit outcome instead of throwing from the drain.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f044b8c14
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| for (ManagedLineageIndex.RetainedState state | ||
| : lineage.retainedStates()) { | ||
| if (state.epoch() == sourceEpoch) { | ||
| return state.blueId(); |
There was a problem hiding this comment.
Use the current representation in static selector preflight
After an indirect cyclic-component rebind changes a lineage's authoritative currentBlueId without appending an epoch, the retained state for currentEpoch() still contains the immutable revision BlueId. Consequently, a static admission whose selector names that current epoch and its authoritative BlueId is rejected with MANAGED_EPOCH_SELECTOR_STATE_MISMATCH. This static-admission preflight has its own lookup separate from the operation path; return lineage.currentBlueId() when sourceEpoch == lineage.currentEpoch() before scanning historical retained states.
Useful? React with 👍 / 👎.
| blue.coordination.api.DocumentSnapshot snapshot = | ||
| engine.auditDocument(id); | ||
| engine.document(id); |
There was a problem hiding this comment.
Preserve not-ready errors when selecting a target by ID
When operations().on(DocumentId) selects an existing document that is BLOCKED or otherwise has no application-readable head, engine.document(id) throws DOCUMENT_NOT_READY, but the surrounding catch handles every CoordinationException as if the document did not exist. The call is then built with presentAtSelection=false and can be appended through the missing-target path, producing a misleading zero-attempt/not-managed outcome; this also differs from selecting the same document through a DocumentHandle, which propagates the readiness failure. Only convert DOCUMENT_NOT_FOUND into the absent-target selection and preserve other typed failures.
Useful? React with 👍 / 👎.
Summary
Verification