@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
package/dist/store/index.js
CHANGED
|
@@ -3,13 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { NodeSqliteDriver } from "./driver/node-sqlite.js";
|
|
5
5
|
import { migrate, verifyReadOnly } from "./migrate.js";
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Migration runs on open, so there is no window in which a caller holds a handle
|
|
10
|
-
* to a store whose version has not been checked — DEC-017's "refuse to read"
|
|
11
|
-
* has to happen before the first read, not on the first query.
|
|
12
|
-
*/
|
|
6
|
+
/** Opens (or creates) a graph at `path`, or ":memory:" for a throwaway one. Migration runs on
|
|
7
|
+
* open — DEC-017's "refuse to read" happens before the first read, never on the first query. */
|
|
13
8
|
export function openStore(path, options = {}) {
|
|
14
9
|
const driver = options.driver ?? new NodeSqliteDriver();
|
|
15
10
|
const openOptions = {
|
|
@@ -18,9 +13,8 @@ export function openStore(path, options = {}) {
|
|
|
18
13
|
};
|
|
19
14
|
driver.open(path, openOptions);
|
|
20
15
|
try {
|
|
21
|
-
// A read-only handle
|
|
22
|
-
//
|
|
23
|
-
// only. This is the path the traversal worker takes.
|
|
16
|
+
// A read-only handle can't run migrate (even CREATE TABLE IF NOT EXISTS needs write) — it
|
|
17
|
+
// verifies instead, same DEC-017 rule, reads only. This is the traversal worker's path.
|
|
24
18
|
if (options.readOnly === true) {
|
|
25
19
|
verifyReadOnly(driver);
|
|
26
20
|
return { driver, created: false, close: () => driver.close() };
|
package/dist/store/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAcvD
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAcvD;iGACiG;AACjG,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,UAA4B,EAAE;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;IACxD,MAAM,WAAW,GAAgB;QAC/B,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1D,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;KAC1E,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,0FAA0F;QAC1F,wFAAwF;QACxF,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC9B,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;QACjE,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO;YACL,MAAM;YACN,OAAO;YACP,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;SAC5B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AASjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGhG,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/store/migrate.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Schema creation and IR-version enforcement —
|
|
3
|
-
*
|
|
4
|
-
* The rule this file implements: **on IR-version mismatch, refuse to read.**
|
|
5
|
-
* Not "migrate what we can", not "read it and hope". A graph written under a
|
|
6
|
-
* different IR carries node ids from a different identity scheme, and reading it
|
|
7
|
-
* would silently mix two incompatible id spaces — the failure would surface much
|
|
8
|
-
* later as missing edges, with nothing to trace it back to.
|
|
2
|
+
* Schema creation and IR-version enforcement (DEC-017): on version mismatch, refuse to read — never migrate or read-and-hope. A different IR version means a different
|
|
3
|
+
* node-id scheme; reading it would silently mix incompatible id spaces, surfacing later as missing edges with nothing to trace back to.
|
|
9
4
|
*/
|
|
10
5
|
import { type SqlDriver } from "./driver/driver.ts";
|
|
11
6
|
export declare class SchemaVersionError extends Error {
|
|
@@ -14,54 +9,23 @@ export declare class SchemaVersionError extends Error {
|
|
|
14
9
|
readonly expected: number;
|
|
15
10
|
constructor(found: number, expected: number);
|
|
16
11
|
}
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* Returns whether the store was newly created, which the caller needs in order
|
|
21
|
-
* to distinguish "empty because it is new" from "empty because a rebuild is
|
|
22
|
-
* pending" — two states that look identical from a row count.
|
|
23
|
-
*/
|
|
12
|
+
/** Creates the schema if absent, then verifies the store is readable. `created`
|
|
13
|
+
* lets a caller distinguish "empty because new" from "empty, rebuild pending". */
|
|
24
14
|
export declare function migrate(driver: SqlDriver): {
|
|
25
15
|
created: boolean;
|
|
26
16
|
};
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* transferable between threads), and `migrate` cannot run there — even
|
|
32
|
-
* `CREATE TABLE IF NOT EXISTS` needs write permission, so the ordinary path
|
|
33
|
-
* would fail on a perfectly healthy graph. This performs the same DEC-017 check
|
|
34
|
-
* with reads only.
|
|
35
|
-
*
|
|
36
|
-
* Deliberately refuses an empty database rather than creating one: a read-only
|
|
37
|
-
* consumer that silently accepts "no schema" would report an empty answer for a
|
|
38
|
-
* graph that was never built, which is the difference between "nothing matched"
|
|
39
|
-
* and "nothing was analysed".
|
|
40
|
-
*/
|
|
17
|
+
/** Verifies a graph without writing to it — `migrate` needs write permission
|
|
18
|
+
* (handles aren't transferable to the traversal worker's thread), so this does
|
|
19
|
+
* the same DEC-017 check read-only, and refuses an empty database rather than
|
|
20
|
+
* creating one ("nothing matched" vs "nothing was analysed"). */
|
|
41
21
|
export declare function verifyReadOnly(driver: SqlDriver): void;
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* This is the whole operational content of DEC-017. It is also what makes the
|
|
46
|
-
* decision falsifiable: a test asserts the earned rows are still there
|
|
47
|
-
* afterwards, so the partition cannot quietly stop being real.
|
|
48
|
-
*/
|
|
22
|
+
/** Drops and recreates every derived table, leaving earned data untouched — the
|
|
23
|
+
* whole operational content of DEC-017; a test asserts earned rows survive. */
|
|
49
24
|
export declare function dropDerived(driver: SqlDriver): void;
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* this first instead of hitting the refusal and stopping.
|
|
55
|
-
*
|
|
56
|
-
* Deliberately a separate entry point from `migrate()`, not a flag on it:
|
|
57
|
-
* `migrate()`'s whole contract is "refuse to read a version this build does
|
|
58
|
-
* not expect," and folding a silent repair into the same function would make
|
|
59
|
-
* every caller's version check optionally not a check. This one opens its own
|
|
60
|
-
* short-lived handle, repairs if (and only if) the stored version is a real
|
|
61
|
-
* mismatch — never on a brand-new graph, where `migrate()`'s own create path
|
|
62
|
-
* already does the right thing — and closes again, so the caller always goes
|
|
63
|
-
* on to open its own handle through the normal, checked path.
|
|
64
|
-
*/
|
|
25
|
+
/** MK-4: the repair `SchemaVersionError` names. Only `analyze` (about to rebuild
|
|
26
|
+
* anyway) calls this instead of hitting the refusal; every other tool keeps
|
|
27
|
+
* refusing per DEC-017. Separate from `migrate()` so its version check stays
|
|
28
|
+
* a real check, not an optional one; repairs only on a genuine mismatch. */
|
|
65
29
|
export declare function rebuildStaleGraph(driver: SqlDriver): {
|
|
66
30
|
readonly rebuilt: boolean;
|
|
67
31
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/store/migrate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/store/migrate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGjE,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAkB,IAAI,wBAAwB;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAU5C;AAkBD;mFACmF;AACnF,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CA2B/D;AAED;;;kEAGkE;AAClE,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsBtD;AAED;gFACgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CASnD;AAED;;;6EAG6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAQlF"}
|
package/dist/store/migrate.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Schema creation and IR-version enforcement —
|
|
3
|
-
*
|
|
4
|
-
* The rule this file implements: **on IR-version mismatch, refuse to read.**
|
|
5
|
-
* Not "migrate what we can", not "read it and hope". A graph written under a
|
|
6
|
-
* different IR carries node ids from a different identity scheme, and reading it
|
|
7
|
-
* would silently mix two incompatible id spaces — the failure would surface much
|
|
8
|
-
* later as missing edges, with nothing to trace it back to.
|
|
2
|
+
* Schema creation and IR-version enforcement (DEC-017): on version mismatch, refuse to read — never migrate or read-and-hope. A different IR version means a different
|
|
3
|
+
* node-id scheme; reading it would silently mix incompatible id spaces, surfacing later as missing edges with nothing to trace back to.
|
|
9
4
|
*/
|
|
10
5
|
import { DriverError } from "./driver/driver.js";
|
|
11
6
|
import { DERIVED_DROP_ORDER, IR_SCHEMA_VERSION, NODE_ID_SCHEME, SCHEMA_SQL } from "./schema.js";
|
|
@@ -31,13 +26,8 @@ function writeMeta(driver, key, value) {
|
|
|
31
26
|
.prepare("INSERT INTO graph_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value")
|
|
32
27
|
.run(key, value);
|
|
33
28
|
}
|
|
34
|
-
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* Returns whether the store was newly created, which the caller needs in order
|
|
38
|
-
* to distinguish "empty because it is new" from "empty because a rebuild is
|
|
39
|
-
* pending" — two states that look identical from a row count.
|
|
40
|
-
*/
|
|
29
|
+
/** Creates the schema if absent, then verifies the store is readable. `created`
|
|
30
|
+
* lets a caller distinguish "empty because new" from "empty, rebuild pending". */
|
|
41
31
|
export function migrate(driver) {
|
|
42
32
|
return driver.transaction(() => {
|
|
43
33
|
driver.exec(SCHEMA_SQL);
|
|
@@ -55,27 +45,16 @@ export function migrate(driver) {
|
|
|
55
45
|
throw new SchemaVersionError(found, IR_SCHEMA_VERSION);
|
|
56
46
|
const scheme = readMeta(driver, "node_id_scheme");
|
|
57
47
|
if (scheme !== NODE_ID_SCHEME) {
|
|
58
|
-
//
|
|
59
|
-
// a recognisable mismatch instead of a silent one (DEC-011).
|
|
48
|
+
// `n1:` tag exists for exactly this check — a recognisable mismatch, not a silent one (DEC-011).
|
|
60
49
|
throw new DriverError(`stored graph uses node id scheme ${String(scheme)}, this build writes ${NODE_ID_SCHEME}`);
|
|
61
50
|
}
|
|
62
51
|
return { created: false };
|
|
63
52
|
});
|
|
64
53
|
}
|
|
65
|
-
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* transferable between threads), and `migrate` cannot run there — even
|
|
70
|
-
* `CREATE TABLE IF NOT EXISTS` needs write permission, so the ordinary path
|
|
71
|
-
* would fail on a perfectly healthy graph. This performs the same DEC-017 check
|
|
72
|
-
* with reads only.
|
|
73
|
-
*
|
|
74
|
-
* Deliberately refuses an empty database rather than creating one: a read-only
|
|
75
|
-
* consumer that silently accepts "no schema" would report an empty answer for a
|
|
76
|
-
* graph that was never built, which is the difference between "nothing matched"
|
|
77
|
-
* and "nothing was analysed".
|
|
78
|
-
*/
|
|
54
|
+
/** Verifies a graph without writing to it — `migrate` needs write permission
|
|
55
|
+
* (handles aren't transferable to the traversal worker's thread), so this does
|
|
56
|
+
* the same DEC-017 check read-only, and refuses an empty database rather than
|
|
57
|
+
* creating one ("nothing matched" vs "nothing was analysed"). */
|
|
79
58
|
export function verifyReadOnly(driver) {
|
|
80
59
|
const exists = driver
|
|
81
60
|
.prepare("SELECT COUNT(*) AS n FROM sqlite_master WHERE type = 'table' AND name = 'graph_meta'")
|
|
@@ -94,13 +73,8 @@ export function verifyReadOnly(driver) {
|
|
|
94
73
|
throw new DriverError(`stored graph uses node id scheme ${String(scheme)}, this build writes ${NODE_ID_SCHEME}`);
|
|
95
74
|
}
|
|
96
75
|
}
|
|
97
|
-
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* This is the whole operational content of DEC-017. It is also what makes the
|
|
101
|
-
* decision falsifiable: a test asserts the earned rows are still there
|
|
102
|
-
* afterwards, so the partition cannot quietly stop being real.
|
|
103
|
-
*/
|
|
76
|
+
/** Drops and recreates every derived table, leaving earned data untouched — the
|
|
77
|
+
* whole operational content of DEC-017; a test asserts earned rows survive. */
|
|
104
78
|
export function dropDerived(driver) {
|
|
105
79
|
driver.transaction(() => {
|
|
106
80
|
for (const table of DERIVED_DROP_ORDER) {
|
|
@@ -111,21 +85,10 @@ export function dropDerived(driver) {
|
|
|
111
85
|
writeMeta(driver, "node_id_scheme", NODE_ID_SCHEME);
|
|
112
86
|
});
|
|
113
87
|
}
|
|
114
|
-
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* this first instead of hitting the refusal and stopping.
|
|
119
|
-
*
|
|
120
|
-
* Deliberately a separate entry point from `migrate()`, not a flag on it:
|
|
121
|
-
* `migrate()`'s whole contract is "refuse to read a version this build does
|
|
122
|
-
* not expect," and folding a silent repair into the same function would make
|
|
123
|
-
* every caller's version check optionally not a check. This one opens its own
|
|
124
|
-
* short-lived handle, repairs if (and only if) the stored version is a real
|
|
125
|
-
* mismatch — never on a brand-new graph, where `migrate()`'s own create path
|
|
126
|
-
* already does the right thing — and closes again, so the caller always goes
|
|
127
|
-
* on to open its own handle through the normal, checked path.
|
|
128
|
-
*/
|
|
88
|
+
/** MK-4: the repair `SchemaVersionError` names. Only `analyze` (about to rebuild
|
|
89
|
+
* anyway) calls this instead of hitting the refusal; every other tool keeps
|
|
90
|
+
* refusing per DEC-017. Separate from `migrate()` so its version check stays
|
|
91
|
+
* a real check, not an optional one; repairs only on a genuine mismatch. */
|
|
129
92
|
export function rebuildStaleGraph(driver) {
|
|
130
93
|
driver.exec(SCHEMA_SQL);
|
|
131
94
|
const storedVersion = readMeta(driver, "ir_schema_version");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/store/migrate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/store/migrate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhG,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACzB,IAAI,GAAG,oBAAoB,CAAC;IACrC,KAAK,CAAS;IACd,QAAQ,CAAS;IAE1B,YAAY,KAAa,EAAE,QAAgB;QACzC,KAAK,CACH,oDAAoD,KAAK,wBAAwB,QAAQ,IAAI;YAC3F,4FAA4F;YAC5F,6FAA6F;YAC7F,6EAA6E,CAChF,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAOD,SAAS,QAAQ,CAAC,MAAiB,EAAE,GAAW;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAU,iDAAiD,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChG,OAAO,GAAG,EAAE,KAAK,CAAC;AACpB,CAAC;AAED,SAAS,SAAS,CAAC,MAAiB,EAAE,GAAW,EAAE,KAAa;IAC9D,MAAM;SACH,OAAO,CAAC,yGAAyG,CAAC;SAClH,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACrB,CAAC;AAED;mFACmF;AACnF,MAAM,UAAU,OAAO,CAAC,MAAiB;IACvC,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;QAC7B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAExB,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;QAC5D,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,SAAS,CAAC,MAAM,EAAE,mBAAmB,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAClE,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;YACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,WAAW,CAAC,mDAAmD,aAAa,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,KAAK,KAAK,iBAAiB;YAAE,MAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QAExF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;YAC9B,iGAAiG;YACjG,MAAM,IAAI,WAAW,CACnB,oCAAoC,MAAM,CAAC,MAAM,CAAC,uBAAuB,cAAc,EAAE,CAC1F,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;kEAGkE;AAClE,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,MAAM,MAAM,GAAG,MAAM;SAClB,OAAO,CACN,sFAAsF,CACvF;SACA,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,WAAW,CAAC,+DAA+D,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,WAAW,CAAC,2DAA2D,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,KAAK,KAAK,iBAAiB;QAAE,MAAM,IAAI,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAExF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,MAAM,IAAI,WAAW,CACnB,oCAAoC,MAAM,CAAC,MAAM,CAAC,uBAAuB,cAAc,EAAE,CAC1F,CAAC;IACJ,CAAC;AACH,CAAC;AAED;gFACgF;AAChF,MAAM,UAAU,WAAW,CAAC,MAAiB;IAC3C,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;QACtB,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,SAAS,CAAC,MAAM,EAAE,mBAAmB,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAClE,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;6EAG6E;AAC7E,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxB,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC5D,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,iBAAiB;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACvF,WAAW,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
package/dist/store/reader.d.ts
CHANGED
|
@@ -1,82 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reads over the stored graph.
|
|
3
|
-
*
|
|
4
|
-
* Deliberately thin. This is not the query layer (plan Step 9) — it is the row
|
|
5
|
-
* access the query layer will be written against, and nothing here knows about
|
|
6
|
-
* scoring, budgets or traversal. Keeping the split means the query layer can be
|
|
7
|
-
* tested against an in-memory adjacency provider with no database at all, which
|
|
8
|
-
* is what stops 95% of the engine's tests needing SQLite and a worker.
|
|
9
|
-
*
|
|
10
|
-
* No row from `driver/` reaches a caller unconverted: SQLite has no booleans, no
|
|
11
|
-
* null-vs-undefined distinction and no nested values, so every read here maps
|
|
12
|
-
* columns back into IR shapes rather than handing out raw rows.
|
|
2
|
+
* Reads over the stored graph. Deliberately thin — not the query layer (Step 9), just the row access it's written against; the split lets the query layer test against an in-memory provider, no database, no SQLite in 95% of tests.
|
|
3
|
+
* No row from driver/ reaches a caller unconverted: SQLite has no booleans, no null-vs-undefined, no nested values.
|
|
13
4
|
*/
|
|
14
5
|
import { type EdgeType, type IREdge, type IRNode, type NodeType, type UnresolvedRef } from "@descryy/ir";
|
|
15
6
|
import type { SqlDriver } from "./driver/driver.ts";
|
|
16
7
|
export declare function getNode(driver: SqlDriver, id: string): IRNode | undefined;
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* A diff names files; scoping seeds on nodes. Nothing bridged the two until now,
|
|
21
|
-
* because every measurement so far started from node ids it had just built.
|
|
22
|
-
*
|
|
23
|
-
* **Which files miss is as important as which nodes hit.** A path present in the
|
|
24
|
-
* diff and absent from the graph is not an empty result — it is a file the
|
|
25
|
-
* analysis never read, and reporting its blast radius as "nothing affected"
|
|
26
|
-
* would put an unanalysed file in §20.2's *confirmed clean* category when it
|
|
27
|
-
* belongs in *not analysable*. So the misses come back alongside the hits and
|
|
28
|
-
* the caller cannot take one without the other.
|
|
29
|
-
*
|
|
30
|
-
* Paths are matched exactly. They are repo-relative by the Normaliser's rule, so
|
|
31
|
-
* a caller passing absolute paths gets zero hits and is told so by `missing`
|
|
32
|
-
* rather than by silence.
|
|
33
|
-
*/
|
|
8
|
+
/** Every node declared in any of `paths` — the diff-to-seeds step. Misses
|
|
9
|
+
* matter as much as hits: an absent path is an unanalysed file (§20.2), not
|
|
10
|
+
* an empty result, so both return together. Paths matched exactly (repo-relative); absolute paths get zero hits via `missing`. */
|
|
34
11
|
export declare function nodesInFiles(driver: SqlDriver, paths: readonly string[]): {
|
|
35
12
|
readonly nodes: IRNode[];
|
|
36
13
|
readonly missing: string[];
|
|
37
14
|
};
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* `limit + 1` is fetched so the caller can tell "exactly the limit" from "the
|
|
42
|
-
* limit and more" without a second `COUNT(*)`. A set-property question answered
|
|
43
|
-
* over a silently truncated set is a fact computed from a sample, so the
|
|
44
|
-
* distinction has to be available.
|
|
45
|
-
*/
|
|
15
|
+
/** Every node of one type, capped, with one row of headroom. `limit + 1` is
|
|
16
|
+
* fetched so the caller can tell "exactly the limit" from "more", without a
|
|
17
|
+
* second COUNT(*) — a truncated set answering a set-property question needs that distinction available. */
|
|
46
18
|
export declare function nodesOfType(driver: SqlDriver, type: NodeType, limit: number): {
|
|
47
19
|
readonly nodes: IRNode[];
|
|
48
20
|
readonly truncated: boolean;
|
|
49
21
|
};
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* Deliberately returns **every** match rather than a best one. Two functions in
|
|
54
|
-
* a repository can legitimately share a name, and picking one by a heuristic —
|
|
55
|
-
* shortest path, most edges, first row — is how a caller ends up reasoning
|
|
56
|
-
* confidently about the wrong symbol. Ambiguity is the caller's to report, so
|
|
57
|
-
* the reader hands it over intact.
|
|
58
|
-
*
|
|
59
|
-
* `repo` narrows to nodes minted by a run recorded against that repository —
|
|
60
|
-
* a subquery against `adapter_runs`, since `nodes` itself carries no `repo`
|
|
61
|
-
* column (only `run_id`). Added for `descry-runtime`'s graph correlator: a
|
|
62
|
-
* multi-repo session (frontend + backend merged into one store, per DEC-228)
|
|
63
|
-
* makes a same-named symbol in the wrong repository a real candidate for a
|
|
64
|
-
* bare `findNodes({ name })` call, and nothing before this filtered it out.
|
|
65
|
-
* Omitted, this behaves exactly as before — existing callers are unaffected.
|
|
66
|
-
*/
|
|
22
|
+
/** Nodes matching a name and/or file — the "I know what it's called" lookup.
|
|
23
|
+
* Returns every match, never a best one: picking one by heuristic is how a
|
|
24
|
+
* caller reasons confidently about the wrong symbol. `repo` narrows via an adapter_runs subquery (nodes carries no repo column) — added for descry-runtime's multi-repo correlator (DEC-228); omitted, behaves exactly as before. */
|
|
67
25
|
export declare function findNodes(driver: SqlDriver, criteria: {
|
|
68
26
|
readonly name?: string;
|
|
69
27
|
readonly file?: string;
|
|
70
28
|
readonly repo?: string;
|
|
71
29
|
readonly limit?: number;
|
|
72
30
|
}): IRNode[];
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* The cap is not optional politeness. The prior-art graphs on this machine have
|
|
77
|
-
* a max in-degree of 1,036 (`append`) — materialising every neighbour of a hub
|
|
78
|
-
* node during a traversal is how a 200-node budget turns into a 10,000-row read.
|
|
79
|
-
*/
|
|
31
|
+
/** Edges leaving a node, filtered by type and capped. Not optional politeness:
|
|
32
|
+
* a real graph's max in-degree of 1,036 turns a 200-node budget into a 10,000-row read without it. */
|
|
80
33
|
export declare function outgoing(driver: SqlDriver, id: string, options?: {
|
|
81
34
|
types?: readonly EdgeType[];
|
|
82
35
|
limit?: number;
|
|
@@ -85,18 +38,9 @@ export declare function incoming(driver: SqlDriver, id: string, options?: {
|
|
|
85
38
|
types?: readonly EdgeType[];
|
|
86
39
|
limit?: number;
|
|
87
40
|
}): IREdge[];
|
|
88
|
-
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* `classified` (default `true`) restricts to `attrs IS NOT NULL` — rows with
|
|
92
|
-
* no `attrs` at all can never become a question (DEC-242: an unset
|
|
93
|
-
* `refusalClass` is never askable) and are always the majority of this table
|
|
94
|
-
* early in a producer's rollout — sherpa-frontend alone carries ~13,000. That
|
|
95
|
-
* filter is a real optimisation, not an approximation: it changes which rows
|
|
96
|
-
* are *materialised*, never which rows the grouper would have turned into a
|
|
97
|
-
* question. The unclassified count for disclosure is `counts(driver)
|
|
98
|
-
* .unresolvedRefs` minus this function's own row count, not recomputed here.
|
|
99
|
-
*/
|
|
41
|
+
/** Refusal-ledger rows for the question-grouping layer (DEC-243). `classified`
|
|
42
|
+
* (default true) restricts to `attrs IS NOT NULL` — rows with none can never
|
|
43
|
+
* become a question (DEC-242) and dominate early rollout (~13,000 on sherpa-frontend). A real optimisation, not an approximation: it never drops a groupable row. */
|
|
100
44
|
export declare function unresolvedRefs(driver: SqlDriver, options?: {
|
|
101
45
|
readonly classified?: boolean;
|
|
102
46
|
readonly limit?: number;
|
|
@@ -111,17 +55,8 @@ export interface StoreCounts {
|
|
|
111
55
|
readonly runs: number;
|
|
112
56
|
}
|
|
113
57
|
export declare function counts(driver: SqlDriver): StoreCounts;
|
|
114
|
-
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* This is the instrument for the determinism proof: ingesting the same batches
|
|
118
|
-
* in a permuted order must produce the same hash. Without it, "the graph does
|
|
119
|
-
* not depend on adapter ordering" is an assertion nobody can check, and by the
|
|
120
|
-
* time a real ordering dependency shows up it presents as an unreproducible
|
|
121
|
-
* difference in impact scores.
|
|
122
|
-
*
|
|
123
|
-
* `written_at` is excluded — a wall-clock stamp is not logical content, and
|
|
124
|
-
* including it would make the proof untestable rather than making it stronger.
|
|
125
|
-
*/
|
|
58
|
+
/** Hash of the store's logical content, independent of insertion order — the
|
|
59
|
+
* determinism proof's instrument (permuted-order ingestion must hash the
|
|
60
|
+
* same). `written_at` is excluded: a wall-clock stamp isn't logical content. */
|
|
126
61
|
export declare function contentHash(driver: SqlDriver): string;
|
|
127
62
|
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/store/reader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/store/reader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,QAAQ,EAEb,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAuGpD,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED;;mIAEmI;AACnI,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA2B1D;AAED;;4GAE4G;AAC5G,wBAAgB,WAAW,CACzB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,GACZ;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAU3D;AAED;;sOAEsO;AACtO,wBAAgB,SAAS,CACvB,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE;IACR,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB,GACA,MAAM,EAAE,CAyBV;AAED;uGACuG;AACvG,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,MAAM,EAAE,CAEV;AAED,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,MAAM,EAAE,CAEV;AA0BD;;sKAEsK;AACtK,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACvE;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAYjE;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,CASrD;AAED;;iFAEiF;AACjF,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAqBrD"}
|
package/dist/store/reader.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reads over the stored graph.
|
|
3
|
-
*
|
|
4
|
-
* Deliberately thin. This is not the query layer (plan Step 9) — it is the row
|
|
5
|
-
* access the query layer will be written against, and nothing here knows about
|
|
6
|
-
* scoring, budgets or traversal. Keeping the split means the query layer can be
|
|
7
|
-
* tested against an in-memory adjacency provider with no database at all, which
|
|
8
|
-
* is what stops 95% of the engine's tests needing SQLite and a worker.
|
|
9
|
-
*
|
|
10
|
-
* No row from `driver/` reaches a caller unconverted: SQLite has no booleans, no
|
|
11
|
-
* null-vs-undefined distinction and no nested values, so every read here maps
|
|
12
|
-
* columns back into IR shapes rather than handing out raw rows.
|
|
2
|
+
* Reads over the stored graph. Deliberately thin — not the query layer (Step 9), just the row access it's written against; the split lets the query layer test against an in-memory provider, no database, no SQLite in 95% of tests.
|
|
3
|
+
* No row from driver/ reaches a caller unconverted: SQLite has no booleans, no null-vs-undefined, no nested values.
|
|
13
4
|
*/
|
|
14
5
|
import { createHash } from "node:crypto";
|
|
15
6
|
import { canonicalJson, isEdgeType, isNodeType, } from "@descryy/ir";
|
|
@@ -19,8 +10,8 @@ const EDGE_COLUMNS = "id, source, target, type, resolution, confidence, produced
|
|
|
19
10
|
const UNRESOLVED_REF_COLUMNS = "from_node_id, edge_type, raw_target, file_path, line, produced_by, reason, attrs";
|
|
20
11
|
function toNode(row) {
|
|
21
12
|
if (!isNodeType(row.type)) {
|
|
22
|
-
// Only reachable if something wrote around the Normaliser
|
|
23
|
-
//
|
|
13
|
+
// Only reachable if something wrote around the Normaliser — worth
|
|
14
|
+
// failing loudly on rather than coercing.
|
|
24
15
|
throw new Error(`stored node ${row.id} has an unknown type: ${row.type}`);
|
|
25
16
|
}
|
|
26
17
|
const type = row.type;
|
|
@@ -74,32 +65,17 @@ export function getNode(driver, id) {
|
|
|
74
65
|
const row = driver.prepare(`SELECT ${NODE_COLUMNS} FROM nodes WHERE id = ?`).get(id);
|
|
75
66
|
return row === undefined ? undefined : toNode(row);
|
|
76
67
|
}
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* A diff names files; scoping seeds on nodes. Nothing bridged the two until now,
|
|
81
|
-
* because every measurement so far started from node ids it had just built.
|
|
82
|
-
*
|
|
83
|
-
* **Which files miss is as important as which nodes hit.** A path present in the
|
|
84
|
-
* diff and absent from the graph is not an empty result — it is a file the
|
|
85
|
-
* analysis never read, and reporting its blast radius as "nothing affected"
|
|
86
|
-
* would put an unanalysed file in §20.2's *confirmed clean* category when it
|
|
87
|
-
* belongs in *not analysable*. So the misses come back alongside the hits and
|
|
88
|
-
* the caller cannot take one without the other.
|
|
89
|
-
*
|
|
90
|
-
* Paths are matched exactly. They are repo-relative by the Normaliser's rule, so
|
|
91
|
-
* a caller passing absolute paths gets zero hits and is told so by `missing`
|
|
92
|
-
* rather than by silence.
|
|
93
|
-
*/
|
|
68
|
+
/** Every node declared in any of `paths` — the diff-to-seeds step. Misses
|
|
69
|
+
* matter as much as hits: an absent path is an unanalysed file (§20.2), not
|
|
70
|
+
* an empty result, so both return together. Paths matched exactly (repo-relative); absolute paths get zero hits via `missing`. */
|
|
94
71
|
export function nodesInFiles(driver, paths) {
|
|
95
72
|
const wanted = [...new Set(paths)].sort();
|
|
96
73
|
if (wanted.length === 0)
|
|
97
74
|
return { nodes: [], missing: [] };
|
|
98
75
|
const nodes = [];
|
|
99
76
|
const seen = new Set();
|
|
100
|
-
// Chunked
|
|
101
|
-
// legitimately exceeds it.
|
|
102
|
-
// keeps the limit where it belongs — a property of the driver, not of a diff.
|
|
77
|
+
// Chunked: SQLite's default parameter ceiling is 999, and a large PR
|
|
78
|
+
// legitimately exceeds it. Kept a driver property, not a caller's concern.
|
|
103
79
|
const CHUNK = 500;
|
|
104
80
|
for (let i = 0; i < wanted.length; i += CHUNK) {
|
|
105
81
|
const chunk = wanted.slice(i, i + CHUNK);
|
|
@@ -117,14 +93,9 @@ export function nodesInFiles(driver, paths) {
|
|
|
117
93
|
const hit = new Set(nodes.map((n) => n.file).filter((f) => f !== null));
|
|
118
94
|
return { nodes, missing: wanted.filter((p) => !hit.has(p)) };
|
|
119
95
|
}
|
|
120
|
-
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* `limit + 1` is fetched so the caller can tell "exactly the limit" from "the
|
|
124
|
-
* limit and more" without a second `COUNT(*)`. A set-property question answered
|
|
125
|
-
* over a silently truncated set is a fact computed from a sample, so the
|
|
126
|
-
* distinction has to be available.
|
|
127
|
-
*/
|
|
96
|
+
/** Every node of one type, capped, with one row of headroom. `limit + 1` is
|
|
97
|
+
* fetched so the caller can tell "exactly the limit" from "more", without a
|
|
98
|
+
* second COUNT(*) — a truncated set answering a set-property question needs that distinction available. */
|
|
128
99
|
export function nodesOfType(driver, type, limit) {
|
|
129
100
|
const rows = driver
|
|
130
101
|
.prepare(`SELECT ${NODE_COLUMNS} FROM nodes WHERE type = ? ORDER BY id ASC LIMIT ${Math.max(1, Math.floor(limit)) + 1}`)
|
|
@@ -132,23 +103,9 @@ export function nodesOfType(driver, type, limit) {
|
|
|
132
103
|
const truncated = rows.length > limit;
|
|
133
104
|
return { nodes: rows.slice(0, limit).map(toNode), truncated };
|
|
134
105
|
}
|
|
135
|
-
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* Deliberately returns **every** match rather than a best one. Two functions in
|
|
139
|
-
* a repository can legitimately share a name, and picking one by a heuristic —
|
|
140
|
-
* shortest path, most edges, first row — is how a caller ends up reasoning
|
|
141
|
-
* confidently about the wrong symbol. Ambiguity is the caller's to report, so
|
|
142
|
-
* the reader hands it over intact.
|
|
143
|
-
*
|
|
144
|
-
* `repo` narrows to nodes minted by a run recorded against that repository —
|
|
145
|
-
* a subquery against `adapter_runs`, since `nodes` itself carries no `repo`
|
|
146
|
-
* column (only `run_id`). Added for `descry-runtime`'s graph correlator: a
|
|
147
|
-
* multi-repo session (frontend + backend merged into one store, per DEC-228)
|
|
148
|
-
* makes a same-named symbol in the wrong repository a real candidate for a
|
|
149
|
-
* bare `findNodes({ name })` call, and nothing before this filtered it out.
|
|
150
|
-
* Omitted, this behaves exactly as before — existing callers are unaffected.
|
|
151
|
-
*/
|
|
106
|
+
/** Nodes matching a name and/or file — the "I know what it's called" lookup.
|
|
107
|
+
* Returns every match, never a best one: picking one by heuristic is how a
|
|
108
|
+
* caller reasons confidently about the wrong symbol. `repo` narrows via an adapter_runs subquery (nodes carries no repo column) — added for descry-runtime's multi-repo correlator (DEC-228); omitted, behaves exactly as before. */
|
|
152
109
|
export function findNodes(driver, criteria) {
|
|
153
110
|
const clauses = [];
|
|
154
111
|
const params = [];
|
|
@@ -173,13 +130,8 @@ export function findNodes(driver, criteria) {
|
|
|
173
130
|
.all(...params)
|
|
174
131
|
.map(toNode);
|
|
175
132
|
}
|
|
176
|
-
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* The cap is not optional politeness. The prior-art graphs on this machine have
|
|
180
|
-
* a max in-degree of 1,036 (`append`) — materialising every neighbour of a hub
|
|
181
|
-
* node during a traversal is how a 200-node budget turns into a 10,000-row read.
|
|
182
|
-
*/
|
|
133
|
+
/** Edges leaving a node, filtered by type and capped. Not optional politeness:
|
|
134
|
+
* a real graph's max in-degree of 1,036 turns a 200-node budget into a 10,000-row read without it. */
|
|
183
135
|
export function outgoing(driver, id, options = {}) {
|
|
184
136
|
return adjacency(driver, "source", id, options);
|
|
185
137
|
}
|
|
@@ -191,9 +143,8 @@ function adjacency(driver, column, id, options) {
|
|
|
191
143
|
const typeFilter = types === undefined || types.length === 0
|
|
192
144
|
? ""
|
|
193
145
|
: ` AND type IN (${types.map(() => "?").join(", ")})`;
|
|
194
|
-
// Ranked before truncation, so a cap keeps the most trustworthy neighbours
|
|
195
|
-
//
|
|
196
|
-
// ties so the result is stable across runs.
|
|
146
|
+
// Ranked before truncation, so a cap keeps the most trustworthy neighbours,
|
|
147
|
+
// not whichever rows the index reached first. `id` breaks ties for stability.
|
|
197
148
|
const sql = `SELECT ${EDGE_COLUMNS} FROM edges WHERE ${column} = ?${typeFilter}` +
|
|
198
149
|
` ORDER BY resolution DESC, confidence DESC, id ASC` +
|
|
199
150
|
(options.limit === undefined ? "" : ` LIMIT ${Math.max(0, Math.floor(options.limit))}`);
|
|
@@ -202,18 +153,9 @@ function adjacency(driver, column, id, options) {
|
|
|
202
153
|
.all(id, ...(types ?? []))
|
|
203
154
|
.map(toEdge);
|
|
204
155
|
}
|
|
205
|
-
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* `classified` (default `true`) restricts to `attrs IS NOT NULL` — rows with
|
|
209
|
-
* no `attrs` at all can never become a question (DEC-242: an unset
|
|
210
|
-
* `refusalClass` is never askable) and are always the majority of this table
|
|
211
|
-
* early in a producer's rollout — sherpa-frontend alone carries ~13,000. That
|
|
212
|
-
* filter is a real optimisation, not an approximation: it changes which rows
|
|
213
|
-
* are *materialised*, never which rows the grouper would have turned into a
|
|
214
|
-
* question. The unclassified count for disclosure is `counts(driver)
|
|
215
|
-
* .unresolvedRefs` minus this function's own row count, not recomputed here.
|
|
216
|
-
*/
|
|
156
|
+
/** Refusal-ledger rows for the question-grouping layer (DEC-243). `classified`
|
|
157
|
+
* (default true) restricts to `attrs IS NOT NULL` — rows with none can never
|
|
158
|
+
* become a question (DEC-242) and dominate early rollout (~13,000 on sherpa-frontend). A real optimisation, not an approximation: it never drops a groupable row. */
|
|
217
159
|
export function unresolvedRefs(driver, options = {}) {
|
|
218
160
|
const classified = options.classified ?? true;
|
|
219
161
|
const where = classified ? "WHERE attrs IS NOT NULL" : "";
|
|
@@ -234,18 +176,9 @@ export function counts(driver) {
|
|
|
234
176
|
runs: one("SELECT COUNT(*) AS n FROM adapter_runs"),
|
|
235
177
|
};
|
|
236
178
|
}
|
|
237
|
-
/**
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* This is the instrument for the determinism proof: ingesting the same batches
|
|
241
|
-
* in a permuted order must produce the same hash. Without it, "the graph does
|
|
242
|
-
* not depend on adapter ordering" is an assertion nobody can check, and by the
|
|
243
|
-
* time a real ordering dependency shows up it presents as an unreproducible
|
|
244
|
-
* difference in impact scores.
|
|
245
|
-
*
|
|
246
|
-
* `written_at` is excluded — a wall-clock stamp is not logical content, and
|
|
247
|
-
* including it would make the proof untestable rather than making it stronger.
|
|
248
|
-
*/
|
|
179
|
+
/** Hash of the store's logical content, independent of insertion order — the
|
|
180
|
+
* determinism proof's instrument (permuted-order ingestion must hash the
|
|
181
|
+
* same). `written_at` is excluded: a wall-clock stamp isn't logical content. */
|
|
249
182
|
export function contentHash(driver) {
|
|
250
183
|
const digest = createHash("sha256");
|
|
251
184
|
for (const table of [...DERIVED_TABLES, ...EARNED_TABLES].sort()) {
|