tracegrove 0.0.0-stage → 0.3.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 (721) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +588 -2
  3. package/conformance/coordination-vectors.json +377 -0
  4. package/dist/adapters/browser/capabilities.d.ts +45 -0
  5. package/dist/adapters/browser/capabilities.js +14 -0
  6. package/dist/adapters/browser/capabilities.js.map +1 -0
  7. package/dist/adapters/browser/driver.d.ts +45 -0
  8. package/dist/adapters/browser/driver.js +295 -0
  9. package/dist/adapters/browser/driver.js.map +1 -0
  10. package/dist/adapters/browser/session.d.ts +21 -0
  11. package/dist/adapters/browser/session.js +87 -0
  12. package/dist/adapters/browser/session.js.map +1 -0
  13. package/dist/adapters/http/capabilities.d.ts +2 -0
  14. package/dist/adapters/http/capabilities.js +21 -0
  15. package/dist/adapters/http/capabilities.js.map +1 -0
  16. package/dist/adapters/http/driver.d.ts +55 -0
  17. package/dist/adapters/http/driver.js +125 -0
  18. package/dist/adapters/http/driver.js.map +1 -0
  19. package/dist/adapters/job/capabilities.d.ts +45 -0
  20. package/dist/adapters/job/capabilities.js +8 -0
  21. package/dist/adapters/job/capabilities.js.map +1 -0
  22. package/dist/adapters/job/driver.d.ts +26 -0
  23. package/dist/adapters/job/driver.js +110 -0
  24. package/dist/adapters/job/driver.js.map +1 -0
  25. package/dist/adapters/job/types.d.ts +9 -0
  26. package/dist/adapters/job/types.js +2 -0
  27. package/dist/adapters/job/types.js.map +1 -0
  28. package/dist/adapters/mcp/capabilities.d.ts +46 -0
  29. package/dist/adapters/mcp/capabilities.js +17 -0
  30. package/dist/adapters/mcp/capabilities.js.map +1 -0
  31. package/dist/adapters/mcp/driver.d.ts +10 -0
  32. package/dist/adapters/mcp/driver.js +83 -0
  33. package/dist/adapters/mcp/driver.js.map +1 -0
  34. package/dist/adapters/poll.d.ts +12 -0
  35. package/dist/adapters/poll.js +31 -0
  36. package/dist/adapters/poll.js.map +1 -0
  37. package/dist/authoring/activity.d.ts +17 -0
  38. package/dist/authoring/activity.js +18 -0
  39. package/dist/authoring/activity.js.map +1 -0
  40. package/dist/authoring/agent.d.ts +70 -0
  41. package/dist/authoring/agent.js +268 -0
  42. package/dist/authoring/agent.js.map +1 -0
  43. package/dist/authoring/appLaunch.d.ts +7 -0
  44. package/dist/authoring/appLaunch.js +32 -0
  45. package/dist/authoring/appLaunch.js.map +1 -0
  46. package/dist/authoring/appLocation.d.ts +2 -0
  47. package/dist/authoring/appLocation.js +5 -0
  48. package/dist/authoring/appLocation.js.map +1 -0
  49. package/dist/authoring/browser.d.ts +15 -0
  50. package/dist/authoring/browser.js +20 -0
  51. package/dist/authoring/browser.js.map +1 -0
  52. package/dist/authoring/compile.d.ts +47 -0
  53. package/dist/authoring/compile.js +508 -0
  54. package/dist/authoring/compile.js.map +1 -0
  55. package/dist/authoring/discover.d.ts +43 -0
  56. package/dist/authoring/discover.js +149 -0
  57. package/dist/authoring/discover.js.map +1 -0
  58. package/dist/authoring/environmentTemplates.d.ts +3 -0
  59. package/dist/authoring/environmentTemplates.js +24 -0
  60. package/dist/authoring/environmentTemplates.js.map +1 -0
  61. package/dist/authoring/heal.d.ts +108 -0
  62. package/dist/authoring/heal.js +723 -0
  63. package/dist/authoring/heal.js.map +1 -0
  64. package/dist/authoring/index.d.ts +14 -0
  65. package/dist/authoring/index.js +15 -0
  66. package/dist/authoring/index.js.map +1 -0
  67. package/dist/authoring/init.d.ts +21 -0
  68. package/dist/authoring/init.js +141 -0
  69. package/dist/authoring/init.js.map +1 -0
  70. package/dist/authoring/localSettings.d.ts +33 -0
  71. package/dist/authoring/localSettings.js +31 -0
  72. package/dist/authoring/localSettings.js.map +1 -0
  73. package/dist/authoring/media.d.ts +10 -0
  74. package/dist/authoring/media.js +37 -0
  75. package/dist/authoring/media.js.map +1 -0
  76. package/dist/authoring/module.d.ts +2 -0
  77. package/dist/authoring/module.js +38 -0
  78. package/dist/authoring/module.js.map +1 -0
  79. package/dist/authoring/run.d.ts +74 -0
  80. package/dist/authoring/run.js +242 -0
  81. package/dist/authoring/run.js.map +1 -0
  82. package/dist/authoring/runSource.d.ts +6 -0
  83. package/dist/authoring/runSource.js +24 -0
  84. package/dist/authoring/runSource.js.map +1 -0
  85. package/dist/authoring/savedRun.d.ts +13 -0
  86. package/dist/authoring/savedRun.js +94 -0
  87. package/dist/authoring/savedRun.js.map +1 -0
  88. package/dist/authoring/schema.d.ts +574 -0
  89. package/dist/authoring/schema.js +147 -0
  90. package/dist/authoring/schema.js.map +1 -0
  91. package/dist/authoring/snapshotSource.d.ts +13 -0
  92. package/dist/authoring/snapshotSource.js +41 -0
  93. package/dist/authoring/snapshotSource.js.map +1 -0
  94. package/dist/authoring/sourceSelection.d.ts +34 -0
  95. package/dist/authoring/sourceSelection.js +13 -0
  96. package/dist/authoring/sourceSelection.js.map +1 -0
  97. package/dist/authoring/sources.d.ts +5 -0
  98. package/dist/authoring/sources.js +65 -0
  99. package/dist/authoring/sources.js.map +1 -0
  100. package/dist/authoring/status.d.ts +48 -0
  101. package/dist/authoring/status.js +100 -0
  102. package/dist/authoring/status.js.map +1 -0
  103. package/dist/authoring/typed.d.ts +6 -0
  104. package/dist/authoring/typed.js +5 -0
  105. package/dist/authoring/typed.js.map +1 -0
  106. package/dist/authoring/ui.d.ts +10 -0
  107. package/dist/authoring/ui.js +486 -0
  108. package/dist/authoring/ui.js.map +1 -0
  109. package/dist/authoring/uiPage.d.ts +1 -0
  110. package/dist/authoring/uiPage.js +358 -0
  111. package/dist/authoring/uiPage.js.map +1 -0
  112. package/dist/authoring/uiSourceControls.d.ts +2 -0
  113. package/dist/authoring/uiSourceControls.js +41 -0
  114. package/dist/authoring/uiSourceControls.js.map +1 -0
  115. package/dist/authoring/verificationSource.d.ts +41 -0
  116. package/dist/authoring/verificationSource.js +46 -0
  117. package/dist/authoring/verificationSource.js.map +1 -0
  118. package/dist/authoring/workspace.d.ts +33 -0
  119. package/dist/authoring/workspace.js +58 -0
  120. package/dist/authoring/workspace.js.map +1 -0
  121. package/dist/cli/arguments.d.ts +288 -0
  122. package/dist/cli/arguments.js +121 -0
  123. package/dist/cli/arguments.js.map +1 -0
  124. package/dist/cli/cleanup.d.ts +18 -0
  125. package/dist/cli/cleanup.js +40 -0
  126. package/dist/cli/cleanup.js.map +1 -0
  127. package/dist/cli/doctor.d.ts +51 -0
  128. package/dist/cli/doctor.js +118 -0
  129. package/dist/cli/doctor.js.map +1 -0
  130. package/dist/cli/errors.d.ts +2 -0
  131. package/dist/cli/errors.js +84 -0
  132. package/dist/cli/errors.js.map +1 -0
  133. package/dist/cli/jsonFile.d.ts +2 -0
  134. package/dist/cli/jsonFile.js +15 -0
  135. package/dist/cli/jsonFile.js.map +1 -0
  136. package/dist/cli/main.d.ts +2 -0
  137. package/dist/cli/main.js +603 -0
  138. package/dist/cli/main.js.map +1 -0
  139. package/dist/cli/render.d.ts +22 -0
  140. package/dist/cli/render.js +150 -0
  141. package/dist/cli/render.js.map +1 -0
  142. package/dist/cli/samples/catalog.d.ts +10 -0
  143. package/dist/cli/samples/catalog.js +3 -0
  144. package/dist/cli/samples/catalog.js.map +1 -0
  145. package/dist/cli/samples/write.d.ts +5 -0
  146. package/dist/cli/samples/write.js +64 -0
  147. package/dist/cli/samples/write.js.map +1 -0
  148. package/dist/cli/source.d.ts +41 -0
  149. package/dist/cli/source.js +59 -0
  150. package/dist/cli/source.js.map +1 -0
  151. package/dist/core/activationDecision.d.ts +153 -0
  152. package/dist/core/activationDecision.js +34 -0
  153. package/dist/core/activationDecision.js.map +1 -0
  154. package/dist/core/artifacts.d.ts +18 -0
  155. package/dist/core/artifacts.js +79 -0
  156. package/dist/core/artifacts.js.map +1 -0
  157. package/dist/core/atomicFiles.d.ts +9 -0
  158. package/dist/core/atomicFiles.js +76 -0
  159. package/dist/core/atomicFiles.js.map +1 -0
  160. package/dist/core/boundedFile.d.ts +2 -0
  161. package/dist/core/boundedFile.js +28 -0
  162. package/dist/core/boundedFile.js.map +1 -0
  163. package/dist/core/bundle.d.ts +77 -0
  164. package/dist/core/bundle.js +375 -0
  165. package/dist/core/bundle.js.map +1 -0
  166. package/dist/core/bundleArchive.d.ts +10 -0
  167. package/dist/core/bundleArchive.js +47 -0
  168. package/dist/core/bundleArchive.js.map +1 -0
  169. package/dist/core/bundleEvidence.d.ts +12 -0
  170. package/dist/core/bundleEvidence.js +169 -0
  171. package/dist/core/bundleEvidence.js.map +1 -0
  172. package/dist/core/bundleExport.d.ts +12 -0
  173. package/dist/core/bundleExport.js +36 -0
  174. package/dist/core/bundleExport.js.map +1 -0
  175. package/dist/core/bundleFiles.d.ts +5 -0
  176. package/dist/core/bundleFiles.js +47 -0
  177. package/dist/core/bundleFiles.js.map +1 -0
  178. package/dist/core/bundlePaths.d.ts +2 -0
  179. package/dist/core/bundlePaths.js +7 -0
  180. package/dist/core/bundlePaths.js.map +1 -0
  181. package/dist/core/bundleSnapshot.d.ts +26 -0
  182. package/dist/core/bundleSnapshot.js +71 -0
  183. package/dist/core/bundleSnapshot.js.map +1 -0
  184. package/dist/core/capabilityBoundary.d.ts +1452 -0
  185. package/dist/core/capabilityBoundary.js +361 -0
  186. package/dist/core/capabilityBoundary.js.map +1 -0
  187. package/dist/core/capabilityLifecycle.d.ts +366 -0
  188. package/dist/core/capabilityLifecycle.js +79 -0
  189. package/dist/core/capabilityLifecycle.js.map +1 -0
  190. package/dist/core/cleanup.d.ts +35 -0
  191. package/dist/core/cleanup.js +71 -0
  192. package/dist/core/cleanup.js.map +1 -0
  193. package/dist/core/cleanupActions.d.ts +5 -0
  194. package/dist/core/cleanupActions.js +15 -0
  195. package/dist/core/cleanupActions.js.map +1 -0
  196. package/dist/core/cleanupAttestation.d.ts +23 -0
  197. package/dist/core/cleanupAttestation.js +57 -0
  198. package/dist/core/cleanupAttestation.js.map +1 -0
  199. package/dist/core/clock.d.ts +4 -0
  200. package/dist/core/clock.js +14 -0
  201. package/dist/core/clock.js.map +1 -0
  202. package/dist/core/compiler.d.ts +19 -0
  203. package/dist/core/compiler.js +200 -0
  204. package/dist/core/compiler.js.map +1 -0
  205. package/dist/core/controller.d.ts +7 -0
  206. package/dist/core/controller.js +132 -0
  207. package/dist/core/controller.js.map +1 -0
  208. package/dist/core/coordination.d.ts +72 -0
  209. package/dist/core/coordination.js +118 -0
  210. package/dist/core/coordination.js.map +1 -0
  211. package/dist/core/corpus.d.ts +60 -0
  212. package/dist/core/corpus.js +216 -0
  213. package/dist/core/corpus.js.map +1 -0
  214. package/dist/core/deadline.d.ts +12 -0
  215. package/dist/core/deadline.js +38 -0
  216. package/dist/core/deadline.js.map +1 -0
  217. package/dist/core/deliveryJournal.d.ts +37 -0
  218. package/dist/core/deliveryJournal.js +85 -0
  219. package/dist/core/deliveryJournal.js.map +1 -0
  220. package/dist/core/environmentPreflight.d.ts +14 -0
  221. package/dist/core/environmentPreflight.js +179 -0
  222. package/dist/core/environmentPreflight.js.map +1 -0
  223. package/dist/core/errors.d.ts +22 -0
  224. package/dist/core/errors.js +29 -0
  225. package/dist/core/errors.js.map +1 -0
  226. package/dist/core/events.d.ts +14 -0
  227. package/dist/core/events.js +37 -0
  228. package/dist/core/events.js.map +1 -0
  229. package/dist/core/executionInspection.d.ts +90 -0
  230. package/dist/core/executionInspection.js +31 -0
  231. package/dist/core/executionInspection.js.map +1 -0
  232. package/dist/core/executionOwnership.d.ts +72 -0
  233. package/dist/core/executionOwnership.js +82 -0
  234. package/dist/core/executionOwnership.js.map +1 -0
  235. package/dist/core/executionPreparation.d.ts +362 -0
  236. package/dist/core/executionPreparation.js +93 -0
  237. package/dist/core/executionPreparation.js.map +1 -0
  238. package/dist/core/executionReadback.d.ts +15 -0
  239. package/dist/core/executionReadback.js +21 -0
  240. package/dist/core/executionReadback.js.map +1 -0
  241. package/dist/core/executor.d.ts +46 -0
  242. package/dist/core/executor.js +616 -0
  243. package/dist/core/executor.js.map +1 -0
  244. package/dist/core/frozenBundle.d.ts +314 -0
  245. package/dist/core/frozenBundle.js +24 -0
  246. package/dist/core/frozenBundle.js.map +1 -0
  247. package/dist/core/fsDurability.d.ts +2 -0
  248. package/dist/core/fsDurability.js +12 -0
  249. package/dist/core/fsDurability.js.map +1 -0
  250. package/dist/core/generators.d.ts +4 -0
  251. package/dist/core/generators.js +71 -0
  252. package/dist/core/generators.js.map +1 -0
  253. package/dist/core/gitSnapshot.d.ts +63 -0
  254. package/dist/core/gitSnapshot.js +55 -0
  255. package/dist/core/gitSnapshot.js.map +1 -0
  256. package/dist/core/gitSources.d.ts +29 -0
  257. package/dist/core/gitSources.js +97 -0
  258. package/dist/core/gitSources.js.map +1 -0
  259. package/dist/core/ledger.d.ts +38 -0
  260. package/dist/core/ledger.js +169 -0
  261. package/dist/core/ledger.js.map +1 -0
  262. package/dist/core/ledgerInspection.d.ts +18 -0
  263. package/dist/core/ledgerInspection.js +66 -0
  264. package/dist/core/ledgerInspection.js.map +1 -0
  265. package/dist/core/ledgerRecords.d.ts +23 -0
  266. package/dist/core/ledgerRecords.js +29 -0
  267. package/dist/core/ledgerRecords.js.map +1 -0
  268. package/dist/core/localActivationState.d.ts +260 -0
  269. package/dist/core/localActivationState.js +49 -0
  270. package/dist/core/localActivationState.js.map +1 -0
  271. package/dist/core/localPromotionState.d.ts +387 -0
  272. package/dist/core/localPromotionState.js +22 -0
  273. package/dist/core/localPromotionState.js.map +1 -0
  274. package/dist/core/localQualificationResults.d.ts +39 -0
  275. package/dist/core/localQualificationResults.js +160 -0
  276. package/dist/core/localQualificationResults.js.map +1 -0
  277. package/dist/core/localReviewStore.d.ts +28 -0
  278. package/dist/core/localReviewStore.js +167 -0
  279. package/dist/core/localReviewStore.js.map +1 -0
  280. package/dist/core/localScenarioActivation.d.ts +6 -0
  281. package/dist/core/localScenarioActivation.js +70 -0
  282. package/dist/core/localScenarioActivation.js.map +1 -0
  283. package/dist/core/localScenarioOwner.d.ts +20 -0
  284. package/dist/core/localScenarioOwner.js +2 -0
  285. package/dist/core/localScenarioOwner.js.map +1 -0
  286. package/dist/core/localScenarioPromotion.d.ts +9 -0
  287. package/dist/core/localScenarioPromotion.js +49 -0
  288. package/dist/core/localScenarioPromotion.js.map +1 -0
  289. package/dist/core/localScenarioState.d.ts +2297 -0
  290. package/dist/core/localScenarioState.js +117 -0
  291. package/dist/core/localScenarioState.js.map +1 -0
  292. package/dist/core/localScenarioStore.d.ts +838 -0
  293. package/dist/core/localScenarioStore.js +218 -0
  294. package/dist/core/localScenarioStore.js.map +1 -0
  295. package/dist/core/localScenarioStructure.d.ts +4 -0
  296. package/dist/core/localScenarioStructure.js +52 -0
  297. package/dist/core/localScenarioStructure.js.map +1 -0
  298. package/dist/core/localStructureState.d.ts +2 -0
  299. package/dist/core/localStructureState.js +22 -0
  300. package/dist/core/localStructureState.js.map +1 -0
  301. package/dist/core/lookup.d.ts +662 -0
  302. package/dist/core/lookup.js +55 -0
  303. package/dist/core/lookup.js.map +1 -0
  304. package/dist/core/ownership.d.ts +3 -0
  305. package/dist/core/ownership.js +24 -0
  306. package/dist/core/ownership.js.map +1 -0
  307. package/dist/core/planInspection.d.ts +108 -0
  308. package/dist/core/planInspection.js +44 -0
  309. package/dist/core/planInspection.js.map +1 -0
  310. package/dist/core/planner.d.ts +14 -0
  311. package/dist/core/planner.js +261 -0
  312. package/dist/core/planner.js.map +1 -0
  313. package/dist/core/qualification.d.ts +26 -0
  314. package/dist/core/qualification.js +58 -0
  315. package/dist/core/qualification.js.map +1 -0
  316. package/dist/core/qualificationBundle.d.ts +6 -0
  317. package/dist/core/qualificationBundle.js +51 -0
  318. package/dist/core/qualificationBundle.js.map +1 -0
  319. package/dist/core/qualificationExecution.d.ts +879 -0
  320. package/dist/core/qualificationExecution.js +54 -0
  321. package/dist/core/qualificationExecution.js.map +1 -0
  322. package/dist/core/recoveryStatus.d.ts +6 -0
  323. package/dist/core/recoveryStatus.js +123 -0
  324. package/dist/core/recoveryStatus.js.map +1 -0
  325. package/dist/core/reducer.d.ts +56 -0
  326. package/dist/core/reducer.js +355 -0
  327. package/dist/core/reducer.js.map +1 -0
  328. package/dist/core/replayAssessment.d.ts +15 -0
  329. package/dist/core/replayAssessment.js +78 -0
  330. package/dist/core/replayAssessment.js.map +1 -0
  331. package/dist/core/replayEvidence.d.ts +7 -0
  332. package/dist/core/replayEvidence.js +58 -0
  333. package/dist/core/replayEvidence.js.map +1 -0
  334. package/dist/core/repositorySelectionEvidence.d.ts +3 -0
  335. package/dist/core/repositorySelectionEvidence.js +58 -0
  336. package/dist/core/repositorySelectionEvidence.js.map +1 -0
  337. package/dist/core/rerun.d.ts +3 -0
  338. package/dist/core/rerun.js +24 -0
  339. package/dist/core/rerun.js.map +1 -0
  340. package/dist/core/resultSink.d.ts +52 -0
  341. package/dist/core/resultSink.js +120 -0
  342. package/dist/core/resultSink.js.map +1 -0
  343. package/dist/core/review.d.ts +22 -0
  344. package/dist/core/review.js +65 -0
  345. package/dist/core/review.js.map +1 -0
  346. package/dist/core/runnerCapabilities.d.ts +22 -0
  347. package/dist/core/runnerCapabilities.js +44 -0
  348. package/dist/core/runnerCapabilities.js.map +1 -0
  349. package/dist/core/scenario.d.ts +32 -0
  350. package/dist/core/scenario.js +119 -0
  351. package/dist/core/scenario.js.map +1 -0
  352. package/dist/core/scenarioActivation.d.ts +16 -0
  353. package/dist/core/scenarioActivation.js +47 -0
  354. package/dist/core/scenarioActivation.js.map +1 -0
  355. package/dist/core/scenarioStructure.d.ts +400 -0
  356. package/dist/core/scenarioStructure.js +72 -0
  357. package/dist/core/scenarioStructure.js.map +1 -0
  358. package/dist/core/snapshotEvidence.d.ts +3 -0
  359. package/dist/core/snapshotEvidence.js +37 -0
  360. package/dist/core/snapshotEvidence.js.map +1 -0
  361. package/dist/core/snapshotRepository.d.ts +48 -0
  362. package/dist/core/snapshotRepository.js +47 -0
  363. package/dist/core/snapshotRepository.js.map +1 -0
  364. package/dist/core/source-analysis.d.ts +18 -0
  365. package/dist/core/source-analysis.js +99 -0
  366. package/dist/core/source-analysis.js.map +1 -0
  367. package/dist/core/source-citation.d.ts +53 -0
  368. package/dist/core/source-citation.js +59 -0
  369. package/dist/core/source-citation.js.map +1 -0
  370. package/dist/core/sourcePromotion.d.ts +929 -0
  371. package/dist/core/sourcePromotion.js +92 -0
  372. package/dist/core/sourcePromotion.js.map +1 -0
  373. package/dist/core/sourceReviewEvidence.d.ts +271 -0
  374. package/dist/core/sourceReviewEvidence.js +24 -0
  375. package/dist/core/sourceReviewEvidence.js.map +1 -0
  376. package/dist/core/targetObservation.d.ts +3 -0
  377. package/dist/core/targetObservation.js +26 -0
  378. package/dist/core/targetObservation.js.map +1 -0
  379. package/dist/hosts/launchTemplates.d.ts +2 -0
  380. package/dist/hosts/launchTemplates.js +5 -0
  381. package/dist/hosts/launchTemplates.js.map +1 -0
  382. package/dist/hosts/local.d.ts +17 -0
  383. package/dist/hosts/local.js +311 -0
  384. package/dist/hosts/local.js.map +1 -0
  385. package/dist/hosts/localSupervisor.d.ts +1 -0
  386. package/dist/hosts/localSupervisor.js +115 -0
  387. package/dist/hosts/localSupervisor.js.map +1 -0
  388. package/dist/hosts/mock.d.ts +4 -0
  389. package/dist/hosts/mock.js +82 -0
  390. package/dist/hosts/mock.js.map +1 -0
  391. package/dist/hosts/pinnedArguments.d.ts +3 -0
  392. package/dist/hosts/pinnedArguments.js +39 -0
  393. package/dist/hosts/pinnedArguments.js.map +1 -0
  394. package/dist/hosts/runtime.d.ts +5 -0
  395. package/dist/hosts/runtime.js +60 -0
  396. package/dist/hosts/runtime.js.map +1 -0
  397. package/dist/hosts/sourceIdentity.d.ts +54 -0
  398. package/dist/hosts/sourceIdentity.js +27 -0
  399. package/dist/hosts/sourceIdentity.js.map +1 -0
  400. package/dist/hosts/types.d.ts +39 -0
  401. package/dist/hosts/types.js +2 -0
  402. package/dist/hosts/types.js.map +1 -0
  403. package/dist/index.d.ts +56 -0
  404. package/dist/index.js +52 -0
  405. package/dist/index.js.map +1 -0
  406. package/dist/integrations/awr/attachment.d.ts +34 -0
  407. package/dist/integrations/awr/attachment.js +120 -0
  408. package/dist/integrations/awr/attachment.js.map +1 -0
  409. package/dist/integrations/awr/attachmentContracts.d.ts +273 -0
  410. package/dist/integrations/awr/attachmentContracts.js +39 -0
  411. package/dist/integrations/awr/attachmentContracts.js.map +1 -0
  412. package/dist/integrations/awr/attachmentHttp.d.ts +9 -0
  413. package/dist/integrations/awr/attachmentHttp.js +19 -0
  414. package/dist/integrations/awr/attachmentHttp.js.map +1 -0
  415. package/dist/integrations/awr/cli.d.ts +7 -0
  416. package/dist/integrations/awr/cli.js +43 -0
  417. package/dist/integrations/awr/cli.js.map +1 -0
  418. package/dist/integrations/awr/contracts.d.ts +54 -0
  419. package/dist/integrations/awr/contracts.js +33 -0
  420. package/dist/integrations/awr/contracts.js.map +1 -0
  421. package/dist/integrations/awr/http.d.ts +8 -0
  422. package/dist/integrations/awr/http.js +23 -0
  423. package/dist/integrations/awr/http.js.map +1 -0
  424. package/dist/integrations/awr/index.d.ts +7 -0
  425. package/dist/integrations/awr/index.js +8 -0
  426. package/dist/integrations/awr/index.js.map +1 -0
  427. package/dist/integrations/awr/jsonHttp.d.ts +15 -0
  428. package/dist/integrations/awr/jsonHttp.js +69 -0
  429. package/dist/integrations/awr/jsonHttp.js.map +1 -0
  430. package/dist/integrations/awr/outbox.d.ts +28 -0
  431. package/dist/integrations/awr/outbox.js +88 -0
  432. package/dist/integrations/awr/outbox.js.map +1 -0
  433. package/dist/integrations/awr/projection.d.ts +4 -0
  434. package/dist/integrations/awr/projection.js +54 -0
  435. package/dist/integrations/awr/projection.js.map +1 -0
  436. package/dist/protocol/canonical.d.ts +41 -0
  437. package/dist/protocol/canonical.js +114 -0
  438. package/dist/protocol/canonical.js.map +1 -0
  439. package/dist/protocol/index.d.ts +9620 -0
  440. package/dist/protocol/index.js +185 -0
  441. package/dist/protocol/index.js.map +1 -0
  442. package/dist/protocol/primitives.d.ts +63 -0
  443. package/dist/protocol/primitives.js +46 -0
  444. package/dist/protocol/primitives.js.map +1 -0
  445. package/dist/protocol/schemas/browser.d.ts +153 -0
  446. package/dist/protocol/schemas/browser.js +29 -0
  447. package/dist/protocol/schemas/browser.js.map +1 -0
  448. package/dist/protocol/schemas/capability.d.ts +2126 -0
  449. package/dist/protocol/schemas/capability.js +165 -0
  450. package/dist/protocol/schemas/capability.js.map +1 -0
  451. package/dist/protocol/schemas/capabilityLifecycle.d.ts +509 -0
  452. package/dist/protocol/schemas/capabilityLifecycle.js +47 -0
  453. package/dist/protocol/schemas/capabilityLifecycle.js.map +1 -0
  454. package/dist/protocol/schemas/cleanup.d.ts +109 -0
  455. package/dist/protocol/schemas/cleanup.js +59 -0
  456. package/dist/protocol/schemas/cleanup.js.map +1 -0
  457. package/dist/protocol/schemas/cli.d.ts +121 -0
  458. package/dist/protocol/schemas/cli.js +24 -0
  459. package/dist/protocol/schemas/cli.js.map +1 -0
  460. package/dist/protocol/schemas/config.d.ts +59 -0
  461. package/dist/protocol/schemas/config.js +32 -0
  462. package/dist/protocol/schemas/config.js.map +1 -0
  463. package/dist/protocol/schemas/corpus.d.ts +36 -0
  464. package/dist/protocol/schemas/corpus.js +10 -0
  465. package/dist/protocol/schemas/corpus.js.map +1 -0
  466. package/dist/protocol/schemas/definitions.d.ts +3409 -0
  467. package/dist/protocol/schemas/definitions.js +431 -0
  468. package/dist/protocol/schemas/definitions.js.map +1 -0
  469. package/dist/protocol/schemas/evidenceProjection.d.ts +146 -0
  470. package/dist/protocol/schemas/evidenceProjection.js +18 -0
  471. package/dist/protocol/schemas/evidenceProjection.js.map +1 -0
  472. package/dist/protocol/schemas/execution.d.ts +3179 -0
  473. package/dist/protocol/schemas/execution.js +500 -0
  474. package/dist/protocol/schemas/execution.js.map +1 -0
  475. package/dist/protocol/schemas/gitSources.d.ts +330 -0
  476. package/dist/protocol/schemas/gitSources.js +32 -0
  477. package/dist/protocol/schemas/gitSources.js.map +1 -0
  478. package/dist/protocol/schemas/mcp.d.ts +24 -0
  479. package/dist/protocol/schemas/mcp.js +16 -0
  480. package/dist/protocol/schemas/mcp.js.map +1 -0
  481. package/dist/protocol/schemas/nativeJob.d.ts +106 -0
  482. package/dist/protocol/schemas/nativeJob.js +16 -0
  483. package/dist/protocol/schemas/nativeJob.js.map +1 -0
  484. package/dist/protocol/schemas/portableEnvironment.d.ts +1256 -0
  485. package/dist/protocol/schemas/portableEnvironment.js +108 -0
  486. package/dist/protocol/schemas/portableEnvironment.js.map +1 -0
  487. package/dist/protocol/schemas/promotion.d.ts +132 -0
  488. package/dist/protocol/schemas/promotion.js +9 -0
  489. package/dist/protocol/schemas/promotion.js.map +1 -0
  490. package/dist/protocol/schemas/protocol.d.ts +146 -0
  491. package/dist/protocol/schemas/protocol.js +25 -0
  492. package/dist/protocol/schemas/protocol.js.map +1 -0
  493. package/dist/protocol/schemas/recoveryStatus.d.ts +88 -0
  494. package/dist/protocol/schemas/recoveryStatus.js +20 -0
  495. package/dist/protocol/schemas/recoveryStatus.js.map +1 -0
  496. package/dist/protocol/schemas/resultSink.d.ts +80 -0
  497. package/dist/protocol/schemas/resultSink.js +14 -0
  498. package/dist/protocol/schemas/resultSink.js.map +1 -0
  499. package/dist/protocol/schemas/review.d.ts +248 -0
  500. package/dist/protocol/schemas/review.js +45 -0
  501. package/dist/protocol/schemas/review.js.map +1 -0
  502. package/dist/protocol/schemas/scenario.d.ts +810 -0
  503. package/dist/protocol/schemas/scenario.js +53 -0
  504. package/dist/protocol/schemas/scenario.js.map +1 -0
  505. package/dist/protocol/schemas/source.d.ts +300 -0
  506. package/dist/protocol/schemas/source.js +25 -0
  507. package/dist/protocol/schemas/source.js.map +1 -0
  508. package/dist/source/git.d.ts +36 -0
  509. package/dist/source/git.js +159 -0
  510. package/dist/source/git.js.map +1 -0
  511. package/dist/source/gitObjectProof.d.ts +12 -0
  512. package/dist/source/gitObjectProof.js +115 -0
  513. package/dist/source/gitObjectProof.js.map +1 -0
  514. package/dist/source/snapshotPaths.d.ts +2 -0
  515. package/dist/source/snapshotPaths.js +24 -0
  516. package/dist/source/snapshotPaths.js.map +1 -0
  517. package/dist/source/snapshotTree.d.ts +15 -0
  518. package/dist/source/snapshotTree.js +79 -0
  519. package/dist/source/snapshotTree.js.map +1 -0
  520. package/docs/architecture.md +126 -0
  521. package/docs/awr-delivery.md +102 -0
  522. package/docs/browser-driver.md +148 -0
  523. package/docs/cleanup-followups.md +74 -0
  524. package/docs/developer-ux.md +315 -0
  525. package/docs/examples/portable-environments/alongside_runner.json +199 -0
  526. package/docs/examples/portable-environments/external_staging.json +183 -0
  527. package/docs/git-object-proof.md +100 -0
  528. package/docs/git-source-resolution.md +133 -0
  529. package/docs/images/ui-run.png +0 -0
  530. package/docs/local-execution-recovery.md +55 -0
  531. package/docs/local-review-store.md +13 -0
  532. package/docs/local-scenario-store.md +91 -0
  533. package/docs/mcp-driver.md +87 -0
  534. package/docs/native-jobs.md +96 -0
  535. package/docs/portable-environments.md +155 -0
  536. package/docs/qualification-registration.md +58 -0
  537. package/docs/qualification-results.md +59 -0
  538. package/docs/replay-assessment.md +17 -0
  539. package/docs/result-sink.md +87 -0
  540. package/docs/scenario-activation.md +54 -0
  541. package/docs/scenario-structure.md +58 -0
  542. package/docs/source-promotion.md +104 -0
  543. package/docs/source-review.md +21 -0
  544. package/docs/verified-bundles.md +175 -0
  545. package/docs/work-report-attachment.md +127 -0
  546. package/package.json +45 -4
  547. package/samples/django-notes/manage.py +8 -0
  548. package/samples/django-notes/notes/__init__.py +0 -0
  549. package/samples/django-notes/notes/auth.py +14 -0
  550. package/samples/django-notes/notes/migrations/0001_initial.py +19 -0
  551. package/samples/django-notes/notes/migrations/__init__.py +0 -0
  552. package/samples/django-notes/notes/models.py +13 -0
  553. package/samples/django-notes/notes/views.py +33 -0
  554. package/samples/django-notes/notesite/__init__.py +0 -0
  555. package/samples/django-notes/notesite/settings.py +17 -0
  556. package/samples/django-notes/notesite/urls.py +9 -0
  557. package/samples/django-notes/requirements.txt +1 -0
  558. package/samples/django-notes/tracegrove/notes/crud.flow.yaml +27 -0
  559. package/samples/django-notes/tracegrove.config.yaml +7 -0
  560. package/samples/fastapi-notes/app/__init__.py +0 -0
  561. package/samples/fastapi-notes/app/main.py +69 -0
  562. package/samples/fastapi-notes/requirements.txt +2 -0
  563. package/samples/fastapi-notes/tracegrove/notes/crud.flow.yaml +27 -0
  564. package/samples/fastapi-notes/tracegrove.config.yaml +8 -0
  565. package/samples/notes-api/app/app.mjs +67 -0
  566. package/samples/notes-api/app/http.mjs +16 -0
  567. package/samples/notes-api/tracegrove/fixtures/existing-note.fixture.yaml +12 -0
  568. package/samples/notes-api/tracegrove/notes/create-read-delete.flow.yaml +35 -0
  569. package/samples/notes-api/tracegrove/notes/list.flow.yaml +25 -0
  570. package/samples/notes-api/tracegrove.config.yaml +15 -0
  571. package/samples/notes-api/verification/actions/notes.registry.yaml +6 -0
  572. package/samples/notes-api/verification/auth/host-issued-owner.yaml +6 -0
  573. package/samples/notes-api/verification/cases/notes.contract.yaml +51 -0
  574. package/samples/notes-api/verification/cases/notes.create.yaml +123 -0
  575. package/samples/notes-api/verification/cases/notes.suite.yaml +5 -0
  576. package/samples/notes-api/verification/components/notes-api-stub.profile.yaml +8 -0
  577. package/samples/notes-api/verification/components/notes-api.profile.yaml +15 -0
  578. package/samples/notes-api/verification/environments/local-notes.yaml +11 -0
  579. package/samples/notes-api/verification/environments/mock-notes.yaml +11 -0
  580. package/samples/notes-api/verification/fidelity/full-live-sandbox.yaml +7 -0
  581. package/samples/notes-api/verification/fidelity/mock-contract.yaml +6 -0
  582. package/samples/notes-api/verification/fixtures/existing-note.payload.yaml +15 -0
  583. package/samples/notes-api/verification/fixtures/existing-note.plan.yaml +9 -0
  584. package/samples/notes-api/verification/fixtures/existing-note.recipe.yaml +29 -0
  585. package/samples/notes-api/verification/hosts/local-process.yaml +27 -0
  586. package/samples/notes-api/verification/hosts/mock-loopback.yaml +14 -0
  587. package/samples/notes-api/verification/mocks/notes.responses.yaml +5 -0
  588. package/samples/notes-api/verification/personas/owner.yaml +16 -0
  589. package/samples/notes-api/verification/policies/no-authoring-inference.yaml +10 -0
  590. package/samples/notes-api/verification/runners/http.yaml +5 -0
  591. package/samples/notes-api/verification/surfaces/http-api.binding.yaml +11 -0
  592. package/samples/notes-api/verification/surfaces/http-api.pack.yaml +7 -0
  593. package/samples/notes-api/verification/workflow.yaml +27 -0
  594. package/samples/notes-browser/tracegrove/notes/browser.flow.yaml +19 -0
  595. package/samples/notes-browser/verification/cases/notes.browser.yaml +63 -0
  596. package/samples/notes-browser/verification/cases/notes.suite.yaml +4 -0
  597. package/samples/notes-browser/verification/runners/http.yaml +5 -0
  598. package/samples/notes-browser/verification/surfaces/http-api.binding.yaml +11 -0
  599. package/samples/notes-browser/verification/surfaces/http-api.pack.yaml +7 -0
  600. package/samples/notes-django/README.md +21 -0
  601. package/samples/notes-django/app/django_app.py +119 -0
  602. package/samples/notes-django/app/requirements.lock +4 -0
  603. package/samples/notes-mcp/app/mcp.mjs +47 -0
  604. package/samples/notes-mcp/tracegrove/notes.flow.yaml +20 -0
  605. package/samples/notes-mcp/tracegrove.config.yaml +13 -0
  606. package/samples/report-jobs/README.md +30 -0
  607. package/samples/report-jobs/app/jobs-api.mjs +65 -0
  608. package/samples/report-jobs/app/native-bridge.mjs +30 -0
  609. package/samples/report-jobs/app/store.mjs +74 -0
  610. package/samples/report-jobs/app/worker.mjs +22 -0
  611. package/samples/report-jobs/tracegrove/fixtures/failed-job.fixture.yaml +12 -0
  612. package/samples/report-jobs/tracegrove/fixtures/held-job.fixture.yaml +12 -0
  613. package/samples/report-jobs/tracegrove/fixtures/success-job.fixture.yaml +12 -0
  614. package/samples/report-jobs/tracegrove/reports/cancellation.flow.yaml +15 -0
  615. package/samples/report-jobs/tracegrove/reports/completion.flow.yaml +31 -0
  616. package/samples/report-jobs/tracegrove/reports/failure.flow.yaml +12 -0
  617. package/samples/report-jobs/tracegrove.config.yaml +10 -0
  618. package/samples/report-native/README.md +11 -0
  619. package/samples/report-native/tracegrove/cancellation.flow.yaml +11 -0
  620. package/samples/report-native/tracegrove/completion.flow.yaml +22 -0
  621. package/samples/report-native/tracegrove/failure.flow.yaml +7 -0
  622. package/samples/report-native/tracegrove.config.yaml +11 -0
  623. package/schema/tracegrove_cli-error_v1.json +156 -0
  624. package/schema/tracegrove_config_v1.json +233 -0
  625. package/schema/tracegrove_fixture_v1.json +297 -0
  626. package/schema/tracegrove_flow_v1.json +960 -0
  627. package/schema/tracegrove_recovery-status_v1.json +234 -0
  628. package/schema/tracegrove_run-video_v1.json +25 -0
  629. package/schema/workflow_action-registry_v1.json +303 -0
  630. package/schema/workflow_auth-recipe_v1.json +146 -0
  631. package/schema/workflow_boundary-observation_v1.json +515 -0
  632. package/schema/workflow_browser-command_v1.json +292 -0
  633. package/schema/workflow_browser-locator_v1.json +74 -0
  634. package/schema/workflow_browser-network-observation_v1.json +48 -0
  635. package/schema/workflow_browser-observation_v1.json +53 -0
  636. package/schema/workflow_budget-reservation_v1.json +150 -0
  637. package/schema/workflow_campaign-result_v1.json +382 -0
  638. package/schema/workflow_capability-artifact-manifest_v1.json +529 -0
  639. package/schema/workflow_capability-descriptor_v1.json +351 -0
  640. package/schema/workflow_capability-lifecycle-checkpoint_v1.json +510 -0
  641. package/schema/workflow_capability-observation_v1.json +1707 -0
  642. package/schema/workflow_capability-operation_v1.json +3212 -0
  643. package/schema/workflow_capability-replay-plan_v1.json +1247 -0
  644. package/schema/workflow_capability-retry-policy_v1.json +39 -0
  645. package/schema/workflow_capability-retry-state_v1.json +242 -0
  646. package/schema/workflow_case_v1.json +4222 -0
  647. package/schema/workflow_change-model_v1.json +614 -0
  648. package/schema/workflow_cleanup-expectation_v1.json +108 -0
  649. package/schema/workflow_cleanup-followup_v1.json +145 -0
  650. package/schema/workflow_component-profile_v1.json +219 -0
  651. package/schema/workflow_config_v1.json +180 -0
  652. package/schema/workflow_corpus_v1.json +172 -0
  653. package/schema/workflow_cost-observation_v1.json +366 -0
  654. package/schema/workflow_credential-lease_v1.json +222 -0
  655. package/schema/workflow_effective-config_v1.json +214 -0
  656. package/schema/workflow_environment-plan_v1.json +445 -0
  657. package/schema/workflow_environment_v1.json +1827 -0
  658. package/schema/workflow_evidence-projection_v1.json +636 -0
  659. package/schema/workflow_execution_v1.json +4086 -0
  660. package/schema/workflow_fidelity-plan_v1.json +512 -0
  661. package/schema/workflow_fidelity-profile_v1.json +396 -0
  662. package/schema/workflow_fixture-manifest_v1.json +918 -0
  663. package/schema/workflow_fixture-plan_v1.json +594 -0
  664. package/schema/workflow_git-source-request_v1.json +124 -0
  665. package/schema/workflow_git-source-resolution_v1.json +660 -0
  666. package/schema/workflow_git-source-snapshot_v1.json +287 -0
  667. package/schema/workflow_host-lease_v1.json +321 -0
  668. package/schema/workflow_host-observation_v1.json +282 -0
  669. package/schema/workflow_host-plan_v1.json +719 -0
  670. package/schema/workflow_identity-attestation_v1.json +412 -0
  671. package/schema/workflow_intelligence-policy_v1.json +153 -0
  672. package/schema/workflow_logical-payload_v1.json +206 -0
  673. package/schema/workflow_mcp-tool-call_v1.json +70 -0
  674. package/schema/workflow_mcp-tool-observation_v1.json +125 -0
  675. package/schema/workflow_mock-responses_v1.json +185 -0
  676. package/schema/workflow_native-job-action_v1.json +123 -0
  677. package/schema/workflow_native-job-observation_v1.json +138 -0
  678. package/schema/workflow_native-job-ready_v1.json +31 -0
  679. package/schema/workflow_native-job-request_v1.json +155 -0
  680. package/schema/workflow_native-job-response_v1.json +125 -0
  681. package/schema/workflow_ownership_v1.json +116 -0
  682. package/schema/workflow_persona_v1.json +499 -0
  683. package/schema/workflow_plan-edit-projection_v1.json +152 -0
  684. package/schema/workflow_plan-review_v1.json +246 -0
  685. package/schema/workflow_portable-environment-intent_v1.json +499 -0
  686. package/schema/workflow_portable-environment-profile_v1.json +1429 -0
  687. package/schema/workflow_portable-preflight_v1.json +2281 -0
  688. package/schema/workflow_qualification-admission_v1.json +467 -0
  689. package/schema/workflow_qualification-intent_v1.json +98 -0
  690. package/schema/workflow_qualification-policy_v1.json +109 -0
  691. package/schema/workflow_qualification-round_v1.json +226 -0
  692. package/schema/workflow_replay-assessment_v1.json +197 -0
  693. package/schema/workflow_replay-finding_v1.json +147 -0
  694. package/schema/workflow_request_v1.json +1567 -0
  695. package/schema/workflow_result-ingest_v1.json +343 -0
  696. package/schema/workflow_revisions_v1.json +334 -0
  697. package/schema/workflow_routing-decision_v1.json +482 -0
  698. package/schema/workflow_runner-capabilities_v1.json +316 -0
  699. package/schema/workflow_runner-profile_v1.json +119 -0
  700. package/schema/workflow_runner-protocol_v1_host.json +382 -0
  701. package/schema/workflow_runner-protocol_v1_plugin.json +491 -0
  702. package/schema/workflow_scenario-activation-intent_v1.json +346 -0
  703. package/schema/workflow_scenario-activation_v1.json +562 -0
  704. package/schema/workflow_scenario-projection_v1.json +221 -0
  705. package/schema/workflow_scenario-promotion_v1.json +455 -0
  706. package/schema/workflow_scenario-replay-assessment_v1.json +696 -0
  707. package/schema/workflow_scenario-revision-token_v1.json +115 -0
  708. package/schema/workflow_scenario-structure_v1.json +368 -0
  709. package/schema/workflow_scenario_v1.json +401 -0
  710. package/schema/workflow_scoped-resource_v1.json +550 -0
  711. package/schema/workflow_seed-recipe_v1.json +724 -0
  712. package/schema/workflow_selection_v1.json +1108 -0
  713. package/schema/workflow_signed-cleanup-followup_v1.json +175 -0
  714. package/schema/workflow_source-plan_v1.json +756 -0
  715. package/schema/workflow_source-selection_v1.json +456 -0
  716. package/schema/workflow_source-validation_v1.json +366 -0
  717. package/schema/workflow_step-event_v1.json +228 -0
  718. package/schema/workflow_stream-transcript_v1.json +1030 -0
  719. package/schema/workflow_suite_v1.json +64 -0
  720. package/schema/workflow_surface-binding_v1.json +411 -0
  721. package/schema/workflow_surface-pack_v1.json +159 -0
