feat(kernel): add foundational family registry schema
This commit is contained in:
parent
5cd377b1b8
commit
02bb80dce1
3 changed files with 549 additions and 0 deletions
|
|
@ -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.
|
- **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.
|
- **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
|
||||||
|
|
|
||||||
294
generate/foundational_families.py
Normal file
294
generate/foundational_families.py
Normal 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",
|
||||||
|
)
|
||||||
159
tests/test_foundational_families.py
Normal file
159
tests/test_foundational_families.py
Normal 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)
|
||||||
Loading…
Reference in a new issue