feat(packs): en_core_action_v1 — action verbs (26 lemmas)

Workstream 1 fourth pack.  Closes the common-action verb gap.  Prior
packs covered reasoning (cognition), speech/perception (meta), and
adjectives (attitude); this pack covers what an agent *does*.

Pack composition (26 VERB entries):

  action.doing.perform     do perform execute carry conduct
  action.doing.make        make
  action.doing.achieve     achieve accomplish
  action.creating.originate create build form produce generate develop
  action.changing.transform change transform
  action.moving.translate  move
  action.moving.depart_arrive go come
  action.moving.transfer   send receive
  action.possessing.acquire get take
  action.possessing.transfer give
  action.possessing.retain keep
  action.possessing.deploy use

Files:
  language_packs/data/en_core_action_v1/
    lexicon.jsonl   — 26 entries, SHA-256 checksum-sealed
    manifest.json   — operational_base / D0
  chat/pack_resolver.py
    Appended to DEFAULT_RESOLVABLE_PACK_IDS after temporal.
  core/config.py
    Added to RuntimeConfig.input_packs default mount.
  tests/test_en_core_action_v1_pack.py
    11 contract tests covering load / POS / namespace / no-collision /
    contiguous-ids / mounted-by-default / resolver-order / routing /
    prior-pack invariance.
  tests/test_procedure_surface.py
    Swapped two test fixtures from "do stuff" to "fix bugs".  ``do``
    is now correctly pack-resident in en_core_action_v1 (semantically
    correct — "How do I do stuff?" should ground on ``do``), so the
    "no pack lemma exists" contract needed a fixture where both verb
    and noun are genuinely OOV.  ``fix bugs`` satisfies this across
    all 7 mounted packs.

Authoring:
  Three parallel subagents — doing / creating / moving+possessing.
  Strict exemplar + forbidden-lemma list against all 6 prior packs.

Verification:
  Cognition eval byte-identical on both splits (100/100/91.7/100 and
  100/100/83.3/100).
  All 70 pack tests pass (cognition + meta + attitude + temporal +
  action + quant tests run together).
  Live composer probes confirm every action lemma surfaces
  deterministically from en_core_action_v1.
This commit is contained in:
Shay 2026-05-18 20:57:52 -07:00
parent 1c7408f7d0
commit cb1eba72ae
6 changed files with 203 additions and 3 deletions

View file

@ -45,6 +45,7 @@ DEFAULT_RESOLVABLE_PACK_IDS: tuple[str, ...] = (
"en_core_meta_v1",
"en_core_attitude_v1",
"en_core_temporal_v1",
"en_core_action_v1",
"en_core_relations_v1",
"en_core_relations_v2",
)

View file

@ -16,6 +16,7 @@ class RuntimeConfig:
"en_core_meta_v1",
"en_core_attitude_v1",
"en_core_temporal_v1",
"en_core_action_v1",
"en_core_relations_v1",
"en_core_relations_v2",
"he_logos_micro_v1",

View file

