Skip to content

126 · T111 — the submission projection and audit surface - #136

Merged
athvin merged 4 commits into
mainfrom
feat/t111-submission-projection-and-audit
Aug 3, 2026
Merged

athvin merged 4 commits into
mainfrom
feat/t111-submission-projection-and-audit

Conversation

@athvin

@athvin athvin commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Ticket: T111 — docs/implementation/126-T111-submission-projection-and-audit.md

Summary

Projects T108's attempt-submitted records into the run index and ships the audit
surface over them. fold_stream surfaces submissions on the RunArtifact — including
submissions that never produced an outcome — while staying a deterministic reader with
no store, network, or graph access. An additive attempt_submitted table (plus a child
attempt_submitted_input carrying positional order) lands through the existing
migration mechanism with no foreign keys, produced through the same build_statements
path so live-tee and sync rows are byte-identical. Four worked audit queries ship in
the cookbook; no new CLI verb.

Tests-first

Confirmed — failing tests committed first in 555e246.

Definition of done

  • fold_stream surfaces attempt-submitted records on the RunArtifact, including submissions with no outcome; the fold stays a deterministic reader with no store, network, or graph access.
  • An additive attempt_submitted table and its indexes land through the existing migration mechanism, with no foreign keys; an existing store upgrades in place and converges with a fresh one.
  • Rows are produced through the same build_statements path; live-tee and sync rows are byte-identical and sync is idempotent.
  • Positional input order is preserved and queryable; a consume-nothing source records zero inputs, distinguishable from unknown.
  • Intended and observed target identity are separate columns; submitted-but-never-completed is a queryable state (completed=0 + NULL outcome_state, rather than a tenth state token).
  • Cookbook ships worked audit queries for: launch parameters of a given attempt, submitted-never-completed attempts, submitted-vs-read divergence, and the join to existing lineage tables.
  • The metastore still has no edge onto dagr-core; the feature stays default-off; a toggle-off run is unchanged; the acceptance-boundary script passes.
  • Tests pass on ubuntu-latest and macos-latestpending, confirmed by this PR's CI.
  • CI is green on the ticket branch — pending. The local gate is GATE=PASS (36 PASS, 1 deliberate SKIP, 0 FAIL), verified on the committed tree, but CI on the PR is the authoritative verdict.

Open questions resolved

Both ticket questions plus two in-PR decisions are recorded in the ticket's
## Open questions section (docs/tasks.md enumerates M0–M4 only and carries no T111
entry):

  1. Child table vs encoded column for inputs → a child attempt_submitted_input
    table with a position column. Decided against the shipped queries: two of the
    four filter on an individual reference, which an encoded column would make
    unqueryable.
  2. Divergence query: SQL or a verb → SQL in the cookbook, a single join, no verb
    added.
  3. Submissions on the RunArtifact type but NOT in to_value() — which preserves
    T108's merged byte-identical-artifact assertion.
  4. Submitted-but-never-completed as completed=0 + NULL outcome_state, rather
    than introducing a tenth state token into the terminal taxonomy.

Deviations

None.

Notes

Two correctness decisions worth calling out, both about not letting the audit surface
overstate what happened:

  • The fold surfaces submissions from the records themselves, not from the assembled
    attempt list. The assembled list synthesizes coverage rows at try 1, so folding from
    it would have claimed an outcome for attempts that never produced one.
  • A submitted input deliberately produces no asset row. Submission is intent, and
    an attempt that never ran consumed nothing.

The four cookbook queries live inside the existing "Querying run state across DAGs" H2,
so metastore_example_and_docs.rs executes them verbatim against a real store (3
passed, 123s) and metastore_docs_claims.rs guards that the surrounding prose stays
true (6 passed).

Boundaries hold: the run index remains a projection, never authoritative for
execution — nothing in the engine reads it back to make a decision. The feature stays
default-off, the metastore keeps no edge onto dagr-core, and no scripts/check-*.sh
was modified
— including check-metastore-acceptance-boundary.sh, which passes
unchanged.

athvin and others added 4 commits August 2, 2026 18:04
…face

The fold-side scenarios (submitted-with-no-outcome, truncation, positional
order, zero-vs-unknown inputs, intent-vs-reality, determinism, and the
unchanged artifact document) and the metastore-side ones (live-equals-sync
byte identity, idempotent re-sync, in-place upgrade + fresh-store
convergence, no foreign keys, the queryable never-completed state, the join
to node_attempt, and the four worked audit queries).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… the audit queries

`fold_stream` now surfaces `attempt-submitted` records on the `RunArtifact` as
`SubmittedAttempt`s — merging the write-ahead record with the additive one that
carries the observed identity, and, crucially, surfacing submissions that never
produced an attempt-outcome. That case is resolved from the records themselves
rather than from the assembled attempt list, which synthesizes coverage rows and
would otherwise claim an outcome that never happened.

The projection adds two additive, foreign-key-free tables through the existing
migration mechanism: `attempt_submitted` (intent and reality in separate
columns, `completed`/`outcome_state` carrying submitted-but-never-completed
positively, `input_count` keeping zero apart from unknown) and
`attempt_submitted_input` (one row per reference, keyed by its declared
position). Both are written through the same `build_statements` path, so the
live tee and a post-hoc `sync` produce byte-identical rows.

`RunArtifact::to_value()` is deliberately untouched: T108's merged additivity
guarantee — a stream carrying submission records folds to a byte-identical
artifact document — still holds, and the projection reads the folded value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Also folds the `inputs` array read to `Option::cloned`, which is what clippy
would have asked for anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`single_match_else` on the merge branch (an `if let … continue` reads better
anyway) and `redundant_closure_for_method_calls` in the ordering assertion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@athvin
athvin merged commit 6b81cb5 into main Aug 3, 2026
16 checks passed
@athvin
athvin deleted the feat/t111-submission-projection-and-audit branch August 3, 2026 01:12
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