feat(packs): en_core_attitude_v1 — adjective pack (40 lemmas)

Workstream 1 second pack.  Closes the ADJ POS gap — prior to this pack
zero adjectives existed in any mounted English content pack, so the
runtime could not emit grounded surfaces for predicative queries like
"What is true?" or "What is important?".

Pack composition (40 ADJ entries):

  attitude.truth_value.*   (8)  true false valid invalid accurate
                                inaccurate factual sound
  attitude.evaluative.*    (6)  good bad right better worse best
  attitude.epistemic.*    (10)  certain uncertain possible impossible
                                likely unlikely probable clear obscure
                                evident
  attitude.modal.*         (4)  necessary sufficient required optional
  attitude.importance.*    (6)  important essential relevant central
                                primary useful
  attitude.scope.*         (6)  general specific broad narrow universal
                                particular

Files:
  language_packs/data/en_core_attitude_v1/
    lexicon.jsonl   — 40 entries, SHA-256 checksum-sealed
    manifest.json   — operational_base / D0 / checksum-verified
  chat/pack_resolver.py
    Appended to DEFAULT_RESOLVABLE_PACK_IDS after cognition + meta.
  core/config.py
    Added to RuntimeConfig.input_packs default mount.
  tests/test_en_core_attitude_v1_pack.py
    11 contract tests: checksum, POS=ADJ uniformity, primary-domain
    namespace, no-collision regression gate against all 4 prior packs,
    contiguous entry_ids, mounted-by-default, resolver-order invariant,
    routing correctness, and cognition+meta resolution unchanged.

Authoring:
  Three parallel subagents (1 per cluster) — truth/eval, epistemic/modal,
  importance/scope.  Strict exemplar + forbidden-lemma list against all
  prior packs.  Main pass assembled, validated, sealed.

Verification:
  Full lane: 2159 passed, 2 skipped, 0 failed (+11 new tests over the
  previous 2148 baseline).
  Cognition eval byte-identical on both splits:
    public  100 / 100 / 91.7 / 100
    holdout 100 / 100 / 83.3 / 100
  Live composer probes: every ADJ lemma emits a deterministic
  pack-grounded surface from en_core_attitude_v1.
This commit is contained in:
Shay 2026-05-18 19:52:27 -07:00
parent a376a30bf8
commit f074ba729e
5 changed files with 210 additions and 0 deletions

View file

@ -43,6 +43,7 @@ from pathlib import Path
DEFAULT_RESOLVABLE_PACK_IDS: tuple[str, ...] = ( DEFAULT_RESOLVABLE_PACK_IDS: tuple[str, ...] = (
"en_core_cognition_v1", "en_core_cognition_v1",
"en_core_meta_v1", "en_core_meta_v1",
"en_core_attitude_v1",
"en_core_relations_v1", "en_core_relations_v1",
"en_core_relations_v2", "en_core_relations_v2",
) )

View file

@ -14,6 +14,7 @@ class RuntimeConfig:
"en_minimal_v1", "en_minimal_v1",
"en_core_cognition_v1", "en_core_cognition_v1",
"en_core_meta_v1", "en_core_meta_v1",
"en_core_attitude_v1",
"en_core_relations_v1", "en_core_relations_v1",
"en_core_relations_v2", "en_core_relations_v2",
"he_logos_micro_v1", "he_logos_micro_v1",

View file

