Menu

#396 docs(cli): define shared JSON-output contract in CLI.md and conftest.py (Issue #192)

closed
nobody
None
2026-08-17
2026-08-17
Anonymous
No

Originally created by: Maqbool61

What

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.

Validation

pytest tests/ -k "json" -v → 51 passed
ruff check . → all checks passed
No existing test modified, no command output changed.

Related

Tickets: #192
Tickets: #193

Discussion

  • Anonymous

    Anonymous - 2026-08-17

    Ticket changed by: fu351

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-08-17

    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_stdout return the parsed value so callers assert on content without re-parsing, and documenting that --json and --jsonl are 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:

    1. The flag table predates doberman status --json, and your "all four modes" framing inherited that gap. status gained --json in cli/main.py but nobody added it to the docs table, so the new section undercounted. It's now five modes, with status folded into the table and the conventions section.
    2. The policy-history --json paragraph under-described the ledger row. It listed timestamp/key/values/actor, but the omitted fields — classification and approved (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 from read_policy_changes().
    3. An editor pass had stripped blank lines from untouched sections in both files, which makes blame noisy for future archaeology. I rebuilt the diff from main plus 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.

     

Log in to post a comment.