devcontour-harness 0.0.0-stage → 0.1.0-alpha.6

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 (390) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -2
  3. package/docs/architecture.md +473 -0
  4. package/docs/compatibility-versions.md +56 -0
  5. package/docs/compatibility.md +192 -0
  6. package/docs/connectors.md +323 -0
  7. package/docs/contracts.md +603 -0
  8. package/docs/integrations/hindsight.md +148 -0
  9. package/docs/quickstart.md +182 -0
  10. package/docs/release-notes/0.1.0-alpha.6.md +238 -0
  11. package/docs/review-probes.md +120 -0
  12. package/docs/review-protocol.md +251 -0
  13. package/docs/toolchains.md +167 -0
  14. package/docs/turbo-starter.md +269 -0
  15. package/docs/upgrade.md +202 -0
  16. package/examples/README.md +27 -0
  17. package/examples/external-connector/README.md +19 -0
  18. package/examples/external-connector/connector.mjs +55 -0
  19. package/examples/files-only/README.md +28 -0
  20. package/examples/files-only/context/norms/rules.md +4 -0
  21. package/examples/files-only/graph.json +23 -0
  22. package/examples/files-only/policy.json +30 -0
  23. package/examples/one-vendor/README.md +19 -0
  24. package/examples/one-vendor/policy.json +27 -0
  25. package/examples/single-task/README.md +18 -0
  26. package/examples/single-task/graph.json +27 -0
  27. package/examples/single-task/policy-same-vendor.json +55 -0
  28. package/examples/single-task/policy.json +52 -0
  29. package/examples/single-task/src/.gitkeep +0 -0
  30. package/examples/single-task/test/run.js +19 -0
  31. package/examples/toolchains/README.md +32 -0
  32. package/examples/toolchains/go/bad/label/label.go +9 -0
  33. package/examples/toolchains/go/good/label/label.go +9 -0
  34. package/examples/toolchains/go/policy.json +79 -0
  35. package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
  36. package/examples/toolchains/go/repo/_gitignore +1 -0
  37. package/examples/toolchains/go/repo/go.mod +5 -0
  38. package/examples/toolchains/go/repo/go.sum +2 -0
  39. package/examples/toolchains/go/repo/label/label.go +9 -0
  40. package/examples/toolchains/go/repo/label/label_test.go +27 -0
  41. package/examples/toolchains/go/repo/label/version.go +9 -0
  42. package/examples/toolchains/go/task.json +25 -0
  43. package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
  44. package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
  45. package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
  46. package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
  47. package/examples/toolchains/mixed-go/policy.json +126 -0
  48. package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
  49. package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
  50. package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
  51. package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
  52. package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
  53. package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
  54. package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
  55. package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
  56. package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
  57. package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
  58. package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
  59. package/examples/toolchains/mixed-go/task.json +25 -0
  60. package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
  61. package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
  62. package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
  63. package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
  64. package/examples/toolchains/mixed-python/policy.json +121 -0
  65. package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
  66. package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
  67. package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
  68. package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
  69. package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
  70. package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
  71. package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
  72. package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
  73. package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
  74. package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
  75. package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
  76. package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
  77. package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
  78. package/examples/toolchains/mixed-python/task.json +25 -0
  79. package/examples/toolchains/npm/bad/src/label.js +4 -0
  80. package/examples/toolchains/npm/good/src/label.js +4 -0
  81. package/examples/toolchains/npm/policy.json +82 -0
  82. package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
  83. package/examples/toolchains/npm/repo/_gitignore +4 -0
  84. package/examples/toolchains/npm/repo/package-lock.json +22 -0
  85. package/examples/toolchains/npm/repo/package.json +13 -0
  86. package/examples/toolchains/npm/repo/src/label.js +4 -0
  87. package/examples/toolchains/npm/repo/test/label.test.js +13 -0
  88. package/examples/toolchains/npm/task.json +25 -0
  89. package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
  90. package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
  91. package/examples/toolchains/pnpm/policy.json +85 -0
  92. package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
  93. package/examples/toolchains/pnpm/repo/_gitignore +4 -0
  94. package/examples/toolchains/pnpm/repo/package.json +10 -0
  95. package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
  96. package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
  97. package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
  98. package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
  99. package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
  100. package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
  101. package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
  102. package/examples/toolchains/pnpm/task.json +25 -0
  103. package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
  104. package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
  105. package/examples/toolchains/python/policy.json +80 -0
  106. package/examples/toolchains/python/repo/.python-version +1 -0
  107. package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
  108. package/examples/toolchains/python/repo/_gitignore +5 -0
  109. package/examples/toolchains/python/repo/pyproject.toml +19 -0
  110. package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
  111. package/examples/toolchains/python/repo/tests/test_label.py +13 -0
  112. package/examples/toolchains/python/repo/uv.lock +108 -0
  113. package/examples/toolchains/python/task.json +25 -0
  114. package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
  115. package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
  116. package/examples/toolchains/turbo/policy.json +110 -0
  117. package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
  118. package/examples/toolchains/turbo/repo/_gitignore +4 -0
  119. package/examples/toolchains/turbo/repo/package.json +13 -0
  120. package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
  121. package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
  122. package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
  123. package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
  124. package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
  125. package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
  126. package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
  127. package/examples/toolchains/turbo/repo/turbo.json +7 -0
  128. package/examples/toolchains/turbo/task.json +25 -0
  129. package/examples/turbo-starter/README.md +16 -0
  130. package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
  131. package/examples/turbo-starter/changes/issued-at.patch +130 -0
  132. package/examples/turbo-starter/cleanup.mjs +58 -0
  133. package/examples/turbo-starter/graph.json +32 -0
  134. package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
  135. package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
  136. package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
  137. package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
  138. package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
  139. package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
  140. package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
  141. package/examples/turbo-starter/harness/env/backend.env.template +7 -0
  142. package/examples/turbo-starter/harness/env/compose.env.template +6 -0
  143. package/examples/turbo-starter/policy.json +109 -0
  144. package/examples/turbo-starter/policy.lifecycle.json +114 -0
  145. package/examples/turbo-starter/setup.mjs +352 -0
  146. package/examples/two-vendors/policy.json +30 -0
  147. package/lib/agents/cli-adapter.d.ts +48 -0
  148. package/lib/agents/cli-adapter.js +386 -0
  149. package/lib/agents/inspect.d.ts +6 -0
  150. package/lib/agents/inspect.js +46 -0
  151. package/lib/agents/probe-server.d.ts +2 -0
  152. package/lib/agents/probe-server.js +13 -0
  153. package/lib/agents/review-probe.d.ts +295 -0
  154. package/lib/agents/review-probe.js +872 -0
  155. package/lib/agents/runtime-events.d.ts +11 -0
  156. package/lib/agents/runtime-events.js +21 -0
  157. package/lib/agents/schemas.d.ts +217 -0
  158. package/lib/agents/schemas.js +124 -0
  159. package/lib/agents/usage.d.ts +8 -0
  160. package/lib/agents/usage.js +83 -0
  161. package/lib/cli.d.ts +2 -0
  162. package/lib/cli.js +491 -0
  163. package/lib/connectors/files.d.ts +108 -0
  164. package/lib/connectors/files.js +133 -0
  165. package/lib/contracts/checks.d.ts +307 -0
  166. package/lib/contracts/checks.js +181 -0
  167. package/lib/contracts/cli.d.ts +3895 -0
  168. package/lib/contracts/cli.js +664 -0
  169. package/lib/contracts/context.d.ts +135 -0
  170. package/lib/contracts/context.js +129 -0
  171. package/lib/contracts/digest.d.ts +9 -0
  172. package/lib/contracts/digest.js +22 -0
  173. package/lib/contracts/errors.d.ts +81 -0
  174. package/lib/contracts/errors.js +70 -0
  175. package/lib/contracts/events.d.ts +827 -0
  176. package/lib/contracts/events.js +258 -0
  177. package/lib/contracts/execution.d.ts +3216 -0
  178. package/lib/contracts/execution.js +872 -0
  179. package/lib/contracts/failure.d.ts +67 -0
  180. package/lib/contracts/failure.js +127 -0
  181. package/lib/contracts/index.d.ts +18 -0
  182. package/lib/contracts/index.js +18 -0
  183. package/lib/contracts/policy.d.ts +1080 -0
  184. package/lib/contracts/policy.js +544 -0
  185. package/lib/contracts/ports.d.ts +417 -0
  186. package/lib/contracts/ports.js +1 -0
  187. package/lib/contracts/primitives.d.ts +63 -0
  188. package/lib/contracts/primitives.js +73 -0
  189. package/lib/contracts/profiles.d.ts +336 -0
  190. package/lib/contracts/profiles.js +109 -0
  191. package/lib/contracts/published.d.ts +3237 -0
  192. package/lib/contracts/published.js +34 -0
  193. package/lib/contracts/result.d.ts +1280 -0
  194. package/lib/contracts/result.js +311 -0
  195. package/lib/contracts/review.d.ts +441 -0
  196. package/lib/contracts/review.js +477 -0
  197. package/lib/contracts/toolchain.d.ts +96 -0
  198. package/lib/contracts/toolchain.js +89 -0
  199. package/lib/contracts/version.d.ts +17 -0
  200. package/lib/contracts/version.js +17 -0
  201. package/lib/contracts/work.d.ts +173 -0
  202. package/lib/contracts/work.js +178 -0
  203. package/lib/control/base-move.d.ts +44 -0
  204. package/lib/control/base-move.js +90 -0
  205. package/lib/control/doctor.d.ts +50 -0
  206. package/lib/control/doctor.js +113 -0
  207. package/lib/control/harness.d.ts +1125 -0
  208. package/lib/control/harness.js +741 -0
  209. package/lib/control/provenance.d.ts +17 -0
  210. package/lib/control/provenance.js +25 -0
  211. package/lib/control/recovery.d.ts +237 -0
  212. package/lib/control/recovery.js +236 -0
  213. package/lib/control/review.d.ts +62 -0
  214. package/lib/control/review.js +178 -0
  215. package/lib/control/workflow.d.ts +247 -0
  216. package/lib/control/workflow.js +259 -0
  217. package/lib/engine/budget.d.ts +345 -0
  218. package/lib/engine/budget.js +278 -0
  219. package/lib/engine/classify.d.ts +8 -0
  220. package/lib/engine/classify.js +32 -0
  221. package/lib/engine/engine.d.ts +1527 -0
  222. package/lib/engine/engine.js +2259 -0
  223. package/lib/engine/failure.d.ts +1 -0
  224. package/lib/engine/failure.js +3 -0
  225. package/lib/engine/joint-runner.d.ts +257 -0
  226. package/lib/engine/joint-runner.js +254 -0
  227. package/lib/engine/measured.d.ts +15 -0
  228. package/lib/engine/measured.js +82 -0
  229. package/lib/engine/prompt.d.ts +66 -0
  230. package/lib/engine/prompt.js +131 -0
  231. package/lib/engine/property-recovery.d.ts +50 -0
  232. package/lib/engine/property-recovery.js +171 -0
  233. package/lib/engine/repair.d.ts +33 -0
  234. package/lib/engine/repair.js +82 -0
  235. package/lib/engine/result.d.ts +9 -0
  236. package/lib/engine/result.js +218 -0
  237. package/lib/engine/reuse.d.ts +80 -0
  238. package/lib/engine/reuse.js +102 -0
  239. package/lib/engine/runner.d.ts +360 -0
  240. package/lib/engine/runner.js +1836 -0
  241. package/lib/engine/standalone.d.ts +6 -0
  242. package/lib/engine/standalone.js +48 -0
  243. package/lib/engine/usage.d.ts +87 -0
  244. package/lib/engine/usage.js +165 -0
  245. package/lib/environment/isolation.d.ts +110 -0
  246. package/lib/environment/isolation.js +238 -0
  247. package/lib/environment/lifecycle.d.ts +40 -0
  248. package/lib/environment/lifecycle.js +197 -0
  249. package/lib/environment/live-calls.d.ts +14 -0
  250. package/lib/environment/live-calls.js +73 -0
  251. package/lib/environment/os-tools.d.ts +16 -0
  252. package/lib/environment/os-tools.js +35 -0
  253. package/lib/environment/process.d.ts +32 -0
  254. package/lib/environment/process.js +369 -0
  255. package/lib/environment/redaction.d.ts +22 -0
  256. package/lib/environment/redaction.js +102 -0
  257. package/lib/environment/resources.d.ts +31 -0
  258. package/lib/environment/resources.js +120 -0
  259. package/lib/index.d.ts +65 -0
  260. package/lib/index.js +67 -0
  261. package/lib/integrations/connector/commands.d.ts +358 -0
  262. package/lib/integrations/connector/commands.js +428 -0
  263. package/lib/integrations/connector/config.d.ts +215 -0
  264. package/lib/integrations/connector/config.js +214 -0
  265. package/lib/integrations/connector/delivery.d.ts +107 -0
  266. package/lib/integrations/connector/delivery.js +591 -0
  267. package/lib/integrations/connector/fake.d.ts +291 -0
  268. package/lib/integrations/connector/fake.js +786 -0
  269. package/lib/integrations/connector/history.d.ts +124 -0
  270. package/lib/integrations/connector/history.js +497 -0
  271. package/lib/integrations/connector/index.d.ts +16 -0
  272. package/lib/integrations/connector/index.js +16 -0
  273. package/lib/integrations/connector/redact.d.ts +19 -0
  274. package/lib/integrations/connector/redact.js +91 -0
  275. package/lib/integrations/connector/registry.d.ts +15 -0
  276. package/lib/integrations/connector/registry.js +43 -0
  277. package/lib/integrations/connector/snapshot.d.ts +131 -0
  278. package/lib/integrations/connector/snapshot.js +422 -0
  279. package/lib/integrations/connector/source.d.ts +37 -0
  280. package/lib/integrations/connector/source.js +73 -0
  281. package/lib/integrations/connector/steps.d.ts +71 -0
  282. package/lib/integrations/connector/steps.js +188 -0
  283. package/lib/integrations/connector/store.d.ts +140 -0
  284. package/lib/integrations/connector/store.js +277 -0
  285. package/lib/integrations/connector/summary.d.ts +38 -0
  286. package/lib/integrations/connector/summary.js +59 -0
  287. package/lib/integrations/connector/testing-worker.d.ts +1 -0
  288. package/lib/integrations/connector/testing-worker.js +81 -0
  289. package/lib/integrations/connector/testing.d.ts +205 -0
  290. package/lib/integrations/connector/testing.js +1615 -0
  291. package/lib/integrations/connector/transport.d.ts +240 -0
  292. package/lib/integrations/connector/transport.js +28 -0
  293. package/lib/integrations/memory/context.d.ts +120 -0
  294. package/lib/integrations/memory/context.js +239 -0
  295. package/lib/integrations/memory/index.d.ts +8 -0
  296. package/lib/integrations/memory/index.js +8 -0
  297. package/lib/integrations/memory/provider.d.ts +79 -0
  298. package/lib/integrations/memory/provider.js +22 -0
  299. package/lib/integrations/memory/sink.d.ts +56 -0
  300. package/lib/integrations/memory/sink.js +116 -0
  301. package/lib/integrations/memory/testing.d.ts +44 -0
  302. package/lib/integrations/memory/testing.js +61 -0
  303. package/lib/integrations/relay-v1/index.d.ts +122 -0
  304. package/lib/integrations/relay-v1/index.js +860 -0
  305. package/lib/integrations/relay-v2/index.d.ts +145 -0
  306. package/lib/integrations/relay-v2/index.js +752 -0
  307. package/lib/integrations/relay-v2/process.d.ts +32 -0
  308. package/lib/integrations/relay-v2/process.js +112 -0
  309. package/lib/integrations/relay-v2/protocol.d.ts +172 -0
  310. package/lib/integrations/relay-v2/protocol.js +142 -0
  311. package/lib/package.d.ts +2 -0
  312. package/lib/package.js +3 -0
  313. package/lib/profiles/resolve.d.ts +190 -0
  314. package/lib/profiles/resolve.js +273 -0
  315. package/lib/storage/document.d.ts +1234 -0
  316. package/lib/storage/document.js +80 -0
  317. package/lib/storage/sqlite.d.ts +35 -0
  318. package/lib/storage/sqlite.js +260 -0
  319. package/lib/testing/index.d.ts +5 -0
  320. package/lib/testing/index.js +5 -0
  321. package/lib/testing/store-contract.d.ts +8 -0
  322. package/lib/testing/store-contract.js +167 -0
  323. package/lib/toolchains/index.d.ts +9 -0
  324. package/lib/toolchains/index.js +9 -0
  325. package/lib/toolchains/inspect.d.ts +105 -0
  326. package/lib/toolchains/inspect.js +831 -0
  327. package/lib/toolchains/manifests.d.ts +67 -0
  328. package/lib/toolchains/manifests.js +238 -0
  329. package/lib/toolchains/probe.d.ts +28 -0
  330. package/lib/toolchains/probe.js +54 -0
  331. package/lib/toolchains/recipes.d.ts +33 -0
  332. package/lib/toolchains/recipes.js +51 -0
  333. package/lib/validate.d.ts +36 -0
  334. package/lib/validate.js +175 -0
  335. package/lib/verification/acceptance.d.ts +284 -0
  336. package/lib/verification/acceptance.js +670 -0
  337. package/lib/verification/checks.d.ts +72 -0
  338. package/lib/verification/checks.js +190 -0
  339. package/lib/verification/confirm.d.ts +125 -0
  340. package/lib/verification/confirm.js +411 -0
  341. package/lib/verification/corpus.d.ts +1303 -0
  342. package/lib/verification/corpus.js +744 -0
  343. package/lib/verification/dependencies.d.ts +66 -0
  344. package/lib/verification/dependencies.js +144 -0
  345. package/lib/verification/gates.d.ts +160 -0
  346. package/lib/verification/gates.js +600 -0
  347. package/lib/verification/joint.d.ts +63 -0
  348. package/lib/verification/joint.js +121 -0
  349. package/lib/verification/proof.d.ts +54 -0
  350. package/lib/verification/proof.js +96 -0
  351. package/lib/verification/property.d.ts +86 -0
  352. package/lib/verification/property.js +214 -0
  353. package/lib/verification/requirements.d.ts +25 -0
  354. package/lib/verification/requirements.js +69 -0
  355. package/lib/verification/self-check.d.ts +29 -0
  356. package/lib/verification/self-check.js +99 -0
  357. package/lib/verification/spike.d.ts +79 -0
  358. package/lib/verification/spike.js +124 -0
  359. package/package.json +100 -4
  360. package/profiles/expo-mobile.json +15 -0
  361. package/profiles/go-api.json +15 -0
  362. package/profiles/go-gotestsum.json +21 -0
  363. package/profiles/mobile-maestro.json +29 -0
  364. package/profiles/nest-api.json +26 -0
  365. package/profiles/next-product.json +72 -0
  366. package/profiles/node-checks.json +77 -0
  367. package/profiles/npm-ci.json +22 -0
  368. package/profiles/pnpm-frozen.json +24 -0
  369. package/profiles/python-api.json +32 -0
  370. package/profiles/python-uv.json +26 -0
  371. package/profiles/react-native.json +50 -0
  372. package/profiles/react-vite-admin.json +71 -0
  373. package/schemas/context-snapshot.schema.json +231 -0
  374. package/schemas/contract-document.schema.json +385 -0
  375. package/schemas/execution-document.schema.json +3695 -0
  376. package/schemas/execution-policy.schema.json +2196 -0
  377. package/schemas/joint-verification.schema.json +617 -0
  378. package/schemas/result-envelope.schema.json +1652 -0
  379. package/schemas/review-record.schema.json +177 -0
  380. package/schemas/run-event.schema.json +2458 -0
  381. package/schemas/run-result.schema.json +1570 -0
  382. package/schemas/stack-profile.schema.json +535 -0
  383. package/schemas/work-graph.schema.json +381 -0
  384. package/schemas/work-order.schema.json +256 -0
  385. package/skills/harness/SKILL.md +64 -0
  386. package/templates/AGENTS.md +13 -0
  387. package/templates/controller-mode/AGENTS.controller.md +58 -0
  388. package/templates/controller-mode/README.md +44 -0
  389. package/templates/graph.json +22 -0
  390. package/templates/policy.json +28 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "apiVersion": "devcontour-harness/v1alpha1",