@ -0,0 +1,40 @@
{"entry_id":"en-core-attitude-001","surface":"true","lemma":"true","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.true","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-002","surface":"false","lemma":"false","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.false","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-003","surface":"valid","lemma":"valid","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.true","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-004","surface":"invalid","lemma":"invalid","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.false","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-005","surface":"accurate","lemma":"accurate","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.true","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-006","surface":"inaccurate","lemma":"inaccurate","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.false","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-007","surface":"factual","lemma":"factual","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.true","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-008","surface":"sound","lemma":"sound","language":"en","pos":"ADJ","semantic_domains":["attitude.truth_value.true","attitude.truth_value","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-009","surface":"good","lemma":"good","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.positive","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-010","surface":"bad","lemma":"bad","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.negative","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-011","surface":"right","lemma":"right","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.positive","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-012","surface":"better","lemma":"better","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.positive","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-013","surface":"worse","lemma":"worse","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.negative","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-014","surface":"best","lemma":"best","language":"en","pos":"ADJ","semantic_domains":["attitude.evaluative.positive","attitude.evaluative","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-015","surface":"certain","lemma":"certain","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.certainty","attitude.epistemic","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-016","surface":"uncertain","lemma":"uncertain","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.uncertainty","attitude.epistemic","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-017","surface":"possible","lemma":"possible","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.possibility","attitude.epistemic","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-018","surface":"impossible","lemma":"impossible","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.impossibility","attitude.epistemic","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-019","surface":"likely","lemma":"likely","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.possibility","attitude.epistemic","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-020","surface":"unlikely","lemma":"unlikely","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.impossibility","attitude.epistemic","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-021","surface":"probable","lemma":"probable","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.possibility","attitude.epistemic","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-022","surface":"clear","lemma":"clear","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.certainty","attitude.epistemic","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-023","surface":"obscure","lemma":"obscure","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.uncertainty","attitude.epistemic","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-024","surface":"evident","lemma":"evident","language":"en","pos":"ADJ","semantic_domains":["attitude.epistemic.certainty","attitude.epistemic","cognition.epistemic"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-025","surface":"necessary","lemma":"necessary","language":"en","pos":"ADJ","semantic_domains":["attitude.modal.necessity","attitude.modal","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-026","surface":"sufficient","lemma":"sufficient","language":"en","pos":"ADJ","semantic_domains":["attitude.modal.sufficiency","attitude.modal","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-027","surface":"required","lemma":"required","language":"en","pos":"ADJ","semantic_domains":["attitude.modal.necessity","attitude.modal","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-028","surface":"optional","lemma":"optional","language":"en","pos":"ADJ","semantic_domains":["attitude.modal.optionality","attitude.modal","cognition.modal"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-029","surface":"important","lemma":"important","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.high","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-030","surface":"essential","lemma":"essential","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.high","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-031","surface":"relevant","lemma":"relevant","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.relevance","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-032","surface":"central","lemma":"central","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.high","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-033","surface":"primary","lemma":"primary","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.high","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-034","surface":"useful","lemma":"useful","language":"en","pos":"ADJ","semantic_domains":["attitude.importance.utility","attitude.importance","cognition.judgment"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-035","surface":"general","lemma":"general","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.general","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-036","surface":"specific","lemma":"specific","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.specific","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-037","surface":"broad","lemma":"broad","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.general","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-038","surface":"narrow","lemma":"narrow","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.specific","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-039","surface":"universal","lemma":"universal","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.general","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}
{"entry_id":"en-core-attitude-040","surface":"particular","lemma":"particular","language":"en","pos":"ADJ","semantic_domains":["attitude.scope.specific","attitude.scope","cognition.category"],"morphology_tags":["adjective"],"provenance_ids":["seed:core_attitude_v1"]}

View file

@ -0,0 +1,13 @@
{
"pack_id": "en_core_attitude_v1",
"language": "en",
"role": "operational_base",
"script": "Latin",
"normalization_policy": "unitize_versor",
"source_manifest": "en_core_attitude_v1.lexicon.jsonl",
"determinism_class": "D0",
"checksum": "11076d46a2b8642e4d2d958a5aa3fc13c42fb53a17d746ec312f27716c237c79",
"version": "1.0.0",
"gate_engaged": true,
"oov_policy": "tagged_fallback"
}

View file

@ -0,0 +1,155 @@
"""``en_core_attitude_v1`` — adjective pack tests.
The attitude pack is the first ADJ-bearing pack in the runtime. It
carries 40 adjectives across three semantic clusters:
- attitude.truth_value.* true, false, valid, accurate, ... (8)
- attitude.evaluative.* good, bad, right, better, ... (6)
- attitude.epistemic.* certain, possible, likely, ... (10)
- attitude.modal.* necessary, sufficient, ... (4)
- attitude.importance.* important, essential, useful, ... (6)
- attitude.scope.* general, specific, broad, ... (6)
Contracts pinned:
- Checksum-verified load.
- 40 entries, all POS=ADJ.
- Every entry's primary semantic_domain begins with ``attitude.``.
- No collision with cognition_v1 / meta_v1 / relations_v1 / relations_v2.
- Mounted by default in ``RuntimeConfig.input_packs``.
- Registered in ``DEFAULT_RESOLVABLE_PACK_IDS`` *after* cognition and
meta (preserves cognition-lane and meta-lane resolution invariants).
"""
from __future__ import annotations
import json
from pathlib import Path
from chat.pack_resolver import DEFAULT_RESOLVABLE_PACK_IDS, resolve_lemma
from core.config import RuntimeConfig
from language_packs.compiler import load_pack
PACK_ID = "en_core_attitude_v1"
_PACK_ROOT = Path(__file__).resolve().parent.parent / "language_packs" / "data" / PACK_ID
EXPECTED_TOTAL = 40
EXPECTED_LEMMAS: tuple[str, ...] = (
"true", "false", "valid", "invalid", "accurate", "inaccurate", "factual",
"sound", "good", "bad", "right", "better", "worse", "best",
"certain", "uncertain", "possible", "impossible", "likely", "unlikely",
"probable", "clear", "obscure", "evident",
"necessary", "sufficient", "required", "optional",
"important", "essential", "relevant", "central", "primary", "useful",
"general", "specific", "broad", "narrow", "universal", "particular",
)
def _read_lexicon() -> list[dict]:
path = _PACK_ROOT / "lexicon.jsonl"
return [
json.loads(line)
for line in path.read_text(encoding="utf-8").splitlines()
if line.strip()
]
def test_pack_loads_with_matching_checksum() -> None:
manifest, manifold = load_pack(PACK_ID)
assert manifest.pack_id == PACK_ID
assert len(manifest.checksum) == 64
assert all(c in "0123456789abcdef" for c in manifest.checksum)
assert len(manifold) == EXPECTED_TOTAL
def test_all_entries_are_adjectives() -> None:
entries = _read_lexicon()
assert len(entries) == EXPECTED_TOTAL
for entry in entries:
assert entry["pos"] == "ADJ", entry["entry_id"]
assert entry["morphology_tags"] == ["adjective"], entry["entry_id"]
def test_all_expected_lemmas_present() -> None:
_, manifold = load_pack(PACK_ID)
surfaces = {manifold.get_word_at(i) for i in range(len(manifold))}
assert surfaces == set(EXPECTED_LEMMAS)
def test_every_entry_has_attitude_namespace_primary_domain() -> None:
for entry in _read_lexicon():
domains = entry["semantic_domains"]
assert isinstance(domains, list) and domains, entry
assert domains[0].startswith("attitude."), (
f"entry {entry['entry_id']} primary domain {domains[0]!r} "
f"is not in the attitude.* namespace"
)
def test_no_collision_with_prior_packs() -> None:
"""Anti-leakage: must not duplicate any lemma in any earlier-mounted
English pack. Re-asserts the authoring-time exclusion."""
prior_lemmas: set[str] = set()
pack_root = _PACK_ROOT.parent
for pack in (
"en_core_cognition_v1",
"en_core_meta_v1",
"en_core_relations_v1",
"en_core_relations_v2",
):
for line in (pack_root / pack / "lexicon.jsonl").read_text("utf-8").splitlines():
if line.strip():
prior_lemmas.add(json.loads(line)["lemma"].lower())
for entry in _read_lexicon():
lemma = entry["lemma"].lower()
assert lemma not in prior_lemmas, (
f"lemma {lemma!r} collides with a prior-mounted pack"
)
def test_provenance_is_seed_core_attitude_v1() -> None:
for entry in _read_lexicon():
assert entry["provenance_ids"] == ["seed:core_attitude_v1"], entry
def test_entry_ids_contiguous_and_zero_padded() -> None:
entries = sorted(_read_lexicon(), key=lambda d: d["entry_id"])
for i, entry in enumerate(entries, start=1):
assert entry["entry_id"] == f"en-core-attitude-{i:03d}", entry["entry_id"]
def test_pack_mounted_in_default_runtime_config() -> None:
cfg = RuntimeConfig()
assert PACK_ID in cfg.input_packs
def test_pack_registered_after_cognition_and_meta() -> None:
assert PACK_ID in DEFAULT_RESOLVABLE_PACK_IDS
cog_idx = DEFAULT_RESOLVABLE_PACK_IDS.index("en_core_cognition_v1")
meta_idx = DEFAULT_RESOLVABLE_PACK_IDS.index("en_core_meta_v1")
attitude_idx = DEFAULT_RESOLVABLE_PACK_IDS.index(PACK_ID)
assert cog_idx < attitude_idx
assert meta_idx < attitude_idx
def test_resolver_routes_attitude_lemmas_to_this_pack() -> None:
for lemma in EXPECTED_LEMMAS:
resolved = resolve_lemma(lemma)
assert resolved is not None, f"lemma {lemma!r} did not resolve"
pack_id, domains = resolved
assert pack_id == PACK_ID, (
f"lemma {lemma!r} resolved to {pack_id} instead of {PACK_ID}"
)
assert domains[0].startswith("attitude.")
def test_prior_pack_lemma_resolution_unchanged() -> None:
"""Cognition + meta lemma resolution unaffected by attitude pack."""
for lemma in ("truth", "knowledge", "memory"):
resolved = resolve_lemma(lemma)
assert resolved is not None and resolved[0] == "en_core_cognition_v1"
for lemma in ("doubt", "fact", "self"):
resolved = resolve_lemma(lemma)
assert resolved is not None and resolved[0] == "en_core_meta_v1"