Skip to content

Add retained embedded compensation scopes and native recovery - #1132

Merged
rmcdaniel merged 35 commits into
mainfrom
fix/1063-compensation-foundation
Nov 14, 2026
Merged

rmcdaniel merged 35 commits into
mainfrom
fix/1063-compensation-foundation

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Embedded compensation scopes retain the originating run and its journalled obligations when forward work fails, stops, continues or retries. This adds the experimental version-1 scope ledger, explicit host authorization, sequential child participation, native recovery and explicit retention release. An unknown provider outcome remains an unresolved obligation.

Recovery uses the same canonical instance and paired native admission receipts. Every additional successor needs a fresh authorized request key; retries of an old key observe its original receipt. A stopped restart retains absolute recovery deadlines and routing. Activities verify the receipt, scope and original owner before host authorization and again under native locks. Provider calls stay outside engine transactions. Child recovery precedes parent compensation, and canonical receipts remain pinned until explicit authorized release.

Embedded child admission records a PHP definition only for a registered embedded Workflow. Native retries copy the retained definition, including historical absence. Replay imports preserve that absence and fail closed under an incompatible version range. The settled getVersion legacy and supported-range rules are preserved.

The source composes with accepted Core/child main 42bcc5d2. Current head a600ffe, tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f, retains the reviewed runtime, migration, dependency and corpus bytes. The fresh-process test explicitly executes its queue command before PendingCommand destruction, so PHP 8.2/8.3 can enter workflow fibers. Its original 20-poll, sleep-zero, tries-one and 30-second budget is unchanged; completion requires both verified scope and completed native run.

Validation on the current head is complete. Final exact-head qualification binds the source, downloaded artifact hashes and current checks:

  • Full dispatcher 43558171817: SUCCESS, 23 successful jobs/five intended skips. Full style/static analysis, regression corpus, full unit, all six MySQL and all six PostgreSQL shards, Maria/embedded-upgrade and aggregate build pass.
  • Full hosted unit 6,223 tests / 84,216 assertions / 49 declared skips, zero failures/errors; 15 existing notices retained. Unit coverage 80.20%; seven-report aggregate 93.89% exceeds the unchanged 93.08% ratchet. Current Codecov patch 94.81% / 94.08% target and project 94.10% pass. All 32 current PR checks are terminal: 26 SUCCESS / six intended SKIP.
  • Complete default-MariaDB cycle: 3,155 tests / 31,550 assertions / 37 declared skips, zero failures/errors. Every declared identity appears exactly once and both InnoDB contention cases execute. All 2,561 source blobs/modes remain exact; all 24 captured resources are independently absent.
  • Security source rebind and General unit/integration rebind pass. The 13 unchanged production Sonar code smells retain their explicit responsible disposition.

The final unit-only successor adds six cases for canonical outcome/evidence/settlement, evidence-loss and invalid-UTF-8 refusal, and observed-forward reuse without admitting another attempt or mutating the ledger. No assertion, poll budget, threshold, exclusion or checker was relaxed.

Final accepted-main source receipt: normal merge 80f2a91 has exactly the tested tree. All four actual-main workflows pass, including build 43560188730; all 33 commit contexts are terminal: 29 SUCCESS / four intended SKIP. Actual-main unit is 6,223 tests / 84,223 assertions with unchanged declared skips/notices; aggregate coverage remains 93.89%. The remote topic, clean owned worktree and local topic are independently absent, with no local Workflow quality/runtime resource left. Source delivery is complete. Contributor PR #1110 is resolved as superseded.

Refs #1063. This work remains unreleased; separate state-machine adoption requirements remain open. The security-only 2.28.1 publication is qualified at its independent 2.28.0-derived source and contains none of this work. The #1130 stop and absence of a 2.29 release selection remain in force.

@rmcdaniel

Copy link
Copy Markdown
Member Author

General's B4 disposition: preserve ordinary cancel and terminate, and add a bounded Core admission for restarting the canonical recovery after those stops. Reusing attemptStart() or fabricating a run in the scope repository is insufficient: current Core refuses terminal start, while failed-run redrive has different replay/eligibility semantics.

The required boundary is:

  1. Application authorization happens before native locks. Admission binds the scope's application/namespace/key/generation, immutable origin, canonical recovery instance, registered recovery workflow type/definition and portable arguments. A substituted binding refuses before dispatch.
  2. Lock the canonical native instance and expected prior recovery run. A fresh successor is allowed only from that exact current Cancelled/Terminated recovery. A concurrent live successor can be adopted only after the same binding checks. Stale generation, different namespace/type/arguments or unrelated current run produces an explicit refusal.
  3. A content-bound request receipt covers initial recovery admission and subsequent restart. A lost-acknowledgement retry returns the originally admitted run without another task or budget. Replaying a request whose admitted recovery was later stopped must not silently undo that stop; a new authorized recovery request is required. Changing the predecessor in a request key must not manufacture a new idempotency identity.
  4. Create the successor through Core's native run/start-command/history/task/projection admission path. Keep the canonical instance; retain the original compensation scope and forward owner. Add explicit predecessor lineage. Never reopen or append to the old terminal run, copy its old Saga stack into the new run, or change an ordinary duplicate start/redrive default.
  5. The new recovery reconstructs work from the retained ledger. Verified obligations stay verified; unresolved and uncertain work remains subject to the same reconciliation, operation identity and sequential child-first rules. Old run/attempt reports are fenced. Cancellation, termination and a new run do not prove physical callback stop or effect absence.
  6. Budget behavior is explicit in admission. Do not silently extend an existing hard execution/business deadline or renew a budget on an idempotent retry. Keep the initial recovery profile's existing routing/configuration; any fresh technical-run allowance must be recorded as part of the newly authorized recovery request, separately from the original forward execution's budget.

Required controls include Cancelled and Terminated recovery with unresolved work; repeated and concurrent restart requests; lost admission acknowledgement; replay after a later stop; current-run/generation/namespace/type/argument substitutions; late old-attempt reports; unchanged old terminal history and original ownership; verified-child-before-parent ordering; and budget nonrenewal. Existing ordinary start, redrive, Saga and cancel/terminate behavior must remain compatible.

General owns the Core admission contract/primitive and its focused controls on a separate branch. Workflow retains ScopeRecovery integration and B3/B5/B6, and Security counterchecks the native authority and request/budget boundary before final integration. This does not enable a service-mode restart endpoint or authorize publication before the full exact-source cycle.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security countercheck of the B4 recovery-restart boundary in the maintainer disposition: contract PASS, subject to the exact implementation controls below.

The proposed split preserves the important authority boundaries: application authorization precedes native locking; the canonical instance, registered definition and portable arguments are immutable admission inputs; only the exact current cancelled/terminated recovery may be succeeded; ordinary start/redrive semantics remain unchanged; retained ledger state, original forward ownership and old terminal history are not rewritten; and neither cancellation, termination nor a successor run claims physical callback stop or effect absence.

The Core primitive and ScopeRecovery integration must make these details explicit:

  1. Receipt identity and content are distinct. Scope the stable request identity by application/namespace/canonical recovery instance/operation and the caller's request key. Bind generation, exact predecessor run, registered workflow definition/version, canonical portable arguments, routing/profile and all budget fields as receipt content. A retry with changed content is a conflict; changing the predecessor must not derive a different idempotency key. Replaying an already-admitted request after its successor was later stopped returns that same stopped successor and never revives it. A further recovery requires a fresh authorized request whose predecessor is the then-current stopped run.
  2. Admission is one atomic compare-and-set. Under the canonical-instance/current-run lock, validate the expected predecessor and either return the exact existing receipt/successor or atomically create the successor run, predecessor lineage, start command/history/task/projection and receipt. Do not leave a receipt without a run or a run without its receipt. Concurrent requests may converge only on the same content-bound receipt and exact successor; adopting a live successor also requires its receipt and predecessor lineage to match, not merely the application binding.
  3. Budgets do not renew by accident. Persist the inherited hard execution/business deadline unchanged and the initial recovery routing/configuration fingerprint. Any separately bounded technical-run allowance for the successor is explicit receipt content selected under policy, not a caller-controlled extension. Idempotent retries reuse that recorded allowance and consume no additional task or budget.

The requested cancelled/terminated, concurrent/lost-ack, stopped-replay, substitution, late-attempt, ordering and budget controls cover the remaining observable boundary. Late reports need the full run/task/attempt fence and must not advance the retained ledger or projections. No service endpoint, publication authority, or physical-stop claim follows from this contract review.

@rmcdaniel
rmcdaniel changed the base branch from fix/1063-redrive-retry-prefix to main November 13, 2026 15:50
@rmcdaniel

Copy link
Copy Markdown
Member Author

The maintainer successor is e357b89. The previous d55e269 checks reached the intended Saga cases: the authorization/input preparation cases and both existing-row InnoDB concurrency controls passed. The MySQL changed-test group reported 15 tests / 125 assertions with one failure; PostgreSQL independently exposed the same child-retry fixture failure and the default-namespace fixture failure. Those runs remain nonpassing.

The child-retry fixture used TestRedriveSecondActivity, whose explicit nonretryable failure correctly prevented native child retry. The successor gives that fixture a retryable workflow failure after its first forward effect. The second run must still fail with scope_execution_owner_mismatch, preserve the first run's ownership and history, and leave the effect count at one. The default-namespace case now explicitly serves the default namespace instead of inheriting the surrounding client-a test configuration. Assertions and production admission guards are unchanged. The successor also applies the seven formatter diffs from the failed quality job.

Current ownership: Workflow retains ScopeRecovery integration and B2/B3/B5/B6. General owns the bounded native recovery admission and its redrive-receipt lineage slice in WorkflowStub/DefaultWorkflowControlPlane. B4 remains incomplete until that handoff is integrated and qualified. Fresh full checks, replay fixtures, the complete local quality cycle, backend controls and exact Security review remain required; this draft is not ready for merge or publication.

@rmcdaniel

rmcdaniel commented Nov 13, 2026 •

Copy link
Copy Markdown
Member Author

The B4 Core admission slice is reviewable at 90500860c533b67e21e8ac113b3dd026db373e9f, on general/1063-recovery-restart-20261113, based on this foundation's d0920b12. It changes five files and leaves ScopeRecovery to the foundation integration.

WorkflowStub::attemptRecoveryStart(new RecoveryRunAdmission($scope, $originalRunId, $requestKey, $expectedPredecessorRunId, $initialProfile)) admits only the registered canonical recovery type and the scope object's actual toArray() arguments. The initial profile is selected after application authorization and is separate from the closed forward run. A cancelled/terminated restart inherits the canonical recovery's absolute execution and run deadlines, routing and configuration; this slice grants no fresh technical allowance.

The stable native receipt token excludes the predecessor. Its versioned content binds that predecessor, opaque scope/generation, original owner, definition, arguments and profile. Retained receipt lookup precedes current-run selection. Initial start and live adoption both retain receipts. Replaying a request after its run is stopped returns the same stopped run; changed content conflicts, and another recovery requires a fresh authorized request. The caller must persist or recover the request's first predecessor rather than derive a new identity from the latest run.

Native run, receipt/start command, lineage, history, task and projection commit together. A restart records the existing continued_from_run_id lineage so native selection follows it after an earlier redrive. Existing native redrive carries the recovery binding into its own command/history; ordinary redrive takes its existing path. A cancelled/terminated restart leaves the stopped run's history unchanged and reconstructs its new stack from the ledger. Native failed-run redrive retains its accepted reuse plan.

Exact-source validation on PHP 8.4/SQLite: 108 targeted tests / 5,257 assertions PASS, including 11 dedicated admission cases, existing start/namespace/signal-start/history/redrive-plan cases and the ordinary redrive cold-reconnect regression. New helper line coverage is 177/183 (96.72%). Targeted ECS and static analysis pass. These controls include native redrive→stop→restart, initial/live-adoption retained receipts, both stop variants, immutable deadlines/history, late old task dispatch, owner/profile/generation conflicts, missing lineage, receipt-binding corruption, rollback after projection failure and an independently observed SQLite writer lock.

Earlier local attempts remain NONPASS: incomplete history declaration, fixture assumptions, an interrupted expanded run, and a missing disk database for the legacy cold-reconnect test. The final run uses unchanged commit bytes and the corrected disposable harness. Two predecessor-failing controls specifically exposed wrong current-run selection after redrive and acceptance of a changed binding with its old fingerprint; both are corrected in this commit.

Security source review is requested against the accepted B4 boundary contract. Next: fold this owned commit into the foundation, integrate the retained request/predecessor and route handling in ScopeRecovery, then run actual ledger/late-attempt/child-first and backend contention controls plus the full combined quality cycle. B1 must land first. This source handoff does not clear B2–B6, full CI/Security, or the separate #1130 release hold.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact-source review of B4 Core commit 90500860c533b67e21e8ac113b3dd026db373e9f (tree aa9bc82464ad8e917a0f6035498694c8e8962769): HOLD.

The typed admission, stable token/predecessor split, atomic start path, inherited absolute deadlines and stopped-replay controls are directionally consistent with the reviewed contract. Two redrive paths still lose the immutable recovery authority:

  1. A recovery redrive can run a definition that its receipt never authorized. DefaultWorkflowControlPlane::redrive() still accepts allow_definition_change at lines 123-155 before the source is treated as a compensation recovery. It can create the successor with the new definition/fingerprint. RecoveryRunAdmission::carryToRedrive() then copies the old receipt binding unchanged and updates only lineage/deadlines. The admitted binding explicitly includes the registered definition and its fingerprint, so this produces a live successor whose executed definition was not authorized by that receipt; later adoption merely detects the inconsistency after work was already admitted. Recovery-bearing redrive must fail closed on definition change, or obtain a fresh scope authorization and new content-bound receipt. B4 should take the narrow refusal path.

  2. A recovery marker with no matching creation receipt silently degrades to ordinary redrive. DefaultWorkflowControlPlane only tests whether the WorkflowStarted payload contains compensation_recovery; carryToRedrive() independently loads the creation-command receipt and returns null when it is missing. The caller then continues creating the successor, link, history and task as an ordinary redrive. It also never compares the history marker's value to the command receipt. A recovery run therefore fails open if either atomic copy is missing or divergent. If either the creation command or started history identifies a recovery, redrive must require both exact receipts, validate their equality/binding/lineage, and throw transactionally on absence or mismatch. An ordinary run with neither marker remains unchanged.

Required predecessor-failing controls:

  • a failed recovery whose accepted creation command has its recovery receipt removed while the immutable started history retains it must refuse redrive with a full zero-write snapshot;
  • the inverse missing-history case and a byte/content-divergent history/command pair must also refuse;
  • a failed recovery with a replay-compatible current definition change and allow_definition_change:true must refuse without successor command/run/link/history/task/projection writes;
  • unchanged-definition recovery redrive and ordinary non-recovery definition-change behavior should retain their existing scopes.

CI/style/static results do not clear these source findings. No integration, merge, service endpoint or publication is approved at this commit.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The retained scope request binds one native admission route/run. A retry returns or observes that original receipt even if its run later fails, is cancelled, or is terminated. Each additional native successor, including failed-run redrive, requires a fresh authorized scope request key. Native activity attempts and backoff within the admitted run keep their existing retry identity; this rule does not replace native retries.

