Phase B · PRD §6, SRD §1.1. Blocked by #573.
The command that joins the two halves and writes a file.
keel analysis fetch [--out shortlist.json]
Connects, collects for a bounded window, writes [{asset, rationale, sources[]}], and prints what it got and what it dropped — every FetchReport counter, on screen.
Then the existing path, unchanged
keel assets propose --from shortlist.json
proposer.py already parses this exact structure, rejects malformed entries per-candidate, routes each through the same gate as assets screen, and admits nothing. It is pure, dependency-free and tested. We reuse it rather than reimplement it — a second parser would be a second place to get validation wrong.
Two commands, on purpose
They may later be one. They are two here because the shortlist is a file a human can read, diff, and keep, and because it keeps the gate's input inspectable. The boundary between "a service said this" and "keel considered it" should be something you can cat.
Module placement
keel/analysis/ is a new top-level subpackage, not another keel/commands/ module. keel/commands/ is 13,606 lines and #525 exists about exactly that; a feed client is not a command. The command layer stays thin — parse options, call the service, echo — per the existing thinness pin.
Done when
Phase B · PRD §6, SRD §1.1. Blocked by #573.
The command that joins the two halves and writes a file.
Connects, collects for a bounded window, writes
[{asset, rationale, sources[]}], and prints what it got and what it dropped — everyFetchReportcounter, on screen.Then the existing path, unchanged
proposer.pyalready parses this exact structure, rejects malformed entries per-candidate, routes each through the same gate asassets screen, and admits nothing. It is pure, dependency-free and tested. We reuse it rather than reimplement it — a second parser would be a second place to get validation wrong.Two commands, on purpose
They may later be one. They are two here because the shortlist is a file a human can read, diff, and keep, and because it keeps the gate's input inspectable. The boundary between "a service said this" and "keel considered it" should be something you can
cat.Module placement
keel/analysis/is a new top-level subpackage, not anotherkeel/commands/module.keel/commands/is 13,606 lines and #525 exists about exactly that; a feed client is not a command. The command layer stays thin — parse options, call the service, echo — per the existing thinness pin.Done when
keel analysis fetchwrites a shortlist and prints the full reportkeel assets propose --fromwith no change toproposer.pyscreen_fn(repo, product, quote)— mutation: passing the rationale as a fourth argument fails