diff --git a/.github/workflows/architecture-cli-boundary-regression.yml b/.github/workflows/architecture-cli-boundary-regression.yml new file mode 100644 index 000000000..784fb27dd --- /dev/null +++ b/.github/workflows/architecture-cli-boundary-regression.yml @@ -0,0 +1,135 @@ +name: Architecture CLI boundary diagnostic + +'on': + push: + branches: + - codex/architecture-cli-boundary-red-20261016 + pull_request: + paths: + - architecture/artifact_index.py + - architecture/graph_artifact_readback.py + - tools/artifact_index_export.py + - tools/architecture_graph_artifact_readback.py + - tests/test_architecture_artifact_index.py + - tests/test_architecture_graph_artifact_readback.py + - tests/test_architecture_cli_boundaries.py + - .github/workflows/architecture-cli-boundary-regression.yml + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: architecture-cli-boundary-${{ github.run_id }}-${{ github.run_attempt }} + cancel-in-progress: false + +jobs: + cli-boundaries: + name: architecture-cli-boundary-${{ matrix.mode }} + runs-on: ubuntu-24.04 + timeout-minutes: 6 + strategy: + fail-fast: false + matrix: + mode: [normal, optimized] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + timeout-minutes: 1 + with: + persist-credentials: false + fetch-depth: 1 + + - name: Record diagnostic native context before running controls + timeout-minutes: 1 + env: + DIAGNOSTIC_MODE: ${{ matrix.mode }} + run: | + set -euo pipefail + evidence="$RUNNER_TEMP/architecture-cli-boundary-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$DIAGNOSTIC_MODE" + mkdir -m 700 "$evidence" + git rev-parse HEAD > "$evidence/checked-commit.txt" + python3 -I -B -S - "$evidence" <<'PY' + from datetime import datetime, timezone + import hashlib + import json + import os + from pathlib import Path + import platform + import sys + root = Path(os.environ['GITHUB_WORKSPACE']) + destination = Path(sys.argv[1]) + paths = ( + '.github/workflows/architecture-cli-boundary-regression.yml', + 'tests/test_architecture_cli_boundaries.py', + 'tests/test_architecture_artifact_index.py', + 'tests/test_architecture_graph_artifact_readback.py', + 'tools/artifact_index_export.py', + 'tools/architecture_graph_artifact_readback.py', + 'architecture/artifact_index.py', + 'architecture/graph_artifact_readback.py', + 'docs/site/dependency-source/GRAPH.json', + ) + sources = {} + for name in paths: + raw = (root / name).read_bytes() + sources[name] = {'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()} + context = { + 'schema': 'architecture-cli-boundary-diagnostic/v1', + 'recorded_at': datetime.now(timezone.utc).isoformat(), + 'repository': os.environ['GITHUB_REPOSITORY'], + 'event_name': os.environ['GITHUB_EVENT_NAME'], + 'workflow_ref': os.environ['GITHUB_WORKFLOW_REF'], + 'workflow_sha': os.environ['GITHUB_WORKFLOW_SHA'], + 'event_sha': os.environ['GITHUB_SHA'], + 'checked_commit': (destination / 'checked-commit.txt').read_text().strip(), + 'run_id': os.environ['GITHUB_RUN_ID'], + 'run_attempt': os.environ['GITHUB_RUN_ATTEMPT'], + 'mode': os.environ['DIAGNOSTIC_MODE'], + 'python': sys.version, + 'platform': platform.platform(), + 'source_identities': sources, + 'scope': 'four CLI boundary methods only; required full suite remains separate', + 'scientific_effect': 'NONE', + 'scientific_status_authority': False, + } + (destination / 'native-context.json').write_text( + json.dumps(context, sort_keys=True, indent=2) + '\n', encoding='utf-8') + PY + + - name: Run only the four external CLI boundary controls + timeout-minutes: 3 + env: + DIAGNOSTIC_MODE: ${{ matrix.mode }} + ARCHITECTURE_CLI_BOUNDARY_REPORT: ${{ runner.temp }}/architecture-cli-boundary-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.mode }}/child-results.jsonl + run: | + set -euo pipefail + evidence="$RUNNER_TEMP/architecture-cli-boundary-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$DIAGNOSTIC_MODE" + flags=(-I -B -S) + if [ "$DIAGNOSTIC_MODE" = optimized ]; then + flags+=(-O) + fi + printf '%q ' timeout --signal=TERM --kill-after=5s 150s \ + python3 "${flags[@]}" -m unittest discover -s tests -p test_architecture_cli_boundaries.py -v \ + > "$evidence/test-command.txt" + printf '\n' >> "$evidence/test-command.txt" + set +e + timeout --signal=TERM --kill-after=5s 150s \ + python3 "${flags[@]}" -m unittest discover -s tests -p test_architecture_cli_boundaries.py -v \ + > "$evidence/tests.stdout" 2> "$evidence/tests.stderr" + status=$? + set -e + printf '%s\n' "$status" > "$evidence/test-exit-status.txt" + cat "$evidence/tests.stdout" + cat "$evidence/tests.stderr" >&2 + exit "$status" + + - name: Retain separate diagnostic originals on every conclusion + if: always() + timeout-minutes: 1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 + with: + name: architecture-cli-boundary-${{ matrix.mode }}-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/architecture-cli-boundary-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.mode }}/ + if-no-files-found: error + retention-days: 90 + compression-level: 6 diff --git a/.github/workflows/current-site.yml b/.github/workflows/current-site.yml index 01b94fdd4..a9a5b19a2 100644 --- a/.github/workflows/current-site.yml +++ b/.github/workflows/current-site.yml @@ -55,6 +55,7 @@ jobs: with: ref: ${{ github.sha }} persist-credentials: false + fetch-depth: 0 - name: Restore and admit all previously published public history env: GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/navigation.yml b/.github/workflows/navigation.yml index 586d2a722..c4e157293 100644 --- a/.github/workflows/navigation.yml +++ b/.github/workflows/navigation.yml @@ -10,7 +10,7 @@ permissions: jobs: navigation: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 diff --git a/.github/workflows/public-intake.yml b/.github/workflows/public-intake.yml index 401ee3228..d1b421ea9 100644 --- a/.github/workflows/public-intake.yml +++ b/.github/workflows/public-intake.yml @@ -11,9 +11,14 @@ permissions: jobs: public-intake: name: public-intake - # Skip metadata edits only for terminal merged PRs. Reopenable PRs must - # still pass the live checker, including closure and head-drift checks. - if: ${{ !(github.event.pull_request.state == 'closed' && toJSON(github.event.pull_request.merged) == 'true') }} + permissions: + contents: read + pull-requests: read + # Only for the neutral "not evaluated" check run. Submitted code is never executed. + checks: write + # Never skip this required job based on event metadata: skipped checks can + # appear passing without validation. The checker handles merged-before-check + # events by posting a separate neutral result and returning nonzero (78). runs-on: ubuntu-24.04 timeout-minutes: 5 steps: @@ -28,4 +33,20 @@ jobs: - name: Verify intake from API bytes without checking out the PR env: GH_TOKEN: ${{ github.token }} - run: python3 -B -I tools/public_intake_check.py + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + set +e + python3 -B -I tools/public_intake_check.py + code=$? + set -e + # Actions cannot mark this job neutral. Skipping the job can count as a + # passing required check, and a zero status would make public-intake + # green without package verification. Record a separate neutral check, + # then exit 78 so this job is failure, not success. A failed post + # still reaches that same nonzero status. + if [ "$code" -eq 78 ]; then + echo "not evaluated: merged before check" + python3 -B -I tools/public_intake_check.py --publish-not-evaluated-check || true + exit 78 + fi + exit "$code" diff --git a/.github/workflows/research-architecture.yml b/.github/workflows/research-architecture.yml index 4b53e755e..8739e26fd 100644 --- a/.github/workflows/research-architecture.yml +++ b/.github/workflows/research-architecture.yml @@ -36,8 +36,8 @@ jobs: graph: name: research-architecture runs-on: ubuntu-24.04 - # Complete stage ceiling: 19 preparation + 11 tests + fourteen 1-minute stages. - timeout-minutes: 44 + # Complete stage ceiling: 19 preparation + 16 tests + fourteen 1-minute stages. + timeout-minutes: 49 outputs: checked_commit: ${{ steps.accepted.outputs.checked_commit }} repository: ${{ steps.accepted.outputs.repository }} @@ -311,17 +311,17 @@ jobs: printf '%s\n' "$GITHUB_RUN_ATTEMPT" > "$RUNNER_TEMP/architecture-publish/run-attempt.txt" - name: Run controls and export in ephemeral restricted container id: architecture_controls - timeout-minutes: 11 + timeout-minutes: 16 env: IMAGE: python:3.11.14-slim-bookworm@sha256:83f339c1be6340ae1096010fdccf6552ac932d8f410d45d206014916bdf37e48 run: | set -euo pipefail set +e - timeout --signal=TERM --kill-after=10s 600s docker run --pull=never --rm --log-driver none --name architecture-controls \ + timeout --signal=TERM --kill-after=10s 900s docker run --pull=never --rm --log-driver none --name architecture-controls \ --network none --read-only --user 65532:65532 --cpus 2 --memory 1g --pids-limit 128 \ --cap-drop ALL --security-opt no-new-privileges \ --env ARCHITECTURE_SANDBOX=1 \ - --tmpfs /tmp:rw,noexec,nosuid,size=64m \ + --tmpfs /tmp:rw,noexec,nosuid,size=128m \ --mount type=bind,source="$GITHUB_WORKSPACE",target=/source,readonly \ --mount type=bind,source="$RUNNER_TEMP/architecture-evidence/container",target=/output \ --workdir /source "$IMAGE" sh -c ' diff --git a/AGENTS.md b/AGENTS.md index cbc0a137b..0899d8381 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,12 @@ Carry both links into task handoffs and new-agent onboarding. Use the [current workflow](governance/OP-WORKFLOW-20260930.md) to choose the smallest useful task, coordinate its ownership, verify it and deliver it. +As of 15 October 2026, direct new claims, reviews, handoffs and releases to +[Agent Message Board #419](https://github.com/d6g8k5htny-coder/main/issues/419). +Earlier [#307](https://github.com/d6g8k5htny-coder/main/issues/307) and +[#229](https://github.com/d6g8k5htny-coder/main/issues/229) remain readable history; +follow an explicit successor pointer if needed. Moving the board does not +transfer, renew, or release any existing claim. Dylan's current explicit instruction resumes the requested reader experience and workflow improvements, including implementation, review and integration. The [September 27 stop](governance/OWNER_STOP_20260927.md) is no longer in effect diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df6b94c82..1fd09dbd5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -111,7 +111,7 @@ HTML, SVG, archives, executable files, symlinks and submodules are refused here. For code or a notebook proposal, describe it in an issue; a maintainer can sponsor a separate engineering PR. Do not encode a refused file inside an allowed format. -`public-intake` runs trusted default-branch code with a read-only token. It reads +`public-intake` runs trusted default-branch code; the job's token is read-only for contents and pull requests, plus `checks: write` used solely to post the neutral 'not evaluated: merged before check' check run, and submitted code is never checked out or executed. It reads PR metadata and blobs through the GitHub API, checks complete path lists and source identities, and fails on missing information or a changing PR. It never checks out or executes submitted code. The credential scan catches a small documented diff --git a/README.md b/README.md index 91ad07eee..c64d7ab07 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ The [research workspace](https://d6g8k5htny-coder.github.io/main/site/workspace. | [query-](https://github.com/d6g8k5htny-coder/query-) | Read-only exact-source lookup | | [Universal-Law-Workspace](https://github.com/d6g8k5htny-coder/Universal-Law-Workspace) | Repository map | -[Reproduction guide](docs/REPRODUCE.md) · [Agent entry](AGENTS.md) · [Current workflow](governance/OP-WORKFLOW-20260930.md) · [Active coordination board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307) · [Historical #229 working guidance](https://github.com/d6g8k5htny-coder/main/issues/229#issuecomment-6038554880) · [Tasks and claims, main #275](https://github.com/d6g8k5htny-coder/main/issues/275) +[Reproduction guide](docs/REPRODUCE.md) · [Agent entry](AGENTS.md) · [Current workflow](governance/OP-WORKFLOW-20260930.md) · [Active coordination board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419) · [Prior board #307 (history)](https://github.com/d6g8k5htny-coder/main/issues/307) · [Historical #229 working guidance](https://github.com/d6g8k5htny-coder/main/issues/229#issuecomment-6038554880) · [Tasks and claims, main #275](https://github.com/d6g8k5htny-coder/main/issues/275) diff --git a/architecture/artifact_index.py b/architecture/artifact_index.py new file mode 100644 index 000000000..7cb920cf6 --- /dev/null +++ b/architecture/artifact_index.py @@ -0,0 +1,325 @@ +"""Project a pinned native Artifact Index capture into fixed public fields. + +This module treats captures as inert JSON data. It performs no I/O, interprets +no cell content, and authenticates no external custody or scientific status. +""" +from __future__ import annotations + +import base64 +from datetime import datetime +import hashlib +import json +import math +import re + + +STDIN_LIMIT = 16 * 1024 * 1024 +CAPTURE_LIMIT = 4 * 1024 * 1024 +DEPTH_LIMIT = 64 +COLLECTION_LIMIT = 4096 +CELL_LIMIT = 8192 +GRID_ROW_LIMIT = 10_000_000 + +HEADER = ( + "Artifact ID", "Title", "Org", "Class", "Priority", "Topics / object tags", + "Status", "Authority / canonical impact", "Dependencies or supersession", + "Modified UTC", "Source", "Notes", +) +PUBLIC_COLUMNS = ( + "Artifact ID", "Title", "Org", "Class", "Status", + "Authority / canonical impact", "Dependencies or supersession", "Modified UTC", +) +PUBLIC_INDICES = tuple(HEADER.index(column) for column in PUBLIC_COLUMNS) +ROLES = frozenset(("source", "review", "kernel", "computation", "alignment", "teaching-source")) +PIN_KEYS = frozenset(( + "capture_sha256", "metadata_sha256", "policy_sha256", + "bindings_sha256", "graph_nodes_sha256", +)) +IDENTIFIER = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.:-]{0,191}") +SHA256 = re.compile(r"[0-9a-f]{64}") +UTC_SECOND = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z") + + +class ArtifactIndexRefused(ValueError): + """An opaque refusal whose message never includes caller data.""" + + def __init__(self): + super().__init__("ARTIFACT_INDEX_REFUSED") + + +def _require(condition): + if not condition: + raise ArtifactIndexRefused() + + +def _validate_json_value(value, depth=0): + """Validate JSON types, finite numbers, Unicode, and container depth.""" + kind = type(value) + if kind is dict: + _require(depth < DEPTH_LIMIT) + for key, child in value.items(): + _require(type(key) is str) + key.encode("utf-8", errors="strict") + _validate_json_value(child, depth + 1) + elif kind is list: + _require(depth < DEPTH_LIMIT) + for child in value: + _validate_json_value(child, depth + 1) + elif kind is str: + value.encode("utf-8", errors="strict") + elif kind is float: + _require(math.isfinite(value)) + else: + _require(kind in (int, bool, type(None))) + + +def _object_pairs(pairs): + result = {} + for key, value in pairs: + _require(key not in result) + result[key] = value + return result + + +def _nonfinite_constant(_token): + raise ArtifactIndexRefused() + + +def _finite_float(token): + value = float(token) + _require(math.isfinite(value)) + return value + + +def _strict_json(raw, limit): + try: + _require(type(raw) is bytes and 0 < len(raw) <= limit) + value = json.loads( + raw.decode("utf-8", errors="strict"), + object_pairs_hook=_object_pairs, + parse_constant=_nonfinite_constant, + parse_float=_finite_float, + ) + _validate_json_value(value) + return value + except Exception: + raise ArtifactIndexRefused() from None + + +def parse_packet(raw): + """Read one bounded strict JSON packet from caller-supplied bytes.""" + return _strict_json(raw, STDIN_LIMIT) + + +def canonical_json(value): + """Return deterministic ASCII JSON bytes, preserving array order/types.""" + try: + _validate_json_value(value) + return json.dumps( + value, sort_keys=True, separators=(",", ":"), + ensure_ascii=True, allow_nan=False, + ).encode("ascii") + except Exception: + raise ArtifactIndexRefused() from None + + +def _object(value, keys=None): + _require(type(value) is dict) + if keys is not None: + _require(value.keys() == keys) + return value + + +def _integer(value, minimum=0, maximum=None): + _require(type(value) is int and value >= minimum) + if maximum is not None: + _require(value <= maximum) + return value + + +def _identifier(value): + _require(type(value) is str and IDENTIFIER.fullmatch(value) is not None) + return value + + +def _bounded_list(value, minimum=0, maximum=COLLECTION_LIMIT): + _require(type(value) is list and minimum <= len(value) <= maximum) + return value + + +def _unique_identifiers(value, minimum=0): + values = _bounded_list(value, minimum) + seen = set() + for item in values: + _identifier(item) + _require(item not in seen) + seen.add(item) + return seen + + +def _expected_pins(expected): + _object(expected, PIN_KEYS) + for value in expected.values(): + _require(type(value) is str and SHA256.fullmatch(value) is not None) + + +def _capture_metadata(capture): + _object(capture, {"capture_id", "captured_at", "source", "raw_base64"}) + _identifier(capture["capture_id"]) + timestamp = capture["captured_at"] + _require(type(timestamp) is str) + match = UTC_SECOND.fullmatch(timestamp) + _require(match is not None) + # A numeric constructor checks calendar validity without parsing cell text. + datetime(*(int(part) for part in match.groups())) + source = _object(capture["source"], { + "spreadsheet_id", "worksheet_id", "title", "ranges", "cell_fields", + }) + _identifier(source["spreadsheet_id"]) + _integer(source["worksheet_id"]) + title = source["title"] + _require(type(title) is str and 0 < len(title.encode("utf-8")) <= 256) + _require("'" not in title and not any(ord(char) < 32 or 127 <= ord(char) <= 159 for char in title)) + _require(source["cell_fields"] == "formattedValue" and type(source["cell_fields"]) is str) + ranges = _bounded_list(source["ranges"], 1, COLLECTION_LIMIT + 1) + range_pattern = re.compile(r"'" + re.escape(title) + r"'!A([1-9][0-9]*):L([1-9][0-9]*)") + intervals = [] + prior_end = 0 + for declared in ranges: + _require(type(declared) is str) + match = range_pattern.fullmatch(declared) + _require(match is not None) + # Bounds precede integer conversion, including enormous decimal text. + _require(all(len(part) <= 8 for part in match.groups())) + first, last = (int(part) for part in match.groups()) + _require(prior_end < first <= last <= GRID_ROW_LIMIT) + intervals.append((first - 1, last)) + prior_end = last + _require(sum(stop - start for start, stop in intervals) <= COLLECTION_LIMIT + 1) + return source, intervals + + +def _capture_bytes(encoded): + _require(type(encoded) is str and 0 < len(encoded) <= 4 * ((CAPTURE_LIMIT + 2) // 3)) + raw = base64.b64decode(encoded.encode("ascii"), validate=True) + _require(0 < len(raw) <= CAPTURE_LIMIT) + _require(base64.b64encode(raw).decode("ascii") == encoded) + return raw + + +def _native_rows(native, source, intervals): + _object(native) + _require(type(native.get("spreadsheetId")) is str and native["spreadsheetId"] == source["spreadsheet_id"]) + sheets = _bounded_list(native.get("sheets"), 1, 1) + sheet = _object(sheets[0]) + properties = _object(sheet.get("properties")) + _integer(properties.get("sheetId")) + _require(properties["sheetId"] == source["worksheet_id"]) + _require(type(properties.get("title")) is str and properties["title"] == source["title"]) + grid = _object(properties.get("gridProperties")) + row_count = _integer(grid.get("rowCount"), 1, GRID_ROW_LIMIT) + _require(_integer(grid.get("columnCount"), 1) == len(HEADER)) + blocks = _bounded_list(sheet.get("data"), len(intervals), len(intervals)) + rows_by_id = {} + header_count = 0 + for block, (start, stop) in zip(blocks, intervals): + _object(block) + _require(stop <= row_count) + _require(_integer(block.get("startRow", 0)) == start) + _require(_integer(block.get("startColumn", 0)) == 0) + rows = _bounded_list(block.get("rowData"), stop - start, stop - start) + for offset, row in enumerate(rows): + _object(row) + cells = _bounded_list(row.get("values"), len(HEADER), len(HEADER)) + values = [] + for cell in cells: + _object(cell) + value = cell.get("formattedValue", "") + _require(type(value) is str and len(value.encode("utf-8")) <= CELL_LIMIT) + values.append(value) + position = start + offset + if position == 0: + _require(values == list(HEADER)) + header_count += 1 + else: + artifact_id = _identifier(values[0]) + _require(artifact_id not in rows_by_id) + rows_by_id[artifact_id] = (position + 1, values) + _require(len(rows_by_id) <= COLLECTION_LIMIT) + _require(header_count == 1) + return rows_by_id + + +def _project(packet, expected): + _validate_json_value(packet) + _expected_pins(expected) + _object(packet, {"schema_version", "capture", "policy", "bindings", "graph_nodes"}) + _require(_integer(packet["schema_version"]) == 1) + capture = packet["capture"] + source, intervals = _capture_metadata(capture) + raw = _capture_bytes(capture["raw_base64"]) + metadata = {key: value for key, value in capture.items() if key != "raw_base64"} + identities = { + "capture_sha256": hashlib.sha256(raw).hexdigest(), + "metadata_sha256": hashlib.sha256(canonical_json(metadata)).hexdigest(), + "policy_sha256": hashlib.sha256(canonical_json(packet["policy"])).hexdigest(), + "bindings_sha256": hashlib.sha256(canonical_json(packet["bindings"])).hexdigest(), + "graph_nodes_sha256": hashlib.sha256(canonical_json(packet["graph_nodes"])).hexdigest(), + } + _require(identities == expected) + policy = _object(packet["policy"], {"schema_version", "artifact_ids", "columns"}) + _require(_integer(policy["schema_version"]) == 1) + _require(type(policy["columns"]) is list and policy["columns"] == list(PUBLIC_COLUMNS)) + selected = _unique_identifiers(policy["artifact_ids"], 1) + graph_nodes = _unique_identifiers(packet["graph_nodes"]) + bindings = [] + pairs = set() + bound_nodes = set() + for binding in _bounded_list(packet["bindings"]): + _object(binding, {"node_id", "artifact_id", "roles"}) + node = _identifier(binding["node_id"]) + artifact = _identifier(binding["artifact_id"]) + _require(node in graph_nodes and artifact in selected) + roles = _bounded_list(binding["roles"], 1, len(ROLES)) + _require(all(type(role) is str and role in ROLES for role in roles)) + _require(len(set(roles)) == len(roles)) + pair = (node, artifact) + _require(pair not in pairs) + pairs.add(pair) + bound_nodes.add(node) + bindings.append({"node_id": node, "artifact_id": artifact, "roles": sorted(roles)}) + native = _strict_json(raw, CAPTURE_LIMIT) + native_rows = _native_rows(native, source, intervals) + _require(selected <= native_rows.keys()) + rows = [] + for artifact in sorted(selected): + source_row, values = native_rows[artifact] + rows.append({ + "artifact_id": artifact, "source_row": source_row, + "fields": {column: values[index] for column, index in zip(PUBLIC_COLUMNS, PUBLIC_INDICES)}, + }) + return { + "schema_version": 1, "scientific_effect": "NONE", + "scientific_status_authority": False, "custody": "unknown", + "source": { + "capture_id": capture["capture_id"], "captured_at": capture["captured_at"], + "spreadsheet_id": source["spreadsheet_id"], "worksheet_id": source["worksheet_id"], + "worksheet_title": source["title"], "ranges": list(source["ranges"]), + "cell_fields": source["cell_fields"], "representation": "native-api-formattedValue-json", + }, + "identities": identities, "columns": list(PUBLIC_COLUMNS), "rows": rows, + "bindings": sorted(bindings, key=lambda item: (item["node_id"], item["artifact_id"])), + "unmapped_nodes": sorted(graph_nodes - bound_nodes), + } + + +def project_artifact_index(packet, expected): + """Return the exact public projection, or raise an opaque refusal. + + Independent expected pins are mandatory; no expectation is learned from + the packet. Input objects are not mutated and private data is not returned. + """ + try: + return _project(packet, expected) + except Exception: + raise ArtifactIndexRefused() from None diff --git a/architecture/graph_artifact_readback.py b/architecture/graph_artifact_readback.py new file mode 100644 index 000000000..c39ffd0fd --- /dev/null +++ b/architecture/graph_artifact_readback.py @@ -0,0 +1,531 @@ +"""Strict byte-only readback of a bounded architecture artifact. + +Caller pins establish declared comparison context, never authenticated custody. +No captured code, producer helper, gate, or test module is imported or executed. +""" +from __future__ import annotations + +import hashlib +import json +import math +import re +import stat +import struct +import zlib +from typing import Any + + +MIB = 1024 * 1024 +RAW_LIMIT = 64 * MIB +INFLATED_LIMIT = 64 * MIB +OUTPUT_LIMIT = 16 * MIB +MAX_DEPTH = 64 +SOURCE_BYTES = 38753 +GRAPH_SOURCE = { + "repository": "d6g8k5htny-coder/Math-", + "commit": "7858329974e28be79f29b22644370084ff43da4f", + "captured_at": "2026-10-03T15:07:03Z", + "graph_sha256": "8822e9618678321a342d69cd0b8ae6552de1b5d578c331de5072b2892ee9dd09", + "gate_sha256": "a78f3e25f3b0cfe113e618a4c31a7a25d7f22af638c46dec1ecba221fa333ac8", +} +IMAGE_DIGEST = "python@sha256:83f339c1be6340ae1096010fdccf6552ac932d8f410d45d206014916bdf37e48" +MEMBER_LIMITS = { + "ARTIFACT_SHA256SUMS": 16 * 1024, + "checked-commit.txt": 128, + "run-id.txt": 128, + "run-attempt.txt": 128, + "container-exit-status.txt": 128, + "exporter.stdout": 64 * 1024, + "exporter.stderr": 64 * 1024, + "runtime-image.json": MIB, + "generated/graph.json": 4 * MIB, + "architecture-run-receipt.json": 4 * MIB, + "console.log": 4 * MIB, + "tests-normal.log": 16 * MIB, + "tests-optimized.log": 16 * MIB, +} +EVIDENCE_MEMBERS = frozenset({ + "generated/graph.json", "checked-commit.txt", "run-id.txt", + "run-attempt.txt", "container-exit-status.txt", "tests-normal.log", + "tests-optimized.log", "runtime-image.json", +}) +BINDING_KEYS = frozenset({ + "checked_commit", "repository", "run_id", "run_attempt", + "receipt_sha256", "artifact_id", "artifact_sha256", "artifact_name", +}) +REVIEW_FIELDS = ( + "review_source", "review_issue", "review_basis", "review_provider", + "review_providers", "review_disposition", +) +HEX40 = re.compile(r"[0-9a-f]{40}") +HEX64 = re.compile(r"[0-9a-f]{64}") +POSITIVE_DECIMAL = re.compile(r"[1-9][0-9]*") +REPOSITORY = re.compile(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+") +IMAGE_ID = re.compile(r"sha256:[0-9a-f]{64}") +TEST_ID = re.compile(r"test_architecture_[A-Za-z0-9_]+\.[A-Za-z_][A-Za-z0-9_]*\.test[A-Za-z0-9_]*") +TEST_RESULT = re.compile(r"(\S+) \(([^()]*)\) \.\.\. (.+)") +TEST_RESULT_LIKE = re.compile(r"^\s*test|\([^()\n]*\.test[^()\n]*\)|\)\s*\.\.\.", re.IGNORECASE) +TEST_SUMMARY = re.compile(r"Ran ([1-9][0-9]*) tests in ([0-9]+(?:\.[0-9]+)?)s") +REQUIRED_IDS = frozenset(""" +test_architecture_binding.ArchitectureBindingContract.test_artifact_id_requires_positive_ascii_decimal_without_leading_zero +test_architecture_binding.ArchitectureBindingContract.test_artifact_name_is_exactly_bound_to_current_run_and_attempt +test_architecture_binding.ArchitectureBindingContract.test_attempt_ten_is_a_positive_decimal_not_a_single_digit +test_architecture_binding.ArchitectureBindingContract.test_commit_format_cannot_be_authorized_by_an_equally_invalid_native_commit +test_architecture_binding.ArchitectureBindingContract.test_deeply_nested_json_is_refused_without_a_success_envelope +test_architecture_binding.ArchitectureBindingContract.test_duplicate_top_level_keys_are_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_current_native_argument_is_used_for_identity_binding +test_architecture_binding.ArchitectureBindingContract.test_each_duplicate_output_key_is_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_expected_native_identity_argument_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_non_success_result_is_refused +test_architecture_binding.ArchitectureBindingContract.test_each_of_the_eight_outputs_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_an_empty_string +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_non_string_identities_without_coercion +test_architecture_binding.ArchitectureBindingContract.test_each_top_level_field_is_required +test_architecture_binding.ArchitectureBindingContract.test_extra_output_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_extra_top_level_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_invalid_or_multiple_json_documents_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_finite_json_numbers_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_object_top_level_values_are_refused +test_architecture_binding.ArchitectureBindingContract.test_other_valid_native_identities_are_accepted_and_preserved +test_architecture_binding.ArchitectureBindingContract.test_outputs_must_be_an_object +test_architecture_binding.ArchitectureBindingContract.test_receipt_and_artifact_sha256_require_lowercase_64_hex_digits +test_architecture_binding.ArchitectureBindingContract.test_repository_substitution_and_case_drift_are_refused +test_architecture_binding.ArchitectureBindingContract.test_run_and_attempt_decimal_format_cannot_be_authorized_by_invalid_native_args +test_architecture_binding.ArchitectureBindingContract.test_stale_attempt_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_stale_checked_commit_is_refused +test_architecture_binding.ArchitectureBindingContract.test_stale_run_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_valid_current_run_has_exact_stable_non_scientific_output +test_architecture_binding.ArchitectureBindingContract.test_valid_json_at_exact_stdin_byte_limit_is_accepted +test_architecture_binding.ArchitectureBindingContract.test_valid_json_over_stdin_byte_limit_is_refused +test_architecture_graph_export.ArchitectureGraphExportContract.test_caller_pinned_provenance_cannot_authorize_different_gate_code +test_architecture_graph_export.ArchitectureGraphExportContract.test_classification_and_proof_review_text_cannot_manufacture_evidence +test_architecture_graph_export.ArchitectureGraphExportContract.test_context_only_cycle_is_allowed_without_changing_gate_semantics +test_architecture_graph_export.ArchitectureGraphExportContract.test_default_trust_rejects_self_consistent_changed_graph_and_provenance +test_architecture_graph_export.ArchitectureGraphExportContract.test_dimensions_describe_only_explicit_recorded_metadata +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_graph_json_keys_are_rejected_after_identity_validation +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_provenance_json_keys_are_rejected_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_exact_source_bound_hard_gate_validator_is_called +test_architecture_graph_export.ArchitectureGraphExportContract.test_failed_export_preserves_an_earlier_valid_export +test_architecture_graph_export.ArchitectureGraphExportContract.test_gate_identity_is_checked_before_untrusted_gate_executes +test_architecture_graph_export.ArchitectureGraphExportContract.test_graph_identity_is_checked_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_missing_required_dependency_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_pinned_49_node_55_edge_export_is_deterministic_and_preserves_records +test_architecture_graph_export.ArchitectureGraphExportContract.test_required_dependency_cycle_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_same_size_gate_change_is_rejected_by_sha_before_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_source_byte_counts_are_validated_even_when_sha_matches +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_directory_is_rejected +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_files_are_rejected_before_gate_import +test_architecture_receipt.ArchitectureReceiptContract.test_attempt_ten_and_other_native_repository_are_preserved +test_architecture_receipt.ArchitectureReceiptContract.test_changed_node_or_edge_is_refused_even_when_graph_source_pins_are_unchanged +test_architecture_receipt.ArchitectureReceiptContract.test_directory_or_fifo_member_is_refused_without_waiting_for_a_writer +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_json_keys_are_refused_even_when_last_value_is_valid +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_test_identity_or_multiple_runs_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_each_expected_host_identity_argument_is_used_and_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_native_identity_file_must_match_current_host_arguments +test_architecture_receipt.ArchitectureReceiptContract.test_each_required_sandbox_control_rejects_skipped_failed_or_error_status +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_is_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_must_be_regular_and_cannot_be_a_symlink +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_over_16_mib_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_empty_or_zero_discovered_test_logs_are_refused_in_each_mode +test_architecture_receipt.ArchitectureReceiptContract.test_every_graph_source_pin_is_required_and_cannot_be_substituted +test_architecture_receipt.ArchitectureReceiptContract.test_every_required_identity_is_needed_even_when_53_other_tests_are_ok +test_architecture_receipt.ArchitectureReceiptContract.test_evidence_directory_or_generated_parent_symlink_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_graph_and_runtime_inspect_require_strict_json +test_architecture_receipt.ArchitectureReceiptContract.test_graph_root_schema_and_non_scientific_flags_are_exact +test_architecture_receipt.ArchitectureReceiptContract.test_invalid_matching_host_identity_does_not_authorize_bad_commit_or_decimal +test_architecture_receipt.ArchitectureReceiptContract.test_later_all_ok_test_methods_are_counted_and_bound +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_extra_result_lines_cannot_be_ignored_before_the_success_footer +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_foreign_or_shortname_mismatched_test_identities_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_missing_extra_or_forged_dimension_cannot_manufacture_scientific_evidence +test_architecture_receipt.ArchitectureReceiptContract.test_native_repository_argument_must_have_owner_and_repository_components +test_architecture_receipt.ArchitectureReceiptContract.test_nested_record_types_cannot_change_even_when_python_values_compare_equal +test_architecture_receipt.ArchitectureReceiptContract.test_non_finite_numbers_are_refused_even_in_additional_inspect_fields +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_names_are_accepted_as_additional_controls +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_prefix_malformed_results_are_not_diagnostics +test_architecture_receipt.ArchitectureReceiptContract.test_nonzero_or_malformed_container_exit_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_normal_and_optimized_must_discover_the_same_additional_passing_tests +test_architecture_receipt.ArchitectureReceiptContract.test_runtime_inspect_is_one_linux_amd64_image_with_the_fixed_digest +test_architecture_receipt.ArchitectureReceiptContract.test_skip_or_failure_in_additional_discovered_test_is_also_refused +test_architecture_receipt.ArchitectureReceiptContract.test_summary_must_report_exact_discovered_count_and_terminal_ok +test_architecture_receipt.ArchitectureReceiptContract.test_valid_53_test_receipt_is_exact_deterministic_and_preserves_staged_bytes +test_architecture_receipt.ArchitectureReceiptContract.test_valid_inspected_image_id_is_preserved_instead_of_hardcoded +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_at_exact_16_mib_limit_is_accepted +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_larger_than_64_kib_is_accepted_and_raw_bytes_are_hashed +test_architecture_sandbox.ArchitectureSandbox.test_kernel_enforces_cpu_memory_and_process_limits +test_architecture_sandbox.ArchitectureSandbox.test_network_namespace_has_no_external_interface_or_route +test_architecture_sandbox.ArchitectureSandbox.test_nonroot_and_no_new_privileges +test_architecture_sandbox.ArchitectureSandbox.test_output_quota_stops_disk_exhaustion_and_cleanup_recovers_space +test_architecture_sandbox.ArchitectureSandbox.test_source_mount_is_read_only_and_environment_has_no_publishing_secret +""".split()) + + +def _require(condition: object) -> None: + if not condition: + raise ValueError("architecture graph readback refused") + + +def _sha(raw: bytes) -> str: + return hashlib.sha256(raw).hexdigest() + + +def _canonical(value: Any) -> str: + return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True, allow_nan=False) + + +def _encoded(value: Any) -> bytes: + return (_canonical(value) + "\n").encode("ascii") + + +def _object(value: Any, fields: set[str] | frozenset[str]) -> dict: + _require(type(value) is dict and set(value) == fields) + return value + + +def _science(document: dict) -> None: + _require(type(document["schema_version"]) is int and document["schema_version"] == 1) + _require(document["scientific_effect"] == "NONE" and document["scientific_status_authority"] is False) + + +def _json_types(value: Any, depth: int = 0) -> None: + kind = type(value) + if kind in (dict, list): + depth += 1 + _require(depth <= MAX_DEPTH) + if kind is dict: + for key, child in value.items(): + _require(type(key) is str) + key.encode("utf-8") + _json_types(child, depth) + else: + for child in value: + _json_types(child, depth) + elif kind is str: + value.encode("utf-8") + elif kind is float: + _require(math.isfinite(value)) + else: + _require(value is None or kind in (bool, int)) + + +def _json(raw: bytes) -> Any: + def unique(pairs): + value = {} + for key, child in pairs: + _require(key not in value) + value[key] = child + return value + + def no_constant(_value): + raise ValueError("architecture graph readback refused") + + def finite_float(value): + number = float(value) + _require(math.isfinite(number)) + return number + + try: + value = json.loads(raw.decode("utf-8"), object_pairs_hook=unique, + parse_constant=no_constant, parse_float=finite_float) + _json_types(value) + return value + except (UnicodeError, RecursionError, OverflowError) as exc: + raise ValueError("architecture graph readback refused") from exc + + +def validate_expected(expected: dict[str, str]) -> dict[str, str]: + _object(expected, BINDING_KEYS) + _require(all(type(value) is str for value in expected.values())) + _require(sum(len(value) for value in expected.values()) <= OUTPUT_LIMIT) + for field, pattern in ( + ("checked_commit", HEX40), ("repository", REPOSITORY), + ("run_id", POSITIVE_DECIMAL), ("run_attempt", POSITIVE_DECIMAL), + ("receipt_sha256", HEX64), ("artifact_id", POSITIVE_DECIMAL), + ("artifact_sha256", HEX64), + ): + _require(pattern.fullmatch(expected[field]) is not None) + _require(all(part not in (".", "..") for part in expected["repository"].split("/"))) + _require(expected["artifact_name"] == "research-architecture-" + expected["run_id"] + "-" + expected["run_attempt"]) + return dict(expected) + + +def _fields(layout: str, raw: bytes, offset: int, boundary: int) -> tuple: + _require(0 <= offset and offset + struct.calcsize(layout) <= boundary <= len(raw)) + return struct.unpack_from(layout, raw, offset) + + +def _archive_geometry(raw: bytes) -> list[dict[str, Any]]: + """Inspect the complete closed inventory and every span before inflation.""" + footer_start = len(raw) - 22 + footer = _fields(" 0) + name_bytes = raw[position + 46:record_end] + try: + name = name_bytes.decode("ascii") + except UnicodeError as exc: + raise ValueError("architecture graph readback refused") from exc + _require(name.encode("ascii") == name_bytes and name in MEMBER_LIMITS) + _require(name not in names and name.casefold() not in folded) + names.add(name) + folded.add(name.casefold()) + file_type = stat.S_IFMT(attributes >> 16) + _require(file_type in (0, stat.S_IFREG) and not attributes & (0x08 | 0x10 | 0x40)) + if file_type == 0: + _require(creator >> 8 == 0) + _require(expanded <= MEMBER_LIMITS[name]) + declared_total += expanded + _require(declared_total <= INFLATED_LIMIT) + rows.append({"name": name, "name_bytes": name_bytes, "needed": needed, + "flags": flags, "method": method, "crc": crc, "compressed": compressed, + "expanded": expanded, "local_offset": local_offset}) + position = record_end + _require(position == footer_start and names == set(MEMBER_LIMITS)) + rows.sort(key=lambda row: row["local_offset"]) + cursor = 0 + for index, row in enumerate(rows): + _require(row["local_offset"] == cursor) + local = _fields(" bytes: + limit = min(MEMBER_LIMITS[row["name"]], remaining) + _require(row["expanded"] <= limit) + parts = [] + total = 0 + crc = 0 + decoder = zlib.decompressobj(-15) if row["method"] == 8 else None + start, end = row["data_start"], row["data_end"] + for position in range(start, end, 64 * 1024): + block = memoryview(raw)[position:min(position + 64 * 1024, end)] + if decoder is None: + part = bytes(block) + else: + try: + part = decoder.decompress(block, min(limit, row["expanded"]) - total + 1) + except zlib.error as exc: + raise ValueError("architecture graph readback refused") from exc + _require(not decoder.unconsumed_tail and not decoder.unused_data) + total += len(part) + _require(total <= limit and total <= row["expanded"]) + parts.append(part) + crc = zlib.crc32(part, crc) + if decoder is not None and decoder.eof: + _require(position + len(block) == end) + if decoder is not None: + _require(decoder.eof and not decoder.unused_data and not decoder.unconsumed_tail) + _require(total == row["expanded"] and crc & 0xFFFFFFFF == row["crc"]) + return b"".join(parts) + + +def _members(raw: bytes) -> dict[str, bytes]: + rows = _archive_geometry(raw) + members = {} + total = 0 + for row in rows: + member = _member(raw, row, INFLATED_LIMIT - total) + total += len(member) + _require(total <= INFLATED_LIMIT) + members[row["name"]] = member + return members + + +def _manifest(members: dict[str, bytes]) -> None: + raw = members["ARTIFACT_SHA256SUMS"] + _require(raw.endswith(b"\n")) + lines = raw[:-1].split(b"\n") + _require(len(lines) == 12) + expected_names = set(MEMBER_LIMITS) - {"ARTIFACT_SHA256SUMS"} + seen = set() + for line in lines: + _require(re.fullmatch(rb"[0-9a-f]{64} [A-Za-z0-9_./-]+", line) is not None) + digest, name_bytes = line.split(b" ", 1) + name = name_bytes.decode("ascii") + _require(name in expected_names and name not in seen) + _require(digest.decode("ascii") == _sha(members[name])) + seen.add(name) + _require(seen == expected_names) + + +def _source_graph(raw: bytes) -> dict: + _require(type(raw) is bytes and len(raw) == SOURCE_BYTES and _sha(raw) == GRAPH_SOURCE["graph_sha256"]) + source = _json(raw) + _require(type(source) is dict and type(source.get("nodes")) is dict and len(source["nodes"]) == 49) + _require(type(source.get("edges")) is list and len(source["edges"]) == 55) + return source + + +def _graph(raw: bytes, source: dict) -> dict: + graph = _object(_json(raw), { + "schema_version", "source", "nodes", "edges", "dimensions", + "scientific_effect", "scientific_status_authority", + }) + _science(graph) + _require(_canonical(graph["source"]) == _canonical(GRAPH_SOURCE)) + for field in ("nodes", "edges"): + _require(_canonical(graph[field]) == _canonical(source[field])) + dimensions = { + identity: { + "source": "recorded" if node.get("source") else "not_recorded", + "review": "recorded" if any(node.get(field) for field in REVIEW_FIELDS) else "not_recorded", + "kernel": "not_recorded", "computation": "not_recorded", "alignment": "not_recorded", + } for identity, node in source["nodes"].items() + } + _require(_canonical(graph["dimensions"]) == _canonical(dimensions)) + return graph + + +def _image(raw: bytes) -> dict[str, str]: + inspected = _json(raw) + _require(type(inspected) is list and len(inspected) == 1 and type(inspected[0]) is dict) + image = inspected[0] + identity = image.get("Id") + _require(type(identity) is str and IMAGE_ID.fullmatch(identity) is not None) + _require(_canonical(image.get("RepoDigests")) == _canonical([IMAGE_DIGEST])) + _require(image.get("Os") == "linux" and image.get("Architecture") == "amd64") + return {"id": identity, "repo_digest": IMAGE_DIGEST} + + +def _log(raw: bytes, mode: str) -> dict[str, Any]: + text = raw.decode("utf-8") + _require(text.endswith("\n") and "\r" not in text and "\x00" not in text) + lines = text.split("\n") + nonempty = [line for line in lines if line.strip()] + _require(bool(nonempty) and nonempty[-1] == "OK" and lines.count("OK") == 1) + identities = set() + footer_index = None + reported_count = None + last_result = -1 + for index, line in enumerate(lines): + if line.lstrip().casefold().startswith("ran "): + summary = TEST_SUMMARY.fullmatch(line) + _require(summary is not None and footer_index is None) + reported_count = int(summary.group(1)) + duration = float(summary.group(2)) + _require(math.isfinite(duration) and duration >= 0 and reported_count <= 4096) + footer_index = index + elif " ... " in line or TEST_RESULT_LIKE.search(line): + result = TEST_RESULT.fullmatch(line) + _require(result is not None) + short, identity, status = result.groups() + _require(TEST_ID.fullmatch(identity) is not None and short == identity.rsplit(".", 1)[1]) + _require(status == "ok" and identity not in identities and len(identities) < 4096) + identities.add(identity) + last_result = index + elif (re.match(r"(?:FAIL|ERROR|FAILED)(?:$|[:\s(])", line.lstrip(), re.IGNORECASE) + or line.lstrip().upper().startswith("OK (")): + raise ValueError("architecture graph readback refused") + _require(footer_index is not None and last_result < footer_index) + _require(REQUIRED_IDS <= identities and reported_count == len(identities)) + return {"mode": mode, "test_count": len(identities), "test_ids": sorted(identities)} + + +def _receipt(members: dict[str, bytes], expected: dict[str, str], image: dict[str, str]) -> dict: + raw = members["architecture-run-receipt.json"] + _require(_sha(raw) == expected["receipt_sha256"]) + receipt = _object(_json(raw), { + "schema_version", "scientific_effect", "scientific_status_authority", "checked_commit", + "repository", "run_id", "run_attempt", "runtime_image", "test_modes", "graph_source", + "evidence_file_sha256", + }) + _science(receipt) + for field in ("checked_commit", "repository", "run_id", "run_attempt"): + _require(type(receipt[field]) is str and receipt[field] == expected[field]) + _require(_canonical(receipt["runtime_image"]) == _canonical(image)) + _require(_canonical(receipt["graph_source"]) == _canonical(GRAPH_SOURCE)) + hashes = _object(receipt["evidence_file_sha256"], EVIDENCE_MEMBERS) + for name, digest in hashes.items(): + _require(type(digest) is str and HEX64.fullmatch(digest) is not None and digest == _sha(members[name])) + modes = [_log(members["tests-" + mode + ".log"], mode) for mode in ("normal", "optimized")] + _require(modes[0]["test_ids"] == modes[1]["test_ids"]) + _require(_canonical(receipt["test_modes"]) == _canonical(modes)) + return receipt + + +def read_graph_archive(raw_zip: bytes, expected: dict[str, str], source_graph_bytes: bytes) -> dict: + """Compare declared pins and preserve validated original records; perform no I/O.""" + binding = validate_expected(expected) + _require(type(raw_zip) is bytes and 22 <= len(raw_zip) <= RAW_LIMIT) + _require(_sha(raw_zip) == binding["artifact_sha256"]) + source = _source_graph(source_graph_bytes) + members = _members(raw_zip) + _manifest(members) + for name, field in ( + ("checked-commit.txt", "checked_commit"), ("run-id.txt", "run_id"), + ("run-attempt.txt", "run_attempt"), + ): + _require(members[name] == (binding[field] + "\n").encode("ascii")) + _require(members["container-exit-status.txt"] == b"0\n") + _require(members["exporter.stderr"] == b"" and members["exporter.stdout"] == b"/output/generated/graph.json\n") + graph = _graph(members["generated/graph.json"], source) + producer = _receipt(members, binding, _image(members["runtime-image.json"])) + metadata = {"schema_version": 1, "scientific_effect": "NONE", + "scientific_status_authority": False, "custody": "unknown"} + unit = { + **metadata, "graph": graph, + "receipt": { + **metadata, "verification_scope": "declared-native-pins-and-archive-content", + "binding": binding, + "archive": { + "sha256": _sha(raw_zip), "bytes": len(raw_zip), + "members": [{"path": name, "bytes": len(members[name]), "sha256": _sha(members[name])} + for name in sorted(members)], + }, + "graph_member": {"path": "generated/graph.json", "bytes": len(members["generated/graph.json"]), + "sha256": _sha(members["generated/graph.json"])}, + "producer_receipt_sha256": _sha(members["architecture-run-receipt.json"]), + "producer_receipt": producer, + }, + } + _require(len(_encoded(unit)) <= OUTPUT_LIMIT) + return unit diff --git a/architecture/public-artifact-index-bindings.json b/architecture/public-artifact-index-bindings.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/architecture/public-artifact-index-bindings.json @@ -0,0 +1 @@ +[] diff --git a/architecture/public-artifact-index-policy.json b/architecture/public-artifact-index-policy.json new file mode 100644 index 000000000..3dcf1909c --- /dev/null +++ b/architecture/public-artifact-index-policy.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "artifact_ids": [ + "C151-MAIN285-LOG-BINDINGS-20261007-v1", + "C152-MAIN286-FACTUAL-REVIEW-20261007-v1", + "C215-GRAPH-ALIAS-AUDIT-20261008-v1" + ], + "columns": [ + "Artifact ID", + "Title", + "Org", + "Class", + "Status", + "Authority / canonical impact", + "Dependencies or supersession", + "Modified UTC" + ] +} diff --git a/docs/FORMAL_VERIFICATION.md b/docs/FORMAL_VERIFICATION.md index 5cab6781b..19c959454 100644 --- a/docs/FORMAL_VERIFICATION.md +++ b/docs/FORMAL_VERIFICATION.md @@ -6,14 +6,16 @@ Owner directive: Dylan Roy, 27 September 2026. Scientific effect: **NONE**. This dated note is contributor routing only. It does not change formal source, the required-check contract, branch protection, or any scientific disposition. A merge or green check is not theorem acceptance. -New formal work is claimed on the relevant current formal pull request, not on closed [main#95](https://github.com/d6g8k5htny-coder/main/issues/95). Use [main#275](https://github.com/d6g8k5htny-coder/main/issues/275) and [main#307](https://github.com/d6g8k5htny-coder/main/issues/307) for discovery and coordination. Read the current workflow before writing, and reconcile exact-path ownership with any open documentation lane. +New formal work is claimed in the relevant current formal pull request or work discussion, not on closed [main#95](https://github.com/d6g8k5htny-coder/main/issues/95). Work without a pull request uses the relevant work discussion. Use [main#275](https://github.com/d6g8k5htny-coder/main/issues/275) for tasks and claims and [main#307](https://github.com/d6g8k5htny-coder/main/issues/307) for coordination. Read the [current workflow](../governance/OP-WORKFLOW-20260930.md) before writing, and reconcile exact-path ownership with any open documentation lane. Examples of later formal companions, kept distinct from the September scalar pilot: - Landed cap companion: [Math- `frontiers/cap_first_exit_lean_20261002/README.md` at `7d2f62500ad6effba2bbdf6f3b89b0826408dc4a`](https://github.com/d6g8k5htny-coder/Math-/blob/7d2f62500ad6effba2bbdf6f3b89b0826408dc4a/frontiers/cap_first_exit_lean_20261002/README.md) (README blob `4f5e1bf09f3ae7acf8dc60289697f40baecba56c`, as cited by main#286). This is a conditional deterministic formal companion, not kernel evidence for the full probability or persistence-module theorem. - Retained formal interfaces: [Math-#193](https://github.com/d6g8k5htny-coder/Math-/issues/193). -The September pilot history below, including its original source identities and failed hosted build, stays unchanged as historical evidence. +The evidence distinctions in "One proof, several separate questions" below explain the separate questions that formal evidence addresses. The September pilot's origin, implementation, execution snapshot and standing instructions are retained as historical evidence, including their original source identities and failed hosted build. Current execution and enforcement requirements are specified in the [required-check contract](FORMAL_REQUIRED_CHECKS.md). + +**September 2026 origin — original wording:** This extends the existing [formal-ladder work item #95](https://github.com/d6g8k5htny-coder/main/issues/95). It does not renumber that ladder, replace the scientific-status authority, or retroactively describe reviewed informal proofs as formal proofs. @@ -41,6 +43,8 @@ The first hosted build exposed three compilation defects. Original source bytes ## Gate and trust boundary +*September 2026 pilot execution snapshot. The counts below are historical; current enforcement is specified in the [required-check contract](FORMAL_REQUIRED_CHECKS.md).* + The source-only gate checks hashes and inventory; it is not a Lean run. Execution additionally performs a fresh local-package build, `leanchecker`, complete `#print axioms` reports, elaborated-type capture and five real negative controls. `sorryAx`, custom axioms and native-computation axioms are rejected; the only allowed foundational axioms are `propext`, `Classical.choice` and `Quot.sound`. Actual installed dependency commits are compared with the lock. Missing evidence fails closed. The controls include false fold and power inequalities, a `sorry` proof, an indirect custom axiom and a native-computation proof. The Python gate has 38 tests in both normal and optimized mode. A receipt is emitted only after the execution checks succeed, and identifies the exact Git commit, environment, manifest, logs and results. Treat a caller-supplied JSON receipt as untrusted until matched to the actual trusted workflow. @@ -49,7 +53,7 @@ The controls include false fold and power inequalities, a `sorry` proof, an indi ## Historical standing instructions (September 2026 pilot) -The following offer table is retained as the September pilot record. It is not the current claim route. Current claim route: the relevant open formal pull request, with discovery and coordination on main#275 and main#307. Closed #95 and Math- PR92 remain the historical pilot references used to avoid rewriting that record. +The following offer table is retained as the September pilot record. It is not the current claim route. Current claim route: the relevant current formal pull request or work discussion, with tasks and claims on main#275 and coordination on main#419 (successor to main#307). Closed #95 and Math- PR92 remain the historical pilot references used to avoid rewriting that record. Use #95 and PR92 to claim work and avoid duplicate writers. The OpenAI implementation author does not supply independent review credit. Read the exact head before reviewing; changed source, scope or dependencies invalidate the prior alignment record. diff --git a/docs/PUBLIC_MATHEMATICS.md b/docs/PUBLIC_MATHEMATICS.md index bb56823d2..46374a25e 100644 --- a/docs/PUBLIC_MATHEMATICS.md +++ b/docs/PUBLIC_MATHEMATICS.md @@ -42,7 +42,7 @@ The [original P15-B localization proof](https://github.com/d6g8k5htny-coder/main The catalog contains **2,138 public files**: 54 from Math at `1e1114f5eb8ef8cdbcde591bf74126274c250f88` and 2,084 from the main research branch at `7caac254cbba5f513b2dc0afb56b78a598bc0c93`. Each entry binds a full public file by commit, path, byte count, Git blob, and SHA-256. The same mathematical text may have several retained historical versions; this count is files, not distinct theorems. -Coverage is explicit: all `.md`, `.txt`, `.tex`, `.pdf`, `.ipynb`, and `.lean` files in the declared mathematical source roots, including legacy proof/review reading copies. The [machine-readable inventory](public-math/sources.json) records the exact selection rules. Private, personal, vault, and quarantine material is outside this catalog. Research governance and operational context within the declared public source roots is retained alongside the mathematical texts. Code and binary replay packages remain available through the linked full research trees. This is not an assertion that every Drive item or every historical branch has been recovered. +Coverage is explicit: all `.md`, `.txt`, `.tex`, `.pdf`, `.ipynb`, and `.lean` files in the declared mathematical source roots, including legacy proof/review reading copies. The [machine-readable inventory](public-math/sources.json) (folder index: [public source catalog](public-math/README.md)) records the exact selection rules. Private, personal, vault, and quarantine material is outside this catalog. Research governance and operational context within the declared public source roots is retained alongside the mathematical texts. Code and binary replay packages remain available through the linked full research trees. This is not an assertion that every Drive item or every historical branch has been recovered. | Inventory page | Files | First source | Last source | |---|---:|---|---| @@ -72,7 +72,7 @@ Coverage is explicit: all `.md`, `.txt`, `.tex`, `.pdf`, `.ipynb`, and `.lean` f - Fixed-remote and moving-cutoff witness pairs: the [fixed-remote collision source](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/frontiers/remote_collision_20260928/PROOF.md) and [off-pin second-moment review](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/reviews/d5_offpin_second_moment_20260928/REVIEW.md) supply the scoped `O(r^5)` window factorial estimate. The [planar moving-cutoff successor](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/frontiers/moving_remote_collision_20261003/README.md) gives the source-conditional `C r^5 rho^(-98) |E|` bound with both witnesses outside the pin ball, fixed torus, compact positive gaps, all frames and the between-pin window. Mixed inner/outer pairs, elder or barcode identification, small-gap uniformity and higher dimensions are outside that successor's scope. - Shrinking witness collisions and register execution: **reviewed source results are available; register reconciliation and execution remain separate**. The [count-level discharge](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/reviews/c6_witness_collision_reconciliation_20260929/RECONCILIATION.md) ([merged Math #160](https://github.com/d6g8k5htny-coder/Math-/pull/160)) and [leading-mass localization record](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/reviews/c6_residual_closure_20260930/RECONCILIATION.md) ([merged Math #173](https://github.com/d6g8k5htny-coder/Math-/pull/173)) retain their source-conditional fixed-dimension, fixed-torus, compact-mark window scopes and review exposure. Their declarative records do not execute the register transitions: `math.rn-region.witness-collision` is still `OPEN_ACTIVE` in the [checked graph](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/frontiers/downstream_gate_20260925/GRAPH.json). No register node is closed by this reading route. -Use [current coordination, main #307](https://github.com/d6g8k5htny-coder/main/issues/307), and [tasks and claims, main #275](https://github.com/d6g8k5htny-coder/main/issues/275), for work assignments. The [closed downstream discussion, main #86](https://github.com/d6g8k5htny-coder/main/issues/86), remains an evidence trail. +Use [current coordination, main #419](https://github.com/d6g8k5htny-coder/main/issues/419) (successor to [#307](https://github.com/d6g8k5htny-coder/main/issues/307)), and [tasks and claims, main #275](https://github.com/d6g8k5htny-coder/main/issues/275), for work assignments. The [closed downstream discussion, main #86](https://github.com/d6g8k5htny-coder/main/issues/86), remains an evidence trail. New work appears first on public branches and pull requests: [main proposals](https://github.com/d6g8k5htny-coder/main/pulls) and [Math proposals](https://github.com/d6g8k5htny-coder/Math-/pulls). The frozen inventory does not imply that these newer sources are absent. Future integrations should add full-text links and preserve superseded proofs, errata, and reviews. diff --git a/docs/REPRODUCE.md b/docs/REPRODUCE.md index 715f18d7a..6eb1c2728 100644 --- a/docs/REPRODUCE.md +++ b/docs/REPRODUCE.md @@ -78,10 +78,12 @@ From the common parent directory, choose new destination directories: ```sh git clone --single-branch --branch main https://github.com/d6g8k5htny-coder/Math-.git Math- +# legacy hardening tree (frozen); pin to its last merge git clone --single-branch --branch chatgpt/drive-github-hardening-20260919 https://github.com/d6g8k5htny-coder/main.git research +git -C research checkout a01c72f1937875b94bfd78e183a6dbbdb2b04da4 ``` -The named branch tracks its current tip. To inspect one work item using that +The checkout is pinned to the frozen tip `a01c72f1`. To inspect one work item using that checkout's existing dispatcher: ```sh @@ -268,7 +270,7 @@ This bounded readback does not crawl every external URL, inspect private sandbox ## Legacy numerical work -Use the [legacy execution guide](https://github.com/d6g8k5htny-coder/main/blob/chatgpt/drive-github-hardening-20260919/docs/RESEARCH_EXECUTION.md) in the hardening checkout. Its RN/24-jet sources, commands and predicates remain separate. Do not apply a main-cut patch onto that different tree or present navigation CI as full research CI. +Use the [legacy execution guide](https://github.com/d6g8k5htny-coder/main/blob/a01c72f1937875b94bfd78e183a6dbbdb2b04da4/docs/RESEARCH_EXECUTION.md) (pinned at `a01c72f1`) in the hardening checkout. Its RN/24-jet sources, commands and predicates remain separate. Do not apply a main-cut patch onto that different tree or present navigation CI as full research CI. ## Interpret the evidence diff --git a/docs/RESEARCH_INDEX.md b/docs/RESEARCH_INDEX.md index eb8b1f307..2ad724ac1 100644 --- a/docs/RESEARCH_INDEX.md +++ b/docs/RESEARCH_INDEX.md @@ -30,7 +30,7 @@ The [public-text catalog](PUBLIC_MATHEMATICS.md) counts 2,138 files at its decla |---|---| | Read or extend mathematics | The topic sections below and [Math-](https://github.com/d6g8k5htny-coder/Math-) | | Run a calculation | [Reproduction guide](REPRODUCE.md) | -| Review or claim work | [Task queue and claims, main #275](https://github.com/d6g8k5htny-coder/main/issues/275), the [Agent Message Board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307), and the relevant issue or PR; [Open work](#open-work) gives each front's current records and remaining obligations | +| Review or claim work | The [active Agent Message Board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419) for new claims and coordination; [task and architecture discussion, main #275](https://github.com/d6g8k5htny-coder/main/issues/275) and the relevant issue or PR for task context; historical boards [#307](https://github.com/d6g8k5htny-coder/main/issues/307) and [#229](https://github.com/d6g8k5htny-coder/main/issues/229) for earlier records. [Open work](#open-work) gives each front's current records and remaining obligations | | Locate exact source bytes | [Catalog](https://github.com/d6g8k5htny-coder/meta-framework/blob/main/registry.json) and [query tool](https://github.com/d6g8k5htny-coder/query-) | | Work on the larger numerical tree | [Hardening branch](https://github.com/d6g8k5htny-coder/main/tree/chatgpt/drive-github-hardening-20260919), which holds the earlier research software and evidence (last merge 27 September 2026, `a01c72f1`), not this default-home checkout. Numerical work on `main` is in [`experiments/periodic_h0/`](../experiments/periodic_h0/README.md) and [`experiments/universality/`](../experiments/universality/README.md) | | Explore zeta zeros, de Bruijn–Newman folds and a CUE short-bar control | [Zeta fold exploration packet](../experiments/zeta_fold_exploration/README.md): exploratory, scientific effect NONE, no claim of progress toward the Riemann Hypothesis | @@ -118,7 +118,7 @@ Still open: arbitrary downsets and the unrestricted prize; overlap patterns outs ## Open work -Each row gives a front's current label and what remains open; the topic sections hold scopes and review details. Claim tasks on [main #275](https://github.com/d6g8k5htny-coder/main/issues/275) and coordinate on the [Agent Message Board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307); the earlier board [#229](https://github.com/d6g8k5htny-coder/main/issues/229) keeps its [working guidance](https://github.com/d6g8k5htny-coder/main/issues/229#issuecomment-6038554880). The review discussions #63, #65, #67, #74 and #76, the downstream-first queue [#86](https://github.com/d6g8k5htny-coder/main/issues/86) and formal work item [#95](https://github.com/d6g8k5htny-coder/main/issues/95) are closed records, not open assignments; a closed issue does not by itself complete its mathematics. A review record does not by itself change the Math- [register](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/frontiers/downstream_gate_20260925/GRAPH.json), which is executed separately and may still show an earlier classification. +Each row gives a front's current label and what remains open; the topic sections hold scopes and review details. Discuss tasks and architecture on [main #275](https://github.com/d6g8k5htny-coder/main/issues/275); post new claims, reviews, handoffs and releases on the [active Agent Message Board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419), linking the relevant issue or PR; the earlier boards [#307](https://github.com/d6g8k5htny-coder/main/issues/307) and [#229](https://github.com/d6g8k5htny-coder/main/issues/229) remain readable history, with #229 retaining its [working guidance](https://github.com/d6g8k5htny-coder/main/issues/229#issuecomment-6038554880). The review discussions #63, #65, #67, #74 and #76, the downstream-first queue [#86](https://github.com/d6g8k5htny-coder/main/issues/86) and formal work item [#95](https://github.com/d6g8k5htny-coder/main/issues/95) are closed records, not open assignments; a closed issue does not by itself complete its mathematics. A review record does not by itself change the Math- [register](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/frontiers/downstream_gate_20260925/GRAPH.json), which is executed separately and may still show an earlier classification. | Front | Current state and remaining work | Records | |---|---|---| @@ -132,7 +132,7 @@ Each row gives a front's current label and what remains open; the topic sections | P15 | Theorem F, the full-range price theorem (OpenAI author), has an xAI/Grok nonauthor ACCEPT, reconciled on #74 for the realized disjoint family with demands `d_i >= 2`, every independent probability, `c_v <= phi(p_v)` and the same palette. The bipartite-overlap/even-capacity and tail/weighted-load successors (OpenAI authors) have an Anthropic/Claude scoped ACCEPT and landed through [Math- #124](https://github.com/d6g8k5htny-coder/Math-/pull/124). Open: arbitrary downsets and any unrestricted prize statement; demand one remains an obstruction | [Full-price review](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/reviews/p15_full_price_nonauthor_20260926/REVIEW.md), [overlap/tail review](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/reviews/p15_overlap_tail_claude_20260928/REVIEW.md), [integration record](https://github.com/d6g8k5htny-coder/Math-/blob/79cb314d5b9f6b8b410bfd0df200414314f6b8c7/docs/integration/2026-09-28-reviewed-mathematics.md), [#74](https://github.com/d6g8k5htny-coder/main/issues/74), [#67](https://github.com/d6g8k5htny-coder/main/issues/67) (closed review discussions) | | Formalization (Layer 1) | Independent alignment review of the 13 Math- pilot targets and the 31 main-side SIDE24 targets (cross-provider); the remaining "Numerical formalizer" steps — exact `c_{d,ref}` definition and a proof-producing enclosure — in the Mathlib package; D6 Theorem F's constant `ρ*` as the next full-theorem target | [Guide](FORMAL_VERIFICATION.md), [work item #95](https://github.com/d6g8k5htny-coder/main/issues/95), [Formal README](../formal/README.md), [review lane](../formal/REVIEW_LANE.md), [rollout record](FORMAL_VERIFICATION_ROLLOUT_20260927.md) | -Check current claims on #275 and #307 before writing, and release completed work. Offered reviews are not accepted tasks or evidence of active agents. This table routes to source and review records; it is not a status register. +Before writing, check current claims on [active board #419](https://github.com/d6g8k5htny-coder/main/issues/419) and the relevant issue or PR, including unresolved claims in existing task records and on earlier boards [#307](https://github.com/d6g8k5htny-coder/main/issues/307) and [#229](https://github.com/d6g8k5htny-coder/main/issues/229), or their explicit successor pointers. Moving the board does not transfer, renew or release any existing claim. Release completed work. Offered reviews are not accepted tasks or evidence of active agents. This table routes to source and review records; it is not a status register. The [discovery / priority ledger](DISCOVERY_PRIORITY_LEDGER_20260925.md) and its [reconnaissance memo](RECON_NOVELTY_20260925.md) record candidate contributions, nearest prior art and source bindings. They are novelty bookkeeping, not status; "apparently novel" is not "accepted". The ledger's "current state" cells were last aligned on 27 September 2026, with `STATUS.md` of 26 September; the rows above give later records. diff --git a/docs/WORKSPACE.md b/docs/WORKSPACE.md index 475b8b2d7..8338c0ff1 100644 --- a/docs/WORKSPACE.md +++ b/docs/WORKSPACE.md @@ -19,7 +19,7 @@ the last an exploratory packet whose scientific effect is NONE, which makes no claim of progress toward the Riemann Hypothesis and whose independent numerical reproduction (review slice C) is open. None of the three reports a held-out confirmation run; each README states its own scope. Two older branches remain -readable context. The [hardening research branch](https://github.com/d6g8k5htny-coder/main/tree/chatgpt/drive-github-hardening-20260919) +readable context. The legacy [hardening research branch](https://github.com/d6g8k5htny-coder/main/tree/a01c72f1937875b94bfd78e183a6dbbdb2b04da4) (`chatgpt/drive-github-hardening-20260919`, frozen; pinned tip `a01c72f1`) holds the earlier research software and evidence; its last merge was on 27 September 2026 (`a01c72f1`). The [Claude migration branch](https://github.com/d6g8k5htny-coder/main/tree/claude/drive-audit-github-migration-rrglpp) @@ -35,7 +35,7 @@ not an instruction to repeat a completed review. Use [pull requests](https://github.com/d6g8k5htny-coder/main/pulls) and [Actions](https://github.com/d6g8k5htny-coder/main/actions) for live collaboration and -execution results. The [research execution guide](https://github.com/d6g8k5htny-coder/main/blob/chatgpt/drive-github-hardening-20260919/docs/RESEARCH_EXECUTION.md) +execution results. The legacy [research execution guide](https://github.com/d6g8k5htny-coder/main/blob/a01c72f1937875b94bfd78e183a6dbbdb2b04da4/docs/RESEARCH_EXECUTION.md) (pinned at `a01c72f1`) describes the research-side commands; read it in the checkout actually being used; it describes the hardening branch. The experiments on `main` are described in [experiments/periodic_h0/README.md](../experiments/periodic_h0/README.md), @@ -108,7 +108,7 @@ git rev-parse HEAD ``` To inspect the older hardening software (last merge 27 September 2026), add -`--single-branch --branch chatgpt/drive-github-hardening-20260919`. +`--single-branch --branch chatgpt/drive-github-hardening-20260919`, then `git checkout a01c72f1937875b94bfd78e183a6dbbdb2b04da4` to read the pinned legacy tip. Current numerical work on `main` is in `experiments/periodic_h0/`, `experiments/universality/`, and `experiments/zeta_fold_exploration/`. Read the checkout's environment files and workflows before installing dependencies. This session prefers project-local environments, identifiable upstream sources, and diff --git a/docs/agents/LEAN_AUDIT_OWNER.md b/docs/agents/LEAN_AUDIT_OWNER.md index 981b505f8..9ebda3f85 100644 --- a/docs/agents/LEAN_AUDIT_OWNER.md +++ b/docs/agents/LEAN_AUDIT_OWNER.md @@ -39,16 +39,16 @@ branches. The new auditor does not acquire Claude's or Sol's writer/integrator claims merely by accepting this role. Before any branch mutation, reconcile live claims and obtain a scoped handoff, release, or confirmed lease expiry followed by fresh refs and results. Record a precise bounded claim in the relevant PR or -active [Agent Message Board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307). +active [Agent Message Board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419). The auditor can review disjoint scope without changing the writer's branch. If it amends a proof, it becomes a contributor to that proof and cannot supply its own nonauthor acceptance. UI/navigation, scientific registers, prizes, `lemma_closed`, controlling graph verdicts and the active C127 research lane are outside this role's write scope. Current coordination is kept on the active -[Agent Message Board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307), -while the historical [main #229](https://github.com/d6g8k5htny-coder/main/issues/229) -remains preserved as the archival issue record. +[Agent Message Board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419), while [main #307](https://github.com/d6g8k5htny-coder/main/issues/307) +and the historical [main #229](https://github.com/d6g8k5htny-coder/main/issues/229) +remain preserved as archival issue records. ## Snapshot and evidence vocabulary diff --git a/docs/agents/UI_UX_OWNER.md b/docs/agents/UI_UX_OWNER.md index d40852345..5b807d36c 100644 --- a/docs/agents/UI_UX_OWNER.md +++ b/docs/agents/UI_UX_OWNER.md @@ -70,7 +70,7 @@ The dedicated agent coordinates public-site authored HTML/CSS/modules and applic Coordinate Home/Research navigation and index content with `next_ui_triage` / session `01a0efe9`, retaining its source/dependency scopes. The [C124 claim5974918396](https://github.com/d6g8k5htny-coder/main/issues/229#issuecomment-5974918396) and its completed release establish the current completed navigation slice only. The [retained Library/equation coordination5971960564](https://github.com/d6g8k5htny-coder/main/pull/247#issuecomment-5971960564) is not transferred by this UI role; any later pickup needs fresh native reconciliation and concrete handoff. The historical unidentified C114/WE701 closeout is separate: do not fabricate identity continuity, infer another lane's release or renew the expired claim. -Before every write, read live branch refs, current claims, delivered artifacts and pending results in the relevant existing PR or the active [Agent Message Board, main #307](https://github.com/d6g8k5htny-coder/main/issues/307). Claim only precise paths, immutable inputs, intended branch/integration owner and a finite lease (normally 120 minutes); link an R17 claim only when that task uses R17. Reconcile confirmed lease expiry against fresh execution/results. An assignment, silence or stale ledger is not an acknowledgment or completed review. Competing mutations stop the affected write for reconciliation. Use isolated branches and non-force updates; the named integration owner refreshes, reviews readiness and merges under a fresh expected-head guard. Release the completed scope through the existing coordination record, without creating another global ownership register. +Before every write, read live branch refs, current claims, delivered artifacts and pending results in the relevant existing PR or the active [Agent Message Board, main #419](https://github.com/d6g8k5htny-coder/main/issues/419). Claim only precise paths, immutable inputs, intended branch/integration owner and a finite lease (normally 120 minutes); link an R17 claim only when that task uses R17. Reconcile confirmed lease expiry against fresh execution/results. An assignment, silence or stale ledger is not an acknowledgment or completed review. Competing mutations stop the affected write for reconciliation. Use isolated branches and non-force updates; the named integration owner refreshes, reviews readiness and merges under a fresh expected-head guard. Release the completed scope through the existing coordination record, without creating another global ownership register. Scientific source/proof bodies, graph/status classifications, inventory/equation payloads, acceptance flags and Lean proof/alignment work are outside this handoff's write scope. A UI worker may identify discrepancies and offer exact source-bound findings to the owner of those surfaces. diff --git a/docs/plans/2026-10-08-architecture-interface.md b/docs/plans/2026-10-08-architecture-interface.md new file mode 100644 index 000000000..aad7b7d2f --- /dev/null +++ b/docs/plans/2026-10-08-architecture-interface.md @@ -0,0 +1,99 @@ +# Architecture Interface and Canvas Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Publish an additive Astro reader of pinned graph and explicitly public evidence inputs, with source-bound cubic and finite elder teaching views and a verifiable immutable build identity. + +**Architecture:** A trusted capture/projection stage produces a public-only input bundle. A hosted offline static build consumes that bundle once; browser tests and publication consume the same assembled output artifact. Original graph and native evidence records retain their distinct scope and authority; the reader is a derived view. + +**Tech Stack:** Stdlib Python capture/projection controls; exact Astro/Node/npm candidates and lockfile after hosted verification; vanilla ES modules and Canvas; existing hosted Chrome tooling; GitHub Pages. + +**Spec:** [Research architecture design, sections 1/4 and 7](../superpowers/specs/2026-10-08-research-architecture-design.md); [global implementation plan, Tasks 3 and 7](../superpowers/plans/2026-10-08-research-architecture-plan.md); [evidence adapter contract](2026-10-08-architecture-evidence-adapter.md). + +## Global Constraints + +- Scientific effect is always `NONE`; scientific status authority is exact boolean `false`. Build success, recorded review, source-relative consistency and teaching output do not promote science. +- Preserve source, review, kernel, computation and alignment as five separate axes. Preserve original classifications, records, qualifiers and unknown/stale/unavailable states. The stdin evidence adapter's custody remains `unknown`; the reader cannot convert its `current` applicability into authenticated kernel verification or declaration existence. +- The public graph may display all 49 currently pinned nodes without any guessed Artifact Index or Lean join. Artifact/node/teaching joins require exact reviewed IDs and roles; absence remains unresolved. +- Keep the complete private Artifact Index/source capture outside the public repository and publication bundle. Publish only explicitly allowed rows and columns. No private original packet, raw table, credential or unlisted field is copied into generated assets, logs or failure artifacts. +- Root retained the actual R17 Artifact Index capture and froze its observed metadata, column names, record schema, size limits and public projection boundary in the first-unit contract. Synthetic TEST fixtures exercise that boundary; they do not substitute for the retained real capture or actual public projection delivery. +- Root owns the isolated interface branch and the precise first-unit and runtime-preparation paths recorded in the pickup and amendment. Tests precede implementation, with hosted RED required before product authoring. The earlier source-only checkpoint is superseded operationally by this scoped execution claim. Standing owner authorization creates no additional user-permission checkpoint. +- No project execution or installation on the laptop. Preparation, RED/GREEN, two clean builds and browser execution occur in disposable hosted environments; network is denied during the actual build/test stage. +- PR #317 owns shared site/brand styles, release-key changes and the existing browser harness/tests. Existing `docs/site` generators and release inventory stay owner-controlled until reconciliation after that PR lands. Root currently owns the architecture producer/required-check workflows. +- New public routes use `/main/reader/`. Preserve the complete existing `/docs` publication namespace and `/main/site/*.html` routes. Pages Actions migration and navigation integration require explicit technical coordination with those owners, not renewed owner permission. +- True 500-token retrieval, lease services, routing and broader execution migration remain separate increments. All eight original requirements remain active until their actual end-to-end completion evidence exists. + +## Review Focus + +- A public-column whitelist applied after serializing the full private capture still leaks data; Task 1 must prove private canaries never enter any output or retained failure artifact. +- Matching caller-provided digests do not establish archive custody; Task 1 must bind original ZIP bytes to the native producer outputs and reject contradictory/stale archive identities. +- Generated graph schema differs from the old source viewer schema; Task 2 must consume the exporter directly without inventing `terminal_classifications` or other missing semantics. +- A disjoint-set parent is not the mathematical elder, and neutral events are not deaths; Task 3 must independently verify those distinctions and interval endpoints. +- A green build rebuilt during deployment can publish different inputs; Task 4 must deploy and read back the exact tested output artifact while preserving legacy URLs. + +--- + +## Task 1: Private capture, public projection and native graph custody + +**Create:** `architecture/artifact_index.py`, `tools/artifact_index_export.py`, `tools/interface_artifact_readback.py`, `tools/interface_build_inputs.py`, `tests/test_architecture_artifact_index.py`, `tests/test_interface_artifact_readback.py`, `tests/test_interface_build_inputs.py`. + +**Interfaces:** `project_artifact_index(packet, expected) -> public_projection` follows the [frozen first-unit contract](2026-10-08-artifact-index-contract.md). The packet carries the native capture, explicit public policy, exact bindings and graph-node inventory; `expected` carries five independently supplied identities. The first CLI reads one packet from stdin and writes one admitted canonical public JSON object to stdout. It opens no caller-selected files, performs no network access, and uses the exact opaque refusal line `ARTIFACT_INDEX_REFUSED` on stderr. Policy selects explicit stable artifact IDs and the fixed eight public columns; bindings contain exactly `{node_id, artifact_id, roles}`. Roles are explicit source/review/kernel/computation/alignment/teaching-source associations, never acceptance. A later separately tested trusted collector reads the retained outside-repository private capture and writes the admitted stdout projection to `public-index.json`; its file and archive custody is outside this first CLI unit. + +`interface_artifact_readback.py` consumes a previously downloaded original ZIP plus expected native repository/checked-commit/run/attempt/artifact-ID/name/archive-digest/host-receipt-digest arguments. Expectations come from the current trusted producer job, not ZIP members. It produces a bounded regular-file staging directory and an original-byte readback receipt. `interface_build_inputs.py` consumes that staged graph, public projection, allowed evidence/teaching/brand inputs and renderer identities and emits the public bundle below. + +- [ ] Root freezes the real capture's metadata and parser ABI, exact public row/column allowlist, explicit ID joins, positive public fixture and refusal fixture. Preserve the full private capture in its existing private evidence location; record only its identity/digest publicly when allowed. +- [ ] Write external CLI controls: valid public projection; absent mapping leaves unresolved; unknown/duplicate IDs and contradictory joins refuse; unlisted columns/rows and private canaries remain absent from all public outputs and failure artifacts; mutable references stay labeled; raw capture/policy/binding hash changes refuse. Observe hosted RED before implementation. +- [ ] Write custody controls: native archive identity/digest mismatch; wrong attempt/checked commit/receipt; duplicate ZIP members; absolute/traversing paths; symlink/special members; expanded-size limits; changed graph member; failed or missing producer evidence. Preserve original failure evidence without producing an accepted input bundle. +- [ ] Implement format-specific projection and archive verification without fetching caller-selected paths/URLs or executing captured code. Validate generated graph's exact seven-key schema and source identity, and match its raw hash to the original host receipt. Keep its dated Math source commit separate from the current executing main commit. +- [ ] Run hosted normal/optimized Python controls, inspect public/failure artifacts for the private canaries, and obtain nonauthor source/custody review. Freeze this unit through root before the renderer consumes it. + +**Public bundle boundary:** `inputs.json` has schema version, exact non-scientific fields, checked repository/commit, graph producer binding and raw graph/receipt identities, public index capture/projection/policy/binding identities, public evidence projection identity, teaching/brand file identities, renderer source/lockfile/runtime identities. Each member is an explicitly listed regular file with byte count and SHA-256. The exact public-index record fields are frozen in the first-unit contract before test/code authoring. The full private capture and evidence adapter `original_packet` are never bundle members. + +## Task 2: Offline Astro proof pages and immutable build receipt + +**Create:** `interface/package.json`, `interface/package-lock.json`, `interface/astro.config.mjs`, `interface/src/lib/load-inputs.mjs`, `interface/src/layouts/Reader.astro`, `interface/src/components/EvidenceDimensions.astro`, `interface/src/components/DependencyTable.astro`, `interface/src/pages/index.astro`, `interface/src/pages/nodes/[id].astro`, `interface/tests/inputs.test.mjs`, `interface/tests/pages.test.mjs`, `tools/interface_build_receipt.py`, `tests/test_interface_build_receipt.py`, `.github/workflows/research-interface.yml`. + +**Interfaces:** `loadPublicInputs(inputDirectory, expectedManifestSha256) -> admittedInputs` reads only the already admitted public bundle; it performs no network fetch. `nodePageData(nodeId, admittedInputs) -> pageData` retains exact original node/edge data and explicitly joined evidence, including unresolved joins. `interface_build_receipt.py` binds the identity core and complete sorted output-file inventory. + +- [ ] In a root-owned trusted hosted preparation stage, verify candidates Astro `7.3.8`, Node `24.21.0` and npm `11.19.0`; retain exact package/runtime bytes and identities, install from a committed integrity-bearing lockfile, and test compatibility. These versions were observed during reconnaissance and are candidates until preparation verifies them. Use no new theme, external fonts, client framework or graph library in this bounded unit. +- [ ] Write controls for missing/tampered bundle members, duplicate/nonfinite/incorrectly typed JSON, mixed build inputs, escaped IDs/URLs, unknown roles, all graph nodes without joins, unavailable evidence and native metadata preservation. Observe hosted RED; a setup/import failure or zero discovery is not RED evidence. +- [ ] Implement static routes with `site: 'https://d6g8k5htny-coder.github.io'`, `base: '/main/reader'`, `output: 'static'`, and `build.inlineStylesheets: 'never'`. Keep scripts/styles as local external assets under the existing self-only CSP. Reuse an owner-approved, byte-pinned brand capture without modifying shared brand/release files. +- [ ] Render an accessible dependency table/view and one page per exact graph ID. Display original classification as a recorded source label; render all five evidence axes independently with custody and as-of identity. Escape retained text; never execute embedded HTML/code or synthesize formal mappings from titles/classifications. +- [ ] Define `build_id = SHA256(canonical identity_core)` binding checked commit, graph/projection/evidence/teaching/brand input hashes, source tree, lockfile and runtime identity. Exclude the build ID itself and fresh wall-clock timestamps. Emit `build-receipt.json` with that identity and sorted output path/byte/SHA inventory; external archive identity binds the receipt itself. Every page links to its build receipt. +- [ ] From two clean hosted work directories, with network denied and identical admitted inputs, run `npm ci --offline` then `npm run build` using the prepared dependency cache. Compare complete output membership and bytes; require identical build IDs and no private canary. Retain both manifests/logs and the single tested output archive. Review source and byte identities before freezing. + +## Task 3: Source-bound cubic and finite elder Canvas views + +**Create:** `interface/src/pages/teach/cubic.astro`, `interface/src/pages/teach/elder.astro`, `interface/src/scripts/cubic-model.mjs`, `interface/src/scripts/elder-model.mjs`, `interface/src/scripts/canvas-reader.mjs`, `interface/tests/cubic.test.mjs`, `interface/tests/elder.test.mjs`, `interface/tests/reader-controls.test.mjs`. Public teaching fixtures enter only through Task 1's explicit source policy. + +**Interfaces:** `cubicModel({r, k, b}) -> scales` implements the pinned educational `gap = k*r^3` definition. `finiteElderTrace({values, n, scale}) -> trace` returns finite-filtration threshold/component/elder/merge/neutral events and positive/zero/essential intervals. `renderTeachingView(host, admittedTeachingData)` connects the same data to Canvas and equivalent DOM tables/controls. Source-node links exist only through explicit admitted mappings. + +- [ ] Pin source bytes for the current cubic definition and `experiments/periodic_h0/{EXACT_H0.md,exact_h0.py,test_exact_h0.py}`. Keep their finite/educational scope and source dates visible. No synthetic source identity, continuum sample, Lean declaration or source-to-component certificate is invented. +- [ ] Write independent controls for positive cubic scales, halving `r` dividing gap by eight, normalization and nonrepresentable/invalid values. Write finite elder controls for `[5,1,4,2,3,0]` repeated six times: positive pairs `[[3,2],[4,1]]`, essential birth `5`, zero count `33`; plateau ties prefer the smaller row-major vertex ID. Include periodic seam and no-diagonal controls and a BFS connectivity oracle distinct from the sweep. +- [ ] Pin superlevel `(d/S,b/S]`, lifetime `(b-d)/S`, zero pairs excluded from the positive diagram, essential class separate, and no longest finite bar removal. Test that disjoint-set parents cannot overrule mathematical elders and same-class edges create neutral events rather than deaths. Missing mappings/certificates render unresolved, never a positive source claim. Observe hosted RED before implementing. +- [ ] Implement exact model/event data separately from approximate drawing coordinates. Label the cubic arithmetic as teaching; label the elder scene as a specified finite periodic filtration. Keep immediate mathematical merge relation, global class equality, essential bars and finite conventions distinct from data-structure pointers. +- [ ] Implement keyboard-operable ordinary DOM controls, event/value tables and source disclosures usable without Canvas. Respect reduced motion; avoid mandatory animation. Source absence/tamper leaves readable unavailable state with no inferred result. Run model and DOM controls hosted and obtain mathematical-scope/source review. + +## Task 4: Browser verification, existing namespace preservation and exact-artifact deployment + +**Create:** `tools/interface_browser_check.py`, `tests/test_interface_browser_contract.py`; extend only the new `research-interface.yml` under root's claim. **Later coordinated paths:** assembled Pages workflow/configuration and existing navigation/docs; exact modifications follow PR #317 integration and a refreshed owner claim. + +**Interfaces:** The browser harness serves Task 2/3's assembled artifact, not a fresh build. Publication consumes the same artifact ID/digest and build receipt accepted by tests. The assembled Pages root includes the complete verified existing `/docs` namespace plus the additive `reader/` subtree. + +- [ ] Test the actual built pages in hosted Chrome at desktop/mobile widths, light/dark schemes, keyboard-only interaction, reduced motion, Canvas unavailable, source/index refusal and no-JavaScript DOM fallback. Check graph-node routes, five-axis qualifiers, focus/overflow and source/build identities; retain exact runtime/report/screenshots and failures. Existing PR #317 browser findings remain separate work to reconcile. +- [ ] Freeze a preservation manifest for every legacy `/docs` file/route from the actual integrated source. Assemble that namespace unchanged with the new reader. Detect output collisions and missing legacy routes before publication; exercise existing reader links and release checks under their owner-controlled hosted lane. +- [ ] After PR #317 and current producer scopes are reconciled, root claims the precise navigation and Pages migration paths. Switch to GitHub Actions publication only through available authorized administration capability and retained readback. This is technical integration work, not another owner approval queue. +- [ ] Use reviewed, commit-pinned Pages upload/deploy actions and scoped publication credentials only in the trusted host stage. Deploy the verified assembled artifact; do not rerun Astro, regenerate graph/index data or fetch mutable cloud inputs during deployment. Keep a recoverable prior artifact and source/configuration record. +- [ ] Read back live build receipt, representative graph/source/teaching pages and asset bytes; verify their hashes/build ID and actual reader interactions. Retain native deployment identity and exact source-bound receipts in existing governance surfaces. Mark this increment deployed only after that evidence exists. + +## Handoff and Completion Boundary + +The initial source-only checkpoint is preserved in the root checkpoint below; its operational wait is superseded by root's retained capture, frozen contract and scoped execution claim. First-unit tests are now authored and under nonauthor review; hosted RED and product implementation remain pending. The build does not authenticate mathematical records, establish unknown declarations, repair missing mappings or complete semantic retrieval. Goals 1 and 7 require tested deployed pages/Canvas; the every-PR producer/SSG join and all remaining original goals retain their explicit incomplete scope until separately verified. + +Primary references: [Astro Pages deployment](https://docs.astro.build/en/guides/deploy/github/), [Astro configuration](https://docs.astro.build/en/reference/configuration-reference/), [Astro package metadata](https://registry.npmjs.org/astro/latest), [Node distribution metadata](https://nodejs.org/dist/index.json), [GitHub publishing-source configuration](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site). Package aliases/docs are mutable research inputs; exact preparation receipts and the committed lockfile govern execution. + +## Root capture and first-unit checkpoint + +The source-only handoff above is the earlier checkpoint. Root now owns the new isolated interface worktree/branch based main879fb4f5 under pickup6070431864, with exact initial path scope published on main307. The actual native formattedValue capture is9273 UTF-8 bytes, SHA25603baf67b92c7b31390fd497431abf120204a6ccbde7d8b00395d1d40288f6ebf, captured22:18:57UTC8October; full private bytes remain outside Git. The [frozen first-unit contract](2026-10-08-artifact-index-contract.md) records its observed12-column header, worksheet200004, three ranges, typed packet, five independent pins and exact public output. The explicit policy selects three dated rows and eight public columns; actual bindings are empty. No title-based graph/Lean join is inferred. + +The first CLI is stdout-only with stdin private bytes and fixed refusal codes. A later trusted collector writes its admitted public JSON to the bundle; that later wrapper's filesystem/archive custody is separate work. External tests use synthetic TEST capture data and private canaries and precede implementation. Hosted absent-CLI RED, implementation, normal/optimized GREEN and nonauthor privacy review remain pending. Existing namespace, Astro/model/browser and exact-artifact deployment work remains unchanged in scope and unfinished. diff --git a/docs/plans/2026-10-08-artifact-index-contract.md b/docs/plans/2026-10-08-artifact-index-contract.md new file mode 100644 index 000000000..c1e95087a --- /dev/null +++ b/docs/plans/2026-10-08-artifact-index-contract.md @@ -0,0 +1,47 @@ +# Artifact Index public projection v1 contract + +Root owns this new boundary under main307 pickup6070431864 through00:00UTC9October. Base main879fb4f5. This is the first unit of the architecture interface plan. Standing owner authorization applies; no additional permission checkpoint is introduced. Product execution, RED/GREEN and installation occur only in disposable hosted environments. Full private captures stay outside Git and publication. + +## Actual source and public policy + +The real R17 source is spreadsheet `1O6x8ivmaVUxYqKmCOXmToIHpMXqDI362ibqBl8HY8no`, worksheet ID200004, title `Artifact Index`, native12-column formatted-cell representation. The2026-10-08T22:18:57Z response capture is9273 UTF-8 bytes with SHA256 `03baf67b92c7b31390fd497431abf120204a6ccbde7d8b00395d1d40288f6ebf`. This is serialized native API formattedValue data, not raw Sheet-file bytes or an export. It has one sheet and three grid-data ranges: row0 header, rows935–936, and row1000, all starting at column0. Capture ranges are `'Artifact Index'!A1:L1`, `'Artifact Index'!A936:L937`, and `'Artifact Index'!A1001:L1001`, cell_fields `formattedValue`. No native Sheet write is part of this unit. + +Header exact order: Artifact ID; Title; Org; Class; Priority; Topics / object tags; Status; Authority / canonical impact; Dependencies or supersession; Modified UTC; Source; Notes. + +Public column policy exact order: Artifact ID; Title; Org; Class; Status; Authority / canonical impact; Dependencies or supersession; Modified UTC. Only these eight native values may appear in public row fields. Source and Notes are prohibited even under a caller-forged policy; Priority and Topics are excluded. Do not serialize the original capture into any output or failure artifact. The real policy selects only C151-MAIN285-LOG-BINDINGS-20261007-v1, C152-MAIN286-FACTUAL-REVIEW-20261007-v1, C215-GRAPH-ALIAS-AUDIT-20261008-v1. These are dated source records with their original negative/scope/independence labels, not current acceptance. Actual initial bindings are empty because there is no exact verified Artifact Index-to-graph mapping. All49 graph IDs remain unmapped. Synthetic tests use TEST IDs, synthetic spreadsheet IDs, and private canaries distinct from the real source; synthetic fixtures are not delivery evidence. + +## CLI and typed packet + +`python -B -S tools/artifact_index_export.py` reads one strict JSON document from stdin, emits exactly one public JSON document on stdout on success, and exits0. On every refusal, including CLI arguments, it exits nonzero, emits no stdout and exactly the public opaque ASCII constant `ARTIFACT_INDEX_REFUSED` plus one newline on stderr. Private values, base64, cells, paths and exception text cannot appear in diagnostics. It performs no network fetch, URL/path read, imports of captured code or filesystem writes. Module API is `project_artifact_index(packet, expected) -> projection`. The output is a projection, not an authenticated table or current status claim. + +All five independent flags are required exactly once, with lower-case64-hex values: `--expected-capture-sha256`, `--expected-metadata-sha256`, `--expected-policy-sha256`, `--expected-bindings-sha256`, `--expected-graph-nodes-sha256`. No abbreviation or duplicate arguments. Expectations are supplied from trusted root capture/policy inputs, not inferred from stdin. They prove consistency with declared pins only, not external custody. Canonical identity JSON uses sorted object keys, compact separators, ensure_ascii=true and allow_nan=false, preserving typed values and array order. Capture SHA covers exact decoded raw bytes; metadata SHA covers the capture object with only raw_base64 removed; remaining SHA values cover policy, bindings and graph_nodes respectively. + +Packet exact keys: +- schema_version: exact integer1 (bool refuses). +- capture: exactly {capture_id, captured_at, source, raw_base64}. +- policy: exactly {schema_version, artifact_ids, columns}. +- bindings: array of exactly {node_id, artifact_id, roles}. +- graph_nodes: array of explicit node IDs. + +Capture ID is a nonempty ASCII identifier matching `[A-Za-z0-9][A-Za-z0-9_.:-]{0,191}`. captured_at is a valid UTC second timestamp YYYY-MM-DDTHH:MM:SSZ. Source exact keys are {spreadsheet_id, worksheet_id, title, ranges, cell_fields}. spreadsheet_id is a nonempty ASCII identifier of at most192 characters; worksheet_id exact nonnegative integer; title nonempty string, at most256 UTF-8 bytes, no controls; ranges is a unique nonempty list of exact quoted title A-to-L ranges `'TITLE'!A:L`, nonreversed and ordered by starting row; title containing a quote is unsupported. cell_fields must be exactly formattedValue. Native metadata must agree with the declared spreadsheet ID, worksheet ID and title. Metadata is declared as-of, not immutable native revision authentication. + +Stdin limit16MiB, decoded capture limit4MiB, JSON nesting at most64 container levels (a scalar leaf does not add a level), at most4096 nonheader native data rows plus the one header and4096 graph IDs/bindings/policy IDs, each formatted cell at most8192 UTF-8 bytes. Artifact and graph IDs use the same ASCII identifier pattern and192-character bound as capture_id. Reject duplicate object keys, nonfinite numbers, multiple JSON documents, malformed UTF-8/base64/noncanonical base64, booleans used as integers, overflow, empty or unknown envelope fields, and mismatching pins. Unknown native annotations stay private and inert; no unknown native field is projected. + +Native response is an object containing spreadsheetId and one sheet. The sheet properties must identify the declared worksheet/title. Grid properties must declare rowCount positive <=10000000 and columnCount exactly12. Its data list must have exactly one grid block for each declared range in the same order. Missing startRow/startColumn means0; supplied offsets are exact nonnegative integers and must equal the range's0-based position/column0. Every block has exactly its declared number of rowData rows, every row exactly12 values. Each cell is an object; missing formattedValue means empty string, supplied formattedValue must be a string within the bound. Unknown annotations remain inert. Blocks may not overlap and must be inside declared grid bounds. Exactly one row0 contains the exact12-column header; all other rows have a nonempty valid artifact ID, with no duplicate ID even on unselected rows. Nonselected row values and private columns never enter output. Selected IDs must each exist exactly once; unknown/duplicate/invalid policy IDs refuse. + +Policy columns must equal the fixed eight public columns above, in that exact order. Policy schema_version exact1. artifact_ids is a nonempty unique list of valid IDs; its order is preserved for identity hashing but output rows sort by artifact ID. graph_nodes are valid unique IDs. Bindings require known graph ID and selected artifact ID. Roles are a nonempty unique list drawn from source, review, kernel, computation, alignment, teaching-source; no inferred acceptance or title join. Duplicate node/artifact pairs refuse, even with different roles. Explicit valid bindings sort by node_id, artifact_id; their roles sort lexically. Unknown mappings refuse; absent mappings remain unmapped. + +## Exact public output + +Projection exact root fields: +`{schema_version:1,scientific_effect:"NONE",scientific_status_authority:false,custody:"unknown",source,identities,columns,rows,bindings,unmapped_nodes}`. + +source exactly `{capture_id,captured_at,spreadsheet_id,worksheet_id,worksheet_title,ranges,cell_fields,representation:"native-api-formattedValue-json"}`; preserve declared metadata/range order only. It contains no source URL, original packet, native annotations or raw capture bytes. identities exactly `{capture_sha256,metadata_sha256,policy_sha256,bindings_sha256,graph_nodes_sha256}`, matching the independently supplied pins. columns equals the eight public column names. + +Every row exactly `{artifact_id,source_row,fields}`: source_row is original1-based native row, fields is an object with exactly the eight column names and original formatted strings. Do not interpret status, authority, review prose, URLs or scope into another evidence axis. Empty fields stay empty. Every binding exactly {node_id,artifact_id,roles} with explicit canonical sorting. unmapped_nodes is the sorted graph IDs with no binding. Success JSON is deterministic ASCII with sorted object keys and one terminal newline. No output timestamp, original private input, accepted marker or inferred formal join. + +## External controls and completion + +Tests launch the CLI as a subprocess with -B -S and propagate the active optimized mode. Before implementation, actual hosted RED must identify the missing CLI, not merely fail discovery/import/setup. Cover valid deterministic preservation and typing; multiple native ranges/default offsets/blank cells; every independently pinned identity; each required/duplicate/invalid flag; duplicate/nonfinite/deep/oversized JSON and canonical base64; native source/header/range/row/grid/type contradictions; unknown/duplicate artifact IDs and bindings; six explicit roles; unknown graph IDs; missing mappings; forged columns; private Source/Notes and unselected-row canaries absent from public stdout and refusal stderr; inert code/URL strings never fetched or executed. Positive selected public strings may themselves contain URLs/code as inert escaped data; omission is determined by explicit field/row policy. + +Keep fixtures synthetic and compact. Do not copy any real private capture into tests or the public repository. Complete this unit only after exact candidate hosted normal/optimized controls pass with full discovery, original failure/success archives and nonauthor source/privacy review. Real selected source projection/readback follows that tested parser; the capture SHA alone does not authenticate a Sheet revision. Native graph archive readback, evidence-public projection, Astro/build/browser/deployment and all other architecture outcomes remain separate work. diff --git a/docs/plans/2026-10-08-interface-graph-custody-contract.md b/docs/plans/2026-10-08-interface-graph-custody-contract.md new file mode 100644 index 000000000..ec17f2d08 --- /dev/null +++ b/docs/plans/2026-10-08-interface-graph-custody-contract.md @@ -0,0 +1,209 @@ +# Interface graph archive readback v1 contract + +Root pickup 6070431864/amendment 6070796606 owns this bounded next graph-to-SSG unit. This document is the only current write. Proposed later files are `architecture/graph_artifact_readback.py`, `tools/architecture_graph_artifact_readback.py`, and `tests/test_architecture_graph_artifact_readback.py`; root claims and assigns those separately after contract review. Standing owner authorization applies. No local project execution, implementation, tests, deployment, or private Artifact Index capture access is part of this design task. + +## Observed retained data and the custody boundary + +Source-only ZIP reads and hashes on 8 October 2026 inspected `work/evidence/architecture-casefold-required-main00bcd-37856787382.zip`, outside the public Git tree. Original bytes are 19001 bytes, SHA256 `7c5891445d327b88f1fb7a82966ebf681643286a64179b2389a5bcb3da41e8b9`. Root supplies the native artifact identity 11584985628, name `research-architecture-37856787382-1`, producer repository `d6g8k5htny-coder/main`, run 37856787382/attempt 1, checked commit `dcb30554f9cc9e60aeb9f6b4b8efa3b5c9287a3b`, and original receipt SHA256 `4d32e7d72b999c74c13726f665cf57632959ae797541a22da458ade3b41ca5d2`. The 19001-byte ZIP has 13 regular DEFLATED members, no archive comment, classic single-disk central directory, and signed 32-bit data descriptors. This inspection read data; it did not rerun the exporter, gate, tests, or receipt helper. + +The original graph member is 48932 bytes with SHA256 `30cdcedabbdd3d9906a6cf13c838a23424ca065225d179c112db3ed7f5b3aa7f`; data inspection counted 49 dictionary node IDs and 55 edges. The original receipt is 22627 bytes. Both full logs record 89 passing qualified IDs and terminal `OK`; the sorted IDs joined with one LF after each ID have SHA256 `b51eaf6cfaede42105ad377c066c4b18789e320ccf542b6817a6850c350fc9ef`. These are original retained-data observations, not a new execution or scientific acceptance. + +Independently supplied native expectations establish comparison context. The reader can prove that bytes match those declared pins and that archive contents satisfy this contract; it cannot authenticate GitHub, an artifact ID, a producer conclusion, or an archive download through caller strings. Root's separate native producer/job/artifact readback establishes that external association. A synthetically regenerated archive with supplied matching pins remains synthetic. Every output retains `custody: "unknown"`, scientific effect `NONE`, and exact false scientific-status authority. No capture-authentication override is accepted. + +The producer checked commit above is distinct from the dated Math source commit below and from a later executing reader/SSG build commit. The reader never rewrites one identity into another and never requires an old producer commit to equal its own current checkout. The later immutable build manifest binds its executing commit, this output unit's SHA256, the separately governed public Artifact Index projection, and emitted assets. That build/deployment unit remains separate. + +## Exact CLI, module, and output ABI + +The external CLI is `python -B -S tools/architecture_graph_artifact_readback.py`. It requires exactly once, with no abbreviation, `--archive FILE` and these eight flags: + +| Flag | Binding field | Exact value type | +|---|---|---| +| `--expected-commit` | checked_commit | lowercase 40-hex string | +| `--expected-repository` | repository | ASCII `[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+`, neither component `.` or `..` | +| `--expected-run-id` | run_id | ASCII positive decimal, no leading zero | +| `--expected-run-attempt` | run_attempt | ASCII positive decimal, no leading zero | +| `--expected-receipt-sha256` | receipt_sha256 | lowercase 64-hex string | +| `--expected-artifact-id` | artifact_id | ASCII positive decimal, no leading zero | +| `--expected-artifact-sha256` | artifact_sha256 | lowercase 64-hex string | +| `--expected-artifact-name` | artifact_name | exactly `research-architecture--` | + +The expectations cannot be learned from stdin, the ZIP, its manifest, receipt, log, or filename. No stdin packet, output-path flag, optional trust pin, URL input, alternate graph source, extraction, network fetch, or captured-code import is supported. Any missing/duplicate/unknown/abbreviated argument or invalid input refuses nonzero with empty stdout and exactly `ARCHITECTURE_GRAPH_READBACK_REFUSED\n` on stderr. Diagnostics never echo paths, members, archive bytes, logs, or exception text. Success exits 0, stderr is empty, and stdout is one deterministic ASCII JSON document with sorted object keys, compact separators, preserved JSON types/array order, and one terminal LF. + +The pure stdlib module API is `read_graph_archive(raw_zip: bytes, expected: dict[str, str], source_graph_bytes: bytes) -> dict`. The expected dictionary has exactly the eight binding keys above, all exact strings. The source bytes must match the independently fixed source SHA below, even if callers provide another internally coherent source. The module performs no I/O. The CLI reads only the archive and the bundled fixed `docs/site/dependency-source/GRAPH.json`; it imports only trusted implementation/stdlib code and never `hard_gate.py`, the producer receipt helper, tests, or captured members. Suppress bytecode writes. Reuse the current helper's documented data rules independently, not its executable acceptance result. + +Success root exact keys are `{schema_version, scientific_effect, scientific_status_authority, custody, graph, receipt}` with schema_version exact integer 1, scientific_effect `NONE`, authority exact false, custody `unknown`, and graph the original parsed seven-field export with every typed record preserved. Receipt exact keys are `{schema_version, scientific_effect, scientific_status_authority, custody, verification_scope, binding, archive, graph_member, producer_receipt_sha256, producer_receipt}`. The same exact non-scientific constants apply; verification_scope is `declared-native-pins-and-archive-content`, binding preserves the eight externally supplied strings, and producer_receipt is the validated original parsed producer receipt without added/mutated fields. + +`archive` is exactly `{sha256, bytes, members}`: original raw ZIP SHA and byte count, then 13 entries sorted by canonical path, each exactly `{path, bytes, sha256}` derived from fully read original member bytes, including `ARTIFACT_SHA256SUMS`. `graph_member` is exactly `{path: "generated/graph.json", bytes, sha256}`. producer_receipt_sha256 is the original member SHA matching the external receipt pin. No raw ZIP/base64, log/console text, exporter output, inspected-image annotations, filesystem path, validation timestamp, inferred graph join, accepted badge, kernel result, or source-custody assertion is projected. + +Validation completes before stdout serialization. The complete encoded output is bounded at 16 MiB. The CLI writes no files; a trusted caller retains stdout in a temporary file and promotes the one unit atomically only after exit 0 and successful complete-output validation. Refusal preserves any previously published caller-owned unit. A broken/partial output transport is discarded by that caller; it is never a valid unit merely because some JSON bytes appeared. + +## File and ZIP admission + +Archive raw bytes are bounded at 64 MiB. The CLI anchors every absolute parent component with `O_DIRECTORY|O_NOFOLLOW`, resolving a relative input against the trusted current directory without erasing symlink components. Reject `..` components; never call resolve/abspath in a way that collapses an unchecked component. The leaf uses `O_NOFOLLOW|O_NONBLOCK`; fstat must establish a regular file before reading. Read at most 64 MiB + 1 once through that descriptor, check byte count and pre/post descriptor identity/size/change metadata, and compare the SHA of that exact buffer to expected artifact_sha256 before archive parsing. Directory, FIFO, device, symlink leaf/ancestor, unavailable, changing, and oversized files refuse without waiting for a writer. The bundled source graph uses the same anchored regular-file policy with a 16 MiB cap and its fixed byte/SHA check. + +V1 admits the observed classic single-disk ZIP subset, with STORED or DEFLATED entries and optional ordinary 32-bit data descriptors. Allowed general-purpose flag bits are 3 (data descriptor), 11 (UTF-8 names), and, for DEFLATED entries only, 1/2 (compression option); all other set bits refuse. ZIP64, multidisk, encrypted/strong-encrypted, unsupported compression/flags, archive/file comments, and extra fields refuse; these are explicit unsupported formats, not claims that all general ZIPs are unsafe. The initial local header begins at byte 0, the end-of-central-directory record ends exactly at EOF, central-directory count/size/offsets agree, and every local entry belongs to exactly one central entry. Local names/flags/methods and declared CRC/sizes or its 12/16-byte descriptor must agree with the central record. Local header/data/descriptor spans cannot overlap, share an offset, contain unreferenced gaps/entries, or extend into the central directory. No self-extracting prefix, concatenated/trailing archive, truncation, hidden duplicate, or unsigned range wrap is accepted. + +Inspect every entry before reading any content. Raw/decoded/original filenames must agree and be ASCII exact canonical names; reject NUL/control characters, backslashes, absolute/drive paths, empty/dot/dot-dot components, directories, trailing separators, casefold aliases, and duplicates even if a library would return the last entry. Unix type bits must be regular when present; absent type bits are admitted only for a nondirectory DOS regular entry. Symlink, FIFO, socket, device, and other special attributes refuse. Permission timestamps/order may vary and are not projected. Both file order and manifest line order may vary; the member-name set may not vary in v1. + +The exact 13 members are the 12 data members in the next section plus `ARTIFACT_SHA256SUMS`. KiB/MiB mean 1024/1048576 bytes. Total inflated member bytes are bounded at 64 MiB; the smaller member limits are stronger for this closed inventory, while independent aggregate accounting remains required. Member limits are: manifest 16 KiB; checked-commit/run-id/run-attempt/container-status each 128 bytes; exporter.stdout and exporter.stderr each 64 KiB; runtime-image.json 1 MiB; generated/graph.json, architecture-run-receipt.json and console.log each 4 MiB; normal/optimized logs each 16 MiB. Declared sizes must satisfy limits before decompression; bounded streaming must enforce each actual count and aggregate count independently. Read every member to its complete end and verify CRC; for DEFLATED data also require one complete deflate stream with no unused compressed tail. A high compression ratio alone is not rejected: valid repetitive logs remain admissible within the actual byte limits. A compression bomb that exceeds a declaration/budget, never ends, or fails structure/CRC refuses before publication. No entry is extracted, evaluated, executed, or imported. + +## Manifest, producer receipt, and native consistency + +`ARTIFACT_SHA256SUMS` is strict ASCII: exactly 12 nonempty lines, each lowercase 64-hex, two spaces, one canonical name from this exact set, and a final LF. No duplicate/case alias, escaped filename, binary marker, blank line, self-entry, unknown/missing member, or trailing text is allowed. Every listed SHA is compared with independently recomputed full original member bytes; never accept the manifest as its own proof. + +```text +runtime-image.json +checked-commit.txt +run-id.txt +run-attempt.txt +container-exit-status.txt +console.log +tests-normal.log +tests-optimized.log +exporter.stdout +exporter.stderr +generated/graph.json +architecture-run-receipt.json +``` + +The receipt's eight evidence_file_sha256 keys are exactly generated/graph.json, checked-commit.txt, run-id.txt, run-attempt.txt, container-exit-status.txt, tests-normal.log, tests-optimized.log, runtime-image.json; every lowercase 64-hex value must independently match those eight raw members. The manifest additionally verifies the receipt and all three diagnostics. Manifest SHA and receipt hashes remain internal integrity until matched with the separate externally supplied raw ZIP and receipt pins; regenerating a manifest does not authorize changed context or source records. + +Producer receipt exact root keys are `{schema_version, scientific_effect, scientific_status_authority, checked_commit, repository, run_id, run_attempt, runtime_image, test_modes, graph_source, evidence_file_sha256}`. Require integer 1, `NONE`, exact false, and all four native strings exactly equal external commit/repository/run/attempt. checked-commit.txt, run-id.txt and run-attempt.txt equal the corresponding ASCII string plus exactly one LF; the repository exists in the receipt, not a fabricated repository.txt member. container-exit-status.txt equals exactly `0\n`. exporter.stderr must be empty and exporter.stdout must equal exactly `/output/generated/graph.json\n`, the current fixed producer invocation. console.log may contain bounded inert diagnostics and is hash-verified but is never interpreted or projected. + +runtime-image.json is strict JSON, a one-element list containing an object. Native extra inspected-image fields are admitted as inert data, but Id must be a lowercase `sha256:<64hex>` string, RepoDigests exactly `["python@sha256:83f339c1be6340ae1096010fdccf6552ac932d8f410d45d206014916bdf37e48"]`, Os `linux`, Architecture `amd64`. The receipt runtime_image is exactly `{id, repo_digest}` and must equal those checked values; do not hardcode a synthetic/current image ID. All JSON members and bundled source refuse duplicate keys at any depth, invalid UTF-8/surrogates, nonfinite constants/overflow, multiple documents, malformed types, and more than 64 container levels (root container counts; scalar leaves do not). Canonical typed comparisons distinguish false/0 and integer/float, without coercion. + +## Complete test inventory and exact graph policy + +Derive both inventories from the full raw normal/optimized logs independently of receipt claims. Logs must be strict UTF-8 text with LF line boundaries and no CR/NUL. Accept only complete lines ` () ... ok`, with no leading whitespace, exact delimiter, short name equal the qualified last component, and identity matching ASCII `test_architecture_[A-Za-z0-9_]+\.[A-Za-z_][A-Za-z0-9_]*\.test[A-Za-z0-9_]*`. `test1` and `testExtra` remain valid prefixes. Every ID occurs exactly once per mode, all 89 immutable IDs in the appendix must occur, and later valid unique passing IDs are allowed, up to 4096 per mode. Both discovered inventories must be identical. A count-only 89 substitute is forbidden. + +Every result-looking line must match the complete passing grammar: detect case-insensitive test prefixes after optional whitespace, parenthesized qualified test markers, ellipses after a right parenthesis, and the ordinary result delimiter. Malformed/foreign/shortname-mismatched results, FAIL/ERROR/FAILED, skips, expected failures, unexpected successes, or duplicate/partial runs refuse. Exactly one `Ran tests in s` footer follows all test results, its count equals discovered IDs, and exactly one terminal `OK` is the last nonempty line. Diagnostic blank lines, separators and ordinary non-result text may remain inert. Receipt test_modes is exactly `[normal, optimized]`; each entry has exactly `{mode, test_count, test_ids}` with an exact integer count and sorted complete IDs equal the derived inventory. Do not discover expected IDs by executing/importing tests or learning a new floor from the input receipt. + +Graph root exact keys are `{schema_version, source, nodes, edges, dimensions, scientific_effect, scientific_status_authority}` with integer 1, `NONE`, exact false. Source exact five fields are repository `d6g8k5htny-coder/Math-`, commit `7858329974e28be79f29b22644370084ff43da4f`, captured_at `2026-10-03T15:07:03Z`, graph_sha256 `8822e9618678321a342d69cd0b8ae6552de1b5d578c331de5072b2892ee9dd09`, gate_sha256 `a78f3e25f3b0cfe113e618a4c31a7a25d7f22af638c46dec1ecba221fa333ac8`. Receipt graph_source must equal those original fields exactly. Bundled GRAPH.json has 38753 original bytes and the graph_sha256 above. Verify its byte count/SHA, strict parse, then canonical typed equality of exported nodes/edges with this independent source. Preserve all 49 dictionary IDs, 55 ordered original edges, records, review qualifiers, classifications and scopes; no conversion to a node array, case aliasing, rewriting, or guessed relation to Lean or Artifact Index IDs. + +Dimensions must have exactly those 49 IDs. Each value has exactly source/review/kernel/computation/alignment. Source is `recorded` iff the original node's explicit source value is truthy; review is `recorded` iff any explicit review_source, review_issue, review_basis, review_provider, review_providers or review_disposition value is truthy; otherwise each is `not_recorded`. Kernel, computation and alignment are always `not_recorded` in this dated export. Classification/proof prose and passing engineering tests cannot manufacture evidence. Raw native formal receipts and the separate evidence adapter remain distinct inputs with unknown graph-to-target joins; no actual Lean elaboration, declaration existence, per-statement proof, or accepted alignment is inferred here. + +The current helper source inspected is tools/architecture_run_receipt.py SHA256 `a4bb66325f64422398ff726bc1c448afb284498275e5894a7d1af6b25fba9890`; its staged receipt validates the original eight members and 53 baseline IDs. This ZIP reader independently repeats those data invariants, strengthens the required floor to the observed complete 89 controls, verifies the producer receipt itself and all 12 manifest entries, and adds bounded archive admission. It never calls receipt() on extracted data or accepts its own newly synthesized receipt in place of the original member. + +## Independent external controls and acceptance + +Freeze reviewed contract before assigning tests. Target about 30 external CLI methods, with an explicit CLI-exists assertion before every child so missing implementation yields genuine hosted RED. Child interpreters retain -B/-S and active -O/-OO. Synthetic ZIP fixtures use TEST native identities and clearly labeled synthetic logs; graph source data may be read inertly from the already-public fixed source. Do not copy the private Artifact Index capture or mistake a synthetic passing log for a new native run. A separately root-supplied real-archive readback control uses the original external eight bindings above. + +Meaningful control groups are: deterministic real-format positive; alternative valid native context and attempt 10; original typed graph/receipt retention; additional valid test1/testExtra controls; each eight expected pin/context substitution; all argument absence/duplicates/format errors; raw and member byte boundaries and aggregate accounting; regular/nofollow/symlink-parent/FIFO refusal; duplicate/casefold/path/NUL members; Unix special/DOS-directory types; encrypted/unsupported/multidisk/ZIP64 cases; central/local disagreement/overlap/truncation/prefix/tail; CRC and bounded expansion corruption; every missing/extra ZIP member; each 12 manifest hash and malformed/duplicate/self-row; each receipt-eight hash; receipt raw pin despite regenerated manifest; nonzero native status and each native identity mismatch; strict JSON/depth/type contrasts; all graph pins and typed node/edge/dimension mutation with coherently regenerated internal hashes; missing/substituted one of 89 IDs despite matching count; skipped/failed/expected-negative additional tests; malformed result-like extras before valid footer; unequal additional suites; receipt inventory mismatch; runtime inspect/receipt contradictions; exporter diagnostics contradictions; and inert captured strings with calibrated I/O/network observers, no extraction or writes. + +Retain first exact tests-only hosted missing-CLI RED, then implementation candidate normal/optimized full discovery and original failure/success archives. Include exact-limit positives plus one-over negatives; mutations must recompute unrelated internal/external synthetic pins where needed so another mismatch does not mask the intended control. Include an independently reviewed count-only/circular-rehash mutant refusal and a meaningful positive so reject-all cannot pass. Nonauthor source review verifies the parser/privacy/IO boundary, with test-author and organizational-independence relationships disclosed. Root checks native job conclusions, original archive bytes/member identities, and executing revisions before reporting this unit implemented. No passing receipt alone promotes science, confirms custody, completes the reader, or authorizes a guessed graph mapping. + +At this plan's source freeze: contract SOURCE_PREPARED; test implementation NOT_WRITTEN; hosted RED/GREEN NOT_RUN; reader/SSG/browser/deployment NOT_RUN. Existing Artifact Index tests at SHA256 `8d6fb4abc139e37f0163f344c7c53f263e2dd6a0c2f440a29643ac01c33d7736` remain unchanged. + +## Immutable required 89 inventory + +The literal fully qualified IDs below are independent v1 expectations, not parsed from an incoming receipt. Their sorted LF-terminated byte inventory has the b51eaf6c SHA above. Additional IDs never replace any of these 89. + +```text +test_architecture_binding.ArchitectureBindingContract.test_artifact_id_requires_positive_ascii_decimal_without_leading_zero +test_architecture_binding.ArchitectureBindingContract.test_artifact_name_is_exactly_bound_to_current_run_and_attempt +test_architecture_binding.ArchitectureBindingContract.test_attempt_ten_is_a_positive_decimal_not_a_single_digit +test_architecture_binding.ArchitectureBindingContract.test_commit_format_cannot_be_authorized_by_an_equally_invalid_native_commit +test_architecture_binding.ArchitectureBindingContract.test_deeply_nested_json_is_refused_without_a_success_envelope +test_architecture_binding.ArchitectureBindingContract.test_duplicate_top_level_keys_are_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_current_native_argument_is_used_for_identity_binding +test_architecture_binding.ArchitectureBindingContract.test_each_duplicate_output_key_is_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_expected_native_identity_argument_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_non_success_result_is_refused +test_architecture_binding.ArchitectureBindingContract.test_each_of_the_eight_outputs_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_an_empty_string +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_non_string_identities_without_coercion +test_architecture_binding.ArchitectureBindingContract.test_each_top_level_field_is_required +test_architecture_binding.ArchitectureBindingContract.test_extra_output_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_extra_top_level_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_invalid_or_multiple_json_documents_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_finite_json_numbers_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_object_top_level_values_are_refused +test_architecture_binding.ArchitectureBindingContract.test_other_valid_native_identities_are_accepted_and_preserved +test_architecture_binding.ArchitectureBindingContract.test_outputs_must_be_an_object +test_architecture_binding.ArchitectureBindingContract.test_receipt_and_artifact_sha256_require_lowercase_64_hex_digits +test_architecture_binding.ArchitectureBindingContract.test_repository_substitution_and_case_drift_are_refused +test_architecture_binding.ArchitectureBindingContract.test_run_and_attempt_decimal_format_cannot_be_authorized_by_invalid_native_args +test_architecture_binding.ArchitectureBindingContract.test_stale_attempt_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_stale_checked_commit_is_refused +test_architecture_binding.ArchitectureBindingContract.test_stale_run_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_valid_current_run_has_exact_stable_non_scientific_output +test_architecture_binding.ArchitectureBindingContract.test_valid_json_at_exact_stdin_byte_limit_is_accepted +test_architecture_binding.ArchitectureBindingContract.test_valid_json_over_stdin_byte_limit_is_refused +test_architecture_graph_export.ArchitectureGraphExportContract.test_caller_pinned_provenance_cannot_authorize_different_gate_code +test_architecture_graph_export.ArchitectureGraphExportContract.test_classification_and_proof_review_text_cannot_manufacture_evidence +test_architecture_graph_export.ArchitectureGraphExportContract.test_context_only_cycle_is_allowed_without_changing_gate_semantics +test_architecture_graph_export.ArchitectureGraphExportContract.test_default_trust_rejects_self_consistent_changed_graph_and_provenance +test_architecture_graph_export.ArchitectureGraphExportContract.test_dimensions_describe_only_explicit_recorded_metadata +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_graph_json_keys_are_rejected_after_identity_validation +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_provenance_json_keys_are_rejected_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_exact_source_bound_hard_gate_validator_is_called +test_architecture_graph_export.ArchitectureGraphExportContract.test_failed_export_preserves_an_earlier_valid_export +test_architecture_graph_export.ArchitectureGraphExportContract.test_gate_identity_is_checked_before_untrusted_gate_executes +test_architecture_graph_export.ArchitectureGraphExportContract.test_graph_identity_is_checked_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_missing_required_dependency_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_pinned_49_node_55_edge_export_is_deterministic_and_preserves_records +test_architecture_graph_export.ArchitectureGraphExportContract.test_required_dependency_cycle_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_same_size_gate_change_is_rejected_by_sha_before_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_source_byte_counts_are_validated_even_when_sha_matches +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_directory_is_rejected +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_files_are_rejected_before_gate_import +test_architecture_receipt.ArchitectureReceiptContract.test_attempt_ten_and_other_native_repository_are_preserved +test_architecture_receipt.ArchitectureReceiptContract.test_changed_node_or_edge_is_refused_even_when_graph_source_pins_are_unchanged +test_architecture_receipt.ArchitectureReceiptContract.test_directory_or_fifo_member_is_refused_without_waiting_for_a_writer +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_json_keys_are_refused_even_when_last_value_is_valid +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_test_identity_or_multiple_runs_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_each_expected_host_identity_argument_is_used_and_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_native_identity_file_must_match_current_host_arguments +test_architecture_receipt.ArchitectureReceiptContract.test_each_required_sandbox_control_rejects_skipped_failed_or_error_status +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_is_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_must_be_regular_and_cannot_be_a_symlink +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_over_16_mib_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_empty_or_zero_discovered_test_logs_are_refused_in_each_mode +test_architecture_receipt.ArchitectureReceiptContract.test_every_graph_source_pin_is_required_and_cannot_be_substituted +test_architecture_receipt.ArchitectureReceiptContract.test_every_required_identity_is_needed_even_when_53_other_tests_are_ok +test_architecture_receipt.ArchitectureReceiptContract.test_evidence_directory_or_generated_parent_symlink_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_graph_and_runtime_inspect_require_strict_json +test_architecture_receipt.ArchitectureReceiptContract.test_graph_root_schema_and_non_scientific_flags_are_exact +test_architecture_receipt.ArchitectureReceiptContract.test_invalid_matching_host_identity_does_not_authorize_bad_commit_or_decimal +test_architecture_receipt.ArchitectureReceiptContract.test_later_all_ok_test_methods_are_counted_and_bound +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_extra_result_lines_cannot_be_ignored_before_the_success_footer +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_foreign_or_shortname_mismatched_test_identities_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_missing_extra_or_forged_dimension_cannot_manufacture_scientific_evidence +test_architecture_receipt.ArchitectureReceiptContract.test_native_repository_argument_must_have_owner_and_repository_components +test_architecture_receipt.ArchitectureReceiptContract.test_nested_record_types_cannot_change_even_when_python_values_compare_equal +test_architecture_receipt.ArchitectureReceiptContract.test_non_finite_numbers_are_refused_even_in_additional_inspect_fields +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_names_are_accepted_as_additional_controls +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_prefix_malformed_results_are_not_diagnostics +test_architecture_receipt.ArchitectureReceiptContract.test_nonzero_or_malformed_container_exit_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_normal_and_optimized_must_discover_the_same_additional_passing_tests +test_architecture_receipt.ArchitectureReceiptContract.test_runtime_inspect_is_one_linux_amd64_image_with_the_fixed_digest +test_architecture_receipt.ArchitectureReceiptContract.test_skip_or_failure_in_additional_discovered_test_is_also_refused +test_architecture_receipt.ArchitectureReceiptContract.test_summary_must_report_exact_discovered_count_and_terminal_ok +test_architecture_receipt.ArchitectureReceiptContract.test_valid_53_test_receipt_is_exact_deterministic_and_preserves_staged_bytes +test_architecture_receipt.ArchitectureReceiptContract.test_valid_inspected_image_id_is_preserved_instead_of_hardcoded +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_at_exact_16_mib_limit_is_accepted +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_larger_than_64_kib_is_accepted_and_raw_bytes_are_hashed +test_architecture_sandbox.ArchitectureSandbox.test_kernel_enforces_cpu_memory_and_process_limits +test_architecture_sandbox.ArchitectureSandbox.test_network_namespace_has_no_external_interface_or_route +test_architecture_sandbox.ArchitectureSandbox.test_nonroot_and_no_new_privileges +test_architecture_sandbox.ArchitectureSandbox.test_output_quota_stops_disk_exhaustion_and_cleanup_recovers_space +test_architecture_sandbox.ArchitectureSandbox.test_source_mount_is_read_only_and_environment_has_no_publishing_secret +``` + +## First implementation run and bounded observer-launcher correction + +The original source-freeze checkpoint above is preserved as history. Reviewed tests at SHA256 `204056347967bbe58e7e13aab1015da51b2754b2f20a8313606af9bf985eae0d` contain 37 external methods; the graph reader module and CLI remain frozen at SHA256 `663dd06f0e65e48f864fbc2143b86d7e09229157b018e84cfea1fefb2995c632` and `0ec793ccfd419d6bb9c83fe419af042b617b53f3a20ccb7993b5ee799084dc98`. The independently retained missing-CLI RED preceded those implementation bytes. This checkpoint does not mark the reader or its integration complete. + +The first actual implementation run, [37863465487/attempt 1](https://github.com/d6g8k5htny-coder/main/actions/runs/37863465487), ran architecture job [113604483110](https://github.com/d6g8k5htny-coder/main/actions/runs/37863465487/job/113604483110) for head `bb92abe5595f97d4defd14b1403980ae15f38987`. The native checkout and original checked-commit member are merge `f21e0fa0796602e0e57f1e35a6e36741d2c127f4`, merging that head into `0be54aa227d7015b0abda00feb5e847a3fbdbcdb`. Formal succeeded; architecture failed, landing was skipped and verify failed. Disposal, regular-output staging, original failure upload and strict unmount succeeded; receipt acceptance and accepted identity emission were skipped. + +The complete original normal log ran 160 methods in 182.623 seconds: all 123 prior methods passed; 36 graph-reader methods passed and the calibrated inert-observer method failed. The optimized log started 99 methods: 97 passed, the same observer method failed, and the typed-node/edge/dimension method remained unfinished. That partial log contains 64 passing prior methods and 35 started graph-reader methods, of which 33 passed. Both retained logs report the exact 64MiB positive and one-byte-over control as passing. Neither optimized completion nor a full two-mode GREEN is inferred. + +The observer failure occurred in the trusted launcher's `runpy.run_path` bootstrap before any CLI frame. Python 3.11.14 runpy.py line 280 imports pkgutil's get_importer; importlib then filled a fixture-CWD directory cache, and the active private-fixture list observer correctly refused that attempt. The correction preloads only trusted pkgutil support before observer installation/calibration and adds `-I` only to the audit-launcher child so the synthetic private CWD is not an import search root. Candidate CLI instructions still run under the active observer; calibration, network/read/write/list observations, normal/-O/-OO propagation and all 37 method identities and bodies remain unchanged. There is no blanket list/read exception, candidate import before activation or private-input access allowance. + +The outer command began at 00:11:26.174 UTC on 9 October and was killed at 00:16:36.186 UTC after approximately 310.012 seconds: the configured 300-second timeout plus its 10-second kill grace. The original container-exit-status member is 137. Normal mode alone took 182.623 seconds; two comparable modes would take approximately 365.246 seconds before exporter overhead. Claim amendment 6071777153 therefore changes only the total ephemeral timeout from 300 to 420 seconds for the next bounded hosted experiment. The 420-second allowance is an estimate, not a measured optimized completion or resource margin. The 20-second child bound, CPU2, 1GiB memory, PID128, 64MiB output filesystem, 128MiB /tmp under the same aggregate memory limit, network-none, nonroot, read-only source/root and strict disposal/collection/release controls remain unchanged. No native peak memory/CPU telemetry or Docker OOM flag was retained, so exit137 is not repurposed as an OOM diagnosis or proof of resource headroom. + +Root retained the completed original failure archive outside Git at `work/evidence/architecture-graph-reader-first-failure-37863465487.zip`: native artifact 11587317831, name `research-architecture-37863465487-1`, 11258 raw bytes, SHA256 `ed8c5afda7da6855ffcbb39696aa205f8849aea3757c26b5ad16ce17201c9139`. It has nine original entries, including ARTIFACT_SHA256SUMS and eight payloads; root verified every payload hash. The archive retains the two original complete/partial logs and original status/context/runtime bytes. No producer graph, exporter output or accepted receipt was manufactured for the failed run, and no raw native ZIP or private capture is added to Git. + +The bootstrap/workflow/history correction is SOURCE_PREPARED under amendments 6071777153 and 6071792491 for a fresh implementation-nonauthor source review before publication or hosted execution. Its author reviewed the earlier controls and authored the graph implementation, so exposure is source/test-exposed and organizational independence remains 0. No local Python, Node, test, YAML, download or Git execution occurred; corrected hosted execution, actual resource measurements, full optimized completion, accepted original graph/archive readback and reader/SSG/browser/deployment remain NOT_RUN. Earlier successful individual controls and this failure remain retained without rewriting the run as GREEN. + +Fresh actual root source assessment now ACCEPT_SCOPED_SOURCE for testSHA256dd3c5b3f2011ae3f7582514eae0fb79f25257d5bf54f40a99585d21dff65116e and workflow9cd51af45dc7892f665756a95c42872cac19297d062877aeb3b70616a6868c97. Root read the full183-line workflow, complete changed launcher and invocation context, and all16 appended history lines; exact whole-source comparison against the retained12-path publication proves only two test-line replacements and one timeout-line replacement. All37 method identities/bodies and both implementation files are unchanged, while the original191-line contract prefix is byte-identical. The trusted launcher imports pkgutil before observer installation, and only its audited child receives -I; calibration and every actual candidate instruction stay observed. This is nonauthor source/test-exposed review with organization-independence0, distinct from correction author /root/graph_tests_review. Corrected160-method two-mode runtime, original archive acceptance and real reader/SSG integration remain NOT_RUN until the new hosted attempt is read back. diff --git a/docs/site/app.js b/docs/site/app.js index ea7399e5b..7205e039b 100644 --- a/docs/site/app.js +++ b/docs/site/app.js @@ -1,6 +1,6 @@ -import {verifiedJSON, verifiedBytes, validateStatus, validateCoefficient, safeSourceURL, hex40, hex64} from './core.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import {connectCatalogQuery} from './catalog-query.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import {prepareWorkspaceFragment} from './workspace-fragment.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {verifiedJSON, verifiedBytes, validateStatus, validateCoefficient, safeSourceURL, hex40, hex64} from './core.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import {connectCatalogQuery} from './catalog-query.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import {prepareWorkspaceFragment} from './workspace-fragment.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const finishFragment=prepareWorkspaceFragment(); const el=id=>document.getElementById(id); const node=(tag,text,cls)=>{const n=document.createElement(tag);if(text!==undefined)n.textContent=text;if(cls)n.className=cls;return n;}; diff --git a/docs/site/atlas.mjs b/docs/site/atlas.mjs index 628d55ef9..69ab25ca3 100644 --- a/docs/site/atlas.mjs +++ b/docs/site/atlas.mjs @@ -1,5 +1,5 @@ -import {currentSnapshot,element,anchor} from './current.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import {hasNode,readState,neighborhood,searchGraph,downstreamReach,requiredDependencyPaths,REQUIRED_ROUTE_SEMANTICS,evidenceAxes,sourceURL,sourceForNode,nodePage} from './current-model.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {currentSnapshot,element,anchor} from './current.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import {hasNode,readState,neighborhood,searchGraph,downstreamReach,requiredDependencyPaths,REQUIRED_ROUTE_SEMANTICS,evidenceAxes,sourceURL,sourceForNode,nodePage} from './current-model.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const byId=id=>document.getElementById(id); const svgElement=(tag,attrs)=>{const n=document.createElementNS('http://www.w3.org/2000/svg',tag);for(const [k,v]of Object.entries(attrs))n.setAttribute(k,String(v));return n;}; function linkRecord(label,value){const p=element('p');if(typeof value==='string'){try{const u=new URL(value);if(u.protocol==='https:'&&u.hostname==='github.com'&&!u.username&&!u.password&&!u.port){p.append(anchor(label,value));return p;}}catch{}}p.textContent=`${label}: ${value||'not recorded'}`;return p;} diff --git a/docs/site/brand.css b/docs/site/brand.css index 26b6d7a0a..f063e675d 100644 --- a/docs/site/brand.css +++ b/docs/site/brand.css @@ -60,7 +60,7 @@ body > header { color: var(--ul-text); font-weight: 750; letter-spacing: .13em; position: relative; padding-left: 57px; min-height: 44px; line-height: 1.65; } -.brand::before { content: ""; position: absolute; left: 0; top: 1px; width: 42px; height: 42px; background: url("brand/mark.svg?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc") center/contain no-repeat; } +.brand::before { content: ""; position: absolute; left: 0; top: 1px; width: 42px; height: 42px; background: url("brand/mark.svg?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53") center/contain no-repeat; } .brand span { color: var(--ul-muted); font-size: 12px; letter-spacing: .16em; text-transform: uppercase; } nav { gap: 12px 24px; flex-wrap: wrap; } nav a { color: var(--ul-text); min-height: 44px; display: inline-flex; align-items: center; font-size: 13px; padding: 0 6px; margin: 0 -6px; } diff --git a/docs/site/cite.html b/docs/site/cite.html index 79060bacf..7eca73422 100644 --- a/docs/site/cite.html +++ b/docs/site/cite.html @@ -2,12 +2,12 @@ - + Cite · Universal Law - - - - + + + +
UNIVERSAL LAW MATHEMATICS IN THE OPEN
diff --git a/docs/site/cite.mjs b/docs/site/cite.mjs index 139a92fe8..dfd11fc96 100644 --- a/docs/site/cite.mjs +++ b/docs/site/cite.mjs @@ -1,4 +1,4 @@ -import {wireReferenceForm} from './source-reference.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {wireReferenceForm} from './source-reference.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const byId = id => document.getElementById(id); wireReferenceForm({form:byId('reference-form'), repository:byId('reference-repository'), commit:byId('reference-commit'), path:byId('reference-path'), sha256:byId('reference-sha256'), output:byId('reference-output'), json:byId('reference-json'), bibtex:byId('reference-bibtex'), link:byId('reference-link'), status:byId('reference-status'), actions:byId('reference-actions'), copyText:byId('reference-copy'), copyJSON:byId('reference-copy-json'), copyBibTeX:byId('reference-copy-bibtex'), share:byId('reference-share'), clipboard:globalThis.navigator?.clipboard, location:globalThis.location, history:globalThis.history, events:globalThis.window}); byId('reference-builder').hidden = false; diff --git a/docs/site/conditionals.mjs b/docs/site/conditionals.mjs index 9fc4067e8..6d652283b 100644 --- a/docs/site/conditionals.mjs +++ b/docs/site/conditionals.mjs @@ -93,7 +93,7 @@ export function renderProjection(document,host,data,source){ el(document,'p','Generated from verified source bytes. This graph is not formal verification, a proof review, or a scientific-status register.')); host.replaceChildren(article); } -const services=()=>import('./museum.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'); +const services=()=>import('./museum.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'); // The museum module already verifies config → manifest → index/status once per // page fetch and caches every pinned byte request. This route consumes that same // verified startup, so it adds only the audited-descriptor check and projection. diff --git a/docs/site/current-model.mjs b/docs/site/current-model.mjs index 45e3bba4a..6453357de 100644 --- a/docs/site/current-model.mjs +++ b/docs/site/current-model.mjs @@ -1,4 +1,4 @@ -import {OPEN_CLASSIFICATIONS, NON_RESEARCH_KINDS} from './dependency-model.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {OPEN_CLASSIFICATIONS, NON_RESEARCH_KINDS} from './dependency-model.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const REPOSITORIES = new Set(['d6g8k5htny-coder/main','d6g8k5htny-coder/Math-']); const SHA = /^[0-9a-f]{40}$/; diff --git a/docs/site/current.mjs b/docs/site/current.mjs index e24b53d00..fba636169 100644 --- a/docs/site/current.mjs +++ b/docs/site/current.mjs @@ -1,4 +1,4 @@ -import {parseVerifiedSnapshot,freshness,filterSources,sourceURL} from './current-model.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {parseVerifiedSnapshot,freshness,filterSources,sourceURL} from './current-model.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; export function element(tag,text,className) { const e=document.createElement(tag);if(text!==undefined)e.textContent=text;if(className)e.className=className;return e; } diff --git a/docs/site/curvature-export.mjs b/docs/site/curvature-export.mjs index 4e099c092..dcb751f2d 100644 --- a/docs/site/curvature-export.mjs +++ b/docs/site/curvature-export.mjs @@ -1,6 +1,6 @@ // Bounded, local export of the Peaks and saddles teaching diagram. No source fetch // or proof verification occurs here; the identity below is recorded provenance. -import { coneModel } from './explore-models.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { coneModel } from './explore-models.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const SVG_NS = 'http://www.w3.org/2000/svg'; const PUBLIC_EXPLORE = 'https://d6g8k5htny-coder.github.io/main/site/explore.html'; diff --git a/docs/site/dependencies.html b/docs/site/dependencies.html index db7e31b19..334d066dc 100644 --- a/docs/site/dependencies.html +++ b/docs/site/dependencies.html @@ -7,14 +7,14 @@ Mathematics · Universal Law - - - - - - - - + + + + + + + + diff --git a/docs/site/dependencies.mjs b/docs/site/dependencies.mjs index 553478d67..7ce99de3c 100644 --- a/docs/site/dependencies.mjs +++ b/docs/site/dependencies.mjs @@ -12,7 +12,7 @@ import { recordedContextRows, recordedReviewText, unresolvedTargets, -} from './dependency-model.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +} from './dependency-model.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const byId = id => document.getElementById(id); diff --git a/docs/site/explore-models.mjs b/docs/site/explore-models.mjs index b148a272a..2184c316c 100644 --- a/docs/site/explore-models.mjs +++ b/docs/site/explore-models.mjs @@ -1,6 +1,6 @@ // NON-CERTIFYING educational arithmetic. These functions illustrate source // definitions; they do not simulate a field or estimate a theorem's constants. -import { annulusModel, p15Model, remoteModel } from './geometry.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { annulusModel, p15Model, remoteModel } from './geometry.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; function finite(value, name) { if (!Number.isFinite(value)) throw new RangeError(`${name} must be finite`); diff --git a/docs/site/explore.html b/docs/site/explore.html index 351e74bbf..8da4839e0 100644 --- a/docs/site/explore.html +++ b/docs/site/explore.html @@ -7,13 +7,13 @@ Explore the mathematics · Universal Law - - - - - - - + + + + + + + diff --git a/docs/site/explore.mjs b/docs/site/explore.mjs index ea550772a..fc58071bf 100644 --- a/docs/site/explore.mjs +++ b/docs/site/explore.mjs @@ -1,10 +1,10 @@ -import { coneModel, pinModel, paletteModel, applyCurvaturePreset } from './explore-models.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { readExploreState, exploreStateURL } from './explore-state.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { coneModel, pinModel, paletteModel, applyCurvaturePreset } from './explore-models.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { readExploreState, exploreStateURL } from './explore-state.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; -import { captureCurvatureDiagram, serializeCurvatureSVG, createCitationController } from './curvature-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { captureTeachingDiagram, createFigureCitationController } from './teaching-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { serializePinSVG, pinFigureCitation } from './pin-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { serializePaletteSVG, paletteFigureCitation } from './palette-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { captureCurvatureDiagram, serializeCurvatureSVG, createCitationController } from './curvature-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { captureTeachingDiagram, createFigureCitationController } from './teaching-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { serializePinSVG, pinFigureCitation } from './pin-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { serializePaletteSVG, paletteFigureCitation } from './palette-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const ns = 'http://www.w3.org/2000/svg'; const byId = id => document.getElementById(id); diff --git a/docs/site/formal.html b/docs/site/formal.html index 4fdca62d1..87e4a5e3a 100644 --- a/docs/site/formal.html +++ b/docs/site/formal.html @@ -5,11 +5,11 @@ Formal verification · Universal Law - - - + + + - + diff --git a/docs/site/index.html b/docs/site/index.html index 116fdcd66..4436688e9 100644 --- a/docs/site/index.html +++ b/docs/site/index.html @@ -4,10 +4,10 @@ The shape of randomness · Universal Law - - - - + + + +
UNIVERSAL LAW MATHEMATICS IN THE OPEN
diff --git a/docs/site/measure.html b/docs/site/measure.html index 2d9536951..18baee042 100644 --- a/docs/site/measure.html +++ b/docs/site/measure.html @@ -7,13 +7,13 @@ From counts to density · Universal Law - - - - - - - + + + + + + + diff --git a/docs/site/measure.mjs b/docs/site/measure.mjs index 8b7f06d39..9ce10eb83 100644 --- a/docs/site/measure.mjs +++ b/docs/site/measure.mjs @@ -1,4 +1,4 @@ -import { measurementModel, parseMeasurementInputs } from './measurement-model.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { measurementModel, parseMeasurementInputs } from './measurement-model.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const byId = id => document.getElementById(id); const fields = Object.fromEntries(['count', 'realizations', 'lower', 'upper'].map(name => [name, byId(`measure-${name}`)])); diff --git a/docs/site/museum.html b/docs/site/museum.html index e77825090..6d51098b5 100644 --- a/docs/site/museum.html +++ b/docs/site/museum.html @@ -5,14 +5,14 @@ Source records & exhibits · Universal Law - + - - + + - - + + diff --git a/docs/site/museum.mjs b/docs/site/museum.mjs index fb76d3b88..41a82c68f 100644 --- a/docs/site/museum.mjs +++ b/docs/site/museum.mjs @@ -1,5 +1,5 @@ -import {renderSourceQuote} from './source-quote.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import {verifiedBytes, hex40, hex64} from './core.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import {renderSourceQuote} from './source-quote.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import {verifiedBytes, hex40, hex64} from './core.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; export const DISCLAIMER='This canvas explains the pinned source. It is not a proof and does not change status.'; const REVIEWED_IDS=['d2-lifetime-remainder','d3-side24-coefficient','d4-fixed-remote-rn','d5-all-height-annulus','d5-height-window-annulus','d5-two-scale','d5-inner-belt-density','d5-fixed-transverse','cumulative-transfer-correction','p15-demand-one-counterexample','d6-p15-full-price']; @@ -264,7 +264,7 @@ function prepareClaimFragment(document,window,currentHash) { return true; }; } -export async function startMuseum({document=globalThis.document,window=globalThis.window,fetcher=globalThis.fetch,search=globalThis.location?.search||'',geometryLoader=()=>import('./geometry.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'),currentHash=()=>globalThis.location?.hash||''}={}){ +export async function startMuseum({document=globalThis.document,window=globalThis.window,fetcher=globalThis.fetch,search=globalThis.location?.search||'',geometryLoader=()=>import('./geometry.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'),currentHash=()=>globalThis.location?.hash||''}={}){ const ids=['museum-state','claim-cards','lifetime-fixture','packet-cards','active-exhibit']; const containers=Object.fromEntries(ids.map(id=>{const node=document.getElementById(id);if(!node)throw Error(`Missing museum container: ${id}`);return [id,node];})); const finishFragment=prepareClaimFragment(document,window,currentHash); diff --git a/docs/site/nodes/eng.d0-packet-allowlist-fix.html b/docs/site/nodes/eng.d0-packet-allowlist-fix.html index 0fcf618d8..1b541d01d 100644 --- a/docs/site/nodes/eng.d0-packet-allowlist-fix.html +++ b/docs/site/nodes/eng.d0-packet-allowlist-fix.html @@ -4,7 +4,7 @@ eng.d0-packet-allowlist-fix · Current research dependency atlas - +
diff --git a/docs/site/nodes/eng.hard-gate.html b/docs/site/nodes/eng.hard-gate.html index e6f97385f..b39da4c12 100644 --- a/docs/site/nodes/eng.hard-gate.html +++ b/docs/site/nodes/eng.hard-gate.html @@ -4,7 +4,7 @@ eng.hard-gate · Current research dependency atlas - +
diff --git a/docs/site/nodes/eng.main-pr87-crosswalk.html b/docs/site/nodes/eng.main-pr87-crosswalk.html index 662e4cb78..5a0c7e833 100644 --- a/docs/site/nodes/eng.main-pr87-crosswalk.html +++ b/docs/site/nodes/eng.main-pr87-crosswalk.html @@ -4,7 +4,7 @@ eng.main-pr87-crosswalk · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.ALLCELL-FDZ-Q4.html b/docs/site/nodes/hist.ALLCELL-FDZ-Q4.html index 784dd9366..892333f3e 100644 --- a/docs/site/nodes/hist.ALLCELL-FDZ-Q4.html +++ b/docs/site/nodes/hist.ALLCELL-FDZ-Q4.html @@ -4,7 +4,7 @@ hist.ALLCELL-FDZ-Q4 · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.CH-LIFT.html b/docs/site/nodes/hist.CH-LIFT.html index 08c0754fc..f44f83ee3 100644 --- a/docs/site/nodes/hist.CH-LIFT.html +++ b/docs/site/nodes/hist.CH-LIFT.html @@ -4,7 +4,7 @@ hist.CH-LIFT · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html b/docs/site/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html index 83260eda4..8720606cc 100644 --- a/docs/site/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html +++ b/docs/site/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html @@ -4,7 +4,7 @@ hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.ENV-RESCOV.html b/docs/site/nodes/hist.ENV-RESCOV.html index d8bebef21..c31d1480d 100644 --- a/docs/site/nodes/hist.ENV-RESCOV.html +++ b/docs/site/nodes/hist.ENV-RESCOV.html @@ -4,7 +4,7 @@ hist.ENV-RESCOV · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.LOGQ-TAIL.html b/docs/site/nodes/hist.LOGQ-TAIL.html index d8bef685e..db7f2ecf8 100644 --- a/docs/site/nodes/hist.LOGQ-TAIL.html +++ b/docs/site/nodes/hist.LOGQ-TAIL.html @@ -4,7 +4,7 @@ hist.LOGQ-TAIL · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.OBL-H5-JETMOD.html b/docs/site/nodes/hist.OBL-H5-JETMOD.html index c19f1ad2d..c869d52b0 100644 --- a/docs/site/nodes/hist.OBL-H5-JETMOD.html +++ b/docs/site/nodes/hist.OBL-H5-JETMOD.html @@ -4,7 +4,7 @@ hist.OBL-H5-JETMOD · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.Piece-2-annulus.html b/docs/site/nodes/hist.Piece-2-annulus.html index 38cda1b78..a68f4e16c 100644 --- a/docs/site/nodes/hist.Piece-2-annulus.html +++ b/docs/site/nodes/hist.Piece-2-annulus.html @@ -4,7 +4,7 @@ hist.Piece-2-annulus · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.SYM-Fw-jet.html b/docs/site/nodes/hist.SYM-Fw-jet.html index de3e1d5eb..adf348a1a 100644 --- a/docs/site/nodes/hist.SYM-Fw-jet.html +++ b/docs/site/nodes/hist.SYM-Fw-jet.html @@ -4,7 +4,7 @@ hist.SYM-Fw-jet · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.allcell_fdz_enclosures.json.html b/docs/site/nodes/hist.allcell_fdz_enclosures.json.html index a91b40973..9f6f3c34e 100644 --- a/docs/site/nodes/hist.allcell_fdz_enclosures.json.html +++ b/docs/site/nodes/hist.allcell_fdz_enclosures.json.html @@ -4,7 +4,7 @@ hist.allcell_fdz_enclosures.json · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.lemma_closed.html b/docs/site/nodes/hist.lemma_closed.html index 34a2e9737..247aa694f 100644 --- a/docs/site/nodes/hist.lemma_closed.html +++ b/docs/site/nodes/hist.lemma_closed.html @@ -4,7 +4,7 @@ hist.lemma_closed · Current research dependency atlas - +
diff --git a/docs/site/nodes/hist.rnu_env.py.html b/docs/site/nodes/hist.rnu_env.py.html index 5647dcfbe..8e70932b1 100644 --- a/docs/site/nodes/hist.rnu_env.py.html +++ b/docs/site/nodes/hist.rnu_env.py.html @@ -4,7 +4,7 @@ hist.rnu_env.py · Current research dependency atlas - +
diff --git a/docs/site/nodes/index.html b/docs/site/nodes/index.html index 5cc798804..5f61a96f2 100644 --- a/docs/site/nodes/index.html +++ b/docs/site/nodes/index.html @@ -4,7 +4,7 @@ Current static graph, equation excerpts and source index · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d1-component.congruence-erratum.html b/docs/site/nodes/math.d1-component.congruence-erratum.html index 8f46acf5f..5e4498ad7 100644 --- a/docs/site/nodes/math.d1-component.congruence-erratum.html +++ b/docs/site/nodes/math.d1-component.congruence-erratum.html @@ -4,7 +4,7 @@ math.d1-component.congruence-erratum · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d1-component.marked-cylinder-cap.html b/docs/site/nodes/math.d1-component.marked-cylinder-cap.html index 3d2f2426d..451e83192 100644 --- a/docs/site/nodes/math.d1-component.marked-cylinder-cap.html +++ b/docs/site/nodes/math.d1-component.marked-cylinder-cap.html @@ -4,7 +4,7 @@ math.d1-component.marked-cylinder-cap · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d1-component.reconciliation-record.html b/docs/site/nodes/math.d1-component.reconciliation-record.html index 7816664a3..c329485cb 100644 --- a/docs/site/nodes/math.d1-component.reconciliation-record.html +++ b/docs/site/nodes/math.d1-component.reconciliation-record.html @@ -4,7 +4,7 @@ math.d1-component.reconciliation-record · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d1-component.section9-replacement-v1_1.html b/docs/site/nodes/math.d1-component.section9-replacement-v1_1.html index 7c4f59224..cd3438f34 100644 --- a/docs/site/nodes/math.d1-component.section9-replacement-v1_1.html +++ b/docs/site/nodes/math.d1-component.section9-replacement-v1_1.html @@ -4,7 +4,7 @@ math.d1-component.section9-replacement-v1_1 · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.annulus-proof.html b/docs/site/nodes/math.d5-component.annulus-proof.html index 35f38b228..7aa361ec5 100644 --- a/docs/site/nodes/math.d5-component.annulus-proof.html +++ b/docs/site/nodes/math.d5-component.annulus-proof.html @@ -4,7 +4,7 @@ math.d5-component.annulus-proof · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.annulus-review.html b/docs/site/nodes/math.d5-component.annulus-review.html index cfe42fb54..3c2ad7378 100644 --- a/docs/site/nodes/math.d5-component.annulus-review.html +++ b/docs/site/nodes/math.d5-component.annulus-review.html @@ -4,7 +4,7 @@ math.d5-component.annulus-review · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.collar-proof.html b/docs/site/nodes/math.d5-component.collar-proof.html index cd9104178..0fec1cac8 100644 --- a/docs/site/nodes/math.d5-component.collar-proof.html +++ b/docs/site/nodes/math.d5-component.collar-proof.html @@ -4,7 +4,7 @@ math.d5-component.collar-proof · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.collar-review.html b/docs/site/nodes/math.d5-component.collar-review.html index 52487ff5d..57bc2b253 100644 --- a/docs/site/nodes/math.d5-component.collar-review.html +++ b/docs/site/nodes/math.d5-component.collar-review.html @@ -4,7 +4,7 @@ math.d5-component.collar-review · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.i5-review-claude.html b/docs/site/nodes/math.d5-component.i5-review-claude.html index e83b59eb8..fe3f64497 100644 --- a/docs/site/nodes/math.d5-component.i5-review-claude.html +++ b/docs/site/nodes/math.d5-component.i5-review-claude.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-claude · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.i5-review-xai.html b/docs/site/nodes/math.d5-component.i5-review-xai.html index e6ddf8f1e..57b28c418 100644 --- a/docs/site/nodes/math.d5-component.i5-review-xai.html +++ b/docs/site/nodes/math.d5-component.i5-review-xai.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-xai · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.intermediate-window-proof.html b/docs/site/nodes/math.d5-component.intermediate-window-proof.html index ef7e978a9..5c975e27a 100644 --- a/docs/site/nodes/math.d5-component.intermediate-window-proof.html +++ b/docs/site/nodes/math.d5-component.intermediate-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.intermediate-window-proof · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.offpin-second-moment-review.html b/docs/site/nodes/math.d5-component.offpin-second-moment-review.html index 8480c26dd..b21fc5cf7 100644 --- a/docs/site/nodes/math.d5-component.offpin-second-moment-review.html +++ b/docs/site/nodes/math.d5-component.offpin-second-moment-review.html @@ -4,7 +4,7 @@ math.d5-component.offpin-second-moment-review · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.punctured-pin-continuum-check.html b/docs/site/nodes/math.d5-component.punctured-pin-continuum-check.html index edeeba30f..afdb439bb 100644 --- a/docs/site/nodes/math.d5-component.punctured-pin-continuum-check.html +++ b/docs/site/nodes/math.d5-component.punctured-pin-continuum-check.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-check · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.punctured-pin-continuum-review.html b/docs/site/nodes/math.d5-component.punctured-pin-continuum-review.html index fa5e7a874..645e271dd 100644 --- a/docs/site/nodes/math.d5-component.punctured-pin-continuum-review.html +++ b/docs/site/nodes/math.d5-component.punctured-pin-continuum-review.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-review · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.punctured-pin-proof.html b/docs/site/nodes/math.d5-component.punctured-pin-proof.html index c5e438f44..f5a316d7a 100644 --- a/docs/site/nodes/math.d5-component.punctured-pin-proof.html +++ b/docs/site/nodes/math.d5-component.punctured-pin-proof.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-proof · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.punctured-pin-review-111.html b/docs/site/nodes/math.d5-component.punctured-pin-review-111.html index b965270ad..4760038b1 100644 --- a/docs/site/nodes/math.d5-component.punctured-pin-review-111.html +++ b/docs/site/nodes/math.d5-component.punctured-pin-review-111.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-review-111 · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-component.remote-window-proof.html b/docs/site/nodes/math.d5-component.remote-window-proof.html index 6e6849d06..35d6ca34b 100644 --- a/docs/site/nodes/math.d5-component.remote-window-proof.html +++ b/docs/site/nodes/math.d5-component.remote-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.remote-window-proof · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.d5-pin-neighborhood-first-moment.html b/docs/site/nodes/math.d5-pin-neighborhood-first-moment.html index 49da5d893..bbde27a46 100644 --- a/docs/site/nodes/math.d5-pin-neighborhood-first-moment.html +++ b/docs/site/nodes/math.d5-pin-neighborhood-first-moment.html @@ -4,7 +4,7 @@ math.d5-pin-neighborhood-first-moment · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.lifetime-remainder.html b/docs/site/nodes/math.lifetime-remainder.html index 10be396e9..0988a0395 100644 --- a/docs/site/nodes/math.lifetime-remainder.html +++ b/docs/site/nodes/math.lifetime-remainder.html @@ -4,7 +4,7 @@ math.lifetime-remainder · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.p15-full-price.html b/docs/site/nodes/math.p15-full-price.html index fea11fc97..75d08a193 100644 --- a/docs/site/nodes/math.p15-full-price.html +++ b/docs/site/nodes/math.p15-full-price.html @@ -4,7 +4,7 @@ math.p15-full-price · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.p15-price-boundary.html b/docs/site/nodes/math.p15-price-boundary.html index bd86a1edf..26494ef1a 100644 --- a/docs/site/nodes/math.p15-price-boundary.html +++ b/docs/site/nodes/math.p15-price-boundary.html @@ -4,7 +4,7 @@ math.p15-price-boundary · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-count-interface.html b/docs/site/nodes/math.rn-count-interface.html index 7a5b7107a..5db02bea9 100644 --- a/docs/site/nodes/math.rn-count-interface.html +++ b/docs/site/nodes/math.rn-count-interface.html @@ -4,7 +4,7 @@ math.rn-count-interface · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-fixed-annulus-window.html b/docs/site/nodes/math.rn-fixed-annulus-window.html index 496d2d947..4769a1dc0 100644 --- a/docs/site/nodes/math.rn-fixed-annulus-window.html +++ b/docs/site/nodes/math.rn-fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-fixed-annulus-window · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-fixed-remote-window.html b/docs/site/nodes/math.rn-fixed-remote-window.html index 253b023ea..609b572bb 100644 --- a/docs/site/nodes/math.rn-fixed-remote-window.html +++ b/docs/site/nodes/math.rn-fixed-remote-window.html @@ -4,7 +4,7 @@ math.rn-fixed-remote-window · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-mesoscopic-reduction.html b/docs/site/nodes/math.rn-mesoscopic-reduction.html index 4c0f307be..1164d991a 100644 --- a/docs/site/nodes/math.rn-mesoscopic-reduction.html +++ b/docs/site/nodes/math.rn-mesoscopic-reduction.html @@ -4,7 +4,7 @@ math.rn-mesoscopic-reduction · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.fixed-annulus-window.html b/docs/site/nodes/math.rn-region.fixed-annulus-window.html index f2e7e46d6..4742ca979 100644 --- a/docs/site/nodes/math.rn-region.fixed-annulus-window.html +++ b/docs/site/nodes/math.rn-region.fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-region.fixed-annulus-window · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.fixed-remote.html b/docs/site/nodes/math.rn-region.fixed-remote.html index 3f5507093..1b78dc8fb 100644 --- a/docs/site/nodes/math.rn-region.fixed-remote.html +++ b/docs/site/nodes/math.rn-region.fixed-remote.html @@ -4,7 +4,7 @@ math.rn-region.fixed-remote · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.intermediate-r-to-rho.html b/docs/site/nodes/math.rn-region.intermediate-r-to-rho.html index 361e6ca7b..8cce97e56 100644 --- a/docs/site/nodes/math.rn-region.intermediate-r-to-rho.html +++ b/docs/site/nodes/math.rn-region.intermediate-r-to-rho.html @@ -4,7 +4,7 @@ math.rn-region.intermediate-r-to-rho · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.mesoscopic-scaled-annulus.html b/docs/site/nodes/math.rn-region.mesoscopic-scaled-annulus.html index 334742938..a4d6f744a 100644 --- a/docs/site/nodes/math.rn-region.mesoscopic-scaled-annulus.html +++ b/docs/site/nodes/math.rn-region.mesoscopic-scaled-annulus.html @@ -4,7 +4,7 @@ math.rn-region.mesoscopic-scaled-annulus · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.pin-collision.html b/docs/site/nodes/math.rn-region.pin-collision.html index b7b8f32df..d06f3a59a 100644 --- a/docs/site/nodes/math.rn-region.pin-collision.html +++ b/docs/site/nodes/math.rn-region.pin-collision.html @@ -4,7 +4,7 @@ math.rn-region.pin-collision · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-region.witness-collision.html b/docs/site/nodes/math.rn-region.witness-collision.html index 26d1e1f6b..62bd5eab6 100644 --- a/docs/site/nodes/math.rn-region.witness-collision.html +++ b/docs/site/nodes/math.rn-region.witness-collision.html @@ -4,7 +4,7 @@ math.rn-region.witness-collision · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.rn-selector-region-crosswalk.html b/docs/site/nodes/math.rn-selector-region-crosswalk.html index ae1d1b0a6..eedf845d5 100644 --- a/docs/site/nodes/math.rn-selector-region-crosswalk.html +++ b/docs/site/nodes/math.rn-selector-region-crosswalk.html @@ -4,7 +4,7 @@ math.rn-selector-region-crosswalk · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.side24-coefficient.html b/docs/site/nodes/math.side24-coefficient.html index cdaa4f2a3..2d8281e2a 100644 --- a/docs/site/nodes/math.side24-coefficient.html +++ b/docs/site/nodes/math.side24-coefficient.html @@ -4,7 +4,7 @@ math.side24-coefficient · Current research dependency atlas - +
diff --git a/docs/site/nodes/math.uniform-matrix-cap-lifetime.html b/docs/site/nodes/math.uniform-matrix-cap-lifetime.html index 12d91ec04..901601a3f 100644 --- a/docs/site/nodes/math.uniform-matrix-cap-lifetime.html +++ b/docs/site/nodes/math.uniform-matrix-cap-lifetime.html @@ -4,7 +4,7 @@ math.uniform-matrix-cap-lifetime · Current research dependency atlas - +
diff --git a/docs/site/nodes/regional.fixed-annulus.high-jet-route.html b/docs/site/nodes/regional.fixed-annulus.high-jet-route.html index c262220c1..2eaa24cad 100644 --- a/docs/site/nodes/regional.fixed-annulus.high-jet-route.html +++ b/docs/site/nodes/regional.fixed-annulus.high-jet-route.html @@ -4,7 +4,7 @@ regional.fixed-annulus.high-jet-route · Current research dependency atlas - +
diff --git a/docs/site/palette-export.mjs b/docs/site/palette-export.mjs index 46cab525c..9bba11d2a 100644 --- a/docs/site/palette-export.mjs +++ b/docs/site/palette-export.mjs @@ -1,7 +1,7 @@ // Bounded teaching export of Explore's current finite P15 diagram. Source // custody is provenance; this module performs no mathematical verification. -import { paletteModel } from './explore-models.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { serializeTeachingSVG } from './teaching-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { paletteModel } from './explore-models.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { serializeTeachingSVG } from './teaching-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const PUBLIC_EXPLORE = 'https://d6g8k5htny-coder.github.io/main/site/explore.html'; const SOURCE = Object.freeze({ diff --git a/docs/site/pin-export.mjs b/docs/site/pin-export.mjs index 38b74ec70..bd966dd98 100644 --- a/docs/site/pin-export.mjs +++ b/docs/site/pin-export.mjs @@ -1,7 +1,7 @@ // Bounded export of the CURRENT displayed Approach-points teaching diagram. // Pinned source identities are provenance, not proof acceptance or verification. -import { pinModel } from './explore-models.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; -import { serializeTeachingSVG } from './teaching-export.mjs?site-release=4764cf2cfa0123b97aca3ec6ff8a1aba79e9ad1b5506d8616775b59c20e65ebc'; +import { pinModel } from './explore-models.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; +import { serializeTeachingSVG } from './teaching-export.mjs?site-release=89345c3c666c10e7247e5c1effbb49ef17b4f65bab75eb811abbd929079a1a53'; const PUBLIC_EXPLORE='https://d6g8k5htny-coder.github.io/main/site/explore.html'; const COMMIT='d6628da09384728992dcbe6e921cc28ba85aebb0'; diff --git a/docs/site/reproduce.html b/docs/site/reproduce.html index ee4ede451..3c9992a22 100644 --- a/docs/site/reproduce.html +++ b/docs/site/reproduce.html @@ -2,13 +2,13 @@ - + Reproduce · Universal Law - + - - - + + +
UNIVERSAL LAW MATHEMATICS IN THE OPEN
diff --git a/docs/site/research.html b/docs/site/research.html index 04f182c4f..1f4152baa 100644 --- a/docs/site/research.html +++ b/docs/site/research.html @@ -4,8 +4,8 @@ Research · Universal Law - - + +
UNIVERSAL LAW MATHEMATICS IN THE OPEN
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.d0-packet-allowlist-fix.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.d0-packet-allowlist-fix.html index 2583fa262..4d58ddf01 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.d0-packet-allowlist-fix.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.d0-packet-allowlist-fix.html @@ -4,7 +4,7 @@ eng.d0-packet-allowlist-fix · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.hard-gate.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.hard-gate.html index a2199e8fb..a300f60f2 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.hard-gate.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.hard-gate.html @@ -4,7 +4,7 @@ eng.hard-gate · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.main-pr87-crosswalk.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.main-pr87-crosswalk.html index 949464d35..42e3ac2f3 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.main-pr87-crosswalk.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/eng.main-pr87-crosswalk.html @@ -4,7 +4,7 @@ eng.main-pr87-crosswalk · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ALLCELL-FDZ-Q4.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ALLCELL-FDZ-Q4.html index 044910461..c63b89bd0 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ALLCELL-FDZ-Q4.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ALLCELL-FDZ-Q4.html @@ -4,7 +4,7 @@ hist.ALLCELL-FDZ-Q4 · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CH-LIFT.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CH-LIFT.html index c73a3b9ec..e73b97189 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CH-LIFT.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CH-LIFT.html @@ -4,7 +4,7 @@ hist.CH-LIFT · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html index dc2a152fd..41d8abaff 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html @@ -4,7 +4,7 @@ hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ENV-RESCOV.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ENV-RESCOV.html index 15487886d..ed61c0832 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ENV-RESCOV.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.ENV-RESCOV.html @@ -4,7 +4,7 @@ hist.ENV-RESCOV · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.LOGQ-TAIL.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.LOGQ-TAIL.html index ea538db45..11f66a84b 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.LOGQ-TAIL.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.LOGQ-TAIL.html @@ -4,7 +4,7 @@ hist.LOGQ-TAIL · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.OBL-H5-JETMOD.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.OBL-H5-JETMOD.html index aa0d42555..87e219a57 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.OBL-H5-JETMOD.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.OBL-H5-JETMOD.html @@ -4,7 +4,7 @@ hist.OBL-H5-JETMOD · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.Piece-2-annulus.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.Piece-2-annulus.html index c0199da36..3cdbf84ed 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.Piece-2-annulus.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.Piece-2-annulus.html @@ -4,7 +4,7 @@ hist.Piece-2-annulus · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.SYM-Fw-jet.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.SYM-Fw-jet.html index 071eafeb7..7b81d4401 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.SYM-Fw-jet.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.SYM-Fw-jet.html @@ -4,7 +4,7 @@ hist.SYM-Fw-jet · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.allcell_fdz_enclosures.json.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.allcell_fdz_enclosures.json.html index f9c8b2ba5..f5c843cae 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.allcell_fdz_enclosures.json.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.allcell_fdz_enclosures.json.html @@ -4,7 +4,7 @@ hist.allcell_fdz_enclosures.json · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.lemma_closed.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.lemma_closed.html index 64373849c..3997fafa3 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.lemma_closed.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.lemma_closed.html @@ -4,7 +4,7 @@ hist.lemma_closed · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.rnu_env.py.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.rnu_env.py.html index 94f1aada6..c5fbbc97c 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.rnu_env.py.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/hist.rnu_env.py.html @@ -4,7 +4,7 @@ hist.rnu_env.py · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/index.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/index.html index 4633ed2cc..ac88a81ba 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/index.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/index.html @@ -4,7 +4,7 @@ Static graph and source index · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.congruence-erratum.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.congruence-erratum.html index 8cbbb9e1c..5ac67620d 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.congruence-erratum.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.congruence-erratum.html @@ -4,7 +4,7 @@ math.d1-component.congruence-erratum · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.marked-cylinder-cap.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.marked-cylinder-cap.html index b517de77d..3312d374b 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.marked-cylinder-cap.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.marked-cylinder-cap.html @@ -4,7 +4,7 @@ math.d1-component.marked-cylinder-cap · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.reconciliation-record.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.reconciliation-record.html index 9bf6bc010..4c5c15c60 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.reconciliation-record.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.reconciliation-record.html @@ -4,7 +4,7 @@ math.d1-component.reconciliation-record · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.section9-replacement-v1_1.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.section9-replacement-v1_1.html index 18efdc921..c3043e3a8 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.section9-replacement-v1_1.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d1-component.section9-replacement-v1_1.html @@ -4,7 +4,7 @@ math.d1-component.section9-replacement-v1_1 · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-proof.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-proof.html index 9fe871cd3..478bf96b9 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-proof.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-proof.html @@ -4,7 +4,7 @@ math.d5-component.annulus-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-review.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-review.html index a141011c7..b8e0ea4bb 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-review.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.annulus-review.html @@ -4,7 +4,7 @@ math.d5-component.annulus-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-proof.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-proof.html index 5551df2f4..77b482020 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-proof.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-proof.html @@ -4,7 +4,7 @@ math.d5-component.collar-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-review.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-review.html index ae1fcba7d..ec12dcd39 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-review.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.collar-review.html @@ -4,7 +4,7 @@ math.d5-component.collar-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-claude.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-claude.html index 85a64ea1f..6a471dcef 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-claude.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-claude.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-claude · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-xai.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-xai.html index 6f1c415d2..24942ab91 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-xai.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.i5-review-xai.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-xai · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.intermediate-window-proof.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.intermediate-window-proof.html index cb04c752a..da5ab8521 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.intermediate-window-proof.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.intermediate-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.intermediate-window-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.offpin-second-moment-review.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.offpin-second-moment-review.html index f055ffee6..ffb392f52 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.offpin-second-moment-review.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.offpin-second-moment-review.html @@ -4,7 +4,7 @@ math.d5-component.offpin-second-moment-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-check.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-check.html index cf3fb6321..68e1271c6 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-check.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-check.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-check · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-review.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-review.html index 253c9ec7a..e562a2a18 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-review.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-continuum-review.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-proof.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-proof.html index 392c43ffb..117285c49 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-proof.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-proof.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-review-111.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-review-111.html index e24fda93d..d385f8b1c 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-review-111.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.punctured-pin-review-111.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-review-111 · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.remote-window-proof.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.remote-window-proof.html index 8723b3258..1ee792c79 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.remote-window-proof.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-component.remote-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.remote-window-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-pin-neighborhood-first-moment.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-pin-neighborhood-first-moment.html index c698e3b26..78670d4ae 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-pin-neighborhood-first-moment.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.d5-pin-neighborhood-first-moment.html @@ -4,7 +4,7 @@ math.d5-pin-neighborhood-first-moment · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.lifetime-remainder.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.lifetime-remainder.html index 69200c3f4..0f9132888 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.lifetime-remainder.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.lifetime-remainder.html @@ -4,7 +4,7 @@ math.lifetime-remainder · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-full-price.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-full-price.html index 53c8f821d..be5f8cb24 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-full-price.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-full-price.html @@ -4,7 +4,7 @@ math.p15-full-price · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-price-boundary.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-price-boundary.html index 1033e5d12..3ced73c58 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-price-boundary.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.p15-price-boundary.html @@ -4,7 +4,7 @@ math.p15-price-boundary · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-count-interface.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-count-interface.html index 7f55d5069..68bb39755 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-count-interface.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-count-interface.html @@ -4,7 +4,7 @@ math.rn-count-interface · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-annulus-window.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-annulus-window.html index 1b8a55ee3..3d66bbd63 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-annulus-window.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-fixed-annulus-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-remote-window.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-remote-window.html index 70236cb8b..450a562f0 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-remote-window.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-fixed-remote-window.html @@ -4,7 +4,7 @@ math.rn-fixed-remote-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-mesoscopic-reduction.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-mesoscopic-reduction.html index c3159c20f..380fdb7c7 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-mesoscopic-reduction.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-mesoscopic-reduction.html @@ -4,7 +4,7 @@ math.rn-mesoscopic-reduction · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-annulus-window.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-annulus-window.html index 9623cd9e0..753ef6855 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-annulus-window.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-region.fixed-annulus-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-remote.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-remote.html index a745e017e..d0013e976 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-remote.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.fixed-remote.html @@ -4,7 +4,7 @@ math.rn-region.fixed-remote · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.intermediate-r-to-rho.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.intermediate-r-to-rho.html index 1b0e4bd16..30a7c914a 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.intermediate-r-to-rho.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.intermediate-r-to-rho.html @@ -4,7 +4,7 @@ math.rn-region.intermediate-r-to-rho · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.mesoscopic-scaled-annulus.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.mesoscopic-scaled-annulus.html index b1cc70338..647adf223 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.mesoscopic-scaled-annulus.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.mesoscopic-scaled-annulus.html @@ -4,7 +4,7 @@ math.rn-region.mesoscopic-scaled-annulus · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.pin-collision.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.pin-collision.html index 3d69b3ddb..3af9453b1 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.pin-collision.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.pin-collision.html @@ -4,7 +4,7 @@ math.rn-region.pin-collision · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.witness-collision.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.witness-collision.html index dbdf0d1c1..6b68f15d6 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.witness-collision.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-region.witness-collision.html @@ -4,7 +4,7 @@ math.rn-region.witness-collision · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-selector-region-crosswalk.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-selector-region-crosswalk.html index cbdf9cad8..ac423af3c 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-selector-region-crosswalk.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.rn-selector-region-crosswalk.html @@ -4,7 +4,7 @@ math.rn-selector-region-crosswalk · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.side24-coefficient.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.side24-coefficient.html index 9a8f0a708..4331245e2 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.side24-coefficient.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.side24-coefficient.html @@ -4,7 +4,7 @@ math.side24-coefficient · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.uniform-matrix-cap-lifetime.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.uniform-matrix-cap-lifetime.html index 5e75f3547..9df3abfca 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.uniform-matrix-cap-lifetime.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/math.uniform-matrix-cap-lifetime.html @@ -4,7 +4,7 @@ math.uniform-matrix-cap-lifetime · Research dependency atlas - +
diff --git a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/regional.fixed-annulus.high-jet-route.html b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/regional.fixed-annulus.high-jet-route.html index aea9c2cbf..7ad0a139f 100644 --- a/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/regional.fixed-annulus.high-jet-route.html +++ b/docs/site/snapshots/38ac44c585feb2f9a480d8e54ad1a7fe56ad35aff19e2eab929861ea81974644/nodes/regional.fixed-annulus.high-jet-route.html @@ -4,7 +4,7 @@ regional.fixed-annulus.high-jet-route · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.d0-packet-allowlist-fix.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.d0-packet-allowlist-fix.html index cf2e14b30..5a3ce813c 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.d0-packet-allowlist-fix.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.d0-packet-allowlist-fix.html @@ -4,7 +4,7 @@ eng.d0-packet-allowlist-fix · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.hard-gate.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.hard-gate.html index 5b1626021..0b8cb80f2 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.hard-gate.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.hard-gate.html @@ -4,7 +4,7 @@ eng.hard-gate · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.main-pr87-crosswalk.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.main-pr87-crosswalk.html index 8a5d58045..b5c860cd0 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.main-pr87-crosswalk.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/eng.main-pr87-crosswalk.html @@ -4,7 +4,7 @@ eng.main-pr87-crosswalk · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ALLCELL-FDZ-Q4.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ALLCELL-FDZ-Q4.html index d670fc3c3..85222a170 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ALLCELL-FDZ-Q4.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ALLCELL-FDZ-Q4.html @@ -4,7 +4,7 @@ hist.ALLCELL-FDZ-Q4 · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CH-LIFT.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CH-LIFT.html index fd75d5f73..b8b810753 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CH-LIFT.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CH-LIFT.html @@ -4,7 +4,7 @@ hist.CH-LIFT · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html index 5dc472e4c..3db221741 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip.html @@ -4,7 +4,7 @@ hist.CL_ANTHROPIC_BUNDLE_2026-09-17_v5.zip · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ENV-RESCOV.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ENV-RESCOV.html index 0b3aa18cb..129200111 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ENV-RESCOV.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.ENV-RESCOV.html @@ -4,7 +4,7 @@ hist.ENV-RESCOV · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.LOGQ-TAIL.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.LOGQ-TAIL.html index c8d41538f..082a57982 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.LOGQ-TAIL.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.LOGQ-TAIL.html @@ -4,7 +4,7 @@ hist.LOGQ-TAIL · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.OBL-H5-JETMOD.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.OBL-H5-JETMOD.html index ee9c888e9..d1c449d83 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.OBL-H5-JETMOD.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.OBL-H5-JETMOD.html @@ -4,7 +4,7 @@ hist.OBL-H5-JETMOD · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.Piece-2-annulus.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.Piece-2-annulus.html index f7c00f058..77109445e 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.Piece-2-annulus.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.Piece-2-annulus.html @@ -4,7 +4,7 @@ hist.Piece-2-annulus · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.SYM-Fw-jet.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.SYM-Fw-jet.html index 7eaf1265d..19d43a73a 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.SYM-Fw-jet.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.SYM-Fw-jet.html @@ -4,7 +4,7 @@ hist.SYM-Fw-jet · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.allcell_fdz_enclosures.json.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.allcell_fdz_enclosures.json.html index 8a932bc04..e372e3d06 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.allcell_fdz_enclosures.json.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.allcell_fdz_enclosures.json.html @@ -4,7 +4,7 @@ hist.allcell_fdz_enclosures.json · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.lemma_closed.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.lemma_closed.html index b38c329dc..c8e2085b0 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.lemma_closed.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.lemma_closed.html @@ -4,7 +4,7 @@ hist.lemma_closed · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.rnu_env.py.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.rnu_env.py.html index 97f342980..f18b83d84 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.rnu_env.py.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/hist.rnu_env.py.html @@ -4,7 +4,7 @@ hist.rnu_env.py · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/index.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/index.html index 8565248e9..a3320a2e6 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/index.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/index.html @@ -4,7 +4,7 @@ Static graph and source index · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.congruence-erratum.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.congruence-erratum.html index 7cf14e05a..0fbe93e95 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.congruence-erratum.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.congruence-erratum.html @@ -4,7 +4,7 @@ math.d1-component.congruence-erratum · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.marked-cylinder-cap.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.marked-cylinder-cap.html index 209bde55e..07ba1e3c5 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.marked-cylinder-cap.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.marked-cylinder-cap.html @@ -4,7 +4,7 @@ math.d1-component.marked-cylinder-cap · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.reconciliation-record.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.reconciliation-record.html index fc374061a..d0292fb16 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.reconciliation-record.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.reconciliation-record.html @@ -4,7 +4,7 @@ math.d1-component.reconciliation-record · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.section9-replacement-v1_1.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.section9-replacement-v1_1.html index d2ae3e5b9..04b2ed41c 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.section9-replacement-v1_1.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d1-component.section9-replacement-v1_1.html @@ -4,7 +4,7 @@ math.d1-component.section9-replacement-v1_1 · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-proof.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-proof.html index 4806d5b4b..8ca56d6a2 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-proof.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-proof.html @@ -4,7 +4,7 @@ math.d5-component.annulus-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-review.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-review.html index c48a42d1f..08cc66dab 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-review.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.annulus-review.html @@ -4,7 +4,7 @@ math.d5-component.annulus-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-proof.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-proof.html index 2fc0fad8a..021d7a0ea 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-proof.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-proof.html @@ -4,7 +4,7 @@ math.d5-component.collar-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-review.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-review.html index 61cd49927..3d0a4b7e7 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-review.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.collar-review.html @@ -4,7 +4,7 @@ math.d5-component.collar-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-claude.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-claude.html index 6f1687125..ccb631d4c 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-claude.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-claude.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-claude · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-xai.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-xai.html index 6533c8158..f72dad2cf 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-xai.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.i5-review-xai.html @@ -4,7 +4,7 @@ math.d5-component.i5-review-xai · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.intermediate-window-proof.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.intermediate-window-proof.html index e595e7b56..6ea968d62 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.intermediate-window-proof.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.intermediate-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.intermediate-window-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.offpin-second-moment-review.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.offpin-second-moment-review.html index 6c06f2474..8188ffca4 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.offpin-second-moment-review.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.offpin-second-moment-review.html @@ -4,7 +4,7 @@ math.d5-component.offpin-second-moment-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-check.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-check.html index 4e63c7d26..1bc7817e6 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-check.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-check.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-check · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-review.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-review.html index 80e85e5f2..a9c56bed1 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-review.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-continuum-review.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-continuum-review · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-proof.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-proof.html index b2e4a62e8..eb7647244 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-proof.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-proof.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-review-111.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-review-111.html index c82f601e6..40f52e07c 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-review-111.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.punctured-pin-review-111.html @@ -4,7 +4,7 @@ math.d5-component.punctured-pin-review-111 · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.remote-window-proof.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.remote-window-proof.html index 430fa88c6..a27a15cd0 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.remote-window-proof.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-component.remote-window-proof.html @@ -4,7 +4,7 @@ math.d5-component.remote-window-proof · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-pin-neighborhood-first-moment.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-pin-neighborhood-first-moment.html index 65acfb853..d2776c5e8 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-pin-neighborhood-first-moment.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.d5-pin-neighborhood-first-moment.html @@ -4,7 +4,7 @@ math.d5-pin-neighborhood-first-moment · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.lifetime-remainder.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.lifetime-remainder.html index 7420bddb8..71b9562c0 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.lifetime-remainder.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.lifetime-remainder.html @@ -4,7 +4,7 @@ math.lifetime-remainder · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-full-price.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-full-price.html index b0f65cf83..87310e6ec 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-full-price.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-full-price.html @@ -4,7 +4,7 @@ math.p15-full-price · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-price-boundary.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-price-boundary.html index 365a72d57..de1234ac1 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-price-boundary.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.p15-price-boundary.html @@ -4,7 +4,7 @@ math.p15-price-boundary · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-count-interface.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-count-interface.html index 17d70a4ba..1f8d76968 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-count-interface.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-count-interface.html @@ -4,7 +4,7 @@ math.rn-count-interface · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-annulus-window.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-annulus-window.html index 040d37859..f63b442e7 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-annulus-window.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-fixed-annulus-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-remote-window.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-remote-window.html index 5efc977d7..2c16df51d 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-remote-window.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-fixed-remote-window.html @@ -4,7 +4,7 @@ math.rn-fixed-remote-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-mesoscopic-reduction.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-mesoscopic-reduction.html index 734265499..62db20125 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-mesoscopic-reduction.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-mesoscopic-reduction.html @@ -4,7 +4,7 @@ math.rn-mesoscopic-reduction · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-annulus-window.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-annulus-window.html index bb6a48fea..2de4b9d6e 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-annulus-window.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-annulus-window.html @@ -4,7 +4,7 @@ math.rn-region.fixed-annulus-window · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-remote.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-remote.html index a987412d2..dcd5ef8d4 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-remote.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.fixed-remote.html @@ -4,7 +4,7 @@ math.rn-region.fixed-remote · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.intermediate-r-to-rho.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.intermediate-r-to-rho.html index 4e1429ab9..762a6f4b3 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.intermediate-r-to-rho.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.intermediate-r-to-rho.html @@ -4,7 +4,7 @@ math.rn-region.intermediate-r-to-rho · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.mesoscopic-scaled-annulus.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.mesoscopic-scaled-annulus.html index ccb5b7c83..973458395 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.mesoscopic-scaled-annulus.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.mesoscopic-scaled-annulus.html @@ -4,7 +4,7 @@ math.rn-region.mesoscopic-scaled-annulus · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.pin-collision.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.pin-collision.html index 033110d20..499b9d555 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.pin-collision.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.pin-collision.html @@ -4,7 +4,7 @@ math.rn-region.pin-collision · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.witness-collision.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.witness-collision.html index 1794d96fb..23832805f 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.witness-collision.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-region.witness-collision.html @@ -4,7 +4,7 @@ math.rn-region.witness-collision · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-selector-region-crosswalk.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-selector-region-crosswalk.html index c6652e8cc..c6a8b6bd4 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-selector-region-crosswalk.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.rn-selector-region-crosswalk.html @@ -4,7 +4,7 @@ math.rn-selector-region-crosswalk · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.side24-coefficient.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.side24-coefficient.html index 633d1620e..a3446ea64 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.side24-coefficient.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.side24-coefficient.html @@ -4,7 +4,7 @@ math.side24-coefficient · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.uniform-matrix-cap-lifetime.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.uniform-matrix-cap-lifetime.html index a61a926b3..1a7e2393c 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.uniform-matrix-cap-lifetime.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/math.uniform-matrix-cap-lifetime.html @@ -4,7 +4,7 @@ math.uniform-matrix-cap-lifetime · Research dependency atlas - +
diff --git a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/regional.fixed-annulus.high-jet-route.html b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/regional.fixed-annulus.high-jet-route.html index 9e6855b2d..0cd9b1320 100644 --- a/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/regional.fixed-annulus.high-jet-route.html +++ b/docs/site/snapshots/7c583e28878d2bf2c94bf37325820bd5eb1e7f3f557e8a78dd27881a27f6548c/nodes/regional.fixed-annulus.high-jet-route.html @@ -4,7 +4,7 @@ regional.fixed-annulus.high-jet-route · Research dependency atlas - +
diff --git a/docs/site/workspace.html b/docs/site/workspace.html index 6e3d1257c..4a78c0104 100644 --- a/docs/site/workspace.html +++ b/docs/site/workspace.html @@ -5,12 +5,12 @@ Library and research workspace · Universal Law - - - + + + - - + + diff --git a/governance/OP-ACCESS-20261007.md b/governance/OP-ACCESS-20261007.md index be8cc9ad6..143b1d4db 100644 --- a/governance/OP-ACCESS-20261007.md +++ b/governance/OP-ACCESS-20261007.md @@ -281,6 +281,7 @@ each item below carries its own date and scope. board continues as [main#307](https://github.com/d6g8k5htny-coder/main/issues/307). Where owner actions 1 and 2 above say "report on main#229" or "reply on main#229", read main#307. + Since 15 October the board continues as [main#419](https://github.com/d6g8k5htny-coder/main/issues/419); read main#419 where this record says main#229 or main#307. - **Claude lane, a second observation.** A different Claude Code session (`017Mi3…`), activated by the coordinator as successor custodian for the thread and body tasks of #282 diff --git a/governance/OP-WORKFLOW-20260930.md b/governance/OP-WORKFLOW-20260930.md index 08289c492..ff423599a 100644 --- a/governance/OP-WORKFLOW-20260930.md +++ b/governance/OP-WORKFLOW-20260930.md @@ -100,6 +100,39 @@ acknowledgement and activation stand alone; an unidentified second successor doe delay the first. Retained stops are carried by name. None of this adds a register, a scheduler, a permission gate, a forced release or independence credit. +Four checks bracket every claim, mutation and verdict: + +1. Before claiming, check whether the requested output has already landed on + the default branch; if it has, do not reselect the work. +2. Right after claiming, and again before substantive work, reread the + task-local and board claims and stop on overlap. There is no fixed wait. + Each claim has one canonical pickup record, named in the claim; board or + task-local mirrors cross-link it and carry no priority of their own. + "Earliest created_at wins" compares canonical records only, applies only to + genuinely equivalent scopes, after the already-landed check; a claimant + withdraws only its own claim. If which record is canonical, or their order, + is ambiguous or tied, both actors stop the affected mutation and reconcile + in the existing thread; this does not reassign claims already released. +3. Before mutating, recheck current state and use an expected-head guard. For + unversioned configuration such as automation prompts, use one serial writer + with a readback after each write. +4. Before posting a verdict, reread the native review collection and stop if an + equivalent review already exists. + +A lease end is a checkpoint, not proof of release: an unknown predecessor goes +through explicit reassignment, successor acknowledgement and fresh activation, +with its closeout kept UNKNOWN. Reuse an existing collision notice where +possible. If none exists, or it cannot reach the affected actors, post one +source-linked warning containing materially new conflict evidence; avoid +duplicate notices. Review +carry-over to a new head also needs unchanged hypotheses and consumed +dependencies, the current tested composition and checks, and the actual +Ready-triggered review, not just matching blobs. The checklist records the +reviewed head, the PR-reported base and the actually tested merge commit and its +parents as separate identities, never inferred from a green badge. A resolved +thread is UI state, not a finding disposition; AMEND history and successor +reviews keep both identities. + Maintain one short current disposition in the PR body or a linked comment: current head, owner, completed review scopes, unresolved finding IDs, validation and next action. Update it on material change; link detailed evidence instead @@ -108,6 +141,15 @@ this shape. Closed [main #95](https://github.com/d6g8k5htny-coder/main/issues/95 is formal-rollout history; current work stays in its relevant PR. Neither issue closure nor an outdated review thread resolves an outstanding obligation. +At source pickup, run a complete by-path contender check of the paths you will +touch against open pull requests; shared generated files and consumed +dependencies count as overlap. Before any mutation, revalidate changed or new +pull request heads. An exact-head, complete, paginated inventory may be reused, +refreshing only changed entries and pull requests merged since the candidate +base; a full repository recrawl is not required before every small docs edit. +Link a compact overlap record from the pull request instead of copying a long +list. Unresolved ownership still stops the affected write. + This is cooperative coordination. It does not install a distributed lock or claim that every agent has acknowledged a notice. A competing mutation stops the affected update and requires reconciliation, not a second competing write. @@ -190,6 +232,15 @@ to finish and reconcile its findings before merging; an earlier automatic review of the same head does not replace it. If it cannot finish, say so on the pull request and settle the next step there instead of merging past it. +Where `public-intake` is required, verify its actual trusted workflow and event +identity and its current head, as CONTRIBUTING requires, as well as its +success. A check name and head alone cannot establish the Ready-event binding. +On an ordinary pending-required-check 405, re-read current refs, ownership, and +protection and check state. One retry at the same expected head is appropriate +only after the missing requirement has actually succeeded and no other stop +applies. This does not waive the separate Ready-triggered review, approve +security changes, or authorize retrying platform denials. + Follow [the required formal checks](../docs/FORMAL_REQUIRED_CHECKS.md) and [release operations](../docs/RELEASE_OPERATIONS.md). A base change can change the tested merge; old CI is not rebound to it. Missing, skipped or failed checks diff --git a/tests/test_architecture_artifact_index.py b/tests/test_architecture_artifact_index.py new file mode 100644 index 000000000..46fc4f736 --- /dev/null +++ b/tests/test_architecture_artifact_index.py @@ -0,0 +1,945 @@ +"""External contract for the inert, explicitly pinned Artifact Index projection. + +Every fixture below is synthetic TEST data. It models formattedValue API JSON, +not a real Sheet capture, native revision authentication, or delivered evidence. +""" + +import base64 +import copy +import hashlib +import http.server +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import threading +import urllib.request +import unittest + + +ROOT = Path(__file__).resolve().parents[1] +CLI = ROOT / "tools" / "artifact_index_export.py" +HEADER = [ + "Artifact ID", "Title", "Org", "Class", "Priority", "Topics / object tags", + "Status", "Authority / canonical impact", "Dependencies or supersession", + "Modified UTC", "Source", "Notes", +] +PUBLIC_COLUMNS = [ + "Artifact ID", "Title", "Org", "Class", "Status", + "Authority / canonical impact", "Dependencies or supersession", "Modified UTC", +] +PIN_FLAGS = { + "capture_sha256": "--expected-capture-sha256", + "metadata_sha256": "--expected-metadata-sha256", + "policy_sha256": "--expected-policy-sha256", + "bindings_sha256": "--expected-bindings-sha256", + "graph_nodes_sha256": "--expected-graph-nodes-sha256", +} +ROLES = ["source", "review", "kernel", "computation", "alignment", "teaching-source"] +TITLE = "TEST Artifact Index" +RANGES = [ + "'TEST Artifact Index'!A1:L1", + "'TEST Artifact Index'!A936:L937", + "'TEST Artifact Index'!A1001:L1001", +] + +# Trusted test launcher, executed only in the external child. Its Python audit +# observer covers the fixture paths; it is not an operating-system sandbox. +AUDIT_LAUNCHER = r''' +import json +import os +import runpy +import sys + +cli_path, report_number, fixture_path, secret_path = sys.argv[1:5] +cli_arguments = sys.argv[5:] +report_fd = int(report_number) +fixture_root = os.path.normcase(os.path.abspath(fixture_path)) +labels = ("read", "write", "mkdir", "remove", "rename", "rmdir") +counts = dict.fromkeys(labels, 0) +calibration = dict(counts) +guard = False + +def fixture_target(path, dir_fd=None): + if isinstance(path, int): + # Standard streams and the trusted report descriptor are allowed. + # Other opaque descriptors conservatively count as fixture attempts. + return path not in (0, 1, 2, report_fd) + if path is None: + path = os.getcwd() + path = os.fsdecode(path) + if not os.path.isabs(path) and dir_fd not in (None, -1): + # A relative dir_fd target cannot safely be assigned to another path + # without extra I/O, so observe/guard it conservatively. + return True + path = os.path.normcase(os.path.abspath(path)) + return path == fixture_root or path.startswith(fixture_root + os.sep) + +def audit(event, arguments): + selected = [] + if event == "open" and fixture_target(arguments[0]): + flags = arguments[2] + if flags & (os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREAT | os.O_TRUNC): + selected.append("write") + if not flags & os.O_WRONLY: + selected.append("read") + elif event in ("os.listdir", "os.scandir") and fixture_target(arguments[0]): + selected.append("read") + elif event == "os.mkdir" and fixture_target(arguments[0], arguments[2]): + selected.append("mkdir") + elif event in ("os.remove", "os.rmdir") and fixture_target(arguments[0], arguments[1]): + selected.append("remove" if event == "os.remove" else "rmdir") + elif event == "os.rename" and ( + fixture_target(arguments[0], arguments[2]) or fixture_target(arguments[1], arguments[3]) + ): + selected.append("rename") + for label in selected: + counts[label] += 1 + if selected and guard: + raise RuntimeError("TEST_FIXTURE_IO_GUARD") + +sys.addaudithook(audit) +try: + # Positive calibration uses trusted paths, never captured code or values. + with open(secret_path, "rb") as stream: + stream.read() + temporary = os.path.join(fixture_root, "TEST-audit-temporary") + renamed = os.path.join(fixture_root, "TEST-audit-renamed") + directory = os.path.join(fixture_root, "TEST-audit-directory") + with open(temporary, "wb") as stream: + stream.write(b"TEST calibration") + os.rename(temporary, renamed) + os.remove(renamed) + os.mkdir(directory) + os.rmdir(directory) + os.listdir(fixture_root) + calibration = dict(counts) + counts = dict.fromkeys(labels, 0) + guard = True + sys.argv = [cli_path, *cli_arguments] + sys.path[0] = os.path.dirname(cli_path) + runpy.run_path(cli_path, run_name="__main__") +finally: + report = {"calibration": calibration, "attempts": counts, "optimize": sys.flags.optimize} + encoded = (json.dumps(report, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + "\n").encode("ascii") + os.write(report_fd, encoded) + os.close(report_fd) +''' + + +def canonical(value): + return json.dumps(value, sort_keys=True, separators=(",", ":"), + ensure_ascii=True, allow_nan=False).encode("ascii") + + +def digest(raw): + return hashlib.sha256(raw).hexdigest() + + +def native_bytes(value): + return (json.dumps(value, separators=(",", ":"), ensure_ascii=False, + allow_nan=False) + "\n").encode("utf-8") + + +def row(values): + return {"values": [{"formattedValue": value} for value in values]} + + +def selected_values(artifact_id, label): + return [ + artifact_id, label + " — α; TEST.node.a is only title text", "TEST Org", + "dated review record", "PRIVATE_PRIORITY_" + artifact_id, + "PRIVATE_TOPICS_" + artifact_id, "HISTORICAL / NOT ACCEPTED", + "independence=0; scope=historical only; as of 2026-10-01", + "supersedes TEST-OLDER only within the stated scope", "2026-10-01T00:00:00Z", + "PRIVATE_SOURCE_" + artifact_id, "PRIVATE_NOTES_" + artifact_id, + ] + + +def synthetic_native(): + unselected = ["TEST-UNSELECTED"] + ["PRIVATE_UNSELECTED_COL_%02d" % i + for i in range(1, 12)] + return { + "spreadsheetId": "TEST-R17-SPREADSHEET", + "privateAnnotation": "PRIVATE_NATIVE_ANNOTATION", + "sheets": [{ + "properties": { + "sheetId": 4242, "title": TITLE, + "gridProperties": {"rowCount": 1002, "columnCount": 12}, + }, + "data": [ + {"startRow": 0, "startColumn": 0, "rowData": [row(HEADER)]}, + {"startRow": 935, "startColumn": 0, "rowData": [ + row(selected_values("TEST-ZETA", "Zeta title")), + row(selected_values("TEST-ALPHA", "Alpha title")), + ]}, + {"startRow": 1000, "startColumn": 0, "rowData": [row(unselected)]}, + ], + }], + } + + +def synthetic_packet(): + return { + "schema_version": 1, + "capture": { + "capture_id": "TEST-capture-1", "captured_at": "2026-10-01T12:34:56Z", + "source": { + "spreadsheet_id": "TEST-R17-SPREADSHEET", "worksheet_id": 4242, + "title": TITLE, "ranges": list(RANGES), "cell_fields": "formattedValue", + }, + "raw_base64": base64.b64encode(native_bytes(synthetic_native())).decode("ascii"), + }, + "policy": {"schema_version": 1, "artifact_ids": ["TEST-ZETA", "TEST-ALPHA"], + "columns": list(PUBLIC_COLUMNS)}, + "bindings": [], + "graph_nodes": ["TEST.node.z", "TEST.node.a", "TEST.node.m"], + } + + +def pins_for(packet): + capture = packet["capture"] + raw = base64.b64decode(capture["raw_base64"], validate=True) + metadata = {key: value for key, value in capture.items() if key != "raw_base64"} + return { + "capture_sha256": digest(raw), "metadata_sha256": digest(canonical(metadata)), + "policy_sha256": digest(canonical(packet["policy"])), + "bindings_sha256": digest(canonical(packet["bindings"])), + "graph_nodes_sha256": digest(canonical(packet["graph_nodes"])), + } + + +def replace_raw(packet, raw): + packet["capture"]["raw_base64"] = base64.b64encode(raw).decode("ascii") + + +def get_native(packet): + return json.loads(base64.b64decode(packet["capture"]["raw_base64"])) + + +def replace_native(packet, value): + replace_raw(packet, native_bytes(value)) + + +class ArtifactIndexProjectionContractTests(unittest.TestCase): + def setUp(self): + self.packet = synthetic_packet() + self.pins = pins_for(self.packet) + self.temp = tempfile.TemporaryDirectory(prefix="TEST-artifact-index-") + self.addCleanup(self.temp.cleanup) + self.workdir = Path(self.temp.name) + self.private_values = ["PRIVATE_NATIVE_ANNOTATION"] + for block in get_native(self.packet)["sheets"][0]["data"][1:]: + for native_row in block["rowData"]: + values = [cell["formattedValue"] for cell in native_row["values"]] + if values[0] == "TEST-UNSELECTED": + self.private_values.extend(values) + else: + self.private_values.extend(values[index] for index in (4, 5, 10, 11)) + + def flag_args(self, pins): + return [argument for name, flag in PIN_FLAGS.items() for argument in (flag, pins[name])] + + def invoke(self, packet=None, *, expected=None, raw=None, args=None, audit=None): + # Missing exporters must fail every control before launching a child. + self.assertTrue(CLI.is_file(), "missing required external CLI: tools/artifact_index_export.py") + packet = self.packet if packet is None else packet + expected = pins_for(packet) if expected is None else expected + raw = canonical(packet) + b"\n" if raw is None else raw + flags = ["-B", "-S"] + if sys.flags.optimize: + flags.append("-" + "O" * sys.flags.optimize) + env = dict(os.environ) + env.pop("PYTHONOPTIMIZE", None) + arguments = self.flag_args(expected) if args is None else args + + def launch(command, pass_fds=()): + return subprocess.run( + command, input=raw, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + cwd=self.workdir, env=env, timeout=20, check=False, pass_fds=pass_fds, + ) + + if audit is None: + return launch([sys.executable, *flags, str(CLI), *arguments]) + with tempfile.TemporaryDirectory(prefix="TEST-audit-report-") as report_directory: + report_root = Path(report_directory) + launcher = report_root / "trusted_launcher.py" + report_path = report_root / "counts.json" + launcher.write_text(AUDIT_LAUNCHER, encoding="utf-8") + report_fd = os.open(report_path, os.O_CREAT | os.O_RDWR | os.O_TRUNC, 0o600) + try: + result = launch([ + sys.executable, *flags, str(launcher), str(CLI), str(report_fd), + str(self.workdir), str(audit["secret"]), *arguments, + ], pass_fds=(report_fd,)) + finally: + os.close(report_fd) + result.audit_report = json.loads(report_path.read_bytes()) + return result + + def assert_private_absent(self, result): + combined = result.stdout + result.stderr + for value in self.private_values: + self.assertNotIn(value.encode("utf-8"), combined) + self.assertNotIn(self.packet["capture"]["raw_base64"].encode("ascii"), combined) + + def expected_projection(self, packet, expected): + source = packet["capture"]["source"] + selected = set(packet["policy"]["artifact_ids"]) + projected_rows = [] + for block in get_native(packet)["sheets"][0]["data"]: + start = block.get("startRow", 0) + for offset, native_row in enumerate(block["rowData"]): + values = [cell.get("formattedValue", "") for cell in native_row["values"]] + if values[0] in selected: + projected_rows.append({ + "artifact_id": values[0], "source_row": start + offset + 1, + "fields": {name: values[HEADER.index(name)] for name in PUBLIC_COLUMNS}, + }) + bindings = [dict(binding, roles=sorted(binding["roles"])) for binding in packet["bindings"]] + bindings.sort(key=lambda binding: (binding["node_id"], binding["artifact_id"])) + bound_nodes = {binding["node_id"] for binding in bindings} + return { + "schema_version": 1, "scientific_effect": "NONE", "scientific_status_authority": False, + "custody": "unknown", + "source": { + "capture_id": packet["capture"]["capture_id"], + "captured_at": packet["capture"]["captured_at"], + "spreadsheet_id": source["spreadsheet_id"], "worksheet_id": source["worksheet_id"], + "worksheet_title": source["title"], "ranges": source["ranges"], + "cell_fields": source["cell_fields"], "representation": "native-api-formattedValue-json", + }, + "identities": expected, "columns": list(PUBLIC_COLUMNS), + "rows": sorted(projected_rows, key=lambda value: value["artifact_id"]), + "bindings": bindings, "unmapped_nodes": sorted(set(packet["graph_nodes"]) - bound_nodes), + } + + def accept(self, packet=None, *, expected=None, raw=None, audit=None): + packet = self.packet if packet is None else packet + expected = pins_for(packet) if expected is None else expected + result = self.invoke(packet, expected=expected, raw=raw, audit=audit) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stderr, b"") + self.assertTrue(result.stdout.isascii()) + projected = json.loads(result.stdout) + self.assertEqual(projected, self.expected_projection(packet, expected)) + self.assertIs(type(projected["schema_version"]), int) + self.assertIs(projected["scientific_status_authority"], False) + self.assertIs(type(projected["source"]["worksheet_id"]), int) + for value in projected["rows"]: + self.assertIs(type(value["source_row"]), int) + self.assertEqual(result.stdout, canonical(projected) + b"\n") + self.assert_private_absent(result) + return result + + def refuse(self, packet=None, *, expected=None, raw=None, args=None): + result = self.invoke(packet, expected=expected, raw=raw, args=args) + self.assertNotEqual(result.returncode, 0) + self.assertEqual(result.stdout, b"") + self.assertEqual(result.stderr, b"ARTIFACT_INDEX_REFUSED\n") + self.assert_private_absent(result) + return result + + def test_exact_public_projection_is_stable_and_retains_original_row_positions(self): + before = sorted(path.name for path in self.workdir.iterdir()) + first = self.accept() + self.assertEqual(self.accept().stdout, first.stdout) + projected = json.loads(first.stdout) + self.assertEqual([(item["artifact_id"], item["source_row"]) for item in projected["rows"]], + [("TEST-ALPHA", 937), ("TEST-ZETA", 936)]) + self.assertEqual(projected["unmapped_nodes"], ["TEST.node.a", "TEST.node.m", "TEST.node.z"]) + self.assertEqual(sorted(path.name for path in self.workdir.iterdir()), before) + + def test_all_49_explicit_graph_nodes_remain_unmapped_without_a_binding(self): + packet = copy.deepcopy(self.packet) + packet["graph_nodes"] = ["TEST.node.%02d" % index for index in reversed(range(49))] + projected = json.loads(self.accept(packet).stdout) + self.assertEqual(len(projected["unmapped_nodes"]), 49) + self.assertEqual(projected["bindings"], []) + + def test_public_unicode_empty_cells_and_historical_scope_are_preserved_without_promotion(self): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + values = native["sheets"][0]["data"][1]["rowData"][1]["values"] + values[1]["formattedValue"] = "Unicode α / résumé / 雪; declared text only" + values[2] = {"unknownAnnotation": "PRIVATE_EMPTY_CELL_ANNOTATION"} + values[6]["formattedValue"] = "FAILED; skipped; as of 2026-09-30" + values[7]["formattedValue"] = "independence=0; historical scope only" + replace_native(packet, native) + result = self.accept(packet) + fields = json.loads(result.stdout)["rows"][0]["fields"] + self.assertEqual(fields["Org"], "") + self.assertEqual(fields["Status"], "FAILED; skipped; as of 2026-09-30") + self.assertNotIn(b"PRIVATE_EMPTY_CELL_ANNOTATION", result.stdout) + + def test_default_zero_offsets_and_unknown_native_annotations_are_private_and_inert(self): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + header = native["sheets"][0]["data"][0] + del header["startRow"] + for block in native["sheets"][0]["data"]: + del block["startColumn"] + block["annotation"] = {"raw": "PRIVATE_BLOCK_ANNOTATION", "nested": [True, None, 1.5]} + native["sheets"][0]["properties"]["annotation"] = "PRIVATE_PROPERTIES_ANNOTATION" + replace_native(packet, native) + result = self.accept(packet) + self.assertNotIn(b"PRIVATE_BLOCK_ANNOTATION", result.stdout) + self.assertNotIn(b"PRIVATE_PROPERTIES_ANNOTATION", result.stdout) + + def test_explicit_six_roles_and_bindings_sort_without_inferred_acceptance(self): + packet = copy.deepcopy(self.packet) + packet["bindings"] = [ + {"node_id": "TEST.node.z", "artifact_id": "TEST-ZETA", "roles": list(ROLES)}, + {"node_id": "TEST.node.a", "artifact_id": "TEST-ZETA", "roles": ["teaching-source"]}, + {"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": ["review", "source"]}, + ] + projected = json.loads(self.accept(packet).stdout) + self.assertEqual(projected["bindings"][2]["roles"], sorted(ROLES)) + self.assertEqual(projected["unmapped_nodes"], ["TEST.node.m"]) + self.assertEqual(projected["custody"], "unknown") + + def test_policy_array_order_is_pinned_even_when_public_rows_have_the_same_order(self): + packet = copy.deepcopy(self.packet) + packet["policy"]["artifact_ids"].reverse() + original = json.loads(self.accept().stdout) + reordered = json.loads(self.accept(packet).stdout) + self.assertEqual(original["rows"], reordered["rows"]) + self.assertNotEqual(original["identities"]["policy_sha256"], reordered["identities"]["policy_sha256"]) + + def test_each_of_the_five_independent_expected_pins_must_match(self): + for name in PIN_FLAGS: + with self.subTest(pin=name): + expected = dict(self.pins) + expected[name] = "0" * 64 if expected[name] != "0" * 64 else "1" * 64 + self.refuse(expected=expected) + + def test_changed_input_components_cannot_replace_independently_supplied_pins(self): + for component in ("capture", "metadata", "policy", "bindings", "graph_nodes"): + with self.subTest(component=component): + packet = copy.deepcopy(self.packet) + if component == "capture": + replace_raw(packet, base64.b64decode(packet["capture"]["raw_base64"]) + b" ") + elif component == "metadata": + packet["capture"]["captured_at"] = "2026-10-02T12:34:56Z" + elif component == "policy": + packet["policy"]["artifact_ids"].reverse() + elif component == "bindings": + packet["bindings"] = [{"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": ["source"]}] + else: + packet["graph_nodes"].reverse() + self.refuse(packet, expected=self.pins) + + def test_all_cli_flags_are_required_once_and_only_full_names_are_accepted(self): + arguments = self.flag_args(self.pins) + for index, (name, flag) in enumerate(PIN_FLAGS.items()): + with self.subTest(flag=flag, fault="missing"): + self.refuse(args=arguments[:2 * index] + arguments[2 * index + 2:]) + with self.subTest(flag=flag, fault="duplicate"): + self.refuse(args=arguments + [flag, self.pins[name]]) + with self.subTest(flag=flag, fault="abbreviated"): + amended = list(arguments) + amended[2 * index] = flag[:-1] + self.refuse(args=amended) + + def test_invalid_cli_digests_and_private_argument_values_are_never_echoed(self): + for name in PIN_FLAGS: + for value in ("", "a" * 63, "a" * 65, "A" * 64, "g" * 64, "../PRIVATE_ARG_PATH"): + with self.subTest(pin=name, value=value): + expected = dict(self.pins) + expected[name] = value + result = self.refuse(expected=expected) + self.assertNotIn(b"PRIVATE_ARG_PATH", result.stderr) + for extra in (["--PRIVATE_UNKNOWN_FLAG", "PRIVATE_ARGUMENT_VALUE"], ["/PRIVATE_POSITIONAL_PATH"]): + with self.subTest(extra=extra): + result = self.refuse(args=self.flag_args(self.pins) + extra) + self.assertNotIn(b"PRIVATE_", result.stderr) + + def test_packet_wrappers_are_closed_and_schema_versions_have_exact_integer_types(self): + wrapped = copy.deepcopy(self.packet) + wrapped["bindings"] = [{"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": ["source"]}] + + def remaining_pins(packet): + # Pin every remaining component, so an unrelated mismatch cannot + # mask the missing/extra-key control. A wholly absent component has + # no hash to supply and retains the positive fixture's expectation. + expected = pins_for(wrapped) + for name, key in (("policy_sha256", "policy"), ("bindings_sha256", "bindings"), + ("graph_nodes_sha256", "graph_nodes")): + if key in packet: + expected[name] = digest(canonical(packet[key])) + if "capture" in packet: + capture = packet["capture"] + expected["metadata_sha256"] = digest(canonical({ + key: value for key, value in capture.items() if key != "raw_base64" + })) + if "raw_base64" in capture: + expected["capture_sha256"] = digest(base64.b64decode(capture["raw_base64"], validate=True)) + return expected + + paths = [(), ("capture",), ("capture", "source"), ("policy",), ("bindings", 0)] + for path in paths: + target = wrapped + for key in path: + target = target[key] + for key in list(target): + with self.subTest(path=path, missing=key): + packet = copy.deepcopy(wrapped) + changed = packet + for part in path: + changed = changed[part] + del changed[key] + self.refuse(packet, expected=remaining_pins(packet)) + with self.subTest(path=path, extra=True): + packet = copy.deepcopy(wrapped) + changed = packet + for part in path: + changed = changed[part] + changed["PRIVATE_UNRECOGNIZED_WRAPPER"] = "PRIVATE_WRAPPER_VALUE" + result = self.refuse(packet, expected=remaining_pins(packet)) + self.assertNotIn(b"PRIVATE_UNRECOGNIZED_WRAPPER", result.stderr) + self.assertNotIn(b"PRIVATE_WRAPPER_VALUE", result.stderr) + for path in ((), ("policy",)): + for value in (True, 1.0, "1", 0, 2, None): + with self.subTest(path=path, schema=value): + packet = copy.deepcopy(self.packet) + target = packet if not path else packet["policy"] + target["schema_version"] = value + self.refuse(packet) + + def test_capture_identity_timestamp_and_declared_source_are_strictly_typed(self): + cases = { + "capture_id": ("", "x" * 193, " space", "TEST\nID", "é", True, 1, None), + "captured_at": ("2026-02-30T12:00:00Z", "2026-10-01T24:00:00Z", "2026-10-01T12:34:56+00:00", + "2026-10-01T12:34:56.000Z", "2026-10-01", True, None), + } + for key, values in cases.items(): + for value in values: + with self.subTest(field=key, value=value): + packet = copy.deepcopy(self.packet) + packet["capture"][key] = value + self.refuse(packet) + source_cases = { + "spreadsheet_id": ("", "x" * 193, "é", True, None), + "worksheet_id": (True, 4242.0, -1, "4242", None), + "title": ("", "λ" * 129, "TEST\nTitle", "TEST'Quote", True, None), + "cell_fields": ("", "formattedValue,userEnteredValue", ["formattedValue"], None), + } + for key, values in source_cases.items(): + for value in values: + with self.subTest(source_field=key, value=value): + packet = copy.deepcopy(self.packet) + packet["capture"]["source"][key] = value + self.refuse(packet) + + def test_native_spreadsheet_worksheet_and_title_must_match_declared_metadata(self): + for field, value in (("spreadsheetId", "TEST-OTHER-SHEET"), ("sheetId", 4243), + ("sheetId", True), ("sheetId", 4242.0), ("title", "TEST Other Title")): + with self.subTest(field=field, value=value): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + target = native if field == "spreadsheetId" else native["sheets"][0]["properties"] + target[field] = value + replace_native(packet, native) + self.refuse(packet) + + def test_exact_header_order_names_types_and_single_header_are_required(self): + for fault in ("rename", "swap", "empty", "nonstring", "second_header"): + with self.subTest(fault=fault): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + header = native["sheets"][0]["data"][0]["rowData"][0]["values"] + if fault == "rename": + header[10]["formattedValue"] = "Sources" + elif fault == "swap": + header[0], header[1] = header[1], header[0] + elif fault == "empty": + header[11] = {} + elif fault == "nonstring": + header[0]["formattedValue"] = 1 + else: + native["sheets"][0]["data"][2]["rowData"][0] = row(HEADER) + replace_native(packet, native) + self.refuse(packet) + + def test_ranges_require_exact_title_a_to_l_syntax_order_and_nonoverlap(self): + cases = [[], RANGES + [RANGES[1]], list(reversed(RANGES)), + [RANGES[0], "'TEST Artifact Index'!A936:L937", "'TEST Artifact Index'!A937:L1001"], + ["TEST Artifact Index!A1:L1", *RANGES[1:]], + ["'TEST Other Title'!A1:L1", *RANGES[1:]], + ["'TEST Artifact Index'!A0:L1", *RANGES[1:]], + ["'TEST Artifact Index'!A01:L1", *RANGES[1:]], + ["'TEST Artifact Index'!B1:L1", *RANGES[1:]], + ["'TEST Artifact Index'!A1:K1", *RANGES[1:]], + [RANGES[0], "'TEST Artifact Index'!A937:L936", RANGES[2]], + [RANGES[0], True, RANGES[2]], "PRIVATE_RANGES_STRING"] + for value in cases: + with self.subTest(ranges=value): + packet = copy.deepcopy(self.packet) + packet["capture"]["source"]["ranges"] = value + self.refuse(packet) + + def test_grid_dimensions_are_exact_integers_and_bound_all_declared_blocks(self): + for key, value in (("rowCount", 0), ("rowCount", -1), ("rowCount", True), + ("rowCount", 1002.0), ("rowCount", 1000), ("rowCount", 10000001), + ("columnCount", 11), ("columnCount", 13), ("columnCount", 12.0), + ("columnCount", True)): + with self.subTest(field=key, value=value): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + native["sheets"][0]["properties"]["gridProperties"][key] = value + replace_native(packet, native) + self.refuse(packet) + + def test_native_offsets_match_range_positions_and_refuse_boolean_float_or_missing_nonzero(self): + for block_index, key, value in ((0, "startRow", 1), (1, "startRow", 934), + (1, "startRow", True), (1, "startRow", 935.0), + (1, "startRow", -1), (1, "startRow", "935"), + (1, "startRow", None), (2, "startColumn", 1), + (2, "startColumn", False), (2, "startColumn", 0.0)): + with self.subTest(block=block_index, offset=key, value=value): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + block = native["sheets"][0]["data"][block_index] + if value is None: + del block[key] + else: + block[key] = value + replace_native(packet, native) + self.refuse(packet) + + def test_native_sheet_block_row_and_cell_shapes_and_cardinalities_are_enforced(self): + for fault in ("root_array", "no_sheet", "two_sheets", "no_block", "extra_block", "block_order", + "short_rows", "extra_rows", "short_cells", "extra_cells", "cell_not_object", + "row_not_object", "block_not_object", "missing_properties", "missing_grid"): + with self.subTest(fault=fault): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + sheet = native["sheets"][0] + blocks = sheet["data"] + if fault == "root_array": + native = [native] + elif fault == "no_sheet": + native["sheets"] = [] + elif fault == "two_sheets": + native["sheets"].append(copy.deepcopy(sheet)) + elif fault == "no_block": + blocks.pop() + elif fault == "extra_block": + blocks.append(copy.deepcopy(blocks[2])) + elif fault == "block_order": + blocks[1], blocks[2] = blocks[2], blocks[1] + elif fault == "short_rows": + blocks[1]["rowData"].pop() + elif fault == "extra_rows": + blocks[1]["rowData"].append(copy.deepcopy(blocks[1]["rowData"][0])) + elif fault == "short_cells": + blocks[2]["rowData"][0]["values"].pop() + elif fault == "extra_cells": + blocks[2]["rowData"][0]["values"].append({}) + elif fault == "cell_not_object": + blocks[2]["rowData"][0]["values"][10] = "PRIVATE_BAD_CELL" + elif fault == "row_not_object": + blocks[2]["rowData"][0] = [] + elif fault == "block_not_object": + blocks[2] = [] + elif fault == "missing_properties": + del sheet["properties"] + else: + del sheet["properties"]["gridProperties"] + replace_native(packet, native) + result = self.refuse(packet) + self.assertNotIn(b"PRIVATE_BAD_CELL", result.stderr) + + def test_all_formatted_cells_are_strings_including_private_and_unselected_cells(self): + for block_index, row_index, column in ((1, 0, 1), (1, 1, 10), (1, 1, 11), (2, 0, 3)): + for value in (None, True, 3, 3.0, ["PRIVATE_ARRAY_CELL"], {"PRIVATE_OBJECT_CELL": "value"}): + with self.subTest(block=block_index, row=row_index, column=column, value=value): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + native["sheets"][0]["data"][block_index]["rowData"][row_index]["values"][column]["formattedValue"] = value + replace_native(packet, native) + result = self.refuse(packet) + self.assertNotIn(b"PRIVATE_ARRAY_CELL", result.stderr) + self.assertNotIn(b"PRIVATE_OBJECT_CELL", result.stderr) + + def test_formatted_cell_limit_counts_utf8_bytes_in_public_private_and_unselected_rows(self): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + native["sheets"][0]["data"][1]["rowData"][1]["values"][1]["formattedValue"] = "λ" * 4096 + replace_native(packet, native) + self.accept(packet) + for block_index, row_index, column in ((1, 1, 1), (1, 0, 10), (2, 0, 11)): + with self.subTest(block=block_index, row=row_index, column=column): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + native["sheets"][0]["data"][block_index]["rowData"][row_index]["values"][column]["formattedValue"] = "λ" * 4096 + "x" + replace_native(packet, native) + self.refuse(packet) + + def test_forged_column_policies_cannot_publish_source_notes_priority_or_topics(self): + cases = [PUBLIC_COLUMNS + [name] for name in ("Source", "Notes", "Priority", "Topics / object tags")] + cases.extend([list(reversed(PUBLIC_COLUMNS)), PUBLIC_COLUMNS[:-1], + PUBLIC_COLUMNS[:-1] + ["Source"], PUBLIC_COLUMNS[:-1] + [PUBLIC_COLUMNS[0]], + PUBLIC_COLUMNS[:-1] + [True], "PRIVATE_COLUMNS_STRING"]) + for columns in cases: + with self.subTest(columns=columns): + packet = copy.deepcopy(self.packet) + packet["policy"]["columns"] = columns + self.refuse(packet) + + def test_policy_ids_are_nonempty_unique_valid_and_present_in_native_rows(self): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + boundary_id = "T" + "x" * 191 + native["sheets"][0]["data"][1]["rowData"][1]["values"][0]["formattedValue"] = boundary_id + packet["policy"]["artifact_ids"] = ["TEST-ZETA", boundary_id] + replace_native(packet, native) + self.accept(packet) + for ids in ([], ["TEST-UNKNOWN"], ["TEST-ALPHA", "TEST-ALPHA"], [""], [True], [1], + ["TEST\nID"], [" TEST-ALPHA"], "TEST-ALPHA", None): + with self.subTest(ids=ids): + packet = copy.deepcopy(self.packet) + packet["policy"]["artifact_ids"] = ids + self.refuse(packet) + + def test_artifact_ids_are_globally_unique_and_valid_even_on_unselected_native_rows(self): + for value in ("TEST-ALPHA", "TEST-ZETA", "", True, 1, " TEST-UNSELECTED", "TEST\nUNSELECTED", + "T" + "x" * 192, "TEST-é", "TEST/UNSELECTED"): + with self.subTest(unselected_id=value): + packet = copy.deepcopy(self.packet) + native = get_native(packet) + native["sheets"][0]["data"][2]["rowData"][0]["values"][0]["formattedValue"] = value + replace_native(packet, native) + self.refuse(packet) + + def test_graph_ids_and_bindings_require_explicit_known_unique_identities(self): + packet = copy.deepcopy(self.packet) + packet["graph_nodes"] = ["T" + "x" * 191] + self.accept(packet) + for nodes in (["TEST.node.a", "TEST.node.a"], [""], [True], [1], ["TEST\nnode"], + [" TEST.node.a"], ["T" + "x" * 192], ["TEST.é"], ["TEST/node"], "TEST.node.a", None): + with self.subTest(nodes=nodes): + packet = copy.deepcopy(self.packet) + packet["graph_nodes"] = nodes + self.refuse(packet) + cases = [ + [{"node_id": "TEST.unknown", "artifact_id": "TEST-ALPHA", "roles": ["source"]}], + [{"node_id": "TEST.node.a", "artifact_id": "TEST-UNSELECTED", "roles": ["source"]}], + [{"node_id": "TEST.node.a", "artifact_id": "TEST-UNKNOWN", "roles": ["source"]}], + [{"node_id": True, "artifact_id": "TEST-ALPHA", "roles": ["source"]}], + [{"node_id": "TEST.node.a", "artifact_id": True, "roles": ["source"]}], + [{"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": ["source"]}, + {"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": ["review"]}], + [True], {}, None, + ] + for bindings in cases: + with self.subTest(bindings=bindings): + packet = copy.deepcopy(self.packet) + packet["bindings"] = bindings + self.refuse(packet) + + def test_binding_roles_are_nonempty_unique_strings_from_the_exact_six_role_set(self): + for roles in ([], ["accepted"], ["Source"], ["source", "source"], ["kernel", True], + [1], "source", None): + with self.subTest(roles=roles): + packet = copy.deepcopy(self.packet) + packet["bindings"] = [{"node_id": "TEST.node.a", "artifact_id": "TEST-ALPHA", "roles": roles}] + self.refuse(packet) + + def test_collection_limits_accept_4096_and_refuse_4097_without_duplicate_shortcuts(self): + packet = copy.deepcopy(self.packet) + packet["graph_nodes"] = ["TEST.node.%04d" % index for index in range(4096)] + packet["bindings"] = [{"node_id": node, "artifact_id": "TEST-ALPHA", "roles": ["source"]} + for node in packet["graph_nodes"]] + self.accept(packet) + too_many = copy.deepcopy(packet) + too_many["graph_nodes"].append("TEST.node.4096") + self.refuse(too_many) + too_many = copy.deepcopy(packet) + too_many["bindings"].append({"node_id": "TEST.node.0000", "artifact_id": "TEST-ZETA", "roles": ["review"]}) + self.refuse(too_many) + for count in (4096, 4097): + with self.subTest(native_rows_and_policy_ids=count): + many = copy.deepcopy(self.packet) + ids = ["TEST-ROW-%04d" % index for index in range(count)] + native = synthetic_native() + native["sheets"][0]["properties"]["gridProperties"]["rowCount"] = count + 1 + native["sheets"][0]["data"] = [ + {"rowData": [row(HEADER)]}, + {"startRow": 1, "rowData": [row([artifact_id] + ["TEST value"] * 9 + + ["PRIVATE_MANY_SOURCE", "PRIVATE_MANY_NOTES"]) + for artifact_id in ids]}, + ] + many["capture"]["source"]["ranges"] = [RANGES[0], "'TEST Artifact Index'!A2:L%d" % (count + 1)] + many["policy"]["artifact_ids"] = ids + replace_native(many, native) + result = self.accept(many) if count == 4096 else self.refuse(many) + self.assertNotIn(b"PRIVATE_MANY_", result.stdout + result.stderr) + + def test_stdin_limit_is_16_mib_of_bytes_including_legal_json_whitespace(self): + raw = canonical(self.packet) + bounded = raw + b" " * (16 * 1024 * 1024 - len(raw)) + self.accept(raw=bounded) + self.refuse(raw=bounded + b" ") + + def test_decoded_capture_limit_is_4_mib_of_original_bytes_not_base64_length(self): + packet = copy.deepcopy(self.packet) + raw = base64.b64decode(packet["capture"]["raw_base64"]) + bounded = raw + b" " * (4 * 1024 * 1024 - len(raw)) + replace_raw(packet, bounded) + self.accept(packet) + replace_raw(packet, bounded + b" ") + self.refuse(packet) + + def test_duplicate_keys_refuse_in_packet_wrappers_and_native_private_annotations(self): + raw = canonical(self.packet) + mutations = [ + raw[:-1] + b',"schema_version":1}', + raw.replace(b'"schema_version":1', b'"schema_version":1,"schema_version":1', 1), + raw.replace(b'"capture_id":"TEST-capture-1"', b'"capture_id":"TEST-capture-1","capture_id":"TEST-capture-1"', 1), + raw.replace(b'"artifact_ids":[', b'"artifact_ids":[],"artifact_ids":[', 1), + ] + for index, changed in enumerate(mutations): + with self.subTest(packet_duplicate=index): + self.refuse(raw=changed, expected=self.pins) + for marker, replacement in ( + (b'"spreadsheetId":"TEST-R17-SPREADSHEET"', b'"spreadsheetId":"TEST-R17-SPREADSHEET","spreadsheetId":"TEST-R17-SPREADSHEET"'), + (b'"formattedValue":"TEST-ZETA"', b'"formattedValue":"TEST-ZETA","formattedValue":"TEST-ZETA"'), + (b'"privateAnnotation":"PRIVATE_NATIVE_ANNOTATION"', b'"privateAnnotation":{"x":1,"x":1}'), + ): + with self.subTest(native_duplicate=marker): + packet = copy.deepcopy(self.packet) + native_raw = base64.b64decode(packet["capture"]["raw_base64"]) + self.assertIn(marker, native_raw) + replace_raw(packet, native_raw.replace(marker, replacement, 1)) + self.refuse(packet) + + def test_nonfinite_numbers_and_numeric_overflow_refuse_even_in_unknown_native_annotations(self): + for token in (b"NaN", b"Infinity", b"-Infinity", b"1e9999"): + with self.subTest(token=token, location="native_annotation"): + packet = copy.deepcopy(self.packet) + raw = base64.b64decode(packet["capture"]["raw_base64"]) + raw = raw.replace(b'"privateAnnotation":"PRIVATE_NATIVE_ANNOTATION"', b'"privateAnnotation":' + token, 1) + replace_raw(packet, raw) + self.refuse(packet) + with self.subTest(token=token, location="packet_schema"): + raw = canonical(self.packet).replace(b'"schema_version":1', b'"schema_version":' + token, 1) + self.refuse(raw=raw, expected=self.pins) + + def test_json_nesting_is_bounded_in_unknown_native_annotations_without_schema_masking(self): + packet = copy.deepcopy(self.packet) + raw = base64.b64decode(packet["capture"]["raw_base64"]) + marker = b'"privateAnnotation":"PRIVATE_NATIVE_ANNOTATION"' + self.assertIn(marker, raw) + # The native root object plus 63 nested arrays occupies 64 levels. + bounded = b"[" * 63 + b"0" + b"]" * 63 + replace_raw(packet, raw.replace(marker, b'"privateAnnotation":' + bounded, 1)) + self.accept(packet) + # One root object plus 64 arrays is exactly one level over the limit. + deep = b"[" * 64 + b"0" + b"]" * 64 + replace_raw(packet, raw.replace(marker, b'"privateAnnotation":' + deep, 1)) + self.refuse(packet) + + def test_malformed_utf8_json_and_multiple_documents_refuse_at_both_input_layers(self): + for raw in (b"", b"{", b"[]", b"null", canonical(self.packet) + b"{}", b"\xff", + canonical(self.packet).replace(b"TEST-capture-1", b"TEST-\xff-capture", 1)): + with self.subTest(packet_raw=raw[:20]): + self.refuse(raw=raw, expected=self.pins) + for raw in (b"", b"{", b"null", b"\xff", native_bytes(synthetic_native()) + b"{}", + native_bytes(synthetic_native()).replace(b"PRIVATE_NATIVE_ANNOTATION", b"PRIVATE_\xff_NATIVE", 1)): + with self.subTest(native_raw=raw[:20]): + packet = copy.deepcopy(self.packet) + replace_raw(packet, raw) + self.refuse(packet) + + def test_base64_is_strict_canonical_and_not_merely_decodable_to_the_expected_bytes(self): + encoded = self.packet["capture"]["raw_base64"] + for value in ("", "!!PRIVATE_BAD_BASE64!!", encoded + "=", encoded + "\n", " " + encoded, + encoded[:-1], True, None): + with self.subTest(base64_type=type(value).__name__, value_prefix=str(value)[:20]): + packet = copy.deepcopy(self.packet) + packet["capture"]["raw_base64"] = value + result = self.refuse(packet, expected=self.pins) + self.assertNotIn(b"PRIVATE_BAD_BASE64", result.stderr) + packet = copy.deepcopy(self.packet) + raw = base64.b64decode(encoded) + raw += b" " * ((1 - len(raw)) % 3) + replace_raw(packet, raw) + canonical_encoded = packet["capture"]["raw_base64"] + self.assertTrue(canonical_encoded.endswith("==")) + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + index = alphabet.index(canonical_encoded[-3]) + alternate = canonical_encoded[:-3] + alphabet[index + 1] + "==" + self.assertEqual(base64.b64decode(alternate, validate=True), raw) + expected = pins_for(packet) + self.accept(packet) + packet["capture"]["raw_base64"] = alternate + self.refuse(packet, expected=expected) + + def test_urls_paths_and_code_are_inert_data_without_fetch_execution_or_filesystem_writes(self): + requests = [] + + class Handler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + requests.append(self.path) + self.send_response(200) + self.end_headers() + self.wfile.write(b"PRIVATE_FETCH_RESULT") + + def log_message(self, *args): + pass + + server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Handler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + marker = self.workdir / "PRIVATE_EXECUTION_MARKER" + secret = self.workdir / "PRIVATE_LOCAL_SOURCE" + secret.write_text("PRIVATE_LOCAL_FILE_CONTENT", encoding="utf-8") + packet = copy.deepcopy(self.packet) + native = get_native(packet) + code = "__import__('pathlib').Path(%r).write_text('executed')" % str(marker) + url = "http://127.0.0.1:%d/PRIVATE_URL_PATH" % server.server_port + probe = "http://127.0.0.1:%d/TEST_OBSERVER_PROBE" % server.server_port + opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) + with opener.open(probe, timeout=5) as response: + self.assertEqual(response.read(), b"PRIVATE_FETCH_RESULT") + self.assertEqual(requests, ["/TEST_OBSERVER_PROBE"]) + requests.clear() + public = "inert URL %s; inert code %s; path %s" % (url, code, secret) + values = native["sheets"][0]["data"][1]["rowData"][1]["values"] + values[1]["formattedValue"] = public + values[10]["formattedValue"] = url + values[11]["formattedValue"] = code + native["privateAnnotation"] = {"file": str(secret), "code": code, "url": url} + replace_native(packet, native) + before = sorted(path.name for path in self.workdir.iterdir()) + result = self.accept(packet, audit={"secret": secret}) + report = result.audit_report + labels = {"read", "write", "mkdir", "remove", "rename", "rmdir"} + self.assertEqual(set(report), {"calibration", "attempts", "optimize"}) + self.assertIs(type(report["optimize"]), int) + self.assertEqual(report["optimize"], sys.flags.optimize) + self.assertEqual(set(report["calibration"]), labels) + for count in report["calibration"].values(): + self.assertIs(type(count), int) + self.assertGreater(count, 0) + self.assertEqual(report["attempts"], dict.fromkeys(labels, 0)) + for count in report["attempts"].values(): + self.assertIs(type(count), int) + projected = json.loads(result.stdout) + self.assertEqual(projected["rows"][0]["fields"]["Title"], public) + self.assertEqual(requests, []) + self.assertFalse(marker.exists()) + self.assertEqual(secret.read_text(encoding="utf-8"), "PRIVATE_LOCAL_FILE_CONTENT") + self.assertEqual(sorted(path.name for path in self.workdir.iterdir()), before) + finally: + server.shutdown() + server.server_close() + thread.join(timeout=5) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_architecture_cli_boundaries.py b/tests/test_architecture_cli_boundaries.py new file mode 100644 index 000000000..9b526cae5 --- /dev/null +++ b/tests/test_architecture_cli_boundaries.py @@ -0,0 +1,225 @@ +"""External CLI boundary regressions; execute only in hosted isolation. + +The sibling package and its private-input canary are trusted, synthetic TEST +instruments. They never refer to an actual private capture or user file. Existing +fixture modules are imported as modules, so their TestCases are not rediscovered +or inherited by these four controls. A passing diagnostic is not the full suite. +""" + +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +import test_architecture_artifact_index as artifact_fixtures +import test_architecture_graph_artifact_readback as graph_fixtures + + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT_CLI = ROOT / "tools/artifact_index_export.py" +GRAPH_CLI = ROOT / "tools/architecture_graph_artifact_readback.py" +CHILD_DEADLINE_SECONDS = 20 +PRIVATE_CANARY = b"TEST_ONLY_SYNTHETIC_PRIVATE_INPUT_CANARY" +# Trusted test instrument: the real stdout descriptor receives a real Python +# buffered stream. No exception, captured value or product result is fabricated. +BUFFERED_STDOUT_LAUNCHER = r''' +import io +import runpy +import sys +capacity, cli = int(sys.argv[1]), sys.argv[2] +sys.stdout = io.TextIOWrapper( + io.BufferedWriter(io.FileIO(1, mode="wb", closefd=False), buffer_size=capacity), + encoding="utf-8", newline="\n") +sys.argv = [cli, *sys.argv[3:]] +runpy.run_path(cli, run_name="__main__") +''' + + +class ArchitectureCliBoundaryContract(unittest.TestCase): + def setUp(self): + temporary = tempfile.TemporaryDirectory(prefix="TEST-cli-boundary-") + self.addCleanup(temporary.cleanup) + self.cwd = Path(temporary.name) + self.environment = dict(os.environ) + for name in ("PYTHONPATH", "PYTHONHOME", "PYTHONOPTIMIZE", "PYTHONUNBUFFERED"): + self.environment.pop(name, None) + + def python_flags(self): + flags = ["-I", "-B", "-S"] + if sys.flags.optimize: + flags.append("-" + "O" * sys.flags.optimize) + return flags + + def invoke(self, command, raw=b"", *, closed_stdout=False): + """Launch the real child, optionally with a pipe that has no reader. + + The reader is closed before Popen, so no child write or shutdown flush + can race a parent read/close. Parent and child each close their writer. + """ + writer = None + if closed_stdout: + reader, writer = os.pipe() + os.close(reader) + try: + process = subprocess.Popen( + command, stdin=subprocess.PIPE, + stdout=writer if closed_stdout else subprocess.PIPE, + stderr=subprocess.PIPE, cwd=self.cwd, env=self.environment, + ) + finally: + if writer is not None: + os.close(writer) + try: + stdout, stderr = process.communicate(raw, timeout=CHILD_DEADLINE_SECONDS) + except subprocess.TimeoutExpired: + process.kill() + # Killing the child closes its pipes; keep cleanup bounded as well. + process.communicate(timeout=5) + self.fail("CLI child exceeded its 20-second deadline") + return subprocess.CompletedProcess(command, process.returncode, stdout or b"", stderr) + + def artifact_case(self): + packet = artifact_fixtures.synthetic_packet() + expected = artifact_fixtures.pins_for(packet) + arguments = [part for name, flag in artifact_fixtures.PIN_FLAGS.items() + for part in (flag, expected[name])] + return ARTIFACT_CLI, arguments, artifact_fixtures.canonical(packet) + b"\n" + + def graph_case(self): + # Reuse the existing fixture builder and its source-pin assertions, + # without inheriting or executing any of its test methods. + fixture = graph_fixtures.ArchitectureGraphArtifactReadbackContract() + self.addCleanup(fixture.doCleanups) + fixture.setUp() + raw = graph_fixtures.classic_zip(fixture.entries()) + archive = fixture.cwd / "TEST-cli-boundary-input.zip" + archive.write_bytes(raw) + return GRAPH_CLI, fixture.arguments(archive, fixture.expected(raw)), b"" + + def command(self, cli, arguments): + self.assertTrue(cli.is_file(), "required external CLI is absent") + return [sys.executable, *self.python_flags(), str(cli), *arguments] + + def accepted_baseline(self, case): + cli, arguments, raw = case + result = self.invoke(self.command(cli, arguments), raw) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stderr, b"") + document = json.loads(result.stdout) + self.assertEqual(document["scientific_effect"], "NONE") + self.assertIs(document["scientific_status_authority"], False) + self.assertEqual(document["custody"], "unknown") + return result.stdout + + def symlink_does_not_select_sibling_package(self, case): + cli, arguments, raw = case + baseline = self.accepted_baseline(case) + attack_root = self.cwd / "TEST-attacker-source-root" + tools = attack_root / "tools" + package = attack_root / "architecture" + tools.mkdir(parents=True) + package.mkdir() + secret = self.cwd / "TEST-synthetic-private-input" + marker = self.cwd / "TEST-sibling-package-read-marker" + secret.write_bytes(PRIVATE_CANARY) + observed = PRIVATE_CANARY + b"\nOPTIMIZE=" + str(sys.flags.optimize).encode("ascii") + package.joinpath("__init__.py").write_text( + "from pathlib import Path\n" + "import sys\n" + "Path(" + repr(str(marker)) + ").write_bytes(\n" + " Path(" + repr(str(secret)) + ").read_bytes()\n" + " + b'\\nOPTIMIZE=' + str(sys.flags.optimize).encode('ascii'))\n" + "raise RuntimeError('TEST_SYNTHETIC_SIBLING_PACKAGE_EXECUTED')\n", + encoding="utf-8", + ) + linked_cli = tools / cli.name + linked_cli.symlink_to(cli) + + # Positive calibration deliberately imports this trusted TEST package. + # It proves the marker detects a synthetic private read in this mode. + calibration = self.invoke([ + sys.executable, *self.python_flags(), "-c", + "import sys; sys.path.insert(0, sys.argv[1]); import architecture", + str(attack_root), + ]) + self.record_diagnostic_child("synthetic-sibling-package-calibration", calibration) + self.assertNotEqual(calibration.returncode, 0) + self.assertIn(b"TEST_SYNTHETIC_SIBLING_PACKAGE_EXECUTED", calibration.stderr) + self.assertEqual(marker.read_bytes(), observed, "sibling-package observer was not live") + marker.unlink() + + result = self.invoke(self.command(linked_cli, arguments), raw) + self.record_diagnostic_child("symlinked-cli-with-synthetic-sibling", result) + self.assertEqual(secret.read_bytes(), PRIVATE_CANARY) + self.assertFalse(marker.exists(), "symlink-selected sibling package read the synthetic private input") + self.assertNotIn(PRIVATE_CANARY, result.stdout + result.stderr) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stderr, b"") + self.assertEqual(result.stdout, baseline, "symlink invocation changed the validated public unit") + + def record_diagnostic_child(self, variant, result): + # Only the focused hosted workflow sets this path. Do not print between + # unittest's progress and result tokens in the required full-suite log. + report = self.environment.get("ARCHITECTURE_CLI_BOUNDARY_REPORT") + if report is not None: + record = { + "test_id": self.id(), "variant": variant, + "optimize": sys.flags.optimize, "returncode": result.returncode, + "stdout_bytes": len(result.stdout), + "stderr": result.stderr.decode("utf-8", errors="backslashreplace"), + } + with open(report, "ab") as stream: + stream.write((json.dumps(record, sort_keys=True) + "\n").encode("utf-8")) + + def assert_opaque_refusal(self, result, refusal): + self.assertEqual(result.returncode, 1, result.stderr) + self.assertEqual(result.stdout, b"") + self.assertEqual(result.stderr, refusal) + + def broken_stdout_has_opaque_refusal(self, case, refusal, *, buffered_flush=False): + # This positive run ensures an unrelated argument/fixture refusal cannot + # satisfy the closed-reader protocol assertion below. + baseline = self.accepted_baseline(case) + cli, arguments, raw = case + with self.subTest(stdout_boundary="direct CLI"): + result = self.invoke(self.command(cli, arguments), raw, closed_stdout=True) + self.record_diagnostic_child("direct-closed-reader", result) + self.assert_opaque_refusal(result, refusal) + if buffered_flush: + # The graph unit can exceed Python's default buffer and fail during + # direct write, leaving no bytes for shutdown to flush. A larger + # real buffer exercises flush-time failure instead. Its capacity is + # derived from the already accepted bounded synthetic unit only. + capacity = len(baseline) + 1 + self.assertLessEqual(capacity, 16 * 1024 * 1024 + 1) + command = [sys.executable, *self.python_flags(), "-c", BUFFERED_STDOUT_LAUNCHER, + str(capacity), str(cli), *arguments] + calibration = self.invoke(command, raw) + self.record_diagnostic_child("buffered-open-reader-calibration", calibration) + self.assertEqual(calibration.returncode, 0, calibration.stderr) + self.assertEqual(calibration.stderr, b"") + self.assertEqual(calibration.stdout, baseline) + with self.subTest(stdout_boundary="real buffered flush"): + result = self.invoke(command, raw, closed_stdout=True) + self.record_diagnostic_child("buffered-closed-reader", result) + self.assert_opaque_refusal(result, refusal) + + def test_artifact_index_symlink_cannot_read_synthetic_private_input(self): + self.symlink_does_not_select_sibling_package(self.artifact_case()) + + def test_graph_readback_symlink_cannot_read_synthetic_private_input(self): + self.symlink_does_not_select_sibling_package(self.graph_case()) + + def test_artifact_index_broken_stdout_has_one_opaque_refusal_and_exit_one(self): + self.broken_stdout_has_opaque_refusal(self.artifact_case(), b"ARTIFACT_INDEX_REFUSED\n") + + def test_graph_readback_broken_stdout_has_one_opaque_refusal_and_exit_one(self): + self.broken_stdout_has_opaque_refusal( + self.graph_case(), b"ARCHITECTURE_GRAPH_READBACK_REFUSED\n", buffered_flush=True) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_architecture_graph_artifact_readback.py b/tests/test_architecture_graph_artifact_readback.py new file mode 100644 index 000000000..5ae0aa7e4 --- /dev/null +++ b/tests/test_architecture_graph_artifact_readback.py @@ -0,0 +1,1185 @@ +"""External CLI controls for graph archive readback; run only in hosted isolation. + +All native identities, logs, console text and runtime-image declarations below +are synthetic TEST fixtures. No fixture log establishes a native run or custody. +The graph records come from the already-public, independently pinned source. +This targeted audit observer is a test instrument, not an operating-system sandbox. +""" + +import copy +import hashlib +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +import json +import os +from pathlib import Path +import stat +import struct +import subprocess +import sys +import tempfile +import threading +import unittest +from urllib.request import urlopen +import zlib + + +ROOT = Path(__file__).resolve().parents[1] +CLI = ROOT / "tools/architecture_graph_artifact_readback.py" +SOURCE = ROOT / "docs/site/dependency-source/GRAPH.json" +SOURCE_SHA = "8822e9618678321a342d69cd0b8ae6552de1b5d578c331de5072b2892ee9dd09" +SOURCE_BYTES = 38753 +IMAGE_DIGEST = "python@sha256:83f339c1be6340ae1096010fdccf6552ac932d8f410d45d206014916bdf37e48" +REFUSAL = b"ARCHITECTURE_GRAPH_READBACK_REFUSED\n" +MIB = 1024 * 1024 +GRAPH_SOURCE = { + "repository": "d6g8k5htny-coder/Math-", + "commit": "7858329974e28be79f29b22644370084ff43da4f", + "captured_at": "2026-10-03T15:07:03Z", + "graph_sha256": SOURCE_SHA, + "gate_sha256": "a78f3e25f3b0cfe113e618a4c31a7a25d7f22af638c46dec1ecba221fa333ac8", +} +NATIVE = {"checked_commit": "a" * 40, "repository": "TEST-owner/TEST-repository", + "run_id": "123", "run_attempt": "1", "artifact_id": "456"} +MEMBERS = ( + "runtime-image.json", "checked-commit.txt", "run-id.txt", "run-attempt.txt", + "container-exit-status.txt", "console.log", "tests-normal.log", "tests-optimized.log", + "exporter.stdout", "exporter.stderr", "generated/graph.json", "architecture-run-receipt.json", +) +EVIDENCE = ( + "generated/graph.json", "checked-commit.txt", "run-id.txt", "run-attempt.txt", + "container-exit-status.txt", "tests-normal.log", "tests-optimized.log", "runtime-image.json", +) +REQUIRED_IDS = tuple(""" +test_architecture_binding.ArchitectureBindingContract.test_artifact_id_requires_positive_ascii_decimal_without_leading_zero +test_architecture_binding.ArchitectureBindingContract.test_artifact_name_is_exactly_bound_to_current_run_and_attempt +test_architecture_binding.ArchitectureBindingContract.test_attempt_ten_is_a_positive_decimal_not_a_single_digit +test_architecture_binding.ArchitectureBindingContract.test_commit_format_cannot_be_authorized_by_an_equally_invalid_native_commit +test_architecture_binding.ArchitectureBindingContract.test_deeply_nested_json_is_refused_without_a_success_envelope +test_architecture_binding.ArchitectureBindingContract.test_duplicate_top_level_keys_are_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_current_native_argument_is_used_for_identity_binding +test_architecture_binding.ArchitectureBindingContract.test_each_duplicate_output_key_is_refused_even_when_last_value_is_valid +test_architecture_binding.ArchitectureBindingContract.test_each_expected_native_identity_argument_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_non_success_result_is_refused +test_architecture_binding.ArchitectureBindingContract.test_each_of_the_eight_outputs_is_required +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_an_empty_string +test_architecture_binding.ArchitectureBindingContract.test_each_output_rejects_non_string_identities_without_coercion +test_architecture_binding.ArchitectureBindingContract.test_each_top_level_field_is_required +test_architecture_binding.ArchitectureBindingContract.test_extra_output_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_extra_top_level_fields_are_refused +test_architecture_binding.ArchitectureBindingContract.test_invalid_or_multiple_json_documents_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_finite_json_numbers_are_refused +test_architecture_binding.ArchitectureBindingContract.test_non_object_top_level_values_are_refused +test_architecture_binding.ArchitectureBindingContract.test_other_valid_native_identities_are_accepted_and_preserved +test_architecture_binding.ArchitectureBindingContract.test_outputs_must_be_an_object +test_architecture_binding.ArchitectureBindingContract.test_receipt_and_artifact_sha256_require_lowercase_64_hex_digits +test_architecture_binding.ArchitectureBindingContract.test_repository_substitution_and_case_drift_are_refused +test_architecture_binding.ArchitectureBindingContract.test_run_and_attempt_decimal_format_cannot_be_authorized_by_invalid_native_args +test_architecture_binding.ArchitectureBindingContract.test_stale_attempt_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_stale_checked_commit_is_refused +test_architecture_binding.ArchitectureBindingContract.test_stale_run_is_refused_even_with_a_matching_stale_artifact_name +test_architecture_binding.ArchitectureBindingContract.test_valid_current_run_has_exact_stable_non_scientific_output +test_architecture_binding.ArchitectureBindingContract.test_valid_json_at_exact_stdin_byte_limit_is_accepted +test_architecture_binding.ArchitectureBindingContract.test_valid_json_over_stdin_byte_limit_is_refused +test_architecture_graph_export.ArchitectureGraphExportContract.test_caller_pinned_provenance_cannot_authorize_different_gate_code +test_architecture_graph_export.ArchitectureGraphExportContract.test_classification_and_proof_review_text_cannot_manufacture_evidence +test_architecture_graph_export.ArchitectureGraphExportContract.test_context_only_cycle_is_allowed_without_changing_gate_semantics +test_architecture_graph_export.ArchitectureGraphExportContract.test_default_trust_rejects_self_consistent_changed_graph_and_provenance +test_architecture_graph_export.ArchitectureGraphExportContract.test_dimensions_describe_only_explicit_recorded_metadata +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_graph_json_keys_are_rejected_after_identity_validation +test_architecture_graph_export.ArchitectureGraphExportContract.test_duplicate_provenance_json_keys_are_rejected_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_exact_source_bound_hard_gate_validator_is_called +test_architecture_graph_export.ArchitectureGraphExportContract.test_failed_export_preserves_an_earlier_valid_export +test_architecture_graph_export.ArchitectureGraphExportContract.test_gate_identity_is_checked_before_untrusted_gate_executes +test_architecture_graph_export.ArchitectureGraphExportContract.test_graph_identity_is_checked_before_gate_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_missing_required_dependency_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_pinned_49_node_55_edge_export_is_deterministic_and_preserves_records +test_architecture_graph_export.ArchitectureGraphExportContract.test_required_dependency_cycle_is_rejected_by_pinned_hard_gate +test_architecture_graph_export.ArchitectureGraphExportContract.test_same_size_gate_change_is_rejected_by_sha_before_import +test_architecture_graph_export.ArchitectureGraphExportContract.test_source_byte_counts_are_validated_even_when_sha_matches +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_directory_is_rejected +test_architecture_graph_export.ArchitectureGraphExportContract.test_symlink_source_files_are_rejected_before_gate_import +test_architecture_receipt.ArchitectureReceiptContract.test_attempt_ten_and_other_native_repository_are_preserved +test_architecture_receipt.ArchitectureReceiptContract.test_changed_node_or_edge_is_refused_even_when_graph_source_pins_are_unchanged +test_architecture_receipt.ArchitectureReceiptContract.test_directory_or_fifo_member_is_refused_without_waiting_for_a_writer +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_json_keys_are_refused_even_when_last_value_is_valid +test_architecture_receipt.ArchitectureReceiptContract.test_duplicate_test_identity_or_multiple_runs_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_each_expected_host_identity_argument_is_used_and_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_native_identity_file_must_match_current_host_arguments +test_architecture_receipt.ArchitectureReceiptContract.test_each_required_sandbox_control_rejects_skipped_failed_or_error_status +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_is_required +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_must_be_regular_and_cannot_be_a_symlink +test_architecture_receipt.ArchitectureReceiptContract.test_each_staged_member_over_16_mib_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_empty_or_zero_discovered_test_logs_are_refused_in_each_mode +test_architecture_receipt.ArchitectureReceiptContract.test_every_graph_source_pin_is_required_and_cannot_be_substituted +test_architecture_receipt.ArchitectureReceiptContract.test_every_required_identity_is_needed_even_when_53_other_tests_are_ok +test_architecture_receipt.ArchitectureReceiptContract.test_evidence_directory_or_generated_parent_symlink_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_graph_and_runtime_inspect_require_strict_json +test_architecture_receipt.ArchitectureReceiptContract.test_graph_root_schema_and_non_scientific_flags_are_exact +test_architecture_receipt.ArchitectureReceiptContract.test_invalid_matching_host_identity_does_not_authorize_bad_commit_or_decimal +test_architecture_receipt.ArchitectureReceiptContract.test_later_all_ok_test_methods_are_counted_and_bound +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_extra_result_lines_cannot_be_ignored_before_the_success_footer +test_architecture_receipt.ArchitectureReceiptContract.test_malformed_foreign_or_shortname_mismatched_test_identities_are_refused +test_architecture_receipt.ArchitectureReceiptContract.test_missing_extra_or_forged_dimension_cannot_manufacture_scientific_evidence +test_architecture_receipt.ArchitectureReceiptContract.test_native_repository_argument_must_have_owner_and_repository_components +test_architecture_receipt.ArchitectureReceiptContract.test_nested_record_types_cannot_change_even_when_python_values_compare_equal +test_architecture_receipt.ArchitectureReceiptContract.test_non_finite_numbers_are_refused_even_in_additional_inspect_fields +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_names_are_accepted_as_additional_controls +test_architecture_receipt.ArchitectureReceiptContract.test_nonunderscore_unittest_prefix_malformed_results_are_not_diagnostics +test_architecture_receipt.ArchitectureReceiptContract.test_nonzero_or_malformed_container_exit_is_refused +test_architecture_receipt.ArchitectureReceiptContract.test_normal_and_optimized_must_discover_the_same_additional_passing_tests +test_architecture_receipt.ArchitectureReceiptContract.test_runtime_inspect_is_one_linux_amd64_image_with_the_fixed_digest +test_architecture_receipt.ArchitectureReceiptContract.test_skip_or_failure_in_additional_discovered_test_is_also_refused +test_architecture_receipt.ArchitectureReceiptContract.test_summary_must_report_exact_discovered_count_and_terminal_ok +test_architecture_receipt.ArchitectureReceiptContract.test_valid_53_test_receipt_is_exact_deterministic_and_preserves_staged_bytes +test_architecture_receipt.ArchitectureReceiptContract.test_valid_inspected_image_id_is_preserved_instead_of_hardcoded +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_at_exact_16_mib_limit_is_accepted +test_architecture_receipt.ArchitectureReceiptContract.test_valid_log_larger_than_64_kib_is_accepted_and_raw_bytes_are_hashed +test_architecture_sandbox.ArchitectureSandbox.test_kernel_enforces_cpu_memory_and_process_limits +test_architecture_sandbox.ArchitectureSandbox.test_network_namespace_has_no_external_interface_or_route +test_architecture_sandbox.ArchitectureSandbox.test_nonroot_and_no_new_privileges +test_architecture_sandbox.ArchitectureSandbox.test_output_quota_stops_disk_exhaustion_and_cleanup_recovers_space +test_architecture_sandbox.ArchitectureSandbox.test_source_mount_is_read_only_and_environment_has_no_publishing_secret +""".split()) +REQUIRED_IDS_SHA = "b51eaf6cfaede42105ad377c066c4b18789e320ccf542b6817a6850c350fc9ef" + + +def sha(raw): + return hashlib.sha256(raw).hexdigest() + + +def encoded(value): + return (json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True, + allow_nan=False) + "\n").encode("ascii") + + +def document(raw): + return json.loads(raw) + + +def synthetic_log(ids=REQUIRED_IDS): + rows = ["Synthetic TEST fixture only; no executed tests or authenticated custody."] + rows.extend(identity.rsplit(".", 1)[1] + " (" + identity + ") ... ok" for identity in ids) + rows.extend(["", "----------------------------------------------------------------------", + "Ran " + str(len(ids)) + " tests in 0.001s", "", "OK", ""]) + return "\n".join(rows).encode("ascii") + + +def padded_log(raw, length): + footer = raw.index(b"\n----------------------------------------------------------------------\n") + padding = length - len(raw) + if padding < 0: + raise ValueError("TEST requested padding below fixture length") + return raw[:footer] + b"\n" + b"x" * max(0, padding - 1) + raw[footer:] if padding else raw + + +def classic_zip(entries, options=None, *, comment=b"", prefix=b"", trailing=b"", zip64=False, + disk=0): + """Construct classic ZIP fixtures independently; this is not an acceptance parser.""" + options = {} if options is None else options + body, central = bytearray(prefix), bytearray() + for index, (name, raw) in enumerate(entries): + option = options.get(index, {}) + filename = option.get("name", name) + filename = filename.encode("utf-8") if isinstance(filename, str) else filename + method, flags = option.get("method", 8), option.get("flags", 0) + compressor = zlib.compressobj(level=6, wbits=-15) + compressed = raw if method == 0 else compressor.compress(raw) + compressor.flush() + compressed = option.get("compressed", compressed) + crc, size, expanded = zlib.crc32(raw) & 0xffffffff, len(compressed), len(raw) + crc, size, expanded = option.get("crc", crc), option.get("size", size), option.get("expanded", expanded) + extra, member_comment = option.get("extra", b""), option.get("comment", b"") + body.extend(option.get("before", b"")) + offset = len(body) + local = {"flags": flags, "method": method, "crc": 0 if flags & 8 else crc, + "size": 0 if flags & 8 else size, "expanded": 0 if flags & 8 else expanded} + local.update(option.get("local", {})) + local_name = option.get("local_name", filename) + body.extend(struct.pack(" 1 else None): + observed(label) + elif event in ("os.rename", "os.replace"): + if fixture_path(args[0], args[2] if len(args) > 2 else None) or fixture_path(args[1], args[3] if len(args) > 3 else None): + observed("rename") + elif event == "socket.connect": + observed("network") +sys.addaudithook(audit) +try: + with open(secret, "rb") as stream: + stream.read() + calibration = os.path.join(cwd, "TEST-calibration") + with open(calibration, "wb") as stream: + stream.write(b"TEST calibration only") + moved = calibration + "-moved" + os.rename(calibration, moved) + os.remove(moved) + os.mkdir(calibration) + os.listdir(cwd) + os.rmdir(calibration) + with socket.socket() as probe: + probe.settimeout(5) + probe.connect(("127.0.0.1", observer_port)) + calibration_counts = dict(counts) + counts = dict.fromkeys(labels, 0) + active = True + sys.argv = [cli, *arguments] + sys.path.insert(0, os.path.dirname(cli)) + runpy.run_path(cli, run_name="__main__") +finally: + raw = (json.dumps({"calibration": calibration_counts, "attempts": counts, + "optimize": sys.flags.optimize}, sort_keys=True) + "\n").encode("ascii") + os.write(report_fd, raw) + os.close(report_fd) +''' + + +class ArchitectureGraphArtifactReadbackContract(unittest.TestCase): + def setUp(self): + temporary = tempfile.TemporaryDirectory() + self.addCleanup(temporary.cleanup) + self.cwd = Path(temporary.name) + source_raw = SOURCE.read_bytes() + self.assertEqual(len(source_raw), SOURCE_BYTES) + self.assertEqual(sha(source_raw), SOURCE_SHA, "public source fixture changed") + self.assertEqual(len(REQUIRED_IDS), 89) + self.assertEqual(sha(("\n".join(sorted(REQUIRED_IDS)) + "\n").encode("ascii")), REQUIRED_IDS_SHA) + source = document(source_raw) + self.graph = { + "schema_version": 1, "source": GRAPH_SOURCE, "nodes": source["nodes"], "edges": source["edges"], + "dimensions": {identity: { + "source": "recorded" if node.get("source") else "not_recorded", + "review": "recorded" if any(node.get(field) for field in ( + "review_source", "review_issue", "review_basis", "review_provider", + "review_providers", "review_disposition")) else "not_recorded", + "kernel": "not_recorded", "computation": "not_recorded", "alignment": "not_recorded", + } for identity, node in source["nodes"].items()}, + "scientific_effect": "NONE", "scientific_status_authority": False, + } + self.base = self.fixture() + + def fixture(self, context=None, ids=REQUIRED_IDS): + context = NATIVE if context is None else context + image = {"Id": "sha256:" + "f" * 64, "RepoDigests": [IMAGE_DIGEST], + "Os": "linux", "Architecture": "amd64", "TEST_annotation": "synthetic image declaration"} + members = { + "generated/graph.json": encoded(self.graph), + "checked-commit.txt": (context["checked_commit"] + "\n").encode("ascii"), + "run-id.txt": (context["run_id"] + "\n").encode("ascii"), + "run-attempt.txt": (context["run_attempt"] + "\n").encode("ascii"), + "container-exit-status.txt": b"0\n", "runtime-image.json": encoded([image]), + "tests-normal.log": synthetic_log(ids), "tests-optimized.log": synthetic_log(ids), + "console.log": b"Synthetic TEST fixture, inert diagnostics; no executed native run.\n", + "exporter.stdout": b"/output/generated/graph.json\n", "exporter.stderr": b"", + } + receipt = {"schema_version": 1, "scientific_effect": "NONE", "scientific_status_authority": False, + **{key: context[key] for key in ("checked_commit", "repository", "run_id", "run_attempt")}, + "runtime_image": {"id": image["Id"], "repo_digest": IMAGE_DIGEST}, + "test_modes": [{"mode": mode, "test_count": len(ids), "test_ids": sorted(ids)} + for mode in ("normal", "optimized")], + "graph_source": GRAPH_SOURCE, + "evidence_file_sha256": {name: sha(members[name]) for name in EVIDENCE}} + members["architecture-run-receipt.json"] = encoded(receipt) + return members + + def rebind(self, members): + receipt = document(members["architecture-run-receipt.json"]) + receipt["evidence_file_sha256"] = {name: sha(members[name]) for name in EVIDENCE} + members["architecture-run-receipt.json"] = encoded(receipt) + + def change_json(self, members, name, change, *, rebind=True): + value = document(members[name]) + change(value) + members[name] = encoded(value) + if rebind: + self.rebind(members) + + def entries(self, members=None, manifest=None, order=None): + members = self.base if members is None else members + if manifest is None: + manifest = "".join(sha(members[name]) + " " + name + "\n" for name in sorted(members)).encode("ascii") + names = list(members) if order is None else order + return [(name, members[name]) for name in names] + [("ARTIFACT_SHA256SUMS", manifest)] + + def expected(self, raw, members=None, context=None): + members, context = (self.base if members is None else members), (NATIVE if context is None else context) + return {**context, "receipt_sha256": sha(members.get("architecture-run-receipt.json", self.base["architecture-run-receipt.json"])), + "artifact_sha256": sha(raw), "artifact_name": "research-architecture-" + context["run_id"] + "-" + context["run_attempt"]} + + def arguments(self, path, expected): + aliases = {"checked_commit": "commit", "repository": "repository", "run_id": "run-id", + "run_attempt": "run-attempt", "receipt_sha256": "receipt-sha256", "artifact_id": "artifact-id", + "artifact_sha256": "artifact-sha256", "artifact_name": "artifact-name"} + return ["--archive", str(path), *[part for field, flag in aliases.items() + for part in ("--expected-" + flag, expected[field])]] + + def invoke(self, raw=None, *, members=None, expected=None, arguments=None, path=None, + audit=False, observer_port=None): + self.assertTrue(CLI.is_file(), "required graph readback CLI tools/architecture_graph_artifact_readback.py is absent") + members = self.base if members is None else members + raw = classic_zip(self.entries(members)) if raw is None else raw + path = self.cwd / "TEST-input.zip" if path is None else path + if arguments is None and not path.exists() and not path.is_symlink(): + path.write_bytes(raw) + elif arguments is None and path.is_file() and not path.is_symlink(): + path.write_bytes(raw) + expected = self.expected(raw, members) if expected is None else expected + arguments = self.arguments(path, expected) if arguments is None else arguments + flags = ["-B", "-S"] + if sys.flags.optimize: + flags.append("-" + "O" * sys.flags.optimize) + command = [sys.executable, *flags, str(CLI), *arguments] + if audit: + command = [sys.executable, *flags, "-I", "-c", AUDIT_LAUNCHER, str(self.cwd), str(path), + str(self.cwd / "TEST-private-secret"), str(self.cwd / "TEST-observer.json"), str(CLI), + str(observer_port), *arguments] + environment = os.environ.copy() + environment.pop("PYTHONOPTIMIZE", None) + try: + return subprocess.run(command, cwd=self.cwd, env=environment, capture_output=True, + timeout=20, check=False) + except subprocess.TimeoutExpired: + self.fail("graph archive CLI exceeded the bounded 20-second fixture run") + + def accepted(self, raw=None, *, manifest=None, **kwargs): + members = kwargs.get("members", self.base) + manifest = self.entries(members)[-1][1] if manifest is None else manifest + raw = classic_zip(self.entries(members)) if raw is None else raw + expected = kwargs.get("expected", self.expected(raw, members)) + result = self.invoke(raw, **kwargs) + self.assertEqual(result.returncode, 0, result.stdout[-2000:] + result.stderr) + self.assertEqual(result.stderr, b"") + self.assertLessEqual(len(result.stdout), 16 * MIB) + report = document(result.stdout) + self.assertEqual(set(report), {"schema_version", "scientific_effect", "scientific_status_authority", + "custody", "graph", "receipt"}) + self.assertIs(type(report["schema_version"]), int) + self.assertEqual(report["schema_version"], 1) + self.assertEqual(report["scientific_effect"], "NONE") + self.assertIs(report["scientific_status_authority"], False) + self.assertEqual(report["custody"], "unknown") + self.assertEqual(encoded(report["graph"]), encoded(document(members["generated/graph.json"]))) + receipt = report["receipt"] + self.assertEqual(set(receipt), {"schema_version", "scientific_effect", "scientific_status_authority", + "custody", "verification_scope", "binding", "archive", "graph_member", + "producer_receipt_sha256", "producer_receipt"}) + self.assertIs(type(receipt["schema_version"]), int) + self.assertEqual(receipt["schema_version"], 1) + self.assertEqual(receipt["scientific_effect"], "NONE") + self.assertIs(receipt["scientific_status_authority"], False) + self.assertEqual(receipt["custody"], "unknown") + self.assertEqual(receipt["verification_scope"], "declared-native-pins-and-archive-content") + self.assertEqual(receipt["binding"], expected) + self.assertEqual(receipt["producer_receipt_sha256"], sha(members["architecture-run-receipt.json"])) + self.assertEqual(encoded(receipt["producer_receipt"]), encoded(document(members["architecture-run-receipt.json"]))) + archive = receipt["archive"] + self.assertEqual(set(archive), {"sha256", "bytes", "members"}) + self.assertEqual(archive["sha256"], sha(raw)) + self.assertIs(type(archive["bytes"]), int) + self.assertEqual(archive["bytes"], len(raw)) + rows = archive["members"] + self.assertEqual(len(rows), 13) + self.assertEqual([row["path"] for row in rows], sorted([*members, "ARTIFACT_SHA256SUMS"])) + for row in rows: + self.assertEqual(set(row), {"path", "bytes", "sha256"}) + self.assertIs(type(row["bytes"]), int) + raw_member = manifest if row["path"] == "ARTIFACT_SHA256SUMS" else members[row["path"]] + self.assertEqual(row, {"path": row["path"], "bytes": len(raw_member), "sha256": sha(raw_member)}) + self.assertIs(type(receipt["graph_member"]["bytes"]), int) + self.assertEqual(receipt["graph_member"], {"path": "generated/graph.json", + "bytes": len(members["generated/graph.json"]), "sha256": sha(members["generated/graph.json"])}) + self.assertEqual(result.stdout, encoded(report), "stdout is not one canonical ASCII/LF unit") + return report, result + + def refused(self, raw=None, **kwargs): + result = self.invoke(raw, **kwargs) + self.assertNotEqual(result.returncode, 0, "invalid archive was accepted") + self.assertEqual(result.stdout, b"", "refusal published partial or success JSON") + self.assertEqual(result.stderr, REFUSAL, "refusal exposed paths/member data or variable diagnostics") + + def test_valid_archive_is_one_stable_non_scientific_unit_with_original_receipt(self): + first, one = self.accepted() + _, two = self.accepted(path=self.cwd / "TEST-second-input.zip") + self.assertEqual(one.stdout, two.stdout) + self.assertNotIn("kernel_verified", first) + self.assertNotIn("lemma_exists", first) + self.assertNotIn(str(self.cwd).encode(), one.stdout) + manifest = self.entries()[-1][1] + self.assertEqual(next(row for row in first["receipt"]["archive"]["members"] + if row["path"] == "ARTIFACT_SHA256SUMS"), + {"path": "ARTIFACT_SHA256SUMS", "bytes": len(manifest), "sha256": sha(manifest)}) + + def test_other_native_context_attempt_ten_and_declared_artifact_id_are_preserved(self): + context = {**NATIVE, "checked_commit": "d" * 40, "repository": "TEST-other/TEST-repo", + "run_id": "987", "run_attempt": "10", "artifact_id": "7654321"} + members = self.fixture(context) + raw = classic_zip(self.entries(members)) + self.accepted(raw, members=members, expected=self.expected(raw, members, context)) + expected = self.expected(classic_zip(self.entries())) + expected["artifact_id"] = "999999" + report, _ = self.accepted(expected=expected) + self.assertEqual(report["receipt"]["binding"]["artifact_id"], "999999") + self.assertEqual(report["custody"], "unknown", "an artifact label became authenticated custody") + + def test_stored_deflated_descriptors_and_member_or_manifest_order_are_valid(self): + reversed_rows = b"".join(reversed(self.entries()[-1][1].splitlines(keepends=True))) + entries = self.entries(manifest=reversed_rows, order=list(reversed(list(self.base)))) + for mode in ("stored", "deflated", "signed_descriptors", "unsigned_descriptors", "dos_regular"): + with self.subTest(mode=mode): + options = {} + for index, (_, raw) in enumerate(entries): + if mode == "stored": + options[index] = {"method": 0} + elif mode == "signed_descriptors": + options[index] = {"flags": 8} + elif mode == "unsigned_descriptors": + compressed = zlib.compressobj(level=6, wbits=-15) + payload = compressed.compress(raw) + compressed.flush() + options[index] = {"flags": 8, "descriptor": struct.pack( + "