@ -0,0 +1,26 @@
{"entry_id":"en-core-action-001","surface":"do","lemma":"do","language":"en","pos":"VERB","semantic_domains":["action.doing.perform","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-002","surface":"make","lemma":"make","language":"en","pos":"VERB","semantic_domains":["action.doing.make","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-003","surface":"perform","lemma":"perform","language":"en","pos":"VERB","semantic_domains":["action.doing.perform","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-004","surface":"conduct","lemma":"conduct","language":"en","pos":"VERB","semantic_domains":["action.doing.perform","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-005","surface":"execute","lemma":"execute","language":"en","pos":"VERB","semantic_domains":["action.doing.perform","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-006","surface":"carry","lemma":"carry","language":"en","pos":"VERB","semantic_domains":["action.doing.perform","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-007","surface":"achieve","lemma":"achieve","language":"en","pos":"VERB","semantic_domains":["action.doing.achieve","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-008","surface":"accomplish","lemma":"accomplish","language":"en","pos":"VERB","semantic_domains":["action.doing.achieve","action.doing","cognition.activity"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-009","surface":"create","lemma":"create","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.production"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-010","surface":"build","lemma":"build","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.construction"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-011","surface":"form","lemma":"form","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.structure"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-012","surface":"produce","lemma":"produce","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.production"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-013","surface":"generate","lemma":"generate","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.production"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-014","surface":"develop","lemma":"develop","language":"en","pos":"VERB","semantic_domains":["action.creating.originate","action.creating","cognition.growth"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-015","surface":"change","lemma":"change","language":"en","pos":"VERB","semantic_domains":["action.changing.transform","action.changing","cognition.modification"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-016","surface":"transform","lemma":"transform","language":"en","pos":"VERB","semantic_domains":["action.changing.transform","action.changing","cognition.modification"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-017","surface":"move","lemma":"move","language":"en","pos":"VERB","semantic_domains":["action.moving.translate","action.moving","cognition.motion"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-018","surface":"go","lemma":"go","language":"en","pos":"VERB","semantic_domains":["action.moving.depart_arrive","action.moving","cognition.motion"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-019","surface":"come","lemma":"come","language":"en","pos":"VERB","semantic_domains":["action.moving.depart_arrive","action.moving","cognition.motion"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-020","surface":"send","lemma":"send","language":"en","pos":"VERB","semantic_domains":["action.moving.transfer","action.moving","cognition.motion"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-021","surface":"receive","lemma":"receive","language":"en","pos":"VERB","semantic_domains":["action.moving.transfer","action.moving","cognition.motion"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-022","surface":"get","lemma":"get","language":"en","pos":"VERB","semantic_domains":["action.possessing.acquire","action.possessing","cognition.possession"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-023","surface":"take","lemma":"take","language":"en","pos":"VERB","semantic_domains":["action.possessing.acquire","action.possessing","cognition.possession"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-024","surface":"give","lemma":"give","language":"en","pos":"VERB","semantic_domains":["action.possessing.transfer","action.possessing","cognition.possession"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-025","surface":"keep","lemma":"keep","language":"en","pos":"VERB","semantic_domains":["action.possessing.retain","action.possessing","cognition.possession"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}
{"entry_id":"en-core-action-026","surface":"use","lemma":"use","language":"en","pos":"VERB","semantic_domains":["action.possessing.deploy","action.possessing","cognition.possession"],"morphology_tags":["verb"],"provenance_ids":["seed:core_action_v1"]}

View file

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

View file

@ -0,0 +1,150 @@
"""``en_core_action_v1`` — action verb pack tests.
The action pack adds common-action verb coverage absent from prior
packs. Cognition verbs are reasoning/relation operators; meta verbs
are speech/mental/perceptual; this pack covers what an agent *does*:
performing, creating, changing, moving, possessing. 26 entries:
- action.doing.* do make perform conduct execute carry achieve accomplish (8)
- action.creating.* create build form produce generate develop (6)
- action.changing.* change transform (2)
- action.moving.* move go come send receive (5)
- action.possessing.* get take give keep use (5)
Contracts pinned: checksum-verified load, all entries POS=VERB,
attitude.*-style primary-domain invariant, no collision with any of
the 6 prior English packs, mounted by default, registered after
temporal in DEFAULT_RESOLVABLE_PACK_IDS, prior-pack resolution
unchanged.
"""
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_action_v1"
_PACK_ROOT = Path(__file__).resolve().parent.parent / "language_packs" / "data" / PACK_ID
EXPECTED_TOTAL = 26
EXPECTED_LEMMAS: tuple[str, ...] = (
"do", "make", "perform", "conduct", "execute", "carry", "achieve",
"accomplish", "create", "build", "form", "produce", "generate",
"develop", "change", "transform", "move", "go", "come", "send",
"receive", "get", "take", "give", "keep", "use",
)
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_verbs() -> None:
for entry in _read_lexicon():
assert entry["pos"] == "VERB", entry["entry_id"]
assert entry["morphology_tags"] == ["verb"], 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_action_namespace_primary_domain() -> None:
for entry in _read_lexicon():
domains = entry["semantic_domains"]
assert isinstance(domains, list) and domains, entry
assert domains[0].startswith("action."), (
f"entry {entry['entry_id']} primary domain {domains[0]!r} "
f"is not in the action.* namespace"
)
def test_no_collision_with_prior_packs() -> None:
prior_lemmas: set[str] = set()
pack_root = _PACK_ROOT.parent
for pack in (
"en_core_cognition_v1",
"en_core_meta_v1",
"en_core_attitude_v1",
"en_core_temporal_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_action_v1() -> None:
for entry in _read_lexicon():
assert entry["provenance_ids"] == ["seed:core_action_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-action-{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_prior_content_packs() -> None:
assert PACK_ID in DEFAULT_RESOLVABLE_PACK_IDS
for earlier in (
"en_core_cognition_v1",
"en_core_meta_v1",
"en_core_attitude_v1",
"en_core_temporal_v1",
):
assert DEFAULT_RESOLVABLE_PACK_IDS.index(earlier) < DEFAULT_RESOLVABLE_PACK_IDS.index(PACK_ID)
def test_resolver_routes_action_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("action.")
def test_prior_pack_lemma_resolution_unchanged() -> None:
for lemma, expected in (
("truth", "en_core_cognition_v1"),
("doubt", "en_core_meta_v1"),
("true", "en_core_attitude_v1"),
("now", "en_core_temporal_v1"),
):
resolved = resolve_lemma(lemma)
assert resolved is not None and resolved[0] == expected

View file

@ -75,7 +75,11 @@ def test_extract_skips_dialogue_fillers() -> None:
def test_extract_none_when_no_pack_lemma() -> None:
assert _extract_procedure_topic_lemma("") is None
assert _extract_procedure_topic_lemma(None) is None # type: ignore[arg-type]
assert _extract_procedure_topic_lemma("do stuff") is None
# Pre-en_core_action_v1 the canonical fixture was "do stuff", but
# ``do`` now resolves via en_core_action_v1 (action.doing.perform).
# Use a genuinely-OOV verb+noun pair to preserve the original
# contract: when no pack-resident lemma exists, return None.
assert _extract_procedure_topic_lemma("fix bugs") is None
def test_extract_strips_punctuation() -> None:
@ -128,7 +132,9 @@ def test_surface_returns_none_for_no_pack_lemma() -> None:
through to the universal disclosure preserves the honesty
contract for fully-unknown procedures."""
assert pack_grounded_procedure_surface("") is None
assert pack_grounded_procedure_surface("do stuff") is None
# ``do`` is now pack-resident in en_core_action_v1; use a verb+noun
# pair where both terms are genuinely OOV across all mounted packs.
assert pack_grounded_procedure_surface("fix bugs") is None
def test_surface_is_deterministic() -> None:
@ -160,7 +166,10 @@ def test_procedure_with_no_pack_lemma_routes_to_oov_invitation() -> None:
universal disclosure. No surface fabrication: the invitation
only references the OOV token and the mounted-pack list."""
rt = ChatRuntime()
response = rt.chat("How do I do stuff?")
# ``fix`` and ``bugs`` are genuinely OOV across all mounted packs
# (``do`` is now pack-resident in en_core_action_v1, so the prior
# fixture "how do I do stuff?" would extract ``do`` and ground).
response = rt.chat("How do I fix bugs?")
# Either UNKNOWN-intent → "none", or PROCEDURE-intent on OOV
# subject → "oov" invitation. Both honour the no-fabrication
# contract; the surface text differs by intent classification.