Compare commits

...

9 commits

279 changed files with 4865 additions and 3177 deletions

View file

@ -117,7 +117,7 @@ Do not introduce new local prose parsers inside derivation organs unless explici
Before editing:
1. Read this file.
2. Read `docs/runtime_contracts.md`.
2. Read `docs/specs/runtime_contracts.md`.
3. Read the latest recent `HANDOFF-*.md` if relevant.
4. Confirm repo root and inspect working tree state.
5. Run the smallest relevant validation lane.
@ -129,6 +129,33 @@ For non-trivial edits:
- keep changes small and load-bearing
- If working in Arena/parallel subagent mode, each subagent must independently satisfy `versor_condition` and results must be reconciled before merge. No subagent output becomes another subagent's unchecked input.
### Repository topology discipline
Before calling a directory, module, or file stale/redundant, classify its
intrinsic role:
- runtime boundary
- candidate/provisional compiler
- reviewed pack or corpus data
- read-only Workbench/API projection
- standalone demo envelope
- benchmark/eval/report artifact
- historical note or handoff
- script/tooling surface
Then verify with `rg` imports/callers, tests, docs/ADR references, and CLI
routes before moving or deleting anything. A file is not dead merely because it
is platform-specific, optional, generated-adjacent, or outside `core/`.
When an intentional split exists, make the boundary local and enforceable:
- add or update a short `README.md` at each side of the split;
- state what owns mutation, what is read-only, and which validation lane proves it;
- add or extend a lightweight hygiene/doctor/package test when drift is likely;
- keep artifact namespaces non-executable unless they are deliberately promoted
to packages or moved under `scripts/`.
Package and CLI changes must check fresh-install visibility, not just source-tree
imports. Use `core doctor`, package include tests, and wheel inspection when a
new top-level package or CLI-imported module is added.
### Workspace Hygiene + Branch Protocol
Before branch movement or edits:
- Confirm cwd/repo root.
@ -199,6 +226,7 @@ If it touched user input, files, dynamic imports, or logs, what trust boundary w
`CLAUDE.md`, `GEMINI.md`, and any future provider file must:
- be short
- stay under 600 bytes unless there is a tool-specific reason reviewed in `AGENTS.md`
- point here as canonical
- avoid duplicating architecture
- avoid introducing provider-only truth

View file

@ -1,34 +1,11 @@
# CORE Agent Instructions for Claude
Read this file before modifying the repository.
`AGENTS.md` is the canonical governance file for this repo. If this file
conflicts with `AGENTS.md`, follow `AGENTS.md`.
`AGENTS.md` is the canonical governance file for this repo.
If this file conflicts with `AGENTS.md`, follow `AGENTS.md`.
Claude-specific startup: read `AGENTS.md`, read
`docs/specs/runtime_contracts.md`, inspect the working tree, then use the
smallest validation lane that proves the change.
## Session start
1. Read `AGENTS.md`.
2. Read `docs/runtime_contracts.md`.
3. Read the most recent `HANDOFF-*.md` from the last 3 days if one exists and is relevant.
4. Confirm repository root and inspect the working tree before editing.
5. Run:
```bash
core test --suite smoke -q
```
6. State the task scope before making changes:
- which module(s) you will touch
- which invariant or contract you must preserve
## Working rules
- Do not invent alternate architecture, alternate invariants, or alternate memory rules.
- Use the smallest relevant validation lane first, then broader lanes as required by change scope.
- For docs/config-only changes, smoke is usually sufficient unless the change affects executable paths, tests, CLI behavior, or generated artifacts.
- Prefer small, load-bearing changes.
- Use `AGENTS.md` as the source of truth for architecture, invariants, validation, and PR standards.
## Session end
When a session produced meaningful implementation or architectural analysis, write or update a handoff document using the repos handoff template and current naming convention.
Do not place architecture, invariants, memory rules, or alternate workflow
policy here. Update `AGENTS.md` instead.

View file

@ -1,34 +1,11 @@
# CORE Agent Instructions for Gemini
Read this file before modifying the repository.
`AGENTS.md` is the canonical governance file for this repo. If this file
conflicts with `AGENTS.md`, follow `AGENTS.md`.
`AGENTS.md` is the canonical governance file for this repo.
If this file conflicts with `AGENTS.md`, follow `AGENTS.md`.
Gemini-specific startup: read `AGENTS.md`, read
`docs/specs/runtime_contracts.md`, inspect the working tree, then use the
smallest validation lane that proves the change.
## Session start
1. Read `AGENTS.md`.
2. Read `docs/runtime_contracts.md`.
3. Read the most recent `HANDOFF-*.md` from the last 3 days if one exists and is relevant.
4. Confirm repository root and inspect the working tree before editing.
5. Run:
```bash
core test --suite smoke -q
```
6. State the task scope before making changes:
- which module(s) you will touch
- which invariant or contract you must preserve
## Working rules
- Do not invent alternate architecture, alternate invariants, or alternate memory rules.
- Use the smallest relevant validation lane first, then broader lanes as required by change scope.
- For docs/config-only changes, smoke is usually sufficient unless the change affects executable paths, tests, CLI behavior, or generated artifacts.
- Prefer small, load-bearing changes.
- Use `AGENTS.md` as the source of truth for architecture, invariants, validation, and PR standards.
## Session end
When a session produced meaningful implementation or architectural analysis, write or update a handoff document using the repos handoff template and current naming convention.
Do not place architecture, invariants, memory rules, or alternate workflow
policy here. Update `AGENTS.md` instead.

View file

@ -111,7 +111,7 @@ uv run pytest tests/test_adr_0131_3_bounded_grammar_lane.py tests/test_binding_g
- **Packs-only Engine Identity:** Stamped manifest scheme updated to scheme `2` (packs-only hash) which ignores `code_revision` as build provenance. `ChatRuntime` now correctly computes identity using the actual resolved/loaded packs rather than config values.
- **Turn-scoped Planner Variables:** `_last_plan_findings` and `_last_plan_metrics` are reset at the beginning of `ChatRuntime.chat` to ensure zero state leakage between fast-path and planning turns.
- **ADR Corpus Cohesion & Definitional Closure:** Completed directory consolidation (`docs/decisions/*` -> `docs/adr/`), fixed backslash escape in `en_arithmetic_v1/glosses.jsonl`, set `definitional_layer: false` for `en_core_syntax_v1` in manifest, and added `Governance Cross-Reference (ADR-0225)` sections to the 7 foundational architecture anchor ADRs.
- **ADR Corpus Cohesion & Definitional Closure:** Completed directory consolidation (`docs/adr/*` -> `docs/adr/`), fixed backslash escape in `en_arithmetic_v1/glosses.jsonl`, set `definitional_layer: false` for `en_core_syntax_v1` in manifest, and added `Governance Cross-Reference (ADR-0225)` sections to the 7 foundational architecture anchor ADRs.
---

View file

