Compare commits
9 commits
main
...
chore/refa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b37d439e2 | ||
|
|
9303cbc31a | ||
|
|
dd52f14fce | ||
|
|
cff3781d7c | ||
|
|
e96bc46ecf | ||
|
|
f9dc1cd71b | ||
|
|
c146ea315a | ||
|
|
7f177bbb17 | ||
|
|
c32b0db6a9 |
279 changed files with 4865 additions and 3177 deletions
30
AGENTS.md
30
AGENTS.md
|
|
@ -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
|
||||
|
|
|
|||
37
CLAUDE.md
37
CLAUDE.md
|
|
@ -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 repo’s handoff template and current naming convention.
|
||||
Do not place architecture, invariants, memory rules, or alternate workflow
|
||||
policy here. Update `AGENTS.md` instead.
|
||||
|
|
|
|||
37
GEMINI.md
37
GEMINI.md
|
|
@ -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 repo’s handoff template and current naming convention.
|
||||
Do not place architecture, invariants, memory rules, or alternate workflow
|
||||
policy here. Update `AGENTS.md` instead.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
54
README.md
54
README.md
|
|
@ -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 1–4
|
||||
First](docs/adr/ADR-0114-expert-capability-roadmap-gsm8k-first.md). Phases 1–4
|
||||
(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
17
calibration/README.md
Normal 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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
19
conftest.py
19
conftest.py
|
|
@ -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
17
contemplation/README.md
Normal 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.
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) -------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
|||
2837
core/cli.py
2837
core/cli.py
File diff suppressed because it is too large
Load diff
435
core/cli_capability.py
Normal file
435
core/cli_capability.py
Normal 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
77
core/cli_doctor.py
Normal 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
263
core/cli_eval.py
Normal 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
232
core/cli_ingest.py
Normal 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
84
core/cli_pack.py
Normal 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
144
core/cli_rust.py
Normal 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
1358
core/cli_teaching.py
Normal file
File diff suppressed because it is too large
Load diff
260
core/cli_test.py
Normal file
260
core/cli_test.py
Normal 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
14
core/demos/README.md
Normal 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
16
core_ingest/README.md
Normal 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
15
demos/README.md
Normal 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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
33
docs/RUST.md
33
docs/RUST.md
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue