@descryy/core 0.3.0 → 0.5.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.
- package/dist/budget/reply.d.ts +11 -46
- package/dist/budget/reply.d.ts.map +1 -1
- package/dist/budget/reply.js +10 -39
- package/dist/budget/reply.js.map +1 -1
- package/dist/budget/size.d.ts +2 -21
- package/dist/budget/size.d.ts.map +1 -1
- package/dist/budget/size.js +3 -24
- package/dist/budget/size.js.map +1 -1
- package/dist/capabilities/preconditions.d.ts +7 -68
- package/dist/capabilities/preconditions.d.ts.map +1 -1
- package/dist/capabilities/preconditions.js +6 -57
- package/dist/capabilities/preconditions.js.map +1 -1
- package/dist/contracts/engine.d.ts +26 -12
- package/dist/contracts/engine.d.ts.map +1 -1
- package/dist/contracts/engine.js +28 -11
- package/dist/contracts/engine.js.map +1 -1
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/orphans.d.ts +28 -77
- package/dist/contracts/orphans.d.ts.map +1 -1
- package/dist/contracts/orphans.js +124 -94
- package/dist/contracts/orphans.js.map +1 -1
- package/dist/contracts/paths.d.ts +4 -114
- package/dist/contracts/paths.d.ts.map +1 -1
- package/dist/contracts/paths.js +7 -140
- package/dist/contracts/paths.js.map +1 -1
- package/dist/contracts/shapes.d.ts +13 -66
- package/dist/contracts/shapes.d.ts.map +1 -1
- package/dist/contracts/shapes.js +20 -91
- package/dist/contracts/shapes.js.map +1 -1
- package/dist/governance/budget.d.ts +12 -48
- package/dist/governance/budget.d.ts.map +1 -1
- package/dist/governance/budget.js +12 -48
- package/dist/governance/budget.js.map +1 -1
- package/dist/governance/candidate-boundary.d.ts +4 -32
- package/dist/governance/candidate-boundary.d.ts.map +1 -1
- package/dist/governance/candidate-boundary.js +4 -32
- package/dist/governance/candidate-boundary.js.map +1 -1
- package/dist/governance/escalation.d.ts +7 -45
- package/dist/governance/escalation.d.ts.map +1 -1
- package/dist/governance/escalation.js +7 -45
- package/dist/governance/escalation.js.map +1 -1
- package/dist/governance/fact-boundary.d.ts +7 -49
- package/dist/governance/fact-boundary.d.ts.map +1 -1
- package/dist/governance/fact-boundary.js +5 -43
- package/dist/governance/fact-boundary.js.map +1 -1
- package/dist/governance/finding-funnel.d.ts +11 -72
- package/dist/governance/finding-funnel.d.ts.map +1 -1
- package/dist/governance/finding-funnel.js +9 -68
- package/dist/governance/finding-funnel.js.map +1 -1
- package/dist/graph/build.d.ts +13 -75
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +0 -0
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/cross-language.d.ts +4 -43
- package/dist/graph/cross-language.d.ts.map +1 -1
- package/dist/graph/cross-language.js +9 -77
- package/dist/graph/cross-language.js.map +1 -1
- package/dist/graph/index.d.ts +1 -1
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/merge.d.ts +8 -76
- package/dist/graph/merge.d.ts.map +1 -1
- package/dist/graph/merge.js +27 -77
- package/dist/graph/merge.js.map +1 -1
- package/dist/graph/observed-tests.d.ts +7 -68
- package/dist/graph/observed-tests.d.ts.map +1 -1
- package/dist/graph/observed-tests.js +5 -60
- package/dist/graph/observed-tests.js.map +1 -1
- package/dist/graph/persist.d.ts +2 -25
- package/dist/graph/persist.d.ts.map +1 -1
- package/dist/graph/persist.js +2 -25
- package/dist/graph/persist.js.map +1 -1
- package/dist/graph/runtime-confirmation.d.ts +14 -91
- package/dist/graph/runtime-confirmation.d.ts.map +1 -1
- package/dist/graph/runtime-confirmation.js +19 -103
- package/dist/graph/runtime-confirmation.js.map +1 -1
- package/dist/ledger/mint.d.ts +9 -43
- package/dist/ledger/mint.d.ts.map +1 -1
- package/dist/ledger/mint.js +15 -65
- package/dist/ledger/mint.js.map +1 -1
- package/dist/ledger/resolve.d.ts +13 -81
- package/dist/ledger/resolve.d.ts.map +1 -1
- package/dist/ledger/resolve.js +13 -76
- package/dist/ledger/resolve.js.map +1 -1
- package/dist/multipr/fingerprint.d.ts +5 -46
- package/dist/multipr/fingerprint.d.ts.map +1 -1
- package/dist/multipr/fingerprint.js +22 -74
- package/dist/multipr/fingerprint.js.map +1 -1
- package/dist/multipr/hidden-dependency.d.ts +13 -73
- package/dist/multipr/hidden-dependency.d.ts.map +1 -1
- package/dist/multipr/hidden-dependency.js +12 -63
- package/dist/multipr/hidden-dependency.js.map +1 -1
- package/dist/multipr/mechanical.d.ts +25 -160
- package/dist/multipr/mechanical.d.ts.map +1 -1
- package/dist/multipr/mechanical.js +21 -137
- package/dist/multipr/mechanical.js.map +1 -1
- package/dist/multipr/migration-heads.d.ts +18 -105
- package/dist/multipr/migration-heads.d.ts.map +1 -1
- package/dist/multipr/migration-heads.js +15 -84
- package/dist/multipr/migration-heads.js.map +1 -1
- package/dist/multipr/overlap.d.ts +16 -94
- package/dist/multipr/overlap.d.ts.map +1 -1
- package/dist/multipr/overlap.js +25 -105
- package/dist/multipr/overlap.js.map +1 -1
- package/dist/multipr/scope-store.d.ts +15 -80
- package/dist/multipr/scope-store.d.ts.map +1 -1
- package/dist/multipr/scope-store.js +17 -87
- package/dist/multipr/scope-store.js.map +1 -1
- package/dist/multipr/superseded.d.ts +10 -95
- package/dist/multipr/superseded.d.ts.map +1 -1
- package/dist/multipr/superseded.js +7 -60
- package/dist/multipr/superseded.js.map +1 -1
- package/dist/query/confirmed-facts.d.ts +12 -58
- package/dist/query/confirmed-facts.d.ts.map +1 -1
- package/dist/query/confirmed-facts.js +8 -47
- package/dist/query/confirmed-facts.js.map +1 -1
- package/dist/query/declared-value-closure.d.ts +13 -104
- package/dist/query/declared-value-closure.d.ts.map +1 -1
- package/dist/query/declared-value-closure.js +15 -104
- package/dist/query/declared-value-closure.js.map +1 -1
- package/dist/query/memory.d.ts +5 -9
- package/dist/query/memory.d.ts.map +1 -1
- package/dist/query/memory.js +31 -15
- package/dist/query/memory.js.map +1 -1
- package/dist/query/prominence.d.ts +6 -55
- package/dist/query/prominence.d.ts.map +1 -1
- package/dist/query/prominence.js +6 -55
- package/dist/query/prominence.js.map +1 -1
- package/dist/query/provider.d.ts +28 -81
- package/dist/query/provider.d.ts.map +1 -1
- package/dist/query/provider.js +8 -29
- package/dist/query/provider.js.map +1 -1
- package/dist/query/queries.d.ts +15 -65
- package/dist/query/queries.d.ts.map +1 -1
- package/dist/query/queries.js +43 -100
- package/dist/query/queries.js.map +1 -1
- package/dist/query/refusal-fetch.d.ts +8 -85
- package/dist/query/refusal-fetch.d.ts.map +1 -1
- package/dist/query/refusal-fetch.js +11 -93
- package/dist/query/refusal-fetch.js.map +1 -1
- package/dist/query/refusal-questions.d.ts +17 -92
- package/dist/query/refusal-questions.d.ts.map +1 -1
- package/dist/query/refusal-questions.js +14 -78
- package/dist/query/refusal-questions.js.map +1 -1
- package/dist/query/resolution-floor.d.ts +3 -23
- package/dist/query/resolution-floor.d.ts.map +1 -1
- package/dist/query/resolution-floor.js +3 -23
- package/dist/query/resolution-floor.js.map +1 -1
- package/dist/query/root-cause-score.d.ts +11 -161
- package/dist/query/root-cause-score.d.ts.map +1 -1
- package/dist/query/root-cause-score.js +6 -137
- package/dist/query/root-cause-score.js.map +1 -1
- package/dist/query/row-closure-picture.d.ts +5 -67
- package/dist/query/row-closure-picture.d.ts.map +1 -1
- package/dist/query/row-closure-picture.js +6 -67
- package/dist/query/row-closure-picture.js.map +1 -1
- package/dist/query/similar-incidents.d.ts +6 -41
- package/dist/query/similar-incidents.d.ts.map +1 -1
- package/dist/query/similar-incidents.js +15 -69
- package/dist/query/similar-incidents.js.map +1 -1
- package/dist/query/sqlite.d.ts +3 -7
- package/dist/query/sqlite.d.ts.map +1 -1
- package/dist/query/sqlite.js +13 -16
- package/dist/query/sqlite.js.map +1 -1
- package/dist/query/test-coverage.d.ts +5 -45
- package/dist/query/test-coverage.d.ts.map +1 -1
- package/dist/query/test-coverage.js +10 -53
- package/dist/query/test-coverage.js.map +1 -1
- package/dist/query/traverse.d.ts +22 -126
- package/dist/query/traverse.d.ts.map +1 -1
- package/dist/query/traverse.js +0 -0
- package/dist/query/traverse.js.map +1 -1
- package/dist/query/unresolved.d.ts +19 -164
- package/dist/query/unresolved.d.ts.map +1 -1
- package/dist/query/unresolved.js +11 -138
- package/dist/query/unresolved.js.map +1 -1
- package/dist/query/verification-status.d.ts +12 -109
- package/dist/query/verification-status.d.ts.map +1 -1
- package/dist/query/verification-status.js +9 -99
- package/dist/query/verification-status.js.map +1 -1
- package/dist/recording/migrate.d.ts +4 -10
- package/dist/recording/migrate.d.ts.map +1 -1
- package/dist/recording/migrate.js +4 -10
- package/dist/recording/migrate.js.map +1 -1
- package/dist/recording/reader.d.ts +2 -7
- package/dist/recording/reader.d.ts.map +1 -1
- package/dist/recording/reader.js +2 -7
- package/dist/recording/reader.js.map +1 -1
- package/dist/recording/redact.d.ts +6 -57
- package/dist/recording/redact.d.ts.map +1 -1
- package/dist/recording/redact.js +8 -64
- package/dist/recording/redact.js.map +1 -1
- package/dist/recording/schema.d.ts +3 -38
- package/dist/recording/schema.d.ts.map +1 -1
- package/dist/recording/schema.js +3 -38
- package/dist/recording/schema.js.map +1 -1
- package/dist/recording/writer.d.ts +11 -74
- package/dist/recording/writer.d.ts.map +1 -1
- package/dist/recording/writer.js +3 -43
- package/dist/recording/writer.js.map +1 -1
- package/dist/scoping/fanout.d.ts +6 -68
- package/dist/scoping/fanout.d.ts.map +1 -1
- package/dist/scoping/fanout.js +6 -68
- package/dist/scoping/fanout.js.map +1 -1
- package/dist/scoping/score.d.ts +20 -70
- package/dist/scoping/score.d.ts.map +1 -1
- package/dist/scoping/score.js +20 -70
- package/dist/scoping/score.js.map +1 -1
- package/dist/scoping/tiers.d.ts +4 -16
- package/dist/scoping/tiers.d.ts.map +1 -1
- package/dist/scoping/tiers.js +4 -16
- package/dist/scoping/tiers.js.map +1 -1
- package/dist/scoping/traverse.d.ts +3 -25
- package/dist/scoping/traverse.d.ts.map +1 -1
- package/dist/scoping/traverse.js +14 -49
- package/dist/scoping/traverse.js.map +1 -1
- package/dist/scoping/weights.d.ts +10 -74
- package/dist/scoping/weights.d.ts.map +1 -1
- package/dist/scoping/weights.js +14 -86
- package/dist/scoping/weights.js.map +1 -1
- package/dist/sources/confirmed/incidents.d.ts +5 -35
- package/dist/sources/confirmed/incidents.d.ts.map +1 -1
- package/dist/sources/confirmed/incidents.js +14 -48
- package/dist/sources/confirmed/incidents.js.map +1 -1
- package/dist/sources/git/diff.d.ts +71 -65
- package/dist/sources/git/diff.d.ts.map +1 -1
- package/dist/sources/git/diff.js +136 -83
- package/dist/sources/git/diff.js.map +1 -1
- package/dist/sources/git/env.d.ts +7 -0
- package/dist/sources/git/env.d.ts.map +1 -1
- package/dist/sources/git/env.js +10 -11
- package/dist/sources/git/env.js.map +1 -1
- package/dist/sources/git/history.d.ts +64 -84
- package/dist/sources/git/history.d.ts.map +1 -1
- package/dist/sources/git/history.js +141 -112
- package/dist/sources/git/history.js.map +1 -1
- package/dist/sources/git/incidents.d.ts +13 -75
- package/dist/sources/git/incidents.d.ts.map +1 -1
- package/dist/sources/git/incidents.js +21 -91
- package/dist/sources/git/incidents.js.map +1 -1
- package/dist/sources/git/index.d.ts +5 -3
- package/dist/sources/git/index.d.ts.map +1 -1
- package/dist/sources/git/index.js +3 -2
- package/dist/sources/git/index.js.map +1 -1
- package/dist/sources/git/source.d.ts +9 -79
- package/dist/sources/git/source.d.ts.map +1 -1
- package/dist/sources/git/source.js +0 -0
- package/dist/sources/git/source.js.map +1 -1
- package/dist/sources/migrations/across-change.d.ts +94 -0
- package/dist/sources/migrations/across-change.d.ts.map +1 -0
- package/dist/sources/migrations/across-change.js +278 -0
- package/dist/sources/migrations/across-change.js.map +1 -0
- package/dist/sources/migrations/dialects.d.ts +20 -36
- package/dist/sources/migrations/dialects.d.ts.map +1 -1
- package/dist/sources/migrations/dialects.js +11 -36
- package/dist/sources/migrations/dialects.js.map +1 -1
- package/dist/sources/migrations/index.d.ts +3 -1
- package/dist/sources/migrations/index.d.ts.map +1 -1
- package/dist/sources/migrations/index.js +2 -1
- package/dist/sources/migrations/index.js.map +1 -1
- package/dist/sources/migrations/read.d.ts +14 -79
- package/dist/sources/migrations/read.d.ts.map +1 -1
- package/dist/sources/migrations/read.js +14 -89
- package/dist/sources/migrations/read.js.map +1 -1
- package/dist/sources/workspace/workspace.d.ts +6 -42
- package/dist/sources/workspace/workspace.d.ts.map +1 -1
- package/dist/sources/workspace/workspace.js +10 -53
- package/dist/sources/workspace/workspace.js.map +1 -1
- package/dist/store/driver/driver.d.ts +9 -38
- package/dist/store/driver/driver.d.ts.map +1 -1
- package/dist/store/driver/driver.js +4 -22
- package/dist/store/driver/driver.js.map +1 -1
- package/dist/store/driver/node-sqlite.d.ts +3 -12
- package/dist/store/driver/node-sqlite.d.ts.map +1 -1
- package/dist/store/driver/node-sqlite.js +4 -18
- package/dist/store/driver/node-sqlite.js.map +1 -1
- package/dist/store/index.d.ts +2 -7
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +4 -10
- package/dist/store/index.js.map +1 -1
- package/dist/store/migrate.d.ts +14 -50
- package/dist/store/migrate.d.ts.map +1 -1
- package/dist/store/migrate.js +15 -52
- package/dist/store/migrate.js.map +1 -1
- package/dist/store/reader.d.ts +19 -84
- package/dist/store/reader.d.ts.map +1 -1
- package/dist/store/reader.js +25 -92
- package/dist/store/reader.js.map +1 -1
- package/dist/store/schema.d.ts +14 -76
- package/dist/store/schema.d.ts.map +1 -1
- package/dist/store/schema.js +14 -76
- package/dist/store/schema.js.map +1 -1
- package/dist/store/writer.d.ts +14 -88
- package/dist/store/writer.d.ts.map +1 -1
- package/dist/store/writer.js +29 -123
- package/dist/store/writer.js.map +1 -1
- package/dist/tiers/certify.d.ts +46 -281
- package/dist/tiers/certify.d.ts.map +1 -1
- package/dist/tiers/certify.js +46 -226
- package/dist/tiers/certify.js.map +1 -1
- package/dist/tiers/ladder.d.ts +7 -51
- package/dist/tiers/ladder.d.ts.map +1 -1
- package/dist/tiers/ladder.js +13 -89
- package/dist/tiers/ladder.js.map +1 -1
- package/dist/validation/attributes.d.ts +47 -0
- package/dist/validation/attributes.d.ts.map +1 -0
- package/dist/validation/attributes.js +130 -0
- package/dist/validation/attributes.js.map +1 -0
- package/dist/validation/config-graph.d.ts +7 -56
- package/dist/validation/config-graph.d.ts.map +1 -1
- package/dist/validation/config-graph.js +15 -61
- package/dist/validation/config-graph.js.map +1 -1
- package/dist/validation/env.d.ts +53 -2
- package/dist/validation/env.d.ts.map +1 -1
- package/dist/validation/env.js +99 -4
- package/dist/validation/env.js.map +1 -1
- package/dist/validation/index.d.ts +5 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +3 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/join-substitution.d.ts +22 -120
- package/dist/validation/join-substitution.d.ts.map +1 -1
- package/dist/validation/join-substitution.js +13 -90
- package/dist/validation/join-substitution.js.map +1 -1
- package/dist/validation/migration-integrity.d.ts +72 -0
- package/dist/validation/migration-integrity.d.ts.map +1 -0
- package/dist/validation/migration-integrity.js +238 -0
- package/dist/validation/migration-integrity.js.map +1 -0
- package/dist/validation/migrations.d.ts +23 -88
- package/dist/validation/migrations.d.ts.map +1 -1
- package/dist/validation/migrations.js +20 -79
- package/dist/validation/migrations.js.map +1 -1
- package/dist/validation/nodes.d.ts +3 -1
- package/dist/validation/nodes.d.ts.map +1 -1
- package/dist/validation/nodes.js +3 -1
- package/dist/validation/nodes.js.map +1 -1
- package/dist/validation/rollback.d.ts +10 -73
- package/dist/validation/rollback.d.ts.map +1 -1
- package/dist/validation/rollback.js +23 -81
- package/dist/validation/rollback.js.map +1 -1
- package/dist/validation/route-drift.d.ts +9 -62
- package/dist/validation/route-drift.d.ts.map +1 -1
- package/dist/validation/route-drift.js +7 -52
- package/dist/validation/route-drift.js.map +1 -1
- package/dist/validation/sources.d.ts +16 -94
- package/dist/validation/sources.d.ts.map +1 -1
- package/dist/validation/sources.js +51 -147
- package/dist/validation/sources.js.map +1 -1
- package/dist/worker/pool.d.ts +6 -45
- package/dist/worker/pool.d.ts.map +1 -1
- package/dist/worker/pool.js +5 -42
- package/dist/worker/pool.js.map +1 -1
- package/dist/worker/protocol.d.ts +7 -20
- package/dist/worker/protocol.d.ts.map +1 -1
- package/dist/worker/protocol.js +3 -10
- package/dist/worker/protocol.js.map +1 -1
- package/dist/worker/traversal.worker.d.ts +2 -21
- package/dist/worker/traversal.worker.d.ts.map +1 -1
- package/dist/worker/traversal.worker.js +4 -23
- package/dist/worker/traversal.worker.js.map +1 -1
- package/package.json +11 -2
|
@@ -1,110 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* it is separate and tested on its own.
|
|
6
|
-
*
|
|
7
|
-
* ## The problem it exists to solve
|
|
8
|
-
*
|
|
9
|
-
* A caller reaching an endpoint no route serves is *sometimes* a bug and
|
|
10
|
-
* *usually* not. Measured on two real repositories: 117 callers, 24 routes, 16
|
|
11
|
-
* joined. The other 101 are overwhelmingly calls to services that are simply not
|
|
12
|
-
* in this graph — a third-party API, a backend nobody has analysed. Reporting
|
|
13
|
-
* all 101 as "no route serves this" would be 101 confident wrong statements, and
|
|
14
|
-
* would bury the handful that are real.
|
|
15
|
-
*
|
|
16
|
-
* So an unmatched caller is only a **finding** when a served route exists that
|
|
17
|
-
* it nearly matches. Nothing similar on the provider side means the provider was
|
|
18
|
-
* probably never analysed, which belongs in §20.2's *not analysable* category
|
|
19
|
-
* and is disclosed as a count rather than enumerated as defects.
|
|
20
|
-
*
|
|
21
|
-
* ## The near-miss rules are deliberately narrow
|
|
22
|
-
*
|
|
23
|
-
* Each one describes a specific, common, *mechanical* mistake. None of them is a
|
|
24
|
-
* similarity score, because a threshold on a score is a knob that turns "is this
|
|
25
|
-
* a bug" into "how high did we set it".
|
|
26
|
-
*
|
|
27
|
-
* | rule | example | why it is a real mistake |
|
|
28
|
-
* | --- | --- | --- |
|
|
29
|
-
* | method differs, path identical | `POST /orders` vs `GET /orders` | someone changed the verb on one side |
|
|
30
|
-
* | exactly one **literal** segment differs, **and the two differ by a typo's worth of characters** | `/order/{param}/items` vs `/orders/{param}/items` | a typo or a rename applied on one side |
|
|
31
|
-
*
|
|
32
|
-
* ## Rule 2's similarity floor, and the measurement that set it
|
|
33
|
-
*
|
|
34
|
-
* That second clause was missing for the whole life of this file, and its
|
|
35
|
-
* absence was not a small thing. "Exactly one segment differs" says nothing at
|
|
36
|
-
* all about *how* it differs: `/api/hmac` and `/api/novu-agent` differ in
|
|
37
|
-
* exactly one segment, share a method and share arity. Precision came only
|
|
38
|
-
* incidentally, from `{param}` segments happening to sit where the paths
|
|
39
|
-
* diverge.
|
|
40
|
-
*
|
|
41
|
-
* `DEC-317` found this from the GraphQL side — every operation path is arity-2
|
|
42
|
-
* with no `{param}` and a first segment drawn from a set of size three, so the
|
|
43
|
-
* whole GraphQL surface of a repository collapsed into three buckets in which
|
|
44
|
-
* every member near-missed every other — and gated it rather than fixing it,
|
|
45
|
-
* because a threshold chosen carelessly costs the near-typo detections this
|
|
46
|
-
* rule exists for, and costs them invisibly.
|
|
47
|
-
*
|
|
48
|
-
* So it was measured, against 3,524 routes from 27 real repositories, by
|
|
49
|
-
* `bench/near-miss-similarity.mjs` — which pre-registers the metric, the
|
|
50
|
-
* candidate thresholds and the decision rule in its header, and was committed
|
|
51
|
-
* before it was run. What it found:
|
|
52
|
-
*
|
|
53
|
-
* - **The rule was not a precision rule.** Treating each real route as an
|
|
54
|
-
* unmatched caller against the rest of its own application's table, it
|
|
55
|
-
* reported a `ONE_SEGMENT` near miss for **1,796 of 3,524 routes — 51%.**
|
|
56
|
-
* Every one is a false positive by construction: both sides are real,
|
|
57
|
-
* deliberately distinct routes of the same service.
|
|
58
|
-
* - **On the genuinely reachable population it was worse.** Across every
|
|
59
|
-
* unmatched `USES_API` caller in the corpus, the rule emitted **18 findings,
|
|
60
|
-
* and all 18 were nonsense** — 15 of them naming the same `/api/novu-agent`
|
|
61
|
-
* route from callers like `/api/hmac` and `/api/send-email`. There were no
|
|
62
|
-
* true positives to lose.
|
|
63
|
-
*
|
|
64
|
-
* The floor is `1 - distance / max(len) >= 0.4`, with any distance of 1 or less
|
|
65
|
-
* admitted outright so that a one-character mistake in a short segment (`/v1`
|
|
66
|
-
* against `/v2`) is not scored away. It rejects **87.4%** of those 1,796 and
|
|
67
|
-
* retains **100%** of a seeded near-typo population of 49,405 — real route
|
|
68
|
-
* segments mutated by transposition, deletion, insertion, substitution,
|
|
69
|
-
* singular/plural and separator variance. Not one seeded typo is lost, in any
|
|
70
|
-
* class.
|
|
71
|
-
*
|
|
72
|
-
* **The distance counts an adjacent transposition as one edit, not two, and
|
|
73
|
-
* that is load-bearing.** With plain Levenshtein a swap costs two, so `api` →
|
|
74
|
-
* `aip` scores `1 - 2/3 = 0.33` and every candidate threshold silently deleted
|
|
75
|
-
* the entire transposition class — 2,916 real detections, all on segments of
|
|
76
|
-
* three characters. The first measurement pass rejected every threshold for
|
|
77
|
-
* exactly this reason, and the reason was a defect in the metric rather than a
|
|
78
|
-
* fact about the corpus.
|
|
79
|
-
*
|
|
80
|
-
* **What the floor is not.** It is a similarity test, not an oracle. `activate`
|
|
81
|
-
* and `deactivate` are two real routes in one API and score 0.80, so they are
|
|
82
|
-
* still reported. Nothing here can distinguish a two-character prefix from a
|
|
83
|
-
* typo, and this does not claim to — it buys precision against *unrelated*
|
|
84
|
-
* words, which is what the corpus says the problem was.
|
|
85
|
-
*
|
|
86
|
-
* **A trailing-slash rule was written and then deleted, and the reason is worth
|
|
87
|
-
* keeping.** `/orders/` and `/orders` look like the classic contract mismatch,
|
|
88
|
-
* but `normaliseEndpointPath` strips the trailing slash *before hashing*, so the
|
|
89
|
-
* two sides mint the **same `API_ENDPOINT` id** and join correctly. The rule
|
|
90
|
-
* could never fire. It was caught by a test that asserted it would.
|
|
91
|
-
*
|
|
92
|
-
* That unification is the right default — the two paths mean the same endpoint
|
|
93
|
-
* to everyone who writes them — but it does make one real class of bug
|
|
94
|
-
* invisible here: a framework configured for strict routing genuinely serves
|
|
95
|
-
* only one of them. Whether it does depends on router configuration this graph
|
|
96
|
-
* does not read, so the limit is stated rather than papered over with a rule
|
|
97
|
-
* that fires on nothing.
|
|
98
|
-
*
|
|
99
|
-
* **Deliberately not a rule: a parameter where the other side has a literal.**
|
|
100
|
-
* `/orders/{param}` and `/orders/recent` legitimately coexist in every routing
|
|
101
|
-
* framework on earth — the literal is matched first and the parameter catches
|
|
102
|
-
* the rest. Treating that as a near miss would report the single most common
|
|
103
|
-
* correct pattern in REST routing as a defect.
|
|
104
|
-
*
|
|
105
|
-
* Segment counts must be equal for the segment rule. `/orders` and
|
|
106
|
-
* `/orders/{param}` are two different endpoints, not a near miss, and a rule
|
|
107
|
-
* that ignored length would pair every collection route with its item route.
|
|
2
|
+
* A near-miss caller is a finding only when genuinely close to a served route (DEC-317: "one segment
|
|
3
|
+
* differs" alone was 51% false positives on 3,524 routes). Floor `1 - distance/max(len) >= 0.4` (transposition
|
|
4
|
+
* = 1 edit not 2) rejects 87.4% of those, keeps 100% of a 49,405-case seeded typo set. Not an oracle.
|
|
108
5
|
*/
|
|
109
6
|
export interface EndpointKey {
|
|
110
7
|
readonly method: string;
|
|
@@ -120,13 +17,6 @@ export interface NearMiss {
|
|
|
120
17
|
readonly detail: string;
|
|
121
18
|
}
|
|
122
19
|
export declare function sameEndpoint(a: EndpointKey, b: EndpointKey): boolean;
|
|
123
|
-
/**
|
|
124
|
-
* The closest served endpoint to `wanted`, or null if nothing is close enough.
|
|
125
|
-
*
|
|
126
|
-
* Rules are tried in order of how certain they are, and the first hit wins —
|
|
127
|
-
* a method mismatch on an otherwise identical path is a better explanation than
|
|
128
|
-
* a one-segment difference somewhere else, and reporting both would be reporting
|
|
129
|
-
* one mistake twice.
|
|
130
|
-
*/
|
|
20
|
+
/** Closest served endpoint to `wanted`, or null. Rules tried in order of certainty; first hit wins. */
|
|
131
21
|
export declare function nearestMiss(wanted: EndpointKey, served: readonly EndpointKey[]): NearMiss | null;
|
|
132
22
|
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/contracts/paths.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/contracts/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2CH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAWD,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAEpE;AAED,uGAAuG;AACvG,wBAAgB,WAAW,CACzB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC7B,QAAQ,GAAG,IAAI,CA0DjB"}
|
package/dist/contracts/paths.js
CHANGED
|
@@ -1,131 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* it is separate and tested on its own.
|
|
6
|
-
*
|
|
7
|
-
* ## The problem it exists to solve
|
|
8
|
-
*
|
|
9
|
-
* A caller reaching an endpoint no route serves is *sometimes* a bug and
|
|
10
|
-
* *usually* not. Measured on two real repositories: 117 callers, 24 routes, 16
|
|
11
|
-
* joined. The other 101 are overwhelmingly calls to services that are simply not
|
|
12
|
-
* in this graph — a third-party API, a backend nobody has analysed. Reporting
|
|
13
|
-
* all 101 as "no route serves this" would be 101 confident wrong statements, and
|
|
14
|
-
* would bury the handful that are real.
|
|
15
|
-
*
|
|
16
|
-
* So an unmatched caller is only a **finding** when a served route exists that
|
|
17
|
-
* it nearly matches. Nothing similar on the provider side means the provider was
|
|
18
|
-
* probably never analysed, which belongs in §20.2's *not analysable* category
|
|
19
|
-
* and is disclosed as a count rather than enumerated as defects.
|
|
20
|
-
*
|
|
21
|
-
* ## The near-miss rules are deliberately narrow
|
|
22
|
-
*
|
|
23
|
-
* Each one describes a specific, common, *mechanical* mistake. None of them is a
|
|
24
|
-
* similarity score, because a threshold on a score is a knob that turns "is this
|
|
25
|
-
* a bug" into "how high did we set it".
|
|
26
|
-
*
|
|
27
|
-
* | rule | example | why it is a real mistake |
|
|
28
|
-
* | --- | --- | --- |
|
|
29
|
-
* | method differs, path identical | `POST /orders` vs `GET /orders` | someone changed the verb on one side |
|
|
30
|
-
* | exactly one **literal** segment differs, **and the two differ by a typo's worth of characters** | `/order/{param}/items` vs `/orders/{param}/items` | a typo or a rename applied on one side |
|
|
31
|
-
*
|
|
32
|
-
* ## Rule 2's similarity floor, and the measurement that set it
|
|
33
|
-
*
|
|
34
|
-
* That second clause was missing for the whole life of this file, and its
|
|
35
|
-
* absence was not a small thing. "Exactly one segment differs" says nothing at
|
|
36
|
-
* all about *how* it differs: `/api/hmac` and `/api/novu-agent` differ in
|
|
37
|
-
* exactly one segment, share a method and share arity. Precision came only
|
|
38
|
-
* incidentally, from `{param}` segments happening to sit where the paths
|
|
39
|
-
* diverge.
|
|
40
|
-
*
|
|
41
|
-
* `DEC-317` found this from the GraphQL side — every operation path is arity-2
|
|
42
|
-
* with no `{param}` and a first segment drawn from a set of size three, so the
|
|
43
|
-
* whole GraphQL surface of a repository collapsed into three buckets in which
|
|
44
|
-
* every member near-missed every other — and gated it rather than fixing it,
|
|
45
|
-
* because a threshold chosen carelessly costs the near-typo detections this
|
|
46
|
-
* rule exists for, and costs them invisibly.
|
|
47
|
-
*
|
|
48
|
-
* So it was measured, against 3,524 routes from 27 real repositories, by
|
|
49
|
-
* `bench/near-miss-similarity.mjs` — which pre-registers the metric, the
|
|
50
|
-
* candidate thresholds and the decision rule in its header, and was committed
|
|
51
|
-
* before it was run. What it found:
|
|
52
|
-
*
|
|
53
|
-
* - **The rule was not a precision rule.** Treating each real route as an
|
|
54
|
-
* unmatched caller against the rest of its own application's table, it
|
|
55
|
-
* reported a `ONE_SEGMENT` near miss for **1,796 of 3,524 routes — 51%.**
|
|
56
|
-
* Every one is a false positive by construction: both sides are real,
|
|
57
|
-
* deliberately distinct routes of the same service.
|
|
58
|
-
* - **On the genuinely reachable population it was worse.** Across every
|
|
59
|
-
* unmatched `USES_API` caller in the corpus, the rule emitted **18 findings,
|
|
60
|
-
* and all 18 were nonsense** — 15 of them naming the same `/api/novu-agent`
|
|
61
|
-
* route from callers like `/api/hmac` and `/api/send-email`. There were no
|
|
62
|
-
* true positives to lose.
|
|
63
|
-
*
|
|
64
|
-
* The floor is `1 - distance / max(len) >= 0.4`, with any distance of 1 or less
|
|
65
|
-
* admitted outright so that a one-character mistake in a short segment (`/v1`
|
|
66
|
-
* against `/v2`) is not scored away. It rejects **87.4%** of those 1,796 and
|
|
67
|
-
* retains **100%** of a seeded near-typo population of 49,405 — real route
|
|
68
|
-
* segments mutated by transposition, deletion, insertion, substitution,
|
|
69
|
-
* singular/plural and separator variance. Not one seeded typo is lost, in any
|
|
70
|
-
* class.
|
|
71
|
-
*
|
|
72
|
-
* **The distance counts an adjacent transposition as one edit, not two, and
|
|
73
|
-
* that is load-bearing.** With plain Levenshtein a swap costs two, so `api` →
|
|
74
|
-
* `aip` scores `1 - 2/3 = 0.33` and every candidate threshold silently deleted
|
|
75
|
-
* the entire transposition class — 2,916 real detections, all on segments of
|
|
76
|
-
* three characters. The first measurement pass rejected every threshold for
|
|
77
|
-
* exactly this reason, and the reason was a defect in the metric rather than a
|
|
78
|
-
* fact about the corpus.
|
|
79
|
-
*
|
|
80
|
-
* **What the floor is not.** It is a similarity test, not an oracle. `activate`
|
|
81
|
-
* and `deactivate` are two real routes in one API and score 0.80, so they are
|
|
82
|
-
* still reported. Nothing here can distinguish a two-character prefix from a
|
|
83
|
-
* typo, and this does not claim to — it buys precision against *unrelated*
|
|
84
|
-
* words, which is what the corpus says the problem was.
|
|
85
|
-
*
|
|
86
|
-
* **A trailing-slash rule was written and then deleted, and the reason is worth
|
|
87
|
-
* keeping.** `/orders/` and `/orders` look like the classic contract mismatch,
|
|
88
|
-
* but `normaliseEndpointPath` strips the trailing slash *before hashing*, so the
|
|
89
|
-
* two sides mint the **same `API_ENDPOINT` id** and join correctly. The rule
|
|
90
|
-
* could never fire. It was caught by a test that asserted it would.
|
|
91
|
-
*
|
|
92
|
-
* That unification is the right default — the two paths mean the same endpoint
|
|
93
|
-
* to everyone who writes them — but it does make one real class of bug
|
|
94
|
-
* invisible here: a framework configured for strict routing genuinely serves
|
|
95
|
-
* only one of them. Whether it does depends on router configuration this graph
|
|
96
|
-
* does not read, so the limit is stated rather than papered over with a rule
|
|
97
|
-
* that fires on nothing.
|
|
98
|
-
*
|
|
99
|
-
* **Deliberately not a rule: a parameter where the other side has a literal.**
|
|
100
|
-
* `/orders/{param}` and `/orders/recent` legitimately coexist in every routing
|
|
101
|
-
* framework on earth — the literal is matched first and the parameter catches
|
|
102
|
-
* the rest. Treating that as a near miss would report the single most common
|
|
103
|
-
* correct pattern in REST routing as a defect.
|
|
104
|
-
*
|
|
105
|
-
* Segment counts must be equal for the segment rule. `/orders` and
|
|
106
|
-
* `/orders/{param}` are two different endpoints, not a near miss, and a rule
|
|
107
|
-
* that ignored length would pair every collection route with its item route.
|
|
2
|
+
* A near-miss caller is a finding only when genuinely close to a served route (DEC-317: "one segment
|
|
3
|
+
* differs" alone was 51% false positives on 3,524 routes). Floor `1 - distance/max(len) >= 0.4` (transposition
|
|
4
|
+
* = 1 edit not 2) rejects 87.4% of those, keeps 100% of a 49,405-case seeded typo set. Not an oracle.
|
|
108
5
|
*/
|
|
109
6
|
/** The normalised placeholder every adapter writes. See `normaliseEndpointPath`. */
|
|
110
7
|
const PARAM = "{param}";
|
|
111
|
-
/**
|
|
112
|
-
* How alike rule 2's two differing segments must be, as a fraction of the
|
|
113
|
-
* longer one's length. **Measured, not chosen** — see the module header, and
|
|
114
|
-
* `bench/near-miss-similarity.mjs` for the pre-registered decision rule that
|
|
115
|
-
* selected it: the lowest candidate that keeps 100% of a 49,405-case seeded
|
|
116
|
-
* near-typo population, which it does while rejecting 87.4% of the false
|
|
117
|
-
* positives the unguarded rule produced on 3,524 real routes.
|
|
118
|
-
*/
|
|
8
|
+
/** How alike rule 2's two differing segments must be. Measured, not chosen — see module header. */
|
|
119
9
|
const SEGMENT_SIMILARITY_FLOOR = 0.4;
|
|
120
|
-
/**
|
|
121
|
-
* Damerau-Levenshtein distance, optimal string alignment.
|
|
122
|
-
*
|
|
123
|
-
* **An adjacent transposition costs one edit, not two**, and that is the whole
|
|
124
|
-
* reason this is not the three-line Levenshtein. A swapped pair of characters
|
|
125
|
-
* is a single keystroke mistake and the single most common way a path is
|
|
126
|
-
* typo'd; charging it two edits puts `api`/`aip` at 0.33 and deletes the entire
|
|
127
|
-
* class from what rule 2 can report.
|
|
128
|
-
*/
|
|
10
|
+
/** Damerau-Levenshtein distance. Adjacent transposition costs 1 edit, not 2 — else `api`/`aip` scores 0.33. */
|
|
129
11
|
function editDistance(a, b) {
|
|
130
12
|
if (a === b)
|
|
131
13
|
return 0;
|
|
@@ -152,15 +34,7 @@ function editDistance(a, b) {
|
|
|
152
34
|
}
|
|
153
35
|
return rows[a.length][b.length];
|
|
154
36
|
}
|
|
155
|
-
/**
|
|
156
|
-
* Are these two segments close enough that one could be a mistyping of the
|
|
157
|
-
* other, rather than simply a different word?
|
|
158
|
-
*
|
|
159
|
-
* A distance of one is admitted whatever the lengths, because on a short
|
|
160
|
-
* segment a single edit is a large fraction of the string and normalising it
|
|
161
|
-
* away would reject `/v1` against `/v2` — the most mechanical mismatch there
|
|
162
|
-
* is.
|
|
163
|
-
*/
|
|
37
|
+
/** Close enough to be a mistyping, not just a different word? Distance-1 always admitted, so `/v1`/`/v2` isn't scored away. */
|
|
164
38
|
function nearlyTheSameWord(a, b) {
|
|
165
39
|
const distance = editDistance(a, b);
|
|
166
40
|
if (distance <= 1)
|
|
@@ -177,14 +51,7 @@ function trimmed(path) {
|
|
|
177
51
|
export function sameEndpoint(a, b) {
|
|
178
52
|
return a.method === b.method && a.pathTemplate === b.pathTemplate;
|
|
179
53
|
}
|
|
180
|
-
/**
|
|
181
|
-
* The closest served endpoint to `wanted`, or null if nothing is close enough.
|
|
182
|
-
*
|
|
183
|
-
* Rules are tried in order of how certain they are, and the first hit wins —
|
|
184
|
-
* a method mismatch on an otherwise identical path is a better explanation than
|
|
185
|
-
* a one-segment difference somewhere else, and reporting both would be reporting
|
|
186
|
-
* one mistake twice.
|
|
187
|
-
*/
|
|
54
|
+
/** Closest served endpoint to `wanted`, or null. Rules tried in order of certainty; first hit wins. */
|
|
188
55
|
export function nearestMiss(wanted, served) {
|
|
189
56
|
const wantedPath = trimmed(wanted.pathTemplate);
|
|
190
57
|
const wantedSegments = segments(wantedPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/contracts/paths.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/contracts/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,56 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Everything here is a pure function over `attrs`, and that is the design rather
|
|
5
|
-
* than an accident. §13.2's mechanism is **shape comparison, not identifier
|
|
6
|
-
* matching**, and a shape reaches this file as a list of fields with optional
|
|
7
|
-
* per-field detail. No type here names a language, and nothing branches on one:
|
|
8
|
-
* a Pydantic model, an OpenAPI schema and a TypeScript interface arrive
|
|
9
|
-
* identically or they do not arrive at all.
|
|
10
|
-
*
|
|
11
|
-
* ## Direction is not symmetric, and getting that wrong produces noise
|
|
12
|
-
*
|
|
13
|
-
* A consumer that ignores a field the provider sends is **fine** — that is how
|
|
14
|
-
* every API client on earth works. A consumer that reads a field the provider
|
|
15
|
-
* does not send is **broken**. So the comparison takes an *expected* side and a
|
|
16
|
-
* *provided* side, and a field present only in `provided` is not a finding.
|
|
17
|
-
*
|
|
18
|
-
* A symmetric diff would report every unused response field in every codebase,
|
|
19
|
-
* which is both enormous and wrong.
|
|
20
|
-
*
|
|
21
|
-
* ## Detail is compared only when both sides have it
|
|
22
|
-
*
|
|
23
|
-
* A shape read from `attrs.fields` is a list of names — R2-grade evidence, good
|
|
24
|
-
* enough to say *this field is missing* and nothing else. A shape read from
|
|
25
|
-
* `attrs.fieldDetail` carries type, nullability and requiredness, which is what
|
|
26
|
-
* a type checker buys.
|
|
27
|
-
*
|
|
28
|
-
* When either side lacks detail, `comparedDetail` comes back false and **no type
|
|
29
|
-
* or nullability differences are emitted**. That flag is load-bearing: an empty
|
|
30
|
-
* difference list is otherwise indistinguishable from "the types agree", and
|
|
31
|
-
* reporting "no type mismatches" after comparing two lists of names is exactly
|
|
32
|
-
* the overstatement principle 3 exists to stop.
|
|
33
|
-
*/
|
|
1
|
+
/** R3 half of §13: comparing two declared shapes, pure over `attrs`, no language named (IR
|
|
2
|
+
* boundary). Asymmetric by design — a field only in `provided` is fine; one only in `expected`
|
|
3
|
+
* is broken. `comparedDetail` false means "no detail to compare," never "types agree" (rule 3). */
|
|
34
4
|
import type { IRNode } from "@descryy/ir";
|
|
35
5
|
export interface ShapeField {
|
|
36
6
|
readonly name: string;
|
|
37
7
|
readonly type?: string | undefined;
|
|
38
8
|
readonly nullable?: boolean | undefined;
|
|
39
9
|
readonly required?: boolean | undefined;
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* **A separate flag rather than part of the type string, and that is rule 1.**
|
|
44
|
-
* The same field is written `Foo[]` by one producer, `List[Foo]` by another and
|
|
45
|
-
* `array` with an `items` schema by a third. Comparing those as strings is an
|
|
46
|
-
* engine above the IR deciding what a language's array syntax looks like, which
|
|
47
|
-
* is the leak the boundary exists to stop — and it fails in both directions at
|
|
48
|
-
* once: `Foo[]` vs `List[Foo]` reports a mismatch that is not there, while
|
|
49
|
-
* `Foo` vs `Foo` with one side an array reports nothing when the consumer is
|
|
50
|
-
* about to iterate an object.
|
|
51
|
-
*
|
|
52
|
-
* Producers put the **element** type in `type` and the cardinality here.
|
|
53
|
-
*/
|
|
10
|
+
/** True when the field holds MANY of `type` (rule 1: separate flag, not baked into the type
|
|
11
|
+
* string — `Foo[]` vs `List[Foo]` vs OpenAPI's `array`+items would otherwise need this engine
|
|
12
|
+
* to parse a language's array syntax). Producers put the element type in `type`, cardinality here. */
|
|
54
13
|
readonly list?: boolean | undefined;
|
|
55
14
|
}
|
|
56
15
|
export interface Shape {
|
|
@@ -60,13 +19,9 @@ export interface Shape {
|
|
|
60
19
|
/** True when per-field type/nullability/requiredness is present — R3-grade. */
|
|
61
20
|
readonly detailed: boolean;
|
|
62
21
|
}
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* Two forms, in order of richness. `fieldDetail` is what a producer emits when a
|
|
67
|
-
* type checker or a schema gave it per-field facts; `fields` is the name-level
|
|
68
|
-
* fallback. Anything else is not a shape and is not guessed at.
|
|
69
|
-
*/
|
|
22
|
+
/** Reads a shape from `attrs`, or null if none declared. Two forms: `fieldDetail` (per-field
|
|
23
|
+
* facts from a type checker/schema) is preferred, `fields` is the name-level fallback.
|
|
24
|
+
* Anything else is not a shape and is not guessed at. */
|
|
70
25
|
export declare function readShape(node: IRNode): Shape | null;
|
|
71
26
|
export type ShapeDifferenceKind = "FIELD_MISSING" | "TYPE_DIFFERS" | "NULLABILITY_DIFFERS" | "REQUIREDNESS_DIFFERS" | "LIST_DIFFERS";
|
|
72
27
|
export interface ShapeDifference {
|
|
@@ -80,20 +35,12 @@ export interface ShapeDifference {
|
|
|
80
35
|
}
|
|
81
36
|
export interface ShapeComparison {
|
|
82
37
|
readonly differences: readonly ShapeDifference[];
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* When false, an empty `differences` means "no field is missing", not "the
|
|
87
|
-
* types agree" — and every consumer of this result has to say so.
|
|
88
|
-
*/
|
|
38
|
+
/** True only when both sides carried per-field detail. False means an empty `differences`
|
|
39
|
+
* reads as "no field is missing," never "the types agree" — every consumer must say so. */
|
|
89
40
|
readonly comparedDetail: boolean;
|
|
90
41
|
readonly fieldsCompared: number;
|
|
91
42
|
}
|
|
92
|
-
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* @param expected the shape the consumer reads
|
|
96
|
-
* @param provided the shape the producer declares
|
|
97
|
-
*/
|
|
43
|
+
/** What the consumer expects that the provider doesn't deliver. `expected`: what the consumer
|
|
44
|
+
* reads. `provided`: what the producer declares. */
|
|
98
45
|
export declare function compareShapes(expected: Shape, provided: Shape): ShapeComparison;
|
|
99
46
|
//# sourceMappingURL=shapes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../../src/contracts/shapes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../../src/contracts/shapes.ts"],"names":[],"mappings":"AAAA;;oGAEoG;AAEpG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC;;2GAEuG;IACvG,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,KAAK;IACpB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;0DAE0D;AAC1D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAUpD;AAoCD,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,cAAc,GACd,qBAAqB,GACrB,sBAAsB,GACtB,cAAc,CAAC;AAEnB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD;gGAC4F;IAC5F,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;qDACqD;AACrD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,GAAG,eAAe,CAuF/E"}
|
package/dist/contracts/shapes.js
CHANGED
|
@@ -1,43 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* per-field detail. No type here names a language, and nothing branches on one:
|
|
8
|
-
* a Pydantic model, an OpenAPI schema and a TypeScript interface arrive
|
|
9
|
-
* identically or they do not arrive at all.
|
|
10
|
-
*
|
|
11
|
-
* ## Direction is not symmetric, and getting that wrong produces noise
|
|
12
|
-
*
|
|
13
|
-
* A consumer that ignores a field the provider sends is **fine** — that is how
|
|
14
|
-
* every API client on earth works. A consumer that reads a field the provider
|
|
15
|
-
* does not send is **broken**. So the comparison takes an *expected* side and a
|
|
16
|
-
* *provided* side, and a field present only in `provided` is not a finding.
|
|
17
|
-
*
|
|
18
|
-
* A symmetric diff would report every unused response field in every codebase,
|
|
19
|
-
* which is both enormous and wrong.
|
|
20
|
-
*
|
|
21
|
-
* ## Detail is compared only when both sides have it
|
|
22
|
-
*
|
|
23
|
-
* A shape read from `attrs.fields` is a list of names — R2-grade evidence, good
|
|
24
|
-
* enough to say *this field is missing* and nothing else. A shape read from
|
|
25
|
-
* `attrs.fieldDetail` carries type, nullability and requiredness, which is what
|
|
26
|
-
* a type checker buys.
|
|
27
|
-
*
|
|
28
|
-
* When either side lacks detail, `comparedDetail` comes back false and **no type
|
|
29
|
-
* or nullability differences are emitted**. That flag is load-bearing: an empty
|
|
30
|
-
* difference list is otherwise indistinguishable from "the types agree", and
|
|
31
|
-
* reporting "no type mismatches" after comparing two lists of names is exactly
|
|
32
|
-
* the overstatement principle 3 exists to stop.
|
|
33
|
-
*/
|
|
34
|
-
/**
|
|
35
|
-
* Read a shape out of a node's `attrs`, or return null if it declares none.
|
|
36
|
-
*
|
|
37
|
-
* Two forms, in order of richness. `fieldDetail` is what a producer emits when a
|
|
38
|
-
* type checker or a schema gave it per-field facts; `fields` is the name-level
|
|
39
|
-
* fallback. Anything else is not a shape and is not guessed at.
|
|
40
|
-
*/
|
|
1
|
+
/** R3 half of §13: comparing two declared shapes, pure over `attrs`, no language named (IR
|
|
2
|
+
* boundary). Asymmetric by design — a field only in `provided` is fine; one only in `expected`
|
|
3
|
+
* is broken. `comparedDetail` false means "no detail to compare," never "types agree" (rule 3). */
|
|
4
|
+
/** Reads a shape from `attrs`, or null if none declared. Two forms: `fieldDetail` (per-field
|
|
5
|
+
* facts from a type checker/schema) is preferred, `fields` is the name-level fallback.
|
|
6
|
+
* Anything else is not a shape and is not guessed at. */
|
|
41
7
|
export function readShape(node) {
|
|
42
8
|
const detail = readEntries(node.attrs["fieldDetail"]);
|
|
43
9
|
if (detail !== null && detail.fields.length > 0) {
|
|
@@ -49,29 +15,9 @@ export function readShape(node) {
|
|
|
49
15
|
}
|
|
50
16
|
return null;
|
|
51
17
|
}
|
|
52
|
-
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* **Measured, not anticipated.** Two shipped adapters both write
|
|
56
|
-
* `attrs.fields` and disagree on what it holds: the contract reader writes a
|
|
57
|
-
* list of **names** with per-field detail alongside in `fieldDetail`, and the
|
|
58
|
-
* TypeScript adapter writes a list of **objects** (`{ name, nullable }`) under
|
|
59
|
-
* the same key. On real repositories, **77 of 77** shape pointers resolved to a
|
|
60
|
-
* node that plainly declared its fields, and every one read as *no shape at
|
|
61
|
-
* all*, because the reader filtered for strings and found none.
|
|
62
|
-
*
|
|
63
|
-
* The silence is the part worth fixing: a reader that cannot read a node which
|
|
64
|
-
* visibly declares fields, and says nothing, answers "no" where it should
|
|
65
|
-
* answer "I could not tell".
|
|
66
|
-
*
|
|
67
|
-
* Reading both beats forcing one spelling on two adapters. `attrs` is where
|
|
68
|
-
* language-specific detail lives and nothing above the IR may demand a single
|
|
69
|
-
* form of it. Neither adapter changed.
|
|
70
|
-
*
|
|
71
|
-
* `detailed` is derived rather than declared: an entry carrying anything beyond
|
|
72
|
-
* a name is per-field evidence. A producer emitting `{ name, nullable }` gets
|
|
73
|
-
* nullability compared and nothing else — exactly what it supplied.
|
|
74
|
-
*/
|
|
18
|
+
/** Reads either spelling a producer uses for `attrs.fields` — measured: the contract reader
|
|
19
|
+
* writes names, the TS adapter writes objects under the same key, and before this read both,
|
|
20
|
+
* all 77/77 real shape pointers silently read as "no shape" instead of "could not tell". */
|
|
75
21
|
function readEntries(raw) {
|
|
76
22
|
if (!Array.isArray(raw))
|
|
77
23
|
return null;
|
|
@@ -101,12 +47,8 @@ function readEntries(raw) {
|
|
|
101
47
|
}
|
|
102
48
|
return { fields, detailed };
|
|
103
49
|
}
|
|
104
|
-
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* @param expected the shape the consumer reads
|
|
108
|
-
* @param provided the shape the producer declares
|
|
109
|
-
*/
|
|
50
|
+
/** What the consumer expects that the provider doesn't deliver. `expected`: what the consumer
|
|
51
|
+
* reads. `provided`: what the producer declares. */
|
|
110
52
|
export function compareShapes(expected, provided) {
|
|
111
53
|
const byName = new Map(provided.fields.map((f) => [f.name, f]));
|
|
112
54
|
const comparedDetail = expected.detailed && provided.detailed;
|
|
@@ -124,10 +66,8 @@ export function compareShapes(expected, provided) {
|
|
|
124
66
|
});
|
|
125
67
|
continue;
|
|
126
68
|
}
|
|
127
|
-
// Below here every claim is about a *shape
|
|
128
|
-
//
|
|
129
|
-
// undefined — `undefined !== "string"` would report a type mismatch on every
|
|
130
|
-
// field of every name-level shape.
|
|
69
|
+
// Below here every claim is about a *shape* — name resolution alone can't establish it.
|
|
70
|
+
// Skipped rather than compared against undefined, which would type-mismatch every name-level shape.
|
|
131
71
|
if (!comparedDetail)
|
|
132
72
|
continue;
|
|
133
73
|
if (want.type !== undefined && have.type !== undefined && want.type !== have.type) {
|
|
@@ -139,18 +79,9 @@ export function compareShapes(expected, provided) {
|
|
|
139
79
|
detail: `"${want.name}" is read as ${want.type} and declared as ${have.type}.`,
|
|
140
80
|
});
|
|
141
81
|
}
|
|
142
|
-
// Cardinality
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
// too. Neither direction is the safe one, so both are reported.
|
|
146
|
-
//
|
|
147
|
-
// Compared only when **both sides say**. An absent `list` is *unknown*, not
|
|
148
|
-
// `false`. A producer that never emits the flag would otherwise read as
|
|
149
|
-
// declaring every field singular, and every array field on the other side
|
|
150
|
-
// would come back as a finding — the 77-of-77 conflation running the other
|
|
151
|
-
// way. There the reader saw no shape and answered "no fields"; here it
|
|
152
|
-
// would see no flag and answer "not a list". Absence of evidence is allowed
|
|
153
|
-
// to stay absence of evidence.
|
|
82
|
+
// Cardinality is symmetric (unlike nullability) — a consumer iterating a single object, or
|
|
83
|
+
// reading fields off an array, both break, so both directions are reported. Compared only
|
|
84
|
+
// when both sides say: absent `list` is unknown, not false — same 77-of-77 absence-of-evidence rule.
|
|
154
85
|
if (want.list !== undefined && have.list !== undefined && want.list !== have.list) {
|
|
155
86
|
const asRead = want.list ? "a list" : "a single value";
|
|
156
87
|
const asDeclared = have.list ? "a list" : "a single value";
|
|
@@ -163,9 +94,8 @@ export function compareShapes(expected, provided) {
|
|
|
163
94
|
`${provided.source.name} as ${asDeclared}.`,
|
|
164
95
|
});
|
|
165
96
|
}
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
// — is safe and is not reported.
|
|
97
|
+
// Provider may return null, consumer doesn't expect it. The reverse (consumer tolerates
|
|
98
|
+
// null, provider never sends it) is safe and not reported.
|
|
169
99
|
if (want.nullable === false && have.nullable === true) {
|
|
170
100
|
differences.push({
|
|
171
101
|
kind: "NULLABILITY_DIFFERS",
|
|
@@ -176,9 +106,8 @@ export function compareShapes(expected, provided) {
|
|
|
176
106
|
`${expected.source.name} reads it as though it never is.`,
|
|
177
107
|
});
|
|
178
108
|
}
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
// *omitted*, not set to null — so they are checked apart.
|
|
109
|
+
// Consumer requires it, provider may omit it. `required` and `nullable` assert different
|
|
110
|
+
// things — absent-from-required means omitted, not null — so checked separately.
|
|
182
111
|
if (want.required === true && have.required === false) {
|
|
183
112
|
differences.push({
|
|
184
113
|
kind: "REQUIREDNESS_DIFFERS",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../src/contracts/shapes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../src/contracts/shapes.ts"],"names":[],"mappings":"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"}
|