Repository navigation
Description
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.
- crates/graphforge-api/src/knowledge/source_artifact.rs:267
- crates/graphforge-api/src/knowledge/source_artifact.rs:853
- crates/graphforge-storage/src/project_generation.rs:768
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.
Activity
perf(api): batch artifact derivation input validation (CurateLabs#1832)