productfoo 0.0.0-stage → 1.0.1

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 (498) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +338 -2
  3. package/bin/foo +3 -0
  4. package/bin/foo.mjs +42 -0
  5. package/commands/bug.md +31 -0
  6. package/commands/discovery.md +28 -0
  7. package/commands/ideate.md +27 -0
  8. package/commands/init.md +28 -0
  9. package/commands/pitch.md +27 -0
  10. package/commands/preview.md +25 -0
  11. package/commands/research.md +31 -0
  12. package/commands/roast.md +27 -0
  13. package/commands/spec.md +30 -0
  14. package/config/pricing.yaml +198 -0
  15. package/config/routing-policy.yaml +171 -0
  16. package/dist-public/src/activeModel.d.ts +83 -0
  17. package/dist-public/src/activeModel.js +331 -0
  18. package/dist-public/src/agentAdapters.d.ts +122 -0
  19. package/dist-public/src/agentAdapters.js +178 -0
  20. package/dist-public/src/agentState.d.ts +43 -0
  21. package/dist-public/src/agentState.js +177 -0
  22. package/dist-public/src/bugCapsule.d.ts +94 -0
  23. package/dist-public/src/bugCapsule.js +227 -0
  24. package/dist-public/src/bugCapture.d.ts +26 -0
  25. package/dist-public/src/bugCapture.js +251 -0
  26. package/dist-public/src/bugOwnerLog.d.ts +93 -0
  27. package/dist-public/src/bugOwnerLog.js +304 -0
  28. package/dist-public/src/bugReportStore.d.ts +48 -0
  29. package/dist-public/src/bugReportStore.js +860 -0
  30. package/dist-public/src/bugSpecContext.d.ts +7 -0
  31. package/dist-public/src/bugSpecContext.js +129 -0
  32. package/dist-public/src/channelFreshness.d.ts +25 -0
  33. package/dist-public/src/channelFreshness.js +194 -0
  34. package/dist-public/src/cli.d.ts +30 -0
  35. package/dist-public/src/cli.js +1667 -0
  36. package/dist-public/src/cliArgs.d.ts +7 -0
  37. package/dist-public/src/cliArgs.js +44 -0
  38. package/dist-public/src/codeCatalog.d.ts +41 -0
  39. package/dist-public/src/codeCatalog.js +197 -0
  40. package/dist-public/src/commandContract.d.ts +84 -0
  41. package/dist-public/src/commandContract.js +390 -0
  42. package/dist-public/src/commandUsage.d.ts +3 -0
  43. package/dist-public/src/commandUsage.js +30 -0
  44. package/dist-public/src/commands/agent.d.ts +60 -0
  45. package/dist-public/src/commands/agent.js +1353 -0
  46. package/dist-public/src/commands/asp.d.ts +8 -0
  47. package/dist-public/src/commands/asp.js +669 -0
  48. package/dist-public/src/commands/evalCmd.d.ts +4 -0
  49. package/dist-public/src/commands/evalCmd.js +405 -0
  50. package/dist-public/src/commands/login.d.ts +25 -0
  51. package/dist-public/src/commands/login.js +94 -0
  52. package/dist-public/src/commands/loop.d.ts +16 -0
  53. package/dist-public/src/commands/loop.js +619 -0
  54. package/dist-public/src/commands/reconcile.d.ts +41 -0
  55. package/dist-public/src/commands/reconcile.js +292 -0
  56. package/dist-public/src/commands/runtime.d.ts +1 -0
  57. package/dist-public/src/commands/runtime.js +36 -0
  58. package/dist-public/src/commands/scanRedact.d.ts +8 -0
  59. package/dist-public/src/commands/scanRedact.js +266 -0
  60. package/dist-public/src/commands/setup.d.ts +28 -0
  61. package/dist-public/src/commands/setup.js +398 -0
  62. package/dist-public/src/commands/shared.d.ts +17 -0
  63. package/dist-public/src/commands/shared.js +147 -0
  64. package/dist-public/src/commands/source.d.ts +1 -0
  65. package/dist-public/src/commands/source.js +134 -0
  66. package/dist-public/src/commands/specCmd.d.ts +24 -0
  67. package/dist-public/src/commands/specCmd.js +794 -0
  68. package/dist-public/src/commands/update.d.ts +61 -0
  69. package/dist-public/src/commands/update.js +244 -0
  70. package/dist-public/src/comprehensionSignal.d.ts +20 -0
  71. package/dist-public/src/comprehensionSignal.js +166 -0
  72. package/dist-public/src/conductor/diversity.d.ts +48 -0
  73. package/dist-public/src/conductor/diversity.js +423 -0
  74. package/dist-public/src/conductor/engine.d.ts +7 -0
  75. package/dist-public/src/conductor/engine.js +295 -0
  76. package/dist-public/src/conductor/families/ideate.d.ts +2 -0
  77. package/dist-public/src/conductor/families/ideate.js +255 -0
  78. package/dist-public/src/conductor/families/interview.d.ts +2 -0
  79. package/dist-public/src/conductor/families/interview.js +39 -0
  80. package/dist-public/src/conductor/families/specSwarm.d.ts +2 -0
  81. package/dist-public/src/conductor/families/specSwarm.js +146 -0
  82. package/dist-public/src/conductor/familyDelivery.d.ts +6 -0
  83. package/dist-public/src/conductor/familyDelivery.js +37 -0
  84. package/dist-public/src/conductor/familyPackArtifact.d.ts +4 -0
  85. package/dist-public/src/conductor/familyPackArtifact.js +260 -0
  86. package/dist-public/src/conductor/ideateDecision.d.ts +6 -0
  87. package/dist-public/src/conductor/ideateDecision.js +237 -0
  88. package/dist-public/src/conductor/pack.d.ts +26 -0
  89. package/dist-public/src/conductor/pack.js +75 -0
  90. package/dist-public/src/conductor/types.d.ts +111 -0
  91. package/dist-public/src/conductor/types.js +7 -0
  92. package/dist-public/src/configPath.d.ts +2 -0
  93. package/dist-public/src/configPath.js +7 -0
  94. package/dist-public/src/discoveryArtifacts.d.ts +54 -0
  95. package/dist-public/src/discoveryArtifacts.js +467 -0
  96. package/dist-public/src/discoveryCommand.d.ts +127 -0
  97. package/dist-public/src/discoveryCommand.js +2148 -0
  98. package/dist-public/src/discoveryConnections.d.ts +339 -0
  99. package/dist-public/src/discoveryConnections.js +613 -0
  100. package/dist-public/src/discoveryDocs.d.ts +129 -0
  101. package/dist-public/src/discoveryDocs.js +577 -0
  102. package/dist-public/src/discoveryEvidence.d.ts +59 -0
  103. package/dist-public/src/discoveryEvidence.js +198 -0
  104. package/dist-public/src/discoveryFireflies.d.ts +25 -0
  105. package/dist-public/src/discoveryFireflies.js +551 -0
  106. package/dist-public/src/discoveryGmail.d.ts +12 -0
  107. package/dist-public/src/discoveryGmail.js +466 -0
  108. package/dist-public/src/discoveryGong.d.ts +12 -0
  109. package/dist-public/src/discoveryGong.js +491 -0
  110. package/dist-public/src/discoveryLearningRouting.d.ts +90 -0
  111. package/dist-public/src/discoveryLearningRouting.js +405 -0
  112. package/dist-public/src/discoveryMatching.d.ts +26 -0
  113. package/dist-public/src/discoveryMatching.js +73 -0
  114. package/dist-public/src/discoveryOutlook.d.ts +12 -0
  115. package/dist-public/src/discoveryOutlook.js +492 -0
  116. package/dist-public/src/discoveryProcess.d.ts +221 -0
  117. package/dist-public/src/discoveryProcess.js +703 -0
  118. package/dist-public/src/discoveryProof.d.ts +143 -0
  119. package/dist-public/src/discoveryProof.js +529 -0
  120. package/dist-public/src/discoveryProviders.d.ts +152 -0
  121. package/dist-public/src/discoveryProviders.js +756 -0
  122. package/dist-public/src/discoveryReadiness.d.ts +219 -0
  123. package/dist-public/src/discoveryReadiness.js +672 -0
  124. package/dist-public/src/discoveryReconcile.d.ts +57 -0
  125. package/dist-public/src/discoveryReconcile.js +424 -0
  126. package/dist-public/src/discoverySlack.d.ts +12 -0
  127. package/dist-public/src/discoverySlack.js +452 -0
  128. package/dist-public/src/discoverySources.d.ts +56 -0
  129. package/dist-public/src/discoverySources.js +322 -0
  130. package/dist-public/src/discoverySync.d.ts +52 -0
  131. package/dist-public/src/discoverySync.js +151 -0
  132. package/dist-public/src/discoverySynthesis.d.ts +57 -0
  133. package/dist-public/src/discoverySynthesis.js +215 -0
  134. package/dist-public/src/discoveryTeams.d.ts +12 -0
  135. package/dist-public/src/discoveryTeams.js +516 -0
  136. package/dist-public/src/discoveryZoom.d.ts +12 -0
  137. package/dist-public/src/discoveryZoom.js +523 -0
  138. package/dist-public/src/elicitationSurface.d.ts +13 -0
  139. package/dist-public/src/elicitationSurface.js +77 -0
  140. package/dist-public/src/errorReport.d.ts +99 -0
  141. package/dist-public/src/errorReport.js +443 -0
  142. package/dist-public/src/errorTaxonomy.d.ts +84 -0
  143. package/dist-public/src/errorTaxonomy.js +189 -0
  144. package/dist-public/src/evalCalibration.d.ts +82 -0
  145. package/dist-public/src/evalCalibration.js +169 -0
  146. package/dist-public/src/evalChecks.d.ts +21 -0
  147. package/dist-public/src/evalChecks.js +295 -0
  148. package/dist-public/src/evalCompile.d.ts +56 -0
  149. package/dist-public/src/evalCompile.js +58 -0
  150. package/dist-public/src/evalImprove.d.ts +60 -0
  151. package/dist-public/src/evalImprove.js +175 -0
  152. package/dist-public/src/evalJudge.d.ts +47 -0
  153. package/dist-public/src/evalJudge.js +143 -0
  154. package/dist-public/src/evalLabels.d.ts +100 -0
  155. package/dist-public/src/evalLabels.js +287 -0
  156. package/dist-public/src/evalRecord.d.ts +68 -0
  157. package/dist-public/src/evalRecord.js +165 -0
  158. package/dist-public/src/evalRoast.d.ts +88 -0
  159. package/dist-public/src/evalRoast.js +249 -0
  160. package/dist-public/src/evidenceIntake.d.ts +66 -0
  161. package/dist-public/src/evidenceIntake.js +356 -0
  162. package/dist-public/src/feedback.d.ts +78 -0
  163. package/dist-public/src/feedback.js +294 -0
  164. package/dist-public/src/firefliesClient.d.ts +106 -0
  165. package/dist-public/src/firefliesClient.js +258 -0
  166. package/dist-public/src/firstMoveTensions.d.ts +10 -0
  167. package/dist-public/src/firstMoveTensions.js +93 -0
  168. package/dist-public/src/gitRun.d.ts +21 -0
  169. package/dist-public/src/gitRun.js +50 -0
  170. package/dist-public/src/githubReconcile.d.ts +94 -0
  171. package/dist-public/src/githubReconcile.js +205 -0
  172. package/dist-public/src/gmailNango.d.ts +131 -0
  173. package/dist-public/src/gmailNango.js +329 -0
  174. package/dist-public/src/gongNango.d.ts +118 -0
  175. package/dist-public/src/gongNango.js +308 -0
  176. package/dist-public/src/grammarGate.d.ts +13 -0
  177. package/dist-public/src/grammarGate.js +72 -0
  178. package/dist-public/src/harnessGates.d.ts +65 -0
  179. package/dist-public/src/harnessGates.js +168 -0
  180. package/dist-public/src/humanSurfaceEval.d.ts +19 -0
  181. package/dist-public/src/humanSurfaceEval.js +156 -0
  182. package/dist-public/src/ideate.d.ts +43 -0
  183. package/dist-public/src/ideate.js +255 -0
  184. package/dist-public/src/ideateContext.d.ts +11 -0
  185. package/dist-public/src/ideateContext.js +83 -0
  186. package/dist-public/src/index.d.ts +2 -0
  187. package/dist-public/src/index.js +4 -0
  188. package/dist-public/src/initCommand.d.ts +25 -0
  189. package/dist-public/src/initCommand.js +558 -0
  190. package/dist-public/src/interviewGate.d.ts +25 -0
  191. package/dist-public/src/interviewGate.js +126 -0
  192. package/dist-public/src/jsonFile.d.ts +2 -0
  193. package/dist-public/src/jsonFile.js +22 -0
  194. package/dist-public/src/loopBudget.d.ts +182 -0
  195. package/dist-public/src/loopBudget.js +494 -0
  196. package/dist-public/src/loopContracts.d.ts +35 -0
  197. package/dist-public/src/loopContracts.js +364 -0
  198. package/dist-public/src/machineState.d.ts +1 -0
  199. package/dist-public/src/machineState.js +9 -0
  200. package/dist-public/src/notionNango.d.ts +93 -0
  201. package/dist-public/src/notionNango.js +279 -0
  202. package/dist-public/src/orchestrationResult.d.ts +11 -0
  203. package/dist-public/src/orchestrationResult.js +73 -0
  204. package/dist-public/src/outlookNango.d.ts +124 -0
  205. package/dist-public/src/outlookNango.js +327 -0
  206. package/dist-public/src/packetCorrections.d.ts +40 -0
  207. package/dist-public/src/packetCorrections.js +172 -0
  208. package/dist-public/src/packetGlossary.d.ts +6 -0
  209. package/dist-public/src/packetGlossary.js +42 -0
  210. package/dist-public/src/packetIndex.d.ts +54 -0
  211. package/dist-public/src/packetIndex.js +744 -0
  212. package/dist-public/src/packetIndexEntry.d.ts +3 -0
  213. package/dist-public/src/packetIndexEntry.js +128 -0
  214. package/dist-public/src/packetIndexServe.d.ts +13 -0
  215. package/dist-public/src/packetIndexServe.js +113 -0
  216. package/dist-public/src/packetIndexWorker.d.ts +7 -0
  217. package/dist-public/src/packetIndexWorker.js +45 -0
  218. package/dist-public/src/packetLifecycle.d.ts +30 -0
  219. package/dist-public/src/packetLifecycle.js +127 -0
  220. package/dist-public/src/packetReconcile.d.ts +73 -0
  221. package/dist-public/src/packetReconcile.js +386 -0
  222. package/dist-public/src/packetStatus.d.ts +125 -0
  223. package/dist-public/src/packetStatus.js +770 -0
  224. package/dist-public/src/packetValidation.d.ts +17 -0
  225. package/dist-public/src/packetValidation.js +333 -0
  226. package/dist-public/src/packetVerify.d.ts +73 -0
  227. package/dist-public/src/packetVerify.js +303 -0
  228. package/dist-public/src/packetWrite.d.ts +52 -0
  229. package/dist-public/src/packetWrite.js +448 -0
  230. package/dist-public/src/pitch.d.ts +38 -0
  231. package/dist-public/src/pitch.js +154 -0
  232. package/dist-public/src/processMemo.d.ts +8 -0
  233. package/dist-public/src/processMemo.js +23 -0
  234. package/dist-public/src/productDetect.d.ts +30 -0
  235. package/dist-public/src/productDetect.js +376 -0
  236. package/dist-public/src/profile.d.ts +62 -0
  237. package/dist-public/src/profile.js +334 -0
  238. package/dist-public/src/questionModel.d.ts +46 -0
  239. package/dist-public/src/questionModel.js +74 -0
  240. package/dist-public/src/questionText.d.ts +7 -0
  241. package/dist-public/src/questionText.js +38 -0
  242. package/dist-public/src/redactConfig.d.ts +2 -0
  243. package/dist-public/src/redactConfig.js +11 -0
  244. package/dist-public/src/redactEngine.d.ts +59 -0
  245. package/dist-public/src/redactEngine.js +509 -0
  246. package/dist-public/src/redactGate.d.ts +63 -0
  247. package/dist-public/src/redactGate.js +209 -0
  248. package/dist-public/src/repoRead.d.ts +29 -0
  249. package/dist-public/src/repoRead.js +160 -0
  250. package/dist-public/src/research.d.ts +242 -0
  251. package/dist-public/src/research.js +1314 -0
  252. package/dist-public/src/researchCompletion.d.ts +34 -0
  253. package/dist-public/src/researchCompletion.js +123 -0
  254. package/dist-public/src/researchExecution.d.ts +47 -0
  255. package/dist-public/src/researchExecution.js +309 -0
  256. package/dist-public/src/researchFormat.d.ts +21 -0
  257. package/dist-public/src/researchFormat.js +77 -0
  258. package/dist-public/src/researchGate.d.ts +86 -0
  259. package/dist-public/src/researchGate.js +1036 -0
  260. package/dist-public/src/researchReceipt.d.ts +76 -0
  261. package/dist-public/src/researchReceipt.js +148 -0
  262. package/dist-public/src/researchRender.d.ts +2 -0
  263. package/dist-public/src/researchRender.js +267 -0
  264. package/dist-public/src/researchSigningKey.d.ts +19 -0
  265. package/dist-public/src/researchSigningKey.js +95 -0
  266. package/dist-public/src/riskClassify.d.ts +42 -0
  267. package/dist-public/src/riskClassify.js +149 -0
  268. package/dist-public/src/routines.d.ts +42 -0
  269. package/dist-public/src/routines.js +269 -0
  270. package/dist-public/src/routingPolicy.d.ts +172 -0
  271. package/dist-public/src/routingPolicy.js +646 -0
  272. package/dist-public/src/secretInput.d.ts +8 -0
  273. package/dist-public/src/secretInput.js +89 -0
  274. package/dist-public/src/selfCheck.d.ts +7 -0
  275. package/dist-public/src/selfCheck.js +473 -0
  276. package/dist-public/src/selfCheckCache.d.ts +29 -0
  277. package/dist-public/src/selfCheckCache.js +147 -0
  278. package/dist-public/src/severityClass.d.ts +15 -0
  279. package/dist-public/src/severityClass.js +22 -0
  280. package/dist-public/src/skillClientPolicy.d.ts +8 -0
  281. package/dist-public/src/skillClientPolicy.js +16 -0
  282. package/dist-public/src/skillLocal.d.ts +98 -0
  283. package/dist-public/src/skillLocal.js +463 -0
  284. package/dist-public/src/skillTreeDigest.d.ts +9 -0
  285. package/dist-public/src/skillTreeDigest.js +64 -0
  286. package/dist-public/src/slackNango.d.ts +62 -0
  287. package/dist-public/src/slackNango.js +208 -0
  288. package/dist-public/src/social/arxiv.d.ts +19 -0
  289. package/dist-public/src/social/arxiv.js +96 -0
  290. package/dist-public/src/social/github.d.ts +2 -0
  291. package/dist-public/src/social/github.js +78 -0
  292. package/dist-public/src/social/hackernews.d.ts +2 -0
  293. package/dist-public/src/social/hackernews.js +67 -0
  294. package/dist-public/src/social/index.d.ts +10 -0
  295. package/dist-public/src/social/index.js +79 -0
  296. package/dist-public/src/social/reddit.d.ts +2 -0
  297. package/dist-public/src/social/reddit.js +125 -0
  298. package/dist-public/src/social/types.d.ts +73 -0
  299. package/dist-public/src/social/types.js +61 -0
  300. package/dist-public/src/social/xml.d.ts +10 -0
  301. package/dist-public/src/social/xml.js +49 -0
  302. package/dist-public/src/social/youtube.d.ts +7 -0
  303. package/dist-public/src/social/youtube.js +217 -0
  304. package/dist-public/src/sourceIngress.d.ts +488 -0
  305. package/dist-public/src/sourceIngress.js +1651 -0
  306. package/dist-public/src/specAfter.d.ts +187 -0
  307. package/dist-public/src/specAfter.js +814 -0
  308. package/dist-public/src/specBudget.d.ts +124 -0
  309. package/dist-public/src/specBudget.js +424 -0
  310. package/dist-public/src/specDecisionSignals.d.ts +38 -0
  311. package/dist-public/src/specDecisionSignals.js +121 -0
  312. package/dist-public/src/specLinkedCommits.d.ts +7 -0
  313. package/dist-public/src/specLinkedCommits.js +107 -0
  314. package/dist-public/src/specSections.d.ts +105 -0
  315. package/dist-public/src/specSections.js +718 -0
  316. package/dist-public/src/statusGlyphs.d.ts +18 -0
  317. package/dist-public/src/statusGlyphs.js +75 -0
  318. package/dist-public/src/swarmCommand.d.ts +10 -0
  319. package/dist-public/src/swarmCommand.js +96 -0
  320. package/dist-public/src/teamsNango.d.ts +114 -0
  321. package/dist-public/src/teamsNango.js +301 -0
  322. package/dist-public/src/tokenStore.d.ts +10 -0
  323. package/dist-public/src/tokenStore.js +77 -0
  324. package/dist-public/src/trustEnvelope.d.ts +78 -0
  325. package/dist-public/src/trustEnvelope.js +392 -0
  326. package/dist-public/src/untrustedText.d.ts +6 -0
  327. package/dist-public/src/untrustedText.js +20 -0
  328. package/dist-public/src/updateNotice.d.ts +41 -0
  329. package/dist-public/src/updateNotice.js +290 -0
  330. package/dist-public/src/vendorYaml.d.ts +1 -0
  331. package/dist-public/src/vendorYaml.js +7374 -0
  332. package/dist-public/src/workflowRunActuals.d.ts +67 -0
  333. package/dist-public/src/workflowRunActuals.js +184 -0
  334. package/dist-public/src/zendeskDiscovery.d.ts +12 -0
  335. package/dist-public/src/zendeskDiscovery.js +513 -0
  336. package/dist-public/src/zendeskNango.d.ts +131 -0
  337. package/dist-public/src/zendeskNango.js +344 -0
  338. package/dist-public/src/zoomNango.d.ts +106 -0
  339. package/dist-public/src/zoomNango.js +351 -0
  340. package/docs/CHANGELOG.md +32 -0
  341. package/docs/THIRD_PARTY_NOTICES.md +36 -0
  342. package/package.json +71 -4
  343. package/schemas/bug-capsule-receipt.schema.json +54 -0
  344. package/schemas/bug-capsule.schema.json +189 -0
  345. package/schemas/discovery-evidence-envelope.schema.json +79 -0
  346. package/schemas/discovery-processing-receipt.schema.json +71 -0
  347. package/schemas/discovery-service-contract.schema.json +189 -0
  348. package/skills/AGENTS.md +32 -0
  349. package/skills/README.md +287 -0
  350. package/skills/bug/SKILL.md +49 -0
  351. package/skills/build-preview-spec/SKILL.md +103 -0
  352. package/skills/capture-external-artifact/SKILL.md +23 -0
  353. package/skills/capture-external-artifact/agents/openai.yaml +4 -0
  354. package/skills/capture-external-artifact/references/extractor-libraries.md +27 -0
  355. package/skills/check-spec-health/SKILL.md +45 -0
  356. package/skills/check-spec-health/agents/openai.yaml +4 -0
  357. package/skills/competitive-positioning/SKILL.md +86 -0
  358. package/skills/competitive-positioning/agents/openai.yaml +4 -0
  359. package/skills/cpo-lens/SKILL.md +398 -0
  360. package/skills/cpo-lens/agents/openai.yaml +4 -0
  361. package/skills/create-prd/SKILL.md +26 -0
  362. package/skills/create-prd/agents/openai.yaml +4 -0
  363. package/skills/customer-discovery/SKILL.md +192 -0
  364. package/skills/design-system/SKILL.md +49 -0
  365. package/skills/design-system/agents/openai.yaml +4 -0
  366. package/skills/discussion-guide/SKILL.md +75 -0
  367. package/skills/discussion-guide/agents/openai.yaml +4 -0
  368. package/skills/firecrawl-research-papers/SKILL.md +96 -0
  369. package/skills/firecrawl-research-papers/agents/openai.yaml +4 -0
  370. package/skills/foo-roast/SKILL.md +325 -0
  371. package/skills/generate-gtm-brief/SKILL.md +41 -0
  372. package/skills/generate-gtm-brief/agents/openai.yaml +4 -0
  373. package/skills/generate-gtm-brief/references/gtm-brief-template.md +56 -0
  374. package/skills/gong-quotes/SKILL.md +43 -0
  375. package/skills/gong-quotes/agents/openai.yaml +4 -0
  376. package/skills/grill-me/SKILL.md +27 -0
  377. package/skills/grill-me/agents/openai.yaml +4 -0
  378. package/skills/ideate/SKILL.md +180 -0
  379. package/skills/ideate/references/family-packs.md +5 -0
  380. package/skills/initiative-tracker/SKILL.md +23 -0
  381. package/skills/initiative-tracker/agents/openai.yaml +4 -0
  382. package/skills/interop-review/SKILL.md +25 -0
  383. package/skills/interop-review/agents/openai.yaml +4 -0
  384. package/skills/interview-me/SKILL.md +404 -0
  385. package/skills/interview-me/agents/openai.yaml +4 -0
  386. package/skills/loop-library-audit/SKILL.md +123 -0
  387. package/skills/pitch/SKILL.md +110 -0
  388. package/skills/pitch/references/opportunity-assessment.md +136 -0
  389. package/skills/pitch/references/prfaq-template.md +54 -0
  390. package/skills/pmm-release-briefing/SKILL.md +27 -0
  391. package/skills/pmm-release-briefing/agents/openai.yaml +4 -0
  392. package/skills/pmm-release-briefing/references/variant-generalized.md +16 -0
  393. package/skills/positioning-messaging/SKILL.md +70 -0
  394. package/skills/positioning-messaging/agents/openai.yaml +4 -0
  395. package/skills/positioning-messaging/references/guest-insights.md +1400 -0
  396. package/skills/preview-swarm/SKILL.md +418 -0
  397. package/skills/preview-swarm/agents/openai.yaml +4 -0
  398. package/skills/preview-swarm/references/html-effectiveness-build-previews.md +168 -0
  399. package/skills/product-copywriting/SKILL.md +127 -0
  400. package/skills/product-copywriting/agents/openai.yaml +4 -0
  401. package/skills/product-copywriting/references/foo-voice.md +26 -0
  402. package/skills/product-shape-interview/SKILL.md +219 -0
  403. package/skills/product-shape-interview/agents/openai.yaml +4 -0
  404. package/skills/ready-for-release/SKILL.md +39 -0
  405. package/skills/ready-for-release/agents/openai.yaml +4 -0
  406. package/skills/redact-transcripts/SKILL.md +23 -0
  407. package/skills/redact-transcripts/agents/openai.yaml +4 -0
  408. package/skills/research-brief/SKILL.md +48 -0
  409. package/skills/research-brief/agents/openai.yaml +4 -0
  410. package/skills/research-refresh/SKILL.md +63 -0
  411. package/skills/research-refresh/references/worked-cases.md +44 -0
  412. package/skills/review-loop/SKILL.md +200 -0
  413. package/skills/review-spec/SKILL.md +32 -0
  414. package/skills/review-spec/agents/openai.yaml +4 -0
  415. package/skills/rfc-from-research/SKILL.md +42 -0
  416. package/skills/rfc-from-research/agents/openai.yaml +4 -0
  417. package/skills/rfc-from-research/references/rfc-pattern.md +69 -0
  418. package/skills/skill-registry.yaml +810 -0
  419. package/skills/spec-cleanup/SKILL.md +103 -0
  420. package/skills/spec-cleanup/agents/openai.yaml +4 -0
  421. package/skills/spec-swarm/SKILL.md +87 -0
  422. package/skills/spec-swarm/agents/openai.yaml +4 -0
  423. package/skills/spec-swarm/template/SKILL.template.md +94 -0
  424. package/skills/spec-swarm/template/personas/accessibility-inclusion.md +40 -0
  425. package/skills/spec-swarm/template/personas/ai-technical-pm.md +69 -0
  426. package/skills/spec-swarm/template/personas/analytics-engineering.md +39 -0
  427. package/skills/spec-swarm/template/personas/applied-ai-eval.md +64 -0
  428. package/skills/spec-swarm/template/personas/business-gm-pm.md +67 -0
  429. package/skills/spec-swarm/template/personas/consumer-craft-pm.md +68 -0
  430. package/skills/spec-swarm/template/personas/content-design.md +40 -0
  431. package/skills/spec-swarm/template/personas/cpo.md +42 -0
  432. package/skills/spec-swarm/template/personas/data-science.md +42 -0
  433. package/skills/spec-swarm/template/personas/developer-experience.md +65 -0
  434. package/skills/spec-swarm/template/personas/dx-product.md +70 -0
  435. package/skills/spec-swarm/template/personas/field.md +43 -0
  436. package/skills/spec-swarm/template/personas/finance-cfo.md +40 -0
  437. package/skills/spec-swarm/template/personas/growth-pm.md +67 -0
  438. package/skills/spec-swarm/template/personas/platform-pm.md +67 -0
  439. package/skills/spec-swarm/template/personas/pmm.md +43 -0
  440. package/skills/spec-swarm/template/personas/principal-product-designer.md +42 -0
  441. package/skills/spec-swarm/template/personas/product-ops-program.md +41 -0
  442. package/skills/spec-swarm/template/personas/qa-release.md +41 -0
  443. package/skills/spec-swarm/template/personas/responsible-ai-safety.md +64 -0
  444. package/skills/spec-swarm/template/personas/security-privacy-legal.md +40 -0
  445. package/skills/spec-swarm/template/personas/strategy-competitive.md +41 -0
  446. package/skills/spec-swarm/template/personas/technical-architect.md +42 -0
  447. package/skills/spec-swarm/template/personas/technical-lead.md +43 -0
  448. package/skills/spec-swarm/template/personas/user-research.md +41 -0
  449. package/skills/spec-swarm-accessibility-inclusion/SKILL.md +95 -0
  450. package/skills/spec-swarm-accessibility-inclusion/agents/openai.yaml +4 -0
  451. package/skills/spec-swarm-ai-technical-pm/SKILL.md +124 -0
  452. package/skills/spec-swarm-analytics-engineering/SKILL.md +94 -0
  453. package/skills/spec-swarm-analytics-engineering/agents/openai.yaml +4 -0
  454. package/skills/spec-swarm-applied-ai-eval/SKILL.md +120 -0
  455. package/skills/spec-swarm-business-gm-pm/SKILL.md +122 -0
  456. package/skills/spec-swarm-consumer-craft-pm/SKILL.md +122 -0
  457. package/skills/spec-swarm-content-design/SKILL.md +95 -0
  458. package/skills/spec-swarm-content-design/agents/openai.yaml +4 -0
  459. package/skills/spec-swarm-cpo/SKILL.md +94 -0
  460. package/skills/spec-swarm-cpo/agents/openai.yaml +4 -0
  461. package/skills/spec-swarm-data-science/SKILL.md +95 -0
  462. package/skills/spec-swarm-data-science/agents/openai.yaml +4 -0
  463. package/skills/spec-swarm-developer-experience/SKILL.md +121 -0
  464. package/skills/spec-swarm-dx-product/SKILL.md +126 -0
  465. package/skills/spec-swarm-field/SKILL.md +96 -0
  466. package/skills/spec-swarm-field/agents/openai.yaml +4 -0
  467. package/skills/spec-swarm-finance-cfo/SKILL.md +95 -0
  468. package/skills/spec-swarm-finance-cfo/agents/openai.yaml +4 -0
  469. package/skills/spec-swarm-growth-pm/SKILL.md +122 -0
  470. package/skills/spec-swarm-platform-pm/SKILL.md +122 -0
  471. package/skills/spec-swarm-pmm/SKILL.md +96 -0
  472. package/skills/spec-swarm-pmm/agents/openai.yaml +4 -0
  473. package/skills/spec-swarm-principal-product-designer/SKILL.md +95 -0
  474. package/skills/spec-swarm-principal-product-designer/agents/openai.yaml +4 -0
  475. package/skills/spec-swarm-product-ops-program/SKILL.md +96 -0
  476. package/skills/spec-swarm-product-ops-program/agents/openai.yaml +4 -0
  477. package/skills/spec-swarm-qa-release/SKILL.md +96 -0
  478. package/skills/spec-swarm-qa-release/agents/openai.yaml +4 -0
  479. package/skills/spec-swarm-responsible-ai-safety/SKILL.md +120 -0
  480. package/skills/spec-swarm-security-privacy-legal/SKILL.md +95 -0
  481. package/skills/spec-swarm-security-privacy-legal/agents/openai.yaml +4 -0
  482. package/skills/spec-swarm-strategy-competitive/SKILL.md +96 -0
  483. package/skills/spec-swarm-strategy-competitive/agents/openai.yaml +4 -0
  484. package/skills/spec-swarm-technical-architect/SKILL.md +95 -0
  485. package/skills/spec-swarm-technical-architect/agents/openai.yaml +4 -0
  486. package/skills/spec-swarm-technical-lead/SKILL.md +96 -0
  487. package/skills/spec-swarm-technical-lead/agents/openai.yaml +4 -0
  488. package/skills/spec-swarm-user-research/SKILL.md +95 -0
  489. package/skills/spec-swarm-user-research/agents/openai.yaml +4 -0
  490. package/skills/strategy-check/SKILL.md +170 -0
  491. package/skills/strategy-check/agents/openai.yaml +4 -0
  492. package/skills/study-digest/SKILL.md +41 -0
  493. package/skills/synthetic-customer/SKILL.md +68 -0
  494. package/skills/update-cli-spec/SKILL.md +69 -0
  495. package/skills/update-cli-spec/agents/openai.yaml +4 -0
  496. package/skills/voc-researcher/SKILL.md +45 -0
  497. package/skills/voc-researcher/agents/openai.yaml +4 -0
  498. package/skills-lock.json +35 -0
