feat(kernel): add foundational family registry schema

This commit is contained in:
Shay 2026-06-20 14:42:21 -07:00
parent 5cd377b1b8
commit 02bb80dce1
3 changed files with 549 additions and 0 deletions

View file

@ -279,3 +279,99 @@ The substantive result of this session is not just “0005 runnable.” It is th
- **Versor condition**: No geometric algebra files were touched; versor invariants remain fully satisfied.
- **Docs-Only Scope**: Verified that all changes are purely documentation additions or comments, with no runtime code or test suite modifications.
---
## PR #840 Addendum — feat(kernel): add foundational family registry schema
### Agent and Session
- **Agent:** gpt55
- **Date:** 2026-06-20
- **Reasoning effort used:** medium
- **Grok Build mode used:** Headless
- **Session entry point:** Implement the typed, read-only foundational-family registry schema for the two #839 specifications without adding recognition, assessment, routing, solving, or serving behavior.
- **Branch:** `feat/kernel-foundational-family-registry-schema`
- **Base:** `origin/main` at `5cd377b1b8169826ea2406a93136b7615c616286`
### Smoke Suite + Bootstrap Status
```text
uv run python -m core.cli test --suite smoke -q
108 passed in 123.94s (baseline)
108 passed in 131.98s (post-edit)
```
`core-bootstrap` was not available as a skill; the GPT55.md checklist was completed manually. The acknowledged dirty/diverged `/Users/kaizenpro/Projects/core` main worktree was not modified, stashed, reset, cleaned, or reconciled.
### Modules Touched
| File | Change type | Summary |
|---|---|---|
| `generate/foundational_families.py` | new | Frozen specification/evidence records, two manually mirrored unauthorized family specs, immutable indices, and public accessors. |
| `tests/test_foundational_families.py` | new | Public-API invariant tests for exact registry membership/order, uniqueness, immutability, required fields, cross-domain evidence, authorization gates, and absence of file/Markdown loading. |
| `HANDOFF-gpt55-2026-06-20.md` | modified | Added this PR #840 continuity record. |
### Invariants Verified
- **Field closure:** Preserved by construction. No algebra, field, propagation, vault, normalization, or runtime field-state path was imported or modified.
- **Exact recall:** Preserved. No CGA lookup, cosine, ANN, HNSW, or memory path was added.
- **Serving and implementation gates:** Both families explicitly carry `serving_allowed=False` and `implementation_authorized=False`; tests enforce both gates.
- **No behavior slice:** The module is unreferenced by runtime code and provides descriptive immutable metadata only. No parser, recognizer, adapter, `ContractAssessment`, routing, derivation, eval, report, or serving behavior was added.
- **No live-substrate claim:** Module and current-state text explicitly state that general substrate/CGA retrieval is not live for these families.
- **No universal IR:** The schema mirrors only ADR-0224/#839 specification fields and contains only the two authorized registry entries.
- **Determinism:** Registry iteration is an explicit immutable tuple; family IDs and primary relation types are unique and tested.
### Subagent / Arena Reconciliation
- Number of subagents spawned: 0
- Each subagent independently verified versor closure: N/A
- Reconciliation: N/A
### Tests Run
```bash
# exit 0 — 13 passed
uv run python -m pytest -q \
tests/test_foundational_families.py \
tests/test_construction_affordances.py
# exit 0 — 108 passed
uv run python -m core.cli test --suite smoke -q
# exit 0
python3 -m compileall -q \
generate/foundational_families.py \
tests/test_foundational_families.py
# exit 0
git diff --check
```
### Open Tasks / Next Session Entry Point
1. Review and publish PR #840 with the required body sections from the implementation brief.
2. Do not connect this registry to `ProblemFrame`, `ContractAssessment`, proposal routing, recognition, adapters, or serving without a separately authorized behavior PR.
### Known Hazards / Do Not Touch
- The two #839 specifications are gating artifacts, not implementation authorization.
- Do not parse `docs/specs/foundational-families/*.md` at runtime.
- Do not add acquisition, transaction, another family, or a universal family IR in this slice.
- The acknowledged local-only state under `/Users/kaizenpro/Projects/core` remains outside this PR and must not be altered.
### Architectural Decision
The foundational registry remains separate from `ConstructionFamily`. The latter describes live diagnostic construction proposals; this schema mirrors constitutional family gates. Combining them would falsely couple specification completeness to executable assessment machinery and blur current versus target state.
### What Must Not Be Forgotten
PR #840 makes the family-spec gate structurally inspectable; it authorizes nothing. Both entries remain non-serving and non-implementable until a separate evidence-backed PR is approved.
### Skills Used
- core-bootstrap: unavailable; checklist completed manually
- versor-coherence-guardian: unavailable; closure preserved by scope and smoke validation
- pre-edit-sweep: completed manually across imports/call sites in `generate/`, `tests/`, `evals/`, and `calibration/`
- claim-proposal-guardian: not needed; no claim or proposal mutation path touched
- Other: none

