proof-harness 0.1.0-next.1 → 0.1.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/COMPATIBILITY.md +437 -1
  2. package/PROOF_SDK_CONTRACT.md +118 -81
  3. package/README.md +108 -10
  4. package/cli/config.mjs +38 -14
  5. package/cli/engines/parse_proof_schema.mjs +43 -82
  6. package/cli/engines/proof_control_sensitivity.mjs +98 -0
  7. package/cli/engines/proof_coverage.mjs +45 -24
  8. package/cli/engines/proof_drift.mjs +119 -96
  9. package/cli/engines/proof_input_scope.mjs +177 -0
  10. package/cli/engines/proof_mutation_check.mjs +361 -108
  11. package/cli/engines/proof_mutation_inventory.mjs +16 -21
  12. package/cli/engines/proof_plant_verification.mjs +88 -0
  13. package/cli/engines/proof_schema_classification.mjs +75 -0
  14. package/cli/engines/proof_schema_provider.mjs +192 -0
  15. package/cli/engines/proof_verify.mjs +56 -37
  16. package/cli/engines/scan_proof_capabilities.mjs +452 -202
  17. package/cli/proof-harness.mjs +3 -5
  18. package/dist/{action-types-C3OmHRyH.d.ts → action-types-Cw-dmSKj.d.ts} +11 -1
  19. package/dist/{fixture-B-dmnG5G.d.ts → fixture-DwDOegDK.d.ts} +9 -1
  20. package/dist/{mission-types-Dr5rBHYO.d.ts → mission-types-CYXrtv5m.d.ts} +3 -3
  21. package/dist/node.d.ts +68 -3
  22. package/dist/node.js +430 -48
  23. package/dist/node.js.map +1 -1
  24. package/dist/playwright.d.ts +39 -8
  25. package/dist/playwright.js +873 -227
  26. package/dist/playwright.js.map +1 -1
  27. package/dist/server.d.ts +26 -2
  28. package/dist/server.js +103 -33
  29. package/dist/server.js.map +1 -1
  30. package/dist/shared.d.ts +3 -168
  31. package/dist/shared.js +7 -31
  32. package/dist/shared.js.map +1 -1
  33. package/dist/{trace-types-DkIzq-l9.d.ts → trace-types-BIW53YPH.d.ts} +6 -22
  34. package/package.json +5 -3
  35. package/proof-consumer-fixtures/action-invocation/auth-refusal.json +8 -0
  36. package/proof-consumer-fixtures/capabilities/auth-admin.json +15 -0
  37. package/proof-consumer-fixtures/capabilities/service-rpc.json +4 -0
  38. package/proof-consumer-fixtures/control-sensitivity/catalog.json +14 -0
  39. package/proof-consumer-fixtures/malformed/contradictory-status.json +45 -0
  40. package/proof-consumer-fixtures/mutations/primary-rpc/failed.json +31 -0
  41. package/proof-consumer-fixtures/schema-provider/catalog.json +13 -0
  42. package/cli/engines/proof_module_check.mjs +0 -498
  43. package/cli/engines/scan_module_meta.mjs +0 -352
package/COMPATIBILITY.md CHANGED
@@ -11,7 +11,7 @@ Consumers must pin an exact prerelease version, for example:
11
11
  ```json
12
12
  {
13
13
  "devDependencies": {
14
- "proof-harness": "0.1.0-next.1"
14
+ "proof-harness": "0.1.0-next.9"
15
15
  }
16
16
  }
17
17
  ```
@@ -24,3 +24,439 @@ tighten validation or packaging contracts even when its base version remains
24
24
  The trace, mission, and health protocol versions are independent from the npm
25
25
  package version. Consumers should reject unsupported artifact or protocol
26
26
  versions rather than guessing how to interpret them.
27
+
28
+ ## Prerelease migration notes
29
+
30
+ ### 0.1.0-next.11 (release candidate) — conservative service RPC assessment
31
+
32
+ Prepared for release. After publication, pin exactly `proof-harness@0.1.0-next.11`.
33
+ Regenerate
34
+ capabilities and rerun the complete baseline, coverage, inventory, and mutation
35
+ validation after adoption. Trace, mission, and health versions are unchanged.
36
+
37
+ Capability schema v1 gains additive `serviceRoleRpcCalls` entries with a literal
38
+ `function` and `assessment: "potential_privileged_write"`. Direct const-bound
39
+ service-client `.rpc("name", args)` calls support awaiting/returning the result
40
+ and zero-argument `.single()` / `.maybeSingle()` result chains. Dynamic names,
41
+ escaped builders, unsupported chains, and RLS-client RPCs remain unassessed.
42
+ An RLS client can invoke a SECURITY DEFINER function; its privilege is not inferred
43
+ from the client name. Result shaping does not establish read-only behavior.
44
+
45
+ This is conservative action-boundary assessment, not SQL function-body analysis.
46
+ It does not infer affected tables, effective grants, overloads, nested functions,
47
+ or transactional correctness. Consumer SQL/function privilege proofs and mutation
48
+ catalogs remain necessary; do not interpret this field as complete SQL write coverage.
49
+
50
+ Every service RPC action requires passing primary denial and allowed control
51
+ assertions targeting the exact `module:action`, both with `operation: "invoke"`.
52
+ The requirement applies without workspace inputs and to `_BOT` actions. Existing
53
+ assertion-origin rules remain in force; explicit authorization assertions retain
54
+ the consumer-owned trust boundary. RPC requirements cannot be waived through
55
+ `acceptedActionGaps`. No new runtime helper or caller-to-callee evidence mapping
56
+ is introduced.
57
+
58
+ Evidence for a signed webhook caller does not automatically satisfy a separately
59
+ callable write action. Protect and test the actual action boundary, including
60
+ alternative invocation paths; a staged route, `_BOT` suffix, or a generic 500
61
+ response is not proof of authorization. If that boundary cannot be established,
62
+ coverage remains blocked. Do not hide RPCs from discovery to bypass the gate.
63
+
64
+
65
+ ### 0.1.0-next.10 — explicit primary mutation evidence
66
+
67
+ Published release. Pin exactly
68
+ `proof-harness@0.1.0-next.10` and rerun a fresh baseline before mutation checks.
69
+ Trace, mission, and health protocol versions remain unchanged.
70
+
71
+ This fixes #26: next.9 accidentally required SDK-helper provenance for primary
72
+ mutation assertions, although primary inventory accepts explicit consumer
73
+ assertions. A mapped, decisive failed `role: "primary"` assertion recorded by
74
+ `recordAssertion` can again detect a mutation without `emittedBy`. An explicit
75
+ selector restriction on `emittedBy` still applies. Control sensitivity continues
76
+ to require recognized SDK-helper provenance; controls never detect primary
77
+ mutations. Existing freshness, plant, failed-run, and restoration checks remain.
78
+
79
+ No new RPC helper or provenance field is required. Do not supply or forge
80
+ `emittedBy`: public `recordAssertion` deliberately strips it. Consumer proof
81
+ specs and protected catalogs own the meaning of explicit primary assertions.
82
+ For an RPC EXECUTE-denial proof, successful unauthorized execution should emit
83
+ the mapped failed primary assertion. Unrelated SQL, transport, or setup errors
84
+ must remain incomplete or emit no decisive failure; they are not evidence of
85
+ the mapped breach. Tightening the consumer denial probe to accept only the
86
+ expected SQLSTATE (for example, `42501`) remains consumer-owned work.
87
+
88
+ ### 0.1.0-next.9 — anonymous actions and control sensitivity
89
+
90
+ Published release. Pin exactly
91
+ `proof-harness@0.1.0-next.9` and regenerate capabilities and baseline traces.
92
+ Trace/mission/health versions remain unchanged. Authentication refusal and
93
+ control-sensitivity output contracts use protocol/schema version 1.
94
+
95
+ #### Anonymous self-service actions (#23)
96
+
97
+ `assert.authorization` accepts `actor: "anonymous"` for **action probes only**.
98
+ It sends the protected POST invoker request in a fresh API context, without
99
+ login cookies or Authorization, and disables redirect following. It does not
100
+ clear or reuse the authenticated page session. Use the Playwright project's
101
+ `use.baseURL`, an explicit `action.baseURL`, or an already navigated page URL.
102
+
103
+ ```ts
104
+ await assert.authorization({
105
+ actor: "anonymous", page,
106
+ action: {
107
+ module: "user-management", name: "selfDeleteAccount", inputParams: {},
108
+ expectedAuthRedirect: "/sign-in",
109
+ },
110
+ });
111
+ ```
112
+
113
+ The consumer must update its **guarded invoker**, after request validation and
114
+ registered-handler lookup. In the catch around actual handler execution:
115
+
116
+ ```ts
117
+ import { authenticationRedirectResponse } from "proof-harness/server";
118
+ // Existing proofGuard, body validation, registry lookup, and handler call stay.
119
+ const refusal = authenticationRedirectResponse(error, request, {
120
+ module: body.module, action: body.action, allowedRedirects: ["/sign-in"],
121
+ });
122
+ if (refusal) return refusal;
123
+ // Keep the existing failure response for all other exceptions.
124
+ ```
125
+
126
+ Choose the exact authentication destination from the consumer's own auth
127
+ middleware. The adapter recognizes Next.js redirect errors only, requires no
128
+ Cookie/Authorization request headers, and matches an exact allowlisted relative
129
+ URL. It returns HTTP 401 with `{ protocolVersion: 1,
130
+ type: "proof_action_auth_refusal", module, action,
131
+ reason: "authentication_required", redirect }`. The client binds that envelope
132
+ to the invoked action and the assertion checks `expectedAuthRedirect`.
133
+ A generic 401/500, `action_threw`, invalid-form rejection, unexpected redirect,
134
+ malformed result, or missing registry entry is incomplete evidence. Anonymous
135
+ success is a failed authorization assertion. No seeded denied role is needed.
136
+
137
+ Use `assert.actionSucceeds` with a disposable authenticated actor for the
138
+ allowed-path control; account-deletion fixtures remain consumer-owned. The
139
+ adapter's destination list and placement are protected trust inputs: it must
140
+ only normalize authentication redirects from an executed registered action,
141
+ not invoker setup errors or unrelated redirects. This is not automatic proof
142
+ of an arbitrary application's authentication semantics.
143
+
144
+ Workspace scope discovery now follows local caller-input bindings and accesses,
145
+ including destructuring aliases and direct parse/safeParse results. It no
146
+ longer counts comments, SQL/output keys, or generated/result workspace IDs.
147
+ Unknown user-input dataflow used as workspace scope and dynamic input keys
148
+ remain unassessed. Internal `_BOT.ts` actions retain their existing exemption
149
+ from caller-boundary coverage. This is bounded local analysis, not intermodule
150
+ schema inference. In particular `createTeamWorkspace` no longer inherits a
151
+ cross-tenant requirement merely because it returns a new workspace ID. Declare
152
+ any additional product invariants and add their proofs in the consumer.
153
+
154
+ #### Separate positive-control sensitivity (#24)
155
+
156
+ Move the old `TENANT-deny-all` entry out of the primary mutation catalog into
157
+ a separate protected module named by `controlSensitivityCatalog` in
158
+ `proof.config.mjs`. Keep its existing subject, apply SQL and spec; add:
159
+
160
+ ```js
161
+ claims: [],
162
+ controls: [{
163
+ kind: "tenant_isolation", target: "workspace_members", operation: "select",
164
+ emittedBy: "assert.tenantIsolation",
165
+ }],
166
+ expectedFailureCode: "tenant_isolation_control",
167
+ ```
168
+
169
+ Run `proof-harness controls --inventory`, then `proof-harness controls` (or
170
+ `--only TENANT-deny-all`). Both require fresh passing baseline evidence for
171
+ every mapped package-origin **control** in the selected spec. The initial
172
+ contract supports tenant-isolation SELECT controls emitted by
173
+ `assert.tenantIsolation` or `assert.authorization`, with the exact failure code
174
+ `tenant_isolation_control`. Other sensitivity categories remain unsupported.
175
+
176
+ The runner reuses mutation planting/readback, isolated execution, restoration,
177
+ and recovery checks. A successful test needs a non-timeout failed proof, a
178
+ failed mapped control assertion of the same helper origin, and a step error
179
+ beginning with that exact failure code. Setup errors, incomplete/skipped
180
+ assertions, another spec, primary-only failures, or a missing failed control do
181
+ not count. Unexpected owner-control database errors are setup failures rather
182
+ than control rejection; explicit permission denial or zero visible owner rows
183
+ can establish the intended anti-vacuity failure.
184
+
185
+ Results live separately in `artifacts.controlSensitivity` (default
186
+ `.proof/control-sensitivity`), with `mode: "control-sensitivity"`,
187
+ `controlRejected`/`controlsTurnedRed`, and `detected: false`. They remain planted
188
+ traces and cannot satisfy baseline claims or primary mutation coverage. Use
189
+ `proof-harness controls --recover` for an interrupted run against the same
190
+ local stack; the shared recovery journal blocks either runner until restored.
191
+ Primary `mutate` still rejects `claims: []` with no resolved primary baseline.
192
+ A failed control can no longer count as a failed primary claim of the same
193
+ kind/target/operation. Wire both commands into consumer CI if both properties
194
+ are required.
195
+
196
+ ### 0.1.0-next.8
197
+
198
+ Published release `0.1.0-next.8`. Consumers pin exactly
199
+ `proof-harness@0.1.0-next.8` when adopting these features.
200
+
201
+ #### Direct RLS clients and Auth administration (#18)
202
+
203
+ The scanner recognizes immutable local bindings returned by
204
+ `createSupabaseRLSClient`, including named-import aliases and awaited calls.
205
+ Their table writes are assessed as RLS writes, never recorded as service-role
206
+ writes. Binding identity is local to its scope: shadowed identifiers,
207
+ reassignment, escaped clients/builders, and unresolved privilege still fail.
208
+ This remains convention-based discovery of the named consumer factories, not
209
+ verification of their implementation or arbitrary wrapper/dataflow analysis.
210
+
211
+ Direct `serviceClient.auth.admin.deleteUser(...)` is recorded in the additive
212
+ capability field `serviceRoleAuthOperations: ["deleteUser"]`, separate from
213
+ `serviceRoleMutations`. This does not pretend the Auth API is a SQL DELETE
214
+ (and does not infer whether its optional soft-delete argument is true).
215
+ Other administrative methods, dynamic method names, detached calls, and
216
+ unresolved administrative privilege remain unassessed.
217
+
218
+ Regenerate capabilities. Changes to Auth operations participate in drift under
219
+ `service_role_mutations_changed`. Coverage requires a package-origin denial
220
+ assertion and an allowed-path control for a user-facing Auth-admin action,
221
+ even when it has no workspace input or voluntary invariant declaration.
222
+ Existing explicit action-gap policy handling remains unchanged; a recognized
223
+ operation alone is not passing authorization evidence. Trace, mission and
224
+ health protocol versions are unchanged; capability schema remains additive v1.
225
+
226
+ #### Catalog providers and rollback INSERT controls (#19, #20)
227
+
228
+ These changes are not in the published `0.1.0-next.7`. They are opt-in; the
229
+ default SQL parser and REST INSERT/DELETE control remain available. No trace,
230
+ mission, or health protocol version changes. Pin exactly `0.1.0-next.8` only
231
+ after it is released.
232
+
233
+ #### Catalog assessment
234
+
235
+ Set `schemaProvider: "scripts/proof/catalog-provider.mjs"` in the protected
236
+ `proof.config.mjs`. `parse`, the parse step of `build`, and both sides of
237
+ `drift` use it instead of the conservative SQL parser. ALTER and DROP are then
238
+ evaluated by PostgreSQL, not inferred from historical CREATE statements.
239
+
240
+ The module must export a default async function receiving:
241
+
242
+ - `protocolVersion: 1`, `rootDir` for the tree being assessed;
243
+ - `migrations`: ordered `{ path, sql, sha256 }` entries from the configured
244
+ migration directory (top-level `.sql` files), and their combined `inputHash`;
245
+ - `withLocalPostgres(connectionUrl, callback)` and
246
+ `readPostgresCatalog(client, schemas = ["public"])` from `proof-harness/node`.
247
+ These are injected so the archived base needs no installed dependencies to
248
+ import these helpers. Keep the provider's own imports dependency-free.
249
+
250
+ The consumer provider must create an empty disposable database, apply its
251
+ versioned platform bootstrap and every supplied migration in order, read the
252
+ catalog, and drop the database in `finally`. Fail on migration or cleanup
253
+ errors. Return `{ protocolVersion: 1, assessed: true, issues: [], tables }` only
254
+ after successful evaluation and cleanup; `tables` is the helper's result.
255
+ The connection helper restricts connections to loopback hosts. The consumer
256
+ owns the local database URL, creation privileges, platform bootstrap, migration
257
+ ordering, schema selection, and any required role setup. Never use the live
258
+ head database as the base catalog, clone an application-populated database,
259
+ or catch a failed migration and return partial facts.
260
+
261
+ Catalog table facts contain `schema`, `name`, `columns` (names), `rls_enabled`,
262
+ `rls_forced`, and `policies`. Each policy contains `name`, `command`, `roles`,
263
+ `mode`, `using`, and `check`. Classification is package-owned. Drift compares
264
+ column names, RLS state including FORCE, and full policy facts; this does not
265
+ add drift coverage for column types, defaults, functions, triggers, or grants.
266
+ Malformed envelopes/facts and changed migration inputs fail assessment and
267
+ replace stale successful output with an unassessed artifact.
268
+
269
+ The schema artifact adds `assessment` with provider protocol/path/hash,
270
+ migration paths/hashes, combined input hash, and repository source hash. This
271
+ is source identity, not a signature. The provider, its platform bootstrap,
272
+ configuration, and installed harness remain protected trust inputs.
273
+
274
+ For generated migrations, retain `driftPrepare` to rebuild them in each tree.
275
+ **Adoption requires a preparatory base commit:** register the provider, its
276
+ platform bootstrap, and config in the consumer before the comparison that
277
+ upgrades the package. Both base and head must declare a provider. Drift rejects
278
+ switching assessment modes across the comparison and never substitutes head
279
+ configuration for a base without the provider. Existing next.7 ignores the new
280
+ keys; registering them does not repair its conservative parser. A consumer
281
+ already blocked on next.7 needs to land this trusted setup separately before
282
+ the candidate's first successful drift run.
283
+
284
+ #### Append-only INSERT controls
285
+
286
+ Configure the protected consumer config explicitly, using your local ports:
287
+
288
+ ```js
289
+ insertControl: {
290
+ mode: "rollback",
291
+ databaseUrlEnv: "PROOF_DATABASE_URL",
292
+ role: "service_role",
293
+ supabaseUrl: "http://127.0.0.1:54321",
294
+ }
295
+ ```
296
+
297
+ Supply the corresponding local PostgreSQL URL through that environment
298
+ variable; never commit its password. The configured REST origin must match
299
+ `NEXT_PUBLIC_SUPABASE_URL`. The database URL must refer to the same stack,
300
+ schema, and migrations as REST; the harness validates the configured origin
301
+ but cannot discover which database a REST server actually serves.
302
+
303
+ The denied INSERT still executes through the authenticated Supabase client.
304
+ Only after an explicit `42501` denial and a service read confirming no write
305
+ does the harness validate the same payload on one PostgreSQL connection:
306
+ BEGIN, SET LOCAL ROLE, INSERT, force deferred constraints, ROLLBACK. The role
307
+ must have the intended INSERT permission. Missing columns keep their database
308
+ defaults; the harness supplies no tenancy values. An invalid payload, failed
309
+ role change, database error, or unacknowledged rollback fails as incomplete
310
+ evidence. The harness records the control assertion only after success and a
311
+ REST reread confirming no matching row remains. There is no consumer callback
312
+ that can stamp a passing control.
313
+
314
+ No DELETE privilege is needed for this control. Transactional trigger writes
315
+ also roll back, but sequence advancement and external side effects do not;
316
+ use only a disposable local stack. This control checks database validity under
317
+ the configured role, not REST middleware or an authenticated user's JWT
318
+ context. Templates whose privileged insert depends on that context must supply
319
+ a suitable database design/control strategy rather than treat this mode as
320
+ equivalent. Product authorization errors must still use SQLSTATE `42501`;
321
+ generic exceptions such as `P0001` are not accepted as authorization evidence.
322
+
323
+ For maintainers, `PROOF_DATABASE_URL=... node tests/postgres-integration.mjs`
324
+ after `pnpm build` exercises a separate temporary database against PostgreSQL,
325
+ including immediate and deferred failures and catalog ALTER/DROP behavior.
326
+
327
+ ### 0.1.0-next.7 — audit hardening
328
+
329
+ Published release `0.1.0-next.7` tightens acceptance behavior. Trace
330
+ <a id="unreleased-audit-hardening"></a>
331
+
332
+ ### 0.1.0-next.7
333
+
334
+ Published September 7, 2026. This release tightens acceptance behavior. Trace
335
+ schema remains 2, with additive source/execution identity fields. Version 1
336
+ and unversioned trace shapes remain explicitly readable, but CLI acceptance
337
+ requires current provenance. Required consumer changes:
338
+
339
+ - Regenerate traces. `verify`, `coverage`, and mutation inventory share a
340
+ decoder: corrupt JSON, duplicate proof IDs, unknown vocabulary, and
341
+ contradictory verdicts fail. Only passing baseline evidence can satisfy
342
+ claims; mutation evidence is separate. Current spec contents must match
343
+ `specHash`; in Git worktrees both `commit` and `sourceHash` must match.
344
+ `sourceHash` includes tracked and untracked nonignored inputs and excludes
345
+ configured generated artifacts. Run generators before proofs. Non-Git
346
+ exports cannot establish whole-source freshness and only check spec hashes.
347
+ - Use a dedicated trace directory. The writer honors `artifacts.traces` and
348
+ the runner's `--traces-dir` override. IDs must use letters, digits, dots,
349
+ underscores, or hyphens, starting with a letter or digit. Duplicate IDs
350
+ cannot overwrite another proof; a later Playwright retry of the same test
351
+ may replace its earlier attempt. Standalone repeated runs need fresh output.
352
+ Mission aggregates now live at `<traces>/missions/<missionId>.json` to
353
+ prevent collisions with proof IDs. Cleanup refuses unknown JSON before
354
+ deleting any trace and rejects repository/ancestor directories, including
355
+ symlink aliases. Move legacy or corrupt files aside before rerunning.
356
+ - UPDATE denial probes require stable `identityColumns` (default `["id"]`),
357
+ present and non-null in every target row, excluded from the update payload.
358
+ The attempted update must change a value. Rereads use original identities,
359
+ even when a write changes a filter column. SQL errors other than `42501`
360
+ are incomplete evidence. INSERT probes require a payload absent before the
361
+ probe and valid for a service-role control insertion; that control is
362
+ cleaned up. HTTP expectations must contain a status or a nonempty matcher
363
+ list. Write requests are never automatically retried after transport errors.
364
+ - Capability discovery uses TypeScript syntax analysis for import aliases and
365
+ multiple actions. Unknown factory/client indirection, escaped service query
366
+ builders, dynamic table names, and ambiguous metadata block assessment.
367
+ Discovery still assumes the configured template action layout.
368
+ - The SQL parser is deliberately conservative, not a final PostgreSQL catalog
369
+ evaluator. Unsupported ALTER/DROP or dynamic SQL makes schema assessment
370
+ fail. RLS must be explicitly enabled for classification; public ALL/write
371
+ policies are never exempted as public-read. Policy expressions and mode
372
+ participate in drift. Resolve unsupported migrations with a catalog-backed
373
+ integration before using this parser as a gate; do not edit shipped SQL or
374
+ mark an unassessed artifact assessed to obtain a pass.
375
+ - Drift always regenerates both trees using the installed harness and each
376
+ tree's consumer configuration. It includes untracked actions, SQL, and
377
+ lockfiles. For ignored/generated migrations, configure `driftPrepare` as a
378
+ command argv array (for example `["node", "scripts/aggregate_migrations.mjs",
379
+ "--fresh"]`). That consumer-owned command runs in each tree before parsing;
380
+ failure prevents assessment. It must work in the archived tree without an
381
+ implicit dependency install. The old `driftSources` optimization is unused.
382
+ - Mutations require fresh mapped baseline claims and write isolated traces.
383
+ SQL applies run as one transaction; recovery is attempted even after a
384
+ failed apply. Policy snapshots preserve expressions, roles, command, and
385
+ permissive/restrictive mode. Generic privilege mutations support direct,
386
+ owner-issued grants without grant options; unsupported inherited/PUBLIC or
387
+ ownership cases fail before planting. Move old mutation outputs aside on
388
+ first use: nonempty output directories require a harness ownership marker.
389
+ An interrupted run leaves `mutation-recovery.json` beside the mutation output
390
+ directory. Run `proof-harness mutate --recover` against the same local
391
+ database to restore and verify the journaled subject. A timeout, signal, or
392
+ incomplete failed claim never counts as detection. Recovery covers the
393
+ catalog's declared subject and cleanup, not arbitrary undeclared side effects.
394
+ - Partial fixture setup is cleaned up, and cleanup errors now fail the proof.
395
+
396
+ These checks validate observed evidence. Protect the installed harness,
397
+ configuration, mission, policies, mutation catalog, and CI acceptance job from
398
+ executor edits. Trace metadata is not a signature or a sandbox: it cannot
399
+ establish honesty against an executor allowed to replace the gate or fabricate
400
+ its inputs. Independent product acceptance and a trusted runner remain needed.
401
+
402
+ ### 0.1.0-next.6
403
+
404
+ **Removed: the module-descriptor system.** It served the consumer's planner
405
+ (what a module is for, what a buyer must decide, where answers land) and never
406
+ fed verification, so it is now consumer-owned. Gone from the package:
407
+
408
+ - CLI commands `modules` and `modules-check` (and the `modules` step inside
409
+ `build`); the `.proof/module-policy.json` accept-list introduced in
410
+ `next.5` went with the checker.
411
+ - `proof-harness/shared` exports `ModuleMeta`, `ModuleDecision`,
412
+ `ModuleInput`, `ModuleDefault`, `ModuleSeam`, `ScannedModule`,
413
+ `ModulesArtifact`, `MODULE_DESCRIPTOR_SCHEMA_VERSION`, `MODULE_KINDS`,
414
+ `APPLIED_BY`, `ModuleKind`, `AppliedBy`, `isModuleKind`, `isAppliedBy`.
415
+ - The `proof.config.mjs` keys `artifacts.modules`, `policies.module`,
416
+ `roots.modules`, `roots.sharedModules`, and `moduleKinds` (now ignored if
417
+ supplied).
418
+
419
+ Migration: consumers using the system vendor it from
420
+ `proof-harness@0.1.0-next.5` (Apache-2.0) — `cli/engines/scan_module_meta.mjs`,
421
+ `cli/engines/proof_module_check.mjs`, and `src/shared/module-types.ts` plus the
422
+ two vocabularies above — and point their `module.meta.ts` type imports at the
423
+ vendored copy. Consumers that never ran `proof:modules` are unaffected. Trace,
424
+ mission, and health protocol versions are unchanged.
425
+
426
+ ### 0.1.0-next.5
427
+
428
+ No artifact schema or protocol changes. Three behavioral changes:
429
+
430
+ - **`seed.workspace` no longer writes `type`.** The insert carries only
431
+ `name` plus caller-supplied values — the harness never invents a column
432
+ value it wasn't given. A schema whose `workspaces` table has required
433
+ columns without defaults (the conventional template's `type` included)
434
+ must supply them via `seed.workspace(name, { columns: { … } })` or the new
435
+ `workspaceColumns` option on `assert.tenantIsolation`, or add a database
436
+ default.
437
+ - **`createProofServiceClient` refuses non-local targets.** Any
438
+ `NEXT_PUBLIC_SUPABASE_URL` whose parsed hostname is not
439
+ `localhost`/`127.0.0.1`/`[::1]` aborts as `unsafe_database` before a
440
+ client is constructed, because the suite deletes the users and workspaces
441
+ it seeds. CI setups reaching Supabase through a docker-network hostname
442
+ call `allowProofServiceHosts(["<host>"])` in code; there is no environment
443
+ override.
444
+ - **`modules-check` gains an accept-list.** `.proof/module-policy.json`
445
+ (`schemaVersion: 1`, `acceptedUndescribed: [{ module, reason }]`) lets an
446
+ adopting consumer record undescribed required-root modules as visible debt
447
+ instead of turning the check off. Entries that stop applying fail as
448
+ `module_policy_stale`. Absent file = no acceptances; existing consumers
449
+ are unaffected.
450
+
451
+ ### 0.1.0-next.4
452
+
453
+ No entry-point, artifact schema, or protocol changes. The `mutate` command
454
+ tightens validation: each mutation's subject is now read back after apply and
455
+ again after its proof, so a defect that never took effect fails as
456
+ `NOT PLANTED` and one that was externally undone mid-run fails as
457
+ `UN-PLANTED` — both distinct from a missed proof. A catalog mutation whose
458
+ `apply` intentionally leaves its subject unchanged (it plants a side object
459
+ that `cleanup` removes) must now declare `applyDoesNotChangeSubject: true`;
460
+ runs with such undeclared mutations fail until the flag is added. The shared
461
+ dev server is also started before the first defect is planted rather than
462
+ inside the first mutation's window.