[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: C11.
Kind: tracking. Source: review §2.2, §2.6 and R5; register C11.
Problem
run_scan is one 1,540-line function on 045d7ec (the review measured 1,499 at 2463257). It does everything a scan does, in order:
- mode folding, socket.yml policy loading, the PATH fan-out, path-scope parsing, the rollout cap and the offline refusal (L1429–L1521);``
- the crawl, the lockfile supplement, the vendored-ledger supplement and the package/path filters (L1560–L1771);``
- a "no packages" exit with its own JSON and human arms (L1772–L1893);``
- the concurrent batch query with the proxy fallback, the fold and the patch counts (L1932–L2132);``
- a JSON arm and a human arm that each dispatch all three modes again.
The JSON arm is L2141–L2428 and the human arm follows it:
The mode is still three booleans (apply/vendor/hosted, L1525–L1527),`` derived from args.mode and branched on in about 27 conditions. Output mode leaks into the engine: `discover_selected` takes progress, warning and `json_warnings: Option<&mut Value>` parameters, so the selection step can't be shared between the two arms.
Impact
Every scan behavior change has to be made twice, once per output arm, and every mode-specific fix touches the same 1,540-line body. The open arch-audit issues on scan's proxy fallback, batch chunking and the JSON error shape (#647, #675, #704) all edit this function. Its size also forces the Box::pin/boxed_* indirections that keep the debug-build poll frame under Windows' 1 MiB main-thread stack.
Target design
run_scan becomes a short pipeline over typed phase results, with rendering only at the end:
prepare (policy, scope, cap, offline) → ScanSetup;
collect_inventory (crawl, supplements, filters) → ScanInventory;
query_patches (batches, fallback, fold, counts) → PatchQuery;
select (rows, partitions, rollout plan, computed once) → Selection;
- one
match mode that hands Selection to the hosted, agent or vendored consumer, which returns a typed outcome;
render_json or render_human over that outcome.
Each step lands as its own PR. Steps 2 and 3 are mechanical moves; steps 4–6 change structure, but must not change output.
Checklist
Acceptance criteria
Dependencies
Children 2 and 5 wait on #647, #675 and decision #704. It relates to C12 (engine code out of the CLI) and C10/#793 (RunCtx): the phase functions should take the RunCtx when it exists.
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: C11.
Kind: tracking. Source: review §2.2, §2.6 and R5; register C11.
Problem
run_scanis one 1,540-line function on045d7ec(the review measured 1,499 at2463257). It does everything a scan does, in order:The JSON arm is L2141–L2428 and the human arm follows it:
run_redirect@2187boxed_run_redirect_selected@2675discover_selected@2226/2246,``classified_rows@2265, `partition_agent_selection` @2282, `plan_kept_rows` @2283discover_selected@2489,classified_rows@2510,partition_agent_selection@2702,plan_kept_rows@2730download_and_apply_patches_with@2339boxed_vendor_json_path@2375boxed_vendor_interactive_path@2912The mode is still three booleans (
apply/vendor/hosted, L1525–L1527),`` derived fromargs.modeand branched on in about 27 conditions. Output mode leaks into the engine: `discover_selected` takes progress, warning and `json_warnings: Option<&mut Value>` parameters, so the selection step can't be shared between the two arms.Impact
Every scan behavior change has to be made twice, once per output arm, and every mode-specific fix touches the same 1,540-line body. The open
arch-auditissues on scan's proxy fallback, batch chunking and the JSONerrorshape (#647, #675, #704) all edit this function. Its size also forces theBox::pin/boxed_*indirections that keep the debug-build poll frame under Windows' 1 MiB main-thread stack.Target design
run_scanbecomes a short pipeline over typed phase results, with rendering only at the end:prepare(policy, scope, cap, offline) →ScanSetup;collect_inventory(crawl, supplements, filters) →ScanInventory;query_patches(batches, fallback, fold, counts) →PatchQuery;select(rows, partitions, rollout plan, computed once) →Selection;match modethat handsSelectionto the hosted, agent or vendored consumer, which returns a typed outcome;render_jsonorrender_humanover that outcome.Each step lands as its own PR. Steps 2 and 3 are mechanical moves; steps 4–6 change structure, but must not change output.
Checklist
collect_inventory→ScanInventory(mechanical). Filed as a sub-issue.query_patches→PatchQuery(mechanical). Lands after Only scan, get <uuid> and vex fall back to the public proxy on 401/403; get search, apply, rollback, repair and vendor eject fail #647 and Chunk patch batch searches through one core helper with one set of batch limits #675, which edit the same block.discover_selected→classified_rows→partition_agent_selection→plan_kept_rows) and remove the output parameters fromdiscover_selectedby returning warnings as data.Selection; delete the secondrun_redirect/boxed_vendor_*/download_and_apply_patches_withcall of each pair.render_json/render_humanover the typed outcome, including the "no packages" exit. Coordinate the JSON shape with decision Decide: one shape for the--jsontop-levelerror(scan and get emit both a string and a {code, message} object) #704.Acceptance criteria
run_scanis under 200 lines and dispatches each mode once.scantest targets and the benchmark gate from Add ascanbenchmark suite and a CI performance gate #485 stay green at every step, with no snapshot or golden JSON changes except where a child says so.Dependencies
Children 2 and 5 wait on #647, #675 and decision #704. It relates to C12 (engine code out of the CLI) and C10/#793 (
RunCtx): the phase functions should take theRunCtxwhen it exists.