ARN-179: execute PostgreSQL actor effects durably - #372
Conversation
Live local PostgreSQL E2E evidenceThis is a non-security behavioral/durability regression suite. It exercises the previously lossy durable actor path against PostgreSQL 17, including restart persistence, transaction rollback, concurrent timer promotion ordering, and concurrent schema initialization. $ TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test -p temper-actor-runtime --test effect_durability -- --nocapture
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.31s
Running tests/effect_durability.rs (target/debug/deps/effect_durability-9ef044f435447ea3)
running 4 tests
test command_flush_failure_rolls_back_parent_state_cursor_and_commands ... ok
test concurrent_schema_initializers_wait_for_the_global_ddl_lock ... ok
test concurrent_timer_promoters_preserve_global_due_order ... ok
test postgres_effects_survive_restart_and_commit_runtime_commands ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14sFull local gate: $ RUST_TEST_THREADS=1 TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test --workspace
...
ARN179_WORKSPACE_SERIAL_EXIT:0Push hook: |
|
Dedicated GPT-5.6 review of the open GitHub diff at head 2209723. The exhaustive JIT match, atomic PostgreSQL state/command flush, scheduled-message staging, serialized promotion query, and transactional DDL initialization are directionally sound. The following behavioral and durability regressions remain blocking:
Verdict: FAIL |
Reviewer-finding RED/GREEN evidenceThe dedicated GPT-5.6 review at head
RED (before fix)GREEN (current head)$ TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test -p temper-actor-runtime
unit tests: 10 passed; 0 failed
effect_durability: 4 passed; 0 failed
integration: 5 passed; 0 failed
reaction_durability: 2 passed; 0 failedAdditional behavioral contracts now green:
$ cargo test -p temper-runtime reaction
test result: ok. 6 passed; 0 failed
$ cargo clippy --workspace --all-targets -- -D warnings
Finished `dev` profile
$ RUST_TEST_THREADS=1 TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test --workspace
...
ARN179_REVIEW_FIX_WORKSPACE_EXIT:0Updated push hook: |
|
Dedicated GPT-5.6 re-review of the open GitHub PR diff at head I rechecked all five blockers from the prior
Additional review:
No actionable correctness or durability finding remains in the current open PR diff. Verdict: PASS |
|
@greptile review |
Final Greptile-finding RED/GREEN and live E2E evidenceThe four prior Greptile threads were treated as non-security behavioral/durability regressions. The two executable failures were isolated before the fixes:
RED evidence: Live local PostgreSQL production-chain E2E after GREEN: $ TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' \
cargo test -p temper-agents --test agent_chain \
test_process_reaction_forwards_only_declared_prompt_to_llm -- --nocapture
running 1 test
test test_process_reaction_forwards_only_declared_prompt_to_llm ... ok
test result: ok. 1 passed; 0 failedThat test persists the actual {"user_prompt":"declared prompt"}The undeclared Final local gates at head Normal |
|
Dedicated GPT-5.6 review of the open GitHub PR diff at exact head I rechecked the full One non-security correctness/durability blocker remains:
Verdict: FAIL |
Dedicated reviewer FAIL follow-up — RED/GREENThe exact-head GPT-5.6 review at Reviewer verdict: #372 (comment) RED — failing regression committed aloneCommit: Added to: The test failed on that exact durability mismatch. GREEN — root-cause fixCommit: The shared actor ingress now projects action parameters into durable entity fields only when the parameters are a non-empty JSON object, matching the canonical server behavior. Scalar, array, and null parameters remain available to JIT effect evaluation but cannot replace the durable entity record. Focused verification: Exact-head review gates: The PR head is now |
|
Dedicated GPT-5.6 re-review of the complete open GitHub PR diff at exact head The prior durable-field replacement blocker is fixed at its root. RED commit One non-security parameter-semantics blocker remains:
Verdict: FAIL |
Dedicated reviewer FAIL follow-up — routed JSON
|
|
Dedicated GPT-5.6 re-review of the complete open GitHub PR diff at exact head The routed-null blocker is resolved. RED commit The complete parameter path is now coherent with the canonical server:
Focused reviewer validation at this exact head passed: actor spec/reaction tests 13/13, runtime reaction-registry tests 8/8, production Temper Agents chain tests 4/4, and Verdict: PASS |
|
@greptile review |
1 similar comment
|
@greptile review |
Greptile finding — duplicate spawn initialization RED/GREENThe identity-correct Greptile review found one additional non-security durability defect: Greptile thread: #372 (comment) RED — failing PostgreSQL behavioral regression committed aloneCommit:
$ TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test -p temper-actor-runtime --test effect_durability duplicate_durable_spawn_enqueues_initial_action_once -- --exact --nocapture
running 1 test
assertion `left == right` failed: an existing durable child must not receive the initial action again
left: 2
right: 1
test duplicate_durable_spawn_enqueues_initial_action_once ... FAILEDGREEN — atomic one-time initializationCommit: The parent activation transaction now retains the affected-row count from Focused regression after the fix: $ TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_final' cargo test -p temper-actor-runtime --test effect_durability duplicate_durable_spawn_enqueues_initial_action_once -- --exact --nocapture
running 1 test
test duplicate_durable_spawn_enqueues_initial_action_once ... ok
test result: ok. 1 passed; 0 failedFresh-database live PostgreSQL E2E: $ createdb -h 127.0.0.1 -p 55432 -U postgres arn179_greptile_fix
$ RUST_TEST_THREADS=1 TEMPER_TEST_DATABASE_URL='host=127.0.0.1 port=55432 user=postgres dbname=arn179_greptile_fix' cargo test -p temper-actor-runtime --test effect_durability -- --nocapture
running 5 tests
test command_flush_failure_rolls_back_parent_state_cursor_and_commands ... ok
test concurrent_schema_initializers_wait_for_the_global_ddl_lock ... ok
test concurrent_timer_promoters_preserve_global_due_order ... ok
test duplicate_durable_spawn_enqueues_initial_action_once ... ok
test postgres_effects_survive_restart_and_commit_runtime_commands ... ok
test result: ok. 5 passed; 0 failedExact-head gates: The PR head is now |
|
Dedicated GPT-5.6 review of the complete open GitHub PR diff at exact head No actionable non-security correctness or durability finding remains. The duplicate-spawn regression is correctly isolated and fixed:
I re-audited the full GitHub-hosted GitHub checks visible during review were green for compile/lint, integrity and DST patterns, verification contract, spec verification, instrumentation hygiene, and platform-random DST; the remaining long-running suites were still pending and do not change this code-review verdict. Verdict: PASS |
|
@greptile review |
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
|
ARENA SHIPPABLE · Codex (GPT-5.6) · 2026-07-13 12:16 PDT
Final audit:
|
|
Closing this ARN-179 competition entry. Adjudicated in favor of Fable #370 (completeness/scope). This branch is preserved for grafting its best parts into the winner; full scoring is on the ARN-165 arena board. (Rita-directed close, 2026-08-11.) |
Behavioral / durability regression\n\nPostgreSQL-backed actors could accept a transition while silently dropping runtime effects. The durable actor path interpreted only a subset of the canonical effect vocabulary, so accepted actions could lose field mutations, item updates, counter changes, tells, schedules, or spawns across commit/restart boundaries.\n\nThis is a non-security correctness and durability fix for ARN-179.\n\n## RED\n\n- Added a PostgreSQL actor regression that drives the complete effect vocabulary through the durable runtime.\n- Confirmed the test failed before the fix because effects were not fully executed/persisted.\n- RED commit: 766ad94\n\n## GREEN\n\n- Added one exhaustive canonical effect executor in temper-jit and shared it across in-memory/server and PostgreSQL actor adapters.\n- Made tells, schedules, and spawns transaction-buffered so rollback cannot leak side effects.\n- Added durable delayed-message staging and globally ordered promotion.\n- Made PostgreSQL actor schema initialization atomic and safe under concurrent startup.\n- Preserved full compatible reaction registries; rejected reaction semantics that the CLI actor mode cannot preserve instead of silently degrading them.\n- GREEN commit: 2209723\n\n## Validation\n\n- Dedicated local code-quality review: PASS\n- Dedicated DST compliance review: PASS\n- PostgreSQL durability E2E: 4/4\n- Canonical effect conformance: PASS\n- CLI reaction wiring: 13/13\n- Server effect tests: 27/27\n- Actor runtime spec tests: 5/5\n- Full workspace tests and doctests: PASS\n- Pre-push rustfmt, strict clippy, readability ratchet, and full workspace suite: ALL GATES PASSED\n\nExact live commands and output are posted as a PR comment.
Greptile Summary
This PR fixes a correctness and durability regression in the PostgreSQL-backed actor runtime: the durable activation path previously interpreted only a subset of the effect vocabulary, silently dropping field mutations, counter changes, list operations, tells, schedules, and spawns across commit/restart boundaries.
temper-jit: A single exhaustiveapply_effectsfunction now covers the fullEffectenum and is shared across the in-memory, server, and PostgreSQL backends — eliminating the silent-discard behaviour and making simulation and production code paths identical.CREATE_ACTOR ON CONFLICT DO NOTHINGidempotency fix ensures a duplicate spawn does not re-deliver the initial action.create_tablesnow holds apg_advisory_xact_lockover the full DDL sequence, and thePROMOTE_DUE_MESSAGESCTE atomically selects, locks, deletes, and reinserts due messages with a global advisory lock, preserving FIFO order under concurrent promoters.Confidence Score: 5/5
Safe to merge — the change restores correct, atomic execution of the full effect vocabulary for PostgreSQL-backed actors with no regressions found in the shared canonical executor or the transaction flush paths.
All durable paths (spawn, scheduled tell, immediate tell, state mutation) are now committed or rolled back together inside one PostgreSQL transaction. The canonical effect executor is exhaustive by design — adding a new Effect variant fails to compile until its semantics are defined. The idempotent-spawn guard, cascade-depth budget, advisory-lock schema initialization, and ordered timer promotion are each covered by dedicated PostgreSQL integration tests. No logic gaps or unguarded edge cases were found across the changed files.
No files require special attention. The most complex new logic — the budget calculation in spec_actor.rs and the spawn-flush loop in pg.rs — has direct test coverage in effect_durability.rs.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Handler as SpecDrivenActor.handle() participant JIT as temper_jit::apply_effects() participant Ctx as ActorContext (buffers) participant PG as PostgreSQL tx Handler->>JIT: "apply_effects(&mut state, &effects, ¶ms)" JIT-->>Handler: "EffectExecution {emitted_events, scheduled_actions, spawn_requests}" Handler->>Ctx: execute_commands(execution, cascade_depth) Ctx->>Ctx: ctx.tell(target, msg) to pending_tells Ctx->>Ctx: ctx.tell_after(self, msg, delay) to pending_tells (deliver_at set) Ctx->>Ctx: ctx.buffer_spawn(target, fields, init_msg) to pending_spawns Handler->>PG: UPDATE actor_instances SET state, version PG-->>Handler: affected rows (optimistic lock check) Handler->>PG: INSERT actor_scheduled_messages (deliver_at tells) Handler->>PG: INSERT actor_messages (immediate tells) Handler->>PG: INSERT actor_instances (spawned children, ON CONFLICT DO NOTHING) Note over Handler,PG: INSERT initial_message only when created==1 Handler->>PG: COMMIT Note over PG: Scheduler PROMOTE_DUE_MESSAGES CTE moves due timers into actor_messages FIFO%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Handler as SpecDrivenActor.handle() participant JIT as temper_jit::apply_effects() participant Ctx as ActorContext (buffers) participant PG as PostgreSQL tx Handler->>JIT: "apply_effects(&mut state, &effects, ¶ms)" JIT-->>Handler: "EffectExecution {emitted_events, scheduled_actions, spawn_requests}" Handler->>Ctx: execute_commands(execution, cascade_depth) Ctx->>Ctx: ctx.tell(target, msg) to pending_tells Ctx->>Ctx: ctx.tell_after(self, msg, delay) to pending_tells (deliver_at set) Ctx->>Ctx: ctx.buffer_spawn(target, fields, init_msg) to pending_spawns Handler->>PG: UPDATE actor_instances SET state, version PG-->>Handler: affected rows (optimistic lock check) Handler->>PG: INSERT actor_scheduled_messages (deliver_at tells) Handler->>PG: INSERT actor_messages (immediate tells) Handler->>PG: INSERT actor_instances (spawned children, ON CONFLICT DO NOTHING) Note over Handler,PG: INSERT initial_message only when created==1 Handler->>PG: COMMIT Note over PG: Scheduler PROMOTE_DUE_MESSAGES CTE moves due timers into actor_messages FIFOReviews (4): Last reviewed commit: "fix: initialize durable child actors onc..." | Re-trigger Greptile