Skip to content

Add typed runtime GraphQL mutations with committed output authorization [skip ci] - #115

Merged
Dastari merged 7 commits into
mainfrom
feat/runtime-graphql-mutations-20261011
Oct 12, 2026
Merged

Dastari merged 7 commits into
mainfrom
feat/runtime-graphql-mutations-20261011

Conversation

@Dastari

@Dastari Dastari commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

Implement D on accepted C/B: typed runtime GraphQL create/update/exact-key delete delegate to B's pinned state-machine transactions, independent intent/preimage/result authority and guarded atomic journal hooks. Every validated response-key group commits before returning a successful payload. Scalar return projections retain C's corrected alias identity and lossless wire forms; CAS authorization retains requested capabilities before empty-list constant lowering.

Base: 9d4cca34cb04ab0fd27c8313215001591f495c43 (#114), containing accepted B 04a1216aff86141ff6500b1dd0bf9adb4b0c6447 (#113).
Head: 3a59d08be5b663ac952de418eb02dc6321ee08e7.
ORM/macros: aligned unpublished 0.43.0. Enable sqlite,runtime-graphql or postgres,runtime-graphql with default features disabled. This implementation awaits exact-head review; it is not an adoptable release.

D1 correction

The reviewed D head e1568ec29cb5b25750cd7f90c39114b26e32be74 allowed the locked dynamic executor's repeated resolver occurrences to start duplicate transactions. Repeated create reproduces constraint errors; repeated CAS could commit then report a redundant conflict. The new regression failed on that implementation before the correction.

Each validated response key now has one request-scoped execution attempt and a terminal payload/error. Preflight merges inline/fragment payload fields, preserves first-occurrence document order and authorizes their complete projection. The first invocation executes B's transaction, guarded journal and post-commit authority once; repeats reuse its immutable captured result. The framework's response-object merger combines the selected fields. Distinct aliases remain separate serial transactions, even for the same record.

A dropped operation guard records a terminal nonretryable error, so an extension catching a resolver timeout and continuing to a repeat cannot restart work. After confirmed commit the error is mutation_payload_canceled with outcome: "committed"; before confirmation it is mutation_outcome_unknown with outcome: "unknown", including possible COMMIT cancellation. Neither promises rollback or permits blind retries. Normal denial/error/timeout results are cached too. Each occurrence may report the cached sanitized error at its own location.

Budgets reserve one group, not every repeated occurrence: four conservative ORM statements, one materialized node and the merged response shape. Document/fragment limits still count every occurrence. Host hooks bound their own extra I/O. Tests check one-group bounds (3 rejected/4 admitted), two-alias bounds (7 rejected/8 admitted), node limits and response capacity.

Owned SQLite/PostgreSQL regressions execute create/update/delete repeats, successful and stale CAS, named and inline fragments, merged scalar aliases, projection denial, distinct aliases in reverse lexical order, journal failures, post-commit denial/error/timeout, and canceled hooks/output authority while the executor continues. They assert single write-intent admission, journal invocation/row and post-commit check, current committed state and undisclosed denied values. Fresh requests do not reuse execution outcomes. Invalid conflicting repeats are still rejected by original GraphQL validation before writes.

No framework upgrade/fork, public interface change, data migration or changes to A–C are required.

Approved post-commit output contract

RuntimeReadAuthority::authorize_mutation_result is object-safe and defaults to denial. Existing C-only implementations remain source-compatible. It supplements projection authorization before selection and B's transaction-bound result authorization.

The callback receives schema/collection identity, mutation action, selected projection and immutable transaction-captured record. RuntimeMutationRecordKind::DeletedPreimage identifies delete output; ORM performs no post-commit reread. Internal policy/key fields stay unloaded, and serialization iterates only the selected projection after approval. Hosts must deny if policy-required values are absent.

Explicit/default denial returns mutation_payload_denied; other callback/encoding/budget errors return mutation_payload_failed; the bounded callback timeout returns mutation_payload_timeout. These sanitized errors contain extensions.outcome = "committed" and extensions.retryable = false, with no protected values. They do not undo the write/journal. No callback runs for no-record/typename-only payloads. Whole-request cancellation or transport loss after commit may deliver no response: clients must reconcile state rather than infer rollback or retry blindly.

Public APIs and executable example

  • RuntimeGraphqlOptions::with_mutations(RuntimeGraphqlMutationOptions); configurable action enablement, mutation limits and post-commit authorization timeout (default five seconds).
  • Checked mutation_root and mutation_field; typed create/update/key inputs, existing recursive filters for CAS, schema fingerprint validation and scalar-only record payloads.
  • Request builders: with_mutation_environment, with_write_authority, with_mutation_hook.
  • RuntimeMutationOutputCheck, RuntimeMutationRecordKind and the default-deny callback above.

The compiled crates/graphql-orm/examples/runtime_graphql_reads.rs now demonstrates C/D together: protected reads, typed create, CAS update, exact-key delete, typed private journal inserts in the transaction, and explicit post-commit public-record release. The external repository consumer executes that same example without a direct async-graphql dependency.

Local verification

Actions remain paused; skip-CI commits; CARGO_BUILD_JOBS=2; sequential backend lanes; disk scratch. SQLite resources are test-owned. PostgreSQL fixtures start isolated disposable servers and verify container identity/ownership before cleanup.

  • SQLite: 76 passed, zero ignored in the selected library/static naming/runtime read/relation/mutation lanes.
  • PostgreSQL: 73 passed, zero ignored in the selected library/runtime GraphQL/mutation lanes. These include C's RLS fixture and B's policy/journal/cancellation tests. Fix runtime string predicates and PostgreSQL native parameter binding #112-gated PostgreSQL string/CAS subcases are still unexecuted; zero ignored does not imply those branches ran.
  • Eleven D integration test functions per backend, including five D1 regression functions. The post-commit matrix executes allow, default denial, explicit denial, error, callback timeout and whole-request cancellation for both create results and delete preimages. It verifies committed journals inside the callback, committed data afterward, hidden fields unloaded and denied records undisclosed. Precommit projection/result denial still rolls back and never invokes the callback.
  • Required/composite keys, null handling, CAS success/conflict, C2 empty-list CAS denial, policy-only revision denial, journal failure and precommit cancellation rollback remain covered. Concurrent GraphQL CAS calls cannot both succeed. SQLite's D fixture uses one in-memory pool/connection; this is not new independent-pool contention evidence.
  • External host examples compiled and executed on SQLite/PostgreSQL; feature-off framework-neutral consumers compiled on both.
  • Formatting, warnings-denied scoped Clippy/Rustdoc for explicit SQLite/PostgreSQL/MSSQL lanes, SQLite+MSSQL compilation, and MSSQL pre-I/O rejection passed. No live MSSQL execution.
  • Static compatibility against accepted C passed 223 checks, with 30 inapplicable checks skipped, using isolated current/baseline outputs.
  • Documentation, generated inventory, dependency direction, package release policy, release-state, release-manifest and PR documentation-impact checks passed.
  • An initial external example build failed because it named serde_json directly. The final example uses graphql-orm's re-export and passed. No extra direct dependency was added.

Commands (all build commands use the two-job environment):

cargo test -p graphql-orm --locked --no-default-features --features sqlite,runtime-graphql --lib --test runtime_graphql --test graphql_naming --test runtime_queries --test runtime_relations --test runtime_mutations -- --test-threads=1
cargo test -p graphql-orm --locked --no-default-features --features postgres,runtime-graphql --lib --test runtime_graphql --test runtime_mutations -- --test-threads=1
cargo run --manifest-path crates/graphql-orm/tests/fixtures/repository-aggregate-consumer/Cargo.toml --locked --no-default-features --features sqlite,runtime-graphql --example runtime_graphql_reads
cargo run --manifest-path crates/graphql-orm/tests/fixtures/repository-aggregate-consumer/Cargo.toml --locked --no-default-features --features postgres,runtime-graphql --example runtime_graphql_reads
cargo clippy -p graphql-orm -p graphql-orm-macros --locked --no-default-features --features sqlite,runtime-graphql --lib --test runtime_graphql --test runtime_mutations --example runtime_graphql_reads -- -D warnings
RUSTDOCFLAGS=-Dwarnings cargo doc -p graphql-orm -p graphql-orm-macros --locked --no-default-features --features sqlite,runtime-graphql --no-deps
cargo test -p graphql-orm --locked --no-default-features --features mssql,runtime-graphql --test runtime_graphql_unsupported
env -u CARGO_TARGET_DIR cargo semver-checks -p graphql-orm --manifest-path crates/graphql-orm/Cargo.toml --baseline-rev 9d4cca34cb04ab0fd27c8313215001591f495c43 --default-features --release-type patch
cargo fmt --all -- --check
python3 scripts/check-documentation.py --base 9d4cca34cb04ab0fd27c8313215001591f495c43

Clippy/Rustdoc were repeated sequentially on PostgreSQL. MSSQL scoped Clippy targets the library and unsupported-backend test; its Rustdoc lane also passed. Hosted checks were not dispatched or rerun.

Compatibility, limitations and integration

No data migration or static API/SDL change. Non-generated create keys are required; generated fields are excluded and keys cannot be patched. Defaults remain omitted from GraphQL SDL; nullable omission/null stay distinct. Enabled create/update actions with no writable input fields reject with unsupported_capability (GraphQL disallows empty input objects); hosts may disable those actions. Nested/bulk writes, new upsert semantics and nested relation return payloads are not provided. Custom-directive factories retain C's explicit composition-time rejection.

Each distinct runtime mutation response-key group is a separate transaction; there is no whole-operation atomicity or durable event replay. Host hooks own and bound their additional I/O. The host owns policy-only revision validation, policy pinning, schema/DDL fencing, transport and outcome reconciliation. Default output denial intentionally means a committed write can yield a committed payload error.

Digibase handoff after exact-head review and owner release: retain the accepted C setup, enable mutations, compose the mutation root, attach the certified environment and pinned B write authority, install the guarded journal hook, and explicitly implement the new output callback. Validate complete public/policy revision independently of the ORM fingerprint. Run downstream SQLite/PostgreSQL null/default/key/CAS/journal and committed-output denial/cancellation contracts before adoption.

Final owner-controlled #112 → A → B → C → D reconciliation must still execute successful PostgreSQL string/CAS behavior. No merge, publication, immutable release identity or downstream adoption is claimed. Sibling repositories and predecessor worktrees remain untouched. T3 native linking attempts return Authentication required.

Documentation impact

  • Documentation updated
  • No documentation impact

Explanation: D updates the approved contract, runtime GraphQL reference, executable host example, compatibility/migration notes, changelog, versions/locks and inventory. D1 additionally documents response-key grouping, ordering, merged budgets and terminal cancellation outcomes; existing 0.43.0 versions and locks are unchanged by this correction. Post-commit denial, deleted preimages, hidden fields and cancellation/transport uncertainty are explicit.

@Dastari Dastari changed the title Runtime GraphQL mutations: D delegation and output-authority checkpoint [skip ci] Add typed runtime GraphQL mutations with committed output authorization [skip ci] Oct 11, 2026
Dastari and others added 2 commits October 11, 2026 17:06
… [skip ci]

Owner-authorized C reconciliation. Exact tested C tree retained, including corrected aliases/filter intent, protected cursors, lossless scalars and approved custom-directive rejection. Actions remain paused.
Retain exact tested reconciliation tree 8e9228b. No source deviation.
@Dastari
Dastari changed the base branch from feat/runtime-graphql-reads-20261009 to main October 12, 2026 00:06
@Dastari
Dastari marked this pull request as ready for review October 12, 2026 00:06
@Dastari
Dastari merged commit 531fa07 into main Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant