Originally created by: Maqbool61
Issue [#192].
Two files changed, no behaviour changed:
docs/CLI.md — added a "JSON output conventions" section that states the shared contract once:
flag naming (--json = one document, --jsonl = one object per line and why they differ),
stdout purity, redaction guarantee, determinism guarantee (sort_keys=True, compact separators),
exit-code semantics, and the policy-history --json schema.
tests/conftest.py — added assert_json_stdout(result, *, jsonl=False), a shared helper that
asserts stdout is valid JSON and nothing else. jsonl=False covers scan, doctor,
policy-history; jsonl=True covers log. The helper asserts shape only — each command's
own redaction assertions are untouched.
pytest tests/ -k "json" -v → 51 passed
ruff check . → all checks passed
No existing test modified, no command output changed.
Ticket changed by: fu351
Originally posted by: fu351
Merged — thank you for turning four scattered acceptance criteria into one contract. Two decisions here were exactly right: having
assert_json_stdoutreturn the parsed value so callers assert on content without re-parsing, and documenting that--jsonand--jsonlare genuinely different shapes instead of papering over the difference. The explicit "shape only — each command keeps its own redaction assertions" note is the kind of safety framing this repo runs on.I pushed one commit to your branch before merging (
9fbee0b) — full disclosure, root causes first:doberman status --json, and your "all four modes" framing inherited that gap.statusgained--jsonincli/main.pybut nobody added it to the docs table, so the new section undercounted. It's now five modes, withstatusfolded into the table and the conventions section.policy-history --jsonparagraph under-described the ledger row. It listed timestamp/key/values/actor, but the omitted fields —classificationandapproved(denied weakening attempts are recorded too) — are the poisoning signal, the most security-relevant part of that ledger. The doc now names the real columns fromread_policy_changes().mainplus your additions, so the PR now carries only the new section and the helper. Your content is unchanged.Your validation held up on my side too: 51 json-selected tests green on the rebuilt branch.
Next one, if you're up for it: #193 (
level-5) — audit and document every CLI exit code. It's the same muscle you used here: read what the commands actually do, state the contract once, catch the places the docs drifted. You just proved you're good at exactly that.