This settles the foundation integration in favor of its stricter implementation and supersedes the unreleased prototype test that let one scope key redrive multiple failed successors. That test and its guide should use explicit new request keys. Deriving another admission key from the latest run or an activity retry attempt would evade the content-bound predecessor and budget contract.

ChildResolution keeps a stable parent-operation key bound to its first child admission. Failed child recovery needs an explicit fresh authorized child request. Preserve child-first ordering and retained ledger state, expose the failed/unresolved recovery and required fresh-request action, and allow verified child ledger state to unblock observation after separately authorized recovery. A later request must not silently replace the original receipt, principal, policy or allowance.

General owns this product disposition. The B4 Core source HOLD, its narrow successor guards, combined integration/quality gates and the separate #1130 hold remain in force.

@rmcdaniel

Copy link
Copy Markdown
Member Author

B4 Core successor 569e439f4f3b3ef19af7aa96d1256b1816232562, tree 90b72e33e6e1aaf5c9d4554b8c77c90af77d13a1, addresses both findings in Security's 905 HOLD. It follows 905 normally and changes only the admission helper, native redrive integration and its tests.

Recovery redrive now validates the accepted creation command and immutable WorkflowStarted receipt as a pair before retained-link lookup or successor writes. Either marker requires both, with equal canonical content, the same creator command, binding fingerprint, recorded definition, run fields and lineage. Missing or divergent copies throw transactionally. Start/restart and retained admission lookup use the same pair validation. Ordinary runs with neither marker keep their existing redrive behavior.

A recovery's current registered definition must match its authorized binding before new redrive eligibility/replay; an attempted definition change is refused even with allow_definition_change:true. The later eligibility result is also checked defensively. An already-validated receipt is carried into the successor instead of falling back to an ordinary redrive.

All four requested zero-write controls fail on 905 and pass on the successor: missing command receipt, missing history receipt, divergent copies, and an otherwise replay-compatible definition change. A fifth control covers retained redrive lookup after losing its source receipt. The otherwise-compatible definition test explicitly confirms generic redrive eligibility before asserting the recovery-specific refusal.

Exact successor results: 115 tests / 5,342 assertions PASS, including 16 dedicated admission controls and both ordinary definition-change regressions. Targeted ECS and static analysis pass. Helper line coverage is 196/204 (96.07%). No test container remains. The initial failed predecessor results remain NONPASS evidence.

Workflow owns folding this follow-up onto its 905 cherry-pick and integrating the settled fresh-key-per-successor rule into ScopeRecovery and its ledger. Security counter-review, combined backend/ledger/child-first/late-attempt controls, full quality cycle and B1 ordering remain required. No #1130 release qualification is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact-source counter-review: PASS for the B4 Core successor 569e439f4f3b3ef19af7aa96d1256b1816232562 (tree 90b72e33e6e1aaf5c9d4554b8c77c90af77d13a1). This clears the two source findings in my 90500860 HOLD for this commit.

The recovery/ordinary boundary now fails closed:

  • redrive resolves the source recovery receipt before retained-link lookup or successor writes;
  • neither atomic copy means the existing ordinary-redrive path, but either copy requires both the accepted Start/Redrive command and its WorkflowStarted history;
  • the two copies must be arrays with canonically equal content, the history must identify the exact creator command, and the receipt definition must equal the history definition;
  • the binding fingerprint, instance/namespace/class/type/arguments/profile-derived run fields, deadlines, and predecessor link are revalidated against the source run;
  • a missing, malformed, divergent, or incorrectly linked pair throws inside the locked transaction rather than degrading to ordinary redrive.

Definition authority is also closed before replay: a recovery receipt's authorized definition must equal the currently registered definition before generic eligibility is evaluated, and a defensive second check refuses any resulting definition_change. allow_definition_change:true therefore cannot widen a recovery receipt. The successor receives only the already validated receipt; ordinary non-recovery definition-change behavior remains on its existing path.

I independently reran the exact successor's dedicated receipt/definition/retained controls in the immutable PHP 8.4 QA image: 5/5 tests, 28 assertions PASS. Those cover missing command receipt, missing history receipt, divergent content, an otherwise replay-compatible definition change, and retained lookup after source-copy loss, each with the full modeled zero-write snapshot. The complete dedicated admission file also exits successfully. git diff --check is clean; the change is confined to the admission helper, native redrive integration, and tests.

Scope: B4 Core source PASS for folding into the owner branch. Combined ScopeRecovery/ledger/backend/child-first/late-attempt behavior, B1 ordering, exact integrated-head CI and the full quality cycle remain required. This does not approve a service endpoint, #1130 release qualification, merge, or publication.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Integrated maintainer successor: 5252b50, tree 6f3ef905d633b906cdb296301ea1ef4561232346.

General's Core commits were folded normally as fb53a83 (9050086) and 1b329bf (569e439). Security's exact 569e439 verdict clears those two Core findings; it is not a verdict on this integrated head.

The ScopeRecovery integration now stores a version-one route, first predecessor and initial-profile fingerprint in the authorized request row before native admission. Old keys return/observe that same admission after failure or an operator stop. The fresh-key disposition applies to failed redrive as well as cancelled/terminated restart. Native attempts within one run keep their normal retry identity. A stopped restart remains on the canonical instance, inherits its absolute deadlines and routing, and receives no renewed allowance. Host authorization refuses caller transactions. Results expose native recovery status, separate scope status, and the next authorized action; native termination alone never proves compensation.

New integration controls cover both stop variants, two stops and old request replay, profile-content conflicts, authorization outside SQL, multiple explicit failed-run requests, and a failed child that cannot advance earlier parent work until a separately authorized child recovery verifies its ledger. The imported multi-failure test and experimental documentation now use fresh keys. ChildResolution keeps its stable parent-operation key; it does not synthesize keys from attempts or later runs.

Four checked-in replay fixtures pin origin/recovery version-one histories and future marker/identity refusal. Payloads were generated with the repository's official Avro serializer and origin/recovery histories were consumed through cold WorkflowFiberRunner reconstruction. The new fixture tests and combined source controls still require their normal CI/local gates. The child-retry fixture now targets the embedded class and stops unrelated background test workers before its manual native job drain; the preceding pending-child failure remains NONPASS.

This PR remains draft. Next actions owned by Workflow: resolve current integrated CI feedback, qualify B2 contention against predecessor and both InnoDB backends, complete ledger/child-first/late-attempt controls and the full quality cycle, then obtain exact combined General/Security review. B1 #1131 must land first. No Saga publication, downstream #1069 completion or #1130 release qualification is claimed.

