Skip to content

P1: unconfirmed JDBC commit or rollback must report an unknown transaction outcome #235

Open

Description

@philipgreat

In the P1 Committed Mutation candidate, JdbcSqlExecutor.executeInTransaction calls Connection.commit inside the transaction body. A SQLException from commit is currently wrapped as ordinary JDBC transaction failed. TeaQLRuntime.saveGraph then restores entity persistence state as though rollback were certain. However a JDBC driver or network may report a lost acknowledgement after the database already committed the business row and Outbox.

Required invariant: a failed commit acknowledgement must not be represented as a known rollback or a known commit. Return a structured unknown-outcome error with a fixed non-sensitive message, mark the affected entity mutation ledger reload-required, and prohibit replay of the same graph until a fresh database/outbox read reconciles the outcome. A true precommit action failure remains a known rollback. Do not attach raw JDBC exception text to logs or public error paths.

Acceptance evidence: real SQLite fault injection that delegates commit to the database and then throws SQLException; a separate connection proves the row durable while the caller receives unknown-outcome, and a second save of the same graph is rejected. Also test a commit failure before the database commit so both possibilities use the same conservative classification. This is separate from post-commit cleanup defect #233 and from audit delivery API choice #225.

Activity

  1. philipgreat commented on Oct 19, 2026

    @philipgreat
    ContributorAuthor

    Red evidence from the integrated P1 candidate plus #234 cleanup fix, before the #235 implementation: the two real-SQLite tests both failed. In the after-commit-then-SQLException case, the durable row and Outbox existed but the caller received ordinary JDBC transaction failed. In the before-commit-SQLException case, the expected row count was 0 but was 1: restoring autoCommit without first rolling back implicitly committed the pending write. The focused red command was: mvn -q -pl teaql-sqlite -am -Dtest=GraphTraceSqliteTest#lostCommitAcknowledgementAfterDurableWriteRequiresReload+failedCommitBeforeWriteRequiresTheSameConservativeReload -Dsurefire.failIfNoSpecifiedTests=false test. This confirms both unknown-outcome classification and rollback-before-autocommit-restoration are required.

  2. changed the title [-]P1: JDBC commit acknowledgement loss must report an unknown transaction outcome[/-] [+]P1: unconfirmed JDBC commit or rollback must report an unknown transaction outcome[/+] on Oct 19, 2026
  3. philipgreat commented on Oct 19, 2026

    @philipgreat
    ContributorAuthor

    Additional red evidence: after a business operation fails because the Outbox table is unavailable, fault-injecting SQLException before the actual rollback leaves the current executor calling setAutoCommit(true). The real-SQLite test failed at the assertion that autoCommit restoration must not occur; this path can implicitly commit business rows without the Outbox. The conservative recovery rule must therefore cover rollback acknowledgement failure as well as commit acknowledgement failure: report unknown outcome, skip autoCommit restoration, close the connection, and require a fresh graph/database read before retry. The focused red test is GraphTraceSqliteTest#failedRollbackMustNotImplicitlyCommitOnAutoCommitRestoration.

  4. philipgreat commented on Oct 19, 2026

    @philipgreat
    ContributorAuthor

    Draft #236 advanced to exact head dee5bbe after a RED/GREEN real-SQLite test found that JVM Error + failed rollback left the same mutation graph retryable. The fix preserves the original Error, attaches a sanitized unknown-outcome marker, fences only that graph, and leaves an independent graph saveable. At this head: GraphTraceSqliteTest 40/40, affected reactor suite green, remote examples green; 21-artifact internal Maven package, installed-JAR fault suite 40/40 twice, and generated Customer save/Q/E twice are retained in teaql-conformance evidence: https://github.com/teaql/teaql-conformance/tree/main/evidence/2026-10-20-p1-java-unknown-error-guard . Review and formal-chain integration remain open; this does not close #235 yet.

  5. philipgreat commented on Oct 19, 2026

    @philipgreat
    ContributorAuthor

    Draft #236 advanced to exact head dd32106. A second RED probe found that an Error with suppressed diagnostics disabled could lose the unknown-outcome marker after failed rollback, leaving the same graph retryable. The fix carries the original Error across the provider/runtime boundary, fences the affected graph before rethrowing it, and preserves sanitized diagnostics. Source GraphTraceSqliteTest 41/41, affected Maven reactor, remote examples CI, exact 21-artifact internal Maven package, downloaded-JAR fault suite 41/41 twice, and generated Customer save/Q/E twice pass. Current review-only evidence: https://github.com/teaql/teaql-conformance/tree/main/evidence/2026-10-20-p1-java-unsuppressible-error-outcome . Earlier dee5bbe evidence is historical. Formal-chain integration, human review, non-SQLite fault injection, and public release remain open; do not close #235 yet.

  6. philipgreat commented on Oct 19, 2026

    @philipgreat
    ContributorAuthor

    Draft #236 advanced to exact head edbae2b after real-SQLite RED probes found JDBC commit/rollback Error paths outside the unknown-outcome guard and a post-commit logging-handler Error that misreported success as failure. The fix fences the affected ledger, skips autoCommit restoration after unconfirmed rollback, and retains confirmed-commit semantics. Source GraphTraceSqliteTest 44/44 plus JdbcCommittedCleanupSqliteTest 6/6, full affected Maven reactor, exact-head examples CI, 21-artifact immutable internal Maven package, downloaded-JAR 44+6 fault suite twice, and generated Customer save/Q/E twice pass. Current review-only evidence: https://github.com/teaql/teaql-conformance/tree/main/evidence/2026-10-20-p1-java-jdbc-error-boundary . Earlier dd32106 evidence is historical. Formal-chain integration, human review, non-SQLite fault injection and public release remain open; #235 is not closed.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions