feat: hydrate validate (dry-run coherence findings) - #72
Merged
Conversation
Add `hydrate validate`: it lowers the current stage to the same typed delta
batch `commit` builds, POSTs it to `POST /v1/branches/{id}/validate`, and prints
the server's coherence report — without committing and, critically, without
clearing the stage (it is a non-mutating server dry-run).
Exit code: `0` when there are no error-severity findings, and a new distinct
code `5` when there are, so an agent can gate a loop: `hydrate validate &&
hydrate commit`. The findings always print (human list, or the verbatim
`{valid, findings[]}` with `--json`); the exit code is only the pass/fail
signal. A transport or parse failure keeps its own existing code.
Re-vendor `openapi.json` and regenerate `wire/` to pick up the updated validate
contract — the response is now `{version, project_id, branch, valid, findings}`
with `Finding {code, severity, locator, message}` — replacing the previous
first-failing-delta shape.
Also wires the verb into the CLI surface, adds `client.validate_deltas`, and
updates the guide, README, and the `--help` verb test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The server is the sole authority for validation. Gate `hydrate validate`'s exit code and human verdict on the server's authoritative `response.valid` rather than re-deriving them from a client-side error-severity scan, closing the silent-divergence trap where `valid:false` with no error-severity finding (a future warning-arm the contract anticipates) would exit 0 / print "Valid" while `--json` reported `valid:false`. - exit_code: exit VALIDATION (5) iff `!response.valid`, else SUCCESS (0); error_findings kept only for the displayed count. - Human verdict line driven by `response.valid`, not the severity scan. - Fail loud: `disagreement_warning` surfaces (to stderr, in both modes) any conflict between the server verdict and the presence of error-severity findings instead of silently trusting one side. - render: borrow findings via `as_deref` instead of cloning the whole vec. - CLAUDE.md: add exit code 5 to the stable-exit-codes enumeration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sync the vendored spec to the backend after the internal codename was scrubbed from the Finding schema description (hydrate-sh/app#228), and regenerate wire/ so the generated client's doc-comment is clean too. No contract shape change — description text only. Keeps the public artifact free of internal codenames (caught by this PR's fan-out review). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merged
rennehan
added a commit
that referenced
this pull request
Jul 29, 2026
* feat: hydrate validate (dry-run coherence findings)
Add `hydrate validate`: it lowers the current stage to the same typed delta
batch `commit` builds, POSTs it to `POST /v1/branches/{id}/validate`, and prints
the server's coherence report — without committing and, critically, without
clearing the stage (it is a non-mutating server dry-run).
Exit code: `0` when there are no error-severity findings, and a new distinct
code `5` when there are, so an agent can gate a loop: `hydrate validate &&
hydrate commit`. The findings always print (human list, or the verbatim
`{valid, findings[]}` with `--json`); the exit code is only the pass/fail
signal. A transport or parse failure keeps its own existing code.
Re-vendor `openapi.json` and regenerate `wire/` to pick up the updated validate
contract — the response is now `{version, project_id, branch, valid, findings}`
with `Finding {code, severity, locator, message}` — replacing the previous
first-failing-delta shape.
Also wires the verb into the CLI surface, adds `client.validate_deltas`, and
updates the guide, README, and the `--help` verb test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: honor server valid verdict; doc exit code 5
The server is the sole authority for validation. Gate `hydrate validate`'s
exit code and human verdict on the server's authoritative `response.valid`
rather than re-deriving them from a client-side error-severity scan, closing
the silent-divergence trap where `valid:false` with no error-severity finding
(a future warning-arm the contract anticipates) would exit 0 / print "Valid"
while `--json` reported `valid:false`.
- exit_code: exit VALIDATION (5) iff `!response.valid`, else SUCCESS (0);
error_findings kept only for the displayed count.
- Human verdict line driven by `response.valid`, not the severity scan.
- Fail loud: `disagreement_warning` surfaces (to stderr, in both modes) any
conflict between the server verdict and the presence of error-severity
findings instead of silently trusting one side.
- render: borrow findings via `as_deref` instead of cloning the whole vec.
- CLAUDE.md: add exit code 5 to the stable-exit-codes enumeration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: re-vendor scrubbed openapi.json + regen wire
Sync the vendored spec to the backend after the internal codename was
scrubbed from the Finding schema description, and
regenerate wire/ so the generated client's doc-comment is clean too. No
contract shape change — description text only. Keeps the public artifact
free of internal codenames (caught by this PR's fan-out review).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
hydrate validate— the agent's dry-run gate in the walk → validate → commit loop.It lowers the current stage into the same typed delta batch
commitbuilds (staging::lower), POSTs it toPOST /v1/branches/{id}/validate, and prints the server's coherence report. Unlikecommitit is non-mutating: it never applies the batch and, critically, never clears the stage.Exit code
0when there are no error-severity findings.5(exit::VALIDATION) when there are — so an agent can gate a loop:{valid, findings[]}with--json); the exit code is only the pass/fail signal. A transport/parse failure keeps its existing code (network6, generic1, ...), so "found errors" is never confused with "couldn't reach the service".5is unused by the existing set (0/1/4/6).Backend dependency
Depends on the merged C04 coherence-findings backend contract.
POST /v1/branches/{id}/validatenow returns{version, project_id, branch, valid, findings[]}withFinding {code, severity, locator, message}, replacing the previous first-failing-delta shape.This PR re-vendors
openapi.json(verbatim from the backend's regenerated spec) and regenerateswire/viascripts/regen-wire.shto pick up the newFinding/ValidateResponseschemas.wire/is generated, not hand-edited; the CI wire-drift check is idempotent against the committed spec.Changes
src/cmd/validate.rs— new verb (prepare/render/exit-code split, all unit-tested).src/client/mod.rs—validate_deltas(branch_id, body)wrapping the generated call (mirrorsapply_deltas).src/exit.rs—SUCCESS = 0,VALIDATION = 5.src/cli.rs,src/cmd/mod.rs— verb wiring (finish_with_codemaps the handler-chosen success code).src/cmd/guide.rs,README.md,tests/help.rs— surface/docs/help updates.openapi.json,wire/**— re-vendored spec + regenerated client.Tests
TDD. New coverage: clean report → exit 0 + valid in both modes; error findings → exit 5 (distinct from conflict/network/generic) + full findings printed;
--jsonvs human parity; warning-only findings are advisory (still pass); mixed findings gate on the error; andpreparelowers the stage without clearing it (the non-mutating invariant).cargo test(326 unit + help suite),cargo fmt -p hydrate -- --check, andcargo clippy --workspace --all-targets -- -D warningsall green.