From 10e9a30eddb9043828de215aaee36c66466650d8 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:22:18 +0930 Subject: [PATCH 001/132] Implement R7 CPU memory-wall study harness --- .github/workflows/c99.yml | 4 +- AGENTS.md | 21 +- Makefile | 14 +- R7-MEMORY-WALL-STUDY.md | 288 +++++ README.md | 15 +- ROADMAP.md | 4 +- evidence/r7/README.md | 32 + machine/project-v1.json | 30 +- machine/r7-memory-wall-study.v1.json | 190 ++++ scripts/r7-run-local.sh | 76 ++ study/r7_memory_wall.c | 1521 ++++++++++++++++++++++++++ 11 files changed, 2173 insertions(+), 22 deletions(-) create mode 100644 R7-MEMORY-WALL-STUDY.md create mode 100644 evidence/r7/README.md create mode 100644 machine/r7-memory-wall-study.v1.json create mode 100755 scripts/r7-run-local.sh create mode 100644 study/r7_memory_wall.c diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 4dab4a6..6d01d60 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -24,8 +24,8 @@ jobs: - name: Check out source uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - name: Build and run R1-R6 tests, R6 proof, and frozen R4 corpus - run: make clean test r6-proof corpus-smoke CC="${{ matrix.cc }}" + - name: Build R1-R7 checks, R6 proof, frozen R4 corpus, and R7 smoke + run: make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" - name: Reject truncated corpus output run: | diff --git a/AGENTS.md b/AGENTS.md index 634aa44..7a485f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,8 +4,8 @@ MODE=MACHINE_ONLY PROJECT=RUNE REFERENCE_LANGUAGE=ISO_C99 LICENSE=MPL-2.0 -CURRENT_PHASE=R6 -RUNTIME_IMPLEMENTATION_ALLOWED=true +CURRENT_PHASE=R7 +RUNTIME_IMPLEMENTATION_ALLOWED=false RUNTIME_PERFORMANCE_CLAIMS_ALLOWED=false READ_ORDER: @@ -18,6 +18,7 @@ READ_ORDER: 7=machine/r4-corpus-v1.json 8=machine/r5-rings-streaming.v1.json 9=machine/r6-operation-receipts.v1.json +10=machine/r7-memory-wall-study.v1.json HUMAN_PROSE: README.md @@ -30,6 +31,7 @@ R3-INTEGER-NUMERIC.md R4-CORPUS-v1.md R5-RINGS-STREAMING.md R6-OPERATIONS-RECEIPTS.md +R7-MEMORY-WALL-STUDY.md MACHINE_AUTHORITY: machine/project-v1.json @@ -41,6 +43,7 @@ machine/r3-integer-numeric.v1.json machine/r4-corpus-v1.json machine/r5-rings-streaming.v1.json machine/r6-operation-receipts.v1.json +machine/r7-memory-wall-study.v1.json CONFLICT_POLICY=FAIL_CLOSED ON_HUMAN_MACHINE_CONTRADICTION=STOP_AND_REPORT @@ -48,7 +51,7 @@ DO_NOT_INVENT_RECONCILIATION=true CORE_RULES: - preserve_all_invariants -- runtime_code_allowed_only_within_current_R6_operation_receipt_scope +- runtime_core_changes_forbidden_in_R7_study_phase - cpu_only - integer_only_public_semantics - fractional_rounding_behavior_must_be_declared @@ -144,7 +147,17 @@ CORE_RULES: - optional_internal_optimization_unavailable_or_losing_requires_fallback_to_correct_simpler_path - requested_contract_capability_unsupported_requires_explicit_failure - optional_internal_optimization_absence_is_not_unsupported_capability_failure -- runtime_performance_claims_forbidden_in_R6 +- runtime_performance_claims_forbidden_until_R7_local_evidence_is_committed_and_reviewed +- R7_raw_observation_capture_is_allowed +- R7_raw_observations_are_not_performance_claims +- R7_CI_smoke_timing_is_not_performance_evidence +- R7_reference_timer_is_C99_clock_process_CPU_time +- R7_observations_record_setup_execute_teardown_and_total_ticks +- R7_pairwise_comparisons_require_exact_result_identity +- R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method +- R7_negative_results_must_be_retained +- R7_timing_alone_must_not_claim_cache_NUMA_or_bandwidth_cause +- R7_runtime_core_changes_are_out_of_scope - causal_performance_claim_requires_support_beyond_timing - portable_identity_requires_explicit_versioned_representation - fixed_width_integer_identity_is_allowed_but_not_the_only_allowed_explicit_representation diff --git a/Makefile b/Makefile index d978a4e..9ce25dc 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,10 @@ TEST_NUMERIC = $(BUILD_DIR)/test_numeric TEST_RING = $(BUILD_DIR)/test_ring TEST_OPERATION = $(BUILD_DIR)/test_operation R6_PROOF = $(BUILD_DIR)/rune_r6_proof +R7_STUDY = $(BUILD_DIR)/rune_r7_study CORPUS = $(BUILD_DIR)/rune_corpus -.PHONY: all test r6-proof corpus-smoke clean +.PHONY: all test r6-proof r7-study-smoke r7-study corpus-smoke clean all: $(LIB) @@ -67,6 +68,17 @@ r6-proof: $(R6_PROOF) ./$(R6_PROOF) > $(BUILD_DIR)/r6-proof.tsv cmp $(BUILD_DIR)/r6-proof.tsv proof/r6-proof-receipts.v1.tsv +$(R7_STUDY): study/r7_memory_wall.c $(LIB) include/rune/arena.h include/rune/region.h include/rune/status.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) study/r7_memory_wall.c $(LIB) -o $@ + +r7-study-smoke: $(R7_STUDY) + ./$(R7_STUDY) --bytes 32768 --repeats 1 > $(BUILD_DIR)/r7-study-smoke.tsv + test "`wc -l < $(BUILD_DIR)/r7-study-smoke.tsv`" -eq 20 + awk -F '\t' 'NF != 17 { exit 1 } END { if (NR != 20) exit 1 }' $(BUILD_DIR)/r7-study-smoke.tsv + +r7-study: $(R7_STUDY) + ./$(R7_STUDY) --profile local --repeats 5 + $(CORPUS): corpus/rune_corpus.c $(LIB) include/rune/arena.h include/rune/numeric.h include/rune/region.h include/rune/status.h $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) corpus/rune_corpus.c $(LIB) -o $@ diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md new file mode 100644 index 0000000..5f1a238 --- /dev/null +++ b/R7-MEMORY-WALL-STUDY.md @@ -0,0 +1,288 @@ +# R7 — CPU Memory-Wall Study + +R7 is the first RUNE phase that records timing observations. + +It does **not** turn a timing number into a universal performance claim. + +The study uses the frozen R4 questions to ask when representation, locality, +resident state, materialization, and recomputation change observed execution +cost on one declared environment. + +## Scope + +The reference study executable is: + +~~~text +study/r7_memory_wall.c +~~~ + +It covers: + +1. sequential versus strided access; +2. materialized versus fused reduction; +3. AoS versus hot-field SoA; +4. microtile sweep; +5. retain versus regenerate; +6. lookup versus integer recomputation; +7. arena peak-live versus cumulative allocation traffic; +8. huge logical domain versus resident metadata. + +The study is tooling. R7 makes **no runtime ABI changes**. + +## Performance gate + +R7 has two distinct states: + +~~~text +raw observation capture +!= +reviewed performance claim +~~~ + +This PR permits raw observations to be produced. + +Performance claims remain prohibited until a local evidence bundle is committed, +reviewed, and accompanied by an interpretation that satisfies RUNE-INV-014. + +GitHub-hosted CI timings are never promoted as R7 performance evidence. + +## Timer + +The portable reference timer is ISO C99: + +~~~text +clock() +~~~ + +The receipt records raw process-CPU-time ticks and CLOCKS_PER_SEC. + +R7 does not call these values wall-clock nanoseconds. + +If clock() is unavailable or a tick interval cannot be represented, the study +fails explicitly. + +## Lifecycle accounting + +Every timed observation records: + +~~~text +setup_ticks +execute_ticks +teardown_ticks +total_ticks +~~~ + +The study therefore preserves setup/allocation and teardown costs alongside the +execution body. + +Kernel-only timing is not sufficient evidence for promotion. + +## Observation format + +The executable emits numeric ASCII TSV with 17 columns: + +~~~text +comparison_id +variant_id +working_set_bytes +repeat_index +logical_items +resident_bytes +peak_live_bytes +cumulative_traffic_bytes +model_bytes_read +model_bytes_written +result_u64 +setup_ticks +execute_ticks +teardown_ticks +total_ticks +clock_ticks_per_second +lifecycle_complete +~~~ + +Timing fields are observations and are excluded from correctness identity. + +## Comparison IDs + +### 1 — Locality + +~~~text +variant 1 = sequential scan +variant 2 = odd-stride full-cycle scan +~~~ + +Both traverse the same uint32 values and must produce the same result. + +### 2 — Materialization + +~~~text +variant 1 = transform -> temporary array -> reduce +variant 2 = fused transform + reduce +~~~ + +Both must produce the same result. + +### 3 — Layout + +~~~text +variant 1 = six-field AoS logical record +variant 2 = three dense hot-field arrays +~~~ + +The AoS representation is six consecutive uint32 lanes, avoiding host structure +padding. Both consume the same three hot fields and must produce the same result. + +### 4 — Microtile + +variant_id is the tile size in elements: + +~~~text +32 64 128 256 512 1024 2048 4096 +~~~ + +Every executed tile size must produce one exact result identity. + +### 5 — Retain versus regenerate + +~~~text +variant 1 = retained procedural uint32 array +variant 2 = deterministic regeneration from (seed, index) +~~~ + +Both execute the same logical passes and must produce the same result. + +### 6 — Lookup versus recompute + +~~~text +variant 1 = 4096-entry retained lookup +variant 2 = recompute the exact table value from (seed, index) +~~~ + +Both must produce the same result. + +### 7 — Peak-live versus cumulative traffic + +Uses the R2 arena/reset workload and records: + +- fixed resident arena bytes; +- high-water bytes; +- cumulative consumed bytes across reuse; +- payload read/write accounting. + +This row is evidence about **resident versus cumulative state accounting**. It +does not by itself establish a causal performance advantage. + +### 8 — Logical domain versus resident state + +Uses the R4 C15 shape: + +~~~text +logical_items = 2^40 +resident metadata = 48 bytes +64 windows x 64 generated values +~~~ + +The row demonstrates the scale relationship without full materialization. + +## Working-set profiles + +The local ladder is: + +~~~text +4 KiB +32 KiB +256 KiB +1 MiB +4 MiB +16 MiB +64 MiB +~~~ + +The default local evidence run uses five repeats. + +The harness normalizes small cases toward roughly 64 MiB of logical work per +sample so very small working sets are not represented by a single tiny loop. + +## Local evidence bundle + +Run: + +~~~sh +./scripts/r7-run-local.sh +~~~ + +or: + +~~~sh +RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host +~~~ + +The script records: + +- exact Git source revision; +- dirty/clean working-tree state; +- compiler path/version; +- build flags; +- uname platform context; +- visible processor count when available; +- CPU model when available; +- total memory when available; +- timer method; +- exact commands; +- raw observations; +- SHA-256 integrity file. + +These fields satisfy the evidence-dimension requirement only when the bundle is +actually captured on the host. A template or planned command is not execution +evidence. + +## CI smoke + +~~~sh +make r7-study-smoke +~~~ + +CI uses one 32 KiB repeat to check: + +- strict C99 compilation; +- all pairwise result identities; +- all eight tile identities; +- numeric TSV schema; +- expected observation count. + +The timing values from this CI job are discarded as performance evidence. + +## Interpreting results + +R7 may later support environment-scoped statements such as: + +> on evidence bundle X, variant A had lower median total ticks than variant B +> for working-set sizes Y under the declared toolchain and timer. + +R7 may **not** infer from timing alone: + +- cache capacity; +- cache misses; +- memory bandwidth saturation; +- NUMA placement; +- DRAM latency; +- CPU microarchitectural cause. + +Hardware counters may strengthen a later causal interpretation. + +Negative and null results must be retained. + +## Phase completion + +This implementation PR establishes the study machinery. + +R7 is complete only after: + +1. a local evidence bundle is captured; +2. raw observations are integrity-bound; +3. correctness parity is preserved; +4. an interpretation includes negative/null results; +5. any performance statement is environment-scoped and reviewed. + +Until then, runtime performance claims remain prohibited. diff --git a/README.md b/README.md index 5567c66..5086245 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ MORE COMPUTE != BETTER EXECUTION ## Status -**R6 — Deterministic operation descriptors and receipts.** +**R7 — CPU memory-wall study.** -R0 through R5 are merged. RUNE now has a small replayable operation vocabulary demonstrated by two existing byte operations: move and fill. Descriptors use fixed-width operation/version/region-slot semantics; replay binds those slots to caller-owned regions at execution time, and receipts record executed-versus-rejected evidence, status, compact byte accounting, scratch requirements, and output identity. +R0 through R6 are merged. RUNE now includes a local-first study harness for the frozen R4 corpus questions: locality, materialization/fusion, AoS/SoA, microtiles, retain/regenerate, lookup/recompute, peak-live versus cumulative traffic, and logical-domain versus resident-state scale. -R6 deliberately avoids a task graph, scheduler, hidden process state, pointer identity, timing fields, and runtime performance claims. +R7 can capture raw environment-scoped timing observations, but **performance claims remain prohibited until a local evidence bundle is committed and reviewed**. GitHub-hosted CI runs only a harness smoke check and is not performance evidence. -See [R6-OPERATIONS-RECEIPTS.md](R6-OPERATIONS-RECEIPTS.md) and [ROADMAP.md](ROADMAP.md). +See [R7-MEMORY-WALL-STUDY.md](R7-MEMORY-WALL-STUDY.md) and [ROADMAP.md](ROADMAP.md). ## Build and test @@ -60,7 +60,8 @@ See [R6-OPERATIONS-RECEIPTS.md](R6-OPERATIONS-RECEIPTS.md) and [ROADMAP.md](ROAD make test make clean test CC=clang make corpus-smoke -./build/rune_corpus --profile local +make r7-study-smoke +./scripts/r7-run-local.sh ~~~ The tests exercise deterministic correctness only. They are not performance benchmarks. @@ -71,7 +72,7 @@ The tests exercise deterministic correctness only. They are not performance benc Project: RUNE Name: Runtime for Unified Numeric Execution Reference language: ISO C99 -Current phase: R6 — Deterministic operation descriptors and receipts +Current phase: R7 — CPU memory-wall study Architecture: CPU-only Numeric boundary: integer-only Memory model: explicit and bounded @@ -281,6 +282,7 @@ Human-facing files: - [R4-CORPUS-v1.md](R4-CORPUS-v1.md) - [R5-RINGS-STREAMING.md](R5-RINGS-STREAMING.md) - [R6-OPERATIONS-RECEIPTS.md](R6-OPERATIONS-RECEIPTS.md) +- [R7-MEMORY-WALL-STUDY.md](R7-MEMORY-WALL-STUDY.md) Machine-facing files: @@ -294,6 +296,7 @@ Machine-facing files: - [machine/r4-corpus-v1.json](machine/r4-corpus-v1.json) - [machine/r5-rings-streaming.v1.json](machine/r5-rings-streaming.v1.json) - [machine/r6-operation-receipts.v1.json](machine/r6-operation-receipts.v1.json) +- [machine/r7-memory-wall-study.v1.json](machine/r7-memory-wall-study.v1.json) A contradiction between the two surfaces is a defect. Automated agents must fail closed rather than invent a reconciliation. diff --git a/ROADMAP.md b/ROADMAP.md index 53c95b3..1eaf7f6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -154,7 +154,7 @@ Success criterion: ## R6 — Deterministic operation descriptors and receipts -**Current phase.** +**Complete — merged in PR #7.** Define only the reusable execution description demonstrated by real RUNE operations. @@ -177,6 +177,8 @@ Success criterion: ## R7 — CPU memory-wall study +**Current phase.** + Use RUNE-CORPUS-v1 to test the core thesis. Required comparisons should include, where meaningful: diff --git a/evidence/r7/README.md b/evidence/r7/README.md new file mode 100644 index 0000000..e07f955 --- /dev/null +++ b/evidence/r7/README.md @@ -0,0 +1,32 @@ +# R7 Evidence Bundles + +This directory is intentionally empty of performance conclusions until a local +R7 study is executed. + +Create a bundle with: + +~~~sh +./scripts/r7-run-local.sh +~~~ + +or choose an explicit destination: + +~~~sh +RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host +~~~ + +A bundle contains: + +- `environment.txt` — source revision, dirty state, timer method, CPU-count and + memory context where available; +- `compiler.txt` — compiler path/version output; +- `command.txt` — exact build/run commands; +- `observations.tsv` — raw numeric R7 observations; +- `SHA256SUMS` — integrity hashes for the bundle. + +Raw observations are execution evidence, not universal performance claims. +Interpretation belongs in a separately reviewed evidence commit. + +GitHub-hosted CI runs only `r7-study-smoke` to prove the harness builds, +executes, preserves comparison result identity, and emits the expected schema. +CI timing values are not R7 performance evidence. diff --git a/machine/project-v1.json b/machine/project-v1.json index 4bb8c56..5632ff8 100644 --- a/machine/project-v1.json +++ b/machine/project-v1.json @@ -3,9 +3,9 @@ "project": "RUNE", "expanded_name": "Runtime for Unified Numeric Execution", "phase": { - "id": "R6", - "name": "Deterministic operation descriptors and receipts", - "runtime_implementation_allowed": true, + "id": "R7", + "name": "CPU memory-wall study", + "runtime_implementation_allowed": false, "runtime_performance_claims_allowed": false, "performance_measurement_planning_allowed": true, "performance_observations_may_be_published_as_runtime_claims": false @@ -37,7 +37,8 @@ "R3-INTEGER-NUMERIC.md", "R4-CORPUS-v1.md", "R5-RINGS-STREAMING.md", - "R6-OPERATIONS-RECEIPTS.md" + "R6-OPERATIONS-RECEIPTS.md", + "R7-MEMORY-WALL-STUDY.md" ], "machine_readable": [ "machine/project-v1.json", @@ -48,7 +49,8 @@ "machine/r3-integer-numeric.v1.json", "machine/r4-corpus-v1.json", "machine/r5-rings-streaming.v1.json", - "machine/r6-operation-receipts.v1.json" + "machine/r6-operation-receipts.v1.json", + "machine/r7-memory-wall-study.v1.json" ], "agent_entrypoint": "AGENTS.md", "contradiction_policy": "fail-closed-and-report", @@ -205,10 +207,13 @@ ] }, "runtime_performance_claim_policy": { - "current_phase": "R6", + "current_phase": "R7", "runtime_performance_claims_allowed": false, "fully_documented_benchmark_receipt_does_not_override_phase_prohibition": true, - "first_permitted_phase_requires_future_versioned_authority": true + "first_permitted_phase_requires_future_versioned_authority": true, + "raw_R7_observation_capture_allowed": true, + "R7_claims_require_committed_reviewed_local_evidence": true, + "github_hosted_CI_timing_is_performance_evidence": false } }, "machine_contracts": { @@ -219,7 +224,8 @@ "r3_integer_numeric": "machine/r3-integer-numeric.v1.json", "r4_corpus_v1": "machine/r4-corpus-v1.json", "r5_rings_streaming": "machine/r5-rings-streaming.v1.json", - "r6_operation_receipts": "machine/r6-operation-receipts.v1.json" + "r6_operation_receipts": "machine/r6-operation-receipts.v1.json", + "r7_memory_wall_study": "machine/r7-memory-wall-study.v1.json" }, "corpus_policy": { "contract": "rune.corpus.receipt.v1", @@ -248,5 +254,13 @@ "timing_in_receipt": false, "general_task_graph": false, "scheduler": false + }, + "study_policy": { + "reference_timer": "C99 clock() process CPU time", + "raw_timing_observations_are_correctness_identity": false, + "local_evidence_bundle_required_for_interpretation": true, + "github_CI_smoke_is_performance_evidence": false, + "timing_alone_can_support_cache_NUMA_bandwidth_cause": false, + "negative_results_must_be_retained": true } } diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json new file mode 100644 index 0000000..cc9d17e --- /dev/null +++ b/machine/r7-memory-wall-study.v1.json @@ -0,0 +1,190 @@ +{ + "contract": "rune.r7-memory-wall-study.v1", + "phase": "R7", + "reference_language": "ISO C99", + "role": "local-first-performance-observation-harness", + "runtime_core_changes_allowed": false, + "raw_observation_capture_allowed": true, + "runtime_performance_claims_allowed": false, + "completion_requires_committed_reviewed_local_evidence": true, + "timer": { + "api": "clock", + "standard": "ISO C99", + "semantic": "process CPU time", + "unit": "clock ticks", + "scale_field": "clock_ticks_per_second", + "wall_clock_claim": false, + "unavailable_is_explicit_failure": true + }, + "lifecycle": { + "fields": [ + "setup_ticks", + "execute_ticks", + "teardown_ticks", + "total_ticks" + ], + "complete_lifecycle_required": true, + "kernel_only_sufficient_for_promotion": false + }, + "observation": { + "contract": "rune.r7.memory-wall-observation.v1", + "encoding": "numeric ASCII TSV", + "columns": [ + "comparison_id", + "variant_id", + "working_set_bytes", + "repeat_index", + "logical_items", + "resident_bytes", + "peak_live_bytes", + "cumulative_traffic_bytes", + "model_bytes_read", + "model_bytes_written", + "result_u64", + "setup_ticks", + "execute_ticks", + "teardown_ticks", + "total_ticks", + "clock_ticks_per_second", + "lifecycle_complete" + ], + "timing_part_of_correctness_identity": false, + "model_byte_fields_are_hardware_counter_evidence": false + }, + "comparisons": { + "1": { + "name": "locality", + "variants": { + "1": "sequential", + "2": "odd-stride-full-cycle" + }, + "exact_result_parity_required": true + }, + "2": { + "name": "materialized-vs-fused", + "variants": { + "1": "materialized", + "2": "fused" + }, + "exact_result_parity_required": true + }, + "3": { + "name": "aos-vs-soa", + "variants": { + "1": "six-u32-lane-AoS", + "2": "three-hot-field-SoA" + }, + "logical_aos_record_bytes": 24, + "host_struct_padding_used": false, + "exact_result_parity_required": true + }, + "4": { + "name": "microtile-sweep", + "variant_id_is_tile_elements": true, + "tile_sizes": [ + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096 + ], + "exact_result_parity_required": true + }, + "5": { + "name": "retain-vs-regenerate", + "variants": { + "1": "retain", + "2": "regenerate" + }, + "exact_result_parity_required": true + }, + "6": { + "name": "lookup-vs-recompute", + "variants": { + "1": "4096-entry-lookup", + "2": "integer-recompute" + }, + "exact_result_parity_required": true + }, + "7": { + "name": "peak-live-vs-cumulative-traffic", + "uses_R2_arena": true, + "high_water_recorded": true, + "cumulative_consumed_recorded": true + }, + "8": { + "name": "logical-domain-vs-resident", + "logical_items": "1099511627776", + "resident_bytes": 48, + "full_materialization": false + } + }, + "profiles": { + "smoke": { + "working_set_bytes": 32768, + "repeats": 1, + "expected_rows": 20 + }, + "local": { + "working_set_bytes": [ + 4096, + 32768, + 262144, + 1048576, + 4194304, + 16777216, + 67108864 + ], + "default_repeats": 5 + }, + "explicit": { + "min_bytes": 4096, + "max_bytes": 67108864, + "power_of_two_required": true, + "repeats_min": 1, + "repeats_max": 100 + } + }, + "evidence_bundle": { + "script": "scripts/r7-run-local.sh", + "required_files": [ + "environment.txt", + "compiler.txt", + "command.txt", + "observations.tsv", + "SHA256SUMS" + ], + "required_dimensions": [ + "source_revision", + "workload", + "compiler_toolchain", + "build_configuration", + "cpu_platform", + "memory_profile", + "measurement_method" + ], + "dirty_state_recorded": true, + "integrity": "SHA-256" + }, + "interpretation": { + "github_hosted_CI_timing_is_performance_evidence": false, + "timing_alone_can_establish_cache_cause": false, + "timing_alone_can_establish_NUMA_cause": false, + "timing_alone_can_establish_memory_bandwidth_cause": false, + "negative_results_must_be_retained": true, + "universal_claims_allowed": false + }, + "validation": { + "source": "study/r7_memory_wall.c", + "smoke_command": "make r7-study-smoke", + "local_capture_command": "./scripts/r7-run-local.sh", + "compilers": [ + "gcc", + "clang" + ], + "CI_validates_harness_not_performance": true + } +} diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh new file mode 100755 index 0000000..edab6c9 --- /dev/null +++ b/scripts/r7-run-local.sh @@ -0,0 +1,76 @@ +#!/bin/sh +set -eu + +repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +cd "$repo_root" + +cc_name=${CC:-cc} +cflags=${CFLAGS:-} +repeats=${RUNE_R7_REPEATS:-5} +stamp=$(date -u +%Y%m%dT%H%M%SZ) +out_dir=${1:-"evidence/r7/local-$stamp"} + +mkdir -p "$out_dir" + +revision=$(git rev-parse HEAD) +if git diff --quiet --ignore-submodules -- && + git diff --cached --quiet --ignore-submodules --; then + dirty=false +else + dirty=true +fi + +{ + echo "contract=rune.r7.environment.v1" + echo "source_revision=$revision" + echo "working_tree_dirty=$dirty" + echo "measurement_method=C99_clock_process_cpu_time" + echo "benchmark_contract=rune.r7.memory-wall-observation.v1" + echo "repeats=$repeats" + echo "cc=$cc_name" + echo "cflags=$cflags" + echo "uname=$(uname -a)" + if command -v getconf >/dev/null 2>&1; then + echo "processors_online=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" + echo "long_bit=$(getconf LONG_BIT 2>/dev/null || echo unknown)" + fi + if [ -r /proc/cpuinfo ]; then + awk -F ': ' ' + /^model name[[:space:]]*:/ { print "cpu_model=" $2; exit } + /^Hardware[[:space:]]*:/ { print "cpu_model=" $2; exit } + ' /proc/cpuinfo + fi + if [ -r /proc/meminfo ]; then + awk '/^MemTotal:/ { print "mem_total_kib=" $2 }' /proc/meminfo + fi +} > "$out_dir/environment.txt" + +{ + command -v "$cc_name" 2>/dev/null || true + "$cc_name" --version 2>&1 || true +} > "$out_dir/compiler.txt" + +{ + echo "make clean build/rune_r7_study CC=$cc_name CFLAGS=$cflags" + echo "./build/rune_r7_study --profile local --repeats $repeats" +} > "$out_dir/command.txt" + +make clean build/rune_r7_study CC="$cc_name" CFLAGS="$cflags" +./build/rune_r7_study --profile local --repeats "$repeats" > "$out_dir/observations.tsv" + +if command -v sha256sum >/dev/null 2>&1; then + ( + cd "$out_dir" + sha256sum environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS + ) +elif command -v shasum >/dev/null 2>&1; then + ( + cd "$out_dir" + shasum -a 256 environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS + ) +else + echo "no SHA-256 utility available" >&2 + exit 1 +fi + +echo "R7 evidence bundle: $out_dir" diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c new file mode 100644 index 0000000..4be220f --- /dev/null +++ b/study/r7_memory_wall.c @@ -0,0 +1,1521 @@ +/* SPDX-License-Identifier: MPL-2.0 */ +#include "rune/arena.h" +#include "rune/region.h" +#include "rune/status.h" + +#include +#include +#include +#include +#include +#include +#include + +#define R7_SEED UINT64_C(303) +#define R7_TARGET_BYTES UINT64_C(67108864) +#define R7_MIN_BYTES UINT64_C(4096) +#define R7_MAX_BYTES UINT64_C(67108864) +#define R7_AOS_LOGICAL_BYTES UINT64_C(24) +#define R7_HOT_LOGICAL_BYTES UINT64_C(12) +#define R7_LOOKUP_ENTRIES UINT64_C(4096) + +#define R7_COMPARE_LOCALITY UINT64_C(1) +#define R7_COMPARE_MATERIALIZATION UINT64_C(2) +#define R7_COMPARE_LAYOUT UINT64_C(3) +#define R7_COMPARE_MICROTILE UINT64_C(4) +#define R7_COMPARE_RETAIN_REGENERATE UINT64_C(5) +#define R7_COMPARE_LOOKUP_RECOMPUTE UINT64_C(6) +#define R7_COMPARE_PEAK_CUMULATIVE UINT64_C(7) +#define R7_COMPARE_LOGICAL_RESIDENT UINT64_C(8) + +#define R7_VARIANT_A UINT64_C(1) +#define R7_VARIANT_B UINT64_C(2) + +typedef struct r7_observation { + uint64_t comparison_id; + uint64_t variant_id; + uint64_t working_set_bytes; + uint64_t repeat_index; + uint64_t logical_items; + uint64_t resident_bytes; + uint64_t peak_live_bytes; + uint64_t cumulative_traffic_bytes; + uint64_t model_bytes_read; + uint64_t model_bytes_written; + uint64_t result_u64; + uint64_t setup_ticks; + uint64_t execute_ticks; + uint64_t teardown_ticks; + uint64_t total_ticks; + uint64_t clock_ticks_per_second; + uint64_t lifecycle_complete; +} r7_observation; + +static volatile uint64_t r7_sink = UINT64_C(0); + +static uint32_t r7_value32(uint64_t seed, uint64_t index) +{ + uint64_t z; + + z = index + seed + UINT64_C(0x9e3779b97f4a7c15); + z = (z ^ (z >> 30u)) * UINT64_C(0xbf58476d1ce4e5b9); + z = (z ^ (z >> 27u)) * UINT64_C(0x94d049bb133111eb); + z ^= z >> 31u; + return (uint32_t)(z >> 32u); +} + +static uint32_t r7_transform32(uint32_t value) +{ + return value * UINT32_C(1664525) + UINT32_C(1013904223); +} + +static uint64_t r7_hash_u64(uint64_t hash, uint64_t value) +{ + uint32_t lane; + + for (lane = 0u; lane < 8u; ++lane) { + hash ^= value & UINT64_C(0xff); + hash *= UINT64_C(1099511628211); + value >>= 8u; + } + + return hash; +} + +static uint64_t r7_hot_result(uint32_t x, uint32_t y, uint32_t flags) +{ + return (uint64_t)x * UINT64_C(3) + + (uint64_t)y * UINT64_C(5) + + (uint64_t)(flags & UINT32_C(0xff)); +} + +static int r7_is_power_of_two_u64(uint64_t value) +{ + return value != 0u && (value & (value - UINT64_C(1))) == 0u; +} + +static void *r7_malloc(uint64_t bytes) +{ + size_t host_bytes; + + host_bytes = (size_t)bytes; + if ((uint64_t)host_bytes != bytes) { + return NULL; + } + + return malloc(host_bytes); +} + +static uint64_t r7_rounds_for_bytes(uint64_t bytes) +{ + uint64_t rounds; + + if (bytes == 0u) { + return UINT64_C(1); + } + + rounds = R7_TARGET_BYTES / bytes; + if (rounds == 0u) { + rounds = UINT64_C(1); + } + if (rounds > UINT64_C(16384)) { + rounds = UINT64_C(16384); + } + + return rounds; +} + +static int r7_now(clock_t *out) +{ + clock_t value; + + if (out == NULL) { + return 0; + } + + value = clock(); + if (value == (clock_t)-1) { + return 0; + } + + *out = value; + return 1; +} + +static int r7_ticks_between( + clock_t start, + clock_t end, + uint64_t *out +) +{ + clock_t delta; + uint64_t converted; + + if (out == NULL) { + return 0; + } + + delta = end - start; + if (delta < (clock_t)0) { + return 0; + } + + converted = (uint64_t)delta; + if ((clock_t)converted != delta) { + return 0; + } + + *out = converted; + return 1; +} + +static int r7_finish_times( + r7_observation *observation, + clock_t total_start, + clock_t setup_end, + clock_t execute_end, + clock_t teardown_end +) +{ + if (!r7_ticks_between( + total_start, + setup_end, + &observation->setup_ticks) || + !r7_ticks_between( + setup_end, + execute_end, + &observation->execute_ticks) || + !r7_ticks_between( + execute_end, + teardown_end, + &observation->teardown_ticks) || + !r7_ticks_between( + total_start, + teardown_end, + &observation->total_ticks)) { + return 0; + } + + observation->clock_ticks_per_second = (uint64_t)CLOCKS_PER_SEC; + observation->lifecycle_complete = UINT64_C(1); + return 1; +} + +static void r7_observation_begin( + r7_observation *observation, + uint64_t comparison_id, + uint64_t variant_id, + uint64_t working_set_bytes, + uint64_t repeat_index +) +{ + memset(observation, 0, sizeof(*observation)); + observation->comparison_id = comparison_id; + observation->variant_id = variant_id; + observation->working_set_bytes = working_set_bytes; + observation->repeat_index = repeat_index; +} + +static int r7_write_byte(uint8_t value) +{ + return fwrite(&value, 1u, 1u, stdout) == 1u; +} + +static int r7_write_u64(uint64_t value) +{ + uint8_t digits[20]; + size_t count; + size_t i; + + count = 0u; + do { + digits[count] = (uint8_t)( + 0x30u + (uint8_t)(value % UINT64_C(10)) + ); + value /= UINT64_C(10); + count += 1u; + } while (value != 0u); + + for (i = count; i != 0u; --i) { + if (!r7_write_byte(digits[i - 1u])) { + return 0; + } + } + + return 1; +} + +static int r7_write_field(uint64_t value, int last) +{ + if (!r7_write_u64(value)) { + return 0; + } + + return r7_write_byte( + last ? (uint8_t)0x0au : (uint8_t)0x09u + ); +} + +static int r7_emit(const r7_observation *observation) +{ + return + r7_write_field(observation->comparison_id, 0) && + r7_write_field(observation->variant_id, 0) && + r7_write_field(observation->working_set_bytes, 0) && + r7_write_field(observation->repeat_index, 0) && + r7_write_field(observation->logical_items, 0) && + r7_write_field(observation->resident_bytes, 0) && + r7_write_field(observation->peak_live_bytes, 0) && + r7_write_field(observation->cumulative_traffic_bytes, 0) && + r7_write_field(observation->model_bytes_read, 0) && + r7_write_field(observation->model_bytes_written, 0) && + r7_write_field(observation->result_u64, 0) && + r7_write_field(observation->setup_ticks, 0) && + r7_write_field(observation->execute_ticks, 0) && + r7_write_field(observation->teardown_ticks, 0) && + r7_write_field(observation->total_ticks, 0) && + r7_write_field(observation->clock_ticks_per_second, 0) && + r7_write_field(observation->lifecycle_complete, 1); +} + +static int r7_fill_values( + uint32_t *values, + uint64_t count, + uint64_t seed +) +{ + uint64_t i; + + if (values == NULL && count != 0u) { + return 0; + } + + for (i = 0u; i < count; ++i) { + values[(size_t)i] = r7_value32(seed, i); + } + + return 1; +} + +static int r7_measure_locality( + uint64_t variant, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t count; + uint64_t rounds; + uint64_t round; + uint64_t i; + uint64_t result; + uint64_t mask; + uint64_t stride; + uint32_t *values; + volatile const uint32_t *read_values; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + rounds = r7_rounds_for_bytes(working_set_bytes); + mask = count - UINT64_C(1); + stride = ((R7_SEED << 1u) | UINT64_C(1)) & mask; + if (stride == 0u) { + stride = UINT64_C(1); + } + + r7_observation_begin( + observation, + R7_COMPARE_LOCALITY, + variant, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + values = (uint32_t *)r7_malloc(working_set_bytes); + if (values == NULL || + !r7_fill_values(values, count, R7_SEED)) { + free(values); + return 0; + } + read_values = values; + + if (!r7_now(&setup_end)) { + free(values); + return 0; + } + + result = 0u; + if (variant == R7_VARIANT_A) { + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + result += (uint64_t)read_values[(size_t)i]; + } + } + } else { + for (round = 0u; round < rounds; ++round) { + uint64_t index; + + index = round & mask; + for (i = 0u; i < count; ++i) { + result += (uint64_t)read_values[(size_t)index]; + index = (index + stride) & mask; + } + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(values); + return 0; + } + + free(values); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * rounds; + observation->resident_bytes = working_set_bytes; + observation->peak_live_bytes = working_set_bytes; + observation->cumulative_traffic_bytes = + working_set_bytes * rounds; + observation->model_bytes_read = + working_set_bytes * rounds; + observation->model_bytes_written = 0u; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_materialization( + uint64_t variant, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t count; + uint64_t rounds; + uint64_t round; + uint64_t i; + uint64_t result; + uint32_t *values; + uint32_t *temporary; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + rounds = r7_rounds_for_bytes(working_set_bytes); + + r7_observation_begin( + observation, + R7_COMPARE_MATERIALIZATION, + variant, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + values = (uint32_t *)r7_malloc(working_set_bytes); + temporary = NULL; + if (values == NULL || + !r7_fill_values(values, count, R7_SEED)) { + free(values); + return 0; + } + + if (variant == R7_VARIANT_A) { + temporary = (uint32_t *)r7_malloc(working_set_bytes); + if (temporary == NULL) { + free(values); + return 0; + } + } + + if (!r7_now(&setup_end)) { + free(temporary); + free(values); + return 0; + } + + result = 0u; + if (variant == R7_VARIANT_A) { + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + temporary[(size_t)i] = + r7_transform32(values[(size_t)i]); + } + for (i = 0u; i < count; ++i) { + result += (uint64_t)temporary[(size_t)i]; + } + } + } else { + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + result += (uint64_t)r7_transform32( + values[(size_t)i] + ); + } + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(temporary); + free(values); + return 0; + } + + free(temporary); + free(values); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * rounds; + if (variant == R7_VARIANT_A) { + observation->resident_bytes = + working_set_bytes * UINT64_C(2); + observation->peak_live_bytes = + working_set_bytes * UINT64_C(2); + observation->model_bytes_read = + working_set_bytes * rounds * UINT64_C(2); + observation->model_bytes_written = + working_set_bytes * rounds; + } else { + observation->resident_bytes = working_set_bytes; + observation->peak_live_bytes = working_set_bytes; + observation->model_bytes_read = + working_set_bytes * rounds; + observation->model_bytes_written = 0u; + } + observation->cumulative_traffic_bytes = + observation->model_bytes_read + + observation->model_bytes_written; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_layout( + uint64_t variant, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t count; + uint64_t rounds; + uint64_t round; + uint64_t i; + uint64_t result; + uint64_t hot_bytes; + uint64_t aos_bytes; + uint32_t *records; + uint32_t *x; + uint32_t *y; + uint32_t *flags; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + count = working_set_bytes / R7_AOS_LOGICAL_BYTES; + if (count == 0u) { + return 0; + } + rounds = r7_rounds_for_bytes(working_set_bytes); + hot_bytes = count * R7_HOT_LOGICAL_BYTES; + aos_bytes = count * R7_AOS_LOGICAL_BYTES; + + records = NULL; + x = NULL; + y = NULL; + flags = NULL; + + r7_observation_begin( + observation, + R7_COMPARE_LAYOUT, + variant, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + if (variant == R7_VARIANT_A) { + records = (uint32_t *)r7_malloc( + count * UINT64_C(6) * (uint64_t)sizeof(uint32_t) + ); + if (records == NULL) { + return 0; + } + + for (i = 0u; i < count; ++i) { + size_t base; + + base = (size_t)(i * UINT64_C(6)); + records[base + 0u] = + r7_value32(R7_SEED ^ UINT64_C(0x11), i); + records[base + 1u] = + r7_value32(R7_SEED ^ UINT64_C(0x22), i); + records[base + 2u] = + r7_value32(R7_SEED ^ UINT64_C(0x33), i); + records[base + 3u] = + r7_value32(R7_SEED ^ UINT64_C(0x44), i); + records[base + 4u] = + r7_value32(R7_SEED ^ UINT64_C(0x55), i); + records[base + 5u] = + r7_value32(R7_SEED ^ UINT64_C(0x66), i); + } + } else { + x = (uint32_t *)r7_malloc( + count * (uint64_t)sizeof(uint32_t) + ); + y = (uint32_t *)r7_malloc( + count * (uint64_t)sizeof(uint32_t) + ); + flags = (uint32_t *)r7_malloc( + count * (uint64_t)sizeof(uint32_t) + ); + + if (x == NULL || y == NULL || flags == NULL) { + free(x); + free(y); + free(flags); + return 0; + } + + for (i = 0u; i < count; ++i) { + x[(size_t)i] = + r7_value32(R7_SEED ^ UINT64_C(0x11), i); + y[(size_t)i] = + r7_value32(R7_SEED ^ UINT64_C(0x22), i); + flags[(size_t)i] = + r7_value32(R7_SEED ^ UINT64_C(0x33), i); + } + } + + if (!r7_now(&setup_end)) { + free(records); + free(x); + free(y); + free(flags); + return 0; + } + + result = 0u; + if (variant == R7_VARIANT_A) { + volatile const uint32_t *read_records; + + read_records = records; + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + size_t base; + + base = (size_t)(i * UINT64_C(6)); + result += r7_hot_result( + read_records[base + 0u], + read_records[base + 1u], + read_records[base + 2u] + ); + } + } + } else { + volatile const uint32_t *read_x; + volatile const uint32_t *read_y; + volatile const uint32_t *read_flags; + + read_x = x; + read_y = y; + read_flags = flags; + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + result += r7_hot_result( + read_x[(size_t)i], + read_y[(size_t)i], + read_flags[(size_t)i] + ); + } + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(records); + free(x); + free(y); + free(flags); + return 0; + } + + free(records); + free(x); + free(y); + free(flags); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * rounds; + observation->resident_bytes = + variant == R7_VARIANT_A ? aos_bytes : hot_bytes; + observation->peak_live_bytes = observation->resident_bytes; + observation->model_bytes_read = hot_bytes * rounds; + observation->model_bytes_written = 0u; + observation->cumulative_traffic_bytes = + observation->model_bytes_read; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_microtile( + uint64_t tile_size, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint32_t tile[4096]; + uint64_t count; + uint64_t rounds; + uint64_t round; + uint64_t index; + uint64_t result; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + if (tile_size == 0u || tile_size > UINT64_C(4096)) { + return 0; + } + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + if (tile_size > count) { + return 0; + } + rounds = r7_rounds_for_bytes(working_set_bytes); + + r7_observation_begin( + observation, + R7_COMPARE_MICROTILE, + tile_size, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start) || + !r7_now(&setup_end)) { + return 0; + } + + result = 0u; + for (round = 0u; round < rounds; ++round) { + index = 0u; + while (index < count) { + uint64_t take; + uint64_t lane; + + take = count - index; + if (take > tile_size) { + take = tile_size; + } + + for (lane = 0u; lane < take; ++lane) { + tile[(size_t)lane] = + r7_value32(R7_SEED, index + lane); + } + + for (lane = 0u; lane < take; ++lane) { + result += (uint64_t)r7_transform32( + tile[(size_t)lane] + ); + } + + index += take; + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end) || + !r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * rounds; + observation->resident_bytes = + tile_size * (uint64_t)sizeof(uint32_t); + observation->peak_live_bytes = observation->resident_bytes; + observation->model_bytes_read = + working_set_bytes * rounds; + observation->model_bytes_written = + working_set_bytes * rounds; + observation->cumulative_traffic_bytes = + observation->model_bytes_read + + observation->model_bytes_written; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_retain_regenerate( + uint64_t variant, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t count; + uint64_t rounds; + uint64_t passes; + uint64_t pass; + uint64_t i; + uint64_t result; + uint32_t *values; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + rounds = r7_rounds_for_bytes(working_set_bytes); + passes = rounds * UINT64_C(4); + values = NULL; + + r7_observation_begin( + observation, + R7_COMPARE_RETAIN_REGENERATE, + variant, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + if (variant == R7_VARIANT_A) { + values = (uint32_t *)r7_malloc(working_set_bytes); + if (values == NULL || + !r7_fill_values(values, count, R7_SEED)) { + free(values); + return 0; + } + } + + if (!r7_now(&setup_end)) { + free(values); + return 0; + } + + result = 0u; + if (variant == R7_VARIANT_A) { + volatile const uint32_t *read_values; + + read_values = values; + for (pass = 0u; pass < passes; ++pass) { + for (i = 0u; i < count; ++i) { + result += (uint64_t)read_values[(size_t)i]; + } + } + } else { + for (pass = 0u; pass < passes; ++pass) { + for (i = 0u; i < count; ++i) { + result += (uint64_t)r7_value32(R7_SEED, i); + } + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(values); + return 0; + } + + free(values); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * passes; + observation->resident_bytes = + variant == R7_VARIANT_A ? + working_set_bytes : + UINT64_C(16); + observation->peak_live_bytes = observation->resident_bytes; + observation->model_bytes_read = + variant == R7_VARIANT_A ? + working_set_bytes * passes : + 0u; + observation->model_bytes_written = 0u; + observation->cumulative_traffic_bytes = + observation->model_bytes_read; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_lookup_recompute( + uint64_t variant, + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t count; + uint64_t rounds; + uint64_t round; + uint64_t i; + uint64_t index; + uint64_t result; + uint32_t *table; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + rounds = r7_rounds_for_bytes(working_set_bytes); + table = NULL; + + r7_observation_begin( + observation, + R7_COMPARE_LOOKUP_RECOMPUTE, + variant, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + if (variant == R7_VARIANT_A) { + table = (uint32_t *)r7_malloc( + R7_LOOKUP_ENTRIES * (uint64_t)sizeof(uint32_t) + ); + if (table == NULL || + !r7_fill_values(table, R7_LOOKUP_ENTRIES, R7_SEED)) { + free(table); + return 0; + } + } + + if (!r7_now(&setup_end)) { + free(table); + return 0; + } + + result = 0u; + if (variant == R7_VARIANT_A) { + volatile const uint32_t *read_table; + + read_table = table; + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + index = i & (R7_LOOKUP_ENTRIES - UINT64_C(1)); + result += (uint64_t)read_table[(size_t)index]; + } + } + } else { + for (round = 0u; round < rounds; ++round) { + for (i = 0u; i < count; ++i) { + index = i & (R7_LOOKUP_ENTRIES - UINT64_C(1)); + result += (uint64_t)r7_value32(R7_SEED, index); + } + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(table); + return 0; + } + + free(table); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = count * rounds; + observation->resident_bytes = + variant == R7_VARIANT_A ? + R7_LOOKUP_ENTRIES * (uint64_t)sizeof(uint32_t) : + UINT64_C(16); + observation->peak_live_bytes = observation->resident_bytes; + observation->model_bytes_read = + variant == R7_VARIANT_A ? + count * rounds * (uint64_t)sizeof(uint32_t) : + 0u; + observation->model_bytes_written = 0u; + observation->cumulative_traffic_bytes = + observation->model_bytes_read; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_arena_accounting( + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + uint64_t arena_bytes; + uint8_t *backing; + rune_region region; + rune_span storage; + rune_arena arena; + rune_span span; + rune_status status; + uint64_t round; + uint64_t allocation_index; + uint64_t lane; + uint64_t result; + uint8_t fill_value; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + arena_bytes = working_set_bytes; + if (arena_bytes > UINT64_C(65536)) { + arena_bytes = UINT64_C(65536); + } + if (arena_bytes < UINT64_C(4096)) { + arena_bytes = UINT64_C(4096); + } + + r7_observation_begin( + observation, + R7_COMPARE_PEAK_CUMULATIVE, + R7_VARIANT_A, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start)) { + return 0; + } + + backing = (uint8_t *)r7_malloc(arena_bytes); + if (backing == NULL) { + return 0; + } + + status = rune_region_attach( + ®ion, + backing, + arena_bytes, + RUNE_ACCESS_READ | RUNE_ACCESS_WRITE + ); + if (status != RUNE_OK) { + free(backing); + return 0; + } + status = rune_span_init( + &storage, + ®ion, + 0u, + arena_bytes, + RUNE_ACCESS_READ | RUNE_ACCESS_WRITE + ); + if (status != RUNE_OK || + rune_arena_init(&arena, &storage) != RUNE_OK) { + free(backing); + return 0; + } + + if (!r7_now(&setup_end)) { + free(backing); + return 0; + } + + result = 0u; + allocation_index = 0u; + for (round = 0u; round < UINT64_C(4); ++round) { + for (;;) { + status = rune_arena_alloc( + &arena, + UINT64_C(37), + UINT64_C(64), + &span + ); + if (status == RUNE_ERR_EXHAUSTED) { + break; + } + if (status != RUNE_OK) { + free(backing); + return 0; + } + + fill_value = (uint8_t)( + r7_value32( + R7_SEED ^ round, + allocation_index + ) & UINT32_C(0xff) + ); + if (rune_span_fill(&span, fill_value) != RUNE_OK) { + free(backing); + return 0; + } + + for (lane = 0u; lane < span.length; ++lane) { + result += (uint64_t)backing[ + (size_t)(span.offset + lane) + ]; + } + allocation_index += 1u; + } + + if (rune_arena_reset(&arena) != RUNE_OK) { + free(backing); + return 0; + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end)) { + free(backing); + return 0; + } + + free(backing); + if (!r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = allocation_index; + observation->resident_bytes = arena_bytes; + observation->peak_live_bytes = arena.high_water; + observation->cumulative_traffic_bytes = + arena.cumulative_consumed_bytes; + observation->model_bytes_read = + arena.cumulative_payload_bytes; + observation->model_bytes_written = + arena.cumulative_payload_bytes; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_logical_resident( + uint64_t working_set_bytes, + uint64_t repeat_index, + r7_observation *observation +) +{ + const uint64_t logical_items = UINT64_C(1) << 40u; + const uint64_t window_items = UINT64_C(64); + const uint64_t window_count = UINT64_C(64); + uint64_t window; + uint64_t lane; + uint64_t result; + clock_t total_start; + clock_t setup_end; + clock_t execute_end; + clock_t teardown_end; + + r7_observation_begin( + observation, + R7_COMPARE_LOGICAL_RESIDENT, + R7_VARIANT_A, + working_set_bytes, + repeat_index + ); + + if (!r7_now(&total_start) || + !r7_now(&setup_end)) { + return 0; + } + + result = UINT64_C(14695981039346656037); + for (window = 0u; window < window_count; ++window) { + uint64_t start; + + start = ( + (uint64_t)r7_value32(R7_SEED, window) * + UINT64_C(2654435761) + ) % (logical_items - window_items); + + result = r7_hash_u64(result, start); + + for (lane = 0u; lane < window_items; ++lane) { + result = r7_hash_u64( + result, + (uint64_t)r7_value32( + R7_SEED, + start + lane + ) + ); + } + } + + r7_sink ^= result; + if (!r7_now(&execute_end) || + !r7_now(&teardown_end)) { + return 0; + } + + observation->logical_items = logical_items; + observation->resident_bytes = UINT64_C(48); + observation->peak_live_bytes = UINT64_C(48); + observation->cumulative_traffic_bytes = 0u; + observation->model_bytes_read = 0u; + observation->model_bytes_written = 0u; + observation->result_u64 = result; + + return r7_finish_times( + observation, + total_start, + setup_end, + execute_end, + teardown_end + ); +} + +static int r7_measure_size( + uint64_t working_set_bytes, + uint64_t repeat_index +) +{ + static const uint64_t tiles[] = { + UINT64_C(32), + UINT64_C(64), + UINT64_C(128), + UINT64_C(256), + UINT64_C(512), + UINT64_C(1024), + UINT64_C(2048), + UINT64_C(4096) + }; + r7_observation a; + r7_observation b; + r7_observation observation; + uint64_t reference; + int have_reference; + size_t i; + + if (!r7_measure_locality( + R7_VARIANT_A, + working_set_bytes, + repeat_index, + &a) || + !r7_measure_locality( + R7_VARIANT_B, + working_set_bytes, + repeat_index, + &b) || + a.result_u64 != b.result_u64 || + !r7_emit(&a) || + !r7_emit(&b)) { + return 0; + } + + if (!r7_measure_materialization( + R7_VARIANT_A, + working_set_bytes, + repeat_index, + &a) || + !r7_measure_materialization( + R7_VARIANT_B, + working_set_bytes, + repeat_index, + &b) || + a.result_u64 != b.result_u64 || + !r7_emit(&a) || + !r7_emit(&b)) { + return 0; + } + + if (!r7_measure_layout( + R7_VARIANT_A, + working_set_bytes, + repeat_index, + &a) || + !r7_measure_layout( + R7_VARIANT_B, + working_set_bytes, + repeat_index, + &b) || + a.result_u64 != b.result_u64 || + !r7_emit(&a) || + !r7_emit(&b)) { + return 0; + } + + reference = 0u; + have_reference = 0; + for (i = 0u; i < sizeof(tiles) / sizeof(tiles[0]); ++i) { + uint64_t count; + + count = working_set_bytes / (uint64_t)sizeof(uint32_t); + if (tiles[i] > count) { + continue; + } + + if (!r7_measure_microtile( + tiles[i], + working_set_bytes, + repeat_index, + &observation)) { + return 0; + } + + if (!have_reference) { + reference = observation.result_u64; + have_reference = 1; + } else if (reference != observation.result_u64) { + return 0; + } + + if (!r7_emit(&observation)) { + return 0; + } + } + + if (!r7_measure_retain_regenerate( + R7_VARIANT_A, + working_set_bytes, + repeat_index, + &a) || + !r7_measure_retain_regenerate( + R7_VARIANT_B, + working_set_bytes, + repeat_index, + &b) || + a.result_u64 != b.result_u64 || + !r7_emit(&a) || + !r7_emit(&b)) { + return 0; + } + + if (!r7_measure_lookup_recompute( + R7_VARIANT_A, + working_set_bytes, + repeat_index, + &a) || + !r7_measure_lookup_recompute( + R7_VARIANT_B, + working_set_bytes, + repeat_index, + &b) || + a.result_u64 != b.result_u64 || + !r7_emit(&a) || + !r7_emit(&b)) { + return 0; + } + + if (!r7_measure_arena_accounting( + working_set_bytes, + repeat_index, + &observation) || + !r7_emit(&observation)) { + return 0; + } + + if (!r7_measure_logical_resident( + working_set_bytes, + repeat_index, + &observation) || + !r7_emit(&observation)) { + return 0; + } + + return 1; +} + +static int r7_parse_u64(const char *text, uint64_t *out) +{ + char *end; + unsigned long long value; + + if (text == NULL || out == NULL || text[0] == '\0' || + text[0] == '-' || + text[0] == ' ' || + text[0] == '\t' || + text[0] == '\n' || + text[0] == '\r' || + text[0] == '\f' || + text[0] == '\v') { + return 0; + } + + errno = 0; + end = NULL; + value = strtoull(text, &end, 10); + if (errno != 0 || end == text || *end != '\0') { + return 0; + } + + *out = (uint64_t)value; + return (unsigned long long)*out == value; +} + +static void r7_usage(const char *program) +{ + fprintf( + stderr, + "usage: %s [--profile smoke|local] [--bytes N] [--repeats N]\n", + program + ); +} + +int main(int argc, char **argv) +{ + static const uint64_t local_sizes[] = { + UINT64_C(4096), + UINT64_C(32768), + UINT64_C(262144), + UINT64_C(1048576), + UINT64_C(4194304), + UINT64_C(16777216), + UINT64_C(67108864) + }; + const char *profile; + uint64_t explicit_bytes; + uint64_t repeats; + int has_explicit_bytes; + int i; + uint64_t repeat; + + profile = "smoke"; + explicit_bytes = 0u; + repeats = UINT64_C(1); + has_explicit_bytes = 0; + + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--profile") == 0) { + if (i + 1 >= argc) { + r7_usage(argv[0]); + return 2; + } + profile = argv[++i]; + if (strcmp(profile, "smoke") != 0 && + strcmp(profile, "local") != 0) { + r7_usage(argv[0]); + return 2; + } + } else if (strcmp(argv[i], "--bytes") == 0) { + if (i + 1 >= argc || + !r7_parse_u64(argv[++i], &explicit_bytes)) { + r7_usage(argv[0]); + return 2; + } + has_explicit_bytes = 1; + } else if (strcmp(argv[i], "--repeats") == 0) { + if (i + 1 >= argc || + !r7_parse_u64(argv[++i], &repeats) || + repeats == 0u || + repeats > UINT64_C(100)) { + r7_usage(argv[0]); + return 2; + } + } else { + r7_usage(argv[0]); + return 2; + } + } + + if (has_explicit_bytes) { + if (explicit_bytes < R7_MIN_BYTES || + explicit_bytes > R7_MAX_BYTES || + !r7_is_power_of_two_u64(explicit_bytes)) { + fprintf(stderr, "invalid R7 working-set size\n"); + return 2; + } + + for (repeat = 0u; repeat < repeats; ++repeat) { + if (!r7_measure_size(explicit_bytes, repeat)) { + fprintf(stderr, "R7 study execution failed\n"); + return 1; + } + } + } else if (strcmp(profile, "smoke") == 0) { + for (repeat = 0u; repeat < repeats; ++repeat) { + if (!r7_measure_size(UINT64_C(32768), repeat)) { + fprintf(stderr, "R7 study execution failed\n"); + return 1; + } + } + } else { + size_t lane; + + for (lane = 0u; + lane < sizeof(local_sizes) / sizeof(local_sizes[0]); + ++lane) { + for (repeat = 0u; repeat < repeats; ++repeat) { + if (!r7_measure_size(local_sizes[lane], repeat)) { + fprintf(stderr, "R7 study execution failed\n"); + return 1; + } + } + } + } + + if (fflush(stdout) == EOF || ferror(stdout)) { + fprintf(stderr, "R7 study output failure\n"); + return 1; + } + + (void)r7_sink; + return 0; +} From 27acc7c668e8e068af89739106a2ef8ae149baa1 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:24:48 +0930 Subject: [PATCH 002/132] Harden R7 study measurement integrity --- .github/workflows/c99.yml | 3 +++ AGENTS.md | 2 ++ R7-MEMORY-WALL-STUDY.md | 6 ++++++ machine/r7-memory-wall-study.v1.json | 6 ++++++ study/r7_memory_wall.c | 29 +++++++++++++++++++--------- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 6d01d60..209c39c 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -27,6 +27,9 @@ jobs: - name: Build R1-R7 checks, R6 proof, frozen R4 corpus, and R7 smoke run: make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" + - name: Validate R7 local evidence script + run: sh -n scripts/r7-run-local.sh + - name: Reject truncated corpus output run: | if ./build/rune_corpus --profile smoke > /dev/full 2>/dev/null; then diff --git a/AGENTS.md b/AGENTS.md index 7a485f6..9a608cd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -154,6 +154,8 @@ CORE_RULES: - R7_reference_timer_is_C99_clock_process_CPU_time - R7_observations_record_setup_execute_teardown_and_total_ticks - R7_pairwise_comparisons_require_exact_result_identity +- R7_volatile_study_accesses_prevent_variant_elision +- R7_clock_wrap_is_rejected_before_tick_subtraction - R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method - R7_negative_results_must_be_retained - R7_timing_alone_must_not_claim_cache_NUMA_or_bandwidth_cause diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 5f1a238..a88b3df 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -204,6 +204,12 @@ The default local evidence run uses five repeats. The harness normalizes small cases toward roughly 64 MiB of logical work per sample so very small working sets are not represented by a single tiny loop. +Selected study storage is accessed through C99 `volatile` views where needed to +prevent an optimizing compiler from legally collapsing one declared benchmark +variant into another (for example, eliminating the materialized temporary or +the microtile). These volatile accesses are **study mechanics**, not RUNE +runtime semantics or an optimization recommendation. + ## Local evidence bundle Run: diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index cc9d17e..7462b8b 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -186,5 +186,11 @@ "clang" ], "CI_validates_harness_not_performance": true + }, + "measurement_integrity": { + "volatile_accesses_are_study_mechanics": true, + "purpose": "prevent-optimizer-from-collapsing-declared-materialization-tile-retain-recompute-variants", + "volatile_semantics_are_part_of_R7_harness_not_runtime_API": true, + "clock_wrap_is_rejected_before_tick_subtraction": true } } diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index 4be220f..2b93f6a 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -155,11 +155,12 @@ static int r7_ticks_between( return 0; } - delta = end - start; - if (delta < (clock_t)0) { + if (end < start) { return 0; } + delta = end - start; + converted = (uint64_t)delta; if ((clock_t)converted != delta) { return 0; @@ -353,6 +354,9 @@ static int r7_measure_locality( result = 0u; if (variant == R7_VARIANT_A) { + volatile const uint32_t *read_values; + + read_values = values; for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { result += (uint64_t)read_values[(size_t)i]; @@ -413,7 +417,7 @@ static int r7_measure_materialization( uint64_t i; uint64_t result; uint32_t *values; - uint32_t *temporary; + volatile uint32_t *temporary; clock_t total_start; clock_t setup_end; clock_t execute_end; @@ -443,7 +447,7 @@ static int r7_measure_materialization( } if (variant == R7_VARIANT_A) { - temporary = (uint32_t *)r7_malloc(working_set_bytes); + temporary = (volatile uint32_t *)r7_malloc(working_set_bytes); if (temporary == NULL) { free(values); return 0; @@ -461,17 +465,20 @@ static int r7_measure_materialization( for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { temporary[(size_t)i] = - r7_transform32(values[(size_t)i]); + r7_transform32(read_values[(size_t)i]); } for (i = 0u; i < count; ++i) { result += (uint64_t)temporary[(size_t)i]; } } } else { + volatile const uint32_t *read_values; + + read_values = values; for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { result += (uint64_t)r7_transform32( - values[(size_t)i] + read_values[(size_t)i] ); } } @@ -709,7 +716,7 @@ static int r7_measure_microtile( r7_observation *observation ) { - uint32_t tile[4096]; + volatile uint32_t tile[4096]; uint64_t count; uint64_t rounds; uint64_t round; @@ -812,6 +819,7 @@ static int r7_measure_retain_regenerate( uint64_t i; uint64_t result; uint32_t *values; + volatile uint64_t regenerate_seed; clock_t total_start; clock_t setup_end; clock_t execute_end; @@ -821,6 +829,7 @@ static int r7_measure_retain_regenerate( rounds = r7_rounds_for_bytes(working_set_bytes); passes = rounds * UINT64_C(4); values = NULL; + regenerate_seed = R7_SEED; r7_observation_begin( observation, @@ -861,7 +870,7 @@ static int r7_measure_retain_regenerate( } else { for (pass = 0u; pass < passes; ++pass) { for (i = 0u; i < count; ++i) { - result += (uint64_t)r7_value32(R7_SEED, i); + result += (uint64_t)r7_value32(regenerate_seed, i); } } } @@ -915,6 +924,7 @@ static int r7_measure_lookup_recompute( uint64_t index; uint64_t result; uint32_t *table; + volatile uint64_t recompute_seed; clock_t total_start; clock_t setup_end; clock_t execute_end; @@ -923,6 +933,7 @@ static int r7_measure_lookup_recompute( count = working_set_bytes / (uint64_t)sizeof(uint32_t); rounds = r7_rounds_for_bytes(working_set_bytes); table = NULL; + recompute_seed = R7_SEED; r7_observation_begin( observation, @@ -967,7 +978,7 @@ static int r7_measure_lookup_recompute( for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { index = i & (R7_LOOKUP_ENTRIES - UINT64_C(1)); - result += (uint64_t)r7_value32(R7_SEED, index); + result += (uint64_t)r7_value32(recompute_seed, index); } } } From 9091c1cfd28a3e5db42d53e783c2a0de4bca59fd Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:25:34 +0930 Subject: [PATCH 003/132] Fix R7 anti-elision pointer handling --- study/r7_memory_wall.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index 2b93f6a..e835b93 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -417,7 +417,9 @@ static int r7_measure_materialization( uint64_t i; uint64_t result; uint32_t *values; - volatile uint32_t *temporary; + uint32_t *temporary; + volatile const uint32_t *read_values; + volatile uint32_t *temporary_view; clock_t total_start; clock_t setup_end; clock_t execute_end; @@ -440,6 +442,7 @@ static int r7_measure_materialization( values = (uint32_t *)r7_malloc(working_set_bytes); temporary = NULL; + temporary_view = NULL; if (values == NULL || !r7_fill_values(values, count, R7_SEED)) { free(values); @@ -447,7 +450,7 @@ static int r7_measure_materialization( } if (variant == R7_VARIANT_A) { - temporary = (volatile uint32_t *)r7_malloc(working_set_bytes); + temporary = (uint32_t *)r7_malloc(working_set_bytes); if (temporary == NULL) { free(values); return 0; @@ -460,21 +463,20 @@ static int r7_measure_materialization( return 0; } + read_values = values; + temporary_view = temporary; result = 0u; if (variant == R7_VARIANT_A) { for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { - temporary[(size_t)i] = + temporary_view[(size_t)i] = r7_transform32(read_values[(size_t)i]); } for (i = 0u; i < count; ++i) { - result += (uint64_t)temporary[(size_t)i]; + result += (uint64_t)temporary_view[(size_t)i]; } } } else { - volatile const uint32_t *read_values; - - read_values = values; for (round = 0u; round < rounds; ++round) { for (i = 0u; i < count; ++i) { result += (uint64_t)r7_transform32( From c7d641f23234925dcc38a86a09651546f87f57a3 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:46:04 +0930 Subject: [PATCH 004/132] Harden R7 evidence provenance and tile lifecycle --- AGENTS.md | 9 ++ R7-MEMORY-WALL-STUDY.md | 29 +++++- evidence/r7/README.md | 14 ++- machine/r7-memory-wall-study.v1.json | 27 +++++- scripts/r7-run-local.sh | 134 ++++++++++++++++++++++----- study/r7_memory_wall.c | 33 +++++-- 6 files changed, 206 insertions(+), 40 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9a608cd..0445cee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -155,6 +155,15 @@ CORE_RULES: - R7_observations_record_setup_execute_teardown_and_total_ticks - R7_pairwise_comparisons_require_exact_result_identity - R7_volatile_study_accesses_prevent_variant_elision +- R7_microtile_allocates_only_selected_extent_inside_timed_lifecycle +- R7_microtile_selected_extent_is_in_resident_peak_and_setup_teardown_timing +- R7_evidence_destination_must_be_new_and_immutable +- R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation +- R7_evidence_class_is_raw_local_execution_observation +- R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound +- R7_compiler_identity_capture_must_succeed +- R7_compound_CC_is_not_accepted_for_evidence_capture +- R7_memory_profile_is_required_on_every_supported_capture_host - R7_clock_wrap_is_rejected_before_tick_subtraction - R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method - R7_negative_results_must_be_retained diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index a88b3df..2c429c3 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -143,6 +143,12 @@ variant_id is the tile size in elements: Every executed tile size must produce one exact result identity. +Each microtile variant allocates **only its selected tile extent** after the +total timer begins and releases it before teardown ends. The allocation is part +of setup timing, release is part of teardown timing, and resident/peak bytes +therefore describe the actual selected tile rather than a hidden fixed 4096-item +automatic buffer. + ### 5 — Retain versus regenerate ~~~text @@ -224,21 +230,36 @@ or: RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ +The script creates an **immutable new destination** and refuses to overwrite an +existing bundle. It samples Git status before creating that destination and +counts tracked, staged, and untracked files when recording dirty state. + +Every bundle declares: + +~~~text +evidence_class=raw-local-execution-observation +~~~ + The script records: - exact Git source revision; -- dirty/clean working-tree state; -- compiler path/version; -- build flags; +- dirty/clean working-tree state including untracked files; +- resolved single-executable compiler path and successful version output; +- both CPPFLAGS and CFLAGS, and binds those exact values into the build command; - uname platform context; - visible processor count when available; - CPU model when available; -- total memory when available; +- a **required memory profile**, using /proc/meminfo, sysctl, or getconf; - timer method; - exact commands; - raw observations; - SHA-256 integrity file. +A compound CC such as `ccache gcc` is rejected for evidence capture; wrappers +or flags must be represented explicitly rather than hidden inside CC. If the +compiler cannot be resolved/identified or memory context cannot be captured, the +bundle fails closed. + These fields satisfy the evidence-dimension requirement only when the bundle is actually captured on the host. A template or planned command is not execution evidence. diff --git a/evidence/r7/README.md b/evidence/r7/README.md index e07f955..b1769a2 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -15,15 +15,23 @@ or choose an explicit destination: RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ +The destination must not already exist; evidence bundles are immutable capture +records and are never overwritten. + A bundle contains: -- `environment.txt` — source revision, dirty state, timer method, CPU-count and - memory context where available; -- `compiler.txt` — compiler path/version output; +- `environment.txt` — evidence class, source revision, dirty state including + untracked files, timer method, exact CPPFLAGS/CFLAGS, CPU/platform context, + and a required memory profile; +- `compiler.txt` — resolved compiler path and successful version output; - `command.txt` — exact build/run commands; - `observations.tsv` — raw numeric R7 observations; - `SHA256SUMS` — integrity hashes for the bundle. +For evidence capture, CC must identify one compiler executable; compound +commands are rejected. Missing compiler identity or memory profile causes the +capture to fail. + Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 7462b8b..6609a49 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -91,7 +91,11 @@ 2048, 4096 ], - "exact_result_parity_required": true + "exact_result_parity_required": true, + "tile_storage_allocation": "selected-tile-only", + "tile_allocation_included_in_setup_ticks": true, + "tile_release_included_in_teardown_ticks": true, + "resident_and_peak_bytes_equal_selected_tile_extent": true }, "5": { "name": "retain-vs-regenerate", @@ -167,7 +171,26 @@ "measurement_method" ], "dirty_state_recorded": true, - "integrity": "SHA-256" + "integrity": "SHA-256", + "evidence_class": "raw-local-execution-observation", + "evidence_class_required": true, + "destination_must_not_preexist": true, + "overwrite_existing_bundle_allowed": false, + "dirty_state_includes_untracked_files": true, + "dirty_state_sampled_before_bundle_creation": true, + "CPPFLAGS_recorded_and_bound": true, + "CFLAGS_recorded_and_bound": true, + "compiler_command_must_be_single_executable": true, + "compiler_path_resolution_required": true, + "compiler_version_capture_required": true, + "compiler_identity_failure_is_capture_failure": true, + "memory_profile_required": true, + "memory_profile_sources": [ + "/proc/meminfo", + "sysctl hw.memsize/hw.physmem64/hw.physmem", + "getconf _PHYS_PAGES + PAGE_SIZE" + ], + "missing_memory_profile_is_capture_failure": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index edab6c9..a4d8e79 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -1,76 +1,164 @@ #!/bin/sh set -eu +fail() +{ + echo "R7 evidence capture: $*" >&2 + exit 1 +} + repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) cd "$repo_root" cc_name=${CC:-cc} +cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} stamp=$(date -u +%Y%m%dT%H%M%SZ) out_dir=${1:-"evidence/r7/local-$stamp"} +out_parent=$(dirname "$out_dir") -mkdir -p "$out_dir" +case "$cc_name" in + *[[:space:]]*) + fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" + ;; +esac -revision=$(git rev-parse HEAD) -if git diff --quiet --ignore-submodules -- && - git diff --cached --quiet --ignore-submodules --; then - dirty=false -else +[ -d "$out_parent" ] || + fail "bundle parent directory does not exist: $out_parent" + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination already exists; refusing overwrite: $out_dir" +fi + +revision=$(git rev-parse HEAD) || + fail "could not resolve source revision" + +git_status=$(git status --porcelain --untracked-files=all) || + fail "could not inspect Git working-tree state" + +if [ -n "$git_status" ]; then dirty=true +else + dirty=false +fi + +cc_path=$(command -v "$cc_name") || + fail "compiler not found: $cc_name" +[ -n "$cc_path" ] && [ -x "$cc_path" ] || + fail "compiler path is not executable: $cc_path" + +compiler_version=$("$cc_path" --version 2>&1) || + fail "compiler identity command failed: $cc_path --version" +[ -n "$compiler_version" ] || + fail "compiler identity output is empty" + +memory_profile= +if [ -r /proc/meminfo ]; then + mem_total_kib=$(awk '/^MemTotal:/ { print $2; exit }' /proc/meminfo) + case "$mem_total_kib" in + ''|*[!0-9]*) ;; + *) memory_profile="mem_total_kib=$mem_total_kib" ;; + esac +fi + +if [ -z "$memory_profile" ] && command -v sysctl >/dev/null 2>&1; then + for key in hw.memsize hw.physmem64 hw.physmem; do + value=$(sysctl -n "$key" 2>/dev/null || :) + case "$value" in + ''|*[!0-9]*) ;; + *) + memory_profile="mem_total_bytes=$value" + break + ;; + esac + done +fi + +if [ -z "$memory_profile" ] && command -v getconf >/dev/null 2>&1; then + phys_pages=$(getconf _PHYS_PAGES 2>/dev/null || :) + page_size=$(getconf PAGE_SIZE 2>/dev/null || :) + case "$phys_pages:$page_size" in + *[!0-9:]*|:|*:0|0:*) ;; + *) + memory_profile="mem_phys_pages=$phys_pages +mem_page_size_bytes=$page_size" + ;; + esac +fi + +[ -n "$memory_profile" ] || + fail "could not capture required memory profile" + +cpu_model= +if [ -r /proc/cpuinfo ]; then + cpu_model=$(awk -F ': ' ' + /^model name[[:space:]]*:/ { print $2; exit } + /^Hardware[[:space:]]*:/ { print $2; exit } + ' /proc/cpuinfo) fi +if [ -z "$cpu_model" ] && command -v sysctl >/dev/null 2>&1; then + for key in machdep.cpu.brand_string hw.model; do + value=$(sysctl -n "$key" 2>/dev/null || :) + if [ -n "$value" ]; then + cpu_model=$value + break + fi + done +fi + +mkdir "$out_dir" || + fail "could not create immutable evidence destination: $out_dir" { echo "contract=rune.r7.environment.v1" + echo "evidence_class=raw-local-execution-observation" echo "source_revision=$revision" echo "working_tree_dirty=$dirty" echo "measurement_method=C99_clock_process_cpu_time" echo "benchmark_contract=rune.r7.memory-wall-observation.v1" echo "repeats=$repeats" - echo "cc=$cc_name" + echo "cc_requested=$cc_name" + echo "cc_resolved=$cc_path" + echo "cppflags=$cppflags" echo "cflags=$cflags" echo "uname=$(uname -a)" if command -v getconf >/dev/null 2>&1; then echo "processors_online=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" echo "long_bit=$(getconf LONG_BIT 2>/dev/null || echo unknown)" fi - if [ -r /proc/cpuinfo ]; then - awk -F ': ' ' - /^model name[[:space:]]*:/ { print "cpu_model=" $2; exit } - /^Hardware[[:space:]]*:/ { print "cpu_model=" $2; exit } - ' /proc/cpuinfo - fi - if [ -r /proc/meminfo ]; then - awk '/^MemTotal:/ { print "mem_total_kib=" $2 }' /proc/meminfo + if [ -n "$cpu_model" ]; then + echo "cpu_model=$cpu_model" fi + printf '%s\n' "$memory_profile" } > "$out_dir/environment.txt" { - command -v "$cc_name" 2>/dev/null || true - "$cc_name" --version 2>&1 || true + echo "compiler_path=$cc_path" + printf '%s\n' "$compiler_version" } > "$out_dir/compiler.txt" { - echo "make clean build/rune_r7_study CC=$cc_name CFLAGS=$cflags" + echo "make clean build/rune_r7_study CC=$cc_path CPPFLAGS=$cppflags CFLAGS=$cflags" echo "./build/rune_r7_study --profile local --repeats $repeats" } > "$out_dir/command.txt" -make clean build/rune_r7_study CC="$cc_name" CFLAGS="$cflags" +make clean build/rune_r7_study CC="$cc_path" CPPFLAGS="$cppflags" CFLAGS="$cflags" + ./build/rune_r7_study --profile local --repeats "$repeats" > "$out_dir/observations.tsv" if command -v sha256sum >/dev/null 2>&1; then ( cd "$out_dir" - sha256sum environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS + sha256sum environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS ) elif command -v shasum >/dev/null 2>&1; then ( cd "$out_dir" - shasum -a 256 environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS + shasum -a 256 environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS ) else - echo "no SHA-256 utility available" >&2 - exit 1 + fail "no SHA-256 utility available" fi echo "R7 evidence bundle: $out_dir" diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index e835b93..35bb849 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -718,7 +718,9 @@ static int r7_measure_microtile( r7_observation *observation ) { - volatile uint32_t tile[4096]; + uint32_t *tile_storage; + volatile uint32_t *tile; + uint64_t tile_bytes; uint64_t count; uint64_t rounds; uint64_t round; @@ -738,6 +740,7 @@ static int r7_measure_microtile( return 0; } rounds = r7_rounds_for_bytes(working_set_bytes); + tile_bytes = tile_size * (uint64_t)sizeof(uint32_t); r7_observation_begin( observation, @@ -747,8 +750,18 @@ static int r7_measure_microtile( repeat_index ); - if (!r7_now(&total_start) || - !r7_now(&setup_end)) { + if (!r7_now(&total_start)) { + return 0; + } + + tile_storage = (uint32_t *)r7_malloc(tile_bytes); + if (tile_storage == NULL) { + return 0; + } + tile = tile_storage; + + if (!r7_now(&setup_end)) { + free(tile_storage); return 0; } @@ -780,15 +793,19 @@ static int r7_measure_microtile( } r7_sink ^= result; - if (!r7_now(&execute_end) || - !r7_now(&teardown_end)) { + if (!r7_now(&execute_end)) { + free(tile_storage); + return 0; + } + + free(tile_storage); + if (!r7_now(&teardown_end)) { return 0; } observation->logical_items = count * rounds; - observation->resident_bytes = - tile_size * (uint64_t)sizeof(uint32_t); - observation->peak_live_bytes = observation->resident_bytes; + observation->resident_bytes = tile_bytes; + observation->peak_live_bytes = tile_bytes; observation->model_bytes_read = working_set_bytes * rounds; observation->model_bytes_written = From 5aa7173d6694df280701339d04befa7b2ac78cbc Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 13:15:35 +0930 Subject: [PATCH 005/132] Harden R7 evidence build isolation --- .github/workflows/c99.yml | 8 +++++- AGENTS.md | 4 +++ R7-MEMORY-WALL-STUDY.md | 10 +++++++ evidence/r7/README.md | 9 +++++-- machine/r7-memory-wall-study.v1.json | 14 +++++++++- scripts/r7-run-local.sh | 39 +++++++++++++++++++++------- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 209c39c..b855c27 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -28,7 +28,13 @@ jobs: run: make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" - name: Validate R7 local evidence script - run: sh -n scripts/r7-run-local.sh + run: | + sh -n scripts/r7-run-local.sh + mkdir -p build + if scripts/r7-run-local.sh build/r7-evidence 2>/dev/null; then + echo "R7 evidence script accepted build/ destination" >&2 + exit 1 + fi - name: Reject truncated corpus output run: | diff --git a/AGENTS.md b/AGENTS.md index 0445cee..1f19fe3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -161,6 +161,10 @@ CORE_RULES: - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound +- R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build +- R7_evidence_build_must_rebuild_from_recorded_source_and_flags +- R7_evidence_destination_must_not_resolve_inside_build_directory +- R7_getconf_memory_profile_requires_both_nonzero_numeric_page_count_and_size - R7_compiler_identity_capture_must_succeed - R7_compound_CC_is_not_accepted_for_evidence_capture - R7_memory_profile_is_required_on_every_supported_capture_host diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 2c429c3..1f1b76e 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -260,6 +260,16 @@ or flags must be represented explicitly rather than hidden inside CC. If the compiler cannot be resolved/identified or memory context cannot be captured, the bundle fails closed. +Evidence destinations resolving to `build/` or a descendant are rejected, +because the recorded build begins with `make clean`. The build itself clears +inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES` so dry-run or other +make-control flags cannot silently reuse a stale executable. The sanitized make +invocation is recorded in `command.txt`. + +The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and +`PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is +not accepted as complete evidence. + These fields satisfy the evidence-dimension requirement only when the bundle is actually captured on the host. A template or planned command is not execution evidence. diff --git a/evidence/r7/README.md b/evidence/r7/README.md index b1769a2..0a8ab6e 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -16,7 +16,8 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The destination must not already exist; evidence bundles are immutable capture -records and are never overwritten. +records and are never overwritten. Destinations resolving inside `build/` are +also rejected because evidence capture performs a clean rebuild. A bundle contains: @@ -30,7 +31,11 @@ A bundle contains: For evidence capture, CC must identify one compiler executable; compound commands are rejected. Missing compiler identity or memory profile causes the -capture to fail. +capture to fail. The getconf fallback requires both a nonzero numeric physical +page count and page size. + +Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build so a +dry-run flag such as MAKEFLAGS=-n cannot certify a stale executable. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 6609a49..bdbd82f 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -190,7 +190,19 @@ "sysctl hw.memsize/hw.physmem64/hw.physmem", "getconf _PHYS_PAGES + PAGE_SIZE" ], - "missing_memory_profile_is_capture_failure": true + "missing_memory_profile_is_capture_failure": true, + "inherited_make_control_variables_sanitized": [ + "MAKEFLAGS", + "GNUMAKEFLAGS", + "MFLAGS", + "MAKEFILES", + "MAKEOVERRIDES" + ], + "inherited_make_dry_run_must_not_affect_build": true, + "build_target_must_be_rebuilt_from_recorded_source_configuration": true, + "destination_under_build_directory_allowed": false, + "destination_path_checked_against_physical_parent": true, + "getconf_memory_profile_requires_both_nonzero_numeric_phys_pages_and_page_size": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index a4d8e79..b6b3383 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -7,7 +7,7 @@ fail() exit 1 } -repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) cd "$repo_root" cc_name=${CC:-cc} @@ -27,6 +27,17 @@ esac [ -d "$out_parent" ] || fail "bundle parent directory does not exist: $out_parent" +out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || + fail "could not resolve bundle parent: $out_parent" +out_leaf=$(basename -- "$out_dir") +out_abs="$out_parent_abs/$out_leaf" + +case "$out_abs" in + "$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not be inside build/: $out_dir" + ;; +esac + if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination already exists; refusing overwrite: $out_dir" fi @@ -78,13 +89,18 @@ fi if [ -z "$memory_profile" ] && command -v getconf >/dev/null 2>&1; then phys_pages=$(getconf _PHYS_PAGES 2>/dev/null || :) page_size=$(getconf PAGE_SIZE 2>/dev/null || :) - case "$phys_pages:$page_size" in - *[!0-9:]*|:|*:0|0:*) ;; - *) - memory_profile="mem_phys_pages=$phys_pages -mem_page_size_bytes=$page_size" - ;; + + case "$phys_pages" in + ''|*[!0-9]*|0) phys_pages= ;; + esac + case "$page_size" in + ''|*[!0-9]*|0) page_size= ;; esac + + if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then + memory_profile="mem_phys_pages=$phys_pages +mem_page_size_bytes=$page_size" + fi fi [ -n "$memory_profile" ] || @@ -122,6 +138,7 @@ mkdir "$out_dir" || echo "cc_resolved=$cc_path" echo "cppflags=$cppflags" echo "cflags=$cflags" + echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" echo "uname=$(uname -a)" if command -v getconf >/dev/null 2>&1; then echo "processors_online=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" @@ -139,11 +156,15 @@ mkdir "$out_dir" || } > "$out_dir/compiler.txt" { - echo "make clean build/rune_r7_study CC=$cc_path CPPFLAGS=$cppflags CFLAGS=$cflags" + echo "MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= make clean build/rune_r7_study CC=$cc_path CPPFLAGS=$cppflags CFLAGS=$cflags" echo "./build/rune_r7_study --profile local --repeats $repeats" } > "$out_dir/command.txt" -make clean build/rune_r7_study CC="$cc_path" CPPFLAGS="$cppflags" CFLAGS="$cflags" +MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ +make clean build/rune_r7_study \ + CC="$cc_path" \ + CPPFLAGS="$cppflags" \ + CFLAGS="$cflags" ./build/rune_r7_study --profile local --repeats "$repeats" > "$out_dir/observations.tsv" From 187c894cd6ec760197339b19fb2e913f286640a3 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 13:28:09 +0930 Subject: [PATCH 006/132] Complete R7 toolchain and profile provenance --- .github/workflows/c99.yml | 1 + AGENTS.md | 5 +++ R7-MEMORY-WALL-STUDY.md | 21 ++++++++--- evidence/r7/README.md | 8 ++-- machine/r7-memory-wall-study.v1.json | 18 ++++++++- scripts/r7-run-local.sh | 56 +++++++++++++++++++++++++++- study/r7_memory_wall.c | 9 +++++ 7 files changed, 106 insertions(+), 12 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index b855c27..5a3722e 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -30,6 +30,7 @@ jobs: - name: Validate R7 local evidence script run: | sh -n scripts/r7-run-local.sh + scripts/r7-run-local.sh --self-test-shell-quote mkdir -p build if scripts/r7-run-local.sh build/r7-evidence 2>/dev/null; then echo "R7 evidence script accepted build/ destination" >&2 diff --git a/AGENTS.md b/AGENTS.md index 1f19fe3..339653b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -161,6 +161,11 @@ CORE_RULES: - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound +- R7_archiver_identity_is_recorded_and_bound +- R7_CC_and_AR_must_each_name_one_resolved_executable_for_evidence_capture +- R7_recorded_build_command_uses_shell_safe_unambiguous_quoting +- R7_shell_safe_quote_serializer_is_CI_self_tested +- R7_local_profile_defaults_to_five_repeats_unless_explicitly_overridden - R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build - R7_evidence_build_must_rebuild_from_recorded_source_and_flags - R7_evidence_destination_must_not_resolve_inside_build_directory diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 1f1b76e..fa7e4d3 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -205,7 +205,14 @@ The local ladder is: 64 MiB ~~~ -The default local evidence run uses five repeats. +The local profile itself defaults to five repeats. Therefore both: + +~~~sh +./build/rune_r7_study --profile local +~~~ + +and the evidence wrapper use five repeats unless `--repeats` (or the wrapper's +RUNE_R7_REPEATS input) explicitly overrides that value. The harness normalizes small cases toward roughly 64 MiB of logical work per sample so very small working sets are not represented by a single tiny loop. @@ -244,8 +251,10 @@ The script records: - exact Git source revision; - dirty/clean working-tree state including untracked files; -- resolved single-executable compiler path and successful version output; -- both CPPFLAGS and CFLAGS, and binds those exact values into the build command; +- resolved single-executable compiler **and archiver** paths with successful + identity/version output; +- both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the + build command; - uname platform context; - visible processor count when available; - CPU model when available; @@ -263,8 +272,10 @@ bundle fails closed. Evidence destinations resolving to `build/` or a descendant are rejected, because the recorded build begins with `make clean`. The build itself clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES` so dry-run or other -make-control flags cannot silently reuse a stale executable. The sanitized make -invocation is recorded in `command.txt`. +make-control flags cannot silently reuse a stale executable. The sanitized make invocation is recorded in `command.txt` using POSIX +single-quote escaping, including embedded apostrophes, so paths and multiword +CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into +different make arguments. CI runs the quote serializer's built-in self-test. The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 0a8ab6e..b758453 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -24,12 +24,14 @@ A bundle contains: - `environment.txt` — evidence class, source revision, dirty state including untracked files, timer method, exact CPPFLAGS/CFLAGS, CPU/platform context, and a required memory profile; -- `compiler.txt` — resolved compiler path and successful version output; -- `command.txt` — exact build/run commands; +- `compiler.txt` — resolved compiler and archiver paths plus successful + identity/version output; +- `command.txt` — exact replayable build/run commands using POSIX shell-safe + quoting, including multiword values and embedded apostrophes; - `observations.tsv` — raw numeric R7 observations; - `SHA256SUMS` — integrity hashes for the bundle. -For evidence capture, CC must identify one compiler executable; compound +For evidence capture, CC and AR must each identify one executable; compound commands are rejected. Missing compiler identity or memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical page count and page size. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index bdbd82f..557c703 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -142,7 +142,8 @@ 16777216, 67108864 ], - "default_repeats": 5 + "default_repeats": 5, + "direct_profile_invocation_uses_default_repeats_when_not_explicit": true }, "explicit": { "min_bytes": 4096, @@ -202,7 +203,20 @@ "build_target_must_be_rebuilt_from_recorded_source_configuration": true, "destination_under_build_directory_allowed": false, "destination_path_checked_against_physical_parent": true, - "getconf_memory_profile_requires_both_nonzero_numeric_phys_pages_and_page_size": true + "getconf_memory_profile_requires_both_nonzero_numeric_phys_pages_and_page_size": true, + "AR_recorded_and_bound": true, + "archiver_command_must_be_single_executable": true, + "archiver_path_resolution_required": true, + "archiver_version_capture_required": true, + "archiver_identity_failure_is_capture_failure": true, + "command_recording": "POSIX-shell-replayable-single-quoted", + "multiword_CPPFLAGS_and_CFLAGS_are_unambiguously_serialized": true, + "command_recording_self_test": "scripts/r7-run-local.sh --self-test-shell-quote", + "shell_safe_quoting_handles_spaces_and_single_quotes": true, + "toolchain_identity_includes": [ + "compiler", + "archiver" + ] }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index b6b3383..9a22688 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -7,10 +7,25 @@ fail() exit 1 } +shell_quote() +{ + printf "'" + printf '%s' "$1" | sed "s/'/'\\\\''/g" + printf "'" +} + +if [ "${1:-}" = "--self-test-shell-quote" ]; then + quoted=$(shell_quote "alpha beta'gamma") + [ "$quoted" = "'alpha beta'\\''gamma'" ] || + fail "shell_quote self-test failed" + exit 0 +fi + repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) cd "$repo_root" cc_name=${CC:-cc} +ar_name=${AR:-ar} cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} @@ -24,6 +39,12 @@ case "$cc_name" in ;; esac +case "$ar_name" in + *[[:space:]]*) + fail "AR must name one archiver executable" + ;; +esac + [ -d "$out_parent" ] || fail "bundle parent directory does not exist: $out_parent" @@ -64,6 +85,21 @@ compiler_version=$("$cc_path" --version 2>&1) || [ -n "$compiler_version" ] || fail "compiler identity output is empty" +ar_path=$(command -v "$ar_name") || + fail "archiver not found: $ar_name" +[ -n "$ar_path" ] && [ -x "$ar_path" ] || + fail "archiver path is not executable: $ar_path" + +if archiver_version=$("$ar_path" --version 2>&1); then + : +elif archiver_version=$("$ar_path" -V 2>&1); then + : +else + fail "archiver identity command failed: $ar_path" +fi +[ -n "$archiver_version" ] || + fail "archiver identity output is empty" + memory_profile= if [ -r /proc/meminfo ]; then mem_total_kib=$(awk '/^MemTotal:/ { print $2; exit }' /proc/meminfo) @@ -136,6 +172,8 @@ mkdir "$out_dir" || echo "repeats=$repeats" echo "cc_requested=$cc_name" echo "cc_resolved=$cc_path" + echo "ar_requested=$ar_name" + echo "ar_resolved=$ar_path" echo "cppflags=$cppflags" echo "cflags=$cflags" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" @@ -153,16 +191,30 @@ mkdir "$out_dir" || { echo "compiler_path=$cc_path" printf '%s\n' "$compiler_version" + echo "archiver_path=$ar_path" + printf '%s\n' "$archiver_version" } > "$out_dir/compiler.txt" { - echo "MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= make clean build/rune_r7_study CC=$cc_path CPPFLAGS=$cppflags CFLAGS=$cflags" - echo "./build/rune_r7_study --profile local --repeats $repeats" + printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make clean build/rune_r7_study CC=" + shell_quote "$cc_path" + printf " AR=" + shell_quote "$ar_path" + printf " CPPFLAGS=" + shell_quote "$cppflags" + printf " CFLAGS=" + shell_quote "$cflags" + printf '\n' + + printf "./build/rune_r7_study --profile local --repeats " + shell_quote "$repeats" + printf '\n' } > "$out_dir/command.txt" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ make clean build/rune_r7_study \ CC="$cc_path" \ + AR="$ar_path" \ CPPFLAGS="$cppflags" \ CFLAGS="$cflags" diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index 35bb849..7ade2ef 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -1464,6 +1464,7 @@ int main(int argc, char **argv) uint64_t explicit_bytes; uint64_t repeats; int has_explicit_bytes; + int repeats_explicit; int i; uint64_t repeat; @@ -1471,6 +1472,7 @@ int main(int argc, char **argv) explicit_bytes = 0u; repeats = UINT64_C(1); has_explicit_bytes = 0; + repeats_explicit = 0; for (i = 1; i < argc; ++i) { if (strcmp(argv[i], "--profile") == 0) { @@ -1499,12 +1501,19 @@ int main(int argc, char **argv) r7_usage(argv[0]); return 2; } + repeats_explicit = 1; } else { r7_usage(argv[0]); return 2; } } + if (!has_explicit_bytes && + strcmp(profile, "local") == 0 && + !repeats_explicit) { + repeats = UINT64_C(5); + } + if (has_explicit_bytes) { if (explicit_bytes < R7_MIN_BYTES || explicit_bytes > R7_MAX_BYTES || From d60e87899ef8c48b9f9947af9204bf3d142d793d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 13:46:01 +0930 Subject: [PATCH 007/132] Bind R7 evidence to clean source and platform identity --- .github/workflows/c99.yml | 7 +++++++ AGENTS.md | 4 ++++ R7-MEMORY-WALL-STUDY.md | 14 ++++++++++---- evidence/r7/README.md | 15 ++++++++++----- machine/r7-memory-wall-study.v1.json | 9 ++++++++- scripts/r7-run-local.sh | 16 ++++++++++------ 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 5a3722e..16e5fe4 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -36,6 +36,13 @@ jobs: echo "R7 evidence script accepted build/ destination" >&2 exit 1 fi + touch r7-untracked-evidence-probe + if scripts/r7-run-local.sh evidence/r7/ci-dirty-probe 2>/dev/null; then + echo "R7 evidence script accepted dirty worktree" >&2 + exit 1 + fi + test ! -e evidence/r7/ci-dirty-probe + rm r7-untracked-evidence-probe - name: Reject truncated corpus output run: | diff --git a/AGENTS.md b/AGENTS.md index 339653b..186c59d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,6 +159,10 @@ CORE_RULES: - R7_microtile_selected_extent_is_in_resident_peak_and_setup_teardown_timing - R7_evidence_destination_must_be_new_and_immutable - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation +- R7_evidence_capture_requires_clean_working_tree +- R7_dirty_worktree_evidence_capture_is_forbidden +- R7_source_revision_must_identify_exact_built_source_contents +- R7_platform_identity_capture_must_succeed_and_be_nonempty - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_archiver_identity_is_recorded_and_bound diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index fa7e4d3..d46fe55 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -238,8 +238,10 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The script creates an **immutable new destination** and refuses to overwrite an -existing bundle. It samples Git status before creating that destination and -counts tracked, staged, and untracked files when recording dirty state. +existing bundle. Before creating that destination it samples tracked, staged, +and untracked Git state. **Any dirty worktree is rejected.** R7 local evidence +therefore binds directly to the recorded `source_revision`; a bundle may not +claim a commit while actually building uncommitted source content. Every bundle declares: @@ -250,12 +252,12 @@ evidence_class=raw-local-execution-observation The script records: - exact Git source revision; -- dirty/clean working-tree state including untracked files; +- a verified clean working tree, including absence of untracked files; - resolved single-executable compiler **and archiver** paths with successful identity/version output; - both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the build command; -- uname platform context; +- mandatory successful, nonempty `uname -a` platform identity; - visible processor count when available; - CPU model when available; - a **required memory profile**, using /proc/meminfo, sysctl, or getconf; @@ -281,6 +283,10 @@ The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is not accepted as complete evidence. +The script fails before bundle creation if `uname -a` fails or returns empty +output, preventing an apparently complete bundle with missing platform +provenance. + These fields satisfy the evidence-dimension requirement only when the bundle is actually captured on the host. A template or planned command is not execution evidence. diff --git a/evidence/r7/README.md b/evidence/r7/README.md index b758453..0597564 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -21,9 +21,10 @@ also rejected because evidence capture performs a clean rebuild. A bundle contains: -- `environment.txt` — evidence class, source revision, dirty state including - untracked files, timer method, exact CPPFLAGS/CFLAGS, CPU/platform context, - and a required memory profile; +- `environment.txt` — evidence class, exact source revision, verified clean + worktree state (including no untracked files), timer method, exact + CPPFLAGS/CFLAGS, mandatory platform identity, CPU context, and required memory + profile; - `compiler.txt` — resolved compiler and archiver paths plus successful identity/version output; - `command.txt` — exact replayable build/run commands using POSIX shell-safe @@ -31,9 +32,13 @@ A bundle contains: - `observations.tsv` — raw numeric R7 observations; - `SHA256SUMS` — integrity hashes for the bundle. +Evidence capture requires a clean Git working tree. Tracked, staged, or +untracked changes cause a fail-closed exit before the bundle directory is +created, so source_revision identifies the exact contents built. + For evidence capture, CC and AR must each identify one executable; compound -commands are rejected. Missing compiler identity or memory profile causes the -capture to fail. The getconf fallback requires both a nonzero numeric physical +commands are rejected. Missing compiler identity, a failed/empty `uname -a` platform identity, or +missing memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build so a diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 557c703..59650e2 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -216,7 +216,14 @@ "toolchain_identity_includes": [ "compiler", "archiver" - ] + ], + "clean_working_tree_required": true, + "dirty_working_tree_capture_allowed": false, + "source_revision_must_identify_exact_built_contents": true, + "platform_identity_required": true, + "platform_identity_command": "uname -a", + "platform_identity_capture_must_succeed": true, + "platform_identity_must_be_nonempty": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 9a22688..af26f7a 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -69,11 +69,10 @@ revision=$(git rev-parse HEAD) || git_status=$(git status --porcelain --untracked-files=all) || fail "could not inspect Git working-tree state" -if [ -n "$git_status" ]; then - dirty=true -else - dirty=false -fi +[ -z "$git_status" ] || + fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" + +dirty=false cc_path=$(command -v "$cc_name") || fail "compiler not found: $cc_name" @@ -142,6 +141,11 @@ fi [ -n "$memory_profile" ] || fail "could not capture required memory profile" +platform_identity=$(uname -a 2>&1) || + fail "platform identity command failed: uname -a" +[ -n "$platform_identity" ] || + fail "platform identity output is empty" + cpu_model= if [ -r /proc/cpuinfo ]; then cpu_model=$(awk -F ': ' ' @@ -177,7 +181,7 @@ mkdir "$out_dir" || echo "cppflags=$cppflags" echo "cflags=$cflags" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" - echo "uname=$(uname -a)" + echo "uname=$platform_identity" if command -v getconf >/dev/null 2>&1; then echo "processors_online=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" echo "long_bit=$(getconf LONG_BIT 2>/dev/null || echo unknown)" From d0db06a61114e2f5da0d2f5e63fd470fd07cc536 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 13:59:29 +0930 Subject: [PATCH 008/132] Pin R7 evidence build to tracked Makefile --- .github/workflows/c99.yml | 8 ++++++++ AGENTS.md | 3 +++ R7-MEMORY-WALL-STUDY.md | 7 ++++++- evidence/r7/README.md | 9 +++++++-- machine/r7-memory-wall-study.v1.json | 8 +++++++- scripts/r7-run-local.sh | 15 +++++++++++++-- 6 files changed, 44 insertions(+), 6 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 16e5fe4..cce6105 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -43,6 +43,14 @@ jobs: fi test ! -e evidence/r7/ci-dirty-probe rm r7-untracked-evidence-probe + printf 'all:\n\t@false\n' > GNUmakefile + printf 'GNUmakefile\n' >> .git/info/exclude + if git status --porcelain --untracked-files=all | grep -q 'GNUmakefile'; then + echo "ignored GNUmakefile unexpectedly visible in normal status" >&2 + exit 1 + fi + grep -Fq 'make -f "$repo_root/Makefile" clean build/rune_r7_study' scripts/r7-run-local.sh + rm GNUmakefile - name: Reject truncated corpus output run: | diff --git a/AGENTS.md b/AGENTS.md index 186c59d..e2fe82b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -172,6 +172,9 @@ CORE_RULES: - R7_local_profile_defaults_to_five_repeats_unless_explicitly_overridden - R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build - R7_evidence_build_must_rebuild_from_recorded_source_and_flags +- R7_evidence_build_pins_tracked_Makefile_with_make_f +- R7_tracked_Makefile_blob_identity_is_recorded +- R7_implicit_GNUmakefile_or_lowercase_makefile_must_not_control_evidence_build - R7_evidence_destination_must_not_resolve_inside_build_directory - R7_getconf_memory_profile_requires_both_nonzero_numeric_page_count_and_size - R7_compiler_identity_capture_must_succeed diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index d46fe55..a46f061 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -277,7 +277,12 @@ inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES make-control flags cannot silently reuse a stale executable. The sanitized make invocation is recorded in `command.txt` using POSIX single-quote escaping, including embedded apostrophes, so paths and multiword CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into -different make arguments. CI runs the quote serializer's built-in self-test. +different make arguments. + +The build recipe is pinned explicitly with `make -f "$repo_root/Makefile"`. +The script verifies that `Makefile` is tracked and records the Git blob ID of +`source_revision:Makefile`. Ignored or globally excluded `GNUmakefile` or +lowercase `makefile` files therefore cannot override the evidence build. CI runs the quote serializer's built-in self-test. The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 0597564..51deb11 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -41,8 +41,13 @@ commands are rejected. Missing compiler identity, a failed/empty `uname -a` plat missing memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical page count and page size. -Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build so a -dry-run flag such as MAKEFLAGS=-n cannot certify a stale executable. +Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for +the evidence build so a dry-run flag such as MAKEFLAGS=-n cannot certify a stale +executable. + +The evidence build also uses the tracked repository Makefile explicitly via +`make -f /Makefile` and records its Git blob identity. Ignored +`GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 59650e2..2411040 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -223,7 +223,13 @@ "platform_identity_required": true, "platform_identity_command": "uname -a", "platform_identity_capture_must_succeed": true, - "platform_identity_must_be_nonempty": true + "platform_identity_must_be_nonempty": true, + "makefile_path": "$repo_root/Makefile", + "makefile_must_be_tracked": true, + "makefile_blob_identity_recorded": true, + "makefile_selected_explicitly_with_make_f": true, + "implicit_GNUmakefile_or_lowercase_makefile_discovery_allowed": false, + "ignored_build_controlling_makefile_can_override_recipe": false }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index af26f7a..0cad043 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -66,6 +66,13 @@ fi revision=$(git rev-parse HEAD) || fail "could not resolve source revision" +git ls-files --error-unmatch Makefile >/dev/null 2>&1 || + fail "tracked Makefile is missing" +makefile_blob=$(git rev-parse "$revision:Makefile") || + fail "could not resolve tracked Makefile at source revision" +[ -n "$makefile_blob" ] || + fail "tracked Makefile identity is empty" + git_status=$(git status --porcelain --untracked-files=all) || fail "could not inspect Git working-tree state" @@ -173,6 +180,8 @@ mkdir "$out_dir" || echo "working_tree_dirty=$dirty" echo "measurement_method=C99_clock_process_cpu_time" echo "benchmark_contract=rune.r7.memory-wall-observation.v1" + echo "makefile_path=$repo_root/Makefile" + echo "makefile_blob=$makefile_blob" echo "repeats=$repeats" echo "cc_requested=$cc_name" echo "cc_resolved=$cc_path" @@ -200,7 +209,9 @@ mkdir "$out_dir" || } > "$out_dir/compiler.txt" { - printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make clean build/rune_r7_study CC=" + printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make -f " + shell_quote "$repo_root/Makefile" + printf " clean build/rune_r7_study CC=" shell_quote "$cc_path" printf " AR=" shell_quote "$ar_path" @@ -216,7 +227,7 @@ mkdir "$out_dir" || } > "$out_dir/command.txt" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ -make clean build/rune_r7_study \ +make -f "$repo_root/Makefile" clean build/rune_r7_study \ CC="$cc_path" \ AR="$ar_path" \ CPPFLAGS="$cppflags" \ From 81e7ee80b3d8a8f6d3e785064256ce5ae925b6c9 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:20:19 +0930 Subject: [PATCH 009/132] Harden R7 source and compiler environment provenance --- .github/workflows/c99.yml | 16 ++++++++++++++++ AGENTS.md | 5 +++++ R7-MEMORY-WALL-STUDY.md | 20 ++++++++++++++++---- evidence/r7/README.md | 8 +++++++- machine/r7-memory-wall-study.v1.json | 18 +++++++++++++++++- scripts/r7-run-local.sh | 23 +++++++++++++++++++++++ 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index cce6105..a3ffca9 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -51,6 +51,22 @@ jobs: fi grep -Fq 'make -f "$repo_root/Makefile" clean build/rune_r7_study' scripts/r7-run-local.sh rm GNUmakefile + git update-index --assume-unchanged study/r7_memory_wall.c + printf '\n/* hidden mutation probe */\n' >> study/r7_memory_wall.c + test -z "$(git status --porcelain --untracked-files=all)" + if scripts/r7-run-local.sh evidence/r7/ci-assume-unchanged-probe 2>/dev/null; then + echo "R7 evidence script accepted assume-unchanged hidden mutation" >&2 + exit 1 + fi + test ! -e evidence/r7/ci-assume-unchanged-probe + git update-index --no-assume-unchanged study/r7_memory_wall.c + git checkout -- study/r7_memory_wall.c + CPATH=/tmp/r7-hostile-cpath C_INCLUDE_PATH=/tmp/r7-hostile-c-include \ + CPLUS_INCLUDE_PATH=/tmp/r7-hostile-cplus \ + COMPILER_PATH=/tmp/r7-hostile-compiler \ + LIBRARY_PATH=/tmp/r7-hostile-library \ + GCC_EXEC_PREFIX=/tmp/r7-hostile-gcc-prefix \ + scripts/r7-run-local.sh --self-test-compiler-search-env - name: Reject truncated corpus output run: | diff --git a/AGENTS.md b/AGENTS.md index e2fe82b..31f4b9e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,6 +160,11 @@ CORE_RULES: - R7_evidence_destination_must_be_new_and_immutable - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation - R7_evidence_capture_requires_clean_working_tree +- R7_assume_unchanged_and_skip_worktree_flags_are_forbidden +- R7_index_visibility_flags_are_checked_before_dirty_state +- R7_ambient_compiler_search_path_environment_is_cleared +- R7_compiler_search_environment_sanitation_is_CI_self_tested +- R7_intentional_external_include_paths_must_be_in_recorded_CPPFLAGS - R7_dirty_worktree_evidence_capture_is_forbidden - R7_source_revision_must_identify_exact_built_source_contents - R7_platform_identity_capture_must_succeed_and_be_nonempty diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index a46f061..267e0c3 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -238,10 +238,14 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The script creates an **immutable new destination** and refuses to overwrite an -existing bundle. Before creating that destination it samples tracked, staged, -and untracked Git state. **Any dirty worktree is rejected.** R7 local evidence +existing bundle. Before creating that destination it rejects Git index flags +that can hide tracked changes (`assume-unchanged` and `skip-worktree`), then +samples tracked, staged, and untracked Git state. **Any dirty worktree is +rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not -claim a commit while actually building uncommitted source content. +claim a commit while actually building uncommitted source content. Files marked +`assume-unchanged` or `skip-worktree` are rejected because those index flags +can suppress ordinary dirty-state reporting. Every bundle declares: @@ -257,6 +261,10 @@ The script records: identity/version output; - both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the build command; +- explicit sanitation of ambient compiler search-path variables + (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, + `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, + `GCC_EXEC_PREFIX`); - mandatory successful, nonempty `uname -a` platform identity; - visible processor count when available; - CPU model when available; @@ -267,7 +275,11 @@ The script records: - SHA-256 integrity file. A compound CC such as `ccache gcc` is rejected for evidence capture; wrappers -or flags must be represented explicitly rather than hidden inside CC. If the +or flags must be represented explicitly rather than hidden inside CC. Ambient +compiler/header search-path variables are unset before compiler identity and the +evidence build; intentional include paths must be expressed in recorded +`CPPFLAGS`. CI executes a hostile-environment self-test to verify the search +variables are actually unset. If the compiler cannot be resolved/identified or memory context cannot be captured, the bundle fails closed. diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 51deb11..b502921 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -35,9 +35,15 @@ A bundle contains: Evidence capture requires a clean Git working tree. Tracked, staged, or untracked changes cause a fail-closed exit before the bundle directory is created, so source_revision identifies the exact contents built. +`assume-unchanged` and `skip-worktree` index flags are forbidden because +they can hide tracked modifications from ordinary status checks. For evidence capture, CC and AR must each identify one executable; compound -commands are rejected. Missing compiler identity, a failed/empty `uname -a` platform identity, or +commands are rejected. Ambient compiler search variables (CPATH, +C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH, COMPILER_PATH, +LIBRARY_PATH, GCC_EXEC_PREFIX) are cleared; intentional include paths belong in +the recorded CPPFLAGS. CI also runs the script's compiler-search-environment +self-test with hostile search paths preloaded. Missing compiler identity, a failed/empty `uname -a` platform identity, or missing memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical page count and page size. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 2411040..a8f9419 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -229,7 +229,23 @@ "makefile_blob_identity_recorded": true, "makefile_selected_explicitly_with_make_f": true, "implicit_GNUmakefile_or_lowercase_makefile_discovery_allowed": false, - "ignored_build_controlling_makefile_can_override_recipe": false + "ignored_build_controlling_makefile_can_override_recipe": false, + "assume_unchanged_index_flags_allowed": false, + "skip_worktree_index_flags_allowed": false, + "index_visibility_flags_checked_before_capture": true, + "compiler_search_environment_sanitized": [ + "CPATH", + "C_INCLUDE_PATH", + "CPLUS_INCLUDE_PATH", + "OBJC_INCLUDE_PATH", + "COMPILER_PATH", + "LIBRARY_PATH", + "GCC_EXEC_PREFIX" + ], + "ambient_compiler_search_paths_allowed": false, + "compiler_search_sanitation_recorded_in_environment": true, + "compiler_search_sanitation_recorded_in_command": true, + "compiler_search_sanitation_self_test": "scripts/r7-run-local.sh --self-test-compiler-search-env" }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 0cad043..2f1f814 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -73,6 +73,13 @@ makefile_blob=$(git rev-parse "$revision:Makefile") || [ -n "$makefile_blob" ] || fail "tracked Makefile identity is empty" +index_hidden=$(git ls-files -v | awk ' + /^[a-z]/ || /^S / { print; exit } +') || fail "could not inspect Git index visibility flags" + +[ -z "$index_hidden" ] || + fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" + git_status=$(git status --porcelain --untracked-files=all) || fail "could not inspect Git working-tree state" @@ -81,6 +88,20 @@ git_status=$(git status --porcelain --untracked-files=all) || dirty=false +unset CPATH +unset C_INCLUDE_PATH +unset CPLUS_INCLUDE_PATH +unset OBJC_INCLUDE_PATH +unset COMPILER_PATH +unset LIBRARY_PATH +unset GCC_EXEC_PREFIX + +if [ "${1:-}" = "--self-test-compiler-search-env" ]; then + [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}" ] || + fail "compiler search environment self-test failed" + exit 0 +fi + cc_path=$(command -v "$cc_name") || fail "compiler not found: $cc_name" [ -n "$cc_path" ] && [ -x "$cc_path" ] || @@ -189,6 +210,7 @@ mkdir "$out_dir" || echo "ar_resolved=$ar_path" echo "cppflags=$cppflags" echo "cflags=$cflags" + echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX cleared" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" echo "uname=$platform_identity" if command -v getconf >/dev/null 2>&1; then @@ -209,6 +231,7 @@ mkdir "$out_dir" || } > "$out_dir/compiler.txt" { + printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make -f " shell_quote "$repo_root/Makefile" printf " clean build/rune_r7_study CC=" From 58a8d8a4c667cbbfc71a51aad55005a522ae5dec Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:21:07 +0930 Subject: [PATCH 010/132] Fix R7 compiler environment self-test routing --- scripts/r7-run-local.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 2f1f814..888aee6 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -21,6 +21,20 @@ if [ "${1:-}" = "--self-test-shell-quote" ]; then exit 0 fi +if [ "${1:-}" = "--self-test-compiler-search-env" ]; then + unset CPATH + unset C_INCLUDE_PATH + unset CPLUS_INCLUDE_PATH + unset OBJC_INCLUDE_PATH + unset COMPILER_PATH + unset LIBRARY_PATH + unset GCC_EXEC_PREFIX + + [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}" ] || + fail "compiler search environment self-test failed" + exit 0 +fi + repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) cd "$repo_root" @@ -96,12 +110,6 @@ unset COMPILER_PATH unset LIBRARY_PATH unset GCC_EXEC_PREFIX -if [ "${1:-}" = "--self-test-compiler-search-env" ]; then - [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}" ] || - fail "compiler search environment self-test failed" - exit 0 -fi - cc_path=$(command -v "$cc_name") || fail "compiler not found: $cc_name" [ -n "$cc_path" ] && [ -x "$cc_path" ] || From 4ade160c73a1492644aa596b6205b2cd354f9a31 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:49:55 +0930 Subject: [PATCH 011/132] Harden R7 evidence execution provenance --- scripts/r7-run-local.sh | 95 ++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 26 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 888aee6..b530bcc 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -14,14 +14,16 @@ shell_quote() printf "'" } -if [ "${1:-}" = "--self-test-shell-quote" ]; then - quoted=$(shell_quote "alpha beta'gamma") - [ "$quoted" = "'alpha beta'\\''gamma'" ] || - fail "shell_quote self-test failed" - exit 0 -fi +sanitize_capture_environment() +{ + unset GIT_DIR + unset GIT_WORK_TREE + unset GIT_INDEX_FILE + unset GIT_OBJECT_DIRECTORY + unset GIT_ALTERNATE_OBJECT_DIRECTORIES + unset GIT_COMMON_DIR + unset GIT_NAMESPACE -if [ "${1:-}" = "--self-test-compiler-search-env" ]; then unset CPATH unset C_INCLUDE_PATH unset CPLUS_INCLUDE_PATH @@ -30,14 +32,50 @@ if [ "${1:-}" = "--self-test-compiler-search-env" ]; then unset LIBRARY_PATH unset GCC_EXEC_PREFIX + unset LD_PRELOAD + unset LD_LIBRARY_PATH + unset LD_AUDIT + unset DYLD_INSERT_LIBRARIES + unset DYLD_LIBRARY_PATH + unset DYLD_FRAMEWORK_PATH + unset DYLD_FALLBACK_LIBRARY_PATH + unset DYLD_FALLBACK_FRAMEWORK_PATH + unset LIBPATH + unset SHLIB_PATH +} + +sanitize_capture_environment + +if [ "${1:-}" = "--self-test-shell-quote" ]; then + quoted=$(shell_quote "alpha beta'gamma") + [ "$quoted" = "'alpha beta'\\''gamma'" ] || + fail "shell_quote self-test failed" + exit 0 +fi + +if [ "${1:-}" = "--self-test-compiler-search-env" ]; then [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}" ] || fail "compiler search environment self-test failed" exit 0 fi +if [ "${1:-}" = "--self-test-dynamic-loader-env" ]; then + [ -z "${LD_PRELOAD+x}${LD_LIBRARY_PATH+x}${LD_AUDIT+x}${DYLD_INSERT_LIBRARIES+x}${DYLD_LIBRARY_PATH+x}${DYLD_FRAMEWORK_PATH+x}${DYLD_FALLBACK_LIBRARY_PATH+x}${DYLD_FALLBACK_FRAMEWORK_PATH+x}${LIBPATH+x}${SHLIB_PATH+x}" ] || + fail "dynamic-loader environment self-test failed" + exit 0 +fi + repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) cd "$repo_root" +if [ "${1:-}" = "--self-test-git-root" ]; then + git_root=$(git -C "$repo_root" rev-parse --show-toplevel) || + fail "Git root self-test could not resolve repository" + [ "$git_root" = "$repo_root" ] || + fail "Git root self-test resolved foreign repository: $git_root" + exit 0 +fi + cc_name=${CC:-cc} ar_name=${AR:-ar} cppflags=${CPPFLAGS:-} @@ -77,24 +115,30 @@ if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination already exists; refusing overwrite: $out_dir" fi -revision=$(git rev-parse HEAD) || +revision=$(git -C "$repo_root" rev-parse HEAD) || fail "could not resolve source revision" -git ls-files --error-unmatch Makefile >/dev/null 2>&1 || +git -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || fail "tracked Makefile is missing" -makefile_blob=$(git rev-parse "$revision:Makefile") || +makefile_blob=$(git -C "$repo_root" rev-parse "$revision:Makefile") || fail "could not resolve tracked Makefile at source revision" [ -n "$makefile_blob" ] || fail "tracked Makefile identity is empty" -index_hidden=$(git ls-files -v | awk ' +index_hidden=$(git -C "$repo_root" ls-files -v | awk ' /^[a-z]/ || /^S / { print; exit } ') || fail "could not inspect Git index visibility flags" [ -z "$index_hidden" ] || fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" -git_status=$(git status --porcelain --untracked-files=all) || +ignored_inputs=$(git -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || + fail "could not inspect ignored compiler-input trees" + +[ -z "$ignored_inputs" ] || + fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" + +git_status=$(git -C "$repo_root" status --porcelain --untracked-files=all) || fail "could not inspect Git working-tree state" [ -z "$git_status" ] || @@ -102,14 +146,6 @@ git_status=$(git status --porcelain --untracked-files=all) || dirty=false -unset CPATH -unset C_INCLUDE_PATH -unset CPLUS_INCLUDE_PATH -unset OBJC_INCLUDE_PATH -unset COMPILER_PATH -unset LIBRARY_PATH -unset GCC_EXEC_PREFIX - cc_path=$(command -v "$cc_name") || fail "compiler not found: $cc_name" [ -n "$cc_path" ] && [ -x "$cc_path" ] || @@ -218,7 +254,10 @@ mkdir "$out_dir" || echo "ar_resolved=$ar_path" echo "cppflags=$cppflags" echo "cflags=$cflags" + echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX cleared" + echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" + echo "ignored_compiler_inputs=forbidden under src,include,study" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" echo "uname=$platform_identity" if command -v getconf >/dev/null 2>&1; then @@ -239,10 +278,12 @@ mkdir "$out_dir" || } > "$out_dir/compiler.txt" { + printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" - printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make -f " - shell_quote "$repo_root/Makefile" - printf " clean build/rune_r7_study CC=" + printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make -C " + shell_quote "$repo_root" + printf " -f Makefile clean build/rune_r7_study CC=" shell_quote "$cc_path" printf " AR=" shell_quote "$ar_path" @@ -252,19 +293,21 @@ mkdir "$out_dir" || shell_quote "$cflags" printf '\n' - printf "./build/rune_r7_study --profile local --repeats " + shell_quote "$repo_root/build/rune_r7_study" + printf " --profile local --repeats " shell_quote "$repeats" printf '\n' } > "$out_dir/command.txt" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ -make -f "$repo_root/Makefile" clean build/rune_r7_study \ +make -C "$repo_root" -f Makefile clean build/rune_r7_study \ CC="$cc_path" \ AR="$ar_path" \ CPPFLAGS="$cppflags" \ CFLAGS="$cflags" -./build/rune_r7_study --profile local --repeats "$repeats" > "$out_dir/observations.tsv" +"$repo_root/build/rune_r7_study" --profile local --repeats "$repeats" \ + > "$out_dir/observations.tsv" if command -v sha256sum >/dev/null 2>&1; then ( From 574e2c60f27e2e2983289d337ef5fb8afa74954b Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:50:40 +0930 Subject: [PATCH 012/132] Reproduce R7 provenance attacks in CI --- .github/workflows/c99.yml | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index a3ffca9..79cd92b 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -51,6 +51,49 @@ jobs: fi grep -Fq 'make -f "$repo_root/Makefile" clean build/rune_r7_study' scripts/r7-run-local.sh rm GNUmakefile + + printf '#define CLOCKS_PER_SEC 424242\n' > include/time.h + printf 'include/time.h\n' >> .git/info/exclude + if git status --porcelain --untracked-files=all | grep -q 'include/time.h'; then + echo "ignored include/time.h unexpectedly visible in normal status" >&2 + exit 1 + fi + if scripts/r7-run-local.sh evidence/r7/ci-ignored-header-probe 2>/dev/null; then + echo "R7 evidence script accepted ignored compiler input" >&2 + exit 1 + fi + test ! -e evidence/r7/ci-ignored-header-probe + rm include/time.h + + foreign_repo=$(mktemp -d) + git -C "$foreign_repo" init -q + printf 'foreign repository\n' > "$foreign_repo/marker" + git -C "$foreign_repo" add marker + git -C "$foreign_repo" -c user.name=RUNE -c user.email=rune@example.invalid commit -qm foreign + GIT_DIR="$foreign_repo/.git" \ + GIT_WORK_TREE="$foreign_repo" \ + GIT_INDEX_FILE="$foreign_repo/.git/index" \ + scripts/r7-run-local.sh --self-test-git-root + rm -rf "$foreign_repo" + + cat > build/r7-preload-probe.c <<'EOF' + #include + clock_t clock(void) + { + return (clock_t)1; + } + EOF + "${{ matrix.cc }}" -shared -fPIC build/r7-preload-probe.c -o build/r7-preload-probe.so + LD_PRELOAD="$PWD/build/r7-preload-probe.so" \ + LD_LIBRARY_PATH=/tmp/r7-hostile-ld-library \ + LD_AUDIT=/tmp/r7-hostile-ld-audit \ + DYLD_INSERT_LIBRARIES=/tmp/r7-hostile-dyld-insert \ + DYLD_LIBRARY_PATH=/tmp/r7-hostile-dyld-library \ + DYLD_FRAMEWORK_PATH=/tmp/r7-hostile-dyld-framework \ + LIBPATH=/tmp/r7-hostile-libpath \ + SHLIB_PATH=/tmp/r7-hostile-shlib \ + scripts/r7-run-local.sh --self-test-dynamic-loader-env + git update-index --assume-unchanged study/r7_memory_wall.c printf '\n/* hidden mutation probe */\n' >> study/r7_memory_wall.c test -z "$(git status --porcelain --untracked-files=all)" @@ -68,6 +111,16 @@ jobs: GCC_EXEC_PREFIX=/tmp/r7-hostile-gcc-prefix \ scripts/r7-run-local.sh --self-test-compiler-search-env + grep -Fq 'make -C "$repo_root" -f Makefile clean build/rune_r7_study' scripts/r7-run-local.sh + grep -Fq 'shell_quote "$repo_root/build/rune_r7_study"' scripts/r7-run-local.sh + ( + cd /tmp + MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ + make -C "$GITHUB_WORKSPACE" -f Makefile clean build/rune_r7_study CC="${{ matrix.cc }}" + "$GITHUB_WORKSPACE/build/rune_r7_study" --bytes 32768 --repeats 1 >/dev/null + ) + make -C "$GITHUB_WORKSPACE" -f Makefile build/rune_corpus CC="${{ matrix.cc }}" + - name: Reject truncated corpus output run: | if ./build/rune_corpus --profile smoke > /dev/full 2>/dev/null; then From 9718176dfaac6da8c2b5df8b8ea43e3fff302ac4 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:51:08 +0930 Subject: [PATCH 013/132] Fix R7 CI command assertion --- .github/workflows/c99.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 79cd92b..d73b387 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -49,7 +49,6 @@ jobs: echo "ignored GNUmakefile unexpectedly visible in normal status" >&2 exit 1 fi - grep -Fq 'make -f "$repo_root/Makefile" clean build/rune_r7_study' scripts/r7-run-local.sh rm GNUmakefile printf '#define CLOCKS_PER_SEC 424242\n' > include/time.h From 934d533b6a66c52bd69f4297c65222a2d2ab35ff Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:51:57 +0930 Subject: [PATCH 014/132] Document R7 provenance hardening authority --- AGENTS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 31f4b9e..d411d85 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -162,8 +162,13 @@ CORE_RULES: - R7_evidence_capture_requires_clean_working_tree - R7_assume_unchanged_and_skip_worktree_flags_are_forbidden - R7_index_visibility_flags_are_checked_before_dirty_state +- R7_Git_routing_environment_is_cleared_before_provenance_checks +- R7_Git_provenance_commands_are_anchored_to_repo_root +- R7_ignored_untracked_files_under_src_include_study_are_forbidden - R7_ambient_compiler_search_path_environment_is_cleared - R7_compiler_search_environment_sanitation_is_CI_self_tested +- R7_dynamic_loader_injection_environment_is_cleared_before_tool_and_study_execution +- R7_dynamic_loader_environment_sanitation_is_CI_self_tested - R7_intentional_external_include_paths_must_be_in_recorded_CPPFLAGS - R7_dirty_worktree_evidence_capture_is_forbidden - R7_source_revision_must_identify_exact_built_source_contents @@ -173,6 +178,8 @@ CORE_RULES: - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_resolved_executable_for_evidence_capture - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting +- R7_recorded_replay_build_uses_make_C_repo_root +- R7_recorded_replay_study_path_is_absolute - R7_shell_safe_quote_serializer_is_CI_self_tested - R7_local_profile_defaults_to_five_repeats_unless_explicitly_overridden - R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build From 79b28ea2c114e09bb0e3ebc83d3fa6828d1b34ad Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:52:00 +0930 Subject: [PATCH 015/132] Bind R7 execution environment in machine contract --- machine/r7-memory-wall-study.v1.json | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index a8f9419..33c3c6a 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -233,6 +233,23 @@ "assume_unchanged_index_flags_allowed": false, "skip_worktree_index_flags_allowed": false, "index_visibility_flags_checked_before_capture": true, + "git_routing_environment_sanitized": [ + "GIT_DIR", + "GIT_WORK_TREE", + "GIT_INDEX_FILE", + "GIT_OBJECT_DIRECTORY", + "GIT_ALTERNATE_OBJECT_DIRECTORIES", + "GIT_COMMON_DIR", + "GIT_NAMESPACE" + ], + "git_provenance_commands_anchored_with_git_C_repo_root": true, + "git_routing_sanitation_self_test": "scripts/r7-run-local.sh --self-test-git-root", + "ignored_untracked_compiler_inputs_allowed": false, + "ignored_compiler_input_trees": [ + "src", + "include", + "study" + ], "compiler_search_environment_sanitized": [ "CPATH", "C_INCLUDE_PATH", @@ -245,7 +262,27 @@ "ambient_compiler_search_paths_allowed": false, "compiler_search_sanitation_recorded_in_environment": true, "compiler_search_sanitation_recorded_in_command": true, - "compiler_search_sanitation_self_test": "scripts/r7-run-local.sh --self-test-compiler-search-env" + "compiler_search_sanitation_self_test": "scripts/r7-run-local.sh --self-test-compiler-search-env", + "dynamic_loader_environment_sanitized": [ + "LD_PRELOAD", + "LD_LIBRARY_PATH", + "LD_AUDIT", + "DYLD_INSERT_LIBRARIES", + "DYLD_LIBRARY_PATH", + "DYLD_FRAMEWORK_PATH", + "DYLD_FALLBACK_LIBRARY_PATH", + "DYLD_FALLBACK_FRAMEWORK_PATH", + "LIBPATH", + "SHLIB_PATH" + ], + "dynamic_loader_injection_allowed": false, + "dynamic_loader_sanitation_recorded_in_environment": true, + "dynamic_loader_sanitation_recorded_in_command": true, + "dynamic_loader_sanitation_self_test": "scripts/r7-run-local.sh --self-test-dynamic-loader-env", + "replay_build_uses_make_C_repo_root": true, + "replay_build_makefile_argument": "Makefile", + "replay_study_executable_path_is_absolute": true, + "replay_command_is_working_directory_independent": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, From 2dd3d9c6f691784686192bc3957772155dcbfa68 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:52:03 +0930 Subject: [PATCH 016/132] Document R7 environment provenance boundary --- R7-MEMORY-WALL-STUDY.md | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 267e0c3..555a80e 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -238,8 +238,11 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The script creates an **immutable new destination** and refuses to overwrite an -existing bundle. Before creating that destination it rejects Git index flags -that can hide tracked changes (`assume-unchanged` and `skip-worktree`), then +existing bundle. It first clears Git repository-routing overrides and anchors +all provenance reads to `repo_root` with `git -C`. Before creating the +destination it rejects Git index flags that can hide tracked changes +(`assume-unchanged` and `skip-worktree`), rejects ignored untracked files +under the compiler-input trees `src/`, `include/`, and `study/`, then samples tracked, staged, and untracked Git state. **Any dirty worktree is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not @@ -255,8 +258,10 @@ evidence_class=raw-local-execution-observation The script records: -- exact Git source revision; -- a verified clean working tree, including absence of untracked files; +- exact Git source revision, with Git routing overrides cleared and provenance + commands explicitly rooted at the repository; +- a verified clean working tree, including absence of untracked files and + ignored untracked files under `src/`, `include/`, and `study/`; - resolved single-executable compiler **and archiver** paths with successful identity/version output; - both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the @@ -265,6 +270,9 @@ The script records: (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, `GCC_EXEC_PREFIX`); +- explicit sanitation of dynamic-loader injection/search variables including + `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT`, the relevant + `DYLD_*` variables, `LIBPATH`, and `SHLIB_PATH`; - mandatory successful, nonempty `uname -a` platform identity; - visible processor count when available; - CPU model when available; @@ -278,8 +286,12 @@ A compound CC such as `ccache gcc` is rejected for evidence capture; wrappers or flags must be represented explicitly rather than hidden inside CC. Ambient compiler/header search-path variables are unset before compiler identity and the evidence build; intentional include paths must be expressed in recorded -`CPPFLAGS`. CI executes a hostile-environment self-test to verify the search -variables are actually unset. If the +`CPPFLAGS`. Dynamic-loader injection/search variables are also cleared before +toolchain identity and the measured executable are launched, so an ambient +preload cannot replace `clock()` or other measured behavior without being +part of the recorded source/build configuration. CI executes hostile-environment +self-tests for Git routing, compiler search paths, ignored compiler inputs, and +dynamic-loader injection. If the compiler cannot be resolved/identified or memory context cannot be captured, the bundle fails closed. @@ -291,10 +303,14 @@ single-quote escaping, including embedded apostrophes, so paths and multiword CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into different make arguments. -The build recipe is pinned explicitly with `make -f "$repo_root/Makefile"`. +The build recipe is pinned explicitly with `make -C "$repo_root" -f Makefile`. The script verifies that `Makefile` is tracked and records the Git blob ID of `source_revision:Makefile`. Ignored or globally excluded `GNUmakefile` or -lowercase `makefile` files therefore cannot override the evidence build. CI runs the quote serializer's built-in self-test. +lowercase `makefile` files therefore cannot override the evidence build. +`command.txt` records that explicit working directory and uses an absolute +path for the study executable, so replay does not depend on the caller's current +directory. CI runs the quote serializer's built-in self-test and executes the +pinned build/run form from outside the repository. The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is From c6a4d3d8f4672dc38d17d0b90cbc1622aebf3ba3 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:52:06 +0930 Subject: [PATCH 017/132] Document replayable R7 evidence capture --- evidence/r7/README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index b502921..305e594 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -36,14 +36,21 @@ Evidence capture requires a clean Git working tree. Tracked, staged, or untracked changes cause a fail-closed exit before the bundle directory is created, so source_revision identifies the exact contents built. `assume-unchanged` and `skip-worktree` index flags are forbidden because -they can hide tracked modifications from ordinary status checks. +they can hide tracked modifications from ordinary status checks. Git routing +overrides are cleared and all provenance reads are rooted at the repository. +Ignored untracked files under `src/`, `include/`, or `study/` are also +forbidden because they can satisfy compiler includes without appearing in +ordinary status output. For evidence capture, CC and AR must each identify one executable; compound commands are rejected. Ambient compiler search variables (CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH, COMPILER_PATH, LIBRARY_PATH, GCC_EXEC_PREFIX) are cleared; intentional include paths belong in -the recorded CPPFLAGS. CI also runs the script's compiler-search-environment -self-test with hostile search paths preloaded. Missing compiler identity, a failed/empty `uname -a` platform identity, or +the recorded CPPFLAGS. Dynamic-loader injection/search variables +(`LD_PRELOAD`, loader library paths/auditing, relevant `DYLD_*` variables, +`LIBPATH`, and `SHLIB_PATH`) are cleared before toolchain identity and study +execution. CI exercises hostile compiler-search, Git-routing, ignored-header, +and loader-injection cases. Missing compiler identity, a failed/empty `uname -a` platform identity, or missing memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical page count and page size. @@ -52,8 +59,10 @@ the evidence build so a dry-run flag such as MAKEFLAGS=-n cannot certify a stale executable. The evidence build also uses the tracked repository Makefile explicitly via -`make -f /Makefile` and records its Git blob identity. Ignored +`make -C -f Makefile` and records its Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. +The recorded run command uses an absolute study executable path, making +`command.txt` replayable from outside the repository. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. From e3cc80c4a1897e464ff04a7af05e38828e4a864d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:51:07 +0930 Subject: [PATCH 018/132] Close remaining R7 provenance escape hatches --- scripts/r7-run-local.sh | 162 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 6 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index b530bcc..b1ffdfc 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -23,6 +23,7 @@ sanitize_capture_environment() unset GIT_ALTERNATE_OBJECT_DIRECTORIES unset GIT_COMMON_DIR unset GIT_NAMESPACE + export GIT_NO_REPLACE_OBJECTS=1 unset CPATH unset C_INCLUDE_PATH @@ -46,6 +47,44 @@ sanitize_capture_environment() sanitize_capture_environment +build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin} + +validate_build_path() +{ + old_ifs=$IFS + IFS=: + for path_entry in $build_path; do + case "$path_entry" in + /*) ;; + *) + IFS=$old_ifs + fail "RUNE_R7_BUILD_PATH entries must be nonempty absolute directories" + ;; + esac + done + IFS=$old_ifs +} + +resolve_build_tool() +{ + PATH="$build_path" command -v "$1" +} + +validate_build_path + +if [ "${1:-}" = "--self-test-build-tools" ]; then + for tool in make mkdir rm; do + tool_path=$(resolve_build_tool "$tool") || + fail "required build tool not found in sanitized build path: $tool" + case "$tool_path" in + /*) ;; + *) fail "build tool did not resolve to an absolute path: $tool_path" ;; + esac + printf '%s=%s\n' "$tool" "$tool_path" + done + exit 0 +fi + if [ "${1:-}" = "--self-test-shell-quote" ]; then quoted=$(shell_quote "alpha beta'gamma") [ "$quoted" = "'alpha beta'\\''gamma'" ] || @@ -69,6 +108,8 @@ repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) cd "$repo_root" if [ "${1:-}" = "--self-test-git-root" ]; then + [ "${GIT_NO_REPLACE_OBJECTS:-}" = "1" ] || + fail "Git replacement objects are not disabled" git_root=$(git -C "$repo_root" rev-parse --show-toplevel) || fail "Git root self-test could not resolve repository" [ "$git_root" = "$repo_root" ] || @@ -78,6 +119,7 @@ fi cc_name=${CC:-cc} ar_name=${AR:-ar} +make_name=${MAKE:-make} cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} @@ -97,6 +139,29 @@ case "$ar_name" in ;; esac +case "$make_name" in + *[[:space:]]*) + fail "MAKE must name one build-driver executable" + ;; +esac + +case "$out_dir" in + *"/../"*|"../"*|*/..|..) + fail "evidence destination must not contain parent-directory traversal: $out_dir" + ;; +esac + +out_route=$out_dir +while [ "${out_route#./}" != "$out_route" ]; do + out_route=${out_route#./} +done + +case "$out_route" in + build|build/*|"$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not route through build/: $out_dir" + ;; +esac + [ -d "$out_parent" ] || fail "bundle parent directory does not exist: $out_parent" @@ -115,6 +180,12 @@ if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination already exists; refusing overwrite: $out_dir" fi +replacement_refs=$(git -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || + fail "could not inspect Git replacement refs" + +[ -z "$replacement_refs" ] || + fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" + revision=$(git -C "$repo_root" rev-parse HEAD) || fail "could not resolve source revision" @@ -144,6 +215,25 @@ git_status=$(git -C "$repo_root" status --porcelain --untracked-files=all) || [ -z "$git_status" ] || fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" +tracked_inputs=$(git -C "$repo_root" ls-files -- Makefile src include study) || + fail "could not enumerate tracked compiler inputs" + +[ -n "$tracked_inputs" ] || + fail "tracked compiler-input set is empty" + +printf '%s\n' "$tracked_inputs" | +while IFS= read -r tracked_path; do + [ -n "$tracked_path" ] || continue + [ -f "$repo_root/$tracked_path" ] || + fail "tracked compiler input is missing from worktree: $tracked_path" + worktree_blob=$(git -C "$repo_root" hash-object --no-filters -- "$tracked_path") || + fail "could not hash raw worktree bytes: $tracked_path" + revision_blob=$(git -C "$repo_root" rev-parse "$revision:$tracked_path") || + fail "could not resolve revision blob: $tracked_path" + [ "$worktree_blob" = "$revision_blob" ] || + fail "raw worktree bytes differ from source revision: $tracked_path" +done + dirty=false cc_path=$(command -v "$cc_name") || @@ -171,6 +261,34 @@ fi [ -n "$archiver_version" ] || fail "archiver identity output is empty" +make_path=$(resolve_build_tool "$make_name") || + fail "build driver not found in sanitized build path: $make_name" +case "$make_path" in + /*) ;; + *) fail "build-driver path is not absolute: $make_path" ;; +esac +[ -x "$make_path" ] || + fail "build-driver path is not executable: $make_path" + +if make_version=$("$make_path" --version 2>&1); then + : +elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then + : +else + fail "build-driver identity command failed: $make_path" +fi +[ -n "$make_version" ] || + fail "build-driver identity output is empty" + +mkdir_path=$(resolve_build_tool mkdir) || + fail "mkdir not found in sanitized build path" +rm_path=$(resolve_build_tool rm) || + fail "rm not found in sanitized build path" +case "$mkdir_path:$rm_path" in + /*:/*) ;; + *) fail "build utility paths must be absolute" ;; +esac + memory_profile= if [ -r /proc/meminfo ]; then mem_total_kib=$(awk '/^MemTotal:/ { print $2; exit }' /proc/meminfo) @@ -235,6 +353,13 @@ if [ -z "$cpu_model" ] && command -v sysctl >/dev/null 2>&1; then done fi +build_dir="$repo_root/build/r7-evidence-$stamp-$" +study_executable="$build_dir/rune_r7_study" + +if [ -e "$build_dir" ] || [ -L "$build_dir" ]; then + fail "fresh evidence build directory already exists: $build_dir" +fi + mkdir "$out_dir" || fail "could not create immutable evidence destination: $out_dir" @@ -252,9 +377,17 @@ mkdir "$out_dir" || echo "cc_resolved=$cc_path" echo "ar_requested=$ar_name" echo "ar_resolved=$ar_path" + echo "make_requested=$make_name" + echo "make_resolved=$make_path" + echo "build_path=$build_path" + echo "mkdir_resolved=$mkdir_path" + echo "rm_resolved=$rm_path" + echo "fresh_build_dir=$build_dir" echo "cppflags=$cppflags" echo "cflags=$cflags" echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" + echo "git_replace_objects=disabled and replacement refs forbidden" + echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX cleared" echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" echo "ignored_compiler_inputs=forbidden under src,include,study" @@ -275,15 +408,26 @@ mkdir "$out_dir" || printf '%s\n' "$compiler_version" echo "archiver_path=$ar_path" printf '%s\n' "$archiver_version" + echo "build_driver_path=$make_path" + printf '%s\n' "$make_version" } > "$out_dir/compiler.txt" { printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" + printf "export GIT_NO_REPLACE_OBJECTS=1\n" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" - printf "MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' make -C " + printf "PATH=" + shell_quote "$build_path" + printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " + shell_quote "$make_path" + printf " -C " shell_quote "$repo_root" - printf " -f Makefile clean build/rune_r7_study CC=" + printf " -f Makefile " + shell_quote "$study_executable" + printf " BUILD_DIR=" + shell_quote "$build_dir" + printf " CC=" shell_quote "$cc_path" printf " AR=" shell_quote "$ar_path" @@ -293,22 +437,28 @@ mkdir "$out_dir" || shell_quote "$cflags" printf '\n' - shell_quote "$repo_root/build/rune_r7_study" + shell_quote "$study_executable" printf " --profile local --repeats " shell_quote "$repeats" printf '\n' } > "$out_dir/command.txt" -MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ -make -C "$repo_root" -f Makefile clean build/rune_r7_study \ +PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ +"$make_path" -C "$repo_root" -f Makefile "$study_executable" \ + BUILD_DIR="$build_dir" \ CC="$cc_path" \ AR="$ar_path" \ CPPFLAGS="$cppflags" \ CFLAGS="$cflags" -"$repo_root/build/rune_r7_study" --profile local --repeats "$repeats" \ +"$study_executable" --profile local --repeats "$repeats" \ > "$out_dir/observations.tsv" +"$rm_path" -rf "$build_dir" || + fail "could not remove fresh evidence build directory: $build_dir" +[ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || + fail "fresh evidence build directory remains after cleanup: $build_dir" + if command -v sha256sum >/dev/null 2>&1; then ( cd "$out_dir" From 504ed1e5032392af0ae33c263966c5a0d8bea8a5 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:51:59 +0930 Subject: [PATCH 019/132] Sanitize R7 tool PATH and raw source checks --- scripts/r7-run-local.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index b1ffdfc..6a68d40 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -51,6 +51,12 @@ build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin} validate_build_path() { + case "$build_path" in + ''|:*|*:|*::*) + fail "RUNE_R7_BUILD_PATH must contain nonempty absolute directory entries" + ;; + esac + old_ifs=$IFS IFS=: for path_entry in $build_path; do @@ -71,6 +77,8 @@ resolve_build_tool() } validate_build_path +PATH=$build_path +export PATH if [ "${1:-}" = "--self-test-build-tools" ]; then for tool in make mkdir rm; do @@ -221,7 +229,6 @@ tracked_inputs=$(git -C "$repo_root" ls-files -- Makefile src include study) || [ -n "$tracked_inputs" ] || fail "tracked compiler-input set is empty" -printf '%s\n' "$tracked_inputs" | while IFS= read -r tracked_path; do [ -n "$tracked_path" ] || continue [ -f "$repo_root/$tracked_path" ] || @@ -232,7 +239,9 @@ while IFS= read -r tracked_path; do fail "could not resolve revision blob: $tracked_path" [ "$worktree_blob" = "$revision_blob" ] || fail "raw worktree bytes differ from source revision: $tracked_path" -done +done < Date: Sun, 27 Sep 2026 15:53:00 +0930 Subject: [PATCH 020/132] Add executable fresh-build provenance self-test --- scripts/r7-run-local.sh | 43 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 6a68d40..f64bf92 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -128,6 +128,10 @@ fi cc_name=${CC:-cc} ar_name=${AR:-ar} make_name=${MAKE:-make} +fresh_build_self_test=false +if [ "${1:-}" = "--self-test-fresh-build" ]; then + fresh_build_self_test=true +fi cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} @@ -298,6 +302,25 @@ case "$mkdir_path:$rm_path" in *) fail "build utility paths must be absolute" ;; esac +build_study() +{ + PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ + "$make_path" -C "$repo_root" -f Makefile "$study_executable" \ + BUILD_DIR="$build_dir" \ + CC="$cc_path" \ + AR="$ar_path" \ + CPPFLAGS="$cppflags" \ + CFLAGS="$cflags" +} + +cleanup_build() +{ + "$rm_path" -rf "$build_dir" || + fail "could not remove fresh evidence build directory: $build_dir" + [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || + fail "fresh evidence build directory remains after cleanup: $build_dir" +} + memory_profile= if [ -r /proc/meminfo ]; then mem_total_kib=$(awk '/^MemTotal:/ { print $2; exit }' /proc/meminfo) @@ -369,6 +392,13 @@ if [ -e "$build_dir" ] || [ -L "$build_dir" ]; then fail "fresh evidence build directory already exists: $build_dir" fi +if [ "$fresh_build_self_test" = true ]; then + build_study + "$study_executable" --bytes 32768 --repeats 1 >/dev/null + cleanup_build + exit 0 +fi + mkdir "$out_dir" || fail "could not create immutable evidence destination: $out_dir" @@ -452,21 +482,12 @@ mkdir "$out_dir" || printf '\n' } > "$out_dir/command.txt" -PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ -"$make_path" -C "$repo_root" -f Makefile "$study_executable" \ - BUILD_DIR="$build_dir" \ - CC="$cc_path" \ - AR="$ar_path" \ - CPPFLAGS="$cppflags" \ - CFLAGS="$cflags" +build_study "$study_executable" --profile local --repeats "$repeats" \ > "$out_dir/observations.tsv" -"$rm_path" -rf "$build_dir" || - fail "could not remove fresh evidence build directory: $build_dir" -[ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || - fail "fresh evidence build directory remains after cleanup: $build_dir" +cleanup_build if command -v sha256sum >/dev/null 2>&1; then ( From a6a26a9aa15ef6ea44404b21eb2ef16dbb38d6a9 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:53:40 +0930 Subject: [PATCH 021/132] Reproduce R7 provenance escape cases in CI --- .github/workflows/c99.yml | 63 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index d73b387..b51d92f 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -36,6 +36,17 @@ jobs: echo "R7 evidence script accepted build/ destination" >&2 exit 1 fi + + symlink_target=$(mktemp -d) + ln -s "$symlink_target" build/r7-out-link + if scripts/r7-run-local.sh build/r7-out-link/run 2>/dev/null; then + echo "R7 evidence script accepted symlink-routed build/ destination" >&2 + exit 1 + fi + test ! -e "$symlink_target/run" + rm build/r7-out-link + rm -rf "$symlink_target" + touch r7-untracked-evidence-probe if scripts/r7-run-local.sh evidence/r7/ci-dirty-probe 2>/dev/null; then echo "R7 evidence script accepted dirty worktree" >&2 @@ -75,6 +86,17 @@ jobs: scripts/r7-run-local.sh --self-test-git-root rm -rf "$foreign_repo" + replacement_commit=$(printf 'R7 replacement probe\n' | \ + git -c user.name=RUNE -c user.email=rune@example.invalid \ + commit-tree "$(git rev-parse 'HEAD^{tree}')") + git replace HEAD "$replacement_commit" + if scripts/r7-run-local.sh evidence/r7/ci-replace-probe 2>/dev/null; then + echo "R7 evidence script accepted active Git replacement ref" >&2 + exit 1 + fi + test ! -e evidence/r7/ci-replace-probe + git replace -d HEAD + cat > build/r7-preload-probe.c <<'EOF' #include clock_t clock(void) @@ -103,6 +125,23 @@ jobs: test ! -e evidence/r7/ci-assume-unchanged-probe git update-index --no-assume-unchanged study/r7_memory_wall.c git checkout -- study/r7_memory_wall.c + + printf 'study/r7_memory_wall.c filter=r7-clean-probe\n' >> .git/info/attributes + git config filter.r7-clean-probe.clean "sed '/R7_CLEAN_FILTER_PROBE/d'" + git config filter.r7-clean-probe.smudge cat + printf '\n/* R7_CLEAN_FILTER_PROBE */\n' >> study/r7_memory_wall.c + git add study/r7_memory_wall.c + test -z "$(git status --porcelain --untracked-files=all)" + if scripts/r7-run-local.sh evidence/r7/ci-clean-filter-probe 2>/dev/null; then + echo "R7 evidence script accepted clean-filter-hidden source mutation" >&2 + exit 1 + fi + test ! -e evidence/r7/ci-clean-filter-probe + git reset --hard HEAD + git config --unset-all filter.r7-clean-probe.clean + git config --unset-all filter.r7-clean-probe.smudge + sed -i '/r7-clean-probe/d' .git/info/attributes + CPATH=/tmp/r7-hostile-cpath C_INCLUDE_PATH=/tmp/r7-hostile-c-include \ CPLUS_INCLUDE_PATH=/tmp/r7-hostile-cplus \ COMPILER_PATH=/tmp/r7-hostile-compiler \ @@ -110,8 +149,28 @@ jobs: GCC_EXEC_PREFIX=/tmp/r7-hostile-gcc-prefix \ scripts/r7-run-local.sh --self-test-compiler-search-env - grep -Fq 'make -C "$repo_root" -f Makefile clean build/rune_r7_study' scripts/r7-run-local.sh - grep -Fq 'shell_quote "$repo_root/build/rune_r7_study"' scripts/r7-run-local.sh + fakebin=$(mktemp -d) + cat > "$fakebin/rm" <<'EOF' + #!/bin/sh + exit 0 + EOF + chmod +x "$fakebin/rm" + PATH="$fakebin:$PATH" scripts/r7-run-local.sh --self-test-build-tools > build/r7-build-tools.txt + if grep -Fq "$fakebin/rm" build/r7-build-tools.txt; then + echo "R7 evidence script selected ambient fake rm" >&2 + exit 1 + fi + PATH="$fakebin:$PATH" CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh --self-test-fresh-build + rm -rf "$fakebin" + rm build/r7-build-tools.txt + + grep -Fq 'BUILD_DIR="$build_dir"' scripts/r7-run-local.sh + if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then + echo "R7 evidence script still depends on clean removing stale study output" >&2 + exit 1 + fi + ( cd /tmp MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ From 5477bdcfdecaff1e02299e18a64876ae23c198c5 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:55:08 +0930 Subject: [PATCH 022/132] Extend R7 provenance authority --- AGENTS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index d411d85..2e8fff1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,6 +164,8 @@ CORE_RULES: - R7_index_visibility_flags_are_checked_before_dirty_state - R7_Git_routing_environment_is_cleared_before_provenance_checks - R7_Git_provenance_commands_are_anchored_to_repo_root +- R7_Git_replacement_objects_are_disabled_and_replacement_refs_are_forbidden +- R7_raw_tracked_build_inputs_must_hash_equal_source_revision_without_filters - R7_ignored_untracked_files_under_src_include_study_are_forbidden - R7_ambient_compiler_search_path_environment_is_cleared - R7_compiler_search_environment_sanitation_is_CI_self_tested @@ -180,6 +182,10 @@ CORE_RULES: - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting - R7_recorded_replay_build_uses_make_C_repo_root - R7_recorded_replay_study_path_is_absolute +- R7_evidence_build_uses_recorded_sanitized_absolute_PATH_entries +- R7_make_driver_and_build_utility_paths_are_resolved_from_sanitized_PATH +- R7_evidence_build_uses_fresh_unique_BUILD_DIR_and_does_not_depend_on_make_clean +- R7_fresh_build_self_test_is_CI_executed_with_hostile_ambient_PATH - R7_shell_safe_quote_serializer_is_CI_self_tested - R7_local_profile_defaults_to_five_repeats_unless_explicitly_overridden - R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build @@ -188,6 +194,8 @@ CORE_RULES: - R7_tracked_Makefile_blob_identity_is_recorded - R7_implicit_GNUmakefile_or_lowercase_makefile_must_not_control_evidence_build - R7_evidence_destination_must_not_resolve_inside_build_directory +- R7_evidence_destination_must_not_lexically_route_through_build_directory +- R7_evidence_destination_parent_traversal_is_forbidden - R7_getconf_memory_profile_requires_both_nonzero_numeric_page_count_and_size - R7_compiler_identity_capture_must_succeed - R7_compound_CC_is_not_accepted_for_evidence_capture From a3e0bb5fafce75d2b5558fbea51d846b58e6b6a0 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:55:11 +0930 Subject: [PATCH 023/132] Bind fresh-build and raw-source provenance --- machine/r7-memory-wall-study.v1.json | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 33c3c6a..8110353 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -203,6 +203,8 @@ "build_target_must_be_rebuilt_from_recorded_source_configuration": true, "destination_under_build_directory_allowed": false, "destination_path_checked_against_physical_parent": true, + "destination_lexical_route_through_build_allowed": false, + "destination_parent_traversal_allowed": false, "getconf_memory_profile_requires_both_nonzero_numeric_phys_pages_and_page_size": true, "AR_recorded_and_bound": true, "archiver_command_must_be_single_executable": true, @@ -215,8 +217,20 @@ "shell_safe_quoting_handles_spaces_and_single_quotes": true, "toolchain_identity_includes": [ "compiler", - "archiver" + "archiver", + "build_driver" ], + "build_driver_path_resolution_required": true, + "build_driver_identity_capture_required": true, + "build_driver_identity_failure_is_capture_failure": true, + "ambient_PATH_inherited_by_evidence_build": false, + "sanitized_build_PATH_default": "/usr/bin:/bin", + "sanitized_build_PATH_override": "RUNE_R7_BUILD_PATH", + "sanitized_build_PATH_entries_must_be_nonempty_absolute_directories": true, + "make_mkdir_rm_resolved_from_sanitized_build_PATH": true, + "fresh_unique_BUILD_DIR_required": true, + "make_clean_required_for_evidence_build": false, + "fresh_build_self_test": "scripts/r7-run-local.sh --self-test-fresh-build", "clean_working_tree_required": true, "dirty_working_tree_capture_allowed": false, "source_revision_must_identify_exact_built_contents": true, @@ -244,6 +258,16 @@ ], "git_provenance_commands_anchored_with_git_C_repo_root": true, "git_routing_sanitation_self_test": "scripts/r7-run-local.sh --self-test-git-root", + "git_no_replace_objects_required": true, + "git_replacement_refs_allowed": false, + "raw_worktree_identity_paths": [ + "Makefile", + "src", + "include", + "study" + ], + "raw_worktree_identity_hash_uses_no_filters": true, + "raw_worktree_bytes_must_equal_revision_blobs": true, "ignored_untracked_compiler_inputs_allowed": false, "ignored_compiler_input_trees": [ "src", From 1783dc1c00984e69fdb6ef3d0309f01627f20fd5 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:55:14 +0930 Subject: [PATCH 024/132] Document R7 fresh-build provenance boundary --- R7-MEMORY-WALL-STUDY.md | 56 +++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 555a80e..b78c4c7 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -238,13 +238,18 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The script creates an **immutable new destination** and refuses to overwrite an -existing bundle. It first clears Git repository-routing overrides and anchors -all provenance reads to `repo_root` with `git -C`. Before creating the +existing bundle. Destinations may not resolve inside, or lexically route +through, the repository `build/` tree, and parent-directory traversal is +rejected. The script clears Git repository-routing overrides, sets +`GIT_NO_REPLACE_OBJECTS=1`, rejects active `refs/replace`, and anchors all +provenance reads to `repo_root` with `git -C`. Before creating the destination it rejects Git index flags that can hide tracked changes (`assume-unchanged` and `skip-worktree`), rejects ignored untracked files -under the compiler-input trees `src/`, `include/`, and `study/`, then -samples tracked, staged, and untracked Git state. **Any dirty worktree is -rejected.** R7 local evidence +under the compiler-input trees `src/`, `include/`, and `study/`, and +compares the raw bytes of every tracked Makefile/source/include/study input +against the recorded revision using `git hash-object --no-filters`. It then +samples tracked, staged, and untracked Git state. **Any dirty or raw-byte +divergent worktree is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not claim a commit while actually building uncommitted source content. Files marked `assume-unchanged` or `skip-worktree` are rejected because those index flags @@ -258,12 +263,14 @@ evidence_class=raw-local-execution-observation The script records: -- exact Git source revision, with Git routing overrides cleared and provenance - commands explicitly rooted at the repository; +- exact Git source revision, with Git routing overrides cleared, replacement + objects disabled/rejected, provenance commands explicitly rooted at the + repository, and raw compiler-input bytes verified against revision blobs + without clean filters; - a verified clean working tree, including absence of untracked files and ignored untracked files under `src/`, `include/`, and `study/`; -- resolved single-executable compiler **and archiver** paths with successful - identity/version output; +- resolved single-executable compiler, archiver, and build-driver paths with + successful identity/version output; - both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the build command; - explicit sanitation of ambient compiler search-path variables @@ -295,22 +302,39 @@ dynamic-loader injection. If the compiler cannot be resolved/identified or memory context cannot be captured, the bundle fails closed. -Evidence destinations resolving to `build/` or a descendant are rejected, -because the recorded build begins with `make clean`. The build itself clears -inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES` so dry-run or other -make-control flags cannot silently reuse a stale executable. The sanitized make invocation is recorded in `command.txt` using POSIX -single-quote escaping, including embedded apostrophes, so paths and multiword +Evidence destinations resolving inside or lexically routing through `build/` +are rejected before bundle creation, including symlink routes whose lexical +parent would be removed or replaced by build activity. Parent-directory +traversal in the requested destination is also rejected. + +The evidence build does **not** depend on `make clean`. Each capture receives +a fresh unique `BUILD_DIR`; a pre-existing directory is a hard failure. The +build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, +`MAKEFILES`, and `MAKEOVERRIDES`, uses a recorded sanitized build `PATH` +(default `/usr/bin:/bin`, explicitly overridable with +`RUNE_R7_BUILD_PATH`), resolves the build driver plus `mkdir` and `rm` +from that path, and invokes the resolved absolute build-driver path. This +prevents an ambient `PATH` shim from turning a successful clean into reuse of +a stale executable. The fresh build directory is removed through the resolved +`rm` path after the measured executable completes. + +The sanitized invocation is recorded in `command.txt` using POSIX single-quote +escaping, including embedded apostrophes, so paths and multiword CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into different make arguments. -The build recipe is pinned explicitly with `make -C "$repo_root" -f Makefile`. +The build recipe is pinned explicitly with the resolved absolute make path, +`-C "$repo_root" -f Makefile`, and the fresh absolute `BUILD_DIR`. The script verifies that `Makefile` is tracked and records the Git blob ID of `source_revision:Makefile`. Ignored or globally excluded `GNUmakefile` or lowercase `makefile` files therefore cannot override the evidence build. `command.txt` records that explicit working directory and uses an absolute path for the study executable, so replay does not depend on the caller's current directory. CI runs the quote serializer's built-in self-test and executes the -pinned build/run form from outside the repository. +pinned build/run form from outside the repository. CI also reproduces +symlink-routed output paths, active Git replacement refs, clean-filter-hidden +raw source edits, and a hostile ambient `PATH` containing a fake `rm`; the +fresh-build self-test must still compile and execute a 32 KiB smoke study. The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is From 696a7bbd6d27556c6fc47c23166d1b52442f8182 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:55:17 +0930 Subject: [PATCH 025/132] Document R7 hostile-environment protections --- evidence/r7/README.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 305e594..37f3460 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -16,8 +16,9 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The destination must not already exist; evidence bundles are immutable capture -records and are never overwritten. Destinations resolving inside `build/` are -also rejected because evidence capture performs a clean rebuild. +records and are never overwritten. Destinations that resolve inside or +lexically route through the repository `build/` tree are rejected, and +parent-directory traversal is not accepted. A bundle contains: @@ -38,9 +39,11 @@ created, so source_revision identifies the exact contents built. `assume-unchanged` and `skip-worktree` index flags are forbidden because they can hide tracked modifications from ordinary status checks. Git routing overrides are cleared and all provenance reads are rooted at the repository. -Ignored untracked files under `src/`, `include/`, or `study/` are also -forbidden because they can satisfy compiler includes without appearing in -ordinary status output. +Git replacement objects are disabled, active replacement refs are rejected, and +tracked Makefile/source/include/study files are raw-hashed with filters disabled +and must match their blobs at `source_revision`. Ignored untracked files under +`src/`, `include/`, or `study/` are also forbidden because they can +satisfy compiler includes without appearing in ordinary status output. For evidence capture, CC and AR must each identify one executable; compound commands are rejected. Ambient compiler search variables (CPATH, @@ -55,11 +58,15 @@ missing memory profile causes the capture to fail. The getconf fallback requires page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for -the evidence build so a dry-run flag such as MAKEFLAGS=-n cannot certify a stale -executable. +the evidence build. Ambient `PATH` is replaced by a recorded sanitized build +path (default `/usr/bin:/bin`), from which make/mkdir/rm are resolved. Each +capture builds into a fresh unique `BUILD_DIR` and never relies on +`make clean`, so a fake ambient `rm` cannot preserve and certify a stale +study executable. The evidence build also uses the tracked repository Makefile explicitly via -`make -C -f Makefile` and records its Git blob identity. Ignored +the resolved absolute make path with `-C -f Makefile`, records that +build-driver identity, and records the Makefile Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. The recorded run command uses an absolute study executable path, making `command.txt` replayable from outside the repository. From fa0deaf7b6762abec5ad5f091723975246704e22 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:56:26 +0930 Subject: [PATCH 026/132] Make loader sanitation CI probe executable --- .github/workflows/c99.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index b51d92f..506cc48 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -107,7 +107,7 @@ jobs: "${{ matrix.cc }}" -shared -fPIC build/r7-preload-probe.c -o build/r7-preload-probe.so LD_PRELOAD="$PWD/build/r7-preload-probe.so" \ LD_LIBRARY_PATH=/tmp/r7-hostile-ld-library \ - LD_AUDIT=/tmp/r7-hostile-ld-audit \ + LD_AUDIT= \ DYLD_INSERT_LIBRARIES=/tmp/r7-hostile-dyld-insert \ DYLD_LIBRARY_PATH=/tmp/r7-hostile-dyld-library \ DYLD_FRAMEWORK_PATH=/tmp/r7-hostile-dyld-framework \ From f650b9cbe04d237f5d01f13f6862991716edb66d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:57:00 +0930 Subject: [PATCH 027/132] Preserve system probe paths in sanitized R7 PATH --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index f64bf92..d96ded8 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -47,7 +47,7 @@ sanitize_capture_environment() sanitize_capture_environment -build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin} +build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin:/usr/sbin:/sbin} validate_build_path() { From 5b043b88b9018d7876e45bfe92f35985127a77ef Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:57:04 +0930 Subject: [PATCH 028/132] Preserve system probe paths in sanitized R7 PATH --- machine/r7-memory-wall-study.v1.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 8110353..aabab8f 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -224,7 +224,7 @@ "build_driver_identity_capture_required": true, "build_driver_identity_failure_is_capture_failure": true, "ambient_PATH_inherited_by_evidence_build": false, - "sanitized_build_PATH_default": "/usr/bin:/bin", + "sanitized_build_PATH_default": "/usr/bin:/bin:/usr/sbin:/sbin", "sanitized_build_PATH_override": "RUNE_R7_BUILD_PATH", "sanitized_build_PATH_entries_must_be_nonempty_absolute_directories": true, "make_mkdir_rm_resolved_from_sanitized_build_PATH": true, From d887bbf5b9277190e3a2070a00ee31d1397c9032 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:57:07 +0930 Subject: [PATCH 029/132] Preserve system probe paths in sanitized R7 PATH --- R7-MEMORY-WALL-STUDY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index b78c4c7..a6dd3da 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -311,7 +311,7 @@ The evidence build does **not** depend on `make clean`. Each capture receives a fresh unique `BUILD_DIR`; a pre-existing directory is a hard failure. The build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES`, uses a recorded sanitized build `PATH` -(default `/usr/bin:/bin`, explicitly overridable with +(default `/usr/bin:/bin:/usr/sbin:/sbin`, explicitly overridable with `RUNE_R7_BUILD_PATH`), resolves the build driver plus `mkdir` and `rm` from that path, and invokes the resolved absolute build-driver path. This prevents an ambient `PATH` shim from turning a successful clean into reuse of From 9f440e3ddf107d3953e8f8aec33c1294d93e8538 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:57:10 +0930 Subject: [PATCH 030/132] Preserve system probe paths in sanitized R7 PATH --- evidence/r7/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 37f3460..8bfb2c5 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -59,7 +59,7 @@ page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by a recorded sanitized build -path (default `/usr/bin:/bin`), from which make/mkdir/rm are resolved. Each +path (default `/usr/bin:/bin:/usr/sbin:/sbin`), from which make/mkdir/rm are resolved. Each capture builds into a fresh unique `BUILD_DIR` and never relies on `make clean`, so a fake ambient `rm` cannot preserve and certify a stale study executable. From 00f1b5923caf5115f5f3608957383f355abbbf8b Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:58:09 +0930 Subject: [PATCH 031/132] Fix clean-filter CI reproduction --- .github/workflows/c99.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 506cc48..781bf4b 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -129,7 +129,7 @@ jobs: printf 'study/r7_memory_wall.c filter=r7-clean-probe\n' >> .git/info/attributes git config filter.r7-clean-probe.clean "sed '/R7_CLEAN_FILTER_PROBE/d'" git config filter.r7-clean-probe.smudge cat - printf '\n/* R7_CLEAN_FILTER_PROBE */\n' >> study/r7_memory_wall.c + printf '/* R7_CLEAN_FILTER_PROBE */\n' >> study/r7_memory_wall.c git add study/r7_memory_wall.c test -z "$(git status --porcelain --untracked-files=all)" if scripts/r7-run-local.sh evidence/r7/ci-clean-filter-probe 2>/dev/null; then From 6f19430257b8c3f4992b03b8e76afdbac6101870 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:58:47 +0930 Subject: [PATCH 032/132] Terminate dirname options in R7 capture --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index d96ded8..1353f85 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -137,7 +137,7 @@ cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} stamp=$(date -u +%Y%m%dT%H%M%SZ) out_dir=${1:-"evidence/r7/local-$stamp"} -out_parent=$(dirname "$out_dir") +out_parent=$(dirname -- "$out_dir") case "$cc_name" in *[[:space:]]*) From ffa3104668e91309f432a4e0898250e07a9a0305 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:59:57 +0930 Subject: [PATCH 033/132] Isolate fresh-build CI reproduction --- .github/workflows/c99.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 781bf4b..c3679c5 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -155,15 +155,17 @@ jobs: exit 0 EOF chmod +x "$fakebin/rm" - PATH="$fakebin:$PATH" scripts/r7-run-local.sh --self-test-build-tools > build/r7-build-tools.txt - if grep -Fq "$fakebin/rm" build/r7-build-tools.txt; then + PATH="$fakebin:$PATH" scripts/r7-run-local.sh --self-test-build-tools > /tmp/r7-build-tools.txt + if grep -Fq "$fakebin/rm" /tmp/r7-build-tools.txt; then echo "R7 evidence script selected ambient fake rm" >&2 exit 1 fi + git reset --hard HEAD + git clean -fdx PATH="$fakebin:$PATH" CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ scripts/r7-run-local.sh --self-test-fresh-build rm -rf "$fakebin" - rm build/r7-build-tools.txt + rm /tmp/r7-build-tools.txt grep -Fq 'BUILD_DIR="$build_dir"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then From 8168b5f1d385ea21e2e696cc7a3d1582a11ccbc9 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:16:47 +0930 Subject: [PATCH 034/132] Make R7 fresh builds unique and Make-safe --- scripts/r7-run-local.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 1353f85..5b179a4 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -305,8 +305,8 @@ esac build_study() { PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ - "$make_path" -C "$repo_root" -f Makefile "$study_executable" \ - BUILD_DIR="$build_dir" \ + "$make_path" -C "$repo_root" -f Makefile "$study_target" \ + BUILD_DIR="$build_dir_rel" \ CC="$cc_path" \ AR="$ar_path" \ CPPFLAGS="$cppflags" \ @@ -385,8 +385,10 @@ if [ -z "$cpu_model" ] && command -v sysctl >/dev/null 2>&1; then done fi -build_dir="$repo_root/build/r7-evidence-$stamp-$" -study_executable="$build_dir/rune_r7_study" +build_dir_rel="build/r7-evidence-$stamp-$" +build_dir="$repo_root/$build_dir_rel" +study_target="$build_dir_rel/rune_r7_study" +study_executable="$repo_root/$study_target" if [ -e "$build_dir" ] || [ -L "$build_dir" ]; then fail "fresh evidence build directory already exists: $build_dir" @@ -421,7 +423,9 @@ mkdir "$out_dir" || echo "build_path=$build_path" echo "mkdir_resolved=$mkdir_path" echo "rm_resolved=$rm_path" + echo "fresh_build_dir_relative=$build_dir_rel" echo "fresh_build_dir=$build_dir" + echo "fresh_study_target=$study_target" echo "cppflags=$cppflags" echo "cflags=$cflags" echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" @@ -463,9 +467,9 @@ mkdir "$out_dir" || printf " -C " shell_quote "$repo_root" printf " -f Makefile " - shell_quote "$study_executable" + shell_quote "$study_target" printf " BUILD_DIR=" - shell_quote "$build_dir" + shell_quote "$build_dir_rel" printf " CC=" shell_quote "$cc_path" printf " AR=" From d0dc9eb70e1a28d1c5daa5f24296dc6dd2a3e554 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:17:16 +0930 Subject: [PATCH 035/132] Use PID in R7 fresh build directory --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 5b179a4..207736f 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -385,7 +385,7 @@ if [ -z "$cpu_model" ] && command -v sysctl >/dev/null 2>&1; then done fi -build_dir_rel="build/r7-evidence-$stamp-$" +build_dir_rel="build/r7-evidence-$stamp-$$" build_dir="$repo_root/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$repo_root/$study_target" From 235bb929f198c8c213920b21cc146a173fc5c86d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:17:47 +0930 Subject: [PATCH 036/132] Test concurrent and space-path R7 builds --- .github/workflows/c99.yml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index c3679c5..c4a5b1a 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -164,10 +164,29 @@ jobs: git clean -fdx PATH="$fakebin:$PATH" CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ scripts/r7-run-local.sh --self-test-fresh-build + + PATH="$fakebin:$PATH" CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh --self-test-fresh-build > /tmp/r7-fresh-a.log 2>&1 & + fresh_a=$! + PATH="$fakebin:$PATH" CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh --self-test-fresh-build > /tmp/r7-fresh-b.log 2>&1 & + fresh_b=$! + wait "$fresh_a" + wait "$fresh_b" + test -z "$(find build -maxdepth 1 -type d -name 'r7-evidence-*' -print -quit)" + rm -rf "$fakebin" - rm /tmp/r7-build-tools.txt + rm /tmp/r7-build-tools.txt /tmp/r7-fresh-a.log /tmp/r7-fresh-b.log + + space_repo="/tmp/RUNE review ${{ matrix.cc }} $" + git worktree add --detach "$space_repo" HEAD + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + "$space_repo/scripts/r7-run-local.sh" --self-test-fresh-build + git worktree remove --force "$space_repo" - grep -Fq 'BUILD_DIR="$build_dir"' scripts/r7-run-local.sh + grep -Fq 'build_dir_rel="build/r7-evidence-$stamp-$"' scripts/r7-run-local.sh + grep -Fq '"$make_path" -C "$repo_root" -f Makefile "$study_target"' scripts/r7-run-local.sh + grep -Fq 'BUILD_DIR="$build_dir_rel"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then echo "R7 evidence script still depends on clean removing stale study output" >&2 exit 1 From 966f66f4079680a854f6e21e086fcd50f9956a2c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:18:31 +0930 Subject: [PATCH 037/132] Define R7 concurrent and space-path build invariants --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 2e8fff1..9bcb20d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -185,7 +185,12 @@ CORE_RULES: - R7_evidence_build_uses_recorded_sanitized_absolute_PATH_entries - R7_make_driver_and_build_utility_paths_are_resolved_from_sanitized_PATH - R7_evidence_build_uses_fresh_unique_BUILD_DIR_and_does_not_depend_on_make_clean +- R7_fresh_BUILD_DIR_identity_includes_UTC_timestamp_and_shell_PID +- R7_concurrent_evidence_builds_must_not_share_BUILD_DIR +- R7_Make_facing_BUILD_DIR_and_study_target_are_repository_relative +- R7_repository_paths_with_spaces_are_supported_for_evidence_capture - R7_fresh_build_self_test_is_CI_executed_with_hostile_ambient_PATH +- R7_concurrent_and_space_path_fresh_builds_are_CI_tested - R7_shell_safe_quote_serializer_is_CI_self_tested - R7_local_profile_defaults_to_five_repeats_unless_explicitly_overridden - R7_inherited_make_dry_run_flags_are_cleared_for_evidence_build From 22d11c67bab461834bd2e096b4a4a0613c8a79b5 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:18:34 +0930 Subject: [PATCH 038/132] Bind R7 Make-safe fresh-build paths --- machine/r7-memory-wall-study.v1.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index aabab8f..1040f80 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -229,8 +229,16 @@ "sanitized_build_PATH_entries_must_be_nonempty_absolute_directories": true, "make_mkdir_rm_resolved_from_sanitized_build_PATH": true, "fresh_unique_BUILD_DIR_required": true, + "fresh_BUILD_DIR_identity": "UTC timestamp + shell PID", + "concurrent_evidence_builds_must_use_distinct_BUILD_DIRs": true, + "make_facing_BUILD_DIR_is_repository_relative": true, + "make_facing_study_target_is_repository_relative": true, + "shell_facing_study_executable_is_absolute": true, + "repository_paths_with_spaces_supported": true, "make_clean_required_for_evidence_build": false, "fresh_build_self_test": "scripts/r7-run-local.sh --self-test-fresh-build", + "fresh_build_concurrency_CI_tested": true, + "repository_space_path_CI_tested": true, "clean_working_tree_required": true, "dirty_working_tree_capture_allowed": false, "source_revision_must_identify_exact_built_contents": true, From 773611e9c1f873083d6d160442aa6d01a1e8bf04 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:18:38 +0930 Subject: [PATCH 039/132] Document unique Make-safe R7 build paths --- R7-MEMORY-WALL-STUDY.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index a6dd3da..23d8704 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -308,7 +308,9 @@ parent would be removed or replaced by build activity. Parent-directory traversal in the requested destination is also rejected. The evidence build does **not** depend on `make clean`. Each capture receives -a fresh unique `BUILD_DIR`; a pre-existing directory is a hard failure. The +a fresh unique `BUILD_DIR` identified by UTC timestamp plus the shell PID, so +captures started in the same second remain isolated. A pre-existing directory +is a hard failure. The build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES`, uses a recorded sanitized build `PATH` (default `/usr/bin:/bin:/usr/sbin:/sbin`, explicitly overridable with @@ -323,8 +325,12 @@ escaping, including embedded apostrophes, so paths and multiword CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into different make arguments. -The build recipe is pinned explicitly with the resolved absolute make path, -`-C "$repo_root" -f Makefile`, and the fresh absolute `BUILD_DIR`. +The build recipe is pinned explicitly with the resolved absolute make path and +`-C "$repo_root" -f Makefile`. Make-facing values remain repository-relative: +the study target is `build/.../rune_r7_study` and `BUILD_DIR` is +`build/...`. The shell-facing executable path remains absolute. This avoids +Make parsing repository-path whitespace while preserving replayability from any +working directory. The script verifies that `Makefile` is tracked and records the Git blob ID of `source_revision:Makefile`. Ignored or globally excluded `GNUmakefile` or lowercase `makefile` files therefore cannot override the evidence build. @@ -335,6 +341,8 @@ pinned build/run form from outside the repository. CI also reproduces symlink-routed output paths, active Git replacement refs, clean-filter-hidden raw source edits, and a hostile ambient `PATH` containing a fake `rm`; the fresh-build self-test must still compile and execute a 32 KiB smoke study. +CI also launches two fresh-build self-tests concurrently and executes the same +self-test from a linked worktree whose repository path contains spaces. The `getconf` memory fallback is valid only when both `_PHYS_PAGES` and `PAGE_SIZE` are present, numeric, and nonzero; a one-sided memory profile is From 3ed7f10a9198728064a29ff1b15f015031e6f9c4 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:18:41 +0930 Subject: [PATCH 040/132] Document concurrent and space-safe R7 builds --- evidence/r7/README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 8bfb2c5..a2ebbea 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -60,13 +60,17 @@ page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by a recorded sanitized build path (default `/usr/bin:/bin:/usr/sbin:/sbin`), from which make/mkdir/rm are resolved. Each -capture builds into a fresh unique `BUILD_DIR` and never relies on -`make clean`, so a fake ambient `rm` cannot preserve and certify a stale -study executable. +capture builds into a fresh unique `BUILD_DIR` keyed by UTC timestamp plus +the shell PID and never relies on `make clean`, so concurrent captures do not +share objects/executables and a fake ambient `rm` cannot preserve and certify +a stale study executable. The evidence build also uses the tracked repository Makefile explicitly via -the resolved absolute make path with `-C -f Makefile`, records that -build-driver identity, and records the Makefile Git blob identity. Ignored +the resolved absolute make path with `-C -f Makefile`. The Make target +and `BUILD_DIR` passed into Make are repository-relative so repository paths +containing spaces remain parseable; the executable used by the shell remains +absolute. The bundle records the build-driver identity and Makefile Git blob +identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. The recorded run command uses an absolute study executable path, making `command.txt` replayable from outside the repository. From 4d86ca1da1d91c20f9ee616a93fc930186dc0f3d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:20:17 +0930 Subject: [PATCH 041/132] Use behavioral R7 uniqueness CI checks --- .github/workflows/c99.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index c4a5b1a..7b1ee1f 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -178,13 +178,12 @@ jobs: rm -rf "$fakebin" rm /tmp/r7-build-tools.txt /tmp/r7-fresh-a.log /tmp/r7-fresh-b.log - space_repo="/tmp/RUNE review ${{ matrix.cc }} $" + space_repo="/tmp/RUNE review ${{ matrix.cc }} $GITHUB_RUN_ID" git worktree add --detach "$space_repo" HEAD CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ "$space_repo/scripts/r7-run-local.sh" --self-test-fresh-build git worktree remove --force "$space_repo" - grep -Fq 'build_dir_rel="build/r7-evidence-$stamp-$"' scripts/r7-run-local.sh grep -Fq '"$make_path" -C "$repo_root" -f Makefile "$study_target"' scripts/r7-run-local.sh grep -Fq 'BUILD_DIR="$build_dir_rel"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then From 31a4c864769576f22a69d7e018e3f3bc1c98e26a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:54:32 +0930 Subject: [PATCH 042/132] Isolate R7 provenance and make replay exact --- scripts/r7-run-local.sh | 99 ++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 207736f..4b90f25 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -47,8 +47,14 @@ sanitize_capture_environment() sanitize_capture_environment +provenance_path=/usr/bin:/bin:/usr/sbin:/sbin build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin:/usr/sbin:/sbin} +resolve_provenance_tool() +{ + PATH="$provenance_path" command -v "$1" +} + validate_build_path() { case "$build_path" in @@ -77,8 +83,19 @@ resolve_build_tool() } validate_build_path -PATH=$build_path -export PATH + +git_path=$(resolve_provenance_tool git) || + fail "Git not found in fixed provenance path" +case "$git_path" in + /*) ;; + *) fail "Git provenance path is not absolute: $git_path" ;; +esac +[ -x "$git_path" ] || + fail "Git provenance path is not executable: $git_path" +git_version=$("$git_path" --version 2>&1) || + fail "Git provenance identity command failed: $git_path --version" +[ -n "$git_version" ] || + fail "Git provenance identity output is empty" if [ "${1:-}" = "--self-test-build-tools" ]; then for tool in make mkdir rm; do @@ -118,7 +135,11 @@ cd "$repo_root" if [ "${1:-}" = "--self-test-git-root" ]; then [ "${GIT_NO_REPLACE_OBJECTS:-}" = "1" ] || fail "Git replacement objects are not disabled" - git_root=$(git -C "$repo_root" rev-parse --show-toplevel) || + case "$git_path" in + "$provenance_path"/*) ;; + *) fail "Git provenance executable escaped fixed provenance path: $git_path" ;; + esac + git_root=$("$git_path" -C "$repo_root" rev-parse --show-toplevel) || fail "Git root self-test could not resolve repository" [ "$git_root" = "$repo_root" ] || fail "Git root self-test resolved foreign repository: $git_root" @@ -192,42 +213,42 @@ if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination already exists; refusing overwrite: $out_dir" fi -replacement_refs=$(git -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || +replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || fail "could not inspect Git replacement refs" [ -z "$replacement_refs" ] || fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" -revision=$(git -C "$repo_root" rev-parse HEAD) || +revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || fail "could not resolve source revision" -git -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || +"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || fail "tracked Makefile is missing" -makefile_blob=$(git -C "$repo_root" rev-parse "$revision:Makefile") || +makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || fail "could not resolve tracked Makefile at source revision" [ -n "$makefile_blob" ] || fail "tracked Makefile identity is empty" -index_hidden=$(git -C "$repo_root" ls-files -v | awk ' +index_hidden=$("$git_path" -C "$repo_root" ls-files -v | awk ' /^[a-z]/ || /^S / { print; exit } ') || fail "could not inspect Git index visibility flags" [ -z "$index_hidden" ] || fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" -ignored_inputs=$(git -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || +ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || fail "could not inspect ignored compiler-input trees" [ -z "$ignored_inputs" ] || fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" -git_status=$(git -C "$repo_root" status --porcelain --untracked-files=all) || +git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || fail "could not inspect Git working-tree state" [ -z "$git_status" ] || fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" -tracked_inputs=$(git -C "$repo_root" ls-files -- Makefile src include study) || +tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || fail "could not enumerate tracked compiler inputs" [ -n "$tracked_inputs" ] || @@ -237,9 +258,9 @@ while IFS= read -r tracked_path; do [ -n "$tracked_path" ] || continue [ -f "$repo_root/$tracked_path" ] || fail "tracked compiler input is missing from worktree: $tracked_path" - worktree_blob=$(git -C "$repo_root" hash-object --no-filters -- "$tracked_path") || + worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || fail "could not hash raw worktree bytes: $tracked_path" - revision_blob=$(git -C "$repo_root" rev-parse "$revision:$tracked_path") || + revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || fail "could not resolve revision blob: $tracked_path" [ "$worktree_blob" = "$revision_blob" ] || fail "raw worktree bytes differ from source revision: $tracked_path" @@ -404,30 +425,34 @@ fi mkdir "$out_dir" || fail "could not create immutable evidence destination: $out_dir" +observations_path="$out_abs/observations.tsv" + { echo "contract=rune.r7.environment.v1" echo "evidence_class=raw-local-execution-observation" - echo "source_revision=$revision" - echo "working_tree_dirty=$dirty" - echo "measurement_method=C99_clock_process_cpu_time" - echo "benchmark_contract=rune.r7.memory-wall-observation.v1" - echo "makefile_path=$repo_root/Makefile" - echo "makefile_blob=$makefile_blob" - echo "repeats=$repeats" - echo "cc_requested=$cc_name" - echo "cc_resolved=$cc_path" - echo "ar_requested=$ar_name" - echo "ar_resolved=$ar_path" - echo "make_requested=$make_name" - echo "make_resolved=$make_path" - echo "build_path=$build_path" - echo "mkdir_resolved=$mkdir_path" - echo "rm_resolved=$rm_path" - echo "fresh_build_dir_relative=$build_dir_rel" - echo "fresh_build_dir=$build_dir" - echo "fresh_study_target=$study_target" - echo "cppflags=$cppflags" - echo "cflags=$cflags" + printf 'source_revision=%s\n' "$revision" + printf 'working_tree_dirty=%s\n' "$dirty" + printf '%s\n' "measurement_method=C99_clock_process_cpu_time" + printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" + printf 'makefile_path=%s\n' "$repo_root/Makefile" + printf 'makefile_blob=%s\n' "$makefile_blob" + printf 'repeats=%s\n' "$repeats" + printf 'git_provenance_path=%s\n' "$provenance_path" + printf 'git_resolved=%s\n' "$git_path" + printf 'cc_requested=%s\n' "$cc_name" + printf 'cc_resolved=%s\n' "$cc_path" + printf 'ar_requested=%s\n' "$ar_name" + printf 'ar_resolved=%s\n' "$ar_path" + printf 'make_requested=%s\n' "$make_name" + printf 'make_resolved=%s\n' "$make_path" + printf 'build_path=%s\n' "$build_path" + printf 'mkdir_resolved=%s\n' "$mkdir_path" + printf 'rm_resolved=%s\n' "$rm_path" + printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" + printf 'fresh_build_dir=%s\n' "$build_dir" + printf 'fresh_study_target=%s\n' "$study_target" + printf 'cppflags=%s\n' "$cppflags" + printf 'cflags=%s\n' "$cflags" echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" echo "git_replace_objects=disabled and replacement refs forbidden" echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" @@ -447,6 +472,8 @@ mkdir "$out_dir" || } > "$out_dir/environment.txt" { + printf 'git_path=%s\n' "$git_path" + printf '%s\n' "$git_version" echo "compiler_path=$cc_path" printf '%s\n' "$compiler_version" echo "archiver_path=$ar_path" @@ -483,13 +510,15 @@ mkdir "$out_dir" || shell_quote "$study_executable" printf " --profile local --repeats " shell_quote "$repeats" + printf " > " + shell_quote "$observations_path" printf '\n' } > "$out_dir/command.txt" build_study "$study_executable" --profile local --repeats "$repeats" \ - > "$out_dir/observations.tsv" + > "$observations_path" cleanup_build From c773dab1bb38baf1134b757a4140ec3787e3b691 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:54:53 +0930 Subject: [PATCH 043/132] Pin Git provenance executable path --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 4b90f25..6cee172 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -136,7 +136,7 @@ if [ "${1:-}" = "--self-test-git-root" ]; then [ "${GIT_NO_REPLACE_OBJECTS:-}" = "1" ] || fail "Git replacement objects are not disabled" case "$git_path" in - "$provenance_path"/*) ;; + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; *) fail "Git provenance executable escaped fixed provenance path: $git_path" ;; esac git_root=$("$git_path" -C "$repo_root" rev-parse --show-toplevel) || From e49771310eaf50bd71a7b9b0968c6776856b0754 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:55:54 +0930 Subject: [PATCH 044/132] Reproduce R7 provenance and replay edge cases --- .github/workflows/c99.yml | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 7b1ee1f..3995b59 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -184,6 +184,57 @@ jobs: "$space_repo/scripts/r7-run-local.sh" --self-test-fresh-build git worktree remove --force "$space_repo" + fakegit=$(mktemp -d) + cat > "$fakegit/git" <<'EOF' + #!/bin/bash + last= + for arg in "$@"; do + last=$arg + done + case " $* " in + *" status --porcelain "*) + exit 0 + ;; + *" hash-object --no-filters -- "*) + exec /usr/bin/git -C "$GITHUB_WORKSPACE" rev-parse "HEAD:$last" + ;; + esac + exec /usr/bin/git "$@" + EOF + chmod +x "$fakegit/git" + printf '/* fake-git provenance probe */\n' >> study/r7_memory_wall.c + if RUNE_R7_BUILD_PATH="$fakegit:/usr/bin:/bin:/usr/sbin:/sbin" \ + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh /tmp/r7-fakegit-${{ matrix.cc }}-$GITHUB_RUN_ID 2>/dev/null; then + echo "R7 evidence script allowed build-path Git shim to certify dirty source" >&2 + exit 1 + fi + test ! -e /tmp/r7-fakegit-${{ matrix.cc }}-$GITHUB_RUN_ID + git checkout -- study/r7_memory_wall.c + rm -rf "$fakegit" + + replay_bundle="/tmp/r7-replay-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$replay_bundle" + CPPFLAGS='-DUNUSED=a\c' CFLAGS=-O2 RUNE_R7_REPEATS=1 \ + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$replay_bundle" + grep -Fxq 'cppflags=-DUNUSED=a\c' "$replay_bundle/environment.txt" + grep -Fxq 'cflags=-O2' "$replay_bundle/environment.txt" + grep -Fq " > '$replay_bundle/observations.tsv'" "$replay_bundle/command.txt" + mv "$replay_bundle/observations.tsv" "$replay_bundle/observations.original.tsv" + ( + cd /tmp + sh "$replay_bundle/command.txt" > "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" + ) + test -s "$replay_bundle/observations.tsv" + awk -F '\t' 'NF != 17 { exit 1 } END { if (NR == 0) exit 1 }' "$replay_bundle/observations.tsv" + if awk -F '\t' 'NF == 17 { found=1 } END { exit found ? 0 : 1 }' "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt"; then + echo "R7 replay leaked observation rows to stdout instead of observations.tsv" >&2 + exit 1 + fi + rm -rf "$replay_bundle" "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" + rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* + grep -Fq '"$make_path" -C "$repo_root" -f Makefile "$study_target"' scripts/r7-run-local.sh grep -Fq 'BUILD_DIR="$build_dir_rel"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then From fe3789f368649ef68250270ff079abeee6303d6e Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:56:31 +0930 Subject: [PATCH 045/132] Define R7 Git isolation and replay invariants --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 9bcb20d..f3b0305 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,6 +164,8 @@ CORE_RULES: - R7_index_visibility_flags_are_checked_before_dirty_state - R7_Git_routing_environment_is_cleared_before_provenance_checks - R7_Git_provenance_commands_are_anchored_to_repo_root +- R7_Git_executable_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_overridable_build_PATH_must_not_control_Git_provenance - R7_Git_replacement_objects_are_disabled_and_replacement_refs_are_forbidden - R7_raw_tracked_build_inputs_must_hash_equal_source_revision_without_filters - R7_ignored_untracked_files_under_src_include_study_are_forbidden @@ -177,11 +179,14 @@ CORE_RULES: - R7_platform_identity_capture_must_succeed_and_be_nonempty - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound +- R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_resolved_executable_for_evidence_capture - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting - R7_recorded_replay_build_uses_make_C_repo_root - R7_recorded_replay_study_path_is_absolute +- R7_recorded_replay_includes_absolute_observations_redirection +- R7_command_txt_recreates_observations_file_from_any_working_directory - R7_evidence_build_uses_recorded_sanitized_absolute_PATH_entries - R7_make_driver_and_build_utility_paths_are_resolved_from_sanitized_PATH - R7_evidence_build_uses_fresh_unique_BUILD_DIR_and_does_not_depend_on_make_clean From 5fd5c12fc39f17db85f18fcf81c7e3769889842e Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:56:34 +0930 Subject: [PATCH 046/132] Bind R7 Git provenance and replay metadata --- machine/r7-memory-wall-study.v1.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 1040f80..9badb7a 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -181,6 +181,8 @@ "dirty_state_sampled_before_bundle_creation": true, "CPPFLAGS_recorded_and_bound": true, "CFLAGS_recorded_and_bound": true, + "CPPFLAGS_and_CFLAGS_recording_uses_printf_not_echo": true, + "CPPFLAGS_and_CFLAGS_backslashes_preserved_exactly": true, "compiler_command_must_be_single_executable": true, "compiler_path_resolution_required": true, "compiler_version_capture_required": true, @@ -265,6 +267,10 @@ "GIT_NAMESPACE" ], "git_provenance_commands_anchored_with_git_C_repo_root": true, + "git_provenance_PATH_fixed": "/usr/bin:/bin:/usr/sbin:/sbin", + "git_executable_resolved_from_fixed_provenance_PATH": true, + "git_executable_identity_recorded": true, + "RUNE_R7_BUILD_PATH_may_control_git_provenance": false, "git_routing_sanitation_self_test": "scripts/r7-run-local.sh --self-test-git-root", "git_no_replace_objects_required": true, "git_replacement_refs_allowed": false, @@ -314,6 +320,9 @@ "replay_build_uses_make_C_repo_root": true, "replay_build_makefile_argument": "Makefile", "replay_study_executable_path_is_absolute": true, + "replay_observations_redirection_is_recorded": true, + "replay_observations_path_is_absolute": true, + "replay_recreates_observations_file": true, "replay_command_is_working_directory_independent": true }, "interpretation": { From bba93dbc2cf521a5ec2ed1c581b747af4b97f70f Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:56:38 +0930 Subject: [PATCH 047/132] Document R7 provenance-path and replay guarantees --- R7-MEMORY-WALL-STUDY.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 23d8704..5bd7185 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -240,9 +240,12 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host The script creates an **immutable new destination** and refuses to overwrite an existing bundle. Destinations may not resolve inside, or lexically route through, the repository `build/` tree, and parent-directory traversal is -rejected. The script clears Git repository-routing overrides, sets -`GIT_NO_REPLACE_OBJECTS=1`, rejects active `refs/replace`, and anchors all -provenance reads to `repo_root` with `git -C`. Before creating the +rejected. The script clears Git repository-routing overrides, resolves Git only from the +fixed provenance path `/usr/bin:/bin:/usr/sbin:/sbin`, records that absolute +Git executable and version, sets `GIT_NO_REPLACE_OBJECTS=1`, rejects active +`refs/replace`, and anchors all provenance reads to `repo_root` with +`git -C`. The overridable `RUNE_R7_BUILD_PATH` is used only for build +utilities and cannot replace the Git executable used for provenance. Before creating the destination it rejects Git index flags that can hide tracked changes (`assume-unchanged` and `skip-worktree`), rejects ignored untracked files under the compiler-input trees `src/`, `include/`, and `study/`, and @@ -271,8 +274,9 @@ The script records: ignored untracked files under `src/`, `include/`, and `study/`; - resolved single-executable compiler, archiver, and build-driver paths with successful identity/version output; -- both CPPFLAGS and CFLAGS, binding those exact values plus CC and AR into the - build command; +- both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other + shell-text content are preserved exactly, binding those values plus CC and AR + into the build command; - explicit sanitation of ambient compiler search-path variables (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, @@ -334,9 +338,11 @@ working directory. The script verifies that `Makefile` is tracked and records the Git blob ID of `source_revision:Makefile`. Ignored or globally excluded `GNUmakefile` or lowercase `makefile` files therefore cannot override the evidence build. -`command.txt` records that explicit working directory and uses an absolute -path for the study executable, so replay does not depend on the caller's current -directory. CI runs the quote serializer's built-in self-test and executes the +`command.txt` records that explicit working directory, uses an absolute path +for the study executable, and records the exact absolute +`> .../observations.tsv` redirection used by capture. Replaying the file from +another working directory therefore recreates the observation artifact rather +than sending numeric rows to the caller's stdout. CI runs the quote serializer's built-in self-test and executes the pinned build/run form from outside the repository. CI also reproduces symlink-routed output paths, active Git replacement refs, clean-filter-hidden raw source edits, and a hostile ambient `PATH` containing a fake `rm`; the From ee4c7d829dbcf3ef321ffc097c2f890d613b8aed Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 16:56:41 +0930 Subject: [PATCH 048/132] Document exact R7 metadata and replay output --- evidence/r7/README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index a2ebbea..8980b38 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -39,7 +39,10 @@ created, so source_revision identifies the exact contents built. `assume-unchanged` and `skip-worktree` index flags are forbidden because they can hide tracked modifications from ordinary status checks. Git routing overrides are cleared and all provenance reads are rooted at the repository. -Git replacement objects are disabled, active replacement refs are rejected, and +Git itself is resolved from a fixed provenance path +(`/usr/bin:/bin:/usr/sbin:/sbin`) and its absolute path/version are recorded; +the overridable build path cannot substitute the Git executable. Git +replacement objects are disabled, active replacement refs are rejected, and tracked Makefile/source/include/study files are raw-hashed with filters disabled and must match their blobs at `source_revision`. Ignored untracked files under `src/`, `include/`, or `study/` are also forbidden because they can @@ -59,7 +62,9 @@ page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by a recorded sanitized build -path (default `/usr/bin:/bin:/usr/sbin:/sbin`), from which make/mkdir/rm are resolved. Each +path (default `/usr/bin:/bin:/usr/sbin:/sbin`), from which make/mkdir/rm are +resolved. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving +backslashes exactly. Each capture builds into a fresh unique `BUILD_DIR` keyed by UTC timestamp plus the shell PID and never relies on `make clean`, so concurrent captures do not share objects/executables and a fake ambient `rm` cannot preserve and certify @@ -72,8 +77,10 @@ containing spaces remain parseable; the executable used by the shell remains absolute. The bundle records the build-driver identity and Makefile Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. -The recorded run command uses an absolute study executable path, making -`command.txt` replayable from outside the repository. +The recorded run command uses an absolute study executable path and includes +the absolute redirection to `observations.tsv`, making `command.txt` +replayable from outside the repository while recreating the captured output +artifact. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. From 23ca4d2f0bd622b51d5dea7a23a22447a580a36e Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:16:49 +0930 Subject: [PATCH 049/132] Run all declared R7 microtiles at every profile size --- study/r7_memory_wall.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index 7ade2ef..6d11c98 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -736,9 +736,6 @@ static int r7_measure_microtile( } count = working_set_bytes / (uint64_t)sizeof(uint32_t); - if (tile_size > count) { - return 0; - } rounds = r7_rounds_for_bytes(working_set_bytes); tile_bytes = tile_size * (uint64_t)sizeof(uint32_t); @@ -1335,13 +1332,6 @@ static int r7_measure_size( reference = 0u; have_reference = 0; for (i = 0u; i < sizeof(tiles) / sizeof(tiles[0]); ++i) { - uint64_t count; - - count = working_set_bytes / (uint64_t)sizeof(uint32_t); - if (tiles[i] > count) { - continue; - } - if (!r7_measure_microtile( tiles[i], working_set_bytes, From 1c28f1e87be31574edd8a205f84a540c92faad6b Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:16:53 +0930 Subject: [PATCH 050/132] Pin R7 platform and integrity probes --- scripts/r7-run-local.sh | 85 +++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 6cee172..b1f3eb6 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -97,6 +97,41 @@ git_version=$("$git_path" --version 2>&1) || [ -n "$git_version" ] || fail "Git provenance identity output is empty" +uname_path=$(resolve_provenance_tool uname) || + fail "uname not found in fixed provenance path" +case "$uname_path" in + /*) ;; + *) fail "uname provenance path is not absolute: $uname_path" ;; +esac +[ -x "$uname_path" ] || + fail "uname provenance path is not executable: $uname_path" + +hash_mode= +hash_path=$(resolve_provenance_tool sha256sum 2>/dev/null || :) +if [ -n "$hash_path" ]; then + hash_mode=sha256sum +else + hash_path=$(resolve_provenance_tool shasum 2>/dev/null || :) + [ -n "$hash_path" ] || fail "no trusted SHA-256 utility available" + hash_mode=shasum +fi +case "$hash_path" in + /*) ;; + *) fail "SHA-256 utility path is not absolute: $hash_path" ;; +esac +[ -x "$hash_path" ] || + fail "SHA-256 utility path is not executable: $hash_path" + +if hash_version=$("$hash_path" --version 2>&1); then + : +elif hash_version=$("$hash_path" -v 2>&1); then + : +else + fail "SHA-256 utility identity command failed: $hash_path" +fi +[ -n "$hash_version" ] || + fail "SHA-256 utility identity output is empty" + if [ "${1:-}" = "--self-test-build-tools" ]; then for tool in make mkdir rm; do tool_path=$(resolve_build_tool "$tool") || @@ -384,8 +419,8 @@ fi [ -n "$memory_profile" ] || fail "could not capture required memory profile" -platform_identity=$(uname -a 2>&1) || - fail "platform identity command failed: uname -a" +platform_identity=$("$uname_path" -a 2>&1) || + fail "platform identity command failed: $uname_path -a" [ -n "$platform_identity" ] || fail "platform identity output is empty" @@ -439,6 +474,9 @@ observations_path="$out_abs/observations.tsv" printf 'repeats=%s\n' "$repeats" printf 'git_provenance_path=%s\n' "$provenance_path" printf 'git_resolved=%s\n' "$git_path" + printf 'uname_resolved=%s\n' "$uname_path" + printf 'sha256_mode=%s\n' "$hash_mode" + printf 'sha256_resolved=%s\n' "$hash_path" printf 'cc_requested=%s\n' "$cc_name" printf 'cc_resolved=%s\n' "$cc_path" printf 'ar_requested=%s\n' "$ar_name" @@ -474,6 +512,9 @@ observations_path="$out_abs/observations.tsv" { printf 'git_path=%s\n' "$git_path" printf '%s\n' "$git_version" + printf 'uname_path=%s\n' "$uname_path" + printf 'sha256_path=%s\n' "$hash_path" + printf '%s\n' "$hash_version" echo "compiler_path=$cc_path" printf '%s\n' "$compiler_version" echo "archiver_path=$ar_path" @@ -522,18 +563,32 @@ build_study cleanup_build -if command -v sha256sum >/dev/null 2>&1; then - ( - cd "$out_dir" - sha256sum environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS - ) -elif command -v shasum >/dev/null 2>&1; then - ( - cd "$out_dir" - shasum -a 256 environment.txt compiler.txt command.txt observations.tsv > SHA256SUMS - ) -else - fail "no SHA-256 utility available" -fi +case "$hash_mode" in + sha256sum) + ( + cd "$out_dir" + "$hash_path" \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + shasum) + ( + cd "$out_dir" + "$hash_path" -a 256 \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + *) + fail "unsupported SHA-256 utility mode: $hash_mode" + ;; +esac echo "R7 evidence bundle: $out_dir" From 4fb9c6a78e66e127f7ab0e574fb86efac496f022 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:17:22 +0930 Subject: [PATCH 051/132] Reproduce R7 trusted-probe and 4KiB microtile cases --- .github/workflows/c99.yml | 47 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 3995b59..6944358 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -25,7 +25,20 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Build R1-R7 checks, R6 proof, frozen R4 corpus, and R7 smoke - run: make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" + run: | + make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" + ./build/rune_r7_study --bytes 4096 --repeats 1 > build/r7-study-4k.tsv + test "$(wc -l < build/r7-study-4k.tsv)" -eq 20 + awk -F '\t' ' + $1 == 4 { seen[$2] = 1; count++ } + END { + split("32 64 128 256 512 1024 2048 4096", expected, " ") + if (count != 8) exit 1 + for (i = 1; i <= 8; ++i) { + if (!(expected[i] in seen)) exit 1 + } + } + ' build/r7-study-4k.tsv - name: Validate R7 local evidence script run: | @@ -184,6 +197,38 @@ jobs: "$space_repo/scripts/r7-run-local.sh" --self-test-fresh-build git worktree remove --force "$space_repo" + fakeprobes=$(mktemp -d) + cat > "$fakeprobes/uname" <<'EOF' + #!/bin/sh + printf 'SPOOFED-PLATFORM\n' + EOF + cat > "$fakeprobes/sha256sum" <<'EOF' + #!/bin/sh + for arg in "$@"; do + printf '%064d %s\n' 0 "$arg" + done + EOF + chmod +x "$fakeprobes/uname" "$fakeprobes/sha256sum" + probe_bundle="/tmp/r7-probe-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$probe_bundle" + PATH="$fakeprobes:$PATH" RUNE_R7_REPEATS=1 \ + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$probe_bundle" + if grep -Fq 'uname=SPOOFED-PLATFORM' "$probe_bundle/environment.txt"; then + echo "R7 evidence script trusted ambient uname shim" >&2 + exit 1 + fi + grep -Fq 'uname_resolved=/usr/bin/uname' "$probe_bundle/environment.txt" || \ + grep -Fq 'uname_resolved=/bin/uname' "$probe_bundle/environment.txt" + grep -Fq 'sha256_resolved=/usr/bin/sha256sum' "$probe_bundle/environment.txt" || \ + grep -Fq 'sha256_resolved=/bin/sha256sum' "$probe_bundle/environment.txt" + ( + cd "$probe_bundle" + /usr/bin/sha256sum -c SHA256SUMS + ) + rm -rf "$probe_bundle" "$fakeprobes" + rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* + fakegit=$(mktemp -d) cat > "$fakegit/git" <<'EOF' #!/bin/bash From ecc403dfa6c979f580af2b63464851e5587b591c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:17:56 +0930 Subject: [PATCH 052/132] Define R7 trusted probes and complete microtile sweep --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index f3b0305..c5fa6e4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -157,6 +157,8 @@ CORE_RULES: - R7_volatile_study_accesses_prevent_variant_elision - R7_microtile_allocates_only_selected_extent_inside_timed_lifecycle - R7_microtile_selected_extent_is_in_resident_peak_and_setup_teardown_timing +- R7_all_eight_declared_microtiles_execute_for_every_valid_working_set +- R7_microtile_may_exceed_logical_input_and_process_only_available_items - R7_evidence_destination_must_be_new_and_immutable - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation - R7_evidence_capture_requires_clean_working_tree @@ -177,6 +179,8 @@ CORE_RULES: - R7_dirty_worktree_evidence_capture_is_forbidden - R7_source_revision_must_identify_exact_built_source_contents - R7_platform_identity_capture_must_succeed_and_be_nonempty +- R7_uname_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_integrity_SHA256_utility_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly From 78dac9397ef12564128587a794597b5257fa5c9c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:18:02 +0930 Subject: [PATCH 053/132] Bind R7 trusted probes and full microtile matrix --- machine/r7-memory-wall-study.v1.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 9badb7a..aa9c17f 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -95,7 +95,9 @@ "tile_storage_allocation": "selected-tile-only", "tile_allocation_included_in_setup_ticks": true, "tile_release_included_in_teardown_ticks": true, - "resident_and_peak_bytes_equal_selected_tile_extent": true + "resident_and_peak_bytes_equal_selected_tile_extent": true, + "all_declared_tile_sizes_execute_for_every_valid_working_set": true, + "tile_larger_than_logical_input_allocates_selected_extent_and_processes_available_items": true }, "5": { "name": "retain-vs-regenerate", @@ -173,6 +175,10 @@ ], "dirty_state_recorded": true, "integrity": "SHA-256", + "integrity_utility_resolved_from_fixed_provenance_PATH": true, + "integrity_utility_path_recorded": true, + "integrity_utility_identity_recorded": true, + "ambient_PATH_may_control_integrity_utility": false, "evidence_class": "raw-local-execution-observation", "evidence_class_required": true, "destination_must_not_preexist": true, @@ -246,6 +252,9 @@ "source_revision_must_identify_exact_built_contents": true, "platform_identity_required": true, "platform_identity_command": "uname -a", + "platform_identity_executable_resolved_from_fixed_provenance_PATH": true, + "platform_identity_executable_path_recorded": true, + "ambient_PATH_may_control_platform_identity": false, "platform_identity_capture_must_succeed": true, "platform_identity_must_be_nonempty": true, "makefile_path": "$repo_root/Makefile", @@ -341,7 +350,8 @@ "gcc", "clang" ], - "CI_validates_harness_not_performance": true + "CI_validates_harness_not_performance": true, + "CI_validates_4096_byte_profile_has_20_rows_and_all_eight_microtiles": true }, "measurement_integrity": { "volatile_accesses_are_study_mechanics": true, From 88b8986b02bdbb2354646c018151fa4195ddaec2 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:18:05 +0930 Subject: [PATCH 054/132] Document trusted R7 probes and full microtile coverage --- R7-MEMORY-WALL-STUDY.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 5bd7185..9d35fd3 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -141,7 +141,11 @@ variant_id is the tile size in elements: 32 64 128 256 512 1024 2048 4096 ~~~ -Every executed tile size must produce one exact result identity. +All eight declared tile sizes execute for every valid R7 working-set size, +including the 4 KiB profile. A tile may therefore be larger than the logical +input: it still allocates the full selected tile extent but processes only the +available logical items. Every tile size must produce the same exact result +identity. Each microtile variant allocates **only its selected tile extent** after the total timer begins and releases it before teardown ends. The allocation is part @@ -284,14 +288,16 @@ The script records: - explicit sanitation of dynamic-loader injection/search variables including `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT`, the relevant `DYLD_*` variables, `LIBPATH`, and `SHLIB_PATH`; -- mandatory successful, nonempty `uname -a` platform identity; +- mandatory successful, nonempty `uname -a` platform identity resolved from + the fixed provenance path and recorded by absolute executable path; - visible processor count when available; - CPU model when available; - a **required memory profile**, using /proc/meminfo, sysctl, or getconf; - timer method; - exact commands; - raw observations; -- SHA-256 integrity file. +- SHA-256 integrity file produced by a SHA-256 utility resolved from the fixed + provenance path, with the utility path/identity recorded before finalization. A compound CC such as `ccache gcc` is rejected for evidence capture; wrappers or flags must be represented explicitly rather than hidden inside CC. Ambient @@ -368,13 +374,15 @@ evidence. make r7-study-smoke ~~~ -CI uses one 32 KiB repeat to check: +CI uses one 32 KiB repeat and an explicit 4 KiB regression run to check: - strict C99 compilation; - all pairwise result identities; - all eight tile identities; - numeric TSV schema; -- expected observation count. +- expected observation count; +- all eight microtile IDs (32 through 4096) execute at the 4 KiB profile, + yielding 20 rows rather than silently omitting the larger tiles. The timing values from this CI job are discarded as performance evidence. From df9c52e8b32755c28baa483a06e5cda3ae05adcb Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:18:08 +0930 Subject: [PATCH 055/132] Document trusted R7 platform and integrity tools --- evidence/r7/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 8980b38..a15a00a 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -31,7 +31,8 @@ A bundle contains: - `command.txt` — exact replayable build/run commands using POSIX shell-safe quoting, including multiword values and embedded apostrophes; - `observations.tsv` — raw numeric R7 observations; -- `SHA256SUMS` — integrity hashes for the bundle. +- `SHA256SUMS` — integrity hashes produced by a trusted-path SHA-256 utility + whose absolute path/identity are recorded in the bundle. Evidence capture requires a clean Git working tree. Tracked, staged, or untracked changes cause a fail-closed exit before the bundle directory is @@ -57,8 +58,10 @@ the recorded CPPFLAGS. Dynamic-loader injection/search variables `LIBPATH`, and `SHLIB_PATH`) are cleared before toolchain identity and study execution. CI exercises hostile compiler-search, Git-routing, ignored-header, and loader-injection cases. Missing compiler identity, a failed/empty `uname -a` platform identity, or -missing memory profile causes the capture to fail. The getconf fallback requires both a nonzero numeric physical -page count and page size. +missing memory profile causes the capture to fail. The required `uname` +platform probe is resolved from the fixed provenance path rather than ambient +`PATH`. The getconf fallback requires both a nonzero numeric physical page +count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by a recorded sanitized build From fc8f3882d61e5161195c9528af74807205b0ea7c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:33:00 +0930 Subject: [PATCH 056/132] Close R7 capture race and trusted-tool gaps --- scripts/r7-run-local.sh | 110 ++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index b1f3eb6..2c5f734 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -10,7 +10,7 @@ fail() shell_quote() { printf "'" - printf '%s' "$1" | sed "s/'/'\\\\''/g" + printf '%s' "$1" | "$sed_path" "s/'/'\\\\''/g" printf "'" } @@ -97,6 +97,24 @@ git_version=$("$git_path" --version 2>&1) || [ -n "$git_version" ] || fail "Git provenance identity output is empty" +sed_path=$(resolve_provenance_tool sed) || + fail "sed not found in fixed provenance path" +awk_path=$(resolve_provenance_tool awk) || + fail "awk not found in fixed provenance path" +bundle_mkdir_path=$(resolve_provenance_tool mkdir) || + fail "mkdir not found in fixed provenance path" +for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path"; do + case "$provenance_tool_path" in + /*) ;; + *) fail "provenance tool path is not absolute: $provenance_tool_path" ;; + esac + [ -x "$provenance_tool_path" ] || + fail "provenance tool path is not executable: $provenance_tool_path" +done + +getconf_path=$(resolve_provenance_tool getconf 2>/dev/null || :) +sysctl_path=$(resolve_provenance_tool sysctl 2>/dev/null || :) + uname_path=$(resolve_provenance_tool uname) || fail "uname not found in fixed provenance path" case "$uname_path" in @@ -191,6 +209,21 @@ fi cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} repeats=${RUNE_R7_REPEATS:-5} +case "$repeats" in + ''|*[!0-9]*) + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" + ;; +esac +normalized_repeats=$repeats +while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do + normalized_repeats=${normalized_repeats#0} +done +[ -n "$normalized_repeats" ] || + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" +case "$normalized_repeats" in + [1-9]|[1-9][0-9]|100) ;; + *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; +esac stamp=$(date -u +%Y%m%dT%H%M%SZ) out_dir=${1:-"evidence/r7/local-$stamp"} out_parent=$(dirname -- "$out_dir") @@ -264,7 +297,7 @@ makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || [ -n "$makefile_blob" ] || fail "tracked Makefile identity is empty" -index_hidden=$("$git_path" -C "$repo_root" ls-files -v | awk ' +index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' /^[a-z]/ || /^S / { print; exit } ') || fail "could not inspect Git index visibility flags" @@ -289,20 +322,29 @@ tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include st [ -n "$tracked_inputs" ] || fail "tracked compiler-input set is empty" -while IFS= read -r tracked_path; do - [ -n "$tracked_path" ] || continue - [ -f "$repo_root/$tracked_path" ] || - fail "tracked compiler input is missing from worktree: $tracked_path" - worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || - fail "could not hash raw worktree bytes: $tracked_path" - revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || - fail "could not resolve revision blob: $tracked_path" - [ "$worktree_blob" = "$revision_blob" ] || - fail "raw worktree bytes differ from source revision: $tracked_path" -done </dev/null 2>&1; then +if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then for key in hw.memsize hw.physmem64 hw.physmem; do - value=$(sysctl -n "$key" 2>/dev/null || :) + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) case "$value" in ''|*[!0-9]*) ;; *) @@ -399,9 +441,9 @@ if [ -z "$memory_profile" ] && command -v sysctl >/dev/null 2>&1; then done fi -if [ -z "$memory_profile" ] && command -v getconf >/dev/null 2>&1; then - phys_pages=$(getconf _PHYS_PAGES 2>/dev/null || :) - page_size=$(getconf PAGE_SIZE 2>/dev/null || :) +if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then + phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) + page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) case "$phys_pages" in ''|*[!0-9]*|0) phys_pages= ;; @@ -426,14 +468,14 @@ platform_identity=$("$uname_path" -a 2>&1) || cpu_model= if [ -r /proc/cpuinfo ]; then - cpu_model=$(awk -F ': ' ' + cpu_model=$("$awk_path" -F ': ' ' /^model name[[:space:]]*:/ { print $2; exit } /^Hardware[[:space:]]*:/ { print $2; exit } ' /proc/cpuinfo) fi -if [ -z "$cpu_model" ] && command -v sysctl >/dev/null 2>&1; then +if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then for key in machdep.cpu.brand_string hw.model; do - value=$(sysctl -n "$key" 2>/dev/null || :) + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) if [ -n "$value" ]; then cpu_model=$value break @@ -457,9 +499,15 @@ if [ "$fresh_build_self_test" = true ]; then exit 0 fi -mkdir "$out_dir" || +"$bundle_mkdir_path" "$out_dir" || fail "could not create immutable evidence destination: $out_dir" +set -- "$out_dir"/* "$out_dir"/.[!.]* "$out_dir"/..?* +for bundle_entry in "$@"; do + [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue + fail "new evidence destination is not empty: $out_dir" +done + observations_path="$out_abs/observations.tsv" { @@ -474,6 +522,9 @@ observations_path="$out_abs/observations.tsv" printf 'repeats=%s\n' "$repeats" printf 'git_provenance_path=%s\n' "$provenance_path" printf 'git_resolved=%s\n' "$git_path" + printf 'sed_resolved=%s\n' "$sed_path" + printf 'awk_resolved=%s\n' "$awk_path" + printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" printf 'uname_resolved=%s\n' "$uname_path" printf 'sha256_mode=%s\n' "$hash_mode" printf 'sha256_resolved=%s\n' "$hash_path" @@ -499,9 +550,11 @@ observations_path="$out_abs/observations.tsv" echo "ignored_compiler_inputs=forbidden under src,include,study" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" echo "uname=$platform_identity" - if command -v getconf >/dev/null 2>&1; then - echo "processors_online=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)" - echo "long_bit=$(getconf LONG_BIT 2>/dev/null || echo unknown)" + if [ -n "$getconf_path" ]; then + processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) + long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) + printf 'processors_online=%s\n' "$processors_online" + printf 'long_bit=%s\n' "$long_bit" fi if [ -n "$cpu_model" ]; then echo "cpu_model=$cpu_model" @@ -512,6 +565,9 @@ observations_path="$out_abs/observations.tsv" { printf 'git_path=%s\n' "$git_path" printf '%s\n' "$git_version" + printf 'sed_path=%s\n' "$sed_path" + printf 'awk_path=%s\n' "$awk_path" + printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" printf 'uname_path=%s\n' "$uname_path" printf 'sha256_path=%s\n' "$hash_path" printf '%s\n' "$hash_version" @@ -557,10 +613,12 @@ observations_path="$out_abs/observations.tsv" } > "$out_dir/command.txt" build_study +validate_source_identity "$study_executable" --profile local --repeats "$repeats" \ > "$observations_path" +validate_source_identity cleanup_build case "$hash_mode" in From 46ffe43219ff4fec4c9797e39ed9f8d3fd0e8603 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:33:31 +0930 Subject: [PATCH 057/132] Validate R7 build before reserving evidence bundle --- scripts/r7-run-local.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 2c5f734..a0aba68 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -499,6 +499,9 @@ if [ "$fresh_build_self_test" = true ]; then exit 0 fi +build_study +validate_source_identity + "$bundle_mkdir_path" "$out_dir" || fail "could not create immutable evidence destination: $out_dir" @@ -612,9 +615,6 @@ observations_path="$out_abs/observations.tsv" printf '\n' } > "$out_dir/command.txt" -build_study -validate_source_identity - "$study_executable" --profile local --repeats "$repeats" \ > "$observations_path" From a4fb6699ccff790fedaa551a9f2b0f9c9b409531 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:34:29 +0930 Subject: [PATCH 058/132] Reproduce R7 post-build and trusted-helper attacks --- .github/workflows/c99.yml | 66 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 6944358..690d804 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -50,6 +50,14 @@ jobs: exit 1 fi + invalid_repeats="/tmp/r7-invalid-repeats-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$invalid_repeats" + if RUNE_R7_REPEATS=0 scripts/r7-run-local.sh "$invalid_repeats" 2>/dev/null; then + echo "R7 evidence script accepted zero repeats" >&2 + exit 1 + fi + test ! -e "$invalid_repeats" + symlink_target=$(mktemp -d) ln -s "$symlink_target" build/r7-out-link if scripts/r7-run-local.sh build/r7-out-link/run 2>/dev/null; then @@ -208,7 +216,28 @@ jobs: printf '%064d %s\n' 0 "$arg" done EOF - chmod +x "$fakeprobes/uname" "$fakeprobes/sha256sum" + cat > "$fakeprobes/sed" <<'EOF' + #!/bin/sh + cat + EOF + cat > "$fakeprobes/awk" <<'EOF' + #!/bin/sh + case "$*" in + *"/proc/meminfo"*) printf '1\n'; exit 0 ;; + esac + exec /usr/bin/awk "$@" + EOF + cat > "$fakeprobes/mkdir" <<'EOF' + #!/bin/sh + /bin/mkdir "$@" + last= + for arg in "$@"; do last=$arg; done + external="/tmp/r7-mkdir-shim-target-$" + printf 'mutable\n' > "$external" + ln -s "$external" "$last/environment.txt" + EOF + chmod +x "$fakeprobes/uname" "$fakeprobes/sha256sum" "$fakeprobes/sed" "$fakeprobes/awk" "$fakeprobes/mkdir" + PATH="$fakeprobes:$PATH" scripts/r7-run-local.sh --self-test-shell-quote probe_bundle="/tmp/r7-probe-${{ matrix.cc }}-$GITHUB_RUN_ID" rm -rf "$probe_bundle" PATH="$fakeprobes:$PATH" RUNE_R7_REPEATS=1 \ @@ -218,6 +247,15 @@ jobs: echo "R7 evidence script trusted ambient uname shim" >&2 exit 1 fi + actual_mem=$(/usr/bin/awk '/^MemTotal:/ { print $2; exit }' /proc/meminfo) + grep -Fxq "mem_total_kib=$actual_mem" "$probe_bundle/environment.txt" + test ! -L "$probe_bundle/environment.txt" + grep -Fq 'sed_resolved=/usr/bin/sed' "$probe_bundle/environment.txt" || \ + grep -Fq 'sed_resolved=/bin/sed' "$probe_bundle/environment.txt" + grep -Fq 'awk_resolved=/usr/bin/awk' "$probe_bundle/environment.txt" || \ + grep -Fq 'awk_resolved=/bin/awk' "$probe_bundle/environment.txt" + grep -Fq 'bundle_mkdir_resolved=/usr/bin/mkdir' "$probe_bundle/environment.txt" || \ + grep -Fq 'bundle_mkdir_resolved=/bin/mkdir' "$probe_bundle/environment.txt" grep -Fq 'uname_resolved=/usr/bin/uname' "$probe_bundle/environment.txt" || \ grep -Fq 'uname_resolved=/bin/uname' "$probe_bundle/environment.txt" grep -Fq 'sha256_resolved=/usr/bin/sha256sum' "$probe_bundle/environment.txt" || \ @@ -227,6 +265,7 @@ jobs: /usr/bin/sha256sum -c SHA256SUMS ) rm -rf "$probe_bundle" "$fakeprobes" + rm -f /tmp/r7-mkdir-shim-target-* rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* fakegit=$(mktemp -d) @@ -258,6 +297,31 @@ jobs: git checkout -- study/r7_memory_wall.c rm -rf "$fakegit" + cc_wrapper="/tmp/r7-mutating-cc-${{ matrix.cc }}-$GITHUB_RUN_ID" + cat > "$cc_wrapper" <> "$GITHUB_WORKSPACE/study/r7_memory_wall.c" + break + fi + done + exec /usr/bin/${{ matrix.cc }} "\$@" + EOF + chmod +x "$cc_wrapper" + race_bundle="/tmp/r7-source-race-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$race_bundle" + if RUNE_R7_REPEATS=1 CC="$cc_wrapper" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$race_bundle" 2>/dev/null; then + echo "R7 evidence script certified source mutated during build" >&2 + exit 1 + fi + test ! -e "$race_bundle" + grep -Fq 'post-preflight compiler mutation' study/r7_memory_wall.c + git checkout -- study/r7_memory_wall.c + rm -f "$cc_wrapper" + rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* + replay_bundle="/tmp/r7-replay-${{ matrix.cc }}-$GITHUB_RUN_ID" rm -rf "$replay_bundle" CPPFLAGS='-DUNUSED=a\c' CFLAGS=-O2 RUNE_R7_REPEATS=1 \ From 3757042717e32adcecbd8e6a970f000bbdae3b65 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:35:10 +0930 Subject: [PATCH 059/132] Define R7 post-build and trusted-helper invariants --- AGENTS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index c5fa6e4..2703da9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,6 +160,8 @@ CORE_RULES: - R7_all_eight_declared_microtiles_execute_for_every_valid_working_set - R7_microtile_may_exceed_logical_input_and_process_only_available_items - R7_evidence_destination_must_be_new_and_immutable +- R7_repeats_are_validated_before_bundle_creation +- R7_bundle_directory_is_created_with_fixed_provenance_mkdir_and_verified_empty - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation - R7_evidence_capture_requires_clean_working_tree - R7_assume_unchanged_and_skip_worktree_flags_are_forbidden @@ -170,6 +172,8 @@ CORE_RULES: - R7_overridable_build_PATH_must_not_control_Git_provenance - R7_Git_replacement_objects_are_disabled_and_replacement_refs_are_forbidden - R7_raw_tracked_build_inputs_must_hash_equal_source_revision_without_filters +- R7_source_identity_is_revalidated_after_build_and_after_measurement +- R7_bundle_is_not_created_until_post_build_source_revalidation_passes - R7_ignored_untracked_files_under_src_include_study_are_forbidden - R7_ambient_compiler_search_path_environment_is_cleared - R7_compiler_search_environment_sanitation_is_CI_self_tested @@ -181,6 +185,9 @@ CORE_RULES: - R7_platform_identity_capture_must_succeed_and_be_nonempty - R7_uname_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_integrity_SHA256_utility_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_quote_serializer_sed_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_memory_profile_awk_parser_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_optional_getconf_and_sysctl_host_probes_use_fixed_provenance_PATH - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly From 2d43851dded162ed56ff00d8e64bcfdf3fc0a43a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:35:14 +0930 Subject: [PATCH 060/132] Bind R7 post-build source and trusted helper provenance --- machine/r7-memory-wall-study.v1.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index aa9c17f..5b4f170 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -183,6 +183,9 @@ "evidence_class_required": true, "destination_must_not_preexist": true, "overwrite_existing_bundle_allowed": false, + "repeats_validated_before_destination_creation": true, + "bundle_directory_created_with_fixed_provenance_mkdir": true, + "new_bundle_directory_must_be_empty_before_metadata_write": true, "dirty_state_includes_untracked_files": true, "dirty_state_sampled_before_bundle_creation": true, "CPPFLAGS_recorded_and_bound": true, @@ -257,6 +260,16 @@ "ambient_PATH_may_control_platform_identity": false, "platform_identity_capture_must_succeed": true, "platform_identity_must_be_nonempty": true, + "shell_quote_serializer_tool": "sed", + "shell_quote_serializer_resolved_from_fixed_provenance_PATH": true, + "shell_quote_serializer_path_recorded": true, + "memory_profile_parser_tool": "awk", + "memory_profile_parser_resolved_from_fixed_provenance_PATH": true, + "memory_profile_parser_path_recorded": true, + "optional_host_probe_tools_resolved_from_fixed_provenance_PATH": [ + "getconf", + "sysctl" + ], "makefile_path": "$repo_root/Makefile", "makefile_must_be_tracked": true, "makefile_blob_identity_recorded": true, @@ -291,6 +304,9 @@ ], "raw_worktree_identity_hash_uses_no_filters": true, "raw_worktree_bytes_must_equal_revision_blobs": true, + "source_identity_revalidated_after_build": true, + "source_identity_revalidated_after_measurement": true, + "bundle_creation_occurs_only_after_post_build_source_revalidation": true, "ignored_untracked_compiler_inputs_allowed": false, "ignored_compiler_input_trees": [ "src", From 7db9a6a9c4f917ee0ed5dac819d0fd92592ca113 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:35:17 +0930 Subject: [PATCH 061/132] Document R7 post-build validation and trusted helpers --- R7-MEMORY-WALL-STUDY.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 9d35fd3..3441202 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -255,8 +255,11 @@ destination it rejects Git index flags that can hide tracked changes under the compiler-input trees `src/`, `include/`, and `study/`, and compares the raw bytes of every tracked Makefile/source/include/study input against the recorded revision using `git hash-object --no-filters`. It then -samples tracked, staged, and untracked Git state. **Any dirty or raw-byte -divergent worktree is rejected.** R7 local evidence +samples tracked, staged, and untracked Git state. The same source-identity check +is repeated immediately after the evidence build and again after the measured +execution. The bundle directory is not created until the post-build check +passes. **Any dirty or raw-byte divergent worktree is rejected.** R7 local +evidence therefore binds directly to the recorded `source_revision`; a bundle may not claim a commit while actually building uncommitted source content. Files marked `assume-unchanged` or `skip-worktree` are rejected because those index flags @@ -292,7 +295,9 @@ The script records: the fixed provenance path and recorded by absolute executable path; - visible processor count when available; - CPU model when available; -- a **required memory profile**, using /proc/meminfo, sysctl, or getconf; +- a **required memory profile**, with Linux parsing performed by `awk` + resolved from the fixed provenance path and optional `sysctl`/`getconf` + fallbacks resolved from that same path; - timer method; - exact commands; - raw observations; @@ -315,7 +320,10 @@ bundle fails closed. Evidence destinations resolving inside or lexically routing through `build/` are rejected before bundle creation, including symlink routes whose lexical parent would be removed or replaced by build activity. Parent-directory -traversal in the requested destination is also rejected. +traversal in the requested destination is also rejected. `RUNE_R7_REPEATS` +is validated as 1..100 before the destination is reserved. Bundle creation uses +a `mkdir` executable resolved from the fixed provenance path, and the newly +created directory is verified empty before any evidence file is written. The evidence build does **not** depend on `make clean`. Each capture receives a fresh unique `BUILD_DIR` identified by UTC timestamp plus the shell PID, so @@ -331,9 +339,9 @@ a stale executable. The fresh build directory is removed through the resolved `rm` path after the measured executable completes. The sanitized invocation is recorded in `command.txt` using POSIX single-quote -escaping, including embedded apostrophes, so paths and multiword -CPPFLAGS/CFLAGS replay as the same shell arguments rather than being split into -different make arguments. +escaping. The quote serializer uses `sed` resolved from the fixed provenance +path rather than ambient `PATH`, so repository paths containing apostrophes +remain replayable even in a hostile shell environment. The build recipe is pinned explicitly with the resolved absolute make path and `-C "$repo_root" -f Makefile`. Make-facing values remain repository-relative: From eb0f4685457348e9646556be122b291808888276 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:35:20 +0930 Subject: [PATCH 062/132] Document R7 trusted bundle creation and source revalidation --- evidence/r7/README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index a15a00a..c0402b6 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -18,7 +18,10 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host The destination must not already exist; evidence bundles are immutable capture records and are never overwritten. Destinations that resolve inside or lexically route through the repository `build/` tree are rejected, and -parent-directory traversal is not accepted. +parent-directory traversal is not accepted. `RUNE_R7_REPEATS` must be an +integer from 1 through 100 and is rejected before destination creation. The +bundle directory itself is created with fixed-provenance `mkdir` and must be +empty before metadata is written. A bundle contains: @@ -45,7 +48,9 @@ Git itself is resolved from a fixed provenance path the overridable build path cannot substitute the Git executable. Git replacement objects are disabled, active replacement refs are rejected, and tracked Makefile/source/include/study files are raw-hashed with filters disabled -and must match their blobs at `source_revision`. Ignored untracked files under +and must match their blobs at `source_revision`. That identity is checked +before the build, immediately after the build, and again after measurement; the +bundle directory is not created until the post-build check succeeds. Ignored untracked files under `src/`, `include/`, or `study/` are also forbidden because they can satisfy compiler includes without appearing in ordinary status output. @@ -58,10 +63,10 @@ the recorded CPPFLAGS. Dynamic-loader injection/search variables `LIBPATH`, and `SHLIB_PATH`) are cleared before toolchain identity and study execution. CI exercises hostile compiler-search, Git-routing, ignored-header, and loader-injection cases. Missing compiler identity, a failed/empty `uname -a` platform identity, or -missing memory profile causes the capture to fail. The required `uname` -platform probe is resolved from the fixed provenance path rather than ambient -`PATH`. The getconf fallback requires both a nonzero numeric physical page -count and page size. +missing memory profile causes the capture to fail. The required `uname` platform probe, the `awk` memory parser, and optional +`getconf`/`sysctl` probes are resolved from the fixed provenance path rather +than ambient `PATH`. The getconf fallback requires both a nonzero numeric +physical page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by a recorded sanitized build @@ -81,9 +86,10 @@ absolute. The bundle records the build-driver identity and Makefile Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. The recorded run command uses an absolute study executable path and includes -the absolute redirection to `observations.tsv`, making `command.txt` -replayable from outside the repository while recreating the captured output -artifact. +the absolute redirection to `observations.tsv`. Shell quoting is serialized +with a fixed-provenance `sed`, so paths containing apostrophes remain valid. +`command.txt` is replayable from outside the repository while recreating the +captured output artifact. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. From ab0990468ab0c5847cc7c288430ef0f68057a8cf Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:57:29 +0930 Subject: [PATCH 063/132] Build R7 evidence from recorded Git snapshot --- scripts/r7-run-local.sh | 140 +++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 16 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index a0aba68..cb161cf 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -103,7 +103,13 @@ awk_path=$(resolve_provenance_tool awk) || fail "awk not found in fixed provenance path" bundle_mkdir_path=$(resolve_provenance_tool mkdir) || fail "mkdir not found in fixed provenance path" -for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path"; do +tar_path=$(resolve_provenance_tool tar) || + fail "tar not found in fixed provenance path" +chmod_path=$(resolve_provenance_tool chmod) || + fail "chmod not found in fixed provenance path" +provenance_rm_path=$(resolve_provenance_tool rm) || + fail "rm not found in fixed provenance path" +for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path"; do case "$provenance_tool_path" in /*) ;; *) fail "provenance tool path is not absolute: $provenance_tool_path" ;; @@ -345,10 +351,61 @@ R7_TRACKED_INPUTS } validate_source_identity + +validate_snapshot_identity() +{ + while IFS= read -r tracked_path; do + [ -n "$tracked_path" ] || continue + [ -f "$source_snapshot/$tracked_path" ] || + fail "snapshot compiler input is missing: $tracked_path" + snapshot_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$source_snapshot/$tracked_path") || + fail "could not hash snapshot bytes: $tracked_path" + revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || + fail "could not resolve revision blob for snapshot: $tracked_path" + [ "$snapshot_blob" = "$revision_blob" ] || + fail "snapshot bytes differ from source revision: $tracked_path" + done < "$archive_path" || + fail "could not materialize source archive for revision: $revision" + "$tar_path" -xf "$archive_path" -C "$source_snapshot" || + fail "could not extract source snapshot" + "$provenance_rm_path" -f "$archive_path" || + fail "could not remove temporary source archive" + + validate_snapshot_identity + "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || + fail "could not make source snapshot read-only" +} + +cleanup_snapshot() +{ + "$provenance_rm_path" -rf "$source_snapshot" || + fail "could not remove source snapshot: $source_snapshot" + [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || + fail "source snapshot remains after cleanup: $source_snapshot" +} + dirty=false -cc_path=$(command -v "$cc_name") || - fail "compiler not found: $cc_name" +cc_path=$(resolve_provenance_tool "$cc_name") || + fail "compiler not found in fixed provenance path: $cc_name" +case "$cc_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "compiler escaped fixed provenance path: $cc_path" ;; +esac [ -n "$cc_path" ] && [ -x "$cc_path" ] || fail "compiler path is not executable: $cc_path" @@ -357,8 +414,12 @@ compiler_version=$("$cc_path" --version 2>&1) || [ -n "$compiler_version" ] || fail "compiler identity output is empty" -ar_path=$(command -v "$ar_name") || - fail "archiver not found: $ar_name" +ar_path=$(resolve_provenance_tool "$ar_name") || + fail "archiver not found in fixed provenance path: $ar_name" +case "$ar_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "archiver escaped fixed provenance path: $ar_path" ;; +esac [ -n "$ar_path" ] && [ -x "$ar_path" ] || fail "archiver path is not executable: $ar_path" @@ -403,7 +464,7 @@ esac build_study() { PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ - "$make_path" -C "$repo_root" -f Makefile "$study_target" \ + "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ BUILD_DIR="$build_dir_rel" \ CC="$cc_path" \ AR="$ar_path" \ @@ -483,23 +544,25 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -build_dir_rel="build/r7-evidence-$stamp-$$" -build_dir="$repo_root/$build_dir_rel" +source_snapshot_rel="build/r7-source-$stamp-$" +source_snapshot="$repo_root/$source_snapshot_rel" +build_dir_rel="build/r7-evidence-$stamp-$" +build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" -study_executable="$repo_root/$study_target" - -if [ -e "$build_dir" ] || [ -L "$build_dir" ]; then - fail "fresh evidence build directory already exists: $build_dir" -fi +study_executable="$source_snapshot/$study_target" if [ "$fresh_build_self_test" = true ]; then + materialize_source_snapshot build_study + validate_snapshot_identity "$study_executable" --bytes 32768 --repeats 1 >/dev/null - cleanup_build + cleanup_snapshot exit 0 fi +materialize_source_snapshot build_study +validate_snapshot_identity validate_source_identity "$bundle_mkdir_path" "$out_dir" || @@ -528,6 +591,11 @@ observations_path="$out_abs/observations.tsv" printf 'sed_resolved=%s\n' "$sed_path" printf 'awk_resolved=%s\n' "$awk_path" printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" + printf 'tar_resolved=%s\n' "$tar_path" + printf 'chmod_resolved=%s\n' "$chmod_path" + printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'source_snapshot=%s\n' "$source_snapshot" + printf 'source_snapshot_revision=%s\n' "$revision" printf 'uname_resolved=%s\n' "$uname_path" printf 'sha256_mode=%s\n' "$hash_mode" printf 'sha256_resolved=%s\n' "$hash_path" @@ -571,6 +639,9 @@ observations_path="$out_abs/observations.tsv" printf 'sed_path=%s\n' "$sed_path" printf 'awk_path=%s\n' "$awk_path" printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" + printf 'tar_path=%s\n' "$tar_path" + printf 'chmod_path=%s\n' "$chmod_path" + printf 'provenance_rm_path=%s\n' "$provenance_rm_path" printf 'uname_path=%s\n' "$uname_path" printf 'sha256_path=%s\n' "$hash_path" printf '%s\n' "$hash_version" @@ -587,12 +658,44 @@ observations_path="$out_abs/observations.tsv" printf "export GIT_NO_REPLACE_OBJECTS=1\n" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + shell_quote "$bundle_mkdir_path" + printf " " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$git_path" + printf " -C " + shell_quote "$repo_root" + printf " archive --format=tar " + shell_quote "$revision" + printf " -- Makefile src include study > " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$tar_path" + printf " -xf " + shell_quote "$source_snapshot/.r7-source.tar" + printf " -C " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$provenance_rm_path" + printf " -f " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$chmod_path" + printf " -R a-w " + shell_quote "$source_snapshot/Makefile" + printf " " + shell_quote "$source_snapshot/src" + printf " " + shell_quote "$source_snapshot/include" + printf " " + shell_quote "$source_snapshot/study" + printf '\n' printf "PATH=" shell_quote "$build_path" printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " shell_quote "$make_path" printf " -C " - shell_quote "$repo_root" + shell_quote "$source_snapshot" printf " -f Makefile " shell_quote "$study_target" printf " BUILD_DIR=" @@ -613,13 +716,18 @@ observations_path="$out_abs/observations.tsv" printf " > " shell_quote "$observations_path" printf '\n' + shell_quote "$provenance_rm_path" + printf " -rf " + shell_quote "$source_snapshot" + printf '\n' } > "$out_dir/command.txt" "$study_executable" --profile local --repeats "$repeats" \ > "$observations_path" +validate_snapshot_identity validate_source_identity -cleanup_build +cleanup_snapshot case "$hash_mode" in sha256sum) From c84fa1fb23ff9dfee23dcd511385e783db086407 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 17:59:25 +0930 Subject: [PATCH 064/132] Fix R7 evidence build to trusted immutable snapshot --- scripts/r7-run-local.sh | 42 ++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index cb161cf..e5f453d 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -48,7 +48,7 @@ sanitize_capture_environment() sanitize_capture_environment provenance_path=/usr/bin:/bin:/usr/sbin:/sbin -build_path=${RUNE_R7_BUILD_PATH:-/usr/bin:/bin:/usr/sbin:/sbin} +build_path=$provenance_path resolve_provenance_tool() { @@ -109,7 +109,13 @@ chmod_path=$(resolve_provenance_tool chmod) || fail "chmod not found in fixed provenance path" provenance_rm_path=$(resolve_provenance_tool rm) || fail "rm not found in fixed provenance path" -for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path"; do +date_path=$(resolve_provenance_tool date) || + fail "date not found in fixed provenance path" +dirname_path=$(resolve_provenance_tool dirname) || + fail "dirname not found in fixed provenance path" +basename_path=$(resolve_provenance_tool basename) || + fail "basename not found in fixed provenance path" +for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path" "$date_path" "$dirname_path" "$basename_path"; do case "$provenance_tool_path" in /*) ;; *) fail "provenance tool path is not absolute: $provenance_tool_path" ;; @@ -230,9 +236,9 @@ case "$normalized_repeats" in [1-9]|[1-9][0-9]|100) ;; *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; esac -stamp=$(date -u +%Y%m%dT%H%M%SZ) +stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) out_dir=${1:-"evidence/r7/local-$stamp"} -out_parent=$(dirname -- "$out_dir") +out_parent=$("$dirname_path" -- "$out_dir") case "$cc_name" in *[[:space:]]*) @@ -274,7 +280,7 @@ esac out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || fail "could not resolve bundle parent: $out_parent" -out_leaf=$(basename -- "$out_dir") +out_leaf=$("$basename_path" -- "$out_dir") out_abs="$out_parent_abs/$out_leaf" case "$out_abs" in @@ -433,11 +439,11 @@ fi [ -n "$archiver_version" ] || fail "archiver identity output is empty" -make_path=$(resolve_build_tool "$make_name") || - fail "build driver not found in sanitized build path: $make_name" +make_path=$(resolve_provenance_tool "$make_name") || + fail "build driver not found in fixed provenance path: $make_name" case "$make_path" in - /*) ;; - *) fail "build-driver path is not absolute: $make_path" ;; + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "build-driver escaped fixed provenance path: $make_path" ;; esac [ -x "$make_path" ] || fail "build-driver path is not executable: $make_path" @@ -452,10 +458,10 @@ fi [ -n "$make_version" ] || fail "build-driver identity output is empty" -mkdir_path=$(resolve_build_tool mkdir) || - fail "mkdir not found in sanitized build path" -rm_path=$(resolve_build_tool rm) || - fail "rm not found in sanitized build path" +mkdir_path=$(resolve_provenance_tool mkdir) || + fail "mkdir not found in fixed provenance path" +rm_path=$(resolve_provenance_tool rm) || + fail "rm not found in fixed provenance path" case "$mkdir_path:$rm_path" in /*:/*) ;; *) fail "build utility paths must be absolute" ;; @@ -544,9 +550,9 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -source_snapshot_rel="build/r7-source-$stamp-$" +source_snapshot_rel="build/r7-source-$stamp-$$" source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$stamp-$" +build_dir_rel="build/r7-evidence-$stamp-$$" build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$source_snapshot/$study_target" @@ -594,6 +600,9 @@ observations_path="$out_abs/observations.tsv" printf 'tar_resolved=%s\n' "$tar_path" printf 'chmod_resolved=%s\n' "$chmod_path" printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'date_resolved=%s\n' "$date_path" + printf 'dirname_resolved=%s\n' "$dirname_path" + printf 'basename_resolved=%s\n' "$basename_path" printf 'source_snapshot=%s\n' "$source_snapshot" printf 'source_snapshot_revision=%s\n' "$revision" printf 'uname_resolved=%s\n' "$uname_path" @@ -642,6 +651,9 @@ observations_path="$out_abs/observations.tsv" printf 'tar_path=%s\n' "$tar_path" printf 'chmod_path=%s\n' "$chmod_path" printf 'provenance_rm_path=%s\n' "$provenance_rm_path" + printf 'date_path=%s\n' "$date_path" + printf 'dirname_path=%s\n' "$dirname_path" + printf 'basename_path=%s\n' "$basename_path" printf 'uname_path=%s\n' "$uname_path" printf 'sha256_path=%s\n' "$hash_path" printf '%s\n' "$hash_version" From 0f0deb5f0014a6f744f8dbb0b48500df16ffac3b Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:00:16 +0930 Subject: [PATCH 065/132] Finalize R7 snapshot materialization path --- scripts/r7-run-local.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index e5f453d..4d1c915 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -377,6 +377,17 @@ R7_SNAPSHOT_INPUTS materialize_source_snapshot() { + if [ -L "$repo_root/build" ]; then + fail "repository build path must not be a symlink" + fi + if [ -e "$repo_root/build" ] && [ ! -d "$repo_root/build" ]; then + fail "repository build path is not a directory" + fi + if [ ! -d "$repo_root/build" ]; then + "$bundle_mkdir_path" "$repo_root/build" || + fail "could not create repository build directory" + fi + [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || fail "source snapshot destination already exists: $source_snapshot" @@ -605,6 +616,8 @@ observations_path="$out_abs/observations.tsv" printf 'basename_resolved=%s\n' "$basename_path" printf 'source_snapshot=%s\n' "$source_snapshot" printf 'source_snapshot_revision=%s\n' "$revision" + printf '%s\n' "build_source_origin=git_archive_recorded_revision" + printf '%s\n' "build_source_worktree_used=false" printf 'uname_resolved=%s\n' "$uname_path" printf 'sha256_mode=%s\n' "$hash_mode" printf 'sha256_resolved=%s\n' "$hash_path" @@ -671,6 +684,10 @@ observations_path="$out_abs/observations.tsv" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" shell_quote "$bundle_mkdir_path" + printf " -p " + shell_quote "$repo_root/build" + printf '\n' + shell_quote "$bundle_mkdir_path" printf " " shell_quote "$source_snapshot" printf '\n' From 8f8e0fe6eceb564a05fa0e869c8dd7dd0cbe7de7 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:00:47 +0930 Subject: [PATCH 066/132] Validate R7 Git-snapshot evidence builds --- .github/workflows/c99.yml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 690d804..d0521fd 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -194,7 +194,7 @@ jobs: fresh_b=$! wait "$fresh_a" wait "$fresh_b" - test -z "$(find build -maxdepth 1 -type d -name 'r7-evidence-*' -print -quit)" + test -z "$(find build -maxdepth 1 -type d \( -name 'r7-evidence-*' -o -name 'r7-source-*' \) -print -quit)" rm -rf "$fakebin" rm /tmp/r7-build-tools.txt /tmp/r7-fresh-a.log /tmp/r7-fresh-b.log @@ -300,12 +300,6 @@ jobs: cc_wrapper="/tmp/r7-mutating-cc-${{ matrix.cc }}-$GITHUB_RUN_ID" cat > "$cc_wrapper" <> "$GITHUB_WORKSPACE/study/r7_memory_wall.c" - break - fi - done exec /usr/bin/${{ matrix.cc }} "\$@" EOF chmod +x "$cc_wrapper" @@ -313,14 +307,26 @@ jobs: rm -rf "$race_bundle" if RUNE_R7_REPEATS=1 CC="$cc_wrapper" AR=/usr/bin/ar \ scripts/r7-run-local.sh "$race_bundle" 2>/dev/null; then - echo "R7 evidence script certified source mutated during build" >&2 + echo "R7 evidence script accepted compiler outside fixed provenance path" >&2 exit 1 fi test ! -e "$race_bundle" - grep -Fq 'post-preflight compiler mutation' study/r7_memory_wall.c - git checkout -- study/r7_memory_wall.c rm -f "$cc_wrapper" - rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* + + snapshot_bundle="/tmp/r7-snapshot-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$snapshot_bundle" + RUNE_R7_REPEATS=1 CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$snapshot_bundle" + grep -Fxq 'build_source_origin=git_archive_recorded_revision' "$snapshot_bundle/environment.txt" + grep -Fxq 'build_source_worktree_used=false' "$snapshot_bundle/environment.txt" + snapshot_revision=$(git rev-parse HEAD) + grep -Fxq "source_snapshot_revision=$snapshot_revision" "$snapshot_bundle/environment.txt" + if awk -F '\t' '$16 == 515151 { bad=1 } END { exit bad ? 0 : 1 }' "$snapshot_bundle/observations.tsv"; then + echo "R7 snapshot capture unexpectedly used transient clock-scale mutation" >&2 + exit 1 + fi + rm -rf "$snapshot_bundle" + rm -rf "$GITHUB_WORKSPACE"/build/r7-source-* "$GITHUB_WORKSPACE"/build/r7-evidence-* replay_bundle="/tmp/r7-replay-${{ matrix.cc }}-$GITHUB_RUN_ID" rm -rf "$replay_bundle" @@ -344,7 +350,7 @@ jobs: rm -rf "$replay_bundle" "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* - grep -Fq '"$make_path" -C "$repo_root" -f Makefile "$study_target"' scripts/r7-run-local.sh + grep -Fq '"$make_path" -C "$source_snapshot" -f Makefile "$study_target"' scripts/r7-run-local.sh grep -Fq 'BUILD_DIR="$build_dir_rel"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then echo "R7 evidence script still depends on clean removing stale study output" >&2 From 02346d0d43a66c17ae6744d9cc7665e6d58df955 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:01:47 +0930 Subject: [PATCH 067/132] Define R7 immutable Git-snapshot build authority --- AGENTS.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2703da9..b65288e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -169,9 +169,14 @@ CORE_RULES: - R7_Git_routing_environment_is_cleared_before_provenance_checks - R7_Git_provenance_commands_are_anchored_to_repo_root - R7_Git_executable_is_resolved_from_fixed_provenance_PATH_and_recorded -- R7_overridable_build_PATH_must_not_control_Git_provenance +- R7_evidence_build_PATH_is_fixed_and_not_caller_overridable - R7_Git_replacement_objects_are_disabled_and_replacement_refs_are_forbidden - R7_raw_tracked_build_inputs_must_hash_equal_source_revision_without_filters +- R7_evidence_build_source_is_git_archive_of_recorded_revision +- R7_source_snapshot_contains_only_recorded_Makefile_src_include_study +- R7_source_snapshot_bytes_must_hash_equal_recorded_revision +- R7_source_snapshot_inputs_are_made_read_only_before_build +- R7_mutable_worktree_is_not_used_as_evidence_build_source - R7_source_identity_is_revalidated_after_build_and_after_measurement - R7_bundle_is_not_created_until_post_build_source_revalidation_passes - R7_ignored_untracked_files_under_src_include_study_are_forbidden @@ -192,14 +197,16 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound -- R7_CC_and_AR_must_each_name_one_resolved_executable_for_evidence_capture +- R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH +- R7_arbitrary_external_compiler_wrappers_are_forbidden_for_evidence_capture - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting -- R7_recorded_replay_build_uses_make_C_repo_root +- R7_recorded_replay_recreates_git_source_snapshot +- R7_recorded_replay_build_uses_make_C_source_snapshot - R7_recorded_replay_study_path_is_absolute - R7_recorded_replay_includes_absolute_observations_redirection - R7_command_txt_recreates_observations_file_from_any_working_directory -- R7_evidence_build_uses_recorded_sanitized_absolute_PATH_entries -- R7_make_driver_and_build_utility_paths_are_resolved_from_sanitized_PATH +- R7_evidence_build_uses_recorded_fixed_absolute_PATH_entries +- R7_make_driver_compiler_archiver_and_build_utilities_are_resolved_from_fixed_provenance_PATH - R7_evidence_build_uses_fresh_unique_BUILD_DIR_and_does_not_depend_on_make_clean - R7_fresh_BUILD_DIR_identity_includes_UTC_timestamp_and_shell_PID - R7_concurrent_evidence_builds_must_not_share_BUILD_DIR From e4896269ab498c1fff3a45bae194728680569101 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:01:50 +0930 Subject: [PATCH 068/132] Bind R7 evidence to immutable Git snapshot --- machine/r7-memory-wall-study.v1.json | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 5b4f170..cf692fb 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -194,6 +194,8 @@ "CPPFLAGS_and_CFLAGS_backslashes_preserved_exactly": true, "compiler_command_must_be_single_executable": true, "compiler_path_resolution_required": true, + "compiler_resolved_from_fixed_provenance_PATH": true, + "external_compiler_wrappers_allowed": false, "compiler_version_capture_required": true, "compiler_identity_failure_is_capture_failure": true, "memory_profile_required": true, @@ -220,6 +222,8 @@ "AR_recorded_and_bound": true, "archiver_command_must_be_single_executable": true, "archiver_path_resolution_required": true, + "archiver_resolved_from_fixed_provenance_PATH": true, + "external_archiver_wrappers_allowed": false, "archiver_version_capture_required": true, "archiver_identity_failure_is_capture_failure": true, "command_recording": "POSIX-shell-replayable-single-quoted", @@ -235,10 +239,9 @@ "build_driver_identity_capture_required": true, "build_driver_identity_failure_is_capture_failure": true, "ambient_PATH_inherited_by_evidence_build": false, - "sanitized_build_PATH_default": "/usr/bin:/bin:/usr/sbin:/sbin", - "sanitized_build_PATH_override": "RUNE_R7_BUILD_PATH", - "sanitized_build_PATH_entries_must_be_nonempty_absolute_directories": true, - "make_mkdir_rm_resolved_from_sanitized_build_PATH": true, + "evidence_build_PATH_fixed": "/usr/bin:/bin:/usr/sbin:/sbin", + "evidence_build_PATH_caller_override_allowed": false, + "make_compiler_archiver_mkdir_rm_resolved_from_fixed_provenance_PATH": true, "fresh_unique_BUILD_DIR_required": true, "fresh_BUILD_DIR_identity": "UTC timestamp + shell PID", "concurrent_evidence_builds_must_use_distinct_BUILD_DIRs": true, @@ -253,6 +256,23 @@ "clean_working_tree_required": true, "dirty_working_tree_capture_allowed": false, "source_revision_must_identify_exact_built_contents": true, + "evidence_build_source_origin": "git archive of source_revision", + "evidence_build_uses_mutable_worktree_source": false, + "source_snapshot_paths": [ + "Makefile", + "src", + "include", + "study" + ], + "source_snapshot_bytes_verified_against_revision": true, + "source_snapshot_inputs_read_only_before_build": true, + "source_snapshot_materialization_tools_resolved_from_fixed_provenance_PATH": [ + "git", + "tar", + "mkdir", + "chmod", + "rm" + ], "platform_identity_required": true, "platform_identity_command": "uname -a", "platform_identity_executable_resolved_from_fixed_provenance_PATH": true, @@ -342,7 +362,8 @@ "dynamic_loader_sanitation_recorded_in_environment": true, "dynamic_loader_sanitation_recorded_in_command": true, "dynamic_loader_sanitation_self_test": "scripts/r7-run-local.sh --self-test-dynamic-loader-env", - "replay_build_uses_make_C_repo_root": true, + "replay_recreates_source_snapshot_from_recorded_revision": true, + "replay_build_uses_make_C_source_snapshot": true, "replay_build_makefile_argument": "Makefile", "replay_study_executable_path_is_absolute": true, "replay_observations_redirection_is_recorded": true, From 0142ef8d4587d83bccc27c018d7acdc11a3b96d6 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:01:54 +0930 Subject: [PATCH 069/132] Document immutable R7 source snapshot builds --- R7-MEMORY-WALL-STUDY.md | 45 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 3441202..4668f7d 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -248,17 +248,20 @@ rejected. The script clears Git repository-routing overrides, resolves Git only fixed provenance path `/usr/bin:/bin:/usr/sbin:/sbin`, records that absolute Git executable and version, sets `GIT_NO_REPLACE_OBJECTS=1`, rejects active `refs/replace`, and anchors all provenance reads to `repo_root` with -`git -C`. The overridable `RUNE_R7_BUILD_PATH` is used only for build -utilities and cannot replace the Git executable used for provenance. Before creating the +`git -C`. Evidence builds use that same fixed system tool path; the build-tool +search path is not caller-overridable. Before creating the destination it rejects Git index flags that can hide tracked changes (`assume-unchanged` and `skip-worktree`), rejects ignored untracked files under the compiler-input trees `src/`, `include/`, and `study/`, and compares the raw bytes of every tracked Makefile/source/include/study input against the recorded revision using `git hash-object --no-filters`. It then -samples tracked, staged, and untracked Git state. The same source-identity check -is repeated immediately after the evidence build and again after the measured -execution. The bundle directory is not created until the post-build check -passes. **Any dirty or raw-byte divergent worktree is rejected.** R7 local +materializes **Makefile, src/, include/, and study/** directly from +`git archive source_revision` into a per-capture source snapshot. The extracted +bytes are checked against the recorded revision and made read-only before Make +runs. Make executes inside that snapshot, so the mutable checkout is not a +compiler input. Worktree and snapshot identity are checked again after the build +and after measurement. The bundle directory is not created until the post-build +checks pass. **Any dirty or divergent checkout/snapshot is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not claim a commit while actually building uncommitted source content. Files marked @@ -279,8 +282,9 @@ The script records: without clean filters; - a verified clean working tree, including absence of untracked files and ignored untracked files under `src/`, `include/`, and `study/`; -- resolved single-executable compiler, archiver, and build-driver paths with - successful identity/version output; +- compiler, archiver, and build-driver executables resolved from the fixed + provenance path, with successful identity/version output; arbitrary external + compiler/archiver wrappers are not accepted for evidence capture; - both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other shell-text content are preserved exactly, binding those values plus CC and AR into the build command; @@ -326,25 +330,24 @@ a `mkdir` executable resolved from the fixed provenance path, and the newly created directory is verified empty before any evidence file is written. The evidence build does **not** depend on `make clean`. Each capture receives -a fresh unique `BUILD_DIR` identified by UTC timestamp plus the shell PID, so -captures started in the same second remain isolated. A pre-existing directory -is a hard failure. The -build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, -`MAKEFILES`, and `MAKEOVERRIDES`, uses a recorded sanitized build `PATH` -(default `/usr/bin:/bin:/usr/sbin:/sbin`, explicitly overridable with -`RUNE_R7_BUILD_PATH`), resolves the build driver plus `mkdir` and `rm` -from that path, and invokes the resolved absolute build-driver path. This -prevents an ambient `PATH` shim from turning a successful clean into reuse of -a stale executable. The fresh build directory is removed through the resolved -`rm` path after the measured executable completes. +a unique source-snapshot directory and a fresh `BUILD_DIR`, both identified by +UTC timestamp plus shell PID, so concurrent captures remain isolated. Source +material is extracted from the recorded Git tree, verified, and made read-only. +The build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, +`MAKEFILES`, and `MAKEOVERRIDES`, uses the fixed +`/usr/bin:/bin:/usr/sbin:/sbin` tool path, and invokes absolute trusted Make, +compiler, archiver, and utility paths. The entire source/build snapshot is +removed after measurement. The sanitized invocation is recorded in `command.txt` using POSIX single-quote escaping. The quote serializer uses `sed` resolved from the fixed provenance path rather than ambient `PATH`, so repository paths containing apostrophes remain replayable even in a hostile shell environment. -The build recipe is pinned explicitly with the resolved absolute make path and -`-C "$repo_root" -f Makefile`. Make-facing values remain repository-relative: +The build recipe is pinned explicitly with the resolved absolute Make path and +`-C "$source_snapshot" -f Makefile`. The replay commands first recreate the +same Git-tree snapshot from `source_revision`. Make-facing values remain +snapshot-relative: the study target is `build/.../rune_r7_study` and `BUILD_DIR` is `build/...`. The shell-facing executable path remains absolute. This avoids Make parsing repository-path whitespace while preserving replayability from any From cf3ef50028b3c77c2df2b78f0357600306e76a7c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:01:57 +0930 Subject: [PATCH 070/132] Document R7 snapshot-bound evidence source --- evidence/r7/README.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index c0402b6..6e3e475 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -45,17 +45,20 @@ they can hide tracked modifications from ordinary status checks. Git routing overrides are cleared and all provenance reads are rooted at the repository. Git itself is resolved from a fixed provenance path (`/usr/bin:/bin:/usr/sbin:/sbin`) and its absolute path/version are recorded; -the overridable build path cannot substitute the Git executable. Git -replacement objects are disabled, active replacement refs are rejected, and -tracked Makefile/source/include/study files are raw-hashed with filters disabled -and must match their blobs at `source_revision`. That identity is checked -before the build, immediately after the build, and again after measurement; the -bundle directory is not created until the post-build check succeeds. Ignored untracked files under +the evidence build path is fixed and cannot substitute the Git/toolchain +executables. Git replacement objects are disabled, active replacement refs are +rejected, and tracked Makefile/source/include/study files are raw-hashed with +filters disabled and must match their blobs at `source_revision`. The actual +evidence build does not compile those worktree files: it extracts +`Makefile`, `src/`, `include/`, and `study/` from +`git archive source_revision` into a per-capture snapshot, verifies the +snapshot bytes, and marks the source inputs read-only before compiling. Ignored untracked files under `src/`, `include/`, or `study/` are also forbidden because they can satisfy compiler includes without appearing in ordinary status output. -For evidence capture, CC and AR must each identify one executable; compound -commands are rejected. Ambient compiler search variables (CPATH, +For evidence capture, CC and AR must each identify one executable available +from the fixed provenance path; arbitrary external compiler/archiver wrappers +and compound commands are rejected. Ambient compiler search variables (CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH, COMPILER_PATH, LIBRARY_PATH, GCC_EXEC_PREFIX) are cleared; intentional include paths belong in the recorded CPPFLAGS. Dynamic-loader injection/search variables @@ -69,17 +72,18 @@ than ambient `PATH`. The getconf fallback requires both a nonzero numeric physical page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for -the evidence build. Ambient `PATH` is replaced by a recorded sanitized build -path (default `/usr/bin:/bin:/usr/sbin:/sbin`), from which make/mkdir/rm are -resolved. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving +the evidence build. Ambient `PATH` is replaced by the fixed recorded +`/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build +utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving backslashes exactly. Each capture builds into a fresh unique `BUILD_DIR` keyed by UTC timestamp plus the shell PID and never relies on `make clean`, so concurrent captures do not share objects/executables and a fake ambient `rm` cannot preserve and certify a stale study executable. -The evidence build also uses the tracked repository Makefile explicitly via -the resolved absolute make path with `-C -f Makefile`. The Make target +The evidence build uses the Makefile extracted from the recorded Git revision +and invokes the resolved absolute Make path with +`-C -f Makefile`. The Make target and `BUILD_DIR` passed into Make are repository-relative so repository paths containing spaces remain parseable; the executable used by the shell remains absolute. The bundle records the build-driver identity and Makefile Git blob From 148640023cc12f192b78161218e8c9ebd1a0cdcf Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:02:40 +0930 Subject: [PATCH 071/132] Restore snapshot permissions only for cleanup --- scripts/r7-run-local.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 4d1c915..0cae743 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -409,6 +409,10 @@ materialize_source_snapshot() cleanup_snapshot() { + if [ -d "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" || + fail "could not restore snapshot write permission for cleanup" + fi "$provenance_rm_path" -rf "$source_snapshot" || fail "could not remove source snapshot: $source_snapshot" [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || @@ -745,6 +749,10 @@ observations_path="$out_abs/observations.tsv" printf " > " shell_quote "$observations_path" printf '\n' + shell_quote "$chmod_path" + printf " -R u+w " + shell_quote "$source_snapshot" + printf '\n' shell_quote "$provenance_rm_path" printf " -rf " shell_quote "$source_snapshot" From 0094465f4aad49f981707e50f6738e3299cc361a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:29:38 +0930 Subject: [PATCH 072/132] Stage R7 bundles and publish only on success --- scripts/r7-run-local.sh | 63 ++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 0cae743..b8bbd72 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -109,13 +109,15 @@ chmod_path=$(resolve_provenance_tool chmod) || fail "chmod not found in fixed provenance path" provenance_rm_path=$(resolve_provenance_tool rm) || fail "rm not found in fixed provenance path" +mv_path=$(resolve_provenance_tool mv) || + fail "mv not found in fixed provenance path" date_path=$(resolve_provenance_tool date) || fail "date not found in fixed provenance path" dirname_path=$(resolve_provenance_tool dirname) || fail "dirname not found in fixed provenance path" basename_path=$(resolve_provenance_tool basename) || fail "basename not found in fixed provenance path" -for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path" "$date_path" "$dirname_path" "$basename_path"; do +for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path" "$mv_path" "$date_path" "$dirname_path" "$basename_path"; do case "$provenance_tool_path" in /*) ;; *) fail "provenance tool path is not absolute: $provenance_tool_path" ;; @@ -565,12 +567,28 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -source_snapshot_rel="build/r7-source-$stamp-$$" +source_snapshot_rel="build/r7-source-$stamp-$" source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$stamp-$$" +build_dir_rel="build/r7-evidence-$stamp-$" build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$source_snapshot/$study_target" +bundle_stage_rel="build/r7-bundle-stage-$stamp-$" +bundle_stage="$repo_root/$bundle_stage_rel" +bundle_published=false + +cleanup_capture_state() +{ + if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : + "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : + fi + if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then + "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : + fi +} + +trap cleanup_capture_state 0 1 2 3 15 if [ "$fresh_build_self_test" = true ]; then materialize_source_snapshot @@ -586,16 +604,18 @@ build_study validate_snapshot_identity validate_source_identity -"$bundle_mkdir_path" "$out_dir" || - fail "could not create immutable evidence destination: $out_dir" +[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || + fail "bundle staging destination already exists: $bundle_stage" +"$bundle_mkdir_path" "$bundle_stage" || + fail "could not create bundle staging directory: $bundle_stage" -set -- "$out_dir"/* "$out_dir"/.[!.]* "$out_dir"/..?* +set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* for bundle_entry in "$@"; do [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue - fail "new evidence destination is not empty: $out_dir" + fail "new bundle staging directory is not empty: $bundle_stage" done -observations_path="$out_abs/observations.tsv" +observations_path="$bundle_stage/observations.tsv" { echo "contract=rune.r7.environment.v1" @@ -615,6 +635,9 @@ observations_path="$out_abs/observations.tsv" printf 'tar_resolved=%s\n' "$tar_path" printf 'chmod_resolved=%s\n' "$chmod_path" printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'mv_resolved=%s\n' "$mv_path" + printf 'bundle_stage=%s\n' "$bundle_stage" + printf '%s\n' "bundle_publish_mode=atomic_rename_after_success" printf 'date_resolved=%s\n' "$date_path" printf 'dirname_resolved=%s\n' "$dirname_path" printf 'basename_resolved=%s\n' "$basename_path" @@ -657,7 +680,7 @@ observations_path="$out_abs/observations.tsv" echo "cpu_model=$cpu_model" fi printf '%s\n' "$memory_profile" -} > "$out_dir/environment.txt" +} > "$bundle_stage/environment.txt" { printf 'git_path=%s\n' "$git_path" @@ -668,6 +691,7 @@ observations_path="$out_abs/observations.tsv" printf 'tar_path=%s\n' "$tar_path" printf 'chmod_path=%s\n' "$chmod_path" printf 'provenance_rm_path=%s\n' "$provenance_rm_path" + printf 'mv_path=%s\n' "$mv_path" printf 'date_path=%s\n' "$date_path" printf 'dirname_path=%s\n' "$dirname_path" printf 'basename_path=%s\n' "$basename_path" @@ -680,7 +704,7 @@ observations_path="$out_abs/observations.tsv" printf '%s\n' "$archiver_version" echo "build_driver_path=$make_path" printf '%s\n' "$make_version" -} > "$out_dir/compiler.txt" +} > "$bundle_stage/compiler.txt" { printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" @@ -747,7 +771,7 @@ observations_path="$out_abs/observations.tsv" printf " --profile local --repeats " shell_quote "$repeats" printf " > " - shell_quote "$observations_path" + shell_quote "$out_abs/observations.tsv" printf '\n' shell_quote "$chmod_path" printf " -R u+w " @@ -757,7 +781,7 @@ observations_path="$out_abs/observations.tsv" printf " -rf " shell_quote "$source_snapshot" printf '\n' -} > "$out_dir/command.txt" +} > "$bundle_stage/command.txt" "$study_executable" --profile local --repeats "$repeats" \ > "$observations_path" @@ -769,7 +793,7 @@ cleanup_snapshot case "$hash_mode" in sha256sum) ( - cd "$out_dir" + cd "$bundle_stage" "$hash_path" \ environment.txt \ compiler.txt \ @@ -780,7 +804,7 @@ case "$hash_mode" in ;; shasum) ( - cd "$out_dir" + cd "$bundle_stage" "$hash_path" -a 256 \ environment.txt \ compiler.txt \ @@ -794,4 +818,15 @@ case "$hash_mode" in ;; esac +validate_source_identity + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination appeared during capture; refusing publish: $out_dir" +fi + +"$mv_path" "$bundle_stage" "$out_dir" || + fail "could not publish completed evidence bundle: $out_dir" +bundle_published=true +trap - 0 1 2 3 15 + echo "R7 evidence bundle: $out_dir" From b5b738c1090ee4a0cffe023947b7800a9cfed8f0 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:30:41 +0930 Subject: [PATCH 073/132] Fix R7 staged capture uniqueness --- scripts/r7-run-local.sh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index b8bbd72..5d72100 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -567,16 +567,14 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -source_snapshot_rel="build/r7-source-$stamp-$" +source_snapshot_rel="build/r7-source-$stamp-$$" source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$stamp-$" +build_dir_rel="build/r7-evidence-$stamp-$$" build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$stamp-$" +bundle_stage_rel="build/r7-bundle-stage-$stamp-$$" bundle_stage="$repo_root/$bundle_stage_rel" -bundle_published=false - cleanup_capture_state() { if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then @@ -826,7 +824,6 @@ fi "$mv_path" "$bundle_stage" "$out_dir" || fail "could not publish completed evidence bundle: $out_dir" -bundle_published=true trap - 0 1 2 3 15 echo "R7 evidence bundle: $out_dir" From fc1f4bd7a021e715bba764d8a42b748fd2b77169 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:31:10 +0930 Subject: [PATCH 074/132] Test R7 failure cleanup and in-repo publish --- .github/workflows/c99.yml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index d0521fd..7023371 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -194,7 +194,7 @@ jobs: fresh_b=$! wait "$fresh_a" wait "$fresh_b" - test -z "$(find build -maxdepth 1 -type d \( -name 'r7-evidence-*' -o -name 'r7-source-*' \) -print -quit)" + test -z "$(find build -maxdepth 1 -type d \( -name 'r7-evidence-*' -o -name 'r7-source-*' -o -name 'r7-bundle-stage-*' \) -print -quit)" rm -rf "$fakebin" rm /tmp/r7-build-tools.txt /tmp/r7-fresh-a.log /tmp/r7-fresh-b.log @@ -350,6 +350,35 @@ jobs: rm -rf "$replay_bundle" "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* + lowmem_bundle="/tmp/r7-lowmem-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$lowmem_bundle" + if ( + ulimit -v 120000 + RUNE_R7_REPEATS=1 CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$lowmem_bundle" >/tmp/r7-lowmem-${{ matrix.cc }}.log 2>&1 + ); then + echo "R7 low-memory capture unexpectedly succeeded" >&2 + exit 1 + fi + test ! -e "$lowmem_bundle" + test -z "$(find build -maxdepth 1 -type d \( -name 'r7-source-*' -o -name 'r7-bundle-stage-*' \) -print -quit)" + rm -f /tmp/r7-lowmem-${{ matrix.cc }}.log + + default_bundle="evidence/r7/ci-default-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$default_bundle" + RUNE_R7_REPEATS=1 CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$default_bundle" + test -s "$default_bundle/observations.tsv" + test -s "$default_bundle/SHA256SUMS" + grep -Fxq 'bundle_publish_mode=atomic_rename_after_success' "$default_bundle/environment.txt" + ( + cd "$default_bundle" + /usr/bin/sha256sum -c SHA256SUMS + ) + test -z "$(find build -maxdepth 1 -type d \( -name 'r7-source-*' -o -name 'r7-bundle-stage-*' \) -print -quit)" + rm -rf "$default_bundle" + test -z "$(git status --porcelain --untracked-files=all)" + grep -Fq '"$make_path" -C "$source_snapshot" -f Makefile "$study_target"' scripts/r7-run-local.sh grep -Fq 'BUILD_DIR="$build_dir_rel"' scripts/r7-run-local.sh if grep -Fq ' clean build/rune_r7_study' scripts/r7-run-local.sh; then From 755fad71a0e840bcd4df52c115f0a5c57fc624e2 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:31:56 +0930 Subject: [PATCH 075/132] Describe R7 staged publication precisely --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 5d72100..bf55f99 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -635,7 +635,7 @@ observations_path="$bundle_stage/observations.tsv" printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" printf 'mv_resolved=%s\n' "$mv_path" printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=atomic_rename_after_success" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" printf 'date_resolved=%s\n' "$date_path" printf 'dirname_resolved=%s\n' "$dirname_path" printf 'basename_resolved=%s\n' "$basename_path" From d724f5c9cd1bb490f8341c55b625e5c88ede39f2 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:32:00 +0930 Subject: [PATCH 076/132] Match R7 staged publish contract in CI --- .github/workflows/c99.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 7023371..61a47e8 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -370,7 +370,7 @@ jobs: scripts/r7-run-local.sh "$default_bundle" test -s "$default_bundle/observations.tsv" test -s "$default_bundle/SHA256SUMS" - grep -Fxq 'bundle_publish_mode=atomic_rename_after_success' "$default_bundle/environment.txt" + grep -Fxq 'bundle_publish_mode=publish_after_success_via_trusted_mv' "$default_bundle/environment.txt" ( cd "$default_bundle" /usr/bin/sha256sum -c SHA256SUMS From 639d38cb4519817ed4c0d2c6bb4d3cb8d1729b9d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:32:03 +0930 Subject: [PATCH 077/132] Define staged R7 publication invariants --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index b65288e..402a3a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,6 +160,10 @@ CORE_RULES: - R7_all_eight_declared_microtiles_execute_for_every_valid_working_set - R7_microtile_may_exceed_logical_input_and_process_only_available_items - R7_evidence_destination_must_be_new_and_immutable +- R7_bundle_files_are_staged_under_ignored_build_until_capture_finalization +- R7_failed_capture_removes_bundle_stage_and_source_snapshot +- R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 +- R7_default_evidence_r7_destination_must_finalize_without_self_dirtying - R7_repeats_are_validated_before_bundle_creation - R7_bundle_directory_is_created_with_fixed_provenance_mkdir_and_verified_empty - R7_dirty_state_includes_untracked_files_and_is_sampled_before_bundle_creation From f27765dcafd54fe2dc46212196705e7cea55514a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:32:07 +0930 Subject: [PATCH 078/132] Bind R7 staged publication and failure cleanup --- machine/r7-memory-wall-study.v1.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index cf692fb..42fc467 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -183,6 +183,15 @@ "evidence_class_required": true, "destination_must_not_preexist": true, "overwrite_existing_bundle_allowed": false, + "bundle_files_staged_under_ignored_build_until_finalization": true, + "bundle_stage_removed_on_capture_failure": true, + "source_snapshot_removed_on_capture_failure": true, + "requested_destination_created_only_by_final_publish": true, + "publish_requires_successful_measurement": true, + "publish_requires_final_source_revalidation": true, + "publish_requires_SHA256SUMS": true, + "publish_uses_trusted_mv": true, + "default_in_repo_evidence_destination_supported": true, "repeats_validated_before_destination_creation": true, "bundle_directory_created_with_fixed_provenance_mkdir": true, "new_bundle_directory_must_be_empty_before_metadata_write": true, @@ -326,7 +335,8 @@ "raw_worktree_bytes_must_equal_revision_blobs": true, "source_identity_revalidated_after_build": true, "source_identity_revalidated_after_measurement": true, - "bundle_creation_occurs_only_after_post_build_source_revalidation": true, + "bundle_staging_occurs_only_after_post_build_source_revalidation": true, + "requested_destination_publish_occurs_after_post_measurement_source_revalidation": true, "ignored_untracked_compiler_inputs_allowed": false, "ignored_compiler_input_trees": [ "src", From bd4359616a7c3b3d1464a1ffb1e346f2fadc4ffe Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:32:11 +0930 Subject: [PATCH 079/132] Document staged R7 evidence publication --- R7-MEMORY-WALL-STUDY.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 4668f7d..4ced7be 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -241,8 +241,11 @@ or: RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ -The script creates an **immutable new destination** and refuses to overwrite an -existing bundle. Destinations may not resolve inside, or lexically route +The script publishes an **immutable new destination** and refuses to overwrite an +existing bundle. During capture, bundle files are written only to a unique +staging directory under the ignored repository `build/` tree. The requested +destination is not created until measurement, final source/snapshot validation, +snapshot cleanup, and SHA-256 finalization have all succeeded. Destinations may not resolve inside, or lexically route through, the repository `build/` tree, and parent-directory traversal is rejected. The script clears Git repository-routing overrides, resolves Git only from the fixed provenance path `/usr/bin:/bin:/usr/sbin:/sbin`, records that absolute @@ -260,8 +263,9 @@ materializes **Makefile, src/, include/, and study/** directly from bytes are checked against the recorded revision and made read-only before Make runs. Make executes inside that snapshot, so the mutable checkout is not a compiler input. Worktree and snapshot identity are checked again after the build -and after measurement. The bundle directory is not created until the post-build -checks pass. **Any dirty or divergent checkout/snapshot is rejected.** R7 local +and after measurement. The publish destination is not created during the build or measurement. An +EXIT/signal cleanup trap removes the source snapshot and staged bundle on +failure, including measurement failures such as resource exhaustion. **Any dirty or divergent checkout/snapshot is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not claim a commit while actually building uncommitted source content. Files marked @@ -325,9 +329,12 @@ Evidence destinations resolving inside or lexically routing through `build/` are rejected before bundle creation, including symlink routes whose lexical parent would be removed or replaced by build activity. Parent-directory traversal in the requested destination is also rejected. `RUNE_R7_REPEATS` -is validated as 1..100 before the destination is reserved. Bundle creation uses -a `mkdir` executable resolved from the fixed provenance path, and the newly -created directory is verified empty before any evidence file is written. +is validated as 1..100 before the destination is reserved. The staging directory is created with a `mkdir` executable resolved from the +fixed provenance path and verified empty before metadata is written. After the +staged bundle is checksummed and the final worktree validation passes, trusted +`mv` publishes it to the requested destination. This permits the documented +default `evidence/r7/local-...` destination without the capture treating its +own output as an untracked source mutation. The evidence build does **not** depend on `make clean`. Each capture receives a unique source-snapshot directory and a fresh `BUILD_DIR`, both identified by From a214ded24809651c6d6aa1cfc9c4bf332a5bcfb9 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:32:14 +0930 Subject: [PATCH 080/132] Document R7 failure cleanup and delayed publish --- evidence/r7/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 6e3e475..b373bf7 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -16,7 +16,10 @@ RUNE_R7_REPEATS=5 CC=cc ./scripts/r7-run-local.sh evidence/r7/my-host ~~~ The destination must not already exist; evidence bundles are immutable capture -records and are never overwritten. Destinations that resolve inside or +records and are never overwritten. Capture output is first staged under the +ignored repository `build/` tree. The requested destination is published only +after successful measurement, final provenance validation, snapshot cleanup, +and SHA-256 generation. Destinations that resolve inside or lexically route through the repository `build/` tree are rejected, and parent-directory traversal is not accepted. `RUNE_R7_REPEATS` must be an integer from 1 through 100 and is rejected before destination creation. The @@ -38,8 +41,10 @@ A bundle contains: whose absolute path/identity are recorded in the bundle. Evidence capture requires a clean Git working tree. Tracked, staged, or -untracked changes cause a fail-closed exit before the bundle directory is -created, so source_revision identifies the exact contents built. +untracked changes cause a fail-closed exit before publication, so +`source_revision` identifies the exact contents built. The requested +`evidence/r7/...` path is absent during the final cleanliness checks and is +therefore not mistaken for a source mutation. `assume-unchanged` and `skip-worktree` index flags are forbidden because they can hide tracked modifications from ordinary status checks. Git routing overrides are cleared and all provenance reads are rooted at the repository. @@ -95,6 +100,10 @@ with a fixed-provenance `sed`, so paths containing apostrophes remain valid. `command.txt` is replayable from outside the repository while recreating the captured output artifact. +If measurement or finalization fails, an exit trap removes the staged bundle +and temporary source snapshot; no partial requested destination is retained. +This keeps the destination reusable after failures such as memory exhaustion. + Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. From 882944c75e721e2231f2507d808a822b9256e7fb Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:33:11 +0930 Subject: [PATCH 081/132] Restore raw source after clean-filter CI probe --- .github/workflows/c99.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 61a47e8..c5f3f6c 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -162,6 +162,9 @@ jobs: git config --unset-all filter.r7-clean-probe.clean git config --unset-all filter.r7-clean-probe.smudge sed -i '/r7-clean-probe/d' .git/info/attributes + git show HEAD:study/r7_memory_wall.c > study/r7_memory_wall.c + git update-index --refresh + test -z "$(git status --porcelain --untracked-files=all)" CPATH=/tmp/r7-hostile-cpath C_INCLUDE_PATH=/tmp/r7-hostile-c-include \ CPLUS_INCLUDE_PATH=/tmp/r7-hostile-cplus \ From 74497ca4b44fe0ac4012fd069acf5e06c702f3a8 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:33:54 +0930 Subject: [PATCH 082/132] Use status as clean-filter teardown assertion --- .github/workflows/c99.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index c5f3f6c..44dd3ac 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -163,7 +163,6 @@ jobs: git config --unset-all filter.r7-clean-probe.smudge sed -i '/r7-clean-probe/d' .git/info/attributes git show HEAD:study/r7_memory_wall.c > study/r7_memory_wall.c - git update-index --refresh test -z "$(git status --porcelain --untracked-files=all)" CPATH=/tmp/r7-hostile-cpath C_INCLUDE_PATH=/tmp/r7-hostile-c-include \ From 128c0f14a403046f7587eccb87556b3a05de442a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:34:40 +0930 Subject: [PATCH 083/132] Remove clean filter before resetting CI worktree --- .github/workflows/c99.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 44dd3ac..8644791 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -158,11 +158,10 @@ jobs: exit 1 fi test ! -e evidence/r7/ci-clean-filter-probe - git reset --hard HEAD git config --unset-all filter.r7-clean-probe.clean git config --unset-all filter.r7-clean-probe.smudge sed -i '/r7-clean-probe/d' .git/info/attributes - git show HEAD:study/r7_memory_wall.c > study/r7_memory_wall.c + git reset --hard HEAD test -z "$(git status --porcelain --untracked-files=all)" CPATH=/tmp/r7-hostile-cpath C_INCLUDE_PATH=/tmp/r7-hostile-c-include \ From fce55fc5c60d99bbf2002b8e5af1a35c7288a590 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:12:23 +0930 Subject: [PATCH 084/132] Harden R7 tool paths replay tar and publication --- scripts/r7-run-local.sh | 118 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index bf55f99..5613dd5 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -43,6 +43,8 @@ sanitize_capture_environment() unset DYLD_FALLBACK_FRAMEWORK_PATH unset LIBPATH unset SHLIB_PATH + + unset TAR_OPTIONS } sanitize_capture_environment @@ -82,6 +84,35 @@ resolve_build_tool() PATH="$build_path" command -v "$1" } +canonicalize_existing_path() +{ + canonical_path=$1 + case "$canonical_path" in + /*) ;; + *) return 1 ;; + esac + + canonical_hops=0 + while [ -L "$canonical_path" ]; do + canonical_hops=$((canonical_hops + 1)) + [ "$canonical_hops" -le 40 ] || return 1 + canonical_link=$("$readlink_path" "$canonical_path") || return 1 + case "$canonical_link" in + /*) canonical_path=$canonical_link ;; + *) canonical_path=${canonical_path%/*}/$canonical_link ;; + esac + canonical_parent=${canonical_path%/*} + canonical_base=${canonical_path##*/} + canonical_parent=$(CDPATH= cd -- "$canonical_parent" && pwd -P) || return 1 + canonical_path=$canonical_parent/$canonical_base + done + + canonical_parent=${canonical_path%/*} + canonical_base=${canonical_path##*/} + canonical_parent=$(CDPATH= cd -- "$canonical_parent" && pwd -P) || return 1 + printf '%s/%s\n' "$canonical_parent" "$canonical_base" +} + validate_build_path git_path=$(resolve_provenance_tool git) || @@ -111,13 +142,19 @@ provenance_rm_path=$(resolve_provenance_tool rm) || fail "rm not found in fixed provenance path" mv_path=$(resolve_provenance_tool mv) || fail "mv not found in fixed provenance path" +cp_path=$(resolve_provenance_tool cp) || + fail "cp not found in fixed provenance path" +find_path=$(resolve_provenance_tool find) || + fail "find not found in fixed provenance path" +readlink_path=$(resolve_provenance_tool readlink) || + fail "readlink not found in fixed provenance path" date_path=$(resolve_provenance_tool date) || fail "date not found in fixed provenance path" dirname_path=$(resolve_provenance_tool dirname) || fail "dirname not found in fixed provenance path" basename_path=$(resolve_provenance_tool basename) || fail "basename not found in fixed provenance path" -for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path" "$mv_path" "$date_path" "$dirname_path" "$basename_path"; do +for provenance_tool_path in "$sed_path" "$awk_path" "$bundle_mkdir_path" "$tar_path" "$chmod_path" "$provenance_rm_path" "$mv_path" "$cp_path" "$find_path" "$readlink_path" "$date_path" "$dirname_path" "$basename_path"; do case "$provenance_tool_path" in /*) ;; *) fail "provenance tool path is not absolute: $provenance_tool_path" ;; @@ -360,6 +397,31 @@ R7_TRACKED_INPUTS validate_source_identity +validate_snapshot_source_entries() +{ + snapshot_entries=$("$find_path" "$source_snapshot" \( -type f -o -type l \) -print) || + fail "could not enumerate source snapshot entries" + + while IFS= read -r snapshot_entry; do + [ -n "$snapshot_entry" ] || continue + snapshot_rel=${snapshot_entry#"$source_snapshot"/} + [ "$snapshot_rel" != "$snapshot_entry" ] || + fail "snapshot entry escaped snapshot root: $snapshot_entry" + [ ! -L "$snapshot_entry" ] || + fail "source snapshot symlink is forbidden: $snapshot_rel" + case " +$tracked_inputs +" in + *" +$snapshot_rel +"*) ;; + *) fail "unexpected source snapshot entry: $snapshot_rel" ;; + esac + done <&1) || ar_path=$(resolve_provenance_tool "$ar_name") || fail "archiver not found in fixed provenance path: $ar_name" +ar_path=$(canonicalize_existing_path "$ar_path") || + fail "could not canonicalize archiver path: $ar_path" case "$ar_path" in /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; *) fail "archiver escaped fixed provenance path: $ar_path" ;; @@ -458,6 +525,8 @@ fi make_path=$(resolve_provenance_tool "$make_name") || fail "build driver not found in fixed provenance path: $make_name" +make_path=$(canonicalize_existing_path "$make_path") || + fail "could not canonicalize build-driver path: $make_path" case "$make_path" in /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; *) fail "build-driver escaped fixed provenance path: $make_path" ;; @@ -573,8 +642,9 @@ build_dir_rel="build/r7-evidence-$stamp-$$" build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$stamp-$$" +bundle_stage_rel="build/r7-bundle-stage-$stamp-$" bundle_stage="$repo_root/$bundle_stage_rel" +publish_stage="$out_parent_abs/.r7-publish-$stamp-$" cleanup_capture_state() { if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then @@ -584,6 +654,9 @@ cleanup_capture_state() if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : fi + if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then + "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : + fi } trap cleanup_capture_state 0 1 2 3 15 @@ -634,6 +707,9 @@ observations_path="$bundle_stage/observations.tsv" printf 'chmod_resolved=%s\n' "$chmod_path" printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" printf 'mv_resolved=%s\n' "$mv_path" + printf 'cp_resolved=%s\n' "$cp_path" + printf 'find_resolved=%s\n' "$find_path" + printf 'readlink_resolved=%s\n' "$readlink_path" printf 'bundle_stage=%s\n' "$bundle_stage" printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" printf 'date_resolved=%s\n' "$date_path" @@ -690,6 +766,9 @@ observations_path="$bundle_stage/observations.tsv" printf 'chmod_path=%s\n' "$chmod_path" printf 'provenance_rm_path=%s\n' "$provenance_rm_path" printf 'mv_path=%s\n' "$mv_path" + printf 'cp_path=%s\n' "$cp_path" + printf 'find_path=%s\n' "$find_path" + printf 'readlink_path=%s\n' "$readlink_path" printf 'date_path=%s\n' "$date_path" printf 'dirname_path=%s\n' "$dirname_path" printf 'basename_path=%s\n' "$basename_path" @@ -705,10 +784,12 @@ observations_path="$bundle_stage/observations.tsv" } > "$bundle_stage/compiler.txt" { + printf "set -eu\n" printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" printf "export GIT_NO_REPLACE_OBJECTS=1\n" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + printf "unset TAR_OPTIONS\n" shell_quote "$bundle_mkdir_path" printf " -p " shell_quote "$repo_root/build" @@ -821,9 +902,38 @@ validate_source_identity if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination appeared during capture; refusing publish: $out_dir" fi +[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || + fail "publish staging destination already exists: $publish_stage" + +"$bundle_mkdir_path" "$publish_stage" || + fail "could not create sibling publish staging directory" +"$cp_path" -R "$bundle_stage/." "$publish_stage/" || + fail "could not copy completed bundle to destination filesystem" + +case "$hash_mode" in + sha256sum) + ( + cd "$publish_stage" + "$hash_path" -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; + shasum) + ( + cd "$publish_stage" + "$hash_path" -a 256 -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; +esac + +"$provenance_rm_path" -rf "$bundle_stage" || + fail "could not remove repository bundle staging directory" + +if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then + fail "evidence destination appeared during publish; refusing rename: $out_abs" +fi -"$mv_path" "$bundle_stage" "$out_dir" || - fail "could not publish completed evidence bundle: $out_dir" +"$mv_path" "$publish_stage" "$out_abs" || + fail "could not rename completed sibling staging bundle into place" trap - 0 1 2 3 15 echo "R7 evidence bundle: $out_dir" From 579b73cee8e05c9e5c914848692339b09233ac88 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:12:41 +0930 Subject: [PATCH 085/132] Reject unrepresentable R7 clock deltas safely --- study/r7_memory_wall.c | 76 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index 6d11c98..f55ecb0 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -148,8 +148,7 @@ static int r7_ticks_between( uint64_t *out ) { - clock_t delta; - uint64_t converted; + uintmax_t converted; if (out == NULL) { return 0; @@ -159,14 +158,79 @@ static int r7_ticks_between( return 0; } - delta = end - start; + if ((clock_t)-1 < (clock_t)0) { + intmax_t signed_start; + intmax_t signed_end; - converted = (uint64_t)delta; - if ((clock_t)converted != delta) { + signed_start = (intmax_t)start; + signed_end = (intmax_t)end; + if ((clock_t)signed_start != start || + (clock_t)signed_end != end) { + return 0; + } + + if (signed_start < 0) { + uintmax_t start_magnitude; + + start_magnitude = + (uintmax_t)(-(signed_start + INTMAX_C(1))) + + UINTMAX_C(1); + + if (signed_end < 0) { + uintmax_t end_magnitude; + + end_magnitude = + (uintmax_t)(-(signed_end + INTMAX_C(1))) + + UINTMAX_C(1); + if (start_magnitude < end_magnitude) { + return 0; + } + converted = start_magnitude - end_magnitude; + } else { + uintmax_t unsigned_end; + + unsigned_end = (uintmax_t)signed_end; + if (UINTMAX_MAX - start_magnitude < unsigned_end) { + return 0; + } + converted = start_magnitude + unsigned_end; + } + } else { + converted = + (uintmax_t)signed_end - + (uintmax_t)signed_start; + } + } else { + uintmax_t unsigned_start; + uintmax_t unsigned_end; + + unsigned_start = (uintmax_t)start; + unsigned_end = (uintmax_t)end; + if ((clock_t)unsigned_start != start || + (clock_t)unsigned_end != end || + unsigned_end < unsigned_start) { + return 0; + } + converted = unsigned_end - unsigned_start; + } + + if (converted > UINT64_MAX) { + return 0; + } + + if ((clock_t)-1 < (clock_t)0) { + clock_t roundtrip; + + roundtrip = (clock_t)converted; + if (roundtrip < (clock_t)0 || + (uintmax_t)roundtrip != converted) { + return 0; + } + } else if ((uintmax_t)(clock_t)converted != converted) { return 0; } - *out = converted; + *out = (uint64_t)converted; return 1; } From bbdd406ad04b864c2154cd978845576b28fd38b4 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:13:35 +0930 Subject: [PATCH 086/132] Add deterministic R7 evidence regressions --- tests/test_r7_run_local.sh | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/test_r7_run_local.sh diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh new file mode 100644 index 0000000..7aba593 --- /dev/null +++ b/tests/test_r7_run_local.sh @@ -0,0 +1,136 @@ +#!/bin/sh +set -eu + +fail() +{ + echo "R7 evidence regression: $*" >&2 + exit 1 +} + +repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) +cd "$repo_root" + +cc_name=${CC:-cc} +ar_name=${AR:-ar} + +case "$cc_name" in + gcc|clang) system_cc="/usr/bin/$cc_name" ;; + /usr/bin/gcc|/usr/bin/clang) system_cc=$cc_name ;; + *) fail "CI regression expects gcc or clang from /usr/bin: $cc_name" ;; +esac + +case "$ar_name" in + ar) system_ar=/usr/bin/ar ;; + /usr/bin/ar) system_ar=$ar_name ;; + *) fail "CI regression expects /usr/bin/ar: $ar_name" ;; +esac + +tmp_root="/tmp/rune-r7-evidence-regression-$$" +mkdir -p "$tmp_root" + +cleanup() +{ + rm -rf "$tmp_root" + rm -f /tmp/r7-reg-cc-$$ /tmp/r7-reg-ar-$$ /tmp/r7-reg-make-$$ + rm -f /tmp/r7-tar-hook-$$ /tmp/r7-tar-hook-ran-$$ + rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* +} +trap cleanup 0 1 2 3 15 + +expect_capture_failure() +{ + label=$1 + shift + dest="$tmp_root/$label" + rm -rf "$dest" + if "$@" "$dest" >/dev/null 2>&1; then + fail "$label unexpectedly succeeded" + fi + [ ! -e "$dest" ] || fail "$label left a requested destination" +} + +# Canonical-path regression: lexical /usr/bin prefixes must not authorize /tmp. +cat > /tmp/r7-reg-cc-$$ < /tmp/r7-reg-ar-$$ < /tmp/r7-reg-make-$$ <<'EOF' +#!/bin/sh +exec /usr/bin/make "$@" +EOF +chmod +x /tmp/r7-reg-cc-$$ /tmp/r7-reg-ar-$$ /tmp/r7-reg-make-$$ + +expect_capture_failure canonical-cc env RUNE_R7_REPEATS=1 CC="/usr/bin/../../tmp/r7-reg-cc-$$" AR="$system_ar" scripts/r7-run-local.sh +expect_capture_failure canonical-ar env RUNE_R7_REPEATS=1 CC="$system_cc" AR="/usr/bin/../../tmp/r7-reg-ar-$$" scripts/r7-run-local.sh +expect_capture_failure canonical-make env RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" MAKE="/usr/bin/../../tmp/r7-reg-make-$$" scripts/r7-run-local.sh + +# Replay must fail immediately and preserve observations when snapshot creation fails. +replay_bundle="$tmp_root/replay" +RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$replay_bundle" >/dev/null +snapshot_path=$(/usr/bin/sed -n 's/^source_snapshot=//p' "$replay_bundle/environment.txt") +[ -n "$snapshot_path" ] || fail "replay bundle did not record source_snapshot" +before_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') +printf 'block replay snapshot\n' > "$snapshot_path" +if (cd /tmp && /bin/sh "$replay_bundle/command.txt" >/dev/null 2>&1); then + fail "replay ignored an early snapshot-creation failure" +fi +after_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') +[ "$before_hash" = "$after_hash" ] || + fail "failed replay modified observations.tsv" +rm -f "$snapshot_path" + +# TAR_OPTIONS must be cleared for capture and replay; hook execution is forbidden. +cat > /tmp/r7-tar-hook-$$ < /tmp/r7-tar-hook-ran-$$ +EOF +chmod +x /tmp/r7-tar-hook-$$ +tar_bundle="$tmp_root/tar" +TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$$" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$tar_bundle" >/dev/null +[ ! -e /tmp/r7-tar-hook-ran-$$ ] || + fail "TAR_OPTIONS hook executed during capture" +TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$$" /bin/sh "$tar_bundle/command.txt" >/dev/null +[ ! -e /tmp/r7-tar-hook-ran-$$ ] || + fail "TAR_OPTIONS hook executed during replay" +if /usr/bin/awk -F '\t' '$16 == 616161 { bad=1 } END { exit bad ? 0 : 1 }' "$tar_bundle/observations.tsv"; then + fail "tar injection changed the study clock scale" +fi + +# Failed destination-filesystem copy must never create the immutable final path. +[ -d /dev/shm ] && [ -w /dev/shm ] || + fail "/dev/shm is required for deterministic publication regression" +publish_parent="/dev/shm/r7-publish-regression-$$" +publish_dest="$publish_parent/evidence" +fill_file="$publish_parent/fill" +mkdir -p "$publish_parent" +available_kb=$(/usr/bin/df -Pk "$publish_parent" | /usr/bin/awk 'NR == 2 { print $4 }') +case "$available_kb" in + ''|*[!0-9]*) fail "could not determine /dev/shm free space" ;; +esac +[ "$available_kb" -gt 16 ] || + fail "/dev/shm has insufficient free space for publication regression" +fill_kb=$((available_kb - 8)) +/usr/bin/fallocate -l "$((fill_kb * 1024))" "$fill_file" +if RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$publish_dest" >/dev/null 2>&1; then + rm -f "$fill_file" + rm -rf "$publish_parent" + fail "nearly-full destination filesystem unexpectedly accepted publication" +fi +[ ! -e "$publish_dest" ] || + fail "failed publication left the immutable destination behind" +if /usr/bin/find "$publish_parent" -maxdepth 1 -name '.r7-publish-*' -print -quit | /usr/bin/grep -q .; then + fail "failed publication left a sibling staging directory" +fi +rm -f "$fill_file" +rm -rf "$publish_parent" + +# No capture regression may leak internal source/staging directories. +if /usr/bin/find build -maxdepth 1 -type d \( -name 'r7-source-*' -o -name 'r7-bundle-stage-*' \) -print -quit | /usr/bin/grep -q .; then + fail "R7 evidence regression leaked internal capture state" +fi + +echo "R7 evidence regressions: OK" From 99ea912d35a70eeeb24e832f1e327071c57e1959 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:13:38 +0930 Subject: [PATCH 087/132] Add deterministic R7 clock regression --- tests/test_r7_clock.c | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/test_r7_clock.c diff --git a/tests/test_r7_clock.c b/tests/test_r7_clock.c new file mode 100644 index 0000000..4e2f7e9 --- /dev/null +++ b/tests/test_r7_clock.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: MPL-2.0 */ +#define main r7_embedded_study_main +#include "../study/r7_memory_wall.c" +#undef main + +#include +#include + +static int require_true(int condition, const char *message) +{ + if (!condition) { + fprintf(stderr, "R7 clock regression: %s\n", message); + return 0; + } + return 1; +} + +int main(void) +{ + uint64_t out; + + out = UINT64_C(99); + if (!require_true( + r7_ticks_between((clock_t)5, (clock_t)12, &out) && + out == UINT64_C(7), + "normal positive delta failed")) { + return 1; + } + + if (!require_true( + !r7_ticks_between((clock_t)12, (clock_t)5, &out), + "decreasing clock interval was accepted")) { + return 1; + } + + if (!require_true( + !r7_ticks_between((clock_t)0, (clock_t)0, NULL), + "NULL output pointer was accepted")) { + return 1; + } + + if ((clock_t)-1 < (clock_t)0 && + sizeof(clock_t) >= sizeof(int64_t)) { + clock_t extreme_start; + + extreme_start = (clock_t)INT64_MIN; + if ((int64_t)extreme_start == INT64_MIN) { + out = UINT64_C(123); + if (!require_true( + !r7_ticks_between(extreme_start, (clock_t)0, &out), + "unrepresentable signed clock delta was accepted")) { + return 1; + } + } + } + + puts("R7 clock regressions: OK"); + return 0; +} From ab041f2105395ee244b3828d45f7134bb95f7bec Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:14:37 +0930 Subject: [PATCH 088/132] Wire deterministic R7 regression targets --- Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9ce25dc..3e22542 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,10 @@ TEST_RING = $(BUILD_DIR)/test_ring TEST_OPERATION = $(BUILD_DIR)/test_operation R6_PROOF = $(BUILD_DIR)/rune_r6_proof R7_STUDY = $(BUILD_DIR)/rune_r7_study +R7_CLOCK_REGRESSION = $(BUILD_DIR)/test_r7_clock CORPUS = $(BUILD_DIR)/rune_corpus -.PHONY: all test r6-proof r7-study-smoke r7-study corpus-smoke clean +.PHONY: all test r6-proof r7-study-smoke r7-study r7-clock-regression r7-evidence-regression corpus-smoke clean all: $(LIB) @@ -79,6 +80,15 @@ r7-study-smoke: $(R7_STUDY) r7-study: $(R7_STUDY) ./$(R7_STUDY) --profile local --repeats 5 +$(R7_CLOCK_REGRESSION): tests/test_r7_clock.c $(LIB) + $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) -fsanitize=undefined -fno-sanitize-recover=undefined tests/test_r7_clock.c $(LIB) -o $@ + +r7-clock-regression: $(R7_CLOCK_REGRESSION) + ./$(R7_CLOCK_REGRESSION) + +r7-evidence-regression: + CC="$(CC)" AR="$(AR)" sh tests/test_r7_run_local.sh + $(CORPUS): corpus/rune_corpus.c $(LIB) include/rune/arena.h include/rune/numeric.h include/rune/region.h include/rune/status.h $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) corpus/rune_corpus.c $(LIB) -o $@ From f5e432f1eb4ce52788687463b2e6a9c81c18c442 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:14:57 +0930 Subject: [PATCH 089/132] Run dedicated R7 regression suites in CI --- .github/workflows/c99.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 8644791..a6c3f1f 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -26,7 +26,7 @@ jobs: - name: Build R1-R7 checks, R6 proof, frozen R4 corpus, and R7 smoke run: | - make clean test r6-proof corpus-smoke r7-study-smoke CC="${{ matrix.cc }}" + make clean test r6-proof corpus-smoke r7-study-smoke r7-clock-regression CC="${{ matrix.cc }}" ./build/rune_r7_study --bytes 4096 --repeats 1 > build/r7-study-4k.tsv test "$(wc -l < build/r7-study-4k.tsv)" -eq 20 awk -F '\t' ' @@ -40,6 +40,10 @@ jobs: } ' build/r7-study-4k.tsv + - name: Run deterministic R7 evidence regressions + run: | + make r7-evidence-regression CC="${{ matrix.cc }}" AR=ar + - name: Validate R7 local evidence script run: | sh -n scripts/r7-run-local.sh From 6d00d326dbf91a2b1a186765a6878ad14fd62374 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:16:06 +0930 Subject: [PATCH 090/132] Canonicalize trusted tool directories without rejecting system symlinks --- scripts/r7-run-local.sh | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 5613dd5..25f0040 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -92,21 +92,6 @@ canonicalize_existing_path() *) return 1 ;; esac - canonical_hops=0 - while [ -L "$canonical_path" ]; do - canonical_hops=$((canonical_hops + 1)) - [ "$canonical_hops" -le 40 ] || return 1 - canonical_link=$("$readlink_path" "$canonical_path") || return 1 - case "$canonical_link" in - /*) canonical_path=$canonical_link ;; - *) canonical_path=${canonical_path%/*}/$canonical_link ;; - esac - canonical_parent=${canonical_path%/*} - canonical_base=${canonical_path##*/} - canonical_parent=$(CDPATH= cd -- "$canonical_parent" && pwd -P) || return 1 - canonical_path=$canonical_parent/$canonical_base - done - canonical_parent=${canonical_path%/*} canonical_base=${canonical_path##*/} canonical_parent=$(CDPATH= cd -- "$canonical_parent" && pwd -P) || return 1 From 9dae6615c535ddc2be078c65a241f75f716bb5ca Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:19:51 +0930 Subject: [PATCH 091/132] Make R7 regression ownership authoritative --- AGENTS.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 402a3a0..d222f88 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -163,6 +163,9 @@ CORE_RULES: - R7_bundle_files_are_staged_under_ignored_build_until_capture_finalization - R7_failed_capture_removes_bundle_stage_and_source_snapshot - R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 +- R7_publish_uses_sibling_destination_filesystem_stage_before_final_rename +- R7_copied_publish_stage_must_pass_SHA256_before_final_rename +- R7_failed_publish_must_leave_requested_destination_absent - R7_default_evidence_r7_destination_must_finalize_without_self_dirtying - R7_repeats_are_validated_before_bundle_creation - R7_bundle_directory_is_created_with_fixed_provenance_mkdir_and_verified_empty @@ -179,6 +182,8 @@ CORE_RULES: - R7_evidence_build_source_is_git_archive_of_recorded_revision - R7_source_snapshot_contains_only_recorded_Makefile_src_include_study - R7_source_snapshot_bytes_must_hash_equal_recorded_revision +- R7_TAR_OPTIONS_is_cleared_for_capture_and_replay +- R7_source_snapshot_rejects_unexpected_files_and_symlinks - R7_source_snapshot_inputs_are_made_read_only_before_build - R7_mutable_worktree_is_not_used_as_evidence_build_source - R7_source_identity_is_revalidated_after_build_and_after_measurement @@ -202,8 +207,10 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH +- R7_CC_AR_and_Make_paths_are_canonicalized_before_trusted_prefix_checks - R7_arbitrary_external_compiler_wrappers_are_forbidden_for_evidence_capture - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting +- R7_recorded_replay_begins_with_set_eu_and_fails_fast - R7_recorded_replay_recreates_git_source_snapshot - R7_recorded_replay_build_uses_make_C_source_snapshot - R7_recorded_replay_study_path_is_absolute @@ -232,8 +239,12 @@ CORE_RULES: - R7_compiler_identity_capture_must_succeed - R7_compound_CC_is_not_accepted_for_evidence_capture - R7_memory_profile_is_required_on_every_supported_capture_host -- R7_clock_wrap_is_rejected_before_tick_subtraction +- R7_clock_delta_representability_is_proven_before_any_subtraction +- R7_signed_clock_extreme_delta_is_UBSan_regression_tested - R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method +- R7_run_local_deterministic_regressions_live_in_tests_test_r7_run_local_sh +- R7_clock_deterministic_regressions_live_in_tests_test_r7_clock_c +- R7_dedicated_regression_targets_run_in_CI_for_GCC_and_Clang - R7_negative_results_must_be_retained - R7_timing_alone_must_not_claim_cache_NUMA_or_bandwidth_cause - R7_runtime_core_changes_are_out_of_scope From 47f062f091af4af463704c599d23c6d69e06b10d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:19:54 +0930 Subject: [PATCH 092/132] Bind R7 dedicated regression suites --- machine/r7-memory-wall-study.v1.json | 31 +++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 42fc467..4dccc62 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -190,7 +190,11 @@ "publish_requires_successful_measurement": true, "publish_requires_final_source_revalidation": true, "publish_requires_SHA256SUMS": true, - "publish_uses_trusted_mv": true, + "publish_copies_to_sibling_stage_on_destination_filesystem": true, + "publish_sibling_stage_SHA256_verified_before_final_rename": true, + "publish_final_rename_is_same_parent_filesystem": true, + "failed_publish_must_leave_requested_destination_absent": true, + "publish_copy_tool_resolved_from_fixed_provenance_PATH": true, "default_in_repo_evidence_destination_supported": true, "repeats_validated_before_destination_creation": true, "bundle_directory_created_with_fixed_provenance_mkdir": true, @@ -204,6 +208,7 @@ "compiler_command_must_be_single_executable": true, "compiler_path_resolution_required": true, "compiler_resolved_from_fixed_provenance_PATH": true, + "compiler_path_canonicalized_before_trusted_prefix_check": true, "external_compiler_wrappers_allowed": false, "compiler_version_capture_required": true, "compiler_identity_failure_is_capture_failure": true, @@ -232,6 +237,7 @@ "archiver_command_must_be_single_executable": true, "archiver_path_resolution_required": true, "archiver_resolved_from_fixed_provenance_PATH": true, + "archiver_path_canonicalized_before_trusted_prefix_check": true, "external_archiver_wrappers_allowed": false, "archiver_version_capture_required": true, "archiver_identity_failure_is_capture_failure": true, @@ -245,6 +251,7 @@ "build_driver" ], "build_driver_path_resolution_required": true, + "build_driver_path_canonicalized_before_trusted_prefix_check": true, "build_driver_identity_capture_required": true, "build_driver_identity_failure_is_capture_failure": true, "ambient_PATH_inherited_by_evidence_build": false, @@ -274,6 +281,9 @@ "study" ], "source_snapshot_bytes_verified_against_revision": true, + "TAR_OPTIONS_cleared_before_snapshot_extraction": true, + "snapshot_unexpected_entries_allowed": false, + "snapshot_symlinks_allowed": false, "source_snapshot_inputs_read_only_before_build": true, "source_snapshot_materialization_tools_resolved_from_fixed_provenance_PATH": [ "git", @@ -372,6 +382,8 @@ "dynamic_loader_sanitation_recorded_in_environment": true, "dynamic_loader_sanitation_recorded_in_command": true, "dynamic_loader_sanitation_self_test": "scripts/r7-run-local.sh --self-test-dynamic-loader-env", + "replay_fail_fast_set_eu": true, + "replay_unsets_TAR_OPTIONS": true, "replay_recreates_source_snapshot_from_recorded_revision": true, "replay_build_uses_make_C_source_snapshot": true, "replay_build_makefile_argument": "Makefile", @@ -398,12 +410,25 @@ "clang" ], "CI_validates_harness_not_performance": true, - "CI_validates_4096_byte_profile_has_20_rows_and_all_eight_microtiles": true + "CI_validates_4096_byte_profile_has_20_rows_and_all_eight_microtiles": true, + "evidence_regression_script": "tests/test_r7_run_local.sh", + "evidence_regression_command": "make r7-evidence-regression", + "clock_regression_source": "tests/test_r7_clock.c", + "clock_regression_command": "make r7-clock-regression", + "evidence_regressions_cover": [ + "canonical tool path traversal for CC/AR/Make", + "fail-fast command.txt replay", + "TAR_OPTIONS injection", + "destination-filesystem ENOSPC publication cleanup" + ], + "clock_regressions_run_under_UBSan": true }, "measurement_integrity": { "volatile_accesses_are_study_mechanics": true, "purpose": "prevent-optimizer-from-collapsing-declared-materialization-tile-retain-recompute-variants", "volatile_semantics_are_part_of_R7_harness_not_runtime_API": true, - "clock_wrap_is_rejected_before_tick_subtraction": true + "clock_wrap_is_rejected_before_tick_subtraction": true, + "clock_delta_representability_checked_before_subtraction": true, + "signed_clock_extreme_delta_UBSan_regression": true } } From a70b6682cc62227435501e2e45cb2cb9d7215304 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:19:58 +0930 Subject: [PATCH 093/132] Document R7 deterministic regression gates --- R7-MEMORY-WALL-STUDY.md | 44 +++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 4ced7be..117bdae 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -59,7 +59,10 @@ The receipt records raw process-CPU-time ticks and CLOCKS_PER_SEC. R7 does not call these values wall-clock nanoseconds. If clock() is unavailable or a tick interval cannot be represented, the study -fails explicitly. +fails explicitly. Delta representability is established before arithmetic, so a +signed negative-to-nonnegative interval cannot overflow `clock_t` during +subtraction. The extreme signed case is exercised under UBSan in +`tests/test_r7_clock.c`. ## Lifecycle accounting @@ -259,9 +262,10 @@ under the compiler-input trees `src/`, `include/`, and `study/`, and compares the raw bytes of every tracked Makefile/source/include/study input against the recorded revision using `git hash-object --no-filters`. It then materializes **Makefile, src/, include/, and study/** directly from -`git archive source_revision` into a per-capture source snapshot. The extracted -bytes are checked against the recorded revision and made read-only before Make -runs. Make executes inside that snapshot, so the mutable checkout is not a +`git archive source_revision` into a per-capture source snapshot. +`TAR_OPTIONS` is cleared before extraction and in replay; after extraction, +unexpected files and symlinks are rejected before the known source bytes are +checked against the recorded revision and made read-only before Make runs. Make executes inside that snapshot, so the mutable checkout is not a compiler input. Worktree and snapshot identity are checked again after the build and after measurement. The publish destination is not created during the build or measurement. An EXIT/signal cleanup trap removes the source snapshot and staged bundle on @@ -287,8 +291,9 @@ The script records: - a verified clean working tree, including absence of untracked files and ignored untracked files under `src/`, `include/`, and `study/`; - compiler, archiver, and build-driver executables resolved from the fixed - provenance path, with successful identity/version output; arbitrary external - compiler/archiver wrappers are not accepted for evidence capture; + provenance path, with their parent paths physically canonicalized before + trusted-prefix checks; arbitrary external compiler/archiver wrappers and + `/usr/bin/../../...` traversal aliases are not accepted; - both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other shell-text content are preserved exactly, binding those values plus CC and AR into the build command; @@ -330,9 +335,11 @@ are rejected before bundle creation, including symlink routes whose lexical parent would be removed or replaced by build activity. Parent-directory traversal in the requested destination is also rejected. `RUNE_R7_REPEATS` is validated as 1..100 before the destination is reserved. The staging directory is created with a `mkdir` executable resolved from the -fixed provenance path and verified empty before metadata is written. After the -staged bundle is checksummed and the final worktree validation passes, trusted -`mv` publishes it to the requested destination. This permits the documented +fixed provenance path and verified empty before metadata is written. After the repository-stage bundle is checksummed and the final worktree +validation passes, it is copied into a hidden sibling staging directory on the +destination filesystem. That copied bundle must pass `SHA256SUMS` verification +before a same-parent rename publishes the requested destination. A failed copy, +including ENOSPC, is cleaned without reserving the immutable final path. This permits the documented default `evidence/r7/local-...` destination without the capture treating its own output as an untracked source mutation. @@ -347,7 +354,9 @@ compiler, archiver, and utility paths. The entire source/build snapshot is removed after measurement. The sanitized invocation is recorded in `command.txt` using POSIX single-quote -escaping. The quote serializer uses `sed` resolved from the fixed provenance +escaping. Replay begins with `set -eu`, so the first failed snapshot, build, or +study command terminates the replay rather than allowing a later cleanup command +to return success. The quote serializer uses `sed` resolved from the fixed provenance path rather than ambient `PATH`, so repository paths containing apostrophes remain replayable even in a hostile shell environment. @@ -386,6 +395,21 @@ These fields satisfy the evidence-dimension requirement only when the bundle is actually captured on the host. A template or planned command is not execution evidence. +## Deterministic regression gates + +Two named regression files now own the failure classes most likely to recur: + +- `tests/test_r7_run_local.sh` — canonical-path traversal for CC/AR/Make, + fail-fast replay, hostile `TAR_OPTIONS`, and destination-filesystem + publication failure/cleanup. +- `tests/test_r7_clock.c` — direct `r7_ticks_between()` boundary tests, + including the signed extreme interval under UBSan. + +They run through `make r7-evidence-regression` and +`make r7-clock-regression` on both GCC and Clang in CI. New defects in either +source file should gain a deterministic reproducer in its corresponding +regression file before the fix is considered complete. + ## CI smoke ~~~sh From 8a6ad067f3bb2f2923f0a3f4e6e1407a07ef9747 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:20:01 +0930 Subject: [PATCH 094/132] Document R7 regression ownership and hardening --- evidence/r7/README.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index b373bf7..44e5b56 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -53,17 +53,21 @@ Git itself is resolved from a fixed provenance path the evidence build path is fixed and cannot substitute the Git/toolchain executables. Git replacement objects are disabled, active replacement refs are rejected, and tracked Makefile/source/include/study files are raw-hashed with -filters disabled and must match their blobs at `source_revision`. The actual -evidence build does not compile those worktree files: it extracts +filters disabled and must match their blobs at `source_revision`. The actual evidence build does not compile those worktree files: it extracts `Makefile`, `src/`, `include/`, and `study/` from -`git archive source_revision` into a per-capture snapshot, verifies the -snapshot bytes, and marks the source inputs read-only before compiling. Ignored untracked files under +`git archive source_revision` into a per-capture snapshot. `TAR_OPTIONS` is +cleared before extraction and replay, unexpected snapshot files/symlinks are +rejected, then the expected snapshot bytes are verified and made read-only +before compiling. Ignored untracked files under `src/`, `include/`, or `study/` are also forbidden because they can satisfy compiler includes without appearing in ordinary status output. For evidence capture, CC and AR must each identify one executable available -from the fixed provenance path; arbitrary external compiler/archiver wrappers -and compound commands are rejected. Ambient compiler search variables (CPATH, +from the fixed provenance path. Their paths (and Make's path) are physically +canonicalized at the parent-directory level before trusted-prefix checks, so +lexical aliases such as `/usr/bin/../../tmp/wrapper` are rejected while normal +system symlinks remain usable. Arbitrary external compiler/archiver wrappers and +compound commands are rejected. Ambient compiler search variables (CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH, COMPILER_PATH, LIBRARY_PATH, GCC_EXEC_PREFIX) are cleared; intentional include paths belong in the recorded CPPFLAGS. Dynamic-loader injection/search variables @@ -94,19 +98,27 @@ containing spaces remain parseable; the executable used by the shell remains absolute. The bundle records the build-driver identity and Makefile Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. -The recorded run command uses an absolute study executable path and includes -the absolute redirection to `observations.tsv`. Shell quoting is serialized +The recorded run command begins with `set -eu`, uses an absolute study +executable path, and includes the absolute redirection to `observations.tsv`. +A replay therefore stops on its first failed setup/build/study command instead +of allowing cleanup to mask the failure. Shell quoting is serialized with a fixed-provenance `sed`, so paths containing apostrophes remain valid. `command.txt` is replayable from outside the repository while recreating the captured output artifact. If measurement or finalization fails, an exit trap removes the staged bundle and temporary source snapshot; no partial requested destination is retained. +Publication first copies the complete bundle to a hidden sibling directory on +the destination filesystem, verifies its SHA-256 manifest there, and only then +renames it into the immutable final path. Cross-filesystem ENOSPC therefore +cannot leave a partial requested destination. This keeps the destination reusable after failures such as memory exhaustion. Raw observations are execution evidence, not universal performance claims. Interpretation belongs in a separately reviewed evidence commit. -GitHub-hosted CI runs only `r7-study-smoke` to prove the harness builds, -executes, preserves comparison result identity, and emits the expected schema. -CI timing values are not R7 performance evidence. +CI includes dedicated deterministic regression gates in addition to the smoke +study: `tests/test_r7_run_local.sh` via `make r7-evidence-regression`, and +`tests/test_r7_clock.c` via `make r7-clock-regression` under UBSan. These +tests are the home for future reproductions affecting the evidence wrapper or +clock arithmetic. CI timing values remain non-performance evidence. From bed6f3bb23aacdeb6a2bf3069d141a0823d33f49 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:33:39 +0930 Subject: [PATCH 095/132] Harden R7 concurrency serialization and Clang environment --- scripts/r7-run-local.sh | 43 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 25f0040..074804b 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -3,10 +3,15 @@ set -eu fail() { - echo "R7 evidence capture: $*" >&2 + printf 'R7 evidence capture: %s\n' "$*" >&2 exit 1 } +emit_key_value() +{ + printf '%s=%s\n' "$1" "$2" +} + shell_quote() { printf "'" @@ -32,6 +37,7 @@ sanitize_capture_environment() unset COMPILER_PATH unset LIBRARY_PATH unset GCC_EXEC_PREFIX + unset CCC_OVERRIDE_OPTIONS unset LD_PRELOAD unset LD_LIBRARY_PATH @@ -207,11 +213,19 @@ if [ "${1:-}" = "--self-test-shell-quote" ]; then fi if [ "${1:-}" = "--self-test-compiler-search-env" ]; then - [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}" ] || + [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}${CCC_OVERRIDE_OPTIONS+x}" ] || fail "compiler search environment self-test failed" exit 0 fi +if [ "${1:-}" = "--self-test-environment-serialization" ]; then + serialized=$(emit_key_value uname 'Linux r7\cprobe'; emit_key_value mem_total_kib 123) + expected=$(printf '%s\n%s' 'uname=Linux r7\cprobe' 'mem_total_kib=123') + [ "$serialized" = "$expected" ] || + fail "environment serialization self-test failed" + exit 0 +fi + if [ "${1:-}" = "--self-test-dynamic-loader-env" ]; then [ -z "${LD_PRELOAD+x}${LD_LIBRARY_PATH+x}${LD_AUDIT+x}${DYLD_INSERT_LIBRARIES+x}${DYLD_LIBRARY_PATH+x}${DYLD_FRAMEWORK_PATH+x}${DYLD_FALLBACK_LIBRARY_PATH+x}${DYLD_FALLBACK_FRAMEWORK_PATH+x}${LIBPATH+x}${SHLIB_PATH+x}" ] || fail "dynamic-loader environment self-test failed" @@ -432,10 +446,10 @@ materialize_source_snapshot() if [ -e "$repo_root/build" ] && [ ! -d "$repo_root/build" ]; then fail "repository build path is not a directory" fi - if [ ! -d "$repo_root/build" ]; then - "$bundle_mkdir_path" "$repo_root/build" || - fail "could not create repository build directory" - fi + "$bundle_mkdir_path" -p "$repo_root/build" || + fail "could not create repository build directory" + [ -d "$repo_root/build" ] && [ ! -L "$repo_root/build" ] || + fail "repository build path changed during creation" [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || fail "source snapshot destination already exists: $source_snapshot" @@ -621,15 +635,16 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -source_snapshot_rel="build/r7-source-$stamp-$$" +capture_id="$stamp-$" +source_snapshot_rel="build/r7-source-$capture_id" source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$stamp-$$" +build_dir_rel="build/r7-evidence-$capture_id" build_dir="$source_snapshot/$build_dir_rel" study_target="$build_dir_rel/rune_r7_study" study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$stamp-$" +bundle_stage_rel="build/r7-bundle-stage-$capture_id" bundle_stage="$repo_root/$bundle_stage_rel" -publish_stage="$out_parent_abs/.r7-publish-$stamp-$" +publish_stage="$out_parent_abs/.r7-publish-$capture_id" cleanup_capture_state() { if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then @@ -724,11 +739,11 @@ observations_path="$bundle_stage/observations.tsv" echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" echo "git_replace_objects=disabled and replacement refs forbidden" echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" - echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX cleared" + echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" echo "ignored_compiler_inputs=forbidden under src,include,study" echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" - echo "uname=$platform_identity" + emit_key_value uname "$platform_identity" if [ -n "$getconf_path" ]; then processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) @@ -736,7 +751,7 @@ observations_path="$bundle_stage/observations.tsv" printf 'long_bit=%s\n' "$long_bit" fi if [ -n "$cpu_model" ]; then - echo "cpu_model=$cpu_model" + emit_key_value cpu_model "$cpu_model" fi printf '%s\n' "$memory_profile" } > "$bundle_stage/environment.txt" @@ -772,7 +787,7 @@ observations_path="$bundle_stage/observations.tsv" printf "set -eu\n" printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" printf "export GIT_NO_REPLACE_OBJECTS=1\n" - printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX\n" + printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" printf "unset TAR_OPTIONS\n" shell_quote "$bundle_mkdir_path" From 804fb0c390f8376232add85c46a9cdc9ae453b42 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:34:25 +0930 Subject: [PATCH 096/132] Add R7 concurrency serialization and Clang regressions --- tests/test_r7_run_local.sh | 84 +++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 7aba593..80eebb4 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -32,8 +32,10 @@ cleanup() { rm -rf "$tmp_root" rm -f /tmp/r7-reg-cc-$$ /tmp/r7-reg-ar-$$ /tmp/r7-reg-make-$$ - rm -f /tmp/r7-tar-hook-$$ /tmp/r7-tar-hook-ran-$$ - rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* + rm -f /tmp/r7-tar-hook-$ /tmp/r7-tar-hook-ran-$ + rm -f /tmp/r7-ccc-header-$.h + rm -f /tmp/r7-concurrent-a-$.log /tmp/r7-concurrent-b-$.log + rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* } trap cleanup 0 1 2 3 15 @@ -49,6 +51,84 @@ expect_capture_failure() [ ! -e "$dest" ] || fail "$label left a requested destination" } +# Environment serialization must preserve backslashes and field boundaries. +scripts/r7-run-local.sh --self-test-environment-serialization + +# Clang ambient option overrides must be cleared by capture and replay. +CCC_OVERRIDE_OPTIONS='#+-include +/tmp/should-not-exist.h' \ + scripts/r7-run-local.sh --self-test-compiler-search-env + +case "$system_cc" in + *clang) + cat > /tmp/r7-ccc-header-$.h <<'EOF' +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF + ccc_bundle="$tmp_root/ccc-override" + CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$.h" \ + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$ccc_bundle" >/dev/null + if /usr/bin/awk -F '\t' '$16 == 424242 { bad=1 } END { exit bad ? 0 : 1 }' "$ccc_bundle/observations.tsv"; then + fail "CCC_OVERRIDE_OPTIONS changed captured clock scale" + fi + /usr/bin/grep -Fq 'CCC_OVERRIDE_OPTIONS' "$ccc_bundle/command.txt" || + fail "replay does not explicitly clear CCC_OVERRIDE_OPTIONS" + CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$.h" \ + /bin/sh "$ccc_bundle/command.txt" >/dev/null + if /usr/bin/awk -F '\t' '$16 == 424242 { bad=1 } END { exit bad ? 0 : 1 }' "$ccc_bundle/observations.tsv"; then + fail "CCC_OVERRIDE_OPTIONS changed replayed clock scale" + fi + ;; +esac + +run_concurrent_pair() +{ + label=$1 + dest_a="$tmp_root/$label-a" + dest_b="$tmp_root/$label-b" + rm -rf "$dest_a" "$dest_b" + + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$dest_a" > /tmp/r7-concurrent-a-$.log 2>&1 & + pid_a=$! + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$dest_b" > /tmp/r7-concurrent-b-$.log 2>&1 & + pid_b=$! + + if wait "$pid_a"; then status_a=0; else status_a=$?; fi + if wait "$pid_b"; then status_b=0; else status_b=$?; fi + + [ "$status_a" -eq 0 ] || { + cat /tmp/r7-concurrent-a-$.log >&2 + fail "$label capture A failed with status $status_a" + } + [ "$status_b" -eq 0 ] || { + cat /tmp/r7-concurrent-b-$.log >&2 + fail "$label capture B failed with status $status_b" + } + + for concurrent_bundle in "$dest_a" "$dest_b"; do + [ -s "$concurrent_bundle/observations.tsv" ] || + fail "$label did not publish observations" + ( + cd "$concurrent_bundle" + /usr/bin/sha256sum -c SHA256SUMS >/dev/null + ) + done + + if /usr/bin/find build -maxdepth 1 -type d \( -name 'r7-source-*' -o -name 'r7-bundle-stage-*' \) -print -quit | /usr/bin/grep -q .; then + fail "$label leaked shared capture state" + fi +} + +# Concurrent captures must isolate all PID-qualified staging paths. +mkdir -p build +run_concurrent_pair concurrent-existing-build + +# Shared build-parent creation must be race-safe from a clean absent build/. +rm -rf build +run_concurrent_pair concurrent-missing-build + # Canonical-path regression: lexical /usr/bin prefixes must not authorize /tmp. cat > /tmp/r7-reg-cc-$$ < Date: Sun, 27 Sep 2026 20:35:25 +0930 Subject: [PATCH 097/132] Use shell PID in centralized R7 capture identity --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 074804b..f4e01c1 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -635,7 +635,7 @@ if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then done fi -capture_id="$stamp-$" +capture_id="$stamp-$$" source_snapshot_rel="build/r7-source-$capture_id" source_snapshot="$repo_root/$source_snapshot_rel" build_dir_rel="build/r7-evidence-$capture_id" From b13ac5061da77f8f790fa2bdbc6ff038ecc4ddc7 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:38:59 +0930 Subject: [PATCH 098/132] Extend R7 concurrency and environment invariants --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index d222f88..6dc6e34 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -161,6 +161,7 @@ CORE_RULES: - R7_microtile_may_exceed_logical_input_and_process_only_available_items - R7_evidence_destination_must_be_new_and_immutable - R7_bundle_files_are_staged_under_ignored_build_until_capture_finalization +- R7_capture_unique_identity_is_UTC_timestamp_plus_shell_PID_for_source_build_bundle_and_publish_stages - R7_failed_capture_removes_bundle_stage_and_source_snapshot - R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 - R7_publish_uses_sibling_destination_filesystem_stage_before_final_rename @@ -190,6 +191,7 @@ CORE_RULES: - R7_bundle_is_not_created_until_post_build_source_revalidation_passes - R7_ignored_untracked_files_under_src_include_study_are_forbidden - R7_ambient_compiler_search_path_environment_is_cleared +- R7_CCC_OVERRIDE_OPTIONS_is_cleared_before_compiler_identity_build_and_replay - R7_compiler_search_environment_sanitation_is_CI_self_tested - R7_dynamic_loader_injection_environment_is_cleared_before_tool_and_study_execution - R7_dynamic_loader_environment_sanitation_is_CI_self_tested @@ -197,6 +199,7 @@ CORE_RULES: - R7_dirty_worktree_evidence_capture_is_forbidden - R7_source_revision_must_identify_exact_built_source_contents - R7_platform_identity_capture_must_succeed_and_be_nonempty +- R7_platform_identity_and_CPU_model_are_serialized_with_printf_without_echo_escape_interpretation - R7_uname_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_integrity_SHA256_utility_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_quote_serializer_sed_is_resolved_from_fixed_provenance_PATH_and_recorded @@ -221,6 +224,8 @@ CORE_RULES: - R7_evidence_build_uses_fresh_unique_BUILD_DIR_and_does_not_depend_on_make_clean - R7_fresh_BUILD_DIR_identity_includes_UTC_timestamp_and_shell_PID - R7_concurrent_evidence_builds_must_not_share_BUILD_DIR +- R7_shared_build_parent_creation_is_idempotent_and_concurrency_safe +- R7_concurrent_full_capture_regressions_cover_build_parent_present_and_absent - R7_Make_facing_BUILD_DIR_and_study_target_are_repository_relative - R7_repository_paths_with_spaces_are_supported_for_evidence_capture - R7_fresh_build_self_test_is_CI_executed_with_hostile_ambient_PATH From aa38a72fc355475c0256a3b4b483d247468128ac Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:39:04 +0930 Subject: [PATCH 099/132] Bind R7 concurrency serialization and Clang regressions --- machine/r7-memory-wall-study.v1.json | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 4dccc62..052d136 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -260,7 +260,12 @@ "make_compiler_archiver_mkdir_rm_resolved_from_fixed_provenance_PATH": true, "fresh_unique_BUILD_DIR_required": true, "fresh_BUILD_DIR_identity": "UTC timestamp + shell PID", + "capture_identity": "UTC timestamp + shell PID", + "capture_identity_shared_by_source_build_bundle_stage_and_publish_stage": true, "concurrent_evidence_builds_must_use_distinct_BUILD_DIRs": true, + "shared_build_parent_creation_is_idempotent": true, + "concurrent_capture_test_with_existing_build_parent": true, + "concurrent_capture_test_with_absent_build_parent": true, "make_facing_BUILD_DIR_is_repository_relative": true, "make_facing_study_target_is_repository_relative": true, "shell_facing_study_executable_is_absolute": true, @@ -299,6 +304,9 @@ "ambient_PATH_may_control_platform_identity": false, "platform_identity_capture_must_succeed": true, "platform_identity_must_be_nonempty": true, + "platform_identity_serialization_uses_printf": true, + "CPU_model_serialization_uses_printf": true, + "environment_serialization_backslash_self_test": "scripts/r7-run-local.sh --self-test-environment-serialization", "shell_quote_serializer_tool": "sed", "shell_quote_serializer_resolved_from_fixed_provenance_PATH": true, "shell_quote_serializer_path_recorded": true, @@ -360,7 +368,8 @@ "OBJC_INCLUDE_PATH", "COMPILER_PATH", "LIBRARY_PATH", - "GCC_EXEC_PREFIX" + "GCC_EXEC_PREFIX", + "CCC_OVERRIDE_OPTIONS" ], "ambient_compiler_search_paths_allowed": false, "compiler_search_sanitation_recorded_in_environment": true, @@ -419,7 +428,11 @@ "canonical tool path traversal for CC/AR/Make", "fail-fast command.txt replay", "TAR_OPTIONS injection", - "destination-filesystem ENOSPC publication cleanup" + "destination-filesystem ENOSPC publication cleanup", + "concurrent captures with existing build parent", + "concurrent captures with absent build parent", + "platform identity backslash serialization", + "Clang CCC_OVERRIDE_OPTIONS injection" ], "clock_regressions_run_under_UBSan": true }, From 235ba3ca83ca6065a00e66002de4b12f6be2d9ad Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:39:07 +0930 Subject: [PATCH 100/132] Document expanded R7 wrapper regressions --- R7-MEMORY-WALL-STUDY.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 117bdae..4517395 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -297,15 +297,17 @@ The script records: - both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other shell-text content are preserved exactly, binding those values plus CC and AR into the build command; -- explicit sanitation of ambient compiler search-path variables +- explicit sanitation of ambient compiler search/override variables (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, - `GCC_EXEC_PREFIX`); + `GCC_EXEC_PREFIX`, and Clang's `CCC_OVERRIDE_OPTIONS`); - explicit sanitation of dynamic-loader injection/search variables including `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT`, the relevant `DYLD_*` variables, `LIBPATH`, and `SHLIB_PATH`; - mandatory successful, nonempty `uname -a` platform identity resolved from - the fixed provenance path and recorded by absolute executable path; + the fixed provenance path and recorded by absolute executable path; platform + identity and CPU-model values are serialized with `printf`, not `echo`, so + backslash escapes such as `\c` cannot corrupt adjacent metadata fields; - visible processor count when available; - CPU model when available; - a **required memory profile**, with Linux parsing performed by `awk` @@ -343,9 +345,13 @@ including ENOSPC, is cleaned without reserving the immutable final path. This pe default `evidence/r7/local-...` destination without the capture treating its own output as an untracked source mutation. -The evidence build does **not** depend on `make clean`. Each capture receives -a unique source-snapshot directory and a fresh `BUILD_DIR`, both identified by -UTC timestamp plus shell PID, so concurrent captures remain isolated. Source +The evidence build does **not** depend on `make clean`. A single +`capture_id = UTC timestamp + shell PID` names the source snapshot, fresh +`BUILD_DIR`, repository bundle stage, and destination sibling publish stage, +so concurrent captures cannot remove or overwrite one another's state. Shared +creation of the repository `build/` parent uses idempotent `mkdir -p` plus a +post-creation type/symlink check, allowing two captures to start concurrently +even when `build/` does not yet exist. Source material is extracted from the recorded Git tree, verified, and made read-only. The build clears inherited `MAKEFLAGS`, `GNUMAKEFLAGS`, `MFLAGS`, `MAKEFILES`, and `MAKEOVERRIDES`, uses the fixed @@ -400,8 +406,10 @@ evidence. Two named regression files now own the failure classes most likely to recur: - `tests/test_r7_run_local.sh` — canonical-path traversal for CC/AR/Make, - fail-fast replay, hostile `TAR_OPTIONS`, and destination-filesystem - publication failure/cleanup. + fail-fast replay, hostile `TAR_OPTIONS`, destination-filesystem publication + failure/cleanup, full concurrent captures with `build/` both present and + absent, backslash-safe environment serialization, and Clang + `CCC_OVERRIDE_OPTIONS` injection during capture/replay. - `tests/test_r7_clock.c` — direct `r7_ticks_between()` boundary tests, including the signed extreme interval under UBSan. From f6d1db4af884dfc44115fa546185ab0eb91e07b6 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:39:12 +0930 Subject: [PATCH 101/132] Document R7 concurrency and override hardening --- evidence/r7/README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 44e5b56..060fdb9 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -69,13 +69,16 @@ lexical aliases such as `/usr/bin/../../tmp/wrapper` are rejected while normal system symlinks remain usable. Arbitrary external compiler/archiver wrappers and compound commands are rejected. Ambient compiler search variables (CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH, COMPILER_PATH, -LIBRARY_PATH, GCC_EXEC_PREFIX) are cleared; intentional include paths belong in -the recorded CPPFLAGS. Dynamic-loader injection/search variables +LIBRARY_PATH, GCC_EXEC_PREFIX, and Clang's CCC_OVERRIDE_OPTIONS) are cleared; +intentional include paths belong in the recorded CPPFLAGS. Replay explicitly +clears the same override state before invoking the recorded compiler. Dynamic-loader injection/search variables (`LD_PRELOAD`, loader library paths/auditing, relevant `DYLD_*` variables, `LIBPATH`, and `SHLIB_PATH`) are cleared before toolchain identity and study execution. CI exercises hostile compiler-search, Git-routing, ignored-header, and loader-injection cases. Missing compiler identity, a failed/empty `uname -a` platform identity, or -missing memory profile causes the capture to fail. The required `uname` platform probe, the `awk` memory parser, and optional +missing memory profile causes the capture to fail. Platform and CPU-model +metadata are emitted with `printf` so shell `echo` escape handling cannot +merge or truncate required fields. The required `uname` platform probe, the `awk` memory parser, and optional `getconf`/`sysctl` probes are resolved from the fixed provenance path rather than ambient `PATH`. The getconf fallback requires both a nonzero numeric physical page count and page size. @@ -85,10 +88,12 @@ the evidence build. Ambient `PATH` is replaced by the fixed recorded `/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving backslashes exactly. Each -capture builds into a fresh unique `BUILD_DIR` keyed by UTC timestamp plus -the shell PID and never relies on `make clean`, so concurrent captures do not -share objects/executables and a fake ambient `rm` cannot preserve and certify -a stale study executable. +capture uses one UTC-timestamp-plus-PID identity for its source snapshot, +`BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared +repository `build/` parent is created idempotently, so concurrent captures are +isolated whether the parent already exists or is created by racing captures. +The build never relies on `make clean`, so a fake ambient `rm` cannot +preserve and certify a stale study executable. The evidence build uses the Makefile extracted from the recorded Git revision and invokes the resolved absolute Make path with From a15a386962a4780eef7346628aa89c92058fa158 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:11:53 +0930 Subject: [PATCH 102/132] Reject recursive Make flags and trust repo-root dirname --- scripts/r7-run-local.sh | 1371 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 1370 insertions(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index f4e01c1..eaf85c2 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -232,7 +232,10 @@ if [ "${1:-}" = "--self-test-dynamic-loader-env" ]; then exit 0 fi -repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) +script_dir=$("$dirname_path" -- "$0") || + fail "could not resolve script directory" +repo_root=$(CDPATH= cd -- "$script_dir/.." && pwd -P) || + fail "could not resolve repository root" cd "$repo_root" if [ "${1:-}" = "--self-test-git-root" ]; then @@ -258,6 +261,1372 @@ if [ "${1:-}" = "--self-test-fresh-build" ]; then fi cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} + +case "$cppflags" in + *' +case "$repeats" in + ''|*[!0-9]*) + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" + ;; +esac +normalized_repeats=$repeats +while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do + normalized_repeats=${normalized_repeats#0} +done +[ -n "$normalized_repeats" ] || + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" +case "$normalized_repeats" in + [1-9]|[1-9][0-9]|100) ;; + *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; +esac +stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) +out_dir=${1:-"evidence/r7/local-$stamp"} +out_parent=$("$dirname_path" -- "$out_dir") + +case "$cc_name" in + *[[:space:]]*) + fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" + ;; +esac + +case "$ar_name" in + *[[:space:]]*) + fail "AR must name one archiver executable" + ;; +esac + +case "$make_name" in + *[[:space:]]*) + fail "MAKE must name one build-driver executable" + ;; +esac + +case "$out_dir" in + *"/../"*|"../"*|*/..|..) + fail "evidence destination must not contain parent-directory traversal: $out_dir" + ;; +esac + +out_route=$out_dir +while [ "${out_route#./}" != "$out_route" ]; do + out_route=${out_route#./} +done + +case "$out_route" in + build|build/*|"$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not route through build/: $out_dir" + ;; +esac + +[ -d "$out_parent" ] || + fail "bundle parent directory does not exist: $out_parent" + +out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || + fail "could not resolve bundle parent: $out_parent" +out_leaf=$("$basename_path" -- "$out_dir") +out_abs="$out_parent_abs/$out_leaf" + +case "$out_abs" in + "$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not be inside build/: $out_dir" + ;; +esac + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination already exists; refusing overwrite: $out_dir" +fi + +replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || + fail "could not inspect Git replacement refs" + +[ -z "$replacement_refs" ] || + fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" + +revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || + fail "could not resolve source revision" + +"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || + fail "tracked Makefile is missing" +makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || + fail "could not resolve tracked Makefile at source revision" +[ -n "$makefile_blob" ] || + fail "tracked Makefile identity is empty" + +index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' + /^[a-z]/ || /^S / { print; exit } +') || fail "could not inspect Git index visibility flags" + +[ -z "$index_hidden" ] || + fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" + +ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || + fail "could not inspect ignored compiler-input trees" + +[ -z "$ignored_inputs" ] || + fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" + +git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || + fail "could not inspect Git working-tree state" + +[ -z "$git_status" ] || + fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" + +tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || + fail "could not enumerate tracked compiler inputs" + +[ -n "$tracked_inputs" ] || + fail "tracked compiler-input set is empty" + +validate_source_identity() +{ + current_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || + fail "could not re-inspect Git working-tree state" + [ -z "$current_status" ] || + fail "working tree changed during evidence capture" + + while IFS= read -r tracked_path; do + [ -n "$tracked_path" ] || continue + [ -f "$repo_root/$tracked_path" ] || + fail "tracked compiler input is missing from worktree: $tracked_path" + worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || + fail "could not hash raw worktree bytes: $tracked_path" + revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || + fail "could not resolve revision blob: $tracked_path" + [ "$worktree_blob" = "$revision_blob" ] || + fail "raw worktree bytes differ from source revision: $tracked_path" + done < "$archive_path" || + fail "could not materialize source archive for revision: $revision" + "$tar_path" -xf "$archive_path" -C "$source_snapshot" || + fail "could not extract source snapshot" + "$provenance_rm_path" -f "$archive_path" || + fail "could not remove temporary source archive" + + validate_snapshot_source_entries + validate_snapshot_identity + "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || + fail "could not make source snapshot read-only" +} + +cleanup_snapshot() +{ + if [ -d "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" || + fail "could not restore snapshot write permission for cleanup" + fi + "$provenance_rm_path" -rf "$source_snapshot" || + fail "could not remove source snapshot: $source_snapshot" + [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || + fail "source snapshot remains after cleanup: $source_snapshot" +} + +dirty=false + +cc_path=$(resolve_provenance_tool "$cc_name") || + fail "compiler not found in fixed provenance path: $cc_name" +cc_path=$(canonicalize_existing_path "$cc_path") || + fail "could not canonicalize compiler path: $cc_path" +case "$cc_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "compiler escaped fixed provenance path: $cc_path" ;; +esac +[ -n "$cc_path" ] && [ -x "$cc_path" ] || + fail "compiler path is not executable: $cc_path" + +compiler_version=$("$cc_path" --version 2>&1) || + fail "compiler identity command failed: $cc_path --version" +[ -n "$compiler_version" ] || + fail "compiler identity output is empty" + +ar_path=$(resolve_provenance_tool "$ar_name") || + fail "archiver not found in fixed provenance path: $ar_name" +ar_path=$(canonicalize_existing_path "$ar_path") || + fail "could not canonicalize archiver path: $ar_path" +case "$ar_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "archiver escaped fixed provenance path: $ar_path" ;; +esac +[ -n "$ar_path" ] && [ -x "$ar_path" ] || + fail "archiver path is not executable: $ar_path" + +if archiver_version=$("$ar_path" --version 2>&1); then + : +elif archiver_version=$("$ar_path" -V 2>&1); then + : +else + fail "archiver identity command failed: $ar_path" +fi +[ -n "$archiver_version" ] || + fail "archiver identity output is empty" + +make_path=$(resolve_provenance_tool "$make_name") || + fail "build driver not found in fixed provenance path: $make_name" +make_path=$(canonicalize_existing_path "$make_path") || + fail "could not canonicalize build-driver path: $make_path" +case "$make_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "build-driver escaped fixed provenance path: $make_path" ;; +esac +[ -x "$make_path" ] || + fail "build-driver path is not executable: $make_path" + +if make_version=$("$make_path" --version 2>&1); then + : +elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then + : +else + fail "build-driver identity command failed: $make_path" +fi +[ -n "$make_version" ] || + fail "build-driver identity output is empty" + +mkdir_path=$(resolve_provenance_tool mkdir) || + fail "mkdir not found in fixed provenance path" +rm_path=$(resolve_provenance_tool rm) || + fail "rm not found in fixed provenance path" +case "$mkdir_path:$rm_path" in + /*:/*) ;; + *) fail "build utility paths must be absolute" ;; +esac + +build_study() +{ + PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ + "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ + BUILD_DIR="$build_dir_rel" \ + CC="$cc_path" \ + AR="$ar_path" \ + CPPFLAGS="$cppflags" \ + CFLAGS="$cflags" +} + +cleanup_build() +{ + "$rm_path" -rf "$build_dir" || + fail "could not remove fresh evidence build directory: $build_dir" + [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || + fail "fresh evidence build directory remains after cleanup: $build_dir" +} + +memory_profile= +if [ -r /proc/meminfo ]; then + mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) + case "$mem_total_kib" in + ''|*[!0-9]*) ;; + *) memory_profile="mem_total_kib=$mem_total_kib" ;; + esac +fi + +if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then + for key in hw.memsize hw.physmem64 hw.physmem; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + case "$value" in + ''|*[!0-9]*) ;; + *) + memory_profile="mem_total_bytes=$value" + break + ;; + esac + done +fi + +if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then + phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) + page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) + + case "$phys_pages" in + ''|*[!0-9]*|0) phys_pages= ;; + esac + case "$page_size" in + ''|*[!0-9]*|0) page_size= ;; + esac + + if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then + memory_profile="mem_phys_pages=$phys_pages +mem_page_size_bytes=$page_size" + fi +fi + +[ -n "$memory_profile" ] || + fail "could not capture required memory profile" + +platform_identity=$("$uname_path" -a 2>&1) || + fail "platform identity command failed: $uname_path -a" +[ -n "$platform_identity" ] || + fail "platform identity output is empty" + +cpu_model= +if [ -r /proc/cpuinfo ]; then + cpu_model=$("$awk_path" -F ': ' ' + /^model name[[:space:]]*:/ { print $2; exit } + /^Hardware[[:space:]]*:/ { print $2; exit } + ' /proc/cpuinfo) +fi +if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then + for key in machdep.cpu.brand_string hw.model; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + if [ -n "$value" ]; then + cpu_model=$value + break + fi + done +fi + +capture_id="$stamp-$$" +source_snapshot_rel="build/r7-source-$capture_id" +source_snapshot="$repo_root/$source_snapshot_rel" +build_dir_rel="build/r7-evidence-$capture_id" +build_dir="$source_snapshot/$build_dir_rel" +study_target="$build_dir_rel/rune_r7_study" +study_executable="$source_snapshot/$study_target" +bundle_stage_rel="build/r7-bundle-stage-$capture_id" +bundle_stage="$repo_root/$bundle_stage_rel" +publish_stage="$out_parent_abs/.r7-publish-$capture_id" +cleanup_capture_state() +{ + if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : + "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : + fi + if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then + "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : + fi + if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then + "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : + fi +} + +trap cleanup_capture_state 0 1 2 3 15 + +if [ "$fresh_build_self_test" = true ]; then + materialize_source_snapshot + build_study + validate_snapshot_identity + "$study_executable" --bytes 32768 --repeats 1 >/dev/null + cleanup_snapshot + exit 0 +fi + +materialize_source_snapshot +build_study +validate_snapshot_identity +validate_source_identity + +[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || + fail "bundle staging destination already exists: $bundle_stage" +"$bundle_mkdir_path" "$bundle_stage" || + fail "could not create bundle staging directory: $bundle_stage" + +set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* +for bundle_entry in "$@"; do + [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue + fail "new bundle staging directory is not empty: $bundle_stage" +done + +observations_path="$bundle_stage/observations.tsv" + +{ + echo "contract=rune.r7.environment.v1" + echo "evidence_class=raw-local-execution-observation" + printf 'source_revision=%s\n' "$revision" + printf 'working_tree_dirty=%s\n' "$dirty" + printf '%s\n' "measurement_method=C99_clock_process_cpu_time" + printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" + printf 'makefile_path=%s\n' "$repo_root/Makefile" + printf 'makefile_blob=%s\n' "$makefile_blob" + printf 'repeats=%s\n' "$repeats" + printf 'git_provenance_path=%s\n' "$provenance_path" + printf 'git_resolved=%s\n' "$git_path" + printf 'sed_resolved=%s\n' "$sed_path" + printf 'awk_resolved=%s\n' "$awk_path" + printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" + printf 'tar_resolved=%s\n' "$tar_path" + printf 'chmod_resolved=%s\n' "$chmod_path" + printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'mv_resolved=%s\n' "$mv_path" + printf 'cp_resolved=%s\n' "$cp_path" + printf 'find_resolved=%s\n' "$find_path" + printf 'readlink_resolved=%s\n' "$readlink_path" + printf 'bundle_stage=%s\n' "$bundle_stage" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" + printf 'date_resolved=%s\n' "$date_path" + printf 'dirname_resolved=%s\n' "$dirname_path" + printf 'basename_resolved=%s\n' "$basename_path" + printf 'source_snapshot=%s\n' "$source_snapshot" + printf 'source_snapshot_revision=%s\n' "$revision" + printf '%s\n' "build_source_origin=git_archive_recorded_revision" + printf '%s\n' "build_source_worktree_used=false" + printf 'uname_resolved=%s\n' "$uname_path" + printf 'sha256_mode=%s\n' "$hash_mode" + printf 'sha256_resolved=%s\n' "$hash_path" + printf 'cc_requested=%s\n' "$cc_name" + printf 'cc_resolved=%s\n' "$cc_path" + printf 'ar_requested=%s\n' "$ar_name" + printf 'ar_resolved=%s\n' "$ar_path" + printf 'make_requested=%s\n' "$make_name" + printf 'make_resolved=%s\n' "$make_path" + printf 'build_path=%s\n' "$build_path" + printf 'mkdir_resolved=%s\n' "$mkdir_path" + printf 'rm_resolved=%s\n' "$rm_path" + printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" + printf 'fresh_build_dir=%s\n' "$build_dir" + printf 'fresh_study_target=%s\n' "$study_target" + printf 'cppflags=%s\n' "$cppflags" + printf 'cflags=%s\n' "$cflags" + echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" + echo "git_replace_objects=disabled and replacement refs forbidden" + echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" + echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" + echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" + echo "ignored_compiler_inputs=forbidden under src,include,study" + echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" + emit_key_value uname "$platform_identity" + if [ -n "$getconf_path" ]; then + processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) + long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) + printf 'processors_online=%s\n' "$processors_online" + printf 'long_bit=%s\n' "$long_bit" + fi + if [ -n "$cpu_model" ]; then + emit_key_value cpu_model "$cpu_model" + fi + printf '%s\n' "$memory_profile" +} > "$bundle_stage/environment.txt" + +{ + printf 'git_path=%s\n' "$git_path" + printf '%s\n' "$git_version" + printf 'sed_path=%s\n' "$sed_path" + printf 'awk_path=%s\n' "$awk_path" + printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" + printf 'tar_path=%s\n' "$tar_path" + printf 'chmod_path=%s\n' "$chmod_path" + printf 'provenance_rm_path=%s\n' "$provenance_rm_path" + printf 'mv_path=%s\n' "$mv_path" + printf 'cp_path=%s\n' "$cp_path" + printf 'find_path=%s\n' "$find_path" + printf 'readlink_path=%s\n' "$readlink_path" + printf 'date_path=%s\n' "$date_path" + printf 'dirname_path=%s\n' "$dirname_path" + printf 'basename_path=%s\n' "$basename_path" + printf 'uname_path=%s\n' "$uname_path" + printf 'sha256_path=%s\n' "$hash_path" + printf '%s\n' "$hash_version" + echo "compiler_path=$cc_path" + printf '%s\n' "$compiler_version" + echo "archiver_path=$ar_path" + printf '%s\n' "$archiver_version" + echo "build_driver_path=$make_path" + printf '%s\n' "$make_version" +} > "$bundle_stage/compiler.txt" + +{ + printf "set -eu\n" + printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" + printf "export GIT_NO_REPLACE_OBJECTS=1\n" + printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" + printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + printf "unset TAR_OPTIONS\n" + shell_quote "$bundle_mkdir_path" + printf " -p " + shell_quote "$repo_root/build" + printf '\n' + shell_quote "$bundle_mkdir_path" + printf " " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$git_path" + printf " -C " + shell_quote "$repo_root" + printf " archive --format=tar " + shell_quote "$revision" + printf " -- Makefile src include study > " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$tar_path" + printf " -xf " + shell_quote "$source_snapshot/.r7-source.tar" + printf " -C " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$provenance_rm_path" + printf " -f " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$chmod_path" + printf " -R a-w " + shell_quote "$source_snapshot/Makefile" + printf " " + shell_quote "$source_snapshot/src" + printf " " + shell_quote "$source_snapshot/include" + printf " " + shell_quote "$source_snapshot/study" + printf '\n' + printf "PATH=" + shell_quote "$build_path" + printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " + shell_quote "$make_path" + printf " -C " + shell_quote "$source_snapshot" + printf " -f Makefile " + shell_quote "$study_target" + printf " BUILD_DIR=" + shell_quote "$build_dir_rel" + printf " CC=" + shell_quote "$cc_path" + printf " AR=" + shell_quote "$ar_path" + printf " CPPFLAGS=" + shell_quote "$cppflags" + printf " CFLAGS=" + shell_quote "$cflags" + printf '\n' + + shell_quote "$study_executable" + printf " --profile local --repeats " + shell_quote "$repeats" + printf " > " + shell_quote "$out_abs/observations.tsv" + printf '\n' + shell_quote "$chmod_path" + printf " -R u+w " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$provenance_rm_path" + printf " -rf " + shell_quote "$source_snapshot" + printf '\n' +} > "$bundle_stage/command.txt" + +"$study_executable" --profile local --repeats "$repeats" \ + > "$observations_path" + +validate_snapshot_identity +validate_source_identity +cleanup_snapshot + +case "$hash_mode" in + sha256sum) + ( + cd "$bundle_stage" + "$hash_path" \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + shasum) + ( + cd "$bundle_stage" + "$hash_path" -a 256 \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + *) + fail "unsupported SHA-256 utility mode: $hash_mode" + ;; +esac + +validate_source_identity + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination appeared during capture; refusing publish: $out_dir" +fi +[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || + fail "publish staging destination already exists: $publish_stage" + +"$bundle_mkdir_path" "$publish_stage" || + fail "could not create sibling publish staging directory" +"$cp_path" -R "$bundle_stage/." "$publish_stage/" || + fail "could not copy completed bundle to destination filesystem" + +case "$hash_mode" in + sha256sum) + ( + cd "$publish_stage" + "$hash_path" -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; + shasum) + ( + cd "$publish_stage" + "$hash_path" -a 256 -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; +esac + +"$provenance_rm_path" -rf "$bundle_stage" || + fail "could not remove repository bundle staging directory" + +if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then + fail "evidence destination appeared during publish; refusing rename: $out_abs" +fi + +"$mv_path" "$publish_stage" "$out_abs" || + fail "could not rename completed sibling staging bundle into place" +trap - 0 1 2 3 15 + +echo "R7 evidence bundle: $out_dir" +*) fail "CPPFLAGS must not contain Make variable expansion syntax ($); resolve it before capture" ;; +esac +case "$cflags" in + *' +case "$repeats" in + ''|*[!0-9]*) + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" + ;; +esac +normalized_repeats=$repeats +while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do + normalized_repeats=${normalized_repeats#0} +done +[ -n "$normalized_repeats" ] || + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" +case "$normalized_repeats" in + [1-9]|[1-9][0-9]|100) ;; + *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; +esac +stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) +out_dir=${1:-"evidence/r7/local-$stamp"} +out_parent=$("$dirname_path" -- "$out_dir") + +case "$cc_name" in + *[[:space:]]*) + fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" + ;; +esac + +case "$ar_name" in + *[[:space:]]*) + fail "AR must name one archiver executable" + ;; +esac + +case "$make_name" in + *[[:space:]]*) + fail "MAKE must name one build-driver executable" + ;; +esac + +case "$out_dir" in + *"/../"*|"../"*|*/..|..) + fail "evidence destination must not contain parent-directory traversal: $out_dir" + ;; +esac + +out_route=$out_dir +while [ "${out_route#./}" != "$out_route" ]; do + out_route=${out_route#./} +done + +case "$out_route" in + build|build/*|"$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not route through build/: $out_dir" + ;; +esac + +[ -d "$out_parent" ] || + fail "bundle parent directory does not exist: $out_parent" + +out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || + fail "could not resolve bundle parent: $out_parent" +out_leaf=$("$basename_path" -- "$out_dir") +out_abs="$out_parent_abs/$out_leaf" + +case "$out_abs" in + "$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not be inside build/: $out_dir" + ;; +esac + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination already exists; refusing overwrite: $out_dir" +fi + +replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || + fail "could not inspect Git replacement refs" + +[ -z "$replacement_refs" ] || + fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" + +revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || + fail "could not resolve source revision" + +"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || + fail "tracked Makefile is missing" +makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || + fail "could not resolve tracked Makefile at source revision" +[ -n "$makefile_blob" ] || + fail "tracked Makefile identity is empty" + +index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' + /^[a-z]/ || /^S / { print; exit } +') || fail "could not inspect Git index visibility flags" + +[ -z "$index_hidden" ] || + fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" + +ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || + fail "could not inspect ignored compiler-input trees" + +[ -z "$ignored_inputs" ] || + fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" + +git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || + fail "could not inspect Git working-tree state" + +[ -z "$git_status" ] || + fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" + +tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || + fail "could not enumerate tracked compiler inputs" + +[ -n "$tracked_inputs" ] || + fail "tracked compiler-input set is empty" + +validate_source_identity() +{ + current_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || + fail "could not re-inspect Git working-tree state" + [ -z "$current_status" ] || + fail "working tree changed during evidence capture" + + while IFS= read -r tracked_path; do + [ -n "$tracked_path" ] || continue + [ -f "$repo_root/$tracked_path" ] || + fail "tracked compiler input is missing from worktree: $tracked_path" + worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || + fail "could not hash raw worktree bytes: $tracked_path" + revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || + fail "could not resolve revision blob: $tracked_path" + [ "$worktree_blob" = "$revision_blob" ] || + fail "raw worktree bytes differ from source revision: $tracked_path" + done < "$archive_path" || + fail "could not materialize source archive for revision: $revision" + "$tar_path" -xf "$archive_path" -C "$source_snapshot" || + fail "could not extract source snapshot" + "$provenance_rm_path" -f "$archive_path" || + fail "could not remove temporary source archive" + + validate_snapshot_source_entries + validate_snapshot_identity + "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || + fail "could not make source snapshot read-only" +} + +cleanup_snapshot() +{ + if [ -d "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" || + fail "could not restore snapshot write permission for cleanup" + fi + "$provenance_rm_path" -rf "$source_snapshot" || + fail "could not remove source snapshot: $source_snapshot" + [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || + fail "source snapshot remains after cleanup: $source_snapshot" +} + +dirty=false + +cc_path=$(resolve_provenance_tool "$cc_name") || + fail "compiler not found in fixed provenance path: $cc_name" +cc_path=$(canonicalize_existing_path "$cc_path") || + fail "could not canonicalize compiler path: $cc_path" +case "$cc_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "compiler escaped fixed provenance path: $cc_path" ;; +esac +[ -n "$cc_path" ] && [ -x "$cc_path" ] || + fail "compiler path is not executable: $cc_path" + +compiler_version=$("$cc_path" --version 2>&1) || + fail "compiler identity command failed: $cc_path --version" +[ -n "$compiler_version" ] || + fail "compiler identity output is empty" + +ar_path=$(resolve_provenance_tool "$ar_name") || + fail "archiver not found in fixed provenance path: $ar_name" +ar_path=$(canonicalize_existing_path "$ar_path") || + fail "could not canonicalize archiver path: $ar_path" +case "$ar_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "archiver escaped fixed provenance path: $ar_path" ;; +esac +[ -n "$ar_path" ] && [ -x "$ar_path" ] || + fail "archiver path is not executable: $ar_path" + +if archiver_version=$("$ar_path" --version 2>&1); then + : +elif archiver_version=$("$ar_path" -V 2>&1); then + : +else + fail "archiver identity command failed: $ar_path" +fi +[ -n "$archiver_version" ] || + fail "archiver identity output is empty" + +make_path=$(resolve_provenance_tool "$make_name") || + fail "build driver not found in fixed provenance path: $make_name" +make_path=$(canonicalize_existing_path "$make_path") || + fail "could not canonicalize build-driver path: $make_path" +case "$make_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "build-driver escaped fixed provenance path: $make_path" ;; +esac +[ -x "$make_path" ] || + fail "build-driver path is not executable: $make_path" + +if make_version=$("$make_path" --version 2>&1); then + : +elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then + : +else + fail "build-driver identity command failed: $make_path" +fi +[ -n "$make_version" ] || + fail "build-driver identity output is empty" + +mkdir_path=$(resolve_provenance_tool mkdir) || + fail "mkdir not found in fixed provenance path" +rm_path=$(resolve_provenance_tool rm) || + fail "rm not found in fixed provenance path" +case "$mkdir_path:$rm_path" in + /*:/*) ;; + *) fail "build utility paths must be absolute" ;; +esac + +build_study() +{ + PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ + "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ + BUILD_DIR="$build_dir_rel" \ + CC="$cc_path" \ + AR="$ar_path" \ + CPPFLAGS="$cppflags" \ + CFLAGS="$cflags" +} + +cleanup_build() +{ + "$rm_path" -rf "$build_dir" || + fail "could not remove fresh evidence build directory: $build_dir" + [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || + fail "fresh evidence build directory remains after cleanup: $build_dir" +} + +memory_profile= +if [ -r /proc/meminfo ]; then + mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) + case "$mem_total_kib" in + ''|*[!0-9]*) ;; + *) memory_profile="mem_total_kib=$mem_total_kib" ;; + esac +fi + +if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then + for key in hw.memsize hw.physmem64 hw.physmem; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + case "$value" in + ''|*[!0-9]*) ;; + *) + memory_profile="mem_total_bytes=$value" + break + ;; + esac + done +fi + +if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then + phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) + page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) + + case "$phys_pages" in + ''|*[!0-9]*|0) phys_pages= ;; + esac + case "$page_size" in + ''|*[!0-9]*|0) page_size= ;; + esac + + if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then + memory_profile="mem_phys_pages=$phys_pages +mem_page_size_bytes=$page_size" + fi +fi + +[ -n "$memory_profile" ] || + fail "could not capture required memory profile" + +platform_identity=$("$uname_path" -a 2>&1) || + fail "platform identity command failed: $uname_path -a" +[ -n "$platform_identity" ] || + fail "platform identity output is empty" + +cpu_model= +if [ -r /proc/cpuinfo ]; then + cpu_model=$("$awk_path" -F ': ' ' + /^model name[[:space:]]*:/ { print $2; exit } + /^Hardware[[:space:]]*:/ { print $2; exit } + ' /proc/cpuinfo) +fi +if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then + for key in machdep.cpu.brand_string hw.model; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + if [ -n "$value" ]; then + cpu_model=$value + break + fi + done +fi + +capture_id="$stamp-$$" +source_snapshot_rel="build/r7-source-$capture_id" +source_snapshot="$repo_root/$source_snapshot_rel" +build_dir_rel="build/r7-evidence-$capture_id" +build_dir="$source_snapshot/$build_dir_rel" +study_target="$build_dir_rel/rune_r7_study" +study_executable="$source_snapshot/$study_target" +bundle_stage_rel="build/r7-bundle-stage-$capture_id" +bundle_stage="$repo_root/$bundle_stage_rel" +publish_stage="$out_parent_abs/.r7-publish-$capture_id" +cleanup_capture_state() +{ + if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : + "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : + fi + if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then + "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : + fi + if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then + "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : + fi +} + +trap cleanup_capture_state 0 1 2 3 15 + +if [ "$fresh_build_self_test" = true ]; then + materialize_source_snapshot + build_study + validate_snapshot_identity + "$study_executable" --bytes 32768 --repeats 1 >/dev/null + cleanup_snapshot + exit 0 +fi + +materialize_source_snapshot +build_study +validate_snapshot_identity +validate_source_identity + +[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || + fail "bundle staging destination already exists: $bundle_stage" +"$bundle_mkdir_path" "$bundle_stage" || + fail "could not create bundle staging directory: $bundle_stage" + +set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* +for bundle_entry in "$@"; do + [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue + fail "new bundle staging directory is not empty: $bundle_stage" +done + +observations_path="$bundle_stage/observations.tsv" + +{ + echo "contract=rune.r7.environment.v1" + echo "evidence_class=raw-local-execution-observation" + printf 'source_revision=%s\n' "$revision" + printf 'working_tree_dirty=%s\n' "$dirty" + printf '%s\n' "measurement_method=C99_clock_process_cpu_time" + printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" + printf 'makefile_path=%s\n' "$repo_root/Makefile" + printf 'makefile_blob=%s\n' "$makefile_blob" + printf 'repeats=%s\n' "$repeats" + printf 'git_provenance_path=%s\n' "$provenance_path" + printf 'git_resolved=%s\n' "$git_path" + printf 'sed_resolved=%s\n' "$sed_path" + printf 'awk_resolved=%s\n' "$awk_path" + printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" + printf 'tar_resolved=%s\n' "$tar_path" + printf 'chmod_resolved=%s\n' "$chmod_path" + printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'mv_resolved=%s\n' "$mv_path" + printf 'cp_resolved=%s\n' "$cp_path" + printf 'find_resolved=%s\n' "$find_path" + printf 'readlink_resolved=%s\n' "$readlink_path" + printf 'bundle_stage=%s\n' "$bundle_stage" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" + printf 'date_resolved=%s\n' "$date_path" + printf 'dirname_resolved=%s\n' "$dirname_path" + printf 'basename_resolved=%s\n' "$basename_path" + printf 'source_snapshot=%s\n' "$source_snapshot" + printf 'source_snapshot_revision=%s\n' "$revision" + printf '%s\n' "build_source_origin=git_archive_recorded_revision" + printf '%s\n' "build_source_worktree_used=false" + printf 'uname_resolved=%s\n' "$uname_path" + printf 'sha256_mode=%s\n' "$hash_mode" + printf 'sha256_resolved=%s\n' "$hash_path" + printf 'cc_requested=%s\n' "$cc_name" + printf 'cc_resolved=%s\n' "$cc_path" + printf 'ar_requested=%s\n' "$ar_name" + printf 'ar_resolved=%s\n' "$ar_path" + printf 'make_requested=%s\n' "$make_name" + printf 'make_resolved=%s\n' "$make_path" + printf 'build_path=%s\n' "$build_path" + printf 'mkdir_resolved=%s\n' "$mkdir_path" + printf 'rm_resolved=%s\n' "$rm_path" + printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" + printf 'fresh_build_dir=%s\n' "$build_dir" + printf 'fresh_study_target=%s\n' "$study_target" + printf 'cppflags=%s\n' "$cppflags" + printf 'cflags=%s\n' "$cflags" + echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" + echo "git_replace_objects=disabled and replacement refs forbidden" + echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" + echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" + echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" + echo "ignored_compiler_inputs=forbidden under src,include,study" + echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" + emit_key_value uname "$platform_identity" + if [ -n "$getconf_path" ]; then + processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) + long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) + printf 'processors_online=%s\n' "$processors_online" + printf 'long_bit=%s\n' "$long_bit" + fi + if [ -n "$cpu_model" ]; then + emit_key_value cpu_model "$cpu_model" + fi + printf '%s\n' "$memory_profile" +} > "$bundle_stage/environment.txt" + +{ + printf 'git_path=%s\n' "$git_path" + printf '%s\n' "$git_version" + printf 'sed_path=%s\n' "$sed_path" + printf 'awk_path=%s\n' "$awk_path" + printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" + printf 'tar_path=%s\n' "$tar_path" + printf 'chmod_path=%s\n' "$chmod_path" + printf 'provenance_rm_path=%s\n' "$provenance_rm_path" + printf 'mv_path=%s\n' "$mv_path" + printf 'cp_path=%s\n' "$cp_path" + printf 'find_path=%s\n' "$find_path" + printf 'readlink_path=%s\n' "$readlink_path" + printf 'date_path=%s\n' "$date_path" + printf 'dirname_path=%s\n' "$dirname_path" + printf 'basename_path=%s\n' "$basename_path" + printf 'uname_path=%s\n' "$uname_path" + printf 'sha256_path=%s\n' "$hash_path" + printf '%s\n' "$hash_version" + echo "compiler_path=$cc_path" + printf '%s\n' "$compiler_version" + echo "archiver_path=$ar_path" + printf '%s\n' "$archiver_version" + echo "build_driver_path=$make_path" + printf '%s\n' "$make_version" +} > "$bundle_stage/compiler.txt" + +{ + printf "set -eu\n" + printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" + printf "export GIT_NO_REPLACE_OBJECTS=1\n" + printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" + printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + printf "unset TAR_OPTIONS\n" + shell_quote "$bundle_mkdir_path" + printf " -p " + shell_quote "$repo_root/build" + printf '\n' + shell_quote "$bundle_mkdir_path" + printf " " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$git_path" + printf " -C " + shell_quote "$repo_root" + printf " archive --format=tar " + shell_quote "$revision" + printf " -- Makefile src include study > " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$tar_path" + printf " -xf " + shell_quote "$source_snapshot/.r7-source.tar" + printf " -C " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$provenance_rm_path" + printf " -f " + shell_quote "$source_snapshot/.r7-source.tar" + printf '\n' + shell_quote "$chmod_path" + printf " -R a-w " + shell_quote "$source_snapshot/Makefile" + printf " " + shell_quote "$source_snapshot/src" + printf " " + shell_quote "$source_snapshot/include" + printf " " + shell_quote "$source_snapshot/study" + printf '\n' + printf "PATH=" + shell_quote "$build_path" + printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " + shell_quote "$make_path" + printf " -C " + shell_quote "$source_snapshot" + printf " -f Makefile " + shell_quote "$study_target" + printf " BUILD_DIR=" + shell_quote "$build_dir_rel" + printf " CC=" + shell_quote "$cc_path" + printf " AR=" + shell_quote "$ar_path" + printf " CPPFLAGS=" + shell_quote "$cppflags" + printf " CFLAGS=" + shell_quote "$cflags" + printf '\n' + + shell_quote "$study_executable" + printf " --profile local --repeats " + shell_quote "$repeats" + printf " > " + shell_quote "$out_abs/observations.tsv" + printf '\n' + shell_quote "$chmod_path" + printf " -R u+w " + shell_quote "$source_snapshot" + printf '\n' + shell_quote "$provenance_rm_path" + printf " -rf " + shell_quote "$source_snapshot" + printf '\n' +} > "$bundle_stage/command.txt" + +"$study_executable" --profile local --repeats "$repeats" \ + > "$observations_path" + +validate_snapshot_identity +validate_source_identity +cleanup_snapshot + +case "$hash_mode" in + sha256sum) + ( + cd "$bundle_stage" + "$hash_path" \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + shasum) + ( + cd "$bundle_stage" + "$hash_path" -a 256 \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + *) + fail "unsupported SHA-256 utility mode: $hash_mode" + ;; +esac + +validate_source_identity + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination appeared during capture; refusing publish: $out_dir" +fi +[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || + fail "publish staging destination already exists: $publish_stage" + +"$bundle_mkdir_path" "$publish_stage" || + fail "could not create sibling publish staging directory" +"$cp_path" -R "$bundle_stage/." "$publish_stage/" || + fail "could not copy completed bundle to destination filesystem" + +case "$hash_mode" in + sha256sum) + ( + cd "$publish_stage" + "$hash_path" -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; + shasum) + ( + cd "$publish_stage" + "$hash_path" -a 256 -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; +esac + +"$provenance_rm_path" -rf "$bundle_stage" || + fail "could not remove repository bundle staging directory" + +if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then + fail "evidence destination appeared during publish; refusing rename: $out_abs" +fi + +"$mv_path" "$publish_stage" "$out_abs" || + fail "could not rename completed sibling staging bundle into place" +trap - 0 1 2 3 15 + +echo "R7 evidence bundle: $out_dir" +*) fail "CFLAGS must not contain Make variable expansion syntax ($); resolve it before capture" ;; +esac + repeats=${RUNE_R7_REPEATS:-5} case "$repeats" in ''|*[!0-9]*) From ad7136239ad4e8dfaa16fda2dd450f7c24757f5e Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:11:57 +0930 Subject: [PATCH 103/132] Add Make flag dirname and cleanup regressions --- tests/test_r7_run_local.sh | 88 ++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 80eebb4..af7c623 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -14,9 +14,9 @@ cc_name=${CC:-cc} ar_name=${AR:-ar} case "$cc_name" in - gcc|clang) system_cc="/usr/bin/$cc_name" ;; - /usr/bin/gcc|/usr/bin/clang) system_cc=$cc_name ;; - *) fail "CI regression expects gcc or clang from /usr/bin: $cc_name" ;; + cc|gcc|clang) system_cc="/usr/bin/$cc_name" ;; + /usr/bin/cc|/usr/bin/gcc|/usr/bin/clang) system_cc=$cc_name ;; + *) fail "R7 regression expects cc, gcc, or clang from /usr/bin: $cc_name" ;; esac case "$ar_name" in @@ -25,16 +25,18 @@ case "$ar_name" in *) fail "CI regression expects /usr/bin/ar: $ar_name" ;; esac -tmp_root="/tmp/rune-r7-evidence-regression-$$" +test_id=$ +tmp_root="/tmp/rune-r7-evidence-regression-$test_id" +publish_parent="/dev/shm/r7-publish-regression-$test_id" mkdir -p "$tmp_root" cleanup() { - rm -rf "$tmp_root" - rm -f /tmp/r7-reg-cc-$$ /tmp/r7-reg-ar-$$ /tmp/r7-reg-make-$$ - rm -f /tmp/r7-tar-hook-$ /tmp/r7-tar-hook-ran-$ - rm -f /tmp/r7-ccc-header-$.h - rm -f /tmp/r7-concurrent-a-$.log /tmp/r7-concurrent-b-$.log + rm -rf "$tmp_root" "$publish_parent" + rm -f "/tmp/r7-reg-cc-$test_id" "/tmp/r7-reg-ar-$test_id" "/tmp/r7-reg-make-$test_id" + rm -f "/tmp/r7-tar-hook-$test_id" "/tmp/r7-tar-hook-ran-$test_id" + rm -f "/tmp/r7-ccc-header-$test_id.h" + rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* } trap cleanup 0 1 2 3 15 @@ -51,6 +53,31 @@ expect_capture_failure() [ ! -e "$dest" ] || fail "$label left a requested destination" } +# Repository-root discovery must not consult ambient dirname. +fake_dirname_bin="$tmp_root/fake-dirname-bin" +mkdir -p "$fake_dirname_bin" +cat > "$fake_dirname_bin/dirname" <<'EOF' +#!/bin/sh +exit 97 +EOF +chmod +x "$fake_dirname_bin/dirname" +PATH="$fake_dirname_bin:$PATH" scripts/r7-run-local.sh --self-test-git-root + +# Caller flags must be literal build configuration, never recursive Make references. +hidden_header="/tmp/r7-hidden-header-$test_id.h" +cat > "$hidden_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF +expect_capture_failure make-reference-cppflags \ + env R7_HEADER="$hidden_header" 'CPPFLAGS=-include $(R7_HEADER)' \ + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh +expect_capture_failure make-reference-cflags \ + env R7_OPT='-O2' 'CFLAGS=$(R7_OPT)' \ + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh +rm -f "$hidden_header" + # Environment serialization must preserve backslashes and field boundaries. scripts/r7-run-local.sh --self-test-environment-serialization @@ -60,12 +87,12 @@ CCC_OVERRIDE_OPTIONS='#+-include +/tmp/should-not-exist.h' \ case "$system_cc" in *clang) - cat > /tmp/r7-ccc-header-$.h <<'EOF' + cat > /tmp/r7-ccc-header-$test_id.h <<'EOF' #undef CLOCKS_PER_SEC #define CLOCKS_PER_SEC 424242 EOF ccc_bundle="$tmp_root/ccc-override" - CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$.h" \ + CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$test_id.h" \ RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh "$ccc_bundle" >/dev/null if /usr/bin/awk -F '\t' '$16 == 424242 { bad=1 } END { exit bad ? 0 : 1 }' "$ccc_bundle/observations.tsv"; then @@ -73,7 +100,7 @@ EOF fi /usr/bin/grep -Fq 'CCC_OVERRIDE_OPTIONS' "$ccc_bundle/command.txt" || fail "replay does not explicitly clear CCC_OVERRIDE_OPTIONS" - CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$.h" \ + CCC_OVERRIDE_OPTIONS="#+-include +/tmp/r7-ccc-header-$test_id.h" \ /bin/sh "$ccc_bundle/command.txt" >/dev/null if /usr/bin/awk -F '\t' '$16 == 424242 { bad=1 } END { exit bad ? 0 : 1 }' "$ccc_bundle/observations.tsv"; then fail "CCC_OVERRIDE_OPTIONS changed replayed clock scale" @@ -89,21 +116,21 @@ run_concurrent_pair() rm -rf "$dest_a" "$dest_b" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ - scripts/r7-run-local.sh "$dest_a" > /tmp/r7-concurrent-a-$.log 2>&1 & + scripts/r7-run-local.sh "$dest_a" > /tmp/r7-concurrent-a-$test_id.log 2>&1 & pid_a=$! RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ - scripts/r7-run-local.sh "$dest_b" > /tmp/r7-concurrent-b-$.log 2>&1 & + scripts/r7-run-local.sh "$dest_b" > /tmp/r7-concurrent-b-$test_id.log 2>&1 & pid_b=$! if wait "$pid_a"; then status_a=0; else status_a=$?; fi if wait "$pid_b"; then status_b=0; else status_b=$?; fi [ "$status_a" -eq 0 ] || { - cat /tmp/r7-concurrent-a-$.log >&2 + cat /tmp/r7-concurrent-a-$test_id.log >&2 fail "$label capture A failed with status $status_a" } [ "$status_b" -eq 0 ] || { - cat /tmp/r7-concurrent-b-$.log >&2 + cat /tmp/r7-concurrent-b-$test_id.log >&2 fail "$label capture B failed with status $status_b" } @@ -130,23 +157,23 @@ rm -rf build run_concurrent_pair concurrent-missing-build # Canonical-path regression: lexical /usr/bin prefixes must not authorize /tmp. -cat > /tmp/r7-reg-cc-$$ < /tmp/r7-reg-cc-$test_id < /tmp/r7-reg-ar-$$ < /tmp/r7-reg-ar-$test_id < /tmp/r7-reg-make-$$ <<'EOF' +cat > /tmp/r7-reg-make-$test_id <<'EOF' #!/bin/sh exec /usr/bin/make "$@" EOF -chmod +x /tmp/r7-reg-cc-$$ /tmp/r7-reg-ar-$$ /tmp/r7-reg-make-$$ +chmod +x /tmp/r7-reg-cc-$test_id /tmp/r7-reg-ar-$test_id /tmp/r7-reg-make-$test_id -expect_capture_failure canonical-cc env RUNE_R7_REPEATS=1 CC="/usr/bin/../../tmp/r7-reg-cc-$$" AR="$system_ar" scripts/r7-run-local.sh -expect_capture_failure canonical-ar env RUNE_R7_REPEATS=1 CC="$system_cc" AR="/usr/bin/../../tmp/r7-reg-ar-$$" scripts/r7-run-local.sh -expect_capture_failure canonical-make env RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" MAKE="/usr/bin/../../tmp/r7-reg-make-$$" scripts/r7-run-local.sh +expect_capture_failure canonical-cc env RUNE_R7_REPEATS=1 CC="/usr/bin/../../tmp/r7-reg-cc-$test_id" AR="$system_ar" scripts/r7-run-local.sh +expect_capture_failure canonical-ar env RUNE_R7_REPEATS=1 CC="$system_cc" AR="/usr/bin/../../tmp/r7-reg-ar-$test_id" scripts/r7-run-local.sh +expect_capture_failure canonical-make env RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" MAKE="/usr/bin/../../tmp/r7-reg-make-$test_id" scripts/r7-run-local.sh # Replay must fail immediately and preserve observations when snapshot creation fails. replay_bundle="$tmp_root/replay" @@ -164,17 +191,17 @@ after_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk rm -f "$snapshot_path" # TAR_OPTIONS must be cleared for capture and replay; hook execution is forbidden. -cat > /tmp/r7-tar-hook-$$ < /tmp/r7-tar-hook-$test_id < /tmp/r7-tar-hook-ran-$$ +printf 'ran\n' > /tmp/r7-tar-hook-ran-$test_id EOF -chmod +x /tmp/r7-tar-hook-$$ +chmod +x /tmp/r7-tar-hook-$test_id tar_bundle="$tmp_root/tar" -TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$$" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$tar_bundle" >/dev/null -[ ! -e /tmp/r7-tar-hook-ran-$$ ] || +TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$test_id" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$tar_bundle" >/dev/null +[ ! -e /tmp/r7-tar-hook-ran-$test_id ] || fail "TAR_OPTIONS hook executed during capture" -TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$$" /bin/sh "$tar_bundle/command.txt" >/dev/null -[ ! -e /tmp/r7-tar-hook-ran-$$ ] || +TAR_OPTIONS="--checkpoint=1 --checkpoint-action=exec=/tmp/r7-tar-hook-$test_id" /bin/sh "$tar_bundle/command.txt" >/dev/null +[ ! -e /tmp/r7-tar-hook-ran-$test_id ] || fail "TAR_OPTIONS hook executed during replay" if /usr/bin/awk -F '\t' '$16 == 616161 { bad=1 } END { exit bad ? 0 : 1 }' "$tar_bundle/observations.tsv"; then fail "tar injection changed the study clock scale" @@ -183,7 +210,6 @@ fi # Failed destination-filesystem copy must never create the immutable final path. [ -d /dev/shm ] && [ -w /dev/shm ] || fail "/dev/shm is required for deterministic publication regression" -publish_parent="/dev/shm/r7-publish-regression-$$" publish_dest="$publish_parent/evidence" fill_file="$publish_parent/fill" mkdir -p "$publish_parent" From 5c3e29d62be593951b96cb85ad696a936b5c96be Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:12:45 +0930 Subject: [PATCH 104/132] Repair literal Make-flag validation --- scripts/r7-run-local.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index eaf85c2..3d1ff26 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -263,7 +263,13 @@ cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} case "$cppflags" in - *' + *'$'*) fail "CPPFLAGS must not contain dollar signs or Make variable references; resolve them before capture" ;; +esac +case "$cflags" in + *'$'*) fail "CFLAGS must not contain dollar signs or Make variable references; resolve them before capture" ;; +esac + +repeats=${RUNE_R7_REPEATS:-5} case "$repeats" in ''|*[!0-9]*) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" From c7679eb547c909f9d36485369bdbd4412fb5515c Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:12:55 +0930 Subject: [PATCH 105/132] Repair regression harness PID identity --- tests/test_r7_run_local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index af7c623..c3e73d2 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -25,7 +25,7 @@ case "$ar_name" in *) fail "CI regression expects /usr/bin/ar: $ar_name" ;; esac -test_id=$ +test_id=$$ tmp_root="/tmp/rune-r7-evidence-regression-$test_id" publish_parent="/dev/shm/r7-publish-regression-$test_id" mkdir -p "$tmp_root" From 9943b3c5ff18d111d67edd77c2ca8709951b41bb Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:13:58 +0930 Subject: [PATCH 106/132] Make default R7 regression target use fixed cc --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e22542..ce0de63 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,9 @@ r7-clock-regression: $(R7_CLOCK_REGRESSION) ./$(R7_CLOCK_REGRESSION) r7-evidence-regression: - CC="$(CC)" AR="$(AR)" sh tests/test_r7_run_local.sh + @r7_cc='$(CC)'; \ + if [ "$r7_cc" = cc ]; then r7_cc=/usr/bin/cc; fi; \ + CC="$r7_cc" AR="$(AR)" sh tests/test_r7_run_local.sh $(CORPUS): corpus/rune_corpus.c $(LIB) include/rune/arena.h include/rune/numeric.h include/rune/region.h include/rune/status.h $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) corpus/rune_corpus.c $(LIB) -o $@ From e2b27b47acc8232db6c59c2a049ec777f22ac63d Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:14:51 +0930 Subject: [PATCH 107/132] Preserve shell variable in R7 regression target --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ce0de63..f08b226 100644 --- a/Makefile +++ b/Makefile @@ -88,8 +88,8 @@ r7-clock-regression: $(R7_CLOCK_REGRESSION) r7-evidence-regression: @r7_cc='$(CC)'; \ - if [ "$r7_cc" = cc ]; then r7_cc=/usr/bin/cc; fi; \ - CC="$r7_cc" AR="$(AR)" sh tests/test_r7_run_local.sh + if [ "$$r7_cc" = cc ]; then r7_cc=/usr/bin/cc; fi; \ + CC="$$r7_cc" AR="$(AR)" sh tests/test_r7_run_local.sh $(CORPUS): corpus/rune_corpus.c $(LIB) include/rune/arena.h include/rune/numeric.h include/rune/region.h include/rune/status.h $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) corpus/rune_corpus.c $(LIB) -o $@ From 6299084de216ec5eefa352db0e240cfea953cbba Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:15:56 +0930 Subject: [PATCH 108/132] Remove stale appended R7 wrapper fragment --- scripts/r7-run-local.sh | 1364 --------------------------------------- 1 file changed, 1364 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 3d1ff26..091e8d3 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -948,1367 +948,3 @@ fi trap - 0 1 2 3 15 echo "R7 evidence bundle: $out_dir" -*) fail "CPPFLAGS must not contain Make variable expansion syntax ($); resolve it before capture" ;; -esac -case "$cflags" in - *' -case "$repeats" in - ''|*[!0-9]*) - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" - ;; -esac -normalized_repeats=$repeats -while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do - normalized_repeats=${normalized_repeats#0} -done -[ -n "$normalized_repeats" ] || - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" -case "$normalized_repeats" in - [1-9]|[1-9][0-9]|100) ;; - *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; -esac -stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) -out_dir=${1:-"evidence/r7/local-$stamp"} -out_parent=$("$dirname_path" -- "$out_dir") - -case "$cc_name" in - *[[:space:]]*) - fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" - ;; -esac - -case "$ar_name" in - *[[:space:]]*) - fail "AR must name one archiver executable" - ;; -esac - -case "$make_name" in - *[[:space:]]*) - fail "MAKE must name one build-driver executable" - ;; -esac - -case "$out_dir" in - *"/../"*|"../"*|*/..|..) - fail "evidence destination must not contain parent-directory traversal: $out_dir" - ;; -esac - -out_route=$out_dir -while [ "${out_route#./}" != "$out_route" ]; do - out_route=${out_route#./} -done - -case "$out_route" in - build|build/*|"$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not route through build/: $out_dir" - ;; -esac - -[ -d "$out_parent" ] || - fail "bundle parent directory does not exist: $out_parent" - -out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || - fail "could not resolve bundle parent: $out_parent" -out_leaf=$("$basename_path" -- "$out_dir") -out_abs="$out_parent_abs/$out_leaf" - -case "$out_abs" in - "$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not be inside build/: $out_dir" - ;; -esac - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination already exists; refusing overwrite: $out_dir" -fi - -replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || - fail "could not inspect Git replacement refs" - -[ -z "$replacement_refs" ] || - fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" - -revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || - fail "could not resolve source revision" - -"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || - fail "tracked Makefile is missing" -makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || - fail "could not resolve tracked Makefile at source revision" -[ -n "$makefile_blob" ] || - fail "tracked Makefile identity is empty" - -index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' - /^[a-z]/ || /^S / { print; exit } -') || fail "could not inspect Git index visibility flags" - -[ -z "$index_hidden" ] || - fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" - -ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || - fail "could not inspect ignored compiler-input trees" - -[ -z "$ignored_inputs" ] || - fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" - -git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not inspect Git working-tree state" - -[ -z "$git_status" ] || - fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" - -tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || - fail "could not enumerate tracked compiler inputs" - -[ -n "$tracked_inputs" ] || - fail "tracked compiler-input set is empty" - -validate_source_identity() -{ - current_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not re-inspect Git working-tree state" - [ -z "$current_status" ] || - fail "working tree changed during evidence capture" - - while IFS= read -r tracked_path; do - [ -n "$tracked_path" ] || continue - [ -f "$repo_root/$tracked_path" ] || - fail "tracked compiler input is missing from worktree: $tracked_path" - worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || - fail "could not hash raw worktree bytes: $tracked_path" - revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || - fail "could not resolve revision blob: $tracked_path" - [ "$worktree_blob" = "$revision_blob" ] || - fail "raw worktree bytes differ from source revision: $tracked_path" - done < "$archive_path" || - fail "could not materialize source archive for revision: $revision" - "$tar_path" -xf "$archive_path" -C "$source_snapshot" || - fail "could not extract source snapshot" - "$provenance_rm_path" -f "$archive_path" || - fail "could not remove temporary source archive" - - validate_snapshot_source_entries - validate_snapshot_identity - "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || - fail "could not make source snapshot read-only" -} - -cleanup_snapshot() -{ - if [ -d "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" || - fail "could not restore snapshot write permission for cleanup" - fi - "$provenance_rm_path" -rf "$source_snapshot" || - fail "could not remove source snapshot: $source_snapshot" - [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || - fail "source snapshot remains after cleanup: $source_snapshot" -} - -dirty=false - -cc_path=$(resolve_provenance_tool "$cc_name") || - fail "compiler not found in fixed provenance path: $cc_name" -cc_path=$(canonicalize_existing_path "$cc_path") || - fail "could not canonicalize compiler path: $cc_path" -case "$cc_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "compiler escaped fixed provenance path: $cc_path" ;; -esac -[ -n "$cc_path" ] && [ -x "$cc_path" ] || - fail "compiler path is not executable: $cc_path" - -compiler_version=$("$cc_path" --version 2>&1) || - fail "compiler identity command failed: $cc_path --version" -[ -n "$compiler_version" ] || - fail "compiler identity output is empty" - -ar_path=$(resolve_provenance_tool "$ar_name") || - fail "archiver not found in fixed provenance path: $ar_name" -ar_path=$(canonicalize_existing_path "$ar_path") || - fail "could not canonicalize archiver path: $ar_path" -case "$ar_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "archiver escaped fixed provenance path: $ar_path" ;; -esac -[ -n "$ar_path" ] && [ -x "$ar_path" ] || - fail "archiver path is not executable: $ar_path" - -if archiver_version=$("$ar_path" --version 2>&1); then - : -elif archiver_version=$("$ar_path" -V 2>&1); then - : -else - fail "archiver identity command failed: $ar_path" -fi -[ -n "$archiver_version" ] || - fail "archiver identity output is empty" - -make_path=$(resolve_provenance_tool "$make_name") || - fail "build driver not found in fixed provenance path: $make_name" -make_path=$(canonicalize_existing_path "$make_path") || - fail "could not canonicalize build-driver path: $make_path" -case "$make_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "build-driver escaped fixed provenance path: $make_path" ;; -esac -[ -x "$make_path" ] || - fail "build-driver path is not executable: $make_path" - -if make_version=$("$make_path" --version 2>&1); then - : -elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then - : -else - fail "build-driver identity command failed: $make_path" -fi -[ -n "$make_version" ] || - fail "build-driver identity output is empty" - -mkdir_path=$(resolve_provenance_tool mkdir) || - fail "mkdir not found in fixed provenance path" -rm_path=$(resolve_provenance_tool rm) || - fail "rm not found in fixed provenance path" -case "$mkdir_path:$rm_path" in - /*:/*) ;; - *) fail "build utility paths must be absolute" ;; -esac - -build_study() -{ - PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ - "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ - BUILD_DIR="$build_dir_rel" \ - CC="$cc_path" \ - AR="$ar_path" \ - CPPFLAGS="$cppflags" \ - CFLAGS="$cflags" -} - -cleanup_build() -{ - "$rm_path" -rf "$build_dir" || - fail "could not remove fresh evidence build directory: $build_dir" - [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || - fail "fresh evidence build directory remains after cleanup: $build_dir" -} - -memory_profile= -if [ -r /proc/meminfo ]; then - mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) - case "$mem_total_kib" in - ''|*[!0-9]*) ;; - *) memory_profile="mem_total_kib=$mem_total_kib" ;; - esac -fi - -if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then - for key in hw.memsize hw.physmem64 hw.physmem; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - case "$value" in - ''|*[!0-9]*) ;; - *) - memory_profile="mem_total_bytes=$value" - break - ;; - esac - done -fi - -if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then - phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) - page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) - - case "$phys_pages" in - ''|*[!0-9]*|0) phys_pages= ;; - esac - case "$page_size" in - ''|*[!0-9]*|0) page_size= ;; - esac - - if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then - memory_profile="mem_phys_pages=$phys_pages -mem_page_size_bytes=$page_size" - fi -fi - -[ -n "$memory_profile" ] || - fail "could not capture required memory profile" - -platform_identity=$("$uname_path" -a 2>&1) || - fail "platform identity command failed: $uname_path -a" -[ -n "$platform_identity" ] || - fail "platform identity output is empty" - -cpu_model= -if [ -r /proc/cpuinfo ]; then - cpu_model=$("$awk_path" -F ': ' ' - /^model name[[:space:]]*:/ { print $2; exit } - /^Hardware[[:space:]]*:/ { print $2; exit } - ' /proc/cpuinfo) -fi -if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then - for key in machdep.cpu.brand_string hw.model; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - if [ -n "$value" ]; then - cpu_model=$value - break - fi - done -fi - -capture_id="$stamp-$$" -source_snapshot_rel="build/r7-source-$capture_id" -source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$capture_id" -build_dir="$source_snapshot/$build_dir_rel" -study_target="$build_dir_rel/rune_r7_study" -study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$capture_id" -bundle_stage="$repo_root/$bundle_stage_rel" -publish_stage="$out_parent_abs/.r7-publish-$capture_id" -cleanup_capture_state() -{ - if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : - "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : - fi - if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then - "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : - fi - if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then - "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : - fi -} - -trap cleanup_capture_state 0 1 2 3 15 - -if [ "$fresh_build_self_test" = true ]; then - materialize_source_snapshot - build_study - validate_snapshot_identity - "$study_executable" --bytes 32768 --repeats 1 >/dev/null - cleanup_snapshot - exit 0 -fi - -materialize_source_snapshot -build_study -validate_snapshot_identity -validate_source_identity - -[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || - fail "bundle staging destination already exists: $bundle_stage" -"$bundle_mkdir_path" "$bundle_stage" || - fail "could not create bundle staging directory: $bundle_stage" - -set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* -for bundle_entry in "$@"; do - [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue - fail "new bundle staging directory is not empty: $bundle_stage" -done - -observations_path="$bundle_stage/observations.tsv" - -{ - echo "contract=rune.r7.environment.v1" - echo "evidence_class=raw-local-execution-observation" - printf 'source_revision=%s\n' "$revision" - printf 'working_tree_dirty=%s\n' "$dirty" - printf '%s\n' "measurement_method=C99_clock_process_cpu_time" - printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" - printf 'makefile_path=%s\n' "$repo_root/Makefile" - printf 'makefile_blob=%s\n' "$makefile_blob" - printf 'repeats=%s\n' "$repeats" - printf 'git_provenance_path=%s\n' "$provenance_path" - printf 'git_resolved=%s\n' "$git_path" - printf 'sed_resolved=%s\n' "$sed_path" - printf 'awk_resolved=%s\n' "$awk_path" - printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" - printf 'tar_resolved=%s\n' "$tar_path" - printf 'chmod_resolved=%s\n' "$chmod_path" - printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" - printf 'mv_resolved=%s\n' "$mv_path" - printf 'cp_resolved=%s\n' "$cp_path" - printf 'find_resolved=%s\n' "$find_path" - printf 'readlink_resolved=%s\n' "$readlink_path" - printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" - printf 'date_resolved=%s\n' "$date_path" - printf 'dirname_resolved=%s\n' "$dirname_path" - printf 'basename_resolved=%s\n' "$basename_path" - printf 'source_snapshot=%s\n' "$source_snapshot" - printf 'source_snapshot_revision=%s\n' "$revision" - printf '%s\n' "build_source_origin=git_archive_recorded_revision" - printf '%s\n' "build_source_worktree_used=false" - printf 'uname_resolved=%s\n' "$uname_path" - printf 'sha256_mode=%s\n' "$hash_mode" - printf 'sha256_resolved=%s\n' "$hash_path" - printf 'cc_requested=%s\n' "$cc_name" - printf 'cc_resolved=%s\n' "$cc_path" - printf 'ar_requested=%s\n' "$ar_name" - printf 'ar_resolved=%s\n' "$ar_path" - printf 'make_requested=%s\n' "$make_name" - printf 'make_resolved=%s\n' "$make_path" - printf 'build_path=%s\n' "$build_path" - printf 'mkdir_resolved=%s\n' "$mkdir_path" - printf 'rm_resolved=%s\n' "$rm_path" - printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" - printf 'fresh_build_dir=%s\n' "$build_dir" - printf 'fresh_study_target=%s\n' "$study_target" - printf 'cppflags=%s\n' "$cppflags" - printf 'cflags=%s\n' "$cflags" - echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" - echo "git_replace_objects=disabled and replacement refs forbidden" - echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" - echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" - echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" - echo "ignored_compiler_inputs=forbidden under src,include,study" - echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" - emit_key_value uname "$platform_identity" - if [ -n "$getconf_path" ]; then - processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) - long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) - printf 'processors_online=%s\n' "$processors_online" - printf 'long_bit=%s\n' "$long_bit" - fi - if [ -n "$cpu_model" ]; then - emit_key_value cpu_model "$cpu_model" - fi - printf '%s\n' "$memory_profile" -} > "$bundle_stage/environment.txt" - -{ - printf 'git_path=%s\n' "$git_path" - printf '%s\n' "$git_version" - printf 'sed_path=%s\n' "$sed_path" - printf 'awk_path=%s\n' "$awk_path" - printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" - printf 'tar_path=%s\n' "$tar_path" - printf 'chmod_path=%s\n' "$chmod_path" - printf 'provenance_rm_path=%s\n' "$provenance_rm_path" - printf 'mv_path=%s\n' "$mv_path" - printf 'cp_path=%s\n' "$cp_path" - printf 'find_path=%s\n' "$find_path" - printf 'readlink_path=%s\n' "$readlink_path" - printf 'date_path=%s\n' "$date_path" - printf 'dirname_path=%s\n' "$dirname_path" - printf 'basename_path=%s\n' "$basename_path" - printf 'uname_path=%s\n' "$uname_path" - printf 'sha256_path=%s\n' "$hash_path" - printf '%s\n' "$hash_version" - echo "compiler_path=$cc_path" - printf '%s\n' "$compiler_version" - echo "archiver_path=$ar_path" - printf '%s\n' "$archiver_version" - echo "build_driver_path=$make_path" - printf '%s\n' "$make_version" -} > "$bundle_stage/compiler.txt" - -{ - printf "set -eu\n" - printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" - printf "export GIT_NO_REPLACE_OBJECTS=1\n" - printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" - printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" - printf "unset TAR_OPTIONS\n" - shell_quote "$bundle_mkdir_path" - printf " -p " - shell_quote "$repo_root/build" - printf '\n' - shell_quote "$bundle_mkdir_path" - printf " " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$git_path" - printf " -C " - shell_quote "$repo_root" - printf " archive --format=tar " - shell_quote "$revision" - printf " -- Makefile src include study > " - shell_quote "$source_snapshot/.r7-source.tar" - printf '\n' - shell_quote "$tar_path" - printf " -xf " - shell_quote "$source_snapshot/.r7-source.tar" - printf " -C " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$provenance_rm_path" - printf " -f " - shell_quote "$source_snapshot/.r7-source.tar" - printf '\n' - shell_quote "$chmod_path" - printf " -R a-w " - shell_quote "$source_snapshot/Makefile" - printf " " - shell_quote "$source_snapshot/src" - printf " " - shell_quote "$source_snapshot/include" - printf " " - shell_quote "$source_snapshot/study" - printf '\n' - printf "PATH=" - shell_quote "$build_path" - printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " - shell_quote "$make_path" - printf " -C " - shell_quote "$source_snapshot" - printf " -f Makefile " - shell_quote "$study_target" - printf " BUILD_DIR=" - shell_quote "$build_dir_rel" - printf " CC=" - shell_quote "$cc_path" - printf " AR=" - shell_quote "$ar_path" - printf " CPPFLAGS=" - shell_quote "$cppflags" - printf " CFLAGS=" - shell_quote "$cflags" - printf '\n' - - shell_quote "$study_executable" - printf " --profile local --repeats " - shell_quote "$repeats" - printf " > " - shell_quote "$out_abs/observations.tsv" - printf '\n' - shell_quote "$chmod_path" - printf " -R u+w " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$provenance_rm_path" - printf " -rf " - shell_quote "$source_snapshot" - printf '\n' -} > "$bundle_stage/command.txt" - -"$study_executable" --profile local --repeats "$repeats" \ - > "$observations_path" - -validate_snapshot_identity -validate_source_identity -cleanup_snapshot - -case "$hash_mode" in - sha256sum) - ( - cd "$bundle_stage" - "$hash_path" \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - shasum) - ( - cd "$bundle_stage" - "$hash_path" -a 256 \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - *) - fail "unsupported SHA-256 utility mode: $hash_mode" - ;; -esac - -validate_source_identity - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination appeared during capture; refusing publish: $out_dir" -fi -[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || - fail "publish staging destination already exists: $publish_stage" - -"$bundle_mkdir_path" "$publish_stage" || - fail "could not create sibling publish staging directory" -"$cp_path" -R "$bundle_stage/." "$publish_stage/" || - fail "could not copy completed bundle to destination filesystem" - -case "$hash_mode" in - sha256sum) - ( - cd "$publish_stage" - "$hash_path" -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; - shasum) - ( - cd "$publish_stage" - "$hash_path" -a 256 -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; -esac - -"$provenance_rm_path" -rf "$bundle_stage" || - fail "could not remove repository bundle staging directory" - -if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then - fail "evidence destination appeared during publish; refusing rename: $out_abs" -fi - -"$mv_path" "$publish_stage" "$out_abs" || - fail "could not rename completed sibling staging bundle into place" -trap - 0 1 2 3 15 - -echo "R7 evidence bundle: $out_dir" -*) fail "CFLAGS must not contain Make variable expansion syntax ($); resolve it before capture" ;; -esac - -repeats=${RUNE_R7_REPEATS:-5} -case "$repeats" in - ''|*[!0-9]*) - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" - ;; -esac -normalized_repeats=$repeats -while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do - normalized_repeats=${normalized_repeats#0} -done -[ -n "$normalized_repeats" ] || - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" -case "$normalized_repeats" in - [1-9]|[1-9][0-9]|100) ;; - *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; -esac -stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) -out_dir=${1:-"evidence/r7/local-$stamp"} -out_parent=$("$dirname_path" -- "$out_dir") - -case "$cc_name" in - *[[:space:]]*) - fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" - ;; -esac - -case "$ar_name" in - *[[:space:]]*) - fail "AR must name one archiver executable" - ;; -esac - -case "$make_name" in - *[[:space:]]*) - fail "MAKE must name one build-driver executable" - ;; -esac - -case "$out_dir" in - *"/../"*|"../"*|*/..|..) - fail "evidence destination must not contain parent-directory traversal: $out_dir" - ;; -esac - -out_route=$out_dir -while [ "${out_route#./}" != "$out_route" ]; do - out_route=${out_route#./} -done - -case "$out_route" in - build|build/*|"$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not route through build/: $out_dir" - ;; -esac - -[ -d "$out_parent" ] || - fail "bundle parent directory does not exist: $out_parent" - -out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || - fail "could not resolve bundle parent: $out_parent" -out_leaf=$("$basename_path" -- "$out_dir") -out_abs="$out_parent_abs/$out_leaf" - -case "$out_abs" in - "$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not be inside build/: $out_dir" - ;; -esac - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination already exists; refusing overwrite: $out_dir" -fi - -replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || - fail "could not inspect Git replacement refs" - -[ -z "$replacement_refs" ] || - fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" - -revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || - fail "could not resolve source revision" - -"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || - fail "tracked Makefile is missing" -makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || - fail "could not resolve tracked Makefile at source revision" -[ -n "$makefile_blob" ] || - fail "tracked Makefile identity is empty" - -index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' - /^[a-z]/ || /^S / { print; exit } -') || fail "could not inspect Git index visibility flags" - -[ -z "$index_hidden" ] || - fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" - -ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || - fail "could not inspect ignored compiler-input trees" - -[ -z "$ignored_inputs" ] || - fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" - -git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not inspect Git working-tree state" - -[ -z "$git_status" ] || - fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" - -tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || - fail "could not enumerate tracked compiler inputs" - -[ -n "$tracked_inputs" ] || - fail "tracked compiler-input set is empty" - -validate_source_identity() -{ - current_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not re-inspect Git working-tree state" - [ -z "$current_status" ] || - fail "working tree changed during evidence capture" - - while IFS= read -r tracked_path; do - [ -n "$tracked_path" ] || continue - [ -f "$repo_root/$tracked_path" ] || - fail "tracked compiler input is missing from worktree: $tracked_path" - worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || - fail "could not hash raw worktree bytes: $tracked_path" - revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || - fail "could not resolve revision blob: $tracked_path" - [ "$worktree_blob" = "$revision_blob" ] || - fail "raw worktree bytes differ from source revision: $tracked_path" - done < "$archive_path" || - fail "could not materialize source archive for revision: $revision" - "$tar_path" -xf "$archive_path" -C "$source_snapshot" || - fail "could not extract source snapshot" - "$provenance_rm_path" -f "$archive_path" || - fail "could not remove temporary source archive" - - validate_snapshot_source_entries - validate_snapshot_identity - "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || - fail "could not make source snapshot read-only" -} - -cleanup_snapshot() -{ - if [ -d "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" || - fail "could not restore snapshot write permission for cleanup" - fi - "$provenance_rm_path" -rf "$source_snapshot" || - fail "could not remove source snapshot: $source_snapshot" - [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || - fail "source snapshot remains after cleanup: $source_snapshot" -} - -dirty=false - -cc_path=$(resolve_provenance_tool "$cc_name") || - fail "compiler not found in fixed provenance path: $cc_name" -cc_path=$(canonicalize_existing_path "$cc_path") || - fail "could not canonicalize compiler path: $cc_path" -case "$cc_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "compiler escaped fixed provenance path: $cc_path" ;; -esac -[ -n "$cc_path" ] && [ -x "$cc_path" ] || - fail "compiler path is not executable: $cc_path" - -compiler_version=$("$cc_path" --version 2>&1) || - fail "compiler identity command failed: $cc_path --version" -[ -n "$compiler_version" ] || - fail "compiler identity output is empty" - -ar_path=$(resolve_provenance_tool "$ar_name") || - fail "archiver not found in fixed provenance path: $ar_name" -ar_path=$(canonicalize_existing_path "$ar_path") || - fail "could not canonicalize archiver path: $ar_path" -case "$ar_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "archiver escaped fixed provenance path: $ar_path" ;; -esac -[ -n "$ar_path" ] && [ -x "$ar_path" ] || - fail "archiver path is not executable: $ar_path" - -if archiver_version=$("$ar_path" --version 2>&1); then - : -elif archiver_version=$("$ar_path" -V 2>&1); then - : -else - fail "archiver identity command failed: $ar_path" -fi -[ -n "$archiver_version" ] || - fail "archiver identity output is empty" - -make_path=$(resolve_provenance_tool "$make_name") || - fail "build driver not found in fixed provenance path: $make_name" -make_path=$(canonicalize_existing_path "$make_path") || - fail "could not canonicalize build-driver path: $make_path" -case "$make_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "build-driver escaped fixed provenance path: $make_path" ;; -esac -[ -x "$make_path" ] || - fail "build-driver path is not executable: $make_path" - -if make_version=$("$make_path" --version 2>&1); then - : -elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then - : -else - fail "build-driver identity command failed: $make_path" -fi -[ -n "$make_version" ] || - fail "build-driver identity output is empty" - -mkdir_path=$(resolve_provenance_tool mkdir) || - fail "mkdir not found in fixed provenance path" -rm_path=$(resolve_provenance_tool rm) || - fail "rm not found in fixed provenance path" -case "$mkdir_path:$rm_path" in - /*:/*) ;; - *) fail "build utility paths must be absolute" ;; -esac - -build_study() -{ - PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ - "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ - BUILD_DIR="$build_dir_rel" \ - CC="$cc_path" \ - AR="$ar_path" \ - CPPFLAGS="$cppflags" \ - CFLAGS="$cflags" -} - -cleanup_build() -{ - "$rm_path" -rf "$build_dir" || - fail "could not remove fresh evidence build directory: $build_dir" - [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || - fail "fresh evidence build directory remains after cleanup: $build_dir" -} - -memory_profile= -if [ -r /proc/meminfo ]; then - mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) - case "$mem_total_kib" in - ''|*[!0-9]*) ;; - *) memory_profile="mem_total_kib=$mem_total_kib" ;; - esac -fi - -if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then - for key in hw.memsize hw.physmem64 hw.physmem; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - case "$value" in - ''|*[!0-9]*) ;; - *) - memory_profile="mem_total_bytes=$value" - break - ;; - esac - done -fi - -if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then - phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) - page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) - - case "$phys_pages" in - ''|*[!0-9]*|0) phys_pages= ;; - esac - case "$page_size" in - ''|*[!0-9]*|0) page_size= ;; - esac - - if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then - memory_profile="mem_phys_pages=$phys_pages -mem_page_size_bytes=$page_size" - fi -fi - -[ -n "$memory_profile" ] || - fail "could not capture required memory profile" - -platform_identity=$("$uname_path" -a 2>&1) || - fail "platform identity command failed: $uname_path -a" -[ -n "$platform_identity" ] || - fail "platform identity output is empty" - -cpu_model= -if [ -r /proc/cpuinfo ]; then - cpu_model=$("$awk_path" -F ': ' ' - /^model name[[:space:]]*:/ { print $2; exit } - /^Hardware[[:space:]]*:/ { print $2; exit } - ' /proc/cpuinfo) -fi -if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then - for key in machdep.cpu.brand_string hw.model; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - if [ -n "$value" ]; then - cpu_model=$value - break - fi - done -fi - -capture_id="$stamp-$$" -source_snapshot_rel="build/r7-source-$capture_id" -source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$capture_id" -build_dir="$source_snapshot/$build_dir_rel" -study_target="$build_dir_rel/rune_r7_study" -study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$capture_id" -bundle_stage="$repo_root/$bundle_stage_rel" -publish_stage="$out_parent_abs/.r7-publish-$capture_id" -cleanup_capture_state() -{ - if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : - "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : - fi - if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then - "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : - fi - if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then - "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : - fi -} - -trap cleanup_capture_state 0 1 2 3 15 - -if [ "$fresh_build_self_test" = true ]; then - materialize_source_snapshot - build_study - validate_snapshot_identity - "$study_executable" --bytes 32768 --repeats 1 >/dev/null - cleanup_snapshot - exit 0 -fi - -materialize_source_snapshot -build_study -validate_snapshot_identity -validate_source_identity - -[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || - fail "bundle staging destination already exists: $bundle_stage" -"$bundle_mkdir_path" "$bundle_stage" || - fail "could not create bundle staging directory: $bundle_stage" - -set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* -for bundle_entry in "$@"; do - [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue - fail "new bundle staging directory is not empty: $bundle_stage" -done - -observations_path="$bundle_stage/observations.tsv" - -{ - echo "contract=rune.r7.environment.v1" - echo "evidence_class=raw-local-execution-observation" - printf 'source_revision=%s\n' "$revision" - printf 'working_tree_dirty=%s\n' "$dirty" - printf '%s\n' "measurement_method=C99_clock_process_cpu_time" - printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" - printf 'makefile_path=%s\n' "$repo_root/Makefile" - printf 'makefile_blob=%s\n' "$makefile_blob" - printf 'repeats=%s\n' "$repeats" - printf 'git_provenance_path=%s\n' "$provenance_path" - printf 'git_resolved=%s\n' "$git_path" - printf 'sed_resolved=%s\n' "$sed_path" - printf 'awk_resolved=%s\n' "$awk_path" - printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" - printf 'tar_resolved=%s\n' "$tar_path" - printf 'chmod_resolved=%s\n' "$chmod_path" - printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" - printf 'mv_resolved=%s\n' "$mv_path" - printf 'cp_resolved=%s\n' "$cp_path" - printf 'find_resolved=%s\n' "$find_path" - printf 'readlink_resolved=%s\n' "$readlink_path" - printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" - printf 'date_resolved=%s\n' "$date_path" - printf 'dirname_resolved=%s\n' "$dirname_path" - printf 'basename_resolved=%s\n' "$basename_path" - printf 'source_snapshot=%s\n' "$source_snapshot" - printf 'source_snapshot_revision=%s\n' "$revision" - printf '%s\n' "build_source_origin=git_archive_recorded_revision" - printf '%s\n' "build_source_worktree_used=false" - printf 'uname_resolved=%s\n' "$uname_path" - printf 'sha256_mode=%s\n' "$hash_mode" - printf 'sha256_resolved=%s\n' "$hash_path" - printf 'cc_requested=%s\n' "$cc_name" - printf 'cc_resolved=%s\n' "$cc_path" - printf 'ar_requested=%s\n' "$ar_name" - printf 'ar_resolved=%s\n' "$ar_path" - printf 'make_requested=%s\n' "$make_name" - printf 'make_resolved=%s\n' "$make_path" - printf 'build_path=%s\n' "$build_path" - printf 'mkdir_resolved=%s\n' "$mkdir_path" - printf 'rm_resolved=%s\n' "$rm_path" - printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" - printf 'fresh_build_dir=%s\n' "$build_dir" - printf 'fresh_study_target=%s\n' "$study_target" - printf 'cppflags=%s\n' "$cppflags" - printf 'cflags=%s\n' "$cflags" - echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" - echo "git_replace_objects=disabled and replacement refs forbidden" - echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" - echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" - echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" - echo "ignored_compiler_inputs=forbidden under src,include,study" - echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" - emit_key_value uname "$platform_identity" - if [ -n "$getconf_path" ]; then - processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) - long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) - printf 'processors_online=%s\n' "$processors_online" - printf 'long_bit=%s\n' "$long_bit" - fi - if [ -n "$cpu_model" ]; then - emit_key_value cpu_model "$cpu_model" - fi - printf '%s\n' "$memory_profile" -} > "$bundle_stage/environment.txt" - -{ - printf 'git_path=%s\n' "$git_path" - printf '%s\n' "$git_version" - printf 'sed_path=%s\n' "$sed_path" - printf 'awk_path=%s\n' "$awk_path" - printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" - printf 'tar_path=%s\n' "$tar_path" - printf 'chmod_path=%s\n' "$chmod_path" - printf 'provenance_rm_path=%s\n' "$provenance_rm_path" - printf 'mv_path=%s\n' "$mv_path" - printf 'cp_path=%s\n' "$cp_path" - printf 'find_path=%s\n' "$find_path" - printf 'readlink_path=%s\n' "$readlink_path" - printf 'date_path=%s\n' "$date_path" - printf 'dirname_path=%s\n' "$dirname_path" - printf 'basename_path=%s\n' "$basename_path" - printf 'uname_path=%s\n' "$uname_path" - printf 'sha256_path=%s\n' "$hash_path" - printf '%s\n' "$hash_version" - echo "compiler_path=$cc_path" - printf '%s\n' "$compiler_version" - echo "archiver_path=$ar_path" - printf '%s\n' "$archiver_version" - echo "build_driver_path=$make_path" - printf '%s\n' "$make_version" -} > "$bundle_stage/compiler.txt" - -{ - printf "set -eu\n" - printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" - printf "export GIT_NO_REPLACE_OBJECTS=1\n" - printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" - printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" - printf "unset TAR_OPTIONS\n" - shell_quote "$bundle_mkdir_path" - printf " -p " - shell_quote "$repo_root/build" - printf '\n' - shell_quote "$bundle_mkdir_path" - printf " " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$git_path" - printf " -C " - shell_quote "$repo_root" - printf " archive --format=tar " - shell_quote "$revision" - printf " -- Makefile src include study > " - shell_quote "$source_snapshot/.r7-source.tar" - printf '\n' - shell_quote "$tar_path" - printf " -xf " - shell_quote "$source_snapshot/.r7-source.tar" - printf " -C " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$provenance_rm_path" - printf " -f " - shell_quote "$source_snapshot/.r7-source.tar" - printf '\n' - shell_quote "$chmod_path" - printf " -R a-w " - shell_quote "$source_snapshot/Makefile" - printf " " - shell_quote "$source_snapshot/src" - printf " " - shell_quote "$source_snapshot/include" - printf " " - shell_quote "$source_snapshot/study" - printf '\n' - printf "PATH=" - shell_quote "$build_path" - printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " - shell_quote "$make_path" - printf " -C " - shell_quote "$source_snapshot" - printf " -f Makefile " - shell_quote "$study_target" - printf " BUILD_DIR=" - shell_quote "$build_dir_rel" - printf " CC=" - shell_quote "$cc_path" - printf " AR=" - shell_quote "$ar_path" - printf " CPPFLAGS=" - shell_quote "$cppflags" - printf " CFLAGS=" - shell_quote "$cflags" - printf '\n' - - shell_quote "$study_executable" - printf " --profile local --repeats " - shell_quote "$repeats" - printf " > " - shell_quote "$out_abs/observations.tsv" - printf '\n' - shell_quote "$chmod_path" - printf " -R u+w " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$provenance_rm_path" - printf " -rf " - shell_quote "$source_snapshot" - printf '\n' -} > "$bundle_stage/command.txt" - -"$study_executable" --profile local --repeats "$repeats" \ - > "$observations_path" - -validate_snapshot_identity -validate_source_identity -cleanup_snapshot - -case "$hash_mode" in - sha256sum) - ( - cd "$bundle_stage" - "$hash_path" \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - shasum) - ( - cd "$bundle_stage" - "$hash_path" -a 256 \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - *) - fail "unsupported SHA-256 utility mode: $hash_mode" - ;; -esac - -validate_source_identity - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination appeared during capture; refusing publish: $out_dir" -fi -[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || - fail "publish staging destination already exists: $publish_stage" - -"$bundle_mkdir_path" "$publish_stage" || - fail "could not create sibling publish staging directory" -"$cp_path" -R "$bundle_stage/." "$publish_stage/" || - fail "could not copy completed bundle to destination filesystem" - -case "$hash_mode" in - sha256sum) - ( - cd "$publish_stage" - "$hash_path" -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; - shasum) - ( - cd "$publish_stage" - "$hash_path" -a 256 -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; -esac - -"$provenance_rm_path" -rf "$bundle_stage" || - fail "could not remove repository bundle staging directory" - -if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then - fail "evidence destination appeared during publish; refusing rename: $out_abs" -fi - -"$mv_path" "$publish_stage" "$out_abs" || - fail "could not rename completed sibling staging bundle into place" -trap - 0 1 2 3 15 - -echo "R7 evidence bundle: $out_dir" From f32ea234d683c6c282f425745f0870e5bf9b4184 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:18:03 +0930 Subject: [PATCH 109/132] Define R7 literal flags trusted root and regression cleanup --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 6dc6e34..205c271 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -176,6 +176,7 @@ CORE_RULES: - R7_index_visibility_flags_are_checked_before_dirty_state - R7_Git_routing_environment_is_cleared_before_provenance_checks - R7_Git_provenance_commands_are_anchored_to_repo_root +- R7_repository_root_derivation_uses_fixed_provenance_dirname - R7_Git_executable_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_evidence_build_PATH_is_fixed_and_not_caller_overridable - R7_Git_replacement_objects_are_disabled_and_replacement_refs_are_forbidden @@ -207,6 +208,7 @@ CORE_RULES: - R7_optional_getconf_and_sysctl_host_probes_use_fixed_provenance_PATH - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_Make_variable_references - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH @@ -248,6 +250,8 @@ CORE_RULES: - R7_signed_clock_extreme_delta_is_UBSan_regression_tested - R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method - R7_run_local_deterministic_regressions_live_in_tests_test_r7_run_local_sh +- R7_documented_r7_evidence_regression_target_accepts_default_cc +- R7_regression_exit_trap_removes_shared_memory_publish_fixture - R7_clock_deterministic_regressions_live_in_tests_test_r7_clock_c - R7_dedicated_regression_targets_run_in_CI_for_GCC_and_Clang - R7_negative_results_must_be_retained From e330828babb5db970eb6507e0786500b957a66b3 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:18:07 +0930 Subject: [PATCH 110/132] Bind R7 literal flags and regression cleanup contract --- machine/r7-memory-wall-study.v1.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 052d136..54e7f44 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -203,6 +203,8 @@ "dirty_state_sampled_before_bundle_creation": true, "CPPFLAGS_recorded_and_bound": true, "CFLAGS_recorded_and_bound": true, + "CPPFLAGS_and_CFLAGS_make_variable_references_allowed": false, + "CPPFLAGS_and_CFLAGS_dollar_signs_allowed": false, "CPPFLAGS_and_CFLAGS_recording_uses_printf_not_echo": true, "CPPFLAGS_and_CFLAGS_backslashes_preserved_exactly": true, "compiler_command_must_be_single_executable": true, @@ -336,6 +338,7 @@ "GIT_NAMESPACE" ], "git_provenance_commands_anchored_with_git_C_repo_root": true, + "repository_root_dirname_resolved_from_fixed_provenance_PATH": true, "git_provenance_PATH_fixed": "/usr/bin:/bin:/usr/sbin:/sbin", "git_executable_resolved_from_fixed_provenance_PATH": true, "git_executable_identity_recorded": true, @@ -422,6 +425,8 @@ "CI_validates_4096_byte_profile_has_20_rows_and_all_eight_microtiles": true, "evidence_regression_script": "tests/test_r7_run_local.sh", "evidence_regression_command": "make r7-evidence-regression", + "evidence_regression_default_CC_cc_supported": true, + "evidence_regression_shared_memory_fixture_removed_by_exit_trap": true, "clock_regression_source": "tests/test_r7_clock.c", "clock_regression_command": "make r7-clock-regression", "evidence_regressions_cover": [ @@ -432,7 +437,11 @@ "concurrent captures with existing build parent", "concurrent captures with absent build parent", "platform identity backslash serialization", - "Clang CCC_OVERRIDE_OPTIONS injection" + "Clang CCC_OVERRIDE_OPTIONS injection", + "Make-variable expansion in CPPFLAGS/CFLAGS", + "ambient dirname repository-root redirection", + "default cc regression entrypoint", + "shared-memory publication fixture cleanup" ], "clock_regressions_run_under_UBSan": true }, From d4502c5f3a46db56909292894537aeb1900e6dc0 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:18:11 +0930 Subject: [PATCH 111/132] Document literal R7 flags and regression entrypoint --- R7-MEMORY-WALL-STUDY.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 4517395..91b26c3 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -252,7 +252,8 @@ snapshot cleanup, and SHA-256 finalization have all succeeded. Destinations may through, the repository `build/` tree, and parent-directory traversal is rejected. The script clears Git repository-routing overrides, resolves Git only from the fixed provenance path `/usr/bin:/bin:/usr/sbin:/sbin`, records that absolute -Git executable and version, sets `GIT_NO_REPLACE_OBJECTS=1`, rejects active +Git executable and version, and derives `repo_root` with the already-resolved +fixed-provenance `dirname` rather than caller `PATH`, sets `GIT_NO_REPLACE_OBJECTS=1`, rejects active `refs/replace`, and anchors all provenance reads to `repo_root` with `git -C`. Evidence builds use that same fixed system tool path; the build-tool search path is not caller-overridable. Before creating the @@ -295,8 +296,10 @@ The script records: trusted-prefix checks; arbitrary external compiler/archiver wrappers and `/usr/bin/../../...` traversal aliases are not accepted; - both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other - shell-text content are preserved exactly, binding those values plus CC and AR - into the build command; + shell-text content are preserved exactly. Dollar signs are rejected: flags + must be literal build arguments and may not contain Make-variable references + such as `$(R7_HEADER)`, because Make would recursively expand them against + unrecorded environment state; - explicit sanitation of ambient compiler search/override variables (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, @@ -409,12 +412,19 @@ Two named regression files now own the failure classes most likely to recur: fail-fast replay, hostile `TAR_OPTIONS`, destination-filesystem publication failure/cleanup, full concurrent captures with `build/` both present and absent, backslash-safe environment serialization, and Clang - `CCC_OVERRIDE_OPTIONS` injection during capture/replay. + `CCC_OVERRIDE_OPTIONS` injection during capture/replay, Make-variable + references hidden in CPPFLAGS/CFLAGS, hostile ambient `dirname` during + repository-root discovery, default-`cc` entrypoint handling, and publication + fixture cleanup. - `tests/test_r7_clock.c` — direct `r7_ticks_between()` boundary tests, including the signed extreme interval under UBSan. They run through `make r7-evidence-regression` and -`make r7-clock-regression` on both GCC and Clang in CI. New defects in either +`make r7-clock-regression` on both GCC and Clang in CI. The evidence +regression target also accepts Make's ordinary default `CC=cc`, normalizing it +to the fixed `/usr/bin/cc` entrypoint. Its exit/signal cleanup trap owns and +removes the temporary `/dev/shm/r7-publish-regression-...` fixture even when +the regression suite is interrupted. New defects in either source file should gain a deterministic reproducer in its corresponding regression file before the fix is considered complete. From 9a84c034a8ceea0ce21c6857853b80fa90c94d27 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:18:15 +0930 Subject: [PATCH 112/132] Document R7 literal flag and cleanup guarantees --- evidence/r7/README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 060fdb9..5c588bf 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -50,6 +50,8 @@ they can hide tracked modifications from ordinary status checks. Git routing overrides are cleared and all provenance reads are rooted at the repository. Git itself is resolved from a fixed provenance path (`/usr/bin:/bin:/usr/sbin:/sbin`) and its absolute path/version are recorded; +repository-root discovery uses the fixed-provenance `dirname` rather than +ambient `PATH`; the evidence build path is fixed and cannot substitute the Git/toolchain executables. Git replacement objects are disabled, active replacement refs are rejected, and tracked Makefile/source/include/study files are raw-hashed with @@ -86,8 +88,10 @@ physical page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by the fixed recorded `/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build -utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving -backslashes exactly. Each +utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with +`printf`, preserving backslashes exactly; dollar signs are rejected so Make +cannot recursively expand hidden `$(NAME)` references against unrecorded +environment variables. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared repository `build/` parent is created idempotently, so concurrent captures are @@ -126,4 +130,7 @@ CI includes dedicated deterministic regression gates in addition to the smoke study: `tests/test_r7_run_local.sh` via `make r7-evidence-regression`, and `tests/test_r7_clock.c` via `make r7-clock-regression` under UBSan. These tests are the home for future reproductions affecting the evidence wrapper or -clock arithmetic. CI timing values remain non-performance evidence. +clock arithmetic. The evidence regression entrypoint works with plain +`make r7-evidence-regression` and Make's default `CC=cc`; its cleanup trap +also removes the shared-memory ENOSPC fixture on normal exit, failure, or +signal. CI timing values remain non-performance evidence. From 384fb296997fff7512d57fd5701f2a4d376f966a Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:47:32 +0930 Subject: [PATCH 113/132] Harden R7 clock conversion and atomic publication --- AGENTS.md | 4 +++ Makefile | 7 ++++- machine/r7-memory-wall-study.v1.json | 18 ++++++++---- scripts/r7-run-local.sh | 32 +++++++++++++++++++- study/r7_memory_wall.c | 10 +++++++ tests/r7_float_clock/time.h | 10 +++++++ tests/test_r7_clock_float.c | 26 ++++++++++++++++ tests/test_r7_run_local.sh | 44 ++++++++++++++++++++++++++++ 8 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 tests/r7_float_clock/time.h create mode 100644 tests/test_r7_clock_float.c diff --git a/AGENTS.md b/AGENTS.md index 205c271..86262c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,6 +166,8 @@ CORE_RULES: - R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 - R7_publish_uses_sibling_destination_filesystem_stage_before_final_rename - R7_copied_publish_stage_must_pass_SHA256_before_final_rename +- R7_final_publish_uses_destination_specific_atomic_mkdir_lock +- R7_competing_same_destination_captures_must_not_nest_publish_stages - R7_failed_publish_must_leave_requested_destination_absent - R7_default_evidence_r7_destination_must_finalize_without_self_dirtying - R7_repeats_are_validated_before_bundle_creation @@ -247,6 +249,8 @@ CORE_RULES: - R7_compound_CC_is_not_accepted_for_evidence_capture - R7_memory_profile_is_required_on_every_supported_capture_host - R7_clock_delta_representability_is_proven_before_any_subtraction +- R7_floating_clock_t_is_rejected_before_any_integer_conversion +- R7_floating_clock_t_rejection_is_float_cast_overflow_regression_tested - R7_signed_clock_extreme_delta_is_UBSan_regression_tested - R7_environment_bundle_requires_source_workload_toolchain_build_CPU_memory_method - R7_run_local_deterministic_regressions_live_in_tests_test_r7_run_local_sh diff --git a/Makefile b/Makefile index f08b226..44e4e99 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ TEST_OPERATION = $(BUILD_DIR)/test_operation R6_PROOF = $(BUILD_DIR)/rune_r6_proof R7_STUDY = $(BUILD_DIR)/rune_r7_study R7_CLOCK_REGRESSION = $(BUILD_DIR)/test_r7_clock +R7_FLOAT_CLOCK_REGRESSION = $(BUILD_DIR)/test_r7_clock_float CORPUS = $(BUILD_DIR)/rune_corpus .PHONY: all test r6-proof r7-study-smoke r7-study r7-clock-regression r7-evidence-regression corpus-smoke clean @@ -83,8 +84,12 @@ r7-study: $(R7_STUDY) $(R7_CLOCK_REGRESSION): tests/test_r7_clock.c $(LIB) $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) $(INCLUDES) -fsanitize=undefined -fno-sanitize-recover=undefined tests/test_r7_clock.c $(LIB) -o $@ -r7-clock-regression: $(R7_CLOCK_REGRESSION) +$(R7_FLOAT_CLOCK_REGRESSION): tests/test_r7_clock_float.c tests/r7_float_clock/time.h $(LIB) + $(CC) $(CPPFLAGS) $(CFLAGS) $(STRICT_CFLAGS) -Itests/r7_float_clock $(INCLUDES) -fsanitize=undefined,float-cast-overflow -fno-sanitize-recover=undefined,float-cast-overflow tests/test_r7_clock_float.c $(LIB) -o $@ + +r7-clock-regression: $(R7_CLOCK_REGRESSION) $(R7_FLOAT_CLOCK_REGRESSION) ./$(R7_CLOCK_REGRESSION) + ./$(R7_FLOAT_CLOCK_REGRESSION) r7-evidence-regression: @r7_cc='$(CC)'; \ diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 54e7f44..923d993 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -14,7 +14,9 @@ "unit": "clock ticks", "scale_field": "clock_ticks_per_second", "wall_clock_claim": false, - "unavailable_is_explicit_failure": true + "unavailable_is_explicit_failure": true, + "integral_clock_t_required": true, + "floating_clock_t_rejected_before_integer_conversion": true }, "lifecycle": { "fields": [ @@ -403,7 +405,9 @@ "replay_observations_redirection_is_recorded": true, "replay_observations_path_is_absolute": true, "replay_recreates_observations_file": true, - "replay_command_is_working_directory_independent": true + "replay_command_is_working_directory_independent": true, + "final_publish_uses_destination_specific_atomic_mkdir_lock": true, + "competing_same_destination_captures_must_not_nest_publish_stages": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -441,9 +445,12 @@ "Make-variable expansion in CPPFLAGS/CFLAGS", "ambient dirname repository-root redirection", "default cc regression entrypoint", - "shared-memory publication fixture cleanup" + "shared-memory publication fixture cleanup", + "competing captures targeting the same absent destination" ], - "clock_regressions_run_under_UBSan": true + "clock_regressions_run_under_UBSan": true, + "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", + "floating_clock_t_regression_uses_float_cast_overflow_sanitizer": true }, "measurement_integrity": { "volatile_accesses_are_study_mechanics": true, @@ -451,6 +458,7 @@ "volatile_semantics_are_part_of_R7_harness_not_runtime_API": true, "clock_wrap_is_rejected_before_tick_subtraction": true, "clock_delta_representability_checked_before_subtraction": true, - "signed_clock_extreme_delta_UBSan_regression": true + "signed_clock_extreme_delta_UBSan_regression": true, + "floating_clock_t_rejected_before_integer_conversion": true } } diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 091e8d3..9aa4a88 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -656,6 +656,24 @@ study_executable="$source_snapshot/$study_target" bundle_stage_rel="build/r7-bundle-stage-$capture_id" bundle_stage="$repo_root/$bundle_stage_rel" publish_stage="$out_parent_abs/.r7-publish-$capture_id" +case "$hash_mode" in + sha256sum) + publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" | "$awk_path" '{ print $1 }') + ;; + shasum) + publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" -a 256 | "$awk_path" '{ print $1 }') + ;; + *) + fail "unsupported SHA-256 utility mode for publication lock: $hash_mode" + ;; +esac +case "$publish_lock_id" in + ''|*[!0-9A-Fa-f]*) + fail "could not derive destination-specific publication lock identity" + ;; +esac +publish_lock="$out_parent_abs/.r7-publish-lock-$publish_lock_id" +publish_lock_held=false cleanup_capture_state() { if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then @@ -668,6 +686,10 @@ cleanup_capture_state() if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : fi + if [ "${publish_lock_held:-false}" = true ] && + [ -n "${publish_lock:-}" ] && [ -d "$publish_lock" ]; then + "$provenance_rm_path" -rf "$publish_lock" >/dev/null 2>&1 || : + fi } trap cleanup_capture_state 0 1 2 3 15 @@ -722,7 +744,8 @@ observations_path="$bundle_stage/observations.tsv" printf 'find_resolved=%s\n' "$find_path" printf 'readlink_resolved=%s\n' "$readlink_path" printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_destination_lock_and_trusted_mv" + printf '%s\n' "publish_lock_strategy=destination_specific_atomic_mkdir" printf 'date_resolved=%s\n' "$date_path" printf 'dirname_resolved=%s\n' "$dirname_path" printf 'basename_resolved=%s\n' "$basename_path" @@ -910,6 +933,10 @@ esac validate_source_identity +"$bundle_mkdir_path" "$publish_lock" || + fail "could not acquire destination publication lock; another capture may be publishing: $out_dir" +publish_lock_held=true + if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then fail "evidence destination appeared during capture; refusing publish: $out_dir" fi @@ -945,6 +972,9 @@ fi "$mv_path" "$publish_stage" "$out_abs" || fail "could not rename completed sibling staging bundle into place" +"$provenance_rm_path" -rf "$publish_lock" || + fail "published bundle but could not release destination publication lock" +publish_lock_held=false trap - 0 1 2 3 15 echo "R7 evidence bundle: $out_dir" diff --git a/study/r7_memory_wall.c b/study/r7_memory_wall.c index f55ecb0..164d2a5 100644 --- a/study/r7_memory_wall.c +++ b/study/r7_memory_wall.c @@ -154,6 +154,16 @@ static int r7_ticks_between( return 0; } + /* + * C99 permits clock_t to be an arithmetic type. R7 requires integral + * tick values: converting an out-of-range floating clock_t to intmax_t + * or uintmax_t is undefined, so reject floating representations before + * any integer conversion or delta arithmetic. + */ + if ((clock_t)0.5 != (clock_t)0) { + return 0; + } + if (end < start) { return 0; } diff --git a/tests/r7_float_clock/time.h b/tests/r7_float_clock/time.h new file mode 100644 index 0000000..c5f6c49 --- /dev/null +++ b/tests/r7_float_clock/time.h @@ -0,0 +1,10 @@ +#ifndef RUNE_R7_FLOAT_CLOCK_TIME_H +#define RUNE_R7_FLOAT_CLOCK_TIME_H + +typedef double clock_t; + +#define CLOCKS_PER_SEC 1000000.0 + +clock_t clock(void); + +#endif diff --git a/tests/test_r7_clock_float.c b/tests/test_r7_clock_float.c new file mode 100644 index 0000000..961ee98 --- /dev/null +++ b/tests/test_r7_clock_float.c @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MPL-2.0 */ +#define main r7_embedded_study_main +#include "../study/r7_memory_wall.c" +#undef main + +#include +#include +#include + +int main(void) +{ + uint64_t out; + + out = UINT64_C(123); + if (r7_ticks_between((clock_t)0.0, (clock_t)DBL_MAX, &out)) { + fputs("R7 floating clock regression: floating clock_t was accepted\n", stderr); + return 1; + } + if (out != UINT64_C(123)) { + fputs("R7 floating clock regression: rejected interval modified output\n", stderr); + return 1; + } + + puts("R7 floating clock regression: OK"); + return 0; +} diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index c3e73d2..a4f7c75 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -37,6 +37,7 @@ cleanup() rm -f "/tmp/r7-tar-hook-$test_id" "/tmp/r7-tar-hook-ran-$test_id" rm -f "/tmp/r7-ccc-header-$test_id.h" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" + rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* } trap cleanup 0 1 2 3 15 @@ -148,6 +149,46 @@ run_concurrent_pair() fi } +run_competing_destination_pair() +{ + label=$1 + dest="$tmp_root/$label" + rm -rf "$dest" + + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$dest" > /tmp/r7-compete-a-$test_id.log 2>&1 & + pid_a=$! + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$dest" > /tmp/r7-compete-b-$test_id.log 2>&1 & + pid_b=$! + + if wait "$pid_a"; then status_a=0; else status_a=$?; fi + if wait "$pid_b"; then status_b=0; else status_b=$?; fi + + success_count=0 + if [ "$status_a" -eq 0 ]; then success_count=$((success_count + 1)); fi + if [ "$status_b" -eq 0 ]; then success_count=$((success_count + 1)); fi + if [ "$success_count" -ne 1 ]; then + cat /tmp/r7-compete-a-$test_id.log >&2 + cat /tmp/r7-compete-b-$test_id.log >&2 + fail "$label expected exactly one successful publisher; got statuses $status_a and $status_b" + fi + + [ -s "$dest/observations.tsv" ] || + fail "$label did not publish observations" + ( + cd "$dest" + /usr/bin/sha256sum -c SHA256SUMS >/dev/null + ) + + if /usr/bin/find "$dest" -maxdepth 1 -type d -name '.r7-publish-*' -print -quit | /usr/bin/grep -q .; then + fail "$label nested a competing publish stage inside the immutable bundle" + fi + if /usr/bin/find "$tmp_root" -maxdepth 1 -type d -name '.r7-publish-lock-*' -print -quit | /usr/bin/grep -q .; then + fail "$label leaked a destination publication lock" + fi +} + # Concurrent captures must isolate all PID-qualified staging paths. mkdir -p build run_concurrent_pair concurrent-existing-build @@ -156,6 +197,9 @@ run_concurrent_pair concurrent-existing-build rm -rf build run_concurrent_pair concurrent-missing-build +# Competing captures for one absent destination must serialize final publication. +run_competing_destination_pair concurrent-same-destination + # Canonical-path regression: lexical /usr/bin prefixes must not authorize /tmp. cat > /tmp/r7-reg-cc-$test_id < Date: Sun, 27 Sep 2026 22:03:58 +0930 Subject: [PATCH 114/132] Clarify R6 to R7 authority migration --- AGENTS.md | 7 +++++++ R7-MEMORY-WALL-STUDY.md | 21 +++++++++++++++++++++ machine/project-v1.json | 25 +++++++++++++++++++++++++ scripts/r7-run-local.sh | 2 +- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 86262c9..cb40901 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,10 @@ LICENSE=MPL-2.0 CURRENT_PHASE=R7 RUNTIME_IMPLEMENTATION_ALLOWED=false RUNTIME_PERFORMANCE_CLAIMS_ALLOWED=false +AUTHORITY_TRANSITION=R6_TO_R7 +TRANSITION_REVIEW_MODE=EVALUATE_PROPOSED_AUTHORITY_MIGRATION +BASE_PHASE_UNTIL_MERGE=R6 +FROZEN_R1_THROUGH_R6_SEMANTICS_PRESERVED=true READ_ORDER: 1=machine/project-v1.json @@ -50,6 +54,9 @@ ON_HUMAN_MACHINE_CONTRADICTION=STOP_AND_REPORT DO_NOT_INVENT_RECONCILIATION=true CORE_RULES: +- PR_review_of_R6_to_R7_must_evaluate_the_proposed_authority_transition_not_enforce_base_R6_phase_fields_against_the_R7_head +- R6_to_R7_transition_supersedes_current_phase_and_phase_specific_runtime_implementation_permission_only +- frozen_R1_through_R6_runtime_semantics_receipts_and_proofs_are_preserved - preserve_all_invariants - runtime_core_changes_forbidden_in_R7_study_phase - cpu_only diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 91b26c3..2383062 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -4,6 +4,27 @@ R7 is the first RUNE phase that records timing observations. It does **not** turn a timing number into a universal performance claim. +## R6 → R7 authority migration + +This change intentionally advances the project authority from **R6** to **R7**. +The R6 values on the base branch are therefore the pre-migration authority being +reviewed, not constraints that the proposed R7 head must continue to report. + +For review of this transition: + +- evaluate whether the proposed R6 → R7 authority migration is valid; +- after accepting the transition, interpret the PR head under + `CURRENT_PHASE=R7` and `RUNTIME_IMPLEMENTATION_ALLOWED=false`; +- preserve all frozen R1–R6 runtime semantics and receipts unless this document + explicitly says otherwise; +- do not treat the phase change as permission for runtime-core implementation; +- until this PR merges, the target branch remains R6 authority. + +R6's implemented runtime primitives, operation descriptors, receipts, and proof +artifacts remain preserved. R7 supersedes only the **current-phase authority and +phase-specific implementation permission**: it adds study/evidence tooling and +makes no runtime ABI or frozen semantic change. + The study uses the frozen R4 questions to ask when representation, locality, resident state, materialization, and recomputation change observed execution cost on one declared environment. diff --git a/machine/project-v1.json b/machine/project-v1.json index 5632ff8..22b8058 100644 --- a/machine/project-v1.json +++ b/machine/project-v1.json @@ -262,5 +262,30 @@ "github_CI_smoke_is_performance_evidence": false, "timing_alone_can_support_cache_NUMA_bandwidth_cause": false, "negative_results_must_be_retained": true + }, + "phase_transition": { + "from": "R6", + "to": "R7", + "status": "proposed-by-this-pull-request", + "review_mode": "evaluate-proposed-authority-migration", + "base_branch_authority_until_merge": "R6", + "head_authority_if_transition_accepted": "R7", + "superseded_phase_fields": [ + "phase.id", + "phase.name", + "phase.runtime_implementation_allowed", + "evidence.runtime_performance_claim_policy.current_phase" + ], + "preserved_frozen_contracts": [ + "R1 region core", + "R2 arena and scratch lifetime", + "R3 integer numeric core", + "R4 corpus v1", + "R5 rings and streaming", + "R6 operation descriptors and receipts" + ], + "frozen_runtime_semantics_preserved": true, + "runtime_abi_change": false, + "runtime_core_implementation_authorized_in_R7": false } } diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 9aa4a88..92da29b 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -744,7 +744,7 @@ observations_path="$bundle_stage/observations.tsv" printf 'find_resolved=%s\n' "$find_path" printf 'readlink_resolved=%s\n' "$readlink_path" printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=publish_after_success_via_destination_lock_and_trusted_mv" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" printf '%s\n' "publish_lock_strategy=destination_specific_atomic_mkdir" printf 'date_resolved=%s\n' "$date_path" printf 'dirname_resolved=%s\n' "$dirname_path" From 36513e3ac559e969000fea0931cd377ac52d5ea0 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:21:45 +0930 Subject: [PATCH 115/132] Reject shell-evaluated R7 build flags --- AGENTS.md | 2 ++ R7-MEMORY-WALL-STUDY.md | 13 +++++---- evidence/r7/README.md | 8 ++++-- machine/r7-memory-wall-study.v1.json | 11 ++++++-- scripts/r7-run-local.sh | 26 ++++++++++++++---- tests/test_r7_run_local.sh | 41 ++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cb40901..cd33eb3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -218,6 +218,8 @@ CORE_RULES: - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Make_variable_references +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_or_glob_syntax +- R7_CPPFLAGS_and_CFLAGS_shell_metacharacter_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 2383062..dd0b30e 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -316,11 +316,14 @@ The script records: provenance path, with their parent paths physically canonicalized before trusted-prefix checks; arbitrary external compiler/archiver wrappers and `/usr/bin/../../...` traversal aliases are not accepted; -- both CPPFLAGS and CFLAGS, recorded with `printf` so backslashes and other - shell-text content are preserved exactly. Dollar signs are rejected: flags - must be literal build arguments and may not contain Make-variable references - such as `$(R7_HEADER)`, because Make would recursively expand them against - unrecorded environment state; +- both CPPFLAGS and CFLAGS, recorded with `printf` so accepted backslashes + and literal flag text are preserved exactly. Evidence flags are deliberately + conservative: Make-variable syntax and shell-evaluated substitution/control + syntax are rejected before Make runs. This includes dollar signs, backticks, + command separators, redirections, shell comments, tilde expansion, and + pathname-globbing metacharacters. Flags must therefore be literal, + replayable compiler arguments rather than expressions whose effective argv + depends on unrecorded shell or filesystem state; - explicit sanitation of ambient compiler search/override variables (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 5c588bf..5906e67 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -89,9 +89,11 @@ Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by the fixed recorded `/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with -`printf`, preserving backslashes exactly; dollar signs are rejected so Make -cannot recursively expand hidden `$(NAME)` references against unrecorded -environment variables. Each +`printf`, preserving accepted backslashes exactly. Before Make runs, evidence +capture rejects Make-variable references and shell-evaluated substitution, +control, redirection, comment, tilde, and pathname-globbing metacharacters, so +the recorded flag text cannot turn into unrecorded commands or filesystem- +dependent argv during recipe evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared repository `build/` parent is created idempotently, so concurrent captures are diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 923d993..3dd0ed1 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -407,7 +407,11 @@ "replay_recreates_observations_file": true, "replay_command_is_working_directory_independent": true, "final_publish_uses_destination_specific_atomic_mkdir_lock": true, - "competing_same_destination_captures_must_not_nest_publish_stages": true + "competing_same_destination_captures_must_not_nest_publish_stages": true, + "CPPFLAGS_and_CFLAGS_shell_substitution_allowed": false, + "CPPFLAGS_and_CFLAGS_shell_control_or_redirection_allowed": false, + "CPPFLAGS_and_CFLAGS_shell_comment_tilde_or_glob_expansion_allowed": false, + "CPPFLAGS_and_CFLAGS_shell_metacharacters_rejected_before_make": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -446,7 +450,10 @@ "ambient dirname repository-root redirection", "default cc regression entrypoint", "shared-memory publication fixture cleanup", - "competing captures targeting the same absent destination" + "competing captures targeting the same absent destination", + "backtick command substitution in CFLAGS", + "shell command separator injection in CFLAGS", + "pathname glob expansion in CPPFLAGS" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 92da29b..8e7b6d6 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -262,12 +262,26 @@ fi cppflags=${CPPFLAGS:-} cflags=${CFLAGS:-} -case "$cppflags" in - *'$'*) fail "CPPFLAGS must not contain dollar signs or Make variable references; resolve them before capture" ;; -esac -case "$cflags" in - *'$'*) fail "CFLAGS must not contain dollar signs or Make variable references; resolve them before capture" ;; -esac +validate_literal_build_flags() +{ + flag_name=$1 + flag_value=$2 + + case "$flag_value" in + *'$'*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*) + fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, or glob metacharacters; use literal replayable compiler arguments" + ;; + esac + case "$flag_value" in + *' +'*|*' '*) + fail "$flag_name must not contain newline or carriage-return shell control characters" + ;; + esac +} + +validate_literal_build_flags CPPFLAGS "$cppflags" +validate_literal_build_flags CFLAGS "$cflags" repeats=${RUNE_R7_REPEATS:-5} case "$repeats" in diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index a4f7c75..ac79088 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -36,6 +36,8 @@ cleanup() rm -f "/tmp/r7-reg-cc-$test_id" "/tmp/r7-reg-ar-$test_id" "/tmp/r7-reg-make-$test_id" rm -f "/tmp/r7-tar-hook-$test_id" "/tmp/r7-tar-hook-ran-$test_id" rm -f "/tmp/r7-ccc-header-$test_id.h" + rm -f "/tmp/r7-backtick-header-$test_id.h" "/tmp/r7-backtick-hook-$test_id" "/tmp/r7-backtick-ran-$test_id" + rm -f "/tmp/r7-separator-hook-$test_id" "/tmp/r7-separator-ran-$test_id" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -79,6 +81,45 @@ expect_capture_failure make-reference-cflags \ RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh rm -f "$hidden_header" +# Shell substitutions/control syntax in flags must be rejected before Make runs. +backtick_header="/tmp/r7-backtick-header-$test_id.h" +backtick_hook="/tmp/r7-backtick-hook-$test_id" +backtick_ran="/tmp/r7-backtick-ran-$test_id" +cat > "$backtick_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF +cat > "$backtick_hook" < "$backtick_ran" +printf '%s\n' '-include $backtick_header' +EOF +chmod +x "$backtick_hook" +backtick_flags=$(printf '`%s`' "$backtick_hook") +expect_capture_failure shell-backtick-cflags \ + env "CFLAGS=$backtick_flags" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +[ ! -e "$backtick_ran" ] || fail "backtick CFLAGS hook executed before rejection" + +separator_hook="/tmp/r7-separator-hook-$test_id" +separator_ran="/tmp/r7-separator-ran-$test_id" +cat > "$separator_hook" < "$separator_ran" +EOF +chmod +x "$separator_hook" +expect_capture_failure shell-separator-cflags \ + env "CFLAGS=-O2; $separator_hook" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +[ ! -e "$separator_ran" ] || fail "separator CFLAGS hook executed before rejection" + +expect_capture_failure shell-glob-cppflags \ + env 'CPPFLAGS=-I/tmp/r7-*' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh + +rm -f "$backtick_header" "$backtick_hook" "$backtick_ran" "$separator_hook" "$separator_ran" + # Environment serialization must preserve backslashes and field boundaries. scripts/r7-run-local.sh --self-test-environment-serialization From a74162cad8bc424a6c57c7704ab50ba41a793db8 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:54:15 +0930 Subject: [PATCH 116/132] Reject compiler response-file build flags --- AGENTS.md | 3 ++- R7-MEMORY-WALL-STUDY.md | 5 +++-- evidence/r7/README.md | 9 +++++---- machine/r7-memory-wall-study.v1.json | 8 ++++++-- scripts/r7-run-local.sh | 4 ++-- tests/test_r7_run_local.sh | 18 ++++++++++++++++++ 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cd33eb3..6cf5ca8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -219,7 +219,8 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Make_variable_references - R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_or_glob_syntax -- R7_CPPFLAGS_and_CFLAGS_shell_metacharacter_rejection_occurs_before_Make_execution +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_compiler_response_file_syntax +- R7_CPPFLAGS_and_CFLAGS_shell_or_response_expansion_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index dd0b30e..5ce3ca4 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -320,8 +320,9 @@ The script records: and literal flag text are preserved exactly. Evidence flags are deliberately conservative: Make-variable syntax and shell-evaluated substitution/control syntax are rejected before Make runs. This includes dollar signs, backticks, - command separators, redirections, shell comments, tilde expansion, and - pathname-globbing metacharacters. Flags must therefore be literal, + command separators, redirections, shell comments, tilde expansion, + pathname-globbing metacharacters, and `@` compiler response-file syntax. + Flags must therefore be literal, replayable compiler arguments rather than expressions whose effective argv depends on unrecorded shell or filesystem state; - explicit sanitation of ambient compiler search/override variables diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 5906e67..41e2951 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -90,10 +90,11 @@ the evidence build. Ambient `PATH` is replaced by the fixed recorded `/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving accepted backslashes exactly. Before Make runs, evidence -capture rejects Make-variable references and shell-evaluated substitution, -control, redirection, comment, tilde, and pathname-globbing metacharacters, so -the recorded flag text cannot turn into unrecorded commands or filesystem- -dependent argv during recipe evaluation. Each +capture rejects Make-variable references, shell-evaluated substitution, +control, redirection, comment, tilde and pathname-globbing metacharacters, and +`@` compiler response-file syntax. The recorded flag text therefore cannot +turn into unrecorded commands, response-file contents, or filesystem-dependent +argv during recipe/compiler evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared repository `build/` parent is created idempotently, so concurrent captures are diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 3dd0ed1..3df94ac 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -411,7 +411,10 @@ "CPPFLAGS_and_CFLAGS_shell_substitution_allowed": false, "CPPFLAGS_and_CFLAGS_shell_control_or_redirection_allowed": false, "CPPFLAGS_and_CFLAGS_shell_comment_tilde_or_glob_expansion_allowed": false, - "CPPFLAGS_and_CFLAGS_shell_metacharacters_rejected_before_make": true + "CPPFLAGS_and_CFLAGS_shell_metacharacters_rejected_before_make": true, + "CPPFLAGS_and_CFLAGS_compiler_response_files_allowed": false, + "CPPFLAGS_and_CFLAGS_at_sign_allowed": false, + "CPPFLAGS_and_CFLAGS_response_file_rejected_before_make": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -453,7 +456,8 @@ "competing captures targeting the same absent destination", "backtick command substitution in CFLAGS", "shell command separator injection in CFLAGS", - "pathname glob expansion in CPPFLAGS" + "pathname glob expansion in CPPFLAGS", + "compiler response-file expansion in CFLAGS/CPPFLAGS" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 8e7b6d6..f5210a1 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -268,8 +268,8 @@ validate_literal_build_flags() flag_value=$2 case "$flag_value" in - *'$'*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*) - fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, or glob metacharacters; use literal replayable compiler arguments" + *'$'*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*|*'@'*) + fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, glob, or compiler response-file metacharacters; use literal replayable compiler arguments" ;; esac case "$flag_value" in diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index ac79088..0b47588 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -38,6 +38,7 @@ cleanup() rm -f "/tmp/r7-ccc-header-$test_id.h" rm -f "/tmp/r7-backtick-header-$test_id.h" "/tmp/r7-backtick-hook-$test_id" "/tmp/r7-backtick-ran-$test_id" rm -f "/tmp/r7-separator-hook-$test_id" "/tmp/r7-separator-ran-$test_id" + rm -f "/tmp/r7-response-header-$test_id.h" "/tmp/r7-response-flags-$test_id.rsp" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -118,7 +119,24 @@ expect_capture_failure shell-glob-cppflags \ env 'CPPFLAGS=-I/tmp/r7-*' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +# Compiler response files must not hide effective build arguments. +response_header="/tmp/r7-response-header-$test_id.h" +response_flags="/tmp/r7-response-flags-$test_id.rsp" +cat > "$response_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF +printf '%s\n' "-include $response_header" > "$response_flags" +expect_capture_failure compiler-response-cflags \ + env "CFLAGS=@$response_flags" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +expect_capture_failure compiler-response-cppflags \ + env "CPPFLAGS=@$response_flags" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh + rm -f "$backtick_header" "$backtick_hook" "$backtick_ran" "$separator_hook" "$separator_ran" +rm -f "$response_header" "$response_flags" # Environment serialization must preserve backslashes and field boundaries. scripts/r7-run-local.sh --self-test-environment-serialization From dab33111b9e341a24433ef96b184a93e09bc2eff Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:13:42 +0930 Subject: [PATCH 117/132] Reject Clang external config build flags --- AGENTS.md | 3 ++- R7-MEMORY-WALL-STUDY.md | 5 +++-- evidence/r7/README.md | 7 ++++--- machine/r7-memory-wall-study.v1.json | 9 +++++++-- scripts/r7-run-local.sh | 5 +++++ tests/test_r7_run_local.sh | 25 ++++++++++++++++++++++++- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6cf5ca8..f3f09b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -220,7 +220,8 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Make_variable_references - R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_or_glob_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_compiler_response_file_syntax -- R7_CPPFLAGS_and_CFLAGS_shell_or_response_expansion_rejection_occurs_before_Make_execution +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_Clang_config_file_or_config_search_directory_controls +- R7_CPPFLAGS_and_CFLAGS_shell_response_or_compiler_config_expansion_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound - R7_CC_and_AR_must_each_name_one_executable_resolved_from_fixed_provenance_PATH diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 5ce3ca4..b417fc6 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -321,8 +321,9 @@ The script records: conservative: Make-variable syntax and shell-evaluated substitution/control syntax are rejected before Make runs. This includes dollar signs, backticks, command separators, redirections, shell comments, tilde expansion, - pathname-globbing metacharacters, and `@` compiler response-file syntax. - Flags must therefore be literal, + pathname-globbing metacharacters, `@` compiler response-file syntax, and + Clang `--config...` configuration-file/search-directory controls. Flags + must therefore be literal, replayable compiler arguments rather than expressions whose effective argv depends on unrecorded shell or filesystem state; - explicit sanitation of ambient compiler search/override variables diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 41e2951..02f7974 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -91,9 +91,10 @@ the evidence build. Ambient `PATH` is replaced by the fixed recorded utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving accepted backslashes exactly. Before Make runs, evidence capture rejects Make-variable references, shell-evaluated substitution, -control, redirection, comment, tilde and pathname-globbing metacharacters, and -`@` compiler response-file syntax. The recorded flag text therefore cannot -turn into unrecorded commands, response-file contents, or filesystem-dependent +control, redirection, comment, tilde and pathname-globbing metacharacters, +`@` compiler response-file syntax, and Clang `--config...` configuration +file/search-directory controls. The recorded flag text therefore cannot turn +into unrecorded commands, response/config-file contents, or filesystem-dependent argv during recipe/compiler evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 3df94ac..c6552fc 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -414,7 +414,10 @@ "CPPFLAGS_and_CFLAGS_shell_metacharacters_rejected_before_make": true, "CPPFLAGS_and_CFLAGS_compiler_response_files_allowed": false, "CPPFLAGS_and_CFLAGS_at_sign_allowed": false, - "CPPFLAGS_and_CFLAGS_response_file_rejected_before_make": true + "CPPFLAGS_and_CFLAGS_response_file_rejected_before_make": true, + "CPPFLAGS_and_CFLAGS_clang_config_file_controls_allowed": false, + "CPPFLAGS_and_CFLAGS_clang_config_search_directory_controls_allowed": false, + "CPPFLAGS_and_CFLAGS_clang_config_controls_rejected_before_make": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -457,7 +460,9 @@ "backtick command substitution in CFLAGS", "shell command separator injection in CFLAGS", "pathname glob expansion in CPPFLAGS", - "compiler response-file expansion in CFLAGS/CPPFLAGS" + "compiler response-file expansion in CFLAGS/CPPFLAGS", + "Clang --config external configuration file in CFLAGS/CPPFLAGS", + "Clang --config-system-dir/--config-user-dir configuration search controls" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index f5210a1..26c5203 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -278,6 +278,11 @@ validate_literal_build_flags() fail "$flag_name must not contain newline or carriage-return shell control characters" ;; esac + case "$flag_value" in + *'--config'*) + fail "$flag_name must not contain Clang configuration-file controls; external compiler config files are not bound evidence inputs" + ;; + esac } validate_literal_build_flags CPPFLAGS "$cppflags" diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 0b47588..7c95073 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -39,6 +39,7 @@ cleanup() rm -f "/tmp/r7-backtick-header-$test_id.h" "/tmp/r7-backtick-hook-$test_id" "/tmp/r7-backtick-ran-$test_id" rm -f "/tmp/r7-separator-hook-$test_id" "/tmp/r7-separator-ran-$test_id" rm -f "/tmp/r7-response-header-$test_id.h" "/tmp/r7-response-flags-$test_id.rsp" + rm -f "/tmp/r7-clang-config-header-$test_id.h" "/tmp/r7-clang-config-$test_id.cfg" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -135,8 +136,30 @@ expect_capture_failure compiler-response-cppflags \ env "CPPFLAGS=@$response_flags" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +# Clang configuration files and config search directories must not hide options. +clang_config_header="/tmp/r7-clang-config-header-$test_id.h" +clang_config="/tmp/r7-clang-config-$test_id.cfg" +cat > "$clang_config_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF +printf '%s\n' "-include $clang_config_header" > "$clang_config" +expect_capture_failure clang-config-equals-cflags \ + env "CFLAGS=--config=$clang_config" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +expect_capture_failure clang-config-split-cppflags \ + env "CPPFLAGS=--config $clang_config" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +expect_capture_failure clang-config-system-dir \ + env 'CFLAGS=--config-system-dir=/tmp' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh +expect_capture_failure clang-config-user-dir \ + env 'CFLAGS=--config-user-dir=/tmp' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh + rm -f "$backtick_header" "$backtick_hook" "$backtick_ran" "$separator_hook" "$separator_ran" -rm -f "$response_header" "$response_flags" +rm -f "$response_header" "$response_flags" "$clang_config_header" "$clang_config" # Environment serialization must preserve backslashes and field boundaries. scripts/r7-run-local.sh --self-test-environment-serialization From 5e805f98c9c211559526fd00de617c2008563aca Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:40:00 +0930 Subject: [PATCH 118/132] Reject GCC external specs build flags --- AGENTS.md | 1 + R7-MEMORY-WALL-STUDY.md | 7 ++++--- evidence/r7/README.md | 7 ++++--- machine/r7-memory-wall-study.v1.json | 7 +++++-- scripts/r7-run-local.sh | 5 +++++ tests/test_r7_run_local.sh | 24 ++++++++++++++++++++++++ 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f3f09b6..ca31edc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -221,6 +221,7 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_or_glob_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_compiler_response_file_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Clang_config_file_or_config_search_directory_controls +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_specs_file_controls - R7_CPPFLAGS_and_CFLAGS_shell_response_or_compiler_config_expansion_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index b417fc6..9a518d5 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -321,9 +321,10 @@ The script records: conservative: Make-variable syntax and shell-evaluated substitution/control syntax are rejected before Make runs. This includes dollar signs, backticks, command separators, redirections, shell comments, tilde expansion, - pathname-globbing metacharacters, `@` compiler response-file syntax, and - Clang `--config...` configuration-file/search-directory controls. Flags - must therefore be literal, + pathname-globbing metacharacters, `@` compiler response-file syntax, + Clang `--config...` configuration-file/search-directory controls, and GCC + `-specs`/`--specs` external specs-file controls. Flags must therefore be + literal, replayable compiler arguments rather than expressions whose effective argv depends on unrecorded shell or filesystem state; - explicit sanitation of ambient compiler search/override variables diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 02f7974..876c662 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -92,9 +92,10 @@ utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving accepted backslashes exactly. Before Make runs, evidence capture rejects Make-variable references, shell-evaluated substitution, control, redirection, comment, tilde and pathname-globbing metacharacters, -`@` compiler response-file syntax, and Clang `--config...` configuration -file/search-directory controls. The recorded flag text therefore cannot turn -into unrecorded commands, response/config-file contents, or filesystem-dependent +`@` compiler response-file syntax, Clang `--config...` configuration +file/search-directory controls, and GCC `-specs`/`--specs` external +specs-file controls. The recorded flag text therefore cannot turn into +unrecorded commands, response/config/specs-file contents, or filesystem-dependent argv during recipe/compiler evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index c6552fc..277424e 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -417,7 +417,9 @@ "CPPFLAGS_and_CFLAGS_response_file_rejected_before_make": true, "CPPFLAGS_and_CFLAGS_clang_config_file_controls_allowed": false, "CPPFLAGS_and_CFLAGS_clang_config_search_directory_controls_allowed": false, - "CPPFLAGS_and_CFLAGS_clang_config_controls_rejected_before_make": true + "CPPFLAGS_and_CFLAGS_clang_config_controls_rejected_before_make": true, + "CPPFLAGS_and_CFLAGS_gcc_specs_file_controls_allowed": false, + "CPPFLAGS_and_CFLAGS_gcc_specs_controls_rejected_before_make": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -462,7 +464,8 @@ "pathname glob expansion in CPPFLAGS", "compiler response-file expansion in CFLAGS/CPPFLAGS", "Clang --config external configuration file in CFLAGS/CPPFLAGS", - "Clang --config-system-dir/--config-user-dir configuration search controls" + "Clang --config-system-dir/--config-user-dir configuration search controls", + "GCC -specs/--specs external specs-file expansion in CFLAGS/CPPFLAGS" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 26c5203..7b1f736 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -283,6 +283,11 @@ validate_literal_build_flags() fail "$flag_name must not contain Clang configuration-file controls; external compiler config files are not bound evidence inputs" ;; esac + case "$flag_value" in + *'-specs='*|*'--specs='*|*'-specs '*|*'--specs '*) + fail "$flag_name must not contain GCC specs-file controls; external compiler specs files are not bound evidence inputs" + ;; + esac } validate_literal_build_flags CPPFLAGS "$cppflags" diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 7c95073..b317d28 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -40,6 +40,7 @@ cleanup() rm -f "/tmp/r7-separator-hook-$test_id" "/tmp/r7-separator-ran-$test_id" rm -f "/tmp/r7-response-header-$test_id.h" "/tmp/r7-response-flags-$test_id.rsp" rm -f "/tmp/r7-clang-config-header-$test_id.h" "/tmp/r7-clang-config-$test_id.cfg" + rm -f "/tmp/r7-gcc-spec-header-$test_id.h" "/tmp/r7-gcc-spec-$test_id.specs" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -158,8 +159,31 @@ expect_capture_failure clang-config-user-dir \ env 'CFLAGS=--config-user-dir=/tmp' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +# GCC specs files must not hide effective compiler arguments. +gcc_spec_header="/tmp/r7-gcc-spec-header-$test_id.h" +gcc_spec="/tmp/r7-gcc-spec-$test_id.specs" +cat > "$gcc_spec_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 424242 +EOF +cat > "$gcc_spec" < Date: Mon, 28 Sep 2026 00:07:36 +0930 Subject: [PATCH 119/132] Harden R7 compiler controls and signal cancellation --- AGENTS.md | 3 + R7-MEMORY-WALL-STUDY.md | 16 +++-- evidence/r7/README.md | 11 +++- machine/r7-memory-wall-study.v1.json | 13 +++- scripts/r7-run-local.sh | 67 +++++++++++++++++---- tests/test_r7_run_local.sh | 90 ++++++++++++++++++++++++++++ 6 files changed, 177 insertions(+), 23 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ca31edc..a8088ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -170,6 +170,7 @@ CORE_RULES: - R7_bundle_files_are_staged_under_ignored_build_until_capture_finalization - R7_capture_unique_identity_is_UTC_timestamp_plus_shell_PID_for_source_build_bundle_and_publish_stages - R7_failed_capture_removes_bundle_stage_and_source_snapshot +- R7_termination_signals_are_forwarded_to_active_study_before_capture_cleanup - R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 - R7_publish_uses_sibling_destination_filesystem_stage_before_final_rename - R7_copied_publish_stage_must_pass_SHA256_before_final_rename @@ -222,6 +223,8 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_must_not_contain_compiler_response_file_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Clang_config_file_or_config_search_directory_controls - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_specs_file_controls +- R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_tokenized_across_all_POSIX_shell_whitespace +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_B_subprogram_search_overrides - R7_CPPFLAGS_and_CFLAGS_shell_response_or_compiler_config_expansion_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index 9a518d5..eeead42 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -289,9 +289,11 @@ materializes **Makefile, src/, include/, and study/** directly from unexpected files and symlinks are rejected before the known source bytes are checked against the recorded revision and made read-only before Make runs. Make executes inside that snapshot, so the mutable checkout is not a compiler input. Worktree and snapshot identity are checked again after the build -and after measurement. The publish destination is not created during the build or measurement. An -EXIT/signal cleanup trap removes the source snapshot and staged bundle on -failure, including measurement failures such as resource exhaustion. **Any dirty or divergent checkout/snapshot is rejected.** R7 local +and after measurement. The publish destination is not created during the build or measurement. The +study runs as a tracked child process; HUP, INT, QUIT, and TERM received by the +wrapper are forwarded to the active study, then normal EXIT cleanup removes the +source snapshot and staged bundle promptly. This also covers measurement +failures such as resource exhaustion. **Any dirty or divergent checkout/snapshot is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not claim a commit while actually building uncommitted source content. Files marked @@ -322,9 +324,11 @@ The script records: syntax are rejected before Make runs. This includes dollar signs, backticks, command separators, redirections, shell comments, tilde expansion, pathname-globbing metacharacters, `@` compiler response-file syntax, - Clang `--config...` configuration-file/search-directory controls, and GCC - `-specs`/`--specs` external specs-file controls. Flags must therefore be - literal, + Clang `--config...` configuration-file/search-directory controls, GCC + `-specs`/`--specs` external specs-file controls, and GCC `-B` compiler + subprogram search overrides. Sensitive compiler controls are tokenized using + POSIX shell whitespace, so tab-separated forms cannot bypass the checks. + Flags must therefore be literal, replayable compiler arguments rather than expressions whose effective argv depends on unrecorded shell or filesystem state; - explicit sanitation of ambient compiler search/override variables diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 876c662..0f967d5 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -93,12 +93,17 @@ utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with capture rejects Make-variable references, shell-evaluated substitution, control, redirection, comment, tilde and pathname-globbing metacharacters, `@` compiler response-file syntax, Clang `--config...` configuration -file/search-directory controls, and GCC `-specs`/`--specs` external -specs-file controls. The recorded flag text therefore cannot turn into +file/search-directory controls, GCC `-specs`/`--specs` external specs-file +controls, and GCC `-B` compiler subprogram search overrides. Sensitive +compiler controls are tokenized over POSIX shell whitespace, including tabs. +The recorded flag text therefore cannot turn into unrecorded commands, response/config/specs-file contents, or filesystem-dependent argv during recipe/compiler evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, -`BUILD_DIR`, repository bundle stage, and sibling publish stage. The shared +`BUILD_DIR`, repository bundle stage, and sibling publish stage. During the +measurement, HUP/INT/QUIT/TERM are forwarded to the tracked study child before +the EXIT trap removes staged capture state, so cancelling the wrapper does not +leave the expensive study running in the background. The shared repository `build/` parent is created idempotently, so concurrent captures are isolated whether the parent already exists or is created by racing captures. The build never relies on `make clean`, so a fake ambient `rm` cannot diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index 277424e..bb1393f 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -419,7 +419,13 @@ "CPPFLAGS_and_CFLAGS_clang_config_search_directory_controls_allowed": false, "CPPFLAGS_and_CFLAGS_clang_config_controls_rejected_before_make": true, "CPPFLAGS_and_CFLAGS_gcc_specs_file_controls_allowed": false, - "CPPFLAGS_and_CFLAGS_gcc_specs_controls_rejected_before_make": true + "CPPFLAGS_and_CFLAGS_gcc_specs_controls_rejected_before_make": true, + "sensitive_compiler_flag_tokenization": "POSIX shell whitespace", + "GCC_specs_split_control_tabs_allowed": false, + "GCC_B_subprogram_search_overrides_allowed": false, + "GCC_B_controls_rejected_before_make": true, + "termination_signals_forwarded_to_active_study": true, + "termination_signal_exit_status_preserved_as_128_plus_signal": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -465,7 +471,10 @@ "compiler response-file expansion in CFLAGS/CPPFLAGS", "Clang --config external configuration file in CFLAGS/CPPFLAGS", "Clang --config-system-dir/--config-user-dir configuration search controls", - "GCC -specs/--specs external specs-file expansion in CFLAGS/CPPFLAGS" + "GCC -specs/--specs external specs-file expansion in CFLAGS/CPPFLAGS", + "tab-separated GCC -specs external specs-file expansion", + "GCC -B compiler subprogram search override", + "SIGTERM forwarding to active R7 study with prompt staging cleanup" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 7b1f736..3a55f71 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -278,16 +278,26 @@ validate_literal_build_flags() fail "$flag_name must not contain newline or carriage-return shell control characters" ;; esac - case "$flag_value" in - *'--config'*) - fail "$flag_name must not contain Clang configuration-file controls; external compiler config files are not bound evidence inputs" - ;; - esac - case "$flag_value" in - *'-specs='*|*'--specs='*|*'-specs '*|*'--specs '*) - fail "$flag_name must not contain GCC specs-file controls; external compiler specs files are not bound evidence inputs" - ;; - esac + old_ifs=$IFS + IFS=' +' + for flag_token in $flag_value; do + case "$flag_token" in + --config|--config=*|--config-system-dir|--config-system-dir=*|--config-user-dir|--config-user-dir=*) + IFS=$old_ifs + fail "$flag_name must not contain Clang configuration-file controls; external compiler config files are not bound evidence inputs" + ;; + -specs|--specs|-specs=*|--specs=*) + IFS=$old_ifs + fail "$flag_name must not contain GCC specs-file controls; external compiler specs files are not bound evidence inputs" + ;; + -B*) + IFS=$old_ifs + fail "$flag_name must not contain GCC -B compiler subprogram search overrides; external compiler executables are not bound evidence inputs" + ;; + esac + done + IFS=$old_ifs } validate_literal_build_flags CPPFLAGS "$cppflags" @@ -698,6 +708,8 @@ case "$publish_lock_id" in esac publish_lock="$out_parent_abs/.r7-publish-lock-$publish_lock_id" publish_lock_held=false +active_study_pid= +termination_status= cleanup_capture_state() { if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then @@ -716,7 +728,21 @@ cleanup_capture_state() fi } -trap cleanup_capture_state 0 1 2 3 15 +forward_termination_signal() +{ + forwarded_signal=$1 + termination_status=$2 + + if [ -n "${active_study_pid:-}" ]; then + kill "-$forwarded_signal" "$active_study_pid" >/dev/null 2>&1 || : + fi +} + +trap cleanup_capture_state 0 +trap 'forward_termination_signal HUP 129' 1 +trap 'forward_termination_signal INT 130' 2 +trap 'forward_termination_signal QUIT 131' 3 +trap 'forward_termination_signal TERM 143' 15 if [ "$fresh_build_self_test" = true ]; then materialize_source_snapshot @@ -921,7 +947,24 @@ observations_path="$bundle_stage/observations.tsv" } > "$bundle_stage/command.txt" "$study_executable" --profile local --repeats "$repeats" \ - > "$observations_path" + > "$observations_path" & +active_study_pid=$! + +if wait "$active_study_pid"; then + study_status=0 +else + study_status=$? +fi + +if [ -n "$termination_status" ]; then + wait "$active_study_pid" >/dev/null 2>&1 || : + active_study_pid= + exit "$termination_status" +fi + +active_study_pid= +[ "$study_status" -eq 0 ] || + fail "R7 study execution failed with status $study_status" validate_snapshot_identity validate_source_identity diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index b317d28..735efab 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -41,6 +41,8 @@ cleanup() rm -f "/tmp/r7-response-header-$test_id.h" "/tmp/r7-response-flags-$test_id.rsp" rm -f "/tmp/r7-clang-config-header-$test_id.h" "/tmp/r7-clang-config-$test_id.cfg" rm -f "/tmp/r7-gcc-spec-header-$test_id.h" "/tmp/r7-gcc-spec-$test_id.specs" + rm -rf "/tmp/r7-bprefix-$test_id" + rm -f "/tmp/r7-b-header-$test_id.h" "/tmp/r7-signal-$test_id.log" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -180,6 +182,32 @@ expect_capture_failure gcc-long-specs-equals-cppflags \ expect_capture_failure gcc-specs-split-cflags \ env "CFLAGS=-specs $gcc_spec" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +tab_specs_flags=$(printf '%s\t%s' -specs "$gcc_spec") +expect_capture_failure gcc-specs-tab-cflags \ + env "CFLAGS=$tab_specs_flags" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh + +# GCC -B must not replace trusted compiler subprograms with unbound executables. +b_prefix="/tmp/r7-bprefix-$test_id" +b_header="/tmp/r7-b-header-$test_id.h" +mkdir -p "$b_prefix" +cat > "$b_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 434343 +EOF +cat > "$b_prefix/cc1" <"$signal_log" 2>&1 & +signal_wrapper_pid=$! +signal_stage= +signal_study_pid= +signal_probe=0 +while [ "$signal_probe" -lt 30 ]; do + signal_stage=$(/usr/bin/find build -maxdepth 1 -type d -name 'r7-bundle-stage-*' -print -quit) + if [ -n "$signal_stage" ] && [ -e "$signal_stage/observations.tsv" ]; then + signal_study_pid=$( + /usr/bin/ps -eo pid=,ppid=,comm= | + /usr/bin/awk -v parent="$signal_wrapper_pid" '$2 == parent && $3 ~ /rune_r7_study/ { print $1; exit }' + ) + [ -n "$signal_study_pid" ] && break + fi + if ! kill -0 "$signal_wrapper_pid" 2>/dev/null; then + cat "$signal_log" >&2 + fail "signal-forward capture exited before the active study was observed" + fi + sleep 1 + signal_probe=$((signal_probe + 1)) +done +[ -n "$signal_study_pid" ] || { + cat "$signal_log" >&2 + kill -TERM "$signal_wrapper_pid" >/dev/null 2>&1 || : + fail "could not observe active R7 study for signal-forward regression" +} + +kill -TERM "$signal_wrapper_pid" +signal_probe=0 +while kill -0 "$signal_wrapper_pid" 2>/dev/null && [ "$signal_probe" -lt 10 ]; do + sleep 1 + signal_probe=$((signal_probe + 1)) +done +if kill -0 "$signal_wrapper_pid" 2>/dev/null; then + kill -KILL "$signal_wrapper_pid" >/dev/null 2>&1 || : + kill -KILL "$signal_study_pid" >/dev/null 2>&1 || : + fail "SIGTERM was not forwarded promptly to the active R7 study" +fi +if wait "$signal_wrapper_pid"; then + fail "signal-forward capture unexpectedly exited successfully" +else + signal_status=$? +fi +[ "$signal_status" -eq 143 ] || + fail "signal-forward capture exited with status $signal_status instead of 143" +signal_probe=0 +while kill -0 "$signal_study_pid" 2>/dev/null && [ "$signal_probe" -lt 5 ]; do + sleep 1 + signal_probe=$((signal_probe + 1)) +done +if kill -0 "$signal_study_pid" 2>/dev/null; then + kill -KILL "$signal_study_pid" >/dev/null 2>&1 || : + fail "R7 study child remained alive after wrapper SIGTERM" +fi +[ ! -e "$signal_dest" ] || fail "terminated capture published a destination" +[ -z "$signal_stage" ] || [ ! -e "$signal_stage" ] || + fail "terminated capture left its bundle staging directory" + run_concurrent_pair() { label=$1 From 380afca9f032f856764f93dd7baa83e7883c9409 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:08:49 +0930 Subject: [PATCH 120/132] Fix R7 compiler override regression fixture --- tests/test_r7_run_local.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 735efab..31edbd9 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -196,10 +196,11 @@ cat > "$b_header" <<'EOF' #undef CLOCKS_PER_SEC #define CLOCKS_PER_SEC 434343 EOF +real_cc1_path=$("$system_cc" -print-prog-name=cc1) +[ -n "$real_cc1_path" ] || fail "could not resolve compiler cc1 for -B regression" cat > "$b_prefix/cc1" < Date: Mon, 28 Sep 2026 00:28:43 +0930 Subject: [PATCH 121/132] Harden R7 wrappers replay and hash environment --- AGENTS.md | 5 ++ R7-MEMORY-WALL-STUDY.md | 12 ++-- evidence/r7/README.md | 22 +++--- machine/r7-memory-wall-study.v1.json | 27 +++++++- scripts/r7-run-local.sh | 75 +++++++++++++++++--- tests/test_r7_run_local.sh | 100 ++++++++++++++++++++++++++- 6 files changed, 217 insertions(+), 24 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a8088ac..3d1b2fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -171,6 +171,7 @@ CORE_RULES: - R7_capture_unique_identity_is_UTC_timestamp_plus_shell_PID_for_source_build_bundle_and_publish_stages - R7_failed_capture_removes_bundle_stage_and_source_snapshot - R7_termination_signals_are_forwarded_to_active_study_before_capture_cleanup +- R7_termination_before_study_start_exits_without_launching_measurement - R7_requested_destination_is_published_only_after_measurement_source_revalidation_and_SHA256 - R7_publish_uses_sibling_destination_filesystem_stage_before_final_rename - R7_copied_publish_stage_must_pass_SHA256_before_final_rename @@ -213,6 +214,7 @@ CORE_RULES: - R7_platform_identity_and_CPU_model_are_serialized_with_printf_without_echo_escape_interpretation - R7_uname_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_integrity_SHA256_utility_is_resolved_from_fixed_provenance_PATH_and_recorded +- R7_shasum_fallback_clears_Perl_interpreter_injection_and_search_environment - R7_quote_serializer_sed_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_memory_profile_awk_parser_is_resolved_from_fixed_provenance_PATH_and_recorded - R7_optional_getconf_and_sysctl_host_probes_use_fixed_provenance_PATH @@ -225,6 +227,7 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_specs_file_controls - R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_tokenized_across_all_POSIX_shell_whitespace - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_B_subprogram_search_overrides +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_subprocess_wrapper_controls - R7_CPPFLAGS_and_CFLAGS_shell_response_or_compiler_config_expansion_rejection_occurs_before_Make_execution - R7_CPPFLAGS_and_CFLAGS_recording_preserves_backslashes_exactly - R7_archiver_identity_is_recorded_and_bound @@ -233,6 +236,8 @@ CORE_RULES: - R7_arbitrary_external_compiler_wrappers_are_forbidden_for_evidence_capture - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting - R7_recorded_replay_begins_with_set_eu_and_fails_fast +- R7_failed_replay_preserves_checksum_bound_observations_and_cleans_snapshot_and_temporary_output +- R7_successful_replay_atomically_replaces_observations_only_after_study_success - R7_recorded_replay_recreates_git_source_snapshot - R7_recorded_replay_build_uses_make_C_source_snapshot - R7_recorded_replay_study_path_is_absolute diff --git a/R7-MEMORY-WALL-STUDY.md b/R7-MEMORY-WALL-STUDY.md index eeead42..959860c 100644 --- a/R7-MEMORY-WALL-STUDY.md +++ b/R7-MEMORY-WALL-STUDY.md @@ -291,8 +291,9 @@ checked against the recorded revision and made read-only before Make runs. Make compiler input. Worktree and snapshot identity are checked again after the build and after measurement. The publish destination is not created during the build or measurement. The study runs as a tracked child process; HUP, INT, QUIT, and TERM received by the -wrapper are forwarded to the active study, then normal EXIT cleanup removes the -source snapshot and staged bundle promptly. This also covers measurement +wrapper are forwarded to the active study. If cancellation arrives before the +study starts, the wrapper exits immediately rather than entering measurement. +Normal EXIT cleanup removes the source snapshot and staged bundle promptly. This also covers measurement failures such as resource exhaustion. **Any dirty or divergent checkout/snapshot is rejected.** R7 local evidence therefore binds directly to the recorded `source_revision`; a bundle may not @@ -325,12 +326,15 @@ The script records: command separators, redirections, shell comments, tilde expansion, pathname-globbing metacharacters, `@` compiler response-file syntax, Clang `--config...` configuration-file/search-directory controls, GCC - `-specs`/`--specs` external specs-file controls, and GCC `-B` compiler - subprogram search overrides. Sensitive compiler controls are tokenized using + `-specs`/`--specs` external specs-file controls, GCC `-B` compiler + subprogram search overrides, and GCC `-wrapper` subprocess wrappers. + Sensitive compiler controls are tokenized using POSIX shell whitespace, so tab-separated forms cannot bypass the checks. Flags must therefore be literal, replayable compiler arguments rather than expressions whose effective argv depends on unrecorded shell or filesystem state; +- explicit sanitation of Perl interpreter injection/search variables before + any Perl-based `shasum` fallback identity or hashing invocation; - explicit sanitation of ambient compiler search/override variables (`CPATH`, `C_INCLUDE_PATH`, `CPLUS_INCLUDE_PATH`, `OBJC_INCLUDE_PATH`, `COMPILER_PATH`, `LIBRARY_PATH`, diff --git a/evidence/r7/README.md b/evidence/r7/README.md index 0f967d5..493eb1a 100644 --- a/evidence/r7/README.md +++ b/evidence/r7/README.md @@ -88,22 +88,26 @@ physical page count and page size. Inherited MAKEFLAGS/GNUMAKEFLAGS/MFLAGS/MAKEFILES/MAKEOVERRIDES are cleared for the evidence build. Ambient `PATH` is replaced by the fixed recorded `/usr/bin:/bin:/usr/sbin:/sbin` path; Make, compiler, archiver and build -utilities are resolved there. CPPFLAGS/CFLAGS metadata is emitted with +utilities are resolved there. If the Perl-based `shasum` fallback is needed, +Perl module/search/option injection variables are cleared before tool identity +capture and every fallback hash invocation. CPPFLAGS/CFLAGS metadata is emitted with `printf`, preserving accepted backslashes exactly. Before Make runs, evidence capture rejects Make-variable references, shell-evaluated substitution, control, redirection, comment, tilde and pathname-globbing metacharacters, `@` compiler response-file syntax, Clang `--config...` configuration file/search-directory controls, GCC `-specs`/`--specs` external specs-file -controls, and GCC `-B` compiler subprogram search overrides. Sensitive -compiler controls are tokenized over POSIX shell whitespace, including tabs. +controls, GCC `-B` compiler subprogram search overrides, and GCC +`-wrapper` subprocess wrappers. Sensitive compiler controls are tokenized over +POSIX shell whitespace, including tabs. The recorded flag text therefore cannot turn into unrecorded commands, response/config/specs-file contents, or filesystem-dependent argv during recipe/compiler evaluation. Each capture uses one UTC-timestamp-plus-PID identity for its source snapshot, `BUILD_DIR`, repository bundle stage, and sibling publish stage. During the measurement, HUP/INT/QUIT/TERM are forwarded to the tracked study child before -the EXIT trap removes staged capture state, so cancelling the wrapper does not -leave the expensive study running in the background. The shared +the EXIT trap removes staged capture state. If cancellation arrives before the +study exists, the wrapper exits immediately and never launches measurement, so +cancelling the wrapper does not leave expensive work running in the background. The shared repository `build/` parent is created idempotently, so concurrent captures are isolated whether the parent already exists or is created by racing captures. The build never relies on `make clean`, so a fake ambient `rm` cannot @@ -118,9 +122,11 @@ absolute. The bundle records the build-driver identity and Makefile Git blob identity. Ignored `GNUmakefile` or lowercase `makefile` files cannot replace the build recipe. The recorded run command begins with `set -eu`, uses an absolute study -executable path, and includes the absolute redirection to `observations.tsv`. -A replay therefore stops on its first failed setup/build/study command instead -of allowing cleanup to mask the failure. Shell quoting is serialized +executable path, and writes replay output to a PID-qualified temporary sibling. +An EXIT trap always cleans that temporary output and the replay source snapshot; +only a fully successful study atomically replaces `observations.tsv`. A failed +replay therefore preserves the checksum-bound evidence bundle while still +stopping on its first failed setup/build/study command. Shell quoting is serialized with a fixed-provenance `sed`, so paths containing apostrophes remain valid. `command.txt` is replayable from outside the repository while recreating the captured output artifact. diff --git a/machine/r7-memory-wall-study.v1.json b/machine/r7-memory-wall-study.v1.json index bb1393f..60b951a 100644 --- a/machine/r7-memory-wall-study.v1.json +++ b/machine/r7-memory-wall-study.v1.json @@ -425,7 +425,26 @@ "GCC_B_subprogram_search_overrides_allowed": false, "GCC_B_controls_rejected_before_make": true, "termination_signals_forwarded_to_active_study": true, - "termination_signal_exit_status_preserved_as_128_plus_signal": true + "termination_signal_exit_status_preserved_as_128_plus_signal": true, + "GCC_subprocess_wrapper_controls_allowed": false, + "GCC_wrapper_controls_rejected_before_make": true, + "termination_before_study_start_exits_without_measurement": true, + "replay_writes_observations_to_temporary_sibling_until_success": true, + "failed_replay_preserves_existing_observations": true, + "failed_replay_cleans_source_snapshot": true, + "failed_replay_cleans_temporary_observations": true, + "successful_replay_replaces_observations_only_after_study_success": true, + "shasum_fallback_perl_environment_sanitized": [ + "PERL5OPT", + "PERL5LIB", + "PERLLIB", + "PERL_UNICODE", + "PERLIO", + "PERL_LOCAL_LIB_ROOT", + "PERL_MB_OPT", + "PERL_MM_OPT" + ], + "shasum_fallback_perl_environment_sanitized_before_identity_and_invocation": true }, "interpretation": { "github_hosted_CI_timing_is_performance_evidence": false, @@ -474,7 +493,11 @@ "GCC -specs/--specs external specs-file expansion in CFLAGS/CPPFLAGS", "tab-separated GCC -specs external specs-file expansion", "GCC -B compiler subprogram search override", - "SIGTERM forwarding to active R7 study with prompt staging cleanup" + "SIGTERM forwarding to active R7 study with prompt staging cleanup", + "GCC -wrapper subprocess override", + "SIGTERM before study start exits without launching measurement", + "resource-constrained replay preserves observations and cleans snapshot/temp output", + "Perl environment sanitation for shasum fallback" ], "clock_regressions_run_under_UBSan": true, "floating_clock_t_regression_source": "tests/test_r7_clock_float.c", diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 3a55f71..6751c75 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -19,6 +19,18 @@ shell_quote() printf "'" } +sanitize_perl_hash_environment() +{ + unset PERL5OPT + unset PERL5LIB + unset PERLLIB + unset PERL_UNICODE + unset PERLIO + unset PERL_LOCAL_LIB_ROOT + unset PERL_MB_OPT + unset PERL_MM_OPT +} + sanitize_capture_environment() { unset GIT_DIR @@ -51,6 +63,8 @@ sanitize_capture_environment() unset SHLIB_PATH unset TAR_OPTIONS + + sanitize_perl_hash_environment } sanitize_capture_environment @@ -179,6 +193,9 @@ case "$hash_path" in /*) ;; *) fail "SHA-256 utility path is not absolute: $hash_path" ;; esac +if [ "$hash_mode" = shasum ]; then + sanitize_perl_hash_environment +fi [ -x "$hash_path" ] || fail "SHA-256 utility path is not executable: $hash_path" @@ -212,6 +229,12 @@ if [ "${1:-}" = "--self-test-shell-quote" ]; then exit 0 fi +if [ "${1:-}" = "--self-test-perl-hash-env" ]; then + [ -z "${PERL5OPT+x}${PERL5LIB+x}${PERLLIB+x}${PERL_UNICODE+x}${PERLIO+x}${PERL_LOCAL_LIB_ROOT+x}${PERL_MB_OPT+x}${PERL_MM_OPT+x}" ] || + fail "Perl hash environment self-test failed" + exit 0 +fi + if [ "${1:-}" = "--self-test-compiler-search-env" ]; then [ -z "${CPATH+x}${C_INCLUDE_PATH+x}${CPLUS_INCLUDE_PATH+x}${OBJC_INCLUDE_PATH+x}${COMPILER_PATH+x}${LIBRARY_PATH+x}${GCC_EXEC_PREFIX+x}${CCC_OVERRIDE_OPTIONS+x}" ] || fail "compiler search environment self-test failed" @@ -295,6 +318,10 @@ validate_literal_build_flags() IFS=$old_ifs fail "$flag_name must not contain GCC -B compiler subprogram search overrides; external compiler executables are not bound evidence inputs" ;; + -wrapper|--wrapper|-wrapper=*|--wrapper=*) + IFS=$old_ifs + fail "$flag_name must not contain GCC subprocess wrapper controls; external compiler wrappers are not bound evidence inputs" + ;; esac done IFS=$old_ifs @@ -695,6 +722,7 @@ case "$hash_mode" in publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" | "$awk_path" '{ print $1 }') ;; shasum) + sanitize_perl_hash_environment publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" -a 256 | "$awk_path" '{ print $1 }') ;; *) @@ -735,7 +763,10 @@ forward_termination_signal() if [ -n "${active_study_pid:-}" ]; then kill "-$forwarded_signal" "$active_study_pid" >/dev/null 2>&1 || : + return fi + + exit "$termination_status" } trap cleanup_capture_state 0 @@ -874,6 +905,35 @@ observations_path="$bundle_stage/observations.tsv" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" printf "unset TAR_OPTIONS\n" + printf "unset PERL5OPT PERL5LIB PERLLIB PERL_UNICODE PERLIO PERL_LOCAL_LIB_ROOT PERL_MB_OPT PERL_MM_OPT\n" + printf "replay_observations_tmp=" + shell_quote "$out_abs/.r7-replay-observations-" + printf "\$\$\n" + printf "replay_cleanup() {\n" + printf " replay_status=\$?\n" + printf " if [ -n \"\${replay_observations_tmp:-}\" ]; then " + shell_quote "$provenance_rm_path" + printf " -f \"\$replay_observations_tmp\" >/dev/null 2>&1 || :; fi\n" + printf " if [ -d " + shell_quote "$source_snapshot" + printf " ]; then " + shell_quote "$chmod_path" + printf " -R u+w " + shell_quote "$source_snapshot" + printf " >/dev/null 2>&1 || :; fi\n" + printf " " + shell_quote "$provenance_rm_path" + printf " -rf " + shell_quote "$source_snapshot" + printf " >/dev/null 2>&1 || :\n" + printf " return \"\$replay_status\"\n" + printf "}\n" + printf "trap replay_cleanup 0\n" + printf "trap 'exit 129' 1\n" + printf "trap 'exit 130' 2\n" + printf "trap 'exit 131' 3\n" + printf "trap 'exit 143' 15\n" + printf "[ ! -e \"\$replay_observations_tmp\" ] && [ ! -L \"\$replay_observations_tmp\" ]\n" shell_quote "$bundle_mkdir_path" printf " -p " shell_quote "$repo_root/build" @@ -933,17 +993,12 @@ observations_path="$bundle_stage/observations.tsv" shell_quote "$study_executable" printf " --profile local --repeats " shell_quote "$repeats" - printf " > " + printf " > \"\$replay_observations_tmp\"\n" + shell_quote "$mv_path" + printf " \"\$replay_observations_tmp\" " shell_quote "$out_abs/observations.tsv" printf '\n' - shell_quote "$chmod_path" - printf " -R u+w " - shell_quote "$source_snapshot" - printf '\n' - shell_quote "$provenance_rm_path" - printf " -rf " - shell_quote "$source_snapshot" - printf '\n' + printf "replay_observations_tmp=\n" } > "$bundle_stage/command.txt" "$study_executable" --profile local --repeats "$repeats" \ @@ -983,6 +1038,7 @@ case "$hash_mode" in ) ;; shasum) + sanitize_perl_hash_environment ( cd "$bundle_stage" "$hash_path" -a 256 \ @@ -1023,6 +1079,7 @@ case "$hash_mode" in ) || fail "copied publish staging bundle failed SHA-256 verification" ;; shasum) + sanitize_perl_hash_environment ( cd "$publish_stage" "$hash_path" -a 256 -c SHA256SUMS diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 31edbd9..4e910e9 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -42,7 +42,8 @@ cleanup() rm -f "/tmp/r7-clang-config-header-$test_id.h" "/tmp/r7-clang-config-$test_id.cfg" rm -f "/tmp/r7-gcc-spec-header-$test_id.h" "/tmp/r7-gcc-spec-$test_id.specs" rm -rf "/tmp/r7-bprefix-$test_id" - rm -f "/tmp/r7-b-header-$test_id.h" "/tmp/r7-signal-$test_id.log" + rm -f "/tmp/r7-b-header-$test_id.h" "/tmp/r7-wrapper-header-$test_id.h" "/tmp/r7-wrapper-$test_id" + rm -f "/tmp/r7-signal-$test_id.log" "/tmp/r7-prestudy-signal-$test_id.log" rm -f "/tmp/r7-concurrent-a-$test_id.log" "/tmp/r7-concurrent-b-$test_id.log" rm -f "/tmp/r7-compete-a-$test_id.log" "/tmp/r7-compete-b-$test_id.log" rm -rf "$repo_root"/build/r7-source-* "$repo_root"/build/r7-evidence-* "$repo_root"/build/r7-bundle-stage-* @@ -210,10 +211,41 @@ expect_capture_failure gcc-b-attached-cppflags \ env "CPPFLAGS=-B$b_prefix/" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +# GCC -wrapper must not introduce mutable subprocess wrappers. +wrapper_header="/tmp/r7-wrapper-header-$test_id.h" +wrapper_path="/tmp/r7-wrapper-$test_id" +cat > "$wrapper_header" <<'EOF' +#include +#undef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 454545 +EOF +cat > "$wrapper_path" <"$pre_signal_log" 2>&1 & +pre_signal_pid=$! +pre_signal_source= +pre_signal_probe=0 +while [ "$pre_signal_probe" -lt 100 ]; do + pre_signal_source=$(/usr/bin/find build -maxdepth 1 -type d -name 'r7-source-*' -print -quit) + [ -n "$pre_signal_source" ] && break + if ! kill -0 "$pre_signal_pid" 2>/dev/null; then + cat "$pre_signal_log" >&2 + fail "pre-study signal capture exited before source snapshot appeared" + fi + sleep 0.05 + pre_signal_probe=$((pre_signal_probe + 1)) +done +[ -n "$pre_signal_source" ] || { + kill -TERM "$pre_signal_pid" >/dev/null 2>&1 || : + fail "could not observe source snapshot for pre-study signal regression" +} +kill -TERM "$pre_signal_pid" +pre_signal_probe=0 +while kill -0 "$pre_signal_pid" 2>/dev/null && [ "$pre_signal_probe" -lt 100 ]; do + sleep 0.05 + pre_signal_probe=$((pre_signal_probe + 1)) +done +if kill -0 "$pre_signal_pid" 2>/dev/null; then + kill -KILL "$pre_signal_pid" >/dev/null 2>&1 || : + fail "pre-study SIGTERM did not terminate wrapper promptly" +fi +if wait "$pre_signal_pid"; then + fail "pre-study signal capture unexpectedly exited successfully" +else + pre_signal_status=$? +fi +[ "$pre_signal_status" -eq 143 ] || + fail "pre-study signal capture exited with status $pre_signal_status instead of 143" +[ ! -e "$pre_signal_dest" ] || fail "pre-study terminated capture published a destination" +[ ! -e "$pre_signal_source" ] || + fail "pre-study terminated capture left its source snapshot" + # SIGTERM to the wrapper must promptly terminate the active study and clean staging. signal_dest="$tmp_root/signal-forward" signal_log="/tmp/r7-signal-$test_id.log" @@ -431,6 +506,29 @@ after_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk fail "failed replay modified observations.tsv" rm -f "$snapshot_path" +# Replay study failure must preserve checksum-bound observations and clean snapshot/temp output. +runtime_replay_bundle="$tmp_root/replay-runtime-failure" +RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$runtime_replay_bundle" >/dev/null +runtime_snapshot=$(/usr/bin/sed -n 's/^source_snapshot=//p' "$runtime_replay_bundle/environment.txt") +[ -n "$runtime_snapshot" ] || fail "runtime replay bundle did not record source_snapshot" +runtime_before_hash=$(/usr/bin/sha256sum "$runtime_replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') +if (ulimit -v 120000; /bin/sh "$runtime_replay_bundle/command.txt" >/dev/null 2>&1); then + fail "resource-constrained replay unexpectedly succeeded" +fi +runtime_after_hash=$(/usr/bin/sha256sum "$runtime_replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') +[ "$runtime_before_hash" = "$runtime_after_hash" ] || + fail "failed runtime replay modified observations.tsv" +[ ! -e "$runtime_snapshot" ] || + fail "failed runtime replay left its source snapshot" +if /usr/bin/find "$runtime_replay_bundle" -maxdepth 1 -name '.r7-replay-observations-*' -print -quit | /usr/bin/grep -q .; then + fail "failed runtime replay left temporary observations" +fi +( + cd "$runtime_replay_bundle" + /usr/bin/sha256sum -c SHA256SUMS >/dev/null +) || fail "failed runtime replay invalidated the evidence bundle" + # TAR_OPTIONS must be cleared for capture and replay; hook execution is forbidden. cat > /tmp/r7-tar-hook-$test_id < Date: Mon, 28 Sep 2026 00:32:18 +0930 Subject: [PATCH 122/132] Update R7 replay CI contract --- .github/workflows/c99.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index a6c3f1f..37bab34 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -340,7 +340,9 @@ jobs: scripts/r7-run-local.sh "$replay_bundle" grep -Fxq 'cppflags=-DUNUSED=a\c' "$replay_bundle/environment.txt" grep -Fxq 'cflags=-O2' "$replay_bundle/environment.txt" - grep -Fq " > '$replay_bundle/observations.tsv'" "$replay_bundle/command.txt" + grep -Fq 'replay_observations_tmp=' "$replay_bundle/command.txt" + grep -Fq ' > "$replay_observations_tmp"' "$replay_bundle/command.txt" + grep -Fq "\"\$replay_observations_tmp\" '$replay_bundle/observations.tsv'" "$replay_bundle/command.txt" mv "$replay_bundle/observations.tsv" "$replay_bundle/observations.original.tsv" ( cd /tmp From aba2be4d331631b8e45124cb95ea8c92380c35ba Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:57:36 +0930 Subject: [PATCH 123/132] Harden R7 evidence isolation and replay concurrency --- scripts/r7-run-local.sh | 70 ++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 6751c75..15fa525 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -40,7 +40,20 @@ sanitize_capture_environment() unset GIT_ALTERNATE_OBJECT_DIRECTORIES unset GIT_COMMON_DIR unset GIT_NAMESPACE + unset GIT_CONFIG + unset GIT_CONFIG_PARAMETERS + unset GIT_CONFIG_SYSTEM + unset GIT_CONFIG_GLOBAL + unset GIT_CONFIG_NOSYSTEM + unset GIT_CONFIG_COUNT export GIT_NO_REPLACE_OBJECTS=1 + export GIT_CONFIG_NOSYSTEM=1 + export GIT_CONFIG_GLOBAL=/dev/null + export GIT_CONFIG_COUNT=2 + export GIT_CONFIG_KEY_0=core.fsmonitor + export GIT_CONFIG_VALUE_0=false + export GIT_CONFIG_KEY_1=core.hooksPath + export GIT_CONFIG_VALUE_1=/dev/null unset CPATH unset C_INCLUDE_PATH @@ -305,22 +318,24 @@ validate_literal_build_flags() IFS=' ' for flag_token in $flag_value; do - case "$flag_token" in + effective_flag_token=$(printf '%s' "$flag_token" | + "$sed_path" -e "s/'//g" -e 's/"//g' -e 's/\\//g') + case "$effective_flag_token" in --config|--config=*|--config-system-dir|--config-system-dir=*|--config-user-dir|--config-user-dir=*) IFS=$old_ifs - fail "$flag_name must not contain Clang configuration-file controls; external compiler config files are not bound evidence inputs" + fail "$flag_name must not contain Clang configuration-file controls, including shell-quoted or escaped forms; external compiler config files are not bound evidence inputs" ;; -specs|--specs|-specs=*|--specs=*) IFS=$old_ifs - fail "$flag_name must not contain GCC specs-file controls; external compiler specs files are not bound evidence inputs" + fail "$flag_name must not contain GCC specs-file controls, including shell-quoted or escaped forms; external compiler specs files are not bound evidence inputs" ;; -B*) IFS=$old_ifs - fail "$flag_name must not contain GCC -B compiler subprogram search overrides; external compiler executables are not bound evidence inputs" + fail "$flag_name must not contain GCC -B compiler subprogram search overrides, including shell-quoted or escaped forms; external compiler executables are not bound evidence inputs" ;; -wrapper|--wrapper|-wrapper=*|--wrapper=*) IFS=$old_ifs - fail "$flag_name must not contain GCC subprocess wrapper controls; external compiler wrappers are not bound evidence inputs" + fail "$flag_name must not contain GCC subprocess wrapper controls, including shell-quoted or escaped forms; external compiler wrappers are not bound evidence inputs" ;; esac done @@ -852,6 +867,7 @@ observations_path="$bundle_stage/observations.tsv" printf 'cppflags=%s\n' "$cppflags" printf 'cflags=%s\n' "$cflags" echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" + echo "git_configuration_environment=system/global config disabled; core.fsmonitor=false; core.hooksPath=/dev/null" echo "git_replace_objects=disabled and replacement refs forbidden" echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" @@ -902,6 +918,10 @@ observations_path="$bundle_stage/observations.tsv" printf "set -eu\n" printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" printf "export GIT_NO_REPLACE_OBJECTS=1\n" + printf "unset GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_CONFIG_SYSTEM GIT_CONFIG_GLOBAL GIT_CONFIG_NOSYSTEM GIT_CONFIG_COUNT\n" + printf "export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_COUNT=2\n" + printf "export GIT_CONFIG_KEY_0=core.fsmonitor GIT_CONFIG_VALUE_0=false\n" + printf "export GIT_CONFIG_KEY_1=core.hooksPath GIT_CONFIG_VALUE_1=/dev/null\n" printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" printf "unset TAR_OPTIONS\n" @@ -909,22 +929,30 @@ observations_path="$bundle_stage/observations.tsv" printf "replay_observations_tmp=" shell_quote "$out_abs/.r7-replay-observations-" printf "\$\$\n" + printf "replay_source_snapshot=" + shell_quote "$repo_root/build/r7-replay-source-$capture_id-" + printf "\$\$\n" + printf "replay_build_dir_rel=" + shell_quote "build/r7-replay-evidence-$capture_id-" + printf "\$\$\n" + printf 'replay_study_target="$replay_build_dir_rel/rune_r7_study"\n' + printf 'replay_study_executable="$replay_source_snapshot/$replay_study_target"\n' printf "replay_cleanup() {\n" printf " replay_status=\$?\n" printf " if [ -n \"\${replay_observations_tmp:-}\" ]; then " shell_quote "$provenance_rm_path" printf " -f \"\$replay_observations_tmp\" >/dev/null 2>&1 || :; fi\n" printf " if [ -d " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf " ]; then " shell_quote "$chmod_path" printf " -R u+w " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf " >/dev/null 2>&1 || :; fi\n" printf " " shell_quote "$provenance_rm_path" printf " -rf " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf " >/dev/null 2>&1 || :\n" printf " return \"\$replay_status\"\n" printf "}\n" @@ -940,7 +968,7 @@ observations_path="$bundle_stage/observations.tsv" printf '\n' shell_quote "$bundle_mkdir_path" printf " " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf '\n' shell_quote "$git_path" printf " -C " @@ -948,38 +976,38 @@ observations_path="$bundle_stage/observations.tsv" printf " archive --format=tar " shell_quote "$revision" printf " -- Makefile src include study > " - shell_quote "$source_snapshot/.r7-source.tar" + printf '"$replay_source_snapshot/.r7-source.tar"' printf '\n' shell_quote "$tar_path" printf " -xf " - shell_quote "$source_snapshot/.r7-source.tar" + printf '"$replay_source_snapshot/.r7-source.tar"' printf " -C " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf '\n' shell_quote "$provenance_rm_path" printf " -f " - shell_quote "$source_snapshot/.r7-source.tar" + printf '"$replay_source_snapshot/.r7-source.tar"' printf '\n' shell_quote "$chmod_path" printf " -R a-w " - shell_quote "$source_snapshot/Makefile" + printf '"$replay_source_snapshot/Makefile"' printf " " - shell_quote "$source_snapshot/src" + printf '"$replay_source_snapshot/src"' printf " " - shell_quote "$source_snapshot/include" + printf '"$replay_source_snapshot/include"' printf " " - shell_quote "$source_snapshot/study" + printf '"$replay_source_snapshot/study"' printf '\n' printf "PATH=" shell_quote "$build_path" printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " shell_quote "$make_path" printf " -C " - shell_quote "$source_snapshot" + printf '"$replay_source_snapshot"' printf " -f Makefile " - shell_quote "$study_target" + printf '"$replay_study_target"' printf " BUILD_DIR=" - shell_quote "$build_dir_rel" + printf '"$replay_build_dir_rel"' printf " CC=" shell_quote "$cc_path" printf " AR=" @@ -990,7 +1018,7 @@ observations_path="$bundle_stage/observations.tsv" shell_quote "$cflags" printf '\n' - shell_quote "$study_executable" + printf '"$replay_study_executable"' printf " --profile local --repeats " shell_quote "$repeats" printf " > \"\$replay_observations_tmp\"\n" From 033a9534aa4e06ce22725ed7884337594f97915f Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:59:11 +0930 Subject: [PATCH 124/132] Add R7 evidence hardening regressions --- .github/workflows/c99.yml | 64 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c99.yml b/.github/workflows/c99.yml index 37bab34..6ba9e73 100644 --- a/.github/workflows/c99.yml +++ b/.github/workflows/c99.yml @@ -175,6 +175,44 @@ jobs: GCC_EXEC_PREFIX=/tmp/r7-hostile-gcc-prefix \ scripts/r7-run-local.sh --self-test-compiler-search-env + quoted_wrapper_bundle="/tmp/r7-quoted-wrapper-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -rf "$quoted_wrapper_bundle" + if CFLAGS="'-wrapper' /tmp/r7-qwrap" RUNE_R7_REPEATS=1 \ + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$quoted_wrapper_bundle" 2>/dev/null; then + echo "R7 evidence script accepted shell-quoted GCC wrapper control" >&2 + exit 1 + fi + test ! -e "$quoted_wrapper_bundle" + if CFLAGS='\-wrapper /tmp/r7-qwrap' RUNE_R7_REPEATS=1 \ + CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$quoted_wrapper_bundle" 2>/dev/null; then + echo "R7 evidence script accepted shell-escaped GCC wrapper control" >&2 + exit 1 + fi + test ! -e "$quoted_wrapper_bundle" + + fsmonitor_hook="/tmp/r7-fsmonitor-${{ matrix.cc }}-$GITHUB_RUN_ID" + fsmonitor_marker="/tmp/r7-fsmonitor-marker-${{ matrix.cc }}-$GITHUB_RUN_ID" + fsmonitor_bundle="/tmp/r7-fsmonitor-bundle-${{ matrix.cc }}-$GITHUB_RUN_ID" + rm -f "$fsmonitor_hook" "$fsmonitor_marker" + rm -rf "$fsmonitor_bundle" + cat > "$fsmonitor_hook" <> "$fsmonitor_marker" + exit 0 + EOF + chmod +x "$fsmonitor_hook" + git config core.fsmonitor "$fsmonitor_hook" + GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=core.fsmonitor GIT_CONFIG_VALUE_0="$fsmonitor_hook" \ + RUNE_R7_REPEATS=1 CC="/usr/bin/${{ matrix.cc }}" AR=/usr/bin/ar \ + scripts/r7-run-local.sh "$fsmonitor_bundle" + git config --unset-all core.fsmonitor + test ! -e "$fsmonitor_marker" + test -s "$fsmonitor_bundle/observations.tsv" + rm -rf "$fsmonitor_bundle" + rm -f "$fsmonitor_hook" "$fsmonitor_marker" + fakebin=$(mktemp -d) cat > "$fakebin/rm" <<'EOF' #!/bin/sh @@ -341,6 +379,9 @@ jobs: grep -Fxq 'cppflags=-DUNUSED=a\c' "$replay_bundle/environment.txt" grep -Fxq 'cflags=-O2' "$replay_bundle/environment.txt" grep -Fq 'replay_observations_tmp=' "$replay_bundle/command.txt" + grep -Fq 'replay_source_snapshot=' "$replay_bundle/command.txt" + grep -Fq 'replay_build_dir_rel=' "$replay_bundle/command.txt" + grep -Fq 'replay_study_executable="$replay_source_snapshot/$replay_study_target"' "$replay_bundle/command.txt" grep -Fq ' > "$replay_observations_tmp"' "$replay_bundle/command.txt" grep -Fq "\"\$replay_observations_tmp\" '$replay_bundle/observations.tsv'" "$replay_bundle/command.txt" mv "$replay_bundle/observations.tsv" "$replay_bundle/observations.original.tsv" @@ -354,7 +395,28 @@ jobs: echo "R7 replay leaked observation rows to stdout instead of observations.tsv" >&2 exit 1 fi - rm -rf "$replay_bundle" "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" + + rm -f "$replay_bundle/observations.tsv" + ( + cd /tmp + sh "$replay_bundle/command.txt" > "/tmp/r7-replay-concurrent-a-${{ matrix.cc }}.txt" + ) & + replay_a=$! + ( + cd /tmp + sh "$replay_bundle/command.txt" > "/tmp/r7-replay-concurrent-b-${{ matrix.cc }}.txt" + ) & + replay_b=$! + wait "$replay_a" + wait "$replay_b" + test -s "$replay_bundle/observations.tsv" + awk -F '\t' 'NF != 17 { exit 1 } END { if (NR == 0) exit 1 }' "$replay_bundle/observations.tsv" + test -z "$(find "$GITHUB_WORKSPACE/build" -maxdepth 1 -type d -name 'r7-replay-source-*' -print -quit)" + + rm -rf "$replay_bundle" \ + "/tmp/r7-replay-stdout-${{ matrix.cc }}.txt" \ + "/tmp/r7-replay-concurrent-a-${{ matrix.cc }}.txt" \ + "/tmp/r7-replay-concurrent-b-${{ matrix.cc }}.txt" rm -rf "$GITHUB_WORKSPACE"/build/r7-evidence-* lowmem_bundle="/tmp/r7-lowmem-${{ matrix.cc }}-$GITHUB_RUN_ID" From b734fba73ddf35adb380770dc1ad10b34d332959 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:59:24 +0930 Subject: [PATCH 125/132] Document R7 evidence isolation invariants --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 3d1b2fe..4d80395 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -200,6 +200,9 @@ CORE_RULES: - R7_source_snapshot_inputs_are_made_read_only_before_build - R7_mutable_worktree_is_not_used_as_evidence_build_source - R7_source_identity_is_revalidated_after_build_and_after_measurement +- R7_Git_system_and_global_configuration_are_disabled_for_provenance_commands +- R7_Git_core_fsmonitor_and_core_hooksPath_are_forced_inert_for_capture_and_replay +- R7_ambient_GIT_CONFIG_injection_cannot_override_provenance_command_isolation - R7_bundle_is_not_created_until_post_build_source_revalidation_passes - R7_ignored_untracked_files_under_src_include_study_are_forbidden - R7_ambient_compiler_search_path_environment_is_cleared @@ -226,6 +229,7 @@ CORE_RULES: - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Clang_config_file_or_config_search_directory_controls - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_specs_file_controls - R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_tokenized_across_all_POSIX_shell_whitespace +- R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_checked_after_conservative_shell_quote_and_backslash_normalization - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_B_subprogram_search_overrides - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_subprocess_wrapper_controls - R7_CPPFLAGS_and_CFLAGS_shell_response_or_compiler_config_expansion_rejection_occurs_before_Make_execution @@ -237,6 +241,7 @@ CORE_RULES: - R7_recorded_build_command_uses_shell_safe_unambiguous_quoting - R7_recorded_replay_begins_with_set_eu_and_fails_fast - R7_failed_replay_preserves_checksum_bound_observations_and_cleans_snapshot_and_temporary_output +- R7_replay_source_snapshot_and_build_directory_are_process_qualified_for_concurrent_replays - R7_successful_replay_atomically_replaces_observations_only_after_study_success - R7_recorded_replay_recreates_git_source_snapshot - R7_recorded_replay_build_uses_make_C_source_snapshot From 7ac5263663086c2063033df543056deadcc58375 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:29:35 +0930 Subject: [PATCH 126/132] Update R7 replay regressions for PID-qualified snapshots --- tests/test_r7_run_local.sh | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 4e910e9..af98e9a 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -491,27 +491,39 @@ expect_capture_failure canonical-cc env RUNE_R7_REPEATS=1 CC="/usr/bin/../.. expect_capture_failure canonical-ar env RUNE_R7_REPEATS=1 CC="$system_cc" AR="/usr/bin/../../tmp/r7-reg-ar-$test_id" scripts/r7-run-local.sh expect_capture_failure canonical-make env RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" MAKE="/usr/bin/../../tmp/r7-reg-make-$test_id" scripts/r7-run-local.sh -# Replay must fail immediately and preserve observations when snapshot creation fails. +# Replay must fail immediately and preserve observations when its PID-qualified +# snapshot path is blocked before command execution. replay_bundle="$tmp_root/replay" -RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh "$replay_bundle" >/dev/null -snapshot_path=$(/usr/bin/sed -n 's/^source_snapshot=//p' "$replay_bundle/environment.txt") -[ -n "$snapshot_path" ] || fail "replay bundle did not record source_snapshot" +RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$replay_bundle" >/dev/null +snapshot_prefix=$(/usr/bin/sed -n "s/^replay_source_snapshot='\(.*\)'\$\$/\1/p" "$replay_bundle/command.txt") +[ -n "$snapshot_prefix" ] || fail "replay command did not record replay_source_snapshot prefix" before_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') -printf 'block replay snapshot\n' > "$snapshot_path" -if (cd /tmp && /bin/sh "$replay_bundle/command.txt" >/dev/null 2>&1); then +if ( + cd /tmp + SNAPSHOT_PREFIX="$snapshot_prefix" REPLAY_COMMAND="$replay_bundle/command.txt" /bin/sh -c ' + blocker="${SNAPSHOT_PREFIX}$$" + printf "%s\n" "block replay snapshot" > "$blocker" + exec /bin/sh "$REPLAY_COMMAND" + ' >/dev/null 2>&1 +); then fail "replay ignored an early snapshot-creation failure" fi after_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') [ "$before_hash" = "$after_hash" ] || fail "failed replay modified observations.tsv" -rm -f "$snapshot_path" +snapshot_parent=${snapshot_prefix%/*} +snapshot_leaf=${snapshot_prefix##*/} +if /usr/bin/find "$snapshot_parent" -maxdepth 1 -name "$snapshot_leaf*" -print -quit | /usr/bin/grep -q .; then + fail "failed replay left its PID-qualified source snapshot" +fi # Replay study failure must preserve checksum-bound observations and clean snapshot/temp output. runtime_replay_bundle="$tmp_root/replay-runtime-failure" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh "$runtime_replay_bundle" >/dev/null -runtime_snapshot=$(/usr/bin/sed -n 's/^source_snapshot=//p' "$runtime_replay_bundle/environment.txt") -[ -n "$runtime_snapshot" ] || fail "runtime replay bundle did not record source_snapshot" +runtime_snapshot_prefix=$(/usr/bin/sed -n "s/^replay_source_snapshot='\(.*\)'\$\$/\1/p" "$runtime_replay_bundle/command.txt") +[ -n "$runtime_snapshot_prefix" ] || fail "runtime replay command did not record replay_source_snapshot prefix" runtime_before_hash=$(/usr/bin/sha256sum "$runtime_replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') if (ulimit -v 120000; /bin/sh "$runtime_replay_bundle/command.txt" >/dev/null 2>&1); then fail "resource-constrained replay unexpectedly succeeded" @@ -519,8 +531,11 @@ fi runtime_after_hash=$(/usr/bin/sha256sum "$runtime_replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') [ "$runtime_before_hash" = "$runtime_after_hash" ] || fail "failed runtime replay modified observations.tsv" -[ ! -e "$runtime_snapshot" ] || - fail "failed runtime replay left its source snapshot" +runtime_snapshot_parent=${runtime_snapshot_prefix%/*} +runtime_snapshot_leaf=${runtime_snapshot_prefix##*/} +if /usr/bin/find "$runtime_snapshot_parent" -maxdepth 1 -name "$runtime_snapshot_leaf*" -print -quit | /usr/bin/grep -q .; then + fail "failed runtime replay left its PID-qualified source snapshot" +fi if /usr/bin/find "$runtime_replay_bundle" -maxdepth 1 -name '.r7-replay-observations-*' -print -quit | /usr/bin/grep -q .; then fail "failed runtime replay left temporary observations" fi @@ -528,7 +543,6 @@ fi cd "$runtime_replay_bundle" /usr/bin/sha256sum -c SHA256SUMS >/dev/null ) || fail "failed runtime replay invalidated the evidence bundle" - # TAR_OPTIONS must be cleared for capture and replay; hook execution is forbidden. cat > /tmp/r7-tar-hook-$test_id < Date: Mon, 28 Sep 2026 01:34:11 +0930 Subject: [PATCH 127/132] Fix R7 replay assignment parsing --- tests/test_r7_run_local.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index af98e9a..763b07d 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -496,8 +496,14 @@ expect_capture_failure canonical-make env RUNE_R7_REPEATS=1 CC="$system_cc" replay_bundle="$tmp_root/replay" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh "$replay_bundle" >/dev/null -snapshot_prefix=$(/usr/bin/sed -n "s/^replay_source_snapshot='\(.*\)'\$\$/\1/p" "$replay_bundle/command.txt") -[ -n "$snapshot_prefix" ] || fail "replay command did not record replay_source_snapshot prefix" +snapshot_assignment=$(/usr/bin/grep -m1 '^replay_source_snapshot=' "$replay_bundle/command.txt") +case "$snapshot_assignment" in + replay_source_snapshot=\'*\'\$\$) ;; + *) fail "replay command missing PID-qualified replay_source_snapshot assignment" ;; +esac +snapshot_prefix=${snapshot_assignment#replay_source_snapshot=\'} +snapshot_prefix=${snapshot_prefix%\'\$\$} +[ -n "$snapshot_prefix" ] || fail "replay command recorded empty replay_source_snapshot prefix" before_hash=$(/usr/bin/sha256sum "$replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') if ( cd /tmp @@ -522,8 +528,14 @@ fi runtime_replay_bundle="$tmp_root/replay-runtime-failure" RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh "$runtime_replay_bundle" >/dev/null -runtime_snapshot_prefix=$(/usr/bin/sed -n "s/^replay_source_snapshot='\(.*\)'\$\$/\1/p" "$runtime_replay_bundle/command.txt") -[ -n "$runtime_snapshot_prefix" ] || fail "runtime replay command did not record replay_source_snapshot prefix" +runtime_snapshot_assignment=$(/usr/bin/grep -m1 '^replay_source_snapshot=' "$runtime_replay_bundle/command.txt") +case "$runtime_snapshot_assignment" in + replay_source_snapshot=\'*\'\$\$) ;; + *) fail "runtime replay command missing PID-qualified replay_source_snapshot assignment" ;; +esac +runtime_snapshot_prefix=${runtime_snapshot_assignment#replay_source_snapshot=\'} +runtime_snapshot_prefix=${runtime_snapshot_prefix%\'\$\$} +[ -n "$runtime_snapshot_prefix" ] || fail "runtime replay command recorded empty replay_source_snapshot prefix" runtime_before_hash=$(/usr/bin/sha256sum "$runtime_replay_bundle/observations.tsv" | /usr/bin/awk '{print $1}') if (ulimit -v 120000; /bin/sh "$runtime_replay_bundle/command.txt" >/dev/null 2>&1); then fail "resource-constrained replay unexpectedly succeeded" From 97655b2ac05d9718c188b0ad825cb41a8aa48450 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:49:27 +0930 Subject: [PATCH 128/132] Harden R7 worktree and compiler configuration isolation --- scripts/r7-run-local.sh | 866 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 865 insertions(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 15fa525..4911802 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -274,6 +274,11 @@ repo_root=$(CDPATH= cd -- "$script_dir/.." && pwd -P) || fail "could not resolve repository root" cd "$repo_root" +git_worktree=$("$git_path" -C "$repo_root" rev-parse --show-toplevel) || + fail "could not resolve Git repository worktree" +[ "$git_worktree" = "$repo_root" ] || + fail "Git configured worktree differs from repository root: $git_worktree" + if [ "${1:-}" = "--self-test-git-root" ]; then [ "${GIT_NO_REPLACE_OBJECTS:-}" = "1" ] || fail "Git replacement objects are not disabled" @@ -304,7 +309,866 @@ validate_literal_build_flags() flag_value=$2 case "$flag_value" in - *'$'*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*|*'@'*) + *' + fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, glob, brace-expansion, or compiler response-file metacharacters; use literal replayable compiler arguments" + ;; + esac + case "$flag_value" in + *' +'*|*' '*) + fail "$flag_name must not contain newline or carriage-return shell control characters" + ;; + esac + old_ifs=$IFS + IFS=' +' + for flag_token in $flag_value; do + effective_flag_token=$(printf '%s' "$flag_token" | + "$sed_path" -e "s/'//g" -e 's/"//g' -e 's/\\//g') + case "$effective_flag_token" in + --config|--config=*|--config-system-dir|--config-system-dir=*|--config-user-dir|--config-user-dir=*) + IFS=$old_ifs + fail "$flag_name must not contain Clang configuration-file controls, including shell-quoted or escaped forms; external compiler config files are not bound evidence inputs" + ;; + -specs|--specs|-specs=*|--specs=*) + IFS=$old_ifs + fail "$flag_name must not contain GCC specs-file controls, including shell-quoted or escaped forms; external compiler specs files are not bound evidence inputs" + ;; + -B*) + IFS=$old_ifs + fail "$flag_name must not contain GCC -B compiler subprogram search overrides, including shell-quoted or escaped forms; external compiler executables are not bound evidence inputs" + ;; + -wrapper|--wrapper|-wrapper=*|--wrapper=*) + IFS=$old_ifs + fail "$flag_name must not contain GCC subprocess wrapper controls, including shell-quoted or escaped forms; external compiler wrappers are not bound evidence inputs" + ;; + esac + done + IFS=$old_ifs +} + +validate_literal_build_flags CPPFLAGS "$cppflags" +validate_literal_build_flags CFLAGS "$cflags" + +repeats=${RUNE_R7_REPEATS:-5} +case "$repeats" in + ''|*[!0-9]*) + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" + ;; +esac +normalized_repeats=$repeats +while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do + normalized_repeats=${normalized_repeats#0} +done +[ -n "$normalized_repeats" ] || + fail "RUNE_R7_REPEATS must be an integer from 1 through 100" +case "$normalized_repeats" in + [1-9]|[1-9][0-9]|100) ;; + *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; +esac +stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) +out_dir=${1:-"evidence/r7/local-$stamp"} +out_parent=$("$dirname_path" -- "$out_dir") + +case "$cc_name" in + *[[:space:]]*) + fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" + ;; +esac + +case "$ar_name" in + *[[:space:]]*) + fail "AR must name one archiver executable" + ;; +esac + +case "$make_name" in + *[[:space:]]*) + fail "MAKE must name one build-driver executable" + ;; +esac + +case "$out_dir" in + *"/../"*|"../"*|*/..|..) + fail "evidence destination must not contain parent-directory traversal: $out_dir" + ;; +esac + +out_route=$out_dir +while [ "${out_route#./}" != "$out_route" ]; do + out_route=${out_route#./} +done + +case "$out_route" in + build|build/*|"$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not route through build/: $out_dir" + ;; +esac + +[ -d "$out_parent" ] || + fail "bundle parent directory does not exist: $out_parent" + +out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || + fail "could not resolve bundle parent: $out_parent" +out_leaf=$("$basename_path" -- "$out_dir") +out_abs="$out_parent_abs/$out_leaf" + +case "$out_abs" in + "$repo_root/build"|"$repo_root/build/"*) + fail "evidence destination must not be inside build/: $out_dir" + ;; +esac + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination already exists; refusing overwrite: $out_dir" +fi + +replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || + fail "could not inspect Git replacement refs" + +[ -z "$replacement_refs" ] || + fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" + +revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || + fail "could not resolve source revision" + +"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || + fail "tracked Makefile is missing" +makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || + fail "could not resolve tracked Makefile at source revision" +[ -n "$makefile_blob" ] || + fail "tracked Makefile identity is empty" + +index_hidden=$("$git_path" -C "$repo_root" --work-tree="$repo_root" ls-files -v | "$awk_path" ' + /^[a-z]/ || /^S / { print; exit } +') || fail "could not inspect Git index visibility flags" + +[ -z "$index_hidden" ] || + fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" + +ignored_inputs=$("$git_path" -C "$repo_root" --work-tree="$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || + fail "could not inspect ignored compiler-input trees" + +[ -z "$ignored_inputs" ] || + fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" + +git_status=$("$git_path" -C "$repo_root" --work-tree="$repo_root" status --porcelain --untracked-files=all) || + fail "could not inspect Git working-tree state" + +[ -z "$git_status" ] || + fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" + +tracked_inputs=$("$git_path" -C "$repo_root" --work-tree="$repo_root" ls-files -- Makefile src include study) || + fail "could not enumerate tracked compiler inputs" + +[ -n "$tracked_inputs" ] || + fail "tracked compiler-input set is empty" + +validate_source_identity() +{ + current_status=$("$git_path" -C "$repo_root" --work-tree="$repo_root" status --porcelain --untracked-files=all) || + fail "could not re-inspect Git working-tree state" + [ -z "$current_status" ] || + fail "working tree changed during evidence capture" + + while IFS= read -r tracked_path; do + [ -n "$tracked_path" ] || continue + [ -f "$repo_root/$tracked_path" ] || + fail "tracked compiler input is missing from worktree: $tracked_path" + worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || + fail "could not hash raw worktree bytes: $tracked_path" + revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || + fail "could not resolve revision blob: $tracked_path" + [ "$worktree_blob" = "$revision_blob" ] || + fail "raw worktree bytes differ from source revision: $tracked_path" + done < "$archive_path" || + fail "could not materialize source archive for revision: $revision" + "$tar_path" -xf "$archive_path" -C "$source_snapshot" || + fail "could not extract source snapshot" + "$provenance_rm_path" -f "$archive_path" || + fail "could not remove temporary source archive" + + validate_snapshot_source_entries + validate_snapshot_identity + "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || + fail "could not make source snapshot read-only" +} + +cleanup_snapshot() +{ + if [ -d "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" || + fail "could not restore snapshot write permission for cleanup" + fi + "$provenance_rm_path" -rf "$source_snapshot" || + fail "could not remove source snapshot: $source_snapshot" + [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || + fail "source snapshot remains after cleanup: $source_snapshot" +} + +dirty=false + +cc_path=$(resolve_provenance_tool "$cc_name") || + fail "compiler not found in fixed provenance path: $cc_name" +cc_path=$(canonicalize_existing_path "$cc_path") || + fail "could not canonicalize compiler path: $cc_path" +case "$cc_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "compiler escaped fixed provenance path: $cc_path" ;; +esac +[ -n "$cc_path" ] && [ -x "$cc_path" ] || + fail "compiler path is not executable: $cc_path" + +cc_identity_path=$cc_path +resolved_cc_identity=$("$readlink_path" -f -- "$cc_path" 2>/dev/null || :) +if [ -n "$resolved_cc_identity" ]; then + cc_identity_path=$resolved_cc_identity +fi +cc_driver_name=$("$basename_path" -- "$cc_identity_path") + +compiler_default_config_control=none +case "$cc_driver_name" in + clang|clang-[0-9]*|clang++|clang++-[0-9]*) + compiler_default_config_control=--no-default-config + ;; +esac + +if [ "$compiler_default_config_control" = --no-default-config ]; then + compiler_version=$("$cc_path" --no-default-config --version 2>&1) || + fail "Clang does not support required --no-default-config isolation: $cc_path" +else + compiler_version=$("$cc_path" --version 2>&1) || + fail "compiler identity command failed: $cc_path --version" +fi +[ -n "$compiler_version" ] || + fail "compiler identity output is empty" + +effective_cppflags=$cppflags +if [ "$compiler_default_config_control" = --no-default-config ]; then + if [ -n "$effective_cppflags" ]; then + effective_cppflags="--no-default-config $effective_cppflags" + else + effective_cppflags=--no-default-config + fi +fi + +ar_path=$(resolve_provenance_tool "$ar_name") || + fail "archiver not found in fixed provenance path: $ar_name" +ar_path=$(canonicalize_existing_path "$ar_path") || + fail "could not canonicalize archiver path: $ar_path" +case "$ar_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "archiver escaped fixed provenance path: $ar_path" ;; +esac +[ -n "$ar_path" ] && [ -x "$ar_path" ] || + fail "archiver path is not executable: $ar_path" + +if archiver_version=$("$ar_path" --version 2>&1); then + : +elif archiver_version=$("$ar_path" -V 2>&1); then + : +else + fail "archiver identity command failed: $ar_path" +fi +[ -n "$archiver_version" ] || + fail "archiver identity output is empty" + +make_path=$(resolve_provenance_tool "$make_name") || + fail "build driver not found in fixed provenance path: $make_name" +make_path=$(canonicalize_existing_path "$make_path") || + fail "could not canonicalize build-driver path: $make_path" +case "$make_path" in + /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; + *) fail "build-driver escaped fixed provenance path: $make_path" ;; +esac +[ -x "$make_path" ] || + fail "build-driver path is not executable: $make_path" + +if make_version=$("$make_path" --version 2>&1); then + : +elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then + : +else + fail "build-driver identity command failed: $make_path" +fi +[ -n "$make_version" ] || + fail "build-driver identity output is empty" + +mkdir_path=$(resolve_provenance_tool mkdir) || + fail "mkdir not found in fixed provenance path" +rm_path=$(resolve_provenance_tool rm) || + fail "rm not found in fixed provenance path" +case "$mkdir_path:$rm_path" in + /*:/*) ;; + *) fail "build utility paths must be absolute" ;; +esac + +build_study() +{ + PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ + "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ + BUILD_DIR="$build_dir_rel" \ + CC="$cc_path" \ + AR="$ar_path" \ + CPPFLAGS="$effective_cppflags" \ + CFLAGS="$cflags" +} + +cleanup_build() +{ + "$rm_path" -rf "$build_dir" || + fail "could not remove fresh evidence build directory: $build_dir" + [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || + fail "fresh evidence build directory remains after cleanup: $build_dir" +} + +memory_profile= +if [ -r /proc/meminfo ]; then + mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) + case "$mem_total_kib" in + ''|*[!0-9]*) ;; + *) memory_profile="mem_total_kib=$mem_total_kib" ;; + esac +fi + +if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then + for key in hw.memsize hw.physmem64 hw.physmem; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + case "$value" in + ''|*[!0-9]*) ;; + *) + memory_profile="mem_total_bytes=$value" + break + ;; + esac + done +fi + +if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then + phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) + page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) + + case "$phys_pages" in + ''|*[!0-9]*|0) phys_pages= ;; + esac + case "$page_size" in + ''|*[!0-9]*|0) page_size= ;; + esac + + if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then + memory_profile="mem_phys_pages=$phys_pages +mem_page_size_bytes=$page_size" + fi +fi + +[ -n "$memory_profile" ] || + fail "could not capture required memory profile" + +platform_identity=$("$uname_path" -a 2>&1) || + fail "platform identity command failed: $uname_path -a" +[ -n "$platform_identity" ] || + fail "platform identity output is empty" + +cpu_model= +if [ -r /proc/cpuinfo ]; then + cpu_model=$("$awk_path" -F ': ' ' + /^model name[[:space:]]*:/ { print $2; exit } + /^Hardware[[:space:]]*:/ { print $2; exit } + ' /proc/cpuinfo) +fi +if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then + for key in machdep.cpu.brand_string hw.model; do + value=$("$sysctl_path" -n "$key" 2>/dev/null || :) + if [ -n "$value" ]; then + cpu_model=$value + break + fi + done +fi + +capture_id="$stamp-$$" +source_snapshot_rel="build/r7-source-$capture_id" +source_snapshot="$repo_root/$source_snapshot_rel" +build_dir_rel="build/r7-evidence-$capture_id" +build_dir="$source_snapshot/$build_dir_rel" +study_target="$build_dir_rel/rune_r7_study" +study_executable="$source_snapshot/$study_target" +bundle_stage_rel="build/r7-bundle-stage-$capture_id" +bundle_stage="$repo_root/$bundle_stage_rel" +publish_stage="$out_parent_abs/.r7-publish-$capture_id" +case "$hash_mode" in + sha256sum) + publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" | "$awk_path" '{ print $1 }') + ;; + shasum) + sanitize_perl_hash_environment + publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" -a 256 | "$awk_path" '{ print $1 }') + ;; + *) + fail "unsupported SHA-256 utility mode for publication lock: $hash_mode" + ;; +esac +case "$publish_lock_id" in + ''|*[!0-9A-Fa-f]*) + fail "could not derive destination-specific publication lock identity" + ;; +esac +publish_lock="$out_parent_abs/.r7-publish-lock-$publish_lock_id" +publish_lock_held=false +active_study_pid= +termination_status= +cleanup_capture_state() +{ + if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then + "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : + "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : + fi + if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then + "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : + fi + if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then + "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : + fi + if [ "${publish_lock_held:-false}" = true ] && + [ -n "${publish_lock:-}" ] && [ -d "$publish_lock" ]; then + "$provenance_rm_path" -rf "$publish_lock" >/dev/null 2>&1 || : + fi +} + +forward_termination_signal() +{ + forwarded_signal=$1 + termination_status=$2 + + if [ -n "${active_study_pid:-}" ]; then + kill "-$forwarded_signal" "$active_study_pid" >/dev/null 2>&1 || : + return + fi + + exit "$termination_status" +} + +trap cleanup_capture_state 0 +trap 'forward_termination_signal HUP 129' 1 +trap 'forward_termination_signal INT 130' 2 +trap 'forward_termination_signal QUIT 131' 3 +trap 'forward_termination_signal TERM 143' 15 + +if [ "$fresh_build_self_test" = true ]; then + materialize_source_snapshot + build_study + validate_snapshot_identity + "$study_executable" --bytes 32768 --repeats 1 >/dev/null + cleanup_snapshot + exit 0 +fi + +materialize_source_snapshot +build_study +validate_snapshot_identity +validate_source_identity + +[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || + fail "bundle staging destination already exists: $bundle_stage" +"$bundle_mkdir_path" "$bundle_stage" || + fail "could not create bundle staging directory: $bundle_stage" + +set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* +for bundle_entry in "$@"; do + [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue + fail "new bundle staging directory is not empty: $bundle_stage" +done + +observations_path="$bundle_stage/observations.tsv" + +{ + echo "contract=rune.r7.environment.v1" + echo "evidence_class=raw-local-execution-observation" + printf 'source_revision=%s\n' "$revision" + printf 'working_tree_dirty=%s\n' "$dirty" + printf '%s\n' "measurement_method=C99_clock_process_cpu_time" + printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" + printf 'makefile_path=%s\n' "$repo_root/Makefile" + printf 'makefile_blob=%s\n' "$makefile_blob" + printf 'repeats=%s\n' "$repeats" + printf 'git_provenance_path=%s\n' "$provenance_path" + printf 'git_resolved=%s\n' "$git_path" + printf 'sed_resolved=%s\n' "$sed_path" + printf 'awk_resolved=%s\n' "$awk_path" + printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" + printf 'tar_resolved=%s\n' "$tar_path" + printf 'chmod_resolved=%s\n' "$chmod_path" + printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" + printf 'mv_resolved=%s\n' "$mv_path" + printf 'cp_resolved=%s\n' "$cp_path" + printf 'find_resolved=%s\n' "$find_path" + printf 'readlink_resolved=%s\n' "$readlink_path" + printf 'bundle_stage=%s\n' "$bundle_stage" + printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" + printf '%s\n' "publish_lock_strategy=destination_specific_atomic_mkdir" + printf 'date_resolved=%s\n' "$date_path" + printf 'dirname_resolved=%s\n' "$dirname_path" + printf 'basename_resolved=%s\n' "$basename_path" + printf 'source_snapshot=%s\n' "$source_snapshot" + printf 'source_snapshot_revision=%s\n' "$revision" + printf '%s\n' "build_source_origin=git_archive_recorded_revision" + printf '%s\n' "build_source_worktree_used=false" + printf 'uname_resolved=%s\n' "$uname_path" + printf 'sha256_mode=%s\n' "$hash_mode" + printf 'sha256_resolved=%s\n' "$hash_path" + printf 'cc_requested=%s\n' "$cc_name" + printf 'cc_resolved=%s\n' "$cc_path" + printf 'ar_requested=%s\n' "$ar_name" + printf 'ar_resolved=%s\n' "$ar_path" + printf 'make_requested=%s\n' "$make_name" + printf 'make_resolved=%s\n' "$make_path" + printf 'build_path=%s\n' "$build_path" + printf 'mkdir_resolved=%s\n' "$mkdir_path" + printf 'rm_resolved=%s\n' "$rm_path" + printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" + printf 'fresh_build_dir=%s\n' "$build_dir" + printf 'fresh_study_target=%s\n' "$study_target" + printf 'cppflags=%s\n' "$cppflags" + printf 'effective_cppflags=%s\n' "$effective_cppflags" + printf 'cflags=%s\n' "$cflags" + printf 'compiler_default_config_control=%s\n' "$compiler_default_config_control" + printf 'git_worktree=%s\n' "$git_worktree" + echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" + echo "git_configuration_environment=system/global config disabled; core.fsmonitor=false; core.hooksPath=/dev/null" + echo "git_replace_objects=disabled and replacement refs forbidden" + echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" + echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" + echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" + echo "ignored_compiler_inputs=forbidden under src,include,study" + echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" + emit_key_value uname "$platform_identity" + if [ -n "$getconf_path" ]; then + processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) + long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) + printf 'processors_online=%s\n' "$processors_online" + printf 'long_bit=%s\n' "$long_bit" + fi + if [ -n "$cpu_model" ]; then + emit_key_value cpu_model "$cpu_model" + fi + printf '%s\n' "$memory_profile" +} > "$bundle_stage/environment.txt" + +{ + printf 'git_path=%s\n' "$git_path" + printf '%s\n' "$git_version" + printf 'sed_path=%s\n' "$sed_path" + printf 'awk_path=%s\n' "$awk_path" + printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" + printf 'tar_path=%s\n' "$tar_path" + printf 'chmod_path=%s\n' "$chmod_path" + printf 'provenance_rm_path=%s\n' "$provenance_rm_path" + printf 'mv_path=%s\n' "$mv_path" + printf 'cp_path=%s\n' "$cp_path" + printf 'find_path=%s\n' "$find_path" + printf 'readlink_path=%s\n' "$readlink_path" + printf 'date_path=%s\n' "$date_path" + printf 'dirname_path=%s\n' "$dirname_path" + printf 'basename_path=%s\n' "$basename_path" + printf 'uname_path=%s\n' "$uname_path" + printf 'sha256_path=%s\n' "$hash_path" + printf '%s\n' "$hash_version" + echo "compiler_path=$cc_path" + printf 'compiler_identity_path=%s\n' "$cc_identity_path" + printf 'compiler_default_config_control=%s\n' "$compiler_default_config_control" + printf '%s\n' "$compiler_version" + echo "archiver_path=$ar_path" + printf '%s\n' "$archiver_version" + echo "build_driver_path=$make_path" + printf '%s\n' "$make_version" +} > "$bundle_stage/compiler.txt" + +{ + printf "set -eu\n" + printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" + printf "export GIT_NO_REPLACE_OBJECTS=1\n" + printf "unset GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_CONFIG_SYSTEM GIT_CONFIG_GLOBAL GIT_CONFIG_NOSYSTEM GIT_CONFIG_COUNT\n" + printf "export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_COUNT=2\n" + printf "export GIT_CONFIG_KEY_0=core.fsmonitor GIT_CONFIG_VALUE_0=false\n" + printf "export GIT_CONFIG_KEY_1=core.hooksPath GIT_CONFIG_VALUE_1=/dev/null\n" + printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" + printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" + printf "unset TAR_OPTIONS\n" + printf "unset PERL5OPT PERL5LIB PERLLIB PERL_UNICODE PERLIO PERL_LOCAL_LIB_ROOT PERL_MB_OPT PERL_MM_OPT\n" + printf "replay_observations_tmp=" + shell_quote "$out_abs/.r7-replay-observations-" + printf "\$\$\n" + printf "replay_source_snapshot=" + shell_quote "$repo_root/build/r7-replay-source-$capture_id-" + printf "\$\$\n" + printf "replay_build_dir_rel=" + shell_quote "build/r7-replay-evidence-$capture_id-" + printf "\$\$\n" + printf 'replay_study_target="$replay_build_dir_rel/rune_r7_study"\n' + printf 'replay_study_executable="$replay_source_snapshot/$replay_study_target"\n' + printf "replay_cleanup() {\n" + printf " replay_status=\$?\n" + printf " if [ -n \"\${replay_observations_tmp:-}\" ]; then " + shell_quote "$provenance_rm_path" + printf " -f \"\$replay_observations_tmp\" >/dev/null 2>&1 || :; fi\n" + printf " if [ -d " + printf '"$replay_source_snapshot"' + printf " ]; then " + shell_quote "$chmod_path" + printf " -R u+w " + printf '"$replay_source_snapshot"' + printf " >/dev/null 2>&1 || :; fi\n" + printf " " + shell_quote "$provenance_rm_path" + printf " -rf " + printf '"$replay_source_snapshot"' + printf " >/dev/null 2>&1 || :\n" + printf " return \"\$replay_status\"\n" + printf "}\n" + printf "trap replay_cleanup 0\n" + printf "trap 'exit 129' 1\n" + printf "trap 'exit 130' 2\n" + printf "trap 'exit 131' 3\n" + printf "trap 'exit 143' 15\n" + printf "[ ! -e \"\$replay_observations_tmp\" ] && [ ! -L \"\$replay_observations_tmp\" ]\n" + shell_quote "$bundle_mkdir_path" + printf " -p " + shell_quote "$repo_root/build" + printf '\n' + shell_quote "$bundle_mkdir_path" + printf " " + printf '"$replay_source_snapshot"' + printf '\n' + shell_quote "$git_path" + printf " -C " + shell_quote "$repo_root" + printf " archive --format=tar " + shell_quote "$revision" + printf " -- Makefile src include study > " + printf '"$replay_source_snapshot/.r7-source.tar"' + printf '\n' + shell_quote "$tar_path" + printf " -xf " + printf '"$replay_source_snapshot/.r7-source.tar"' + printf " -C " + printf '"$replay_source_snapshot"' + printf '\n' + shell_quote "$provenance_rm_path" + printf " -f " + printf '"$replay_source_snapshot/.r7-source.tar"' + printf '\n' + shell_quote "$chmod_path" + printf " -R a-w " + printf '"$replay_source_snapshot/Makefile"' + printf " " + printf '"$replay_source_snapshot/src"' + printf " " + printf '"$replay_source_snapshot/include"' + printf " " + printf '"$replay_source_snapshot/study"' + printf '\n' + printf "PATH=" + shell_quote "$build_path" + printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " + shell_quote "$make_path" + printf " -C " + printf '"$replay_source_snapshot"' + printf " -f Makefile " + printf '"$replay_study_target"' + printf " BUILD_DIR=" + printf '"$replay_build_dir_rel"' + printf " CC=" + shell_quote "$cc_path" + printf " AR=" + shell_quote "$ar_path" + printf " CPPFLAGS=" + shell_quote "$effective_cppflags" + printf " CFLAGS=" + shell_quote "$cflags" + printf '\n' + + printf '"$replay_study_executable"' + printf " --profile local --repeats " + shell_quote "$repeats" + printf " > \"\$replay_observations_tmp\"\n" + shell_quote "$mv_path" + printf " \"\$replay_observations_tmp\" " + shell_quote "$out_abs/observations.tsv" + printf '\n' + printf "replay_observations_tmp=\n" +} > "$bundle_stage/command.txt" + +"$study_executable" --profile local --repeats "$repeats" \ + > "$observations_path" & +active_study_pid=$! + +if wait "$active_study_pid"; then + study_status=0 +else + study_status=$? +fi + +if [ -n "$termination_status" ]; then + wait "$active_study_pid" >/dev/null 2>&1 || : + active_study_pid= + exit "$termination_status" +fi + +active_study_pid= +[ "$study_status" -eq 0 ] || + fail "R7 study execution failed with status $study_status" + +validate_snapshot_identity +validate_source_identity +cleanup_snapshot + +case "$hash_mode" in + sha256sum) + ( + cd "$bundle_stage" + "$hash_path" \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + shasum) + sanitize_perl_hash_environment + ( + cd "$bundle_stage" + "$hash_path" -a 256 \ + environment.txt \ + compiler.txt \ + command.txt \ + observations.tsv \ + > SHA256SUMS + ) + ;; + *) + fail "unsupported SHA-256 utility mode: $hash_mode" + ;; +esac + +validate_source_identity + +"$bundle_mkdir_path" "$publish_lock" || + fail "could not acquire destination publication lock; another capture may be publishing: $out_dir" +publish_lock_held=true + +if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then + fail "evidence destination appeared during capture; refusing publish: $out_dir" +fi +[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || + fail "publish staging destination already exists: $publish_stage" + +"$bundle_mkdir_path" "$publish_stage" || + fail "could not create sibling publish staging directory" +"$cp_path" -R "$bundle_stage/." "$publish_stage/" || + fail "could not copy completed bundle to destination filesystem" + +case "$hash_mode" in + sha256sum) + ( + cd "$publish_stage" + "$hash_path" -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; + shasum) + sanitize_perl_hash_environment + ( + cd "$publish_stage" + "$hash_path" -a 256 -c SHA256SUMS + ) || fail "copied publish staging bundle failed SHA-256 verification" + ;; +esac + +"$provenance_rm_path" -rf "$bundle_stage" || + fail "could not remove repository bundle staging directory" + +if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then + fail "evidence destination appeared during publish; refusing rename: $out_abs" +fi + +"$mv_path" "$publish_stage" "$out_abs" || + fail "could not rename completed sibling staging bundle into place" +"$provenance_rm_path" -rf "$publish_lock" || + fail "published bundle but could not release destination publication lock" +publish_lock_held=false +trap - 0 1 2 3 15 + +echo "R7 evidence bundle: $out_dir" +*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*|*'{'*|*'}'*|*'@'*) fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, glob, or compiler response-file metacharacters; use literal replayable compiler arguments" ;; esac From f5abebf3365261aba563fd8651acb3807bb7dfc3 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:49:51 +0930 Subject: [PATCH 129/132] Repair R7 flag metacharacter validation --- scripts/r7-run-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 4911802..2f163b5 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -309,7 +309,7 @@ validate_literal_build_flags() flag_value=$2 case "$flag_value" in - *' + *'$'*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*|*'{'*|*'}'*|*'@'*) fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, glob, brace-expansion, or compiler response-file metacharacters; use literal replayable compiler arguments" ;; esac From 1f1ac7fc1a6ea5d13a535ec96db0f36325c0da16 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:50:16 +0930 Subject: [PATCH 130/132] Add R7 worktree brace and Clang config regressions --- tests/test_r7_run_local.sh | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test_r7_run_local.sh b/tests/test_r7_run_local.sh index 763b07d..c239922 100644 --- a/tests/test_r7_run_local.sh +++ b/tests/test_r7_run_local.sh @@ -32,6 +32,8 @@ mkdir -p "$tmp_root" cleanup() { + git config --local --unset-all core.worktree >/dev/null 2>&1 || : + rm -f "$repo_root/r7-core-worktree-probe-$test_id" rm -rf "$tmp_root" "$publish_parent" rm -f "/tmp/r7-reg-cc-$test_id" "/tmp/r7-reg-ar-$test_id" "/tmp/r7-reg-make-$test_id" rm -f "/tmp/r7-tar-hook-$test_id" "/tmp/r7-tar-hook-ran-$test_id" @@ -72,6 +74,26 @@ EOF chmod +x "$fake_dirname_bin/dirname" PATH="$fake_dirname_bin:$PATH" scripts/r7-run-local.sh --self-test-git-root +# Repository-local core.worktree must not redirect provenance away from repo_root. +foreign_worktree="$tmp_root/foreign-worktree" +mkdir -p "$foreign_worktree" +core_worktree_probe="$repo_root/r7-core-worktree-probe-$test_id" +git config --local core.worktree "$foreign_worktree" +printf 'dirty actual repository\n' > "$core_worktree_probe" +core_worktree_dest="$tmp_root/core-worktree-redirect" +if RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$core_worktree_dest" >/dev/null 2>&1; then + core_worktree_status=0 +else + core_worktree_status=$? +fi +git config --local --unset-all core.worktree +rm -f "$core_worktree_probe" +[ "$core_worktree_status" -ne 0 ] || + fail "core.worktree redirect allowed evidence capture from the wrong worktree" +[ ! -e "$core_worktree_dest" ] || + fail "core.worktree redirect published an evidence destination" + # Caller flags must be literal build configuration, never recursive Make references. hidden_header="/tmp/r7-hidden-header-$test_id.h" cat > "$hidden_header" <<'EOF' @@ -123,6 +145,12 @@ expect_capture_failure shell-separator-cflags \ expect_capture_failure shell-glob-cppflags \ env 'CPPFLAGS=-I/tmp/r7-*' RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ scripts/r7-run-local.sh +expect_capture_failure shell-brace-cflags \ + env 'CFLAGS=-{specs=/tmp/r7.specs,specs=/tmp/r7.specs}' \ + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh +expect_capture_failure shell-brace-cppflags \ + env 'CPPFLAGS=-I{/tmp/r7-a,/tmp/r7-b}' \ + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" scripts/r7-run-local.sh # Compiler response files must not hide effective build arguments. response_header="/tmp/r7-response-header-$test_id.h" @@ -255,6 +283,18 @@ CCC_OVERRIDE_OPTIONS='#+-include +/tmp/should-not-exist.h' \ case "$system_cc" in *clang) + clang_default_bundle="$tmp_root/clang-default-config" + RUNE_R7_REPEATS=1 CC="$system_cc" AR="$system_ar" \ + scripts/r7-run-local.sh "$clang_default_bundle" >/dev/null + /usr/bin/grep -Fxq 'compiler_default_config_control=--no-default-config' \ + "$clang_default_bundle/environment.txt" || + fail "Clang capture did not record --no-default-config isolation" + /usr/bin/grep -Fxq 'compiler_default_config_control=--no-default-config' \ + "$clang_default_bundle/compiler.txt" || + fail "Clang compiler metadata did not bind --no-default-config" + /usr/bin/grep -Fq "CPPFLAGS='--no-default-config" "$clang_default_bundle/command.txt" || + fail "Clang replay did not carry --no-default-config" + cat > /tmp/r7-ccc-header-$test_id.h <<'EOF' #undef CLOCKS_PER_SEC #define CLOCKS_PER_SEC 424242 From 8b54592c72323f833c2345548366a4a9d5ba5d83 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:50:36 +0930 Subject: [PATCH 131/132] Document R7 worktree and compiler config invariants --- AGENTS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 4d80395..3841ae2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -186,6 +186,8 @@ CORE_RULES: - R7_assume_unchanged_and_skip_worktree_flags_are_forbidden - R7_index_visibility_flags_are_checked_before_dirty_state - R7_Git_routing_environment_is_cleared_before_provenance_checks +- R7_repository_local_core_worktree_must_resolve_to_repo_root +- R7_worktree_sensitive_Git_provenance_commands_force_repo_root_as_worktree - R7_Git_provenance_commands_are_anchored_to_repo_root - R7_repository_root_derivation_uses_fixed_provenance_dirname - R7_Git_executable_is_resolved_from_fixed_provenance_PATH_and_recorded @@ -224,9 +226,11 @@ CORE_RULES: - R7_evidence_class_is_raw_local_execution_observation - R7_CPPFLAGS_and_CFLAGS_are_recorded_and_bound - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Make_variable_references -- R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_or_glob_syntax +- R7_CPPFLAGS_and_CFLAGS_must_not_contain_shell_substitution_control_redirection_comment_tilde_glob_or_brace_expansion_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_compiler_response_file_syntax - R7_CPPFLAGS_and_CFLAGS_must_not_contain_Clang_config_file_or_config_search_directory_controls +- R7_Clang_capture_and_replay_must_pass_and_record_no_default_config +- R7_Clang_implicit_default_configuration_files_are_not_evidence_inputs - R7_CPPFLAGS_and_CFLAGS_must_not_contain_GCC_specs_file_controls - R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_tokenized_across_all_POSIX_shell_whitespace - R7_CPPFLAGS_and_CFLAGS_sensitive_compiler_controls_are_checked_after_conservative_shell_quote_and_backslash_normalization From fa111b1895043832afb37f8164fadebc836b1f04 Mon Sep 17 00:00:00 2001 From: Trent Slade <73952179+EmergentMonk@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:51:46 +0930 Subject: [PATCH 132/132] Remove duplicated R7 script tail --- scripts/r7-run-local.sh | 826 ---------------------------------------- 1 file changed, 826 deletions(-) diff --git a/scripts/r7-run-local.sh b/scripts/r7-run-local.sh index 2f163b5..c563680 100755 --- a/scripts/r7-run-local.sh +++ b/scripts/r7-run-local.sh @@ -1168,829 +1168,3 @@ publish_lock_held=false trap - 0 1 2 3 15 echo "R7 evidence bundle: $out_dir" -*|*'`'*|*';'*|*'&'*|*'|'*|*'<'*|*'>'*|*'#'*|*'~'*|*'*'*|*'?'*|*'['*|*']'*|*'{'*|*'}'*|*'@'*) - fail "$flag_name must not contain shell substitution, control, redirection, comment, tilde, glob, or compiler response-file metacharacters; use literal replayable compiler arguments" - ;; - esac - case "$flag_value" in - *' -'*|*' '*) - fail "$flag_name must not contain newline or carriage-return shell control characters" - ;; - esac - old_ifs=$IFS - IFS=' -' - for flag_token in $flag_value; do - effective_flag_token=$(printf '%s' "$flag_token" | - "$sed_path" -e "s/'//g" -e 's/"//g' -e 's/\\//g') - case "$effective_flag_token" in - --config|--config=*|--config-system-dir|--config-system-dir=*|--config-user-dir|--config-user-dir=*) - IFS=$old_ifs - fail "$flag_name must not contain Clang configuration-file controls, including shell-quoted or escaped forms; external compiler config files are not bound evidence inputs" - ;; - -specs|--specs|-specs=*|--specs=*) - IFS=$old_ifs - fail "$flag_name must not contain GCC specs-file controls, including shell-quoted or escaped forms; external compiler specs files are not bound evidence inputs" - ;; - -B*) - IFS=$old_ifs - fail "$flag_name must not contain GCC -B compiler subprogram search overrides, including shell-quoted or escaped forms; external compiler executables are not bound evidence inputs" - ;; - -wrapper|--wrapper|-wrapper=*|--wrapper=*) - IFS=$old_ifs - fail "$flag_name must not contain GCC subprocess wrapper controls, including shell-quoted or escaped forms; external compiler wrappers are not bound evidence inputs" - ;; - esac - done - IFS=$old_ifs -} - -validate_literal_build_flags CPPFLAGS "$cppflags" -validate_literal_build_flags CFLAGS "$cflags" - -repeats=${RUNE_R7_REPEATS:-5} -case "$repeats" in - ''|*[!0-9]*) - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" - ;; -esac -normalized_repeats=$repeats -while [ "${normalized_repeats#0}" != "$normalized_repeats" ]; do - normalized_repeats=${normalized_repeats#0} -done -[ -n "$normalized_repeats" ] || - fail "RUNE_R7_REPEATS must be an integer from 1 through 100" -case "$normalized_repeats" in - [1-9]|[1-9][0-9]|100) ;; - *) fail "RUNE_R7_REPEATS must be an integer from 1 through 100" ;; -esac -stamp=$("$date_path" -u +%Y%m%dT%H%M%SZ) -out_dir=${1:-"evidence/r7/local-$stamp"} -out_parent=$("$dirname_path" -- "$out_dir") - -case "$cc_name" in - *[[:space:]]*) - fail "CC must name one compiler executable; put flags in CPPFLAGS/CFLAGS" - ;; -esac - -case "$ar_name" in - *[[:space:]]*) - fail "AR must name one archiver executable" - ;; -esac - -case "$make_name" in - *[[:space:]]*) - fail "MAKE must name one build-driver executable" - ;; -esac - -case "$out_dir" in - *"/../"*|"../"*|*/..|..) - fail "evidence destination must not contain parent-directory traversal: $out_dir" - ;; -esac - -out_route=$out_dir -while [ "${out_route#./}" != "$out_route" ]; do - out_route=${out_route#./} -done - -case "$out_route" in - build|build/*|"$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not route through build/: $out_dir" - ;; -esac - -[ -d "$out_parent" ] || - fail "bundle parent directory does not exist: $out_parent" - -out_parent_abs=$(CDPATH= cd -- "$out_parent" && pwd -P) || - fail "could not resolve bundle parent: $out_parent" -out_leaf=$("$basename_path" -- "$out_dir") -out_abs="$out_parent_abs/$out_leaf" - -case "$out_abs" in - "$repo_root/build"|"$repo_root/build/"*) - fail "evidence destination must not be inside build/: $out_dir" - ;; -esac - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination already exists; refusing overwrite: $out_dir" -fi - -replacement_refs=$("$git_path" -C "$repo_root" for-each-ref --format='%(refname)' refs/replace) || - fail "could not inspect Git replacement refs" - -[ -z "$replacement_refs" ] || - fail "Git replacement refs are forbidden during evidence capture: $replacement_refs" - -revision=$("$git_path" -C "$repo_root" rev-parse HEAD) || - fail "could not resolve source revision" - -"$git_path" -C "$repo_root" ls-files --error-unmatch Makefile >/dev/null 2>&1 || - fail "tracked Makefile is missing" -makefile_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:Makefile") || - fail "could not resolve tracked Makefile at source revision" -[ -n "$makefile_blob" ] || - fail "tracked Makefile identity is empty" - -index_hidden=$("$git_path" -C "$repo_root" ls-files -v | "$awk_path" ' - /^[a-z]/ || /^S / { print; exit } -') || fail "could not inspect Git index visibility flags" - -[ -z "$index_hidden" ] || - fail "tracked files use assume-unchanged or skip-worktree flags; clear them before evidence capture" - -ignored_inputs=$("$git_path" -C "$repo_root" ls-files --others --ignored --exclude-standard -- src include study) || - fail "could not inspect ignored compiler-input trees" - -[ -z "$ignored_inputs" ] || - fail "ignored untracked files exist under compiler-input trees; remove them before evidence capture: $ignored_inputs" - -git_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not inspect Git working-tree state" - -[ -z "$git_status" ] || - fail "working tree is dirty; commit/stash tracked and untracked changes before evidence capture" - -tracked_inputs=$("$git_path" -C "$repo_root" ls-files -- Makefile src include study) || - fail "could not enumerate tracked compiler inputs" - -[ -n "$tracked_inputs" ] || - fail "tracked compiler-input set is empty" - -validate_source_identity() -{ - current_status=$("$git_path" -C "$repo_root" status --porcelain --untracked-files=all) || - fail "could not re-inspect Git working-tree state" - [ -z "$current_status" ] || - fail "working tree changed during evidence capture" - - while IFS= read -r tracked_path; do - [ -n "$tracked_path" ] || continue - [ -f "$repo_root/$tracked_path" ] || - fail "tracked compiler input is missing from worktree: $tracked_path" - worktree_blob=$("$git_path" -C "$repo_root" hash-object --no-filters -- "$tracked_path") || - fail "could not hash raw worktree bytes: $tracked_path" - revision_blob=$("$git_path" -C "$repo_root" rev-parse "$revision:$tracked_path") || - fail "could not resolve revision blob: $tracked_path" - [ "$worktree_blob" = "$revision_blob" ] || - fail "raw worktree bytes differ from source revision: $tracked_path" - done < "$archive_path" || - fail "could not materialize source archive for revision: $revision" - "$tar_path" -xf "$archive_path" -C "$source_snapshot" || - fail "could not extract source snapshot" - "$provenance_rm_path" -f "$archive_path" || - fail "could not remove temporary source archive" - - validate_snapshot_source_entries - validate_snapshot_identity - "$chmod_path" -R a-w "$source_snapshot/Makefile" "$source_snapshot/src" "$source_snapshot/include" "$source_snapshot/study" || - fail "could not make source snapshot read-only" -} - -cleanup_snapshot() -{ - if [ -d "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" || - fail "could not restore snapshot write permission for cleanup" - fi - "$provenance_rm_path" -rf "$source_snapshot" || - fail "could not remove source snapshot: $source_snapshot" - [ ! -e "$source_snapshot" ] && [ ! -L "$source_snapshot" ] || - fail "source snapshot remains after cleanup: $source_snapshot" -} - -dirty=false - -cc_path=$(resolve_provenance_tool "$cc_name") || - fail "compiler not found in fixed provenance path: $cc_name" -cc_path=$(canonicalize_existing_path "$cc_path") || - fail "could not canonicalize compiler path: $cc_path" -case "$cc_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "compiler escaped fixed provenance path: $cc_path" ;; -esac -[ -n "$cc_path" ] && [ -x "$cc_path" ] || - fail "compiler path is not executable: $cc_path" - -compiler_version=$("$cc_path" --version 2>&1) || - fail "compiler identity command failed: $cc_path --version" -[ -n "$compiler_version" ] || - fail "compiler identity output is empty" - -ar_path=$(resolve_provenance_tool "$ar_name") || - fail "archiver not found in fixed provenance path: $ar_name" -ar_path=$(canonicalize_existing_path "$ar_path") || - fail "could not canonicalize archiver path: $ar_path" -case "$ar_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "archiver escaped fixed provenance path: $ar_path" ;; -esac -[ -n "$ar_path" ] && [ -x "$ar_path" ] || - fail "archiver path is not executable: $ar_path" - -if archiver_version=$("$ar_path" --version 2>&1); then - : -elif archiver_version=$("$ar_path" -V 2>&1); then - : -else - fail "archiver identity command failed: $ar_path" -fi -[ -n "$archiver_version" ] || - fail "archiver identity output is empty" - -make_path=$(resolve_provenance_tool "$make_name") || - fail "build driver not found in fixed provenance path: $make_name" -make_path=$(canonicalize_existing_path "$make_path") || - fail "could not canonicalize build-driver path: $make_path" -case "$make_path" in - /usr/bin/*|/bin/*|/usr/sbin/*|/sbin/*) ;; - *) fail "build-driver escaped fixed provenance path: $make_path" ;; -esac -[ -x "$make_path" ] || - fail "build-driver path is not executable: $make_path" - -if make_version=$("$make_path" --version 2>&1); then - : -elif make_version=$("$make_path" -V MAKE_VERSION 2>&1); then - : -else - fail "build-driver identity command failed: $make_path" -fi -[ -n "$make_version" ] || - fail "build-driver identity output is empty" - -mkdir_path=$(resolve_provenance_tool mkdir) || - fail "mkdir not found in fixed provenance path" -rm_path=$(resolve_provenance_tool rm) || - fail "rm not found in fixed provenance path" -case "$mkdir_path:$rm_path" in - /*:/*) ;; - *) fail "build utility paths must be absolute" ;; -esac - -build_study() -{ - PATH="$build_path" MAKEFLAGS= GNUMAKEFLAGS= MFLAGS= MAKEFILES= MAKEOVERRIDES= \ - "$make_path" -C "$source_snapshot" -f Makefile "$study_target" \ - BUILD_DIR="$build_dir_rel" \ - CC="$cc_path" \ - AR="$ar_path" \ - CPPFLAGS="$cppflags" \ - CFLAGS="$cflags" -} - -cleanup_build() -{ - "$rm_path" -rf "$build_dir" || - fail "could not remove fresh evidence build directory: $build_dir" - [ ! -e "$build_dir" ] && [ ! -L "$build_dir" ] || - fail "fresh evidence build directory remains after cleanup: $build_dir" -} - -memory_profile= -if [ -r /proc/meminfo ]; then - mem_total_kib=$("$awk_path" '/^MemTotal:/ { print $2; exit }' /proc/meminfo) - case "$mem_total_kib" in - ''|*[!0-9]*) ;; - *) memory_profile="mem_total_kib=$mem_total_kib" ;; - esac -fi - -if [ -z "$memory_profile" ] && [ -n "$sysctl_path" ]; then - for key in hw.memsize hw.physmem64 hw.physmem; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - case "$value" in - ''|*[!0-9]*) ;; - *) - memory_profile="mem_total_bytes=$value" - break - ;; - esac - done -fi - -if [ -z "$memory_profile" ] && [ -n "$getconf_path" ]; then - phys_pages=$("$getconf_path" _PHYS_PAGES 2>/dev/null || :) - page_size=$("$getconf_path" PAGE_SIZE 2>/dev/null || :) - - case "$phys_pages" in - ''|*[!0-9]*|0) phys_pages= ;; - esac - case "$page_size" in - ''|*[!0-9]*|0) page_size= ;; - esac - - if [ -n "$phys_pages" ] && [ -n "$page_size" ]; then - memory_profile="mem_phys_pages=$phys_pages -mem_page_size_bytes=$page_size" - fi -fi - -[ -n "$memory_profile" ] || - fail "could not capture required memory profile" - -platform_identity=$("$uname_path" -a 2>&1) || - fail "platform identity command failed: $uname_path -a" -[ -n "$platform_identity" ] || - fail "platform identity output is empty" - -cpu_model= -if [ -r /proc/cpuinfo ]; then - cpu_model=$("$awk_path" -F ': ' ' - /^model name[[:space:]]*:/ { print $2; exit } - /^Hardware[[:space:]]*:/ { print $2; exit } - ' /proc/cpuinfo) -fi -if [ -z "$cpu_model" ] && [ -n "$sysctl_path" ]; then - for key in machdep.cpu.brand_string hw.model; do - value=$("$sysctl_path" -n "$key" 2>/dev/null || :) - if [ -n "$value" ]; then - cpu_model=$value - break - fi - done -fi - -capture_id="$stamp-$$" -source_snapshot_rel="build/r7-source-$capture_id" -source_snapshot="$repo_root/$source_snapshot_rel" -build_dir_rel="build/r7-evidence-$capture_id" -build_dir="$source_snapshot/$build_dir_rel" -study_target="$build_dir_rel/rune_r7_study" -study_executable="$source_snapshot/$study_target" -bundle_stage_rel="build/r7-bundle-stage-$capture_id" -bundle_stage="$repo_root/$bundle_stage_rel" -publish_stage="$out_parent_abs/.r7-publish-$capture_id" -case "$hash_mode" in - sha256sum) - publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" | "$awk_path" '{ print $1 }') - ;; - shasum) - sanitize_perl_hash_environment - publish_lock_id=$(printf '%s' "$out_abs" | "$hash_path" -a 256 | "$awk_path" '{ print $1 }') - ;; - *) - fail "unsupported SHA-256 utility mode for publication lock: $hash_mode" - ;; -esac -case "$publish_lock_id" in - ''|*[!0-9A-Fa-f]*) - fail "could not derive destination-specific publication lock identity" - ;; -esac -publish_lock="$out_parent_abs/.r7-publish-lock-$publish_lock_id" -publish_lock_held=false -active_study_pid= -termination_status= -cleanup_capture_state() -{ - if [ -n "${source_snapshot:-}" ] && [ -e "$source_snapshot" ]; then - "$chmod_path" -R u+w "$source_snapshot" >/dev/null 2>&1 || : - "$provenance_rm_path" -rf "$source_snapshot" >/dev/null 2>&1 || : - fi - if [ -n "${bundle_stage:-}" ] && [ -e "$bundle_stage" ]; then - "$provenance_rm_path" -rf "$bundle_stage" >/dev/null 2>&1 || : - fi - if [ -n "${publish_stage:-}" ] && [ -e "$publish_stage" ]; then - "$provenance_rm_path" -rf "$publish_stage" >/dev/null 2>&1 || : - fi - if [ "${publish_lock_held:-false}" = true ] && - [ -n "${publish_lock:-}" ] && [ -d "$publish_lock" ]; then - "$provenance_rm_path" -rf "$publish_lock" >/dev/null 2>&1 || : - fi -} - -forward_termination_signal() -{ - forwarded_signal=$1 - termination_status=$2 - - if [ -n "${active_study_pid:-}" ]; then - kill "-$forwarded_signal" "$active_study_pid" >/dev/null 2>&1 || : - return - fi - - exit "$termination_status" -} - -trap cleanup_capture_state 0 -trap 'forward_termination_signal HUP 129' 1 -trap 'forward_termination_signal INT 130' 2 -trap 'forward_termination_signal QUIT 131' 3 -trap 'forward_termination_signal TERM 143' 15 - -if [ "$fresh_build_self_test" = true ]; then - materialize_source_snapshot - build_study - validate_snapshot_identity - "$study_executable" --bytes 32768 --repeats 1 >/dev/null - cleanup_snapshot - exit 0 -fi - -materialize_source_snapshot -build_study -validate_snapshot_identity -validate_source_identity - -[ ! -e "$bundle_stage" ] && [ ! -L "$bundle_stage" ] || - fail "bundle staging destination already exists: $bundle_stage" -"$bundle_mkdir_path" "$bundle_stage" || - fail "could not create bundle staging directory: $bundle_stage" - -set -- "$bundle_stage"/* "$bundle_stage"/.[!.]* "$bundle_stage"/..?* -for bundle_entry in "$@"; do - [ -e "$bundle_entry" ] || [ -L "$bundle_entry" ] || continue - fail "new bundle staging directory is not empty: $bundle_stage" -done - -observations_path="$bundle_stage/observations.tsv" - -{ - echo "contract=rune.r7.environment.v1" - echo "evidence_class=raw-local-execution-observation" - printf 'source_revision=%s\n' "$revision" - printf 'working_tree_dirty=%s\n' "$dirty" - printf '%s\n' "measurement_method=C99_clock_process_cpu_time" - printf '%s\n' "benchmark_contract=rune.r7.memory-wall-observation.v1" - printf 'makefile_path=%s\n' "$repo_root/Makefile" - printf 'makefile_blob=%s\n' "$makefile_blob" - printf 'repeats=%s\n' "$repeats" - printf 'git_provenance_path=%s\n' "$provenance_path" - printf 'git_resolved=%s\n' "$git_path" - printf 'sed_resolved=%s\n' "$sed_path" - printf 'awk_resolved=%s\n' "$awk_path" - printf 'bundle_mkdir_resolved=%s\n' "$bundle_mkdir_path" - printf 'tar_resolved=%s\n' "$tar_path" - printf 'chmod_resolved=%s\n' "$chmod_path" - printf 'provenance_rm_resolved=%s\n' "$provenance_rm_path" - printf 'mv_resolved=%s\n' "$mv_path" - printf 'cp_resolved=%s\n' "$cp_path" - printf 'find_resolved=%s\n' "$find_path" - printf 'readlink_resolved=%s\n' "$readlink_path" - printf 'bundle_stage=%s\n' "$bundle_stage" - printf '%s\n' "bundle_publish_mode=publish_after_success_via_trusted_mv" - printf '%s\n' "publish_lock_strategy=destination_specific_atomic_mkdir" - printf 'date_resolved=%s\n' "$date_path" - printf 'dirname_resolved=%s\n' "$dirname_path" - printf 'basename_resolved=%s\n' "$basename_path" - printf 'source_snapshot=%s\n' "$source_snapshot" - printf 'source_snapshot_revision=%s\n' "$revision" - printf '%s\n' "build_source_origin=git_archive_recorded_revision" - printf '%s\n' "build_source_worktree_used=false" - printf 'uname_resolved=%s\n' "$uname_path" - printf 'sha256_mode=%s\n' "$hash_mode" - printf 'sha256_resolved=%s\n' "$hash_path" - printf 'cc_requested=%s\n' "$cc_name" - printf 'cc_resolved=%s\n' "$cc_path" - printf 'ar_requested=%s\n' "$ar_name" - printf 'ar_resolved=%s\n' "$ar_path" - printf 'make_requested=%s\n' "$make_name" - printf 'make_resolved=%s\n' "$make_path" - printf 'build_path=%s\n' "$build_path" - printf 'mkdir_resolved=%s\n' "$mkdir_path" - printf 'rm_resolved=%s\n' "$rm_path" - printf 'fresh_build_dir_relative=%s\n' "$build_dir_rel" - printf 'fresh_build_dir=%s\n' "$build_dir" - printf 'fresh_study_target=%s\n' "$study_target" - printf 'cppflags=%s\n' "$cppflags" - printf 'cflags=%s\n' "$cflags" - echo "git_routing_environment=GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR,GIT_NAMESPACE cleared" - echo "git_configuration_environment=system/global config disabled; core.fsmonitor=false; core.hooksPath=/dev/null" - echo "git_replace_objects=disabled and replacement refs forbidden" - echo "raw_worktree_identity=tracked Makefile/src/include/study hashed with git hash-object --no-filters" - echo "compiler_search_environment=CPATH,C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH,COMPILER_PATH,LIBRARY_PATH,GCC_EXEC_PREFIX,CCC_OVERRIDE_OPTIONS cleared" - echo "dynamic_loader_environment=LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH,DYLD_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,LIBPATH,SHLIB_PATH cleared" - echo "ignored_compiler_inputs=forbidden under src,include,study" - echo "make_control_environment=MAKEFLAGS,GNUMAKEFLAGS,MFLAGS,MAKEFILES,MAKEOVERRIDES cleared" - emit_key_value uname "$platform_identity" - if [ -n "$getconf_path" ]; then - processors_online=$("$getconf_path" _NPROCESSORS_ONLN 2>/dev/null || printf '%s' unknown) - long_bit=$("$getconf_path" LONG_BIT 2>/dev/null || printf '%s' unknown) - printf 'processors_online=%s\n' "$processors_online" - printf 'long_bit=%s\n' "$long_bit" - fi - if [ -n "$cpu_model" ]; then - emit_key_value cpu_model "$cpu_model" - fi - printf '%s\n' "$memory_profile" -} > "$bundle_stage/environment.txt" - -{ - printf 'git_path=%s\n' "$git_path" - printf '%s\n' "$git_version" - printf 'sed_path=%s\n' "$sed_path" - printf 'awk_path=%s\n' "$awk_path" - printf 'bundle_mkdir_path=%s\n' "$bundle_mkdir_path" - printf 'tar_path=%s\n' "$tar_path" - printf 'chmod_path=%s\n' "$chmod_path" - printf 'provenance_rm_path=%s\n' "$provenance_rm_path" - printf 'mv_path=%s\n' "$mv_path" - printf 'cp_path=%s\n' "$cp_path" - printf 'find_path=%s\n' "$find_path" - printf 'readlink_path=%s\n' "$readlink_path" - printf 'date_path=%s\n' "$date_path" - printf 'dirname_path=%s\n' "$dirname_path" - printf 'basename_path=%s\n' "$basename_path" - printf 'uname_path=%s\n' "$uname_path" - printf 'sha256_path=%s\n' "$hash_path" - printf '%s\n' "$hash_version" - echo "compiler_path=$cc_path" - printf '%s\n' "$compiler_version" - echo "archiver_path=$ar_path" - printf '%s\n' "$archiver_version" - echo "build_driver_path=$make_path" - printf '%s\n' "$make_version" -} > "$bundle_stage/compiler.txt" - -{ - printf "set -eu\n" - printf "unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_COMMON_DIR GIT_NAMESPACE\n" - printf "export GIT_NO_REPLACE_OBJECTS=1\n" - printf "unset GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_CONFIG_SYSTEM GIT_CONFIG_GLOBAL GIT_CONFIG_NOSYSTEM GIT_CONFIG_COUNT\n" - printf "export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_COUNT=2\n" - printf "export GIT_CONFIG_KEY_0=core.fsmonitor GIT_CONFIG_VALUE_0=false\n" - printf "export GIT_CONFIG_KEY_1=core.hooksPath GIT_CONFIG_VALUE_1=/dev/null\n" - printf "unset CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH COMPILER_PATH LIBRARY_PATH GCC_EXEC_PREFIX CCC_OVERRIDE_OPTIONS\n" - printf "unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT DYLD_INSERT_LIBRARIES DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FALLBACK_FRAMEWORK_PATH LIBPATH SHLIB_PATH\n" - printf "unset TAR_OPTIONS\n" - printf "unset PERL5OPT PERL5LIB PERLLIB PERL_UNICODE PERLIO PERL_LOCAL_LIB_ROOT PERL_MB_OPT PERL_MM_OPT\n" - printf "replay_observations_tmp=" - shell_quote "$out_abs/.r7-replay-observations-" - printf "\$\$\n" - printf "replay_source_snapshot=" - shell_quote "$repo_root/build/r7-replay-source-$capture_id-" - printf "\$\$\n" - printf "replay_build_dir_rel=" - shell_quote "build/r7-replay-evidence-$capture_id-" - printf "\$\$\n" - printf 'replay_study_target="$replay_build_dir_rel/rune_r7_study"\n' - printf 'replay_study_executable="$replay_source_snapshot/$replay_study_target"\n' - printf "replay_cleanup() {\n" - printf " replay_status=\$?\n" - printf " if [ -n \"\${replay_observations_tmp:-}\" ]; then " - shell_quote "$provenance_rm_path" - printf " -f \"\$replay_observations_tmp\" >/dev/null 2>&1 || :; fi\n" - printf " if [ -d " - printf '"$replay_source_snapshot"' - printf " ]; then " - shell_quote "$chmod_path" - printf " -R u+w " - printf '"$replay_source_snapshot"' - printf " >/dev/null 2>&1 || :; fi\n" - printf " " - shell_quote "$provenance_rm_path" - printf " -rf " - printf '"$replay_source_snapshot"' - printf " >/dev/null 2>&1 || :\n" - printf " return \"\$replay_status\"\n" - printf "}\n" - printf "trap replay_cleanup 0\n" - printf "trap 'exit 129' 1\n" - printf "trap 'exit 130' 2\n" - printf "trap 'exit 131' 3\n" - printf "trap 'exit 143' 15\n" - printf "[ ! -e \"\$replay_observations_tmp\" ] && [ ! -L \"\$replay_observations_tmp\" ]\n" - shell_quote "$bundle_mkdir_path" - printf " -p " - shell_quote "$repo_root/build" - printf '\n' - shell_quote "$bundle_mkdir_path" - printf " " - printf '"$replay_source_snapshot"' - printf '\n' - shell_quote "$git_path" - printf " -C " - shell_quote "$repo_root" - printf " archive --format=tar " - shell_quote "$revision" - printf " -- Makefile src include study > " - printf '"$replay_source_snapshot/.r7-source.tar"' - printf '\n' - shell_quote "$tar_path" - printf " -xf " - printf '"$replay_source_snapshot/.r7-source.tar"' - printf " -C " - printf '"$replay_source_snapshot"' - printf '\n' - shell_quote "$provenance_rm_path" - printf " -f " - printf '"$replay_source_snapshot/.r7-source.tar"' - printf '\n' - shell_quote "$chmod_path" - printf " -R a-w " - printf '"$replay_source_snapshot/Makefile"' - printf " " - printf '"$replay_source_snapshot/src"' - printf " " - printf '"$replay_source_snapshot/include"' - printf " " - printf '"$replay_source_snapshot/study"' - printf '\n' - printf "PATH=" - shell_quote "$build_path" - printf " MAKEFLAGS='' GNUMAKEFLAGS='' MFLAGS='' MAKEFILES='' MAKEOVERRIDES='' " - shell_quote "$make_path" - printf " -C " - printf '"$replay_source_snapshot"' - printf " -f Makefile " - printf '"$replay_study_target"' - printf " BUILD_DIR=" - printf '"$replay_build_dir_rel"' - printf " CC=" - shell_quote "$cc_path" - printf " AR=" - shell_quote "$ar_path" - printf " CPPFLAGS=" - shell_quote "$cppflags" - printf " CFLAGS=" - shell_quote "$cflags" - printf '\n' - - printf '"$replay_study_executable"' - printf " --profile local --repeats " - shell_quote "$repeats" - printf " > \"\$replay_observations_tmp\"\n" - shell_quote "$mv_path" - printf " \"\$replay_observations_tmp\" " - shell_quote "$out_abs/observations.tsv" - printf '\n' - printf "replay_observations_tmp=\n" -} > "$bundle_stage/command.txt" - -"$study_executable" --profile local --repeats "$repeats" \ - > "$observations_path" & -active_study_pid=$! - -if wait "$active_study_pid"; then - study_status=0 -else - study_status=$? -fi - -if [ -n "$termination_status" ]; then - wait "$active_study_pid" >/dev/null 2>&1 || : - active_study_pid= - exit "$termination_status" -fi - -active_study_pid= -[ "$study_status" -eq 0 ] || - fail "R7 study execution failed with status $study_status" - -validate_snapshot_identity -validate_source_identity -cleanup_snapshot - -case "$hash_mode" in - sha256sum) - ( - cd "$bundle_stage" - "$hash_path" \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - shasum) - sanitize_perl_hash_environment - ( - cd "$bundle_stage" - "$hash_path" -a 256 \ - environment.txt \ - compiler.txt \ - command.txt \ - observations.tsv \ - > SHA256SUMS - ) - ;; - *) - fail "unsupported SHA-256 utility mode: $hash_mode" - ;; -esac - -validate_source_identity - -"$bundle_mkdir_path" "$publish_lock" || - fail "could not acquire destination publication lock; another capture may be publishing: $out_dir" -publish_lock_held=true - -if [ -e "$out_dir" ] || [ -L "$out_dir" ]; then - fail "evidence destination appeared during capture; refusing publish: $out_dir" -fi -[ ! -e "$publish_stage" ] && [ ! -L "$publish_stage" ] || - fail "publish staging destination already exists: $publish_stage" - -"$bundle_mkdir_path" "$publish_stage" || - fail "could not create sibling publish staging directory" -"$cp_path" -R "$bundle_stage/." "$publish_stage/" || - fail "could not copy completed bundle to destination filesystem" - -case "$hash_mode" in - sha256sum) - ( - cd "$publish_stage" - "$hash_path" -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; - shasum) - sanitize_perl_hash_environment - ( - cd "$publish_stage" - "$hash_path" -a 256 -c SHA256SUMS - ) || fail "copied publish staging bundle failed SHA-256 verification" - ;; -esac - -"$provenance_rm_path" -rf "$bundle_stage" || - fail "could not remove repository bundle staging directory" - -if [ -e "$out_abs" ] || [ -L "$out_abs" ]; then - fail "evidence destination appeared during publish; refusing rename: $out_abs" -fi - -"$mv_path" "$publish_stage" "$out_abs" || - fail "could not rename completed sibling staging bundle into place" -"$provenance_rm_path" -rf "$publish_lock" || - fail "published bundle but could not release destination publication lock" -publish_lock_held=false -trap - 0 1 2 3 15 - -echo "R7 evidence bundle: $out_dir"