Skip to content

feat: fallow's exit-code and JSON output contract, gates, hallow schema - #22

Merged
sarob merged 24 commits into
mainfrom
feat/exit-codes-json-envelope
Oct 12, 2026
Merged

sarob merged 24 commits into
mainfrom
feat/exit-codes-json-envelope

Conversation

@sarob

@sarob sarob commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #21 (and through it on #11–#20). The base branch is feat/finding-ids-and-baselines, so this diff is one commit (a54a6fb). Merge #21 first, with a merge commit; GitHub then retargets this PR to main.

Problem

  • Exit codes didn't follow the documented gating:
    • hallow check exited 0 on error-severity findings unless --ci was given;
    • a bad config or an unknown --format produced a Python traceback, with exit 1 (the same code as "findings");
    • a missing --config file was a traceback too.
  • --format json wrote whatever model_dump produced:
    • no kind or version field;
    • the internal fix object instead of the actions a script can take;
    • no list of which gates passed;
    • health and dupes JSON were bare lists and dicts with no shared shape.
  • There was no machine-readable description of the CLI.
  • SARIF, CodeClimate and GitHub-annotation output reported every import cycle twice: once from its circular-dependencies finding and again from results.cycles. GitHub annotations also repeated every clone group, and compact output repeated cycles.

Change

Ports fallow's exit-code contract (crates/cli/src/exit_codes.rs, schema.rs) and JSON output (docs/output-schema.json).

Exit codes (hallow.exit_codes)

Code Meaning
0 No enforced gate failed
1 An enforced gate failed
2 Invalid input or runtime error
3 A requested resource is unavailable (the --config file does not exist)
  • check, security and bare hallow exit 1 on error-severity findings without any flag.
  • --fail-on-issues counts warn-severity findings too.
  • --ci means --format sarif --fail-on-issues --quiet; an explicit --format wins.
  • --quiet silences status messages on stderr, never the output.
  • --fail-on-stale-baseline turns on enforcement of the stale-baseline gate.
  • With --format json, an error raised while a command runs (bad config, unwritable --output, unknown format, refused baseline) is a document on stdout: {"error": true, "message", "exit_code", "code"}. Otherwise it prints error: … on stderr. Command-line usage errors caught by the argument parser (unknown option, invalid --boundaries, options before the command) stay text on stderr, with exit 2.

JSON documents (hallow.output.envelope, pydantic models)

  • Root fields: kind (check, security, health, dupes or baselines-prune), schema_version, version, elapsed_ms, gate_outcomes and next_steps.
  • gate_outcomes: {status: pass|warn|fail|skipped, enforced, observed}. The run exits 1 when an enforced gate has status fail.
  • next_steps: a list of {id, command, reason}. Each is a read-only, shell-quoted command carrying the run's effective project root and config as absolute paths, so it runs as written from any directory.
  • Findings: finding_id, symbol and actions[] ({type, auto_fixable, description, comment | config_key | value}) replace the internal fix object.
  • MCP: the analyze tool returns the same check document.

hallow schema

  • Prints the commands, flags (type, short form, default, possible values), output formats, exit codes, rules with their default severities, suppression syntax and MCP tools.
  • Commands, flags, types and declared defaults are read from the live CLI definitions. Where a declared default is empty and the command applies one itself (--format defaults to human), the effective default is given in the flag's help text, not in default. The allowed values for --format and --mode come from hallow.cli.options, which the commands validate against. The --boundaries values listed there are a separate tuple, checked against the preset table by get_preset; tests pin the manifest's --format and --mode values, and nothing checks the --boundaries tuple against the preset table.
  • hallow schema --output-schema prints the JSON Schema of every document. It is committed as docs/output-schema.json, and a test fails when the file is stale.

Behaviour changes

  • Exit 1 without --ci. hallow check with no flags now exits 1 on error-severity findings.
  • --ci fails on warnings. It now also fails on warn-severity findings, and its default output is SARIF. Both the bundled workflow (hallow check --format github --ci) and the pre-commit hook (hallow check --ci) will fail on warnings.
  • JSON shape. The check JSON is now a document: findings sit under findings with actions, and counts under summary. The top-level fix / total_issues layout is gone.

Verification

  • tests/test_cli_contract.py (12 tests) covers:
    • exit 1 on errors with no flag;
    • exit 0 when clean;
    • warnings with and without --fail-on-issues;
    • the document's root fields, actions and next_steps;
    • --ci producing SARIF, with an explicit format winning;
    • the JSON error document with exit 3;
    • exit 2 for bad TOML, an unknown format and an unknown dupes mode;
    • the stale-baseline gate, enforced only with the flag;
    • --quiet silencing status but not output;
    • the health and dupes documents;
    • the schema manifest;
    • the committed output schema being current.
  • The output-format fixture now carries the cycle's finding, as real analysis does, and asserts the cycle is emitted once.
  • 165 tests pass on Python 3.14; ruff check and ruff format are clean.
  • On hallow's own source: exit 0, and exit 1 with --fail-on-issues (warnings only).

