@descryy/core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/budget/index.d.ts +3 -0
  2. package/dist/budget/index.d.ts.map +1 -0
  3. package/dist/budget/index.js +2 -0
  4. package/dist/budget/index.js.map +1 -0
  5. package/dist/budget/size.d.ts +43 -0
  6. package/dist/budget/size.d.ts.map +1 -0
  7. package/dist/budget/size.js +52 -0
  8. package/dist/budget/size.js.map +1 -0
  9. package/dist/contracts/engine.d.ts.map +1 -1
  10. package/dist/contracts/engine.js +16 -9
  11. package/dist/contracts/engine.js.map +1 -1
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/multipr/mechanical.d.ts.map +1 -1
  17. package/dist/multipr/mechanical.js +1 -0
  18. package/dist/multipr/mechanical.js.map +1 -1
  19. package/dist/query/confirmed-facts.d.ts +21 -5
  20. package/dist/query/confirmed-facts.d.ts.map +1 -1
  21. package/dist/query/confirmed-facts.js +30 -7
  22. package/dist/query/confirmed-facts.js.map +1 -1
  23. package/dist/query/index.d.ts +2 -0
  24. package/dist/query/index.d.ts.map +1 -1
  25. package/dist/query/index.js +1 -0
  26. package/dist/query/index.js.map +1 -1
  27. package/dist/query/memory.d.ts.map +1 -1
  28. package/dist/query/memory.js +4 -0
  29. package/dist/query/memory.js.map +1 -1
  30. package/dist/query/provider.d.ts +7 -0
  31. package/dist/query/provider.d.ts.map +1 -1
  32. package/dist/query/provider.js.map +1 -1
  33. package/dist/query/queries.d.ts.map +1 -1
  34. package/dist/query/queries.js +39 -15
  35. package/dist/query/queries.js.map +1 -1
  36. package/dist/query/resolution-floor.d.ts +36 -0
  37. package/dist/query/resolution-floor.d.ts.map +1 -0
  38. package/dist/query/resolution-floor.js +39 -0
  39. package/dist/query/resolution-floor.js.map +1 -0
  40. package/dist/query/sqlite.d.ts.map +1 -1
  41. package/dist/query/sqlite.js +1 -0
  42. package/dist/query/sqlite.js.map +1 -1
  43. package/dist/query/traverse.d.ts.map +1 -1
  44. package/dist/query/traverse.js +0 -0
  45. package/dist/query/traverse.js.map +1 -1
  46. package/dist/scoping/traverse.d.ts.map +1 -1
  47. package/dist/scoping/traverse.js +18 -4
  48. package/dist/scoping/traverse.js.map +1 -1
  49. package/dist/sources/confirmed/incidents.d.ts +47 -0
  50. package/dist/sources/confirmed/incidents.d.ts.map +1 -0
  51. package/dist/sources/confirmed/incidents.js +173 -0
  52. package/dist/sources/confirmed/incidents.js.map +1 -0
  53. package/dist/sources/confirmed/index.d.ts +3 -0
  54. package/dist/sources/confirmed/index.d.ts.map +1 -0
  55. package/dist/sources/confirmed/index.js +2 -0
  56. package/dist/sources/confirmed/index.js.map +1 -0
  57. package/dist/sources/git/diff.d.ts +37 -0
  58. package/dist/sources/git/diff.d.ts.map +1 -1
  59. package/dist/sources/git/diff.js +59 -8
  60. package/dist/sources/git/diff.js.map +1 -1
  61. package/dist/sources/git/incidents.d.ts +109 -0
  62. package/dist/sources/git/incidents.d.ts.map +1 -0
  63. package/dist/sources/git/incidents.js +187 -0
  64. package/dist/sources/git/incidents.js.map +1 -0
  65. package/dist/sources/git/index.d.ts +4 -2
  66. package/dist/sources/git/index.d.ts.map +1 -1
  67. package/dist/sources/git/index.js +2 -1
  68. package/dist/sources/git/index.js.map +1 -1
  69. package/dist/sources/git/source.d.ts.map +1 -1
  70. package/dist/sources/git/source.js +0 -0
  71. package/dist/sources/git/source.js.map +1 -1
  72. package/dist/tiers/certify.d.ts.map +1 -1
  73. package/dist/tiers/certify.js +47 -3
  74. package/dist/tiers/certify.js.map +1 -1
  75. package/package.json +2 -2
