@descryy/core 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/dist/budget/reply.d.ts +11 -46
  2. package/dist/budget/reply.d.ts.map +1 -1
  3. package/dist/budget/reply.js +10 -39
  4. package/dist/budget/reply.js.map +1 -1
  5. package/dist/budget/size.d.ts +2 -21
  6. package/dist/budget/size.d.ts.map +1 -1
  7. package/dist/budget/size.js +3 -24
  8. package/dist/budget/size.js.map +1 -1
  9. package/dist/capabilities/preconditions.d.ts +7 -68
  10. package/dist/capabilities/preconditions.d.ts.map +1 -1
  11. package/dist/capabilities/preconditions.js +6 -57
  12. package/dist/capabilities/preconditions.js.map +1 -1
  13. package/dist/contracts/engine.d.ts +23 -11
  14. package/dist/contracts/engine.d.ts.map +1 -1
  15. package/dist/contracts/engine.js +23 -11
  16. package/dist/contracts/engine.js.map +1 -1
  17. package/dist/contracts/orphans.d.ts +18 -122
  18. package/dist/contracts/orphans.d.ts.map +1 -1
  19. package/dist/contracts/orphans.js +36 -134
  20. package/dist/contracts/orphans.js.map +1 -1
  21. package/dist/contracts/paths.d.ts +4 -114
  22. package/dist/contracts/paths.d.ts.map +1 -1
  23. package/dist/contracts/paths.js +7 -140
  24. package/dist/contracts/paths.js.map +1 -1
  25. package/dist/contracts/shapes.d.ts +13 -66
  26. package/dist/contracts/shapes.d.ts.map +1 -1
  27. package/dist/contracts/shapes.js +20 -91
  28. package/dist/contracts/shapes.js.map +1 -1
  29. package/dist/governance/budget.d.ts +12 -48
  30. package/dist/governance/budget.d.ts.map +1 -1
  31. package/dist/governance/budget.js +12 -48
  32. package/dist/governance/budget.js.map +1 -1
  33. package/dist/governance/candidate-boundary.d.ts +4 -32
  34. package/dist/governance/candidate-boundary.d.ts.map +1 -1
  35. package/dist/governance/candidate-boundary.js +4 -32
  36. package/dist/governance/candidate-boundary.js.map +1 -1
  37. package/dist/governance/escalation.d.ts +7 -45
  38. package/dist/governance/escalation.d.ts.map +1 -1
  39. package/dist/governance/escalation.js +7 -45
  40. package/dist/governance/escalation.js.map +1 -1
  41. package/dist/governance/fact-boundary.d.ts +7 -49
  42. package/dist/governance/fact-boundary.d.ts.map +1 -1
  43. package/dist/governance/fact-boundary.js +5 -43
  44. package/dist/governance/fact-boundary.js.map +1 -1
  45. package/dist/governance/finding-funnel.d.ts +11 -72
  46. package/dist/governance/finding-funnel.d.ts.map +1 -1
  47. package/dist/governance/finding-funnel.js +9 -68
  48. package/dist/governance/finding-funnel.js.map +1 -1
  49. package/dist/graph/build.d.ts +9 -90
  50. package/dist/graph/build.d.ts.map +1 -1
  51. package/dist/graph/build.js +15 -62
  52. package/dist/graph/build.js.map +1 -1
  53. package/dist/graph/cross-language.d.ts +4 -43
  54. package/dist/graph/cross-language.d.ts.map +1 -1
  55. package/dist/graph/cross-language.js +9 -77
  56. package/dist/graph/cross-language.js.map +1 -1
  57. package/dist/graph/merge.d.ts +8 -88
  58. package/dist/graph/merge.d.ts.map +1 -1
  59. package/dist/graph/merge.js +9 -93
  60. package/dist/graph/merge.js.map +1 -1
  61. package/dist/graph/observed-tests.d.ts +7 -68
  62. package/dist/graph/observed-tests.d.ts.map +1 -1
  63. package/dist/graph/observed-tests.js +5 -60
  64. package/dist/graph/observed-tests.js.map +1 -1
  65. package/dist/graph/persist.d.ts +2 -25
  66. package/dist/graph/persist.d.ts.map +1 -1
  67. package/dist/graph/persist.js +2 -25
  68. package/dist/graph/persist.js.map +1 -1
  69. package/dist/graph/runtime-confirmation.d.ts +14 -91
  70. package/dist/graph/runtime-confirmation.d.ts.map +1 -1
  71. package/dist/graph/runtime-confirmation.js +19 -103
  72. package/dist/graph/runtime-confirmation.js.map +1 -1
  73. package/dist/ledger/mint.d.ts +9 -43
  74. package/dist/ledger/mint.d.ts.map +1 -1
  75. package/dist/ledger/mint.js +15 -65
  76. package/dist/ledger/mint.js.map +1 -1
  77. package/dist/ledger/resolve.d.ts +13 -81
  78. package/dist/ledger/resolve.d.ts.map +1 -1
  79. package/dist/ledger/resolve.js +13 -76
  80. package/dist/ledger/resolve.js.map +1 -1
  81. package/dist/multipr/fingerprint.d.ts +5 -46
  82. package/dist/multipr/fingerprint.d.ts.map +1 -1
  83. package/dist/multipr/fingerprint.js +22 -74
  84. package/dist/multipr/fingerprint.js.map +1 -1
  85. package/dist/multipr/hidden-dependency.d.ts +13 -73
  86. package/dist/multipr/hidden-dependency.d.ts.map +1 -1
  87. package/dist/multipr/hidden-dependency.js +12 -63
  88. package/dist/multipr/hidden-dependency.js.map +1 -1
  89. package/dist/multipr/mechanical.d.ts +25 -160
  90. package/dist/multipr/mechanical.d.ts.map +1 -1
  91. package/dist/multipr/mechanical.js +21 -137
  92. package/dist/multipr/mechanical.js.map +1 -1
  93. package/dist/multipr/migration-heads.d.ts +18 -105
  94. package/dist/multipr/migration-heads.d.ts.map +1 -1
  95. package/dist/multipr/migration-heads.js +15 -84
  96. package/dist/multipr/migration-heads.js.map +1 -1
  97. package/dist/multipr/overlap.d.ts +16 -94
  98. package/dist/multipr/overlap.d.ts.map +1 -1
  99. package/dist/multipr/overlap.js +25 -105
  100. package/dist/multipr/overlap.js.map +1 -1
  101. package/dist/multipr/scope-store.d.ts +15 -80
  102. package/dist/multipr/scope-store.d.ts.map +1 -1
  103. package/dist/multipr/scope-store.js +17 -87
  104. package/dist/multipr/scope-store.js.map +1 -1
  105. package/dist/multipr/superseded.d.ts +10 -95
  106. package/dist/multipr/superseded.d.ts.map +1 -1
  107. package/dist/multipr/superseded.js +7 -60
  108. package/dist/multipr/superseded.js.map +1 -1
  109. package/dist/query/confirmed-facts.d.ts +12 -58
  110. package/dist/query/confirmed-facts.d.ts.map +1 -1
  111. package/dist/query/confirmed-facts.js +8 -47
  112. package/dist/query/confirmed-facts.js.map +1 -1
  113. package/dist/query/declared-value-closure.d.ts +13 -104
  114. package/dist/query/declared-value-closure.d.ts.map +1 -1
  115. package/dist/query/declared-value-closure.js +15 -104
  116. package/dist/query/declared-value-closure.js.map +1 -1
  117. package/dist/query/memory.d.ts +4 -16
  118. package/dist/query/memory.d.ts.map +1 -1
  119. package/dist/query/memory.js +9 -22
  120. package/dist/query/memory.js.map +1 -1
  121. package/dist/query/prominence.d.ts +6 -55
  122. package/dist/query/prominence.d.ts.map +1 -1
  123. package/dist/query/prominence.js +6 -55
  124. package/dist/query/prominence.js.map +1 -1
  125. package/dist/query/provider.d.ts +27 -93
  126. package/dist/query/provider.d.ts.map +1 -1
  127. package/dist/query/provider.js +8 -29
  128. package/dist/query/provider.js.map +1 -1
  129. package/dist/query/queries.d.ts +15 -65
  130. package/dist/query/queries.d.ts.map +1 -1
  131. package/dist/query/queries.js +30 -104
  132. package/dist/query/queries.js.map +1 -1
  133. package/dist/query/refusal-fetch.d.ts +8 -85
  134. package/dist/query/refusal-fetch.d.ts.map +1 -1
  135. package/dist/query/refusal-fetch.js +11 -93
  136. package/dist/query/refusal-fetch.js.map +1 -1
  137. package/dist/query/refusal-questions.d.ts +17 -92
  138. package/dist/query/refusal-questions.d.ts.map +1 -1
  139. package/dist/query/refusal-questions.js +14 -78
  140. package/dist/query/refusal-questions.js.map +1 -1
  141. package/dist/query/resolution-floor.d.ts +3 -23
  142. package/dist/query/resolution-floor.d.ts.map +1 -1
  143. package/dist/query/resolution-floor.js +3 -23
  144. package/dist/query/resolution-floor.js.map +1 -1
  145. package/dist/query/root-cause-score.d.ts +11 -161
  146. package/dist/query/root-cause-score.d.ts.map +1 -1
  147. package/dist/query/root-cause-score.js +6 -137
  148. package/dist/query/root-cause-score.js.map +1 -1
  149. package/dist/query/row-closure-picture.d.ts +5 -67
  150. package/dist/query/row-closure-picture.d.ts.map +1 -1
  151. package/dist/query/row-closure-picture.js +6 -67
  152. package/dist/query/row-closure-picture.js.map +1 -1
  153. package/dist/query/similar-incidents.d.ts +6 -41
  154. package/dist/query/similar-incidents.d.ts.map +1 -1
  155. package/dist/query/similar-incidents.js +15 -69
  156. package/dist/query/similar-incidents.js.map +1 -1
  157. package/dist/query/sqlite.d.ts +3 -7
  158. package/dist/query/sqlite.d.ts.map +1 -1
  159. package/dist/query/sqlite.js +9 -19
  160. package/dist/query/sqlite.js.map +1 -1
  161. package/dist/query/test-coverage.d.ts +5 -45
  162. package/dist/query/test-coverage.d.ts.map +1 -1
  163. package/dist/query/test-coverage.js +10 -53
  164. package/dist/query/test-coverage.js.map +1 -1
  165. package/dist/query/traverse.d.ts +22 -126
  166. package/dist/query/traverse.d.ts.map +1 -1
  167. package/dist/query/traverse.js +25 -126
  168. package/dist/query/traverse.js.map +1 -1
  169. package/dist/query/unresolved.d.ts +19 -164
  170. package/dist/query/unresolved.d.ts.map +1 -1
  171. package/dist/query/unresolved.js +11 -138
  172. package/dist/query/unresolved.js.map +1 -1
  173. package/dist/query/verification-status.d.ts +12 -109
  174. package/dist/query/verification-status.d.ts.map +1 -1
  175. package/dist/query/verification-status.js +9 -99
  176. package/dist/query/verification-status.js.map +1 -1
  177. package/dist/recording/migrate.d.ts +4 -10
  178. package/dist/recording/migrate.d.ts.map +1 -1
  179. package/dist/recording/migrate.js +4 -10
  180. package/dist/recording/migrate.js.map +1 -1
  181. package/dist/recording/reader.d.ts +2 -7
  182. package/dist/recording/reader.d.ts.map +1 -1
  183. package/dist/recording/reader.js +2 -7
  184. package/dist/recording/reader.js.map +1 -1
  185. package/dist/recording/redact.d.ts +6 -57
  186. package/dist/recording/redact.d.ts.map +1 -1
  187. package/dist/recording/redact.js +8 -64
  188. package/dist/recording/redact.js.map +1 -1
  189. package/dist/recording/schema.d.ts +3 -38
  190. package/dist/recording/schema.d.ts.map +1 -1
  191. package/dist/recording/schema.js +3 -38
  192. package/dist/recording/schema.js.map +1 -1
  193. package/dist/recording/writer.d.ts +11 -74
  194. package/dist/recording/writer.d.ts.map +1 -1
  195. package/dist/recording/writer.js +3 -43
  196. package/dist/recording/writer.js.map +1 -1
  197. package/dist/scoping/fanout.d.ts +6 -68
  198. package/dist/scoping/fanout.d.ts.map +1 -1
  199. package/dist/scoping/fanout.js +6 -68
  200. package/dist/scoping/fanout.js.map +1 -1
  201. package/dist/scoping/score.d.ts +20 -70
  202. package/dist/scoping/score.d.ts.map +1 -1
  203. package/dist/scoping/score.js +20 -70
  204. package/dist/scoping/score.js.map +1 -1
  205. package/dist/scoping/tiers.d.ts +4 -16
  206. package/dist/scoping/tiers.d.ts.map +1 -1
  207. package/dist/scoping/tiers.js +4 -16
  208. package/dist/scoping/tiers.js.map +1 -1
  209. package/dist/scoping/traverse.d.ts +3 -25
  210. package/dist/scoping/traverse.d.ts.map +1 -1
  211. package/dist/scoping/traverse.js +14 -49
  212. package/dist/scoping/traverse.js.map +1 -1
  213. package/dist/scoping/weights.d.ts +10 -74
  214. package/dist/scoping/weights.d.ts.map +1 -1
  215. package/dist/scoping/weights.js +14 -86
  216. package/dist/scoping/weights.js.map +1 -1
  217. package/dist/sources/confirmed/incidents.d.ts +5 -35
  218. package/dist/sources/confirmed/incidents.d.ts.map +1 -1
  219. package/dist/sources/confirmed/incidents.js +14 -48
  220. package/dist/sources/confirmed/incidents.js.map +1 -1
  221. package/dist/sources/git/diff.d.ts +93 -63
  222. package/dist/sources/git/diff.d.ts.map +1 -1
  223. package/dist/sources/git/diff.js +200 -81
  224. package/dist/sources/git/diff.js.map +1 -1
  225. package/dist/sources/git/env.d.ts +7 -0
  226. package/dist/sources/git/env.d.ts.map +1 -1
  227. package/dist/sources/git/env.js +10 -11
  228. package/dist/sources/git/env.js.map +1 -1
  229. package/dist/sources/git/history.d.ts +64 -84
  230. package/dist/sources/git/history.d.ts.map +1 -1
  231. package/dist/sources/git/history.js +141 -112
  232. package/dist/sources/git/history.js.map +1 -1
  233. package/dist/sources/git/incidents.d.ts +13 -75
  234. package/dist/sources/git/incidents.d.ts.map +1 -1
  235. package/dist/sources/git/incidents.js +21 -91
  236. package/dist/sources/git/incidents.js.map +1 -1
  237. package/dist/sources/git/index.d.ts +5 -3
  238. package/dist/sources/git/index.d.ts.map +1 -1
  239. package/dist/sources/git/index.js +3 -2
  240. package/dist/sources/git/index.js.map +1 -1
  241. package/dist/sources/git/source.d.ts +9 -79
  242. package/dist/sources/git/source.d.ts.map +1 -1
  243. package/dist/sources/git/source.js +33 -133
  244. package/dist/sources/git/source.js.map +1 -1
  245. package/dist/sources/migrations/across-change.d.ts +94 -0
  246. package/dist/sources/migrations/across-change.d.ts.map +1 -0
  247. package/dist/sources/migrations/across-change.js +278 -0
  248. package/dist/sources/migrations/across-change.js.map +1 -0
  249. package/dist/sources/migrations/dialects.d.ts +20 -36
  250. package/dist/sources/migrations/dialects.d.ts.map +1 -1
  251. package/dist/sources/migrations/dialects.js +11 -36
  252. package/dist/sources/migrations/dialects.js.map +1 -1
  253. package/dist/sources/migrations/index.d.ts +3 -1
  254. package/dist/sources/migrations/index.d.ts.map +1 -1
  255. package/dist/sources/migrations/index.js +2 -1
  256. package/dist/sources/migrations/index.js.map +1 -1
  257. package/dist/sources/migrations/read.d.ts +14 -79
  258. package/dist/sources/migrations/read.d.ts.map +1 -1
  259. package/dist/sources/migrations/read.js +14 -89
  260. package/dist/sources/migrations/read.js.map +1 -1
  261. package/dist/sources/workspace/workspace.d.ts +6 -42
  262. package/dist/sources/workspace/workspace.d.ts.map +1 -1
  263. package/dist/sources/workspace/workspace.js +10 -53
  264. package/dist/sources/workspace/workspace.js.map +1 -1
  265. package/dist/store/driver/driver.d.ts +9 -38
  266. package/dist/store/driver/driver.d.ts.map +1 -1
  267. package/dist/store/driver/driver.js +4 -22
  268. package/dist/store/driver/driver.js.map +1 -1
  269. package/dist/store/driver/node-sqlite.d.ts +3 -12
  270. package/dist/store/driver/node-sqlite.d.ts.map +1 -1
  271. package/dist/store/driver/node-sqlite.js +4 -18
  272. package/dist/store/driver/node-sqlite.js.map +1 -1
  273. package/dist/store/index.d.ts +2 -7
  274. package/dist/store/index.d.ts.map +1 -1
  275. package/dist/store/index.js +4 -10
  276. package/dist/store/index.js.map +1 -1
  277. package/dist/store/migrate.d.ts +14 -50
  278. package/dist/store/migrate.d.ts.map +1 -1
  279. package/dist/store/migrate.js +15 -52
  280. package/dist/store/migrate.js.map +1 -1
  281. package/dist/store/reader.d.ts +19 -84
  282. package/dist/store/reader.d.ts.map +1 -1
  283. package/dist/store/reader.js +25 -92
  284. package/dist/store/reader.js.map +1 -1
  285. package/dist/store/schema.d.ts +14 -76
  286. package/dist/store/schema.d.ts.map +1 -1
  287. package/dist/store/schema.js +14 -76
  288. package/dist/store/schema.js.map +1 -1
  289. package/dist/store/writer.d.ts +14 -88
  290. package/dist/store/writer.d.ts.map +1 -1
  291. package/dist/store/writer.js +29 -123
  292. package/dist/store/writer.js.map +1 -1
  293. package/dist/tiers/certify.d.ts +46 -281
  294. package/dist/tiers/certify.d.ts.map +1 -1
  295. package/dist/tiers/certify.js +46 -226
  296. package/dist/tiers/certify.js.map +1 -1
  297. package/dist/tiers/ladder.d.ts +7 -51
  298. package/dist/tiers/ladder.d.ts.map +1 -1
  299. package/dist/tiers/ladder.js +13 -89
  300. package/dist/tiers/ladder.js.map +1 -1
  301. package/dist/validation/attributes.d.ts +6 -55
  302. package/dist/validation/attributes.d.ts.map +1 -1
  303. package/dist/validation/attributes.js +6 -55
  304. package/dist/validation/attributes.js.map +1 -1
  305. package/dist/validation/config-graph.d.ts +7 -56
  306. package/dist/validation/config-graph.d.ts.map +1 -1
  307. package/dist/validation/config-graph.js +15 -61
  308. package/dist/validation/config-graph.js.map +1 -1
  309. package/dist/validation/env.d.ts +47 -8
  310. package/dist/validation/env.d.ts.map +1 -1
  311. package/dist/validation/env.js +119 -31
  312. package/dist/validation/env.js.map +1 -1
  313. package/dist/validation/index.d.ts +2 -0
  314. package/dist/validation/index.d.ts.map +1 -1
  315. package/dist/validation/index.js +1 -0
  316. package/dist/validation/index.js.map +1 -1
  317. package/dist/validation/join-substitution.d.ts +22 -120
  318. package/dist/validation/join-substitution.d.ts.map +1 -1
  319. package/dist/validation/join-substitution.js +13 -90
  320. package/dist/validation/join-substitution.js.map +1 -1
  321. package/dist/validation/migration-integrity.d.ts +11 -72
  322. package/dist/validation/migration-integrity.d.ts.map +1 -1
  323. package/dist/validation/migration-integrity.js +16 -79
  324. package/dist/validation/migration-integrity.js.map +1 -1
  325. package/dist/validation/migrations.d.ts +22 -101
  326. package/dist/validation/migrations.d.ts.map +1 -1
  327. package/dist/validation/migrations.js +19 -83
  328. package/dist/validation/migrations.js.map +1 -1
  329. package/dist/validation/nodes.d.ts +3 -1
  330. package/dist/validation/nodes.d.ts.map +1 -1
  331. package/dist/validation/nodes.js +3 -1
  332. package/dist/validation/nodes.js.map +1 -1
  333. package/dist/validation/orm-registration.d.ts +106 -0
  334. package/dist/validation/orm-registration.d.ts.map +1 -0
  335. package/dist/validation/orm-registration.js +191 -0
  336. package/dist/validation/orm-registration.js.map +1 -0
  337. package/dist/validation/rollback.d.ts +10 -73
  338. package/dist/validation/rollback.d.ts.map +1 -1
  339. package/dist/validation/rollback.js +15 -82
  340. package/dist/validation/rollback.js.map +1 -1
  341. package/dist/validation/route-drift.d.ts +9 -62
  342. package/dist/validation/route-drift.d.ts.map +1 -1
  343. package/dist/validation/route-drift.js +7 -52
  344. package/dist/validation/route-drift.js.map +1 -1
  345. package/dist/validation/sources.d.ts +16 -94
  346. package/dist/validation/sources.d.ts.map +1 -1
  347. package/dist/validation/sources.js +51 -147
  348. package/dist/validation/sources.js.map +1 -1
  349. package/dist/worker/pool.d.ts +6 -45
  350. package/dist/worker/pool.d.ts.map +1 -1
  351. package/dist/worker/pool.js +5 -42
  352. package/dist/worker/pool.js.map +1 -1
  353. package/dist/worker/protocol.d.ts +7 -20
  354. package/dist/worker/protocol.d.ts.map +1 -1
  355. package/dist/worker/protocol.js +3 -10
  356. package/dist/worker/protocol.js.map +1 -1
  357. package/dist/worker/traversal.worker.d.ts +2 -21
  358. package/dist/worker/traversal.worker.d.ts.map +1 -1
  359. package/dist/worker/traversal.worker.js +4 -23
  360. package/dist/worker/traversal.worker.js.map +1 -1
  361. package/package.json +11 -2
@@ -1,38 +1,8 @@
1
- /**
2
- * The `IRSource` that projects developer-confirmed incidents into the graph.
3
- *
4
- * ## Why a source, and not a direct write
5
- *
6
- * A `ConfirmedIncident` lives in `.descry/config.json` because it is testimony
7
- * — a developer fixed something and said so, and no commit records that they
8
- * said it (see the type's own doc). But a store is derived data: DEC-017 drops
9
- * every derived table on a schema change and rebuilds from source. So a
10
- * confirmed incident written *only* into the graph would survive until the next
11
- * IR-version bump and then vanish, which is the failure the EARNED partition
12
- * exists to prevent — arriving through a writer that simply did not think about
13
- * it.
14
- *
15
- * Making this a source solves it by construction. The file is the record; the
16
- * graph is a projection of the record; every `analyze` re-projects. There is no
17
- * migration to write and no earned table to extend, and the same discipline
18
- * every other producer in this system already follows applies unchanged: a
19
- * batch in, `writeBatch` out, invalidation by producer id.
20
- *
21
- * ## Identity
22
- *
23
- * The `INCIDENT` node keys on `confirmed:<confirmedAt>:<summary>` — the moment
24
- * the developer said it, plus what they said. Deliberately **not** the file set:
25
- * node ids never contain a path (renames churn them and silently destroy
26
- * incident links), and a developer correcting the file list of an incident they
27
- * already recorded is editing one incident rather than creating a second.
28
- *
29
- * ## What it does not do
30
- *
31
- * It mints no `FIX_PATTERN` unless the record names a fixing commit, and it
32
- * never infers one from HEAD. "The developer confirmed an incident" and "the
33
- * developer confirmed which commit fixed it" are separate claims, and only the
34
- * second one licenses a `FIXED_BY` edge.
35
- */
1
+ /** IRSource projecting developer-confirmed incidents (`.descry/config.json`)
2
+ * into the graph. A source, not a direct write: a store is derived data
3
+ * (DEC-017 drops it on schema bump), so a direct write would silently
4
+ * vanish. `INCIDENT` keys on `confirmed:<at>:<summary>`, never the file
5
+ * set (no paths in node ids). Mints `FIX_PATTERN` only when a commit is named — never inferred from HEAD. */
36
6
  import { fileQsp, nodeId, } from "@descryy/ir";