sarob added 2 commits October 12, 2026 07:11
…ema`

Exit codes (hallow.exit_codes):
- 0 no enforced gate failed; 1 an enforced gate failed; 2 invalid input or
  runtime error; 3 resource unavailable (--config file missing)
- check, security and bare `hallow` exit 1 on error-severity findings by
  default; previously only with --ci
- --fail-on-issues counts warn-severity findings too; --ci is
  --format sarif --fail-on-issues --quiet (explicit --format wins);
  --quiet silences stderr status, never output
- --fail-on-stale-baseline enforces the stale-baseline gate
- errors under --format json are {"error": true, message, exit_code, code}
  on stdout; otherwise `error: ...` on stderr; no tracebacks for bad
  config, unknown formats or modes, missing files

JSON documents (hallow.output.envelope, pydantic models):
- root kind (check, security, health, dupes, baselines-prune),
  schema_version, version, elapsed_ms, gate_outcomes{status, enforced,
  observed}, next_steps[{id, command, reason}]
- findings carry finding_id, symbol and actions[{type, auto_fixable,
  description, comment|config_key|value}] instead of the internal `fix`
- health and dupes JSON were bare dicts/lists; now typed documents
- MCP `analyze` returns the same check document

`hallow schema` prints commands, flags, formats, exit codes, rules,
suppression syntax and MCP tools, built from the live CLI definitions.
`hallow schema --output-schema` prints the JSON Schema of every document;
docs/output-schema.json is committed and a test fails when it is stale.

Also: SARIF, CodeClimate and GitHub annotations reported each cycle twice
(once from its finding, once from results.cycles) and GitHub annotations
each clone group twice; compact output repeated cycles. They now emit
findings only.
@sarob

sarob commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Adversarial review — baseline-orchestrator-codex (Codex, gpt-6-astra), round 1 at 97df907

Posted verbatim. Citations of the form evidence/pr/hallow/22/diff.patch:N are line numbers in this PR's diff against its base branch at 97df907.


What the PR claims

The reviewed head is 97df9074cddea041aeb304304aba22e1d888d6bb, based on #21 at 1a3df718704253be95708e4afee8c0392e932c37. Its own commit is a54a6fb; seven subsequent base merges include three conflict resolutions. (evidence/pr/hallow/22/head.json:1)

The body makes these claims, all recorded in evidence/pr/hallow/22/metadata.json:1:

  • The change ports fallow’s exit-code and JSON contracts.
  • Exit codes distinguish success (0), enforced gate failure (1), invalid input/runtime errors (2), and unavailable requested resources (3).
  • check, security, and bare hallow fail on errors without flags.
  • --fail-on-issues also fails on warnings.
  • --ci selects SARIF, warning enforcement, and quiet mode; explicit format wins.
  • Quiet mode silences status messages without silencing output.
  • Stale-baseline enforcement is opt-in.
  • Errors produce JSON on stdout when JSON is requested, otherwise an stderr message, without tracebacks.
  • JSON documents share kind, schema version, tool version, elapsed time, gates, and next steps.
  • Enforced failing gates determine exit 1.
  • Next steps are read-only commands that run as written.
  • Findings expose identity, symbol, and actions instead of the internal fix object.
  • MCP analyze returns the same check document.
  • The schema manifest describes commands, typed flags, short forms, defaults, possible values, formats, exit codes, rule defaults, suppressions, and MCP tools.
  • Live CLI definitions prevent manifest drift.
  • Output JSON Schema is generated and committed, with a freshness test.
  • Cycles are no longer duplicated in SARIF, CodeClimate, GitHub, and compact output; GitHub clone groups are no longer repeated.
  • Existing users see changed default exit behavior, warning enforcement under CI, SARIF as CI output, and a changed JSON layout.
  • Twelve contract tests cover the listed behavior, and the output fixture checks cycle deduplication.
  • Local verification passed 165 tests on Python 3.14 and both ruff checks; self-analysis returned 0 normally and 1 with warning enforcement.
  • feat: stable line-free finding IDs and key-based baselines #21 must merge first with a merge commit, after which this PR can target main.

What the diff shows

Backed: Default error enforcement, optional warning enforcement, CI defaults, and explicit-format precedence are implemented by _ci_defaults, findings_gate, and _exit_for. Bare invocation and security use those paths. (evidence/pr/hallow/22/diff.patch:1250,1261,1575,1638,1984,2012,2616)

Backed: Baseline filtering precedes gate evaluation; stale enforcement is controlled by the new flag. Quiet status handling leaves the result output intact. Baseline warnings deliberately remain visible. (evidence/pr/hallow/22/diff.patch:1636,1640,1655,1663,2630)

Partly backed: Error mapping handles HallowError, FileNotFoundError, TOML decoding, and pydantic validation. It does not cover ordinary filesystem errors or CLI parsing errors outside the command body. The unconditional no-traceback/JSON-error promise is false. (evidence/pr/hallow/22/diff.patch:1176,1201,1238)

Partly backed: Check/security and dupes have the claimed envelope. Health has no gate_outcomes. Prune has no elapsed_ms, gate_outcomes, or next_steps; prune returns exit 1 directly without recording a failing gate. (evidence/pr/hallow/22/diff.patch:2461,2476,2486,2513,2147)

Backed: Finding serialization replaces fix with actions and preserves identity and symbol. Partly backed: MCP uses the same model but passes empty gates and zero elapsed time, unlike the CLI’s computed findings gate. (evidence/pr/hallow/22/diff.patch:2546,2599,2337,1638)

Not backed as stated: Next steps omit the originating root/config and interpolate a baseline path without quoting. (evidence/pr/hallow/22/diff.patch:2641,2647,2656,2664)

Partly backed: Manifest commands/options come from Typer, and rule defaults/MCP names come from live registries. Format values are manually listed, --format and --mode are strings rather than choices, and the manifest reads possible values only from the option type. The manifest therefore omits these flags’ allowed values and the effective human format default. “Cannot drift” is too broad. (evidence/pr/hallow/22/diff.patch:1094,1800,1845,2205,2208,2240,2266)

Backed: Schema generation and the committed-file freshness assertion exist. That assertion verifies synchronization with the models, not compliance with the promised envelope. (evidence/pr/hallow/22/diff.patch:2696,2967)

Backed: The redundant cycle and clone-group emission loops are removed. The cycle fixture now includes both the finding and auxiliary cycle data; reverting SARIF deduplication would produce four results and fail its three-result assertion. (evidence/pr/hallow/22/diff.patch:2349,2733,2748,2771,2983,2998)

Backed as intentional compatibility changes: Default exit status, CI warning enforcement/output, and finding JSON structure change. README documents them. (evidence/pr/hallow/22/diff.patch:18,1575,1644,2427)

Verification: The twelve tests exist and generally invoke the CLI on temporary projects. Current staged checks pass lint, self-check, and Python 3.11–3.14 tests. The workflow installs from the checkout and runs coverage, both ruff checks, and self-analysis; the configured coverage floor is 80%. The unpublished-PyPI failure is obsolete for this head. The exact historical count of 165 and the warning-enforced self-analysis result remain author claims: current self-check does not use --fail-on-issues. (evidence/pr/hallow/22/diff.patch:2835,2967; evidence/pr/hallow/22/checks.txt:3; evidence/pr/hallow/22/context/ci.yml:22; evidence/pr/hallow/22/context/ci.yml:30; evidence/pr/hallow/22/context/ci.yml:46; evidence/pr/hallow/22/context/ci.yml:63; evidence/pr/hallow/22/context/pyproject.toml:72)

Not independently established: Equivalence to fallow and historical problem statements are not proved by this diff. The staged change does establish the removed implementation and its replacement, not the external contract’s full requirements. (evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/diff.patch:1616,1646,2722)

Attacks

  1. Default behavior changes: confirmed and documented. An existing plain check now exits 1 on errors; an existing --ci invocation now fails on warnings and emits SARIF unless explicitly overridden. Standalone dupes also gains finding-based failure behavior. These are deliberate changes, not undisclosed regressions. (evidence/pr/hallow/22/diff.patch:27,1575,1644,1830,1869)

  2. Error-contract escape: blocker. With a valid project, hallow check --root PROJECT --format json --output EXISTING_DIRECTORY reaches Path.write_text and raises IsADirectoryError. _guarded does not catch it. Permission errors likewise escape. A script receives neither the advertised JSON error nor the promised runtime-error exit 2. Add behavior tests for output/config I/O failures and handle expected operational exceptions. Typer validation also occurs outside this wrapper, so a bad boundary preset or malformed option does not follow the universal JSON-error promise. (evidence/pr/hallow/22/diff.patch:1176,1238,1152,1705)

  3. Generated commands: blocker. A stale baseline named baseline old.json generates two shell arguments instead of one. A literal filename containing $(...) is emitted as shell substitution if a consumer executes the advertised command. Hallow itself does not execute that string, but the promised read-only command is unsafe to execute as written. In addition, analysis run with --root PROJECT --config CUSTOM recommends commands that use the current directory/default config instead. Quote arguments and retain analysis context, or return a structured argument vector with an explicit execution context. (evidence/pr/hallow/22/diff.patch:2641,2647,2656,2664,2671)

  4. Shared document and gate contract: blocker. Generic consumers cannot read the advertised root fields from health/prune. Prune can exit 1 with no gate explaining it, and MCP check output has empty gates even when findings would fail the CLI. Implement consistent fields and gate outcomes, or explicitly narrow the published contract before merging. (evidence/pr/hallow/22/diff.patch:31,32,2147,2337,2476,2513)

  5. Tests that validate construction rather than behavior: gaps confirmed. The next-step test asserts the literal command string but never executes it, even though the test itself analyzes a non-current root. It therefore approves the lost-context bug. The schema freshness test passes with the incomplete models. Health/dupes checks verify only a few fields and never require the shared envelope. The CI test uses an error finding, so removing CI’s warning-enforcement behavior would not make that test fail. Add warning-only CI, executable next-step, and per-kind envelope assertions. Existing exit/gate tests otherwise exercise analysis output and would detect reverting their principal changes. (evidence/pr/hallow/22/diff.patch:2835,2855,2866,2879,2886,2945,2967)

  6. False positives/negatives and sibling interactions: Removing auxiliary cycle/clone emission makes the affected formats follow filtered findings. The feat: stable line-free finding IDs and key-based baselines #21 analyzer retains raw cycles/duplicates separately while applying plugin and source suppressions to findings, so the removal also prevents these formats from resurrecting suppressed issues. This interaction is correct for the staged pipeline. It does remove output for manually constructed results containing only raw cycle data, which is an API compatibility effect; the evidence does not establish a requirement to preserve that usage. (evidence/pr/hallow/21/context/head-files/src__hallow__core__analyzer.py.01.txt:50,57,63,69; evidence/pr/hallow/22/diff.patch:2346,2748,2768)

    A separate inconsistency arises in standalone dupes: the new findings gate receives raw detector findings without the analyzer’s suppression pass. Suppressed clone findings can therefore fail dupes --fail-on-issues while being absent from full check. Align standalone suppression behavior or explicitly document/test this difference. (evidence/pr/hallow/22/diff.patch:1852; evidence/pr/hallow/21/context/head-files/src__hallow__core__analyzer.py.01.txt:57,63)

  7. Unsupported body claims: Uniform root fields, universally structured errors, runnable next steps, equivalent MCP gates, and a drift-proof complete manifest are not supported as stated. The specific failures are above. In particular, the manifest has no per-flag enum for mode/format despite runtime restrictions. (evidence/pr/hallow/22/diff.patch:1845,2208,2337,2476,2513,2656)

  8. Merge resolutions: The CLI resolution preserves rejection of options before subcommands; the README resolutions preserve the new exit contract while incorporating the new CI description. No dropped safeguard is apparent in those resolutions. However, the preserved pre-subcommand rejection raises Typer BadParameter outside _guarded, another exception to the JSON-error promise. The actual conflicts are CLI and README conflicts, not evidence of unresolved detector conflicts. (evidence/pr/hallow/22/merge-resolution.patch:14; evidence/pr/hallow/22/merge-resolution.patch:150; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1286)

  9. Stacked-base attack: This review covers the diff on the specified feat: stable line-free finding IDs and key-based baselines #21 head, not a standalone patch on main. Identity imports, BaselineStaleness, and prune integration require the inherited base API. Applying only the own commit without that implementation can fail imports or baseline behavior. Merging the whole existing branch instead carries the inherited changes with it, including any sibling intentionally left unmerged. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1839,2113,2397)

    Squashing feat: stable line-free finding IDs and key-based baselines #21 or a sibling does not inherently break runtime if the final tree is identical. It does remove ancestry that this stack relies on to identify already-merged work: inherited commits can remain in PR history/diffs, and later edits can conflict with those inherited versions. If any dependency is changed or withheld, rebuild/rebase feat: fallow's exit-code and JSON output contract, gates, hallow schema #22 onto the accepted tree, review the resulting diff and resolutions, and rerun checks. Do not treat current green checks or mergeability as validation of that new combination. Any downstream feat(audit): gate a change on the findings it introduces #23 integration also needs the corrected feat: fallow's exit-code and JSON output contract, gates, hallow schema #22 tree; this case does not establish its resulting behavior. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/checks.txt:3)

Earlier reviews

There are no staged reviews, review comments, or issue comments. There are no recorded change requests to mark closed. (evidence/pr/hallow/22/reviews.json:1; evidence/pr/hallow/22/review-comments.json:1; evidence/pr/hallow/22/issue-comments.json:1)

Verdict

NOT READY.

  • Handle operational errors consistently with the promised exit/JSON contract. (evidence/pr/hallow/22/diff.patch:1176,1238)
  • Make generated next steps safe and preserve the originating analysis context. (evidence/pr/hallow/22/diff.patch:2647,2656,2664)
  • Reconcile the shared envelope and gate contract across CLI documents and MCP. (evidence/pr/hallow/22/diff.patch:2147,2337,2476,2513)
  • Resolve standalone dupes gating on findings that bypass the suppression pass used by full analysis. (evidence/pr/hallow/22/diff.patch:1852; evidence/pr/hallow/21/context/head-files/src__hallow__core__analyzer.py.01.txt:63)

The manifest omissions and test gaps also need correction or narrower claims; current passing CI does not test away these counterexamples. (evidence/pr/hallow/22/diff.patch:2208,2879,2945; evidence/pr/hallow/22/checks.txt:3)

I could not write review.md with the available read-only tools; I had no execution facility, external fallow sources, detailed CI logs, or rebuilt post-merge #23 tree to verify the remaining points.

…O errors

Review findings on #22:
- Error contract: OSError (an --output that is a directory, permission
  denied) escaped as a traceback. It is now the JSON error document, exit
  2, code HALLOW_IO_ERROR. A refused or missing baseline in `baselines
  prune` is an error document, not a prune document. Usage errors caught
  by the argument parser stay text on stderr with exit 2; the README now
  says so instead of promising JSON for them.
- next_steps: commands are built with shlex.join and carry the run's
  --root/--config, so a baseline path with a space or `$(...)` is one
  quoted argument and the command analyses the same project from any
  directory.
- Envelope: all documents share one base model (kind, schema_version,
  version, elapsed_ms, gate_outcomes, next_steps). health and
  baselines-prune now carry every field; prune reports a `prune-check`
  gate (enforced with --check). MCP `analyze` and the JSON formatter
  report the default findings gate instead of an empty one.
- `dupes` applies `# hallow-ignore` suppressions like the full analysis,
  so a suppressed clone cannot fail `dupes --fail-on-issues`.
- `hallow schema` publishes possible values for --format, --mode and
  --boundaries per command.

Tests: next steps executed from another directory with a spaced config
and baseline path; warnings-only --ci exits 1; envelope fields on every
document kind; I/O error and refused-prune error documents; MCP gate;
dupes suppression; manifest values. Seven fail on the previous head.
@sarob

sarob commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner Author

Response to the round-1 review (code changes are in f7ee5b1):

  • Error-contract escape.
    • Fixed for run-time errors: OSError (an --output that is a directory, permission denied) is now the JSON error document, with exit 2 and code HALLOW_IO_ERROR.
    • A refused or missing baseline in baselines prune is now an error document rather than a prune document.
    • Usage errors caught by the argument parser (unknown option, invalid --boundaries, options before the command) stay as text on stderr with exit 2. The README states that instead of promising JSON for them.
    • Tests: test_io_errors_are_json_error_documents and test_refused_prune_is_an_error_document.
  • Generated commands. Fixed. next_steps commands are built with shlex.join and carry the run's --root/--config. Test: test_next_steps_run_as_written_from_another_directory analyses a project with a config and a baseline whose paths contain spaces, chdirs elsewhere, then shlex.splits and runs every suggested command.
  • Shared document and gate contract. Fixed.
    • All documents inherit one Envelope model: kind, schema_version, version, elapsed_ms, gate_outcomes, next_steps.
    • health and baselines-prune now carry every field, and prune reports a prune-check gate (enforced with --check, which is what makes it exit 1).
    • MCP analyze and the JSON formatter report the default findings gate instead of an empty one.
    • Tests: test_every_document_kind_has_the_envelope_fields and test_mcp_analyze_reports_the_findings_gate.
  • Standalone dupes bypassing suppressions. Fixed. dupes applies # hallow-ignore like the full analysis. Test: test_dupes_honours_suppressions; the clone data is still reported, and the suppressed finding neither appears nor fails --fail-on-issues.
  • Manifest values. hallow schema publishes possible_values for --format, --mode and --boundaries per command. Test: test_manifest_publishes_allowed_values.
  • Test gaps. Added test_ci_fails_on_warnings_only. The next-step test now executes commands instead of comparing strings, and envelope fields are asserted per document kind.
  • Raw cycles-only results through the API. Agreed that this is an API compatibility effect. The formatters now follow findings, which is what keeps suppressed cycles from reappearing in SARIF, GitHub annotations and CodeClimate.
  • Stack. feat(audit): gate a change on the findings it introduces #23 is being re-merged onto this head and re-run before anything is merged.

Seven of the new tests fail on the previous head (3e9c5ae).

sarob added 2 commits October 12, 2026 08:07
f7ee5b1 had cli/manifest.py import FLAG_VALUES from cli/main.py while
main.py imports manifest.py, so hallow's own self-check reported a
circular-dependencies error (exit 1 under the new exit-code contract).
The option value tuples now live in hallow.cli.options, imported by both.
sarob added a commit that referenced this pull request Oct 12, 2026
Once security exits 1 on error-severity findings (#22), CliRunner reports
SystemExit(1) as result.exception. The test now rejects any exception
other than SystemExit and checks the exit code is 0 or 1, alongside the
control/suppressed assertions.
@sarob

sarob commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Adversarial review — baseline-orchestrator-codex (Codex, gpt-6-astra), round 2 at 590674e

Posted verbatim. Citations of the form evidence/pr/hallow/22/diff.patch:N are line numbers in this PR's diff against its base branch at 590674e.


Round-1 findings

Reviewed head: 590674e23e582b208b47749ecd8c8c1b43f258d1, based on #21 at 5e1095f2392ca8fc5180e33ca570228c61d3dbee. The whole-PR diff is against that base branch. The round-2 delta excludes inherited base changes. The own commits are a54a6fb, f7ee5b1, and 1aba261. (evidence/pr/hallow/22/head.json:1)

  1. Operational-error blocker: closed for the reported failures; error-contract claim partly closed. _guarded now catches OSError, including directory outputs and permission failures, and emits exit 2 with HALLOW_IO_ERROR. A behavior test exercises the directory-output counterexample. Parser errors remain text on stderr, explicitly documented in the revised README. The PR body and exported exit-code description still promise JSON errors without that exception. (evidence/pr/hallow/22/diff.patch:1200–1244,2414–2415,3165–3171; evidence/pr/hallow/22/round2-delta.patch:13–14; evidence/pr/hallow/22/metadata.json:1)

  2. Generated-command blocker: partly closed. shlex.join closes the whitespace and POSIX shell-substitution defects. Explicit root/config arguments are carried forward. However, _context copies their original spelling rather than resolving them and omits an implicit root. check --root ./project -c ./custom.toml -f json therefore recommends commands whose targets change after chdir. MCP still supplies no context at all. The new claim that commands work from any directory is false. (evidence/pr/hallow/22/diff.patch:1729–1737,2446,2753–2786; evidence/pr/hallow/22/round2-delta.patch:10)

  3. Shared-envelope and gate blocker: closed. All five successful document kinds inherit the six common fields. Prune records a gate matching its exit-1 condition. MCP and the generic JSON formatter now compute the default findings gate. Error documents remain the explicitly separate error shape. The broader MCP equivalence claim remains partly closed: MCP still reports literal elapsed time 0 and lacks next-step execution context. (evidence/pr/hallow/22/diff.patch:2210–2225,2446,2572–2648,2801–2833,2865)

  4. Standalone dupes suppression blocker: closed for the reported source-suppression inconsistency. Extraction and apply_suppressions(..., report_stale=False) now precede identity stamping and gating. The new test requires suppressed findings to disappear and exit 0 while clone data remains present. (evidence/pr/hallow/22/diff.patch:1909–1931,3190–3198)

  5. Test gaps: partly closed. Warning-only CI enforcement and per-kind envelope assertions now exercise CLI output. The next-step test executes parsed arguments instead of comparing a constructed string, but supplies only absolute paths. It checks acceptable exit codes rather than proving the commands inspected the original project. It therefore misses the remaining context defect. The schema freshness test remains a synchronization test; the separate envelope test now covers its earlier blind spot. (evidence/pr/hallow/22/diff.patch:3104–3109,3119–3162)

  6. Manifest omissions and drift claim: partly closed. Per-command format and dupes-mode choices now come from shared constants. The effective human format default remains absent: _flag omits None, while _check_format converts it to human. Boundary choices and the top-level format list remain manually enumerated, so the absolute claim that the manifest cannot drift remains unsupported. (evidence/pr/hallow/22/diff.patch:1247–1254,2282–2287,2296–2306,2348–2358,2376–2387)

  7. Default compatibility changes: closed as documented intentional changes, not withdrawn. Default error enforcement, CI warning enforcement and SARIF selection remain. Standalone dupes still gates findings. Round 2 changes suppression handling, not these policies. (evidence/pr/hallow/22/diff.patch:1606–1609,1669,1914–1931,2728–2739; evidence/pr/hallow/22/metadata.json:1)

  8. Cycle/clone formatter interaction and raw-cycle API compatibility: closed as an acknowledged tradeoff. The whole PR still removes the auxiliary emission loops. The author explicitly accepts that raw-cycle-only API results no longer produce those findings in these formats. Round 2 does not change those loops. (evidence/pr/hallow/22/diff.patch:2454–2473,2869–2875,2884–2898,2907–2938; evidence/pr/hallow/22/issue-comments.json:1)

  9. Merge-resolution concern: closed for the known parser-error issue through documented scope. The revised contract expressly excludes options before subcommands from JSON error handling. Every base merge listed after the round-1 head has zero conflict-resolved hunks. This does not validate a future rebuilt stack. (evidence/pr/hallow/22/diff.patch:1203–1207; evidence/pr/hallow/22/head.json:1)

  10. Stacked-base condition: open. feat: fallow's exit-code and JSON output contract, gates, hallow schema #22 remains based on feat: stable line-free finding IDs and key-based baselines #21 and imports its identity/baseline APIs. The author’s promise to rebuild feat(audit): gate a change on the findings it introduces #23 is not evidence of a completed downstream integration. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1896,2186,2508; evidence/pr/hallow/22/issue-comments.json:1)

  11. Historical and external verification claims: open as evidence limits. Current CI substantiates passing lint, self-check and tests on four Python versions. It does not independently establish the historical 165-test run, warning-enforced self-analysis, exact equivalence to fallow, or the author’s claim that seven new tests fail on the previous head. The workflow’s self-check has no warning-enforcement flag. (evidence/pr/hallow/22/checks.txt:3–8; evidence/pr/hallow/22/context/ci.yml:63; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1)

The remaining unsupported claims are runnable next steps, complete MCP equivalence, universal JSON errors, and a complete drift-proof manifest. Uniform successful-document fields and default MCP gates are now supported by code. (evidence/pr/hallow/22/diff.patch:1729–1737,2282–2287,2446,2572–2648,2801–2827)

What the PR claims

The following body claims remain in the staged metadata. (evidence/pr/hallow/22/metadata.json:1)

  • The PR ports fallow’s exit-code and JSON contracts.
  • Exit codes distinguish success, enforced failure, invalid input/runtime failure, and unavailable resources.
  • Check, security and bare invocation fail on errors without flags.
  • --fail-on-issues also enforces warnings.
  • CI selects SARIF, warning enforcement and quiet mode; explicit format wins.
  • Quiet mode preserves result output.
  • Stale-baseline enforcement is opt-in.
  • Errors produce JSON on stdout when JSON is requested, otherwise stderr text, without tracebacks.
  • Successful JSON documents share kind, schema version, tool version, elapsed time, gates and next steps.
  • Enforced failing gates determine exit 1.
  • Next steps are read-only commands that run as written.
  • Findings expose identity, symbol and actions instead of the internal fix object.
  • MCP analyze returns the same check document.
  • The manifest describes commands, typed flags, short forms, defaults, possible values, formats, exits, rule defaults, suppressions and MCP tools.
  • Live CLI definitions prevent manifest drift.
  • Generated output schema is committed and freshness-tested.
  • Cycles and clone groups no longer receive the listed duplicate formatter emissions.
  • Default exits, CI behavior and JSON shape intentionally change.
  • Twelve contract tests and the formatter fixture cover the listed behavior.
  • Local verification passed 165 tests and both ruff checks; self-analysis returned 0 normally and 1 with warning enforcement.
  • feat: stable line-free finding IDs and key-based baselines #21 must merge first with a merge commit; the PR is described as one own commit.

The response additionally claims that all four blockers are fixed, commands work after changing directory, manifest values and test gaps are corrected, seven new tests fail on the previous head, and #23 is being rebuilt. The revised README strengthens the command promise to “from any directory” and narrows JSON errors to command execution rather than parser errors. (evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/round2-delta.patch:10–14)

What the diff shows

Backed by the round-2 changes: ordinary I/O error translation; shared successful-document fields; prune gate reporting; default MCP/formatter findings gates; dupes source suppression before gating; shared format/mode values; warning-only CI and per-kind envelope tests. (evidence/pr/hallow/22/round2-delta.patch:233–236,329–337,363–388,450–461,494–557,619–637,717–781)

Partly backed: runnable commands. POSIX shell quoting and explicit argument propagation are implemented; absolute execution context and MCP context are not. The “from any directory” claim exceeds the implementation. (evidence/pr/hallow/22/round2-delta.patch:257–263,471–472,565–598)

Partly backed: the error and manifest claims. README now acknowledges parser text errors, but the PR body and exported exit-code description remain broader. Allowed values are supplied, but effective format defaults and a guarantee against drift are not. (evidence/pr/hallow/22/round2-delta.patch:13–14,413–432,450–461; evidence/pr/hallow/22/diff.patch:2282–2287,2348–2358,2414–2415; evidence/pr/hallow/22/metadata.json:1)

Backed and unchanged from round 1: exit/CI enforcement, quiet handling, opt-in stale gating, finding actions, schema generation/freshness and formatter deduplication. These are retained whole-PR findings, not new round-2 changes. (evidence/pr/hallow/22/diff.patch:1606–1609,1669–1698,2711–2750,2836–2853,2884–2938,3104–3109)

Verification backed at this head: lint, self-check and Python 3.11–3.14 tests pass. The workflow installs from the checkout and runs pytest coverage, ruff check and ruff format. The former unpublished-PyPI failure does not apply. Historical test counts, the previous-head mutation result and external fallow equivalence remain unverified. The body’s one-commit description is stale; head.json lists three own commits. (evidence/pr/hallow/22/checks.txt:3–8; evidence/pr/hallow/22/context/ci.yml:22–33,44–49,60–63; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1)

Attacks

  1. Existing defaults. Round 2 changes JSON consumers’ observable results: health/prune gain fields, MCP/formatter gates become populated, and refused/error prune results become error documents. Suppressed dupes no longer fail enforcement. These are the announced repairs. No additional severity-policy default change appears in the delta. (evidence/pr/hallow/22/round2-delta.patch:329–337,363–388,471–472,494–557,619–637)

  2. Tests that permit the defect. The new command test uses absolute tmp_path values and accepts either exit 0 or 1. A command inspecting a different valid project can satisfy that exit assertion. Add relative-root/config inputs, omitted-root inputs and an MCP-originated recommendation, execute after chdir, and assert the target-specific result. The warning-only CI test would detect removal of CI warning enforcement; the envelope and I/O tests exercise actual CLI documents. (evidence/pr/hallow/22/round2-delta.patch:694–746,758–762)

  3. False positives and false negatives. The new suppression call removes the reported dupes false-positive gate failure while retaining clone data. report_stale=False avoids reporting stale directives for rules standalone dupes did not run. No additional detector algorithm changes appear in the delta. The remaining command-context defect can make follow-up analysis report another project’s findings or miss the intended project entirely. (evidence/pr/hallow/22/round2-delta.patch:329–337,565–598,765–773)

  4. Unsupported claims. “From any directory” is disproved by the unchanged relative argument strings. For a project with an auto-fixable finding, check --root ./project -c ./custom.toml -f json produces a preview command with those same relative arguments. Run it in another directory and it addresses different paths. A run without explicit root emits no root at all; MCP also omits context. Shell quoting fixes interpretation of arguments, not their filesystem meaning. Normalize the effective root/config and baseline target at the originating run, and pass that context through MCP, or return an explicit execution directory with structured arguments. (evidence/pr/hallow/22/round2-delta.patch:257–263,471–472,565–598,619–631)

  5. Sibling interactions. The new dupes suppression pass uses the inherited extraction/suppression APIs; the new option module has no imports and removes the direct option-value dependency on CLI main. No new conflict resolution is recorded in this round’s base merges. This supports the staged combination, not arbitrary independent merges of fix(discovery): match default ignores at the top level, skip virtualenvs by marker #11–fix(types): stop counting cycles and duplicate groups twice in total_issues #20 or a rebuilt feat(audit): gate a change on the findings it introduces #23. (evidence/pr/hallow/22/round2-delta.patch:311–335,436–462; evidence/pr/hallow/22/head.json:1)

  6. Stacked-base squash attack. Squashing feat: stable line-free finding IDs and key-based baselines #21 does not inherently break runtime if the final tree is identical. It changes the ancestry used to identify inherited work, so this branch can retain inherited commits in its review history/diff. Applying only feat: fallow's exit-code and JSON output contract, gates, hallow schema #22’s own commits without the accepted dependency implementation can break identity/baseline integration. If feat: stable line-free finding IDs and key-based baselines #21 or any sibling is changed or withheld, rebuild feat: fallow's exit-code and JSON output contract, gates, hallow schema #22 on the accepted tree, review the resulting diff/resolutions and rerun checks. Current green checks cover only the staged stack. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1896,2186,2508; evidence/pr/hallow/22/checks.txt:3–8)

Earlier reviews

Formal reviews and inline review comments are empty. Issue comments contain the round-1 review and the author’s response. The response closes the ordinary I/O, shared-envelope/gate and dupes-suppression blockers. Generated-command context remains partly closed; manifest/default and documentation claims still need correction. The claimed seven-test previous-head result is not independently demonstrated by staged execution logs. (evidence/pr/hallow/22/reviews.json:1; evidence/pr/hallow/22/review-comments.json:1; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/diff.patch:1217–1220,1734–1737,1913–1916,2210–2214,2282–2287,2446,2753–2767)

Verdict

NOT READY at 590674e23e582b208b47749ecd8c8c1b43f258d1.

The remaining blocker is generated next-step context. Relative and implicit CLI roots/configs are not anchored to the originating run, and MCP next steps receive no context. The newly added health recommendation uses the same defective context builder. Preserve the effective execution context and add behavioral assertions for relative paths, omitted roots and MCP recommendations after changing directory. (evidence/pr/hallow/22/diff.patch:1729–1737,1825–1828,2446,2753–2786,3119–3139)

Also correct the remaining universal-error and drift-proof/default-manifest claims, and preserve the stack integration condition. Passing CI does not settle these counterexamples. (evidence/pr/hallow/22/diff.patch:2282–2287,2348–2358,2386–2387,2414–2415; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/checks.txt:3–8)

I could not write evidence/pr/hallow/22/review.md with the read-only tools; I had no execution facility, detailed CI logs, external fallow sources, previous-head test run, or rebuilt post-merge #23 tree.

Round-2 review: next-step commands repeated --root/--config as typed, so
`check --root ./project -c ./custom.toml` produced commands that address
other paths when run elsewhere; a run without --root emitted no root; MCP
emitted no context. The command now carries the run's effective project
root (also when it was found by walking up from the cwd) and config as
absolute paths, the prune suggestion's baseline path is absolute, and MCP
`analyze` passes its resolved root.

Tests: relative --root/--config and an implicit root, each command run
from another directory and shown to analyse the original project; MCP
next step carries the absolute root. Both fail on the previous head.
@sarob

sarob commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Response to the round-2 review (code changes are in dcda5be):

  • Blocker — next-step context. Fixed.
    • Commands now carry the run's effective project root as an absolute path, even when the root was found by walking up from the cwd, plus an absolute --config when one was given. The prune suggestion's baseline path is absolute too.
    • MCP analyze passes its resolved root.
    • test_next_steps_anchor_relative_and_implicit_roots runs check --root proj -c custom.toml from the parent directory and check with no --root from inside the project. It then runs each suggested command from a third directory and asserts that the command previews the original project's fix.
    • test_mcp_next_steps_carry_the_absolute_root covers the MCP path.
    • Both fail on 590674e.
  • Universal-error claim. The body now separates run-time errors (JSON error document) from parser usage errors (text on stderr, exit 2), matching the README.
  • Drift-proof manifest claim. The body now says which parts come from the live CLI, and that the allowed values come from hallow.cli.options, the same tuples the commands validate against.
  • Stack. Unchanged: feat: stable line-free finding IDs and key-based baselines #21 needs a merge commit, and feat(audit): gate a change on the findings it introduces #23 is re-merged onto this head and re-run before anything merges.

sarob added a commit that referenced this pull request Oct 12, 2026
Audit's next step now uses the effective-root context from #22 (absolute
--root); test asserts the suggested audit command targets the repo.
@sarob

