Repository navigation
Description
Problem or Motivation
The plan in PR #3260 (for #3200) adds a probes parameter to check_proposal and passes it only from the replay (_path_gate in src/devops_cli/roadmap/stage_eval_gates.py). The one call that the stage job makes, in _settle of src/devops_cli/roadmap/stage.py, is in no task and in no Changes list. The replay reads no git, so the probe rule would never run in the job. A person had to find it.
A plan that adds a parameter to a function, or changes what it returns, must name every caller. The path gates (path_problems) check that a path exists, and not that the files of all callers are in the plan.
Proposed Solution & Architectural Design
- When a task text names a function and a new parameter (
Add ... to \name`), find the callers of the function in the staged tree (git grep -n "name("undersrc/`). - Refuse a plan whose
Changeslists lack a file that holds a caller, and name the function and the file. - Test with the
check_proposalplan: a plan withstage_eval_gates.pyand withoutstage.pyis refused.
Target Subsystem
src/devops_cli/roadmap/stage_paths.py, src/devops_cli/roadmap/stage_change.py (path gates of the stage job).
Source: #3260
Proposed design
Problem statement
The stage job can accept a plan that adds a parameter to a function and lists one caller but not another. The path gates check only that a named path exists. The change adds a caller check to the path gate and refuses a plan that leaves a caller file out.
Acceptance criteria
Requirement: Added parameter is found
The path gate SHALL find the function name in a task text of the form Add ... to name``.
Scenario: Task adds a parameter
- WHEN A group task text contains
Addprobestocheck_proposal``. - THEN The caller check reads the function name
check_proposal.
Requirement: Callers come from the staged tree
The staged tree SHALL return each src/ file that calls a named function.
Scenario: Two files call the function
- WHEN The staged tree holds
src/a.pyandsrc/b.py, and both callcheck_proposal(. - THEN The caller search returns
src/a.pyandsrc/b.py.
Requirement: Missing caller file is refused
The path gate SHALL refuse a plan that omits a file that holds a caller of a function with an added parameter.
Scenario: Stage caller is omitted
- WHEN A plan adds a parameter to
check_proposaland listsstage_eval_gates.pybut notstage.py. - THEN
path_problemsreturns a problem that namescheck_proposalandsrc/devops_cli/roadmap/stage.py.
Requirement: Complete caller list passes
The path gate MUST accept a plan whose changes lists hold every caller file of the function.
Scenario: All callers are listed
- WHEN A plan adds a parameter to
check_proposaland itschangeslists hold every file that the caller search returns. - THEN
path_problemsreturns no problem forcheck_proposal.
Requirement: Replay skips caller check
The caller check SHALL skip a staged tree that holds no checkout.
Scenario: Replay tree has no checkout
- WHEN The path gate runs on a case tree that holds no checkout.
- THEN
path_problemsreturns no caller problem.
Existing Tool Considered
No alternatives check has run. Git's git grep is open and maintained, and it covers the textual caller search. It lacks the task parsing and the plan comparison. The change builds that check: about 40,000 tokens to build, keep and fix it, and about one engineer-day.
Key questions
- Where does the caller check live?: It lives in
stage_paths.pyascaller_problems, andpath_problemscalls it.StagedTreegives the caller search, so the job and the replay use the same path gate. (best practice) [sources: src/devops_cli/roadmap/stage_paths.py, src/devops_cli/roadmap/stage_change.py]- Chosen: Add it to
path_problemsinstage_paths.py. The issue names the path gates, andcheck_proposalalready callspath_problems. - Rejected: Add it to
check_proposalinstage_change.py. It would not sit with the path checks and would need a second tree walk. - Rejected: Add a new gate in
stage_eval_gates.py. The job must refuse the plan before a draft opens, and the replay reads no git.
- Chosen: Add it to
- How does the check find a function that a task adds a parameter to?: It matches the task text with a regular expression. The expression captures the name after
toinAdd ... toname``. It scans thetest, `implementation`, `documentation` and `process` texts. (best practice) [sources: openspec/changes/3200-refuse-a-plan-with-placeholder-or/tasks.md:15, src/devops_cli/roadmap/stage_change.py]- Chosen: Match the task text for
Add ... toname``. The issue states this form, and the feat(roadmap): refuse a plan with placeholder or cut text #3200 task uses it. - Rejected: Parse the
changeslist for a function name. The list holds paths, not the function signature. - Rejected: Ask the model to declare the callers. The check must be deterministic and offline.
- Chosen: Match the task text for
- Which caller files must the plan name, and how does the check find them?: The plan must name every file under
src/that calls the function, except the definition line.StagedTree.callers(name)runsgit grep -n -F -- "name(" -- srcon the checkout and returns those files. (best practice) [sources: src/devops_cli/roadmap/stage_paths.py, src/devops_cli/roadmap/stage.py]- Chosen: Every
src/caller, found withgit grep. The issue says every caller, and the search reads the same commit as the path gate. - Rejected: Only callers that pass the new parameter. The issue says every caller, and a default parameter still leaves the call to review.
- Rejected: Parse every file with an AST. The project has no AST index, and the issue asks for a textual search.
- Chosen: Every
- What happens when the staged tree has no checkout, as in the replay?: The caller check is skipped. The replay reads no git, so it cannot find callers and must not refuse a plan on an unknown caller set. (best practice) [sources: src/devops_cli/roadmap/stage_eval_gates.py, docs/ROADMAP_WORKFLOW.md]
- Chosen: Skip the caller check. The replay has no checkout, and a refusal would need a caller set that it cannot read.
- Rejected: Fail the replay. It would break every case with no source.
- Rejected: Use the case facts as a caller list. The case facts hold a thinned tree and no file text.
- How does the check report a missing caller file?: It returns one problem sentence for each function and file. The sentence names the function and the file. The check uses a message in
messages.py. (best practice) [sources: src/devops_cli/lang/en/messages.py, src/devops_cli/roadmap/stage_paths.py]- Chosen: One sentence for each missing caller file. A person can act on each file, and the model gets the exact path.
- Rejected: One sentence that lists all files. A long list hides the function and the first missing file.
Fit
Fits in one pull request.
Suspected block
None.
Dependencies
None.
Activity
dan-petty commentedon Nov 3, 2026
Intake placed this item to the backlog: intake puts every new item in the backlog. A person plans the milestones.
featprefix of the title gives the type.(roadmap)scope of the title gives the scope.It catches a real class of plan errors but one person currently finds them manually.It removes a manual search for missing caller files in every plan that changes a signature.It needs signature parsing, a git grep for callers, and a new refusal path in the stage job.Both work on plan-check gates, but #3201 is the umbrella for all plan checks while the candidate adds one specific caller-completeness check.devops-cli-service commentedon Nov 3, 2026
Status set to Ready at d895bae (see proposed design in issue body).
devops-cli-service commentedon Nov 3, 2026
Staged: branch
feat/3307-the-plan-check-names-a-caller, draft pull request #3323. The pull request plans the item and closes no issue.The task groups, with the tokens of the inputs of each step, for a budget of 40000 tokens:
The plan run made 2 model request(s), and used 145922 input tokens and 4232 output tokens. The model made no tool call.
A model review of the plan found these points. They stop no draft, and a person judges them:
otherat group 1: The design reports a missing caller with a message inmessages.py, but the group lists onlystage_paths.pyinchanges. The plan leaves out a file that the change needs, which is the defect the issue describes. Evidence: "The check uses a message inmessages.py."criterion_droppedat plan.criteria and group 1: Thecriterialist is empty. The one group has placeholdertestandimplementationtext, so no task covers the five requirements of the issue (task parsing, caller search, refusal, complete list, replay skip). Evidence: "#### Scenario: Replay tree has no checkout"docs(openspec): plan #3307 name every caller of a changed function
docs(openspec): plan #3307 name every caller of a changed function (#…