projscan 4.14.0 → 4.15.0

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 (186) hide show
  1. package/README.md +71 -21
  2. package/dist/cli/commands/evidencePack.js +2 -0
  3. package/dist/cli/commands/evidencePack.js.map +1 -1
  4. package/dist/cli/commands/prove.js +172 -23
  5. package/dist/cli/commands/prove.js.map +1 -1
  6. package/dist/cli/commands/startConsole.d.ts +2 -2
  7. package/dist/cli/commands/startConsole.js +2 -260
  8. package/dist/cli/commands/startConsole.js.map +1 -1
  9. package/dist/cli/commands/startConsoleExecution.d.ts +5 -0
  10. package/dist/cli/commands/startConsoleExecution.js +108 -0
  11. package/dist/cli/commands/startConsoleExecution.js.map +1 -0
  12. package/dist/cli/commands/startConsoleMission.d.ts +6 -0
  13. package/dist/cli/commands/startConsoleMission.js +157 -0
  14. package/dist/cli/commands/startConsoleMission.js.map +1 -0
  15. package/dist/cli/commands/startMissionBundle.js +24 -27
  16. package/dist/cli/commands/startMissionBundle.js.map +1 -1
  17. package/dist/core/adoption.d.ts +8 -81
  18. package/dist/core/adoption.js +4 -549
  19. package/dist/core/adoption.js.map +1 -1
  20. package/dist/core/adoptionFirstRunDiagnostics.d.ts +20 -0
  21. package/dist/core/adoptionFirstRunDiagnostics.js +240 -0
  22. package/dist/core/adoptionFirstRunDiagnostics.js.map +1 -0
  23. package/dist/core/adoptionMcpConfig.d.ts +27 -0
  24. package/dist/core/adoptionMcpConfig.js +123 -0
  25. package/dist/core/adoptionMcpConfig.js.map +1 -0
  26. package/dist/core/adoptionMcpDoctor.d.ts +23 -0
  27. package/dist/core/adoptionMcpDoctor.js +87 -0
  28. package/dist/core/adoptionMcpDoctor.js.map +1 -0
  29. package/dist/core/adoptionWorkflowRecipes.d.ts +14 -0
  30. package/dist/core/adoptionWorkflowRecipes.js +110 -0
  31. package/dist/core/adoptionWorkflowRecipes.js.map +1 -0
  32. package/dist/core/bugHunt.js +26 -255
  33. package/dist/core/bugHunt.js.map +1 -1
  34. package/dist/core/bugHuntPreflightFindings.d.ts +2 -1
  35. package/dist/core/bugHuntPreflightFindings.js +20 -0
  36. package/dist/core/bugHuntPreflightFindings.js.map +1 -1
  37. package/dist/core/bugHuntReportAssembly.d.ts +20 -0
  38. package/dist/core/bugHuntReportAssembly.js +179 -0
  39. package/dist/core/bugHuntReportAssembly.js.map +1 -0
  40. package/dist/core/bugHuntSourceFindings.d.ts +3 -0
  41. package/dist/core/bugHuntSourceFindings.js +61 -0
  42. package/dist/core/bugHuntSourceFindings.js.map +1 -0
  43. package/dist/core/dogfood.js +4 -393
  44. package/dist/core/dogfood.js.map +1 -1
  45. package/dist/core/dogfoodMarketValidation.d.ts +5 -0
  46. package/dist/core/dogfoodMarketValidation.js +265 -0
  47. package/dist/core/dogfoodMarketValidation.js.map +1 -0
  48. package/dist/core/dogfoodRepoEvaluation.d.ts +4 -0
  49. package/dist/core/dogfoodRepoEvaluation.js +137 -0
  50. package/dist/core/dogfoodRepoEvaluation.js.map +1 -0
  51. package/dist/core/evidenceComment.js +50 -13
  52. package/dist/core/evidenceComment.js.map +1 -1
  53. package/dist/core/feedback.js +2 -252
  54. package/dist/core/feedback.js.map +1 -1
  55. package/dist/core/feedbackIntakeClassifier.d.ts +2 -0
  56. package/dist/core/feedbackIntakeClassifier.js +255 -0
  57. package/dist/core/feedbackIntakeClassifier.js.map +1 -0
  58. package/dist/core/intentRouterKeywordToolGuards.js +1 -55
  59. package/dist/core/intentRouterKeywordToolGuards.js.map +1 -1
  60. package/dist/core/intentRouterKeywordWeights.js +13 -28
  61. package/dist/core/intentRouterKeywordWeights.js.map +1 -1
  62. package/dist/core/intentRouterProductGuardSignals.d.ts +3 -0
  63. package/dist/core/intentRouterProductGuardSignals.js +59 -0
  64. package/dist/core/intentRouterProductGuardSignals.js.map +1 -0
  65. package/dist/core/markdownSafety.d.ts +3 -0
  66. package/dist/core/markdownSafety.js +14 -0
  67. package/dist/core/markdownSafety.js.map +1 -0
  68. package/dist/core/preflight.d.ts +2 -0
  69. package/dist/core/preflight.js.map +1 -1
  70. package/dist/core/preflightChangedFiles.d.ts +2 -0
  71. package/dist/core/preflightChangedFiles.js +1 -1
  72. package/dist/core/preflightChangedFiles.js.map +1 -1
  73. package/dist/core/preflightInputs.d.ts +2 -0
  74. package/dist/core/preflightInputs.js +5 -2
  75. package/dist/core/preflightInputs.js.map +1 -1
  76. package/dist/core/proofLedger.d.ts +5 -1
  77. package/dist/core/proofLedger.js +161 -12
  78. package/dist/core/proofLedger.js.map +1 -1
  79. package/dist/core/proofReplay.d.ts +9 -0
  80. package/dist/core/proofReplay.js +164 -0
  81. package/dist/core/proofReplay.js.map +1 -0
  82. package/dist/core/proofSufficiency.d.ts +19 -0
  83. package/dist/core/proofSufficiency.js +425 -0
  84. package/dist/core/proofSufficiency.js.map +1 -0
  85. package/dist/core/prove.d.ts +6 -0
  86. package/dist/core/prove.js +277 -87
  87. package/dist/core/prove.js.map +1 -1
  88. package/dist/core/qualityScorecard.js +8 -238
  89. package/dist/core/qualityScorecard.js.map +1 -1
  90. package/dist/core/qualityScorecardDimensions.d.ts +14 -0
  91. package/dist/core/qualityScorecardDimensions.js +99 -0
  92. package/dist/core/qualityScorecardDimensions.js.map +1 -0
  93. package/dist/core/qualityScorecardRisks.d.ts +8 -0
  94. package/dist/core/qualityScorecardRisks.js +107 -0
  95. package/dist/core/qualityScorecardRisks.js.map +1 -0
  96. package/dist/core/qualityScorecardSignals.d.ts +20 -0
  97. package/dist/core/qualityScorecardSignals.js +59 -0
  98. package/dist/core/qualityScorecardSignals.js.map +1 -0
  99. package/dist/core/releaseEvidence.d.ts +1 -0
  100. package/dist/core/releaseEvidence.js +15 -40
  101. package/dist/core/releaseEvidence.js.map +1 -1
  102. package/dist/core/releaseEvidenceBaseline.js +4 -1
  103. package/dist/core/releaseEvidenceBaseline.js.map +1 -1
  104. package/dist/core/releaseEvidenceProofReceipt.d.ts +6 -0
  105. package/dist/core/releaseEvidenceProofReceipt.js +140 -0
  106. package/dist/core/releaseEvidenceProofReceipt.js.map +1 -0
  107. package/dist/core/releaseEvidenceVerdict.d.ts +5 -2
  108. package/dist/core/releaseEvidenceVerdict.js +39 -1
  109. package/dist/core/releaseEvidenceVerdict.js.map +1 -1
  110. package/dist/core/repositoryScanner.d.ts +1 -0
  111. package/dist/core/repositoryScanner.js +5 -4
  112. package/dist/core/repositoryScanner.js.map +1 -1
  113. package/dist/core/sessionResources.d.ts +14 -2
  114. package/dist/core/sessionResources.js +3 -3
  115. package/dist/core/sessionResources.js.map +1 -1
  116. package/dist/core/startInputs.d.ts +1 -1
  117. package/dist/core/startIntentTargets.d.ts +1 -1
  118. package/dist/core/startIntentTargets.js +1 -16
  119. package/dist/core/startIntentTargets.js.map +1 -1
  120. package/dist/core/startMissionInputStatusPolicy.d.ts +7 -0
  121. package/dist/core/startMissionInputStatusPolicy.js +74 -0
  122. package/dist/core/startMissionInputStatusPolicy.js.map +1 -0
  123. package/dist/core/startMissionPolicy.d.ts +6 -15
  124. package/dist/core/startMissionPolicy.js +4 -305
  125. package/dist/core/startMissionPolicy.js.map +1 -1
  126. package/dist/core/startMissionProofPolicy.d.ts +6 -0
  127. package/dist/core/startMissionProofPolicy.js +84 -0
  128. package/dist/core/startMissionProofPolicy.js.map +1 -0
  129. package/dist/core/startMissionRiskPolicy.d.ts +4 -0
  130. package/dist/core/startMissionRiskPolicy.js +85 -0
  131. package/dist/core/startMissionRiskPolicy.js.map +1 -0
  132. package/dist/core/startMissionRoutingPolicy.d.ts +6 -0
  133. package/dist/core/startMissionRoutingPolicy.js +67 -0
  134. package/dist/core/startMissionRoutingPolicy.js.map +1 -0
  135. package/dist/core/startMode.d.ts +1 -2
  136. package/dist/core/startMode.js +4 -151
  137. package/dist/core/startMode.js.map +1 -1
  138. package/dist/core/startModeIntentPolicy.d.ts +12 -0
  139. package/dist/core/startModeIntentPolicy.js +41 -0
  140. package/dist/core/startModeIntentPolicy.js.map +1 -0
  141. package/dist/core/startModeRoutingPolicy.d.ts +4 -0
  142. package/dist/core/startModeRoutingPolicy.js +117 -0
  143. package/dist/core/startModeRoutingPolicy.js.map +1 -0
  144. package/dist/core/startSearchQueryTargets.d.ts +1 -0
  145. package/dist/core/startSearchQueryTargets.js +17 -0
  146. package/dist/core/startSearchQueryTargets.js.map +1 -0
  147. package/dist/core/workplan.d.ts +3 -2
  148. package/dist/core/workplan.js +11 -585
  149. package/dist/core/workplan.js.map +1 -1
  150. package/dist/core/workplanCoordinationTasks.d.ts +3 -0
  151. package/dist/core/workplanCoordinationTasks.js +82 -0
  152. package/dist/core/workplanCoordinationTasks.js.map +1 -0
  153. package/dist/core/workplanModeTasks.d.ts +2 -0
  154. package/dist/core/workplanModeTasks.js +192 -0
  155. package/dist/core/workplanModeTasks.js.map +1 -0
  156. package/dist/core/workplanPreflightTasks.d.ts +2 -0
  157. package/dist/core/workplanPreflightTasks.js +126 -0
  158. package/dist/core/workplanPreflightTasks.js.map +1 -0
  159. package/dist/core/workplanQualitySignals.d.ts +7 -0
  160. package/dist/core/workplanQualitySignals.js +63 -0
  161. package/dist/core/workplanQualitySignals.js.map +1 -0
  162. package/dist/core/workplanReport.d.ts +4 -0
  163. package/dist/core/workplanReport.js +79 -0
  164. package/dist/core/workplanReport.js.map +1 -0
  165. package/dist/core/workplanRiskOwnership.d.ts +5 -0
  166. package/dist/core/workplanRiskOwnership.js +97 -0
  167. package/dist/core/workplanRiskOwnership.js.map +1 -0
  168. package/dist/core/workplanSuggestedActions.d.ts +2 -0
  169. package/dist/core/workplanSuggestedActions.js +43 -0
  170. package/dist/core/workplanSuggestedActions.js.map +1 -0
  171. package/dist/mcp/tools/prove.js +23 -17
  172. package/dist/mcp/tools/prove.js.map +1 -1
  173. package/dist/projscan-sbom.cdx.json +6 -6
  174. package/dist/tool-manifest.json +2 -2
  175. package/dist/types/config.d.ts +15 -0
  176. package/dist/types/evidencePack.d.ts +21 -0
  177. package/dist/types/prove.d.ts +79 -0
  178. package/dist/utils/changedFiles.js +57 -16
  179. package/dist/utils/changedFiles.js.map +1 -1
  180. package/dist/utils/config.js +2 -0
  181. package/dist/utils/config.js.map +1 -1
  182. package/dist/utils/configProofRecipes.d.ts +2 -0
  183. package/dist/utils/configProofRecipes.js +91 -0
  184. package/dist/utils/configProofRecipes.js.map +1 -0
  185. package/docs/GUIDE.md +120 -19
  186. package/package.json +1 -1
