Governance Conformance and Signed Rejection Evidence
Overview
v1.1.0 is a minor release on top of v1.0.6. Every governed ingress now returns typed, Operator-signed evidence for a rejection or refusal, not just for success. A new governance conformance suite drives a case catalogue over every ingress and posture, grades each case from that signed evidence alone, and verifies the sealed record offline. Tier-qualification campaigns carry the signed receipt of every governed tool call and reject unverifiable evidence. Runtime scratch moves under .ztd/. The plaintext master key file is removed.
The release adds wire contracts and removes CLI surface (ztd eval boundary, --master-key-file), so it is a minor bump. See Removed for the upgrade path.
Highlights
- Signed rejection evidence on every ingress — Direct envelope submission, governed dispatch, MCP and A2A return a typed
GovernanceRejectioncarrying the executing Operator's signed rejection receipt, or a typedIngressRefusalfor pre-envelope refusals. A denied L3 approval is now a signedL3_DENIEDrejection too. - Governance conformance suite —
ztd eval conformance run | verify | reportrunsgovernance-conformance@1.0.0against a live native stack, seals the record with a digest sidecar, and re-derives every verdict offline. - Evidence-first campaigns —
agent-trace.v2keeps each governed tool call's signed receipt, the Data Operator's ledger bracket is verified on import, and unverifiable evidence gradesINVALID_EVIDENCE. - Fail-closed key custody — The plaintext
--master-key-filepath is gone. Hosts without an OS key store seal under ssh-agent or fail closed. - Windows onboarding script (native end-to-end validation pending) —
irm https://zerotrustdata.io/start.ps1 | iex.
Added
- Typed governance outcomes on every ingress —
GovernanceRejection(with the Operator-signed rejection receipt and itsrejection_code),IngressRefusal(pre-envelope refusals, including MCP and A2Aerror.data), the full signedActionReceipton governed dispatch, MCPtools/calland A2Aa2a/call, and one typedGovernedSuspensionfor a suspended call.ztd operator runprints the transaction ID and rejection code. - Signed L3 deny —
L3Metadata.denied(outside the transaction hash) andGOVERNANCE_REJECTION_CODE_L3_DENIED. A denied approval resubmits the suspended envelope with the deny marker. L4 rejects it in every posture withErrTxL3Deniedand keeps the nonce spent, and L5 signs the rejection on the executing runtime.POST /api/v1/approvals/respondwithapproved: falsereturns that receipt, andapproval.completedcarries it to every consumer:ztd auth approvefails withErrTxL3Denied, the TUI reports "denied", and the console has a Deny button. - Governance conformance suite —
ztd eval conformance run,verifyandreport.governance-conformance@1.0.0drives a 26-row case catalogue over direct, dispatch, CLI, MCP and A2A ingresses in every posture, and grades each case from the Operator's signed evidence (oracle, canary manifest, commitment-ledger bracket). The run is sealed as aConformanceRunRecordwith a digest sidecar.verifyrecomputes every verdict offline, and any changed byte isINVALID_EVIDENCE.reportbuilds a case-by-posture coverage table and an L1 doctrine recall report. The doctrine adversarial corpus is an embedded package. - Conformance protocol —
protocol/proto/ztd/eval/v1/eval.protoaddsConformanceRunRecord,ConformanceCaseEvidence,ConformanceObservation,ConformanceVerdict(Set),ConformanceFailureClass,ConformanceSuiteVerdict,CanaryManifest,ConformanceAnchor,EVALUATION_SCENARIO_CATEGORY_CONTAINMENTandEVALUATION_ASSIGNMENT_LIFECYCLE_STATUS_INVALID_EVIDENCE. Go and TypeScript bindings are regenerated. - Agent SUT groundwork — Canonical SUT contract vectors, the SUT client, per-persona graders, the secondary judge, and three seeded-investigation scenarios under
eval/investigations. Live runs wait on an external SUT. - Ephemeral ssh-agent for multi-process harnesses —
ztd test scaleandztd test release-smokerun a private in-process ssh-agent under the run Gateway's.ztd/agent/(keystore.EphemeralAgent, Linux). Children seal under it without touching the host keyring. - Runtime scratch API —
RuntimeFileService.MkdirTempcreates scratch under.ztd/tmp/, andssh.MkdirRemoteScratchstages remote uploads under<login>/.ztd/tmp. INV-FS-11 documents both. - Windows onboarding script —
website/static/start.ps1implements installation, Gateway startup, sign-in, and a first governed action. Automated script tests, including PowerShell cases, passed on Linux. The complete flow has not been verified on a native Windows host; Windows end-to-end readiness is not claimed for this release. The homepage quick start and Releases pages list the script.
Changed
- Receipt trust — Receipts verify only against the key bound to the executing Operator at enrollment. A self-declared signer key ID is no longer trusted.
- Direct envelope submission — Binds
requestor_user_idandacting_app_idto the authenticated identity. Returns 503 instead of 500 when the verifier cannot run, renders pre-L4 refusals as sentinels only, and returns its 200 receipt as canonical protojson (enums by name) instead ofencoding/json. - Governed dispatch — Runs L1 doctrine before the L3 gate, renders only typed sentinels, and returns 404 for an unresolved target session.
- Pipeline classification — An event/action mismatch is a signed L4 rejection, a forged L2 vote rejects as
L2_SIGNATURE_INVALID, and L5 receipts copy the Warden's L2/L3 status. - A2A — Suspends only on a missing L3 proof, like MCP. The agent harness A2A client posts to
/api/v1/a2a/call. - Approval waits — The CLI, harness and attended flows open the SSE stream before submitting, so an early approval is no longer lost.
- MCP
tools/list— Returns native tools alongside a downstream MCP server's tools. - Campaign traces (breaking) — Traces are
agent-trace.v2, and every governed tool call keeps its signed receipt. Import verifies the Data Operator's ledger bracket, and unverifiable evidence isINVALID_EVIDENCEwith no grades. run_commands_with_operator— Executes the command the model wrote incommand. The second command-generation inference is removed.- Empty model replies — An empty completion is a receipted empty
InferenceResultand gradesFAILagainst the model instead ofprovider_response_invalid(INV-EVAL-CAMP-34). - Compliance — Admits native eval runs only from a verified conformance record.
- Data Operator binding —
ValidateAgentDataOperatoraccepts only a direct child of<project>/.ztd/operators(INV-EVAL-CAMP-32).operator deploy --localwithout--hosts/--dest-dirdeploys numberedop-NNNNNdirs there. - Throwaway Operator trees —
.ztd/operators/<name>/…is agent-editable. The operators dir,<name>itself and the nested.ztd/stay protected. - Port resolution —
config.LoadGatewayonly validates.gw startresolves free ports (config.ResolveGatewayPorts). - Scratch locations — The system trust installer, assignment audit, agent verify, compliance bundle verifier, chaos targets, remote stream/deploy staging and the release-smoke default root (
.ztd/operators/release-smoke-<UTC ts>) all use.ztd/scratch. The Makefile no longer setsTMPDIR. - Headless onboarding —
start.shtells a host with no OS key store to start an ssh-agent with a key loaded. CI onboarding and the website live smoke run under an ephemeral ssh-agent.
Removed
--master-key-file/ZTD_MASTER_KEY_FILE(breaking) — The plaintext master key file is removed fromgw start,operator start,operator deploy, vault, report, compliance, public and the root command, along withZTD_E2E_MASTER_KEY_FILEand the launch-profile field. Production uses Linux Secret Service, macOS Keychain, or Windows DPAPI. Linux hosts without a usable Secret Service seal under ssh-agent (an Ed25519 or RSA key reachable throughSSH_AUTH_SOCK); key-store failures fail closed.- Upgrade: a Gateway started on v1.0.x with
--master-key-filehasmaster_key_filein its launch profile and fails closed on restart withErrLaunchProfileCorrupted. Its vault was sealed under the file. Load the host's key source (on Linux without Secret Service,eval "$(ssh-agent)" && ssh-add), then run./ztd gw clean --yes,./ztd gw startwith the old startup flags, and./ztd login.gw cleankeeps the old runtime as.ztd-<MMDDHHMM>. See Upgrading a v1.0.x Gateway.
- Upgrade: a Gateway started on v1.0.x with
ztd eval boundaryand thecore-execution-boundarysuite — replaced byztd eval conformance.- Second command-generation inference in
run_commands_with_operator, andCommandForbiddenTerms. PathTmpand all/tmp,$HOMEand%TEMP%scratch in code, tests, the Makefile and remote staging.- Dead Windows certificate import (
internal/cli/auth/windows_crypto*.go).
Fixed
- Release smoke runtime and receipt verification — Mutable smoke runtimes now default to
.ztd/operators/and protected--rootlocations are rejected before startup. Receipt verification pins the Gateway-local actuator key and checks the outbound Operator key against enrollment, then verifies both the signature and persistence attestation. - Rejected file edit stalled dispatch — An Operator's early path-policy rejection now publishes a typed failed file-edit result before L5 signs its failed receipt, so dispatch can return the correlated failure without waiting for a result timeout.
- L3 deny left no evidence — A denied L3 suspension on MCP and A2A wrote no signed receipt. It is now a signed
L3_DENIEDrejection (see Added). - Early approval lost — An approval that arrived before the waiter subscribed was dropped. Waiters now subscribe first.
- Throwaway Operators could not edit their own tree —
security.IsProtectedRuntimePathrejected every.ztdpath component, including.ztd/operators/<name>/…. - Campaign mirror misclassification —
CampaignMirrorReconcilertreated a run with no verification report as failed instead of ineligible, because it checkedfs.ErrNotExistwhereRuntimeFileServicereturnsconstants.ErrNotFound. - Config loading probed ports —
config.LoadGatewayopened sockets while loading configuration. - Model-provenance preflight test race — The fake Gateway in
TestPreflightModelProvenanceContext_SSEReadyBeforeDispatchsignalled readiness after flushing SSE headers. It now mirrors the real Gateway's order.
Tests
- The Tier 1 socket check follows helpers transitively to dials and listeners, and its seeds cover
tls.Listen/Dial/DialWithDialer,http.Serve/ServeTLS, and thenet.Dialer,net.ListenConfig,tls.Dialer,http.Serverandhttptest.Servermethods. Every test it flagged moved to a same-package integration file. testutil.TempDiris project-local (<module>/.ztd/tmp/tNNN), andtestutil.OperatorDirgives agent-editable Operator roots. forbidigo rejectsos.TempDirandt.TempDir, andmake lintrejects empty-diros.MkdirTemp("")/os.CreateTemp("").- In-process tests use memory keyrings.
ephemeral_agent_linux_integration_test.gocovers the ephemeral ssh-agent.
Candidate verification (Linux, 2026-10-14):
| Command | Result |
|---|---|
./ztd test unit |
Pass |
./ztd test integration |
Pass (118 packages, race detector; before final lint fixes) |
./ztd test integration --pkg <package> (each of ./internal/services/gateway, ./internal/services/evaluation, ./internal/cli/cmd/gwremote, ./internal/cli/auth, ./internal/cli/cmd/eval) |
Pass after lint fixes, race detector enabled |
./ztd test lint |
0 issues |
make lint |
Pass after lint fixes: 0 issues, doctrine JSON valid, no called-code vulnerabilities (one non-called module vulnerability reported) |
make console-lint, make console-test |
Pass (44/44) |
make explorer-lint, make explorer-test |
Pass (590/590) |
make website-test |
Pass (123/123, PowerShell included) |
make website-build |
Pass |
make test-onboarding |
Pass |
make version-sync-check |
Pass (1.1.0, 16 declarations) |
make proto-generate, make swagger-generate |
No diff |
make console-embed-check, make constants-check, make doctrines-validate, make third-party-notices-check |
Pass |
- Release smoke (
./ztd test release-smoke) — Pass (exit 0,result: PASSin.ztd/operators/release-smoke-20261014T232325Z/evidence/smoke-summary.json): 3 scenarios (file-create,document-merge,embedded-file-create), 6 local receipts (2 worker, 4 gateway, allEXECUTION_STATUS_COMPLETED), 0 failed rows, 0 skipped rows across both Gateway and worker reports.
Documentation
CHANGELOG.md— Added the## v1.1.xindex with the1.1.0row. The## Unreleasedbullets moved into these notes.VERSION— Bumped tov1.1.0.make version-syncupdated the console, evaluation explorer, adapter andprotocol/nodepackages and theprotocol/docs/headers.docs/architecture/evals.md(conformance suite, INV-EVAL-CAMP-32/34),governance.md(INV-GOV-ACT-13, protected runtime paths),auth.md,console.md,gateway.md,encryption.mdandstorage.md(key custody, scratch),docs/devs/devs.md(INV-FS-11) andtests.md.- Guides: install examples and the cosign identity name
v1.1.0, and every master key file reference is replaced by the ssh-agent path.
Compliance Evidence
Operational evidence bundle generated by ./ztd compliance release-prepare:
- Scope:
gateway-operational-20261014(window 2026-10-14T20:52:32.092Z to 2026-10-14T20:53:02.092Z, 3 receipts, 4 commitments, 2 source signer keys). - Public bundle:
release-evidence/v1.1.0/report-bundle/manifest.json. - Offline verification:
compliance_bundle@2.0.0valid=true, failures=0, checksum root10f63dd77790705606ff0189b2df8631674abb52173f80bccdceda23e799b8dc. - Source revision:
6e9dd54869add43ccea6029d026ed2a8bc513d54. - Canonical projections:
docs/release_notes/v1.1.x/v1.1.0-compliance-evidence.mdanddocs/release_notes/v1.1.x/v1.1.0-compliance-evidence.csv.
Deferred
- evals-reimagined: F21 (single posture table), T26, T27/T28, T34, T35, T37, T39, T40, T41, M5 attended, M6, M7, M9, M10, E1/E2 (ztde).
- Standalone Operator + Autochthon tribunal: all of T00–T16, G1, G2. This is the v1.2.0 candidate.
- Multi-OS onboarding VMs: all six phases, including removing the Docker-based
scripts/onboarding/. - macOS onboarding: Developer ID signing and notarization, first macOS CI run, integration timeouts under load, Keychain isolation audit, live guide walkthrough.
- clean-dead-code: the second deadcode cascade. It overlaps F21 and T35, so it follows them.
- clean-store-paths: AuditService idempotency race,
FinalizeNonce,logBlockedTransaction,TransactionAuditStoreremoval, live HTTP-dispatch checks, pubsub setter injection, NULL-session receipts, and the open owner decisions (L12 SSE plaintext, Operatoractiveafter disconnect). - v1.0.0 carry-forward: owner security G09/G10 (
g8ee.keyhistory, off-machine backup, rulesets and immutable releases, Dependabot), distribution D1–D3, docs-site proposal, scope trim B5 (ensemble/ztde/Python mentions, reputation endpoint, orphan collections), console/TUI parity. - Pending plans: llama.cpp Inference Operator backend, Autochthon host-unique culture, Operator follow-ups (TUI liveness, native harnesses), and the Go-side env-config ratchet.
- On Windows,
.envownership and mode checking remains deferred.