Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
99bdac1
feat(filesystem): measure allocated bytes from retained handles
DecisionNerd Aug 27, 2026
ad3b25d
feat(storage): attribute retained and construction bytes
DecisionNerd Aug 27, 2026
08bfb10
feat(scale): validate disk-bound ladder evidence
DecisionNerd Aug 27, 2026
433b843
test(scale): reconcile storage lifecycle attribution
DecisionNerd Aug 28, 2026
25f23cb
fix(scale): require real lifecycle peak headroom
DecisionNerd Aug 28, 2026
2edce32
fix(storage): separate staging and recovery attribution
DecisionNerd Aug 28, 2026
266b7cf
feat(scale): emit qualification source evidence
DecisionNerd Aug 28, 2026
76193ef
test(scale): record source I/O submissions
DecisionNerd Aug 28, 2026
8c27bbc
test(scale): complete lifecycle I/O accounting
DecisionNerd Aug 28, 2026
4b14701
feat(scale): expose attribution and split canonical projections
DecisionNerd Aug 28, 2026
ce1299c
fix(scale): replace disk scans with active allocation union
DecisionNerd Aug 28, 2026
101fc88
test(scale): reject fake-zero phase evidence
DecisionNerd Aug 28, 2026
78246d5
docs(scale): define applicable phase evidence
DecisionNerd Aug 28, 2026
71418c0
fix(scale): track exact lifecycle allocation
DecisionNerd Aug 28, 2026
e5a2311
fix(scale): complete construction identity transitions
DecisionNerd Aug 28, 2026
0656d81
fix(scale): retain project identity unions
DecisionNerd Aug 28, 2026
75e1e02
fix(scale): observe export allocation transitions
DecisionNerd Aug 28, 2026
38ef3bb
test(scale): prove full lifecycle phase slopes
DecisionNerd Aug 28, 2026
46ba933
fix(scale): include all retained generations
DecisionNerd Aug 28, 2026
f0f7270
fix(storage): preserve exact lifecycle qualification evidence
DecisionNerd Aug 28, 2026
5b17741
fix(scale): retain project unions through import drills (#951)
DecisionNerd Aug 28, 2026
c92fdb9
fix(portable): receipt durable import cleanup
DecisionNerd Aug 28, 2026
1abf468
fix(storage): retain complete CAS identity union
DecisionNerd Aug 28, 2026
e2838d7
fix(scale): sanitize qualification evidence
DecisionNerd Aug 28, 2026
b782244
fix(scale): close certification storage contract
DecisionNerd Aug 28, 2026
30b32d4
fix(scale): preserve source project union numerator
DecisionNerd Aug 28, 2026
14639ab
fix(scale): reject every raw UUID form
DecisionNerd Aug 28, 2026
a748bac
fix(storage): account exact merge IO calls
DecisionNerd Aug 28, 2026
063a7c3
fix(scale): satisfy storage attribution gates
DecisionNerd Aug 28, 2026
d877708
fix: reconcile storage attribution CI behavior
DecisionNerd Aug 28, 2026
f3cc1b4
fix: make attribution repair CI-hermetic
DecisionNerd Aug 28, 2026
c4c2be1
fix: preserve truthful zero-I/O qualification phases
DecisionNerd Aug 28, 2026
ff0d396
Merge remote-tracking branch 'origin/main' into test/951-storage-attr…
DecisionNerd Aug 29, 2026
274ef28
Merge remote-tracking branch 'origin/main' into test/951-storage-attr…
DecisionNerd Aug 29, 2026
3e89627
fix: reconcile storage qualification evidence
DecisionNerd Aug 29, 2026
97798a9
Merge remote-tracking branch 'origin/main' into test/951-storage-attr…
DecisionNerd Aug 29, 2026
490283d
fix: reconcile compact checkpoint recovery evidence
DecisionNerd Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help lint format type-check security workflow-lint license-check third-party-notices third-party-notices-check cargo-deny-licenses test pre-push pre-push-clean pre-push-preflight pre-push-fast bazel-test clean test-tck docstring-coverage test-network benchmark test-perf test-perf-xs test-perf-slow test-perf-large coverage coverage-rust coverage-python coverage-node coverage-quick coverage-report coverage-diff coverage-strict check-coverage check-coverage-rust check-coverage-python check-coverage-node check-patch-coverage test-durations test-analytics docs-serve docs-build docs-clean cargo-build codspeed-build codspeed-build-walltime codspeed-run bench-traversal bench-fixed-hop-limit bench-fixed-hop-livejournal bench-m4-entry bench-g500-scale20 bench-g500-ladder bench-adjacency-200m bench-file-backed-128m m4-entry-matrix-check durability-isolation-check native-consumers release-load-matrix-check release-load-matrix bulk-construction-conformance-check bulk-construction-conformance cargo-test cargo-check cargo-clippy cargo-fmt cargo-fmt-check clean-builds clean-builds-all pnpm-install pnpm-build pnpm-test-bdd install build release-version-check package-license-verify publish-dry-run publish-dry-run-npm publish-dry-run-docs publish-dry-run-python publish-dry-run-cargo record-release-artifacts clean-env-verify-check clean-env-verify-preflight clean-env-verify
.PHONY: help lint format type-check security workflow-lint license-check third-party-notices third-party-notices-check cargo-deny-licenses test pre-push pre-push-clean pre-push-preflight pre-push-fast bazel-test clean test-tck docstring-coverage test-network benchmark test-perf test-perf-xs test-perf-slow test-perf-large coverage coverage-rust coverage-python coverage-node coverage-quick coverage-report coverage-diff coverage-strict check-coverage check-coverage-rust check-coverage-python check-coverage-node check-patch-coverage test-durations test-analytics docs-serve docs-build docs-clean cargo-build codspeed-build codspeed-build-walltime codspeed-run bench-traversal bench-fixed-hop-limit bench-fixed-hop-livejournal bench-m4-entry bench-g500-scale20 bench-g500-ladder g500-ladder-qualification g500-ladder-qualification-check bench-adjacency-200m bench-file-backed-128m m4-entry-matrix-check durability-isolation-check native-consumers release-load-matrix-check release-load-matrix bulk-construction-conformance-check bulk-construction-conformance cargo-test cargo-check cargo-clippy cargo-fmt cargo-fmt-check clean-builds clean-builds-all pnpm-install pnpm-build pnpm-test-bdd install build release-version-check package-license-verify publish-dry-run publish-dry-run-npm publish-dry-run-docs publish-dry-run-python publish-dry-run-cargo record-release-artifacts clean-env-verify-check clean-env-verify-preflight clean-env-verify

help: ## Show this help message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
Expand Down Expand Up @@ -329,6 +329,19 @@ bench-g500-ladder: ## Bounded billion-edge scale ladder S20-S26 first-fail evid
GF_G500_LADDER_MAX_SCALE="$$GF_G500_LADDER_MAX_SCALE" \
cargo test -p graphforge-api --release --test scale_g500_ladder ladder_public_facade_first_fail_evidence -- --ignored --nocapture --test-threads=1

g500-ladder-qualification-check: ## Validate #951 disk attribution and conservative S26 projection
@test -n "$$EVIDENCE" || (echo "EVIDENCE is required" && exit 2)
uv run --frozen --with jsonschema python scripts/ci/validate-g500-ladder-qualification.py "$$EVIDENCE"

g500-ladder-qualification: ## Build and validate #951 evidence from adjacent real certifications
@test -n "$$LOW_CERT" || (echo "LOW_CERT is required" && exit 2)
@test -n "$$HIGH_CERT" || (echo "HIGH_CERT is required" && exit 2)
@test -n "$$EVIDENCE" || (echo "EVIDENCE is required" && exit 2)
@test -n "$$VOLUME_BYTES" || (echo "VOLUME_BYTES is required" && exit 2)
@test -n "$$RESERVED_HEADROOM_BYTES" || (echo "RESERVED_HEADROOM_BYTES is required" && exit 2)
uv run --frozen python scripts/ci/build-g500-ladder-qualification.py "$$LOW_CERT" "$$HIGH_CERT" "$$EVIDENCE" --volume-bytes "$$VOLUME_BYTES" --reserved-headroom-bytes "$$RESERVED_HEADROOM_BYTES"
$(MAKE) g500-ladder-qualification-check EVIDENCE="$$EVIDENCE"

bench-adjacency-200m: ## >200M-edge public adjacency build evidence (#336; ignored, scale-host)
GF_ADJACENCY_SCALE_EVIDENCE_OUT="$(CURDIR)/docs/development/adjacency-200m-evidence.json" \
GF_ADJACENCY_SCALE_WORK="$(CURDIR)/build/adjacency-200m-work" \
Expand Down
2 changes: 1 addition & 1 deletion crates/graphforge-api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ gf_rust_integration_test(
data = _API_TEST_DATA,
size = "large",
timeout = "long",
deps = _API_DEPS,
deps = _API_DEPS + ["//crates/graphforge-filesystem:graphforge_filesystem"],
)

gf_rust_integration_test(
Expand Down
1 change: 1 addition & 0 deletions crates/graphforge-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ cucumber = { workspace = true }
tokio = { workspace = true }
graphforge-cypher = { path = "../graphforge-cypher" }
graphforge-storage = { path = "../graphforge-storage", features = ["test-failpoints", "test-support"] }
graphforge-filesystem = { path = "../graphforge-filesystem" }

# BDD runner for the public-API + TCK feature files (tests/features/).
# A custom-harness target (cucumber drives its own main).
Expand Down
29 changes: 29 additions & 0 deletions crates/graphforge-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,22 @@ impl std::fmt::Debug for GraphForge {
}

impl GraphForge {
/// Capture authenticated logical and physical storage attribution for the
/// generation visible to this facade.
///
/// The storage layer walks only the generation's authenticated inventories
/// and opens retained file capabilities. It never recursively scans the
/// project directory, and qualification fails closed on an unclassified
/// graph artifact.
pub fn storage_attribution(
&self,
) -> Result<graphforge_storage::StorageAttributionSnapshot, GfError> {
let generation = self.generation_for_read()?;
let snapshot = graphforge_storage::capture_storage_attribution(&generation)?;
snapshot.validate_for_qualification()?;
Ok(snapshot)
}

pub(crate) fn stage_project_generation(
&self,
request: &graphforge_storage::ProjectGenerationRequest,
Expand Down Expand Up @@ -4099,6 +4115,19 @@ fn materialize_compact_graph_target(
files_opened_in_place: 0,
files_reused: reused.files_reused,
bytes_reused: reused.bytes_reused,
application_read_bytes: reused
.application_read_bytes
.saturating_add(copied.application_read_bytes),
application_read_calls: reused
.application_read_calls
.saturating_add(copied.application_read_calls),
application_write_bytes: reused
.application_write_bytes
.saturating_add(copied.application_write_bytes),
application_write_calls: reused
.application_write_calls
.saturating_add(copied.application_write_calls),
fsync_calls: reused.fsync_calls.saturating_add(copied.fsync_calls),
};
Ok(evidence)
}
Expand Down
37 changes: 37 additions & 0 deletions crates/graphforge-api/src/portable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ pub struct PortableV2ImportResult {
pub generation_uuid: Uuid,
/// Whether the operation replayed an identical publication.
pub idempotent_replay: bool,
/// Exact private-materialization identity allocation for lifecycle qualification.
#[doc(hidden)]
pub materialized_identity_allocated_bytes: std::collections::BTreeMap<String, u64>,
/// Exact published-project identity union for lifecycle qualification,
/// including controls and every retained generation.
#[doc(hidden)]
pub published_identity_allocated_bytes: std::collections::BTreeMap<String, u64>,
/// Exact identities durably removed by private-materialization cleanup.
#[doc(hidden)]
pub materialized_cleanup_removed_identity_allocated_bytes:
std::collections::BTreeMap<String, u64>,
/// Whether the cleanup namespace synchronization completed.
#[doc(hidden)]
pub materialized_cleanup_parent_sync_confirmed: bool,
}

/// Publish a verified local portable-v2 package to an OCI registry.
Expand Down Expand Up @@ -186,6 +200,18 @@ pub struct PortableV2ExportFacadeResult {
pub selection_fingerprint: String,
/// Caller-selected output path.
pub output: PathBuf,
/// Exact writer-owned published allocation for lifecycle qualification.
#[doc(hidden)]
#[serde(skip)]
pub allocation_identity_allocated_bytes: std::collections::BTreeMap<String, u64>,
/// Writer-owned logical bytes of the published package identity union.
#[doc(hidden)]
#[serde(skip)]
pub allocation_logical_bytes: u64,
/// Writer-owned distinct published package identities.
#[doc(hidden)]
#[serde(skip)]
pub allocation_physical_objects: u64,
}

/// Stable export result.
Expand Down Expand Up @@ -421,6 +447,9 @@ impl GraphForge {
},
selection_fingerprint: receipt.selection_fingerprint,
output: request.output_path.clone(),
allocation_identity_allocated_bytes: receipt.allocation_identity_allocated_bytes,
allocation_logical_bytes: receipt.allocation_logical_bytes,
allocation_physical_objects: receipt.allocation_physical_objects,
})
}

