feat: add lightweight MCP replay context layer#198
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a lightweight, replay-aware context layer for MCP-style runtime systems, featuring a compression engine for operational commitments, a file-backed context store, and a deterministic admissibility validator. The reviewer feedback focuses on increasing error handling strictness by consistently using RuntimeError for JSON validation and improving robustness during file loading by handling JSONDecodeError alongside FileNotFoundError.
| def _object(value: Any, field: str) -> dict[str, Any]: | ||
| if isinstance(value, dict): | ||
| return value | ||
| raise ValueError(f"{field} must be an object") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError when validating JSON data types to maintain strictness.
| raise ValueError(f"{field} must be an object") | |
| raise RuntimeError(f"{field} must be an object") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| return [] | ||
| if isinstance(value, list): | ||
| return value | ||
| raise ValueError(f"{field} must be a list") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError when validating JSON data types.
| raise ValueError(f"{field} must be a list") | |
| raise RuntimeError(f"{field} must be a list") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| value = context.get(key) | ||
| if isinstance(value, str) and value.strip(): | ||
| return value.strip() | ||
| raise ValueError("context requires task, task_id, or fixture_id") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used for validation errors during JSON processing.
| raise ValueError("context requires task, task_id, or fixture_id") | |
| raise RuntimeError("context requires task, task_id, or fixture_id") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| try: | ||
| payload = json.loads(path.read_text(encoding="utf-8")) | ||
| except FileNotFoundError as exc: | ||
| raise KeyError(f"context not found: {task_id}") from exc |
There was a problem hiding this comment.
The general rules require handling both FileNotFoundError and JSONDecodeError when loading JSON files, raising a RuntimeError that includes a repo-relative path. Note that using KeyError here might be intended for the API, but the repository rules specify RuntimeError for file loading issues.
| try: | |
| payload = json.loads(path.read_text(encoding="utf-8")) | |
| except FileNotFoundError as exc: | |
| raise KeyError(f"context not found: {task_id}") from exc | |
| try: | |
| payload = json.loads(path.read_text(encoding="utf-8")) | |
| except (FileNotFoundError, json.JSONDecodeError) as exc: | |
| raise RuntimeError(f"Failed to load context from {path}: {exc}") from exc |
References
- When loading JSON files, handle FileNotFoundError and JSONDecodeError by raising a RuntimeError that includes a repo-relative path.
| except FileNotFoundError as exc: | ||
| raise KeyError(f"context not found: {task_id}") from exc | ||
| if not isinstance(payload, dict): | ||
| raise ValueError(f"context payload must be an object: {path}") |
There was a problem hiding this comment.
Per the general rules, use RuntimeError instead of ValueError to validate that the decoded JSON payload is of the expected type.
| raise ValueError(f"context payload must be an object: {path}") | |
| raise RuntimeError(f"context payload must be an object: {path}") |
References
- Validate that the decoded payload is of the expected type using RuntimeError instead of assertions.
| edges: list[Edge] = [] | ||
| for item in value: | ||
| if not isinstance(item, list) or len(item) != 2: | ||
| raise ValueError(f"{field} entries must be [source, target]") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError for strict validation of JSON data structures.
| raise ValueError(f"{field} entries must be [source, target]") | |
| raise RuntimeError(f"{field} entries must be [source, target]") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| raise ValueError(f"{field} entries must be [source, target]") | ||
| source, target = item | ||
| if not isinstance(source, str) or not source or not isinstance(target, str) or not target: | ||
| raise ValueError(f"{field} entries must contain non-empty strings") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError for strict validation of JSON data content.
| raise ValueError(f"{field} entries must contain non-empty strings") | |
| raise RuntimeError(f"{field} entries must contain non-empty strings") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| if value is None: | ||
| return () | ||
| if not isinstance(value, list): | ||
| raise ValueError(f"{field} must be a list") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError for type validation of JSON data.
| raise ValueError(f"{field} must be a list") | |
| raise RuntimeError(f"{field} must be a list") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| strings: list[str] = [] | ||
| for item in value: | ||
| if not isinstance(item, str) or not item: | ||
| raise ValueError(f"{field} entries must be non-empty strings") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError for strict validation of JSON data content.
| raise ValueError(f"{field} entries must be non-empty strings") | |
| raise RuntimeError(f"{field} entries must be non-empty strings") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
| def validate_replay_payload(payload: dict[str, Any]) -> dict[str, object]: | ||
| """Return deterministic admissibility evidence for a compact replay payload.""" | ||
| if not isinstance(payload.get("task"), str) or not payload["task"]: | ||
| raise ValueError("payload.task must be a non-empty string") |
There was a problem hiding this comment.
Per the general rules, RuntimeError should be used instead of ValueError for strict validation of JSON data fields.
| raise ValueError("payload.task must be a non-empty string") | |
| raise RuntimeError("payload.task must be a non-empty string") |
References
- When processing JSON data, raise a RuntimeError for non-expected types to maintain strictness.
Summary
Adds a lightweight deterministic MCP-compatible replay-aware context layer.
This introduces:
Scope
This is intentionally not:
Validation
python -m compileall -q src/comptext_v7/mcppytest tests/test_mcp_context_layer.py -qNotes
The MCP context layer is a small replay-aware context integrity foundation. It is designed to preserve operational commitments in compact deterministic form without broadening CompTextv7 beyond fixture-bound replay-integrity validation.