Skip to main content
Date: 2026-09-07, the day after the run that found them. Channel: the pilot channel on channel.vexa.ai — the live registry. Source: Vexa-ai/vexa-delivery main @ 4a82369, clean detached checkout. Container work ran on bbb, never on the laptop. Two sentences. The entry-5 station install recorded five findings and fixed none of them; they are fixed here, published as kit v0.1.7, and the channel’s latest tag now resolves to it. Three of the five are one shape — a write that reached a surface it does not own, and a check that then reported the result as green — which is the same invariant this repository states about ledger surfaces, one level down.
The subscriber is not named. Their registry hostnames, project names and estate details are not in this document. The channel is written as <pilot-channel>.

The five, and what each one now does

1 · A namespace the installer did not create is not written to

install.sh’s ensure_namespace ran kubectl create namespace <ns> --dry-run=client -o yaml | kubectl apply -f - unconditionally. Applying a bare Namespace is a three-way merge, so against a project the platform team pre-created it pruned
down to the single kubernetes.io/metadata.name label. Silently, on a namespace the installer does not own — and a pre-created project carrying exactly those labels and annotations is the documented shape for a shared cluster. It is now create-only: the installer writes a Namespace object only when it is the thing creating it, says so once per namespace when it is not, and touches no label, annotation or rolebinding of a namespace that already exists. And the check that reported the result as green no longer can. Preflight P4 returned PASS with “no SCC and no PSA enforce label on the namespace — admission here is permissive; nothing to trip, nothing verified about hardened namespaces”. A green obtained from the enforcement being absent, in the one check whose subject is the enforcement. P4 now prints the effective admission it read — PSA enforce level, whether the cluster serves SCC, which openshift.io/sa.scc.* annotations the namespace carries — and a namespace that enforces neither is NOT EVALUATED, never a pass.

2 · Preflight P2 compares what admission compares

The delivered postgres asks a 4Gi memory limit; the documented project shape caps a container at 2560Mi, the figure sized for the meeting bot’s 2Gi memory-backed /dev/shm. Admission refused the database, the admin tier crash-looped behind it, and the estate came up partly down — after a green preflight. The receipt’s diagnosis of why P2 passed was wrong, and the correction is the more useful finding. It read “P2 checks that limits are declared, not that they are under the LimitRange’s max. It did compare, and a test pinned that comparison. P2 passed because the live max.memory was 8Gi when the preflight ran — the session’s own admin snapshot records max.memory: 8Gi beside a last-applied-configuration reading 2560Mi, a hand-widened value that a later re-apply of the project’s grant reset. The refusal arrived when every pod was deleted and re-admitted under the restored ceiling. So the check was true when it was taken and false an hour later, and nothing in its output could distinguish those two worlds: it printed namespace has 1 LimitRange(s) and no number. It now prints the numbers it compared against, which is the same discipline this repository applies to verdicts — positive evidence, not the absence of a complaint. Three real holes were beside it, and all three are closed. The LimitRanger checks max and min against the request and the limit, for every resource the LimitRange names; P2 compared exactly one of those four pairs, in one dimension. It now compares all four, in memory and cpu, and names the object and the number:
P3 sums cpu as well as memory, so a quota’s limits.cpu is no longer a bound nothing is compared against. And the delivered set now fits the documented project shape by default. postgres is the only container in the chart above 2560Mi; every other component asks 1Gi or less. The shipped customer-values.example.yaml — the file the installer renders with unless you hand it your own — caps it. The other road is unchanged and still documented: if your platform team can size the project to the chart’s own largest ask, do that and delete the cap. Both are now checked by P2 before the first sync rather than at admission.

3 · A path typo no longer wears the attack message

vexa-verify.sh chdirs into its workdir and only then resolves --pubkey and --policy, so a relative path silently missed and the miss surfaced as
The identical entry verified Verified OK by hand one command later. The script’s own comment says a signature failure “says someone may be attacking you” — which makes it the worst available message a mistyped path can produce, because the subscriber’s next move is to call their security team. Both paths are resolved before the chdir and before anything is pulled, and a file that is not there is named as what it is: pubkey file not found: <path>, exit 2, with no signature language anywhere near it. A --policy that cannot be read refuses too — it used to degrade to no contract, which turns every contract check into a check that did not run.

