Date: 2026-07-24
Branch: codex/data-rule-execution-m3a-m5
Task 7 establishes a fail-closed path from an AI-authored natural-language candidate to an immutable published RuleVersion. Neither caller-supplied compile evidence nor caller-supplied test evidence can advance lifecycle state.
The delivered chain is:
/interpret resolves distinct server-owned input/output schema snapshots,
a required input sample, and an optional golden output before invoking the
authoring model.draft RuleVersion plus an immutable validation profile.ArtifactStore.draft -> validated and logical
plan compiled -> tested.published.compiled -> tested -> published. They must reference a published
RuleVersion and its successful logical test evidence.The public catalog returns published rules only. DataFlow release continues to consume published plans only, so Task 7 does not weaken the Task 4–6 execution boundary.
GenerationReceiptSigner signs a compact, closed JSON claim set containing:
Receipts use the dedicated required RULE_GENERATION_RECEIPT_SECRET and never
fall back to the Flask session secret. Issued-at, expiry, maximum lifetime, and
clock skew are checked cryptographically and against current database time
during consumption.
Draft creation performs SELECT ... FOR UPDATE on the generation record and a
compare-and-set consumption update. A receipt is rejected if it is expired,
tampered, belongs to another actor, has a different source/RuleSpec/candidate
or validation context, has already been consumed, or is linked to another
version.
Publication locks the rule/plan/profile/schema or plan/component/rule/binding/schema rows in one transaction and re-reads the current compiler, RuleSpec, plan, schema, binding, data source, object, dialect, evidence, and audit chain. Same-actor retries after an unknown commit outcome return the canonical published result; a different actor cannot use that replay path. Real PostgreSQL concurrency tests use independent threads, connections, and sessions: same-actor contenders return one canonical result and one audit, while a different actor is rejected after the winning commit.
The authoring agent now has a deterministic maximum of two repair attempts. Each attempt persists:
The prompt hash is calculated from the actual full prompt sent for that attempt, including the output JSON schema and accumulated repair messages. The final generation receipt therefore binds the final repair prompt, not the initial prompt.
Only malformed JSON and closed candidate-contract errors are repairable. Ambiguity and low confidence return clarification requirements immediately. Permission failures, destructive scope, lifecycle failures, and execution failures are never sent into the automatic repair loop.
Logical compile evidence binds the RuleVersion, compiler version, exact plan hash, schema hashes, capabilities, and actor. Logical test evidence additionally binds the exact trusted run ID and server-generated attestation:
All four evidence writers use INSERT ... RETURNING. On a uniqueness conflict
they load the canonical database row, compare the complete security-relevant
content, and return the real existing evidence ID; divergent replay fails
closed.
The logical runner supports assert with both reject and quarantine.
Quarantined rows are removed from the primary output, counted separately as
rows_quarantined, and are not misreported as rejected. The compiler version
was advanced to dataops-polars-1.43.0 for this result-contract change.
Physical SQL preflight validates the exact SQLGlot-bound plan and executes only
EXPLAIN <compiled INSERT ... SELECT ...> through the governed data-source
manager. It never uses ANALYZE and never executes the DML. The resulting
evidence contains dialect, statement digest, and EXPLAIN digest. Real
PostgreSQL and MySQL tests assert that destination row counts remain zero.
Physical Polars preflight stages the latest trusted, ready, unexpired input artifact and executes the exact bound plan in the isolated worker. Both physical backends are rejected on current schema, binding, dialect, plan-hash, RuleVersion, or logical-evidence drift.
Logical dry-run supports a distinct output schema and optional golden Parquet
result. Golden comparison uses canonical output-field order. The real
cross-schema acceptance reads name/mobile, derives name_copy, removes one
quarantined row, and compares the output to the pinned golden artifact.
Migration 20260723_200 is forward-only and adds:
The migration refuses to run when revision 190 contains any published
RuleVersion or execution plan, because pre-Task-7 rows cannot be silently
upgraded into trusted evidence. Physical evidence carries an explicit
legacy_untrusted marker, and publication/Runner/DataFlow gates require it to
be false. Downgrade is deliberately rejected because deleting publication and
generation evidence would break audit and replay guarantees.
The following server-owned operations are available:
POST /api/rules/interpret;POST /api/rules/rule-versions;POST /api/rules/rule-versions/<id>/validate;POST /api/rules/rule-versions/<id>/test;POST /api/rules/rule-versions/<id>/publish;GET /api/rules/rule-versions/<id>/evidence;GET /api/rules/catalog;POST /api/rules/execution-plans/<id>/validate;POST /api/rules/execution-plans/<id>/test;POST /api/rules/execution-plans/<id>/publish.Request bodies and catalog query parameters use closed shapes. Compile/test endpoints do not accept caller evidence. Editor permissions cover validation/testing while publication keeps the existing administrative permission boundary. The documented canonical catalog path is implemented; the prior nested path remains a compatibility alias.
Fail-first evidence included:
Final verification:
183 passed;126 passed;1 passed;PhysicalPlanPublicationService PostgreSQL/MySQL lifecycle, drift,
evidence replay, and PostgreSQL concurrency: 2 passed;626 passed, 29 skipped, 59 subtests passed;All checks passed!;git diff --check: passed;20260723_200 (head);1 passed.Skipped tests are environment-gated integration suites. The required real PostgreSQL, MySQL, and MinIO acceptance tests above were run explicitly against the local Docker services and passed.
Task 7 records publication preflight run IDs and exact evidence in dedicated
logical/physical evidence tables. It does not fabricate production rule_runs
for logical validation because those rows require a real deployment and
component binding. Production execution evidence remains owned by the Task 6
Runner path after a physical plan is published.
Task 7 now supports separate input/output snapshots and cross-schema transformations. The remaining scope is production operational rollout: secret provisioning/rotation, multi-replica load and failure testing, monitoring/alert thresholds, and production canary/rollback evidence. Those operational gates are outside this local Docker acceptance and must be closed before a production environment is declared ready.