sarob commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Adversarial review — baseline-orchestrator-codex (Codex, gpt-6-astra), round 3 at d1fea85

Posted verbatim. Citations of the form evidence/pr/hallow/22/diff.patch:N are line numbers in this PR's diff against its base branch at d1fea85.


Round-2 findings

Reviewed head: d1fea854b5d9974d1073fc13b5e0f218a06c33be, based on #21 at d8676daadccf560bcdf06ca5650116022acb5e83. The round-3 delta removes inherited base-branch changes. Its own new commit is dcda5be; the three subsequent base merges have zero conflict-resolved hunks. Citations to round3-delta.patch use the numbered delta chunk. Citations to diff.patch refer to the newly staged whole-PR diff. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/delta-chunks/01.txt:1)

  1. BLOCKER, generated-command context: closed for the reported CLI and MCP failures. _context now takes the loaded configuration and resolves its effective root, including an implicit root. Explicit config paths are absolute. Check, health and security use that context. MCP loads the configuration once and passes its resolved root into the document builder. Prune recommendations resolve their baseline path before serialization. The relative-root/config and omitted-root counterexamples from round 2 no longer retain directory-dependent target paths. (evidence/pr/hallow/22/round3-delta.patch:5–47,63–78,94–101)

  2. BLOCKER, operational errors: closed, retained. DOC, error-contract wording: partly closed. The current whole diff retains OSError translation and its directory-output test. The body now explicitly excludes parser usage errors from JSON handling. However, the exported exit-code description still says that bad flag values with JSON format produce a JSON document, without the parser exception. This remaining inconsistency is in the exported description, not the corrected body. (evidence/pr/hallow/22/diff.patch:1200–1244,2417–2418,3186–3192; evidence/pr/hallow/22/metadata.json:1)

  3. BLOCKER, shared envelope and gate reporting: closed, retained. Broader MCP equivalence: partly closed. Successful document kinds still inherit the common envelope, prune reports its gate, and MCP uses the default findings gate. Round 3 supplies MCP execution context. MCP still passes literal elapsed time zero. The body’s claim of the same check document is supported as a document-type claim; it does not establish equivalent timing telemetry. Clarifying that distinction remains a DOC item, not an analysis blocker. (evidence/pr/hallow/22/diff.patch:2213–2217,2457–2464,2591–2649,2829–2848)

  4. BLOCKER, standalone dupes source suppression: closed, retained. The current whole diff applies source suppression before identity stamping and gating. Its test checks both the absence of findings and exit zero while retaining clone data. Round 3 does not alter this path. (evidence/pr/hallow/22/diff.patch:1913–1934,3211–3219; evidence/pr/hallow/22/round3-delta.patch:1–144)

  5. Test gaps: partly closed. The new CLI test supplies relative root/config arguments and an omitted root, executes the resulting preview from another directory, and requires Would remove. It would detect reverting the reported CLI context fix. The MCP test reads an actual analysis document but only inspects its root argument; it does not execute the command after changing directory. The CLI test exercises the first recommendation, not every recommendation, and the baseline test still uses an absolute baseline path. These are remaining coverage boundaries, not demonstrated runtime failures. The author’s statement that the new test runs each suggested command is a DOC overstatement. (evidence/pr/hallow/22/round3-delta.patch:115–144; evidence/pr/hallow/22/diff.patch:3140–3160; evidence/pr/hallow/22/issue-comments.json:1)

  6. DOC, manifest omissions and drift claims: partly closed. The body no longer promises that the manifest cannot drift. Declared non-null defaults come from Typer, but the effective human format default remains absent as a structured default value. It is present in the copied help description. Boundary values remain separately enumerated in FLAG_VALUES, while runtime validation calls get_preset; the revised claim that commands use the same boundary tuples is inaccurate about implementation. The module docstring also retains “cannot drift.” No actual mismatch in the listed boundary values is demonstrated. (evidence/pr/hallow/22/diff.patch:2244–2247,2285–2287,2389–2390; evidence/pr/hallow/22/context/head-files/src__hallow__cli__main.py.01.txt:71–84; evidence/pr/hallow/22/metadata.json:1)

  7. Default compatibility changes: closed as intentional changes. Default error enforcement, CI warning enforcement and SARIF selection remain documented. Round 3 changes recommendation paths, not those policies. (evidence/pr/hallow/22/diff.patch:1606–1609,1669,2747–2758; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/round3-delta.patch:1–104)

  8. Cycle/clone formatter interaction and raw-cycle API compatibility: closed as previously acknowledged. The auxiliary emission loops remain removed. The author’s earlier response accepts the raw-cycle-only API tradeoff. Round 3 adds no formatter change. This is retained disposition, not a new limitation discovered in this delta. (evidence/pr/hallow/22/diff.patch:2476–2491,2894–2896,2909–2919,2932–2959; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/round3-delta.patch:1–144)

  9. Merge-resolution concern: closed for the reported parser issue. The body now states the parser exception, and no new conflict resolution is recorded after round 2. That evidence does not validate a future rebase. (evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/head.json:1)

  10. Stacked-base integration: open as a future-tree verification boundary. The branch still depends on feat: stable line-free finding IDs and key-based baselines #21. The author’s statement about rebuilding feat(audit): gate a change on the findings it introduces #23 is not a staged downstream tree or its checks. This does not establish a defect in the reviewed feat: fallow's exit-code and JSON output contract, gates, hallow schema #22 head and is not an additional BLOCKER under the severity rule. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1899,2189,2527; evidence/pr/hallow/22/issue-comments.json:1)

  11. Historical/external verification: open as evidence limits. DOC, historical descriptions: open. Current checks substantiate lint, self-check and Python 3.11–3.14 tests. They do not independently establish the historical 165-test run, warning-enforced self-analysis, fallow equivalence, or the claimed previous-head failures. The body still describes one own commit and twelve contract tests, while the current head lists four own commits and the test file contains subsequent additions. (evidence/pr/hallow/22/checks.txt:3–8; evidence/pr/hallow/22/context/ci.yml:63; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:3140–3259; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1)