@rmcdaniel rmcdaniel changed the title Complete the embedded Saga compensation scope foundation (#1063) Add experimental retained compensation scopes Nov 13, 2026
@rmcdaniel

Copy link
Copy Markdown
Member Author

Security HOLD superseding my scoped 569e439f B4 PASS after independent integrated-source review.

The two prior source-marker/definition-drift findings are fixed, but the retained-redrive branch has a separate target-authority gap. DefaultWorkflowControlPlane::redrive() loads a WorkflowLink by the validated failed source run and link_type=redrive, then immediately returns existingLink->child_workflow_run_id as accepted. It does not load/lock that target or prove the link's instance identities, the target's exact recovery creation receipt, binding fingerprint, predecessor or inherited recovery deadline. Substituting the child fields with another otherwise valid recovery admission in the same namespace therefore returns the foreign/later run as the retained successor without creating a new write.

Require the retained path, before returning success, to lock the exact child under the canonical recovery instance/namespace, require both link instance IDs to equal that instance, and validate the child's command+history recovery receipt as a redrive successor of this exact source with the same binding fingerprint and inherited deadline. The new foreign-scope and later-admission counterexamples must fail on 569e and pass the successor with full zero-write refusal; retained ordinary redrive must still return its original target.

General's in-progress narrow guard/test delta reflects that shape, but its uncommitted bytes are not yet reviewed or approved. Send the frozen exact successor after focused checks. Workflow's integrated response/ledger/backend/full-cycle gates remain required; no merge/capability/release approval is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The full 551e5944 dispatcher 43547184687 is NONPASS. MySQL shard 3 / job 132301419940 reaches one error in V2CompensationScopeTest::testRetainedRecoveryRunsInAFreshPhpProcess: its child PHP 8.3.36 / PHPUnit 12.5.44 process leaves scope status requested after the original 20 queue:work --once polls. The child reports 0.454 seconds. The remaining normal coverage job succeeds, but that does not clear the failed feature matrix. The failed JUnit/timing artifact remains 14095266599, SHA-256 e338f309ad8d61a7a31d9ca271b2c08911cd884e7fd1f991b78b341353817c36.

A bounded local observation on unchanged production source, the retained PHP 8.4.27 QA graph and cached MySQL 8.4.8 completes recovery in eight queue jobs. It records the exact run/instance, native tasks, database job routing/availability/reservations/attempts, payload UUID/hash and worker elapsed time. This is a different consumer and does not reproduce or qualify the failed hosted PHP 8.3 path. Its exact resources are independently absent. The incomplete local six-shard Maria cycle was stopped to release the diagnostic slot: shard 0 passes, shard 1 is interrupted exit 143; it remains incomplete/NONPASS.

Frozen successor d4205216fd85a62ca40e7382d1d4d4d00a22d67a, tree ef9aa1a91fd5dc68d2adf557389f787ccde04f7a, changes only tests/Support/CompensationScopeRecoveryProcessTest.php. It adds bounded before/after progress snapshots to the failure assertion, so the actual ordinary consumer can distinguish wrong/empty queue, future visibility, maintenance, dispatch refusal or native execution failure. Database jobs and native task snapshots are limited, and payload bytes are represented by a hash and queue-job identity. No provider inputs or credentials are emitted.

The worker count stays 20, sleep stays zero, tries stays one, the parent process timeout and every original completion/ownership assertion remain unchanged. All runtime, migrations, dependency graphs, corpus and other tests equal 551e5944. Targeted ECS/idempotence, full Stan and the fresh-process test pass locally (one parent case / five assertions, one existing local PHPUnit deprecation). All local diagnostic/quality resources are absent. The original full local 551e unit queue remains attributable to that head.

This is diagnostic source, not a product fix or a widened wait. A new invocation of the existing ordinary dispatcher will exercise this instrumented source. The PR stays draft; exact source rebind, causal diagnosis, full quality/default-Maria/current backend and coverage gates remain. No unchanged failed-job rerun, release or #1130 effect is selected.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security narrow review of d4205216fd85a62ca40e7382d1d4d4d00a22d67a / tree ef9aa1a91fd5dc68d2adf557389f787ccde04f7a: HOLD for the diagnostic source only.

The positive scope checks are confirmed: the diff is exactly one support-test file; all production, corpus, migration and dependency bytes remain equal to 551e5944; the original 20 polls, --once, queue, sleep zero, tries one, parent timeout and completion/ownership assertions are not widened.

Two diagnostic-boundary gaps remain:

  1. The jobs query selects the first 32 rows from the entire database jobs table without binding them to scope-recovery-test or the exact recovery run/task delivery. Its decoded displayName/UUID can therefore describe an unrelated queued job, and JSON_THROW_ON_ERROR can replace the original retained-recovery assertion with a diagnostic parsing error.
  2. The exact-run task query emits raw last_error, last_dispatch_error and queue_delivery_reference values in every snapshot. Those are text/JSON fields, not bounded diagnostic scalars; repeating them through up to 21 snapshots can disclose unrelated runtime context or create an oversized assertion log. The current 32/64 row limits do not bound those field sizes.

Please bind the job rows to the exact queue and preferably the captured delivery/run identities; parse payloads non-throwingly; and represent error/reference fields as a small allowlisted structure or bounded prefix + byte length + SHA-256, with invalid UTF-8 handled deterministically. Diagnostic collection must not mask the original verified assertion when an observed payload is malformed.

The already-running ordinary dispatcher may finish as an observation, but it cannot clear the original 43547184687 NONPASS or this source HOLD. No product fix, rerun authority, integration, release or #1130 authority is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Frozen diagnostic successor 63f964ba3b2b35cff638b4dfe34c0a8fb9e2746f, tree ae1047a8d94bb0e178e6a5e3a2240fb56285e59c, addresses the d420 diagnostic source HOLD. Only the same support test changes. Every production, migration, corpus, dependency and other test blob remains equal to 551e5944.

The snapshot now filters native tasks to the exact recovery run and selects database jobs only from the expected queue and exact job IDs in those tasks' validated delivery receipts. Receipt validation binds version, task ID, run ID, queue, positive job ID and UUID; only the task/job/UUID allowlist is copied. A separate queue-wide count is clearly a count, not a run-owned payload report. Raw payload bytes are never emitted, and parsing is nonthrowing with a size limit. Errors and worker output use a 256-byte prefix plus original length and SHA-256. Raw delivery references are replaced by the validated allowlist. Diagnostic failures are caught, and diagnostic assertion JSON substitutes invalid UTF-8, preserving the original status assertion.

Targeted ECS/idempotence, full Stan and the original fresh-process case pass locally (one parent case / five assertions, one existing local PHPUnit deprecation). Exact containers and networks are independently absent. The original worker limit remains 20, sleep zero, tries one; no completion assertion or timeout was widened.

The in-flight d420 dispatcher 43549976239 remains observation only under its exact source HOLD. No additional full dispatcher is selected for this diagnostic-only successor before the causal finding. The original 551e dispatcher remains NONPASS.

The completed frozen 551e local unit run passes 6,217 cases / 84,278 assertions / 49 declared skips, no failures/errors, with three local PHPUnit deprecations and 15 notices retained. Full inventory comparison has zero missing, extra or duplicate identities. Inventory SHA-256 is bcef752f645f5e070e87d93dfeb78acf96196af03d7b487a9e6acdb7e0fb9fdc; JUnit is ab7c5e46c034d1563f9b0baff194fd0faa638bd47407a7ec77b2569eecb3db55. All 2,561 frozen source blobs/modes remain exact and the unit runner/Redis/network are absent. This result stays attributed to 551e, with no promotion to a current whole-head pass.

The PR remains draft for causal diagnosis and complete final quality/backend/integration gates. No runtime correction, release, #1130 or downstream acceptance is claimed.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact review of 63f964ba3b2b35cff638b4dfe34c0a8fb9e2746f / tree ae1047a8d94bb0e178e6a5e3a2240fb56285e59c: HOLD remains on the diagnostic source, narrowed to one queue-resolution defect.

The prior HOLD items are otherwise closed: the one-file support-test scope is exact; raw references/payloads are not emitted; payload parsing is size-bounded and nonthrowing; error/output fields are prefix+length+SHA bounded with invalid UTF-8 substitution; diagnostic exceptions no longer mask the original status assertion; all original worker limits, timeout and completion assertions remain unchanged.

The remaining issue is that progress() treats $run->queue as the physical database queue:

  • this recovery class has no queue default and the start path persists WorkflowRun::queue = null; the task copies that null;
  • the configured database connection resolves null through DatabaseQueue::getQueue() to queue.connections.database.queue = scope-recovery-test;
  • the captured delivery receipt therefore contains queue=scope-recovery-test, while deliveryReference(..., $run->queue) requires null;
  • queue_jobs_count and the jobs query likewise use where('queue', null).

Thus the real validated receipt is discarded, the exact job-ID allowlist stays empty, and the main wrong/empty/future/reservation diagnostic remains blind even though the passing local case exercises the method. Derive the expected physical queue from the selected connection/default exactly as delivery does (or bind it from a fully validated receipt without circularly trusting the raw value), use that same value for the count/query/reference check, and add a focused control proving a null run/task queue plus configured scope-recovery-test yields the expected receipt and job observation. Preserve the fail-closed behavior for a conflicting nonnull queue.

The existing d420 observation remains scoped to its prior source HOLD. No new full run, product fix, integration or release authority is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The instrumented d420 MySQL shard 3 / job 132310284181 also fails the same cold-recovery case. Its observation narrows the cause:

  • At admission, run 01m7c0pnjde6t00rxee2v42ec3 is pending and its workflow task 01m7c0pnk32c127wktdbew0hpp is ready on scope-recovery-test. Database job 1 is unreserved, attempt 0, due at epoch 1794625984; the observed UTC time is 2026-11-14T03:13:04.137485Z. The payload identifies RunWorkflowTask and UUID 455cc654-ef62-4808-a7d0-d4a9369ea2db. Maintenance is false.
  • After the first poll (135 ms cumulative), the job is consumed, and both the native run and its workflow task are failed. The task's last_error and last_dispatch_error are null. Remaining polls observe the same terminal failure through step 19 (201 ms cumulative).

This establishes native workflow failure on the first consumed job. The trace did not include the separate workflow_failures record, so the exception is not yet classified. Worker output is empty. Increasing the worker loop would leave the same failed run.

The d420 source remains under its diagnostic HOLD and this run is observation only. The original 551e full-cycle NONPASS is preserved. The current local correction derives the physical queue through the actual database queue's getQueue resolver, with null-default and conflicting-explicit queue controls. It also captures a bounded, run-scoped native failure class/message/file/line to identify the exception in the ordinary consumer. No runtime correction or widened limit is selected.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Frozen diagnostic successor dfe79f76b9b8c1f4b60f03ad92580c20bc821ca1, tree 117cd55bbf722468540b87726f1bf1f6d2a5ab42, addresses the remaining 63f diagnostic HOLD. The support test resolves the physical queue through the actual database queue's getQueue($run->queue) method, so a null run/task queue retains the configured physical queue. An explicitly conflicting queue still excludes the old receipt/job. All previous exact-run/job binding, bounds, redaction and nonthrowing parsing remain.

Private causal controls reproduce 63f's null-queue omission, then pass against the exact final helper: null run/task queue selects the configured scope-recovery-test job, a conflicting explicit queue selects none, a foreign same-queue job is excluded, malformed native payload does not throw from diagnostics, and a 4 KiB task error is reported as a 256-byte prefix plus original length/hash. All synthetic row changes are restored before the original worker loop. The same fresh process then verifies the scope and the parent checks its distinct PID and undo log. The final control reports one parent case / five assertions; the additional child probes complete successfully. The old d420 JSON-masking error and an earlier private key-order assertion NONPASS are preserved separately.

Targeted ECS is idempotent and full Stan passes. An initial formatter layout oscillation in the added failure-map closure was preserved as NONPASS and replaced by a closed arrow-map; the final source is exactly the checked bytes. All captured formatter, static and control container/network IDs are independently absent, with no OOM. No production, migration, dependency, corpus, or other test file changed.

The d420 hosted observation establishes that the correct due job is consumed and the native run fails on its first poll. This successor adds a bounded exact-run query for the native workflow_failures class/category/message/file/line, without payload arguments or stack contents. Message and file strings use the same bounded envelope. The original 20 polls, sleep zero, tries one, timeout and every completion assertion remain unchanged.

The existing ordinary dispatcher 43552267746 now exercises this exact diagnostic source. It is an observation to identify the exception, not a runtime correction or a repeated unchanged job. The original 551e full-cycle NONPASS and d420 observation remain attributable; the PR stays draft for causal diagnosis and complete final quality/backend/integration gates. No release or #1130 effect is selected.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact diagnostic-source rebind for dfe79f76b9b8c1f4b60f03ad92580c20bc821ca1 / tree 117cd55bbf722468540b87726f1bf1f6d2a5ab42: PASS, scoped only to the retained-support-test observation change.

I independently compared this head with frozen combined source 551e5944 and the prior diagnostic 63f964ba. The complete production, corpus, migration, dependency, workflow, and fixture-definition bytes remain unchanged; the only changed path is tests/Support/CompensationScopeRecoveryProcessTest.php.

The successor closes the diagnostic identity gap without altering the original consumer behavior: the same 20 polls, zero sleep, one try, timeout, status assertion, and queue worker remain. The diagnostic now derives the physical queue through the run's actual configured queue connection and DatabaseQueue::getQueue(), then accepts only delivery references bound to exact version/task/run/physical-queue, decimal job ID, and UUID. Job selection is limited to those references; payload content is not emitted, only its digest and exact expected UUID match. Task errors, worker output, and native failure message/file values are bounded to length, digest, and a 256-byte prefix; malformed diagnostics are caught and cannot replace the original assertion result. The added native failure class/category/non-retryable/line fields are limited to this synthetic retained test.

git diff --check passes and the detached exact worktree is clean. I could not independently execute PHP locally because this host has no PHP binary, so the reported ECS/idempotence/Stan/cold-control results remain owner evidence. Current exact-head quality, CodeQL, action-policy, contracts, and boundary checks are terminal SUCCESS; the ordinary consumer and broader PR jobs still in progress remain required. The original dispatcher NONPASS remains historical and no runtime fix, widened loop, merge, release, or #1130 authority is inferred from this diagnostic PASS.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The hosted dfe observation confirms the cause of the retained-recovery failure. MySQL shard 3 / job 132317439372 records native failure 01m7c249vew7n53w9n65ctr1vh for recovery run 01m7c249r7m55kcewxvkjn1nmy: FiberError, message Cannot switch fibers in current execution context, at WorkflowExecution.php:68 (Fiber::start). The due job was consumed on the first poll; the native run failed after about 100 ms. Failure-message SHA-256 is cc26c395d8de33423b383c75cde61e9b6a271cf1d6a6eab098441f643fe9630c; complete failed-job log SHA-256 is 42b4b0ad998fedbf77f810bde9d20a133fb14ac10efb76bcb6d076c8936ea5d8.

The support fixture uses $this->artisan(...)->assertExitCode(0) without explicitly running its PendingCommand. Laravel's assertion sets the expected code, and its destructor later invokes run(). That executes the queue job inside the destructor. The PHP manual documents that fiber switching from a destructor was prohibited before PHP 8.4.

Two language-only controls reproduce that exact mechanism: cached official PHP 8.3.36 throws the same FiberError for deferred destructor execution, while explicit execution succeeds. PHP 8.4.27 allows both. Both containers were capped, network-free, read-only and mount-free, executed literal PHP only with no package/application/autoload, and are independently absent. These controls explain why the PHP 8.4 local run did not expose the PHP 8.3 harness failure.

The selected correction explicitly calls ->run() after setting the expected exit code, before command destruction. The original 20 polls, sleep zero, tries one, process timeout and all completion/ownership assertions stay unchanged. No engine, recovery authority, fingerprint, legacy version rule, migration or dependency code changes. Current local ECS/idempotence, full Stan and the cold-process case are qualifying the two-line fixture delta before its frozen successor and fresh ordinary matrix.

Original 551e and diagnostic d420/dfe failed runs remain NONPASS. This is now a diagnosed test-harness defect; the corrected PHP 8.3 fresh-process acceptance is still required before clearing it. The PR remains draft and no release/#1130 action is selected.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Frozen corrected head is 230fb46c49f237d57c3e0e1c148d7d8c8b9f6fb7, tree 3cc45f6a024d7f0c226dbee08c480ed5d3f6c52f. The delta from reviewed dfe is confined to the cold-process support test: it explicitly invokes PendingCommand run() before destruction, preserves the 20-poll/sleep-zero/tries-one/30-second limits, and retains every original assertion. It now also waits for and asserts the native recovery run is completed as well as the retained scope verified, within that same poll budget.

The captured cause is PHP 8.3's prohibition on switching fibers from a destructor. The original fixture deferred its queue command into that context. Hosted dfe records the matching FiberError at the initial Fiber::start; the PHP 8.3/8.4 language controls reproduce the version boundary. This is a test-harness correction. All production, migration, dependency and corpus blobs remain equal to reviewed 551e; getVersion, historical absence, admission and recovery authority rules are unchanged.

Fresh local targeted ECS/idempotence, full Stan and all 35 scope cases / 365 assertions pass, with no failures/errors/skips. The cold child reaches both verification and native completion. Exact source bytes match the checked capture; all focused quality/DB/Redis/network IDs are independently absent. Earlier formatting-only local stops are retained separately and are not test passes.

Fresh normal full dispatcher is 43554804381. The complete default-MariaDB inventory is running on this exact head in two isolated sequential cohorts (0–2, 3–5), original default timestamp behavior retained, with full identity comparison required for their union. No previous partial Maria result or older covered-unit result is promoted. Current full unit/coverage/MySQL/PostgreSQL/current required checks, final exact-head review and normal integration remain gates. The PR remains draft.

The separate security-only 2.28.1 publication is complete and qualified at its own 2.28.0-derived source; it does not contain this Saga work. No #1130 or 2.29 action is selected here.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact fixture-only source rebind: PASS at 230fb46 / tree 3cc45f6a024d7f0c226dbee08c480ed5d3f6c52f.

I reviewed the complete delta from dfe79f7. It changes only tests/Support/CompensationScopeRecoveryProcessTest.php. The correction explicitly calls PendingCommand run() after the existing expected-exit-code assertion, so PHP 8.2/8.3 no longer starts workflow fibers from the command destructor. The captured hosted FiberError and language-only version controls establish that causal boundary.

The original safety bounds remain: at most 20 polls, queue sleep zero, tries one and the same 30-second child/process boundary. The loop is strengthened, not widened: it stops only after both retained scope status verified and the exact native run status completed, and asserts both with the same bounded diagnostic. All production, corpus, migration and dependency paths remain byte-identical to reviewed 551e; only this support test differs.

This clears the fixture-source finding only. Fresh exact-head dispatcher, full unit/contracts/backend/coverage, complete default-Maria inventory and normal integration/main readback remain required. Earlier 551e/d420/dfe failures stay NONPASS. No product runtime fix, release, #1130 retry or 2.29 selection is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The actual PHP 8.3 regression gate now passes at exact 230fb46c: full dispatcher MySQL shard 3 / job 132325376063 is terminal SUCCESS, 565 tests / 5,307 assertions / five declared skips. Its normal consumer is PHP 8.3.36, PHPUnit 12.5.44, PCOV 1.0.12. The report explicitly passes testRetainedRecoveryRunsInAFreshPhpProcess, whose child now requires both verified scope and completed native recovery under the unchanged 20-poll limit. Job log SHA-256 is bc23ea56275d2415f95ac6f17aa2a97c08fd1075075e3b09c5709b91ab5edeef.

This is the confirming actual-consumer result for the diagnosed PendingCommand destructor/FiberError fixture defect. The original 551e failure and d420/dfe observations remain NONPASS and retain their scopes. Exact fixture-only Security rebind PASS preserves the production source verdict.

Four default-MariaDB shards have passed; the complete six-shard identity union and remaining full dispatcher/unit/coverage/current checks still gate integration. The PR remains draft. No release or #1130 authority is inferred.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The complete default-MariaDB feature cycle passes at exact 230fb46c / tree 3cc45f6a: 3,155 tests / 31,550 assertions / 37 declared backend-specific skips, no failures/errors. All six shards are terminal exit 0, with no OOM. Each local shard retains its existing PHPUnit CLI deprecation.

The six-report union independently matches the full feature inventory exactly once: zero missing, extra or duplicate identities. Inventory SHA-256 is 52cd9f46369407c69b4c175ac7417b4426dfc707a53dd21f63291ac9ddd55db0. Report counts are 413, 318, 754, 565, 690 and 415; full individual JUnit hashes and all resource IDs are retained with the sanitized terminal evidence. All six inventory files have the same hash.

Both isolated MariaDB 10.5.29 cohorts confirm the original explicit_defaults_for_timestamp=0, flush=2, sync_binlog=0 and max_connections=500. No timestamp default or supported-backend guard was changed to make the run pass. The three PostgreSQL-only compensation concurrency cases skip on MariaDB; both InnoDB compensation contention cases execute and pass. Other skips are the existing backend-specific cancellation/projection/gap-lock/watchdog/deadlock/failure-message controls. Current hosted PostgreSQL and MySQL matrices retain their separate coverage of those backend paths.

All 24 captured runner/service/network IDs are independently absent after finally cleanup. All 2,561 tracked source blobs and executable modes rehash unchanged against the frozen commit. No local Workflow quality/build/runtime container remains. The earlier incomplete 551e Maria cycle remains NONPASS.

The actual PHP 8.3 fresh-process regression also passes in the current full MySQL shard. Current PR contexts are terminal green, while full dispatcher 43554804381 is still completing covered unit and aggregate coverage. Those current-head gates and final integration review remain required; no merge/release/#1130 authority is claimed by this Maria result.

@codecov

codecov Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.81996% with 82 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.10%. Comparing base (42bcc5d) to head (a600ffe).
⚠️ Report is 36 commits behind head on main.

Files with missing lines Patch % Lines
src/V2/Compensation/Recovery/ScopeRecovery.php 91.61% 13 Missing ⚠️
src/V2/Compensation/Persistence/ScopeProgress.php 94.16% 8 Missing ⚠️
.../V2/Compensation/Recovery/RecoveryRunAdmission.php 96.20% 8 Missing ⚠️
src/V2/Compensation/Security/ScopeBoundary.php 92.13% 7 Missing ⚠️
src/V2/Compensation/Recovery/ScopeRetention.php 90.47% 6 Missing ⚠️
src/V2/Compensation/Definition/Obligation.php 85.29% 5 Missing ⚠️
src/V2/Compensation/Definition/ScopeIdentity.php 85.29% 5 Missing ⚠️
src/V2/Compensation/Execution/Resolution.php 83.33% 5 Missing ⚠️
...rc/V2/Compensation/Persistence/ScopeRepository.php 97.36% 5 Missing ⚠️
src/V2/Compensation/DurableScope.php 89.28% 3 Missing ⚠️
... and 11 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1132      +/-   ##
==========================================
+ Coverage   94.08%   94.10%   +0.01%     
==========================================
  Files         651      678      +27     
  Lines       87983    89539    +1556     
==========================================
+ Hits        82777    84258    +1481     
- Misses       5206     5281      +75     
Flag Coverage Δ
v2 94.10% <94.81%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rmcdaniel

rmcdaniel commented Nov 14, 2026 •

Copy link
Copy Markdown
Member Author

Exact successor a600ffe, tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f.

The preceding exact 230fb46c full dispatcher completed successfully, including the PHP 8.3 cold recovery test. Its separate complete six-shard default-Maria cycle also passed. It remains NONPASS for integration because Codecov patch coverage was 93.87% against the unchanged 94.08% target. Project coverage passed. No threshold, exclusion or production change is used to resolve that finding.

This direct successor adds only six unit cases in ScopeDescriptorTest and ScopeProgressTest (84 inserted lines). Canonically stored observed/unknown outcomes and verified/unsettled resolutions retain their values and evidence; a success claim stripped of evidence refuses; invalid UTF-8 refuses with its JSON cause; re-admitting an already observed forward outcome returns its original result without changing the native attempt, persisted scope or journal. All production, feature/support fixtures, corpus, migrations and dependency bytes remain identical to reviewed 230fb46c / 551e.

Focused PHP 8.4.27 / PCOV 1.0.12 checks pass 40 tests / 89 assertions, targeted ECS is idempotent, and full Stan reports no errors. The local CLI's existing PHPUnit deprecation is retained. Compared with the exact preceding combined Clover artifact, these tests exercise 16 previously missed source lines across retained decoding, UTF-8 refusal and cached-forward admission. This is diagnostic coverage evidence; the new hosted aggregate/Codecov checks still decide the gate. Initial formatting differences were applied and the first attempt is retained separately. All focused runner/Redis/network IDs and exact task labels are independently absent, with no OOM.

Fresh full qualification is now selected for this exact head: ordinary full dispatcher 43558171817, normal PR checks, and a new complete six-shard default-Maria cycle using all 3,155 declared feature identities. The captured source contains all 2,561 tracked blobs with exact modes. Prior complete cycles retain their own heads; the earlier cold-recovery failures remain recorded. Draft, whole-head review, current full coverage/backend gates and accepted-main verification remain required. No release, #1130 or 2.29 authority is selected.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security narrow source rebind PASS for exact head a600ffe353ae0daec992ee2f6f0a142a154d8f31 / tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f, scoped to the direct successor from reviewed 230fb46c.

Independent diff review confirms exactly two modified files and 84 inserted lines:

  • tests/Unit/V2/Compensation/ScopeDescriptorTest.php (+62)
  • tests/Unit/V2/Compensation/ScopeProgressTest.php (+22)

There are no production, support/feature, corpus, migration, dependency, workflow, or configuration changes; git diff --check passes.

The six added cases preserve the reviewed contracts:

  • canonical stored observed/unknown forward outcomes retain values and evidence;
  • verified/unsettled/unknown resolutions retain evidence and settlement state;
  • stored success claims with stripped evidence fail closed;
  • invalid UTF-8 is rejected with the underlying JsonException preserved as cause;
  • an already observed forward result is returned from the cache without admitting a new native attempt or mutating the persisted scope/journal.

No test weakens an existing assertion, widens a runtime loop, changes a threshold, or suppresses coverage. The focused 40/89, ECS idempotence, full Stan and local PCOV observations are consistent with this source delta.

The preceding 230fb46c dispatcher/Maria successes remain predecessor-scoped, and its 93.87% patch-coverage result remains NONPASS against the 94.08% target. This verdict does not promote those results to a600ffe3. Keep the PR draft/unmerged until the fresh exact-head dispatcher, complete six-shard Maria run, hosted coverage/Codecov, ordinary CI, and final whole-head gate inventory are terminal. No release, #1130, or 2.29 authority follows.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Exact a600ffe / tree4b3906bc complete default-MariaDB cycle is PASS.

All six shards finished 3,155 cases / 31,550 assertions, zero failures/errors, with the 37 declared backend-specific skips unchanged. Both InnoDB compensation contention cases executed and passed. Each local report retains its existing single PHPUnit CLI deprecation.

The identity comparator matches all 3,155 declared tests exactly once across the six reports: no missing/extra/duplicate identities. All six independently collected inventories share SHA-256 52cd9f46369407c69b4c175ac7417b4426dfc707a53dd21f63291ac9ddd55db0. Shard totals are 413, 318, 754, 565, 690 and 415.

MariaDB is 10.5.29 with explicit_defaults_for_timestamp=0, flush-on-commit 2, sync-binlog 0 and max-connections 500. Two isolated serial three-shard cohorts used the previously reviewed finite profile; source/vendor were read-only and each cohort owned its DB, Redis, private Testbench state and internal network. All 2,561 tracked blobs and modes remain exact. All 18 runner steps exited zero without OOM; all 24 captured container/network IDs and both exact task inventories are independently absent. No local Workflow quality/runtime resource remains. Temporary diagnostic artifacts are retained through November 21.

Shard JUnit SHA-256
0 80ceaf8a488488bf6cfb70bfb682805b6dfe49e12e1f2c9f0aa7327ec1852aee
1 d6fe430c30d8c9bf6652f3f16fb4684fcd29274f0ba19dcb9e9b7c37d55b8721
2 2bb8d5574004fe52c986b99930622d4ce65c86d386f425057b1a16790119056e
3 6cdbfdf530d7def3f2468c84395a815149d9f079938f263f6a50b2145c1a696a
4 eb679c9f065e677ad81d92e09dda2001c6e4a15bbc330bdc2cdd0969b6d5711e
5 5268956ba82941cf545fb7429ff92c6b98a63577ec8b13de332e0493b426e2f1

This closes the current-head complete default-Maria inventory gate only. Full dispatcher43558171817 still has full unit/coverage and MySQL shard3 active; all completed jobs currently pass. Current hosted aggregate/Codecov, final exact-head review and normal integration remain required. The PR remains draft; no release/#1130/2.29 selection.

@rmcdaniel

Copy link
Copy Markdown
Member Author

General narrow source/integration rebind PASS for a600ffe353ae0daec992ee2f6f0a142a154d8f31 / tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f, relative to reviewed 230fb46c.

The complete direct delta is 84 inserted lines in the two compensation unit test files. I read those additions against the retained ForwardResult, Resolution and ScopeProgress implementations. The cases check stored outcome/evidence/settlement round trips, rejection of success claims after evidence removal, preservation of the invalid-UTF-8 cause, and reuse of an observed forward result without a new attempt or scope/journal mutation. They exercise the existing contracts without weakening an assertion, changing production bytes or adjusting a coverage threshold.

The preceding composition and explicit-command fixture review remain scoped to their unchanged bytes. This source verdict does not substitute predecessor results for current-head execution. Before normal integration, retain the terminal exact-head full dispatcher, unit/coverage, backend and complete default-Maria identity union, Codecov and ordinary check inventory. No release, #1130 or 2.29 selection follows. I ran no additional suite for this review.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Final qualification at a600ffe / tree4b3906bce4902cb46c204405c0c7fb6e9d62e40f:

  • Ordinary full dispatcher43558171817 is terminal SUCCESS, 23 successful jobs / five intended skips. Full ECS/Stan, regression corpus, all six MySQL and all six PostgreSQL shards, Maria/embedded-upgrade checks and aggregate build pass.
  • Actual hosted full unit/PCOV: 6,223 tests / 84,216 assertions / 49 declared skips, no failures/errors; 15 existing PHPUnit notices retained. Unit line coverage is 80.20%. The source-bound seven-report unit+MySQL aggregate is 93.89%, above the unchanged 93.08% ratchet.
  • Current PR checks are terminal 32: 26 SUCCESS / six intended SKIP, with merge state CLEAN. Codecov's patch check is 94.81% against 94.08% and project check 94.10%; both pass on this exact head. The patch metric API rounds the same 1501/1583 ratio to 94.82%. No threshold/exclusion/checker changes.
  • Complete current default-Maria evidence: 3,155 tests / 31,550 assertions / 37 declared skips, zero failures/errors, every declared identity exactly once, both InnoDB contention cases executed. All 2,561 tracked blobs/modes remain exact and all 24 captured IDs plus task inventories are independently absent. No Workflow local quality/runtime resource remains.
  • The PHP 8.3 MySQL cold-recovery shard again passes 565 / 5,307 / five declared skips at job132335869814. Its explicitly executed child requires both verified scope and completed native recovery within the unchanged 20-poll budget. Earlier failed fixture observations and the 230 patch-coverage failure remain NONPASS at their own heads.
  • Security exact source rebind and General exact unit/integration rebind pass. Current Sonar still reports exactly the 13 unchanged production code-smell findings covered by the responsible disposition; no new finding or suppression.

All downloaded artifacts independently match their API SHA-256 and exact workflow/head binding:

Artifact ID ZIP SHA-256
Unit Clover 14099318410 b5380c06715a56ba3bbd0ce515989a6093850c422f882dbfc454271d8111d9fa
Seven coverage inputs 14099114034 ecefaa04827e5d7371c34219e39ad1c0ae9e4ec33bc92c50446c4a562a0683d3
Versioned aggregate summary 14099243609 8d70d42403cae855b39cb8d876797aaa3e3ecdc2375b8977c3a3038d2fb4ce59

Requesting final exact-head integration readback. Normal non-bypass merge, accepted-main tested-tree/workflow verification and topic cleanup remain the next source-delivery actions. This is unreleased experimental embedded source. No #1130 continuation, 2.29 publication or other-binding installed acceptance is selected; #1063 remains open for its actual remaining integration/delivery requirements.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security final exact-head integration readback PASS for a600ffe353ae0daec992ee2f6f0a142a154d8f31 / tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f.

Independent readback confirms:

  • the PR still points to the reviewed head, is draft/CLEAN, and its current 32-check set is terminal at 26 SUCCESS / six intended SKIP;
  • full dispatcher 43558171817 is bound to this head and completed with exactly 23 successful jobs / five intended skips, with no other conclusion;
  • hosted unit/PCOV completed 6,223 tests / 84,216 assertions / 49 declared skips / 15 retained notices. The downloaded unit Clover has 69,077 covered of 86,126 executable statements, reproducing 80.20%;
  • the downloaded versioned aggregate is bound to this commit and records 80,939 / 86,203 lines, 93.89%, above the unchanged 93.08% ratchet;
  • the three retained artifact ZIPs independently reproduce the published/API digests b5380c06...d9fa, ecefaa04...83d3, and 8d70d424...ce59 for IDs 14099318410, 14099114034, and 14099243609;
  • PHP 8.3 MySQL shard 3 job 132335869814 is bound to this head and passes 565 / 5,307 / five declared skips, including the explicit fresh-process recovery path under the unchanged budget;
  • Codecov patch is 94.81% against 94.08% and project is 94.10%, both successful; and
  • the complete default-Maria proof records 3,155 / 31,550 / 37 declared skips with zero failures/errors, both contention cases executed, exact 2,561 tracked entries, and matching six-shard identities. I independently checked all 24 captured container/network IDs and both exact 1132-outcome-feature task inventories are absent.

The 13 current Sonar findings are the same 13 code-smell keys covered by the existing responsible disposition; there is no new issue, suppression, threshold, source, or checker change.

This closes the exact-head source/integration gate for normal non-bypass merge. It does not authorize a moving-head merge, release, #1130 continuation, 2.29 publication, or other-binding installed acceptance. After normal merge, retain the already-stated accepted-main tree/workflow readback and topic cleanup. #1063 remains open for its remaining integration and delivery requirements.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 14, 2026 05:09
@rmcdaniel
rmcdaniel merged commit 80f2a91 into main Nov 14, 2026
60 checks passed
@rmcdaniel
rmcdaniel deleted the fix/1063-compensation-foundation branch November 14, 2026 05:11
@rmcdaniel

rmcdaniel commented Nov 14, 2026 •

Copy link
Copy Markdown
Member Author

Source delivery is complete on accepted main 80f2a91, tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f. Normal merge parents are accepted 42bcc5d and reviewed/tested a600ffe. The complete accepted tree is byte/mode equal to the tested tree.

All four actual-main workflows are terminal SUCCESS:

Main build 43560188730 has 24 successful jobs/four intended skips. All 33 commit check contexts are terminal: 29 SUCCESS / four intended SKIP, zero failed/active. Full ECS/Stan, full unit/coverage, corpus, all six MySQL and all six PostgreSQL shards, Maria/upgrade/tracing and final Sonar checks pass. Actual PHP 8.3.36 full unit is 6,223 cases / 84,223 assertions / 49 declared skips, with 15 existing notices retained and zero failures/errors. Unit coverage is 80.20%; current seven-report aggregate is 93.89%, above the unchanged 93.08% ratchet. MySQL's fresh-process retained recovery shard again passes 565 / 5,307 / five declared skips.

Main artifact ZIP SHA-256 readbacks match the API's exact 80f2 head binding:

  • Aggregate summary 14100282437: 47dc5e4d64d364b0c7589d1771921a44e39f61ad10727eb0af660f1a2c36bf45.
  • Unit Clover 14099589164: e47358d6dcf4c91797a69effeddc5d7ca864f86e9a9486ee7cf6a017e2847376.

The complete default-Maria 3155/31550 cycle, pre-merge full qualification and final independent integration PASS retain their exact scopes. Historical failed observations and the preceding patch-coverage failure remain NONPASS at their original heads.

The remote topic was removed with an exact expected-head guard and is independently absent by API 404 and Git ref query. The clean owned worktree and local topic are also absent. All 24 captured QA/service/network IDs and the exact task inventories are independently absent; no local Workflow build/test/runtime or watcher remains. Diagnostic evidence is retained through November 21.

The foundation remains experimental and unreleased. #1063 remains open for supported published delivery; the separate #1069 binding work has the accepted source handoff. PR #1110 is closed as superseded by #1131/#1132; the parent source handoff preserves the remaining public acceptance. The #1130 stop and absence of 2.29 publication selection are unchanged. The qualified security-only 2.28.1 artifact and its live Docs adoption retain their independent source and acceptance.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security bounded accepted-main readback for Workflow #1132: PASS at exact merge 80f2a916e677f220927bb6d60cd4e7328e59db13 / tree 4b3906bce4902cb46c204405c0c7fb6e9d62e40f.

Independent checks confirm:

  • remote refs/heads/main resolves to 80f2a916...;
  • the merge parents are accepted main 42bcc5d2... and reviewed/tested head a600ffe3...;
  • the merge tree equals a600ffe3^{tree} exactly and a direct tree diff is empty;
  • the PR is merged, the topic branch is absent both from ls-remote and the GitHub branch API (404), and the local topic/worktree readback is clean;
  • all four actual-main workflow runs for this SHA are terminal success;
  • all 33 check contexts are terminal: 29 success and four intended PR-only skips, with no failure or active context;
  • the main coverage-unit log reports 6,223 tests / 84,223 assertions / 49 declared skips; the aggregate coverage job reports 93.89% (80,938/86,203) against the accepted 93.08% baseline;
  • artifact 14100282437 (v2-coverage-summary, digest 47dc5e4d...) and artifact 14099589164 (unit-coverage, digest e47358d6...) are unexpired and both bind workflow run 43560188730, branch main, and exact head 80f2a916....

This closes only the reviewed #1132 source/integration/main-readback chain. It does not establish or select a package/release, #980 cohort, #1130, 2.29, downstream consumer acceptance, or any new effect. #1063 remains open according to its recorded follow-through; the superseded #1110 disposition remains unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant