task-6-report.md 4.9 KB

Task 6 Report — Artifact handoff and governed rule evidence

Date: 2026-07-23 Branch: codex/data-rule-execution-m3a-m5

Lifecycle boundary: Task 6 consumes only plans already marked published. It does not add, relax, or emulate the Task 7 publication gate.

Outcome

Task 6 now provides a production-wired path from a signed Runner task to one server-attested rule_runs record, optional durable violation evidence, and a closed artifact-only handoff to the next node.

The implementation includes:

  • PostgresRuleEvidenceWriter with canonical deployment, component, rule version, plan hash, DataFlow, workflow version, node, and correlation attestation;
  • a server-derived evidence key that makes a node execution idempotent across different signed task tokens and Runner retries;
  • reliable running to success, failed, unknown, or cancelled finalization with row counts, timings, commit outcome, and bounded public result;
  • commit-acknowledgement rechecks for both run and sample finalization;
  • a maximum 100-row violation sample, redacted before it leaves the isolated Polars worker and redacted again at the evidence boundary;
  • a pending to verified MinIO upload to ready sample state machine with digest, schema hash, reference, expiry, and bounded TTL cleanup;
  • no raw sample values in Runner responses or application log calls;
  • correlation-scoped upstream output resolution that accepts only current, ready, unexpired, storage-attested artifacts;
  • a closed SQL staging reference for same-source pushdown handoff instead of row JSON;
  • Kestra single-predecessor input_artifact and multi-predecessor named input_artifacts expressions, with governed rule nodes receiving no unrelated workflow parameters;
  • a top-level Runner output_artifact field matching the Kestra expression contract while retaining the full bounded result object.

Forward-only schema change

Migration 20260723_160 extends the existing evidence tables without changing historical migrations 110, 140, or 150.

rule_runs gains:

  • nullable legacy-compatible evidence_key with a unique constraint;
  • commit_outcome;
  • bounded public_result;
  • failure_code and updated_at.

rule_violation_samples gains:

  • artifact and schema digests;
  • legacy, pending, ready, and failed handoff states;
  • failure and update fields;
  • one sample per run;
  • a strict 100-row ceiling and retention index.

Downgrade is deliberately rejected because deleting execution evidence would break audit and replay guarantees.

The local Docker PostgreSQL was upgraded through the formal 20260723_150 -> 20260723_160 Alembic path. The existing isolated old-140 migration acceptance also passes through current head.

RED / GREEN evidence

The initial fail-first slice produced five expected failures:

  • four executor evidence tests failed because RulePlanExecutor did not accept an evidence writer;
  • the Kestra artifact-only test failed because downstream parameters contained only workflow inputs and no upstream output reference.

A second fail-first assertion proved that the Polars adapter did not expose a bounded violation sample before the worker implementation was added.

Final verification:

  • focused evidence, Runner, Polars, Kestra, migration, and real integration: 27 passed;
  • full suite: 586 passed, 26 skipped, 59 subtests passed;
  • Ruff across every changed Python file: All checks passed!;
  • git diff --check: passed;
  • Docker Compose configuration validation: passed;
  • historical migration 140/150 diff check: empty.

Real PostgreSQL and MinIO acceptance

The production-path integration uses:

  • source PostgreSQL and source MySQL;
  • platform PostgreSQL at migration head;
  • real MinIO;
  • the isolated Polars worker;
  • PostgresRulePlanRepository;
  • PostgresArtifactResolver;
  • PostgresRuleEvidenceWriter;
  • RulePlanExecutor;
  • signed Runner HTTP tokens and the durable task ledger.

It proves:

  1. the first node reads the PostgreSQL and MySQL artifacts, executes normalize/join/assert/deduplicate, publishes an output, and records one successful run;
  2. one violating row is stored as an all-field-redacted, expiring Parquet sample with ready state and exact digest;
  3. a second published rule node consumes the first node's exact output_artifact reference and publishes a distinct output;
  4. the same correlation contains exactly two successful run records;
  5. a different signed token for the same node replays the existing run and sample instead of executing again;
  6. a failed adapter records failed/not_committed;
  7. an uncertain write records unknown/unknown;
  8. all test-owned PostgreSQL rows and MinIO objects are removed after acceptance.

Residual boundary

Task 6 deliberately does not decide whether a compiled plan may become published. Task 7 must require trusted generation, test, and preflight evidence before changing plan lifecycle state. The evidence added here is the immutable input to that gate, not a bypass around it.