@@ -0,0 +1,173 @@
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
+ */
36
+ import { fileQsp, nodeId, } from "@descryy/ir";
37
+ export const CONFIRMED_INCIDENT_SOURCE_ID = "confirmed-incidents";
38
+ export const CONFIRMED_INCIDENT_SOURCE_VERSION = "0.1.0";
39
+ const PRODUCED_BY = `${CONFIRMED_INCIDENT_SOURCE_ID}@${CONFIRMED_INCIDENT_SOURCE_VERSION}`;
40
+ /** The `INCIDENT` node id for one record. Stable across re-projections. */
41
+ export function confirmedIncidentId(scope, incident) {
42
+ return nodeId(scope, "INCIDENT", `confirmed:${incident.confirmedAt}:${incident.summary}`, null);
43
+ }
44
+ export function createConfirmedIncidentSource(options) {
45
+ return {
46
+ id: CONFIRMED_INCIDENT_SOURCE_ID,
47
+ version: CONFIRMED_INCIDENT_SOURCE_VERSION,
48
+ emit(ctx) {
49
+ const repo = options.repo || ctx.root.repo;
50
+ // INCIDENT and FIX_PATTERN are workspace-scoped (DEC-054), FILE is
51
+ // repo-scoped, and `scopeOf` picks between them per type.
52
+ 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.
56
+ const mine = options.incidents.filter((i) => i.repo === repo);
57
+ const nodes = [];
58
+ const edges = [];
59
+ const unresolved = [];
60
+ const touched = new Set();
61
+ for (const incident of mine)
62
+ for (const path of incident.files)
63
+ touched.add(path);
64
+ const sourceFiles = [...touched].sort();
65
+ for (const path of sourceFiles) {
66
+ nodes.push({
67
+ id: nodeId(scope, "FILE", fileQsp(path), null),
68
+ type: "FILE",
69
+ name: path.split("/").pop() ?? path,
70
+ file: path,
71
+ 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).
75
+ language: null,
76
+ producedBy: PRODUCED_BY,
77
+ resolution: 0,
78
+ attrs: {},
79
+ });
80
+ }
81
+ for (const incident of mine) {
82
+ const incidentId = confirmedIncidentId(scope, incident);
83
+ nodes.push({
84
+ id: incidentId,
85
+ type: "INCIDENT",
86
+ name: incident.summary.slice(0, 120),
87
+ file: null,
88
+ range: null,
89
+ language: null,
90
+ producedBy: PRODUCED_BY,
91
+ resolution: 0,
92
+ 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.
96
+ detectedVia: incident.observedInRun === undefined ? "developer-confirmed" : "runtime-observed",
97
+ ...(incident.observedInRun === undefined ? {} : { observedInRun: incident.observedInRun }),
98
+ confirmedBy: incident.confirmedBy,
99
+ confirmedAt: incident.confirmedAt,
100
+ // The message-similarity signal's real input, which until now had
101
+ // only a commit subject line to work with.
102
+ ...(incident.errorText === undefined ? {} : { errorText: incident.errorText }),
103
+ ...(incident.fixedAtCommit === undefined ? {} : { fixedAtCommit: incident.fixedAtCommit }),
104
+ },
105
+ });
106
+ for (const path of [...new Set(incident.files)].sort()) {
107
+ edges.push({
108
+ from: incidentId,
109
+ to: nodeId(scope, "FILE", fileQsp(path), null),
110
+ type: "INCIDENT_CORRELATED",
111
+ resolution: 0,
112
+ confidence: 1,
113
+ producedBy: PRODUCED_BY,
114
+ attrs: {
115
+ detectedVia: incident.observedInRun === undefined ? "developer-confirmed" : "runtime-observed",
116
+ },
117
+ });
118
+ }
119
+ // Only when the record names one. "A defect existed" and "this commit
120
+ // fixed it" are separate claims and only the second licenses this edge.
121
+ if (incident.fixedAtCommit === undefined)
122
+ continue;
123
+ const fixId = nodeId(scope, "FIX_PATTERN", incident.fixedAtCommit, null);
124
+ nodes.push({
125
+ id: fixId,
126
+ type: "FIX_PATTERN",
127
+ name: `fix for: ${incident.summary}`.slice(0, 120),
128
+ file: null,
129
+ range: null,
130
+ language: null,
131
+ producedBy: PRODUCED_BY,
132
+ resolution: 0,
133
+ attrs: {
134
+ commitSha: incident.fixedAtCommit,
135
+ detectedVia: incident.observedInRun === undefined ? "developer-confirmed" : "runtime-observed",
136
+ },
137
+ });
138
+ edges.push({
139
+ from: incidentId,
140
+ to: fixId,
141
+ type: "FIXED_BY",
142
+ resolution: 0,
143
+ confidence: 1,
144
+ producedBy: PRODUCED_BY,
145
+ attrs: {
146
+ detectedVia: incident.observedInRun === undefined ? "developer-confirmed" : "runtime-observed",
147
+ },
148
+ });
149
+ }
150
+ // Deterministic: two projections of the same records must produce a
151
+ // byte-identical batch, or the store's content hash moves for no reason.
152
+ nodes.sort((a, b) => a.id.localeCompare(b.id));
153
+ edges.sort((a, b) => `${a.from}${a.to}${a.type}`.localeCompare(`${b.from}${b.to}${b.type}`));
154
+ return Promise.resolve({
155
+ repo,
156
+ ...(scope.workspace === undefined ? {} : { workspace: scope.workspace }),
157
+ commitSha: ctx.root.commitSha,
158
+ producedBy: PRODUCED_BY,
159
+ sourceFiles,
160
+ 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.
165
+ reachedResolution: 0,
166
+ nodes,
167
+ edges,
168
+ unresolved,
169
+ });
170
+ },
171
+ };
172
+ }
173
+ //# sourceMappingURL=incidents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incidents.js","sourceRoot":"","sources":["../../../src/sources/confirmed/incidents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createConfirmedIncidentSource, confirmedIncidentId, CONFIRMED_INCIDENT_SOURCE_ID, CONFIRMED_INCIDENT_SOURCE_VERSION, } from "./incidents.ts";
2
+ export type { ConfirmedIncidentSourceOptions } from "./incidents.ts";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sources/confirmed/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,mBAAmB,EACnB,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createConfirmedIncidentSource, confirmedIncidentId, CONFIRMED_INCIDENT_SOURCE_ID, CONFIRMED_INCIDENT_SOURCE_VERSION, } from "./incidents.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sources/confirmed/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,mBAAmB,EACnB,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,gBAAgB,CAAC"}
@@ -12,6 +12,13 @@
12
12
  * rather than silently shrinking the reply — the empty-denominator rule
