Production Tribunal, Governed Approvals, and Investigation Campaigns
Overview
v1.2.0 moves command authoring behind a Gateway-side Tribunal, adds a CLI L3 approval path with local L3 proof
verification on outbound Operators, makes consensus bindings K-of-N, and gives evaluation campaigns fresh and persistent
investigations with sealed agent-trace.v7 evidence. The legacy evaluation SUT and the JSON agent-tool registry
are removed.
Protocol changes are additive except where noted under Removed; retired field and enum numbers are reserved.
Highlights
- Production Tribunal — New
POST /api/v1/operators/intents(internal/services/tribunal/,internal/services/gateway/tribunal_intent.go). A caller submits a plain-language intent; the Tribunal runs generate → vote → marshal (risk) → audit as governedINFERENCEdispatches (a high-risk winner isBLOCKEDbefore audit), then dispatches the approved command as an ordinary governedEXECUTE_BASHunder the caller's identity. It never supplies or replaces L2 or L3 proof. Outcomes:APPROVED,NO_CONSENSUS,BLOCKED(high risk, with rationale),AUDIT_FAILED,INFERENCE_FAILED. Requires an app workload identity with a delegated user (INV-GW-GOV-07). - CLI and outbound L3 approval —
ztd auth approve --clisigns the transaction hash with the enrolled CLI certificate. Outbound Operators verify L3 proof locally: notary proofs carry the CLI certificate chain (cli_certificate_der,cli_intermediates_der) or aPasskeyVerificationContext(user, credential, COSE key, RP ID, allowed origins). Approval logic lives ininternal/governance/cli_approval.goandpasskey_approval.go; outbound verification is ininternal/services/governance/outbound_l3_notary.go. - K-of-N consensus bindings —
ztd auth enroll consensus bindaccepts repeated--member-appand--quorum. A multi-member set must state its quorum, and the primary app must be a member. The Gateway and the L5 handler resolve membership through one owner (models.ResolveConsensusMembership). New enrollment payload fields:consensus_member_app_ids = 22,consensus_quorum = 23. - Investigation campaigns —
ztd eval campaigns creategains--investigation fresh|persistent:<id>,--data-operator,--condition longitudinal|control|held-context,--formations, and--posture.--hold-contextnow defaults tofalse. Campaigns can settribunal_commands, so the model states intent throughrun_commands_with_operatorand the Tribunal writes the command. - Sealed campaign evidence — Each assignment seals its full conversation and tool trajectory as a
content-addressed
agent-trace.v7envelope (v1.1.3 sealedagent-trace.v5). Campaign import and the assignment verifier accept only v7 for new campaign evidence. - Event-driven runtime — Process-exit waiting uses platform-specific process handles
(
internal/cli/platform/process_exit_*.go).ztd eval runsfollows stop and status events over the existing event stream. The@ztd/adapterSSE polling fallback is gone.
Added
- Protocol
ztd/tribunal/v1/tribunal.proto:TribunalIntentRequest,TribunalIntentResult,TribunalMemberCall,TribunalStage,TribunalOutcome.common.proto:PasskeyVerificationContext; notary proof fieldscli_certificate_der = 7,passkey_context = 8,cli_intermediates_der = 9;pending_dispatch = 3; consensus enrollment fieldsconsensus_member_app_ids = 22,consensus_quorum = 23.eval.proto:EvaluationInvestigationMode(FRESH,PERSISTENT),EvaluationInvestigation,EvaluationRun.provider_observation_policy = 14andmodel_provenance_policy = 15,formation_stack_set_digest = 15,tribunal_commands = 17.operator.proto:observation_receiptson inference results and failures;GOVERNANCE_REJECTION_CODE_MCP_TARGET_MISMATCH = 25;RECEIPT_FAILURE_CODE_REHYDRATION_FAILED = 21.
- API —
POST /api/v1/operators/intents. - CLI
ztd auth approve --cliztd auth enroll consensus bindgains repeatable--member-app <id>and--quorum <n>ztd eval campaigns createflags listed aboveztd test eval-loop [--posture ratify|notary] [--live-ollama-endpoint --live-model]: cross-process evaluation loop against real Gateway, Data Operator, and Inference Operator processes. The live mode reaches Ollama only through the governed Inference Operator.
- Assignment audit database (
internal/services/assignmentaudit/) — Holds one assignment's public feed records. Its signed proof segment authenticates it by SHA-256, andztd public verify-assignment --db --segments --public-keyverifies it offline (see Removed for the dropped vault key). - Constants —
ErrScrubbingTokenUnresolved,ErrScrubbingKeyCollision,ErrMCPNativeToolHostMissing,ErrProcessNotFound,ErrUnsupportedPlatform,ErrConfigLeafCertTTLInvalid,ErrGovernanceCLISessionRequired,ErrEvaluationInvestigationInvalid,ErrMCPAuditReceiptListInvestigationReq,ErrEventRequestWireValue,ErrEventStreamTransport,ErrEventRegistryUnknownField.
Changed
- Agent tools — The evaluation agent tool catalog is built from native tool definitions
(
agent_native_tools.go), not a JSON registry. - Campaign trace pin — Live and recovered campaign import accepts only
agent-trace.v7. Older campaign traces are recorded asINVALID_EVIDENCEand are not graded.ztd public verify-agent-tracestill verifies published v3–v5 traces and now also v6. - Judging — Agent traces are now scored by the evaluation judge.
INVALID_EVIDENCEandPROVIDER_FAILEDassignments are never judged. Each judge score must bind to a signed inference receipt whose result summary matches the scored result. - Witness collection — Provider-boundary observation and model provenance are optional at dispatch. An attempt with no connected observer or provenance Operator skips the window; run witness policies enforce coverage at verification.
- Compliance catalog 2.1.0 —
ZTD-DLP-BOUNDARY-001,ZTD-DLP-REHYDRATE-001, andZTD-CM-STATE-001are scoped togateway/operator, andcomponent_scopeis a closed set. - Operator bootstrap — The bootstrap client requires TLS 1.3.
- Tunnels —
ztd gw tunnel create --ca-bundlesends the Gateway internal hostname as origin SNI.--origin-server-namewithout--ca-bundleis rejected. - Enrollment — App-name validation has one owner shared by the CLI and Gateway. A reserved or invalid name returns HTTP 400, not 500.
.envloading — The working-directory.envis loaded at the end of the root pre-run, after command gates pass. A command refused at pre-run,--help, and--versionno longer read it.- Scrubbing boundary — Rehydration fails closed on unresolved tokens and key collisions. The FAILED receipt
carries
RECEIPT_FAILURE_CODE_REHYDRATION_FAILED. - Event registry validation —
make constants-generaterejects unknown registry fields, non-governed request events whose wire value does not end in.requested, and stream events with an absent or non-ssetransport.protocol/models/event_registry.schema.jsonnow matches the generator's checks, and a test pins the two together. - Public mirror listeners — The private listener (
:8081) serves ingest routes only. Anonymous read routes are served only on the public listener (:8082).
Removed
- Legacy evaluation SUT —
internal/services/evaluation/sut/, the/ztd-sutroutes, SUT timing constants, and theScoredTurnRequest/ScoredTurnEvent/InvestigationSeedprotocol messages. - JSON agent-tool registry —
protocol/constants/agenttools/. provider_boundary_observation_ref = 32— Reserved. Observations travel asobservation_receipts.- Assignment audit vault encryption —
--vault-keyis removed from public assignment verification. The database carries only already-published public feed records and is authenticated by its signed proof segment. - PID-file fallback in deployment stop — Deploy-host stop no longer signals workers found only through
operator.pidfiles; it stops workers through verified process discovery and fails closed. @ztd/adapterSSE polling fallback (src/sse/polling.ts).- Sentinels —
ErrEvaluationSystemLaneUnavailableand sixErrCLIL3*sentinels (ErrCLIL3ApprovalExpired,ErrCLIL3GetSuspendedTransactionFailed,ErrCLIL3InvalidFingerprintFormat,ErrCLIL3PublicKeyMissing,ErrCLIL3SuspendedStoreNotConfigured,ErrCLIL3TransactionNotApproved). CLI L3 verification now usesErrGovernanceCLISessionRequiredand the shared approval owner.
Fixed
- Host deployment stop propagates signal and exit-wait failures and reports an Operator stopped only after its exit is observed. A missing Operator executable is rejected before an existing Operator is stopped or its log is truncated.
- The public mirror rejects ingest when no token is configured.
@ztd/adapterresolves under plain Node ESM: it has a root barrel (src/index.ts),.jsimport specifiers, and exported error classes.- The evaluation explorer seed script fails closed on mirror snapshot, status, or push errors. The dev supervisor exits with Vite's exit code.
- External MCP server help examples use
ztd gw start. - The base init campaign queue declares 41 cells per model, matching the default suite, and lists only base
inventory models (
pdevine/qwen3.6:27b-mtp-q4_K_Mandqwen3:30bremoved). - The
A2A_CALLevent registry entry names its actual payload message,A2aCallRequested. - A new public-feed signing key no longer adopts proof state signed by a deleted key. Gateway startup fails
closed with
ErrPublicFeedOrphanedGenerationwhenpublic-proofs/,proof-mirror-sync.json, the outbox, or another feed-generation path exists without its signing key. Source transition also archivesproof-mirror-sync.json.
Tests
Linux amd64 qualification of the release candidate:
make build— pass../ztd test unit— pass (128 packages)../ztd test lint— pass, 0 issues../ztd test integration— pass (129 packages)../ztd test eval-loop— pass, ratify and notary postures, scripted provider../ztd test release-smoke—result: PASS, doctrine posture.make console-lint console-test console-embed-check— pass, 49 tests.make explorer-lint explorer-test explorer-embed-check— pass, 711 tests.npm test --prefix ztd-adapterandnpm run gen:contract-pack:check --prefix ztd-adapter— pass, 429 tests.make ci-protocol,make swagger-generate,make constants-check doctrines-validate version-sync-check third-party-notices-check explorer-catalog-check— pass, no generated drift.make website-test website-build— pass; 12 PowerShell checks skipped (nopwshon the qualification host).
Not qualified in this release: native macOS and Windows runs, and live Tier 4 model evaluation. No model-quality or hosted-provider claims are made.
Documentation
docs/architecture/agents.md— Production Tribunal section.docs/architecture/gateway.md—INV-GW-GOV-07(Tribunal intent dispatch).docs/architecture/evals.md— Investigation modes, formation campaigns, Tribunal commands,agent-trace.v7.docs/architecture/consensus.md— K-of-N bindings.protocol/docs/reference/api/ztd/tribunal/v1/— Generated Tribunal reference.CHANGELOG.md—1.2.0entry under## v1.2.x.
Compliance Evidence
Operational evidence bundle generated by ./ztd compliance release-prepare:
- Scope:
gateway-operational-20261020(window 2026-10-20T16:30:10.965Z to 2026-10-20T16:30:40.965Z, 3 receipts, 4 commitments, 2 source signer keys). - Public bundle:
release-evidence/v1.2.0/report-bundle/manifest.json. - Offline verification:
compliance_bundle@2.0.0valid=true, failures=0, checksum root0b9e7ace733c7fd4c1bf908af9e0d94ed637ee32d1cffe491c43d8e520b9130c. - Source revision:
3b99359cd00e19e4f6a0663cfdc8f42f7bdfaa5a. - Canonical projections:
docs/release_notes/v1.2.x/v1.2.0-compliance-evidence.mdanddocs/release_notes/v1.2.x/v1.2.0-compliance-evidence.csv.
Deferred
- All prior deferred items carry forward; see v1.1.3 Deferred.
- External SUT support.
- Formation repetitions beyond one per cell.
- Execution of the Triage, Dash, and Codex roles through
persona/. - Durable case memory, expanded verification, public chronology, and statistical analysis of longitudinal campaigns.