View file

@ -0,0 +1,294 @@
"""Read-only registry of approved foundational-family specifications.
This module manually mirrors the constitutional family specifications approved
under ADR-0224. It is descriptive metadata only: it does not read specification
documents, recognize constructions, assess ``ProblemFrame`` contracts, route
proposals, or authorize implementation or serving.
The current registry deliberately contains only the two specifications approved
by the initial family-spec gate. General substrate/CGA retrieval for these
families is not live.
"""
from __future__ import annotations
from dataclasses import dataclass
from types import MappingProxyType
@dataclass(frozen=True, slots=True)
class FoundationalDomainEvidence:
"""One cross-domain example declared by a foundational-family spec."""
domain: str
example: str
expected_roles: tuple[str, ...]
@dataclass(frozen=True, slots=True)
class FoundationalFamilySpec:
"""Immutable descriptive mirror of an approved family specification.
The fields state the future contract shape and its constitutional gates.
They do not implement recognition, binding, assessment, verification, or
serving behavior.
"""
family_id: str
display_name: str
status: str
related_adrs: tuple[str, ...]
domains: tuple[str, ...]
summary: str
surface_chunk_patterns: tuple[str, ...]
semantic_neighborhood: tuple[str, ...]
construction_signatures: tuple[str, ...]
required_roles: tuple[str, ...]
optional_roles: tuple[str, ...]
hazards_confusers: tuple[str, ...]
frame_representation: tuple[str, ...]
contract_readiness_criteria: tuple[str, ...]
verification_style: tuple[str, ...]
refusal_conditions: tuple[str, ...]
cross_domain_evidence: tuple[FoundationalDomainEvidence, ...]
current_state: str
target_state: str
serving_status: str
serving_allowed: bool
implementation_authorized: bool
primary_relation_type: str
future_adapter: str | None = None
_QUANTITY_ENTITY_BINDING = FoundationalFamilySpec(
family_id="binding.quantity_entity",
display_name="Quantity-Entity Binding",
status="Proposed (gating specification)",
related_adrs=("ADR-0223", "ADR-0224"),
domains=(
"arithmetic_quantitative",
"physical_science",
"charts_tables_data",
"social_studies",
),
summary=(
"Binds a grounded scalar quantity to the entity, object, category, or "
"measured property that it quantifies."
),
surface_chunk_patterns=(
"<number> <noun>",
"<number> of the <noun>",
"<noun>: <number>",
"<number> <unit> of <material>",
),
semantic_neighborhood=(
"quantified_group",
"measured_property",
"category_cardinality",
"resource_population",
),
construction_signatures=("quantity_entity_binding",),
required_roles=("quantity", "entity"),
optional_roles=("unit",),
hazards_confusers=(
"PF-EN-002 quantity_entity_unbound",
"PF-LX-004 span_collision",
"PF-EN-005 role_alias_collision",
"PF-HZ-005 conflict_auto_resolved",
),
frame_representation=(
"GroundedMention for the quantity and entity spans",
"MentionBinding(binding_type='quantity_entity') from quantity to entity",
"Optional MentionBinding(binding_type='quantity_unit') from quantity to unit",
),
contract_readiness_criteria=(
"Quantity is grounded to an exact parsed scalar.",
"Entity is grounded to a valid noun phrase or category span.",
"No active overlap or scalar span collision remains.",
"No unresolved quantity-entity hazard remains.",
"Independent verification and wrong-zero preservation are required before serving.",
),
verification_style=(
"Lexical-substitution invariance must preserve binding topology modulo spans.",
"Comparative confusers must not be accepted as generic quantity-entity bindings.",
),
refusal_conditions=(
"Ambiguous referents remain unresolved while multiple entity candidates are active.",
"Overlapping scalar spans cannot be deterministically ordered.",
),
cross_domain_evidence=(
FoundationalDomainEvidence(
domain="physical_science",
example="A block of iron has a mass of 12 grams.",
expected_roles=("quantity", "entity", "unit"),
),
FoundationalDomainEvidence(
domain="charts_tables_data",
example="The bar graph shows: Apples: 15, Bananas: 8.",
expected_roles=("quantity", "entity"),
),
FoundationalDomainEvidence(
domain="social_studies",
example="The town of Shelbyville has a population of 50,000 residents.",
expected_roles=("quantity", "entity"),
),
),
current_state=(
"Not implemented as a general family. Local parser heuristics and selected "
"math diagnostic proposal traces exist; general substrate/CGA retrieval does not."
),
target_state=(
"Proposal-first quantity-entity binding with span grounding, contract assessment, "
"independent verification, and cross-domain evidence."
),
serving_status="Not implemented / not serving.",
serving_allowed=False,
implementation_authorized=False,
primary_relation_type="quantity_entity",
future_adapter="quantity_entity_adapter",
)
_STATE_CHANGE = FoundationalFamilySpec(
family_id="state_change.transition",
display_name="State Change",
status="Proposed (gating specification)",
related_adrs=("ADR-0223", "ADR-0224"),
domains=(
"arithmetic_proportional",
"physical_science",
"life_science",
"reading_comprehension",
"procedural_reasoning",
),
summary=(
"Represents an entity or system transitioning from an initial state to a "
"final state through an event, action, or process."
),
surface_chunk_patterns=(
"<verb-change> to <value>",
"<verb-change> by <value>",
"originally <value>, now <value>",
"after <event>, <actor> has <value>",
),
semantic_neighborhood=(
"possession_change",
"proportional_scaling",
"temperature_transition",
"growth_stage",
"procedural_step",
),
construction_signatures=("state_change",),
required_roles=("entity", "initial_state", "transition_event", "final_state"),
optional_roles=("scale", "delta"),
hazards_confusers=(
"PF-BD-004 positional_binding",
"PF-TG-004 target_direction_unknown",
"PF-TP-006 state_transition_open",
"PF-HZ-003 hazard_ignored_by_contract",
),
frame_representation=(
"BoundRelation(relation_type='state_change')",
"RelationRole bindings for entity, initial_state, transition, and final_state",
"Optional RelationRole bindings for scale or delta",
"Exact SourceSpan evidence for the proposed transition",
),
contract_readiness_criteria=(
"The changing entity is bound with continuity across the transition span.",
"Transition direction is explicitly resolved from grounded evidence.",
"The question target names a mathematically closed variable.",
"No unresolved 'by' versus 'to' directional hazard remains.",
"Independent verification and wrong-zero preservation are required before serving.",
),
verification_style=(
"Validate the applicable state equation over grounded roles.",
"Changing 'decreased to' to 'decreased by' must require rebinding and reverification.",
),
refusal_conditions=(
"Event order is missing or temporally ambiguous.",
"The transition is open because initial, delta, and final values cannot close a target.",
),
cross_domain_evidence=(
FoundationalDomainEvidence(
domain="physical_science",
example="Water originally at 20 degrees Celsius is heated to 80 degrees Celsius.",
expected_roles=("entity", "initial_state", "transition_event", "final_state"),
),
FoundationalDomainEvidence(
domain="life_science",
example="The plant grew from 5 inches tall to 9 inches tall over the summer.",
expected_roles=("entity", "initial_state", "transition_event", "final_state"),
),
FoundationalDomainEvidence(
domain="reading_comprehension",
example=(
"Before the storm, the streets were dry. After the storm, the streets "
"were flooded."
),
expected_roles=("entity", "initial_state", "transition_event", "final_state"),
),
FoundationalDomainEvidence(
domain="procedural_reasoning",
example="Step 1: Set X to 10. Step 2: Decrement X by 2.",
expected_roles=("entity", "initial_state", "transition_event", "delta"),
),
),
current_state=(
"Selected math constructions have assessment-backed diagnostic proposal traces. "
"A general state-change adapter and non-math serving frames do not exist."
),
target_state=(
"Proposal-first state-change binding with role-complete contract assessment, "
"independent verification, typed refusal, and cross-domain evidence."
),
serving_status="Not implemented / not serving.",
serving_allowed=False,
implementation_authorized=False,
primary_relation_type="state_change",
future_adapter="state_change_adapter",
)
_FAMILIES = (_QUANTITY_ENTITY_BINDING, _STATE_CHANGE)
_BY_ID = MappingProxyType({family.family_id: family for family in _FAMILIES})
_BY_RELATION_TYPE = MappingProxyType(
{family.primary_relation_type: family for family in _FAMILIES}
)
def iter_foundational_families() -> tuple[FoundationalFamilySpec, ...]:
"""Return all approved foundational-family specs in deterministic order."""
return _FAMILIES
def get_foundational_family(family_id: str) -> FoundationalFamilySpec | None:
"""Return the registered spec for ``family_id``, if present."""
return _BY_ID.get(family_id)
def require_foundational_family(family_id: str) -> FoundationalFamilySpec:
"""Return the registered spec or raise ``KeyError`` with a clear identifier."""
family = get_foundational_family(family_id)
if family is None:
raise KeyError(f"unknown foundational family: {family_id!r}")
return family
def get_foundational_family_by_relation_type(
relation_type: str,
) -> FoundationalFamilySpec | None:
"""Return the spec whose primary relation type matches ``relation_type``."""
return _BY_RELATION_TYPE.get(relation_type)
__all__ = (
"FoundationalDomainEvidence",
"FoundationalFamilySpec",
"get_foundational_family",
"get_foundational_family_by_relation_type",
"iter_foundational_families",
"require_foundational_family",
)