What the PR claims

The current body makes the following claims. Each is recorded in evidence/pr/hallow/22/metadata.json:1.

  • It ports fallow’s exit-code and JSON contracts.
  • Exit codes distinguish success, enforced failure, invalid input/runtime errors and unavailable resources.
  • Check, security and bare invocation fail on error findings without flags.
  • --fail-on-issues additionally enforces warnings.
  • CI selects SARIF, warning enforcement and quiet mode; explicit format wins.
  • Quiet suppresses status messages without suppressing results.
  • Stale-baseline enforcement is opt-in.
  • Command-runtime errors use JSON stdout when JSON is requested; parser usage errors remain stderr text with exit 2.
  • Successful JSON documents share kind, schema version, tool version, elapsed time, gate outcomes and next steps.
  • Enforced failing gates determine exit 1.
  • Next steps are read-only, shell-quoted commands carrying absolute effective root and config paths and runnable from another directory.
  • Findings expose identity, symbol and actions instead of the internal fix object.
  • MCP analyze returns the same check document.
  • The manifest describes commands, flag types, short forms, defaults, allowed values, formats, exits, rule defaults, suppressions and MCP tools.
  • Commands, flags, types and defaults come from live CLI definitions; format, mode and boundary values come from shared option definitions used by commands.
  • Generated output schema is committed and freshness-tested.
  • The listed formatter emissions no longer duplicate cycles and clone groups.
  • Default exits, CI behavior and JSON shape intentionally change.
  • Twelve contract tests and the formatter fixture cover the listed cases.
  • Local verification passed 165 tests and both ruff checks; self-analysis returned 0 normally and 1 with warning enforcement.
  • feat: stable line-free finding IDs and key-based baselines #21 must merge first with a merge commit; the PR is described as one own commit.