package/README.md CHANGED
@@ -101,19 +101,25 @@ Success criteria: the agent can name the files to read first, the likely files t
101
101
  ```bash
102
102
  projscan start --intent "is my agent allowed to change billing retry logic?"
103
103
  projscan prove --intent "is my agent allowed to change billing retry logic?" --save-contract .projscan/proof-contract.json
104
+ # Make the bounded edit, then run the proof command.
104
105
  projscan prove --run -- npm test -- tests/billing/retry.test.ts
105
106
  projscan prove --changed --contract .projscan/proof-contract.json --format markdown
106
107
  ```
107
108
 
108
- The path is `start -> prove -> run -> changed`. `start` chooses the contract workflow. `prove --intent` writes the contract only when `--save-contract` is present. `prove --run -- <command...>` executes a local proof command, records the exit code, captures a redacted log, and fingerprints the current changed files. `prove --record-command` remains available for imported CI or external evidence when projscan did not run the command. `prove --changed` checks the current working tree against the contract and local ledger.
109
+ The command path is `start -> prove -> run -> changed`. Make the bounded edit after the contract exists and before `prove --run`. `start` chooses the contract workflow. `prove --intent` writes `.projscan/proof-contract.json` only when `--save-contract` is present. `prove --run -- <command...>` executes a local proof command, records the exit code, captures a redacted log, and fingerprints the current changed files. `prove --record-command` remains available for imported CI or external evidence when projscan did not run the command. `prove --changed` checks the current working tree against the contract and local ledger.
109
110
 