37
7
  export const CONFIRMED_INCIDENT_SOURCE_ID = "confirmed-incidents";
38
8
  export const CONFIRMED_INCIDENT_SOURCE_VERSION = "0.1.0";
@@ -50,9 +20,8 @@ export function createConfirmedIncidentSource(options) {
50
20
  // INCIDENT and FIX_PATTERN are workspace-scoped (DEC-054), FILE is
51
21
  // repo-scoped, and `scopeOf` picks between them per type.
52
22
  const scope = { repo, workspace: ctx.root.workspace };
53
- // A record for another repository is not this batch's business. The
54
- // structural refusal `applyConfirmedFacts` makes for the same reason:
55
- // never an inference about a second case.
23
+ // A record for another repo is not this batch's business — same
24
+ // structural refusal `applyConfirmedFacts` makes: never infer across cases.
56
25
  const mine = options.incidents.filter((i) => i.repo === repo);
57
26
  const nodes = [];
58
27
  const edges = [];
@@ -69,9 +38,8 @@ export function createConfirmedIncidentSource(options) {
69
38
  name: path.split("/").pop() ?? path,
70
39
  file: path,
71
40
  range: null,
72
- // A developer naming a path says nothing about what language it is
73
- // written in, and guessing from the extension would be a language
74
- // decision made where none may be made (DEC-026).
41
+ // A path says nothing about language; guessing from extension would
42
+ // be a language decision made where none may be made (DEC-026).
75
43
  language: null,
76
44
  producedBy: PRODUCED_BY,
77
45
  resolution: 0,
@@ -90,9 +58,8 @@ export function createConfirmedIncidentSource(options) {
90
58
  producedBy: PRODUCED_BY,
91
59
  resolution: 0,
92
60
  attrs: {
93
- // The record's own shape decides this, never the caller: a run id
94
- // is present exactly when a run witnessed the failure, and absent
95
- // exactly when a person asserted it.
61
+ // The record's own shape decides this: a run id present means a
62
+ // run witnessed it, absent means a person asserted it.
96
63
  detectedVia: incident.observedInRun === undefined ? "developer-confirmed" : "runtime-observed",
97
64
  ...(incident.observedInRun === undefined ? {} : { observedInRun: incident.observedInRun }),
98
65
  confirmedBy: incident.confirmedBy,
@@ -158,10 +125,9 @@ export function createConfirmedIncidentSource(options) {
158
125
  producedBy: PRODUCED_BY,
159
126
  sourceFiles,
160
127
  skippedFiles: [],
161
- // R0. A person's sentence is not a resolution level at all — the
162
- // reliability consequence lives in `humanAsserted` (DEC-223), a second
163
- // and independent ceiling, and slotting testimony into the R0–R4 ladder
164
- // to express it would be the overclaim that ladder exists to prevent.
128
+ // R0: a person's sentence isn't a resolution level. The reliability
129
+ // consequence lives in `humanAsserted` (DEC-223), a separate ceiling —
130
+ // slotting testimony into R0-R4 would be the overclaim the ladder prevents.
165
131
  reachedResolution: 0,
166
132
  nodes,
167
133
  edges,
@@ -1 +1 @@
1
- {"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../../src/sources/confirmed/incidents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../../src/sources/confirmed/incidents.ts"],"names":[],"mappings":"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"}
@@ -1,48 +1,9 @@
1
1
  /**
2
- * `gitDiff` — a live textual diff between two refs. §18's `get_git_diff`.
3
- *
4
- * `changedFiles` (`history.ts`) already answers "which files changed" — a
5
- * bare path list. This answers "what changed in them" — per-file status and
6
- * line counts always, plus the actual unified-diff patch text when it is
7
- * cheap enough to hand to a model. §4's own worry ("the client's context
8
- * window is not yours to spend") is the reason a patch is never returned
9
- * unconditionally: a single large file rewrite can be tens of thousands of
10
- * tokens, and a caller that wanted only "did this file change and how much"
11
- * pays that cost with no way to decline it. `patchOmittedReason` names why,
12
- * rather than silently shrinking the reply — the empty-denominator rule
13
- * applies to a dropped patch exactly as it does to a dropped finding.
14
- *
15
- * Two size caps here, because one of them bounds nothing on its own:
16
- * `maxPatchBytes` per file, and `maxTotalPatchBytes` across every patch in the
17
- * reply. The second exists because a real 48-file branch diff, with 44 patches
18
- * each *under* the per-file cap, summed to 229KB and hard-failed the call —
19
- * the reply never reached the caller at all, which is the one failure mode a
20
- * disclosure cannot repair after the fact.
21
- *
22
- * And a third above this file, for the same reason one level out: the same
23
- * diff re-run with `maxTotalPatchBytes` correctly enforced still failed, at
24
- * 84,516 characters, because these two caps bound patch text and a reply is
25
- * not only patch text. `MAX_REPLY_BYTES` and `ToolAnswer.fitToBudget` in the
26
- * MCP layer bound the serialized reply itself. Nothing here needs to know
27
- * about that; it is noted because "the aggregate cap is enforced" was once
28
- * mistaken for "the call now succeeds," and they are different claims.
29
- *
30
- * One `git diff` invocation for every file at once, not one per file — a
31
- * PR touching fifty files would otherwise spawn fifty processes. The output
32
- * is a concatenation of per-file blocks, each beginning with a line
33
- * `diff --git a/<path> b/<path>`; parsing splits on that boundary and reads
34
- * the more specific `rename from`/`rename to`/`new file mode`/
35
- * `deleted file mode`/`Binary files … differ`/`---`/`+++` lines within each
36
- * block, which are unambiguous where the `diff --git` header line alone is
37
- * not (a path containing the literal substring `" b/"` defeats that header's
38
- * own regex — an accepted, narrow gap, not a silent one, since every other
39
- * line used here does not share it).
40
- */
41
- /**
42
- * The stable prefix of `patchOmittedReason` when the *total* budget, not the
43
- * per-file cap, is what withheld a patch. Exported so a caller can tell the
44
- * two apart without matching on prose it does not own.
2
+ * §18's `get_git_diff`: live diff, patch text only when cheap — `patchOmittedReason` names why otherwise.
3
+ * Two caps here (`maxPatchBytes` per file, `maxTotalPatchBytes` total) plus a third in the MCP layer
4
+ * (`MAX_REPLY_BYTES`) — measured real failures at 229KB and 84,516 chars before these existed.
45
5
  */
6
+ /** Stable prefix of `patchOmittedReason` when the total budget, not the per-file cap, withheld a patch. */
46
7
  export declare const TOTAL_PATCH_BUDGET_REASON_PREFIX = "the reply's total patch budget";
47
8
  export interface GitDiffFile {
48
9
  /** Path as it is known after the change (the only path for A/M/D). */
@@ -64,35 +25,104 @@ export interface GitDiffOptions {
64
25
  readonly files?: readonly string[];
65
26
  /** A file's patch is omitted (stats are still reported) above this many bytes. Default 20,000. */
66
27
  readonly maxPatchBytes?: number;
67
- /**
68
- * The cap on the sum of all returned patches. Files past it keep their
69
- * stats and name the budget as the reason. Default 40,000.
70
- */
28
+ /** Cap on the sum of all returned patches; files past it keep their stats. Default 40,000. */
71
29
  readonly maxTotalPatchBytes?: number;
72
30
  }
31
+ /** One contiguous run of added lines, in the new (head-side) file. 1-based, inclusive on both ends. */
32
+ export interface LineRange {
33
+ readonly start: number;
34
+ readonly end: number;
35
+ }
73
36
  /**
74
- * `base...head` (three dots), matching `changedFiles`'s own reasoning: two
75
- * dots would include everything changed on `base` since the branch point,
76
- * misattributing someone else's history to this diff.
37
+ * Which lines a unified-diff patch actually *added*, in new-file line numbers.
38
+ *
39
+ * C2 (UAT phase 4): `checkEnvironment`'s `NEW_READ_UNDECLARED` used to call any
40
+ * undeclared read in a `files`-scoped file "new", even a pre-existing read the
41
+ * diff never touched — this is what lets a caller ask the narrower, true
42
+ * question instead: is this line one the diff actually added?
43
+ *
44
+ * Parses the hunk headers (`@@ -a,b +c,d @@`) and walks each hunk counting the
45
+ * new-file line pointer: a `+` line claims the current pointer and advances it,
46
+ * a context line (or blank) advances the pointer without claiming a line, and a
47
+ * `-` line does neither — it consumes no new-file line — but does end any run
48
+ * of consecutive additions in progress, so an added block interrupted by a
49
+ * removed line reports as two ranges, not one spanning the gap. Takes the raw
50
+ * `patch` text `GitDiffFile` already carries; a `null` patch (binary, or
51
+ * withheld by a size budget) has nothing to parse and is the caller's problem
52
+ * to ask for separately — this function only ever sees text that exists.
77
53
  */
54
+ export declare function addedLineRanges(patch: string): readonly LineRange[];
55
+ /** `base...head` (three dots) — two dots would include everything changed on `base` since the branch point. */
78
56
  export declare function gitDiff(cwd: string, base: string, head?: string, options?: GitDiffOptions): Promise<readonly GitDiffFile[]>;
79
57
  export interface GitWorkingTreeDiffOptions extends GitDiffOptions {
80
- /**
81
- * `"unstaged"` (default) — the working tree against the index (`git diff -M`),
82
- * i.e. edits not yet `git add`-ed.
83
- * `"staged"` — the index against `HEAD` (`git diff -M --cached`), i.e. what
84
- * a commit right now would contain.
85
- * `"all"` — the working tree against `HEAD` (`git diff -M HEAD`), staged and
86
- * unstaged combined — everything not yet committed.
87
- */
58
+ /** `"unstaged"` (default): tree vs. index. `"staged"`: index vs. HEAD. `"all"`: tree vs. HEAD (both). */
88
59
  readonly scope?: "unstaged" | "staged" | "all";
89
60
  }
90
61
  /**
91
- * The working-tree counterpart to {@link gitDiff}: a live diff against
92
- * uncommitted state, which no two-revision form of `git diff` can express
93
- * (`HEAD...HEAD` is empty by construction). Reuses the exact same block
94
- * parser, rename detection and patch cap `gitDiff` does — see
95
- * `DEC-NEXT-working-tree-diff-in-core` for why a second parser was rejected.
62
+ * Working-tree counterpart to {@link gitDiff}: a live diff against uncommitted state, which no
63
+ * two-revision `git diff` form can express. Reuses the same parser (`DEC-NEXT-working-tree-diff-in-core`).
96
64
  */
97
65
  export declare function gitWorkingTreeDiff(cwd: string, options?: GitWorkingTreeDiffOptions): Promise<readonly GitDiffFile[]>;
66
+ export interface GitWorkingTreeChangeOptions extends GitWorkingTreeDiffOptions {
67
+ /**
68
+ * Include files git has never seen, as new-file patches.
69
+ *
70
+ * **Off by default**, so no existing caller changes behaviour by upgrading,
71
+ * and because it is a different question: the three scopes above all ask
72
+ * about files git already tracks.
73
+ */
74
+ readonly includeUntracked?: boolean;
75
+ /** Cap on untracked files diffed. The real count is reported regardless. */
76
+ readonly maxUntracked?: number;
77
+ /**
78
+ * Directory prefixes whose contents are not the change under review.
79
+ *
80
+ * The same argument as `--exclude-standard`, for state a `.gitignore` does not
81
+ * happen to cover. Descry writes its own graph database inside the repository
82
+ * and nothing gitignores it, so the first working-tree answer on a fresh
83
+ * checkout listed that database and its two SQLite sidecars as the
84
+ * developer's uncommitted change — three files they did not write, at the top
85
+ * of an answer about what they did.
86
+ *
87
+ * Matched as a path prefix at a segment boundary, so `.descry` excludes
88
+ * `.descry/graph.db` and not `src/.descryfile.ts`.
89
+ */
90
+ readonly exclude?: readonly string[];
91
+ }
92
+ export interface GitWorkingTreeChange {
93
+ readonly files: readonly GitDiffFile[];
94
+ /** Untracked files found, before any cap. */
95
+ readonly untrackedTotal: number;
96
+ /** True when the cap kept some of them out of `files`. */
97
+ readonly untrackedTruncated: boolean;
98
+ }
99
+ /**
100
+ * The working tree as a change set, including files git has never seen.
101
+ *
102
+ * ## Why untracked needs its own mechanism
103
+ *
104
+ * No form of `git diff` reports an untracked file. `git diff HEAD` compares
105
+ * against what the index and `HEAD` hold, and a file git has never seen is in
106
+ * neither — so a working-tree mode built on the scopes above alone still misses
107
+ * the most common shape of work in progress: a new file, written, not yet
108
+ * added. That is exactly the case this was built for.
109
+ *
110
+ * ## `--no-index` rather than `add -N`
111
+ *
112
+ * The usual trick is `git add -N` to give the file an intent-to-add entry, then
113
+ * diff normally. **It writes to the index**, and a read tool that mutates the
114
+ * caller's repository to answer a question is not a read tool — it would also
115
+ * race any real `git add` the developer runs while it works.
116
+ *
117
+ * `git diff --no-index -- /dev/null <path>` needs no index and emits exactly the
118
+ * `new file mode` block the shared parser already handles, with the real path.
119
+ * It exits non-zero when the files differ, which for this call is always, so a
120
+ * non-zero exit here is the success case and is read for its stdout.
121
+ *
122
+ * ## `--exclude-standard` is load-bearing
123
+ *
124
+ * Without it the first answer on any real repository is a dependency directory
125
+ * reported as the developer's uncommitted work.
126
+ */
127
+ export declare function gitWorkingTreeChange(cwd: string, options?: GitWorkingTreeChangeOptions): Promise<GitWorkingTreeChange>;
98
128
  //# sourceMappingURL=diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AA2CH;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,mCAAmC,CAAC;AAEjF,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAmID;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,SAAS,EACb,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAEjC;AAED,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC/D;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC;CAChD;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAIjC"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH,2GAA2G;AAC3G,eAAO,MAAM,gCAAgC,mCAAmC,CAAC;AAEjF,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,kGAAkG;IAClG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8FAA8F;IAC9F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AA+HD,uGAAuG;AACvG,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CA4CnE;AAED,+GAA+G;AAC/G,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,SAAS,EACb,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAEjC;AAED,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC/D,yGAAyG;IACzG,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAIjC;AAKD,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,6CAA6C;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,oBAAoB,CAAC,CA6C/B"}
@@ -1,79 +1,25 @@
1
1
  /**
2
- * `gitDiff` — a live textual diff between two refs. §18's `get_git_diff`.
3
- *
4
- * `changedFiles` (`history.ts`) already answers "which files changed" — a
5
- * bare path list. This answers "what changed in them" — per-file status and
6
- * line counts always, plus the actual unified-diff patch text when it is
7
- * cheap enough to hand to a model. §4's own worry ("the client's context
8
- * window is not yours to spend") is the reason a patch is never returned
9
- * unconditionally: a single large file rewrite can be tens of thousands of
10
- * tokens, and a caller that wanted only "did this file change and how much"
11
- * pays that cost with no way to decline it. `patchOmittedReason` names why,
12
- * rather than silently shrinking the reply — the empty-denominator rule
13
- * applies to a dropped patch exactly as it does to a dropped finding.
14
- *
15
- * Two size caps here, because one of them bounds nothing on its own:
16
- * `maxPatchBytes` per file, and `maxTotalPatchBytes` across every patch in the
17
- * reply. The second exists because a real 48-file branch diff, with 44 patches
18
- * each *under* the per-file cap, summed to 229KB and hard-failed the call —
19
- * the reply never reached the caller at all, which is the one failure mode a
20
- * disclosure cannot repair after the fact.
21
- *
22
- * And a third above this file, for the same reason one level out: the same
23
- * diff re-run with `maxTotalPatchBytes` correctly enforced still failed, at
24
- * 84,516 characters, because these two caps bound patch text and a reply is
25
- * not only patch text. `MAX_REPLY_BYTES` and `ToolAnswer.fitToBudget` in the
26
- * MCP layer bound the serialized reply itself. Nothing here needs to know
27
- * about that; it is noted because "the aggregate cap is enforced" was once
28
- * mistaken for "the call now succeeds," and they are different claims.
29
- *
30
- * One `git diff` invocation for every file at once, not one per file — a
31
- * PR touching fifty files would otherwise spawn fifty processes. The output
32
- * is a concatenation of per-file blocks, each beginning with a line
33
- * `diff --git a/<path> b/<path>`; parsing splits on that boundary and reads
34
- * the more specific `rename from`/`rename to`/`new file mode`/
35
- * `deleted file mode`/`Binary files … differ`/`---`/`+++` lines within each
36
- * block, which are unambiguous where the `diff --git` header line alone is
37
- * not (a path containing the literal substring `" b/"` defeats that header's
38
- * own regex — an accepted, narrow gap, not a silent one, since every other
39
- * line used here does not share it).
2
+ * §18's `get_git_diff`: live diff, patch text only when cheap — `patchOmittedReason` names why otherwise.
3
+ * Two caps here (`maxPatchBytes` per file, `maxTotalPatchBytes` total) plus a third in the MCP layer
4
+ * (`MAX_REPLY_BYTES`) — measured real failures at 229KB and 84,516 chars before these existed.
40
5
  */
41
6
  import { execFile } from "node:child_process";
42
7
  import { promisify } from "node:util";
43
8
  import { applySerializedSizeBudget } from "../../budget/index.js";
44
- import { cleanGitEnv } from "./env.js";
9
+ import { cleanGitEnv, HARDENED_GIT_CONFIG_ARGS } from "./env.js";
45
10
  const execFileAsync = promisify(execFile);
46
- // Always strips GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_COMMON_DIR — see env.ts.
11
+ // Strips GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_COMMON_DIR, applies HARDENED_GIT_CONFIG_ARGS (env.ts, B-11).
47
12
  function run(command, args, options) {
48
- return execFileAsync(command, args, {
13
+ return execFileAsync(command, [...HARDENED_GIT_CONFIG_ARGS, ...args], {
49
14
  ...options,
50
15
  encoding: "utf8",
51
16
  env: cleanGitEnv(),
52
17
  });
53
18
  }
54
19
  const DEFAULT_MAX_PATCH_BYTES = 20_000;
55
- /**
56
- * The cap on the sum of every returned patch. A per-file cap bounds no total:
57
- * 44 files each under the 20,000-byte per-file cap summed to 229KB and
58
- * hard-failed an ordinary 48-file branch diff before the reply was ever
59
- * returned.
60
- *
61
- * Was 80,000, lowered after the same diff was re-run against that value and
62
- * the call *still* failed, at 84,516 characters: 80,000 bytes of patch text
63
- * leaves nothing for the 48 per-file rows, the disclosures and the envelope
64
- * that surround them, so a budget that large is one the reply can never
65
- * actually afford to spend. 40,000 leaves the reply's own size ceiling
66
- * (`MAX_REPLY_BYTES`, in the MCP layer) room to be a backstop rather than the
67
- * thing that fires on every ordinary wide diff — which matters because this
68
- * budget's reason names an action the caller can take and that ceiling's does
69
- * not. A starting value, as before, not a measurement.
70
- */
20
+ /** Cap on the sum of every returned patch — a per-file cap alone let 44 files summed to 229KB hard-fail a real diff. Was 80,000, lowered after 84,516 chars still failed. Starting value. */
71
21
  const DEFAULT_MAX_TOTAL_PATCH_BYTES = 40_000;
72
- /**
73
- * The stable prefix of `patchOmittedReason` when the *total* budget, not the
74
- * per-file cap, is what withheld a patch. Exported so a caller can tell the
75
- * two apart without matching on prose it does not own.
76
- */
22
+ /** Stable prefix of `patchOmittedReason` when the total budget, not the per-file cap, withheld a patch. */
77
23
  export const TOTAL_PATCH_BUDGET_REASON_PREFIX = "the reply's total patch budget";
78
24
  function stripPrefix(path, prefix) {
79
25
  return path.startsWith(prefix) ? path.slice(prefix.length) : path;
@@ -138,7 +84,9 @@ function parseDiffBlock(block) {
138
84
  async function runGitDiff(cwd, revisionArgs, options) {
139
85
  const maxPatchBytes = options.maxPatchBytes ?? DEFAULT_MAX_PATCH_BYTES;
140
86
  const maxTotalPatchBytes = options.maxTotalPatchBytes ?? DEFAULT_MAX_TOTAL_PATCH_BYTES;
141
- const args = ["diff", "-M", ...revisionArgs];
87
+ // --no-ext-diff (B-11): renders real patch text, so a repo-local
88
+ // `diff.external` would actually run here otherwise.
89
+ const args = ["diff", "--no-ext-diff", "-M", ...revisionArgs];
142
90
  if (options.files !== undefined && options.files.length > 0)
143
91
  args.push("--", ...options.files);
144
92
  const { stdout } = await run("git", args, { cwd, maxBuffer: 256 * 1024 * 1024 });
@@ -170,19 +118,13 @@ async function runGitDiff(cwd, revisionArgs, options) {
170
118
  : null,
171
119
  });
172
120
  }
173
- // The aggregate cap, applied after every per-file decision: a file whose
174
- // patch was already withheld (binary, or over its own cap) costs nothing
175
- // here and keeps the reason it already has.
121
+ // Aggregate cap, applied after per-file decisions — a file already withheld
122
+ // (binary or over its own cap) costs nothing here.
176
123
  return applySerializedSizeBudget(files, {
177
124
  maxTotalBytes: maxTotalPatchBytes,
178
125
  sizeOf: (f) => (f.patch === null ? 0 : Buffer.byteLength(f.patch, "utf8")),
179
- // Short on purpose. This reason lands on *every* file past the boundary —
180
- // 187 of 200 on a wide diff — so the advice tail it used to carry ("narrow
181
- // files, or raise maxTotalPatchBytes") was paid for once per file to say
182
- // the same thing each time, and measured at ~30KB on that diff: more than
183
- // the patches it was explaining the absence of. The caller is told what to
184
- // do once, in the reply's own note, which is where advice that is identical
185
- // for every file belongs.
126
+ // Short on purpose: this reason repeats per file (187 of 200 on one wide
127
+ // diff), so a longer advice tail measured ~30KB — bigger than the patches it explained.
186
128
  withhold: (f, spentBytes) => ({
187
129
  ...f,
188
130
  patch: null,
@@ -191,24 +133,201 @@ async function runGitDiff(cwd, revisionArgs, options) {
191
133
  }),
192
134
  }).items;
193
135
  }
136
+ const HUNK_HEADER = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
194
137
  /**
195
- * `base...head` (three dots), matching `changedFiles`'s own reasoning: two
196
- * dots would include everything changed on `base` since the branch point,
197
- * misattributing someone else's history to this diff.
138
+ * Which lines a unified-diff patch actually *added*, in new-file line numbers.
139
+ *
140
+ * C2 (UAT phase 4): `checkEnvironment`'s `NEW_READ_UNDECLARED` used to call any
141
+ * undeclared read in a `files`-scoped file "new", even a pre-existing read the
142
+ * diff never touched — this is what lets a caller ask the narrower, true
143
+ * question instead: is this line one the diff actually added?
144
+ *
145
+ * Parses the hunk headers (`@@ -a,b +c,d @@`) and walks each hunk counting the
146
+ * new-file line pointer: a `+` line claims the current pointer and advances it,
147
+ * a context line (or blank) advances the pointer without claiming a line, and a
148
+ * `-` line does neither — it consumes no new-file line — but does end any run
149
+ * of consecutive additions in progress, so an added block interrupted by a
150
+ * removed line reports as two ranges, not one spanning the gap. Takes the raw
151
+ * `patch` text `GitDiffFile` already carries; a `null` patch (binary, or
152
+ * withheld by a size budget) has nothing to parse and is the caller's problem
153
+ * to ask for separately — this function only ever sees text that exists.
198
154
  */
155
+ export function addedLineRanges(patch) {
156
+ const ranges = [];
157
+ let newLine = 0;
158
+ let inHunk = false;
159
+ let start = null;
160
+ let end = null;
161
+ const flush = () => {
162
+ if (start !== null && end !== null)
163
+ ranges.push({ start, end });
164
+ start = null;
165
+ end = null;
166
+ };
167
+ for (const line of patch.split("\n")) {
168
+ const header = HUNK_HEADER.exec(line);
169
+ if (header !== null) {
170
+ flush();
171
+ newLine = Number(header[1]);
172
+ inHunk = true;
173
+ continue;
174
+ }
175
+ if (!inHunk)
176
+ continue;
177
+ if (line.startsWith("+") && !line.startsWith("+++")) {
178
+ if (start === null)
179
+ start = newLine;
180
+ end = newLine;
181
+ newLine += 1;
182
+ }
183
+ else if (line.startsWith("-") && !line.startsWith("---")) {
184
+ // A deletion consumes no new-file line, but it does break a run of
185
+ // consecutive additions — the two sides of it are not contiguous.
186
+ flush();
187
+ }
188
+ else if (line.startsWith("\\")) {
189
+ // "" — not a line, claims no pointer.
190
+ continue;
191
+ }
192
+ else {
193
+ // Context line (or the trailing empty split element): advances the
194
+ // pointer, claims nothing.
195
+ flush();
196
+ newLine += 1;
197
+ }
198
+ }
199
+ flush();
200
+ return ranges;
201
+ }
202
+ /** `base...head` (three dots) — two dots would include everything changed on `base` since the branch point. */
199
203
  export async function gitDiff(cwd, base, head = "HEAD", options = {}) {
200
204
  return runGitDiff(cwd, [`${base}...${head}`], options);
201
205
  }
202
206
  /**
203
- * The working-tree counterpart to {@link gitDiff}: a live diff against
204
- * uncommitted state, which no two-revision form of `git diff` can express
205
- * (`HEAD...HEAD` is empty by construction). Reuses the exact same block
206
- * parser, rename detection and patch cap `gitDiff` does — see
207
- * `DEC-NEXT-working-tree-diff-in-core` for why a second parser was rejected.
207
+ * Working-tree counterpart to {@link gitDiff}: a live diff against uncommitted state, which no
208
+ * two-revision `git diff` form can express. Reuses the same parser (`DEC-NEXT-working-tree-diff-in-core`).
208
209
  */
209
210
  export async function gitWorkingTreeDiff(cwd, options = {}) {
210
211
  const scope = options.scope ?? "unstaged";
211
212
  const revisionArgs = scope === "staged" ? ["--cached"] : scope === "all" ? ["HEAD"] : [];
212
213
  return runGitDiff(cwd, revisionArgs, options);
213
214
  }
215
+ /** Untracked files past this many are counted and not diffed. */
216
+ const DEFAULT_MAX_UNTRACKED = 200;
217
+ /**
218
+ * The working tree as a change set, including files git has never seen.
219
+ *
220
+ * ## Why untracked needs its own mechanism
221
+ *
222
+ * No form of `git diff` reports an untracked file. `git diff HEAD` compares
223
+ * against what the index and `HEAD` hold, and a file git has never seen is in
224
+ * neither — so a working-tree mode built on the scopes above alone still misses
225
+ * the most common shape of work in progress: a new file, written, not yet
226
+ * added. That is exactly the case this was built for.
227
+ *
228
+ * ## `--no-index` rather than `add -N`
229
+ *
230
+ * The usual trick is `git add -N` to give the file an intent-to-add entry, then
231
+ * diff normally. **It writes to the index**, and a read tool that mutates the
232
+ * caller's repository to answer a question is not a read tool — it would also
233
+ * race any real `git add` the developer runs while it works.
234
+ *
235
+ * `git diff --no-index -- /dev/null <path>` needs no index and emits exactly the
236
+ * `new file mode` block the shared parser already handles, with the real path.
237
+ * It exits non-zero when the files differ, which for this call is always, so a
238
+ * non-zero exit here is the success case and is read for its stdout.
239
+ *
240
+ * ## `--exclude-standard` is load-bearing
241
+ *
242
+ * Without it the first answer on any real repository is a dependency directory
243
+ * reported as the developer's uncommitted work.
244
+ */
245
+ export async function gitWorkingTreeChange(cwd, options = {}) {
246
+ const all = await gitWorkingTreeDiff(cwd, options);
247
+ const tracked = all.filter((file) => !isExcluded(file.path, options.exclude));
248
+ if (options.includeUntracked !== true) {
249
+ return { files: tracked, untrackedTotal: 0, untrackedTruncated: false };
250
+ }
251
+ const maxUntracked = options.maxUntracked ?? DEFAULT_MAX_UNTRACKED;
252
+ const listArgs = ["ls-files", "--others", "--exclude-standard"];
253
+ if (options.files !== undefined && options.files.length > 0) {
254
+ listArgs.push("--", ...options.files);
255
+ }
256
+ const { stdout } = await run("git", listArgs, { cwd, maxBuffer: 64 * 1024 * 1024 });
257
+ const untracked = stdout
258
+ .split("\n")
259
+ .map((line) => line.trim())
260
+ .filter((line) => line !== "" && !isExcluded(line, options.exclude))
261
+ .sort();
262
+ const diffed = untracked.slice(0, maxUntracked);
263
+ const added = [];
264
+ for (const path of diffed) {
265
+ let text;
266
+ try {
267
+ const result = await run("git", ["diff", "--no-index", "--", "/dev/null", path], {
268
+ cwd,
269
+ maxBuffer: 256 * 1024 * 1024,
270
+ });
271
+ text = result.stdout;
272
+ }
273
+ catch (error) {
274
+ // Non-zero exit is the ordinary outcome here: `--no-index` reports a
275
+ // difference the way `diff(1)` does. The patch is on the error.
276
+ const stdout = error.stdout;
277
+ if (typeof stdout !== "string" || stdout.trim() === "")
278
+ continue;
279
+ text = stdout;
280
+ }
281
+ const parsed = parseUntrackedBlock(text, path, options);
282
+ if (parsed !== null)
283
+ added.push(parsed);
284
+ }
285
+ return {
286
+ files: [...tracked, ...added].sort((a, b) => a.path.localeCompare(b.path)),
287
+ untrackedTotal: untracked.length,
288
+ untrackedTruncated: untracked.length > diffed.length,
289
+ };
290
+ }
291
+ /**
292
+ * Is this path inside an excluded directory?
293
+ *
294
+ * A segment-boundary prefix match rather than `startsWith`: `.descry` must
295
+ * exclude `.descry/graph.db` and leave `src/.descryfile.ts` alone.
296
+ */
297
+ function isExcluded(path, exclude) {
298
+ if (exclude === undefined)
299
+ return false;
300
+ return exclude.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
301
+ }
302
+ /** One `--no-index` block, through the same cap rules every other patch gets. */
303
+ function parseUntrackedBlock(text, path, options) {
304
+ const block = text.split(/\n(?=diff --git )/).find((b) => b.startsWith("diff --git "));
305
+ if (block === undefined)
306
+ return null;
307
+ const parsed = parseDiffBlock(block);
308
+ if (parsed === null)
309
+ return null;
310
+ const maxPatchBytes = options.maxPatchBytes ?? DEFAULT_MAX_PATCH_BYTES;
311
+ const bytes = Buffer.byteLength(block, "utf8");
312
+ const overCap = !parsed.binary && bytes > maxPatchBytes;
313
+ return {
314
+ // `--no-index` was given a path relative to `cwd` and echoes it back, but
315
+ // the finding is reported under the path the caller asked about.
316
+ path,
317
+ fromPath: null,
318
+ // A file git has never seen is an addition, whatever the block header says
319
+ // about `/dev/null` on the left.
320
+ status: "A",
321
+ binary: parsed.binary,
322
+ additions: parsed.binary ? null : parsed.additions,
323
+ deletions: parsed.binary ? null : 0,
324
+ patch: parsed.binary || overCap ? null : block,
325
+ patchOmittedReason: parsed.binary
326
+ ? "binary file — no textual patch"
327
+ : overCap
328
+ ? `diff for this file is ${bytes} bytes, over the ${maxPatchBytes}-byte cap — narrow ` +
329
+ '"files" to fetch it on its own, or raise "maxPatchBytes"'
330
+ : null,
331
+ };
332
+ }
214
333
  //# sourceMappingURL=diff.js.map