Skip to content

perf(api): batch artifact derivation input validation by ledger kind #1812

Closed

Description

@DecisionNerd

Problem

validate_derivation_inputs loops over inputs and separately loads the complete source/artifact/assertion/evidence/run ledger for each input of that kind. Each load reads and verifies participant bytes and decodes rows. K inputs from one ledger cost K ledger loads for one artifact registration.

Source inspection at 172dee39902ff2afac86232725223dd0bdff155a; no runtime speedup or measured severity is claimed. Reconfirm against current main before implementing.

Outcome and acceptance criteria

Validate all requested derivation subjects against one pinned operation view, loading each required ledger kind at most once.

  • Within derivation-input validation, each referenced ledger kind is read/decoded at most once regardless of input count, reusing any already-loaded operation snapshot; unreferenced kinds are not loaded for validation.
  • Build or reuse operation-scoped UUID membership for requested inputs and batch node/edge validation where the existing API supports it; do not introduce a stale cross-generation cache.
  • Preserve all input-kind validation, missing-subject errors, duplicate/order semantics, same-generation consistency and atomic publication.
  • Tests with repeated and mixed-kind inputs verify exact errors/results and ledger read/decode counts at increasing input counts and ledger sizes.

Completion scenarios

  • Given many derivation inputs from one ledger and several from another, when an artifact is registered, then validation loads each required ledger at most once and every input is checked.
  • Given a missing subject, an unsupported/invalid request or a concurrently changed generation, when validation/publication occurs, then the existing structured failure and conflict rules are preserved.

Validation and implementation boundaries

Quality regime A: exact semantics plus deterministic work counters. Add a regression that exposes this cost on the baseline and exercises real Rust-facade execution; unit-only or logical-plan proof is insufficient. Attribute the named phase so another child's cost cannot hide or invalidate the result. Reuse existing I/O, hash, decoded-row and allocation instrumentation; counters must measure actual work, not merely fewer helper calls. Record bounded fixture sizes, commands and results on this issue/PR. No wall-clock CI threshold, new certification lane or S26 run is required to close this leaf.

Run the narrow relevant make test-rust ARGS="-p graphforge-api" / -p graphforge-exec / -p graphforge-storage suites, format after final edits, and make check before pushing. Rebuild native bindings before any required binding tests. The ordinary exact-head CI Gate and squash merge queue remain the merge gate.

Preserve corruption refusal, path/handle validation, cancellation, memory limits, atomicity and structured errors. Diagnostics expose counts/bytes only, not graph values, UUID inventories or sensitive paths. Update the nearest existing architecture/development documentation only where the implementation changes its contract or reproduction method; results stay on the issue/PR, not in a new per-issue document.

Scope and relationships

#1421 (row revalidation) and #1410 (a different epistemic snapshot repeated-read path) are related but not duplicates.

Non-goals: Global caches, ledger-format changes, broad provenance redesign or unchanged participant publication.

Native child and blocker of #1803, in M5. This finite repair batch must finish before the S26 run under #900/#745. The epic owns aggregate acceptance; this child owns only the cost described above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcoreCore source code changes

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions