core/language_packs/schema.py
Shay 0390491c93 feat(packs): implement ADR-0097 — Mathematics-Logic Reasoning-Capable
First concrete domain claim under ADR-0091's Domain Pack Contract v1.
en_mathematics_logic_v1 is now formally ratified as reasoning-capable
in the capability ledger: 9/9 ADR-0091 predicates pass.

ADR-0097 §"No code changes outside pack artifacts and corpus" relaxed
to include two latent bug fixes that ADR-0093's predicate enforcement
just exposed:

1. language_packs/schema.py: LanguageRole enum widened to include
   DOMAIN_SEED. Three in-tree packs (en_mathematics_logic_v1,
   en_physics_v1, en_systems_software_v1) have declared role="domain_seed"
   since landing but the enum was never updated; load_pack() always
   raised on them. ADR-0093's P1 predicate exposed the mismatch.

2. core/capability/domain_contract_predicates.py: P2 (gloss checksum)
   was reading manifest["checksums"]["glosses_sha256"]; the canonical
   in-tree location is manifest["glosses_checksum"] (top-level). Fixed
   to prefer the canonical key and fall back to the nested form for
   forward compatibility.

ADR-0097 manifest additions to en_mathematics_logic_v1:
- domain_contract_version: 1
- domain_id: "mathematics_logic"
- axioms: null  (rules in v1 — pack proves reasoning via chain
  composition, not declarative axioms)
- rules: null
- teaching_chains: ["mathematics_logic_chains_v1"]
- eval_lanes: three lanes with dev/public/holdout (elementary_mathematics_ood,
  inference_closure, fabrication_control)
- reviewers: ["shay-j"] (resolved via ADR-0092 registry)
- known_gaps: [] (all math/logic gaps in docs/gaps.md were [x])
- provenance: "adr-0097:reviewed:2026-05-21"

Verified evidence:
- core capability domain-contract --pack-id en_mathematics_logic_v1
  → all_passed=True (P1-P9 all pass)
- core capability ledger → mathematics_logic row shows
  status=reasoning-capable, predicates.reasoning_capable=True,
  predicates.expert_demo=False, open_gaps=[],
  operator_chain_coverage all ready=True (8 chains each),
  intent_shapes_present=5
- 14 ADR-0097 invariant tests in
  test_adr_0097_mathematics_logic_ratification.py pin
  status/provenance/expert-demo-gate/contract shape

Two pre-existing tests updated for the new CLI default
(predicate-running, non-zero on missing contract):
- test_capability_domain_contract_json_absent_contract_is_noop now
  uses --structural-only to assert legacy parse-only shape
- test_cli_returns_nonzero_on_missing_contract switched its fixture
  pack from en_mathematics_logic_v1 (now has a contract) to
  en_core_cognition_v1 (no contract)

The pre-existing test_flag_report_tracks_default_off_flags failure
(discourse_planner flag default mismatch, seen since ADR-0092) is
unchanged and unrelated.

Smoke 67/67, packs 6/6, capability tests 49/50, cognition eval
byte-identical 100/100/100/100; lanes byte-identical:
reviewer_registry 6/6, miner_loop_closure 6/6,
domain_contract_validation 9/9, fabrication_control dev 12/12 +
public 9/9.
2026-05-21 18:51:58 -07:00

202 lines
7.2 KiB
Python