110
- You get a Proof Contract before edits and a Proof Receipt after edits. The contract names allowed files, forbidden files, risky contracts, likely tests, missing regression-test evidence, proof commands, safe change shape, rollback, confidence, and reviewer guidance. The receipt checks the real working tree against that contract and classifies changed files as allowed production, expected tests, documentation, generated proof artifacts, config/security drift, forbidden touches, or unexpected production. It also reports proof replay status, risk delta, commit readiness, and a reviewer checklist.
111
+ You get a Proof Contract before edits and a Proof Receipt after edits. The contract names allowed files, forbidden files, risky contracts, likely tests, missing regression-test evidence, proof commands, safe change shape, rollback, confidence, reviewer guidance, and `proofRequirements` for each risk surface. The receipt checks the real working tree against that contract and classifies changed files as allowed production, expected tests, documentation, generated proof artifacts, config/security drift, forbidden touches, or unexpected production. The receipt reports proof replay status, Proof Sufficiency, risk delta, commit readiness, and a reviewer checklist.
111
112
 
112
- Proof Replay records command, exit code, duration, changed-file fingerprint, redacted summary, log path, and source in `.projscan/proof-ledger.jsonl`. Executed proof logs stay under `.projscan/proof-logs/`. `prove --changed` marks proof as passed, missing, failed, partial, or stale. If the agent edits new files after proof ran, the receipt says the proof is stale before a reviewer reads the diff.
113
+ Proof Replay records command, exit code, duration, changed-file fingerprint, redacted summary, log path, and source in `.projscan/proof-ledger.jsonl`. Executed proof logs stay under `.projscan/proof-logs/`. `prove --changed` marks proof as passed, missing, failed, partial, or stale. The receipt JSON includes `proofReplay` with a replay timeline, `changedAfterProof`, replay command, and local receipt fingerprint. If the agent edits new files after proof ran, the receipt says the proof is stale before a reviewer reads the diff.
113
114
 
114
- Every `prove` report includes `verifiedWorkflow`, a compact JSON summary for agents and MCP clients. It names the phase, next action, next command, scope status, proof status, risk delta direction, reviewer decision, and stale/missing/failed proof flags.
115
+ Proof Sufficiency estimates whether the local ledger covers each changed surface. `proofSufficiency` marks rows as strong, adequate, weak, missing, stale, or failed, then lists the exact gaps reviewers need to resolve.
115
116
 
116
- Success criteria: the reviewer sees whether the agent stayed inside the contract, whether the right proof ran, and whether that proof is still fresh.
117
+ Team Proof Recipes let a repo encode required proof for sensitive paths in `proofRecipes`; when a matching recipe is configured, `prove --intent` adds that recipe's commands, reviewers, and forbidden files to the Proof Contract. `prove --changed` and `projscan evidence-pack --pr-comment` then show missing recipe proof, required reviewers, and recipe drift in the Proof Receipt. The recipe does not run proof commands by itself; use `prove --run -- <command...>` or `prove --record-command` to add evidence to the local ledger.
118
+ Saved contracts are the source of truth for `prove --changed`; update the contract when a team recipe changes.
119
+
120
+ Every `prove` report includes `verifiedWorkflow`, a compact JSON summary for agents and MCP clients. It names the phase, next action, next command, scope status, proof status, proof sufficiency status, risk delta direction, reviewer decision, and stale/missing/failed proof flags.
121
+
122
+ Success criteria: the reviewer sees scope, proof execution, proof freshness, and sufficiency for the changed risk surface.
117
123
 
118
124
  ### Before handoff or commit
119
125
 
@@ -124,7 +130,7 @@ projscan preflight --mode before_commit --format json
124
130
  projscan evidence-pack --pr-comment
125
131
  ```
126
132
 
127
- You get the changed-file risk, one or two trusted next actions, manual review gates, owner routing, baseline trend memory, and exact proof commands for the reviewer. Use `projscan bug-hunt --format json` when you want the raw fix queue behind the assessment.
133
+ You get changed-file risk, one or two ranked next actions, manual review gates, owner routing, baseline trend memory, and exact proof commands for the reviewer. Use `projscan bug-hunt --format json` when you want the raw fix queue behind the assessment.
128
134
 
129
135
  Success criteria: the reviewer sees the top fix, the remaining proof, and any manual sign-off gate without reading the full scan output.
130
136
 
@@ -197,15 +203,15 @@ npm run docs:screenshots
197
203
  npm run docs:demos
198
204
  ```
199
205
 
200
- ## 4.14.0 Notes
206
+ ## 4.15.0 Notes
201
207
 
202
- 4.14.0 ships the Verified Change Workflow and Executed Proof Runner:
208
+ 4.15.0 strengthens the proof-first change loop:
203
209
 
204
210
  - `projscan prove --intent "<change>"` creates a local Proof Contract before
205
211
  editing. It names allowed files, forbidden files, risky contracts, likely
206
212
  tests, missing regression-test evidence, proof commands, rollback, confidence,
