@vyuhlabs/dxkit 2.20.0 → 2.21.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.
- package/CHANGELOG.md +57 -0
- package/dist/allowlist/categories.d.ts.map +1 -1
- package/dist/allowlist/categories.js +4 -0
- package/dist/allowlist/categories.js.map +1 -1
- package/dist/allowlist/hint.d.ts.map +1 -1
- package/dist/allowlist/hint.js +6 -0
- package/dist/allowlist/hint.js.map +1 -1
- package/dist/analyzers/flow/config.d.ts +37 -0
- package/dist/analyzers/flow/config.d.ts.map +1 -0
- package/dist/analyzers/flow/config.js +84 -0
- package/dist/analyzers/flow/config.js.map +1 -0
- package/dist/analyzers/flow/contract.d.ts +93 -0
- package/dist/analyzers/flow/contract.d.ts.map +1 -0
- package/dist/analyzers/flow/contract.js +176 -0
- package/dist/analyzers/flow/contract.js.map +1 -0
- package/dist/analyzers/flow/gate.d.ts +64 -0
- package/dist/analyzers/flow/gate.d.ts.map +1 -0
- package/dist/analyzers/flow/gate.js +84 -0
- package/dist/analyzers/flow/gate.js.map +1 -0
- package/dist/analyzers/flow/gather.d.ts +11 -0
- package/dist/analyzers/flow/gather.d.ts.map +1 -1
- package/dist/analyzers/flow/gather.js +10 -9
- package/dist/analyzers/flow/gather.js.map +1 -1
- package/dist/analyzers/flow/model.d.ts +12 -0
- package/dist/analyzers/flow/model.d.ts.map +1 -1
- package/dist/analyzers/flow/model.js +25 -3
- package/dist/analyzers/flow/model.js.map +1 -1
- package/dist/analyzers/tools/fingerprint.d.ts +32 -0
- package/dist/analyzers/tools/fingerprint.d.ts.map +1 -1
- package/dist/analyzers/tools/fingerprint.js +37 -1
- package/dist/analyzers/tools/fingerprint.js.map +1 -1
- package/dist/baseline/check-renderers.d.ts +33 -0
- package/dist/baseline/check-renderers.d.ts.map +1 -1
- package/dist/baseline/check-renderers.js +136 -3
- package/dist/baseline/check-renderers.js.map +1 -1
- package/dist/baseline/check.d.ts +18 -0
- package/dist/baseline/check.d.ts.map +1 -1
- package/dist/baseline/check.js +26 -2
- package/dist/baseline/check.js.map +1 -1
- package/dist/baseline/entry-to-located.d.ts.map +1 -1
- package/dist/baseline/entry-to-located.js +7 -0
- package/dist/baseline/entry-to-located.js.map +1 -1
- package/dist/baseline/finding-identity.d.ts.map +1 -1
- package/dist/baseline/finding-identity.js +5 -0
- package/dist/baseline/finding-identity.js.map +1 -1
- package/dist/baseline/flow-gate-check.d.ts +80 -0
- package/dist/baseline/flow-gate-check.d.ts.map +1 -0
- package/dist/baseline/flow-gate-check.js +216 -0
- package/dist/baseline/flow-gate-check.js.map +1 -0
- package/dist/baseline/migrate.d.ts.map +1 -1
- package/dist/baseline/migrate.js +3 -0
- package/dist/baseline/migrate.js.map +1 -1
- package/dist/baseline/producers/index.d.ts.map +1 -1
- package/dist/baseline/producers/index.js +9 -0
- package/dist/baseline/producers/index.js.map +1 -1
- package/dist/baseline/show.js +2 -0
- package/dist/baseline/show.js.map +1 -1
- package/dist/baseline/types.d.ts +32 -2
- package/dist/baseline/types.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/explore/flow-graph.d.ts +1 -1
- package/dist/explore/flow-graph.d.ts.map +1 -1
- package/dist/explore/flow-graph.js +4 -12
- package/dist/explore/flow-graph.js.map +1 -1
- package/dist/flow-cli.d.ts +10 -0
- package/dist/flow-cli.d.ts.map +1 -1
- package/dist/flow-cli.js +63 -18
- package/dist/flow-cli.js.map +1 -1
- package/dist/languages/index.d.ts +21 -0
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +41 -0
- package/dist/languages/index.js.map +1 -1
- package/dist/loop/policy.d.ts +4 -1
- package/dist/loop/policy.d.ts.map +1 -1
- package/dist/loop/policy.js +3 -0
- package/dist/loop/policy.js.map +1 -1
- package/dist/loop/stop-gate.d.ts.map +1 -1
- package/dist/loop/stop-gate.js +8 -2
- package/dist/loop/stop-gate.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.21.1] - 2026-07-01
|
|
11
|
+
|
|
12
|
+
### Fixed — the flow gate now honors the per-finding allowlist
|
|
13
|
+
|
|
14
|
+
A net-new broken integration could not be accepted per-finding: the
|
|
15
|
+
`flow-binding` allowlist category and identity existed, but the guardrail's
|
|
16
|
+
flow pass ran outside the matcher-pair suppression path, so an allowlist entry
|
|
17
|
+
never actually waived a flow block. The only escape hatch was the global
|
|
18
|
+
`flow.mode`. Now an active `flow-binding` allowlist entry (matched by
|
|
19
|
+
fingerprint, kind-guarded, expiry-respected) waives the block exactly like any
|
|
20
|
+
other finding kind — the finding is still surfaced as "suppressed by allowlist"
|
|
21
|
+
in the console, `--json`, and PR-comment markdown, but no longer fails the
|
|
22
|
+
build. Expired entries do not waive; the finding re-blocks.
|
|
23
|
+
|
|
24
|
+
### Known limitation (tracked)
|
|
25
|
+
|
|
26
|
+
The flow gate runs in **ref-based mode only**. In committed-baseline modes it
|
|
27
|
+
skips (no committed prior flow side to diff against), so a repo pinned to
|
|
28
|
+
`committed-full` is not yet flow-gated unless it sets `baseline.mode: ref-based`.
|
|
29
|
+
A fix that recomputes the base flow model from the baseline's commit is planned.
|
|
30
|
+
|
|
31
|
+
## [2.21.0] - 2026-07-01
|
|
32
|
+
|
|
33
|
+
### Added — the integration gate (`flow refresh` + guardrail flow pass)
|
|
34
|
+
|
|
35
|
+
The Flow feature's third slice turns UI→API traceability into a guardrail: a PR
|
|
36
|
+
that net-new breaks an integration — a frontend call to an endpoint no backend
|
|
37
|
+
serves, or a backend route removal a consumer still binds to — fails the check,
|
|
38
|
+
the same way a net-new secret or CVE does.
|
|
39
|
+
|
|
40
|
+
- **Net-new broken-integration gate.** The guardrail check now runs an additive,
|
|
41
|
+
fail-open flow pass over its ref-based `base↔HEAD` comparison. One algorithm
|
|
42
|
+
covers both directions (dead frontend call / removed backend route), because
|
|
43
|
+
both reduce to "a consumed binding whose `(method, path)` is not served."
|
|
44
|
+
Pre-existing breakage is grandfathered — only what the diff *newly* breaks is
|
|
45
|
+
surfaced. It never touches the existing finding matcher.
|
|
46
|
+
- **Confidence-gated, false-positive-safe.** An exact, fully specified binding
|
|
47
|
+
blocks; a placeholder-only path (`/{var}`) warns. The gate self-skips when it
|
|
48
|
+
has no served-side truth to check against (a pure frontend with no committed
|
|
49
|
+
contract), so it can never false-block a repo it can't fully see, and it fails
|
|
50
|
+
open on any error.
|
|
51
|
+
- **`vyuh-dxkit flow refresh`** writes the cross-repo contract snapshots
|
|
52
|
+
(`.dxkit/flow/served.json` + `consumed.json`). A backend publishes what it
|
|
53
|
+
serves; a frontend commits the counterpart's snapshot and gates against it —
|
|
54
|
+
so a split-repo setup needs a cross-repo fetch only at refresh time, never on
|
|
55
|
+
a developer's machine or in the per-check gate. A monorepo gates live against
|
|
56
|
+
its own routes and needs no snapshot.
|
|
57
|
+
- **Posture.** `.dxkit/policy.json:flow.mode` (`block` / `warn` / `off`, default
|
|
58
|
+
`block`) governs the verdict; the loop preset overrides it (`security-only`
|
|
59
|
+
warns, `full-debt` blocks) so an unattended loop can't wedge on a cross-repo
|
|
60
|
+
false positive. Broken integrations render in the console, `--json`, and
|
|
61
|
+
PR-comment markdown, and count toward the verdict banner.
|
|
62
|
+
- Runs only in ref-based mode (committed mode has no base flow model to diff);
|
|
63
|
+
a diff that touches no client call, route, or spec is skipped up front.
|
|
64
|
+
Binding identity is line-independent and environment-independent, so a
|
|
65
|
+
committed contract keeps matching when the check moves from a laptop to CI.
|
|
66
|
+
|
|
10
67
|
## [2.20.0] - 2026-07-01
|
|
11
68
|
|
|
12
69
|
### Added — native flow map + blast radius (`flow`, `flow trace`)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/allowlist/categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAMjB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,iBAAiB,CAG7D,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,iBAAiB,CAItE,CAAC;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,YAAY,CAO5D,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/allowlist/categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAMjB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,iBAAiB,CAG7D,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,iBAAiB,CAItE,CAAC;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,YAAY,CAO5D,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAkD3F,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAErF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAE/F;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,IAAiB,GAAG,MAAM,CAIhE"}
|
|
@@ -130,6 +130,10 @@ exports.CATEGORIES_BY_KIND = {
|
|
|
130
130
|
// TODO / FIXME / HACK / console-log / any-type markers: only
|
|
131
131
|
// accepted-risk or deferred (the marker IS the hygiene issue)
|
|
132
132
|
hygiene: ['accepted-risk', 'deferred'],
|
|
133
|
+
// Broken integration: false-positive (a cross-repo consumer exists that the
|
|
134
|
+
// scan didn't see, so the binding isn't actually dead); otherwise
|
|
135
|
+
// accepted-risk or deferred
|
|
136
|
+
'flow-binding': ['false-positive', 'accepted-risk', 'deferred'],
|
|
133
137
|
// Stale-allow (orphaned inline allowlist annotation): never
|
|
134
138
|
// allowlisted. The right response is always "remove the stale
|
|
135
139
|
// annotation" — allowlisting the warning that an annotation is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../src/allowlist/categories.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../src/allowlist/categories.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hint.d.ts","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAUtB,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;oBAEgB;IAChB,QAAQ,CAAC,oBAAoB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5D;;;mCAG+B;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;4CAGwC;IACxC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;2DACuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAyB3F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"hint.d.ts","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAUtB,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;oBAEgB;IAChB,QAAQ,CAAC,oBAAoB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5D;;;mCAG+B;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;4CAGwC;IACxC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;2DACuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAyB3F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CA+FlE"}
|
package/dist/allowlist/hint.js
CHANGED
|
@@ -179,6 +179,11 @@ function remediationFor(kind) {
|
|
|
179
179
|
'suppressed is no longer present, so the annotation is dead code. ' +
|
|
180
180
|
'Allowlisting THIS finding is not supported; the only remediation is ' +
|
|
181
181
|
'to delete the annotation comment.');
|
|
182
|
+
case 'flow-binding':
|
|
183
|
+
return ('A UI call no longer resolves to a served route (or a route a consumer ' +
|
|
184
|
+
'still binds to was removed). Restore the endpoint, fix the call to match ' +
|
|
185
|
+
'the current route, or — if a cross-repo consumer the scan cannot see is ' +
|
|
186
|
+
'intended — allowlist with category=false-positive.');
|
|
182
187
|
}
|
|
183
188
|
}
|
|
184
189
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
@@ -202,6 +207,7 @@ function entryLocator(entry) {
|
|
|
202
207
|
case 'config':
|
|
203
208
|
case 'hygiene':
|
|
204
209
|
case 'stale-allow':
|
|
210
|
+
case 'flow-binding':
|
|
205
211
|
return { file: entry.file, line: entry.line };
|
|
206
212
|
case 'coverage-gap':
|
|
207
213
|
case 'test-gap':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hint.js","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DH,0CAyBC;AAQD,
|
|
1
|
+
{"version":3,"file":"hint.js","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DH,0CAyBC;AAQD,wCA+FC;AAxLD,2CAA6B;AAC7B,mDAAmD;AAEnD,4CAAyC;AAEzC,6CAMsB;AACtB,qCAA4C;AAC5C,wDAA8C;AAE9C;;;GAGG;AACH,MAAM,iBAAiB,GAAG,IAAA,0BAAQ,EAAC,eAAe,CAAC,CAAC;AA0BpD;;;;;;;;;;GAUG;AACH,SAAgB,eAAe,CAAC,KAAoB,EAAE,QAA0B;IAC9E,MAAM,oBAAoB,GAAG,+BAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,0BAA0B,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACnE,yCAA4B,CAAC,GAAG,CAAC,CAAC,CAAC,CACpC,CAAC;IACF,MAAM,aAAa,GACjB,CAAC,oCAAuB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,0BAA0B,CAAC,MAAM,KAAK,CAAC,CAAC;IAEtF,MAAM,mBAAmB,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;IAE/D,kEAAkE;IAClE,wDAAwD;IACxD,KAAK,QAAQ,CAAC;IAEd,OAAO;QACL,WAAW,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC;QACvC,oBAAoB;QACpB,aAAa;QACb,UAAU;QACV,aAAa;QACb,aAAa;KACd,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,IAA2B;IACxD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,CACL,8EAA8E;gBAC9E,4EAA4E;gBAC5E,qEAAqE,CACtE,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,CACL,6EAA6E;gBAC7E,6EAA6E;gBAC7E,wDAAwD,CACzD,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,CACL,+DAA+D;gBAC/D,oEAAoE;gBACpE,uEAAuE;gBACvE,iCAAiC,CAClC,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,CACL,gEAAgE;gBAChE,GAAG;gBACH,IAAA,0BAAQ,EAAC,iBAAiB,CAAC;gBAC3B,yCAAyC;gBACzC,qBAAqB,CACtB,CAAC;QACJ,KAAK,aAAa;YAChB,OAAO,CACL,kEAAkE;gBAClE,uDAAuD;gBACvD,wEAAwE,CACzE,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO,CACL,gEAAgE;gBAChE,sEAAsE;gBACtE,kEAAkE,CACnE,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,CACL,sEAAsE;gBACtE,iEAAiE;gBACjE,sCAAsC,CACvC,CAAC;QACJ,KAAK,uBAAuB;YAC1B,OAAO,CACL,0EAA0E;gBAC1E,yEAAyE;gBACzE,0DAA0D,CAC3D,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO,CACL,uEAAuE;gBACvE,0EAA0E;gBAC1E,yEAAyE;gBACzE,+BAA+B,CAChC,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,CACL,yEAAyE;gBACzE,uEAAuE;gBACvE,yEAAyE;gBACzE,+BAA+B,CAChC,CAAC;QACJ,KAAK,YAAY;YACf,OAAO,CACL,+DAA+D;gBAC/D,gEAAgE;gBAChE,uDAAuD,CACxD,CAAC;QACJ,KAAK,YAAY;YACf,OAAO,CACL,wEAAwE;gBACxE,wEAAwE;gBACxE,+CAA+C,CAChD,CAAC;QACJ,KAAK,aAAa;YAChB,OAAO,CACL,iEAAiE;gBACjE,mEAAmE;gBACnE,sEAAsE;gBACtE,mCAAmC,CACpC,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO,CACL,wEAAwE;gBACxE,2EAA2E;gBAC3E,0EAA0E;gBAC1E,oDAAoD,CACrD,CAAC;IACN,CAAC;AACH,CAAC;AAED,4EAA4E;AAE5E;;;;;;;;;;GAUG;AACH,SAAS,YAAY,CAAC,KAAoB;IACxC,IAAI,IAAA,sBAAW,EAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc;YACjB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,KAAK,cAAc,CAAC;QACpB,KAAK,UAAU,CAAC;QAChB,KAAK,uBAAuB,CAAC;QAC7B,KAAK,UAAU,CAAC;QAChB,KAAK,YAAY,CAAC;QAClB,KAAK,YAAY;YACf,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAC9B,KAAK,aAAa,CAAC;QACnB,KAAK,UAAU,CAAC;QAChB,KAAK,aAAa;YAChB,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,qBAAS,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;IACvD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,kBAAkB,CACzB,KAAoB,EACpB,mBAAkD;IAElD,IAAI,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,CAAC,oCAAuB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/D,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,IAAA,yBAAgB,EAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,eAAe,CACtB,KAAoB,EACpB,oBAAkD;IAElD,MAAM,aAAa,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,6BAA6B,CAAC;IAChD,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,cAAc,aAAa,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC;IAC5F,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAEhC,oEAAoE;IACpE,oEAAoE;IACpE,EAAE;IACF,qEAAqE;IACrE,kEAAkE;IAClE,qDAAqD;IACrD,iEAAiE;IACjE,kEAAkE;IAClE,kDAAkD;IAClD,IAAI,oCAAuB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClF,OAAO,GAAG,iBAAiB,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;IACpF,CAAC;IACD,OAAO,GAAG,iBAAiB,kBAAkB,KAAK,CAAC,EAAE,WAAW,KAAK,CAAC,IAAI,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;AAC3G,CAAC;AAED,SAAS,kBAAkB,CACzB,oBAAkD;IAElD,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gCAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACzF,IAAI,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,CACL,2EAA2E;QAC3E,iFAAiF;QACjF,yCAAyC,CAC1C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow configuration read from `.dxkit/policy.json:flow` — the single reader of
|
|
3
|
+
* that section (Rule 2). Kept out of the shared `BrownfieldPolicy` schema (the
|
|
4
|
+
* same way the loop preset is read separately): the flow concept stays
|
|
5
|
+
* self-contained, and every flow surface — the `flow` CLI, the `flow refresh`
|
|
6
|
+
* snapshot writer, and the guardrail gate pass — resolves its config here.
|
|
7
|
+
*
|
|
8
|
+
* All fields are optional in the file; a missing / malformed policy yields the
|
|
9
|
+
* conservative defaults (fail-open), never a throw.
|
|
10
|
+
*/
|
|
11
|
+
/** How the guardrail treats a net-new broken integration.
|
|
12
|
+
* - `block` (default): honor the per-finding verdict — an exact, fully
|
|
13
|
+
* specified binding fails the build; a low-confidence (placeholder-only)
|
|
14
|
+
* one warns.
|
|
15
|
+
* - `warn`: every net-new break warns, never fails a build (soft launch, or
|
|
16
|
+
* a repo still tuning its served-side inventory).
|
|
17
|
+
* - `off`: the gate does not run at all. */
|
|
18
|
+
export type FlowGateMode = 'block' | 'warn' | 'off';
|
|
19
|
+
export interface FlowConfig {
|
|
20
|
+
/** Host-helper prefixes stripped during URL normalization (per-app config,
|
|
21
|
+
* e.g. `["https://api.example.com"]`). */
|
|
22
|
+
readonly stripUrlPrefixes: string[];
|
|
23
|
+
/** OpenAPI/spec files whose served routes union with static extraction. */
|
|
24
|
+
readonly specs: string[];
|
|
25
|
+
/** Guardrail posture for net-new broken integrations. */
|
|
26
|
+
readonly mode: FlowGateMode;
|
|
27
|
+
/** Confidence at/above which a net-new break BLOCKS (else warns). Default 1 —
|
|
28
|
+
* only exact, fully specified bindings can fail a build. */
|
|
29
|
+
readonly blockThreshold: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read the `flow` section of `.dxkit/policy.json`. Fail-open — a read/parse
|
|
33
|
+
* error, or an absent `flow` block, returns the defaults so a repo without flow
|
|
34
|
+
* config behaves as "monorepo, block on exact net-new breaks".
|
|
35
|
+
*/
|
|
36
|
+
export declare function readFlowConfig(cwd: string): FlowConfig;
|
|
37
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;;;;;8CAM8C;AAC9C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB;+CAC2C;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B;iEAC6D;IAC7D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAwBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAiBtD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Flow configuration read from `.dxkit/policy.json:flow` — the single reader of
|
|
4
|
+
* that section (Rule 2). Kept out of the shared `BrownfieldPolicy` schema (the
|
|
5
|
+
* same way the loop preset is read separately): the flow concept stays
|
|
6
|
+
* self-contained, and every flow surface — the `flow` CLI, the `flow refresh`
|
|
7
|
+
* snapshot writer, and the guardrail gate pass — resolves its config here.
|
|
8
|
+
*
|
|
9
|
+
* All fields are optional in the file; a missing / malformed policy yields the
|
|
10
|
+
* conservative defaults (fail-open), never a throw.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.readFlowConfig = readFlowConfig;
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const DEFAULTS = {
|
|
50
|
+
stripUrlPrefixes: [],
|
|
51
|
+
specs: [],
|
|
52
|
+
mode: 'block',
|
|
53
|
+
blockThreshold: 1,
|
|
54
|
+
};
|
|
55
|
+
function stringList(v) {
|
|
56
|
+
return Array.isArray(v) ? v.filter((s) => typeof s === 'string') : [];
|
|
57
|
+
}
|
|
58
|
+
function isMode(v) {
|
|
59
|
+
return v === 'block' || v === 'warn' || v === 'off';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read the `flow` section of `.dxkit/policy.json`. Fail-open — a read/parse
|
|
63
|
+
* error, or an absent `flow` block, returns the defaults so a repo without flow
|
|
64
|
+
* config behaves as "monorepo, block on exact net-new breaks".
|
|
65
|
+
*/
|
|
66
|
+
function readFlowConfig(cwd) {
|
|
67
|
+
let raw;
|
|
68
|
+
try {
|
|
69
|
+
const text = fs.readFileSync(path.join(cwd, '.dxkit', 'policy.json'), 'utf8');
|
|
70
|
+
raw = (JSON.parse(text)?.flow ?? {});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return DEFAULTS;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
stripUrlPrefixes: stringList(raw.stripUrlPrefixes),
|
|
77
|
+
specs: stringList(raw.specs),
|
|
78
|
+
mode: isMode(raw.mode) ? raw.mode : DEFAULTS.mode,
|
|
79
|
+
blockThreshold: typeof raw.blockThreshold === 'number' && raw.blockThreshold > 0
|
|
80
|
+
? raw.blockThreshold
|
|
81
|
+
: DEFAULTS.blockThreshold,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/analyzers/flow/config.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDH,wCAiBC;AArED,uCAAyB;AACzB,2CAA6B;AAwB7B,MAAM,QAAQ,GAAe;IAC3B,gBAAgB,EAAE,EAAE;IACpB,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,OAAO;IACb,cAAc,EAAE,CAAC;CAClB,CAAC;AASF,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC;AAED,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9E,GAAG,GAAG,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,EAAE,IAAI,IAAI,EAAE,CAAY,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO;QACL,gBAAgB,EAAE,UAAU,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAClD,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;QACjD,cAAc,EACZ,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,GAAG,CAAC;YAC9D,CAAC,CAAC,GAAG,CAAC,cAAc;YACpB,CAAC,CAAC,QAAQ,CAAC,cAAc;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-repo flow contract snapshots under `.dxkit/flow/`.
|
|
3
|
+
*
|
|
4
|
+
* The integration gate is cross-repo: each side publishes its inventory as a
|
|
5
|
+
* committed artifact the OTHER side gates against (mirror of the ingest
|
|
6
|
+
* snapshot pattern, CLAUDE.md Rule 13). A backend refreshes `served.json`
|
|
7
|
+
* (every `(method, path)` it serves); a frontend refreshes `consumed.json`
|
|
8
|
+
* (every binding it depends on). A repo commits the COUNTERPART's snapshot (or
|
|
9
|
+
* a monorepo computes both live), so the gate needs a cross-repo fetch/token
|
|
10
|
+
* only at refresh time — never on the developer's machine or in the per-stop
|
|
11
|
+
* gate.
|
|
12
|
+
*
|
|
13
|
+
* This module is the single reader/writer of `.dxkit/flow/`: confining the path
|
|
14
|
+
* here (arch-check enforced) stops the "different modules pick different
|
|
15
|
+
* defaults" drift class and keeps a future cross-repo fetch composing on one
|
|
16
|
+
* primitive. Snapshots carry only finding data (normalized method/path/file) —
|
|
17
|
+
* no token, no account id — so they are safe to commit.
|
|
18
|
+
*/
|
|
19
|
+
import { type FlowModel } from './model';
|
|
20
|
+
/** Directory (relative to repo root) where flow contract snapshots live. */
|
|
21
|
+
export declare const FLOW_DIR: string;
|
|
22
|
+
export declare const SERVED_SNAPSHOT = "served.json";
|
|
23
|
+
export declare const CONSUMED_SNAPSHOT = "consumed.json";
|
|
24
|
+
/** One served endpoint in the served-side inventory. */
|
|
25
|
+
export interface ServedRoute {
|
|
26
|
+
readonly method: string;
|
|
27
|
+
readonly path: string;
|
|
28
|
+
readonly handler: string | null;
|
|
29
|
+
readonly via: 'decorator' | 'router-call' | 'spec';
|
|
30
|
+
}
|
|
31
|
+
/** One binding in the consumed-side inventory — a UI call site's dependency on
|
|
32
|
+
* a served `(method, path)`. `file` + the normalized key are the flow-binding
|
|
33
|
+
* identity inputs; `line` is display metadata (never hashed). `confidence` in
|
|
34
|
+
* [0,1] is the path-specificity signal the gate thresholds on — a
|
|
35
|
+
* placeholder-only path (`/{var}`) is too generic to block a build. */
|
|
36
|
+
export interface ConsumedBinding {
|
|
37
|
+
readonly method: string;
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly file: string;
|
|
40
|
+
readonly line: number;
|
|
41
|
+
readonly confidence: number;
|
|
42
|
+
}
|
|
43
|
+
interface SnapshotMeta {
|
|
44
|
+
readonly schemaVersion: 1;
|
|
45
|
+
/** ISO timestamp, stamped by the caller so this module stays clock-free
|
|
46
|
+
* (testability — mirror of ingest/snapshot.ts). */
|
|
47
|
+
readonly generatedAt: string;
|
|
48
|
+
/** Commit the snapshot was produced against, when known. */
|
|
49
|
+
readonly commitSha?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface ServedContract extends SnapshotMeta {
|
|
52
|
+
readonly side: 'served';
|
|
53
|
+
readonly routes: ServedRoute[];
|
|
54
|
+
}
|
|
55
|
+
export interface ConsumedContract extends SnapshotMeta {
|
|
56
|
+
readonly side: 'consumed';
|
|
57
|
+
readonly bindings: ConsumedBinding[];
|
|
58
|
+
}
|
|
59
|
+
/** The `${method} ${path}` join key both sides meet on. */
|
|
60
|
+
export declare function contractKey(method: string, routePath: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* The served inventory: every distinct `(method, path)` this repo serves,
|
|
63
|
+
* deduped via the shared helper (spec wins). Sorted for byte-stable snapshots
|
|
64
|
+
* across runs (a committed artifact should not churn on extraction order).
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildServedContract(model: FlowModel, meta: SnapshotMeta): ServedContract;
|
|
67
|
+
/**
|
|
68
|
+
* The consumed inventory: every internal binding this repo depends on — each
|
|
69
|
+
* client call that resolved to an internal path (external/absolute URLs, whose
|
|
70
|
+
* `path` is null, are not internal integrations). Deduped by
|
|
71
|
+
* `(method, path, file)` — the flow-binding identity — so multiple call sites
|
|
72
|
+
* for one dependency collapse to one entry (the earliest line kept for
|
|
73
|
+
* display). Sorted for byte-stability.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildConsumedContract(model: FlowModel, meta: SnapshotMeta): ConsumedContract;
|
|
76
|
+
/** Write the served snapshot (overwrite). Returns the file path. */
|
|
77
|
+
export declare function writeServedContract(cwd: string, contract: ServedContract): string;
|
|
78
|
+
/** Write the consumed snapshot (overwrite). Returns the file path. */
|
|
79
|
+
export declare function writeConsumedContract(cwd: string, contract: ConsumedContract): string;
|
|
80
|
+
/**
|
|
81
|
+
* Read the served snapshot from a repo root (default `.dxkit/flow/served.json`,
|
|
82
|
+
* or an explicit path for a counterpart's committed snapshot). Fail-open: a
|
|
83
|
+
* missing / unreadable / malformed file yields `undefined`, never a throw — the
|
|
84
|
+
* gate degrades to "no contract to check against", never an error.
|
|
85
|
+
*/
|
|
86
|
+
export declare function readServedContract(cwd: string, filePath?: string): ServedContract | undefined;
|
|
87
|
+
/** Read the consumed snapshot (see {@link readServedContract}). */
|
|
88
|
+
export declare function readConsumedContract(cwd: string, filePath?: string): ConsumedContract | undefined;
|
|
89
|
+
/** The `${method} ${path}` keys a served contract exposes — the O(1) lookup the
|
|
90
|
+
* gate uses to check whether a consumed binding still resolves. */
|
|
91
|
+
export declare function servedKeySet(contract: ServedContract): Set<string>;
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,QAA8B,CAAC;AACpD,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;CACpD;AAED;;;;wEAIwE;AACxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B;wDACoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;CACtC;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAErE;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,cAAc,CAKxF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,gBAAgB,CAsB5F;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAEjF;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAErF;AAgBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAG7F;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGjG;AAED;oEACoE;AACpE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC,CAElE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-repo flow contract snapshots under `.dxkit/flow/`.
|
|
4
|
+
*
|
|
5
|
+
* The integration gate is cross-repo: each side publishes its inventory as a
|
|
6
|
+
* committed artifact the OTHER side gates against (mirror of the ingest
|
|
7
|
+
* snapshot pattern, CLAUDE.md Rule 13). A backend refreshes `served.json`
|
|
8
|
+
* (every `(method, path)` it serves); a frontend refreshes `consumed.json`
|
|
9
|
+
* (every binding it depends on). A repo commits the COUNTERPART's snapshot (or
|
|
10
|
+
* a monorepo computes both live), so the gate needs a cross-repo fetch/token
|
|
11
|
+
* only at refresh time — never on the developer's machine or in the per-stop
|
|
12
|
+
* gate.
|
|
13
|
+
*
|
|
14
|
+
* This module is the single reader/writer of `.dxkit/flow/`: confining the path
|
|
15
|
+
* here (arch-check enforced) stops the "different modules pick different
|
|
16
|
+
* defaults" drift class and keeps a future cross-repo fetch composing on one
|
|
17
|
+
* primitive. Snapshots carry only finding data (normalized method/path/file) —
|
|
18
|
+
* no token, no account id — so they are safe to commit.
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.CONSUMED_SNAPSHOT = exports.SERVED_SNAPSHOT = exports.FLOW_DIR = void 0;
|
|
55
|
+
exports.contractKey = contractKey;
|
|
56
|
+
exports.buildServedContract = buildServedContract;
|
|
57
|
+
exports.buildConsumedContract = buildConsumedContract;
|
|
58
|
+
exports.writeServedContract = writeServedContract;
|
|
59
|
+
exports.writeConsumedContract = writeConsumedContract;
|
|
60
|
+
exports.readServedContract = readServedContract;
|
|
61
|
+
exports.readConsumedContract = readConsumedContract;
|
|
62
|
+
exports.servedKeySet = servedKeySet;
|
|
63
|
+
const fs = __importStar(require("fs"));
|
|
64
|
+
const path = __importStar(require("path"));
|
|
65
|
+
const model_1 = require("./model");
|
|
66
|
+
/** Directory (relative to repo root) where flow contract snapshots live. */
|
|
67
|
+
exports.FLOW_DIR = path.join('.dxkit', 'flow');
|
|
68
|
+
exports.SERVED_SNAPSHOT = 'served.json';
|
|
69
|
+
exports.CONSUMED_SNAPSHOT = 'consumed.json';
|
|
70
|
+
/** The `${method} ${path}` join key both sides meet on. */
|
|
71
|
+
function contractKey(method, routePath) {
|
|
72
|
+
return `${method} ${routePath}`;
|
|
73
|
+
}
|
|
74
|
+
// ─── Build (from a flow model) ────────────────────────────────────────────────
|
|
75
|
+
/**
|
|
76
|
+
* The served inventory: every distinct `(method, path)` this repo serves,
|
|
77
|
+
* deduped via the shared helper (spec wins). Sorted for byte-stable snapshots
|
|
78
|
+
* across runs (a committed artifact should not churn on extraction order).
|
|
79
|
+
*/
|
|
80
|
+
function buildServedContract(model, meta) {
|
|
81
|
+
const routes = (0, model_1.dedupeServedRoutes)(model.routes)
|
|
82
|
+
.map((r) => ({ method: r.method, path: r.path, handler: r.handler, via: r.via }))
|
|
83
|
+
.sort(byMethodPath);
|
|
84
|
+
return { ...meta, side: 'served', routes };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The consumed inventory: every internal binding this repo depends on — each
|
|
88
|
+
* client call that resolved to an internal path (external/absolute URLs, whose
|
|
89
|
+
* `path` is null, are not internal integrations). Deduped by
|
|
90
|
+
* `(method, path, file)` — the flow-binding identity — so multiple call sites
|
|
91
|
+
* for one dependency collapse to one entry (the earliest line kept for
|
|
92
|
+
* display). Sorted for byte-stability.
|
|
93
|
+
*/
|
|
94
|
+
function buildConsumedContract(model, meta) {
|
|
95
|
+
const byKey = new Map();
|
|
96
|
+
for (const call of model.calls) {
|
|
97
|
+
if (call.path == null)
|
|
98
|
+
continue;
|
|
99
|
+
const key = `${call.method}\0${call.path}\0${call.file}`;
|
|
100
|
+
const existing = byKey.get(key);
|
|
101
|
+
if (!existing || call.line < existing.line) {
|
|
102
|
+
byKey.set(key, {
|
|
103
|
+
method: call.method,
|
|
104
|
+
path: call.path,
|
|
105
|
+
file: call.file,
|
|
106
|
+
line: call.line,
|
|
107
|
+
// A placeholder-only path carries no static signal → low confidence, so
|
|
108
|
+
// the gate warns rather than blocks on it.
|
|
109
|
+
confidence: (0, model_1.isPlaceholderOnlyPath)(call.path) ? 0.3 : 1,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const bindings = [...byKey.values()].sort((a, b) => byMethodPath(a, b) || a.file.localeCompare(b.file));
|
|
114
|
+
return { ...meta, side: 'consumed', bindings };
|
|
115
|
+
}
|
|
116
|
+
function byMethodPath(a, b) {
|
|
117
|
+
return a.method.localeCompare(b.method) || a.path.localeCompare(b.path);
|
|
118
|
+
}
|
|
119
|
+
// ─── Persist ──────────────────────────────────────────────────────────────────
|
|
120
|
+
/** Write the served snapshot (overwrite). Returns the file path. */
|
|
121
|
+
function writeServedContract(cwd, contract) {
|
|
122
|
+
return writeSnapshot(cwd, exports.SERVED_SNAPSHOT, contract);
|
|
123
|
+
}
|
|
124
|
+
/** Write the consumed snapshot (overwrite). Returns the file path. */
|
|
125
|
+
function writeConsumedContract(cwd, contract) {
|
|
126
|
+
return writeSnapshot(cwd, exports.CONSUMED_SNAPSHOT, contract);
|
|
127
|
+
}
|
|
128
|
+
function writeSnapshot(cwd, name, contract) {
|
|
129
|
+
const dir = path.join(cwd, exports.FLOW_DIR);
|
|
130
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
131
|
+
const file = path.join(dir, name);
|
|
132
|
+
fs.writeFileSync(file, JSON.stringify(contract, null, 2) + '\n', 'utf-8');
|
|
133
|
+
return file;
|
|
134
|
+
}
|
|
135
|
+
// ─── Load (fail-open) ───────────────────────────────────────────────────────
|
|
136
|
+
/**
|
|
137
|
+
* Read the served snapshot from a repo root (default `.dxkit/flow/served.json`,
|
|
138
|
+
* or an explicit path for a counterpart's committed snapshot). Fail-open: a
|
|
139
|
+
* missing / unreadable / malformed file yields `undefined`, never a throw — the
|
|
140
|
+
* gate degrades to "no contract to check against", never an error.
|
|
141
|
+
*/
|
|
142
|
+
function readServedContract(cwd, filePath) {
|
|
143
|
+
const raw = readJson(filePath ?? path.join(cwd, exports.FLOW_DIR, exports.SERVED_SNAPSHOT));
|
|
144
|
+
return isServed(raw) ? raw : undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Read the consumed snapshot (see {@link readServedContract}). */
|
|
147
|
+
function readConsumedContract(cwd, filePath) {
|
|
148
|
+
const raw = readJson(filePath ?? path.join(cwd, exports.FLOW_DIR, exports.CONSUMED_SNAPSHOT));
|
|
149
|
+
return isConsumed(raw) ? raw : undefined;
|
|
150
|
+
}
|
|
151
|
+
/** The `${method} ${path}` keys a served contract exposes — the O(1) lookup the
|
|
152
|
+
* gate uses to check whether a consumed binding still resolves. */
|
|
153
|
+
function servedKeySet(contract) {
|
|
154
|
+
return new Set(contract.routes.map((r) => contractKey(r.method, r.path)));
|
|
155
|
+
}
|
|
156
|
+
function readJson(absPath) {
|
|
157
|
+
try {
|
|
158
|
+
return JSON.parse(fs.readFileSync(absPath, 'utf-8'));
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function isServed(v) {
|
|
165
|
+
return (typeof v === 'object' &&
|
|
166
|
+
v !== null &&
|
|
167
|
+
v.side === 'served' &&
|
|
168
|
+
Array.isArray(v.routes));
|
|
169
|
+
}
|
|
170
|
+
function isConsumed(v) {
|
|
171
|
+
return (typeof v === 'object' &&
|
|
172
|
+
v !== null &&
|
|
173
|
+
v.side === 'consumed' &&
|
|
174
|
+
Array.isArray(v.bindings));
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/analyzers/flow/contract.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDH,kCAEC;AASD,kDAKC;AAUD,sDAsBC;AAYD,kDAEC;AAGD,sDAEC;AAsBD,gDAGC;AAGD,oDAGC;AAID,oCAEC;AA1JD,uCAAyB;AACzB,2CAA6B;AAC7B,mCAAoF;AAEpF,4EAA4E;AAC/D,QAAA,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACvC,QAAA,eAAe,GAAG,aAAa,CAAC;AAChC,QAAA,iBAAiB,GAAG,eAAe,CAAC;AA0CjD,2DAA2D;AAC3D,SAAgB,WAAW,CAAC,MAAc,EAAE,SAAiB;IAC3D,OAAO,GAAG,MAAM,IAAI,SAAS,EAAE,CAAC;AAClC,CAAC;AAED,iFAAiF;AAEjF;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,KAAgB,EAAE,IAAkB;IACtE,MAAM,MAAM,GAAG,IAAA,0BAAkB,EAAC,KAAK,CAAC,MAAM,CAAC;SAC5C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;SAChF,IAAI,CAAC,YAAY,CAAC,CAAC;IACtB,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,qBAAqB,CAAC,KAAgB,EAAE,IAAkB;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;YAAE,SAAS;QAChC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC3C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;gBACb,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,wEAAwE;gBACxE,2CAA2C;gBAC3C,UAAU,EAAE,IAAA,6BAAqB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aACvD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAC7D,CAAC;IACF,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AACjD,CAAC;AAED,SAAS,YAAY,CACnB,CAAmC,EACnC,CAAmC;IAEnC,OAAO,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC1E,CAAC;AAED,iFAAiF;AAEjF,oEAAoE;AACpE,SAAgB,mBAAmB,CAAC,GAAW,EAAE,QAAwB;IACvE,OAAO,aAAa,CAAC,GAAG,EAAE,uBAAe,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED,sEAAsE;AACtE,SAAgB,qBAAqB,CAAC,GAAW,EAAE,QAA0B;IAC3E,OAAO,aAAa,CAAC,GAAG,EAAE,yBAAiB,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CACpB,GAAW,EACX,IAAY,EACZ,QAA2C;IAE3C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAQ,CAAC,CAAC;IACrC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+EAA+E;AAE/E;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,GAAW,EAAE,QAAiB;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAQ,EAAE,uBAAe,CAAC,CAAC,CAAC;IAC5E,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACzC,CAAC;AAED,mEAAmE;AACnE,SAAgB,oBAAoB,CAAC,GAAW,EAAE,QAAiB;IACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAQ,EAAE,yBAAiB,CAAC,CAAC,CAAC;IAC9E,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3C,CAAC;AAED;oEACoE;AACpE,SAAgB,YAAY,CAAC,QAAwB;IACnD,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAoB,CAAC,IAAI,KAAK,QAAQ;QACvC,KAAK,CAAC,OAAO,CAAE,CAAoB,CAAC,MAAM,CAAC,CAC5C,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAsB,CAAC,IAAI,KAAK,UAAU;QAC3C,KAAK,CAAC,OAAO,CAAE,CAAsB,CAAC,QAAQ,CAAC,CAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The integration-breakage gate — pure evaluation core.
|
|
3
|
+
*
|
|
4
|
+
* Answers "does this diff NET-NEW break a UI→API integration?" from a base↔HEAD
|
|
5
|
+
* contract comparison, with no running system. One algorithm covers both
|
|
6
|
+
* directions (CLAUDE.md design §6):
|
|
7
|
+
* - a FRONTEND PR that adds a call to an endpoint no backend serves, and
|
|
8
|
+
* - a BACKEND PR that removes/renames a route a frontend still calls,
|
|
9
|
+
* because both reduce to "a consumed binding whose (method, path) is not in the
|
|
10
|
+
* served set". The diff makes it net-new: a binding already broken BEFORE the
|
|
11
|
+
* PR (present at base and unresolved against the base served set) is
|
|
12
|
+
* grandfathered; only a binding the PR NEWLY breaks is surfaced.
|
|
13
|
+
*
|
|
14
|
+
* Pure over its inputs — the ref-based gather (base worktree via
|
|
15
|
+
* `withRefWorktree`, Rule 11) and the guardrail wiring live above this module;
|
|
16
|
+
* here we only diff two already-materialized contract sides. Identity is the
|
|
17
|
+
* flow-binding fingerprint (line-independent (method, path, file), Rule 9),
|
|
18
|
+
* computed through the canonical helper so an emitted finding shares one
|
|
19
|
+
* identity contract with the baseline + allowlist.
|
|
20
|
+
*/
|
|
21
|
+
import { type ConsumedBinding } from './contract';
|
|
22
|
+
/** Why a binding is broken: the endpoint was never served (a new call to a
|
|
23
|
+
* non-existent route, or a typo), or a route that WAS served got removed. */
|
|
24
|
+
export type BrokenReason = 'no-route' | 'route-removed';
|
|
25
|
+
/** One net-new broken integration the gate surfaces. */
|
|
26
|
+
export interface BrokenIntegration {
|
|
27
|
+
/** Flow-binding fingerprint — the durable identity (Rule 9). */
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly method: string;
|
|
30
|
+
readonly path: string;
|
|
31
|
+
readonly file: string;
|
|
32
|
+
readonly line: number;
|
|
33
|
+
readonly confidence: number;
|
|
34
|
+
readonly reason: BrokenReason;
|
|
35
|
+
/** `block` when confidence clears the threshold (a real, specific breakage),
|
|
36
|
+
* else `warn` — conservative by construction to protect the false-positive
|
|
37
|
+
* budget (fuzzy / placeholder-only paths never fail a build). */
|
|
38
|
+
readonly verdict: 'block' | 'warn';
|
|
39
|
+
}
|
|
40
|
+
export interface GateInputs {
|
|
41
|
+
/** Bindings this side depends on at HEAD (the consumed contract post-diff). */
|
|
42
|
+
readonly headConsumed: readonly ConsumedBinding[];
|
|
43
|
+
/** Bindings at the base ref — the grandfathering set. */
|
|
44
|
+
readonly baseConsumed: readonly ConsumedBinding[];
|
|
45
|
+
/** `${method} ${path}` keys served at HEAD (the counterpart's served
|
|
46
|
+
* contract, or this repo's own in a monorepo). */
|
|
47
|
+
readonly headServed: ReadonlySet<string>;
|
|
48
|
+
/** Served keys at the base ref. */
|
|
49
|
+
readonly baseServed: ReadonlySet<string>;
|
|
50
|
+
/** Confidence at/above which a net-new broken binding BLOCKS (else warns).
|
|
51
|
+
* Default 1 — only exact, fully-specified bindings can fail a build. */
|
|
52
|
+
readonly blockThreshold?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Evaluate the gate. Returns every NET-NEW broken integration, most-severe
|
|
56
|
+
* (block before warn) first, then by location for stable output. Empty when the
|
|
57
|
+
* diff breaks nothing new.
|
|
58
|
+
*/
|
|
59
|
+
export declare function evaluateFlowGate(inputs: GateInputs): BrokenIntegration[];
|
|
60
|
+
/** Does the gate result block? True when any finding's verdict is `block`. */
|
|
61
|
+
export declare function flowGateBlocks(findings: readonly BrokenIntegration[]): boolean;
|
|
62
|
+
/** Human-readable one-liner for a broken integration (report + Stop-gate). */
|
|
63
|
+
export declare function describeBrokenIntegration(f: BrokenIntegration): string;
|
|
64
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/analyzers/flow/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D;8EAC8E;AAC9E,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,eAAe,CAAC;AAExD,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B;;sEAEkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,EAAE,SAAS,eAAe,EAAE,CAAC;IAClD,yDAAyD;IACzD,QAAQ,CAAC,YAAY,EAAE,SAAS,eAAe,EAAE,CAAC;IAClD;uDACmD;IACnD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,mCAAmC;IACnC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC;6EACyE;IACzE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,iBAAiB,EAAE,CAwCxE;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAE9E;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAMtE"}
|