13
13
  * applies to a dropped patch exactly as it does to a dropped finding.
14
14
  *
15
+ * Two size caps, because one of them bounds nothing on its own:
16
+ * `maxPatchBytes` per file, and `maxTotalPatchBytes` across the whole reply.
17
+ * The second exists because a real 48-file branch diff, with 44 patches each
18
+ * *under* the per-file cap, summed to 229KB and hard-failed the call — the
19
+ * reply never reached the caller at all, which is the one failure mode a
20
+ * disclosure cannot repair after the fact.
21
+ *
15
22
  * One `git diff` invocation for every file at once, not one per file — a
16
23
  * PR touching fifty files would otherwise spawn fifty processes. The output
17
24
  * is a concatenation of per-file blocks, each beginning with a line
@@ -23,6 +30,12 @@
23
30
  * own regex — an accepted, narrow gap, not a silent one, since every other
24
31
  * line used here does not share it).
25
32
  */
33
+ /**
34
+ * The stable prefix of `patchOmittedReason` when the *total* budget, not the
35
+ * per-file cap, is what withheld a patch. Exported so a caller can tell the
36
+ * two apart without matching on prose it does not own.
37
+ */
38
+ export declare const TOTAL_PATCH_BUDGET_REASON_PREFIX = "the reply's total patch budget";
26
39
  export interface GitDiffFile {
27
40
  /** Path as it is known after the change (the only path for A/M/D). */
28
41
  readonly path: string;
@@ -43,6 +56,11 @@ export interface GitDiffOptions {
43
56
  readonly files?: readonly string[];
44
57
  /** A file's patch is omitted (stats are still reported) above this many bytes. Default 20,000. */
45
58
  readonly maxPatchBytes?: number;
59
+ /**
60
+ * The cap on the sum of all returned patches. Files past it keep their
61
+ * stats and name the budget as the reason. Default 80,000.
62
+ */
63
+ readonly maxTotalPatchBytes?: number;
46
64
  }
47
65
  /**
48
66
  * `base...head` (three dots), matching `changedFiles`'s own reasoning: two
@@ -50,4 +68,23 @@ export interface GitDiffOptions {
50
68
  * misattributing someone else's history to this diff.
51
69
  */
52
70
  export declare function gitDiff(cwd: string, base: string, head?: string, options?: GitDiffOptions): Promise<readonly GitDiffFile[]>;
71
+ export interface GitWorkingTreeDiffOptions extends GitDiffOptions {
72
+ /**
73
+ * `"unstaged"` (default) — the working tree against the index (`git diff -M`),
74
+ * i.e. edits not yet `git add`-ed.
75
+ * `"staged"` — the index against `HEAD` (`git diff -M --cached`), i.e. what
76
+ * a commit right now would contain.
77
+ * `"all"` — the working tree against `HEAD` (`git diff -M HEAD`), staged and
78
+ * unstaged combined — everything not yet committed.
79
+ */
80
+ readonly scope?: "unstaged" | "staged" | "all";
81
+ }
82
+ /**
83
+ * The working-tree counterpart to {@link gitDiff}: a live diff against
84
+ * uncommitted state, which no two-revision form of `git diff` can express
85
+ * (`HEAD...HEAD` is empty by construction). Reuses the exact same block
86
+ * parser, rename detection and patch cap `gitDiff` does — see
87
+ * `DEC-NEXT-working-tree-diff-in-core` for why a second parser was rejected.
88
+ */
89
+ export declare function gitWorkingTreeDiff(cwd: string, options?: GitWorkingTreeDiffOptions): Promise<readonly GitDiffFile[]>;
53
90
  //# sourceMappingURL=diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAwBH,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;CACjC;AAmED;;;;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,CAqCjC"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAkCH;;;;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;AA6HD;;;;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"}
@@ -12,6 +12,13 @@
12
12
  * rather than silently shrinking the reply — the empty-denominator rule
13
13
  * applies to a dropped patch exactly as it does to a dropped finding.
14
14
  *
15
+ * Two size caps, because one of them bounds nothing on its own:
16
+ * `maxPatchBytes` per file, and `maxTotalPatchBytes` across the whole reply.
17
+ * The second exists because a real 48-file branch diff, with 44 patches each
18
+ * *under* the per-file cap, summed to 229KB and hard-failed the call — the
19
+ * reply never reached the caller at all, which is the one failure mode a
20
+ * disclosure cannot repair after the fact.
21
+ *
15
22
  * One `git diff` invocation for every file at once, not one per file — a
16
23
  * PR touching fifty files would otherwise spawn fifty processes. The output
17
24
  * is a concatenation of per-file blocks, each beginning with a line
@@ -25,6 +32,7 @@
25
32
  */
26
33
  import { execFile } from "node:child_process";
27
34
  import { promisify } from "node:util";
35
+ import { applySerializedSizeBudget } from "../../budget/index.js";
28
36
  import { cleanGitEnv } from "./env.js";
29
37
  const execFileAsync = promisify(execFile);
30
38
  // Always strips GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_COMMON_DIR — see env.ts.
@@ -36,6 +44,20 @@ function run(command, args, options) {
36
44
  });
37
45
  }
38
46
  const DEFAULT_MAX_PATCH_BYTES = 20_000;
47
+ /**
48
+ * The cap on the sum of every returned patch. A per-file cap bounds no total:
49
+ * 44 files each under the 20,000-byte per-file cap summed to 229KB and
50
+ * hard-failed an ordinary 48-file branch diff before the reply was ever
51
+ * returned. A starting value, not a measurement — roughly 20k tokens of
52
+ * patch text, leaving a caller's context room for the answer built on it.
53
+ */
54
+ const DEFAULT_MAX_TOTAL_PATCH_BYTES = 80_000;
55
+ /**
56
+ * The stable prefix of `patchOmittedReason` when the *total* budget, not the
57
+ * per-file cap, is what withheld a patch. Exported so a caller can tell the
58
+ * two apart without matching on prose it does not own.
59
+ */
60
+ export const TOTAL_PATCH_BUDGET_REASON_PREFIX = "the reply's total patch budget";
39
61
  function stripPrefix(path, prefix) {
40
62
  return path.startsWith(prefix) ? path.slice(prefix.length) : path;
41
63
  }
@@ -96,14 +118,10 @@ function parseDiffBlock(block) {
96
118
  deletions: binary ? 0 : deletions,
97
119
  };
98
120
  }