207
- Trust Memory signals, evidence gaps, and reviewer guidance. Noisy feedback or
208
- missing-signal feedback lowers the confidence reason instead of hiding it.
213
+ Trust Memory signals, evidence gaps, reviewer guidance, and
214
+ `proofRequirements` for each risk surface.
209
215
  - `projscan start --intent "is my agent allowed to change billing retry logic?"`
210
216
  routes directly to `projscan prove`, so agent-permission prompts start with a
211
217
  bounded contract instead of a broad checklist.
@@ -218,22 +224,51 @@ npm run docs:demos
218
224
  classes separate allowed production edits, expected tests, documentation,
219
225
  generated proof artifacts, config/security drift, forbidden touches, and
220
226
  unexpected production changes before giving a copyable reviewer decision.
227
+ The receipt also includes `proofReplay` with replay status, timeline events,
228
+ `changedAfterProof`, replay command, and receipt fingerprint. Proof
229
+ Sufficiency shows whether each `proofRequirements` row has strong, adequate,
230
+ weak, missing, stale, or failed proof.
231
+ - Team Proof Recipes let a repo add path-matched `proofRecipes` to
232
+ `.projscanrc.json`. Matching recipes add required commands, reviewers, and
233
+ forbidden drift to the Proof Contract and Proof Receipt.
221
234
  - `projscan prove --record-command "<command>" --exit-code <code>` appends a
222
235
  local Proof Ledger row with command, duration, changed-file fingerprint,
223
236
  redacted output summary, and optional log path when importing proof from CI or
224
- another trusted runner.
237
+ another runner.
225
238
  - Every `prove` JSON report includes `verifiedWorkflow`, so agents can read the
226
- next action, next command, scope status, proof status, reviewer decision, and
227
- stale/missing/failed proof flags without parsing Markdown.
239
+ next action, next command, scope status, proof status, `proofSufficiency`
240
+ status, reviewer decision, and stale/missing/failed proof flags without
241
+ parsing Markdown.
228
242
  - Saved Mission Control bundles append Proof Ledger rows while `mission.sh`
229
243
  runs the existing proof queue. The script still writes proof logs and status
230
244
  JSONL for humans.
231
245
  - `projscan evidence-pack --pr-comment` includes the latest Proof Receipt
232
246
  summary when a contract and ledger are available, so PR comments show proof
233
- status, reviewer decision, scope, stale proof, failed proof, and the replay
234
- command.
247
+ status, proof replay, reviewer decision, scope, stale proof, failed proof,
248
+ proof sufficiency, recipe gaps, required reviewers, changed-after-proof files,
249
+ receipt fingerprint, and the replay command.
250
+ - Proof artifacts are harder to spoof: Proof Contract and Proof Ledger reads
251
+ reject symlink escapes, proof logs redact more standalone token/key shapes,
252
+ and generated mission scripts reject shell control syntax before running.
253
+ - The codebase behind the proof workflow is smaller and easier to review:
254
+ source hotspots in Mission Control, bug-hunt, quality-scorecard, workplan,
255
+ adoption, start-mode routing, and intent routing were split into focused
256
+ helpers with architecture tests.
235
257
  - MCP now includes `projscan_prove`, bringing the MCP surface to 48 tools.
236
258
 
259
+ ## 4.14.0 Notes
260
+
261
+ 4.14.0 ships the Verified Change Workflow and Executed Proof Runner:
262
+
263
+ - `projscan prove --intent "<change>"` creates a local Proof Contract before
264
+ editing.
265
+ - `projscan prove --run -- <command...>` executes an explicit local proof
266
+ command with shell execution disabled and writes a redacted Proof Ledger row.
267
+ - `projscan prove --changed` emits a Proof Receipt for PRs, agents, and CI.
268
+ - `projscan evidence-pack --pr-comment` includes the latest Proof Receipt
269
+ summary when a contract and ledger are available.
270
+ - MCP includes `projscan_prove`, bringing the MCP surface to 48 tools.
271
+
237
272
  ## 4.12.1 Notes
238
273
 
239
274
  4.12.1 is the simulator precision patch for the Proof Cards V2 release:
@@ -264,7 +299,7 @@ npm run docs:demos
264
299
 
265
300
  - Added a dedicated Proof Cards screenshot for `projscan assess` and
266
301
  `projscan simulate`.
267
- - Regenerated README screenshots so public media shows the current 47-tool MCP
302
+ - Regenerated README screenshots so public media showed the 47-tool MCP
268
303
  surface.
269
304
  - Updated website handoff guidance to use immutable `v4.11.1` media URLs.
270
305
 
@@ -333,7 +368,7 @@ npx -y projscan mcp --watch
333
368
  | `projscan assess` | proof-first assessment with Proof Cards, risk delta, and fix-first guidance |
334
369
  | `projscan simulate` | risk delta simulator for a proposed change plan before editing |
335
370
  | `projscan prove` | executable Proof Contracts, Verified Workflow JSON, and Proof Receipts |
336
- | `projscan evidence-pack` | PR-ready proof with risks, owners, and next commands |
371
+ | `projscan evidence-pack` | review evidence with risks, owners, proof receipts, and next commands |
337
372
  | `projscan bug-hunt` | ranked fix queue from health, hotspots, session, and preflight evidence |
338
373
  | `projscan workplan` | ordered agent tasks with proof and handoff text |
339
374
  | `projscan doctor` | project health, tooling gaps, dead code, and supply-chain signals |
@@ -400,6 +435,15 @@ Create a `.projscanrc.json` when repo defaults should live in source control:
400
435
  "severityOverrides": {
401
436
  "missing-prettier": "info"
402
437
  },