View file

@ -0,0 +1,159 @@
from __future__ import annotations
import ast
from dataclasses import FrozenInstanceError
from pathlib import Path
import pytest
import generate.foundational_families as foundational_families
from generate.foundational_families import (
FoundationalFamilySpec,
get_foundational_family,
get_foundational_family_by_relation_type,
iter_foundational_families,
require_foundational_family,
)
EXPECTED_FAMILY_IDS = (
"binding.quantity_entity",
"state_change.transition",
)
def test_registry_contains_only_the_two_approved_specs_in_deterministic_order() -> None:
families = iter_foundational_families()
assert isinstance(families, tuple)
assert tuple(family.family_id for family in families) == EXPECTED_FAMILY_IDS
assert tuple(family.family_id for family in iter_foundational_families()) == (
EXPECTED_FAMILY_IDS
)
def test_public_family_accessors() -> None:
quantity = get_foundational_family("binding.quantity_entity")
state_change = require_foundational_family("state_change.transition")
assert quantity is not None
assert quantity.family_id == "binding.quantity_entity"
assert state_change.family_id == "state_change.transition"
assert get_foundational_family("missing.family") is None
with pytest.raises(KeyError, match="missing.family"):
require_foundational_family("missing.family")
def test_lookup_by_primary_relation_type() -> None:
quantity = get_foundational_family_by_relation_type("quantity_entity")
state_change = get_foundational_family_by_relation_type("state_change")
assert quantity is get_foundational_family("binding.quantity_entity")
assert state_change is get_foundational_family("state_change.transition")
assert get_foundational_family_by_relation_type("missing_relation") is None
def test_registry_keys_are_unique() -> None:
families = iter_foundational_families()
family_ids = tuple(family.family_id for family in families)
relation_types = tuple(family.primary_relation_type for family in families)
assert len(family_ids) == len(set(family_ids))
assert len(relation_types) == len(set(relation_types))
def test_specs_are_frozen_and_explicitly_not_authorized() -> None:
for family in iter_foundational_families():
assert isinstance(family, FoundationalFamilySpec)
assert family.serving_allowed is False
assert family.implementation_authorized is False
assert "not serving" in family.serving_status.lower()
with pytest.raises(FrozenInstanceError):
family.display_name = "mutated" # type: ignore[misc]
def test_required_adr_0224_fields_are_populated() -> None:
required_fields = (
"family_id",
"display_name",
"status",
"related_adrs",
"domains",
"summary",
"surface_chunk_patterns",
"semantic_neighborhood",
"construction_signatures",
"required_roles",
"optional_roles",
"hazards_confusers",
"frame_representation",
"contract_readiness_criteria",
"verification_style",
"refusal_conditions",
"cross_domain_evidence",
"current_state",
"target_state",
"serving_status",
"primary_relation_type",
"future_adapter",
)
for family in iter_foundational_families():
assert all(getattr(family, field) for field in required_fields)
assert "ADR-0224" in family.related_adrs
assert family.hazards_confusers
assert family.refusal_conditions
assert family.current_state != family.target_state
def test_each_family_has_at_least_two_non_math_evidence_examples() -> None:
math_domains = {
"arithmetic",
"arithmetic_quantitative",
"arithmetic_proportional",
"mathematics",
}
for family in iter_foundational_families():
non_math_evidence = tuple(
evidence
for evidence in family.cross_domain_evidence
if evidence.domain not in math_domains
)
assert len(non_math_evidence) >= 2
assert all(evidence.example for evidence in non_math_evidence)
assert all(evidence.expected_roles for evidence in non_math_evidence)
def test_registry_module_has_no_markdown_or_filesystem_loading_surface() -> None:
source_path = Path(foundational_families.__file__)
tree = ast.parse(source_path.read_text(encoding="utf-8"))
imported_modules = {
alias.name
for node in ast.walk(tree)
if isinstance(node, ast.Import)
for alias in node.names
}
imported_from_modules = {
node.module
for node in ast.walk(tree)
if isinstance(node, ast.ImportFrom) and node.module is not None
}
called_names = {
node.func.id
for node in ast.walk(tree)
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name)
}
called_attributes = {
node.func.attr
for node in ast.walk(tree)
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute)
}
assert "pathlib" not in imported_modules | imported_from_modules
assert "markdown" not in imported_modules | imported_from_modules
assert "open" not in called_names
assert not ({"read_text", "read_bytes"} & called_attributes)