@@ -0,0 +1,703 @@
1
+ // One server-enforced processing operation (nango-discovery-connector-v0
2
+ // T-004; R-005/R-006/R-007/R-012).
3
+ //
4
+ // processDiscoverySession is the whole privileged surface in one operation:
5
+ // authorization gates → exactly one transcript fetch → untrusted-text
6
+ // synthesis behind the isolated processor seam → deterministic
7
+ // privacy/injection/schema screening → raw disposal → a signed payload-free
8
+ // processing receipt. The transcript exists only inside this one request:
9
+ // it crosses no log, no queue, no cache, no backup, and no diagnostic —
10
+ // errors and coverage are content-free, trace ids are opaque, and there is
11
+ // no automatic retry or alternate source (a second body call is structurally
12
+ // impossible: one guarded call site, no loop).
13
+ //
14
+ // At-most-once (D-013): the content-free attempt ledger claims every attempt;
15
+ // a repeat claim in any state returns `result_lost` without a provider call,
16
+ // a lost success response is reported `result_lost` and never recovered from
17
+ // a store, and a new process attempt needs fresh human-confirmed budget
18
+ // authorization. Hosted deployment stays out of scope (contract_only): the
19
+ // operation is proven by fixtures and the published closed-union schemas,
20
+ // with the real transport/identity/confirmation stack owned by
21
+ // foo-mcp-server-v0 (T-002's seams, never rebuilt here).
22
+ import { createHash, createPublicKey, createPrivateKey, generateKeyPairSync, randomBytes } from "node:crypto";
23
+ import { screenDiscoveryServiceEnvelope, } from "./discoveryEvidence.js";
24
+ import { SYNTHESIS_MAX_OUTPUT_TOKENS, SYNTHESIS_SYSTEM_PROMPT, constructEnvelopeFromSynthesis, extractSynthesisJsonObject, synthesisUserMessage, } from "./discoverySynthesis.js";
25
+ import { boundaryFailureFor, DISCOVERY_SERVICE_POLICY, hostedDiscoverySourceFingerprint, openDiscoverySessionRef, } from "./discoveryReadiness.js";
26
+ import { guardedDiscoveryAccess, recheckDiscoveryAccessBoundary, } from "./discoveryConnections.js";
27
+ import { canonicalJson, signEnvelope, verifyEnvelope, } from "./trustEnvelope.js";
28
+ import { sanitizeDiscoveryStableUrl } from "./discoverySources.js";
29
+ // --- Versioned identity -------------------------------------------------------
30
+ export const PROCESSING_VERSION = "discovery-process-0.1";
31
+ export const PROMPT_VERSION = "discovery-process-prompt-0.1";
32
+ export const RECEIPT_VERSION = "v1";
33
+ export const RECEIPT_ARTIFACT_KIND = "discovery-processing-receipt";
34
+ // A processing receipt lives long enough for a local apply session to verify
35
+ // it online (D-014); after expiry the apply fails closed and the work is
36
+ // re-requested under a fresh budget, never recovered from a store.
37
+ export const RECEIPT_TTL_MS = 24 * 60 * 60_000;
38
+ // Ceilings: the hosted service policy T-003 already ported from the Gong
39
+ // worker's GONG_POLICY (R-001 — one versioned policy, not new magic numbers).
40
+ // The module re-verifies every ceiling itself before synthesis or release;
41
+ // the source seam enforces the same values while reading.
42
+ export const DISCOVERY_PROCESSING_LIMITS = {
43
+ max_response_bytes: DISCOVERY_SERVICE_POLICY.max_response_bytes,
44
+ fetch_timeout_ms: DISCOVERY_SERVICE_POLICY.fetch_timeout_ms,
45
+ max_model_input_tokens: DISCOVERY_SERVICE_POLICY.max_model_input_tokens,
46
+ };
47
+ // D-015's closed mutation allowlist for SERVICE CONNECTION state. The
48
+ // processing operation performs none of these — it only claims and finishes
49
+ // content-free ledger rows and records budget spend. The conformance fixtures
50
+ // (V-016) journal every service call and prove exactly that.
51
+ export const DISCOVERY_CONNECTION_MUTATION_ALLOWLIST = [
52
+ "connect",
53
+ "credential_refresh",
54
+ "target_suspend",
55
+ "target_grant_revoke",
56
+ "disconnect_revoke",
57
+ ];
58
+ const ATTEMPT_ID = /^att:[a-f0-9]{16,64}$/;
59
+ const CONNECTION_REF_SHAPE = /^conn:[a-z0-9][a-z0-9.-]*$/;
60
+ const TARGET_REF_SHAPE = /^dtarget:[a-z0-9][a-z0-9.-]*$/;
61
+ const SHA256_DIGEST = /^sha256:[a-f0-9]{64}$/;
62
+ const NO_STABLE_LINK_CAVEAT = "The provider did not supply a stable link for this call; the evidence cites in-transcript locators only.";
63
+ const NO_TIMESTAMPS_CAVEAT = "The provider's transcript carried no usable timestamps; findings cannot cite in-transcript locators.";
64
+ const UNTRUSTED_FAILURE = "the isolated synthesis processor failed; no evidence was produced";
65
+ const SCREEN_FAILURE = "the synthesized evidence failed deterministic screening";
66
+ const UNPARSEABLE_FAILURE = "synthesis did not return parseable JSON";
67
+ // --- Typed transcript-source failures (content-free) --------------------------
68
+ export class DiscoveryTranscriptOversizeError extends Error {
69
+ limit_bytes;
70
+ constructor(limit_bytes) {
71
+ super(`the transcript response exceeded the ${limit_bytes}-byte policy ceiling`);
72
+ this.limit_bytes = limit_bytes;
73
+ this.name = "DiscoveryTranscriptOversizeError";
74
+ }
75
+ }
76
+ export class DiscoveryTranscriptTimeoutError extends Error {
77
+ timeout_ms;
78
+ constructor(timeout_ms) {
79
+ super(`the transcript fetch exceeded the ${timeout_ms}-ms policy ceiling`);
80
+ this.timeout_ms = timeout_ms;
81
+ this.name = "DiscoveryTranscriptTimeoutError";
82
+ }
83
+ }
84
+ export class DiscoveryTranscriptCancelledError extends Error {
85
+ constructor() {
86
+ super("the transcript fetch was cancelled before completion");
87
+ this.name = "DiscoveryTranscriptCancelledError";
88
+ }
89
+ }
90
+ export function createInMemoryDiscoveryLedger() {
91
+ const byAttempt = new Map();
92
+ const activeBySource = new Map();
93
+ return {
94
+ beginAttempt(row) {
95
+ const repeated = byAttempt.get(row.attempt_id);
96
+ if (repeated)
97
+ return { accepted: false, existing_state: repeated.state };
98
+ const sourceKey = [row.subject_ref, row.target_ref, row.source_fingerprint].join("\n");
99
+ const activeAttempt = activeBySource.get(sourceKey);
100
+ if (activeAttempt)
101
+ return { accepted: false, existing_state: byAttempt.get(activeAttempt).state };
102
+ byAttempt.set(row.attempt_id, { ...row, state: "claimed" });
103
+ activeBySource.set(sourceKey, row.attempt_id);
104
+ return { accepted: true };
105
+ },
106
+ finishAttempt(attempt_id, state) {
107
+ const row = byAttempt.get(attempt_id);
108
+ if (!row)
109
+ throw new Error(`attempt ${attempt_id} was never claimed`);
110
+ row.state = state;
111
+ },
112
+ rows() {
113
+ return [...byAttempt.values()];
114
+ },
115
+ };
116
+ }
117
+ const RECEIPT_PAYLOAD_KEYS = new Set([
118
+ "kind",
119
+ "receipt_version",
120
+ "subject_ref",
121
+ "workspace_ref",
122
+ "connection_ref",
123
+ "target_ref",
124
+ "target_id",
125
+ "lane",
126
+ "source_fingerprint",
127
+ "approval_digest",
128
+ "grant_digest",
129
+ "revocation_epoch",
130
+ "envelope_hash",
131
+ "attempt_id",
132
+ "processing",
133
+ "limits",
134
+ ]);
135
+ const RECEIPT_PROCESSING_KEYS = new Set(["processing_version", "prompt_version", "policy_version", "synthesizer_model", "envelope_schema_version"]);
136
+ const RECEIPT_LIMITS_KEYS = new Set(["max_response_bytes", "fetch_timeout_ms", "max_model_input_tokens"]);
137
+ // The ed25519 pattern of src/researchSigningKey.ts, scoped to discovery
138
+ // receipts: machine-local private key material is the deployer's concern and
139
+ // is accepted as a PEM or generated for fixtures; only the public entry is
140
+ // ever published into the trust store.
141
+ export function createInMemoryDiscoveryReceiptSigner(options = {}) {
142
+ let privatePem;
143
+ let publicPem;
144
+ if (options.private_key_pem) {
145
+ const key = createPrivateKey(options.private_key_pem);
146
+ privatePem = key.export({ type: "pkcs8", format: "pem" }).toString();
147
+ publicPem = createPublicKey(key).export({ type: "spki", format: "pem" }).toString();
148
+ }
149
+ else {
150
+ const pair = generateKeyPairSync("ed25519");
151
+ privatePem = pair.privateKey.export({ type: "pkcs8", format: "pem" }).toString();
152
+ publicPem = pair.publicKey.export({ type: "spki", format: "pem" }).toString();
153
+ }
154
+ const keyId = options.key_id ?? `discovery-receipt-${createHash("sha256").update(publicPem).digest("hex").slice(0, 12)}`;
155
+ return {
156
+ key_id: keyId,
157
+ signReceipt({ payload, issued_at, expires_at }) {
158
+ return signEnvelope({
159
+ namespace: "foo",
160
+ artifact_kind: RECEIPT_ARTIFACT_KIND,
161
+ artifact_id: payload.attempt_id,
162
+ payload,
163
+ key_id: keyId,
164
+ issued_at,
165
+ not_before: issued_at,
166
+ expires_at,
167
+ sequence: 1,
168
+ previous_hash: null,
169
+ }, privatePem);
170
+ },
171
+ trustEntry(entry = {}) {
172
+ return {
173
+ key_id: keyId,
174
+ public_key_pem: publicPem,
175
+ status: entry.status ?? "active",
176
+ valid_from: entry.valid_from ?? new Date(0).toISOString(),
177
+ valid_until: entry.valid_until ?? null,
178
+ };
179
+ },
180
+ };
181
+ }
182
+ const RECEIPT_FAILURE_MESSAGES = {
183
+ malformed_envelope: "the receipt is not a well-formed signed envelope",
184
+ wrong_namespace: "the receipt was not signed in the foo namespace",
185
+ wrong_artifact_kind: "the receipt is not a discovery-processing-receipt",
186
+ wrong_artifact_id: "the receipt does not belong to this attempt",
187
+ invalid_trust_store: "the trust store is unusable; verification fails closed",
188
+ unknown_key: "the receipt was signed by an unknown key",
189
+ revoked_key: "the receipt was signed by a revoked key",
190
+ retired_key_for_new_acceptance: "the receipt was signed by a retired key",
191
+ key_not_yet_valid: "the signing key was not valid when the receipt was issued",
192
+ key_expired: "the signing key had expired when the receipt was issued",
193
+ envelope_not_yet_valid: "the receipt is not yet within its validity interval",
194
+ envelope_expired: "the receipt has expired",
195
+ signature_invalid: "the receipt signature does not verify",
196
+ invalid_sequence_state: "the receipt's sequence state is invalid",
197
+ replay: "this receipt was already accepted",
198
+ rollback: "the receipt's sequence rolls back an accepted state",
199
+ sequence_gap: "the receipt's sequence does not continue the accepted state",
200
+ previous_hash_mismatch: "the receipt's hash chain does not connect",
201
+ };
202
+ // The apply-side verifier T-005 consumes. Fail-closed by construction: an
203
+ // unknown or revoked key, an expired receipt, a closed-payload violation, or
204
+ // any mismatched binding returns ok: false and nothing else.
205
+ export function verifyDiscoveryProcessingReceipt(input) {
206
+ const receipt = input.receipt;
207
+ const selfArtifactId = receipt && typeof receipt.artifact_id === "string" ? receipt.artifact_id : "";
208
+ const verdict = verifyEnvelope(input.receipt, {
209
+ expected_namespace: "foo",
210
+ expected_artifact_kind: RECEIPT_ARTIFACT_KIND,
211
+ expected_artifact_id: input.expectation?.attempt_id ?? selfArtifactId,
212
+ trust_stores: { customer: { namespace: "customer", keys: [] }, foo: input.trust_store },
213
+ accepted_state: null,
214
+ verification_mode: "accept",
215
+ now: input.now,
216
+ });
217
+ if (!verdict.ok)
218
+ return { ok: false, reason: verdict.reason, message: RECEIPT_FAILURE_MESSAGES[verdict.reason] };
219
+ const payloadCheck = validateReceiptPayload(verdict.verified_envelope.payload);
220
+ if (!payloadCheck.ok)
221
+ return { ok: false, reason: "malformed_payload", message: payloadCheck.message };
222
+ const payload = payloadCheck.payload;
223
+ if (input.expectation) {
224
+ for (const [field, expected] of Object.entries(input.expectation)) {
225
+ const actual = payload[field];
226
+ if (expected !== actual)
227
+ return { ok: false, reason: "binding_mismatch", message: `the receipt's ${field} does not match the envelope being applied` };
228
+ }
229
+ }
230
+ return { ok: true, payload, receipt_hash: verdict.envelope_hash, key_status: verdict.key_status };
231
+ }
232
+ export class DiscoveryReceiptServiceUnreachableError extends Error {
233
+ constructor() {
234
+ super("the discovery service is unreachable; receipt status could not be verified");
235
+ this.name = "DiscoveryReceiptServiceUnreachableError";
236
+ }
237
+ }
238
+ // The V0 default endpoint: foo-mcp-server-v0 owns the transport and identity
239
+ // stack, so every status query fails closed until it exists — callers report
240
+ // needs_service_verification and write nothing.
241
+ export function createUnreachableDiscoveryReceiptStatus() {
242
+ return {
243
+ receiptStatus: async () => {
244
+ throw new DiscoveryReceiptServiceUnreachableError();
245
+ },
246
+ };
247
+ }
248
+ function validateReceiptPayload(value) {
249
+ if (!value || typeof value !== "object" || Array.isArray(value))
250
+ return { ok: false, message: "receipt payload must be an object" };
251
+ const raw = value;
252
+ for (const key of Object.keys(raw))
253
+ if (!RECEIPT_PAYLOAD_KEYS.has(key))
254
+ return { ok: false, message: `receipt payload carries an unknown field: ${key}` };
255
+ for (const key of RECEIPT_PAYLOAD_KEYS)
256
+ if (!(key in raw))
257
+ return { ok: false, message: `receipt payload is missing ${key}` };
258
+ if (raw.kind !== "discovery_processing_receipt" || raw.receipt_version !== "v1")
259
+ return { ok: false, message: "receipt payload must be a v1 discovery_processing_receipt" };
260
+ for (const key of ["subject_ref", "workspace_ref", "connection_ref", "target_ref", "target_id", "lane", "source_fingerprint", "approval_digest", "grant_digest", "envelope_hash", "attempt_id"]) {
261
+ if (typeof raw[key] !== "string" || !raw[key].trim())
262
+ return { ok: false, message: `receipt payload ${key} must be a non-empty string` };
263
+ }
264
+ if (!CONNECTION_REF_SHAPE.test(raw.connection_ref))
265
+ return { ok: false, message: "receipt payload connection_ref must be an opaque conn: reference" };
266
+ if (!TARGET_REF_SHAPE.test(raw.target_ref))
267
+ return { ok: false, message: "receipt payload target_ref must be an opaque dtarget: reference" };
268
+ if (raw.lane !== "study" && raw.lane !== "inbox")
269
+ return { ok: false, message: "receipt payload lane must be study or inbox" };
270
+ if (!SHA256_DIGEST.test(raw.approval_digest))
271
+ return { ok: false, message: "receipt payload approval_digest must be sha256:<hex>" };
272
+ if (!SHA256_DIGEST.test(raw.envelope_hash))
273
+ return { ok: false, message: "receipt payload envelope_hash must be sha256:<hex>" };
274
+ if (typeof raw.revocation_epoch !== "number" || !Number.isInteger(raw.revocation_epoch) || raw.revocation_epoch < 0)
275
+ return { ok: false, message: "receipt payload revocation_epoch must be a non-negative integer" };
276
+ if (!ATTEMPT_ID.test(raw.attempt_id))
277
+ return { ok: false, message: "receipt payload attempt_id must be an opaque att: reference" };
278
+ const processing = raw.processing;
279
+ if (!processing || typeof processing !== "object" || Array.isArray(processing))
280
+ return { ok: false, message: "receipt payload processing must be an object" };
281
+ for (const key of Object.keys(processing))
282
+ if (!RECEIPT_PROCESSING_KEYS.has(key))
283
+ return { ok: false, message: `receipt payload processing carries an unknown field: ${key}` };
284
+ for (const key of RECEIPT_PROCESSING_KEYS)
285
+ if (typeof processing[key] !== "string" || !processing[key].trim())
286
+ return { ok: false, message: `receipt payload processing.${key} must be a non-empty string` };
287
+ const limits = raw.limits;
288
+ if (!limits || typeof limits !== "object" || Array.isArray(limits))
289
+ return { ok: false, message: "receipt payload limits must be an object" };
290
+ for (const key of Object.keys(limits))
291
+ if (!RECEIPT_LIMITS_KEYS.has(key))
292
+ return { ok: false, message: `receipt payload limits carries an unknown field: ${key}` };
293
+ for (const key of RECEIPT_LIMITS_KEYS)
294
+ if (typeof limits[key] !== "number" || limits[key] <= 0)
295
+ return { ok: false, message: `receipt payload limits.${key} must be a positive number` };
296
+ return { ok: true, payload: raw };
297
+ }
298
+ // sha256 over the canonical serialization of the sanitized envelope — the
299
+ // binding the local apply re-computes before trusting the receipt (D-014).
300
+ export function discoveryEnvelopeDigest(envelope) {
301
+ return `sha256:${createHash("sha256").update(canonicalJson(envelope), "utf8").digest("hex")}`;
302
+ }
303
+ export function discoveryGrantDigest(grant) {
304
+ return `sha256:${createHash("sha256").update(canonicalJson(grant), "utf8").digest("hex")}`;
305
+ }
306
+ const RESULT_KEYS = new Set(["schema_version", "operation", "status", "errors", "handoff", "next_actions", "coverage", "connection_ref", "target_ref", "stable_url", "envelope", "processing_receipt"]);
307
+ function closedResult(result) {
308
+ for (const key of Object.keys(result)) {
309
+ if (!RESULT_KEYS.has(key))
310
+ throw new Error(`discovery service result carries a field outside the closed contract: ${key}`);
311
+ }
312
+ return result;
313
+ }
314
+ function coverage(counts, extras = {}) {
315
+ return {
316
+ provider_metadata_probes: counts.metadata,
317
+ transcript_body_calls: counts.body,
318
+ synthesis_requests: counts.synthesis,
319
+ receipts_issued: counts.receipts,
320
+ raw_content_retained: false,
321
+ ...(extras.attempt_id ? { attempt_id: extras.attempt_id } : {}),
322
+ ...(extras.recorded_attempt_state ? { recorded_attempt_state: extras.recorded_attempt_state } : {}),
323
+ };
324
+ }
325
+ function failureOf(code, message, trace_id) {
326
+ return [{ code, message, trace_id }];
327
+ }
328
+ function withTimeout(promise, timeout_ms) {
329
+ return new Promise((resolve, reject) => {
330
+ const timer = setTimeout(() => reject(new DiscoveryTranscriptTimeoutError(timeout_ms)), timeout_ms);
331
+ if (typeof timer.unref === "function")
332
+ timer.unref();
333
+ promise.then((value) => {
334
+ clearTimeout(timer);
335
+ resolve(value);
336
+ }, (error) => {
337
+ clearTimeout(timer);
338
+ reject(error);
339
+ });
340
+ });
341
+ }
342
+ export async function processDiscoverySession(input, deps) {
343
+ const counts = { metadata: 0, body: 0, synthesis: 0, receipts: 0 };
344
+ const trace = `tr:${randomBytes(8).toString("hex")}`;
345
+ const attempt_id = input.attempt_id ?? `att:${randomBytes(16).toString("hex")}`;
346
+ const common = { connection_ref: input.connection_ref, target_ref: input.target_ref };
347
+ const base = coverage(counts, { attempt_id });
348
+ const shapeFailure = (message, code = "service_bug", status = "invalid", recorded = undefined) => closedResult({
349
+ schema_version: "0.1",
350
+ operation: "discovery_process_session",
351
+ status,
352
+ errors: failureOf(code, message, trace),
353
+ handoff: null,
354
+ next_actions: [],
355
+ coverage: recorded ? coverage(counts, recorded) : base,
356
+ ...common,
357
+ });
358
+ // 1. Shape gate — malformed requests cost zero provider calls and zero
359
+ // ledger rows.
360
+ if (!input.subject_ref?.trim())
361
+ return shapeFailure("subject_ref is required");
362
+ if (!input.workspace_ref?.trim())
363
+ return shapeFailure("workspace_ref is required");
364
+ if (!CONNECTION_REF_SHAPE.test(input.connection_ref ?? ""))
365
+ return shapeFailure("connection_ref must be an opaque conn: reference");
366
+ if (!TARGET_REF_SHAPE.test(input.target_ref ?? ""))
367
+ return shapeFailure("target_ref must be an opaque dtarget: reference");
368
+ if (!ATTEMPT_ID.test(attempt_id))
369
+ return shapeFailure("attempt_id must be an opaque att: reference");
370
+ // 2. Connection gate. Unreachability is never dressed up as a state.
371
+ let connection;
372
+ try {
373
+ connection = await deps.service.connectionState({ subject_ref: input.subject_ref, connection_ref: input.connection_ref });
374
+ }
375
+ catch {
376
+ return closedResult({
377
+ ...shapeFailure("the discovery service is unreachable; hosted state is unchanged", "network"),
378
+ status: "needs_service_verification",
379
+ });
380
+ }
381
+ if (connection.state === "revoked")
382
+ return shapeFailure("the connection has been revoked", "access_denied");
383
+ if (connection.state === "auth_expired")
384
+ return shapeFailure("the connection's credentials have expired; reconnect the provider", "auth_expired");
385
+ if (connection.state === "not_connected")
386
+ return shapeFailure("the connection is not established for this subject", "not_connected");
387
+ if (!connection.canonical_connection_key.trim())
388
+ return shapeFailure("the connected connection carries no canonical key");
389
+ // 3. Session-reference gate: open, then bind every identity the ref claims.
390
+ const opened = openDiscoverySessionRef(input.session_ref, deps.keys.session_ref_key, deps.now);
391
+ if (!opened.ok)
392
+ return shapeFailure(`the session reference could not be opened (${opened.reason})`, "access_denied");
393
+ const ref = opened.payload;
394
+ if (ref.subject_ref !== input.subject_ref)
395
+ return shapeFailure("the session reference belongs to a different subject", "access_denied");
396
+ if (ref.target_ref !== input.target_ref)
397
+ return shapeFailure("the session reference does not belong to this target", "access_denied");
398
+ if (ref.provider !== deps.source.provider)
399
+ return shapeFailure("the session reference cannot be processed through this provider source", "access_denied");
400
+ if (input.revocation_epoch > ref.revocation_epoch) {
401
+ return closedResult({
402
+ ...shapeFailure("the session reference predates a local revocation", "approval_missing"),
403
+ status: "revoked",
404
+ next_actions: ["Re-approve the source and re-register the target if hosted reads are wanted again."],
405
+ });
406
+ }
407
+ if (input.revocation_epoch < ref.revocation_epoch)
408
+ return shapeFailure("the session reference carries a revocation epoch from another ledger", "access_denied");
409
+ if (ref.canonical_connection_key !== connection.canonical_connection_key) {
410
+ return shapeFailure("the session reference does not belong to this connection", "access_denied");
411
+ }
412
+ const recomputedFingerprint = hostedDiscoverySourceFingerprint({ subject_ref: ref.subject_ref, provider: ref.provider, canonical_connection_key: ref.canonical_connection_key, provider_session_identity: ref.provider_session_identity }, deps.keys.source_fingerprint_key);
413
+ if (recomputedFingerprint !== ref.hosted_source_fingerprint)
414
+ return shapeFailure("the session reference failed source-identity verification", "access_denied");
415
+ // 4. Grant lookup + boundary recheck (R-008): subject, workspace, target,
416
+ // lane, connection, CURRENT approval digest and revocation epoch, expiry,
417
+ // and budget — first mismatch wins, all before any provider call.
418
+ let lookup;
419
+ try {
420
+ lookup = await deps.service.grantForTarget({ subject_ref: input.subject_ref, target_ref: input.target_ref });
421
+ }
422
+ catch {
423
+ return closedResult({
424
+ ...shapeFailure("the discovery service is unreachable; hosted state is unchanged", "network"),
425
+ status: "needs_service_verification",
426
+ });
427
+ }
428
+ const expected = {
429
+ subject_ref: input.subject_ref,
430
+ connection_ref: input.connection_ref,
431
+ workspace_ref: input.workspace_ref,
432
+ target_id: lookup.grant?.target_id ?? "",
433
+ lane: lookup.grant?.lane ?? "study",
434
+ approval_digest: input.approval_digest,
435
+ revocation_epoch: input.revocation_epoch,
436
+ };
437
+ const boundary = recheckDiscoveryAccessBoundary({ grant: lookup.grant, expected, operations_used: lookup.operations_used, now: deps.now });
438
+ if (!boundary.ok) {
439
+ const mapped = boundaryFailureFor(boundary.reason);
440
+ return closedResult({
441
+ ...shapeFailure(mapped.message, mapped.code),
442
+ status: mapped.status,
443
+ next_actions: [mapped.resume],
444
+ });
445
+ }
446
+ const grant = lookup.grant;
447
+ if (ref.grant_digest !== grant.approval_digest) {
448
+ return closedResult({
449
+ ...shapeFailure("the session reference was not minted under the target's current grant", "approval_missing"),
450
+ status: "needs_service_grant",
451
+ next_actions: ["List the source again under the confirmed target to mint a fresh session reference."],
452
+ });
453
+ }
454
+ // 5. Study-hypothesis gate. Study-linked synthesis must bind every finding
455
+ // to a pre-existing hypothesis; without them the operation refuses before
456
+ // spending the fetch.
457
+ const evidenceLane = grant.lane === "study" ? "study_linked" : "unassigned_call_evidence";
458
+ let hypotheses = [];
459
+ if (grant.lane === "study") {
460
+ hypotheses = await deps.service.studyHypotheses({ subject_ref: input.subject_ref, target_ref: input.target_ref });
461
+ if (hypotheses.length === 0)
462
+ return shapeFailure("the study target has no recorded hypotheses; study-linked synthesis cannot bind findings", "service_bug");
463
+ }
464
+ // 6. Pre-fetch recheck (revocation may have landed between the grant lookup
465
+ // and now), then the at-most-once claim, then the budget spend. A repeat
466
+ // claim returns result_lost with the recorded state and zero provider calls.
467
+ const preFetch = recheckDiscoveryAccessBoundary({ grant: lookup.grant, expected, operations_used: lookup.operations_used, now: deps.now });
468
+ if (!preFetch.ok) {
469
+ const mapped = boundaryFailureFor(preFetch.reason);
470
+ return closedResult({
471
+ ...shapeFailure(mapped.message, mapped.code),
472
+ status: mapped.status,
473
+ next_actions: [mapped.resume],
474
+ });
475
+ }
476
+ const claim = deps.ledger.beginAttempt({
477
+ subject_ref: input.subject_ref,
478
+ target_ref: input.target_ref,
479
+ source_fingerprint: ref.hosted_source_fingerprint,
480
+ processing_version: PROCESSING_VERSION,
481
+ attempt_id,
482
+ });
483
+ if (!claim.accepted) {
484
+ return closedResult({
485
+ ...shapeFailure(`this source was already processed in attempt ${claim.existing_state === "receipt_issued" ? "and its receipt was issued" : "whose result was not delivered"}; productfoo never re-runs a claimed attempt or recovers a lost result`, "network"),
486
+ status: "result_lost",
487
+ coverage: coverage(counts, { attempt_id, recorded_attempt_state: claim.existing_state }),
488
+ });
489
+ }
490
+ deps.service.recordOperation(input.target_ref);
491
+ // 7. Capability probe — a metadata observation, never a body call.
492
+ counts.metadata += 1;
493
+ const observed = await deps.source.observeConnection({ subject_ref: input.subject_ref, connection_ref: input.connection_ref });
494
+ if (observed.state !== "connected") {
495
+ deps.ledger.finishAttempt(attempt_id, "lost");
496
+ const status = observed.state === "revoked" ? "revoked" : observed.state === "auth_expired" ? "auth_expired" : "not_connected";
497
+ return closedResult({
498
+ ...shapeFailure(`the connection is no longer connected for processing (${observed.state})`, "access_denied", "invalid", { attempt_id, recorded_attempt_state: "lost" }),
499
+ status,
500
+ });
501
+ }
502
+ if (!observed.capabilities.open_transcript) {
503
+ deps.ledger.finishAttempt(attempt_id, "lost");
504
+ return closedResult({
505
+ ...shapeFailure("the connection's observed capabilities do not include transcript access", "capability_missing", "needs_provider_access", { attempt_id, recorded_attempt_state: "lost" }),
506
+ status: "needs_provider_access",
507
+ next_actions: ["Connect a provider plan that includes transcript access, then retry."],
508
+ });
509
+ }
510
+ // 8. THE one transcript fetch — the operation's only body call, behind the
511
+ // guarded boundary, with the versioned ceilings enforced in-band.
512
+ counts.body += 1;
513
+ let fetched;
514
+ try {
515
+ fetched = await withTimeout(guardedDiscoveryAccess(preFetch, () => deps.source.fetchTranscript({
516
+ subject_ref: input.subject_ref,
517
+ provider_session_identity: ref.provider_session_identity,
518
+ limits: DISCOVERY_PROCESSING_LIMITS,
519
+ })), DISCOVERY_PROCESSING_LIMITS.fetch_timeout_ms);
520
+ }
521
+ catch (error) {
522
+ deps.ledger.finishAttempt(attempt_id, "lost");
523
+ if (error instanceof DiscoveryTranscriptOversizeError)
524
+ return shapeFailure("the transcript response exceeded the policy ceiling; nothing was retained", "provider_failure", "transcript_too_large", { attempt_id, recorded_attempt_state: "lost" });
525
+ if (error instanceof DiscoveryTranscriptTimeoutError)
526
+ return shapeFailure("the transcript fetch exceeded the policy ceiling; nothing was retained", "provider_failure", "provider_timeout", { attempt_id, recorded_attempt_state: "lost" });
527
+ if (error instanceof DiscoveryTranscriptCancelledError)
528
+ return shapeFailure("the transcript fetch was cancelled before completion; nothing was retained", "provider_failure", "invalid", { attempt_id, recorded_attempt_state: "lost" });
529
+ return shapeFailure("the transcript fetch failed; nothing was retained", "provider_failure", "invalid", { attempt_id, recorded_attempt_state: "lost" });
530
+ }
531
+ // Ceiling re-verification before synthesis or release — the module enforces
532
+ // the policy itself, independent of what the seam reports.
533
+ if (Buffer.byteLength(fetched.transcript_text, "utf8") > DISCOVERY_PROCESSING_LIMITS.max_response_bytes) {
534
+ deps.ledger.finishAttempt(attempt_id, "lost");
535
+ return shapeFailure("the transcript response exceeded the policy ceiling; nothing was retained", "provider_failure", "transcript_too_large", { attempt_id, recorded_attempt_state: "lost" });
536
+ }
537
+ const estimatedTokens = Math.ceil(fetched.transcript_text.length / 4);
538
+ if (estimatedTokens > DISCOVERY_PROCESSING_LIMITS.max_model_input_tokens) {
539
+ deps.ledger.finishAttempt(attempt_id, "lost");
540
+ return shapeFailure("the transcript exceeds the model-input-token ceiling; nothing was retained", "provider_failure", "transcript_too_large", { attempt_id, recorded_attempt_state: "lost" });
541
+ }
542
+ if (!Number.isFinite(Date.parse(fetched.completed_at))) {
543
+ deps.ledger.finishAttempt(attempt_id, "lost");
544
+ return shapeFailure("the transcript fetch reported an unusable completion time", "service_bug");
545
+ }
546
+ // 9. Untrusted-text synthesis behind the isolated processor seam.
547
+ let stableUrl;
548
+ const caveats = [];
549
+ if (fetched.stable_url !== undefined) {
550
+ try {
551
+ stableUrl = sanitizeDiscoveryStableUrl(deps.source.provider, fetched.stable_url);
552
+ }
553
+ catch {
554
+ stableUrl = undefined;
555
+ caveats.push("The provider's stable link failed sanitization and was not attached.");
556
+ }
557
+ }
558
+ const locatorCapability = observed.capabilities.timestamps ? "timestamp" : "none";
559
+ if (!stableUrl)
560
+ caveats.push(NO_STABLE_LINK_CAVEAT);
561
+ if (locatorCapability === "none")
562
+ caveats.push(NO_TIMESTAMPS_CAVEAT);
563
+ const synthesisInput = {
564
+ target_id: grant.target_id,
565
+ lane: evidenceLane,
566
+ source: {
567
+ provider: ref.provider,
568
+ ...(stableUrl ? { stable_url: stableUrl } : {}),
569
+ source_fingerprint: ref.hosted_source_fingerprint,
570
+ completed_at: fetched.completed_at,
571
+ locator_capability: locatorCapability,
572
+ },
573
+ title: "",
574
+ hypotheses,
575
+ transcript_text: fetched.transcript_text,
576
+ transcript_complete: fetched.transcript_complete,
577
+ caveats,
578
+ };
579
+ counts.synthesis += 1;
580
+ let rawOutput;
581
+ try {
582
+ rawOutput = (await deps.processor.process({ system: SYNTHESIS_SYSTEM_PROMPT, prompt: synthesisUserMessage(synthesisInput), max_output_tokens: SYNTHESIS_MAX_OUTPUT_TOKENS })).raw_output;
583
+ }
584
+ catch {
585
+ deps.ledger.finishAttempt(attempt_id, "lost");
586
+ return shapeFailure(UNTRUSTED_FAILURE, "service_bug", "invalid", { attempt_id, recorded_attempt_state: "lost" });
587
+ }
588
+ // 10. Raw disposal + deterministic reduction and screening. The transcript
589
+ // and the raw processor output are dropped here; nothing downstream of this
590
+ // block ever sees them.
591
+ let envelope;
592
+ let parsed;
593
+ try {
594
+ parsed = extractSynthesisJsonObject(rawOutput);
595
+ }
596
+ catch {
597
+ // JSON.parse errors can quote input fragments — the fixed message keeps
598
+ // them off the result surface.
599
+ deps.ledger.finishAttempt(attempt_id, "lost");
600
+ return shapeFailure(UNPARSEABLE_FAILURE, "service_bug", "invalid", { attempt_id, recorded_attempt_state: "lost" });
601
+ }
602
+ try {
603
+ const context = { expected_study_id: grant.target_id, expected_lane: evidenceLane };
604
+ envelope = screenDiscoveryServiceEnvelope(constructEnvelopeFromSynthesis(synthesisInput, parsed), context);
605
+ }
606
+ catch (error) {
607
+ // Reduction and screening failures are fixed-vocabulary messages (no
608
+ // content) — safe to surface verbatim.
609
+ deps.ledger.finishAttempt(attempt_id, "lost");
610
+ return shapeFailure(`${SCREEN_FAILURE}: ${error.message}`, "service_bug", "invalid", { attempt_id, recorded_attempt_state: "lost" });
611
+ }
612
+ fetched = null;
613
+ rawOutput = "";
614
+ // 11. Post-screen recheck: authorization must still hold at release time.
615
+ let postLookup;
616
+ try {
617
+ postLookup = await deps.service.grantForTarget({ subject_ref: input.subject_ref, target_ref: input.target_ref });
618
+ }
619
+ catch {
620
+ deps.ledger.finishAttempt(attempt_id, "lost");
621
+ return closedResult({
622
+ ...shapeFailure("the discovery service is unreachable; hosted state is unchanged", "network"),
623
+ status: "needs_service_verification",
624
+ coverage: coverage(counts, { attempt_id, recorded_attempt_state: "lost" }),
625
+ });
626
+ }
627
+ const postCheck = recheckDiscoveryAccessBoundary({ grant: postLookup.grant, expected, operations_used: Math.max(postLookup.operations_used - 1, 0), now: deps.now });
628
+ if (!postCheck.ok) {
629
+ deps.ledger.finishAttempt(attempt_id, "lost");
630
+ const mapped = boundaryFailureFor(postCheck.reason);
631
+ return closedResult({
632
+ ...shapeFailure(mapped.message, mapped.code, "invalid", { attempt_id, recorded_attempt_state: "lost" }),
633
+ status: mapped.status,
634
+ next_actions: [mapped.resume],
635
+ });
636
+ }
637
+ // 12. Signed payload-free receipt + at-most-once finish.
638
+ counts.receipts += 1;
639
+ const issuedAt = new Date(deps.now).toISOString();
640
+ const receipt = deps.signer.signReceipt({
641
+ payload: {
642
+ kind: "discovery_processing_receipt",
643
+ receipt_version: RECEIPT_VERSION,
644
+ subject_ref: input.subject_ref,
645
+ workspace_ref: input.workspace_ref,
646
+ connection_ref: input.connection_ref,
647
+ target_ref: input.target_ref,
648
+ target_id: grant.target_id,
649
+ lane: grant.lane,
650
+ source_fingerprint: ref.hosted_source_fingerprint,
651
+ approval_digest: input.approval_digest,
652
+ grant_digest: ref.grant_digest,
653
+ revocation_epoch: input.revocation_epoch,
654
+ envelope_hash: discoveryEnvelopeDigest(envelope),
655
+ attempt_id,
656
+ processing: {
657
+ processing_version: PROCESSING_VERSION,
658
+ prompt_version: PROMPT_VERSION,
659
+ policy_version: DISCOVERY_SERVICE_POLICY.policy_version,
660
+ synthesizer_model: deps.processor.synthesizer_model,
661
+ envelope_schema_version: "0.1",
662
+ },
663
+ limits: { ...DISCOVERY_PROCESSING_LIMITS },
664
+ },
665
+ issued_at: issuedAt,
666
+ expires_at: new Date(Date.parse(deps.now) + RECEIPT_TTL_MS).toISOString(),
667
+ });
668
+ deps.ledger.finishAttempt(attempt_id, "receipt_issued");
669
+ const success = closedResult({
670
+ schema_version: "0.1",
671
+ operation: "discovery_process_session",
672
+ status: "processed",
673
+ errors: [],
674
+ handoff: null,
675
+ next_actions: ["Review the evidence and apply it in the local productfoo workspace; the receipt verifies at apply time."],
676
+ coverage: coverage(counts, { attempt_id, recorded_attempt_state: "receipt_issued" }),
677
+ ...common,
678
+ ...(stableUrl ? { stable_url: stableUrl } : {}),
679
+ envelope,
680
+ processing_receipt: receipt,
681
+ });
682
+ // 13. Delivery seam: a lost success response is reported result_lost and
683
+ // never recovered (D-013) — the receipt stays issued in the ledger, and no
684
+ // envelope rides the loss.
685
+ if (deps.delivery) {
686
+ try {
687
+ return await deps.delivery(success);
688
+ }
689
+ catch {
690
+ return closedResult({
691
+ schema_version: "0.1",
692
+ operation: "discovery_process_session",
693
+ status: "result_lost",
694
+ errors: failureOf("network", "the processing result could not be delivered; productfoo never re-runs a claimed attempt or recovers a lost result", trace),
695
+ handoff: null,
696
+ next_actions: [],
697
+ coverage: coverage(counts, { attempt_id, recorded_attempt_state: "receipt_issued" }),
698
+ ...common,
699
+ });
700
+ }
701
+ }
702
+ return success;
703
+ }