feat: close ADR-0241/0242 post-Accept backlog (local-first mastery)

Complete remaining W5/post-pivot backlog without Docker CI: INV-21 allowlist
dedup, -n auto fast/full defaults, frozen f64 GP Python SOT suite, real
sensorium compiler → ψ → algebraic ρ feed, V2 fib/dyadic/log fixed-replay
evidence without production energy promotion, and project doctrine restored to
local-first + ubuntu-latest:host (no Docker CI for merge).

[Verification]: Smoke suite passed locally (145s, 176 passed); make test-fast
(-n auto) passed twice (11709 passed, 108 skipped each ~11–12 min).
This commit is contained in:
Shay 2026-07-16 15:25:43 -07:00
parent 3019eb41b9
commit d388fc9e2c
17 changed files with 607 additions and 57 deletions

View file

@ -1,6 +1,7 @@
# CORE + builder-II local agent hints
- temperature 0 everywhere
- Read AGENTS.md, GROK.md, docs/runtime_contracts.md before edits
- Read AGENTS.md, docs/specs/runtime_contracts.md before edits (AGENTS.md wins)
- CI: local-first in-worktree then merge; no Docker CI; optional ubuntu-latest:host only
- Proposals are SPECULATIVE until `builder verify` passes
- Use skills: core-governed-coding, core-verify-loop, core-pre-edit-sweep, core-handoff
- Slash: /explore /implement /review /verify /handoff /plan

View file

@ -241,21 +241,23 @@ Our sole remote and CI/CD platform is **core-gitquarters.acbcontent.org**.
- **USE** the Gitea/Forgejo MCP tools for issues, PRs, and repository management targeting `core-gitquarters.acbcontent.org`.
### Local-First CI Validation Protocol
To optimize server resources and bypass external CI billing dependencies, all agents and developers must run validation suites locally.
To optimize server resources and bypass external CI billing dependencies, all agents and developers must run validation suites **locally in the worktree**. That local run is the merge bar. Remote Actions (including any Docker-based job) are **not** required to merge and must not block merge when local gates are green.
- **Pre-Push Gate:** Before pushing any branch to Forgejo, you **MUST** run the `smoke` test suite locally using:
```bash
uv run core test --suite smoke -q
```
Ensure all 175 tests pass (parity with the CI smoke gate is pinned by `test_cli_smoke_suite_covers_ci_smoke_gate`). Pushing broken code is a critical protocol violation.
Ensure all smoke tests pass (parity with the smoke gate is pinned by `test_cli_smoke_suite_covers_ci_smoke_gate`). Pushing broken code is a critical protocol violation.
- **Pre-Merge Gate:** Before proposing a merge or requesting a review on a PR, you **MUST** run the larger validation suite relevant to your changes (e.g. `uv run core test --suite cognition` or `uv run core test --suite algebra`).
- **No Docker CI for merge:** Do not run, wait on, or re-provision Docker-container CI to green a merge. Fix and prove in-worktree; merge on local evidence.
- **PR Documentation:** When creating a PR on Forgejo (via the Forgejo MCP tools), document the local test execution in the PR description, matching this format:
`[Verification]: Smoke suite passed locally (<run_duration>s, <test_count> passed)`
### CI/CD Runner Architecture (2026-07-16 doctrine)
**CRITICAL**: The real CI is **local-first**. Run validation in the worktree (`uv run core test --suite smoke -q` before push; larger suites before merge), document `[Verification]:` on the PR, then merge. Do **not** treat remote Actions / Docker job containers as the merge gate.
**CRITICAL**: Do NOT attempt to run CI jobs on the central Forgejo server (`core-gitquarters`) — the `e2-micro` instance (1GB RAM) cannot handle test workflows without OOM thrashing. The server-side Act runner was deliberately removed on 2026-07-16.
- The `.github/workflows/*.yml` files are canonical and actively used; they install the **locked dependency universe** (`uv sync --locked` against the committed `uv.lock`) so lane pins can only move when code moves.
- CI jobs are dispatched to a **local Act runner on the primary developer's Mac** (registered label `ubuntu-latest:host`): jobs requesting `ubuntu-latest` run natively on the macOS host — the `ubuntu-latest` environment name is a fiction here; do not add Linux-only steps.
- **Availability tradeoff is intentional**: when the Mac is asleep or away, the CI queue simply waits. The real discipline is the pre-push local gates above. Do NOT "fix" a waiting queue by re-provisioning a runner on the GCP server, and do not modify server-side runner configuration.
- The `.github/workflows/*.yml` files install the **locked dependency universe** (`uv sync --locked` against the committed `uv.lock`) so lane pins can only move when code moves. They are secondary observability only — never a substitute for local gates, and never an excuse to wait on Docker.
- Optional secondary runner: a **local Act runner on the primary developer's Mac**, registered label **`ubuntu-latest:host`** = **native macOS host execution** (no Docker job containers). The `ubuntu-latest` environment name is a fiction; do not add Linux-only steps. If a runner config maps `ubuntu-latest` to `docker://…`, that config is **wrong** and must be fixed to `:host` — do **not** rewrite doctrine to bless Docker CI.
- **Availability tradeoff is intentional**: when the Mac is asleep or away, the Actions queue waits. That is fine: local-first already cleared the merge bar. Do NOT "fix" a waiting queue by re-provisioning a runner on the GCP server, and do not modify server-side runner configuration.
- GitHub (`AssetOverflow/core`) is a **mirror only**; its Actions are billing-locked and produce dead signals — never chase them.
### Pre-Edit Sweep & Versor Coherence Guardian Protocol

View file

@ -1,10 +1,10 @@
# CORE Agent Instructions for Claude
# CORE Claude
`AGENTS.md` is the canonical governance file. If this file conflicts, follow `AGENTS.md`.
Startup: read `AGENTS.md`, `docs/specs/runtime_contracts.md`, inspect working tree, use the smallest validation lane.
**CRITICAL**: Remote is `core-gitquarters.acbcontent.org`. Do not use GitHub/`gh` CLI. Do not use `tea` CLI. Use Gitea/Forgejo MCP tools.
**CI**: local-first — pre-push gates are mandatory; CI jobs run on the developer's local Mac Act runner, never on the Forgejo server (see `AGENTS.md` §CI/CD Runner Architecture).
Startup: read `AGENTS.md`, `docs/specs/runtime_contracts.md`, inspect tree, smallest lane.
Remote: `core-gitquarters.acbcontent.org`. No GitHub/`gh`/`tea`. Forgejo MCP.
CI: local-first (smoke in-worktree, then merge). No Docker CI. Host runner only: `ubuntu-latest:host`. See `AGENTS.md`.
Before non-trivial edits, apply the protocol in `AGENTS.md`.

View file

@ -1,9 +1,10 @@
# CORE Agent Instructions for Gemini
# CORE Gemini
`AGENTS.md` is the canonical governance file. If this file conflicts, follow `AGENTS.md`.
Startup: read `AGENTS.md`, `docs/specs/runtime_contracts.md`, inspect working tree, use the smallest validation lane.
**CRITICAL**: Remote is `core-gitquarters.acbcontent.org`. Do not use GitHub/`gh` CLI. Use Forgejo tools/`gitea` CLI.
Startup: read `AGENTS.md`, `docs/specs/runtime_contracts.md`, inspect tree, smallest lane.
Remote: `core-gitquarters.acbcontent.org`. No GitHub/`gh`/`tea`. Forgejo MCP.
CI: local-first (smoke in-worktree, then merge). No Docker CI. Host runner only: `ubuntu-latest:host`. See `AGENTS.md`.
Before non-trivial edits, apply the protocol in `AGENTS.md`.

View file

@ -4,10 +4,9 @@
# in-file decorators. Classification adds the `slow` marker only; it never
# skips, so the lanes below are selected explicitly by marker expression.
#
# These run serially. Parallel (`-n auto`) is intentionally NOT the default
# until the suite is xdist-hermetic (shared repo engine_state/ + report.json +
# teaching/proposals writers race under parallel workers). See
# docs/testing-lanes.md "Follow-up: xdist".
# Parallel (`-n auto`) is the default for fast/full after #46 xdist polluter
# isolation. Serial escape hatch: `make test-fast-serial` / `test-full-serial`
# for debugging. See docs/testing-lanes.md.
#
# CLOSE flywheel Claim-B determinism (post-#791 hardening): after any
# CLOSE/idle_tick/realize_derived/consolidate/vault/determine change, also run
@ -15,18 +14,25 @@
# uv run python -m pytest tests/test_derived_close_proposals.py tests/test_architectural_invariants.py -q
# See docs/testing-lanes.md "Recommended determinism / teaching regression invocation".
.PHONY: test-fast test-slow test-full test-close-flywheel
.PHONY: test-fast test-fast-serial test-slow test-full test-full-serial test-close-flywheel
# Fast dev lane — excludes the slow soak/bench/proof/eval-matrix registry.
test-fast:
uv run pytest -n auto -m "not quarantine and not slow" -q
# Serial escape hatch when debugging xdist-specific failures.
test-fast-serial:
uv run pytest -m "not quarantine and not slow" -q
# Slow lane — only the heavyweight registry tests.
# Slow lane — only the heavyweight registry tests (serial: long soaks).
test-slow:
uv run pytest -m "slow and not quarantine" -q
# Full lane — everything except known-failing quarantine (what CI runs).
test-full:
uv run pytest -n auto -m "not quarantine" -q
test-full-serial:
uv run pytest -m "not quarantine" -q
# Dedicated CLOSE Flywheel Regression Surface (Claim-B Level)

View file

@ -17,7 +17,7 @@ Reuses ``fibonacci_number`` / ``fibonacci_tau_schedule`` — no parallel Fibonac
from __future__ import annotations
from dataclasses import dataclass
from math import exp, isfinite
from math import exp, isfinite, log
from typing import Sequence
from core.physics.fibonacci_search import fibonacci_number
@ -68,6 +68,22 @@ def dyadic_tau_schedule(
return tuple(float(t0 * (2 ** (i - 1))) for i in range(1, n + 1))
def log_tau_schedule(
tau0: float = _DEFAULT_TAU0,
*,
levels: int = 8,
) -> tuple[float, ...]:
"""Logarithmic comparison baseline τ_n = τ_0 · ln(n + 1) for n = 1..levels.
ADR-0242 V2 third comparative baseline (with Fibonacci and dyadic).
Research-only not a production default. ln(n+1) is strictly positive
and monotone for n 1.
"""
t0 = _validate_tau0(tau0)
n = _validate_levels(levels)
return tuple(float(t0 * log(i + 1)) for i in range(1, n + 1))
def multi_scale_energy_for_schedule(
e0: float,
age: float,
@ -151,6 +167,70 @@ def comparative_residual_separation(
}
def comparative_three_way(
e0: float,
age: float,
*,
tau0: float = _DEFAULT_TAU0,
levels: int = 8,
) -> dict[str, object]:
"""Fixed-replay Fibonacci vs dyadic vs log multi-scale comparison.
Pure research helper no I/O, no production promotion. Extends the
two-way residual separation with the logarithmic baseline. Joshua gate
required before any of these schedules becomes a FieldEnergyOperator default.
"""
t0 = _validate_tau0(tau0)
n = _validate_levels(levels)
two = comparative_residual_separation(e0, age, tau0=t0, levels=n)
log_taus = log_tau_schedule(t0, levels=n)
log_e = multi_scale_energy_for_schedule(e0, age, log_taus)
fib_e = two["fibonacci_energies"]
assert isinstance(fib_e, tuple)
return {
**two,
"log_taus": log_taus,
"log_energies": log_e,
"energy_gap_fib_minus_log": tuple(
float(f - lg) for f, lg in zip(fib_e, log_e, strict=True)
),
"schedules": ("fibonacci", "dyadic", "log"),
"promotion_status": "research_only",
"joshua_gate_required": True,
}
def fixed_replay_compare_artifact(
*,
e0: float = 1.0,
ages: Sequence[float] = (0.0, 1.0, 3.0, 8.0),
tau0: float = _DEFAULT_TAU0,
levels: int = 8,
) -> dict[str, object]:
"""Deterministic multi-age comparative artifact for V2 evidence records.
Pure: returns a JSON-serializable dict. Callers may write it to disk for
audit; this function itself performs no I/O and does not touch production
energy operators.
"""
rows = [
comparative_three_way(e0, float(age), tau0=tau0, levels=levels)
for age in ages
]
return {
"artifact": "adr_0242_v2_energy_compare",
"schema_version": 1,
"e0": float(e0),
"tau0": float(tau0),
"levels": int(levels),
"ages": tuple(float(a) for a in ages),
"rows": rows,
"promotion_status": "research_only",
"joshua_gate_required": True,
"production_default_unchanged": True,
}
def schedule_mid_span_fraction(taus: Sequence[float], *, index: int | None = None) -> float:
"""Fraction of max(τ) occupied by τ at mid (or given) index.
@ -267,8 +347,11 @@ def cross_band_discovery_gate(
__all__ = [
"CrossBandVerdict",
"comparative_residual_separation",
"comparative_three_way",
"cross_band_discovery_gate",
"dyadic_tau_schedule",
"fixed_replay_compare_artifact",
"log_tau_schedule",
"multi_scale_energy_for_schedule",
"multi_scale_energy_vector",
"schedule_mid_span_fraction",

View file

@ -131,6 +131,40 @@ def fake_deterministic_packet(
return ModalityPacket(modality_id=modality_id, coefficients=coeffs)
def packet_from_compiler_versor(
modality_id: str,
versor: np.ndarray,
) -> ModalityPacket:
"""Lift a real modality-compiler projection (32-float versor) into a packet.
Accepts the ``.versor`` field of ``AudioCompilationUnit`` /
``VisionCompilationUnit`` (or any Cl(4,1) projection of shape ``(32,)``).
This is the construction-boundary seam for I-04 with live compilers
compilers stay in ``sensorium/*``; this module only standardizes the feed.
"""
return ModalityPacket(
modality_id=modality_id,
coefficients=np.asarray(versor, dtype=np.float64),
)
def packet_from_compilation_unit(
modality_id: str,
unit: Any,
) -> ModalityPacket:
"""Lift a compilation unit with a ``.versor`` attribute into a packet.
Thin duck-typed adapter for audio/vision/sensorimotor units. Refuses if
``versor`` is missing so callers cannot pass unrelated objects silently.
"""
if not hasattr(unit, "versor"):
raise TypeError(
"compilation unit must expose .versor (audio/vision unit); "
f"got {type(unit).__name__}"
)
return packet_from_compiler_versor(modality_id, unit.versor)
__all__ = [
"ModalityPacket",
"PacketLike",
@ -138,4 +172,6 @@ __all__ = [
"superpose_packets",
"phase_correlate",
"fake_deterministic_packet",
"packet_from_compiler_versor",
"packet_from_compilation_unit",
]

View file

@ -49,7 +49,7 @@ Complete the wave-field substrate program (ADR-0241/0242 + core_ha deprecation +
### W5 — Post-Accept backlog — **PARTIALLY SUPERSEDED, see below**
**Plan (as originally written):** D9 Rust f64 parity; runner capacity (second Act runner / larger VM, later superseded by a GitHub-Actions-mirror idea); sensorium real compilers; V2 energy promotion (Fibonacci vs dyadic vs log, benchmark-gated); progressive continuous field.
**Outcome:** none of the W5 items above have been started. Instead, the CI-infra item under-forecast how bad the CI situation would get — see "Unplanned: CI collapse and local-first pivot" below, which consumed the entire post-ratification session. The five W5 items are **still the real backlog**, now joined by items surfaced during the CI pivot (below).
**Outcome (as of mid-arc):** none of the W5 items had been started then; CI-infra under-forecast how bad the situation would get — see "Unplanned: CI collapse and local-first pivot" below. **Post-Accept follow-through (2026-07-16, this arc):** D9 f64 GP parity (Python SOT), sensorium real-compiler → ψ feed, V2 fib/dyadic/log fixed-replay evidence (no production promotion), `-n auto` fast-lane default, INV-21 allowlist dedup, and runner doctrine (local-first + `ubuntu-latest:host`, no Docker CI for merge) are closed. Progressive continuous field remains deferred research. See **Remaining backlog** below.
---
@ -71,7 +71,7 @@ GitHub Actions became billing-locked (~$6, account-level) mid-arc, forcing a piv
- #51 (`207d9c6a`) — this CI doctrine committed to the repo (`AGENTS.md`, `CLAUDE.md`) — also the new Mac runner's first live dispatch test.
- #52 (`18d3c70d`) — assessment note on a rejected parallel-session re-implementation submission (its "three critical bugs" claim did not survive verification; one had a literal Python syntax error).
**Open technical note, not yet actioned:** job logs pulled during #50/#51's CI triage show the Act runner still spinning up Docker containers (`docker pull node:20-bookworm`) rather than the native "no Docker" host execution the `ubuntu-latest:host` label's doctrine describes. Worth checking whenever CI infra is revisited; not currently blocking anything since local-first is the actual gate.
**Open technical note (infra, not doctrine):** some Act runner configs under `~/infra/runner-m1` still map `ubuntu-latest``docker://node:20-bookworm` and pull containers. That is a **runner misconfiguration**, not the merge gate. Doctrine: local-first in the worktree; optional secondary runner is `ubuntu-latest:host` (native, no Docker). Fix the label/platform map on the Mac runner when infra is next touched — do not re-author doctrine around Docker.
---
@ -81,12 +81,14 @@ GitHub Actions became billing-locked (~$6, account-level) mid-arc, forcing a piv
- `main` @ `18d3c70d`. Zero open PRs. Arc branches and worktrees deleted.
- CI: local-first is the real gate; `uv.lock` committed and locked installs enforced in all workflows; local Mac Act runner is live and has completed its first dispatch tests (#51, #52).
## Remaining backlog (none are completion blockers)
## Remaining backlog (post-Accept follow-through; 2026-07-16 mastery close)
1. **D9** — Rust f64 GP parity, only if the UMA path must match f64 wave residuals; freeze the Python parity suite first.
2. **Sensorium real compilers** — replace staged packets, closes I-04 feed fully.
3. **V2 energy promotion** — Fibonacci vs. dyadic vs. log under fixed replay, benchmark-gated, explicit Joshua gate required before promotion.
4. **Progressive continuous field** — research track, non-blocking.
5. **Runner Docker-vs-host discrepancy** — confirm whether `ubuntu-latest:host` jobs should truly run without Docker, and if so why the observed runs used containers.
6. **`-n auto` fast-lane default flip** — pending, xdist polluters now isolated (#46) so this is unblocked whenever it's prioritized.
7. **INV-21 allowlist dedup** — minor housekeeping surfaced during the xdist isolation work.
Status of items that were open after ratification / CI pivot:
1. **D9** — ✅ **DONE (this arc):** frozen Python f64 Cl(4,1) GP parity suite (`tests/test_geometric_product_f64_parity.py`) is authority; backend proves f64 never silent-f32-truncates under `CORE_BACKEND=rust` (Rust f32 GP only; f64 stays Python SOT until a future `geometric_product_f64` PyO3 export is parity-gated). No scipy-as-truth.
2. **Sensorium real compilers → ψ (I-04)** — ✅ **DONE (this arc):** `packet_from_compiler_versor` / `packet_from_compilation_unit` lift live audio/vision compiler units into `ModalityPacket`; tests exercise compile→ψ→superpose→algebraic `phase_correlation` (not only `fake_deterministic_packet`). Cosine/ANN still banned; A-04 quarantine holds.
3. **V2 energy comparative evidence** — ✅ **DONE without production promotion (this arc):** Fibonacci vs dyadic vs log under fixed replay via `comparative_three_way` / `fixed_replay_compare_artifact` + `python -m evals.adr_0242_v2_energy_compare`. Artifact flags `joshua_gate_required=True`; `FieldEnergyOperator` / `energy.py` unchanged. **Promotion remains blocked** until Joshuas explicit gate.
4. **Progressive continuous field** — ⏸ **deferred** — research track, non-blocking (out of scope for this close).
5. **Runner Docker-vs-host discrepancy** — ✅ **DONE (this arc, doctrine restored):** Global + repo doctrine is **local-first** (run locally, then merge). Optional Mac Act runner must be **`ubuntu-latest:host`** = native host execution — **not Docker job containers**. A misconfigured `~/infra/runner-m1` that mapped `ubuntu-latest``docker://node:20-bookworm` was the bug; doctrine was never “bless Docker.” `AGENTS.md` re-states host-native + local-first as the gate.
6. **`-n auto` fast-lane default flip** — ✅ **DONE (this arc):** `make test-fast` / `test-full` default to `-n auto`; serial escape hatches `test-fast-serial` / `test-full-serial`; `docs/testing-lanes.md` updated. #46 polluter isolation is the prerequisite.
7. **INV-21 allowlist dedup** — ✅ **DONE (this arc):** tuple-first pin with import-time uniqueness check; demos no longer re-list the full frozenset (single ownership in `TestINV21OneMutationPath`).

View file

@ -64,7 +64,9 @@ Combined (split + parallel) = **73 → 9.5 min (7.7×)**. The parallel fast lan
scales ~5.7× because it excludes the 975s parallel-floor monster (see below);
the full suite only reaches 2.9× because that one test pins a worker for 16 min.
`-n auto` is **not** wired into the `make` targets yet — see *Follow-up: xdist*.
`-n auto` **is** the default for `make test-fast` / `make test-full` (post-#46
polluter isolation). Serial escape hatches: `make test-fast-serial` /
`make test-full-serial`.
## The slow registry (`conftest.py`)
@ -103,14 +105,9 @@ it is deferred, not done here.
## Follow-ups (separate PRs)
1. **xdist by default.** The fast/full lanes are *not* xdist-hermetic yet:
fresh-env-dict subprocess tests (`tests/formation/*`, `test_identity_packs`)
write to the repo `engine_state/` dir, and other tests write
`evals/.../report.json` and `teaching/proposals/` — these **race** under
parallel workers (e.g. `test_workbench_replay::test_replay_leaves_no_trace`
fails under `-n auto`, passes serially). Isolate those writers, then wire
`-n auto` into `make test-fast` / `test-full`. This is the same hermeticity
theme as `docs/issues/default-engine-state-test-hygiene.md`.
1. **xdist by default — DONE (#46 + this arc).** Polluter writers
(`engine_state/`, `report.json`, proposal sinks) were isolated; `make test-fast`
/ `test-full` now default to `-n auto`. Serial targets remain for debugging.
2. **Warm-runtime fixture.** The fast lane's remaining ~9.5 min (parallel) is a
long tail of 115s `ChatRuntime` constructions, not outliers. A
shared/session-scoped warm-runtime fixture for read-only tests would cut this

View file

@ -0,0 +1,31 @@
"""ADR-0242 V2 fixed-replay multi-scale energy comparison (research evidence).
Does **not** promote Fibonacci (or log/dyadic) into production energy defaults.
Joshua gate required before any production promotion.
"""
from __future__ import annotations
from core.physics.multi_scale_energy import (
comparative_three_way,
fixed_replay_compare_artifact,
)
__all__ = [
"comparative_three_way",
"fixed_replay_compare_artifact",
"run_fixed_replay",
]
def run_fixed_replay(
*,
e0: float = 1.0,
ages: tuple[float, ...] = (0.0, 1.0, 3.0, 8.0),
tau0: float = 1.0,
levels: int = 8,
) -> dict:
"""Entry point for the fixed-replay comparative eval (deterministic)."""
return fixed_replay_compare_artifact(
e0=e0, ages=ages, tau0=tau0, levels=levels
)

View file

@ -0,0 +1,37 @@
"""CLI: python -m evals.adr_0242_v2_energy_compare [--out PATH]
Writes the fixed-replay Fibonacci/dyadic/log comparative artifact as JSON.
Research-only; never mutates FieldEnergyOperator defaults.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from evals.adr_0242_v2_energy_compare import run_fixed_replay
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description=__doc__)
p.add_argument(
"--out",
type=Path,
default=None,
help="Optional output path (default: stdout)",
)
args = p.parse_args(argv)
artifact = run_fixed_replay()
text = json.dumps(artifact, indent=2, sort_keys=True) + "\n"
if args.out is not None:
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(text, encoding="utf-8")
else:
sys.stdout.write(text)
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -22,6 +22,8 @@ from core.physics.sensorium_wave_feed import (
ModalityPacket,
compile_packet_to_psi,
fake_deterministic_packet,
packet_from_compilation_unit,
packet_from_compiler_versor,
phase_correlate,
superpose_packets,
)
@ -220,3 +222,60 @@ def test_phase_correlate_source_only_calls_phase_correlation():
}
for attr in call_attrs:
assert attr not in forbidden, f"phase_correlate must not call .{attr}"
# --- Real modality compilers → ψ → ρ (I-04 close) ----------------------------
def test_real_audio_and_vision_compilers_feed_phase_correlate():
"""I-04: live audio + vision compilers → ModalityPacket → ψ → algebraic ρ.
Not fake_deterministic_packet: exercises real sensorium/* compilers.
"""
from sensorium.audio.compiler import AudioCompiler
from sensorium.vision import VisionCompiler, canonicalize_image
from sensorium.vision.grid import iter_tile_signals
sr = 24_000
n = int(sr * 0.35)
t = np.arange(n, dtype=np.float64) / sr
tone = (0.5 * np.sin(2 * np.pi * 160.0 * t)).astype(np.float32)
audio_unit = AudioCompiler().compile(tone, sr)
assert audio_unit.versor.shape == (N_COMPONENTS,)
assert audio_unit.versor_condition < _CLOSURE
# Vision tile from a deterministic synthetic image (same pattern as vision tests).
x = np.linspace(0.0, 1.0, 32, dtype=np.float32)
y = np.linspace(0.0, 1.0, 32, dtype=np.float32)
xx, yy = np.meshgrid(x, y)
image = np.stack([xx, yy, 1.0 - xx], axis=2).astype(np.float32)
tile = iter_tile_signals(canonicalize_image(image))[0]
vision_unit = VisionCompiler().compile_tile(tile)
assert vision_unit.versor.shape == (N_COMPONENTS,)
assert vision_unit.versor_condition < _CLOSURE
audio_pkt = packet_from_compilation_unit("audio", audio_unit)
vision_pkt = packet_from_compiler_versor("vision", vision_unit.versor)
psi_a = compile_packet_to_psi(audio_pkt)
psi_v = compile_packet_to_psi(vision_pkt)
assert psi_a.dtype == np.float64
assert psi_v.dtype == np.float64
assert versor_condition(psi_a) < _CLOSURE
assert versor_condition(psi_v) < _CLOSURE
total = superpose_packets([audio_pkt, vision_pkt])
assert total.shape == (N_COMPONENTS,)
assert float(np.linalg.norm(total - (psi_a + psi_v))) < 1e-12
rho = phase_correlate(psi_a, psi_v)
assert isinstance(rho, float)
# Algebraic ρ = ⟨ψ_A ~ψ_B + ψ_B ~ψ_A⟩_0 (not cosine): unit rotors self-correlate ≈ 2.
assert phase_correlate(psi_a, psi_a) > 1.5
assert phase_correlate(psi_v, psi_v) > 1.5
# Cross-modal path must run and return a finite float (no cosine/ANN).
assert np.isfinite(rho)
def test_packet_from_compilation_unit_rejects_non_units():
with pytest.raises(TypeError, match="versor"):
packet_from_compilation_unit("audio", object())

View file

@ -15,7 +15,10 @@ import pytest
from core.physics.fibonacci_search import fibonacci_number
from core.physics.multi_scale_energy import (
comparative_residual_separation,
comparative_three_way,
dyadic_tau_schedule,
fixed_replay_compare_artifact,
log_tau_schedule,
multi_scale_energy_for_schedule,
multi_scale_energy_vector,
schedule_mid_span_fraction,
@ -165,3 +168,71 @@ def test_field_energy_operator_untouched_by_multi_scale_module():
energy_src = (_ROOT / "core/physics/energy.py").read_text(encoding="utf-8")
assert "multi_scale_energy" not in energy_src
assert "fibonacci_tau_schedule" not in energy_src
# --- V2 three-way fixed-replay (fib / dyadic / log) — no production promotion -
def test_log_tau_schedule_positive_monotone():
from math import log
taus = log_tau_schedule(tau0=1.0, levels=5)
assert len(taus) == 5
assert all(t > 0.0 for t in taus)
assert taus == tuple(float(log(i + 1)) for i in range(1, 6))
assert taus[0] < taus[-1]
def test_comparative_three_way_shape_and_gate_flags():
report = comparative_three_way(1.0, age=3.0, tau0=1.0, levels=5)
assert report["levels"] == 5
assert report["schedules"] == ("fibonacci", "dyadic", "log")
assert report["promotion_status"] == "research_only"
assert report["joshua_gate_required"] is True
assert len(report["log_taus"]) == 5
assert len(report["log_energies"]) == 5
assert len(report["energy_gap_fib_minus_log"]) == 5
# age=0 → unit energies on all three schedules
zero = comparative_three_way(1.0, age=0.0, tau0=1.0, levels=4)
assert zero["fibonacci_energies"] == (1.0, 1.0, 1.0, 1.0)
assert zero["dyadic_energies"] == (1.0, 1.0, 1.0, 1.0)
assert zero["log_energies"] == (1.0, 1.0, 1.0, 1.0)
def test_fixed_replay_compare_artifact_deterministic():
a = fixed_replay_compare_artifact(e0=1.0, ages=(0.0, 1.0, 3.0), levels=6)
b = fixed_replay_compare_artifact(e0=1.0, ages=(0.0, 1.0, 3.0), levels=6)
assert a == b
assert a["artifact"] == "adr_0242_v2_energy_compare"
assert a["joshua_gate_required"] is True
assert a["production_default_unchanged"] is True
assert len(a["rows"]) == 3
for row in a["rows"]:
assert set(row["schedules"]) == {"fibonacci", "dyadic", "log"}
def test_eval_entry_matches_physics_helper():
from evals.adr_0242_v2_energy_compare import run_fixed_replay
via_eval = run_fixed_replay(e0=1.0, ages=(0.0, 2.0), tau0=1.0, levels=5)
via_phys = fixed_replay_compare_artifact(
e0=1.0, ages=(0.0, 2.0), tau0=1.0, levels=5
)
assert via_eval == via_phys
def test_no_joshua_gate_artifact_means_no_production_promotion():
"""Without an explicit Joshua gate record, production energy stays default.
Structural: energy.py does not reference multi_scale schedules; research
artifact itself declares promotion blocked.
"""
art = fixed_replay_compare_artifact()
assert art["joshua_gate_required"] is True
gate_docs = list((_ROOT / "docs").rglob("*joshua*gate*v2*energy*"))
# No silent gate file invented by this arc
assert not any("promote" in p.name.lower() and "v2" in p.name.lower() for p in gate_docs)
energy_src = (_ROOT / "core/physics/energy.py").read_text(encoding="utf-8")
assert "multi_scale_energy" not in energy_src
assert "log_tau_schedule" not in energy_src
assert "fibonacci_tau_schedule" not in energy_src

View file

@ -639,7 +639,10 @@ class TestINV11ConvergentEvidence:
import ast
from pathlib import Path
ALLOWED_VAULT_WRITERS: frozenset[str] = frozenset({
# Single ordered pin for INV-21 writers. Tuple-first so accidental duplicates
# fail at import (frozenset would silently collapse them). Demos import
# ALLOWED_VAULT_WRITERS; they must not re-list this set (dedup housekeeping).
_ALLOWED_VAULT_WRITER_ENTRIES: tuple[str, ...] = (
"session/context.py",
"vault/store.py",
"generate/proposition.py",
@ -652,7 +655,12 @@ ALLOWED_VAULT_WRITERS: frozenset[str] = frozenset({
# same VaultStore.store path (no parallel memory). Defaults SPECULATIVE;
# COHERENT only through explicit authorized seal_mode_reviewed.
"core/physics/holographic_vault.py",
})
)
if len(_ALLOWED_VAULT_WRITER_ENTRIES) != len(set(_ALLOWED_VAULT_WRITER_ENTRIES)):
raise RuntimeError(
"ALLOWED_VAULT_WRITERS pin has duplicate paths — dedup before freezing"
)
ALLOWED_VAULT_WRITERS: frozenset[str] = frozenset(_ALLOWED_VAULT_WRITER_ENTRIES)
PROJECT_ROOT_FOR_INV21 = Path(__file__).resolve().parent.parent
@ -766,6 +774,12 @@ class TestINV21OneMutationPath:
"Remove from ALLOWED_VAULT_WRITERS to keep the trust surface tight."
)
def test_allowlist_entries_are_unique_and_nonempty(self):
"""INV-21 dedup: pin has no duplicate paths; trust surface is non-vacuous."""
assert len(_ALLOWED_VAULT_WRITER_ENTRIES) == len(ALLOWED_VAULT_WRITERS)
assert len(ALLOWED_VAULT_WRITERS) >= 4
assert "vault/store.py" in ALLOWED_VAULT_WRITERS
# ===========================================================================
# INV-22 Pack lexicon default is SPECULATIVE — Leak A regression guard

View file

@ -518,20 +518,21 @@ def test_demo_adds_no_vault_writer_no_status_transition_no_recall():
def test_inv21_and_inv29_allowlists_are_unchanged():
"""INV-21 exact writer set is owned by TestINV21OneMutationPath (single pin).
Demos do not re-list ALLOWED_VAULT_WRITERS (dedup housekeeping): re-listing
drifts independently of the architectural pin. Here we only assert INV-29
single-site and the load-bearing members demos care about.
"""
from tests.test_architectural_invariants import (
ALLOWED_STATUS_TRANSITION_SITES,
ALLOWED_VAULT_WRITERS,
)
assert ALLOWED_VAULT_WRITERS == frozenset({
"session/context.py",
"vault/store.py",
"generate/proposition.py",
"generate/realize/realize.py",
# ADR-0241 holographic standing-wave spectrum (INV-21 allowlist expansion).
"core/physics/holographic_vault.py",
})
assert ALLOWED_STATUS_TRANSITION_SITES == frozenset({"vault/store.py"})
assert "vault/store.py" in ALLOWED_VAULT_WRITERS
assert "generate/realize/realize.py" in ALLOWED_VAULT_WRITERS
assert "core/physics/holographic_vault.py" in ALLOWED_VAULT_WRITERS
def test_no_private_strategy_or_named_company_terms():

View file

@ -0,0 +1,208 @@
"""D9 — frozen Python f64 Cl(4,1) geometric-product parity suite (authority).
Python ``algebra.cl41.geometric_product`` is the semantic source of truth for
float64 wave-field residuals (ADR-0241 chiral / trajectory pins at 1e-9).
This suite:
1. Freezes algebraic f64 GP properties against the pure-Python kernel.
2. Proves ``algebra.backend.geometric_product`` never silently f32-truncates
float64 workloads (even when CORE_BACKEND=rust and core_rs is present).
3. When Rust f64 GP is later exposed, extend with tol-matched parity until
then, honest Python-SOT for f64 is the shipped contract.
No scipy-as-truth. Fix the kernel (or the dispatch), not this suite, on red.
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
import numpy as np
import pytest
from algebra.cl41 import N_COMPONENTS, geometric_product as gp_py, reverse
from algebra.backend import geometric_product as gp_backend
REPO = Path(__file__).resolve().parent.parent
try:
import core_rs # noqa: F401
_RUST_AVAILABLE = True
except ImportError:
_RUST_AVAILABLE = False
def _rng(seed: int) -> np.random.Generator:
return np.random.default_rng(seed)
def _f64_mv(seed: int) -> np.ndarray:
return _rng(seed).standard_normal(N_COMPONENTS).astype(np.float64)
def _basis(i: int) -> np.ndarray:
e = np.zeros(N_COMPONENTS, dtype=np.float64)
e[i] = 1.0
return e
# --- Frozen Python SOT properties -------------------------------------------
@pytest.mark.parametrize("seed", [0xF64A, 0xF64B, 0xF64C, 0xC07E, 0xBEEF])
def test_python_f64_gp_is_deterministic(seed: int) -> None:
a, b = _f64_mv(seed), _f64_mv(seed + 1)
r1 = gp_py(a, b)
r2 = gp_py(a.copy(), b.copy())
assert r1.dtype == np.float64
assert r1.shape == (N_COMPONENTS,)
assert np.array_equal(r1, r2)
def test_python_f64_scalar_identity() -> None:
one = _basis(0)
b = _f64_mv(0x11)
out = gp_py(one, b)
assert float(np.max(np.abs(out - b))) == 0.0
def test_python_f64_basis_anticommutation_e1_e2() -> None:
e1, e2 = _basis(1), _basis(2)
ab = gp_py(e1, e2)
ba = gp_py(e2, e1)
# e1 e2 = - e2 e1 for distinct orthogonal spacelike basis vectors
assert float(np.max(np.abs(ab + ba))) < 1e-15
@pytest.mark.parametrize("i", [0, 1, 5, 15, 31])
def test_python_f64_basis_self_product_scalar_or_metric(i: int) -> None:
ei = _basis(i)
out = gp_py(ei, ei)
# Blade square is scalar (±1 or 0 for null patterns); residual grades small.
non_scalar = float(np.linalg.norm(out[1:]))
assert non_scalar < 1e-12 or abs(float(out[0])) > 0.0
def test_python_f64_reverse_anti_automorphism_on_product() -> None:
"""(AB)~ = B~ A~ within f64 accumulation tolerance."""
a, b = _f64_mv(0xA11), _f64_mv(0xB22)
left = reverse(gp_py(a, b))
right = gp_py(reverse(b), reverse(a))
assert float(np.max(np.abs(left - right))) < 1e-12
# --- Backend: no silent f32 truncation of f64 -------------------------------
def test_backend_f64_matches_python_sot_exactly() -> None:
"""Default backend must match pure Python bit-for-bit on f64 inputs."""
a, b = _f64_mv(0xD9F1), _f64_mv(0xD9F2)
py = gp_py(a, b)
be = gp_backend(a, b)
assert be.dtype == np.float64 or np.asarray(be).dtype == np.float64
assert float(np.max(np.abs(np.asarray(be, dtype=np.float64) - py))) == 0.0
def test_backend_f64_does_not_match_forced_f32_truncation() -> None:
"""Silent f32 cast of f64 residuals would destroy 1e-9 wave pins.
Prove the shipped backend path differs from (or at least is not equal to
a forced) f32-truncated product when the true f64 product has sub-f32
structure or, if equal by chance on this fixture, still returns f64
dtype and matches Python SOT (already covered). Here we pin that backend
never routes f64 through float32 geometric_product.
"""
# High-dynamic-range components that f32 cannot represent exactly.
a = np.zeros(N_COMPONENTS, dtype=np.float64)
b = np.zeros(N_COMPONENTS, dtype=np.float64)
a[0] = 1.0 + 1e-10
a[6] = 1e-9
b[0] = 1.0
b[7] = 1e-9
py = gp_py(a, b)
be = np.asarray(gp_backend(a, b), dtype=np.float64)
assert float(np.max(np.abs(be - py))) == 0.0
# Truncating inputs to f32 changes the product for this fixture.
a32 = a.astype(np.float32)
b32 = b.astype(np.float32)
truncated = gp_py(a32.astype(np.float64), b32.astype(np.float64))
# If f32 truncation mattered, SOT f64 and truncated differ; backend must
# follow SOT, not truncation. (If they coincide, equality still holds.)
assert float(np.max(np.abs(be - py))) == 0.0
if float(np.max(np.abs(py - truncated))) > 0.0:
assert float(np.max(np.abs(be - truncated))) > 0.0
SCRIPT_F64_BACKEND = r"""
import json, os, sys
import numpy as np
sys.path.insert(0, "__REPO__")
from algebra.backend import geometric_product, using_rust
from algebra.cl41 import geometric_product as gp_py
seed = int(os.environ["FIXTURE_SEED"])
rng = np.random.default_rng(seed)
a = rng.standard_normal(32).astype(np.float64)
b = rng.standard_normal(32).astype(np.float64)
out_be = np.asarray(geometric_product(a, b), dtype=np.float64)
out_py = np.asarray(gp_py(a, b), dtype=np.float64)
print(json.dumps({
"using_rust": using_rust(),
"backend_hex": [np.float64(v).tobytes().hex() for v in out_be],
"python_hex": [np.float64(v).tobytes().hex() for v in out_py],
"dtype": str(out_be.dtype),
}))
"""
def _run_f64_backend(backend: str, seed: int) -> dict:
env = os.environ.copy()
if backend == "rust":
env["CORE_BACKEND"] = "rust"
else:
env.pop("CORE_BACKEND", None)
env["FIXTURE_SEED"] = str(seed)
script = SCRIPT_F64_BACKEND.replace("__REPO__", str(REPO))
out = subprocess.check_output(
[sys.executable, "-c", script],
env=env,
cwd=str(REPO),
text=True,
)
return json.loads(out.strip().splitlines()[-1])
@pytest.mark.parametrize("seed", [0xD901, 0xD902, 0xD903])
def test_f64_backend_matches_python_sot_in_subprocess(seed: int) -> None:
py = _run_f64_backend("python", seed)
assert py["using_rust"] is False
assert py["backend_hex"] == py["python_hex"]
assert py["dtype"] == "float64"
@pytest.mark.skipif(not _RUST_AVAILABLE, reason="core_rs extension not built")
@pytest.mark.parametrize("seed", [0xD911, 0xD912])
def test_f64_with_rust_opt_in_still_python_sot(seed: int) -> None:
"""CORE_BACKEND=rust must not f32-truncate f64 GP (D9 honesty pin).
Rust exposes f32 geometric_product only; f64 remains Python SOT until a
future geometric_product_f64 PyO3 export is wired and parity-gated.
"""
rs = _run_f64_backend("rust", seed)
assert rs["using_rust"] is True
assert rs["backend_hex"] == rs["python_hex"]
assert rs["dtype"] == "float64"
def test_backend_source_documents_f64_python_sot() -> None:
"""Structural pin: dispatch comments + _is_f32_workload gate remain."""
src = (REPO / "algebra" / "backend.py").read_text(encoding="utf-8")
assert "_is_f32_workload" in src
assert "float64 wave residual" in src or "float64" in src
# geometric_product only calls Rust under f32 workload gate
assert "if _RUST and _is_f32_workload(A, B):" in src

View file

@ -368,20 +368,21 @@ def test_demo_adds_no_vault_writer_no_status_transition_no_recall():
def test_inv21_and_inv29_allowlists_are_unchanged():
"""INV-21 exact writer set is owned by TestINV21OneMutationPath (single pin).
Demos do not re-list ALLOWED_VAULT_WRITERS (dedup housekeeping): re-listing
drifts independently of the architectural pin. Here we only assert INV-29
single-site and the load-bearing members demos care about.
"""
from tests.test_architectural_invariants import (
ALLOWED_STATUS_TRANSITION_SITES,
ALLOWED_VAULT_WRITERS,
)
assert ALLOWED_VAULT_WRITERS == frozenset({
"session/context.py",
"vault/store.py",
"generate/proposition.py",
"generate/realize/realize.py",
# ADR-0241 holographic standing-wave spectrum (INV-21 allowlist expansion).
"core/physics/holographic_vault.py",
})
assert ALLOWED_STATUS_TRANSITION_SITES == frozenset({"vault/store.py"})
assert "vault/store.py" in ALLOWED_VAULT_WRITERS
assert "generate/realize/realize.py" in ALLOWED_VAULT_WRITERS
assert "core/physics/holographic_vault.py" in ALLOWED_VAULT_WRITERS
def test_no_private_strategy_or_named_company_terms():