438
+ "proofRecipes": [
439
+ {
440
+ "id": "billing-critical",
441
+ "matches": ["src/billing/**"],
442
+ "requiredCommands": ["npm test -- tests/billing/retry.test.ts"],
443
+ "requiredReviewers": ["@platform"],
444
+ "forbiddenFiles": ["src/auth/**"]
445
+ }
446
+ ],
403
447
  "reportPolicies": {
404
448
  "apiEvidence": {
405
449
  "reportScope": ["src/api", "packages/backend"],
@@ -416,6 +460,12 @@ the rule everywhere. For one line, add an inline directive next to the value:
416
460
  const firebaseKey = 'AIza...'; // projscan-ignore-line hardcoded-secret -- Firebase web keys are public identifiers
417
461
  ```
418
462
 
463
+ Use `proofRecipes` when a path needs team-specific proof; when a matching recipe
464
+ is configured, `projscan prove` adds its proof commands, reviewers, and forbidden
465
+ files to the contract and receipt. It does not run proof commands by itself.
466
+ Recipes without `requiredCommands` are skipped, and duplicate recipe IDs keep the
467
+ first valid recipe.
468
+
419
469
  Config docs live in [docs/GUIDE.md](docs/GUIDE.md#configuration-projscanrc).
420
470
 
421
471
  ## CI
@@ -491,7 +541,7 @@ Plugin docs:
491
541
 
492
542
  ## Supported Repos
493
543
 
494
- projscan reads TypeScript, JavaScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, Swift, C, and C++ with AST-aware adapters where available. It also detects file-level signals for Shell, CSS, HTML, SQL, Dart, Lua, Scala, R, and related project files.
544
+ projscan reads TypeScript, JavaScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, Swift, and C++ with AST-aware adapters where available. It also detects file-level signals for C, Shell, CSS, HTML, SQL, Dart, Lua, Scala, R, and related project files.
495
545
 
496
546
  Framework signals cover React, Next.js, Vue, Nuxt, Svelte, Angular, Express, Fastify, NestJS, Vite, Tailwind CSS, Prisma, Remix, SvelteKit, Astro, Hono, Koa, and common monorepo layouts.
497
547
 
@@ -507,7 +557,7 @@ JavaScript and TypeScript use `@babel/parser`. Non-JS languages use packaged tre
507
557
  | Network | `audit`, registry checks, opt-in telemetry, and optional semantic model download can contact the network. |
508
558
  | Telemetry | Off until you run `projscan telemetry enable` or accept the `init team` prompt. |
509
559
  | Plugins | Local plugin code runs after `PROJSCAN_PLUGINS_PREVIEW=1` and an execution path such as `doctor`, `ci`, `analyze`, or `plugin test --execute`. |
510
- | Repo writes | Source writes require explicit fix commands. Cache and mission proof files stay under local projscan directories. |
560
+ | Repo writes | Source writes require explicit fix commands. Caches, saved missions, Proof Contracts, Proof Ledger rows, and proof logs stay under `.projscan*` local directories. |
511
561
 
512
562
  Audit helpers:
513
563
 
@@ -522,7 +572,7 @@ Supply-chain scanners may flag package strings or APIs used by `git`, `npm audit
522
572
 
523
573
  ## Install Notes
524
574
 
525
- `projscan@4.14.0` has seven direct runtime dependencies:
575
+ `projscan@4.15.0` has seven direct runtime dependencies:
526
576
 
527
577
  - `@babel/parser`
528
578
  - `@babel/types`
@@ -532,7 +582,7 @@ Supply-chain scanners may flag package strings or APIs used by `git`, `npm audit
532
582
  - `ora`
533
583
  - `web-tree-sitter`
534
584
 
535
- If npm prints `allow-scripts` warnings during a global install, check which package names it lists. projscan core does not need `node-gyp` grammar builds at runtime in 4.14.0. Open an issue with the warning text if npm reports install scripts from `projscan@latest`, or run `projscan feedback intake --text "<warning text>" --format json` to turn it into a focused setup-trust task.
585
+ If npm prints `allow-scripts` warnings during a global install, check which package names it lists. projscan core does not need `node-gyp` grammar builds at runtime in 4.15.0. Open an issue with the warning text if npm reports install scripts from `projscan@latest`, or run `projscan feedback intake --text "<warning text>" --format json` to turn it into a focused setup-trust task.
536
586
 
537
587
  The grammar packages are build-time sources, not global-install dependencies. Published grammar assets include `tree-sitter-python.wasm` and `tree-sitter-c_sharp.wasm`.
538
588
 
@@ -8,6 +8,7 @@ export function registerEvidencePack() {
8
8
  .option('--line <line>', 'product line to include, repeatable (default: next six minor lines)', collectLine, [])
9
9
  .option('--website-prompt', 'include website-update prompt text')
10
10
  .option('--pr-comment', 'print a GitHub PR comment markdown artifact')
11
+ .option('--base-ref <ref>', 'explicit git base ref for review evidence')
11
12
  .option('--max-findings <count>', 'maximum bug-hunt findings to include', parsePositiveInt)
12
13
  .action(async (cmdOpts) => {
13
14
  setupLogLevel();
@@ -18,6 +19,7 @@ export function registerEvidencePack() {
18
19
  lines: cmdOpts.line,
19
20
  includeWebsitePrompt: cmdOpts.websitePrompt === true,
20
21
  includePrComment: cmdOpts.prComment === true,
22
+ baseRef: cmdOpts.baseRef,
21
23
  maxFindings: cmdOpts.maxFindings,
22
24
  });
23
25
  if (format === 'json') {
@@ -1 +1 @@
1
- {"version":3,"file":"evidencePack.js","sourceRoot":"","sources":["../../../src/cli/commands/evidencePack.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evidencePack.js","sourceRoot":"","sources":["../../../src/cli/commands/evidencePack.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
- import { assertFormatSupported, getRootPath, maybeCompactBanner, program, setupLogLevel, } from '../_shared.js';
2
+ import { assertFormatSupported, getRootPath, maybeCompactBanner, program, loadProjectConfig, setupLogLevel, } from '../_shared.js';
3
3
  import { computeProve } from '../../core/prove.js';
4
+ import { escapeMarkdownText, markdownInlineCode, markdownInlineList, } from '../../core/markdownSafety.js';
4
5
  export function registerProve() {
5
6
  program
6
7
  .command('prove')
@@ -17,6 +18,7 @@ export function registerProve() {
17
18
  .option('--duration-ms <ms>', 'duration in milliseconds for --record-command', parseDurationMs)
18
19
  .option('--summary <text>', 'safe proof output summary for --record-command')
19
20
  .option('--log <path>', 'redacted proof log path for --record-command')
21
+ .option('--record-source <source>', 'source for --record-command evidence', parseProofLedgerSource)
20
22
  .option('--run', 'execute a local proof command supplied after -- and record the outcome')
21
23
  .option('--run-timeout-ms <ms>', 'timeout in milliseconds for --run commands', parseDurationMs)
22
24
  .option('--ledger <path>', 'proof ledger JSONL path')
@@ -40,6 +42,10 @@ export function registerProve() {
40
42
  if (cmdOpts.run && runArgs.length === 0) {
41
43
  throw new Error('prove --run requires a command after --, for example: projscan prove --run -- npm test');
42
44
  }
45
+ if (cmdOpts.recordSource && !cmdOpts.recordCommand) {
46
+ throw new Error('prove --record-source requires --record-command');
47
+ }
48
+ const config = await loadProjectConfig();
43
49
  const report = await computeProve(getRootPath(), {
44
50
  intent: cmdOpts.intent,
45
51
  changed: Boolean(cmdOpts.changed),
@@ -54,8 +60,10 @@ export function registerProve() {
54
60
  durationMs: cmdOpts.durationMs,
55
61
  summary: cmdOpts.summary,
56
62
  logPath: cmdOpts.log,
63
+ recordSource: cmdOpts.recordSource,
57
64
  runCommand: cmdOpts.run ? runArgs : undefined,
58
65
  runTimeoutMs: cmdOpts.runTimeoutMs,
66
+ proofRecipes: cmdOpts.changed ? undefined : config.proofRecipes,
59
67
  });
60
68
  if (format === 'json') {
61
69
  console.log(JSON.stringify(report, null, 2));
@@ -116,6 +124,8 @@ function printContractConsole(contract) {
116
124
  printList(contract.proofCommands.slice(0, 8), 'No proof commands inferred');
117
125
  }
118
126
  function printReceiptConsole(receipt) {
127
+ const proofReplay = proofReplayForReceipt(receipt);
128
+ const proofSufficiency = proofSufficiencyForReceipt(receipt);
119
129
  console.log(chalk.bold('Scope Decision'));
120
130
  console.log(`- ${receipt.scope.status}`);
121
131
  console.log('');
@@ -135,10 +145,28 @@ function printReceiptConsole(receipt) {
135
145
  console.log('');
136
146
  console.log(chalk.bold('Proof Commands'));
137
147
  printList(receipt.proofStatus.commandsRequired.slice(0, 8), 'No proof commands required');
148
+ if (receipt.teamProofRecipes?.length) {
149
+ console.log('');
150
+ console.log(chalk.bold('Team Proof Recipes'));
151
+ for (const recipe of receipt.teamProofRecipes) {
152
+ const reviewers = recipe.requiredReviewers?.length ? recipe.requiredReviewers.join(', ') : 'none';
153
+ const drift = recipe.forbiddenTouched?.length ? recipe.forbiddenTouched.join(', ') : 'none';
154
+ console.log(`- ${recipe.id}: reviewers ${reviewers}; recipe drift ${drift}`);
155
+ }
156
+ }
138
157
  console.log('');
139
158
  console.log(chalk.bold('Proof Replay'));
140
- console.log(`- status: ${receipt.proofStatus.status}`);
159
+ console.log(`- replay status: ${proofReplay.status}`);
160
+ console.log(`- proof status: ${receipt.proofStatus.status}`);
141
161
  console.log(`- reviewer decision: ${receipt.reviewerDecision}`);
162
+ console.log(`- changed after proof: ${inlineList(proofReplay.changedAfterProof)}`);
163
+ console.log(`- receipt fingerprint: ${proofReplay.receiptFingerprint}`);
164
+ console.log('');
165
+ console.log(chalk.bold('Proof Sufficiency'));
166
+ console.log(`- status: ${proofSufficiency.status}`);
167
+ for (const gap of proofSufficiency.gaps.slice(0, 3)) {
168
+ console.log(`- gap: ${gap}`);
169
+ }
142
170
  }
143
171
  export function renderProveMarkdown(report) {
144
172
  if (report.receipt)
@@ -153,24 +181,24 @@ function renderLedgerRecordMarkdown(report) {
153
181
  record?.source === 'prove-run' ? '# Projscan Executed Proof' : '# Projscan Recorded Proof',
154
182
  '',
155
183
  `- **Verdict:** ${report.verdict}`,
156
- `- **Summary:** ${report.summary}`,
184
+ `- **Summary:** ${escapeMarkdownText(report.summary)}`,
157
185
  ];
158
186
  if (!record)
159
187
  return lines.join('\n');
160
188
  lines.push(`- **Source:** ${record.source}`);
161
189
  lines.push(`- **Status:** ${record.status}`);
162
- lines.push(`- **Command:** \`${record.command}\``);
190
+ lines.push(`- **Command:** ${markdownInlineCode(record.command)}`);
163
191
  lines.push(`- **Exit code:** ${record.exitCode}`);
164
192
  lines.push(`- **Duration:** ${record.durationMs}ms`);
165
193
  lines.push(`- **Completed:** ${record.completedAt}`);
166
194
  lines.push(`- **Changed-file fingerprint:** ${record.changedFileFingerprint}`);
167
195
  if (record.logPath)
168
- lines.push(`- **Log:** \`${record.logPath}\``);
196
+ lines.push(`- **Log:** ${markdownInlineCode(record.logPath)}`);
169
197
  lines.push('');
170
198
  pushVerifiedWorkflow(lines, report.verifiedWorkflow);
171
199
  lines.push('');
172
200
  lines.push('## Output Summary');
173
- lines.push(record.outputSummary);
201
+ lines.push(escapeMarkdownText(record.outputSummary));
174
202
  lines.push('');
175
203
  lines.push('## Changed Files');
176
204
  pushList(lines, record.changedFiles, 'No changed files were fingerprinted.');
@@ -183,10 +211,10 @@ function renderContractMarkdown(report) {
183
211
  const contract = report.contract;
184
212
  const lines = ['# Projscan Proof Contract', ''];
185
213
  lines.push(`- **Verdict:** ${report.verdict}`);
186
- lines.push(`- **Summary:** ${report.summary}`);
214
+ lines.push(`- **Summary:** ${escapeMarkdownText(report.summary)}`);
187
215
  if (!contract)
188
216
  return lines.join('\n');
189
- lines.push(`- **Intent:** ${contract.intent}`);
217
+ lines.push(`- **Intent:** ${escapeMarkdownText(contract.intent)}`);
190
218
  lines.push(`- **Confidence:** ${contract.confidence}`);
191
219
  lines.push(`- **Evidence strength:** ${contract.evidenceStrength.level} (${contract.evidenceStrength.score})`);
192
220
  lines.push('');
@@ -208,13 +236,15 @@ function renderContractMarkdown(report) {
208
236
  pushCodeList(lines, contract.proofCommands);
209
237
  lines.push('');
210
238
  lines.push('## Reviewer Guidance');
211
- lines.push(contract.reviewerGuidance);
239
+ lines.push(escapeMarkdownText(contract.reviewerGuidance));
212
240
  return lines.join('\n');
213
241
  }
214
242
  function renderReceiptMarkdown(report, receipt) {
243
+ const proofReplay = proofReplayForReceipt(receipt);
244
+ const proofSufficiency = proofSufficiencyForReceipt(receipt);
215
245
  const lines = ['# Projscan Proof Receipt', ''];
216
246
  lines.push(`- **Verdict:** ${report.verdict}`);
217
- lines.push(`- **Summary:** ${receipt.summary}`);
247
+ lines.push(`- **Summary:** ${escapeMarkdownText(receipt.summary)}`);
218
248
  lines.push(`- **Commit readiness:** ${receipt.commitReadiness}`);
219
249
  lines.push(`- **Scope:** ${receipt.scope.status}`);
220
250
  lines.push(`- **Proof status:** ${receipt.proofStatus.status}`);
@@ -258,12 +288,34 @@ function renderReceiptMarkdown(report, receipt) {
258
288
  lines.push('## Proof Commands');
259
289
  pushCodeList(lines, receipt.proofStatus.commandsRequired);
260
290
  lines.push('');
291
+ lines.push('## Team Proof Recipes');
292
+ pushTeamProofRecipes(lines, receipt);
293
+ lines.push('');
261
294
  lines.push('## Proof Replay');
262
- lines.push(`- **Proof status:** ${receipt.proofStatus.status}`);
295
+ lines.push(`- **replay status:** ${proofReplay.status}`);
296
+ lines.push(`- **summary:** ${escapeMarkdownText(proofReplay.summary)}`);
297
+ lines.push(`- **proof status:** ${receipt.proofStatus.status}`);
263
298
  lines.push(`- **Reviewer decision:** ${receipt.reviewerDecision}`);
264
- lines.push(`- **Risk delta:** ${receipt.riskDeltaDirection} (${receipt.riskDelta.delta})`);
265
- lines.push(`- **Commands required:** ${receipt.proofStatus.commandsRequired.length}`);
266
- lines.push(`- **Commands recorded:** ${receipt.proofStatus.commandsRun.length}`);
299
+ lines.push(`- **risk delta:** ${receipt.riskDeltaDirection} (${receipt.riskDelta.delta})`);
300
+ lines.push(`- **commands required:** ${receipt.proofStatus.commandsRequired.length}`);
301
+ lines.push(`- **commands recorded:** ${receipt.proofStatus.commandsRun.length}`);
302
+ lines.push(`- **changed after proof:** ${markdownInlineList(proofReplay.changedAfterProof)}`);
303
+ lines.push(`- **replay command:** ${markdownInlineCode(proofReplay.replayCommand)}`);
304
+ lines.push(`- **receipt fingerprint:** ${markdownInlineCode(proofReplay.receiptFingerprint)}`);
305
+ lines.push('');
306
+ lines.push('### Replay Timeline');
307
+ pushReplayEvents(lines, proofReplay.events);
308
+ lines.push('');
309
+ lines.push('## Proof Sufficiency');
310
+ lines.push(`- **sufficiency status:** ${proofSufficiency.status}`);
311
+ lines.push(`- **summary:** ${escapeMarkdownText(proofSufficiency.summary)}`);
312
+ lines.push(`- **weak requirements:** ${proofSufficiency.weakRequirements.length}`);
313
+ lines.push(`- **missing requirements:** ${proofSufficiency.missingRequirements.length}`);
314
+ lines.push(`- **stale requirements:** ${proofSufficiency.staleRequirements.length}`);
315
+ lines.push(`- **failed requirements:** ${proofSufficiency.failedRequirements.length}`);
316
+ lines.push('');
317
+ lines.push('### Requirement Evidence');
318
+ pushRequirementEvidence(lines, proofSufficiency.requirements);
267
319
  lines.push('');
268
320
  lines.push('### Command Evidence');
269
321
  pushCommandEvidence(lines, receipt.proofStatus.commandEvidence);
@@ -281,7 +333,7 @@ function renderReceiptMarkdown(report, receipt) {
281
333
  pushList(lines, receipt.evidenceGaps, 'No evidence gaps reported.');
282
334
  lines.push('');
283
335
  lines.push('## Reviewer Guidance');
284
- lines.push(receipt.reviewerGuidance);
336
+ lines.push(escapeMarkdownText(receipt.reviewerGuidance));
285
337
  lines.push('');
286
338
  lines.push('## Reviewer Checklist');
287
339
  lines.push('- [ ] Confirm unexpected production/config/security files are intentional or removed.');
@@ -297,12 +349,15 @@ function pushVerifiedWorkflow(lines, workflow) {
297
349
  lines.push('## Verified Workflow');
298
350
  lines.push(`- **phase:** ${workflow.phase}`);
299
351
  lines.push(`- **status:** ${workflow.status}`);
300
- lines.push(`- **next action:** ${workflow.nextAction}`);
301
- lines.push(`- **next command:** \`${workflow.nextCommand}\``);
352
+ lines.push(`- **next action:** ${escapeMarkdownText(workflow.nextAction)}`);
353
+ lines.push(`- **next command:** ${markdownInlineCode(workflow.nextCommand)}`);
302
354
  if (workflow.scopeStatus)
303
355
  lines.push(`- **scope:** ${workflow.scopeStatus}`);
304
356
  if (workflow.proofStatus)
305
357
  lines.push(`- **proof:** ${workflow.proofStatus}`);
358
+ if (workflow.proofSufficiencyStatus) {
359
+ lines.push(`- **proof sufficiency:** ${workflow.proofSufficiencyStatus}`);
360
+ }
306
361
  if (workflow.reviewerDecision)
307
362
  lines.push(`- **reviewer decision:** ${workflow.reviewerDecision}`);
308
363
  if (workflow.riskDeltaDirection)
@@ -325,7 +380,7 @@ function pushList(lines, values, empty) {
325
380
  return;
326
381
  }
327
382
  for (const value of values)
328
- lines.push(`- ${value}`);
383
+ lines.push(`- ${escapeMarkdownText(value)}`);
329
384
  }
330
385
  function pushCodeList(lines, values) {
331
386
  if (values.length === 0) {
@@ -333,7 +388,37 @@ function pushCodeList(lines, values) {
333
388
  return;
334
389
  }
335
390
  for (const value of values)
336
- lines.push(`- \`${value}\``);
391
+ lines.push(`- ${markdownInlineCode(value)}`);
392
+ }
393
+ function pushTeamProofRecipes(lines, receipt) {
394
+ const recipes = receipt.teamProofRecipes ?? [];
395
+ if (recipes.length === 0) {
396
+ lines.push('- No Team Proof Recipes matched this receipt.');
397
+ return;
398
+ }
399
+ for (const recipe of recipes) {
400
+ lines.push(`- **recipe:** ${markdownInlineCode(recipe.id)}`);
401
+ lines.push(` - matched files: ${markdownInlineList(recipe.matchedFiles)}`);
402
+ lines.push(` - required reviewers: ${markdownInlineList(recipe.requiredReviewers ?? [])}`);
403
+ lines.push(` - recipe drift: ${markdownInlineList(recipe.forbiddenTouched ?? [])}`);
404
+ lines.push(` - recipe proof gaps: ${markdownInlineList(recipeGapsForRecipe(recipe))}`);
405
+ }
406
+ if (receipt.requiredReviewers?.length) {
407
+ lines.push(`- **required reviewers:** ${markdownInlineList(receipt.requiredReviewers)}`);
408
+ }
409
+ if (receipt.recipeDrift?.length) {
410
+ lines.push(`- **recipe drift:** ${markdownInlineList(receipt.recipeDrift)}`);
411
+ }
412
+ if (receipt.recipeGaps?.length) {
413
+ lines.push(`- **recipe gaps:** ${markdownInlineList(receipt.recipeGaps)}`);
414
+ }
415
+ }
416
+ function recipeGapsForRecipe(recipe) {
417
+ return [
418
+ ...(recipe.missingCommands ?? []).map((command) => `missing: ${command}`),
419
+ ...(recipe.failedCommands ?? []).map((command) => `failed: ${command}`),
420
+ ...(recipe.staleCommands ?? []).map((command) => `stale: ${command}`),
421
+ ];
337
422
  }
338
423
  function pushCommandEvidence(lines, values) {
339
424
  if (values.length === 0) {
@@ -343,14 +428,72 @@ function pushCommandEvidence(lines, values) {
343
428
  for (const value of values)
344
429
  lines.push(formatCommandEvidence(value));
345
430
  }
431
+ function pushRequirementEvidence(lines, values) {
432
+ if (values.length === 0) {
433
+ lines.push('- No proof requirements were evaluated.');
434
+ return;
435
+ }
436
+ for (const value of values)
437
+ lines.push(formatRequirementEvidence(value));
438
+ }
439
+ function pushReplayEvents(lines, values) {
440
+ if (values.length === 0) {
441
+ lines.push('- No proof replay events recorded.');
442
+ return;
443
+ }
444
+ for (const value of values)
445
+ lines.push(formatReplayEvent(value));
446
+ }
447
+ function formatReplayEvent(value) {
448
+ const command = value.command ? ` ${markdownInlineCode(value.command)}` : '';
449
+ const source = value.source ? ` source: ${value.source}.` : '';
450
+ const changedAfter = value.changedAfterProof && value.changedAfterProof.length > 0
451
+ ? ` changed after proof: ${markdownInlineList(value.changedAfterProof)}.`
452
+ : '';
453
+ const completedAt = value.completedAt ? ` completed: ${escapeMarkdownText(value.completedAt)}.` : '';
454
+ return `- **${value.status} ${value.kind}:**${command} ${escapeMarkdownText(value.summary)}${source}${changedAfter}${completedAt}`;
455
+ }
456
+ function formatRequirementEvidence(value) {
457
+ const files = value.files.length > 0 ? value.files.join(', ') : 'contract-only';
458
+ const commands = value.requiredCommands.length > 0 ? value.requiredCommands.join('; ') : 'no command required';
459
+ const matched = value.matchedCommands.length > 0 ? value.matchedCommands.join('; ') : 'none';
460
+ const gaps = value.gaps.length > 0 ? ` gaps: ${value.gaps.join('; ')}` : '';
461
+ return `- **${value.status} ${value.surface}:** ${escapeMarkdownText(files)}; required: ${escapeMarkdownText(commands)}; matched: ${escapeMarkdownText(matched)}.${escapeMarkdownText(gaps)}`;
462
+ }
346
463
  function formatCommandEvidence(value) {
347
464
  const state = value.fresh ? 'fresh' : value.staleReason ? 'stale' : value.status;
348
465
  const exit = typeof value.exitCode === 'number' ? ` exit ${value.exitCode}` : ' no exit code';
349
466
  const duration = typeof value.durationMs === 'number' ? `, ${value.durationMs}ms` : '';
350
- const log = value.logPath ? `, log ${value.logPath}` : '';
351
- const summary = value.outputSummary ? ` - ${value.outputSummary}` : '';
352
- const stale = value.staleReason ? ` (${value.staleReason})` : '';
353
- return `- **${value.status} ${state}:** \`${value.command}\` (${exit}${duration}${log})${stale}${summary}`;
467
+ const source = value.source ? `, source ${value.source}` : '';
468
+ const log = value.logPath ? `, log ${markdownInlineCode(value.logPath)}` : '';
469
+ const summary = value.outputSummary ? ` - ${escapeMarkdownText(value.outputSummary)}` : '';
470
+ const stale = value.staleReason ? ` (${escapeMarkdownText(value.staleReason)})` : '';
471
+ return `- **${value.status} ${state}:** ${markdownInlineCode(value.command)} (${exit}${duration}${source}${log})${stale}${summary}`;
472
+ }
473
+ function inlineList(values) {
474
+ return values.length > 0 ? values.join(', ') : 'none';
475
+ }
476
+ function proofReplayForReceipt(receipt) {
477
+ return (receipt.proofReplay ?? {
478
+ status: 'needs-proof',
479
+ summary: 'No proof replay evidence recorded.',
480
+ events: [],
481
+ changedAfterProof: [],
482
+ replayCommand: 'projscan prove --changed --format markdown',
483
+ receiptFingerprint: 'missing',
484
+ });
485
+ }
486
+ function proofSufficiencyForReceipt(receipt) {
487
+ return (receipt.proofSufficiency ?? {
488
+ status: 'missing',
489
+ summary: 'No proof sufficiency evidence recorded.',
490
+ requirements: [],
491
+ gaps: ['No proof sufficiency evidence recorded.'],
492
+ weakRequirements: [],
493
+ missingRequirements: [],
494
+ staleRequirements: [],
495
+ failedRequirements: [],
496
+ });
354
497
  }
355
498
  function unique(values) {
356
499
  return [...new Set(values)];
@@ -376,4 +519,10 @@ function parseDurationMs(value) {
376
519
  }
377
520
  return parsed;
378
521
  }
522
+ function parseProofLedgerSource(value) {
523
+ if (value === 'prove-record' || value === 'prove-run' || value === 'mission' || value === 'external') {
524
+ return value;
525
+ }
526
+ throw new Error('record-source must be prove-record, prove-run, mission, or external');
527
+ }
379
528
  //# sourceMappingURL=prove.js.map