test(plan_actions): repair _InputStub after model_copy/model_dump usage#929
Conversation
PR Tracer-Cloud#807 added a masking round-trip in ``node_plan_actions``: input_data = input_data.model_copy( update={k: masking_ctx.mask_value(v) for k, v in input_data.model_dump().items()} ) The matching test (``test_node_plan_actions_emits_retrieval_controls``) was not updated, so its ``_InputStub`` (which only defines ``tool_budget = 10``) raises: AttributeError: '_InputStub' object has no attribute 'model_copy' This breaks the ``test (ubuntu-latest)`` CI job for every PR opened against ``main`` after Tracer-Cloud#807. Add the two pydantic-surface methods the production code path uses, keeping ``_InputStub`` as a thin stub rather than dragging in a full ``BaseModel``: - ``model_dump`` returns a dict carrying ``tool_budget``. - ``model_copy(update=...)`` returns a new ``_InputStub`` with the update applied via ``setattr``. After the fix the test passes locally; ruff check + format clean.
Greptile SummaryThis test-only PR repairs Confidence Score: 5/5Safe to merge — single test file change, no production code modified, fixes a broken CI gate. The fix is minimal, correct, and scoped entirely to the test. Both added methods faithfully replicate the pydantic surface (model_dump / model_copy) that production code invokes, the forward-reference annotation -> _InputStub is valid because from future import annotations is already in scope, and the PR author confirms the test passes. No P0/P1 findings exist. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Test as test_node_plan_actions_emits_retrieval_controls
participant Node as node_plan_actions
participant Stub as _InputStub
participant Mask as MaskingContext
participant Builder as build_plan_actions (monkeypatched)
Test->>Node: call with state dict
Node->>Stub: InvestigateInput.from_state(state) → _InputStub()
Node->>Mask: MaskingContext.from_state(state)
Node->>Stub: input_data.model_dump() → {"tool_budget": 10}
Node->>Mask: mask_value(v) for each field
Node->>Stub: input_data.model_copy(update={...}) → new _InputStub
Node->>Builder: build_plan_actions(input_data=...) → (plan, ...)
Node->>Test: return {planned_actions, retrieval_controls, ...}
Test->>Test: assert retrieval_controls emitted correctly
Reviews (1): Last reviewed commit: "test(plan_actions): repair _InputStub af..." | Re-trigger Greptile |
|
This looks good to me. The stub now correctly mirrors the CI is green and there are no production code changes. Merging ✅ |
Summary
PR #807 added a masking round-trip in
node_plan_actions:```python
input_data = input_data.model_copy(
update={k: masking_ctx.mask_value(v) for k, v in input_data.model_dump().items()}
)
```
The matching test (`test_node_plan_actions_emits_retrieval_controls`) was not updated, so its `_InputStub` — which only defines `tool_budget = 10` — raises on every CI run since #807 landed:
```
E AttributeError: '_InputStub' object has no attribute 'model_copy'
app/nodes/plan_actions/node.py:55: AttributeError
```
This breaks the `test (ubuntu-latest)` CI job for every PR currently in flight against `main` and blocks merges.
Fix
Add the two pydantic-surface methods the production code path uses, keeping `_InputStub` a thin stub rather than dragging in a full `BaseModel`:
Verification
Scope
One file (the test), 14 inserted lines, 0 production-code change.