@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,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The call-recording schema — `ai-tool-contract.md` §6, rule 5: "every call is
|
|
3
|
+
* recorded" (§41.15), the basis of replay (`ai-layer-plan.md` §9 layer 6,
|
|
4
|
+
* §12's reproducibility requirement).
|
|
5
|
+
*
|
|
6
|
+
* A separate store from `../store` on purpose, not an extra table bolted onto
|
|
7
|
+
* the graph schema:
|
|
8
|
+
*
|
|
9
|
+
* 1. **The two version numbers move for unrelated reasons.** `IR_SCHEMA_VERSION`
|
|
10
|
+
* bumps when the graph's own shape changes; this schema bumps when the
|
|
11
|
+
* recording format changes. Coupling them would force a recording-format
|
|
12
|
+
* change to carry a graph rebuild, and vice versa.
|
|
13
|
+
* 2. **Nothing here is "derived."** DEC-017's derived/earned split exists
|
|
14
|
+
* because derived rows can be regenerated from source. A recorded call is a
|
|
15
|
+
* fact about one already-finished execution — there is no source to
|
|
16
|
+
* regenerate it from, ever. Every table below is earned in DEC-017's sense,
|
|
17
|
+
* and the version check refuses on mismatch rather than offering a
|
|
18
|
+
* `dropDerived()`-equivalent: there is nothing safe to drop.
|
|
19
|
+
* 3. Same reasoning DEC-018 gives for the graph store applies here unchanged:
|
|
20
|
+
* `node:sqlite` behind the existing `SqlDriver` interface, not a second
|
|
21
|
+
* persistence technology. This module imports the driver, it does not
|
|
22
|
+
* reinvent one.
|
|
23
|
+
*
|
|
24
|
+
* ## Unredacted material — read before wiring this to a live tool boundary
|
|
25
|
+
*
|
|
26
|
+
* Contract §6: redaction happens *at the tool boundary, before the model
|
|
27
|
+
* call*. **This store holds whatever `arguments` and `result` it is given,
|
|
28
|
+
* verbatim, unless a redactor was supplied.** `recordCall`'s `redact` option
|
|
29
|
+
* (`writer.ts`) is the seam; `redact.ts`'s `createRecordingRedactor` is a
|
|
30
|
+
* real, tested implementation of it, given the caller's own configured
|
|
31
|
+
* secret values. No live call site in this repo constructs and passes one
|
|
32
|
+
* today — recording is not yet wired into the MCP server's or
|
|
33
|
+
* `descry-runtime`'s actual tool dispatch — so every row written by this
|
|
34
|
+
* repo's current callers is still unredacted. Treat a database file under
|
|
35
|
+
* this schema as containing the same sensitive material the tool calls
|
|
36
|
+
* themselves carried, until whoever wires the live call path passes a
|
|
37
|
+
* redactor built from real secret values.
|
|
38
|
+
*/
|
|
39
|
+
export const RECORDING_SCHEMA_VERSION = 1;
|
|
40
|
+
export const SCHEMA_SQL = `
|
|
41
|
+
-- ---------------------------------------------------------------------------
|
|
42
|
+
-- recording_meta — same role as the graph store's graph_meta: identity of the
|
|
43
|
+
-- store itself, checked before anything else is trusted.
|
|
44
|
+
-- ---------------------------------------------------------------------------
|
|
45
|
+
CREATE TABLE IF NOT EXISTS recording_meta (
|
|
46
|
+
key TEXT PRIMARY KEY,
|
|
47
|
+
value TEXT NOT NULL
|
|
48
|
+
) STRICT;
|
|
49
|
+
|
|
50
|
+
-- ---------------------------------------------------------------------------
|
|
51
|
+
-- recorded_runs — one row per AI-layer run. The graph stamp (commit_sha,
|
|
52
|
+
-- built_at, ir_schema_version) is captured ONCE here, per §12: replay needs to
|
|
53
|
+
-- know what graph the run saw, not re-derive it from the first call.
|
|
54
|
+
--
|
|
55
|
+
-- prompt_version and model_id are present and nullable, never a column that
|
|
56
|
+
-- does not exist: §3's rule that "a missing field and a null field read
|
|
57
|
+
-- identically to a careless caller, and only one of them is honest" applies
|
|
58
|
+
-- to a database column exactly as it applies to the wire envelope. No model
|
|
59
|
+
-- calls exist yet in this repo, so both are null on every row written today —
|
|
60
|
+
-- that is a true statement about the current build, not a gap in the schema.
|
|
61
|
+
--
|
|
62
|
+
-- next_seq is the ordering counter writer.ts increments atomically with
|
|
63
|
+
-- every insert into recorded_calls, so "what order did these calls happen in"
|
|
64
|
+
-- is answerable without trusting wall-clock timestamps, which two calls in the
|
|
65
|
+
-- same millisecond cannot distinguish.
|
|
66
|
+
-- ---------------------------------------------------------------------------
|
|
67
|
+
CREATE TABLE IF NOT EXISTS recorded_runs (
|
|
68
|
+
id TEXT PRIMARY KEY,
|
|
69
|
+
started_at INTEGER NOT NULL,
|
|
70
|
+
commit_sha TEXT,
|
|
71
|
+
built_at TEXT,
|
|
72
|
+
ir_schema_version INTEGER,
|
|
73
|
+
prompt_version TEXT,
|
|
74
|
+
model_id TEXT,
|
|
75
|
+
next_seq INTEGER NOT NULL DEFAULT 0
|
|
76
|
+
) STRICT;
|
|
77
|
+
|
|
78
|
+
-- ---------------------------------------------------------------------------
|
|
79
|
+
-- recorded_calls — one row per tool call. (run_id, seq) is the primary key
|
|
80
|
+
-- rather than an autoincrement id: ordering within a run is the whole point of
|
|
81
|
+
-- seq, and a composite key makes "give me run X in order" a primary-key range
|
|
82
|
+
-- scan instead of a sort.
|
|
83
|
+
--
|
|
84
|
+
-- arguments and result are stored as canonicalJson of exactly what the
|
|
85
|
+
-- caller passed — the full envelope, not a summary. Dropping a field here
|
|
86
|
+
-- (say, disclosures, or the resolution level buried in graph) would make
|
|
87
|
+
-- this store unable to reproduce whatever the finding drew from that field,
|
|
88
|
+
-- which is the one failure mode replay exists to rule out.
|
|
89
|
+
-- ---------------------------------------------------------------------------
|
|
90
|
+
CREATE TABLE IF NOT EXISTS recorded_calls (
|
|
91
|
+
run_id TEXT NOT NULL REFERENCES recorded_runs(id) ON DELETE CASCADE,
|
|
92
|
+
seq INTEGER NOT NULL,
|
|
93
|
+
tool TEXT NOT NULL,
|
|
94
|
+
tool_version TEXT NOT NULL,
|
|
95
|
+
class TEXT NOT NULL,
|
|
96
|
+
arguments TEXT NOT NULL,
|
|
97
|
+
result TEXT NOT NULL,
|
|
98
|
+
duration_ms INTEGER NOT NULL,
|
|
99
|
+
cost REAL,
|
|
100
|
+
recorded_at INTEGER NOT NULL,
|
|
101
|
+
PRIMARY KEY (run_id, seq)
|
|
102
|
+
) STRICT;
|
|
103
|
+
`;
|
|
104
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/recording/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DzB,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recording a run and its calls — `ai-tool-contract.md` §6, rule 5 (§41.15).
|
|
3
|
+
*
|
|
4
|
+
* ## Ordering is a counter, not a clock
|
|
5
|
+
*
|
|
6
|
+
* Two calls can land in the same millisecond, so `recorded_at` cannot be the
|
|
7
|
+
* ordering key. `recorded_runs.next_seq` is incremented atomically with every
|
|
8
|
+
* insert into `recorded_calls`, in the same transaction, so "what order did
|
|
9
|
+
* these happen in" is answerable from the primary key alone — the property
|
|
10
|
+
* §12's replay requirement depends on ("same inputs + same recorded responses
|
|
11
|
+
* = the same finding, byte for byte" only holds if a replayer can tell what
|
|
12
|
+
* order to feed them back in).
|
|
13
|
+
*
|
|
14
|
+
* ## `recordCall` cannot change the tool's own return
|
|
15
|
+
*
|
|
16
|
+
* A caller is expected to call the real tool, get its result, and *then* call
|
|
17
|
+
* `recordCall` — recording is telemetry about a call that has already
|
|
18
|
+
* happened, never a gate on it. So `recordCall` never throws: every failure
|
|
19
|
+
* inside it — no such run, a driver error, `arguments`/`result` containing
|
|
20
|
+
* something `canonicalJson` refuses (a `bigint`, a top-level `undefined`) — is
|
|
21
|
+
* caught here and reported back as `{ recorded: false, error }`. A caller that
|
|
22
|
+
* ignores the return value still gets its tool result untouched. This is
|
|
23
|
+
* `CLAUDE.md`'s honest-degradation rule applied to the recorder itself: a
|
|
24
|
+
* failed recording is disclosed in the return value, never silent, and never
|
|
25
|
+
* fatal to the call it was recording.
|
|
26
|
+
*
|
|
27
|
+
* ## Redaction is a documented seam
|
|
28
|
+
*
|
|
29
|
+
* Contract §6 puts redaction at the tool boundary, before the model call.
|
|
30
|
+
* `RecordCallOptions.redact`, when supplied, runs on the call *before* it is
|
|
31
|
+
* serialised, so nothing unredacted ever reaches `canonicalJson` once a
|
|
32
|
+
* redactor is passed in. `./redact.ts`'s `createRecordingRedactor` is a real
|
|
33
|
+
* implementation of that seam, ported from the model-client redaction seam in
|
|
34
|
+
* descry-desktop — see its module header. It is still opt-in rather than
|
|
35
|
+
* automatic here: this module has no way to know a deployment's actual
|
|
36
|
+
* secret values on its own, only the caller does, so a caller must construct
|
|
37
|
+
* the redactor and pass it. **No caller in this repo does that yet** — the
|
|
38
|
+
* MCP server's tool dispatch and `descry-runtime`'s do not call `recordCall`
|
|
39
|
+
* at all today (that wiring is separate, P3-boundary work) — so every row
|
|
40
|
+
* this module writes today is still exactly what the tool call carried. See
|
|
41
|
+
* `schema.ts`'s module header before treating a recording database file as
|
|
42
|
+
* safe to hand around.
|
|
43
|
+
*/
|
|
44
|
+
import { type ToolClass } from "@descryy/ir";
|
|
45
|
+
import type { SqlDriver } from "../store/driver/driver.ts";
|
|
46
|
+
/**
|
|
47
|
+
* The graph stamp, captured once per run. `null` where the graph was not
|
|
48
|
+
* consulted — never omitted, for the same reason the wire envelope's
|
|
49
|
+
* `graph.resolutionFloor` is never absent (contract §3): a missing field and a
|
|
50
|
+
* null field read identically to a careless caller, and only one of them is
|
|
51
|
+
* honest about what this run actually saw.
|
|
52
|
+
*/
|
|
53
|
+
export interface RunStamp {
|
|
54
|
+
readonly commitSha: string | null;
|
|
55
|
+
readonly builtAt: string | null;
|
|
56
|
+
readonly irSchemaVersion: number | null;
|
|
57
|
+
}
|
|
58
|
+
export interface StartRunOptions {
|
|
59
|
+
/**
|
|
60
|
+
* §12: present and nullable, **and null on every row this store will ever
|
|
61
|
+
* hold.** That is a settled fact now, not a pending wiring job.
|
|
62
|
+
*
|
|
63
|
+
* This comment used to say a caller in `descry-desktop/packages/pipeline`
|
|
64
|
+
* would eventually pass a value here. It will not, and the reason is
|
|
65
|
+
* structural rather than a matter of scheduling: this is the **tool-call**
|
|
66
|
+
* recording store, and `descry-desktop` never calls into it — measured, a
|
|
67
|
+
* grep for `startRun(`, `recordCall(` and `readRun(` across every `src`
|
|
68
|
+
* directory in that repository returns no reference to this module. It
|
|
69
|
+
* records model calls in its own `model_recording_attempts` table
|
|
70
|
+
* (`packages/session/src/model-recording/`), which carries its own
|
|
71
|
+
* `prompt_version` column, **per attempt** — because one run of that
|
|
72
|
+
* pipeline renders eight distinct prompts, and one column once per run
|
|
73
|
+
* cannot carry eight values without inventing a summary of seven of them.
|
|
74
|
+
*
|
|
75
|
+
* The column stays. A store that records tool calls has an honest place to
|
|
76
|
+
* name the prompt a run was issued under, if this repository ever grows a
|
|
77
|
+
* caller that knows one. What it does not have is a caller today, and
|
|
78
|
+
* saying "until that wiring lands" implied one was on its way.
|
|
79
|
+
*
|
|
80
|
+
* Corrected by PF-1 of `documents/plans/prompt-fingerprinting.md`.
|
|
81
|
+
*/
|
|
82
|
+
readonly promptVersion?: string | null;
|
|
83
|
+
/** §12: present and nullable. No model layer exists yet, so always null today. */
|
|
84
|
+
readonly modelId?: string | null;
|
|
85
|
+
/** Injectable so determinism proofs are not at the mercy of the wall clock. */
|
|
86
|
+
readonly now?: () => number;
|
|
87
|
+
/** Injectable so determinism proofs are not at the mercy of `randomUUID`. */
|
|
88
|
+
readonly id?: () => string;
|
|
89
|
+
}
|
|
90
|
+
export declare function startRun(driver: SqlDriver, stamp: RunStamp, options?: StartRunOptions): {
|
|
91
|
+
runId: string;
|
|
92
|
+
};
|
|
93
|
+
/** One tool call, as the contract envelope defines it (§2, §6) — never a summary. */
|
|
94
|
+
export interface ToolCallRecord {
|
|
95
|
+
readonly tool: string;
|
|
96
|
+
readonly toolVersion: string;
|
|
97
|
+
readonly class: ToolClass;
|
|
98
|
+
/** The full arguments passed to the call. */
|
|
99
|
+
readonly arguments: unknown;
|
|
100
|
+
/** The full result envelope returned — every field, including `disclosures`. */
|
|
101
|
+
readonly result: unknown;
|
|
102
|
+
readonly durationMs: number;
|
|
103
|
+
/** No model calls exist yet in this repo — always `null` today. Never invented as 0. */
|
|
104
|
+
readonly cost: number | null;
|
|
105
|
+
}
|
|
106
|
+
export interface RecordCallOptions {
|
|
107
|
+
readonly now?: () => number;
|
|
108
|
+
/** The redaction seam — see this file's module header. */
|
|
109
|
+
readonly redact?: (call: ToolCallRecord) => ToolCallRecord;
|
|
110
|
+
}
|
|
111
|
+
export type RecordCallResult = {
|
|
112
|
+
readonly recorded: true;
|
|
113
|
+
readonly seq: number;
|
|
114
|
+
} | {
|
|
115
|
+
readonly recorded: false;
|
|
116
|
+
readonly error: unknown;
|
|
117
|
+
};
|
|
118
|
+
/** Record one call. Never throws — see this file's module header. */
|
|
119
|
+
export declare function recordCall(driver: SqlDriver, runId: string, call: ToolCallRecord, options?: RecordCallOptions): RecordCallResult;
|
|
120
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/recording/writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAGH,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,eAAoB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAsB7G;AAED,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,cAAc,CAAC;CAC5D;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1D,qEAAqE;AACrE,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,iBAAsB,GAC9B,gBAAgB,CAsClB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recording a run and its calls — `ai-tool-contract.md` §6, rule 5 (§41.15).
|
|
3
|
+
*
|
|
4
|
+
* ## Ordering is a counter, not a clock
|
|
5
|
+
*
|
|
6
|
+
* Two calls can land in the same millisecond, so `recorded_at` cannot be the
|
|
7
|
+
* ordering key. `recorded_runs.next_seq` is incremented atomically with every
|
|
8
|
+
* insert into `recorded_calls`, in the same transaction, so "what order did
|
|
9
|
+
* these happen in" is answerable from the primary key alone — the property
|
|
10
|
+
* §12's replay requirement depends on ("same inputs + same recorded responses
|
|
11
|
+
* = the same finding, byte for byte" only holds if a replayer can tell what
|
|
12
|
+
* order to feed them back in).
|
|
13
|
+
*
|
|
14
|
+
* ## `recordCall` cannot change the tool's own return
|
|
15
|
+
*
|
|
16
|
+
* A caller is expected to call the real tool, get its result, and *then* call
|
|
17
|
+
* `recordCall` — recording is telemetry about a call that has already
|
|
18
|
+
* happened, never a gate on it. So `recordCall` never throws: every failure
|
|
19
|
+
* inside it — no such run, a driver error, `arguments`/`result` containing
|
|
20
|
+
* something `canonicalJson` refuses (a `bigint`, a top-level `undefined`) — is
|
|
21
|
+
* caught here and reported back as `{ recorded: false, error }`. A caller that
|
|
22
|
+
* ignores the return value still gets its tool result untouched. This is
|
|
23
|
+
* `CLAUDE.md`'s honest-degradation rule applied to the recorder itself: a
|
|
24
|
+
* failed recording is disclosed in the return value, never silent, and never
|
|
25
|
+
* fatal to the call it was recording.
|
|
26
|
+
*
|
|
27
|
+
* ## Redaction is a documented seam
|
|
28
|
+
*
|
|
29
|
+
* Contract §6 puts redaction at the tool boundary, before the model call.
|
|
30
|
+
* `RecordCallOptions.redact`, when supplied, runs on the call *before* it is
|
|
31
|
+
* serialised, so nothing unredacted ever reaches `canonicalJson` once a
|
|
32
|
+
* redactor is passed in. `./redact.ts`'s `createRecordingRedactor` is a real
|
|
33
|
+
* implementation of that seam, ported from the model-client redaction seam in
|
|
34
|
+
* descry-desktop — see its module header. It is still opt-in rather than
|
|
35
|
+
* automatic here: this module has no way to know a deployment's actual
|
|
36
|
+
* secret values on its own, only the caller does, so a caller must construct
|
|
37
|
+
* the redactor and pass it. **No caller in this repo does that yet** — the
|
|
38
|
+
* MCP server's tool dispatch and `descry-runtime`'s do not call `recordCall`
|
|
39
|
+
* at all today (that wiring is separate, P3-boundary work) — so every row
|
|
40
|
+
* this module writes today is still exactly what the tool call carried. See
|
|
41
|
+
* `schema.ts`'s module header before treating a recording database file as
|
|
42
|
+
* safe to hand around.
|
|
43
|
+
*/
|
|
44
|
+
import { randomUUID } from "node:crypto";
|
|
45
|
+
import { canonicalJson } from "@descryy/ir";
|
|
46
|
+
export function startRun(driver, stamp, options = {}) {
|
|
47
|
+
const now = options.now ?? Date.now;
|
|
48
|
+
const mintId = options.id ?? (() => `run1:${randomUUID()}`);
|
|
49
|
+
const runId = mintId();
|
|
50
|
+
driver
|
|
51
|
+
.prepare(`INSERT INTO recorded_runs
|
|
52
|
+
(id, started_at, commit_sha, built_at, ir_schema_version, prompt_version, model_id, next_seq)
|
|
53
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 0)`)
|
|
54
|
+
.run(runId, now(), stamp.commitSha, stamp.builtAt, stamp.irSchemaVersion, options.promptVersion ?? null, options.modelId ?? null);
|
|
55
|
+
return { runId };
|
|
56
|
+
}
|
|
57
|
+
/** Record one call. Never throws — see this file's module header. */
|
|
58
|
+
export function recordCall(driver, runId, call, options = {}) {
|
|
59
|
+
try {
|
|
60
|
+
const now = options.now ?? Date.now;
|
|
61
|
+
return driver.transaction(() => {
|
|
62
|
+
const run = driver.prepare("SELECT next_seq FROM recorded_runs WHERE id = ?").get(runId);
|
|
63
|
+
if (run === undefined) {
|
|
64
|
+
throw new Error(`recordCall: no such run "${runId}" — startRun must be called first`);
|
|
65
|
+
}
|
|
66
|
+
const seq = run.next_seq;
|
|
67
|
+
const effective = options.redact ? options.redact(call) : call;
|
|
68
|
+
driver
|
|
69
|
+
.prepare(`INSERT INTO recorded_calls
|
|
70
|
+
(run_id, seq, tool, tool_version, class, arguments, result, duration_ms, cost, recorded_at)
|
|
71
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
72
|
+
.run(runId, seq, effective.tool, effective.toolVersion, effective.class, canonicalJson(effective.arguments), canonicalJson(effective.result), effective.durationMs, effective.cost, now());
|
|
73
|
+
driver.prepare("UPDATE recorded_runs SET next_seq = ? WHERE id = ?").run(seq + 1, runId);
|
|
74
|
+
return { recorded: true, seq };
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return { recorded: false, error };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/recording/writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC;AAkD5D,MAAM,UAAU,QAAQ,CAAC,MAAiB,EAAE,KAAe,EAAE,UAA2B,EAAE;IACxF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,UAAU,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;IAEvB,MAAM;SACH,OAAO,CACN;;uCAEiC,CAClC;SACA,GAAG,CACF,KAAK,EACL,GAAG,EAAE,EACL,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,eAAe,EACrB,OAAO,CAAC,aAAa,IAAI,IAAI,EAC7B,OAAO,CAAC,OAAO,IAAI,IAAI,CACxB,CAAC;IAEJ,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AA0BD,qEAAqE;AACrE,MAAM,UAAU,UAAU,CACxB,MAAiB,EACjB,KAAa,EACb,IAAoB,EACpB,UAA6B,EAAE;IAE/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAEpC,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAuB,iDAAiD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC/G,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,mCAAmC,CAAC,CAAC;YACxF,CAAC;YACD,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC;YACzB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAE/D,MAAM;iBACH,OAAO,CACN;;iDAEuC,CACxC;iBACA,GAAG,CACF,KAAK,EACL,GAAG,EACH,SAAS,CAAC,IAAI,EACd,SAAS,CAAC,WAAW,EACrB,SAAS,CAAC,KAAK,EACf,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,EAClC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,EAC/B,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,IAAI,EACd,GAAG,EAAE,CACN,CAAC;YAEJ,MAAM,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;YAEzF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAW,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan-out attenuation — DEC-067.
|
|
3
|
+
*
|
|
4
|
+
* ## The problem this solves, and the one it must not create
|
|
5
|
+
*
|
|
6
|
+
* A handful of declarations are depended on by everything: on one measured
|
|
7
|
+
* repository `Stage` has 186 dependents and `DocumentType` 165. Those
|
|
8
|
+
* dependencies are **real**, and the graph represents them at full weight. The
|
|
9
|
+
* damage is not in the edge, it is in what traversal does when it *passes
|
|
10
|
+
* through* such a node — one function's reference to an enum drags 164
|
|
11
|
+
* unrelated consumers into a blast radius they have nothing to do with.
|
|
12
|
+
*
|
|
13
|
+
* So the attenuation attaches to **expansion out of a hub**, never to the edge.
|
|
14
|
+
* Weighting the edge would penalise both directions, and only one of them is
|
|
15
|
+
* wrong:
|
|
16
|
+
*
|
|
17
|
+
* - **change `DocumentType`** — all 165 dependents genuinely break. Damping that
|
|
18
|
+
* makes Descry *understate* real impact, which is the opposite of the failure
|
|
19
|
+
* being fixed.
|
|
20
|
+
* - **change a function that references `DocumentType`** — the other 164
|
|
21
|
+
* consumers are unaffected, and pulling them in is noise.
|
|
22
|
+
*
|
|
23
|
+
* **The seed exemption is what separates those two cases**, and without it this
|
|
24
|
+
* module contradicts its own reason for existing. Seeds enter traversal at depth
|
|
25
|
+
* 0; attenuation applies only from depth 1 onward. A hub that was *changed* is
|
|
26
|
+
* never attenuated; a hub that was *reached* always is.
|
|
27
|
+
*
|
|
28
|
+
* ## Fan-out is not stored anywhere
|
|
29
|
+
*
|
|
30
|
+
* It is derived at traversal time from the adjacency already fetched, and is
|
|
31
|
+
* never written to a node, never part of identity, never hashed, never in a
|
|
32
|
+
* qualified symbol path, and never persisted (DEC-017's derived/earned split
|
|
33
|
+
* puts it firmly on the derived side — in fact it is not even that, it is not
|
|
34
|
+
* stored at all).
|
|
35
|
+
*
|
|
36
|
+
* ## Why the candidate count and not a separate in-degree query
|
|
37
|
+
*
|
|
38
|
+
* Traversal has already enumerated exactly the edges it would follow out of the
|
|
39
|
+
* current node. That count **is** the operational fan-out — the number of ways
|
|
40
|
+
* this node can explode — and it needs no second query, no index and no
|
|
41
|
+
* post-build pass. Defining fan-out as "edges expansion would follow" rather
|
|
42
|
+
* than as abstract in-degree also makes it the quantity that actually causes the
|
|
43
|
+
* dilution, rather than a proxy for it.
|
|
44
|
+
*
|
|
45
|
+
* One consequence has to be stated: `perNodeLimit` caps that enumeration, so a
|
|
46
|
+
* limit at or below the top boundary would understate a hub's fan-out and
|
|
47
|
+
* under-attenuate it. `validateScopingConfig` refuses that combination rather
|
|
48
|
+
* than silently mis-bucketing.
|
|
49
|
+
*
|
|
50
|
+
* ## Calibration
|
|
51
|
+
*
|
|
52
|
+
* Every number here is **provisional** (DEC-067). They are starting values from
|
|
53
|
+
* a single repository, chosen so that all four buckets are occupied — measured
|
|
54
|
+
* at 8.5% / 22.0% / 28.5% / 41.0% of `USES_TYPE` edges — which is the minimum
|
|
55
|
+
* property that makes the table worth having. They are to be tuned from real
|
|
56
|
+
* traversal data, like every other weight in §12.
|
|
57
|
+
*/
|
|
58
|
+
/** One band of the attenuation table. `upTo` is inclusive. */
|
|
59
|
+
export interface FanOutBucket {
|
|
60
|
+
/** Largest fan-out in this band. The final bucket uses `Infinity`. */
|
|
61
|
+
readonly upTo: number;
|
|
62
|
+
/** Multiplier applied to expansion out of a node in this band. */
|
|
63
|
+
readonly multiplier: number;
|
|
64
|
+
/** Human label, for explaining a score rather than for logic. */
|
|
65
|
+
readonly label: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* DEC-067's provisional table.
|
|
69
|
+
*
|
|
70
|
+
* `1.0` for the first band matters: an ordinary node must be completely
|
|
71
|
+
* unaffected, so that introducing this feature cannot move any score in a graph
|
|
72
|
+
* without hubs.
|
|
73
|
+
*/
|
|
74
|
+
export declare const DEFAULT_FANOUT_BUCKETS: readonly FanOutBucket[];
|
|
75
|
+
/** The bucket a fan-out falls in. Never undefined — the last bucket is open. */
|
|
76
|
+
export declare function bucketFor(fanOut: number, buckets?: readonly FanOutBucket[]): FanOutBucket;
|
|
77
|
+
/**
|
|
78
|
+
* The multiplier for expansion out of a node.
|
|
79
|
+
*
|
|
80
|
+
* `depth === 0` is the seed exemption and is checked here rather than at the
|
|
81
|
+
* call site, so the rule lives in one place and cannot be half-applied.
|
|
82
|
+
*/
|
|
83
|
+
export declare function attenuationFor(fanOut: number, depth: number, buckets?: readonly FanOutBucket[]): number;
|
|
84
|
+
/** The largest multiplier any bucket can apply — what termination must clear. */
|
|
85
|
+
export declare function maxAttenuation(buckets: readonly FanOutBucket[]): number;
|
|
86
|
+
//# sourceMappingURL=fanout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanout.d.ts","sourceRoot":"","sources":["../../src/scoping/fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,YAAY,EAKzD,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,SAAS,YAAY,EAA2B,GACxD,YAAY,CAMd;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,SAAS,YAAY,EAA2B,GACxD,MAAM,CAGR;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAEvE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan-out attenuation — DEC-067.
|
|
3
|
+
*
|
|
4
|
+
* ## The problem this solves, and the one it must not create
|
|
5
|
+
*
|
|
6
|
+
* A handful of declarations are depended on by everything: on one measured
|
|
7
|
+
* repository `Stage` has 186 dependents and `DocumentType` 165. Those
|
|
8
|
+
* dependencies are **real**, and the graph represents them at full weight. The
|
|
9
|
+
* damage is not in the edge, it is in what traversal does when it *passes
|
|
10
|
+
* through* such a node — one function's reference to an enum drags 164
|
|
11
|
+
* unrelated consumers into a blast radius they have nothing to do with.
|
|
12
|
+
*
|
|
13
|
+
* So the attenuation attaches to **expansion out of a hub**, never to the edge.
|
|
14
|
+
* Weighting the edge would penalise both directions, and only one of them is
|
|
15
|
+
* wrong:
|
|
16
|
+
*
|
|
17
|
+
* - **change `DocumentType`** — all 165 dependents genuinely break. Damping that
|
|
18
|
+
* makes Descry *understate* real impact, which is the opposite of the failure
|
|
19
|
+
* being fixed.
|
|
20
|
+
* - **change a function that references `DocumentType`** — the other 164
|
|
21
|
+
* consumers are unaffected, and pulling them in is noise.
|
|
22
|
+
*
|
|
23
|
+
* **The seed exemption is what separates those two cases**, and without it this
|
|
24
|
+
* module contradicts its own reason for existing. Seeds enter traversal at depth
|
|
25
|
+
* 0; attenuation applies only from depth 1 onward. A hub that was *changed* is
|
|
26
|
+
* never attenuated; a hub that was *reached* always is.
|
|
27
|
+
*
|
|
28
|
+
* ## Fan-out is not stored anywhere
|
|
29
|
+
*
|
|
30
|
+
* It is derived at traversal time from the adjacency already fetched, and is
|
|
31
|
+
* never written to a node, never part of identity, never hashed, never in a
|
|
32
|
+
* qualified symbol path, and never persisted (DEC-017's derived/earned split
|
|
33
|
+
* puts it firmly on the derived side — in fact it is not even that, it is not
|
|
34
|
+
* stored at all).
|
|
35
|
+
*
|
|
36
|
+
* ## Why the candidate count and not a separate in-degree query
|
|
37
|
+
*
|
|
38
|
+
* Traversal has already enumerated exactly the edges it would follow out of the
|
|
39
|
+
* current node. That count **is** the operational fan-out — the number of ways
|
|
40
|
+
* this node can explode — and it needs no second query, no index and no
|
|
41
|
+
* post-build pass. Defining fan-out as "edges expansion would follow" rather
|
|
42
|
+
* than as abstract in-degree also makes it the quantity that actually causes the
|
|
43
|
+
* dilution, rather than a proxy for it.
|
|
44
|
+
*
|
|
45
|
+
* One consequence has to be stated: `perNodeLimit` caps that enumeration, so a
|
|
46
|
+
* limit at or below the top boundary would understate a hub's fan-out and
|
|
47
|
+
* under-attenuate it. `validateScopingConfig` refuses that combination rather
|
|
48
|
+
* than silently mis-bucketing.
|
|
49
|
+
*
|
|
50
|
+
* ## Calibration
|
|
51
|
+
*
|
|
52
|
+
* Every number here is **provisional** (DEC-067). They are starting values from
|
|
53
|
+
* a single repository, chosen so that all four buckets are occupied — measured
|
|
54
|
+
* at 8.5% / 22.0% / 28.5% / 41.0% of `USES_TYPE` edges — which is the minimum
|
|
55
|
+
* property that makes the table worth having. They are to be tuned from real
|
|
56
|
+
* traversal data, like every other weight in §12.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* DEC-067's provisional table.
|
|
60
|
+
*
|
|
61
|
+
* `1.0` for the first band matters: an ordinary node must be completely
|
|
62
|
+
* unaffected, so that introducing this feature cannot move any score in a graph
|
|
63
|
+
* without hubs.
|
|
64
|
+
*/
|
|
65
|
+
export const DEFAULT_FANOUT_BUCKETS = [
|
|
66
|
+
{ upTo: 5, multiplier: 1.0, label: "local" },
|
|
67
|
+
{ upTo: 20, multiplier: 0.8, label: "shared" },
|
|
68
|
+
{ upTo: 50, multiplier: 0.5, label: "high fan-out" },
|
|
69
|
+
{ upTo: Number.POSITIVE_INFINITY, multiplier: 0.25, label: "hub" },
|
|
70
|
+
];
|
|
71
|
+
/** The bucket a fan-out falls in. Never undefined — the last bucket is open. */
|
|
72
|
+
export function bucketFor(fanOut, buckets = DEFAULT_FANOUT_BUCKETS) {
|
|
73
|
+
for (const bucket of buckets) {
|
|
74
|
+
if (fanOut <= bucket.upTo)
|
|
75
|
+
return bucket;
|
|
76
|
+
}
|
|
77
|
+
// Unreachable when the table is validated, since the last `upTo` is Infinity.
|
|
78
|
+
return buckets[buckets.length - 1];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The multiplier for expansion out of a node.
|
|
82
|
+
*
|
|
83
|
+
* `depth === 0` is the seed exemption and is checked here rather than at the
|
|
84
|
+
* call site, so the rule lives in one place and cannot be half-applied.
|
|
85
|
+
*/
|
|
86
|
+
export function attenuationFor(fanOut, depth, buckets = DEFAULT_FANOUT_BUCKETS) {
|
|
87
|
+
if (depth === 0)
|
|
88
|
+
return 1;
|
|
89
|
+
return bucketFor(fanOut, buckets).multiplier;
|
|
90
|
+
}
|
|
91
|
+
/** The largest multiplier any bucket can apply — what termination must clear. */
|
|
92
|
+
export function maxAttenuation(buckets) {
|
|
93
|
+
return buckets.reduce((largest, bucket) => Math.max(largest, bucket.multiplier), 0);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=fanout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanout.js","sourceRoot":"","sources":["../../src/scoping/fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAYH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA4B;IAC7D,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;IAC5C,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC9C,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE;IACpD,EAAE,IAAI,EAAE,MAAM,CAAC,iBAAiB,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE;CACnE,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,SAAS,CACvB,MAAc,EACd,UAAmC,sBAAsB;IAEzD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,MAAM,CAAC;IAC3C,CAAC;IACD,8EAA8E;IAC9E,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,KAAa,EACb,UAAmC,sBAAsB;IAEzD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC;AAC/C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,OAAgC;IAC7D,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { DEFAULT_EDGE_WEIGHTS, DEFAULT_SCOPING_CONFIG, validateScopingConfig, ScopingConfigError, } from "./weights.ts";
|
|
2
|
+
export type { ScopingConfig } from "./weights.ts";
|
|
3
|
+
export { attenuationFor, bucketFor, maxAttenuation, DEFAULT_FANOUT_BUCKETS, } from "./fanout.ts";
|
|
4
|
+
export type { FanOutBucket } from "./fanout.ts";
|
|
5
|
+
export { HistoryFactors, hopDecay, finalScore, maxBoost } from "./score.ts";
|
|
6
|
+
export { NODE_BUDGETS, TIER_THRESHOLDS, tierFor } from "./tiers.ts";
|
|
7
|
+
export type { ScopeTier, Trigger } from "./tiers.ts";
|
|
8
|
+
export { scopeChange } from "./traverse.ts";
|
|
9
|
+
export type { Scope, ScopedNode, ScopeOptions } from "./traverse.ts";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scoping/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EACL,cAAc,EACd,SAAS,EACT,cAAc,EACd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACpE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DEFAULT_EDGE_WEIGHTS, DEFAULT_SCOPING_CONFIG, validateScopingConfig, ScopingConfigError, } from "./weights.js";
|
|
2
|
+
export { attenuationFor, bucketFor, maxAttenuation, DEFAULT_FANOUT_BUCKETS, } from "./fanout.js";
|
|
3
|
+
export { HistoryFactors, hopDecay, finalScore, maxBoost } from "./score.js";
|
|
4
|
+
export { NODE_BUDGETS, TIER_THRESHOLDS, tierFor } from "./tiers.js";
|
|
5
|
+
export { scopeChange } from "./traverse.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scoping/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,cAAc,EACd,SAAS,EACT,cAAc,EACd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The impact score — §12.4.
|
|
3
|
+
*
|
|
4
|
+
* NewScore = ParentScore × EdgeWeight × ChangeCouplingFactor
|
|
5
|
+
* × IncidentCorrelationFactor × EdgeConfidence
|
|
6
|
+
*
|
|
7
|
+
* Both history factors **default to 1.0** so a brand-new file, or a repo with no
|
|
8
|
+
* logged incidents, is not unfairly under-scored. `EdgeConfidence` defaults to
|
|
9
|
+
* the edge's own value, which is 1.0 for a well-resolved adapter — so in a clean
|
|
10
|
+
* R3 repository the last three terms vanish and the formula is just weight
|
|
11
|
+
* decay. They do their work in a degraded one, which is the point.
|
|
12
|
+
*
|
|
13
|
+
* **The formula is applied in two parts, not as one product per hop.** Path
|
|
14
|
+
* decay uses only `EdgeWeight × EdgeConfidence`, which is strictly below 1 and
|
|
15
|
+
* therefore always terminates; the two history factors are applied once to a
|
|
16
|
+
* node's final score. See the long note in `weights.ts` for why the literal
|
|
17
|
+
* per-hop form cannot hold alongside §12.3 and §12.7, and DEC-037 for the
|
|
18
|
+
* decision. The short version: compounding a node's incident history at every
|
|
19
|
+
* hop of a path that merely passes through it counts the same evidence
|
|
20
|
+
* repeatedly.
|
|
21
|
+
*/
|
|
22
|
+
import type { IREdge } from "@descryy/ir";
|
|
23
|
+
import type { AdjacencyProvider } from "../query/provider.ts";
|
|
24
|
+
import type { ScopingConfig } from "./weights.ts";
|
|
25
|
+
/**
|
|
26
|
+
* Per-node history factors, computed once and cached.
|
|
27
|
+
*
|
|
28
|
+
* Both are looked up on the node being *entered*, not on the edge: "this file
|
|
29
|
+
* has been involved in incidents" and "this file moves with the change" are
|
|
30
|
+
* properties of the destination, and computing them per edge would multiply the
|
|
31
|
+
* same boost in twice for a node reached two ways.
|
|
32
|
+
*/
|
|
33
|
+
export declare class HistoryFactors {
|
|
34
|
+
#private;
|
|
35
|
+
constructor(provider: AdjacencyProvider, config: ScopingConfig, seeds: ReadonlySet<string>);
|
|
36
|
+
/**
|
|
37
|
+
* §12.4's `ChangeCouplingFactor`, from `CHANGES_WITH` edges (§11.7).
|
|
38
|
+
*
|
|
39
|
+
* Boosts a node that historically moves with something in the diff. Two things
|
|
40
|
+
* make this narrower than it first appears, and both are honest limits rather
|
|
41
|
+
* than bugs:
|
|
42
|
+
*
|
|
43
|
+
* - `CHANGES_WITH` is **file-to-file**, so this only fires for `FILE` nodes.
|
|
44
|
+
* A `FUNCTION` never has co-change history of its own.
|
|
45
|
+
* - The edge is stored in one canonical direction (DEC-036), so both
|
|
46
|
+
* directions must be read. This is the one edge type where `outgoing` alone
|
|
47
|
+
* is wrong.
|
|
48
|
+
*/
|
|
49
|
+
couplingFor(nodeId: string): number;
|
|
50
|
+
/**
|
|
51
|
+
* §12.4's `IncidentCorrelationFactor`, from `INCIDENT_CORRELATED` edges (§11.6).
|
|
52
|
+
*
|
|
53
|
+
* Saturating rather than linear: the third incident on a file says much less
|
|
54
|
+
* than the first, and an unbounded count would let one pathological file
|
|
55
|
+
* dominate every blast radius it appears in.
|
|
56
|
+
*/
|
|
57
|
+
incidentFor(nodeId: string): number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The per-hop decay: `EdgeWeight × EdgeConfidence`, and nothing else.
|
|
61
|
+
*
|
|
62
|
+
* Strictly below 1 for any valid configuration, so the path score decreases
|
|
63
|
+
* monotonically and traversal terminates on any graph, cyclic or not. That is
|
|
64
|
+
* the whole termination argument, and it does not depend on what the history
|
|
65
|
+
* factors happen to be — which is what makes it a guarantee rather than a hope.
|
|
66
|
+
*/
|
|
67
|
+
export declare function hopDecay(edge: IREdge, config: ScopingConfig): number;
|
|
68
|
+
/**
|
|
69
|
+
* A node's final score: its best path decay, adjusted once by its own history.
|
|
70
|
+
*
|
|
71
|
+
* Capped at `maxScore` because §12.7 tiers on absolute thresholds — a boosted
|
|
72
|
+
* score above 1.0 would put a two-hop node above the diff itself.
|
|
73
|
+
*/
|
|
74
|
+
export declare function finalScore(pathScore: number, nodeId: string, config: ScopingConfig, history: HistoryFactors): number;
|
|
75
|
+
/**
|
|
76
|
+
* The largest amount any node's score can be raised by history.
|
|
77
|
+
*
|
|
78
|
+
* Pruning happens on the *unboosted* path score, so the prune point must be
|
|
79
|
+
* lowered by this much — otherwise a node that would clear the threshold once
|
|
80
|
+
* boosted is discarded before its boost is ever computed.
|
|
81
|
+
*/
|
|
82
|
+
export declare function maxBoost(config: ScopingConfig): number;
|
|
83
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/scoping/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAY,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;GAOG;AACH,qBAAa,cAAc;;gBAOb,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;IAM1F;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAwBnC;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAUpC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,GACtB,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEtD"}
|