Skip to content

feat(roadmap): the plan check names a caller file that a changed signature leaves out #3307

Open

Description

@dan-petty

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

  1. 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/`).
  2. Refuse a plan whose Changes lists lack a file that holds a caller, and name the function and the file.
  3. Test with the check_proposal plan: a plan with stage_eval_gates.py and without stage.py is 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 Add probestocheck_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.py and src/b.py, and both call check_proposal(.
  • THEN The caller search returns src/a.py and src/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_proposal and lists stage_eval_gates.py but not stage.py.
  • THEN path_problems returns a problem that names check_proposal and src/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_proposal and its changes lists hold every file that the caller search returns.
  • THEN path_problems returns no problem for check_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_problems returns 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.py as caller_problems, and path_problems calls it. StagedTree gives 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_problems in stage_paths.py. The issue names the path gates, and check_proposal already calls path_problems.
    • Rejected: Add it to check_proposal in stage_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.
  • 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 to in Add ... to name``. It scans the test, `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 ... to name``. The issue states this form, and the feat(roadmap): refuse a plan with placeholder or cut text #3200 task uses it.
    • Rejected: Parse the changes list 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.
  • 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) runs git grep -n -F -- "name(" -- src on 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 with git 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.
  • 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

  1. added
    type/featureNew user-facing functionality or capability addition
    scope/roadmapThe roadmap jobs: intake, refine, stage, implement and the Service that runs them
    status/newStatus New: the item is not ready yet
    on Nov 3, 2026
  2. dan-petty commented on Nov 3, 2026

    @dan-petty
    OwnerAuthor

    Intake placed this item to the backlog: intake puts every new item in the backlog. A person plans the milestones.

    • Type: type/feature. The feat prefix of the title gives the type.
    • Scope: scope/roadmap. The (roadmap) scope of the title gives the scope.
    • Priority: P2-Medium. It catches a real class of plan errors but one person currently finds them manually.
    • Value: Medium. It removes a manual search for missing caller files in every plan that changes a signature.
    • Effort: Medium. It needs signature parsing, a git grep for callers, and a new refusal path in the stage job.
    • Related: feat(roadmap): add a plan-check command for a plan pull request #3201, which asks for a different change. Both work on plan-check gates, but #3201 is the umbrella for all plan checks while the candidate adds one specific caller-completeness check.
  3. added
    priority/p2-mediumStandard priority feature work and architectural improvements
    on Nov 3, 2026
  4. added
    status/readyStatus Ready: problem, acceptance criteria and an answer to each key question
    and removed
    status/newStatus New: the item is not ready yet
    on Nov 3, 2026
  5. devops-cli-service commented on Nov 3, 2026

    @devops-cli-service
    Contributor

    Status set to Ready at d895bae (see proposed design in issue body).

  6. devops-cli-service commented on Nov 3, 2026

    @devops-cli-service
    Contributor

    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:

    1. x: 4210 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:

    • other at group 1: The design reports a missing caller with a message in messages.py, but the group lists only stage_paths.py in changes. The plan leaves out a file that the change needs, which is the defect the issue describes. Evidence: "The check uses a message in messages.py."
    • criterion_dropped at plan.criteria and group 1: The criteria list is empty. The one group has placeholder test and implementation text, 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"
  7. added a commit that references this issue on Nov 3, 2026
  8. added a commit that references this issue on Nov 3, 2026
  9. added
    status/plannedStatus Planned: the plan is merged and the item waits for its implementation
    and removed
    status/readyStatus Ready: problem, acceptance criteria and an answer to each key question
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort/mediumEffort Mediumpriority/p2-mediumStandard priority feature work and architectural improvementsscope/roadmapThe roadmap jobs: intake, refine, stage, implement and the Service that runs themsource/agentFiled by an agentstatus/plannedStatus Planned: the plan is merged and the item waits for its implementationtype/featureNew user-facing functionality or capability additionvalue/mediumValue Medium

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions