> ## Documentation Index
> Fetch the complete documentation index at: https://delivery.vexa.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# vexa_station_verdict.py

> Render and sign a station's departure verdict over the proof it compiled.

Source: `publisher/vexa_station_verdict.py` · audience: publisher

## Overview

Emitted from `python3 publisher/vexa_station_verdict.py --help`.

```text theme={null}
usage: vexa-station-verdict [-h] {render,sign} ...

vexa-station-verdict — render and sign a station's departure verdict.

THE OBJECT THIS WRITES. The delivery line's station cell is ADMIT (verify the
upstream station's verdict) -> MINT (the PRD) -> PROVE (the fills) -> DEPART.
Lane A built the currency that DEPART compiles: the `values_proven` block, out
of the station's committed fills. This is the signature over it. A downstream
contract that sets

    require_attestations: [ { kind: station-verdict, station: <S> } ]

refuses cargo that never departed S.

WHY IT IS NOT `vexa_station.py`. That tool is about a CUSTOMER's station — it
ingests a station report and gates a publish on that customer's contract (S1..
S10). The word "station" means a different thing there: an installation we
deliver to, not a stop on our own line. Putting a verdict renderer inside it
would make one 1200-line tool answer two unrelated questions, and every reader
would have to work out which sense of "station" a given check meant. Separate
file, separate verb namespace.

  render  compute the verdict from the contract and the proof block, and write
          station-verdict.json
  sign    cosign key-mode over that file, offline, same flags as every other
          signature this repo makes

THE VERDICT IS COMPUTED, NEVER SUPPLIED. There is no --verdict flag and there
will not be one. ELIGIBLE iff every `required_values[]` row the contract marks
`enforcement: required` is answered by a `proven` or human-`waived` row in the
values_proven block. That rule is lane A's and it is IMPORTED, not restated:
`read_contract` decides what "required" means, `check_values_proven` decides
what a well-formed row is. A second copy of either would drift, and the drift
would show up as a station signing ELIGIBLE for a block the subscriber's
verifier then refuses.

A REFUSED VERDICT IS STILL AN OBJECT, and it is signable. A station that finds
a required value unproven could simply write nothing — that is what the older
accumulated-attestation path does, and it is why "no attestation" is ambiguous
downstream between "the station said no" and "the station never ran". A
REFUSED verdict names the values that caused it. `platform-entry` refuses to
carry one into an entry: an entry does not carry a station's no.

WHAT `values_proven_sha256` HASHES. The CANONICAL form of the block — keys
sorted recursively, no whitespace, no trailing newline, UTF-8 — not the bytes
of the file on disk. The block is re-serialised when `platform-entry` embeds
it, so a file hash would never match what a subscriber actually holds, and the
check would fail on every honest entry. The verifier recomputes the same string
with `jq -Sc '.values_proven'`; that agreement is tested, not assumed.

  usage:
    python3 publisher/vexa_station_verdict.py render \
        --station vexa-staging-bbb \
        --candidate-sha 0f9e...  --manifest-sha256 4c1d... \
        --contract <ledger>/channels/vexa-internal/contracts/internal-estate-2026-09.json \
        --values-proven values-proven.json \
        --out work/verdict

    python3 publisher/vexa_station_verdict.py sign \
        --verdict work/verdict/station-verdict.json --key cosign.key

Exit 0 wrote it · 2 usage · 3 refused, and says what is wrong.

positional arguments:
  {render,sign}
    render       compute and write a station's departure verdict
    sign         cosign key-mode over a rendered verdict, offline

options:
  -h, --help     show this help message and exit
```

## `render`

At a station's DEPART, once the fills are committed and `vexa-values-proven` has compiled the block: compute this station's verdict over that block and write `station-verdict.json`. The verdict is COMPUTED — ELIGIBLE only when every value the contract marks `required` is answered `proven` or human-`waived` — so there is no flag that declares one, and a station that cannot clear a value gets a REFUSED object naming it rather than a silence a reader cannot distinguish from a station that never ran.

```text theme={null}
usage: vexa-station-verdict render [-h] --station STATION --candidate-sha CANDIDATE_SHA
                                   --manifest-sha256 MANIFEST_SHA256 --contract CONTRACT
                                   --values-proven VALUES_PROVEN --out OUT

options:
  -h, --help            show this help message and exit
  --station STATION     the station making the claim; matched by a downstream contract's
                        require_attestations[].station
  --candidate-sha CANDIDATE_SHA
                        source commit of the candidate this station exercised; must equal the
                        entry's release.source_sha
  --manifest-sha256 MANIFEST_SHA256
                        sha256 of the consist manifest this station ran against
  --contract CONTRACT   the contract THIS station adjudicated against; its bytes are hashed in
  --values-proven VALUES_PROVEN
                        the values_proven block compiled at DEPART
                        (publisher/vexa_values_proven.py)
  --out OUT             directory to write station-verdict.json into
```

## `sign`

Sign a rendered verdict with the channel key, offline, before carrying it into an entry with `platform-entry --station-verdict`. Same toolchain pin and same offline flags as every other signature this repo makes. The signature is what a downstream `require_attestations` clause verifies, so an unsigned verdict is a text file and `platform-entry` refuses it.

```text theme={null}
usage: vexa-station-verdict sign [-h] --verdict VERDICT --key KEY

options:
  -h, --help         show this help message and exit
  --verdict VERDICT  station-verdict.json, or the directory holding it
  --key KEY          cosign private key file
```
