@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13

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 (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Provenance checks: is this artifact anchored to anything, and has anyone
3
+ * vouched for it?
4
+ *
5
+ * SCHEMA.md has declared `status` / `owner` / `sources` / `last_verified` since
6
+ * the beginning and nothing read them. They matter more now that the prose is
7
+ * written by an agent: coherence proves the corpus agrees with itself, and only
8
+ * `sources` says it has anything to do with the code.
9
+ *
10
+ * Absence and contradiction are graded differently on purpose. A missing field
11
+ * is incompleteness — a warning, something to work through. A field that says
12
+ * the wrong thing (a spec claiming to be another service, a status nobody
13
+ * defined) is a bug, and gates.
14
+ */
15
+ import { existsSync } from "node:fs";
16
+ import { readFile } from "node:fs/promises";
17
+ import { movedUnderVouch, parseFrontmatter, readFrontmatter, stringField, FEATURE_STATUSES, SERVICE_STATUSES, } from "../document/frontmatter.js";
18
+ import { featurePaths, SPEC_AXES } from "../repo/paths.js";
19
+ import { locateServicePaths } from "../repo/service-target.js";
20
+ import { readVouchScope } from "./sample/scope.js";
21
+ import { sourceFindings } from "./sources.js";
22
+ /** Fields every artifact is expected to carry, beyond its identity and status. */
23
+ const EXPECTED = ["owner"];
24
+ export async function serviceProvenance(docsDir, service, opts = {}) {
25
+ const paths = await locateServicePaths(docsDir, service, opts.fleet);
26
+ const repo = opts.repoDir === undefined ? undefined : { dir: opts.repoDir, loamOwned: opts.loamOwned ?? [] };
27
+ const findings = [];
28
+ const owners = [];
29
+ // Both requirement-carrying specs get the same pass: arch.spec.md follows
30
+ // spec.md's frontmatter conventions exactly, so the checks are one loop —
31
+ // only the label tells a reader which file moved. The pair comes from
32
+ // SPEC_AXES rather than being respelled, so a third axis is graded here the
33
+ // day it is declared instead of the day somebody notices.
34
+ for (const { path, file } of SPEC_AXES.map((axis) => ({ path: paths[axis.key], file: axis.file }))) {
35
+ if (!existsSync(path))
36
+ continue;
37
+ const raw = await readFile(path, "utf8");
38
+ const fm = parseFrontmatter(raw);
39
+ const label = `${service}: ${file}`;
40
+ findings.push(...identityFindings(fm, {
41
+ label,
42
+ idField: "service",
43
+ idValue: service,
44
+ statuses: [...SERVICE_STATUSES],
45
+ }));
46
+ // With no frontmatter at all, "it names no sources" says nothing the missing
47
+ // header did not already say — and a malformed one proves nothing either:
48
+ // `sources.absent` against a header nobody can read is the same false
49
+ // advice as the field cascade, so frontmatter.malformed stands alone.
50
+ if (fm.present && !fm.malformed) {
51
+ findings.push(...(await sourceFindings(fm, service, label, repo)));
52
+ findings.push(...contentFindings(fm, raw, service, label));
53
+ findings.push(...scopeFindings(fm, service, label));
54
+ // Trimmed and non-empty, so `owner: ""` stays the absence it means
55
+ // rather than a second owner that disagrees with the first.
56
+ const owner = stringField(fm, "owner")?.trim();
57
+ if (owner !== undefined && owner.length > 0)
58
+ owners.push({ file, owner });
59
+ }
60
+ }
61
+ findings.push(...ownerFindings(service, owners));
62
+ return findings;
63
+ }
64
+ /**
65
+ * The two spec files of ONE service naming two different owners.
66
+ *
67
+ * `owner` is free text and loam never decides who owns anything (SCHEMA:
68
+ * ownership is CODEOWNERS, and there is no permission model to grow). But
69
+ * `loam show` and `loam context` print spec.md's value as the service's badge,
70
+ * so when spec.md says `orders-team` and arch.spec.md says a team that left
71
+ * last quarter, an agent reading arch.spec.md routes its question to one team
72
+ * while every summary names the other — and nothing said so. That is a
73
+ * disagreement between two documents in one directory, which is loam's own job
74
+ * to catch whatever the forge says. Comparing against CODEOWNERS is NOT done
75
+ * here: that is a separate question with a separate owner decision behind it.
76
+ *
77
+ * A WARNING: neither value is wrong on its own, and only a person knows which
78
+ * one is current. Silent when either file names no owner — absence is
79
+ * `frontmatter.field-missing`'s finding, and one fact gets one code.
80
+ */
81
+ function ownerFindings(service, owners) {
82
+ if (new Set(owners.map((o) => o.owner)).size < 2)
83
+ return [];
84
+ return [
85
+ {
86
+ severity: "warn",
87
+ code: "frontmatter.owner-mismatch",
88
+ subject: service,
89
+ message: `${service}: ${owners.map((o) => `${o.file} names owner '${o.owner}'`).join(", ")} — ` +
90
+ "one service, two owners, while `loam show` and `loam context` print only spec.md's. " +
91
+ "Make them agree; only a person knows which one is current",
92
+ details: owners.map((o) => `${o.file}: ${o.owner}`),
93
+ },
94
+ ];
95
+ }
96
+ export async function featureProvenance(featureDir, featureId) {
97
+ const path = featurePaths(featureDir).intent;
98
+ if (!existsSync(path))
99
+ return [];
100
+ const fm = await readFrontmatter(path);
101
+ return identityFindings(fm, {
102
+ label: "intent.md",
103
+ idField: "feature",
104
+ idValue: featureId,
105
+ statuses: [...FEATURE_STATUSES],
106
+ });
107
+ }
108
+ function identityFindings(fm, spec) {
109
+ const findings = [];
110
+ if (!fm.present) {
111
+ return [
112
+ {
113
+ severity: "warn",
114
+ code: "frontmatter.missing",
115
+ subject: spec.idValue,
116
+ message: `${spec.label} has no frontmatter — no owner, no status, no link to the code it describes`,
117
+ },
118
+ ];
119
+ }
120
+ // One honest error instead of the cascade: with an unreadable header the
121
+ // field checks below would grade owner/status/service "missing" and send the
122
+ // author adding fields to a block YAML refuses to parse. Nothing can be
123
+ // concluded from a header nobody can read — including that it lacks fields.
124
+ if (fm.malformed) {
125
+ return [
126
+ {
127
+ severity: "error",
128
+ code: "frontmatter.malformed",
129
+ subject: spec.idValue,
130
+ message: `${spec.label} has frontmatter that does not parse as YAML — owner, status and sources are unreadable until the header is fixed`,
131
+ },
132
+ ];
133
+ }
134
+ const id = stringField(fm, spec.idField);
135
+ if (id !== undefined && id !== spec.idValue) {
136
+ findings.push({
137
+ severity: "error",
138
+ code: "frontmatter.field-mismatch",
139
+ subject: spec.idValue,
140
+ message: `${spec.label} declares ${spec.idField}: ${id}, but it lives under ${spec.idValue}`,
141
+ });
142
+ }
143
+ const status = stringField(fm, "status");
144
+ if (status !== undefined && !spec.statuses.includes(status)) {
145
+ findings.push({
146
+ severity: "error",
147
+ code: "frontmatter.status-unknown",
148
+ subject: spec.idValue,
149
+ message: `${spec.label} has status '${status}' — expected one of ${spec.statuses.join(", ")}`,
150
+ });
151
+ }
152
+ const missing = [
153
+ ...(id === undefined ? [spec.idField] : []),
154
+ ...(status === undefined ? ["status"] : []),
155
+ ...EXPECTED.filter((f) => stringField(fm, f) === undefined),
156
+ ];
157
+ if (missing.length > 0) {
158
+ findings.push({
159
+ severity: "warn",
160
+ code: "frontmatter.field-missing",
161
+ subject: spec.idValue,
162
+ message: `${spec.label} is missing ${missing.length} frontmatter field(s)`,
163
+ details: missing,
164
+ text: { detailPrefix: "- " },
165
+ });
166
+ }
167
+ return findings;
168
+ }
169
+ /**
170
+ * The doc-side half of the freshness check. `sources_digest` says whether the
171
+ * CODE moved since a person looked, and only that service's repo can recompute
172
+ * it; `content_digest` says whether the DOCUMENT did, and needs nothing but
173
+ * the document — so this runs wherever the spec is readable, `--service` and
174
+ * `--all` alike. Without it, editing a spec after it was vouched left
175
+ * `status: verified` standing over words nobody read — forged freshness, in
176
+ * the exact agent-written-prose threat model this layer exists for.
177
+ */
178
+ function contentFindings(fm, raw, service, label) {
179
+ // `movedUnderVouch` is the one spelling of the condition, read by the fleet
180
+ // enumeration (core/repo/repo.ts) and `loam archive` too, so `loam list`
181
+ // cannot call a document fresh that this check calls stale. A verified doc
182
+ // with no stamp predates the field and is quiet on purpose; `contentStamp`'s
183
+ // docblock says why.
184
+ if (!movedUnderVouch(fm, raw))
185
+ return [];
186
+ const since = stringField(fm, "last_verified") ?? "it was vouched";
187
+ return [
188
+ {
189
+ // A warning, not an error — the sources.stale doctrine: the doc changed
190
+ // since it was vouched, and only a person can say whether verified still
191
+ // holds of the new words.
192
+ severity: "warn",
193
+ code: "content.stale",
194
+ message: `${label} changed since ${since} — the doc moved under its vouch, and only a person can say whether 'verified' still holds. Run \`loam vouch --pack --service ${service}\` for what to re-read, then \`loam vouch --service ${service}\`.`,
195
+ },
196
+ ];
197
+ }
198
+ /**
199
+ * The other half of what a stamp can hide: a `verified` document that a person
200
+ * read only a SAMPLE of.
201
+ *
202
+ * `loam vouch --sample <n>` deliberately trades assurance for a vouch that
203
+ * actually happens, and the trade is only sound while the reduction stays
204
+ * visible. `status: verified` cannot carry it — that string is a published
205
+ * contract and the maturity rung `vouched` is derived from it — so the scope
206
+ * rides beside it in `vouch_scope`, and this is the check that makes a fleet
207
+ * able to see it: one warning per sampled spec file, with the k/n, the seed
208
+ * to recompute the sample from, and the one action that clears it.
209
+ *
210
+ * A WARNING, following the `sources.stale` / `content.stale` doctrine: the
211
+ * document is not wrong, it is incompletely read, and only a person can close
212
+ * that. Warnings never gate, which is exactly what a fleet adopting sampling
213
+ * as policy needs — and a fleet that wants to gate on it branches on the code
214
+ * in its own CI, which is what stable codes are for.
215
+ *
216
+ * Doc-side, like `content.stale`: it needs no service repo, so it fires from
217
+ * the docs repo under `--service` and `--all` alike. A scope that does not
218
+ * decode still fires, saying so — `isSampled` asks about PRESENCE, because a
219
+ * mangled field must never be the way a partial read is promoted to a full
220
+ * one.
221
+ */
222
+ function scopeFindings(fm, service, label) {
223
+ if (stringField(fm, "status") !== "verified")
224
+ return [];
225
+ const stamp = readVouchScope(fm);
226
+ if (stamp.kind === "none")
227
+ return [];
228
+ const when = stringField(fm, "last_verified");
229
+ const said = stamp.kind === "unreadable"
230
+ ? `carries a vouch_scope that does not decode (${stamp.text === null ? "its value is not text at all" : `\`${stamp.text}\``}), so it is graded as sampled — an unreadable scope must never read as a full vouch`
231
+ : `was vouched from a sample: ${stamp.scope.sections} of ${stamp.scope.of} section(s) were read${when === undefined ? "" : ` on ${when}`}, ` +
232
+ `chosen by seed ${stamp.scope.seed} — the other ${stamp.scope.of - stamp.scope.sections} were read by nobody`;
233
+ return [
234
+ {
235
+ severity: "warn",
236
+ code: "sources.sampled-vouch",
237
+ subject: service,
238
+ message: `${label} ${said}. \`status: verified\` stands over the whole document either way. Only a person can clear ` +
239
+ `it, by reading the rest and running a full \`loam vouch --service ${service}\` (no --sample); ` +
240
+ `\`loam vouch --pack --service ${service}\` lists what that sample left unread.`,
241
+ },
242
+ ];
243
+ }
244
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../../src/core/provenance/findings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provenance checks: is this artifact anchored to anything, and has anyone\n * vouched for it?\n *\n * SCHEMA.md has declared `status` / `owner` / `sources` / `last_verified` since\n * the beginning and nothing read them. They matter more now that the prose is\n * written by an agent: coherence proves the corpus agrees with itself, and only\n * `sources` says it has anything to do with the code.\n *\n * Absence and contradiction are graded differently on purpose. A missing field\n * is incompleteness — a warning, something to work through. A field that says\n * the wrong thing (a spec claiming to be another service, a status nobody\n * defined) is a bug, and gates.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport {\n movedUnderVouch,\n parseFrontmatter,\n readFrontmatter,\n stringField,\n FEATURE_STATUSES,\n SERVICE_STATUSES,\n type Frontmatter,\n} from \"../document/frontmatter.js\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\nimport type { Finding } from \"../vocabulary/report.js\";\nimport { featurePaths, SPEC_AXES } from \"../repo/paths.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { readVouchScope } from \"./sample/scope.js\";\nimport { sourceFindings } from \"./sources.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n\n/** Fields every artifact is expected to carry, beyond its identity and status. */\nconst EXPECTED = [\"owner\"] as const;\n\nexport interface ProvenanceOptions {\n /**\n * The repo `sources` resolve against — the service repo loam is running in.\n * Undefined when the docs being validated describe some other repository, in\n * which case the paths are not ours to resolve and are left alone.\n */\n repoDir?: string;\n /**\n * Repo-relative files loam itself owns in `repoDir` — loam.json and the agent\n * files it records (`loamOwnedFiles`). Only the walk check reads them, to\n * leave them out of `sources.unwalked`'s denominator; absent means none.\n */\n loamOwned?: readonly string[];\n /** The invocation's read index, when the caller holds one — resolves the service's directory without a second walk. */\n fleet?: FleetContext;\n}\n\nexport async function serviceProvenance(\n docsDir: DocsDir,\n service: PathableService,\n opts: ProvenanceOptions = {},\n): Promise<Finding[]> {\n const paths = await locateServicePaths(docsDir, service, opts.fleet);\n const repo = opts.repoDir === undefined ? undefined : { dir: opts.repoDir, loamOwned: opts.loamOwned ?? [] };\n const findings: Finding[] = [];\n const owners: { file: string; owner: string }[] = [];\n // Both requirement-carrying specs get the same pass: arch.spec.md follows\n // spec.md's frontmatter conventions exactly, so the checks are one loop —\n // only the label tells a reader which file moved. The pair comes from\n // SPEC_AXES rather than being respelled, so a third axis is graded here the\n // day it is declared instead of the day somebody notices.\n for (const { path, file } of SPEC_AXES.map((axis) => ({ path: paths[axis.key], file: axis.file }))) {\n if (!existsSync(path)) continue;\n const raw = await readFile(path, \"utf8\");\n const fm = parseFrontmatter(raw);\n const label = `${service}: ${file}`;\n findings.push(\n ...identityFindings(fm, {\n label,\n idField: \"service\",\n idValue: service,\n statuses: [...SERVICE_STATUSES],\n }),\n );\n // With no frontmatter at all, \"it names no sources\" says nothing the missing\n // header did not already say — and a malformed one proves nothing either:\n // `sources.absent` against a header nobody can read is the same false\n // advice as the field cascade, so frontmatter.malformed stands alone.\n if (fm.present && !fm.malformed) {\n findings.push(...(await sourceFindings(fm, service, label, repo)));\n findings.push(...contentFindings(fm, raw, service, label));\n findings.push(...scopeFindings(fm, service, label));\n // Trimmed and non-empty, so `owner: \"\"` stays the absence it means\n // rather than a second owner that disagrees with the first.\n const owner = stringField(fm, \"owner\")?.trim();\n if (owner !== undefined && owner.length > 0) owners.push({ file, owner });\n }\n }\n findings.push(...ownerFindings(service, owners));\n return findings;\n}\n\n/**\n * The two spec files of ONE service naming two different owners.\n *\n * `owner` is free text and loam never decides who owns anything (SCHEMA:\n * ownership is CODEOWNERS, and there is no permission model to grow). But\n * `loam show` and `loam context` print spec.md's value as the service's badge,\n * so when spec.md says `orders-team` and arch.spec.md says a team that left\n * last quarter, an agent reading arch.spec.md routes its question to one team\n * while every summary names the other — and nothing said so. That is a\n * disagreement between two documents in one directory, which is loam's own job\n * to catch whatever the forge says. Comparing against CODEOWNERS is NOT done\n * here: that is a separate question with a separate owner decision behind it.\n *\n * A WARNING: neither value is wrong on its own, and only a person knows which\n * one is current. Silent when either file names no owner — absence is\n * `frontmatter.field-missing`'s finding, and one fact gets one code.\n */\nfunction ownerFindings(service: string, owners: { file: string; owner: string }[]): Finding[] {\n if (new Set(owners.map((o) => o.owner)).size < 2) return [];\n return [\n {\n severity: \"warn\",\n code: \"frontmatter.owner-mismatch\",\n subject: service,\n message:\n `${service}: ${owners.map((o) => `${o.file} names owner '${o.owner}'`).join(\", \")} — ` +\n \"one service, two owners, while `loam show` and `loam context` print only spec.md's. \" +\n \"Make them agree; only a person knows which one is current\",\n details: owners.map((o) => `${o.file}: ${o.owner}`),\n },\n ];\n}\n\nexport async function featureProvenance(\n featureDir: FeatureDir,\n featureId: string,\n): Promise<Finding[]> {\n const path = featurePaths(featureDir).intent;\n if (!existsSync(path)) return [];\n const fm = await readFrontmatter(path);\n return identityFindings(fm, {\n label: \"intent.md\",\n idField: \"feature\",\n idValue: featureId,\n statuses: [...FEATURE_STATUSES],\n });\n}\n\ninterface IdentitySpec {\n label: string;\n idField: \"service\" | \"feature\";\n idValue: string;\n statuses: string[];\n}\n\nfunction identityFindings(fm: Frontmatter, spec: IdentitySpec): Finding[] {\n const findings: Finding[] = [];\n if (!fm.present) {\n return [\n {\n severity: \"warn\",\n code: \"frontmatter.missing\",\n subject: spec.idValue,\n message: `${spec.label} has no frontmatter — no owner, no status, no link to the code it describes`,\n },\n ];\n }\n\n // One honest error instead of the cascade: with an unreadable header the\n // field checks below would grade owner/status/service \"missing\" and send the\n // author adding fields to a block YAML refuses to parse. Nothing can be\n // concluded from a header nobody can read — including that it lacks fields.\n if (fm.malformed) {\n return [\n {\n severity: \"error\",\n code: \"frontmatter.malformed\",\n subject: spec.idValue,\n message: `${spec.label} has frontmatter that does not parse as YAML — owner, status and sources are unreadable until the header is fixed`,\n },\n ];\n }\n\n const id = stringField(fm, spec.idField);\n if (id !== undefined && id !== spec.idValue) {\n findings.push({\n severity: \"error\",\n code: \"frontmatter.field-mismatch\",\n subject: spec.idValue,\n message: `${spec.label} declares ${spec.idField}: ${id}, but it lives under ${spec.idValue}`,\n });\n }\n\n const status = stringField(fm, \"status\");\n if (status !== undefined && !spec.statuses.includes(status)) {\n findings.push({\n severity: \"error\",\n code: \"frontmatter.status-unknown\",\n subject: spec.idValue,\n message: `${spec.label} has status '${status}' — expected one of ${spec.statuses.join(\", \")}`,\n });\n }\n\n const missing = [\n ...(id === undefined ? [spec.idField] : []),\n ...(status === undefined ? [\"status\"] : []),\n ...EXPECTED.filter((f) => stringField(fm, f) === undefined),\n ];\n if (missing.length > 0) {\n findings.push({\n severity: \"warn\",\n code: \"frontmatter.field-missing\",\n subject: spec.idValue,\n message: `${spec.label} is missing ${missing.length} frontmatter field(s)`,\n details: missing,\n text: { detailPrefix: \"- \" },\n });\n }\n return findings;\n}\n\n/**\n * The doc-side half of the freshness check. `sources_digest` says whether the\n * CODE moved since a person looked, and only that service's repo can recompute\n * it; `content_digest` says whether the DOCUMENT did, and needs nothing but\n * the document — so this runs wherever the spec is readable, `--service` and\n * `--all` alike. Without it, editing a spec after it was vouched left\n * `status: verified` standing over words nobody read — forged freshness, in\n * the exact agent-written-prose threat model this layer exists for.\n */\nfunction contentFindings(fm: Frontmatter, raw: string, service: string, label: string): Finding[] {\n // `movedUnderVouch` is the one spelling of the condition, read by the fleet\n // enumeration (core/repo/repo.ts) and `loam archive` too, so `loam list`\n // cannot call a document fresh that this check calls stale. A verified doc\n // with no stamp predates the field and is quiet on purpose; `contentStamp`'s\n // docblock says why.\n if (!movedUnderVouch(fm, raw)) return [];\n const since = stringField(fm, \"last_verified\") ?? \"it was vouched\";\n return [\n {\n // A warning, not an error — the sources.stale doctrine: the doc changed\n // since it was vouched, and only a person can say whether verified still\n // holds of the new words.\n severity: \"warn\",\n code: \"content.stale\",\n message: `${label} changed since ${since} — the doc moved under its vouch, and only a person can say whether 'verified' still holds. Run \\`loam vouch --pack --service ${service}\\` for what to re-read, then \\`loam vouch --service ${service}\\`.`,\n },\n ];\n}\n\n/**\n * The other half of what a stamp can hide: a `verified` document that a person\n * read only a SAMPLE of.\n *\n * `loam vouch --sample <n>` deliberately trades assurance for a vouch that\n * actually happens, and the trade is only sound while the reduction stays\n * visible. `status: verified` cannot carry it — that string is a published\n * contract and the maturity rung `vouched` is derived from it — so the scope\n * rides beside it in `vouch_scope`, and this is the check that makes a fleet\n * able to see it: one warning per sampled spec file, with the k/n, the seed\n * to recompute the sample from, and the one action that clears it.\n *\n * A WARNING, following the `sources.stale` / `content.stale` doctrine: the\n * document is not wrong, it is incompletely read, and only a person can close\n * that. Warnings never gate, which is exactly what a fleet adopting sampling\n * as policy needs — and a fleet that wants to gate on it branches on the code\n * in its own CI, which is what stable codes are for.\n *\n * Doc-side, like `content.stale`: it needs no service repo, so it fires from\n * the docs repo under `--service` and `--all` alike. A scope that does not\n * decode still fires, saying so — `isSampled` asks about PRESENCE, because a\n * mangled field must never be the way a partial read is promoted to a full\n * one.\n */\nfunction scopeFindings(fm: Frontmatter, service: string, label: string): Finding[] {\n if (stringField(fm, \"status\") !== \"verified\") return [];\n const stamp = readVouchScope(fm);\n if (stamp.kind === \"none\") return [];\n const when = stringField(fm, \"last_verified\");\n const said =\n stamp.kind === \"unreadable\"\n ? `carries a vouch_scope that does not decode (${stamp.text === null ? \"its value is not text at all\" : `\\`${stamp.text}\\``}), so it is graded as sampled — an unreadable scope must never read as a full vouch`\n : `was vouched from a sample: ${stamp.scope.sections} of ${stamp.scope.of} section(s) were read${when === undefined ? \"\" : ` on ${when}`}, ` +\n `chosen by seed ${stamp.scope.seed} — the other ${stamp.scope.of - stamp.scope.sections} were read by nobody`;\n return [\n {\n severity: \"warn\",\n code: \"sources.sampled-vouch\",\n subject: service,\n message:\n `${label} ${said}. \\`status: verified\\` stands over the whole document either way. Only a person can clear ` +\n `it, by reading the rest and running a full \\`loam vouch --service ${service}\\` (no --sample); ` +\n `\\`loam vouch --pack --service ${service}\\` lists what that sample left unread.`,\n },\n ];\n}\n"]}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Subprocess questions to git: what the repository tracks, what it ignores,
3
+ * and who is working in it. Four questions, one spawn (`gitText`), one
4
+ * timeout, one doctrine — every way git can decline to answer (not a
5
+ * repository, not installed, a non-zero exit, a timeout) reads as "git will
6
+ * not say", never as an error a caller must handle. No denominator, no
7
+ * finding. The subsystem surface's own questions (dirty paths, rename hops,
8
+ * the one blessed `git add`) live in `./gitq/`, asked through the same
9
+ * `gitText` and so under the same timeout and output cap.
10
+ *
11
+ * Beside this module's own four questions live the neutral ANSWER-SHAPE
12
+ * helpers — `gitText`, `GitAnswer`, `gitSaid`, `declineDetail`,
13
+ * `collectStderr` — shared by the two modules that carry git's words to a
14
+ * user: `core/diff/base-git.ts` (which REFUSES when git declines, because a
15
+ * silently empty base reports the fleet as added) and `./gitq/vouched-ancestor.ts`
16
+ * (which DEGRADES to "full read", because a reading list may only ever grow
17
+ * when nobody could look). The helpers are spawn-and-capture with no verdict
18
+ * in them: the consequence of a decline belongs to each caller and is stated
19
+ * there — sharing the mechanics is what keeps a hardening (an env pin, a cap
20
+ * change) from landing in one of two byte-identical copies.
21
+ */
22
+ import { spawn } from "node:child_process";
23
+ /** How long the digest waits on git before deciding it learned nothing. */
24
+ export const GIT_TIMEOUT_MS = 10_000;
25
+ /**
26
+ * How much a git answer may SAY. The three streamed reads below accumulated
27
+ * without bound — a fleet repo's ls-files fits in single-digit MiB, so the
28
+ * cap is generous, and past it the child is killed and the doctrine answers
29
+ * exactly as for any other way git declines: null, or the empty set — "git
30
+ * will not say", never a truncated denominator presented as the whole one.
31
+ */
32
+ const MAX_GIT_OUTPUT_BYTES = 64 * 1024 * 1024;
33
+ /**
34
+ * Accumulate a child's stdout up to the cap; past it, kill the child and
35
+ * remember why. One helper because the three readers below had three copies
36
+ * of the same `out += chunk` line, which is where an unbounded buffer hides;
37
+ * every text question now reaches it through `gitText`, so it is private.
38
+ */
39
+ function collectStdout(child) {
40
+ let out = "";
41
+ let overflowed = false;
42
+ child.stdout?.setEncoding("utf8");
43
+ child.stdout?.on("data", (chunk) => {
44
+ if (overflowed)
45
+ return;
46
+ if (out.length + chunk.length > MAX_GIT_OUTPUT_BYTES) {
47
+ overflowed = true;
48
+ child.kill();
49
+ return;
50
+ }
51
+ out += chunk;
52
+ });
53
+ return { text: () => out, overflowed: () => overflowed };
54
+ }
55
+ /**
56
+ * How much of git's stderr an outcome may quote. The point is the first
57
+ * `fatal:` line, not a transcript; past the cap the words are dropped, never
58
+ * the outcome.
59
+ */
60
+ const STDERR_CAP = 2048;
61
+ /** Accumulate a child's stderr up to the cap; past it, keep what is held. */
62
+ export function collectStderr(child) {
63
+ let err = "";
64
+ child.stderr?.setEncoding("utf8");
65
+ child.stderr?.on("data", (chunk) => {
66
+ if (err.length < STDERR_CAP)
67
+ err = (err + chunk).slice(0, STDERR_CAP);
68
+ });
69
+ return () => err;
70
+ }
71
+ /**
72
+ * One git question, stdout as text, stderr held for quoting. No verdict here
73
+ * — see the banner: what a decline MEANS belongs to the caller. `input`, when
74
+ * given, is written to git's stdin and closed (`check-ignore --stdin`); every
75
+ * other question leaves stdin unopened.
76
+ */
77
+ export async function gitText(cwd, args, input) {
78
+ return new Promise((done) => {
79
+ const child = spawn("git", args, {
80
+ cwd,
81
+ stdio: [input === undefined ? "ignore" : "pipe", "pipe", "pipe"],
82
+ timeout: GIT_TIMEOUT_MS,
83
+ });
84
+ const out = collectStdout(child);
85
+ const err = collectStderr(child);
86
+ child.on("error", (e) => done({ code: null, out: "", err: "", spawnError: e.message, overflowed: false }));
87
+ child.on("close", (code) => done({ code, out: out.text(), err: err(), overflowed: out.overflowed() }));
88
+ if (input === undefined)
89
+ return;
90
+ // A git that died before reading its input hands us EPIPE; the close
91
+ // handler above is what decides the outcome either way.
92
+ child.stdin?.on("error", () => undefined);
93
+ child.stdin?.end(input);
94
+ });
95
+ }
96
+ /** The first line of git's stderr, trimmed — the quotable half of a decline. */
97
+ export function gitSaid(answer) {
98
+ const line = answer.err.split("\n").find((l) => l.trim() !== "");
99
+ return line === undefined ? "" : line.trim();
100
+ }
101
+ /** The one sentence a decline collapses to when git left no words behind. */
102
+ export function declineDetail(answer) {
103
+ if (answer.spawnError !== undefined)
104
+ return `git could not be started: ${answer.spawnError}.`;
105
+ const said = gitSaid(answer);
106
+ return said === "" ? "git answered nothing (killed or timed out)." : `git said: ${said}`;
107
+ }
108
+ /**
109
+ * What this repository considers its own, as repo-relative paths — or null for
110
+ * every way git can decline to say: not a repository, not installed, a timeout,
111
+ * a non-zero exit. The caller distinguishes none of them, exactly as
112
+ * `gitConfig` does not, because they all mean the same thing: there is no
113
+ * denominator here, so there is nothing to report.
114
+ *
115
+ * `-z` rather than the default line output: git QUOTES paths containing spaces
116
+ * or non-ASCII bytes when it is writing lines, so a service with one such file
117
+ * would have had a phantom top-level directory named `"src` in its untouched
118
+ * list.
119
+ */
120
+ export async function gitTrackedFiles(repoDir) {
121
+ const a = await gitText(repoDir, ["ls-files", "-z", "--cached", "--exclude-standard"]);
122
+ return a.code === 0 && !a.overflowed ? a.out.split("\0").filter((p) => p !== "") : null;
123
+ }
124
+ /**
125
+ * Which of these repo-relative paths the repository ignores, asked once for the
126
+ * whole list. `git check-ignore` is the authority on purpose — it reads
127
+ * `.gitignore` at every level, `.git/info/exclude` and the user's global
128
+ * excludes, and it already knows that a TRACKED file is not ignored no matter
129
+ * what a pattern says, which is the distinction a re-implementation always gets
130
+ * wrong.
131
+ *
132
+ * Every failure answers "nothing is ignored": exit 1 is git saying so, exit 128
133
+ * is "not a git repository", a spawn error is git not being installed, and a
134
+ * timeout is a repository too strange to wait for. None of them justify
135
+ * dropping a file from a digest a person is going to sign.
136
+ */
137
+ export async function gitIgnoredPaths(repoDir, rels) {
138
+ if (rels.length === 0)
139
+ return new Set();
140
+ const a = await gitText(repoDir, ["check-ignore", "--stdin", "-z"], rels.join("\0") + "\0");
141
+ // 0: some paths are ignored and are on stdout. 1: none are — an empty
142
+ // answer, not a failure. Anything else, the overflow and a spawn failure
143
+ // included: we learned nothing, and nothing is ignored.
144
+ return (a.code === 0 || a.code === 1) && !a.overflowed
145
+ ? new Set(a.out.split("\0").filter((s) => s.length > 0))
146
+ : new Set();
147
+ }
148
+ /**
149
+ * Who git says is working in this repository — `Name <email>`, or null when git
150
+ * cannot answer.
151
+ *
152
+ * This is the only identity loam has, and it is deliberately a weak one: git
153
+ * config is a text file anybody can edit, so `vouched_by` is a name, not a
154
+ * signature, and it proves nothing cryptographically. What it does is make the
155
+ * claim ATTRIBUTABLE — a `status: verified` with nobody's name against it says
156
+ * only that some process wrote the word, which is exactly the state that let a
157
+ * vouch be indistinguishable from an agent's own draft. A reviewer reading the
158
+ * frontmatter, or `git log` on the docs repo, can now ask a specific person what
159
+ * they read. Signing is the real answer and it is not this one; nothing here
160
+ * pretends otherwise.
161
+ *
162
+ * `user.email` is what is required — it is the field git itself refuses to
163
+ * commit without, so a repository where a person has ever committed has one —
164
+ * and `user.name` rides along when it is set.
165
+ */
166
+ export async function gitIdentity(repoDir) {
167
+ // The environment first, because that is git's own precedence: GIT_COMMITTER_*
168
+ // overrides `user.*` for the identity git records, and GIT_AUTHOR_* behind it.
169
+ // Reading them is loam agreeing with git rather than inventing a second rule —
170
+ // and it is the only identity a CI job or a container has, where there is no
171
+ // `user.email` anywhere and running `git config --global` first would be a
172
+ // step nobody documents.
173
+ const fromEnv = identity(process.env.GIT_COMMITTER_NAME ?? process.env.GIT_AUTHOR_NAME, process.env.GIT_COMMITTER_EMAIL ?? process.env.GIT_AUTHOR_EMAIL);
174
+ if (fromEnv !== null)
175
+ return fromEnv;
176
+ const [name, email] = await Promise.all([
177
+ gitConfig(repoDir, "user.name"),
178
+ gitConfig(repoDir, "user.email"),
179
+ ]);
180
+ return identity(name ?? undefined, email ?? undefined);
181
+ }
182
+ /** `Name <email>`, or the bare email, or null — the one spelling of the stamp. */
183
+ function identity(name, email) {
184
+ const e = email?.trim();
185
+ if (e === undefined || e === "")
186
+ return null;
187
+ const n = name?.trim();
188
+ return n === undefined || n === "" ? e : `${n} <${e}>`;
189
+ }
190
+ /**
191
+ * One `git config --get` value, or null for every way it can fail to be one:
192
+ * unset (exit 1), not a repository, git not installed, a timeout. The caller
193
+ * distinguishes none of them, and should not — they all mean "git will not tell
194
+ * us who this is", and the fix is the same sentence in each case.
195
+ */
196
+ async function gitConfig(repoDir, key) {
197
+ const a = await gitText(repoDir, ["config", "--get", key]);
198
+ const value = a.out.trim();
199
+ return a.code === 0 && !a.overflowed && value !== "" ? value : null;
200
+ }
201
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/core/provenance/git.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Subprocess questions to git: what the repository tracks, what it ignores,\n * and who is working in it. Four questions, one spawn (`gitText`), one\n * timeout, one doctrine — every way git can decline to answer (not a\n * repository, not installed, a non-zero exit, a timeout) reads as \"git will\n * not say\", never as an error a caller must handle. No denominator, no\n * finding. The subsystem surface's own questions (dirty paths, rename hops,\n * the one blessed `git add`) live in `./gitq/`, asked through the same\n * `gitText` and so under the same timeout and output cap.\n *\n * Beside this module's own four questions live the neutral ANSWER-SHAPE\n * helpers — `gitText`, `GitAnswer`, `gitSaid`, `declineDetail`,\n * `collectStderr` — shared by the two modules that carry git's words to a\n * user: `core/diff/base-git.ts` (which REFUSES when git declines, because a\n * silently empty base reports the fleet as added) and `./gitq/vouched-ancestor.ts`\n * (which DEGRADES to \"full read\", because a reading list may only ever grow\n * when nobody could look). The helpers are spawn-and-capture with no verdict\n * in them: the consequence of a decline belongs to each caller and is stated\n * there — sharing the mechanics is what keeps a hardening (an env pin, a cap\n * change) from landing in one of two byte-identical copies.\n */\nimport { spawn } from \"node:child_process\";\n\n/** How long the digest waits on git before deciding it learned nothing. */\nexport const GIT_TIMEOUT_MS = 10_000;\n\n/**\n * How much a git answer may SAY. The three streamed reads below accumulated\n * without bound — a fleet repo's ls-files fits in single-digit MiB, so the\n * cap is generous, and past it the child is killed and the doctrine answers\n * exactly as for any other way git declines: null, or the empty set — \"git\n * will not say\", never a truncated denominator presented as the whole one.\n */\nconst MAX_GIT_OUTPUT_BYTES = 64 * 1024 * 1024;\n\n/**\n * Accumulate a child's stdout up to the cap; past it, kill the child and\n * remember why. One helper because the three readers below had three copies\n * of the same `out += chunk` line, which is where an unbounded buffer hides;\n * every text question now reaches it through `gitText`, so it is private.\n */\nfunction collectStdout(child: import(\"node:child_process\").ChildProcess): { text: () => string; overflowed: () => boolean } {\n let out = \"\";\n let overflowed = false;\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n if (overflowed) return;\n if (out.length + chunk.length > MAX_GIT_OUTPUT_BYTES) {\n overflowed = true;\n child.kill();\n return;\n }\n out += chunk;\n });\n return { text: () => out, overflowed: () => overflowed };\n}\n\n/**\n * How much of git's stderr an outcome may quote. The point is the first\n * `fatal:` line, not a transcript; past the cap the words are dropped, never\n * the outcome.\n */\nconst STDERR_CAP = 2048;\n\n/** Everything one git question can come back as. `code` is null when the child never ran or was killed. */\nexport interface GitAnswer {\n code: number | null;\n out: string;\n err: string;\n /** The spawn itself failed — git is not installed, or cannot be started. */\n spawnError?: string;\n overflowed: boolean;\n}\n\n/** Accumulate a child's stderr up to the cap; past it, keep what is held. */\nexport function collectStderr(child: import(\"node:child_process\").ChildProcess): () => string {\n let err = \"\";\n child.stderr?.setEncoding(\"utf8\");\n child.stderr?.on(\"data\", (chunk: string) => {\n if (err.length < STDERR_CAP) err = (err + chunk).slice(0, STDERR_CAP);\n });\n return () => err;\n}\n\n/**\n * One git question, stdout as text, stderr held for quoting. No verdict here\n * — see the banner: what a decline MEANS belongs to the caller. `input`, when\n * given, is written to git's stdin and closed (`check-ignore --stdin`); every\n * other question leaves stdin unopened.\n */\nexport async function gitText(cwd: string, args: string[], input?: string): Promise<GitAnswer> {\n return new Promise<GitAnswer>((done) => {\n const child = spawn(\"git\", args, {\n cwd,\n stdio: [input === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n timeout: GIT_TIMEOUT_MS,\n });\n const out = collectStdout(child);\n const err = collectStderr(child);\n child.on(\"error\", (e) =>\n done({ code: null, out: \"\", err: \"\", spawnError: e.message, overflowed: false }),\n );\n child.on(\"close\", (code) =>\n done({ code, out: out.text(), err: err(), overflowed: out.overflowed() }),\n );\n if (input === undefined) return;\n // A git that died before reading its input hands us EPIPE; the close\n // handler above is what decides the outcome either way.\n child.stdin?.on(\"error\", () => undefined);\n child.stdin?.end(input);\n });\n}\n\n/** The first line of git's stderr, trimmed — the quotable half of a decline. */\nexport function gitSaid(answer: GitAnswer): string {\n const line = answer.err.split(\"\\n\").find((l) => l.trim() !== \"\");\n return line === undefined ? \"\" : line.trim();\n}\n\n/** The one sentence a decline collapses to when git left no words behind. */\nexport function declineDetail(answer: GitAnswer): string {\n if (answer.spawnError !== undefined) return `git could not be started: ${answer.spawnError}.`;\n const said = gitSaid(answer);\n return said === \"\" ? \"git answered nothing (killed or timed out).\" : `git said: ${said}`;\n}\n\n/**\n * What this repository considers its own, as repo-relative paths — or null for\n * every way git can decline to say: not a repository, not installed, a timeout,\n * a non-zero exit. The caller distinguishes none of them, exactly as\n * `gitConfig` does not, because they all mean the same thing: there is no\n * denominator here, so there is nothing to report.\n *\n * `-z` rather than the default line output: git QUOTES paths containing spaces\n * or non-ASCII bytes when it is writing lines, so a service with one such file\n * would have had a phantom top-level directory named `\"src` in its untouched\n * list.\n */\nexport async function gitTrackedFiles(repoDir: string): Promise<string[] | null> {\n const a = await gitText(repoDir, [\"ls-files\", \"-z\", \"--cached\", \"--exclude-standard\"]);\n return a.code === 0 && !a.overflowed ? a.out.split(\"\\0\").filter((p) => p !== \"\") : null;\n}\n\n/**\n * Which of these repo-relative paths the repository ignores, asked once for the\n * whole list. `git check-ignore` is the authority on purpose — it reads\n * `.gitignore` at every level, `.git/info/exclude` and the user's global\n * excludes, and it already knows that a TRACKED file is not ignored no matter\n * what a pattern says, which is the distinction a re-implementation always gets\n * wrong.\n *\n * Every failure answers \"nothing is ignored\": exit 1 is git saying so, exit 128\n * is \"not a git repository\", a spawn error is git not being installed, and a\n * timeout is a repository too strange to wait for. None of them justify\n * dropping a file from a digest a person is going to sign.\n */\nexport async function gitIgnoredPaths(repoDir: string, rels: string[]): Promise<Set<string>> {\n if (rels.length === 0) return new Set();\n const a = await gitText(repoDir, [\"check-ignore\", \"--stdin\", \"-z\"], rels.join(\"\\0\") + \"\\0\");\n // 0: some paths are ignored and are on stdout. 1: none are — an empty\n // answer, not a failure. Anything else, the overflow and a spawn failure\n // included: we learned nothing, and nothing is ignored.\n return (a.code === 0 || a.code === 1) && !a.overflowed\n ? new Set(a.out.split(\"\\0\").filter((s) => s.length > 0))\n : new Set();\n}\n\n/**\n * Who git says is working in this repository — `Name <email>`, or null when git\n * cannot answer.\n *\n * This is the only identity loam has, and it is deliberately a weak one: git\n * config is a text file anybody can edit, so `vouched_by` is a name, not a\n * signature, and it proves nothing cryptographically. What it does is make the\n * claim ATTRIBUTABLE — a `status: verified` with nobody's name against it says\n * only that some process wrote the word, which is exactly the state that let a\n * vouch be indistinguishable from an agent's own draft. A reviewer reading the\n * frontmatter, or `git log` on the docs repo, can now ask a specific person what\n * they read. Signing is the real answer and it is not this one; nothing here\n * pretends otherwise.\n *\n * `user.email` is what is required — it is the field git itself refuses to\n * commit without, so a repository where a person has ever committed has one —\n * and `user.name` rides along when it is set.\n */\nexport async function gitIdentity(repoDir: string): Promise<string | null> {\n // The environment first, because that is git's own precedence: GIT_COMMITTER_*\n // overrides `user.*` for the identity git records, and GIT_AUTHOR_* behind it.\n // Reading them is loam agreeing with git rather than inventing a second rule —\n // and it is the only identity a CI job or a container has, where there is no\n // `user.email` anywhere and running `git config --global` first would be a\n // step nobody documents.\n const fromEnv = identity(\n process.env.GIT_COMMITTER_NAME ?? process.env.GIT_AUTHOR_NAME,\n process.env.GIT_COMMITTER_EMAIL ?? process.env.GIT_AUTHOR_EMAIL,\n );\n if (fromEnv !== null) return fromEnv;\n const [name, email] = await Promise.all([\n gitConfig(repoDir, \"user.name\"),\n gitConfig(repoDir, \"user.email\"),\n ]);\n return identity(name ?? undefined, email ?? undefined);\n}\n\n/** `Name <email>`, or the bare email, or null — the one spelling of the stamp. */\nfunction identity(name: string | undefined, email: string | undefined): string | null {\n const e = email?.trim();\n if (e === undefined || e === \"\") return null;\n const n = name?.trim();\n return n === undefined || n === \"\" ? e : `${n} <${e}>`;\n}\n\n/**\n * One `git config --get` value, or null for every way it can fail to be one:\n * unset (exit 1), not a repository, git not installed, a timeout. The caller\n * distinguishes none of them, and should not — they all mean \"git will not tell\n * us who this is\", and the fix is the same sentence in each case.\n */\nasync function gitConfig(repoDir: string, key: string): Promise<string | null> {\n const a = await gitText(repoDir, [\"config\", \"--get\", key]);\n const value = a.out.trim();\n return a.code === 0 && !a.overflowed && value !== \"\" ? value : null;\n}\n"]}