99
- /**
100
- * `base...head` (three dots), matching `changedFiles`'s own reasoning: two
101
- * dots would include everything changed on `base` since the branch point,
102
- * misattributing someone else's history to this diff.
103
- */
104
- export async function gitDiff(cwd, base, head = "HEAD", options = {}) {
121
+ async function runGitDiff(cwd, revisionArgs, options) {
105
122
  const maxPatchBytes = options.maxPatchBytes ?? DEFAULT_MAX_PATCH_BYTES;
106
- const args = ["diff", "-M", `${base}...${head}`];
123
+ const maxTotalPatchBytes = options.maxTotalPatchBytes ?? DEFAULT_MAX_TOTAL_PATCH_BYTES;
124
+ const args = ["diff", "-M", ...revisionArgs];
107
125
  if (options.files !== undefined && options.files.length > 0)
108
126
  args.push("--", ...options.files);
109
127
  const { stdout } = await run("git", args, { cwd, maxBuffer: 256 * 1024 * 1024 });
@@ -135,6 +153,39 @@ export async function gitDiff(cwd, base, head = "HEAD", options = {}) {
135
153
  : null,
136
154
  });
137
155
  }
138
- return files;
156
+ // The aggregate cap, applied after every per-file decision: a file whose
157
+ // patch was already withheld (binary, or over its own cap) costs nothing
158
+ // here and keeps the reason it already has.
159
+ return applySerializedSizeBudget(files, {
160
+ maxTotalBytes: maxTotalPatchBytes,
161
+ sizeOf: (f) => (f.patch === null ? 0 : Buffer.byteLength(f.patch, "utf8")),
162
+ withhold: (f, spentBytes) => ({
163
+ ...f,
164
+ patch: null,
165
+ patchOmittedReason: `${TOTAL_PATCH_BUDGET_REASON_PREFIX} of ${maxTotalPatchBytes} bytes was already spent ` +
166
+ `(${spentBytes} bytes on earlier files) — narrow "files" to this one, or raise ` +
167
+ '"maxTotalPatchBytes"',
168
+ }),
169
+ }).items;
170
+ }
171
+ /**
172
+ * `base...head` (three dots), matching `changedFiles`'s own reasoning: two
173
+ * dots would include everything changed on `base` since the branch point,
174
+ * misattributing someone else's history to this diff.
175
+ */
176
+ export async function gitDiff(cwd, base, head = "HEAD", options = {}) {
177
+ return runGitDiff(cwd, [`${base}...${head}`], options);
178
+ }
179
+ /**
180
+ * The working-tree counterpart to {@link gitDiff}: a live diff against
181
+ * uncommitted state, which no two-revision form of `git diff` can express
182
+ * (`HEAD...HEAD` is empty by construction). Reuses the exact same block
183
+ * parser, rename detection and patch cap `gitDiff` does — see
184
+ * `DEC-NEXT-working-tree-diff-in-core` for why a second parser was rejected.
185
+ */
186
+ export async function gitWorkingTreeDiff(cwd, options = {}) {
187
+ const scope = options.scope ?? "unstaged";
188
+ const revisionArgs = scope === "staged" ? ["--cached"] : scope === "all" ? ["HEAD"] : [];
189
+ return runGitDiff(cwd, revisionArgs, options);
139
190
  }
140
191
  //# sourceMappingURL=diff.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,kFAAkF;AAClF,SAAS,GAAG,CACV,OAAe,EACf,IAAuB,EACvB,OAA4C;IAE5C,OAAO,aAAa,CAAC,OAAO,EAAE,IAAgB,EAAE;QAC9C,GAAG,OAAO;QACV,QAAQ,EAAE,MAAe;QACzB,GAAG,EAAE,WAAW,EAAE;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAkCvC,SAAS,WAAW,CAAC,IAAY,EAAE,MAAc;IAC/C,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEnE,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC;YAAE,KAAK,GAAG,IAAI,CAAC;aAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC;YAAE,SAAS,GAAG,IAAI,CAAC;aAC3D,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;YAChB,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5C,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,QAAQ;gBAAE,QAAQ,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,WAAW;gBAAE,MAAM,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC/D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,MAAM,GAA0B,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE3F,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;QAC1C,MAAM;QACN,MAAM;QACN,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACjC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAClC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,IAAY,EACZ,IAAI,GAAG,MAAM,EACb,UAA0B,EAAE;IAE5B,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC;IACvE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,MAAM,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAE/F,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACjF,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC;YAAE,SAAS;QAC/C,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,IAAI;YAAE,SAAS;QAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,GAAG,aAAa,CAAC;QAExD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;YAClD,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;YAClD,KAAK,EAAE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;YAC9C,kBAAkB,EAAE,MAAM,CAAC,MAAM;gBAC/B,CAAC,CAAC,gCAAgC;gBAClC,CAAC,CAAC,OAAO;oBACP,CAAC,CAAC,yBAAyB,KAAK,oBAAoB,aAAa,qBAAqB;wBACpF,0DAA0D;oBAC5D,CAAC,CAAC,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/sources/git/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,kFAAkF;AAClF,SAAS,GAAG,CACV,OAAe,EACf,IAAuB,EACvB,OAA4C;IAE5C,OAAO,aAAa,CAAC,OAAO,EAAE,IAAgB,EAAE;QAC9C,GAAG,OAAO;QACV,QAAQ,EAAE,MAAe;QACzB,GAAG,EAAE,WAAW,EAAE;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,6BAA6B,GAAG,MAAM,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,gCAAgC,CAAC;AAuCjF,SAAS,WAAW,CAAC,IAAY,EAAE,MAAc;IAC/C,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEnE,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC;YAAE,KAAK,GAAG,IAAI,CAAC;aAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC;YAAE,SAAS,GAAG,IAAI,CAAC;aAC3D,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;YAChB,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5C,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,QAAQ;gBAAE,QAAQ,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,WAAW;gBAAE,MAAM,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,SAAS,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC/D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,MAAM,GAA0B,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE3F,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;QAC1C,MAAM;QACN,MAAM;QACN,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACjC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAClC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,GAAW,EACX,YAA+B,EAC/B,OAAuB;IAEvB,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC;IACvE,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,6BAA6B,CAAC;IACvF,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAE/F,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACjF,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC;YAAE,SAAS;QAC/C,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,IAAI;YAAE,SAAS;QAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,GAAG,aAAa,CAAC;QAExD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;YAClD,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS;YAClD,KAAK,EAAE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;YAC9C,kBAAkB,EAAE,MAAM,CAAC,MAAM;gBAC/B,CAAC,CAAC,gCAAgC;gBAClC,CAAC,CAAC,OAAO;oBACP,CAAC,CAAC,yBAAyB,KAAK,oBAAoB,aAAa,qBAAqB;wBACpF,0DAA0D;oBAC5D,CAAC,CAAC,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,yEAAyE;IACzE,4CAA4C;IAC5C,OAAO,yBAAyB,CAAC,KAAK,EAAE;QACtC,aAAa,EAAE,kBAAkB;QACjC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1E,QAAQ,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;YAC5B,GAAG,CAAC;YACJ,KAAK,EAAE,IAAI;YACX,kBAAkB,EAChB,GAAG,gCAAgC,OAAO,kBAAkB,2BAA2B;gBACvF,IAAI,UAAU,kEAAkE;gBAChF,sBAAsB;SACzB,CAAC;KACH,CAAC,CAAC,KAAK,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,IAAY,EACZ,IAAI,GAAG,MAAM,EACb,UAA0B,EAAE;IAE5B,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,MAAM,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAW,EACX,UAAqC,EAAE;IAEvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,YAAY,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,OAAO,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Which commits in a history describe a failure, and how we know.
3
+ *
4
+ * Split out of `source.ts` when the answer stopped being one regex. The git
5
+ * source minted an `INCIDENT` for exactly one thing — a commit body carrying
6
+ * `This reverts commit <40 hex>` — and that produced **zero** incidents across
7
+ * three measured repositories (734/459/203 commits) and two in a real product
8
+ * repository. `similarIncidents` was therefore built, tested, correct and
9
+ * starved: its recall is not 0%, it is not computable, because it has never
10
+ * been given a real incident to find.
11
+ *
12
+ * ## The rule every mechanism here answers to
13
+ *
14
+ * `INCIDENT` is an EARNED node (DEC-017). It is never dropped, it survives
15
+ * every rebuild, and `INCIDENT_CORRELATED` biases diff-scoping traversal toward
16
+ * the files it names for as long as the store exists. A wrong incident is not a
17
+ * bad answer that a later run corrects — it is unrecoverable pollution in the
18
+ * one table that cannot be recomputed away. So:
19
+ *
20
+ * **Every mechanism rests on something a person declared. None rests on
21
+ * something Descry inferred.**
22
+ *
23
+ * A revert trailer is written by `git revert`. A `Revert "…"` subject is typed
24
+ * by a person or by GitHub's own button on their behalf. `Fixes #123` is a
25
+ * developer stating that something was broken and this commit fixed it. What is
26
+ * deliberately *not* here is any reading of "fix", "hotfix" or "bug" in prose —
27
+ * the original mechanism's own comment says why, and it applies unchanged to
28
+ * every mechanism added since: matching on the word "fix" would classify
29
+ * ordinary work as an incident.
30
+ *
31
+ * ## Refusals, not guesses
32
+ *
33
+ * A `Revert "X"` naming a subject this history does not contain, or containing
34
+ * twice, produces a `DetectedRefusal` rather than a ranked guess. Two candidates
35
+ * is a genuine ambiguity and picking the nearer one would be recency standing in
36
+ * for evidence — the same discipline every resolver in this project follows.
37
+ *
38
+ * See `DEC-NEXT-incident-minting-beyond-explicit-reverts`.
39
+ */
40
+ import type { Commit } from "./history.ts";
41
+ /**
42
+ * How an incident was established. Written to `attrs.detectedVia` on the
43
+ * `INCIDENT` node and on its `FIXED_BY` edge, so a consumer can tell a
44
+ * machine-written trailer from a developer's typed sentence.
45
+ */
46
+ export type IncidentMechanism = "explicit-revert" | "manual-revert" | "issue-reference";
47
+ export interface DetectedIncident {
48
+ readonly mechanism: IncidentMechanism;
49
+ /** The commit that resolved it. Always a real commit in the history read. */
50
+ readonly fix: Commit;
51
+ /**
52
+ * The commit that broke it, for the mechanisms that name one.
53
+ *
54
+ * `null` for `issue-reference`, where no bad commit is named at all — the
55
+ * incident is the issue, and that is a different shape rather than a missing
56
+ * field.
57
+ */
58
+ readonly incidentCommit: Commit | null;
59
+ /** `#123`, for `issue-reference`. `null` for the revert mechanisms. */
60
+ readonly issueRef: string | null;
61
+ /**
62
+ * The files to correlate the incident with, already deduplicated and sorted.
63
+ *
64
+ * For a revert these are the files the *reverted* commit touched — where the
65
+ * defect was. For an issue reference there is no such commit, so they are the
66
+ * files the *fix* touched, which is the same claim reached from the other
67
+ * side: this is where the broken code lived.
68
+ */
69
+ readonly correlatedPaths: readonly string[];
70
+ }
71
+ /** A revert whose target could not be established. Disclosed, never dropped. */
72
+ export interface DetectedRefusal {
73
+ readonly fixSha: string;
74
+ /** The subject the revert quoted. */
75
+ readonly rawTarget: string;
76
+ readonly reason: string;
77
+ }
78
+ /**
79
+ * A revert trailer naming a sha this history does not contain.
80
+ *
81
+ * Not a refusal yet, and the distinction is load-bearing: `readHistory` reads
82
+ * HEAD-reachable, non-merge commits within a window, and a squash-merged or
83
+ * branch-deleted target is genuinely absent from that view while still being
84
+ * present in the object database. The caller holds the git process and can go
85
+ * look; this function is synchronous and cannot. Resolved out of band by
86
+ * `source.ts`, and only *then* refused if the object is really gone.
87
+ */
88
+ export interface UnresolvedTrailer {
89
+ readonly fix: Commit;
90
+ readonly revertedSha: string;
91
+ }
92
+ export interface IncidentDetection {
93
+ readonly incidents: readonly DetectedIncident[];
94
+ readonly refusals: readonly DetectedRefusal[];
95
+ readonly unresolvedTrailers: readonly UnresolvedTrailer[];
96
+ }
97
+ /** `git revert` writes this. Machine-generated, and the strongest signal available. */
98
+ declare const REVERT_TRAILER: RegExp;
99
+ /**
100
+ * Every incident this history declares, plus every revert whose target it does
101
+ * not contain.
102
+ *
103
+ * `commits` is the history as `readHistory` returns it — newest first. Order is
104
+ * not relied on for correctness: a revert's target is found by timestamp, so
105
+ * the result is identical for any permutation of the same commits.
106
+ */
107
+ export declare function detectIncidents(commits: readonly Commit[]): IncidentDetection;
108
+ export { REVERT_TRAILER };
109
+ //# sourceMappingURL=incidents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incidents.d.ts","sourceRoot":"","sources":["../../../src/sources/git/incidents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAExF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC3D;AAED,uFAAuF;AACvF,QAAA,MAAM,cAAc,QAAuC,CAAC;AAkD5D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CAgG7E;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}