@delfini/drift-engine 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /** Why a path or hunk was dropped. */
2
- export type DropReason = 'lockfile' | 'generated' | 'vendored' | 'fixture' | 'whitespace-only' | 'import-only';
2
+ export type DropReason = 'lockfile' | 'generated' | 'vendored' | 'fixture' | 'whitespace-only' | 'import-only' | 'ignored';
3
3
  export interface DroppedPath {
4
4
  path: string;
5
5
  reason: DropReason;
@@ -17,6 +17,25 @@ export interface FilterDiffResult {
17
17
  /** Individual hunks dropped from otherwise-kept files. */
18
18
  droppedHunks: DroppedHunk[];
19
19
  }
20
+ /** Options controlling which filtering passes `filterDiff` applies. */
21
+ export interface FilterDiffOptions {
22
+ /**
23
+ * Apply the built-in noise classifiers (lockfile/generated/vendored/fixture
24
+ * path-level + whitespace-only/import-only hunk-level). Defaults to `true`
25
+ * so the legacy single-arg call `filterDiff(diff)` is byte-identical to the
26
+ * pre-options behaviour (the `enableDiffPreFilter` consumer path). Pass
27
+ * `false` to run an ignore-only pass that leaves all non-ignored files
28
+ * verbatim.
29
+ */
30
+ builtins?: boolean;
31
+ /**
32
+ * User `ignore_code_scope` entries (repo-relative; picomatch@4 dialect via
33
+ * the shared `isFileInDocScope` predicate). A changed file matching any
34
+ * entry is dropped whole with reason `'ignored'`, classified BEFORE the
35
+ * built-ins. Empty / omitted → no ignore dropping (observably no-op).
36
+ */
37
+ ignorePaths?: string[];
38
+ }
20
39
  /**
21
40
  * Filter a unified-diff string deterministically.
22
41
  *
@@ -28,6 +47,11 @@ export interface FilterDiffResult {
28
47
  * not lose surrounding context.
29
48
  *
30
49
  * Identical input → identical output (NFR46 reproducibility carries forward).
50
+ *
51
+ * `options.builtins` (default `true`) gates the built-in noise classifiers;
52
+ * `options.ignorePaths` adds user `ignore_code_scope` dropping on top. With
53
+ * the default options (`{ builtins: true, ignorePaths: [] }`) the output is
54
+ * byte-identical to the legacy single-arg `filterDiff(diff)`.
31
55
  */
32
- export declare function filterDiff(diff: string): FilterDiffResult;
56
+ export declare function filterDiff(diff: string, options?: FilterDiffOptions): FilterDiffResult;
33
57
  //# sourceMappingURL=diff-filter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-filter.d.ts","sourceRoot":"","sources":["../src/diff-filter.ts"],"names":[],"mappings":"AAsBA,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,GACT,iBAAiB,GACjB,aAAa,CAAA;AAEjB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,0DAA0D;IAC1D,YAAY,EAAE,WAAW,EAAE,CAAA;CAC5B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CA0DzD"}
1
+ {"version":3,"file":"diff-filter.d.ts","sourceRoot":"","sources":["../src/diff-filter.ts"],"names":[],"mappings":"AAgCA,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,GACT,iBAAiB,GACjB,aAAa,GAGb,SAAS,CAAA;AAEb,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,0DAA0D;IAC1D,YAAY,EAAE,WAAW,EAAE,CAAA;CAC5B;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAgF1F"}
@@ -8,8 +8,16 @@
8
8
  // Pure-logic — no I/O, no clock, no randomness, no new runtime dep. ESLint
9
9
  // `no-restricted-imports` on packages/drift-engine/src/**/*.ts forbids fs /
10
10
  // child_process / http / https / @anthropic-ai/sdk / openai / @langchain/* /
11
- // process.env. Path classification uses hand-written predicates NO
12
- // `picomatch` (Story Dev Notes §"Path classification predicates").
11
+ // process.env. The BUILT-IN noise classifiers (lockfile/generated/vendored/
12
+ // fixture) use hand-written predicates — NO `picomatch` (Story Dev Notes
13
+ // §"Path classification predicates").
14
+ //
15
+ // ignore_code_scope (user-configurable ignore paths) is the ONE place this
16
+ // module reaches for picomatch — via the shared `isFileInDocScope` predicate
17
+ // (sibling module, same package, no new external dep). User globs MUST use the
18
+ // same picomatch@4 dialect as the CLI config + the Action array-filter so a
19
+ // file the Skill ignores is the file the Action ignores (ADR-2026-06-01
20
+ // dialect parity). The hand-written built-ins above are unrelated and stay.
13
21
  //
14
22
  // Exposed via `index.ts` (unlike the P3.7.1 relevance internals, which run
15
23
  // INSIDE `buildPrompt`). The gate for this filter lives at the CONSUMER —
@@ -19,6 +27,7 @@
19
27
  // `@delfini/drift-engine/src/...` imports). The default consumer path never
20
28
  // invokes this module, so `buildPrompt` output stays byte-identical and the
21
29
  // NFR44 snapshot gate stays green (NFR49(b) parity discipline).
30
+ import { isFileInDocScope } from './doc-scope.js';
22
31
  // -- Public entry point ------------------------------------------------------
23
32
  /**
24
33
  * Filter a unified-diff string deterministically.
@@ -31,8 +40,16 @@
31
40
  * not lose surrounding context.
32
41
  *
33
42
  * Identical input → identical output (NFR46 reproducibility carries forward).
43
+ *
44
+ * `options.builtins` (default `true`) gates the built-in noise classifiers;
45
+ * `options.ignorePaths` adds user `ignore_code_scope` dropping on top. With
46
+ * the default options (`{ builtins: true, ignorePaths: [] }`) the output is
47
+ * byte-identical to the legacy single-arg `filterDiff(diff)`.
34
48
  */
35
- export function filterDiff(diff) {
49
+ export function filterDiff(diff, options = {}) {
50
+ const builtins = options.builtins ?? true;
51
+ const ignorePaths = options.ignorePaths ?? [];
52
+ const hasIgnore = ignorePaths.length > 0;
36
53
  const droppedPaths = [];
37
54
  const droppedHunks = [];
38
55
  const files = parseDiffIntoFiles(diff);
@@ -41,6 +58,22 @@ export function filterDiff(diff) {
41
58
  keptParts.push(files.preamble);
42
59
  }
43
60
  for (const file of files.files) {
61
+ // ignore_code_scope wins over everything — the dev explicitly told Delfini
62
+ // this code path is out of bounds for drift, so it is dropped whole and
63
+ // reported as 'ignored' regardless of whether the built-ins would also have
64
+ // matched it. Shared picomatch@4 predicate → parity with the CLI config and
65
+ // the Action's array-filter.
66
+ if (hasIgnore && isFileInDocScope(file.path, ignorePaths)) {
67
+ droppedPaths.push({ path: file.path, reason: 'ignored' });
68
+ continue;
69
+ }
70
+ // Built-ins off (ignore-only pass): a non-ignored file passes through
71
+ // verbatim — no path-level or hunk-level noise dropping. Byte-fidelity via
72
+ // the original slice.
73
+ if (!builtins) {
74
+ keptParts.push(file.rawSlice);
75
+ continue;
76
+ }
44
77
  // Path-level drops — classified first, in priority order. Lockfiles win
45
78
  // over generated/vendored/fixture since the canonical lockfile names
46
79
  // never overlap those patterns in practice.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,6 @@ export { normalizeDocScope, validateDocScopeEntry, classifyEntry, isFileInDocSco
6
6
  export { filterDiff } from './diff-filter.js';
7
7
  export { rankedFillSections } from './relevance.js';
8
8
  export type { AnalysisInput, AnalysisResult, DocFile, Contradiction, Addition, ClarifyingQuestion, PRMetadata, Severity, BuildPromptOptions, } from './types.js';
9
- export type { DropReason, DroppedPath, DroppedHunk, FilterDiffResult, } from './diff-filter.js';
9
+ export type { DropReason, DroppedPath, DroppedHunk, FilterDiffResult, FilterDiffOptions, } from './diff-filter.js';
10
10
  export type { DocSection, DroppedSection, RankedFillCandidate, RankedFillResult, } from './relevance.js';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAI5C,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AAOvB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAS7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,YAAY,EACV,aAAa,EACb,cAAc,EACd,OAAO,EACP,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EACV,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAI5C,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AAOvB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAS7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,YAAY,EACV,aAAa,EACb,cAAc,EACd,OAAO,EACP,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EACV,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delfini/drift-engine",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "repository": {