@descryy/core 0.1.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/LICENSE +21 -0
- package/dist/capabilities/index.d.ts +3 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +2 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/preconditions.d.ts +99 -0
- package/dist/capabilities/preconditions.d.ts.map +1 -0
- package/dist/capabilities/preconditions.js +94 -0
- package/dist/capabilities/preconditions.js.map +1 -0
- package/dist/contracts/engine.d.ts +90 -0
- package/dist/contracts/engine.d.ts.map +1 -0
- package/dist/contracts/engine.js +291 -0
- package/dist/contracts/engine.js.map +1 -0
- package/dist/contracts/index.d.ts +9 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +5 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/orphans.d.ts +96 -0
- package/dist/contracts/orphans.d.ts.map +1 -0
- package/dist/contracts/orphans.js +241 -0
- package/dist/contracts/orphans.js.map +1 -0
- package/dist/contracts/paths.d.ts +132 -0
- package/dist/contracts/paths.d.ts.map +1 -0
- package/dist/contracts/paths.js +245 -0
- package/dist/contracts/paths.js.map +1 -0
- package/dist/contracts/shapes.d.ts +99 -0
- package/dist/contracts/shapes.d.ts.map +1 -0
- package/dist/contracts/shapes.js +196 -0
- package/dist/contracts/shapes.js.map +1 -0
- package/dist/governance/budget.d.ts +89 -0
- package/dist/governance/budget.d.ts.map +1 -0
- package/dist/governance/budget.js +101 -0
- package/dist/governance/budget.js.map +1 -0
- package/dist/governance/candidate-boundary.d.ts +49 -0
- package/dist/governance/candidate-boundary.d.ts.map +1 -0
- package/dist/governance/candidate-boundary.js +51 -0
- package/dist/governance/candidate-boundary.js.map +1 -0
- package/dist/governance/escalation.d.ts +63 -0
- package/dist/governance/escalation.d.ts.map +1 -0
- package/dist/governance/escalation.js +72 -0
- package/dist/governance/escalation.js.map +1 -0
- package/dist/governance/fact-boundary.d.ts +77 -0
- package/dist/governance/fact-boundary.d.ts.map +1 -0
- package/dist/governance/fact-boundary.js +91 -0
- package/dist/governance/fact-boundary.js.map +1 -0
- package/dist/governance/finding-funnel.d.ts +109 -0
- package/dist/governance/finding-funnel.d.ts.map +1 -0
- package/dist/governance/finding-funnel.js +137 -0
- package/dist/governance/finding-funnel.js.map +1 -0
- package/dist/governance/index.d.ts +11 -0
- package/dist/governance/index.d.ts.map +1 -0
- package/dist/governance/index.js +6 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/graph/build.d.ts +127 -0
- package/dist/graph/build.d.ts.map +1 -0
- package/dist/graph/build.js +0 -0
- package/dist/graph/build.js.map +1 -0
- package/dist/graph/cross-language.d.ts +70 -0
- package/dist/graph/cross-language.d.ts.map +1 -0
- package/dist/graph/cross-language.js +104 -0
- package/dist/graph/cross-language.js.map +1 -0
- package/dist/graph/index.d.ts +11 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +6 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/merge.d.ts +95 -0
- package/dist/graph/merge.d.ts.map +1 -0
- package/dist/graph/merge.js +131 -0
- package/dist/graph/merge.js.map +1 -0
- package/dist/graph/persist.d.ts +42 -0
- package/dist/graph/persist.d.ts.map +1 -0
- package/dist/graph/persist.js +52 -0
- package/dist/graph/persist.js.map +1 -0
- package/dist/graph/runtime-confirmation.d.ts +169 -0
- package/dist/graph/runtime-confirmation.d.ts.map +1 -0
- package/dist/graph/runtime-confirmation.js +318 -0
- package/dist/graph/runtime-confirmation.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/index.d.ts +5 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +3 -0
- package/dist/ledger/index.js.map +1 -0
- package/dist/ledger/mint.d.ts +81 -0
- package/dist/ledger/mint.d.ts.map +1 -0
- package/dist/ledger/mint.js +138 -0
- package/dist/ledger/mint.js.map +1 -0
- package/dist/ledger/resolve.d.ts +124 -0
- package/dist/ledger/resolve.d.ts.map +1 -0
- package/dist/ledger/resolve.js +290 -0
- package/dist/ledger/resolve.js.map +1 -0
- package/dist/multipr/fingerprint.d.ts +56 -0
- package/dist/multipr/fingerprint.d.ts.map +1 -0
- package/dist/multipr/fingerprint.js +169 -0
- package/dist/multipr/fingerprint.js.map +1 -0
- package/dist/multipr/hidden-dependency.d.ts +120 -0
- package/dist/multipr/hidden-dependency.d.ts.map +1 -0
- package/dist/multipr/hidden-dependency.js +185 -0
- package/dist/multipr/hidden-dependency.js.map +1 -0
- package/dist/multipr/index.d.ts +14 -0
- package/dist/multipr/index.d.ts.map +1 -0
- package/dist/multipr/index.js +8 -0
- package/dist/multipr/index.js.map +1 -0
- package/dist/multipr/mechanical.d.ts +239 -0
- package/dist/multipr/mechanical.d.ts.map +1 -0
- package/dist/multipr/mechanical.js +333 -0
- package/dist/multipr/mechanical.js.map +1 -0
- package/dist/multipr/migration-heads.d.ts +160 -0
- package/dist/multipr/migration-heads.d.ts.map +1 -0
- package/dist/multipr/migration-heads.js +212 -0
- package/dist/multipr/migration-heads.js.map +1 -0
- package/dist/multipr/overlap.d.ts +186 -0
- package/dist/multipr/overlap.d.ts.map +1 -0
- package/dist/multipr/overlap.js +254 -0
- package/dist/multipr/overlap.js.map +1 -0
- package/dist/multipr/scope-store.d.ts +105 -0
- package/dist/multipr/scope-store.d.ts.map +1 -0
- package/dist/multipr/scope-store.js +182 -0
- package/dist/multipr/scope-store.js.map +1 -0
- package/dist/multipr/superseded.d.ts +133 -0
- package/dist/multipr/superseded.d.ts.map +1 -0
- package/dist/multipr/superseded.js +128 -0
- package/dist/multipr/superseded.js.map +1 -0
- package/dist/query/confirmed-facts.d.ts +56 -0
- package/dist/query/confirmed-facts.d.ts.map +1 -0
- package/dist/query/confirmed-facts.js +64 -0
- package/dist/query/confirmed-facts.js.map +1 -0
- package/dist/query/declared-value-closure.d.ts +126 -0
- package/dist/query/declared-value-closure.d.ts.map +1 -0
- package/dist/query/declared-value-closure.js +156 -0
- package/dist/query/declared-value-closure.js.map +1 -0
- package/dist/query/index.d.ts +28 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +15 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/memory.d.ts +20 -0
- package/dist/query/memory.d.ts.map +1 -0
- package/dist/query/memory.js +55 -0
- package/dist/query/memory.js.map +1 -0
- package/dist/query/provider.d.ts +127 -0
- package/dist/query/provider.d.ts.map +1 -0
- package/dist/query/provider.js +54 -0
- package/dist/query/provider.js.map +1 -0
- package/dist/query/queries.d.ts +119 -0
- package/dist/query/queries.d.ts.map +1 -0
- package/dist/query/queries.js +267 -0
- package/dist/query/queries.js.map +1 -0
- package/dist/query/refusal-fetch.d.ts +114 -0
- package/dist/query/refusal-fetch.d.ts.map +1 -0
- package/dist/query/refusal-fetch.js +200 -0
- package/dist/query/refusal-fetch.js.map +1 -0
- package/dist/query/refusal-questions.d.ts +123 -0
- package/dist/query/refusal-questions.d.ts.map +1 -0
- package/dist/query/refusal-questions.js +122 -0
- package/dist/query/refusal-questions.js.map +1 -0
- package/dist/query/root-cause-score.d.ts +218 -0
- package/dist/query/root-cause-score.d.ts.map +1 -0
- package/dist/query/root-cause-score.js +251 -0
- package/dist/query/root-cause-score.js.map +1 -0
- package/dist/query/row-closure-picture.d.ts +108 -0
- package/dist/query/row-closure-picture.d.ts.map +1 -0
- package/dist/query/row-closure-picture.js +131 -0
- package/dist/query/row-closure-picture.js.map +1 -0
- package/dist/query/similar-incidents.d.ts +76 -0
- package/dist/query/similar-incidents.d.ts.map +1 -0
- package/dist/query/similar-incidents.js +169 -0
- package/dist/query/similar-incidents.js.map +1 -0
- package/dist/query/sqlite.d.ts +13 -0
- package/dist/query/sqlite.d.ts.map +1 -0
- package/dist/query/sqlite.js +54 -0
- package/dist/query/sqlite.js.map +1 -0
- package/dist/query/traverse.d.ts +110 -0
- package/dist/query/traverse.d.ts.map +1 -0
- package/dist/query/traverse.js +0 -0
- package/dist/query/traverse.js.map +1 -0
- package/dist/query/unresolved.d.ts +195 -0
- package/dist/query/unresolved.d.ts.map +1 -0
- package/dist/query/unresolved.js +225 -0
- package/dist/query/unresolved.js.map +1 -0
- package/dist/query/verification-status.d.ts +134 -0
- package/dist/query/verification-status.d.ts.map +1 -0
- package/dist/query/verification-status.js +163 -0
- package/dist/query/verification-status.js.map +1 -0
- package/dist/recording/index.d.ts +26 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +30 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/migrate.d.ts +22 -0
- package/dist/recording/migrate.d.ts.map +1 -0
- package/dist/recording/migrate.js +51 -0
- package/dist/recording/migrate.js.map +1 -0
- package/dist/recording/reader.d.ts +27 -0
- package/dist/recording/reader.d.ts.map +1 -0
- package/dist/recording/reader.js +55 -0
- package/dist/recording/reader.js.map +1 -0
- package/dist/recording/redact.d.ts +63 -0
- package/dist/recording/redact.d.ts.map +1 -0
- package/dist/recording/redact.js +98 -0
- package/dist/recording/redact.js.map +1 -0
- package/dist/recording/schema.d.ts +41 -0
- package/dist/recording/schema.d.ts.map +1 -0
- package/dist/recording/schema.js +104 -0
- package/dist/recording/schema.js.map +1 -0
- package/dist/recording/writer.d.ts +120 -0
- package/dist/recording/writer.d.ts.map +1 -0
- package/dist/recording/writer.js +81 -0
- package/dist/recording/writer.js.map +1 -0
- package/dist/scoping/fanout.d.ts +86 -0
- package/dist/scoping/fanout.d.ts.map +1 -0
- package/dist/scoping/fanout.js +95 -0
- package/dist/scoping/fanout.js.map +1 -0
- package/dist/scoping/index.d.ts +10 -0
- package/dist/scoping/index.d.ts.map +1 -0
- package/dist/scoping/index.js +6 -0
- package/dist/scoping/index.js.map +1 -0
- package/dist/scoping/score.d.ts +83 -0
- package/dist/scoping/score.d.ts.map +1 -0
- package/dist/scoping/score.js +125 -0
- package/dist/scoping/score.js.map +1 -0
- package/dist/scoping/tiers.d.ts +32 -0
- package/dist/scoping/tiers.d.ts.map +1 -0
- package/dist/scoping/tiers.js +35 -0
- package/dist/scoping/tiers.js.map +1 -0
- package/dist/scoping/traverse.d.ts +60 -0
- package/dist/scoping/traverse.d.ts.map +1 -0
- package/dist/scoping/traverse.js +172 -0
- package/dist/scoping/traverse.js.map +1 -0
- package/dist/scoping/weights.d.ts +97 -0
- package/dist/scoping/weights.d.ts.map +1 -0
- package/dist/scoping/weights.js +167 -0
- package/dist/scoping/weights.js.map +1 -0
- package/dist/sources/git/diff.d.ts +53 -0
- package/dist/sources/git/diff.d.ts.map +1 -0
- package/dist/sources/git/diff.js +140 -0
- package/dist/sources/git/diff.js.map +1 -0
- package/dist/sources/git/env.d.ts +2 -0
- package/dist/sources/git/env.d.ts.map +1 -0
- package/dist/sources/git/env.js +21 -0
- package/dist/sources/git/env.js.map +1 -0
- package/dist/sources/git/history.d.ts +140 -0
- package/dist/sources/git/history.d.ts.map +1 -0
- package/dist/sources/git/history.js +314 -0
- package/dist/sources/git/history.js.map +1 -0
- package/dist/sources/git/index.d.ts +7 -0
- package/dist/sources/git/index.d.ts.map +1 -0
- package/dist/sources/git/index.js +4 -0
- package/dist/sources/git/index.js.map +1 -0
- package/dist/sources/git/source.d.ts +95 -0
- package/dist/sources/git/source.d.ts.map +1 -0
- package/dist/sources/git/source.js +0 -0
- package/dist/sources/git/source.js.map +1 -0
- package/dist/sources/migrations/dialects.d.ts +59 -0
- package/dist/sources/migrations/dialects.d.ts.map +1 -0
- package/dist/sources/migrations/dialects.js +84 -0
- package/dist/sources/migrations/dialects.js.map +1 -0
- package/dist/sources/migrations/index.d.ts +3 -0
- package/dist/sources/migrations/index.d.ts.map +1 -0
- package/dist/sources/migrations/index.js +2 -0
- package/dist/sources/migrations/index.js.map +1 -0
- package/dist/sources/migrations/read.d.ts +113 -0
- package/dist/sources/migrations/read.d.ts.map +1 -0
- package/dist/sources/migrations/read.js +270 -0
- package/dist/sources/migrations/read.js.map +1 -0
- package/dist/sources/workspace/index.d.ts +3 -0
- package/dist/sources/workspace/index.d.ts.map +1 -0
- package/dist/sources/workspace/index.js +2 -0
- package/dist/sources/workspace/index.js.map +1 -0
- package/dist/sources/workspace/workspace.d.ts +64 -0
- package/dist/sources/workspace/workspace.d.ts.map +1 -0
- package/dist/sources/workspace/workspace.js +294 -0
- package/dist/sources/workspace/workspace.js.map +1 -0
- package/dist/store/driver/driver.d.ts +82 -0
- package/dist/store/driver/driver.d.ts.map +1 -0
- package/dist/store/driver/driver.js +31 -0
- package/dist/store/driver/driver.js.map +1 -0
- package/dist/store/driver/node-sqlite.d.ts +28 -0
- package/dist/store/driver/node-sqlite.d.ts.map +1 -0
- package/dist/store/driver/node-sqlite.js +188 -0
- package/dist/store/driver/node-sqlite.js.map +1 -0
- package/dist/store/index.d.ts +33 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +46 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/migrate.d.ts +68 -0
- package/dist/store/migrate.d.ts.map +1 -0
- package/dist/store/migrate.js +140 -0
- package/dist/store/migrate.js.map +1 -0
- package/dist/store/reader.d.ts +127 -0
- package/dist/store/reader.d.ts.map +1 -0
- package/dist/store/reader.js +269 -0
- package/dist/store/reader.js.map +1 -0
- package/dist/store/schema.d.ts +87 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +322 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store/writer.d.ts +116 -0
- package/dist/store/writer.d.ts.map +1 -0
- package/dist/store/writer.js +279 -0
- package/dist/store/writer.js.map +1 -0
- package/dist/tiers/certify.d.ts +375 -0
- package/dist/tiers/certify.d.ts.map +1 -0
- package/dist/tiers/certify.js +434 -0
- package/dist/tiers/certify.js.map +1 -0
- package/dist/tiers/index.d.ts +5 -0
- package/dist/tiers/index.d.ts.map +1 -0
- package/dist/tiers/index.js +3 -0
- package/dist/tiers/index.js.map +1 -0
- package/dist/tiers/ladder.d.ts +73 -0
- package/dist/tiers/ladder.d.ts.map +1 -0
- package/dist/tiers/ladder.js +197 -0
- package/dist/tiers/ladder.js.map +1 -0
- package/dist/validation/config-graph.d.ts +104 -0
- package/dist/validation/config-graph.d.ts.map +1 -0
- package/dist/validation/config-graph.js +205 -0
- package/dist/validation/config-graph.js.map +1 -0
- package/dist/validation/env.d.ts +243 -0
- package/dist/validation/env.d.ts.map +1 -0
- package/dist/validation/env.js +447 -0
- package/dist/validation/env.js.map +1 -0
- package/dist/validation/index.d.ts +16 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +9 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/join-substitution.d.ts +186 -0
- package/dist/validation/join-substitution.d.ts.map +1 -0
- package/dist/validation/join-substitution.js +191 -0
- package/dist/validation/join-substitution.js.map +1 -0
- package/dist/validation/migrations.d.ts +133 -0
- package/dist/validation/migrations.d.ts.map +1 -0
- package/dist/validation/migrations.js +315 -0
- package/dist/validation/migrations.js.map +1 -0
- package/dist/validation/nodes.d.ts +32 -0
- package/dist/validation/nodes.d.ts.map +1 -0
- package/dist/validation/nodes.js +45 -0
- package/dist/validation/nodes.js.map +1 -0
- package/dist/validation/rollback.d.ts +124 -0
- package/dist/validation/rollback.d.ts.map +1 -0
- package/dist/validation/rollback.js +302 -0
- package/dist/validation/rollback.js.map +1 -0
- package/dist/validation/route-drift.d.ts +108 -0
- package/dist/validation/route-drift.d.ts.map +1 -0
- package/dist/validation/route-drift.js +103 -0
- package/dist/validation/route-drift.js.map +1 -0
- package/dist/validation/sources.d.ts +153 -0
- package/dist/validation/sources.d.ts.map +1 -0
- package/dist/validation/sources.js +409 -0
- package/dist/validation/sources.js.map +1 -0
- package/dist/worker/index.d.ts +5 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +3 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/pool.d.ts +73 -0
- package/dist/worker/pool.d.ts.map +1 -0
- package/dist/worker/pool.js +203 -0
- package/dist/worker/pool.js.map +1 -0
- package/dist/worker/protocol.d.ts +91 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +19 -0
- package/dist/worker/protocol.js.map +1 -0
- package/dist/worker/traversal.worker.d.ts +25 -0
- package/dist/worker/traversal.worker.d.ts.map +1 -0
- package/dist/worker/traversal.worker.js +124 -0
- package/dist/worker/traversal.worker.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlap.js","sourceRoot":"","sources":["../../src/multipr/overlap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §14.2 — persisting a change's scoped subgraph, and the one field that makes
|
|
3
|
+
* two of them comparable.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this is stored at all, when everything else derived is thrown away
|
|
6
|
+
*
|
|
7
|
+
* A scope looks derived. It is not, and the reason is easy to get backwards:
|
|
8
|
+
* everything on the derived side regenerates because *the source still produces
|
|
9
|
+
* it*. A PR scope was computed against a graph **at one commit**, and that graph
|
|
10
|
+
* moves. Recomputing it later does not restore it — it answers a different
|
|
11
|
+
* question and returns a plausible answer to it. Dropping it does not lose time,
|
|
12
|
+
* it loses the comparison basis.
|
|
13
|
+
*
|
|
14
|
+
* That is why `pr_scopes` sits in `EARNED_TABLES` beside observed edges and
|
|
15
|
+
* human corrections, and it is the weaker-looking member of that set in one
|
|
16
|
+
* respect and the more dangerous in another: an R4 observation cannot be
|
|
17
|
+
* recomputed at any price, whereas a PR scope can be recomputed **wrongly**.
|
|
18
|
+
*
|
|
19
|
+
* ## `graphCommitSha` is the whole design
|
|
20
|
+
*
|
|
21
|
+
* Two scopes are comparable only when they were computed against the same
|
|
22
|
+
* graph. The schema puts that commit in the primary key so the same PR at two
|
|
23
|
+
* graph states is two rows rather than one silently overwriting the other, and
|
|
24
|
+
* indexes `(repo, graph_commit_sha)` because overlap scoring's only real query
|
|
25
|
+
* is *every scope computed against one graph*.
|
|
26
|
+
*
|
|
27
|
+
* **It is a different commit from the PR's own head**, and this module renamed a
|
|
28
|
+
* field to say so. `overlap.ts` originally carried one `baseSha` described as
|
|
29
|
+
* "the base commit it was computed against", which is ambiguous between the two
|
|
30
|
+
* and would have let a comparison key on the wrong one. The store's column
|
|
31
|
+
* comment is what caught it.
|
|
32
|
+
*
|
|
33
|
+
* ## An incomparable pair and a non-conflicting pair look identical
|
|
34
|
+
*
|
|
35
|
+
* Both produce an empty overlap. The schema comment warns that a reader
|
|
36
|
+
* ignoring `graph_commit_sha` "will happily overlap a scope from last week with
|
|
37
|
+
* one from today and report a number" — so the refusal lives in `findOverlaps`
|
|
38
|
+
* rather than here, where it also protects the caller who never touches a store.
|
|
39
|
+
*/
|
|
40
|
+
import type { SqlDriver } from "../store/driver/driver.ts";
|
|
41
|
+
import type { PrScope } from "./overlap.ts";
|
|
42
|
+
/**
|
|
43
|
+
* Thrown when a stored scope cannot be turned back into one.
|
|
44
|
+
*
|
|
45
|
+
* A corrupt row is not an empty scope. Returning `[]` here would make a damaged
|
|
46
|
+
* store indistinguishable from a PR that touched nothing, which is the
|
|
47
|
+
* conflation §14.8 exists to refuse one layer up.
|
|
48
|
+
*/
|
|
49
|
+
export declare class ScopeDecodeError extends Error {
|
|
50
|
+
readonly name = "ScopeDecodeError";
|
|
51
|
+
constructor(message: string, options?: {
|
|
52
|
+
cause?: unknown;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Row access for `pr_scopes`. Thin on purpose, in the style of `reader.ts`:
|
|
57
|
+
* nothing here scores, compares or decides staleness.
|
|
58
|
+
*/
|
|
59
|
+
export declare class ScopeStore {
|
|
60
|
+
#private;
|
|
61
|
+
constructor(driver: SqlDriver);
|
|
62
|
+
/**
|
|
63
|
+
* Write a scope, replacing any row for the same `(repo, prId, graphCommitSha)`.
|
|
64
|
+
*
|
|
65
|
+
* Replacement is safe **only** because the graph commit is in the key:
|
|
66
|
+
* recomputing the same PR against the same graph must produce the same scope,
|
|
67
|
+
* so the row being replaced is equal to the one replacing it. Recomputing
|
|
68
|
+
* against a *different* graph writes a new row and leaves the old comparison
|
|
69
|
+
* basis intact, which is the entire reason the column is in the key.
|
|
70
|
+
*/
|
|
71
|
+
save(scope: PrScope): void;
|
|
72
|
+
saveAll(scopes: readonly PrScope[]): void;
|
|
73
|
+
/** One scope, or `undefined` when no row exists for that exact graph state. */
|
|
74
|
+
load(repo: string, prId: string, graphCommitSha: string): PrScope | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* **The query overlap scoring is for**: every scope computed against one
|
|
77
|
+
* graph, and therefore every scope that can legitimately be compared.
|
|
78
|
+
*
|
|
79
|
+
* Ordered by `pr_id` so a report is stable across runs — an unordered read
|
|
80
|
+
* makes two identical graphs produce two differently-ordered reports and
|
|
81
|
+
* turns a diff into noise.
|
|
82
|
+
*/
|
|
83
|
+
loadForGraph(repo: string, graphCommitSha: string): PrScope[];
|
|
84
|
+
/**
|
|
85
|
+
* Every graph state a PR has a scope for, newest computation first.
|
|
86
|
+
*
|
|
87
|
+
* Exposed because "this PR was scoped against three different graphs" is a
|
|
88
|
+
* fact a caller may need and cannot reconstruct from `load`, which requires
|
|
89
|
+
* knowing the commit in advance.
|
|
90
|
+
*/
|
|
91
|
+
graphStatesFor(repo: string, prId: string): {
|
|
92
|
+
graphCommitSha: string;
|
|
93
|
+
computedAt: number;
|
|
94
|
+
}[];
|
|
95
|
+
/**
|
|
96
|
+
* Forget a PR entirely — every graph state it was scoped against.
|
|
97
|
+
*
|
|
98
|
+
* The only legitimate deletion: a closed or merged PR is not in flight and
|
|
99
|
+
* cannot conflict with anything. Deleting a *single* graph state is not
|
|
100
|
+
* offered, because the row is the comparison basis and there is no caller who
|
|
101
|
+
* wants exactly one of them gone.
|
|
102
|
+
*/
|
|
103
|
+
forget(repo: string, prId: string): number;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=scope-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-store.d.ts","sourceRoot":"","sources":["../../src/multipr/scope-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AAc1D;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;gBAEhC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAG3D;AAiDD;;;GAGG;AACH,qBAAa,UAAU;;gBAGT,MAAM,EAAE,SAAS;IAI7B;;;;;;;;OAQG;IACH,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAsB1B,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI;IAMzC,+EAA+E;IAC/E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAS7E;;;;;;;OAOG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,EAAE;IAS7D;;;;;;OAMG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE;IAU5F;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;CAK3C"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §14.2 — persisting a change's scoped subgraph, and the one field that makes
|
|
3
|
+
* two of them comparable.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this is stored at all, when everything else derived is thrown away
|
|
6
|
+
*
|
|
7
|
+
* A scope looks derived. It is not, and the reason is easy to get backwards:
|
|
8
|
+
* everything on the derived side regenerates because *the source still produces
|
|
9
|
+
* it*. A PR scope was computed against a graph **at one commit**, and that graph
|
|
10
|
+
* moves. Recomputing it later does not restore it — it answers a different
|
|
11
|
+
* question and returns a plausible answer to it. Dropping it does not lose time,
|
|
12
|
+
* it loses the comparison basis.
|
|
13
|
+
*
|
|
14
|
+
* That is why `pr_scopes` sits in `EARNED_TABLES` beside observed edges and
|
|
15
|
+
* human corrections, and it is the weaker-looking member of that set in one
|
|
16
|
+
* respect and the more dangerous in another: an R4 observation cannot be
|
|
17
|
+
* recomputed at any price, whereas a PR scope can be recomputed **wrongly**.
|
|
18
|
+
*
|
|
19
|
+
* ## `graphCommitSha` is the whole design
|
|
20
|
+
*
|
|
21
|
+
* Two scopes are comparable only when they were computed against the same
|
|
22
|
+
* graph. The schema puts that commit in the primary key so the same PR at two
|
|
23
|
+
* graph states is two rows rather than one silently overwriting the other, and
|
|
24
|
+
* indexes `(repo, graph_commit_sha)` because overlap scoring's only real query
|
|
25
|
+
* is *every scope computed against one graph*.
|
|
26
|
+
*
|
|
27
|
+
* **It is a different commit from the PR's own head**, and this module renamed a
|
|
28
|
+
* field to say so. `overlap.ts` originally carried one `baseSha` described as
|
|
29
|
+
* "the base commit it was computed against", which is ambiguous between the two
|
|
30
|
+
* and would have let a comparison key on the wrong one. The store's column
|
|
31
|
+
* comment is what caught it.
|
|
32
|
+
*
|
|
33
|
+
* ## An incomparable pair and a non-conflicting pair look identical
|
|
34
|
+
*
|
|
35
|
+
* Both produce an empty overlap. The schema comment warns that a reader
|
|
36
|
+
* ignoring `graph_commit_sha` "will happily overlap a scope from last week with
|
|
37
|
+
* one from today and report a number" — so the refusal lives in `findOverlaps`
|
|
38
|
+
* rather than here, where it also protects the caller who never touches a store.
|
|
39
|
+
*/
|
|
40
|
+
import { canonicalJson } from "@descryy/ir";
|
|
41
|
+
const COLUMNS = "pr_id, repo, head_sha, graph_commit_sha, scope_json, node_count, computed_at";
|
|
42
|
+
/**
|
|
43
|
+
* Thrown when a stored scope cannot be turned back into one.
|
|
44
|
+
*
|
|
45
|
+
* A corrupt row is not an empty scope. Returning `[]` here would make a damaged
|
|
46
|
+
* store indistinguishable from a PR that touched nothing, which is the
|
|
47
|
+
* conflation §14.8 exists to refuse one layer up.
|
|
48
|
+
*/
|
|
49
|
+
export class ScopeDecodeError extends Error {
|
|
50
|
+
name = "ScopeDecodeError";
|
|
51
|
+
constructor(message, options) {
|
|
52
|
+
super(message, options);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* `canonicalJson` throws on `undefined` rather than dropping the key, which is
|
|
57
|
+
* the right call everywhere else in this project and means an optional field
|
|
58
|
+
* cannot simply be handed to it. `file` is the only one, and it is genuinely
|
|
59
|
+
* absent rather than null — a scope entry for a node the graph has no path for
|
|
60
|
+
* is not a scope entry with a null path.
|
|
61
|
+
*/
|
|
62
|
+
function encodeEntry(entry) {
|
|
63
|
+
const encoded = {
|
|
64
|
+
nodeId: entry.nodeId,
|
|
65
|
+
nodeType: entry.nodeType,
|
|
66
|
+
impactScore: entry.impactScore,
|
|
67
|
+
tier: entry.tier,
|
|
68
|
+
diffType: entry.diffType,
|
|
69
|
+
resolution: entry.resolution,
|
|
70
|
+
};
|
|
71
|
+
if (entry.file !== undefined)
|
|
72
|
+
encoded["file"] = entry.file;
|
|
73
|
+
return encoded;
|
|
74
|
+
}
|
|
75
|
+
function decode(row) {
|
|
76
|
+
let entries;
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(row.scope_json);
|
|
79
|
+
if (!Array.isArray(parsed)) {
|
|
80
|
+
throw new Error(`scope_json is ${typeof parsed}, expected an array of entries`);
|
|
81
|
+
}
|
|
82
|
+
entries = parsed;
|
|
83
|
+
}
|
|
84
|
+
catch (cause) {
|
|
85
|
+
throw new ScopeDecodeError(`Scope for PR ${row.pr_id} in ${row.repo} at graph ${row.graph_commit_sha} could not be ` +
|
|
86
|
+
"decoded. It is not an empty scope — a damaged row and a change that touched nothing " +
|
|
87
|
+
"are different answers.", { cause });
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
prId: row.pr_id,
|
|
91
|
+
repo: row.repo,
|
|
92
|
+
headSha: row.head_sha,
|
|
93
|
+
graphCommitSha: row.graph_commit_sha,
|
|
94
|
+
entries,
|
|
95
|
+
computedAt: row.computed_at,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Row access for `pr_scopes`. Thin on purpose, in the style of `reader.ts`:
|
|
100
|
+
* nothing here scores, compares or decides staleness.
|
|
101
|
+
*/
|
|
102
|
+
export class ScopeStore {
|
|
103
|
+
#driver;
|
|
104
|
+
constructor(driver) {
|
|
105
|
+
this.#driver = driver;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Write a scope, replacing any row for the same `(repo, prId, graphCommitSha)`.
|
|
109
|
+
*
|
|
110
|
+
* Replacement is safe **only** because the graph commit is in the key:
|
|
111
|
+
* recomputing the same PR against the same graph must produce the same scope,
|
|
112
|
+
* so the row being replaced is equal to the one replacing it. Recomputing
|
|
113
|
+
* against a *different* graph writes a new row and leaves the old comparison
|
|
114
|
+
* basis intact, which is the entire reason the column is in the key.
|
|
115
|
+
*/
|
|
116
|
+
save(scope) {
|
|
117
|
+
const json = canonicalJson(scope.entries.map(encodeEntry));
|
|
118
|
+
this.#driver
|
|
119
|
+
.prepare(`INSERT INTO pr_scopes (${COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
120
|
+
ON CONFLICT(repo, pr_id, graph_commit_sha) DO UPDATE SET
|
|
121
|
+
head_sha = excluded.head_sha,
|
|
122
|
+
scope_json = excluded.scope_json,
|
|
123
|
+
node_count = excluded.node_count,
|
|
124
|
+
computed_at = excluded.computed_at`)
|
|
125
|
+
.run(scope.prId, scope.repo, scope.headSha, scope.graphCommitSha, json, scope.entries.length, scope.computedAt);
|
|
126
|
+
}
|
|
127
|
+
saveAll(scopes) {
|
|
128
|
+
this.#driver.transaction(() => {
|
|
129
|
+
for (const scope of scopes)
|
|
130
|
+
this.save(scope);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** One scope, or `undefined` when no row exists for that exact graph state. */
|
|
134
|
+
load(repo, prId, graphCommitSha) {
|
|
135
|
+
const row = this.#driver
|
|
136
|
+
.prepare(`SELECT ${COLUMNS} FROM pr_scopes WHERE repo = ? AND pr_id = ? AND graph_commit_sha = ?`)
|
|
137
|
+
.get(repo, prId, graphCommitSha);
|
|
138
|
+
return row === undefined ? undefined : decode(row);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* **The query overlap scoring is for**: every scope computed against one
|
|
142
|
+
* graph, and therefore every scope that can legitimately be compared.
|
|
143
|
+
*
|
|
144
|
+
* Ordered by `pr_id` so a report is stable across runs — an unordered read
|
|
145
|
+
* makes two identical graphs produce two differently-ordered reports and
|
|
146
|
+
* turns a diff into noise.
|
|
147
|
+
*/
|
|
148
|
+
loadForGraph(repo, graphCommitSha) {
|
|
149
|
+
return this.#driver
|
|
150
|
+
.prepare(`SELECT ${COLUMNS} FROM pr_scopes WHERE repo = ? AND graph_commit_sha = ? ORDER BY pr_id`)
|
|
151
|
+
.all(repo, graphCommitSha)
|
|
152
|
+
.map(decode);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Every graph state a PR has a scope for, newest computation first.
|
|
156
|
+
*
|
|
157
|
+
* Exposed because "this PR was scoped against three different graphs" is a
|
|
158
|
+
* fact a caller may need and cannot reconstruct from `load`, which requires
|
|
159
|
+
* knowing the commit in advance.
|
|
160
|
+
*/
|
|
161
|
+
graphStatesFor(repo, prId) {
|
|
162
|
+
return this.#driver
|
|
163
|
+
.prepare(`SELECT graph_commit_sha, computed_at FROM pr_scopes
|
|
164
|
+
WHERE repo = ? AND pr_id = ? ORDER BY computed_at DESC`)
|
|
165
|
+
.all(repo, prId)
|
|
166
|
+
.map((r) => ({ graphCommitSha: r.graph_commit_sha, computedAt: r.computed_at }));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Forget a PR entirely — every graph state it was scoped against.
|
|
170
|
+
*
|
|
171
|
+
* The only legitimate deletion: a closed or merged PR is not in flight and
|
|
172
|
+
* cannot conflict with anything. Deleting a *single* graph state is not
|
|
173
|
+
* offered, because the row is the comparison basis and there is no caller who
|
|
174
|
+
* wants exactly one of them gone.
|
|
175
|
+
*/
|
|
176
|
+
forget(repo, prId) {
|
|
177
|
+
return this.#driver
|
|
178
|
+
.prepare("DELETE FROM pr_scopes WHERE repo = ? AND pr_id = ?")
|
|
179
|
+
.run(repo, prId).changes;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=scope-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-store.js","sourceRoot":"","sources":["../../src/multipr/scope-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §14.5 — a change whose work is already in base.
|
|
3
|
+
*
|
|
4
|
+
* The architecture gives one sentence: *"Compare a PR's resulting code
|
|
5
|
+
* (post-diff) against current base. If functionally identical, flag as
|
|
6
|
+
* superseded."* Everything below is what that sentence turns into once the
|
|
7
|
+
* consequences of being wrong are taken seriously.
|
|
8
|
+
*
|
|
9
|
+
* ## This is the one check in §14 whose finding destroys work
|
|
10
|
+
*
|
|
11
|
+
* Every other multi-PR check tells someone to look at something. This one tells
|
|
12
|
+
* them to **close a pull request**, and a wrong answer throws away work that
|
|
13
|
+
* nobody has a copy of. §14.4's auto-apply path is the documented exception to
|
|
14
|
+
* approval-before-code-change and is hedged with a mandatory verify-after; this
|
|
15
|
+
* check has no such gate because the action it prompts is a human's.
|
|
16
|
+
*
|
|
17
|
+
* So the bar is asymmetric on purpose, and it is rule 2 applied to a finding
|
|
18
|
+
* rather than to an edge: **a missed supersession costs a redundant review; a
|
|
19
|
+
* false one costs the work.** Concretely, `superseded` is claimed only when
|
|
20
|
+
* *every* touched node was compared and *every* comparison matched. One node
|
|
21
|
+
* whose base state could not be read is enough to withhold the claim — and the
|
|
22
|
+
* partial result is still reported, because "9 of 10 already landed" is useful
|
|
23
|
+
* to the same reader and is a different sentence.
|
|
24
|
+
*
|
|
25
|
+
* ## Partial supersession is the common case, not an edge case
|
|
26
|
+
*
|
|
27
|
+
* The realistic history is that someone landed *most* of this work in another
|
|
28
|
+
* change. A binary verdict answers that with `false` and discards the only
|
|
29
|
+
* interesting part. So the report is a count and a list either way, and the
|
|
30
|
+
* boolean is a summary of it rather than the result itself.
|
|
31
|
+
*
|
|
32
|
+
* ## Three states, again, and for the same reason
|
|
33
|
+
*
|
|
34
|
+
* A node whose base fingerprint is absent is not a node that differs. Both
|
|
35
|
+
* would make `superseded` false, and only one of them is a statement about the
|
|
36
|
+
* code — the other is a statement about the reading. `BaseState` therefore has
|
|
37
|
+
* an explicit `"unknown"` rather than letting a missing fingerprint mean
|
|
38
|
+
* "different", which is the shape this project has now paid for seven times.
|
|
39
|
+
*
|
|
40
|
+
* ## What "functionally identical" is allowed to mean here
|
|
41
|
+
*
|
|
42
|
+
* Whatever the caller's fingerprint says, and no more. This module compares
|
|
43
|
+
* opaque strings; it does not normalise whitespace, sort imports or reason
|
|
44
|
+
* about equivalence, because every one of those is a judgement about a language
|
|
45
|
+
* and would put language knowledge above the IR boundary. A producer that
|
|
46
|
+
* fingerprints a normalised AST and one that hashes raw bytes both work here,
|
|
47
|
+
* and the report states which was used so a reader is never left to assume the
|
|
48
|
+
* stronger one.
|
|
49
|
+
*/
|
|
50
|
+
import type { ReliabilityClass, ResolutionLevel } from "@descryy/ir";
|
|
51
|
+
import type { DiffType } from "./overlap.ts";
|
|
52
|
+
/**
|
|
53
|
+
* One node the change touches, with the two states to compare.
|
|
54
|
+
*
|
|
55
|
+
* `after` is the node as the change leaves it. `base` is the same node on the
|
|
56
|
+
* target branch **now** — not at the change's merge base, which is the whole
|
|
57
|
+
* point: the question is whether this work is already there today.
|
|
58
|
+
*/
|
|
59
|
+
export interface SupersededCandidate {
|
|
60
|
+
readonly nodeId: string;
|
|
61
|
+
readonly file?: string | undefined;
|
|
62
|
+
readonly diffType: DiffType;
|
|
63
|
+
/**
|
|
64
|
+
* Fingerprint of the node as this change leaves it, or `"absent"` when the
|
|
65
|
+
* change deletes it.
|
|
66
|
+
*/
|
|
67
|
+
readonly after: string | "absent";
|
|
68
|
+
/**
|
|
69
|
+
* The same node on base today: a fingerprint, `"absent"` when base does not
|
|
70
|
+
* have it, or `"unknown"` when it could not be read.
|
|
71
|
+
*
|
|
72
|
+
* **`"absent"` and `"unknown"` are different.** A node base genuinely lacks
|
|
73
|
+
* matches a deletion; a node whose base state could not be read matches
|
|
74
|
+
* nothing, and the difference decides whether a human is told to close a
|
|
75
|
+
* change.
|
|
76
|
+
*/
|
|
77
|
+
readonly base: string | "absent" | "unknown";
|
|
78
|
+
readonly resolution: ResolutionLevel;
|
|
79
|
+
}
|
|
80
|
+
export type NodeVerdict = "already-in-base" | "differs" | "not-compared";
|
|
81
|
+
export interface NodeComparison {
|
|
82
|
+
readonly nodeId: string;
|
|
83
|
+
readonly file?: string | undefined;
|
|
84
|
+
readonly diffType: DiffType;
|
|
85
|
+
readonly verdict: NodeVerdict;
|
|
86
|
+
}
|
|
87
|
+
export interface SupersededReport {
|
|
88
|
+
/**
|
|
89
|
+
* True only when every touched node was compared and every one matched.
|
|
90
|
+
*
|
|
91
|
+
* A single `not-compared` node withholds this, however many matched — the
|
|
92
|
+
* finding it feeds tells a human to discard work.
|
|
93
|
+
*/
|
|
94
|
+
readonly superseded: boolean;
|
|
95
|
+
readonly comparisons: readonly NodeComparison[];
|
|
96
|
+
readonly counts: {
|
|
97
|
+
readonly total: number;
|
|
98
|
+
readonly alreadyInBase: number;
|
|
99
|
+
readonly differs: number;
|
|
100
|
+
readonly notCompared: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* False when there was nothing to compare.
|
|
104
|
+
*
|
|
105
|
+
* **Not the same as "not superseded".** A change with no candidates and a
|
|
106
|
+
* change whose every node differs both report `superseded: false`.
|
|
107
|
+
*/
|
|
108
|
+
readonly analysed: boolean;
|
|
109
|
+
readonly reliability: ReliabilityClass;
|
|
110
|
+
readonly disclosure: string;
|
|
111
|
+
readonly notes: readonly string[];
|
|
112
|
+
}
|
|
113
|
+
export interface SupersededOptions {
|
|
114
|
+
/**
|
|
115
|
+
* How the caller's fingerprints were produced — "sha256 of raw bytes",
|
|
116
|
+
* "hash of normalised AST". Carried into the disclosure verbatim.
|
|
117
|
+
*
|
|
118
|
+
* Required in substance rather than in type: omitting it produces a
|
|
119
|
+
* disclosure that says the basis was not stated, because a reader who assumes
|
|
120
|
+
* AST normalisation when the producer hashed bytes will read a `differs` as
|
|
121
|
+
* meaningful when it was whitespace.
|
|
122
|
+
*/
|
|
123
|
+
readonly fingerprintBasis?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether a change's work is already present on base.
|
|
127
|
+
*
|
|
128
|
+
* Pure over candidates: no store, no graph, no language. The caller's producer
|
|
129
|
+
* decides what a fingerprint means and at what resolution it was obtained; this
|
|
130
|
+
* propagates both.
|
|
131
|
+
*/
|
|
132
|
+
export declare function findSuperseded(candidates: readonly SupersededCandidate[], options?: SupersededOptions): SupersededReport;
|
|
133
|
+
//# sourceMappingURL=superseded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"superseded.d.ts","sourceRoot":"","sources":["../../src/multipr/superseded.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;CACtC;AAED,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,SAAS,GAAG,cAAc,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,cAAc,EAAE,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;OAQG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAWD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,SAAS,mBAAmB,EAAE,EAC1C,OAAO,GAAE,iBAAsB,GAC9B,gBAAgB,CA2ElB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §14.5 — a change whose work is already in base.
|
|
3
|
+
*
|
|
4
|
+
* The architecture gives one sentence: *"Compare a PR's resulting code
|
|
5
|
+
* (post-diff) against current base. If functionally identical, flag as
|
|
6
|
+
* superseded."* Everything below is what that sentence turns into once the
|
|
7
|
+
* consequences of being wrong are taken seriously.
|
|
8
|
+
*
|
|
9
|
+
* ## This is the one check in §14 whose finding destroys work
|
|
10
|
+
*
|
|
11
|
+
* Every other multi-PR check tells someone to look at something. This one tells
|
|
12
|
+
* them to **close a pull request**, and a wrong answer throws away work that
|
|
13
|
+
* nobody has a copy of. §14.4's auto-apply path is the documented exception to
|
|
14
|
+
* approval-before-code-change and is hedged with a mandatory verify-after; this
|
|
15
|
+
* check has no such gate because the action it prompts is a human's.
|
|
16
|
+
*
|
|
17
|
+
* So the bar is asymmetric on purpose, and it is rule 2 applied to a finding
|
|
18
|
+
* rather than to an edge: **a missed supersession costs a redundant review; a
|
|
19
|
+
* false one costs the work.** Concretely, `superseded` is claimed only when
|
|
20
|
+
* *every* touched node was compared and *every* comparison matched. One node
|
|
21
|
+
* whose base state could not be read is enough to withhold the claim — and the
|
|
22
|
+
* partial result is still reported, because "9 of 10 already landed" is useful
|
|
23
|
+
* to the same reader and is a different sentence.
|
|
24
|
+
*
|
|
25
|
+
* ## Partial supersession is the common case, not an edge case
|
|
26
|
+
*
|
|
27
|
+
* The realistic history is that someone landed *most* of this work in another
|
|
28
|
+
* change. A binary verdict answers that with `false` and discards the only
|
|
29
|
+
* interesting part. So the report is a count and a list either way, and the
|
|
30
|
+
* boolean is a summary of it rather than the result itself.
|
|
31
|
+
*
|
|
32
|
+
* ## Three states, again, and for the same reason
|
|
33
|
+
*
|
|
34
|
+
* A node whose base fingerprint is absent is not a node that differs. Both
|
|
35
|
+
* would make `superseded` false, and only one of them is a statement about the
|
|
36
|
+
* code — the other is a statement about the reading. `BaseState` therefore has
|
|
37
|
+
* an explicit `"unknown"` rather than letting a missing fingerprint mean
|
|
38
|
+
* "different", which is the shape this project has now paid for seven times.
|
|
39
|
+
*
|
|
40
|
+
* ## What "functionally identical" is allowed to mean here
|
|
41
|
+
*
|
|
42
|
+
* Whatever the caller's fingerprint says, and no more. This module compares
|
|
43
|
+
* opaque strings; it does not normalise whitespace, sort imports or reason
|
|
44
|
+
* about equivalence, because every one of those is a judgement about a language
|
|
45
|
+
* and would put language knowledge above the IR boundary. A producer that
|
|
46
|
+
* fingerprints a normalised AST and one that hashes raw bytes both work here,
|
|
47
|
+
* and the report states which was used so a reader is never left to assume the
|
|
48
|
+
* stronger one.
|
|
49
|
+
*/
|
|
50
|
+
import { reliabilityCap, reliabilityNote } from "@descryy/ir";
|
|
51
|
+
function compare(c) {
|
|
52
|
+
if (c.base === "unknown")
|
|
53
|
+
return "not-compared";
|
|
54
|
+
// A deletion is superseded when base has already lost the node. `after` and
|
|
55
|
+
// `base` both being "absent" is a match, not two missing values.
|
|
56
|
+
if (c.after === "absent")
|
|
57
|
+
return c.base === "absent" ? "already-in-base" : "differs";
|
|
58
|
+
if (c.base === "absent")
|
|
59
|
+
return "differs";
|
|
60
|
+
return c.after === c.base ? "already-in-base" : "differs";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether a change's work is already present on base.
|
|
64
|
+
*
|
|
65
|
+
* Pure over candidates: no store, no graph, no language. The caller's producer
|
|
66
|
+
* decides what a fingerprint means and at what resolution it was obtained; this
|
|
67
|
+
* propagates both.
|
|
68
|
+
*/
|
|
69
|
+
export function findSuperseded(candidates, options = {}) {
|
|
70
|
+
const notes = [];
|
|
71
|
+
const comparisons = candidates.map((c) => ({
|
|
72
|
+
nodeId: c.nodeId,
|
|
73
|
+
file: c.file,
|
|
74
|
+
diffType: c.diffType,
|
|
75
|
+
verdict: compare(c),
|
|
76
|
+
}));
|
|
77
|
+
const alreadyInBase = comparisons.filter((c) => c.verdict === "already-in-base").length;
|
|
78
|
+
const differs = comparisons.filter((c) => c.verdict === "differs").length;
|
|
79
|
+
const notCompared = comparisons.filter((c) => c.verdict === "not-compared").length;
|
|
80
|
+
// The weakest candidate decides, as everywhere else a claim rests on several
|
|
81
|
+
// observations. Whether two fingerprints are equal is a name-level fact — it
|
|
82
|
+
// is an identity of strings, not a claim about behaviour — so R2's carve-out
|
|
83
|
+
// applies and nothing here reaches beyond what its evidence bought.
|
|
84
|
+
const weakest = candidates.reduce((min, c) => (c.resolution < min ? c.resolution : min), 4);
|
|
85
|
+
const reliability = reliabilityCap(weakest, true);
|
|
86
|
+
let disclosure = reliabilityNote(weakest, true);
|
|
87
|
+
disclosure +=
|
|
88
|
+
options.fingerprintBasis === undefined
|
|
89
|
+
? " The basis on which two versions were called identical was not stated by the caller, so " +
|
|
90
|
+
"no claim is made about what a difference means: it may be a behavioural change or it " +
|
|
91
|
+
"may be whitespace."
|
|
92
|
+
: ` Two versions were called identical on this basis: ${options.fingerprintBasis}. A ` +
|
|
93
|
+
"difference means only that this basis differs.";
|
|
94
|
+
const analysed = candidates.length > 0;
|
|
95
|
+
const superseded = analysed && alreadyInBase === candidates.length;
|
|
96
|
+
if (!analysed) {
|
|
97
|
+
notes.push("No node was available to compare, so this check did not run. That is not a finding that " +
|
|
98
|
+
"the change is unsuperseded — a change whose every node differs and a change nothing " +
|
|
99
|
+
"was read for are different answers.");
|
|
100
|
+
}
|
|
101
|
+
if (notCompared > 0) {
|
|
102
|
+
notes.push(`${notCompared} of ${candidates.length} node(s) could not be compared against base, so ` +
|
|
103
|
+
"supersession is not claimed however many matched. This finding tells a human to close " +
|
|
104
|
+
"a change and discard work; a missed supersession costs a redundant review, and a false " +
|
|
105
|
+
"one costs the work.");
|
|
106
|
+
}
|
|
107
|
+
if (superseded) {
|
|
108
|
+
notes.push(`Every one of the ${candidates.length} node(s) this change touches is already in this ` +
|
|
109
|
+
"state on base. The work appears to have landed by another route.");
|
|
110
|
+
notes.push(disclosure);
|
|
111
|
+
}
|
|
112
|
+
else if (alreadyInBase > 0) {
|
|
113
|
+
// The interesting middle, and the reason the verdict is not just a boolean.
|
|
114
|
+
notes.push(`${alreadyInBase} of ${candidates.length} node(s) are already in this state on base, and ` +
|
|
115
|
+
`${differs} still differ. The change is partly landed rather than superseded, and the ` +
|
|
116
|
+
"nodes that still differ are what remains of it.");
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
superseded,
|
|
120
|
+
comparisons,
|
|
121
|
+
counts: { total: candidates.length, alreadyInBase, differs, notCompared },
|
|
122
|
+
analysed,
|
|
123
|
+
reliability,
|
|
124
|
+
disclosure,
|
|
125
|
+
notes,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=superseded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"superseded.js","sourceRoot":"","sources":["../../src/multipr/superseded.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DEC-223's answer half, matching side: which refusal-ledger rows does a
|
|
3
|
+
* confirmed fact actually answer?
|
|
4
|
+
*
|
|
5
|
+
* Deliberately does **not** mint a graph edge. Turning an answered row into a
|
|
6
|
+
* real `USES_API`/etc. edge needs a target to join against — an endpoint, a
|
|
7
|
+
* route — which this function has no way to resolve and which DEC-223 §6
|
|
8
|
+
* named as future work, not this row. What this function owns is narrower
|
|
9
|
+
* and load-bearing on its own: **which rows are answered, by what value, and
|
|
10
|
+
* that the match never crosses a repo or accessor boundary it should not.**
|
|
11
|
+
* A caller minting an edge from `answered` is the one obligated to pass
|
|
12
|
+
* `reliabilityCap`'s `humanAsserted: true` — this function does not compute a
|
|
13
|
+
* reliability class itself, because it has no resolution level to reason
|
|
14
|
+
* from (`UnresolvedRef` carries none — refusals are not edges and were never
|
|
15
|
+
* scored). Inventing one here would be exactly the overclaim principle 2
|
|
16
|
+
* exists to prevent.
|
|
17
|
+
*/
|
|
18
|
+
import type { ConfirmedFact, UnresolvedRef } from "@descryy/ir";
|
|
19
|
+
export interface ConfirmedFactMatch {
|
|
20
|
+
readonly ref: UnresolvedRef;
|
|
21
|
+
/**
|
|
22
|
+
* Every fact sharing this row's `(repo, blockedBy)`, regardless of
|
|
23
|
+
* `environment` — never picks one. A row's own site carries no environment
|
|
24
|
+
* of its own (the code runs in whichever environment it is deployed to),
|
|
25
|
+
* so this function cannot know which of several environment-scoped facts
|
|
26
|
+
* applies; surfacing all of them lets a caller show the split rather than
|
|
27
|
+
* silently choosing a value that might be wrong for the environment the
|
|
28
|
+
* row actually runs in. Almost always length 1 — DEC-223's own measured
|
|
29
|
+
* cases were unscoped, single-fact answers — but never assumed to be.
|
|
30
|
+
*/
|
|
31
|
+
readonly facts: readonly ConfirmedFact[];
|
|
32
|
+
}
|
|
33
|
+
export interface ConfirmedFactApplication {
|
|
34
|
+
/** Rows a stored fact answers — same `(repo, blockedBy)` key, exact match. */
|
|
35
|
+
readonly answered: readonly ConfirmedFactMatch[];
|
|
36
|
+
/** Every other row: unclassified, a different class than `"value-unknown"`, or no matching fact yet. */
|
|
37
|
+
readonly stillOpen: readonly UnresolvedRef[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Match ledger rows against confirmed facts, scoped to one repository.
|
|
41
|
+
*
|
|
42
|
+
* Three things keep a row out of `answered`, all deliberate:
|
|
43
|
+
*
|
|
44
|
+
* 1. **No `attrs.refusalClass === "value-unknown"`.** Everything else —
|
|
45
|
+
* unclassified, `capability-gap`, `out-of-scope`, `varies-per-call` — is
|
|
46
|
+
* not askable at all (DEC-242), so no fact could ever answer it; matching
|
|
47
|
+
* on `blockedBy` alone without this check would let a stored fact silently
|
|
48
|
+
* resolve a `varies-per-call` row that structurally has no single answer.
|
|
49
|
+
* 2. **No `attrs.blockedBy`, or it is not a string.** Nothing to key against.
|
|
50
|
+
* 3. **No fact in `facts` shares this repo's exact `(repo, blockedBy)` pair.**
|
|
51
|
+
* `facts` entries for a different `repo` are never consulted, even when the
|
|
52
|
+
* blockedBy text is identical — rule 3's "never an inference about a
|
|
53
|
+
* second case," enforced structurally rather than left to caller discipline.
|
|
54
|
+
*/
|
|
55
|
+
export declare function applyConfirmedFacts(refs: readonly UnresolvedRef[], facts: readonly ConfirmedFact[], repo: string): ConfirmedFactApplication;
|
|
56
|
+
//# sourceMappingURL=confirmed-facts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmed-facts.d.ts","sourceRoot":"","sources":["../../src/query/confirmed-facts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B;;;;;;;;;OASG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACjD,wGAAwG;IACxG,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,aAAa,EAAE,EAC9B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,IAAI,EAAE,MAAM,GACX,wBAAwB,CA4B1B"}
|