4 · The bytes the gate hashes are the bytes the ledger holds

install.sh wrote the contract ConfigMap through json.dumps(yaml.safe_load(file)), re-serializing a 757-byte record into 617 bytes of compact JSON. The in-cluster gate hashes the copy it is mounted, so the recorded verdict named one hash while the ledger record — and the station report’s own contract_document section — hashed to another. An audit asking which promise was this admitted under could not answer from either side. A JSON contract is now mounted verbatim. YAML is still converted, because the gate reads the document with jq, and then both shas are recorded in the ConfigMap so the converted document traces back to the bytes a human signed off. The installer prints the sha it wrote, which is the number the verdict will carry. This is the same defect the chart template fixed with a double-quoted scalar after the 2026-08-29 station lost a verdict to a single 0a. It was the other write path, and it still had it.

5 · The ledger records the position the report carries

The ingest reducer read targetRevision out of a values file and then a position key that appears in no schema. It never read the station report’s own release block — which carried the entry sequence, the entry digest, the chart version and the chart digest — so a report saying exactly where a station stands reduced to subscribed_position: unknown and entry_seq: null, and the staleness flag could not fire for it. It now reads that block, most specific source first, and cross-checks the entry identity against the ingest receipt rather than silently ranking two sources for one fact. A disagreement is recorded as a flag, because it is a finding about the submission.

What was published

kit/release.sh --dry-run ran first. It packaged 270382 bytes against the real run’s 270381; the difference is the built= timestamp inside VERSION, written per run. The tree packaged was the same tree — worth saying rather than claiming a byte-identical dry run that did not happen.

Proof 1 — the version tag and latest name one digest

latest is moved with oras tag against the same descriptor bytes, so the signature made over the digest carries without a second signing operation. The predecessor still resolves to its own digest, unmoved.

Proof 2 — it verifies against the channel’s pinned key

cosign tree on that digest shows exactly one signature, one layer — not a second stacked beside it. The control: kit v0.1.6 still verifies against the same key. One key verifies both, which is what makes “one key for this channel’s whole life” a check rather than a claim. --insecure-ignore-tlog=true is correct here rather than a weakening: the channel signs offline against a pinned key and uploads nothing to a transparency log, which is what makes it air-gappable, and it is the same form kit/bootstrap.sh runs on the subscriber’s side.

Proof 3 — a subscriber-shaped pull gets a verified v0.1.7, with the fixes in it

Run from a clean directory with HOME and TMPDIR pointed at it, so the publisher credential this same host had just pushed with was not reachable — the isolated HOME has no .docker directory at all, checked after the run — and with a pull-only credential supplied on stdin of a script already resident on the host, so it never reached argv, a file or a transcript.
The ordering is the security property and it held: the signature is checked before a single byte is unpacked. The isolation is not decoration — without it the pull would have quietly authenticated as the publisher and proven nothing about the subscriber’s path. And the fixes are in the artifact, not only in the branch — grepped in the unpacked tree, which is bytes that came off the registry: python3 preflight/vexa_preflight.py --help runs from the unpacked tree.

What this pass does NOT claim

  • Nothing was installed from this kit. Pull, verify, unpack, shape and content are proven. install.sh was not run against a cluster here, so the five fixes rest on their own tests — a fake pre-created namespace, the contract bytes, path resolution, the LimitRange cases and the reducer cases — and on their presence in the published artifact. The next station install is what closes that, and it is the one that will exercise finding 1’s fix against a real pre-created project.
  • No cluster was read or written in this pass, and no meeting was captured, so nothing here says anything about the release’s quality.
  • The pull-only credential was an existing account of ours, not a freshly minted throwaway; the credential tool still cannot mint one against the live channel. Reads are not scoped per account at the edge — only writes are — so the path exercised is the one a subscriber takes, but this pass did not exercise credential issue and revoke.
  • No entry, pin or contract moved. No credential was minted or rotated, and the signing key stayed in tmpfs on the build host for the length of the run.