diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index d8461a965d..97e26634e5 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -305,6 +305,15 @@ jobs: - name: Type-check kernel contracts run: python -m mypy + # Preserve the kernel gate above, including its import traversal. This + # additive boundary checks the adapters strictly and analyzes legacy + # imports for types without claiming their implementations are qualified. + - name: Type-check Todo CLI adapters + run: >- + python -m mypy --no-incremental --follow-imports=silent + loopx/cli_commands/todo_event.py + loopx/control_plane/todos/markdown.py + - name: Qualify agent-facing CLI output env: # Compare the tested revision to its event base, even after main moves diff --git a/loopx/cli_commands/todo_event.py b/loopx/cli_commands/todo_event.py index 4299ef929f..dc8b12c476 100644 --- a/loopx/cli_commands/todo_event.py +++ b/loopx/cli_commands/todo_event.py @@ -104,7 +104,7 @@ def todo_error_payload( from ..control_plane.coordination.shadow_management import ShadowManagementError from ..control_plane.todos.external_wait_contract import TodoExternalWaitAuthoringError from ..control_plane.todos.handoff_mode import HandoffModeError - from ..control_plane.work_items.task_lease import TaskLeaseError + from ..control_plane.work_items.local_lease_record import TaskLeaseError from .todo_argument_validation import TodoClaimArgumentError payload: dict[str, object] = { @@ -219,8 +219,8 @@ def append_todo_rollout_event( "mutation_authority": payload.get("mutation_authority"), "replan_transition": payload.get("replan_transition"), "settlement_effect_id": ( - payload.get("settlement_identity", {}).get("effect_id") - if isinstance(payload.get("settlement_identity"), dict) + identity.get("effect_id") + if isinstance(identity, dict) else None ), }, diff --git a/loopx/control_plane/todos/markdown.py b/loopx/control_plane/todos/markdown.py index 701adee69d..4a14fc3bbb 100644 --- a/loopx/control_plane/todos/markdown.py +++ b/loopx/control_plane/todos/markdown.py @@ -367,12 +367,10 @@ def render_todo_markdown(payload: dict[str, Any]) -> str: lines.extend(["", "```sh", command, "```"]) correctness = payload.get("local_state_write_correctness") if isinstance(correctness, dict): - intent = correctness.get("write_intent") if isinstance(correctness.get("write_intent"), dict) else {} - apply_result = ( - correctness.get("apply_result") - if isinstance(correctness.get("apply_result"), dict) - else {} - ) + intent_value = correctness.get("write_intent") + intent = intent_value if isinstance(intent_value, dict) else {} + apply_result_value = correctness.get("apply_result") + apply_result = apply_result_value if isinstance(apply_result_value, dict) else {} lines.extend( [ "", diff --git a/skills/loopx-self-repair/references/repair-patterns.md b/skills/loopx-self-repair/references/repair-patterns.md index bd1f6efbcb..0117da7243 100644 --- a/skills/loopx-self-repair/references/repair-patterns.md +++ b/skills/loopx-self-repair/references/repair-patterns.md @@ -5,6 +5,7 @@ teaches a reusable control-plane lesson. | Pattern | Symptoms | Evidence To Read | Likely Root | Durable Repair | | --- | --- | --- | --- | --- | +| `typed_adapter_validation_scope_mismatch` | A local adapter type check passes while the same CI entry reports a large legacy dependency error set. | Exact source revisions, configured roots, cold same-environment runs, installation/import paths, and original-root plus adapter counterfactuals. | Adding runtime adapters to a kernel root list expands its import closure; an extra source path can mask that traversal locally. | Preserve the existing kernel gate and its import behavior. Make the additive adapter boundary explicit, retain imported-code debt as unqualified, and prove strict root checking with original diagnostics and core/adapter mutations in an unmasked source installation. Do not globally disable import checks, remove original roots or rewrite historical failures as passes. | | `saved_projection_goal_route_coupling` | A saved context projection fails on conflicting default runtime roots even with native transport disabled, while the same capture remains readable. | Run the shipped projection and returned reader against one digest-bound synthetic capture, with implicit, missing and global registry selectors; retain digest/identity refusals and unchanged runtime snapshots. | Shared CLI registry discovery runs before the saved-view owner validates its source. | Classify the saved presentation at the existing CLI route owner; preserve machine-configuration routing, live authority conflict checks and source/session validation. Reuse the registry-independence integration tests rather than adding a second recovery path or repairing live state. | | `native_reader_program_route_loss` | A native producer or read uses a selected CLI or interpreter, but returned navigation, continuation or recovery invokes another runtime. | Actual lifecycle capture, generated first-read and recovery instructions, unchanged execution of emitted commands with an isolated competing program, complete source/digest readback and installed-package provenance. | A presentation layer used its generic command-renderer default after the caller had already selected the runtime. | Pass the current program argv through existing CLI, navigation, bounded-result and reader renderers; retain constructor defaults and shell quoting. Include emitted command metadata in native byte-cost estimates. Cover cold guard and saved-context projection before direct first reads, raw/selected/index pagination, quoted aliases, refusal details and source-state immutability through real CLI and isolated wheel entrypoints. Routing preserves the selected program; it does not pin an installation version or prove Host adoption. | | `host_bridge_reader_orphan` | A rejected bridge observation leaves its reader thread and output pipe alive after the child has exited. | Original framing error, cleanup result, child exit, bounded-queue backpressure and reader/pipe state across repeated failures. | Cancellation rejects another malformed frame; the sole consumer leaves while the producer blocks on a full queue, and joining alone cannot release it. | Stop publication, release the waiting producer, join and close through the existing transport helper. Retain cleanup-unconfirmed results and original Host drain ownership; reclaiming a reader does not prove Host exit. Cover malformed JSON and invalid typed observations with real subprocesses, plus existing real Host cancellation and success paths. Do not increase timeouts or fabricate a successful result. |