@@ -10,9 +10,183 @@ evidence set matches the current published `openadapt-flow` release. It does
1010not mean the campaign is production acceptance. The evidence manifest records
1111that distinction in ` campaigns[].evidence_scope.production_acceptance ` .
1212
13+ That campaign field is now descriptive only and must remain ` false ` . A person
14+ cannot promote an evidence set by changing it, changing an evidence class, or
15+ adding summary counts. Production acceptance can enter this repository only
16+ through ` scripts/import_production_acceptance.py ` after the private-export gate
17+ opens.
18+
19+ ## Independent hosted-acceptance verifier
20+
21+ The verifier mechanism is implemented. The private-evidence import is not
22+ enabled. ` import_files ` refuses every file import until OpenAdapt approves one
23+ exact private-export contract. Do not export an admission or campaign to this
24+ repository. Do not set ` production_acceptance: true ` while this gate is closed.
25+ The checked-in fixtures are synthetic test vectors only.
26+
27+ The future approval must bind the complete payload schema and digest, the
28+ destination account, service, container, and prefix, the encryption-key
29+ identity, the immutable retention mode and period, the authorized importer
30+ workflow and ref, and the approval authority. A broad enable flag or approval
31+ of only the admission and campaign digests is not sufficient.
32+
33+ After approval, the importer will compose four evidence inputs:
34+
35+ 1 . The closed ` openadapt.execute-live-acceptance-record/v2 ` certificate from
36+ the protected Cloud production workflow.
37+ 2 . The signed ` openadapt.qualification-admission/v2 ` envelope from the
38+ protected qualification authority.
39+ 3 . The full ` openadapt.qualification-campaign/v2 ` artifact with every retained
40+ trial row and normalized evidence receipt for the exact qualification
41+ contract.
42+ 4 . The GitHub artifact-attestation bundle for the certificate bytes.
43+
44+ The future importer also needs external control inputs: the approved Cloud
45+ source commit, the approved qualification signer registry, the admission and
46+ signer revocation lists, and the exact private-export approval. The evidence
47+ artifacts cannot select these values. The full admission and campaign stay in
48+ the encrypted retained evidence package until that approval exists. After
49+ approval, a protected job can stage only the approved payload for
50+ verification. The derived public result contains hashes and bounded counts. It
51+ does not contain tenant or workflow identifiers.
52+
53+ The verifier asks GitHub CLI to verify the certificate against the exact
54+ ` OpenAdaptAI/openadapt-cloud ` workflow on ` refs/heads/main ` , the GitHub Actions
55+ OIDC issuer, and a GitHub-hosted runner. It then validates the verified SLSA
56+ provenance. It refuses an unknown repository, workflow, ref, source digest,
57+ issuer, runner class, signature, or empty verification result.
58+
59+ The expected Cloud commit is an external reviewer input. The importer requires
60+ the certificate commit, the GitHub signing-certificate source commit, and the
61+ SLSA resolved ` gitCommit ` to equal that value. It also requires the signing
62+ certificate and the SLSA source dependency to use ` refs/heads/main ` . The
63+ certificate cannot select its own approved commit.
64+
65+ The evidence manifest does not store or select this approval. The repository
66+ checker reads it from the protected ` APPROVED_CLOUD_ACCEPTANCE_COMMIT ` GitHub
67+ repository variable. A production declaration fails when that variable is
68+ absent or differs from the certificate and verified provenance.
69+
70+ The certificate is necessary but not sufficient. It proves one authenticated,
71+ qualified browser transaction and binds the private request, idempotent
72+ responses, runner delivery, result, report, receipt, target attestation,
73+ single-use runner permit, independent observer, webhook, billing outcome, and
74+ separate signing identities by digest. The importer also verifies the external
75+ qualification admission. It checks the exact issuer workflow and main-branch
76+ commit, the Ed25519 signature, the derived key ID, the active time window, and
77+ the external admission and key revocation lists. It refuses a trust key that
78+ the imported evidence supplies for itself.
79+
80+ The admission signs one shared evidence identity for the exact workflow,
81+ campaign, environment, Flow release and wheel, runner build and artifact,
82+ browser image, runtime manifest, signer registry revision, and every admitted
83+ contract. The certificate repeats the public domain-separated campaign,
84+ admission, runtime-validation, and workflow-version digests. The importer
85+ recomputes each digest from the retained admission. The admission also signs
86+ canonical hashes for the full campaign, qualification contract, outcomes
87+ projection, oracle, and exact task inventory. The campaign must retain every
88+ condition in the bound qualification contract and at least three unique trials
89+ for each condition. Trial indexes are one-based and contiguous. Attempt IDs
90+ and run IDs cannot repeat. An excluded or hidden trial causes refusal.
91+
92+ The shared identity calls the receipt authority
93+ ` evidence_runner_signer_sha256 ` . This name applies to browser, native Desktop,
94+ BYOC, RDP, Citrix, and offline customer-controlled evidence. It does not imply
95+ that the evidence runner is an OpenAdapt-managed browser runner.
96+
97+ Each ` openadapt.qualification-trial-row/v2 ` trial refers to hash-keyed
98+ ` openadapt.qualification-evidence-receipt/v2 ` Ed25519 envelopes for the runner,
99+ independent observer, webhook, replay, cleanup, and cleanup-absence result.
100+ Fault cases also require a signed fault receipt. The importer verifies each
101+ envelope body, signature, authority key, source digest, task, condition, trial
102+ index, attempt, run, workflow version, bundle artifact, runtime validation,
103+ admission, evidence identity, verdict, and time. A digest with no signed body is
104+ not evidence. An unused envelope is hidden evidence and causes refusal.
105+
106+ The importer classifies the verified rows itself. The signed observer receipt
107+ contains the exact effect inventory. The signed runner receipt contains the
108+ model-call counters, provider-model inventory, egress-policy digest, report
109+ digest, and operator-intervention inventory. The importer derives failures
110+ from these facts. It rejects a count-only claim, declared production class or
111+ boolean, unsupported failure class, vacuous invariant, healthy-path contract
112+ that permits a model call, healthy-path model call, silent incorrect success,
113+ over-halt, wrong-record effect, duplicate effect, collateral effect, uncertain
114+ delivery, platform failure, or operator intervention.
115+
116+ The derived result binds the certificate's campaign-outcomes and independent
117+ oracle-contract digests. It repeats the validated task, condition, required
118+ trial, and observed trial counts. It includes every closed failure-taxonomy
119+ count used for the verdict. Task and condition identities use domain-separated
120+ SHA-256 values. The public result does not contain the private task or condition
121+ labels. The derived-result file digest therefore changes after a one-field
122+ change to a binding, count, or privacy-safe identity.
123+
124+ ## Target-neutral acceptance manifest
125+
126+ The importer contains a pure builder and validator for the closed
127+ ` openadapt.production-acceptance/v1 ` manifest. The mechanism does not write,
128+ sign, export, attest, or publish a manifest. It accepts only a complete accepted
129+ private result. It binds the target and its exact claim scope in both the fixed
130+ policy and the manifest.
131+
132+ | Target | Exact claim scope |
133+ | --- | --- |
134+ | ` agent ` | ` qualified_agent_bridge_release ` |
135+ | ` capture ` | ` qualified_native_recorder_release ` |
136+ | ` cloud ` | ` qualified_workflow_control_plane_deployment ` |
137+ | ` desktop ` | ` qualified_native_workflow_desktop_release ` |
138+ | ` docs ` | ` production_documentation_deployment ` |
139+ | ` flow ` | ` qualified_workflow_runtime_release ` |
140+ | ` openadapt ` | ` qualified_workflow_launcher_release ` |
141+
142+ The current browser evidence adapter can build only the Flow target manifest.
143+ The other targets require their own evidence adapter. Cloud also requires a
144+ reviewed deployment-manifest binding. The builder refuses Cloud until that
145+ binding exists. It does not emit a placeholder or failed record when an adapter
146+ is absent.
147+
148+ For Flow, a separate lifecycle verifier accepts the exact raw lifecycle-policy
149+ bytes, one closed public-package release, and the PyPI release metadata. It
150+ requires the exact GitHub source-commit URL. It requires one sorted sdist and
151+ one wheel. Each artifact includes its authority, kind, name, URL, size, and
152+ SHA-256 digest. The verifier matches each field to exactly one non-yanked PyPI
153+ file. It then returns an immutable verified-release object. A caller-supplied
154+ mapping or digest cannot replace this object.
155+
156+ The pure manifest builder accepts only this verified-release object. It matches
157+ the Flow version, source commit, and wheel digest to the private result. It
158+ binds the complete sdist and wheel inventory. It uses the same release and
159+ artifact digest domains as the Production lifecycle validator. The manifest
160+ contains two separate policy digests. The acceptance-policy digest covers the
161+ fixed Evals acceptance rules. The lifecycle-policy digest covers the exact raw
162+ lifecycle-policy bytes.
163+
164+ The public qualification section contains aggregate trial counts and one
165+ campaign-scoped task-condition inventory digest. It does not publish task or
166+ condition labels. The closed source-result digest remains the authority for the
167+ hidden per-condition inventory.
168+
169+ When the private-export gate opens, the output claim will be only
170+ ` qualified_browser_workflow_on_bound_environment ` . It is not a general product
171+ production-readiness claim. The checker can accept ` production_acceptance: true `
172+ only when the evidence manifest contains digest-bound links to all four inputs
173+ and the exact derived output, the protected workflow supplies the external
174+ trust, revocation, and export-approval controls, and the importer reproduces
175+ that output. Until then, the importer refuses. A bare registry boolean or
176+ campaign label fails the check.
177+
178+ Cloud does not issue a complete acceptance record before it verifies durable
179+ retention. The private evidence envelope uses encrypted immutable storage with
180+ Object Lock and KMS. The public record retains only opaque digests and the
181+ verified retention facts. The importer verifies the public retention receipt
182+ and its exact binding to the candidate and retained envelope. GitHub artifact
183+ retention alone does not satisfy this contract.
184+
13185## What the current public Evals set establishes
14186
15187The Flow 1.31.0 set contains four campaigns. Every condition has three trials.
188+ This set is development evidence. It is not a Production lifecycle admission,
189+ and this change does not emit a Production record for it.
16190
17191| Campaign | Environment | What it measures | Production acceptance |
18192| --- | --- | --- | --- |
0 commit comments