fae438a7a7
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 15s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 33s
CI / typecheck (pull_request) Successful in 35s
CI / unit_tests (pull_request) Successful in 2m22s
CI / integration_tests (pull_request) Successful in 3m0s
CI / docker (pull_request) Successful in 39s
CI / coverage (pull_request) Successful in 4m21s
CI / lint (push) Successful in 14s
CI / quality (push) Successful in 16s
CI / build (push) Successful in 16s
CI / security (push) Successful in 30s
CI / typecheck (push) Successful in 36s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 3m38s
CI / docker (push) Successful in 39s
CI / integration_tests (push) Successful in 4m25s
CI / coverage (push) Successful in 4m19s
CI / benchmark-publish (push) Successful in 15m57s
CI / benchmark-regression (pull_request) Successful in 28m50s
Core domain types (FragmentProvenance, ContextFragment, ContextBudget, ContextPayload) now extend their CRP counterparts via Pydantic v2 inheritance, ensuring isinstance compatibility across the model hierarchy. Key changes: - CRP base types made frozen=True (no consumer mutates them) - CRP AssembledContext fields changed from list to tuple (frozen consistency) - Core types extend CRP bases: FragmentProvenance(CRPFragmentProvenance), ContextFragment(CRPContextFragment), ContextBudget(CRPContextBudget), ContextPayload(CRPAssembledContext) - Removed duplicate ContextFragment dataclass from skeleton_compressor - Updated project_context.py to pass tuples to frozen AssembledContext - Added Behave tests (10 scenarios), Robot integration tests (3 cases), and ASV benchmarks for the unified hierarchy - Updated Known Limitations table in docs/reference/acms.md ISSUES CLOSED: #569
179 lines
5.3 KiB
Python
179 lines
5.3 KiB
Python
"""Robot Framework helper for unified context model integration tests.
|
|
|
|
Verifies isinstance compatibility across the CRP/core model hierarchy
|
|
and basic construction/immutability contracts.
|
|
|
|
Usage:
|
|
python robot/helper_unified_context_models.py isinstance-check
|
|
python robot/helper_unified_context_models.py construction-check
|
|
python robot/helper_unified_context_models.py immutability-check
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from collections.abc import Callable
|
|
from pathlib import Path
|
|
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from cleveragents.domain.models.acms.crp import ( # noqa: E402
|
|
AssembledContext as CRPAssembledContext,
|
|
)
|
|
from cleveragents.domain.models.acms.crp import ( # noqa: E402
|
|
ContextBudget as CRPContextBudget,
|
|
)
|
|
from cleveragents.domain.models.acms.crp import ( # noqa: E402
|
|
ContextFragment as CRPContextFragment,
|
|
)
|
|
from cleveragents.domain.models.acms.crp import ( # noqa: E402
|
|
FragmentProvenance as CRPFragmentProvenance,
|
|
)
|
|
from cleveragents.domain.models.core.context_fragment import ( # noqa: E402
|
|
ContextBudget,
|
|
ContextFragment,
|
|
ContextPayload,
|
|
FragmentProvenance,
|
|
)
|
|
|
|
_DEFAULT_PROV = FragmentProvenance(resource_uri="test://robot-unified")
|
|
|
|
|
|
def _cmd_isinstance_check() -> int:
|
|
"""Verify isinstance compatibility for all four model types."""
|
|
prov = FragmentProvenance(resource_uri="test://robot")
|
|
if not isinstance(prov, CRPFragmentProvenance):
|
|
print("FAIL: FragmentProvenance is not instance of CRP type")
|
|
return 1
|
|
|
|
frag = ContextFragment(
|
|
uko_node="test://robot",
|
|
content="hello",
|
|
token_count=5,
|
|
provenance=prov,
|
|
)
|
|
if not isinstance(frag, CRPContextFragment):
|
|
print("FAIL: ContextFragment is not instance of CRP type")
|
|
return 1
|
|
|
|
budget = ContextBudget(max_tokens=4096, reserved_tokens=512)
|
|
if not isinstance(budget, CRPContextBudget):
|
|
print("FAIL: ContextBudget is not instance of CRP type")
|
|
return 1
|
|
|
|
payload = ContextPayload(plan_id="01JQTESTPN00000000000000AA")
|
|
if not isinstance(payload, CRPAssembledContext):
|
|
print("FAIL: ContextPayload is not instance of CRP AssembledContext")
|
|
return 1
|
|
|
|
print("unified-isinstance-ok")
|
|
return 0
|
|
|
|
|
|
def _cmd_construction_check() -> int:
|
|
"""Verify construction with inherited and extended fields."""
|
|
prov = FragmentProvenance(
|
|
resource_uri="test://construct",
|
|
strategy="test_strategy",
|
|
resource_type="git-checkout",
|
|
)
|
|
if prov.strategy != "test_strategy":
|
|
print(f"FAIL: expected strategy='test_strategy', got {prov.strategy!r}")
|
|
return 1
|
|
if prov.resource_type != "git-checkout":
|
|
print(
|
|
f"FAIL: expected resource_type='git-checkout', got {prov.resource_type!r}"
|
|
)
|
|
return 1
|
|
|
|
frag = ContextFragment(
|
|
uko_node="project://test",
|
|
content="constructed fragment",
|
|
token_count=20,
|
|
tier="hot",
|
|
provenance=prov,
|
|
)
|
|
if frag.tier != "hot":
|
|
print(f"FAIL: expected tier='hot', got {frag.tier!r}")
|
|
return 1
|
|
if not frag.fragment_id:
|
|
print("FAIL: fragment_id is empty")
|
|
return 1
|
|
if len(frag.fragment_id) != 26:
|
|
print(f"FAIL: expected ULID (26 chars), got {len(frag.fragment_id)}")
|
|
return 1
|
|
|
|
budget = ContextBudget(max_tokens=8192, reserved_tokens=1024)
|
|
if budget.available_tokens != 7168:
|
|
print(f"FAIL: expected available=7168, got {budget.available_tokens}")
|
|
return 1
|
|
|
|
print("unified-construction-ok")
|
|
return 0
|
|
|
|
|
|
def _cmd_immutability_check() -> int:
|
|
"""Verify that frozen models reject mutation."""
|
|
frag = ContextFragment(
|
|
uko_node="project://immut",
|
|
content="test",
|
|
token_count=4,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
try:
|
|
frag.uko_node = "project://mutated" # type: ignore[misc]
|
|
print("FAIL: expected frozen error for ContextFragment mutation")
|
|
return 1
|
|
except Exception:
|
|
pass
|
|
|
|
budget = ContextBudget(max_tokens=4096, reserved_tokens=512)
|
|
try:
|
|
budget.max_tokens = 9999 # type: ignore[misc]
|
|
print("FAIL: expected frozen error for ContextBudget mutation")
|
|
return 1
|
|
except Exception:
|
|
pass
|
|
|
|
prov = CRPFragmentProvenance(resource_uri="test://crp")
|
|
try:
|
|
prov.resource_uri = "test://mutated" # type: ignore[misc]
|
|
print("FAIL: expected frozen error for CRP FragmentProvenance mutation")
|
|
return 1
|
|
except Exception:
|
|
pass
|
|
|
|
print("unified-immutability-ok")
|
|
return 0
|
|
|
|
|
|
_COMMANDS: dict[str, Callable[[], int]] = {
|
|
"isinstance-check": _cmd_isinstance_check,
|
|
"construction-check": _cmd_construction_check,
|
|
"immutability-check": _cmd_immutability_check,
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
"""Entry point called by Robot Framework ``Run Process``."""
|
|
if len(sys.argv) < 2:
|
|
print(
|
|
"Usage: helper_unified_context_models.py "
|
|
"<isinstance-check|construction-check|immutability-check>"
|
|
)
|
|
return 1
|
|
|
|
command = sys.argv[1]
|
|
handler = _COMMANDS.get(command)
|
|
if handler is None:
|
|
print(f"Unknown command: {command}")
|
|
return 1
|
|
|
|
return handler()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|