@@ -0,0 +1,119 @@
1
+ """Local Django notes API: real file persistence, no ORM or database connection."""
2
+ from dataclasses import asdict, dataclass
3
+ from datetime import datetime, timezone
4
+ from importlib.metadata import version
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+ from uuid import UUID, uuid4
9
+ from wsgiref.simple_server import WSGIRequestHandler, make_server
10
+
11
+ import django
12
+ from django.conf import settings
13
+ from django.core.wsgi import get_wsgi_application
14
+ from django.http import HttpResponse, JsonResponse
15
+ from django.urls import re_path
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Note:
20
+ id: str
21
+ title: str
22
+ body: str
23
+ ownerId: str
24
+ createdAt: str
25
+
26
+ @classmethod
27
+ def create(cls, payload: object, owner: str) -> "Note":
28
+ if not isinstance(payload, dict) or not all(isinstance(payload.get(key), str) for key in ("title", "body")):
29
+ raise ValueError("invalid_note")
30
+ return cls(str(uuid4()), payload["title"], payload["body"], owner, datetime.now(timezone.utc).isoformat())
31
+
32
+
33
+ class NoteStore:
34
+ def __init__(self, root: Path):
35
+ self.root = root
36
+ self.root.mkdir(parents=True, exist_ok=True)
37
+
38
+ def path(self, identifier: str) -> Path:
39
+ return self.root / f"{UUID(identifier)}.json"
40
+
41
+ def read(self, identifier: str) -> Note | None:
42
+ try:
43
+ return Note(**json.loads(self.path(identifier).read_text()))
44
+ except (ValueError, FileNotFoundError):
45
+ return None
46
+
47
+ def write(self, note: Note) -> None:
48
+ path = self.path(note.id)
49
+ temporary = path.with_suffix(".tmp")
50
+ temporary.write_text(json.dumps(asdict(note)))
51
+ temporary.replace(path)
52
+
53
+ def owned(self, owner: str) -> list[dict]:
54
+ return [asdict(note) for path in sorted(self.root.glob("*.json"))
55
+ if (note := self.read(path.stem)) is not None and note.ownerId == owner]
56
+
57
+
58
+ class NotesAPI:
59
+ def __init__(self, store: NoteStore, tokens: dict[str, str], build: str):
60
+ self.store, self.tokens, self.build = store, tokens, build
61
+
62
+ def health(self, request):
63
+ return JsonResponse({"ok": True, "build": self.build, "notes": len(list(self.store.root.glob("*.json")))})
64
+
65
+ def notes(self, request, identifier: str | None = None):
66
+ authorization = request.headers.get("Authorization", "")
67
+ owner = self.tokens.get(authorization[7:]) if authorization.startswith("Bearer ") else None
68
+ if not owner:
69
+ return JsonResponse({"error": "unauthorized"}, status=401)
70
+ if identifier is None:
71
+ if request.method == "GET":
72
+ return JsonResponse({"notes": self.store.owned(owner)})
73
+ if request.method == "POST":
74
+ try:
75
+ note = Note.create(json.loads(request.body or b"{}"), owner)
76
+ except (ValueError, UnicodeDecodeError):
77
+ return JsonResponse({"error": "invalid_note"}, status=400)
78
+ self.store.write(note)
79
+ return JsonResponse({"note": asdict(note)}, status=201)
80
+ return JsonResponse({"error": "method_not_allowed"}, status=405)
81
+ note = self.store.read(identifier)
82
+ if note is None:
83
+ return JsonResponse({"error": "not_found"}, status=404)
84
+ if note.ownerId != owner:
85
+ return JsonResponse({"error": "forbidden"}, status=403)
86
+ if request.method == "GET":
87
+ return JsonResponse({"note": asdict(note)})
88
+ if request.method == "DELETE":
89
+ self.store.path(identifier).unlink()
90
+ return HttpResponse(status=204)
91
+ return JsonResponse({"error": "method_not_allowed"}, status=405)
92
+
93
+
94
+ class QuietHandler(WSGIRequestHandler):
95
+ def log_message(self, format, *args):
96
+ pass
97
+
98
+
99
+ def check_dependencies() -> None:
100
+ # Fail readiness when the installed versions disagree with the pinned input.
101
+ for line in Path(__file__).with_name("requirements.lock").read_text().splitlines():
102
+ if line and not line.startswith("#"):
103
+ name, expected = line.split()[0].split("==")
104
+ if version(name) != expected:
105
+ raise RuntimeError("Install the dependencies from app/requirements.lock")
106
+
107
+
108
+ check_dependencies()
109
+ settings.configure(DEBUG=False, ROOT_URLCONF=__name__, ALLOWED_HOSTS=["127.0.0.1"],
110
+ INSTALLED_APPS=[], DATABASES={}, MIDDLEWARE=[], DATA_UPLOAD_MAX_MEMORY_SIZE=65536)
111
+ django.setup()
112
+ api = NotesAPI(NoteStore(Path(os.environ["NOTES_DIR"])), json.loads(os.environ["NOTES_TOKENS"]),
113
+ os.environ.get("NOTES_BUILD", "django-sample"))
114
+ urlpatterns = [re_path(r"^health$", api.health), re_path(r"^notes(?:/(?P<identifier>[^/]+))?$", api.notes)]
115
+
116
+ if __name__ == "__main__":
117
+ with make_server("127.0.0.1", int(os.environ.get("PORT", "0")), get_wsgi_application(), handler_class=QuietHandler) as server:
118
+ print(f"listening {server.server_port}", flush=True)
119
+ server.serve_forever()
@@ -0,0 +1,4 @@
1
+ # Pure-Python wheels downloaded from PyPI; installs require these exact hashes.
2
+ asgiref==3.12.1 --hash=sha256:fe386d1c2bff7259ea95929266d12a8cf9a8b5a1c2598402967d8792e7a7c094
3
+ Django==6.1.2 --hash=sha256:141efee6ec64d1db6db90683bf734c550102450f444fb099063b0be1bd27d991
4
+ sqlparse==0.6.0 --hash=sha256:b861c0288ce2fa56209a9a6412d2e066ac664b3873b89c26c9d8415e8e32996f
@@ -0,0 +1,47 @@
1
+ // Local native application: file-backed notes over MCP and independent HTTP readback.
2
+ // Implements the bounded JSON-response 2025-11-25 transport, not an MCP widget host.
3
+ import { createServer } from 'node:http';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { mkdirSync, writeFileSync, readFileSync, readdirSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { send, readBody } from './http.mjs';
8
+
9
+ const directory = process.env.NOTES_DIR;
10
+ if (!directory) throw new Error('NOTES_DIR is required');
11
+ mkdirSync(directory, { recursive: true });
12
+ const tokens = JSON.parse(process.env.NOTES_TOKENS ?? '{}');
13
+ const server = createServer(async (request, response) => {
14
+ try {
15
+ const path = new URL(request.url ?? '/', 'http://127.0.0.1').pathname;
16
+ if (request.method === 'GET' && path === '/health') return send(response, 200, { ok: true, notes: readdirSync(directory).length });
17
+ const token = String(request.headers.authorization ?? '').replace(/^Bearer /, '');
18
+ if (!Object.hasOwn(tokens, token)) return send(response, 401, { error: 'unauthorized' });
19
+ const ownerId = tokens[token];
20
+ const match = path.match(/^\/notes\/([0-9a-f-]{36})$/);
21
+ if (request.method === 'GET' && match) {
22
+ let note;
23
+ try { note = JSON.parse(readFileSync(join(directory, `${match[1]}.json`), 'utf8')); }
24
+ catch { return send(response, 404, { error: 'not_found' }); }
25
+ if (note.ownerId !== ownerId) return send(response, 403, { error: 'forbidden' });
26
+ return send(response, 200, { note });
27
+ }
28
+ if (path !== '/mcp') return send(response, 404, { error: 'not_found' });
29
+ if (request.method !== 'POST') return send(response, 405, { error: 'method_not_allowed' });
30
+ const message = await readBody(request);
31
+ if (message.jsonrpc !== '2.0' || typeof message.method !== 'string') return send(response, 400, { error: 'invalid_request' });
32
+ if (message.id === undefined) { response.writeHead(202); response.end(); return; }
33
+ const reply = result => send(response, 200, { jsonrpc: '2.0', id: message.id, result });
34
+ if (message.method === 'initialize') return reply({ protocolVersion: '2025-11-25', capabilities: { tools: {} }, serverInfo: { name: 'native-notes', version: '1.0.0' } });
35
+ if (message.method === 'tools/list') return reply({ tools: [{ name: 'notes.create', inputSchema: { type: 'object', properties: { title: { type: 'string' }, body: { type: 'string' } }, required: ['title', 'body'], additionalProperties: false } }] });
36
+ if (message.method === 'tools/call' && message.params?.name === 'notes.create') {
37
+ const input = message.params.arguments;
38
+ if (!input || typeof input.title !== 'string' || typeof input.body !== 'string') return reply({ isError: true, content: [{ type: 'text', text: 'Invalid note input' }] });
39
+ const note = { id: randomUUID(), title: input.title, body: input.body, ownerId };
40
+ writeFileSync(join(directory, `${note.id}.json`), JSON.stringify(note));
41
+ return reply({ content: [{ type: 'text', text: JSON.stringify({ note }) }], structuredContent: { note }, isError: false });
42
+ }
43
+ return send(response, 200, { jsonrpc: '2.0', id: message.id, error: { code: -32601, message: 'Unsupported method or tool' } });
44
+ } catch { send(response, 400, { error: 'invalid_request' }); }
45
+ });
46
+ server.listen(Number(process.env.PORT ?? 0), '127.0.0.1');
47
+ process.on('SIGTERM', () => server.close(() => process.exit(0)));
@@ -0,0 +1,20 @@
1
+ title: MCP creation is independently visible through the notes API
2
+ effects:
3
+ maxMcpCalls: 1
4
+ allowedMcpTools: [notes.create]
5
+ steps:
6
+ - name: create
7
+ mcp:
8
+ endpoint: /mcp
9
+ tool: notes.create
10
+ arguments: { title: Protocol proof, body: Saved by the native application }
11
+ expect:
12
+ json: { structuredContent.note.title: Protocol proof }
13
+ save: { noteId: structuredContent.note.id }
14
+ - GET: /notes/{noteId}
15
+ expect:
16
+ status: 200
17
+ json: { note.title: Protocol proof, note.ownerId: alice }
18
+ - GET: /notes/{noteId}
19
+ as: intruder
20
+ expect: 403
@@ -0,0 +1,13 @@
1
+ project: mcp-notes
2
+ app:
3
+ adapter: node
4
+ entry: app/mcp.mjs
5
+ health: /health
6
+ sources: [app/**]
7
+ inject:
8
+ port: PORT
9
+ dataDir: NOTES_DIR
10
+ tokens: NOTES_TOKENS
11
+ personas:
12
+ owner: { subject: alice }
13
+ intruder: { subject: bob }
@@ -0,0 +1,30 @@
1
+ # Report jobs
2
+
3
+ This sample runs a local HTTP API and a separate Node worker against one persisted
4
+ SQLite queue. Only the worker publishes report rows. Duplicate owner/request keys
5
+ reuse one job, cancellation waits for a worker acknowledgement, and failed jobs
6
+ leave no report. Fixture cleanup deletes its owned job and report atomically.
7
+
8
+ Generate the sample with `tracegrove sample-config --sample report-jobs --output
9
+ <empty-directory>`. From that directory, run `tracegrove test`. Sample generation
10
+ also compiles the low-level corpus and prints its config path; pass that exact
11
+ path to `workflow-verify plan` or `doctor`. Compilation checks the installed Node
12
+ runtime but does not start the API or worker.
13
+
14
+ All flows use the existing HTTP submit/readback/oracle contracts. A 202 submission
15
+ alone cannot satisfy the completion case: it polls job state, reads the persisted
16
+ report independently, checks one-job idempotency and verifies owner isolation.
17
+ `effects.maxJobs: 1` declares each flow's admitted job ceiling; it does not impose
18
+ a quota on an arbitrary external provider.
19
+
20
+ The `REPORTS_TEST_DROP_REPORT=1` application flag is a controlled defect: the
21
+ worker records success without inserting the report. The completion flow must
22
+ fail on independent report readback, while retaining its sealed failed attempt.
23
+ The flag is part of the frozen app launch configuration. It is not a normal
24
+ successful lane.
25
+
26
+ The package's pinned Node 22 range supplies `node:sqlite`; no database server,
27
+ account, model call or OrgX connection is needed. The core attests the complete
28
+ application source set, including worker and storage code. This is local
29
+ application/job behavior, not a separately issued worker attestation, hosted
30
+ provider qualification, a native `job.submit` adapter, or crash-recovery proof.
@@ -0,0 +1,65 @@
1
+ import { createServer } from 'node:http';
2
+ import { fork } from 'node:child_process';
3
+ import { mkdirSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { JobStore, validJobInput } from './store.mjs';
6
+ import { nativeBridge } from './native-bridge.mjs';
7
+ import { send, readBody } from './http.mjs';
8
+
9
+ const dir = process.env.REPORTS_DIR;
10
+ if (!dir) throw new Error('REPORTS_DIR is required');
11
+ mkdirSync(dir, { recursive: true });
12
+ const store = new JobStore(join(dir, 'reports.sqlite'));
13
+ const tokens = JSON.parse(process.env.REPORTS_TOKENS ?? '{}');
14
+ const worker = fork(new URL('./worker.mjs', import.meta.url), [join(dir, 'reports.sqlite')], {
15
+ stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
16
+ env: { REPORTS_TEST_DROP_REPORT: process.env.REPORTS_TEST_DROP_REPORT ?? '0' },
17
+ });
18
+ let ready = false;
19
+ const nativeReady = nativeBridge(store, tokens, () => ready);
20
+ worker.on('message', message => { if (message?.type === 'ready') { ready = true; nativeReady(); } });
21
+ worker.on('exit', () => { ready = false; });
22
+ const view = job => ({ id: job.id, requestKey: job.request_key, title: job.title, mode: job.mode,
23
+ status: job.status, workerPid: job.worker_pid, apiPid: process.pid });
24
+ const server = createServer(async (req, res) => {
25
+ const url = new URL(req.url ?? '/', 'http://127.0.0.1');
26
+ if (req.method === 'GET' && url.pathname === '/health') return send(res, ready ? 200 : 503, { ok: ready, workerPid: worker.pid, apiPid: process.pid });
27
+ const authorization = req.headers.authorization ?? '';
28
+ const token = authorization.startsWith('Bearer ') ? authorization.slice(7) : '';
29
+ const owner = Object.hasOwn(tokens, token) ? tokens[token] : null;
30
+ if (typeof owner !== 'string' || !owner) return send(res, 401, { error: 'unauthorized' });
31
+ try {
32
+ if (url.pathname === '/jobs' && req.method === 'GET') return send(res, 200, { jobs: store.list(owner).map(view) });
33
+ if (url.pathname === '/jobs' && req.method === 'POST') {
34
+ if (!ready) return send(res, 503, { error: 'worker_unavailable' });
35
+ const body = await readBody(req);
36
+ if (!validJobInput(body)) return send(res, 400, { error: 'invalid_job' });
37
+ const result = store.submit(owner, body);
38
+ if (result.conflict) return send(res, 409, { error: 'idempotency_conflict' });
39
+ return send(res, result.duplicate ? 200 : 202, { job: view(result.job), deduplicated: result.duplicate });
40
+ }
41
+ const match = /^\/(jobs|reports)\/([0-9a-f-]{36})(\/cancel)?$/.exec(url.pathname);
42
+ if (!match) return send(res, 404, { error: 'not_found' });
43
+ const [, resource, id, cancel] = match;
44
+ const job = store.get(id);
45
+ if (!job) return send(res, 404, { error: 'not_found' });
46
+ if (job.owner_id !== owner) return send(res, 403, { error: 'forbidden' });
47
+ if (resource === 'reports' && req.method === 'GET' && !cancel) {
48
+ const report = store.report(id);
49
+ return report ? send(res, 200, { report }) : send(res, 404, { error: 'report_absent' });
50
+ }
51
+ if (resource !== 'jobs') return send(res, 405, { error: 'method_not_allowed' });
52
+ if (cancel && req.method === 'POST') return send(res, store.requestCancel(id) ? 202 : 409, { requested: true });
53
+ if (!cancel && req.method === 'GET') return send(res, 200, { job: view(job) });
54
+ if (!cancel && req.method === 'DELETE') { store.remove(id); return send(res, 204); }
55
+ return send(res, 405, { error: 'method_not_allowed' });
56
+ } catch { return send(res, 400, { error: 'bad_request' }); }
57
+ });
58
+ server.listen(Number(process.env.PORT ?? 0), '127.0.0.1', () => {
59
+ process.send?.({ type: 'listening', port: server.address().port });
60
+ });
61
+ process.on('SIGTERM', () => {
62
+ const close = () => server.close(() => { store.close(); process.exit(0); });
63
+ if (worker.exitCode !== null || worker.signalCode !== null) close();
64
+ else { worker.once('exit', close); worker.kill('SIGTERM'); }
65
+ });
@@ -0,0 +1,30 @@
1
+ import { validJobInput } from './store.mjs';
2
+
3
+ /** The application owns auth and queue semantics; the worker and SQLite store remain real. */
4
+ export function nativeBridge(store, tokens, workerReady) {
5
+ if (process.env.TRACEGROVE_NATIVE_JOBS !== 'node_ipc/v1') return () => {};
6
+ const empty = status => ({ jobId: null, status, requestKey: null, output: null, workerId: null });
7
+ process.on('message', request => {
8
+ if (request?.kind !== 'tracegrove.job.request') return;
9
+ const { command, credential } = request;
10
+ const owner = Object.hasOwn(tokens, credential) ? tokens[credential] : null;
11
+ let result = empty('forbidden');
12
+ if (typeof owner === 'string' && command.queue === 'reports') {
13
+ let job;
14
+ if (command.action === 'submit') {
15
+ const input = { ...command.payload, requestKey: command.requestKey };
16
+ if (!workerReady() || !validJobInput(input)) result = empty('conflict');
17
+ else { const submitted = store.submit(owner, input); job = submitted.job; if (submitted.conflict) result = empty('conflict'); }
18
+ } else {
19
+ job = store.get(command.jobId);
20
+ if (!job) result = empty('missing');
21
+ else if (job.owner_id !== owner) { job = null; result = empty('forbidden'); }
22
+ else if (command.action === 'cancel') { store.requestCancel(job.id); job = store.get(job.id); }
23
+ }
24
+ if (job) result = { jobId: job.id, status: job.status, requestKey: job.request_key,
25
+ output: { report: store.report(job.id), apiPid: process.pid, totalJobs: store.list(owner).length }, workerId: job.worker_pid ? String(job.worker_pid) : null };
26
+ }
27
+ process.send?.({ kind: 'tracegrove.job.response', id: request.id, result });
28
+ });
29
+ return () => process.send?.({ kind: 'tracegrove.job.ready', version: 1, queues: ['reports'] });
30
+ }
@@ -0,0 +1,74 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import { randomUUID } from 'node:crypto';
3
+
4
+ export function validJobInput(input) {
5
+ return typeof input.requestKey === 'string' && !!input.requestKey && input.requestKey.length <= 100 &&
6
+ typeof input.title === 'string' && !!input.title && input.title.length <= 200 && ['succeed', 'fail', 'hold'].includes(input.mode);
7
+ }
8
+
9
+ /** Example application storage, separate from Tracegrove's authority and ledger. */
10
+ export class JobStore {
11
+ constructor(path) {
12
+ this.db = new DatabaseSync(path);
13
+ this.db.exec(`PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL;
14
+ CREATE TABLE IF NOT EXISTS jobs (
15
+ id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, request_key TEXT NOT NULL,
16
+ title TEXT NOT NULL, mode TEXT NOT NULL, status TEXT NOT NULL,
17
+ worker_pid INTEGER, UNIQUE(owner_id,request_key)
18
+ ) STRICT;
19
+ CREATE TABLE IF NOT EXISTS reports (
20
+ job_id TEXT PRIMARY KEY, content TEXT NOT NULL, worker_pid INTEGER NOT NULL
21
+ ) STRICT;`);
22
+ }
23
+ transaction(action) {
24
+ this.db.exec('BEGIN IMMEDIATE');
25
+ try { const value = action(); this.db.exec('COMMIT'); return value; }
26
+ catch (error) { this.db.exec('ROLLBACK'); throw error; }
27
+ }
28
+ get(id) { return this.db.prepare('SELECT * FROM jobs WHERE id=?').get(id) ?? null; }
29
+ list(owner) { return this.db.prepare('SELECT * FROM jobs WHERE owner_id=? ORDER BY id').all(owner); }
30
+ submit(owner, input) {
31
+ return this.transaction(() => {
32
+ const existing = this.db.prepare('SELECT * FROM jobs WHERE owner_id=? AND request_key=?').get(owner, input.requestKey);
33
+ if (existing) return existing.title === input.title && existing.mode === input.mode
34
+ ? { job: existing, duplicate: true } : { conflict: true };
35
+ const id = randomUUID();
36
+ this.db.prepare('INSERT INTO jobs(id,owner_id,request_key,title,mode,status) VALUES(?,?,?,?,?,?)')
37
+ .run(id, owner, input.requestKey, input.title, input.mode, 'queued');
38
+ return { job: this.get(id), duplicate: false };
39
+ });
40
+ }
41
+ claim() {
42
+ return this.transaction(() => {
43
+ const row = this.db.prepare("SELECT * FROM jobs WHERE status IN ('queued','cancel_requested') ORDER BY rowid LIMIT 1").get();
44
+ if (!row) return null;
45
+ if (row.status === 'cancel_requested') {
46
+ this.db.prepare("UPDATE jobs SET status='cancelled', worker_pid=? WHERE id=?").run(process.pid, row.id);
47
+ return null;
48
+ }
49
+ this.db.prepare("UPDATE jobs SET status='running', worker_pid=? WHERE id=?").run(process.pid, row.id);
50
+ return this.get(row.id);
51
+ });
52
+ }
53
+ requestCancel(id) {
54
+ return this.db.prepare("UPDATE jobs SET status='cancel_requested' WHERE id=? AND status IN ('queued','running','cancel_requested')").run(id).changes > 0;
55
+ }
56
+ finish(id, dropReport = false) {
57
+ return this.transaction(() => {
58
+ const job = this.get(id);
59
+ if (!job || !['running', 'cancel_requested'].includes(job.status)) return;
60
+ const status = job.status === 'cancel_requested' ? 'cancelled' : job.mode === 'fail' ? 'failed' : 'succeeded';
61
+ if (status === 'succeeded' && !dropReport) this.db.prepare('INSERT INTO reports(job_id,content,worker_pid) VALUES(?,?,?)')
62
+ .run(id, `Report: ${job.title}`, process.pid);
63
+ this.db.prepare('UPDATE jobs SET status=?, worker_pid=? WHERE id=?').run(status, process.pid, id);
64
+ });
65
+ }
66
+ report(id) { return this.db.prepare('SELECT * FROM reports WHERE job_id=?').get(id) ?? null; }
67
+ remove(id) {
68
+ this.transaction(() => {
69
+ this.db.prepare('DELETE FROM reports WHERE job_id=?').run(id);
70
+ this.db.prepare('DELETE FROM jobs WHERE id=?').run(id);
71
+ });
72
+ }
73
+ close() { this.db.close(); }
74
+ }
@@ -0,0 +1,22 @@
1
+ import { setTimeout as pause } from 'node:timers/promises';
2
+ import { JobStore } from './store.mjs';
3
+
4
+ const store = new JobStore(process.argv[2]);
5
+ let busy = false;
6
+ const tick = async () => {
7
+ if (busy) return;
8
+ busy = true;
9
+ try {
10
+ const job = store.claim();
11
+ if (!job) return;
12
+ // Hold mode exercises a genuine worker acknowledgement of cancellation.
13
+ while (job.mode === 'hold' && store.get(job.id)?.status === 'running') await pause(25);
14
+ store.finish(job.id, process.env.REPORTS_TEST_DROP_REPORT === '1');
15
+ } catch { process.exitCode = 1; shutdown(); }
16
+ finally { busy = false; }
17
+ };
18
+ const timer = setInterval(() => { void tick(); }, 25);
19
+ function shutdown() { clearInterval(timer); store.close(); process.exit(process.exitCode ?? 0); }
20
+ process.on('SIGTERM', shutdown);
21
+ process.on('disconnect', shutdown);
22
+ process.send?.({ type: 'ready' });
@@ -0,0 +1,12 @@
1
+ create:
2
+ POST: /jobs
3
+ json: { requestKey: { uuid: true }, title: Failed report, mode: fail }
4
+ expect: 202
5
+ save: { jobId: job.id }
6
+ readback:
7
+ GET: /jobs/{jobId}
8
+ expect: { status: 200, json: { job.title: Failed report } }
9
+ cleanup:
10
+ DELETE: /jobs/{jobId}
11
+ expect: 204
12
+ gone: { GET: "/jobs/{jobId}", status: 404 }
@@ -0,0 +1,12 @@
1
+ create:
2
+ POST: /jobs
3
+ json: { requestKey: { uuid: true }, title: Held report, mode: hold }
4
+ expect: 202
5
+ save: { jobId: job.id }
6
+ readback:
7
+ GET: /jobs/{jobId}
8
+ expect: { status: 200, json: { job.title: Held report } }
9
+ cleanup:
10
+ DELETE: /jobs/{jobId}
11
+ expect: 204
12
+ gone: { GET: "/jobs/{jobId}", status: 404 }
@@ -0,0 +1,12 @@
1
+ create:
2
+ POST: /jobs
3
+ json: { requestKey: { uuid: true }, title: Weekly review, mode: succeed }
4
+ expect: 202
5
+ save: { jobId: job.id, requestKey: job.requestKey }
6
+ readback:
7
+ GET: /jobs/{jobId}
8
+ expect: { status: 200, json: { job.title: Weekly review } }
9
+ cleanup:
10
+ DELETE: /jobs/{jobId}
11
+ expect: 204
12
+ gone: { GET: "/jobs/{jobId}", status: 404 }
@@ -0,0 +1,15 @@
1
+ title: Cancellation is acknowledged by the worker and leaves no report
2
+ tags: [jobs, cancellation]
3
+ effects: { maxJobs: 1 }
4
+ given: { report: held-job }
5
+ steps:
6
+ - name: request cancellation
7
+ POST: /jobs/{report.jobId}/cancel
8
+ expect: 202
9
+ - name: worker acknowledges cancellation
10
+ GET: /jobs/{report.jobId}
11
+ observe: true
12
+ expect: { status: 200, json: { job.status: cancelled }, present: [job.workerPid] }
13
+ - name: no report was published
14
+ GET: /reports/{report.jobId}
15
+ expect: 404
@@ -0,0 +1,31 @@
1
+ title: One queued report produces one persisted output for its owner
2
+ tags: [jobs, smoke]
3
+ effects: { maxJobs: 1 }
4
+ given: { report: success-job }
5
+ steps:
6
+ - name: redeliver the same request
7
+ POST: /jobs
8
+ json: { requestKey: "{report.requestKey}", title: Weekly review, mode: succeed }
9
+ expect: { status: 200, json: { deduplicated: true } }
10
+ - name: only one job exists
11
+ GET: /jobs
12
+ expect: { status: 200, count: { jobs: 1 } }
13
+ - name: worker completes the job
14
+ GET: /jobs/{report.jobId}
15
+ observe: true
16
+ expect: { status: 200, json: { job.status: succeeded }, present: [job.workerPid] }
17
+ - name: read persisted output independently
18
+ GET: /reports/{report.jobId}
19
+ expect: { status: 200, json: { report.content: "Report: Weekly review" } }
20
+ - name: another owner cannot read the job
21
+ GET: /jobs/{report.jobId}
22
+ as: intruder
23
+ expect: 403
24
+ - name: another owner cannot read the report
25
+ GET: /reports/{report.jobId}
26
+ as: intruder
27
+ expect: 403
28
+ - name: an anonymous caller is rejected
29
+ GET: /reports/{report.jobId}
30
+ as: none
31
+ expect: 401
@@ -0,0 +1,12 @@
1
+ title: A failed worker job exposes failure and leaves no report
2
+ tags: [jobs, failure]
3
+ effects: { maxJobs: 1 }
4
+ given: { report: failed-job }
5
+ steps:
6
+ - name: worker records its failure
7
+ GET: /jobs/{report.jobId}
8
+ observe: true
9
+ expect: { status: 200, json: { job.status: failed }, present: [job.workerPid] }
10
+ - name: failure did not publish a report
11
+ GET: /reports/{report.jobId}
12
+ expect: 404
@@ -0,0 +1,10 @@
1
+ project: reports
2
+ app:
3
+ adapter: node
4
+ entry: app/jobs-api.mjs
5
+ sources: [app/**]
6
+ inject: { port: PORT, dataDir: REPORTS_DIR, tokens: REPORTS_TOKENS }
7
+ personas:
8
+ owner: { subject: alice }
9
+ intruder: { subject: bob }
10
+ defaults: { stepTimeoutMs: 3000, caseTimeoutMs: 20000 }
@@ -0,0 +1,11 @@
1
+ # Native report jobs
2
+
3
+ Generate with `tracegrove sample-config --sample report-native --output <folder>`.
4
+ The generator composes this config and these flows with the shared report-jobs
5
+ application, SQLite store, and independent worker. No application code is copied
6
+ into a second source of truth in this sample directory.
7
+
8
+ Run `tracegrove test --config <folder>/tracegrove.config.yaml`. Submission,
9
+ readback, and cancellation use the native Node IPC bridge. HTTP serves only
10
+ application readiness. See `docs/native-jobs.md` for the typed bridge contract,
11
+ effect limits, scope, and qualification boundaries.
@@ -0,0 +1,11 @@
1
+ title: Native cancellation waits for a real worker acknowledgement
2
+ effects: { maxJobs: 1 }
3
+ steps:
4
+ - job: { action: submit, queue: reports, requestKey: cancellation, payload: { title: Held report, mode: hold } }
5
+ save: { jobId: jobId }
6
+ - job: { action: read, queue: reports, jobId: '{jobId}' }
7
+ expect: { json: { status: running } }
8
+ - job: { action: cancel, queue: reports, jobId: '{jobId}' }
9
+ expect: { present: [jobId] }
10
+ - job: { action: read, queue: reports, jobId: '{jobId}' }
11
+ expect: { json: { status: cancelled, output.report: null }, present: [workerId] }
@@ -0,0 +1,22 @@
1
+ title: Native submission deduplicates and an independent native read observes persisted worker output
2
+ effects: { maxJobs: 3 }
3
+ steps:
4
+ - name: submit report
5
+ job: { action: submit, queue: reports, requestKey: completion, payload: { title: Native report, mode: succeed } }
6
+ save: { jobId: jobId }
7
+ expect: { present: [jobId] }
8
+ - name: duplicate delivery
9
+ job: { action: submit, queue: reports, requestKey: completion, payload: { title: Native report, mode: succeed } }
10
+ expect: { json: { output.totalJobs: 1 } }
11
+ - name: conflicting delivery
12
+ job: { action: submit, queue: reports, requestKey: completion, payload: { title: Changed report, mode: succeed } }
13
+ expect: { json: { status: conflict } }
14
+ - name: another persona cannot read the job
15
+ as: intruder
16
+ job: { action: read, queue: reports, jobId: '{jobId}' }
17
+ expect: { json: { status: forbidden } }
18
+ - name: independent persisted output
19
+ job: { action: read, queue: reports, jobId: '{jobId}' }
20
+ expect:
21
+ json: { status: succeeded, output.report.content: 'Report: Native report', output.totalJobs: 1 }
22
+ present: [workerId]
@@ -0,0 +1,7 @@
1
+ title: A native provider failure remains a failed job with no persisted report
2
+ effects: { maxJobs: 1 }
3
+ steps:
4
+ - job: { action: submit, queue: reports, requestKey: failure, payload: { title: Failed report, mode: fail } }
5
+ save: { jobId: jobId }
6
+ - job: { action: read, queue: reports, jobId: '{jobId}' }
7
+ expect: { json: { status: failed, output.report: null }, present: [workerId] }
@@ -0,0 +1,11 @@
1
+ project: native_reports
2
+ app:
3
+ adapter: node
4
+ nativeJobs: node_ipc/v1
5
+ entry: app/jobs-api.mjs
6
+ sources: [app/**]
7
+ inject: { port: PORT, dataDir: REPORTS_DIR, tokens: REPORTS_TOKENS }
8
+ personas:
9
+ owner: { subject: alice }
10
+ intruder: { subject: bob }
11
+ defaults: { stepTimeoutMs: 3000, caseTimeoutMs: 20000 }