Expand Down Expand Up @@ -526,6 +555,14 @@ impl GraphForge {
transport_digest: receipt.transport_digest,
generation_uuid: receipt.publication.generation_uuid,
idempotent_replay: receipt.publication.idempotent_replay,
materialized_identity_allocated_bytes: receipt.materialized_identity_allocated_bytes,
published_identity_allocated_bytes: receipt.published_identity_allocated_bytes,
materialized_cleanup_removed_identity_allocated_bytes: receipt
.materialized_cleanup
.removed_identity_allocated_bytes,
materialized_cleanup_parent_sync_confirmed: receipt
.materialized_cleanup
.parent_sync_confirmed,
})
}
}
Expand Down
6 changes: 1 addition & 5 deletions crates/graphforge-api/src/resumable_construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,7 @@ impl GraphConstructionSession<'_> {
}
let (prepared_dir, prepared_guard, hydration_evidence) =
super::hydrate_graph_workspace(&resolved, false)?;
self.inner.record_hydration_application_read_bytes(
hydration_evidence
.bytes_validated
.saturating_add(hydration_evidence.bytes_copied),
)?;
self.inner.record_hydration_evidence(&hydration_evidence)?;
let runtime_catalog = super::load_runtime_catalog(&prepared_dir)?;
let property_inventory = std::sync::Arc::new(
graphforge_storage::AuthenticatedPropertyInventory::from_resolved_generation(
Expand Down
Loading