feat(verdict): VerdictFailureClass + cargoless verdict --advisory — structural fix for INDETERMINATE bypass spiral #77
Open
triform-admin
wants to merge 12 commits from
agent/verdict-failure-class into main
pull from: agent/verdict-failure-class
merge into: triform:main
triform:main
triform:agent/zstd-project-check-runtime-20260804
triform:agent/lane-restart-continuity
triform:agent/diagnostic-retrigger-refresh-20260804
triform:agent/candidate-notfound-idempotent
triform:agent/lanetree-stale-remove-race
triform:agent/lane-stale-candidate-cleanup-20260804
triform:agent/lane-stale-candidate-cleanup-ci-retry-20260804
triform:agent/lane-cutover-integration-r3-20260804
triform:agent/lane-abandoned-verdict
triform:agent/lane-cutover-integration-r2-20260804
triform:agent/lane-point-retry
triform:agent/witness-scratch-recovery-20260804
triform:agent/lane-cutover-integration-20260804
triform:agent/project-timeout-finalization-linear3-20260804
triform:agent/diagnostic-cancel-backoff-20260803
triform:agent/project-timeout-finalization-linear2-20260804
triform:agent/project-timeout-finalization-linear-20260804
triform:agent/project-timeout-finalization-20260804
triform:agent/lane-red-files-evidence
triform:agent/lane-member-identities
triform:agent/lane-dispatch-artifact
triform:agent/lane-honesty
triform:agent/lane-stages
triform:agent/lsp-pipe-liveness-20260803
triform:agent/lane-point-reassert-20260803
triform:agent/lane-infra-backoff
triform:agent/analyzer-pathology-rollout-20260803
triform:agent/unattributed-witness-20260803
triform:agent/respawn-nonlatching-main
triform:agent/rejection-reason-refresh-20260803
triform:agent/rejection-reason-20260803
triform:agent/lane-compose-legs
triform:agent/overlay-response-timeout-20260803
triform:agent/diagnostic-event-origin-20260803
triform:agent/http-partial-write-20260803
triform:agent/readyz-liveness
triform:agent/diagnostic-absolute-uri-20260803
triform:agent/diagnostic-final-fence-20260803
triform:agent/diagnostic-freshness-rebased-20260803
triform:agent/diagnostic-freshness-20260803
triform:agent/diagnostic-timeout-20260803
triform:agent/reuse-result-protocol-20260803
triform:agent/project-check-lifecycle-fix
triform:agent/outcome-pending-race
triform:agent/red-files-attribution
triform:agent/name-the-unattributed-diagnostic
triform:agent/ra-proper-20260731
triform:agent/build-lane
triform:agent/serve-image-tag-epoch
triform:agent/ci-no-cancel-in-progress
triform:agent/witness-serial-class
triform:agent/batch-obs
triform:agent/cgls11-reopen-cap
triform:agent/coalesce-gated-witness-by-base-rebased
triform:agent/get-status-attributed
triform:agent/ra-memory-cap
triform:agent/witness-stranded-unknown
triform:agent/witness-ra-reap-handover
triform:agent/coalesce-gated-witness-by-base
triform:agent/witness-warm-target
triform:agent/witness-serial-warm
triform:agent/coalesced-emit-gated-checks-ran
triform:agent/test-flake-hardening
triform:agent/appdrv-test-isolation
triform:agent/cgls-26-attribution-guard
triform:agent/appserve-clear-stale-last-red
triform:agent/witness-watchdog-25m
triform:agent/docs-ci-log-pointer
triform:agent/appserve-enospc-selfheal
triform:agent/eager-boot-warm
triform:agent/deploy-ref-parity-fsgroup
triform:feat/serial-batch-witness
triform:agent/witness-base-sha-keying
triform:agent/instances-sighup-reload
triform:agent/eager-boot-warm-basefetch
triform:agent/serveapi-base-local-no-fetch
triform:agent/preview-restart-persistence
triform:agent/hot-trunk-no-cancel
triform:agent/preview-selfserve-integrated
triform:agent/gated-checks-ran-on-deployed
triform:agent/gated-checks-ran
triform:agent/preview-rename-public-status
triform:fix/interaction-red-unknown
triform:agent/overlay-cap-128
triform:agent/per-lane-build-slot
triform:agent/runplan-per-build-reread
triform:agent/cgls11-pool-overlay-flycheck
triform:agent/cgls12-content-macro-detection
triform:agent/manifest-run-plan-on-main
triform:agent/ci-concurrency
triform:agent/macro-witness-fix
triform:agent/appserve-build-job
triform:agent/build-to-completion
triform:agent/fix-overlay-reaches-ra
triform:agent/fix-appbuild-test-manifest-hash
triform:agent/fix-serve-ra-procmacro-skew
triform:agent/fix-otlp-v1-traces-path
triform:agent/ra-stderr-visible
triform:agent/manifest-run-plan
triform:agent/self-serve-previews
triform:agent/appserve-worktree-setup
triform:agent/appserve-dockerfile-fix
triform:agent/timer-settle-unknown-cgls9
triform:agent/verdict-freshness-cgls9
triform:agent/app-serve
triform:agent/verdict-cli
triform:agent/witness-offloop
triform:agent/bounded-git
triform:agent/readyz
triform:agent/verdict-attribution
triform:agent/otlp-queue
triform:agent/infra-258-260
triform:agent/project-checks-nonblocking
triform:agent/attribution-helper
triform:release/v0.3.0
triform:agent/batch-concurrency-validation
triform:agent/project-checks-hard
triform:agent/amem-49-exporter-timeout
triform:agent/infra-54-init-success-log
triform:agent/infra-49-blocking-client
triform:agent/infra-49-simple-exporter
triform:agent/honest-verdict-and-otel
triform:agent/overlay-project-checks
triform:agent/fsn-serve-shards
triform:agent/existing-red-report
triform:agent/checks-base-pruning
triform:agent/docs-project-check-resource-discipline
triform:agent/session-handover-2026-05-25
triform:agent/builder-template-cache-repair
triform:agent/tf-multiverse-serve-service
triform:agent/serve-auth-read-image
triform:agent/cargoless-http-read-auth
triform:agent/serve-image-bump
triform:agent/push-only-ready
triform:agent/architect
triform:agent/bench-lead-m3
triform:agent/builder-infra-msrv-doc
triform:agent/builder-infra-doc-housekeeping
triform:agent/builder-infra-roadmap-integration
triform:agent/builder-infra-docs-combined
triform:agent/docs-launch-lead-roadmap-refresh
triform:agent/docs-launch-lead-prestage
triform:agent/builder-infra-update-lock
triform:agent/docs-launch-lead-w2-docs
triform:agent/builder-infra-263-disk-full
triform:agent/dev-fixer-2c
triform:agent/dev-fixer-2b
triform:agent/bench-lead-m2-on-9429462
triform:agent/docs-launch-lead-brand-coherence
triform:agent/bench-lead-m2-approx
triform:agent/docs-launch-lead-dewasm-scope
triform:agent/dev-fixer-otel-wave1
triform:agent/dev-fixer-dewasm
triform:agent/dogfood-lead-stage1-rework
triform:agent/dev-fixer-respawn-driver-reset
triform:agent/dev-fixer-pushoverlay
triform:agent/dev-fixer-healthz
triform:agent/dogfood-lead-stage1-suite
triform:agent/bench-lead-diffharness
triform:agent/dev-fixer-serve-wire
triform:agent/builder-infra-serve-image
triform:agent/docs-launch-lead-inc2spec
triform:agent/builder-infra-serve-k8s
triform:agent/builder-infra-v020
triform:agent/docs-launch-lead-e5
triform:agent/builder-infra-198
triform:agent/dev-fixer-modelr-cio
triform:agent/builder-infra-podinfra
triform:agent/bench-lead-15bench-r
triform:agent/bench-lead-15bench
triform:agent/builder-infra-14-integ
triform:agent/builder-infra-14auth-fix
triform:agent/builder-infra-tripleguard
triform:agent/builder-infra-i2fixed
triform:agent/builder-infra-i1
triform:agent/builder-infra-reset0
triform:agent/builder-infra-capcore
triform:agent/builder-infra-12
triform:agent/builder-infra-4
triform:agent/builder-infra-incr4
triform:agent/builder-infra-incr3
triform:agent/builder-infra-182
triform:agent/builder-infra-14auth
triform:agent/docs-launch-lead-e4
triform:agent/bench-lead-modelr-13c
triform:agent/docs-launch-lead-e3
triform:agent/bench-lead-modelr-13
triform:agent/dev-fixer-modelr-c
triform:agent/docs-launch-lead-e2
triform:agent/builder-infra-comp2v2
triform:agent/builder-infra-cigatefix2
triform:agent/dev-fixer-modelr-b
triform:agent/bench-lead-modelr
triform:agent/builder-infra-cigatefix
triform:agent/builder-infra-comp2
triform:agent/docs-launch-lead-modelr
triform:agent/builder-infra-modelr
triform:agent/docs-launch-lead-final
triform:agent/bench-lead
triform:agent/dev-fixer-132
triform:agent/dev-fixer-97
triform:agent/docs-launch-lead-prep
triform:agent/dev-fixer-128
triform:agent/dev-fixer-procmacro-downrank
triform:agent/dev-fixer-idle-evict
triform:agent/dev-fixer-structural-trigger
triform:agent/dev-fixer-openclosed-design
triform:agent/dev-fixer-94
triform:agent/dev-fixer-97-plan
triform:agent/docs-launch-sf
triform:agent/docs-launch-lead-d1b
triform:chore/f13a-integrate-v2
triform:agent/dev-fixer-f13a
triform:chore/cwdl-71-phase-d
triform:chore/buildid-integrate-v2
triform:agent/dev-fixer-f13b
triform:agent/buildid
triform:agent/ra-config
triform:agent/d-a2-design
triform:agent/docs-launch-lead-d1
triform:agent/docs-launch-lead
triform:agent/dev-fixer-5
triform:agent/dev-fixer-4
triform:agent/dev-fixer-3
triform:chore/launch-readiness-docs
triform:agent/dev-fixer-2
triform:agent/f8-integrate
triform:agent/integration-default
triform:agent/dev-fixer-f8
triform:agent/dev-fixer
triform:agent/builder-infra
triform:agent/v0-feature-complete
triform:agent/daemon-core-21
triform:agent/v0-final-converge2
triform:agent/ra-bench-wt
triform:agent/cli-ux-v0
triform:agent/v0-final-converge
triform:agent/build-cas-publisher
triform:agent/docs-v0
triform:agent/v0-core-converge
triform:agent/gate-locked
triform:agent/main-stabilize
triform:agent/cli-ux-wire
triform:agent/devserver-bundle
triform:agent/daemon-core-sup
triform:agent/integration-converge
triform:agent/build-cas-bundle
triform:agent/daemon-core-wt
triform:agent/build-cas
triform:agent/devserver
triform:agent/cli-ux
triform:integ/dc-ac6
triform:integ/ra-bench
triform:integ/daemon-core
triform:agent/ra-bench
triform:agent/proto-contracts
triform:agent/daemon-core
No reviewers
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
triform/cargoless!77
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "agent/verdict-failure-class"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Structural depth-fix for the pre-commit
--no-verifybypass spiral on INDETERMINATE verdicts. Three phases:VerdictFailureClassenum (DaemonDegraded/Unwitnessable/NonAttributable/TimeBudget) +classify_reasonlock-table incargoless-proto. Threaded throughProjectCheckSummary::Indeterminate,WorktreeStatus,TransitionEvent, and the statusfile. Rust's exhaustiveness check is the audit-completeness guarantee — every construction site stamps a class. Omit-when-None ser/de discipline (precedent:ra_blind_paths); unknown class tags drop toNoneforward-compat.cargoless verdict --advisoryreifies the operator-design contract at the exit-code seam:red_diagnostics > 0AND non-emptycrates[]→ 1 (justified hard-block)examples/pre-commit-advisory.shreference hook, anddocs/operator/pre-commit-hook-contract.md.Four commits in branch:
4544401feat(verdict): structured VerdictFailureClass +cargoless verdict --advisory118aafdfix(verdict): reach VerdictFailureClass through cargoless-core re-exportb3334abfix(verdict): complete Status literals + re-export classify_reasonc1b5f4efix(proto): classify_reason prefix-match the project_check/red/ra armsThe last fix-forward addresses a real semantic bug:
classify_reasonwas exact-match onproject_check_*arms but production formats them asformat!("{reason}: {detail}")at the publish edge. The detail-bearing lock-table assertions are the regression guard.Test plan
c1b5f4ecompose_hard_mode_payloadlifts class without losing reason--advisoryAND plain (no behavior change for plain)class: Noneexamples/pre-commit-advisory.shcargoless verdict --advisoryThe operator's pre-commit hook produced 4× INDETERMINATE in a row on a 110-file / 13k-line codegen sweep, forcing `--no-verify` each time. The cargoless wire flattens 14 distinct INDETERMINATE reasons into one free-text `verdict_failure_reason`, so a hook cannot structurally distinguish "daemon was degraded for this push class" from "real RED", and hard-blocks on both. The operator-design contract (cargoless-gate witness is advisory by design; the downstream compile-witness is the authoritative gate) was not encoded anywhere a hook could consume it. Structural fix shipped here: Phase A — Daemon: VerdictFailureClass enum * `cargoless-proto` gains `VerdictFailureClass` (DaemonDegraded / Unwitnessable / NonAttributable / TimeBudget) + `classify_reason`, a lock-table mapping each of the 14 reason strings to its class. * `ProjectCheckSummary::Indeterminate` now carries `class`, so Rust's exhaustiveness check refuses to compile until every construction site stamps one — audit completeness by the type system, not by sidecar. * Class lifts through `compose_hard_mode_payload` (the publish-edge funnel where the prior code flattened `{reason, detail}` into a single string and lost the `&'static str` boundary). * `WorktreeStatus` and `TransitionEvent` gain `verdict_failure_class: Option<VerdictFailureClass>`, with the `ra_blind_paths` additive-on-the-wire precedent: emit when Some, omit when None, parser drops unknown tags to None instead of erroring. JSON byte shape is unchanged when class is None. * Statusfile mirrors the additive field on disk under the same omit-when-None discipline. Phase B — CLI: `cargoless verdict --advisory` * New flag reifies the advisory contract at the exit-code seam. `green` → 0; `red` with `red_diagnostics > 0` AND non-empty `crates[]` → 1 (the one justified hard-block); every other shape (red-without-evidence, red-without-attribution, unknown of any class, client-synthesized unknown from ladder exhaustion / await timeout) → 0 with one structured `[cargoless:advisory] verdict=... class=... reason=...` stderr line per skip. * JSON wire shape on stdout is unchanged. * Non-advisory mode is byte-identical to the legacy 0/1/75 ladder. * Config-error exit 2 (unauthorized everywhere) still hard-fails under `--advisory` — a misconfigured remote is a setup error, not a degraded daemon. Phase C — Publish the consumer contract * README section ("Local hooks: use `cargoless verdict --advisory`"). * `examples/pre-commit-advisory.sh` reference hook (env-driven, three substantive lines — all policy lives in cargoless). * `docs/operator/pre-commit-hook-contract.md` carves the exit-code mapping and the rationale for the protective shape. Test coverage: * `classify_reason` lock-table test: all 14 reasons mapped, an unmapped reason → None. * Wire round-trip test in transport/mod.rs: every class round-trips via JSON; None stays absent from the wire; unknown tag from a newer daemon drops to None. * Statusfile round-trip test mirrors the wire pattern. * `compose_hard_mode_payload` truth-table test: every Indeterminate class preserves through to the published verdict. * `exit_byte_for_status`: plain mode matches legacy byte-for-byte; advisory mode tests cover all four protective vs non-protective shapes plus every VerdictFailureClass variant on unknown. * `--advisory` flag parsing + scoping test (verdict-only). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>The exact-match block silently mis-classed every reason that reaches the publish edge, because `compose_hard_mode_payload` formats reasons as `format!("{reason}: {detail}")`. A reason like `"project_check_setup_error: oops"` therefore fell through to `None` instead of `DaemonDegraded`, even though the bare prefix is on the locked list — the exact regression caught by the new `verdict_payload_unknown_post_classifies_known_reasons` test. The `witness:*` arms above already use `starts_with`. Apply the same discipline to `project_check_*`, `red_claimed_without_evidence`, and `ra_native_*` / `ra_blind_path_*` — the rest of the locked taxonomy. The lock-table test now asserts BOTH the bare form (existing) AND a detail-bearing form (new) for each project_check / red / ra reason, so the exact-match regression cannot silently come back. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.