"""
Schemas for CORE compiled linguistic manifolds.
A language pack is not a dataset. It is a deterministic, checksummed,
compiled linguistic manifold: lexical surfaces, morphology, grammar
attractors, cross-language resonances, and holonomy-level proof cases.
These schemas intentionally do not load corpora. They define the contract the
Supervised Seeding Epoch must satisfy before Hebrew and Koine Greek gates can
engage.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Mapping, Sequence
class LanguageRole(str, Enum):
"""Architectural role of a language pack in CORE-Logos."""
OPERATIONAL_BASE = "operational_base"
ARTICULATION_SURFACE = "articulation_surface"
DEPTH_ROOT = "depth_root"
DEPTH_RELATION = "depth_relation"
# ADR-0097 — added to recognize the domain-pack role used by
# en_mathematics_logic_v1, en_physics_v1, en_systems_software_v1.
# These packs declared role="domain_seed" since landing but the
# enum was never widened; ADR-0093's P1 predicate exposed the
# latent mismatch.
DOMAIN_SEED = "domain_seed"
class OOVPolicy(str, Enum):
"""Out-of-vocabulary behavior for a pack."""
FAIL_CLOSED = "fail_closed"
TAGGED_FALLBACK = "tagged_fallback"
PROPOSE_VOCAB_EXPANSION = "propose_vocab_expansion"
@dataclass(frozen=True, slots=True)
class LanguagePackManifest:
"""Pinned manifest for one compiled language pack."""
pack_id: str
language: str
role: LanguageRole
script: str
normalization_policy: str
source_manifest: str
determinism_class: str
checksum: str
version: str = "1.0.0"
gate_engaged: bool = False
oov_policy: OOVPolicy = OOVPolicy.FAIL_CLOSED
# Optional dual-checksum for the companion ``glosses.jsonl`` file.
# When present, the loader verifies the bytes-on-disk match this
# SHA-256 just like the lexicon checksum. Absent on legacy packs
# that ship no glosses (back-compat — never raised in that case).
# Glosses are an additive overlay; bumping ``glosses_checksum`` does
# NOT perturb the immutable ``checksum`` (lexicon seal).
glosses_checksum: str | None = None
# ADR-0084 — pack-level opt-in for the definitional layer. When
# True, every gloss entry must carry the extended schema
# (``definitional_atoms``, ``predicates_invited``,
# ``definition_version``) and pass the closure rule. Default False
# leaves every existing pack byte-identical.
definitional_layer: bool = False
def __post_init__(self) -> None:
if not self.pack_id:
raise ValueError("LanguagePackManifest.pack_id is required.")
if not self.language:
raise ValueError("LanguagePackManifest.language is required.")
if not self.checksum:
raise ValueError("LanguagePackManifest.checksum is required.")
if self.role in {LanguageRole.DEPTH_ROOT, LanguageRole.DEPTH_RELATION}:
if self.gate_engaged and self.oov_policy is not OOVPolicy.FAIL_CLOSED:
raise ValueError(
"Depth packs must fail closed while gate_engaged=True; "
"unknown Hebrew/Greek surfaces must not collapse to a fallback point."
)
@dataclass(frozen=True, slots=True)
class MorphologyEntry:
"""
Morphological decomposition for a surface form.
Ordering is load-bearing. For Semitic root morphology and Koine grammar,
non-commutative composition means prefix/stem/inflection/suffix order must
be preserved exactly.
"""
morphology_id: str
surface: str
lemma: str
language: str
root: str | None = None
prefix_chain: tuple[str, ...] = field(default_factory=tuple)
stem: str | None = None
inflection: Mapping[str, str] = field(default_factory=dict)
suffix_chain: tuple[str, ...] = field(default_factory=tuple)
def __post_init__(self) -> None:
if not self.morphology_id:
raise ValueError("MorphologyEntry.morphology_id is required.")
if not self.surface:
raise ValueError("MorphologyEntry.surface is required.")
if not self.lemma:
raise ValueError("MorphologyEntry.lemma is required.")
if not self.language:
raise ValueError("MorphologyEntry.language is required.")
@dataclass(frozen=True, slots=True)
class LexicalEntry:
"""One surface/lemma entry in a compiled linguistic manifold.
`epistemic_status` follows ADR-0021: it is a *position in the
revision graph*, not a source-trust tier. The default is
``"speculative"`` per ADR-0021 §Schema impact: "transitions to
COHERENT / CONTESTED / FALSIFIED only via the review path." A pack
lexicon row that wants to be admissible as evidence
(``ADMISSIBLE_AS_EVIDENCE``) must declare
``"epistemic_status": "coherent"`` explicitly; the declaration is
itself the curator's stamp. Pack authority alone is not coherence
judgment — defaulting unmarked rows to COHERENT would re-import the
bias ADR-0021 refuses (see ``docs/truth_seeking_schema.md`` §1).
"""
entry_id: str
surface: str
lemma: str
language: str
part_of_speech: str | None = None
pos: str | None = None
morphology_id: str | None = None
morphology_tags: tuple[str, ...] = field(default_factory=tuple)
semantic_domains: tuple[str, ...] = field(default_factory=tuple)
manifold_point_checksum: str | None = None
provenance_ids: tuple[str, ...] = field(default_factory=tuple)
epistemic_status: str = "speculative"
@dataclass(frozen=True, slots=True)
class GrammarAttractor:
"""
Structural grammar attractor seeded into the shared manifold.
Morphology is operator composition. Semantic domain is attractor geometry.
Alignment is resonance. This class represents the attractor layer only.
"""
attractor_id: str
language: str
role: str
description: str
operator_order: tuple[str, ...] = field(default_factory=tuple)
checksum: str | None = None
@dataclass(frozen=True, slots=True)
class AlignmentEdge:
"""Weighted directional resonance between entries or concepts."""
source_id: str
target_id: str
relation: str
weight: float
evidence_ids: tuple[str, ...] = field(default_factory=tuple)
def __post_init__(self) -> None:
if not 0.0 <= self.weight <= 1.0:
raise ValueError("AlignmentEdge.weight must be in [0, 1].")
@dataclass(frozen=True, slots=True)
class HolonomyAlignmentCase:
"""
Crown proof case for the three-language design.
The language system succeeds when aligned canonical clauses produce nearby
holonomies without flattening their distinctions. This is not token-level
translation; it is dynamic field-path resonance.
"""
case_id: str
description: str
source_refs: tuple[str, ...]
pack_ids: tuple[str, ...]
expected_relation: str
negative_source_refs: tuple[str, ...] = field(default_factory=tuple)
tolerance: float | None = None
def __post_init__(self) -> None:
if len(self.source_refs) < 2:
raise ValueError("HolonomyAlignmentCase requires at least two source_refs.")
if len(self.pack_ids) < 2:
raise ValueError("HolonomyAlignmentCase requires at least two pack_ids.")