Repository navigation
[BUG] --scope-mode and --diff-base are silently ignored on --resume, and run.json/coverage.json then contradict themselves #1508
Description
Describe the bug
--scope-mode is documented as 'full' disables diff-scope (strix/interface/cli_args.py:233), but on a resume it is a silent no-op, and the run record then contradicts itself about what was scanned.
Two things go wrong together:
1. The flag is never consulted on resume. prepare_run() returns early for resumes:
# strix/interface/scan_setup.py:245-246
if args.resume:
returnresolve_diff_scope_context(..., scope_mode=args.scope_mode, diff_base=args.diff_base, ...) sits at line 257, after that return, so it never runs. Meanwhile load_resume_state() restores the persisted scope verbatim, without reference to args.scope_mode:
# strix/interface/cli_args.py:530-531
if state.get("diff_scope"):
args.diff_scope = state.get("diff_scope")So resuming a diff-scoped run with --scope-mode full still runs diff-scoped. strix/core/runner.py:393-394 derives is_diff_scoped from the restored diff_scope["active"], which adds the scan_modes/diff skill to the root agent's and every child's system prompt (strix/agents/prompt.py:55) and keeps the diff-scope preamble. --diff-base is ignored the same way.
Unlike --scan-mode (see #1507), there is no sentinel ambiguity here: --scope-mode has default="auto", so full is unmistakably explicit. The code simply never looks at it on this path.
2. The published record then asserts two incompatible things. args.scope_mode is forwarded into scan_config and persisted, while diff_scope comes from the old run:
# strix/interface/cli.py
"diff_scope": getattr(args, "diff_scope", {"active": False}), # :93 — restored, old
"scope_mode": getattr(args, "scope_mode", "auto"), # :98 — new, from the flagstrix/report/state.py:780,783 writes both side by side, so run.json and coverage.json's scope block end up recording scope_mode: "full" next to diff_scope: {"active": true}.
This second part is a defect regardless of how the first is resolved: whichever behaviour is intended for the flag on resume, a published artifact should not claim full scope and active diff-scope at the same time.
To Reproduce
- Start a diff-scoped scan over a local repo, so
run.jsoncarries"scope_mode": "diff"and"diff_scope": {"active": true, ...}. - Resume it asking for the full repository:
strix --resume <run_name> --scope-mode full - The agents still carry the diff-scope skill and preamble, and
run.json/coverage.jsonrecordscope_mode: "full"together withdiff_scope.active: true.
Reproduced without launching a sandbox by writing a minimal run.json and calling parse_arguments() with ["strix", "--resume", "<name>", "--scope-mode", "full"]:
args.scope_mode = full
args.diff_scope = {'active': True, 'base': 'origin/main', 'repos': []}
is_diff_scoped would be: True
Expected behavior
--scope-mode full on a resume should widen the scan to the full repository as --help promises, and --diff-base should be honoured — or both should be rejected with a clear error when combined with --resume, the way --target already is. In no case should the persisted scope_mode and diff_scope be written out contradicting each other.
Suggested fix
In load_resume_state(), let an explicit --scope-mode/--diff-base re-resolve the scope — at minimum honour scope_mode == "full" by forcing args.diff_scope = {"active": False}. If preserving the original scope across a resume is deliberate, parser.error() on either flag with --resume instead. Either way, keep the two fields consistent in the record.
System Information:
- OS: Ubuntu 24.04.4 LTS
- Strix Version or Commit:
f7a32ae(main, v1.7.0) - Python Version: 3.12.3
- LLM Used: n/a — argument parsing only
Additional context
Separate from #1507, which is about --scan-mode deep being masked by its own default value in the same function. This one needs no sentinel work; the flag is already unambiguous.
Activity
fix(cli): honor --scope-mode full on --resume and keep scope records …