The round-2 response additionally claims absolute implicit/relative CLI context, absolute baseline paths, resolved MCP context, two regression tests that fail on the previous head, corrected error/manifest wording and a downstream #23 rebuild. (evidence/pr/hallow/22/issue-comments.json:1)

What the diff shows

Backed by the round-3 delta: effective absolute CLI roots; absolute explicit config paths; absolute prune baseline paths; MCP configuration reuse and root propagation. The existing command builder still quotes arguments with shlex.join and uses fix --dry-run, prune --check and health analysis. These changes close the concrete round-2 recommendation failures without adding an execution or write path. (evidence/pr/hallow/22/round3-delta.patch:18–47,63–101; evidence/pr/hallow/22/diff.patch:2779–2818)

Backed and retained: exit/gate enforcement, CI format precedence, quiet status handling, opt-in stale gating, ordinary operational-error translation, successful-document fields, action serialization, schema generation/freshness and formatter deduplication. These are whole-PR confirmations used to assess prior findings, not new round-3 changes. (evidence/pr/hallow/22/diff.patch:1200–1244,1276–1282,1606–1609,1669–1698,2591–2649,2677–2741,2857–2874,2894–2959,3125–3129)

Partly backed: the manifest description. Live definitions supply command metadata and declared defaults; shared constants supply format and mode values. Effective format defaults are represented in help text rather than a structured default field. Boundary validation does not use the claimed shared tuple. These are the DOC qualifications described above. (evidence/pr/hallow/22/diff.patch:2272–2321,2379–2390; evidence/pr/hallow/22/context/head-files/src__hallow__cli__main.py.01.txt:71–84)

Partly backed: complete MCP equivalence and verification scope. MCP uses the same check model and gate computation but still reports zero elapsed time. The new CLI test demonstrates a preview in the original project; the new MCP test demonstrates the emitted root. Neither test file proves the author actually ran a previous-head comparison. (evidence/pr/hallow/22/diff.patch:2457–2464,2829–2848; evidence/pr/hallow/22/round3-delta.patch:115–144)

Backed by current CI evidence: lint, self-check and tests on Python 3.11–3.14 pass at the staged head. The workflow installs the checkout, runs pytest coverage and both ruff checks; coverage configuration sets an 80% floor. The former unpublished-PyPI failure does not apply. The self-check does not enforce warnings. (evidence/pr/hallow/22/checks.txt:3–8; evidence/pr/hallow/22/context/ci.yml:22–33,44–49,60–63; evidence/pr/hallow/22/context/pyproject.toml:70–72)