3
+ "id": "notes",
4
+ "source": { "connector": "files", "ref": "graph.json", "revision": "1" },
5
+ "orders": [
6
+ {
7
+ "apiVersion": "devcontour-harness/v1alpha1",
8
+ "id": "add-tags",
9
+ "source": { "connector": "files", "ref": "add-tags", "revision": "1" },
10
+ "title": "Add tags to notes",
11
+ "goal": "Notes accept a list of tags; tags are trimmed and deduplicated.",
12
+ "acceptance": [
13
+ "createNote({ tags: [' a', 'a', 'b'] }) stores ['a', 'b']",
14
+ "npm test passes with a JUnit report"
15
+ ],
16
+ "role": "developer",
17
+ "repositoryId": "app",
18
+ "writeScope": ["src", "test"],
19
+ "gates": ["unit"],
20
+ "context": ["norms"]
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "policyVersion": 1,
3
+ "repositories": [
4
+ {
5
+ "id": "app",
6
+ "path": ".",
7
+ "targetRef": "refs/heads/harness/accepted",
8
+ "gates": [
9
+ {
10
+ "id": "unit",
11
+ "kind": "test",
12
+ "command": ["npm", "test"],
13
+ "timeoutMs": 240000,
14
+ "report": { "type": "junit", "path": ".reports/junit.xml" }
15
+ }
16
+ ],
17
+ "protectedPaths": [".github/", "package-lock.json", "policy.json", "graph.json"]
18
+ }
19
+ ],
20
+ "roles": {
21
+ "developer": { "writer": { "runtime": "claude" }, "writePaths": ["src", "test"] }
22
+ },
23
+ "review": {
24
+ "code": { "reviewer": { "runtime": "codex" } },
25
+ "plan": { "reviewer": { "runtime": "codex" }, "alternates": [{ "runtime": "claude" }] },
26
+ "contract": { "reviewer": { "runtime": "codex" }, "alternates": [{ "runtime": "claude" }] }
27
+ },
28
+ "maxAttempts": 3,
29
+ "budgets": { "work": { "usd": 5 }, "total": { "usd": 50 }, "onUnknown": "stop" }
30
+ }
@@ -0,0 +1,19 @@
1
+ # Один вендор
2
+
3
+ Writer и reviewer — claude. Это разрешено только потому, что каждое правило
4
+ ревью явно говорит `"vendor": "same-vendor-allowed"`. Без этой строки
5
+ `harness validate` отклоняет политику (`REVIEWER_SAME_VENDOR`).
6
+
7
+ Что сохраняется и при одном вендоре:
8
+
9
+ - reviewer — отдельная роль и отдельный вызов со свежей сессией: в его запросе
10
+ нет разговора, отчёта и идентификатора сессии writer;
11
+ - reviewer получает исходные критерии приёмки, закреплённый контекст, diff,
12
+ evidence проверенного SHA и прежние находки;
13
+ - reviewer работает только на чтение: правка дерева или HEAD делает его
14
+ ответ недействительным;
15
+ - приёмка требует тех же gates и ревью обеих фаз; разные модели не нужны.
16
+
17
+ Тот же эффект для одного runtime без смены вендора по умолчанию даёт
18
+ `alternates`: reviewer `codex`, запасной `claude` — для автора codex будет
19
+ выбран claude только при `same-vendor-allowed`.
@@ -0,0 +1,27 @@
1
+ {
2
+ "policyVersion": 1,
3
+ "repositories": [
4
+ {
5
+ "id": "app",
6
+ "path": ".",
7
+ "targetRef": "refs/heads/harness/accepted",
8
+ "gates": [
9
+ {
10
+ "id": "unit",
11
+ "kind": "test",
12
+ "command": ["npm", "test"],
13
+ "report": { "type": "junit", "path": ".reports/junit.xml" }
14
+ }
15
+ ],
16
+ "protectedPaths": [".github/", "package-lock.json", "policy.json", "graph.json"]
17
+ }
18
+ ],
19
+ "roles": {
20
+ "developer": { "writer": { "runtime": "claude" } }
21
+ },
22
+ "review": {
23
+ "code": { "reviewer": { "runtime": "claude" }, "vendor": "same-vendor-allowed" },
24
+ "plan": { "reviewer": { "runtime": "claude" }, "vendor": "same-vendor-allowed" },
25
+ "contract": { "reviewer": { "runtime": "claude" }, "vendor": "same-vendor-allowed" }
26
+ }
27
+ }
@@ -0,0 +1,18 @@
1
+ # Пример: одна задача
2
+
3
+ Вымышленный репозиторий с одним поручением: добавить `greet(name)` в
4
+ `src/greet.js`. Проверка — `node test/run.js`, она пишет JUnit-отчёт в путь из
5
+ `DEVCONTOUR_REPORT_PATH`.
6
+
7
+ ```sh
8
+ cp -R node_modules/devcontour-harness/examples/single-task greeting && cd greeting
9
+ git init -q && git add -A && git commit -qm init
10
+ npx harness validate --graph graph.json --policy policy.json
11
+ npx harness run --graph graph.json --policy policy.json --state ../greeting-state --author external --sink file:../greeting-results
12
+ npx harness result --state ../greeting-state --work add-greeting
13
+ git rev-parse refs/heads/harness/accepted # совпадает с result.shas.result
14
+ ```
15
+
16
+ `policy.json` — writer claude, reviewer codex (разные вендоры).
17
+ `policy-same-vendor.json` — reviewer того же вендора, разрешённый явно.
18
+ Для запуска нужны установленные и авторизованные CLI `codex` и `claude`.
@@ -0,0 +1,27 @@
1
+ {
2
+ "apiVersion": "devcontour-harness/v1alpha1",
3
+ "id": "greeting",
4
+ "source": {
5
+ "connector": "files",
6
+ "ref": "graph.json",
7
+ "revision": "1"
8
+ },
9
+ "orders": [
10
+ {
11
+ "apiVersion": "devcontour-harness/v1alpha1",
12
+ "id": "add-greeting",
13
+ "source": {
14
+ "connector": "files",
15
+ "ref": "add-greeting",
16
+ "revision": "1"
17
+ },
18
+ "title": "Add a greeting function",
19
+ "goal": "Add greet(name) to src/greet.js returning 'Hello, <name>!'.",
20
+ "acceptance": ["greet('Ada') returns 'Hello, Ada!'", "npm test passes with a JUnit report"],
21
+ "role": "developer",
22
+ "repositoryId": "app",
23
+ "writeScope": ["src"],
24
+ "gates": ["unit"]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "policyVersion": 1,
3
+ "repositories": [
4
+ {
5
+ "id": "app",
6
+ "path": ".",
7
+ "targetRef": "refs/heads/harness/accepted",
8
+ "gates": [
9
+ {
10
+ "id": "unit",
11
+ "kind": "test",
12
+ "command": ["node", "test/run.js"],
13
+ "report": {
14
+ "type": "junit",
15
+ "path": "test-results/junit.xml"
16
+ }
17
+ }
18
+ ],
19
+ "protectedPaths": [
20
+ ".github/",
21
+ "test/",
22
+ "policy.json",
23
+ "policy-same-vendor.json",
24
+ "graph.json"
25
+ ]
26
+ }
27
+ ],
28
+ "roles": {
29
+ "developer": {
30
+ "writer": {
31
+ "runtime": "claude"
32
+ }
33
+ }
34
+ },
35
+ "review": {
36
+ "code": {
37
+ "reviewer": {
38
+ "runtime": "claude"
39
+ },
40
+ "vendor": "same-vendor-allowed"
41
+ },
42
+ "plan": {
43
+ "reviewer": {
44
+ "runtime": "claude"
45
+ },
46
+ "vendor": "same-vendor-allowed"
47
+ },
48
+ "contract": {
49
+ "reviewer": {
50
+ "runtime": "claude"
51
+ },
52
+ "vendor": "same-vendor-allowed"
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "policyVersion": 1,
3
+ "repositories": [
4
+ {
5
+ "id": "app",
6
+ "path": ".",
7
+ "targetRef": "refs/heads/harness/accepted",
8
+ "gates": [
9
+ {
10
+ "id": "unit",
11
+ "kind": "test",
12
+ "command": ["node", "test/run.js"],
13
+ "report": {
14
+ "type": "junit",
15
+ "path": "test-results/junit.xml"
16
+ }
17
+ }
18
+ ],
19
+ "protectedPaths": [
20
+ ".github/",
21
+ "test/",
22
+ "policy.json",
23
+ "policy-same-vendor.json",
24
+ "graph.json"
25
+ ]
26
+ }
27
+ ],
28
+ "roles": {
29
+ "developer": {
30
+ "writer": {
31
+ "runtime": "claude"
32
+ }
33
+ }
34
+ },
35
+ "review": {
36
+ "code": {
37
+ "reviewer": {
38
+ "runtime": "codex"
39
+ }
40
+ },
41
+ "plan": {
42
+ "reviewer": {
43
+ "runtime": "codex"
44
+ }
45
+ },
46
+ "contract": {
47
+ "reviewer": {
48
+ "runtime": "codex"
49
+ }
50
+ }
51
+ }
52
+ }
File without changes
@@ -0,0 +1,19 @@
1
+ // Тест примера: проверяет src/greet.js и пишет JUnit в путь, который задаёт harness.
2
+ const fs = require('fs');
3
+ let ok = false;
4
+ let message = '';
5
+ try {
6
+ const { greet } = require(process.cwd() + '/src/greet.js');
7
+ ok = greet('Ada') === 'Hello, Ada!';
8
+ message = 'greet("Ada") = ' + greet('Ada');
9
+ } catch (error) {
10
+ message = String(error.message);
11
+ }
12
+ const report = process.env.DEVCONTOUR_REPORT_PATH || 'test-results/junit.xml';
13
+ fs.mkdirSync(require('path').dirname(report), { recursive: true });
14
+ const failure = ok ? '' : '<failure message="' + message.replace(/[<&"]/g, '') + '"/>';
15
+ fs.writeFileSync(
16
+ report,
17
+ '<testsuite><testcase classname="greet" name="greets">' + failure + '</testcase></testsuite>',
18
+ );
19
+ console.log(ok ? 'greet: ok' : 'greet: ' + message);
@@ -0,0 +1,32 @@
1
+ # Toolchains: семь вариантов target-проекта
2
+
3
+ Каждый каталог — маленький target-проект с детерминированной функцией `label(n)` и поручением
4
+ дополнять номер нулями до трёх знаков (`item-007`). Тесты проекта уже описывают новое
5
+ поведение и защищены от записи.
6
+
7
+ | Каталог | Проект | Установка | Проверки |
8
+ | -------------- | ----------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------- |
9
+ | `npm` | Node + npm | `npm ci` | `npm run check`, `npm run test` (node --test, JUnit) |
10
+ | `pnpm` | pnpm workspace, локальный бинарник `fx-check` | `pnpm install --frozen-lockfile` | `pnpm run check`, `pnpm run test` (фильтр `@fx/label`) |
11
+ | `turbo` | pnpm + Turborepo 2.11.10 | `pnpm install --frozen-lockfile` | `turbo run check/test --filter=@fx/label`, test — `--force` |
12
+ | `go` | Go-модуль без package.json | `go mod download` | `go vet`, `gotestsum … -- -count=1` |
13
+ | `python` | uv-проект без package.json | `uv sync --locked` | `ruff check`, `pytest --junitxml` |
14
+ | `mixed-go` | один Git root: pnpm `frontend/` + Go `backend/` + `contract/` | оба рецепта | gates с `cwd`, проверка контракта |
15
+ | `mixed-python` | один Git root: pnpm `frontend/` + Python `backend/` + `contract/` | оба рецепта | gates с `cwd`, проверка контракта |
16
+
17
+ Состав каталога: `repo/` — target-проект (`_gitignore` при подготовке становится
18
+ `.gitignore`), `policy.json` — политика (`path: "repo"`), `task.json` — поручение и требования
19
+ с `testId`, `good/` и `bad/` — файлы, которые пишет fixture writer в положительном и
20
+ отрицательном прогоне.
21
+
22
+ <!-- repo-only -->
23
+
24
+ В репозитории harness (не входит в пакет). Сквозной прогон через обычный путь harness (нужны npm, pnpm, go + gotestsum, uv):
25
+
26
+ ```sh
27
+ node --import tsx scripts/acceptance/t01.mjs
28
+ ```
29
+
30
+ <!-- /repo-only -->
31
+
32
+ Подробности — `docs/toolchains.md`.
@@ -0,0 +1,9 @@
1
+ // Package label форматирует метки позиций заказа.
2
+ package label
3
+
4
+ import "fmt"
5
+
6
+ // Неверная реализация для отрицательного прогона: два знака.
7
+ func Label(n int) string {
8
+ return fmt.Sprintf("item-%02d", n)
9
+ }
@@ -0,0 +1,9 @@
1
+ // Package label форматирует метки позиций заказа.
2
+ package label
3
+
4
+ import "fmt"
5
+
6
+ // Label возвращает метку позиции: номер дополняется нулями до трёх знаков.
7
+ func Label(n int) string {
8
+ return fmt.Sprintf("item-%03d", n)
9
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "policyVersion": 1,
3
+ "repositories": [
4
+ {
5
+ "id": "app",
6
+ "path": "repo",
7
+ "targetRef": "refs/heads/harness/accepted",
8
+ "prepare": [
9
+ {
10
+ "id": "install",
11
+ "command": ["go", "mod", "download"],
12
+ "timeoutMs": 600000
13
+ }
14
+ ],
15
+ "gates": [
16
+ {
17
+ "id": "vet",
18
+ "kind": "check",
19
+ "command": ["go", "vet", "./..."],
20
+ "timeoutMs": 240000
21
+ },
22
+ {
23
+ "id": "acceptance",
24
+ "kind": "test",
25
+ "command": ["gotestsum", "--junitfile", ".reports/junit.xml", "--", "-count=1", "./..."],
26
+ "timeoutMs": 240000,
27
+ "dependsOn": ["vet"],
28
+ "report": {
29
+ "type": "junit",
30
+ "path": ".reports/junit.xml"
31
+ }
32
+ }
33
+ ],
34
+ "toolchain": {
35
+ "tools": {
36
+ "gotestsum": "1.12.3"
37
+ }
38
+ },
39
+ "protectedPaths": [
40
+ ".github/",
41
+ ".githooks/",
42
+ "go.mod",
43
+ "go.sum",
44
+ "label/label_test.go",
45
+ "REQUIREMENTS.md"
46
+ ]
47
+ }
48
+ ],
49
+ "roles": {
50
+ "developer": {
51
+ "writer": {
52
+ "runtime": "claude"
53
+ }
54
+ }
55
+ },
56
+ "review": {
57
+ "code": {
58
+ "reviewer": {
59
+ "runtime": "codex"
60
+ }
61
+ },
62
+ "plan": {
63
+ "reviewer": {
64
+ "runtime": "codex"
65
+ }
66
+ },
67
+ "contract": {
68
+ "reviewer": {
69
+ "runtime": "codex"
70
+ }
71
+ }
72
+ },
73
+ "isolation": {
74
+ "mode": "none",
75
+ "domains": []
76
+ },
77
+ "maxAttempts": 2,
78
+ "runTimeoutMs": 900000
79
+ }
@@ -0,0 +1,9 @@
1
+ # Requirements
2
+
3
+ ## REQ-LABEL-PAD
4
+
5
+ label(n) pads the number to three digits: label(7) is "item-007", label(42) is "item-042".
6
+
7
+ ## REQ-LABEL-LONG
8
+
9
+ label(n) keeps numbers longer than three digits unchanged: label(1234) is "item-1234".
@@ -0,0 +1 @@
1
+ .reports/
@@ -0,0 +1,5 @@
1
+ module example.com/fxlabel
2
+
3
+ go 1.24
4
+
5
+ require golang.org/x/mod v0.25.0
@@ -0,0 +1,2 @@
1
+ golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
2
+ golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
@@ -0,0 +1,9 @@
1
+ // Package label форматирует метки позиций заказа.
2
+ package label
3
+
4
+ import "fmt"
5
+
6
+ // Label возвращает метку позиции.
7
+ func Label(n int) string {
8
+ return fmt.Sprintf("item-%d", n)
9
+ }
@@ -0,0 +1,27 @@
1
+ package label
2
+
3
+ import "testing"
4
+
5
+ func TestLabelPadsOneDigit(t *testing.T) {
6
+ if got := Label(7); got != "item-007" {
7
+ t.Fatalf("Label(7) = %q, want item-007", got)
8
+ }
9
+ }
10
+
11
+ func TestLabelPadsTwoDigits(t *testing.T) {
12
+ if got := Label(42); got != "item-042" {
13
+ t.Fatalf("Label(42) = %q, want item-042", got)
14
+ }
15
+ }
16
+
17
+ func TestLabelKeepsLong(t *testing.T) {
18
+ if got := Label(1234); got != "item-1234" {
19
+ t.Fatalf("Label(1234) = %q, want item-1234", got)
20
+ }
21
+ }
22
+
23
+ func TestFormatVersion(t *testing.T) {
24
+ if !ValidFormat() {
25
+ t.Fatal("format version is not semver")
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ package label
2
+
3
+ import "golang.org/x/mod/semver"
4
+
5
+ // FormatVersion — версия формата меток (внешняя зависимость модуля проверяется go.sum).
6
+ const FormatVersion = "v1.0.0"
7
+
8
+ // ValidFormat сообщает, что версия формата — корректная semver.
9
+ func ValidFormat() bool { return semver.IsValid(FormatVersion) }
@@ -0,0 +1,25 @@
1
+ {
2
+ "title": "Pad item labels to three digits",
3
+ "goal": "Change label(n) in label/label.go so the number is zero-padded to three digits (item-007), keeping longer numbers unchanged.",
4
+ "acceptance": [
5
+ "label(7) is item-007 and label(42) is item-042",
6
+ "label(1234) is item-1234",
7
+ "All gates pass with fresh JUnit reports"
8
+ ],
9
+ "writeScope": ["label"],
10
+ "gates": ["vet", "acceptance"],
11
+ "requirements": [
12
+ {
13
+ "id": "REQ-LABEL-PAD",
14
+ "gate": "acceptance",
15
+ "testId": "example.com/fxlabel/label.TestLabelPadsOneDigit",
16
+ "scenario": "example.com/fxlabel/label.TestLabelPadsOneDigit runs and passes on the accepted SHA"
17
+ },
18
+ {
19
+ "id": "REQ-LABEL-LONG",
20
+ "gate": "acceptance",
21
+ "testId": "example.com/fxlabel/label.TestLabelKeepsLong",
22
+ "scenario": "example.com/fxlabel/label.TestLabelKeepsLong runs and passes on the accepted SHA"
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,9 @@
1
+ // Package label форматирует метки позиций заказа.
2
+ package label
3
+
4
+ import "fmt"
5
+
6
+ // Неверная реализация для отрицательного прогона: два знака.
7
+ func Label(n int) string {
8
+ return fmt.Sprintf("item-%02d", n)
9
+ }
@@ -0,0 +1,4 @@
1
+ // Метка позиции заказа: номер дополняется нулями до трёх знаков.
2
+ export function label(n) {
3
+ return `item-${String(n).padStart(3, '0')}`;
4
+ }
@@ -0,0 +1,9 @@
1
+ // Package label форматирует метки позиций заказа.
2
+ package label
3
+
4
+ import "fmt"
5
+
6
+ // Label возвращает метку позиции: номер дополняется нулями до трёх знаков.
7
+ func Label(n int) string {
8
+ return fmt.Sprintf("item-%03d", n)
9
+ }
@@ -0,0 +1,4 @@
1
+ // Метка позиции заказа: номер дополняется нулями до трёх знаков.
2
+ export function label(n) {
3
+ return `item-${String(n).padStart(3, '0')}`;
4
+ }