@ -200,7 +200,7 @@ core demo pack-measurements # ADR-0043 — pack-layer claims as p
core demo long-context-comparison # ADR-0045 — CORE NIAH recall + frozen transformer baselines
core demo anti-regression # ADR-0057 — three-gate defense against learning harm
# (CLOSE / idle consolidation now also climbs declared strict-order relations
# (less_than etc.); see docs/runtime_contracts.md § "Idle consolidation (Step D — CLOSE)"
# (less_than etc.); see docs/specs/runtime_contracts.md § "Idle consolidation (Step D — CLOSE)"
# and the PR-1 analysis note for contracts + evidence)
core demo phase6 # 3-condition comparative table (CORE vs baseline)
core demo phase5 # stratified 5-family mechanism-isolation
@ -237,11 +237,11 @@ implementation evidence.
| Layer | What it guarantees | ADR |
|---|---|---|
| **AdmissibilityRegion** | A typed region (`allowed_indices`, `relation_blade`, `frame_versor`) carried alongside every generation step. | [0022](docs/decisions/ADR-0022-forward-semantic-control.md) |
| **Region intersection proof** | The admissible token set is honored at the language/salience intersection layer. | [0023](docs/decisions/ADR-0023-forward-semantic-control-proof.md) |
| **Inner-loop destination check** | Each candidate's `cga_inner(versor(candidate), relation_blade)` is checked at the destination; rejection appears in `rejected_attempts`; exhaustion raises a typed `InnerLoopExhaustion`. | [0024](docs/decisions/ADR-0024-inner-loop-admissibility.md) |
| **Rotor / frame admissibility** | The rotor's *effect* on the field state is additionally checked against `frame_versor` in `generate/rotor_admissibility.py` — separate from algebra closure (intentional). | [0025](docs/decisions/ADR-0025-rotor-frame-admissibility-design-note.md) |
| **Ranked-with-margin gate** | Static-threshold tuning fails geometrically under Cl(4,1) signature; replaced with a scale-invariant margin gate (admit iff `score(top) score(second) ≥ δ`). | [0026](docs/decisions/ADR-0026-ranked-admissibility-with-margin.md) |
| **AdmissibilityRegion** | A typed region (`allowed_indices`, `relation_blade`, `frame_versor`) carried alongside every generation step. | [0022](docs/adr/ADR-0022-forward-semantic-control.md) |
| **Region intersection proof** | The admissible token set is honored at the language/salience intersection layer. | [0023](docs/adr/ADR-0023-forward-semantic-control-proof.md) |
| **Inner-loop destination check** | Each candidate's `cga_inner(versor(candidate), relation_blade)` is checked at the destination; rejection appears in `rejected_attempts`; exhaustion raises a typed `InnerLoopExhaustion`. | [0024](docs/adr/ADR-0024-inner-loop-admissibility.md) |
| **Rotor / frame admissibility** | The rotor's *effect* on the field state is additionally checked against `frame_versor` in `generate/rotor_admissibility.py` — separate from algebra closure (intentional). | [0025](docs/adr/ADR-0025-rotor-frame-admissibility-design-note.md) |
| **Ranked-with-margin gate** | Static-threshold tuning fails geometrically under Cl(4,1) signature; replaced with a scale-invariant margin gate (admit iff `score(top) score(second) ≥ δ`). | [0026](docs/adr/ADR-0026-ranked-admissibility-with-margin.md) |
The chain's three head-to-head claims, all CI-enforced:
@ -253,7 +253,7 @@ The chain's three head-to-head claims, all CI-enforced:
Full evidence:
* Runtime contract: [`docs/runtime_contracts.md`](docs/runtime_contracts.md) — Refusal / Margin / Rotor admissibility sections
* Runtime contract: [`docs/specs/runtime_contracts.md`](docs/specs/runtime_contracts.md) — Refusal / Margin / Rotor admissibility sections
* Stratified findings: [`docs/evals/phase5_stratified_findings.md`](docs/evals/phase5_stratified_findings.md) — 5 failure-mode families, 20 cases, per-family pass rates
* Comparative demo: [`docs/evals/phase6_comparative_demo.md`](docs/evals/phase6_comparative_demo.md) — three head-to-head conditions vs in-system baseline
* Reports directory: `evals/forward_semantic_control/results/`
@ -264,17 +264,17 @@ Full evidence:
Sibling to the identity packs but architecturally distinct: the safety pack at `packs/safety/core_safety_axes_v1.json` carries the boundaries CORE will **never** cross — `no_fabricated_source`, `no_hot_path_repair`, `no_identity_override`, `no_silent_correction`, `preserve_versor_closure`. The pack loads unconditionally at runtime startup (fail-closed on missing or unverified), and its boundaries are unioned into whatever identity pack is selected. Identity packs may *add* boundaries on top, but may never remove safety boundaries.
This is the architecture downstream robotics, healthcare, and other high-stakes deployments will need before they can build CORE into anything that matters. Full doctrine: [`docs/safety_packs.md`](docs/safety_packs.md); decision record: [ADR-0029](docs/decisions/ADR-0029-safety-packs.md).
This is the architecture downstream robotics, healthcare, and other high-stakes deployments will need before they can build CORE into anything that matters. Full doctrine: [`docs/safety_packs.md`](docs/safety_packs.md); decision record: [ADR-0029](docs/adr/ADR-0029-safety-packs.md).
---
## Identity Packs
CORE's identity is load-bearing: every reasoning trajectory is scored against an `IdentityManifold` of value axes, and a `PersonaMotor` derived from those axes biases every field walk. As of [ADR-0027](docs/decisions/ADR-0027-identity-packs.md) the manifold is no longer hardcoded — it is loaded at runtime from a swappable, content-addressed pack under `packs/identity/`.
CORE's identity is load-bearing: every reasoning trajectory is scored against an `IdentityManifold` of value axes, and a `PersonaMotor` derived from those axes biases every field walk. As of [ADR-0027](docs/adr/ADR-0027-identity-packs.md) the manifold is no longer hardcoded — it is loaded at runtime from a swappable, content-addressed pack under `packs/identity/`.
The shipping default `identity.default_general_v1` carries the previously-hardcoded three axes (`truthfulness`, `coherence`, `reverence`) so the default behavior is preserved. Two specialization packs ship alongside it for demonstrating identity-divergence: `identity.precision_first_v1` and `identity.generosity_first_v1`. Override on the chat surface with `core chat --identity <pack_id>`.
[ADR-0028](docs/decisions/ADR-0028-identity-surface-wiring.md) makes the swap *visibly load-bearing*: each pack carries a `surface_preferences` block (hedge thresholds, hedge phrases, claim-strength policy) consumed by the assembler. On the same prompt at the same alignment, `precision_first_v1` hedges sooner with "Arguably," / "In some cases," while `generosity_first_v1` leaves the assertion bare — see `tests/test_identity_surface_divergence.py` for the proof.
[ADR-0028](docs/adr/ADR-0028-identity-surface-wiring.md) makes the swap *visibly load-bearing*: each pack carries a `surface_preferences` block (hedge thresholds, hedge phrases, claim-strength policy) consumed by the assembler. On the same prompt at the same alignment, `precision_first_v1` hedges sooner with "Arguably," / "In some cases," while `generosity_first_v1` leaves the assertion bare — see `tests/test_identity_surface_divergence.py` for the proof.
Robotics, personalization, and creative-tool builders author their own ratified identity packs via the formation pipeline's `identity_anchor` template, then ship them under `packs/identity/` in their deployment. Full format spec, loader contract, and authoring guide: [`docs/identity_packs.md`](docs/identity_packs.md).
@ -290,7 +290,7 @@ Full doctrine, decision rules, and curriculum-platform locations: [`docs/teachin
## Inter-Session Memory — Reviewed Learning
CORE extends its own teaching corpus through a four-tier path: session vault → turn-event audit → reviewed teaching corpus → ratified packs. No opaque gradient updates, no uncurated ingestion. The only path to active-corpus extension is the review-gated `TeachingChainProposal` ([ADR-0057](docs/decisions/ADR-0057-teaching-chain-proposal-review.md)), built from a contemplated `DiscoveryCandidate` ([ADR-0056](docs/decisions/ADR-0056-contemplation-loop.md)) emitted by the turn loop ([ADR-0055](docs/decisions/ADR-0055-inter-session-memory.md)).
CORE extends its own teaching corpus through a four-tier path: session vault → turn-event audit → reviewed teaching corpus → ratified packs. No opaque gradient updates, no uncurated ingestion. The only path to active-corpus extension is the review-gated `TeachingChainProposal` ([ADR-0057](docs/adr/ADR-0057-teaching-chain-proposal-review.md)), built from a contemplated `DiscoveryCandidate` ([ADR-0056](docs/adr/ADR-0056-contemplation-loop.md)) emitted by the turn loop ([ADR-0055](docs/adr/ADR-0055-inter-session-memory.md)).
Three independent gates every extension must pass:
@ -326,32 +326,32 @@ core teaching supersessions # pair retired chains with r
## Evidence-Governed Domain Layer — The ADR-0091 Chain
CORE distinguishes *contract-passing* from *demonstrated*. A pack that satisfies the nine ADR-0091 predicates earns a `reasoning-capable` ledger row; that's a structural claim, not an empirical one. Promotion to `audit_passed=true` (formerly `expert_demo`; renamed by [ADR-0113](docs/decisions/ADR-0113-rename-expert-demo-to-audit-passed.md)) requires a **reviewer-signed evidence-bundle digest** that reproduces byte-for-byte from on-disk lane results (ADR-0106 + ADR-0109).
CORE distinguishes *contract-passing* from *demonstrated*. A pack that satisfies the nine ADR-0091 predicates earns a `reasoning-capable` ledger row; that's a structural claim, not an empirical one. Promotion to `audit_passed=true` (formerly `expert_demo`; renamed by [ADR-0113](docs/adr/ADR-0113-rename-expert-demo-to-audit-passed.md)) requires a **reviewer-signed evidence-bundle digest** that reproduces byte-for-byte from on-disk lane results (ADR-0106 + ADR-0109).
> **What `audit-passed` actually means** — and what it does NOT mean.
> The gate verifies CORE *claim-shape compliance*: signed digest, replay determinism, typed refusal, exact recall, grounding-source provenance. **These are claim shapes a transformer LLM cannot structurally produce regardless of raw accuracy.** A frontier LLM might score higher on the same benchmark but cannot pass this contract because it cannot produce a digest that re-derives, cannot guarantee typed refusal, cannot emit a deterministic trace hash, cannot replay byte-equal. **This is NOT a raw-capability claim.** The future `expert` ledger tier ([ADR-0114](docs/decisions/ADR-0114-expert-capability-roadmap-gsm8k-first.md)) is reserved for an actual benchmark-calibrated capability claim; no domain holds it yet.
> The gate verifies CORE *claim-shape compliance*: signed digest, replay determinism, typed refusal, exact recall, grounding-source provenance. **These are claim shapes a transformer LLM cannot structurally produce regardless of raw accuracy.** A frontier LLM might score higher on the same benchmark but cannot pass this contract because it cannot produce a digest that re-derives, cannot guarantee typed refusal, cannot emit a deterministic trace hash, cannot replay byte-equal. **This is NOT a raw-capability claim.** The future `expert` ledger tier ([ADR-0114](docs/adr/ADR-0114-expert-capability-roadmap-gsm8k-first.md)) is reserved for an actual benchmark-calibrated capability claim; no domain holds it yet.
| Layer | What it guarantees | ADR |
|---|---|---|
| **Domain Pack Contract v1** | Nine predicate checks on every ratified pack (lemma coverage, operator chain count, intent shapes, holdout coverage, reviewer-resolution, etc.). | [0091](docs/decisions/ADR-0091-domain-pack-contract-v1.md) |
| **Reviewer Registry v1** | YAML-anchored, schema-validated reviewer roster. Wildcard `*` reserved for primary reviewers; domain-scoped reviewers gated by `can_review(domain, scope)`. | [0092](docs/decisions/ADR-0092-reviewer-registry-v1.md) |
| **Fabrication-control eval lane** | Negative-control lane: phantom endpoints, cross-pack non-bridges, sibling collapses must all refuse. `fabricated=0` across all by-class buckets is the gate. | [0096](docs/decisions/ADR-0096-fabrication-control-eval-lane.md) |
| **Audit-passed promotion contract** | Domain-aware, reviewer-signed, replay-deterministic. No domain promotes silently; every `audit_passed=true` row points to an `audit_passed_claims` entry whose SHA-256 reproduces. (Originally landed as `expert-demo`; renamed by ADR-0113.) | [0106](docs/decisions/ADR-0106-expert-demo-promotion-contract.md), [0113](docs/decisions/ADR-0113-rename-expert-demo-to-audit-passed.md) |
| **Lane-shape registry** | Eight lane ids dispatch to five shapes (`cognition_shape`, `accuracy_shape`, `inference_shape`, `refusal_shape`, `symbolic_logic_shape`); unknown lanes fail-closed. | [0109](docs/decisions/ADR-0109-lane-shape-aware-thresholds.md) |
| **Domain Pack Contract v1** | Nine predicate checks on every ratified pack (lemma coverage, operator chain count, intent shapes, holdout coverage, reviewer-resolution, etc.). | [0091](docs/adr/ADR-0091-domain-pack-contract-v1.md) |
| **Reviewer Registry v1** | YAML-anchored, schema-validated reviewer roster. Wildcard `*` reserved for primary reviewers; domain-scoped reviewers gated by `can_review(domain, scope)`. | [0092](docs/adr/ADR-0092-reviewer-registry-v1.md) |
| **Fabrication-control eval lane** | Negative-control lane: phantom endpoints, cross-pack non-bridges, sibling collapses must all refuse. `fabricated=0` across all by-class buckets is the gate. | [0096](docs/adr/ADR-0096-fabrication-control-eval-lane.md) |
| **Audit-passed promotion contract** | Domain-aware, reviewer-signed, replay-deterministic. No domain promotes silently; every `audit_passed=true` row points to an `audit_passed_claims` entry whose SHA-256 reproduces. (Originally landed as `expert-demo`; renamed by ADR-0113.) | [0106](docs/adr/ADR-0106-expert-demo-promotion-contract.md), [0113](docs/adr/ADR-0113-rename-expert-demo-to-audit-passed.md) |
| **Lane-shape registry** | Eight lane ids dispatch to five shapes (`cognition_shape`, `accuracy_shape`, `inference_shape`, `refusal_shape`, `symbolic_logic_shape`); unknown lanes fail-closed. | [0109](docs/adr/ADR-0109-lane-shape-aware-thresholds.md) |
**Current ledger state** (per `core capability ledger`):
| Domain | Status |
|---|---|
| `mathematics_logic` | **`audit-passed`** (first promotion, [ADR-0110](docs/decisions/ADR-0110-mathematics-logic-expert-demo-promotion.md); status string renamed by [ADR-0113](docs/decisions/ADR-0113-rename-expert-demo-to-audit-passed.md)) |
| `physics` | **`audit-passed`** (second promotion, [ADR-0111](docs/decisions/ADR-0111-physics-expert-demo-promotion.md)) |
| `systems_software` | **`audit-passed`** (third promotion, [ADR-0124](docs/decisions/ADR-0124-systems-software-audit-passed-promotion.md)) |
| `mathematics_logic` | **`audit-passed`** (first promotion, [ADR-0110](docs/adr/ADR-0110-mathematics-logic-expert-demo-promotion.md); status string renamed by [ADR-0113](docs/adr/ADR-0113-rename-expert-demo-to-audit-passed.md)) |
| `physics` | **`audit-passed`** (second promotion, [ADR-0111](docs/adr/ADR-0111-physics-expert-demo-promotion.md)) |
| `systems_software` | **`audit-passed`** (third promotion, [ADR-0124](docs/adr/ADR-0124-systems-software-audit-passed-promotion.md)) |
| `hebrew_greek_textual_reasoning` | `reasoning-capable` |
| `philosophy_theology` | `reasoning-capable` |
The contract has now demonstrated its load-bearing behavior end-to-end: refused one promotion attempt honestly ([ADR-0107](docs/decisions/ADR-0107-mathematics-logic-expert-demo-deferred.md)), amended its threshold rules once cleanly (ADR-0109), succeeded against `mathematics_logic` (ADR-0110), and succeeded against a second distinct domain `physics` without further contract change (ADR-0111). External readers can distinguish the two ceilings at a glance; the "math-only" objection is retired.
The contract has now demonstrated its load-bearing behavior end-to-end: refused one promotion attempt honestly ([ADR-0107](docs/adr/ADR-0107-mathematics-logic-expert-demo-deferred.md)), amended its threshold rules once cleanly (ADR-0109), succeeded against `mathematics_logic` (ADR-0110), and succeeded against a second distinct domain `physics` without further contract change (ADR-0111). External readers can distinguish the two ceilings at a glance; the "math-only" objection is retired.
**See the actual demonstration ([ADR-0112](docs/decisions/ADR-0112-runnable-expert-demo-showcase.md), renamed by [ADR-0113](docs/decisions/ADR-0113-rename-expert-demo-to-audit-passed.md)):**
**See the actual demonstration ([ADR-0112](docs/adr/ADR-0112-runnable-expert-demo-showcase.md), renamed by [ADR-0113](docs/adr/ADR-0113-rename-expert-demo-to-audit-passed.md)):**
```bash
core demo audit-passed --domain mathematics_logic
@ -365,12 +365,12 @@ Each run re-derives the signed evidence-bundle digest from on-disk lane result f
The `audit-passed` gate above is intentionally *not* a raw-capability claim. The
honest path to one is laid out in [ADR-0114 — Expert-Capability Roadmap: GSM8K-Math
First](docs/decisions/ADR-0114-expert-capability-roadmap-gsm8k-first.md). Phases 14
First](docs/adr/ADR-0114-expert-capability-roadmap-gsm8k-first.md). Phases 14
(parser, solver, verifier, stepped-realizer) and Phase 5 (GSM8K eval lane) have now
all landed.
**Phase 5 substrate is complete as of 2026-05-23.** All 8 sub-phases of
[ADR-0119](docs/decisions/ADR-0119-gsm8k-eval-lane-roadmap.md) have landed.
[ADR-0119](docs/adr/ADR-0119-gsm8k-eval-lane-roadmap.md) have landed.
ADR-0114a's 10 anti-overfitting proof obligations are all discharged for the
`gsm8k_math` lane.
@ -387,7 +387,7 @@ evidence-derived digest and invalidated the signature. That revert is the
contract's fail-closed property working as designed — CORE revoked its own expert
claim rather than carry a stale one. **No domain is at `expert` today**, and when
`expert` is held at all it rests on CORE-authored lanes, not external GSM8K. Full
record: [ADR-0200](docs/decisions/ADR-0200-expert-claim-reconciliation.md) and
record: [ADR-0200](docs/adr/ADR-0200-expert-claim-reconciliation.md) and
[`docs/claims_ledger.md`](docs/claims_ledger.md).
To run the GSM8K math eval lane:
@ -397,7 +397,7 @@ core eval gsm8k_math # run against CORE-original public split
# evals/gsm8k_math/runner.py # lane runner (LaneReport with correct/wrong/refused)
```
Full ADR index, frontier, and chain notes: [`docs/decisions/README.md`](docs/decisions/README.md).
Full ADR index, frontier, and chain notes: [`docs/adr/README.md`](docs/adr/README.md).
---

17
calibration/README.md Normal file
View file

@ -0,0 +1,17 @@
# Calibration Package
`calibration/` is the deterministic operator-parameter replay and tuning
package. It explores bounded `CalibrationParams` candidates against eval cases
and emits before/after metrics for review.
It is not the ADR-0175 reliability ledger and it does not grant serving
licenses. Serving discipline is owned by `core.reliability_gate`; Workbench reads
that evidence through `workbench/calibration.py` without re-running lanes or
mutating license state.
This boundary is intentional:
- `calibration/params.py`, `calibration/replay.py`, `calibration/tune.py`, and
`calibration/report.py` support deterministic parameter audits.
- `workbench/calibration.py` projects committed practice and serving artifacts
into a read-only UI/API surface.

View file

@ -20,8 +20,8 @@ The refusal surface remains:
``refusal_commitments`` to count. Safety is always in scope; the
pack-layer doctrine in ADR-0029 prohibits opting safety out.
See `docs/decisions/ADR-0036-safety-refusal-policy.md` and
`docs/decisions/ADR-0037-per-predicate-ethics-refusal.md`.
See `docs/adr/ADR-0036-safety-refusal-policy.md` and
`docs/adr/ADR-0037-per-predicate-ethics-refusal.md`.
"""
from __future__ import annotations

View file

@ -1205,7 +1205,7 @@ class ChatRuntime:
``govern_response`` widens to APPROXIMATE iff the predicate-class holds a genuine
SERVE license, and ``shape_surface`` DISCLOSES it as ``[approximate] ``. An
unlicensed class stays STRICT (the surface is unchanged the honest refusal).
Off-flag turns never reach here. See ``docs/runtime_contracts.md``.
Off-flag turns never reach here. See ``docs/specs/runtime_contracts.md``.
"""
accrual = self._last_turn_accrual
if accrual is None:

View file

@ -21,7 +21,7 @@ Trust boundary (per CLAUDE.md):
* **Idempotent flush.** Each ``emit()`` flushes immediately so a
crashed turn loop still has its prior turns durable on disk.
See ``docs/decisions/ADR-0040-telemetry-sink.md``.
See ``docs/adr/ADR-0040-telemetry-sink.md``.
"""
from __future__ import annotations

View file

@ -1,15 +1,14 @@
"""Project-root conftest — quarantine registry for known-failing tests.
"""Project-root conftest — test classification registries.
The QUARANTINE set lists test IDs that are pre-existing failures
predating the substrate-liveness audit work (verified via bisect
against c1a1b7a, the commit immediately before the first W-* PR
of 2026-05-24). The CI gate at .github/workflows/full-pytest.yml
runs ``pytest -m "not quarantine"`` so these failures do not block
PRs, but the suite is a ratchet: a quarantined test removed from
this set must pass on its own merits.
The QUARANTINE set is the only allowed registry for known-failing tests.
It is currently empty. If it ever contains nodeids, the CI gate at
.github/workflows/full-pytest.yml runs ``pytest -m "not quarantine"``
so those explicitly tracked failures do not block unrelated PRs. The
suite is a ratchet: a quarantined test removed from this set must pass
on its own merits.
See docs/test-debt-quarantine.md for cluster diagnoses, removal
policy, and the per-test rationale.
See docs/test-debt-quarantine.md for current policy and historical cluster
diagnoses.
To remove a test from quarantine:
1. Land a PR that makes the test pass.

17
contemplation/README.md Normal file
View file

@ -0,0 +1,17 @@
# Contemplation Artifacts
This directory is an artifact namespace for committed contemplation process
reports, especially the `runs/` evidence consumed by teaching queue and
Workbench readers.
It is intentionally not a Python package:
- no `contemplation/__init__.py`
- no Python source files under this tree
- executable contemplation code lives under `core/contemplation/`
- always-on runtime life writes local reports under
`<engine_state>/contemplation_runs/`
Keeping this split explicit prevents `import contemplation` ambiguity while
preserving the deterministic JSON evidence shape expected by queue and
Workbench surfaces.

View file

@ -35,16 +35,14 @@ const fn build_blade_masks() -> [u8; 32] {
// Hardcoded to guarantee exact parity with Python cl41.py.
[
// grade 0: ()
0b00000,
// grade 1: (0,), (1,), (2,), (3,), (4,)
0b00000, // grade 1: (0,), (1,), (2,), (3,), (4,)
0b00001, 0b00010, 0b00100, 0b01000, 0b10000,
// grade 2: (0,1), (0,2), (0,3), (0,4), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4)
0b00011, 0b00101, 0b01001, 0b10001, 0b00110, 0b01010, 0b10010, 0b01100, 0b10100, 0b11000,
// grade 3: (0,1,2), (0,1,3), (0,1,4), (0,2,3), (0,2,4), (0,3,4), (1,2,3), (1,2,4), (1,3,4), (2,3,4)
0b00111, 0b01011, 0b10011, 0b01101, 0b10101, 0b11001, 0b01110, 0b10110, 0b11010, 0b11100,
// grade 4: (0,1,2,3), (0,1,2,4), (0,1,3,4), (0,2,3,4), (1,2,3,4)
0b01111, 0b10111, 0b11011, 0b11101, 0b11110,
// grade 5: (0,1,2,3,4)
0b01111, 0b10111, 0b11011, 0b11101, 0b11110, // grade 5: (0,1,2,3,4)
0b11111,
]
}
@ -60,13 +58,6 @@ const fn build_mask_to_idx() -> [u8; 32] {
lut
}
const fn popcount5(x: u8) -> u8 {
let mut n = x & 0x1F;
let mut c = 0u8;
while n != 0 { c += n & 1; n >>= 1; }
c
}
// Multiply two basis blades given as bitmasks. Returns (result_mask, sign).
// The sign is the parity of swaps needed to canonicalize A followed by B,
// multiplied by the metric contractions for repeated basis vectors.
@ -106,17 +97,17 @@ const fn blade_product(a: u8, b: u8) -> (u8, i8) {
}
struct Table {
idx: [[u8; 32]; 32],
idx: [[u8; 32]; 32],
sign: [[i8; 32]; 32],
}
fn build_table() -> Table {
let mut idx = [[0u8; 32]; 32];
let mut idx = [[0u8; 32]; 32];
let mut sign = [[0i8; 32]; 32];
for i in 0..32usize {
for j in 0..32usize {
let (result_mask, s) = blade_product(BLADE_MASKS[i], BLADE_MASKS[j]);
idx[i][j] = MASK_TO_IDX[result_mask as usize];
idx[i][j] = MASK_TO_IDX[result_mask as usize];
sign[i][j] = s;
}
}
@ -137,10 +128,14 @@ pub fn geometric_product_f64(a: &[f64; 32], b: &[f64; 32]) -> [f64; 32] {
let mut result = [0f64; 32];
for i in 0..32 {
let ai = a[i];
if ai == 0.0 { continue; }
if ai == 0.0 {
continue;
}
for j in 0..32 {
let bj = b[j];
if bj == 0.0 { continue; }
if bj == 0.0 {
continue;
}
let k = t.idx[i][j] as usize;
let s = t.sign[i][j] as f64;
result[k] += s * ai * bj;
@ -156,10 +151,14 @@ pub fn geometric_product_raw(a: &[f32; 32], b: &[f32; 32]) -> Result<[f32; 32],
let mut result = [0f32; 32];
for i in 0..32 {
let ai = a[i];
if ai == 0.0 { continue; }
if ai == 0.0 {
continue;
}
for j in 0..32 {
let bj = b[j];
if bj == 0.0 { continue; }
if bj == 0.0 {
continue;
}
let k = t.idx[i][j] as usize;
let s = t.sign[i][j] as f32;
result[k] += s * ai * bj;
@ -173,15 +172,23 @@ pub fn geometric_product_raw(a: &[f32; 32], b: &[f32; 32]) -> Result<[f32; 32],
/// Grade 0,1: +1. Grade 2,3: -1. Grade 4,5: +1.
pub fn reverse_raw(a: &[f32; 32]) -> [f32; 32] {
let mut r = *a;
for i in 6..=15 { r[i] = -r[i]; }
for i in 16..=25 { r[i] = -r[i]; }
for i in 6..=15 {
r[i] = -r[i];
}
for i in 16..=25 {
r[i] = -r[i];
}
r
}
/// Reverse anti-automorphism (f64).
pub fn reverse_f64(a: &[f64; 32]) -> [f64; 32] {
let mut r = *a;
for i in 6..=15 { r[i] = -r[i]; }
for i in 16..=25 { r[i] = -r[i]; }
for i in 6..=15 {
r[i] = -r[i];
}
for i in 16..=25 {
r[i] = -r[i];
}
r
}

View file

@ -11,10 +11,6 @@
use crate::cl41::geometric_product_f64;
use std::collections::HashMap;
/// Blade indices 9, 12, 14, 15 square to +1 (boost/hyperbolic planes involving e5).
/// Remaining bivector indices (6-8, 10-11, 13) square to -1 (rotation planes).
const BOOST_INDICES: [usize; 4] = [9, 12, 14, 15];
fn is_boost(blade_idx: usize) -> bool {
matches!(blade_idx, 9 | 12 | 14 | 15)
}
@ -26,7 +22,9 @@ fn is_boost(blade_idx: usize) -> bool {
pub fn unitize_f32(v: &[f32; 32]) -> [f32; 32] {
let v64: [f64; 32] = {
let mut arr = [0f64; 32];
for i in 0..32 { arr[i] = v[i] as f64; }
for i in 0..32 {
arr[i] = v[i] as f64;
}
arr
};
@ -40,7 +38,9 @@ pub fn unitize_f32(v: &[f32; 32]) -> [f32; 32] {
// Extract bivector content (indices 6..16)
let bv: [f64; 10] = {
let mut arr = [0f64; 10];
for i in 0..10 { arr[i] = v64[6 + i]; }
for i in 0..10 {
arr[i] = v64[6 + i];
}
arr
};
let bv_norm: f64 = bv.iter().map(|x| x * x).sum::<f64>().sqrt();
@ -57,7 +57,9 @@ pub fn unitize_f32(v: &[f32; 32]) -> [f32; 32] {
for i in 0..10usize {
let w = bv[i] / bv_norm;
if w.abs() < 1e-14 { continue; }
if w.abs() < 1e-14 {
continue;
}
let theta = angle * w;
let mut factor = [0f64; 32];
let blade_idx = 6 + i;
@ -72,11 +74,15 @@ pub fn unitize_f32(v: &[f32; 32]) -> [f32; 32] {
}
if v64[0] < 0.0 {
for x in rotor.iter_mut() { *x = -*x; }
for x in rotor.iter_mut() {
*x = -*x;
}
}
let mut result = [0f32; 32];
for i in 0..32 { result[i] = rotor[i] as f32; }
for i in 0..32 {
result[i] = rotor[i] as f32;
}
result
}
@ -103,19 +109,27 @@ pub fn graph_diffusion_step(
}
for (&node, srcs) in &neighbors {
if node >= n || srcs.is_empty() { continue; }
if node >= n || srcs.is_empty() {
continue;
}
// Current node in f64
let mut f = [0f64; 32];
for i in 0..32 { f[i] = fields[node][i] as f64; }
for i in 0..32 {
f[i] = fields[node][i] as f64;
}
// Neighbor average in f64
let mut avg = [0f64; 32];
for &src in srcs {
for i in 0..32 { avg[i] += fields[src][i] as f64; }
for i in 0..32 {
avg[i] += fields[src][i] as f64;
}
}
let inv = 1.0 / srcs.len() as f64;
for x in avg.iter_mut() { *x *= inv; }
for x in avg.iter_mut() {
*x *= inv;
}
// Blend
let mut blended = [0f32; 32];
@ -170,7 +184,7 @@ mod tests {
let mut v = [0f32; 32];
v[0] = 0.8;
v[6] = 0.3;
v[9] = 0.2; // boost blade
v[9] = 0.2; // boost blade
let result = unitize_f32(&v);
let cond = versor_condition_raw(&result).unwrap();
assert!(cond < 1e-4, "versor condition {} too large", cond);

View file

@ -1,81 +0,0 @@
//! Holonomy encoder in Rust — the forward+reverse versor walk.
//!
//! This is in Rust because:
//! - Long prompts (100+ tokens) do 200+ geometric products in sequence
//! - Each geometric product is O(32^2) = 1024 multiply-adds
//! - Python overhead per call makes this 10-50x slower than necessary
//! - Rust collapses the entire walk into a single allocation-free loop
use crate::cl41::{geometric_product_raw, reverse_raw};
use crate::versor::normalize_to_versor_raw;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum HolonomyError {
#[error("Empty word list")]
Empty,
#[error("Versor error: {0}")]
Versor(String),
}
/// Compute holonomy of a word versor sequence.
///
/// Forward walk: F = w0 * w1 * ... * wn
/// Reverse walk: R = (1-alpha) * rev(wn) * ... * rev(w0)
/// Holonomy: H = normalize(F * R)
///
/// weights: per-word scalars (inverse frequency). If empty, uniform 1.0.
/// alpha: blend factor [0,1]. 0.5 recommended.
pub fn holonomy_encode_raw(
words: &[[f32; 32]],
weights: &[f32],
alpha: f32,
) -> Result<[f32; 32], HolonomyError> {
if words.is_empty() {
return Err(HolonomyError::Empty);
}
let n = words.len();
let use_weights = !weights.is_empty() && weights.len() == n;
// Forward accumulation
let mut scaled = words[0];
if use_weights {
let w = weights[0];
for x in scaled.iter_mut() { *x *= w; }
}
let mut f = normalize_to_versor_raw(&scaled)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
for k in 1..n {
let mut wk = words[k];
if use_weights {
let w = weights[k];
for x in wk.iter_mut() { *x *= w; }
}
let wk_norm = normalize_to_versor_raw(&wk)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
f = geometric_product_raw(&f, &wk_norm)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
}
// Reverse accumulation with (1-alpha) damping
let damp = 1.0 - alpha;
let mut last_rev = reverse_raw(&words[n - 1]);
for x in last_rev.iter_mut() { *x *= damp; }
let mut r = normalize_to_versor_raw(&last_rev)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
for k in (0..n - 1).rev() {
let rev_wk = reverse_raw(&words[k]);
let rev_norm = normalize_to_versor_raw(&rev_wk)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
r = geometric_product_raw(&rev_norm, &r)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
}
let h = geometric_product_raw(&f, &r)
.map_err(|e| HolonomyError::Versor(e.to_string()))?;
normalize_to_versor_raw(&h)
.map_err(|e| HolonomyError::Versor(e.to_string()))
}

View file

@ -6,6 +6,7 @@
//! - versor_condition (||F*rev(F) - 1||_F)
//! - cga_inner (symmetric inner product)
//! - vault_recall (parallel top-k scan)
//! - diffusion_step (zero-copy graph diffusion step)
//!
//! All multivectors are f32 arrays of length 32, passed as numpy arrays.
@ -21,8 +22,6 @@ pub mod versor;
use cga::cga_inner_raw;
use cl41::geometric_product_raw;
use diffusion::{graph_diffusion_step, unitize_f32};
#[allow(unused_imports)]
use vault::vault_recall_raw;
use versor::{
normalize_to_versor_raw, versor_apply_closed, versor_apply_closed_f64, versor_apply_raw,
versor_condition_raw,
@ -50,13 +49,13 @@ fn geometric_product(
#[pyfunction]
fn versor_apply(
py: Python<'_>,
v: &pyo3::types::PyAny,
f: &pyo3::types::PyAny,
v: &Bound<'_, pyo3::types::PyAny>,
f: &Bound<'_, pyo3::types::PyAny>,
) -> PyResult<PyObject> {
let v_slice = extract_f32_slice(v)?;
let f_slice = extract_f32_slice(f)?;
let result = versor_apply_raw(&v_slice, &f_slice)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
let result =
versor_apply_raw(&v_slice, &f_slice).map_err(|e| PyValueError::new_err(e.to_string()))?;
f32_array_to_numpy(py, &result)
}
@ -70,8 +69,8 @@ fn versor_apply_with_closure(
) -> PyResult<PyObject> {
let v_slice = read_f32_cl41_mv(&v)?;
let f_slice = read_f32_cl41_mv(&f)?;
let result = versor_apply_closed(v_slice, f_slice)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
let result =
versor_apply_closed(v_slice, f_slice).map_err(|e| PyValueError::new_err(e.to_string()))?;
f32_array_to_numpy(py, &result)
}
@ -100,13 +99,10 @@ fn versor_condition(f: numpy::PyReadonlyArray1<'_, f32>) -> PyResult<f32> {
/// Project F onto versor manifold: F / sqrt(|F*rev(F)|).
#[pyfunction]
fn normalize_to_versor(
py: Python<'_>,
f: &pyo3::types::PyAny,
) -> PyResult<PyObject> {
fn normalize_to_versor(py: Python<'_>, f: &Bound<'_, pyo3::types::PyAny>) -> PyResult<PyObject> {
let f_slice = extract_f32_slice(f)?;
let result = normalize_to_versor_raw(&f_slice)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
let result =
normalize_to_versor_raw(&f_slice).map_err(|e| PyValueError::new_err(e.to_string()))?;
f32_array_to_numpy(py, &result)
}
@ -179,9 +175,9 @@ fn vault_recall(
)));
}
let n = shape[0];
let q_slice = query.as_slice().map_err(|e| {
PyValueError::new_err(format!("query must be contiguous f32 (32,): {}", e))
})?;
let q_slice = query
.as_slice()
.map_err(|e| PyValueError::new_err(format!("query must be contiguous f32 (32,): {}", e)))?;
if q_slice.len() != 32 {
return Err(PyValueError::new_err(format!(
"query must have length 32, got {}",
@ -189,10 +185,7 @@ fn vault_recall(
)));
}
let v_slice = versors.as_slice().map_err(|e| {
PyValueError::new_err(format!(
"versors must be C-contiguous f32 (N, 32): {}",
e
))
PyValueError::new_err(format!("versors must be C-contiguous f32 (N, 32): {}", e))
})?;
let mut q_arr = [0f32; 32];
q_arr.copy_from_slice(q_slice);
@ -204,10 +197,7 @@ fn vault_recall(
/// Unitize a multivector via the Cl(4,1) exponential map.
/// Distinguishes boost planes (cosh/sinh) from rotation planes (cos/sin).
#[pyfunction]
fn unitize_expmap(
py: Python<'_>,
v: &pyo3::types::PyAny,
) -> PyResult<PyObject> {
fn unitize_expmap(py: Python<'_>, v: &Bound<'_, pyo3::types::PyAny>) -> PyResult<PyObject> {
let v_slice = extract_f32_slice(v)?;
let result = unitize_f32(&v_slice);
f32_array_to_numpy(py, &result)
@ -257,16 +247,10 @@ fn diffusion_step<'py>(
}
let fields_slice = fields.as_slice().map_err(|e| {
PyValueError::new_err(format!(
"fields must be C-contiguous f32 (N, 32): {}",
e
))
PyValueError::new_err(format!("fields must be C-contiguous f32 (N, 32): {}", e))
})?;
let edges_slice = edges.as_slice().map_err(|e| {
PyValueError::new_err(format!(
"edges must be C-contiguous i32 (E, 2): {}",
e
))
PyValueError::new_err(format!("edges must be C-contiguous i32 (E, 2): {}", e))
})?;
// ``[f32; 32]`` and ``[i32; 2]`` are both ``Pod`` (arrays of POD
@ -275,8 +259,7 @@ fn diffusion_step<'py>(
let fields_blocks: &[[f32; 32]] = bytemuck::cast_slice(fields_slice);
let edges_blocks: &[[i32; 2]] = bytemuck::cast_slice(edges_slice);
let (new_fields, delta) =
graph_diffusion_step(fields_blocks, edges_blocks, damping);
let (new_fields, delta) = graph_diffusion_step(fields_blocks, edges_blocks, damping);
// ``Vec<[f32; 32]>`` → ``Vec<f32>`` is a zero-copy reinterpretation
// of the allocation (requires the ``extern_crate_alloc`` bytemuck
@ -302,14 +285,11 @@ fn read_f32_cl41_mv<'a>(arr: &'a numpy::PyReadonlyArray1<'a, f32>) -> PyResult<&
)));
}
let slice = arr.as_slice().map_err(|e| {
PyValueError::new_err(format!(
"input must be C-contiguous float32 (32,): {}",
e
))
PyValueError::new_err(format!("input must be C-contiguous float32 (32,): {}", e))
})?;
slice.try_into().map_err(|_| {
PyValueError::new_err("expected contiguous float32 array of length 32")
})
slice
.try_into()
.map_err(|_| PyValueError::new_err("expected contiguous float32 array of length 32"))
}
fn read_f64_cl41_mv<'a>(arr: &'a numpy::PyReadonlyArray1<'a, f64>) -> PyResult<&'a [f64; 32]> {
@ -321,14 +301,11 @@ fn read_f64_cl41_mv<'a>(arr: &'a numpy::PyReadonlyArray1<'a, f64>) -> PyResult<&
)));
}
let slice = arr.as_slice().map_err(|e| {
PyValueError::new_err(format!(
"input must be C-contiguous float64 (32,): {}",
e
))
PyValueError::new_err(format!("input must be C-contiguous float64 (32,): {}", e))
})?;
slice.try_into().map_err(|_| {
PyValueError::new_err("expected contiguous float64 array of length 32")
})
slice
.try_into()
.map_err(|_| PyValueError::new_err("expected contiguous float64 array of length 32"))
}
fn read_f32_xyz<'a>(arr: &'a numpy::PyReadonlyArray1<'a, f32>) -> PyResult<&'a [f32; 3]> {
@ -350,8 +327,8 @@ fn read_f32_xyz<'a>(arr: &'a numpy::PyReadonlyArray1<'a, f32>) -> PyResult<&'a [
})
}
fn extract_f32_slice(obj: &pyo3::types::PyAny) -> PyResult<[f32; 32]> {
let np = obj.py().import("numpy")?;
fn extract_f32_slice(obj: &Bound<'_, pyo3::types::PyAny>) -> PyResult<[f32; 32]> {
let np = obj.py().import_bound("numpy")?;
let arr = np.call_method1("asarray", (obj, "float32"))?;
let flat = arr.call_method0("flatten")?;
let list: Vec<f32> = flat.extract()?;
@ -367,30 +344,14 @@ fn extract_f32_slice(obj: &pyo3::types::PyAny) -> PyResult<[f32; 32]> {
}
fn f32_array_to_numpy(py: Python<'_>, data: &[f32; 32]) -> PyResult<PyObject> {
let np = py.import("numpy")?;
let np = py.import_bound("numpy")?;
let list: Vec<f32> = data.to_vec();
let arr = np.call_method1("array", (list, "float32"))?;
Ok(arr.into_py(py))
}
fn extract_f64_slice(obj: &pyo3::types::PyAny) -> PyResult<[f64; 32]> {
let np = obj.py().import("numpy")?;
let arr = np.call_method1("asarray", (obj, "float64"))?;
let flat = arr.call_method0("flatten")?;
let list: Vec<f64> = flat.extract()?;
if list.len() != 32 {
return Err(PyValueError::new_err(format!(
"Expected array of length 32, got {}",
list.len()
)));
}
let mut out = [0f64; 32];
out.copy_from_slice(&list);
Ok(out)
}
fn f64_array_to_numpy(py: Python<'_>, data: &[f64; 32]) -> PyResult<PyObject> {
let np = py.import("numpy")?;
let np = py.import_bound("numpy")?;
let list: Vec<f64> = data.to_vec();
let arr = np.call_method1("array", (list, "float64"))?;
Ok(arr.into_py(py))

View file

@ -1,48 +0,0 @@
//! Propagation loop in Rust — tight versor_apply chain.
//!
//! propagate_n steps runs N versor_apply calls in a single Rust stack frame,
//! eliminating Python dispatch overhead for each step.
//! Used by generate/stream.py when stepping more than one token at a time
//! (e.g. prefill, speculative steps, or batch generation).
use crate::versor::versor_apply_raw;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum PropagateError {
#[error("Versor error during propagation: {0}")]
Versor(String),
}
/// Run n versor_apply steps in sequence.
/// rotors: slice of n [f32;32] versors to apply in order
/// f0: initial field state
/// Returns final field state after n steps.
pub fn propagate_n_raw(
rotors: &[[f32; 32]],
f0: &[f32; 32],
) -> Result<[f32; 32], PropagateError> {
let mut f = *f0;
for v in rotors {
f = versor_apply_raw(v, &f)
.map_err(|e| PropagateError::Versor(e.to_string()))?;
}
Ok(f)
}
/// Parallel batch propagation: apply the same rotor V to a batch of field states.
/// Used for beam search or multi-hypothesis generation.
/// Returns new batch of field states.
pub fn propagate_batch_raw(
v: &[f32; 32],
fields: &[[f32; 32]],
) -> Result<Vec<[f32; 32]>, PropagateError> {
use rayon::prelude::*;
fields
.par_iter()
.map(|f| {
versor_apply_raw(v, f)
.map_err(|e| PropagateError::Versor(e.to_string()))
})
.collect()
}

View file

@ -33,10 +33,8 @@ pub enum VaultError {
/// basis. See `tests/test_vault_recall_vectorised.py` (Python
/// side) for the empirical derivation that pins this vector.
const CGA_INNER_METRIC: [f32; 32] = [
1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0,
-1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0,
1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0,
-1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
];
/// Per-versor diagonal-metric CGA inner product. Same arithmetic
@ -291,8 +289,7 @@ pub trait SemilatticeDelta: Sized {
impl SemilatticeDelta for Delta {
fn join(&self, other: &Self) -> Self {
let mut merged =
Vec::with_capacity(self.entries.len() + other.entries.len());
let mut merged = Vec::with_capacity(self.entries.len() + other.entries.len());
merged.extend_from_slice(&self.entries);
merged.extend_from_slice(&other.entries);
Delta::from_entries(merged)

View file

@ -4,7 +4,9 @@
//! normalize_to_versor F/sqrt(|F*rev(F)|) — called once at injection gate
//! versor_condition ||F*rev(F)-1||_F — used in tests and gate only
use crate::cl41::{geometric_product_f64, geometric_product_raw, reverse_f64, reverse_raw, Cl41Error};
use crate::cl41::{
geometric_product_f64, geometric_product_raw, reverse_f64, reverse_raw, Cl41Error,
};
use thiserror::Error;
#[derive(Debug, Error)]
@ -16,7 +18,6 @@ pub enum VersorError {
}
const NEAR_ZERO_TOL: f64 = 1e-12;
const NULL_SCALAR_TOL: f64 = 1e-9;
const CONSTRUCTION_RESIDUE_TOL: f64 = 1e-2;
const SEED_BIVECTORS: [usize; 6] = [6, 7, 8, 10, 11, 13];
@ -52,7 +53,9 @@ fn unitize_closed(v: &[f64; 32]) -> Result<[f64; 32], ()> {
let inv = 1.0 / scalar_sq.sqrt();
let mut result = *v;
for x in result.iter_mut() { *x *= inv; }
for x in result.iter_mut() {
*x *= inv;
}
Ok(result)
}
@ -83,19 +86,25 @@ fn close_applied_versor(v: &[f32; 32]) -> [f32; 32] {
let v_f64: [f64; 32] = {
let mut arr = [0f64; 32];
for i in 0..32 { arr[i] = v[i] as f64; }
for i in 0..32 {
arr[i] = v[i] as f64;
}
arr
};
if let Ok(closed) = unitize_closed(&v_f64) {
let mut result = [0f32; 32];
for i in 0..32 { result[i] = closed[i] as f32; }
for i in 0..32 {
result[i] = closed[i] as f32;
}
return result;
}
if let Ok(seeded) = seed_to_rotor(&v_f64) {
let mut result = [0f32; 32];
for i in 0..32 { result[i] = seeded[i] as f32; }
for i in 0..32 {
result[i] = seeded[i] as f32;
}
return result;
}
@ -122,10 +131,7 @@ pub fn versor_apply_closed(v: &[f32; 32], f: &[f32; 32]) -> Result<[f32; 32], Ve
/// accepted — otherwise the deterministic `seed_to_rotor`
/// construction map is used. ADR-0020 parity gate
/// `tests/test_versor_apply_rust_parity.py`.
pub fn versor_apply_closed_f64(
v: &[f64; 32],
f: &[f64; 32],
) -> Result<[f64; 32], VersorError> {
pub fn versor_apply_closed_f64(v: &[f64; 32], f: &[f64; 32]) -> Result<[f64; 32], VersorError> {
let rev_v = reverse_f64(v);
let vf = geometric_product_f64(v, f);
let vfrv = geometric_product_f64(&vf, &rev_v);
@ -167,10 +173,7 @@ fn unitize_versor_f64(v: &[f64; 32]) -> Result<[f64; 32], ()> {
// `unitize_closed` signature; mirror Python's policy by gating
// the fallback on the dense-support heuristic, which is the
// condition Python also requires before invoking the rotor seed.
let support = v
.iter()
.filter(|x| x.abs() > NEAR_ZERO_TOL)
.count();
let support = v.iter().filter(|x| x.abs() > NEAR_ZERO_TOL).count();
if support < DENSE_SEED_MIN_COMPONENTS {
Err(())
} else {
@ -199,8 +202,8 @@ fn close_applied_versor_f64(v: &[f64; 32]) -> [f64; 32] {
/// Raw sandwich product V * F * reverse(V) without closure.
pub fn versor_apply_raw(v: &[f32; 32], f: &[f32; 32]) -> Result<[f32; 32], VersorError> {
let rev_v = reverse_raw(v);
let vf = geometric_product_raw(v, f)?;
let vfrv = geometric_product_raw(&vf, &rev_v)?;
let vf = geometric_product_raw(v, f)?;
let vfrv = geometric_product_raw(&vf, &rev_v)?;
Ok(vfrv)
}
@ -208,14 +211,16 @@ pub fn versor_apply_raw(v: &[f32; 32], f: &[f32; 32]) -> Result<[f32; 32], Verso
/// Called ONCE at ingest/gate. Never mid-propagation.
pub fn normalize_to_versor_raw(f: &[f32; 32]) -> Result<[f32; 32], VersorError> {
let rev_f = reverse_raw(f);
let frv = geometric_product_raw(f, &rev_f)?;
let n2 = frv[0]; // grade-0 = scalar part
let frv = geometric_product_raw(f, &rev_f)?;
let n2 = frv[0]; // grade-0 = scalar part
if n2.abs() < 1e-12 {
return Err(VersorError::NullVersor(n2));
}
let inv_norm = 1.0 / n2.abs().sqrt();
let mut result = *f;
for x in result.iter_mut() { *x *= inv_norm; }
for x in result.iter_mut() {
*x *= inv_norm;
}
Ok(result)
}

View file

@ -112,9 +112,7 @@ fn merge_kernel_equals_semilattice_fold() {
delta(vec![entry(5, "c")]),
delta(vec![entry(2, "b"), entry(9, "d")]), // overlaps the first delta
];
let folded = deltas
.iter()
.fold(Delta::default(), |acc, d| acc.join(d));
let folded = deltas.iter().fold(Delta::default(), |acc, d| acc.join(d));
// The cheap union-then-canonicalise path must equal the explicit
// semilattice fold, or the kernel has silently diverged from the trait.
assert_eq!(keys(&merge_kernel(&deltas)), keys(&folded));
@ -141,7 +139,10 @@ fn merge_result_is_content_sorted() {
let ks = keys(&d);
let mut sorted = ks.clone();
sorted.sort();
assert_eq!(ks, sorted, "merge output must be in content-addressed order");
assert_eq!(
ks, sorted,
"merge output must be in content-addressed order"
);
}
// --- LocalArena (ADR-0180 §2.1) -------------------------------------------

View file

@ -4,7 +4,10 @@ use core_rs::cga::{cga_inner_raw, embed_point_raw, is_null_raw, null_project_raw
fn test_embedded_point_is_null() {
let p = [1.0f32, 2.0, 3.0];
let x = embed_point_raw(&p);
assert!(is_null_raw(&x, 1e-5).unwrap(), "Embedded point should be null");
assert!(
is_null_raw(&x, 1e-5).unwrap(),
"Embedded point should be null"
);
}
#[test]
@ -27,7 +30,11 @@ fn test_cga_distance_identity() {
let x = embed_point_raw(&[0.0, 0.0, 0.0]);
let y = embed_point_raw(&[1.0, 0.0, 0.0]);
let inner = cga_inner_raw(&x, &y).unwrap();
assert!((inner - (-0.5)).abs() < 1e-5, "Expected -0.5 for unit-distance points, got {}", inner);
assert!(
(inner - (-0.5)).abs() < 1e-5,
"Expected -0.5 for unit-distance points, got {}",
inner
);
}
#[test]
@ -37,5 +44,8 @@ fn test_null_project_restores_null() {
x[0] += 0.05;
x[7] -= 0.03;
let fixed = null_project_raw(&x);
assert!(is_null_raw(&fixed, 1e-5).unwrap(), "null_project failed to restore null cone");
assert!(
is_null_raw(&fixed, 1e-5).unwrap(),
"null_project failed to restore null cone"
);
}

View file

@ -40,7 +40,11 @@ fn test_e1_e2_anticommute() {
let e1e2 = geometric_product_raw(&e1, &e2).unwrap();
let e2e1 = geometric_product_raw(&e2, &e1).unwrap();
for i in 0..32 {
assert!((e1e2[i] + e2e1[i]).abs() < 1e-6, "e1*e2 + e2*e1 != 0 at index {}", i);
assert!(
(e1e2[i] + e2e1[i]).abs() < 1e-6,
"e1*e2 + e2*e1 != 0 at index {}",
i
);
}
}
@ -57,12 +61,18 @@ fn test_reverse_grade2_sign() {
let mut a = [0f32; 32];
a[6] = 1.0;
let r = reverse_raw(&a);
assert!((r[6] + 1.0).abs() < 1e-6, "reverse of grade-2 blade should negate");
assert!(
(r[6] + 1.0).abs() < 1e-6,
"reverse of grade-2 blade should negate"
);
}
#[test]
fn test_reverse_grade1_unchanged() {
let e1 = basis(0);
let r = reverse_raw(&e1);
assert!((r[1] - 1.0).abs() < 1e-6, "reverse of grade-1 blade should be unchanged");
assert!(
(r[1] - 1.0).abs() < 1e-6,
"reverse of grade-1 blade should be unchanged"
);
}

View file

@ -47,7 +47,11 @@ fn expected(name: &str) -> &'static str {
fn assert_parity(name: &str, deltas: Vec<Delta>) {
let merged = merge_kernel(&deltas);
assert_eq!(hex(&merged.canonical_bytes()), expected(name), "case {name}");
assert_eq!(
hex(&merged.canonical_bytes()),
expected(name),
"case {name}"
);
}
#[test]

View file

@ -1,5 +1,5 @@
use core_rs::vault::vault_recall_raw;
use core_rs::cga::embed_point_raw;
use core_rs::vault::vault_recall_raw;
fn sample_point(seed: u64) -> [f32; 32] {
let x = ((seed * 17 + 3) % 101) as f32 / 10.0;

View file

@ -1,16 +1,16 @@
use core_rs::versor::{normalize_to_versor_raw, versor_apply_raw, versor_condition_raw};
use core_rs::versor::{versor_apply_raw, versor_condition_raw};
fn random_versor(seed: u64) -> [f32; 32] {
let theta = ((seed * 17 + 3) % 101) as f32 / 100.0;
let mut v = [0f32; 32];
v[0] = theta.cos();
// Choose a bivector with negative square, e.g. e12
// e1^2 = 1, e2^2 = 1 => (e1 e2)^2 = -e1^2 e2^2 = -1
// MASK_TO_IDX for e1e2: e1 is bit 0, e2 is bit 1 => mask 3
// MASK_TO_IDX[3] = 6 (grade 2 starts at 6)
v[6] = theta.sin();
v
}
@ -30,7 +30,12 @@ fn test_versor_apply_preserves_manifold() {
let f = random_versor(seed + 1000);
let result = versor_apply_raw(&v, &f).unwrap();
let cond = versor_condition_raw(&result).unwrap();
assert!(cond < 1e-4, "versor_apply broke manifold: condition={:.2e} at seed={}", cond, seed);
assert!(
cond < 1e-4,
"versor_apply broke manifold: condition={:.2e} at seed={}",
cond,
seed
);
}
}
@ -41,7 +46,13 @@ fn test_identity_versor() {
let f = random_versor(42);
let result = versor_apply_raw(&identity, &f).unwrap();
for i in 0..32 {
assert!((result[i] - f[i]).abs() < 1e-5, "Identity apply changed component {}: {} vs {}", i, result[i], f[i]);
assert!(
(result[i] - f[i]).abs() < 1e-5,
"Identity apply changed component {}: {} vs {}",
i,
result[i],
f[i]
);
}
}
@ -53,5 +64,9 @@ fn test_composition_closed() {
let f2 = versor_apply_raw(&v1, &f).unwrap();
let f3 = versor_apply_raw(&v2, &f2).unwrap();
let cond = versor_condition_raw(&f3).unwrap();
assert!(cond < 1e-4, "Composition broke manifold: condition={:.2e}", cond);
assert!(
cond < 1e-4,
"Composition broke manifold: condition={:.2e}",
cond
);
}

File diff suppressed because it is too large Load diff

435
core/cli_capability.py Normal file
View file

@ -0,0 +1,435 @@
"""Extracted commands."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
def cmd_capability_chains(args: argparse.Namespace) -> int:
from core.capability import chain_report
report = chain_report()
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0
def cmd_capability_flags(args: argparse.Namespace) -> int:
from core.capability import flag_report
report = flag_report()
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0
def cmd_capability_ledger(args: argparse.Namespace) -> int:
from core.capability import ledger_report
report = ledger_report()
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0
def cmd_capability_artifact(args: argparse.Namespace) -> int:
from core.capability import CapabilityArtifactQuery, artifact_report
report = artifact_report(
CapabilityArtifactQuery(lane=args.lane, split=args.split, version=args.version)
)
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0
def cmd_capability_domain_contract(args: argparse.Namespace) -> int:
"""ADR-0093 domain-contract dry-run validator.
Default behavior runs the nine ADR-0091 predicates plus eval-lane
artifact resolution and exits non-zero on any predicate failure.
The legacy structural-only output remains available via
``--structural-only`` for callers that depend on the prior shape.
"""
from language_packs.domain_contract import validate_domain_contract_pack
if getattr(args, "structural_only", False):
report = validate_domain_contract_pack(args.pack_id).as_dict()
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0 if report["valid"] else 1
from core.capability.domain_contract_predicates import evaluate_domain_contract
predicate_report = evaluate_domain_contract(args.pack_id).as_dict()
print(
json.dumps(predicate_report, indent=2, sort_keys=True)
if args.json
else predicate_report
)
return 0 if predicate_report["all_passed"] else 1
def cmd_capability_evidence_plan(args: argparse.Namespace) -> int:
from core.capability import evidence_plan_report
report = evidence_plan_report()
print(json.dumps(report, indent=2, sort_keys=True) if args.json else report)
return 0
def cmd_capability_perturbation(args: argparse.Namespace) -> int:
"""ADR-0114a Obligation #5 — reasoning-isolation perturbation suite for B3.
Generates and scores invariance-preserving and invariance-breaking
perturbations over B3 (bounded grammar) expected-correct cases.
Writes the report to ``evals/obligation_5_perturbation/<lane_id>.json``.
Exit 0 iff both preserving_rate == 1.0 AND breaking_rate == 1.0.
"""
from pathlib import Path as _Path
from core.capability.perturbation_b3 import (
validate_perturbation_suite,
emit_perturbation_report,
)
lane_id = args.lane_id
report = validate_perturbation_suite(lane_id=lane_id)
out_dir = (
_Path(__file__).resolve().parent.parent / "evals" / "obligation_5_perturbation"
)
out_dir.mkdir(parents=True, exist_ok=True)
out_path = out_dir / f"{lane_id}.json"
emit_perturbation_report(report, out_path)
if args.json:
print(json.dumps(report.as_dict(), indent=2, sort_keys=True))
else:
print(f"lane_id: {report.lane_id}")
print(f"cases_total: {report.cases_total}")
print(f"cases_expected_correct: {report.cases_expected_correct}")
print(
f"preserving: {report.preserving_correct}/{report.preserving_attempted} "
f"= {report.preserving_rate:.4f}"
)
print(
f"breaking: {report.breaking_correct}/{report.breaking_attempted} "
f"= {report.breaking_rate:.4f}"
)
print(f"obligation_5_passed: {report.obligation_5_passed}")
print(f"report_digest: {report.report_digest}")
print(f"artifact: {out_path}")
if not report.obligation_5_passed:
print(f"refusal_reason: {report.refusal_reason}")
return 0 if report.obligation_5_passed else 1
def cmd_capability_math_expert_gate(args: argparse.Namespace) -> int:
"""ADR-0131.4 — evaluate the composite math-expert promotion gate
(Benchmark 1 + 2 + 3, ADR-0131's revision of ADR-0120's single-lane
coverage check). Emits ``expert_claims_math_v1.json`` to ``--out``
(default: ``evals/math_expert_claims/v1/expert_claims_math_v1.json``).
Exit 0 iff every benchmark passes."""
from core.capability.composite_math_gate import (
emit_expert_claims_artifact,
evaluate_composite_math_gate,
)
verdict = evaluate_composite_math_gate()
out_path = (
Path(args.out)
if args.out
else (
Path(__file__).resolve().parent.parent
/ "evals"
/ "math_expert_claims"
/ "v1"
/ "expert_claims_math_v1.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_expert_claims_artifact(verdict, out_path)
if args.json:
print(json.dumps(verdict.as_dict(), indent=2, sort_keys=True))
else:
print(f"composite_gate_passed: {verdict.composite_gate_passed}")
print(f"claim_digest: {verdict.claim_digest}")
print(f"artifact: {out_path}")
for b in verdict.benchmarks:
print(
f" {b.benchmark_id:>20} passed={b.passed} "
f"correct={b.correct}/{b.cases_total} wrong={b.wrong} "
f"rate={b.correct_rate:.4f}"
)
hd = verdict.honest_disclosure
print(
f"GSM8K honest disclosure: admission={hd.get('admitted_solved', 0)}/"
f"{hd.get('cases_total', 0)}, wrong={hd.get('admitted_wrong', 0)}, "
f"substrate={hd.get('substrate', '?')}"
)
if not verdict.composite_gate_passed:
print(f"refusal_reason: {verdict.refusal_reason}")
return 0 if verdict.composite_gate_passed else 1
def cmd_capability_pack_provenance(args: argparse.Namespace) -> int:
"""ADR-0114a Obligation #10 — external audit that every solver
step's ``pack_lemma_id`` resolves to a real entry in the domain's
operator pack lexicon. Defaults to B3 (bounded grammar) under
``en_arithmetic_v1``. Emits report to ``--out`` (default:
``evals/obligation_10_pack_provenance/<lane_id>.json``).
Exit 0 iff obligation passes."""
from core.capability.pack_provenance import (
emit_provenance_report,
validate_lane,
)
report = validate_lane()
out_path = (
Path(args.out)
if args.out
else (
Path(__file__).resolve().parent.parent
/ "evals"
/ "obligation_10_pack_provenance"
/ f"{report.lane_id}.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_provenance_report(report, out_path)
if args.json:
print(json.dumps(report.as_dict(), indent=2, sort_keys=True))
else:
print(f"lane: {report.lane_id}")
print(f"pack_id: {report.pack_id}")
print(f"cases_total: {report.cases_total}")
print(f"cases_validated: {report.cases_validated}")
print(f"cases_skipped_unsolved: {report.cases_skipped_unsolved}")
print(f"cases_violated: {report.cases_violated}")
print(f"obligation_10_passed: {report.obligation_10_passed}")
print("distinct_lemma_ids_observed:")
for lid in report.distinct_lemma_ids_observed:
print(f" - {lid}")
print(f"artifact: {out_path}")
if report.refusal_reason:
print(f"refusal_reason: {report.refusal_reason}")
return 0 if report.obligation_10_passed else 1
def cmd_capability_adversarial(args: argparse.Namespace) -> int:
"""ADR-0114a Obligation #8 — adversarial generation auditor. Runs
a committed adversarial case set through the candidate-graph
pipeline; gate is ``wrong == 0`` across all families AND
``cases_total >= 30`` AND ``families_total >= 8``. Default cases
set ``evals/obligation_8_adversarial/v1/cases.jsonl``; writes
report to ``--out`` (default
``evals/obligation_8_adversarial/<lane_id>.json``). Exit 0 iff
obligation passes."""
from core.capability.adversarial import (
emit_adversarial_report,
evaluate_adversarial,
)
report = evaluate_adversarial()
out_path = (
Path(args.out)
if args.out
else (
Path(__file__).resolve().parent.parent
/ "evals"
/ "obligation_8_adversarial"
/ f"{report.lane_id}.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_adversarial_report(report, out_path)
if args.json:
print(json.dumps(report.as_dict(), indent=2, sort_keys=True))
else:
print(f"lane: {report.lane_id}")
print(
f"cases_total: {report.cases_total} (min {report.cases_total >= 30 and 'OK' or 'FAIL'})"
)
print(
f"families_total: {report.families_total} ({'OK' if report.families_total >= 8 else 'FAIL'})"
)
print(f"cases_refused: {report.cases_refused}")
print(f"cases_solved: {report.cases_solved}")
print(f"cases_wrong: {report.cases_wrong} (gate: must be 0)")
print(f"obligation_8_passed: {report.obligation_8_passed}")
print()
print(f" {'family':<22} {'total':<7} {'refused':<8} {'solved':<8} {'wrong'}")
for f in report.families:
print(
f" {f.family:<22} {f.cases_total:<7} {f.cases_refused:<8} {f.cases_solved:<8} {f.cases_wrong}"
)
print(f"\nartifact: {out_path}")
if report.refusal_reason:
print(f"refusal_reason: {report.refusal_reason}")
return 0 if report.obligation_8_passed else 1
def cmd_capability_depth_curve(args: argparse.Namespace) -> int:
"""ADR-0114a Obligation #6 — compositional-depth curve. Re-runs the
lane's expected-correct cases, buckets by ``len(trace.steps)``,
asserts ``accuracy(N) >= accuracy(depth_1) * (1 - eps)^(N-1)`` for
eps = 0.05. Defaults to B3 (bounded grammar). Emits report to
``--out`` (default ``evals/obligation_6_depth_curve/<lane_id>.json``).
Exit 0 iff the assertion holds."""
from core.capability.depth_curve import (
emit_depth_curve_report,
evaluate_depth_curve,
)
report = evaluate_depth_curve()
out_path = (
Path(args.out)
if args.out
else (
Path(__file__).resolve().parent.parent
/ "evals"
/ "obligation_6_depth_curve"
/ f"{report.lane_id}.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_depth_curve_report(report, out_path)
if args.json:
print(json.dumps(report.as_dict(), indent=2, sort_keys=True))
else:
print(f"lane: {report.lane_id}")
print(f"cases_total: {report.cases_total}")
print(f"cases_solved: {report.cases_solved}")
print(f"epsilon: {report.epsilon}")
print(f"mechanism_wired: {report.obligation_6_mechanism_wired}")
print(f"assertion_holds: {report.obligation_6_assertion_holds}")
print(f"coverage_sufficient: {report.coverage_sufficient}")
print(f"populated_buckets: {list(report.populated_buckets)}")
print()
print(
f" {'bucket':<12} {'total':<7} {'correct':<8} {'accuracy':<10} {'bound':<10} {'satisfied'}"
)
for b in report.buckets:
bound = (
f"{b.bound_required:.4f}"
if b.bound_required is not None
else "(anchor)"
)
print(
f" {b.bucket:<12} {b.cases_total:<7} {b.cases_correct:<8} {b.accuracy:<10.4f} {bound:<10} {b.bound_satisfied}"
)
print(f"\nartifact: {out_path}")
if report.refusal_reason:
print(f"refusal_reason: {report.refusal_reason}")
return 0 if report.obligation_6_assertion_holds else 1
def cmd_capability_ood_ratio(args: argparse.Namespace) -> int:
"""ADR-0114a Obligation #2 — OOD surface variation ratio auditor.
Reads the B3 public ``report.json`` and the OOD lane ``report.json``,
computes ``ood_ratio = ood_accuracy / public_accuracy``, and exits 0
iff ratio >= 0.95 AND ood wrong == 0. Writes report to ``--out``
(default: ``evals/obligation_2_ood_ratio/<lane_id>.json``)."""
from core.capability.ood_ratio import (
emit_ood_ratio_report,
evaluate_ood_ratio,
)
from evals.obligation_2_ood_ratio.v1.runner import (
build_report,
load_cases,
write_report as write_ood_report,
)
_repo_root = Path(__file__).resolve().parent.parent
# Regenerate OOD report so auditor always reads fresh results.
ood_report_path = (
_repo_root / "evals" / "obligation_2_ood_ratio" / "v1" / "report.json"
)
ood_cases = load_cases()
ood_runner_report = build_report(ood_cases)
write_ood_report(ood_runner_report, ood_report_path)
report = evaluate_ood_ratio()
out_path = (
Path(args.out)
if args.out
else (
_repo_root / "evals" / "obligation_2_ood_ratio" / f"{report.lane_id}.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_ood_ratio_report(report, out_path)
if args.json:
print(json.dumps(report.as_dict(), indent=2, sort_keys=True))
else:
print(f"lane: {report.lane_id}")
print(
f"public_accuracy: {report.public_accuracy:.4f} ({report.public_cases_correct}/{report.public_cases_total})"
)
print(
f"ood_accuracy: {report.ood_accuracy:.4f} ({report.ood_cases_correct}/{report.ood_cases_total})"
)
print(f"ood_ratio: {report.ood_ratio:.4f}")
print(f"obligation_2_ratio_satisfied:{report.obligation_2_ratio_satisfied}")
print(f"obligation_2_wrong_zero: {report.obligation_2_wrong_zero}")
print(f"obligation_2_passed: {report.obligation_2_passed}")
print(f"artifact: {out_path}")
if report.refusal_reason:
print(f"refusal_reason: {report.refusal_reason}")
return 0 if report.obligation_2_passed else 1
def cmd_capability_math_expert_promote(args: argparse.Namespace) -> int:
"""ADR-0120 math-expert promotion composer. Collects all 10 ADR-0114a
obligation verdicts + the ADR-0131.4 composite math gate verdict +
the reviewer-signed claim entry from ``docs/reviewers.yaml``;
emits a deterministic ``expert_claims_math_v1_signed.json``
artifact. Exit 0 iff ``promote_admitted == True``.
"""
from core.capability.expert_promotion_math import (
emit_promotion_artifact,
evaluate_math_expert_promotion,
)
verdict = evaluate_math_expert_promotion()
out_path = (
Path(args.out)
if args.out
else (
Path(__file__).resolve().parent.parent
/ "evals"
/ "math_expert_claims"
/ "v1"
/ "expert_claims_math_v1_signed.json"
)
)
out_path.parent.mkdir(parents=True, exist_ok=True)
emit_promotion_artifact(verdict, out_path)
if args.json:
print(json.dumps(verdict.as_dict(), indent=2, sort_keys=True))
else:
print(f"domain: {verdict.domain}")
print()
print(f" {'id':<4} {'passed':<7} title")
for o in verdict.obligations:
print(f" {o.obligation_id:<4} {str(o.passed):<7} {o.title}")
if not o.passed:
print(f" refusal: {o.refusal_reason}")
print()
print(f"composite_gate_passed: {verdict.composite_gate_passed}")
print(f"all_obligations_passed: {verdict.all_obligations_passed}")
print(f"technical_pass: {verdict.technical_pass}")
print(f"claim_digest: {verdict.claim_digest}")
print(f"reviewer_signature_present: {verdict.reviewer_signature is not None}")
print(f"reviewer_signature_matches: {verdict.reviewer_signature_matches}")
print(f"promote_admitted: {verdict.promote_admitted}")
print(f"artifact: {out_path}")
if verdict.refusal_reason:
print()
print("refusal_reason:")
print(f" {verdict.refusal_reason}")
return 0 if verdict.promote_admitted else 1

77
core/cli_doctor.py Normal file
View file

@ -0,0 +1,77 @@
"""Doctor/package-health CLI command handler."""
from __future__ import annotations
import argparse
from pathlib import Path
from core import cli_rust
DEFAULT_REPO_ROOT = Path(__file__).resolve().parent.parent
IMPORT_CHECKS: tuple[tuple[str, str], ...] = (
("algebra", "algebra"),
("alignment", "alignment.graph"),
("benchmarks", "benchmarks.run_benchmarks"),
("calibration", "calibration"),
("chat", "chat.runtime"),
("core_ingest", "core_ingest"),
("demos", "demos.claude_tool_authority"),
("engine_state", "engine_state"),
("evals", "evals.framework"),
("language_packs", "language_packs"),
("morphology", "morphology.registry"),
("packs", "packs.safety.loader"),
("scripts", "scripts.run_pulse"),
("sensorium", "sensorium.protocol"),
("teaching", "teaching"),
("workbench", "workbench"),
)
def cmd_doctor(args: argparse.Namespace, *, repo_root: Path = DEFAULT_REPO_ROOT) -> int:
"""Inspect import/package health for the CLI runtime path."""
ok = True
print(f"repo_root: {repo_root}")
for label, module_name in IMPORT_CHECKS:
try:
__import__(module_name)
except Exception as exc:
ok = False
print(f"FAIL {label:<14} {module_name}: {exc.__class__.__name__}: {exc}")
else:
print(f"OK {label:<14} {module_name}")
rust_importable, rust_detail = cli_rust.probe_core_rs()
print(
"INFO native core_rs "
f"{'importable' if rust_importable else 'not importable'}: {rust_detail}"
)
print(
"INFO native policy optional; run `core doctor --rust --require-rust` to gate it"
)
if args.packs:
try:
from language_packs import list_packs
packs = list_packs()
except Exception as exc:
ok = False
print(
f"FAIL packs language_packs.list_packs: {exc.__class__.__name__}: {exc}"
)
else:
print("packs:")
if packs:
for pack_id in packs:
print(f" {pack_id}")
else:
print(" none found")
if args.rust:
rust_active = cli_rust.print_rust_status(repo_root=repo_root)
if args.require_rust and not rust_active:
ok = False
return 0 if ok else 1

263
core/cli_eval.py Normal file
View file

@ -0,0 +1,263 @@
"""Extracted commands."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from core.cli import _validate_output_path, _DEFAULT_AUDIT_PATH
from core.cli import _die, _REPO_ROOT
def cmd_eval(args: argparse.Namespace) -> int:
"""Run an eval lane by name, or list available lanes."""
if getattr(args, "lane", None) == "sensorium":
return cmd_eval_sensorium(args)
if getattr(args, "lane", None) == "environment-falsification":
return cmd_eval_environment_falsification(args)
if getattr(args, "lane", None) == "math-contemplation":
return cmd_eval_math_contemplation(args)
from evals._parallel import normalize_workers
from evals.framework import (
discover_lanes,
get_lane,
load_cases,
run_lane,
write_result,
)
if args.list_lanes:
lanes = discover_lanes()
if not lanes:
print("no eval lanes found")
for lane in lanes:
versions = ", ".join(lane.versions) if lane.versions else "none"
print(f" {lane.name:20s} versions: {versions}")
return 0
lane_name = args.lane
if not lane_name:
_die(
"eval requires a lane name. Use `core eval --list` to see available lanes."
)
try:
lane = get_lane(lane_name)
except FileNotFoundError as exc:
_die(str(exc))
version = args.version or (lane.versions[0] if lane.versions else "v1")
split = args.split
if not args.json and lane_name == "cognition":
if split == "dev":
cases_path = lane.dev_cases_path()
elif split == "public":
cases_path = lane.public_cases_path(version)
else:
cases_path = lane.holdout_cases_path(version)
cases = load_cases(cases_path)
effective_workers = normalize_workers(
args.workers if args.workers is not None else 4,
len(cases),
)
print(f"workers : {effective_workers}")
try:
result = run_lane(
lane,
version=version,
split=split,
workers=args.workers,
)
except FileNotFoundError as exc:
_die(str(exc))
if args.json:
print(
json.dumps(result.as_dict(), ensure_ascii=False, indent=2, sort_keys=True)
)
else:
print(f"lane : {result.lane}")
print(f"version : {result.version}")
print(f"split : {result.split}")
print(f"cases : {result.metrics.get('total', 0)}")
for key, value in result.metrics.items():
if key == "total":
continue
if isinstance(value, float):
print(f"{key:15s}: {value:.1%}")
else:
print(f"{key:15s}: {value}")
if lane_name == "cognition":
# The cognition lane case_details carry `intent_correct` and
# `versor_closure` booleans; other lanes do not, so the
# cognition-specific failure printer is gated on lane identity to
# avoid spurious "failures" output for lanes that pass cleanly.
failures = [
c
for c in result.case_details
if not c.get("intent_correct") or not c.get("versor_closure")
]
if failures:
print(f"\nfailures ({len(failures)}):")
for c in failures:
issues = []
if not c.get("intent_correct"):
issues.append("intent")
if not c.get("versor_closure"):
vc = c.get("versor_condition", 0)
issues.append(f"versor={vc:.2e}")
cid = c.get("case_id") or c.get("id") or "<unknown>"
print(f" {cid}: {', '.join(issues)}")
if args.save:
result_path = write_result(lane, result)
print(f"\nresult written: {result_path}", file=sys.stderr)
if args.report:
report_path = Path(args.report)
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text(
json.dumps(result.as_dict(), ensure_ascii=False, indent=2, sort_keys=True)
)
print(f"\nreport written: {report_path}", file=sys.stderr)
return 0
def cmd_eval_sensorium(args: argparse.Namespace) -> int:
"""Run deterministic sensorium modality evidence reports."""
from evals.sensorium import build_sensorium_report
modality = getattr(args, "modality", "vision") or "vision"
try:
report = build_sensorium_report(modality)
except ValueError as exc:
_die(str(exc), code=2)
if getattr(args, "json", False):
print(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))
else:
print(f"lane : {report['lane']}")
print(f"modality : {report['modality']}")
print(f"pack_id : {report['pack_id']}")
print(f"gate_engaged : {report['gate_engaged']}")
print(f"gate_closed : {report['gate_closed']}")
print(f"cases : {report['total']}")
print(f"passed : {report['passed']}")
print(f"failed : {report['failed']}")
if getattr(args, "report", None):
report_path = Path(args.report)
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text(
json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True)
)
print(f"\nreport written: {report_path}", file=sys.stderr)
return 0 if report["failed"] == 0 and report["gate_closed"] else 1
def cmd_eval_environment_falsification(args: argparse.Namespace) -> int:
"""Run deterministic environmental falsification replay reports."""
from evals.environment_falsification import build_environment_falsification_report
report = build_environment_falsification_report()
if getattr(args, "json", False):
print(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))
else:
print(f"lane : {report['lane']}")
print(f"version : {report['version']}")
print(f"cases : {report['total']}")
print(f"passed : {report['passed']}")
print(f"failed : {report['failed']}")
print(f"report_sha256 : {report['report_sha256']}")
if getattr(args, "report", None):
report_path = Path(args.report)
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text(
json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True)
)
print(f"\nreport written: {report_path}", file=sys.stderr)
return 0 if report["failed"] == 0 and report["expected_report_hash_ok"] else 1
def cmd_eval_math_contemplation(args: argparse.Namespace) -> int:
"""ADR-0172 W3 — decompose an audit brief into refusal-shape proposals.
Reads ``--audit`` (default: ``evals/gsm8k_math/train_sample/v1/audit_brief_11.json``),
runs :func:`teaching.math_contemplation.decompose_audit`, and writes one
``canonical_bytes()`` JSON line per proposal to ``--output``
(default: ``teaching/math_proposals/proposals.jsonl``).
Idempotency: re-running on the same audit overwrites byte-identical bytes.
Output is sorted by ``proposal_id`` (matches the decomposer sort contract).
Exit codes:
0 success
1 audit file not found
2 parse error or path-traversal rejection
Forbidden by design: no proposal is auto-applied, no file outside
``teaching/math_proposals/`` is written, the audit file is not mutated.
"""
from teaching.math_contemplation import decompose_audit
from teaching.math_contemplation_proposal import to_jsonl_record
audit_raw = getattr(args, "audit", None)
output_raw = getattr(args, "output", None)
audit_path = Path(audit_raw) if audit_raw else _DEFAULT_AUDIT_PATH
if not audit_path.is_absolute():
audit_path = (_REPO_ROOT / audit_path).resolve()
if not audit_path.exists():
_die(f"audit file not found: {audit_path}", code=1)
output_path = _validate_output_path(output_raw)
try:
proposals = decompose_audit(audit_path)
except json.JSONDecodeError as exc:
_die(f"parse error in audit file {audit_path}: {exc}", code=2)
output_path.parent.mkdir(parents=True, exist_ok=True)
# Self-contained JSONL (ADR-0172 tightening follow-up #1): each line
# carries proposal_id, full evidence_pointers, and full
# reasoning_trace.steps so consumers can load without re-running the
# decomposer.
lines: list[bytes] = []
for proposal in proposals:
record = to_jsonl_record(proposal)
encoded = json.dumps(
record,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
).encode("utf-8")
lines.append(encoded + b"\n")
output_path.write_bytes(b"".join(lines))
if not getattr(args, "json", False):
print(f"proposals : {len(proposals)}")
print(f"output : {output_path}")
else:
print(
json.dumps(
{
"proposals": len(proposals),
"output": str(output_path),
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0

232
core/cli_ingest.py Normal file
View file

@ -0,0 +1,232 @@
"""Operator-facing CLI for the durable ``core_ingest`` boundary."""
from __future__ import annotations
import argparse
import hashlib
import json
import sys
from pathlib import Path
from typing import Any
from core_ingest import IngestPipeline, IngestPipelineConfig, SegmentManifold
from core_ingest.types import LearningArtifact, SourceSpan, ValidationReport
_MODALITY_HINTS = ("prose", "scripture", "code", "math")
_DEFAULT_MAX_BYTES = 1_048_576
_TRUST_BOUNDARY = (
"read_only_durable_core_ingest_compile_no_gate_import_no_vault_or_pack_mutation"
)
def _source_from_args(args: argparse.Namespace) -> tuple[bytes, dict[str, Any]]:
if args.text is not None:
source = args.text.encode("utf-8")
return source, {
"kind": "text",
"bytes": len(source),
"sha256": hashlib.sha256(source).hexdigest(),
}
path = Path(args.file).expanduser()
try:
resolved = path.resolve(strict=True)
except FileNotFoundError as exc:
raise ValueError(f"source file does not exist: {path}") from exc
if not resolved.is_file():
raise ValueError(f"source path is not a regular file: {resolved}")
size = resolved.stat().st_size
if size > args.max_bytes:
raise ValueError(
f"source file is {size} bytes, above --max-bytes {args.max_bytes}"
)
source = resolved.read_bytes()
return source, {
"kind": "file",
"path": str(resolved),
"bytes": len(source),
"sha256": hashlib.sha256(source).hexdigest(),
}
def _span_payload(span: SourceSpan) -> dict[str, Any]:
return {
"byte_start": span.byte_start,
"byte_end": span.byte_end,
"source_sha256": span.source_sha256,
"page": span.page,
"region": span.region,
}
def _report_payload(
*,
source_info: dict[str, Any],
modality_hint: str,
report: ValidationReport,
artifacts: list[LearningArtifact],
manifold: SegmentManifold,
register_all: bool,
) -> dict[str, Any]:
return {
"command": "ingest compile",
"path": "durable",
"boundary_owner": "core_ingest",
"runtime_gate": "ingest/gate.py is not imported or called",
"trust_boundary": _TRUST_BOUNDARY,
"mutates": False,
"modality_hint": modality_hint,
"source": source_info,
"summary": {
"results": len(report.results),
"accepted": len(report.accepted_ids),
"rejected": len(report.rejected_ids),
"review_required": len(report.review_ids),
"acceptance_rate": report.acceptance_rate,
"manifold_keys": len(manifold),
"register_all": register_all,
},
"results": [
{
"pressure_id": result.pressure_id,
"semantic_key": result.semantic_key,
"disposition": result.disposition.value,
"gate_failed": result.gate_failed,
"failure_reason": result.failure_reason,
"warnings": list(result.warnings),
}
for result in report.results
],
"artifacts": [
{
"pressure_id": artifact.packet.pressure_id,
"semantic_key": artifact.packet.semantic_key,
"kind": artifact.packet.kind,
"modality": artifact.packet.modality.value,
"review_level": artifact.packet.review_level.value,
"instrument_id": artifact.packet.frontend.instrument_id,
"lemma": artifact.packet.lemma,
"spans": [_span_payload(span) for span in artifact.packet.provenance],
}
for artifact in artifacts
],
}
def _print_text(payload: dict[str, Any]) -> None:
summary = payload["summary"]
source = payload["source"]
source_label = (
source["path"]
if source["kind"] == "file"
else f"inline:{source['sha256'][:12]}"
)
print("core_ingest durable compile")
print(f"source : {source_label}")
print(f"source_bytes : {source['bytes']}")
print(f"modality_hint : {payload['modality_hint']}")
print(f"trust_boundary : {payload['trust_boundary']}")
print(f"runtime_gate : {payload['runtime_gate']}")
print(f"mutates : {payload['mutates']}")
print(f"results : {summary['results']}")
print(f"accepted : {summary['accepted']}")
print(f"rejected : {summary['rejected']}")
print(f"review_required: {summary['review_required']}")
print(f"acceptance_rate: {summary['acceptance_rate']:.3f}")
for result in payload["results"][:10]:
reason = f" {result['failure_reason']}" if result["failure_reason"] else ""
print(
f" {result['disposition']:<20} "
f"{result['pressure_id'][:12]} semantic={result['semantic_key'][:12]}"
f"{reason}"
)
if len(payload["results"]) > 10:
print(f" ... {len(payload['results']) - 10} more result(s)")
def cmd_ingest_compile(args: argparse.Namespace) -> int:
"""Run the durable core_ingest pipeline and print a validation report."""
try:
source, source_info = _source_from_args(args)
if not source:
raise ValueError("ingest source is empty")
manifold = SegmentManifold()
pipeline = IngestPipeline(
manifold=manifold,
config=IngestPipelineConfig(register_all=args.register_all),
)
report, artifacts = pipeline.run(source, modality_hint=args.modality)
except ValueError as exc:
print(f"error: {exc}", file=sys.stderr)
return 2
payload = _report_payload(
source_info=source_info,
modality_hint=args.modality,
report=report,
artifacts=artifacts,
manifold=manifold,
register_all=args.register_all,
)
if args.json:
print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True))
else:
_print_text(payload)
return 0
def register(subparsers: argparse._SubParsersAction) -> None:
"""Attach the ``core ingest`` subcommand tree to a top-level parser."""
ingest = subparsers.add_parser(
"ingest",
help="inspect durable input-to-pressure compilation",
description=(
"Run the durable core_ingest compiler. This is read-only: it does "
"not import ingest/gate.py, write vault memory, mutate packs, or "
"ratify learning."
),
)
sub = ingest.add_subparsers(
dest="ingest_command",
metavar="ingest-command",
required=True,
)
compile_cmd = sub.add_parser(
"compile",
help="compile source bytes into validated candidate pressure",
description=(
"Compile source bytes through StructuralSegmenter -> "
"IngestCompiler -> SegmentManifold and emit a validation report."
),
)
source = compile_cmd.add_mutually_exclusive_group(required=True)
source.add_argument("--text", help="inline UTF-8 source text to compile")
source.add_argument(
"--file",
type=Path,
help="regular local file to read as source bytes",
)
compile_cmd.add_argument(
"--modality",
choices=_MODALITY_HINTS,
default="prose",
help="structural modality hint (default: prose)",
)
compile_cmd.add_argument(
"--max-bytes",
type=int,
default=_DEFAULT_MAX_BYTES,
help=f"maximum file size accepted by --file (default: {_DEFAULT_MAX_BYTES})",
)
compile_cmd.add_argument(
"--register-all",
action="store_true",
help="index rejected packets in the reconstruction manifold report",
)
compile_cmd.add_argument("--json", action="store_true", help="emit JSON")
compile_cmd.set_defaults(func=cmd_ingest_compile)

84
core/cli_pack.py Normal file
View file

@ -0,0 +1,84 @@
"""Extracted commands."""
from __future__ import annotations
import argparse
import json
import sys
from core.cli_teaching import _safe_pack_id
from core.cli import _die, _REPO_ROOT, _run
def cmd_pack_list(args: argparse.Namespace) -> int:
"""List compiled language packs."""
from language_packs import list_packs
packs = list_packs()
if not packs:
print("no compiled packs found")
return 0
for pack_id in packs:
print(pack_id)
return 0
def cmd_pack_verify(args: argparse.Namespace) -> int:
"""Verify one language pack checksum."""
return _run(sys.executable, "-m", "language_packs", "verify", args.pack_id)
def cmd_pack_validate(args: argparse.Namespace) -> int:
"""Run executable source-pack validation gates."""
pack_id = _safe_pack_id(args.pack_id)
pack_dir = _REPO_ROOT / "packs" / pack_id
validator_path = pack_dir / "validators.py"
if not validator_path.exists():
_die(f"source-pack validator not found: {validator_path}", code=1)
if getattr(args, "dry_run", False):
if args.json:
print(
json.dumps(
{
"pack_id": pack_id,
"validator_path": str(validator_path),
"would_execute": False,
"exists": True,
},
ensure_ascii=False,
indent=2,
sort_keys=True,
)
)
else:
print(f"dry-run: pack_id={pack_id}")
print(f"validator: {validator_path}")
print("status: validator exists, would not execute")
return 0
if not getattr(args, "allow_arbitrary_code", False):
_die(
"dynamic validator execution requires --allow-arbitrary-code",
code=2,
)
import importlib.util
spec = importlib.util.spec_from_file_location(
f"{pack_id}_validators", validator_path
)
if spec is None or spec.loader is None:
_die(f"cannot load source-pack validator: {validator_path}", code=1)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
report = module.validate_pack()
if args.json:
print(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))
else:
print(f"pack_id: {report['pack_id']}")
print(f"active : {report['active']}")
for name, result in report["gates"].items():
status = "PASS" if result["passed"] else "FAIL"
print(f"{status} {name:<12} {result['reason']}")
return 0 if report["active"] else 1

144
core/cli_rust.py Normal file
View file

@ -0,0 +1,144 @@
"""Rust backend CLI command handlers.
The top-level CLI owns argparse construction and subprocess policy. This module
owns the Rust/native-substrate command behavior so ``core/cli.py`` does not keep
absorbing every command family.
"""
from __future__ import annotations
import argparse
import os
import shutil
import subprocess
import sys
from pathlib import Path
from typing import NoReturn, Protocol
DEFAULT_REPO_ROOT = Path(__file__).resolve().parent.parent
CORE_RS_DIR = DEFAULT_REPO_ROOT / "core-rs"
CORE_RS_MANIFEST = CORE_RS_DIR / "Cargo.toml"
class CommandRunner(Protocol):
def __call__(
self,
*args: str,
check: bool = False,
cwd: Path | None = None,
env: dict[str, str] | None = None,
) -> int: ...
class DieHandler(Protocol):
def __call__(self, message: str, *, code: int = 2) -> NoReturn: ...
def rust_paths(repo_root: Path = DEFAULT_REPO_ROOT) -> tuple[Path, Path]:
core_rs_dir = repo_root / "core-rs"
return core_rs_dir, core_rs_dir / "Cargo.toml"
def run_command(
*args: str,
check: bool = False,
cwd: Path | None = None,
env: dict[str, str] | None = None,
) -> int:
completed = subprocess.run(args, check=check, text=True, cwd=cwd, env=env)
return int(completed.returncode)
def die(message: str, *, code: int = 2) -> NoReturn:
print(f"error: {message}", file=sys.stderr)
raise SystemExit(code)
def rust_build_env() -> dict[str, str]:
"""Return the environment used for PyO3-backed Rust build/test commands."""
env = os.environ.copy()
# PyO3 0.21 supports Python through 3.12. Fresh uv environments may be
# 3.13+, so use PyO3's documented forward-compatibility escape hatch unless
# the operator has provided a more specific PYO3_* policy.
env.setdefault("PYO3_USE_ABI3_FORWARD_COMPATIBILITY", "1")
return env
def probe_core_rs() -> tuple[bool, str]:
try:
import core_rs
except Exception as exc:
return False, f"{exc.__class__.__name__}: {exc}"
return True, str(getattr(core_rs, "__file__", "<built-in>"))
def print_rust_status(*, repo_root: Path = DEFAULT_REPO_ROOT) -> bool:
from algebra.backend import using_rust
core_rs_dir, core_rs_manifest = rust_paths(repo_root)
active = using_rust()
importable, import_detail = probe_core_rs()
print(f"core_rs crate : {core_rs_dir}")
print(f"cargo manifest: {core_rs_manifest}")
print(f"CORE_BACKEND : {os.environ.get('CORE_BACKEND', '') or '(default python)'}")
print(f"core_rs import: {'ok' if importable else 'missing'}")
print(f"core_rs detail: {import_detail}")
print(f"rust backend : {'active' if active else 'inactive'}")
if not active:
print("activation : run `core rust build`")
return active
def cmd_rust_status(
args: argparse.Namespace,
*,
repo_root: Path = DEFAULT_REPO_ROOT,
) -> int:
"""Print Rust backend activation status."""
return 0 if print_rust_status(repo_root=repo_root) or not args.require_active else 1
def cmd_rust_build(
args: argparse.Namespace,
*,
repo_root: Path = DEFAULT_REPO_ROOT,
run: CommandRunner = run_command,
fail: DieHandler = die,
python_executable: str = sys.executable,
) -> int:
"""Build/install core_rs into the active Python environment."""
_, core_rs_manifest = rust_paths(repo_root)
if not core_rs_manifest.exists():
fail(f"core-rs manifest not found: {core_rs_manifest}", code=1)
if shutil.which("uv") is not None:
rc = run("uv", "pip", "install", "maturin")
if rc != 0:
return rc
cmd = [
python_executable,
"-m",
"maturin",
"develop",
"--release",
"--manifest-path",
str(core_rs_manifest),
]
if args.skip_auditwheel:
cmd.append("--skip-auditwheel")
return run(*cmd, env=rust_build_env())
def cmd_rust_test(
args: argparse.Namespace,
*,
repo_root: Path = DEFAULT_REPO_ROOT,
run: CommandRunner = run_command,
fail: DieHandler = die,
) -> int:
"""Run Rust crate tests."""
del args
core_rs_dir, _ = rust_paths(repo_root)
if shutil.which("cargo") is None:
fail("cargo not found. Install a Rust toolchain first.", code=1)
return run("cargo", "test", "--release", cwd=core_rs_dir, env=rust_build_env())

1358
core/cli_teaching.py Normal file

File diff suppressed because it is too large Load diff

260
core/cli_test.py Normal file
View file

@ -0,0 +1,260 @@
"""Curated pytest and ruff CLI command handlers."""
from __future__ import annotations
import argparse
import subprocess
import sys
from collections.abc import Sequence
from pathlib import Path
from typing import Protocol
TEST_SUITES: dict[str, tuple[str, ...]] = {
"fast": (
"tests/test_cli_test_suites.py",
"tests/test_runtime_config.py",
"tests/test_core_semantic_seed_pack.py",
"tests/test_intent_proposition_graph.py",
"tests/test_articulation_realizer_v2.py",
"tests/test_reviewed_teaching_loop.py",
"tests/test_cognitive_eval_harness.py",
),
"smoke": (
"tests/test_chat_runtime.py",
"tests/test_achat.py",
"tests/test_runtime_config.py",
"tests/test_cognitive_turn_pipeline.py",
"tests/test_architectural_invariants.py",
# ADR-0043 — identity falsifiability: ratified identity packs must
# produce distinct, directionally-correct articulations, with a
# pack-invariant grounding/refusal floor and zero fabrication. Lives
# only under ``full`` historically, so a divergence regression cleared
# the PR gate and surfaced only post-merge. Promoted into smoke so
# the falsifiability claim blocks-on-regression rather than
# detect-after-merge.
"tests/test_pack_measurements_phase2.py",
),
"runtime": (
"tests/test_chat_runtime.py",
"tests/test_achat.py",
"tests/test_runtime_config.py",
"tests/test_session_coherence.py",
),
"cognition": (
"tests/test_intent_proposition_graph.py",
"tests/test_cognitive_turn_pipeline.py",
"tests/test_articulation_realizer_v2.py",
"tests/test_semantic_realizer_integration.py",
"tests/test_cognitive_eval_harness.py",
"tests/test_deterministic_hash.py",
"tests/test_morphology_irregular.py",
"tests/test_realizer_quantifier_agreement.py",
"tests/test_benchmarks_profiler.py",
"tests/test_compose_relations.py",
"tests/test_replay_vs_llm_benchmark.py",
),
"teaching": (
"tests/test_reviewed_teaching_loop.py",
"tests/test_pipeline_teaching_integration.py",
"tests/test_epistemic_invariants.py",
"tests/test_adr_0172_w2_decomposer.py",
"tests/test_adr_0172_w5_inference_proposal.py",
"tests/test_math_frame_ratification.py",
"tests/test_math_composition_ratification.py",
"tests/test_teaching_coverage_cli.py",
),
"packs": (
"tests/test_core_semantic_seed_pack.py",
"tests/test_adr_0127_pack_ratification.py",
"tests/test_frame_registry_load.py",
"tests/test_composition_registry_load.py",
"tests/test_composition_consult_in_injector.py",
"tests/test_consumption_case_0050_hazard_pin.py",
"tests/test_consumption_empty_registry_no_op.py",
"tests/test_consumption_partition.py",
"tests/test_matcher_extension_currency_per_unit.py",
"tests/test_matcher_extension_case_0050_hazard_pin.py",
"tests/test_matcher_extension_end_to_end_admission.py",
"tests/test_me2_cross_sentence_subject.py",
"tests/test_me2_case_0019_admits.py",
"tests/test_me3_additive_composition.py",
"tests/test_me4_subtractive_composition.py",
"tests/test_me5_all_categories_integration.py",
"tests/test_rat1_end_to_end_admission.py",
"tests/test_wave_a_multiplicative_aggregation_injector.py",
),
"algebra": (
"tests/test_versor_closure.py",
"tests/test_holonomy.py",
"tests/test_holonomy_resonance.py",
"tests/test_energy.py",
"tests/test_motor.py",
"tests/test_null_cone.py",
"tests/test_vault_recall.py",
"tests/test_vault_recall_vectorised.py",
"tests/test_vault_recall_rust_parity.py",
"tests/test_cga_inner_rust_parity.py",
"tests/test_geometric_product_rust_parity.py",
"tests/test_versor_condition_rust_parity.py",
"tests/test_versor_apply_rust_parity.py",
),
"sensorium": (
"tests/test_sensorium_compiler_delta.py",
"tests/test_audio_compiler.py",
"tests/test_audio_crdt_merge.py",
"tests/test_audio_eval_gates.py",
"tests/test_audio_pack_manifest.py",
"tests/test_audio_sensorium_mount.py",
"tests/test_vision_compiler.py",
"tests/test_event_vision_compiler.py",
"tests/test_vision_crdt_merge.py",
"tests/test_vision_eval_gates.py",
"tests/test_vision_sensorium_mount.py",
"tests/test_sensorimotor_contract.py",
"tests/test_sensorimotor_pack_manifest.py",
"tests/test_observation_frame_contract.py",
"tests/test_observation_frame_harness.py",
"tests/test_environment_falsification.py",
"tests/test_environment_falsification_eval_cli.py",
"tests/test_witness_log_importer.py",
"tests/test_tabletop_lab_protocol.py",
"tests/test_sensorium_eval_cli.py",
"tests/test_efferent_gate.py",
),
"pulse": (
"tests/test_pulse_integration.py",
"tests/test_graph_diffusion.py",
),
"formation": ("tests/formation",),
"proof": ("tests/test_proof_properties.py",),
# ADR-0024 chain suites (Phases 2-6). Each phase has its own contract
# tests so reviewers can run them independently; ``adr-0024`` runs the full
# chain end-to-end.
"refusal": ("tests/test_refusal_contract.py",),
"margin": ("tests/test_margin_admissibility.py",),
"rotor": ("tests/test_rotor_admissibility.py",),
"inner-loop": (
"tests/test_inner_loop_admissibility.py",
"tests/test_inner_loop_phase2.py",
"tests/test_inner_loop_phase3.py",
"tests/test_inner_loop_phase4.py",
),
"phase5": ("tests/test_phase5_corpus.py",),
"phase6": ("tests/test_phase6_demo.py",),
"adr-0024": (
"tests/test_refusal_contract.py",
"tests/test_margin_admissibility.py",
"tests/test_rotor_admissibility.py",
"tests/test_inner_loop_admissibility.py",
"tests/test_inner_loop_phase2.py",
"tests/test_inner_loop_phase3.py",
"tests/test_inner_loop_phase4.py",
"tests/test_phase5_corpus.py",
"tests/test_phase6_demo.py",
),
# ADR-0126 P6 — measurement harness for the GSM8K candidate-graph parser
# exit criterion. ``wrong == 0`` is a hard gate (Obligation #4: refuse
# rather than confabulate).
"math": ("tests/test_adr_0126_train_sample_runner.py",),
"deductive": ("tests/test_deductive_logic_entail.py",),
"full": ("tests/",),
}
class CommandRunner(Protocol):
def __call__(
self,
*args: str,
check: bool = False,
cwd: Path | None = None,
env: dict[str, str] | None = None,
) -> int: ...
def run_command(
*args: str,
check: bool = False,
cwd: Path | None = None,
env: dict[str, str] | None = None,
) -> int:
completed = subprocess.run(args, check=check, text=True, cwd=cwd, env=env)
return int(completed.returncode)
def pytest_args_for_suite(suite: str, extra_args: Sequence[str]) -> list[str]:
paths = TEST_SUITES[suite]
forwarded = list(extra_args)
if forwarded and forwarded[0] == "--":
forwarded = forwarded[1:]
return [*paths, *forwarded]
def xdist_available() -> bool:
"""Return True iff ``pytest-xdist`` is importable."""
try:
import xdist # noqa: F401
except ImportError:
return False
return True
def maybe_inject_xdist(forwarded: list[str], suite: str | None) -> list[str]:
"""Inject ``-n auto`` for suites large enough to benefit from parallelism."""
if not xdist_available():
return forwarded
# Honour explicit operator override.
if any(a.startswith("-n") or a == "--dist" for a in forwarded):
return forwarded
if suite == "full":
return ["-n", "auto", *forwarded]
return forwarded
def cmd_test(
args: argparse.Namespace,
*,
run: CommandRunner = run_command,
python_executable: str = sys.executable,
) -> int:
"""Run pytest through curated suite aliases or direct passthrough args."""
default_args = ["-q", "--tb=short"]
if args.list_suites:
for name in sorted(TEST_SUITES):
print(name)
return 0
if args.suite:
forwarded = pytest_args_for_suite(args.suite, args.args or default_args)
else:
forwarded = list(args.args or default_args)
if forwarded and forwarded[0] == "--":
forwarded = forwarded[1:]
forwarded = maybe_inject_xdist(forwarded, args.suite)
return run(python_executable, "-m", "pytest", *forwarded)
def cmd_check(
args: argparse.Namespace,
*,
run: CommandRunner = run_command,
python_executable: str = sys.executable,
) -> int:
"""Run ruff over selected project paths."""
targets = args.paths or [
"algebra",
"alignment",
"chat",
"core",
"field",
"generate",
"ingest",
"language_packs",
"morphology",
"persona",
"sensorium",
"session",
"vault",
"vocab",
"tests",
]
return run(python_executable, "-m", "ruff", "check", *targets)

14
core/demos/README.md Normal file
View file

@ -0,0 +1,14 @@
# Demo Composition Layer
`core/demos/` contains the typed composition surface for demos:
contracts, adapters, showcase rendering, and expert-demo packaging.
It does not own standalone scenario fixtures. Those live under top-level
`demos/`, where each demo package can pin its inputs, expected artifacts, and
honesty ledger.
Boundary:
- `demos/` proves a narrow claim inside a deterministic local envelope.
- `core/demos/` adapts proven demos into shared presentation and Workbench
surfaces.

16
core_ingest/README.md Normal file
View file

@ -0,0 +1,16 @@
# Core Ingest
`core_ingest/` converts external source material into typed candidate pressure:
content-addressed packets with provenance, modality, determinism class, review
level, and semantic keys.
Its durable path runs the three-gate `IngestCompiler` and can export
`LearningArtifact` objects. Its read-only CLI surface (`core ingest compile`) is
for inspection and does not write vault entries, mutate packs, ratify learning,
or call `ingest/gate.py`.
Boundary:
- `core_ingest` prepares and validates candidate pressure.
- `ingest/gate.py` injects runtime field state into the versor manifold.
- durable mutation still belongs to the reviewed teaching path.

15
demos/README.md Normal file
View file

@ -0,0 +1,15 @@
# Deterministic Demo Packages
`demos/` contains standalone, claim-scoped demonstration packages. Each demo
has its own fixtures, expected artifacts, local authority code, and runner.
These packages are intentionally importable because tests and Workbench demo
routes execute them as deterministic envelopes. They are not generic runtime
adapters and they must not perform hidden side effects.
Use this directory for bounded proof demos such as proposer authority,
proof-carrying promotion, epistemic truth-state refusal, or domain-specific
decision substrates.
Use `core/demos/` for composition contracts, showcase adapters, and runtime
presentation of already-proven demos.

View file

@ -34,11 +34,11 @@ ADRs strengthened: 0022 (TBDs closed), 0023 (proof evidence expanded).
Evidence locations:
- Runtime contracts: `docs/runtime_contracts.md` — Refusal / Margin / Rotor admissibility sections
- Runtime contracts: `docs/specs/runtime_contracts.md` — Refusal / Margin / Rotor admissibility sections
- Stratified findings: `docs/evals/phase5_stratified_findings.md`
- Comparative demo: `docs/evals/phase6_comparative_demo.md`
- Reports: `evals/forward_semantic_control/results/` (+ auto-refreshed `index.json`)
- ADR index: `docs/decisions/README.md` — "ADR-0024 chain" section
- ADR index: `docs/adr/README.md` — "ADR-0024 chain" section
How to verify on a fresh checkout:
@ -800,7 +800,7 @@ Also retroactive (the bulk happened between 2026-05-18 and 2026-05-20):
**Status:** Complete ✓ (all 8 sub-phases landed 2026-05-22/23)
**Depends on:** ADR-0114, ADR-0114a, ADR-0115, ADR-0116, ADR-0117, ADR-0118
**Roadmap:** `docs/decisions/ADR-0119-gsm8k-eval-lane-roadmap.md`
**Roadmap:** `docs/adr/ADR-0119-gsm8k-eval-lane-roadmap.md`
This phase completes the GSM8K eval lane substrate defined in ADR-0114 §Phase 5 and
decomposed into 8 sub-phases by ADR-0119. The lane is now substrate-complete;

View file

@ -2,13 +2,17 @@
## Why Rust
Three operations dominate CORE-AI's runtime:
The active Rust extension is an opt-in native substrate for parity-gated hot
paths, not a shadow cognition path. These operations currently justify Rust:
1. `geometric_product` — O(32^2) = 1024 multiply-adds per call, called 2-3x per `versor_apply`
2. `vault_recall` scan — O(N) CGA inner product calls, N = all stored versors, called during generation recall
3. `cga_inner` — called by vocabulary/proposition nearest selection and vault recall
4. `diffusion_step` — zero-copy graph diffusion over `(N, 32)` field buffers
None of the Python fallback paths release the Python GIL. Rayon gives `vault_recall` true multithreaded parallelism across CPU cores. The geometric product loop is cache-friendly and compiler-optimized in release mode.
None of the Python fallback paths release the Python GIL. Rayon gives
`vault_recall` true multithreaded parallelism across CPU cores. The geometric
product loop is cache-friendly and compiler-optimized in release mode.
## What is in Rust
@ -18,6 +22,7 @@ None of the Python fallback paths release the Python GIL. Rayon gives `vault_rec
| Versor ops | `versor.rs` | 3x geometric product per field step |
| CGA inner product | `cga.rs` | Called by nearest search and recall |
| Vault top-k scan | `vault.rs` | Rayon parallel scan |
| Graph diffusion | `diffusion.rs` | Zero-copy field graph step |
## What stays in Python
@ -27,10 +32,18 @@ None of the Python fallback paths release the Python GIL. Rayon gives `vault_rec
| `SessionContext` | Orchestration, not arithmetic |
| `FieldState` | Plain dataclass |
| `PersonaMotor` | Motor construction is infrequent |
| `holonomy_encode` | Python-canonical until a native port proves byte-for-byte parity with position-rotor/f64 construction semantics |
| `propagate_batch` | Not an active runtime surface; future native propagation must use closure-preserving `versor_apply` semantics |
## Zero-Copy Semantics
## Buffer Semantics
The runtime contract is numpy `float32` arrays of length 32. Rust reads them into stack `[f32; 32]` values, executes the hot loop, and returns a new numpy array. The Python fallback remains behaviorally available when `core_rs` is not installed.
Scalar multivector bindings validate numpy-compatible arrays of length 32,
copy them into fixed stack arrays, execute the kernel, and return a new numpy
array. Bulk bindings (`vault_recall`, `diffusion_step`) consume contiguous
numpy buffers via `PyReadonlyArray` views so they avoid Python-list marshalling.
The Python fallback remains behaviorally available when `core_rs` is not
installed or `CORE_BACKEND=rust` is not explicit. A fresh root install is
therefore correct without the native extension, but not mechanically optimal.
## Build / Activate
@ -43,6 +56,11 @@ core rust build
core rust status --require-active
```
`core rust build` and `core rust test` set
`PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1` for their subprocesses so PyO3 0.21 can
build from Python 3.13+ uv environments. Operators who need a specific Python
interpreter can still override with `PYO3_PYTHON`.
Equivalent explicit maturin command:
```bash
@ -66,7 +84,7 @@ True
```bash
core rust test
# or
cargo test --release --manifest-path core-rs/Cargo.toml
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo test --release --manifest-path core-rs/Cargo.toml
```
## Type Safety Contract
@ -78,7 +96,10 @@ All multivectors entering the Rust layer must be numpy-compatible `float32` arra
If `core_rs` is absent or fails to import, `algebra.backend` silently falls back to Python. This keeps the engine correct but not mechanically optimal. Use:
```bash
core doctor
core doctor --rust --require-rust
```
to fail fast when benchmarking or profiling requires the Rust backend.
`core doctor` reports whether `core_rs` is importable without failing the Python
runtime. `core doctor --rust --require-rust` fails fast when benchmarking or
profiling requires the Rust backend.

View file

@ -53,7 +53,7 @@ From the first commit, CORE was designed as a three-language implementation stac
| Language | Role | Reason |
|---|---|---|
| **Python** | Orchestration, session management, vocabulary, persona construction | Human-readable system topology. The field lifecycle is expressed as Python because humans need to read, audit, and extend the cognitive architecture. |
| **Rust** | Algebra kernel, vault recall, holonomy encoding, batch propagation | Zero-cost abstractions, ownership semantics, and Rayon parallelism for the operations that are called 10,000 times per generation. No GIL. No heap allocation in the hot path. |
| **Rust** | Algebra kernel, exact vault recall, closure-preserving versor apply, graph diffusion | Zero-cost abstractions, ownership semantics, and Rayon parallelism for the native operations that are parity-gated and explicitly enabled. No hidden backend substitution. |
| **MLX** | Tensor operations on Apple Silicon UMA | The field is a dense f32 array. MLX executes on the Neural Engine and AMX coprocessors with zero PCIe transfer overhead. The hardware *is* the memory bus. |
This is not a stack — it is a stratification. Each language governs its natural domain. Python describes structure. Rust computes algebra. MLX executes tensor operations on silicon. The boundary between them is defined by contract, not convention.
@ -350,7 +350,7 @@ deterministic trace. The chain is the structural defense against
the confabulation failure mode at exactly the layer where it must
be defended — generation itself.
Full evidence: `docs/runtime_contracts.md` (contracts),
Full evidence: `docs/specs/runtime_contracts.md` (contracts),
`docs/evals/phase5_stratified_findings.md` (geometric
characterization), `docs/evals/phase6_comparative_demo.md`
(head-to-head demo).
@ -407,14 +407,14 @@ sampling, not from a replay-deterministic trace bound to a signed
evidence bundle. CORE makes the commitment first-class.
External readers can inspect the ledger
(`core capability ledger` / `docs/decisions/README.md` table) to see
(`core capability ledger` / `docs/adr/README.md` table) to see
which domains are *contract-passing* and which are *demonstrated*. As
of 2026-05-23: three domains demonstrated (`mathematics_logic`,
`physics`, `systems_software`); one ratified domain pending its
own promotion ADR (`hebrew_greek_textual_reasoning`).
Full evidence chain: `docs/decisions/README.md` (index + frontier),
`docs/decisions/ADR-0091-domain-pack-contract-v1.md` through
Full evidence chain: `docs/adr/README.md` (index + frontier),
`docs/adr/ADR-0091-domain-pack-contract-v1.md` through
`ADR-0111-physics-expert-demo-promotion.md`.
#### Phase 5 — Capability Substrate (ADR-0119 arc)

View file

@ -193,7 +193,11 @@ H = normalize(F · R)
Where α ∈ [0,1] is the blend factor (default 0.5). The holonomy versor encodes not just which words appeared, but the order in which they appeared and the curvature of the path they traced.
Implementation: `core-rs/src/holonomy.rs` — the entire computation is a single allocation-free Rust function. At 100-token inputs, this replaces 200+ Python dispatch calls with a single call crossing the PyO3 boundary.
Implementation: `algebra/holonomy.py`. Holonomy remains Python-canonical because
the current construction includes deterministic position rotors, f64 boundary
semantics, and construction-time fallback through `construction_seed_versor`.
There is no active Rust holonomy binding; a future native port must first prove
byte-for-byte parity with this Python contract.
**Boundedness invariant:**
```
@ -371,19 +375,25 @@ Personas compose. Two persona motors can be combined into a single motor before
| Layer | Language | Entry point | Invariant |
|---|---|---|---|
| Orchestration | Python | `session/context.py` | Reads and writes `FieldState`. Never calls algebra directly — always via `algebra/backend.py`. |
| Backend dispatch | Python | `algebra/backend.py` | Single switch: core_rs if available, pure Python fallback. |
| Algebra kernel | Rust (PyO3) | `core-rs/src/lib.rs` | `[f32; 32]` in, `[f32; 32]` out. No heap allocation in hot path. All errors are `thiserror` named variants. |
| Backend dispatch | Python | `algebra/backend.py` | Pure Python by default; `core_rs` only when `CORE_BACKEND=rust` / `core_rs` is explicit. |
| Algebra kernel | Rust (PyO3) | `core-rs/src/lib.rs` | Active bindings: geometric product, closure-preserving versor apply, versor condition, CGA inner, exact vault recall, exp-map unitization, and diffusion step. |
| Tensor ops | MLX | `field/propagate.py` | Used for batched matmul and field tensor operations. Stays in UMA. |
**Zero-copy contract:**
- Python passes numpy arrays to Rust via PyO3 buffer protocol
- Rust reads into `[f32; 32]` stack arrays — one copy from Python heap to Rust stack
- Rust returns new `[f32; 32]` as numpy array — one copy from Rust stack to Python heap
- No intermediate heap allocation in the Rust kernel
- Scalar 32-component bindings validate contiguous arrays and copy into fixed
`[f32; 32]` / `[f64; 32]` stack arrays before the kernel
- Bulk bindings (`vault_recall`, `diffusion_step`) read contiguous numpy buffers
through `PyReadonlyArray` views without Python-list marshalling
- Return values are owned numpy arrays or Python tuples/lists at the API boundary
- No semantic state is mutated inside the Rust kernel
**GIL contract:**
- `vault_recall` (Rayon parallel scan) releases the GIL before entering Rayon and reacquires after
- All other Rust functions hold the GIL for the duration of the call (fast enough that release is not worth the overhead)
- Current PyO3 bindings hold the Python GIL for the duration of the call.
- Rayon-backed kernels do not call back into Python while scoring, but the binding
does not currently wrap the scan in an explicit `Python::allow_threads`.
- Any future GIL-release change is a performance change only and must preserve the
exact ordering and tie-break contracts.
---
@ -625,8 +635,14 @@ These are structural contracts, not regression tests. A failing invariant means
| `versor_apply` | 3× geometric_product | No allocation; entire sandwich product in one stack frame |
| `cga_inner` | O(32) | Called every token decode and every vault recall |
| `vault_recall` | O(N × 32) | Rayon parallel scan across N stored versors |
| `holonomy_encode` | O(2L × 32²) | 2L products for L-token prompt; replaces 2L Python dispatch calls |
| `propagate_batch` | O(B × 32²) | B parallel versor_apply for beam search |
| `diffusion_step` | O((N + E) × 32) | Zero-copy Rust step over field graph buffers; skipped explicitly when Rust is unavailable |
Python-canonical operations that are not Rust bindings today:
| Operation | Current status |
|---|---|
| `holonomy_encode` | Python-only; native port requires byte-for-byte parity with position-rotor/f64 construction semantics |
| `propagate_batch` | Not an active runtime surface; future native propagation must use closure-preserving `versor_apply` semantics |
**Build:**
```bash

View file

@ -89,7 +89,7 @@ Contract:
## Cross-references
- [ADR-0163 — Path to GSM8K mastery](decisions/ADR-0163-gsm8k-path-to-mastery.md)
- [ADR-0163 — Path to GSM8K mastery](adr/ADR-0163-gsm8k-path-to-mastery.md)
- [Phase A refusal taxonomy contract](../evals/refusal_taxonomy/contract.md)
- [ADR-0057 — Proposal review + replay-equivalence](decisions/ADR-0057-teaching-chain-proposal-review.md)
- [ADR-0161 — HITL async queue](decisions/ADR-0161-hitl-async-queue.md)
- [ADR-0057 — Proposal review + replay-equivalence](adr/ADR-0057-teaching-chain-proposal-review.md)
- [ADR-0161 — HITL async queue](adr/ADR-0161-hitl-async-queue.md)

View file

@ -189,7 +189,7 @@ a stated path.
*Schema impact* above, with the non-hardening invariant
test. This is a Phase 5 parallel-track item alongside Rust
parity.
- `docs/runtime_contracts.md` must add an *Epistemic surface*
- `docs/specs/runtime_contracts.md` must add an *Epistemic surface*
section documenting the four statuses, the non-hardening
invariant, and the curator review rule.
- Pack mutation review tooling must record curator

View file

@ -18,7 +18,7 @@ Today CORE runs two largely independent paths to produce a turn:
realize → generate (walk)`. The proposition is built by
`_nearest_content_word(vocab, prompt_versor)` — geometric-nearest
token selection wrapped in a frame. The walk afterward feeds
`walk_surface` (telemetry per `docs/runtime_contracts.md`).
`walk_surface` (telemetry per `docs/specs/runtime_contracts.md`).
2. **Semantic path** (`core/cognition/pipeline.py:68`): `classify_intent
→ graph_from_intent → plan_articulation → realize_semantic`. When
@ -481,7 +481,7 @@ with its own evidence.
- CLAUDE.md — non-negotiable field invariant, normalization
doctrine, surface contract, work sequencing.
- `docs/runtime_contracts.md` — surface vs walk_surface
- `docs/specs/runtime_contracts.md` — surface vs walk_surface
separation.
- ADR-0018 — typed deterministic operators, replay evidence.
- ADR-0019 — exact vault recall (no ANN — this ADR preserves

View file

@ -184,7 +184,7 @@ Wiring:
| `generate/stream.py` (threshold mode) | Per-candidate rotor check after destination admit; on reject, log rotor score in `rejected_attempts`, retry next candidate, escalate to `InnerLoopExhaustion` with `reason=ROTOR_REJECTION` on exhaustion (iff *any* rotor rejection occurred) |
| `generate/stream.py` (margin mode) | Rotor check on the top-ranked admissible candidate; on reject, immediate `InnerLoopExhaustion(reason=ROTOR_REJECTION)` carrying the destination ranking plus the rejected rotor's score |
| `generate/exhaustion.py` | `RefusalReason.ROTOR_REJECTION` enum member (Phase 2 plumbing carries it through traces unchanged) |
| `docs/runtime_contracts.md` | "Rotor admissibility contract" subsection documenting the seam, the algorithm, and the refusal taxonomy |
| `docs/specs/runtime_contracts.md` | "Rotor admissibility contract" subsection documenting the seam, the algorithm, and the refusal taxonomy |
The check itself:
@ -357,4 +357,4 @@ Phase 3. No trace-hash migration required.
* ADR-0026 — Ranked admissibility with margin (Phase 3)
* `generate/rotor_admissibility.py` — the module
* `tests/test_rotor_admissibility.py` — 11 tests pinning the contract
* `docs/runtime_contracts.md` §"Rotor admissibility contract"
* `docs/specs/runtime_contracts.md` §"Rotor admissibility contract"

View file

@ -2,7 +2,7 @@
**Status:** Accepted (2026-05-17)
**Author:** Joshua Shay + planner pass
**Companion docs:** [`identity_packs.md`](../identity_packs.md), [`ADR-0027-identity-packs.md`](ADR-0027-identity-packs.md), [`runtime_contracts.md`](../runtime_contracts.md)
**Companion docs:** [`identity_packs.md`](../identity_packs.md), [`ADR-0027-identity-packs.md`](ADR-0027-identity-packs.md), [`runtime_contracts.md`](../specs/runtime_contracts.md)
## Context

View file

@ -2,7 +2,7 @@
**Status:** Accepted (2026-05-17)
**Author:** Joshua Shay + planner pass
**Companion docs:** [`ADR-0028-surface-preferences.md`](../decisions), [`ADR-0036-safety-refusal-policy.md`](ADR-0036-safety-refusal-policy.md), [`ADR-0037-per-predicate-ethics-refusal.md`](ADR-0037-per-predicate-ethics-refusal.md)
**Companion docs:** [`ADR-0028-surface-preferences.md`](../adr), [`ADR-0036-safety-refusal-policy.md`](ADR-0036-safety-refusal-policy.md), [`ADR-0037-per-predicate-ethics-refusal.md`](ADR-0037-per-predicate-ethics-refusal.md)
## Context

View file

@ -257,8 +257,8 @@ tests/test_pack_resolver.py NEW (28 tests)
tests/test_cross_pack_grounding.py NEW (17 tests)
tests/test_pack_grounding.py 2 stale tests rewritten
tests/test_en_core_relations_v1_pack.py default-input test inverted
docs/decisions/ADR-0063-cross-pack-surface-resolver.md NEW (this file)
docs/decisions/README.md ADR-0063 index entry
docs/adr/ADR-0063-cross-pack-surface-resolver.md NEW (this file)
docs/adr/README.md ADR-0063 index entry
```
Lines of net change: small. The architectural unlock is in

View file

@ -202,8 +202,8 @@ teaching/discovery.py cross-corpus gat
teaching/replay.py swap-the-registry
teaching/relations_chains/relations_chains_v1.jsonl NEW (seed corpus, 7 chains)
tests/test_relations_chains_v1.py NEW (17 tests)
docs/decisions/ADR-0064-cross-pack-teaching-chains.md NEW (this file)
docs/decisions/README.md index entry
docs/adr/ADR-0064-cross-pack-teaching-chains.md NEW (this file)
docs/adr/README.md index entry
docs/curriculum/relations_chains_v1.md NEW (curriculum unit doc)
```

View file

@ -183,7 +183,7 @@ tests/test_oov_surface.py NEW (22 tests)
tests/test_partial_surface.py NEW (16 tests)
tests/test_oov_pipeline.py NEW (24 tests)
tests/test_en_core_relations_v2_pack.py NEW (10 tests)
docs/decisions/ADR-0065-oov-gradient-and-relations-v2.md NEW (this file)
docs/adr/ADR-0065-oov-gradient-and-relations-v2.md NEW (this file)
```
---

View file

@ -211,8 +211,8 @@ generate/intent.py NARRATIVE / EXAMPLE enu
tests/test_thread_context.py NEW (20 tests)
tests/test_anaphora.py NEW (12 tests)
tests/test_narrative_example_intents.py NEW (30 tests)
docs/decisions/ADR-0066-turn-level-composition.md NEW (this file)
docs/decisions/README.md ADR-0066 index entry
docs/adr/ADR-0066-turn-level-composition.md NEW (this file)
docs/adr/README.md ADR-0066 index entry
```
---

Some files were not shown because too many files have changed in this diff Show more