Not established by this diff: exact fallow equivalence, historical local results and a verified downstream #23 tree. The one-commit and twelve-test descriptions are stale DOC items. (evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/diff.patch:3140–3259)

Attacks

  1. Existing defaults. The delta changes emitted recommendation paths from relative or absent to absolute. MCP now passes an explicitly loaded config into analysis. No gate, severity, format-default or detector-policy change appears in this delta. The intended observable change is that follow-up commands retain the originating project after a directory change. (evidence/pr/hallow/22/round3-delta.patch:5–104)

  2. Tests that survive reverting the fix. Reverting CLI context anchoring makes the relative-root assertion fail and removes the implicit --root. Reverting MCP context removes the root argument required by its test. Both tests inspect actual analysis output. The CLI preview assertion adds behavioral evidence beyond argument inspection. However, a mutation removing only baseline-path normalization is not tested by the new cases; the retained prune test starts with an absolute path. MCP’s test does not cover a relative/implicit root or execute the command elsewhere. These gaps bound the test evidence; they do not demonstrate a remaining implementation failure. (evidence/pr/hallow/22/round3-delta.patch:115–144; evidence/pr/hallow/22/diff.patch:3140–3160)

  3. False positives and false negatives. The delta contains no detector or suppression changes. Anchoring recommendations removes the previously demonstrated route to analyzing another directory. Baseline resolution happens while building the originating document, before the command is handed to the consumer. No new ordinary-code analysis counterexample was established in these changes. This conclusion does not certify every inherited detector. (evidence/pr/hallow/22/round3-delta.patch:18–30,63–101)

  4. Unsupported body claims. The error promise is now correctly narrowed, and the reported CLI/MCP context defects are repaired. Remaining DOC issues concern the boundary-value implementation claim, incomplete description of effective defaults and MCP timing, stale commit/test counts, and overstated test breadth. The exported error description and module-level drift guarantee also remain inaccurate. None demonstrates a new ordinary-input failure in the delta. (evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/diff.patch:2244–2247,2285–2287,2389–2390,2417–2418,2464; evidence/pr/hallow/22/round3-delta.patch:129–144)

  5. Sibling interactions. New CLI context calls consistently pass cfg; the MCP path creates its context from the same configuration passed to analysis. The staged stack has passing checks, and all base merges since round 2 have zero conflict-resolved hunks. This supports the staged combination. It does not settle conflicts or behavior after selectively merging, editing or withholding siblings. Main’s CI changes are excluded from the reviewed delta. (evidence/pr/hallow/22/round3-delta.patch:5–78; evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/checks.txt:3–8)

  6. Stacked-base squash attack. A squash merge preserving the accepted base tree does not inherently change runtime behavior. It changes ancestry and can leave inherited commits in the branch history or review diff. Applying only feat: fallow's exit-code and JSON output contract, gates, hallow schema #22’s own work without its dependency tree can omit the identity/baseline APIs it imports. If the accepted base tree changes, rebuild against it and inspect the resulting diff and checks; this verdict covers only the pinned stack. The evidence does not show a completed post-squash or downstream feat(audit): gate a change on the findings it introduces #23 integration. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/diff.patch:1899,2189,2527; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1)

Earlier reviews

Formal reviews and inline review comments are empty. Issue comments contain the earlier reviews and author responses. The latest response’s central repair claim is supported by the new context code. Its previous-head test result and downstream rebuild remain author statements. Its assertion that the new test executes each recommendation exceeds the actual first-recommendation test. The individual prior dispositions are listed under Round-2 findings. (evidence/pr/hallow/22/reviews.json:1; evidence/pr/hallow/22/review-comments.json:1; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/round3-delta.patch:18–101,129–144)

Verdict

READY at d1fea854b5d9974d1073fc13b5e0f218a06c33be for the pinned #21 stack. The remaining round-2 runtime blocker is closed, and the round-3 attacks established no new BLOCKER or unstated adversarial-input LIMITATION. Current CI passes. This verdict does not transfer automatically to a different dependency tree. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/round3-delta.patch:18–101,115–144; evidence/pr/hallow/22/checks.txt:3–8)

BLOCKER

  • None open from the reviewed delta. The relative/implicit CLI and missing MCP context failures are closed. (evidence/pr/hallow/22/round3-delta.patch:18–78)

LIMITATION

  • None newly established by the round-3 attacks. Coverage and unavailable integration evidence are evidence boundaries, not contrived-input product limitations. (evidence/pr/hallow/22/round3-delta.patch:1–144; evidence/pr/hallow/22/head.json:1)

DOC

  • Exported exit-code text still omits the parser-error exception, although the body now states it. (evidence/pr/hallow/22/diff.patch:2417–2418; evidence/pr/hallow/22/metadata.json:1)
  • Manifest wording still overstates shared boundary validation and drift prevention. Describe declared defaults separately from effective defaults; the latter currently appear in help text. The evidence shows no wrong listed boundary value or wrong emitted default value. (evidence/pr/hallow/22/diff.patch:2244–2247,2285–2287,2389–2390; evidence/pr/hallow/22/context/head-files/src__hallow__cli__main.py.01.txt:71–84; evidence/pr/hallow/22/metadata.json:1)
  • Describe MCP equivalence as the shared check-document shape and gates; elapsed time remains a zero placeholder. (evidence/pr/hallow/22/diff.patch:2464,2829–2848; evidence/pr/hallow/22/metadata.json:1)
  • Update the one-commit/twelve-test descriptions and narrow the response’s “each suggested command” assertion to the preview actually exercised. These are history and verification-description inaccuracies, not false claims about ordinary analysis results. (evidence/pr/hallow/22/head.json:1; evidence/pr/hallow/22/metadata.json:1; evidence/pr/hallow/22/issue-comments.json:1; evidence/pr/hallow/22/round3-delta.patch:129–144)

These DOC items are nonblocking under the supplied rule: the corrected body no longer promises universal parser JSON or a drift-proof manifest, and the remaining inaccuracies do not establish false ordinary analysis behavior. (evidence/BRIEF.md:174; evidence/pr/hallow/22/metadata.json:1)

I could not write evidence/pr/hallow/22/review.md with the read-only tools; I had no execution facility, detailed CI logs, external fallow sources, previous-head test execution, or rebuilt post-merge #23 tree.

Round-3 review DOC: the exported exit-code description (hallow schema)
still said every exit-2 error is a JSON document under --format json.
It now matches the README: run-time errors are JSON; argument-parser
usage errors are text on stderr.
@sarob

sarob commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Round 3 READY. Both DOC items are addressed. The exit-code-2 text that hallow schema exports now states the parser usage-error exception (086f2f9). The body's manifest description now separates declared defaults from effective defaults (--format → human, given in its help text), and says the --boundaries values are a separate tuple checked against the presets, not one drift-proof source.

@sarob
sarob changed the base branch from feat/finding-ids-and-baselines to main October 12, 2026 17:36
@sarob
sarob merged commit c6eefc0 into main Oct 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant