@skill-map/cli 0.56.0 → 0.57.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/cli/tutorial/sm-tutorial/references/part-cli.md +1 -1
- package/dist/cli.js +969 -912
- package/dist/index.js +120 -33
- package/dist/kernel/index.d.ts +139 -63
- package/dist/kernel/index.js +120 -33
- package/dist/migrations/001_initial.sql +45 -0
- package/dist/ui/{chunk-W3Z3CZL4.js → chunk-5MK5Y6FQ.js} +2 -2
- package/dist/ui/{chunk-GHOVZAAV.js → chunk-EEDP2D5A.js} +1 -1
- package/dist/ui/chunk-EL6RUV24.js +3 -0
- package/dist/ui/chunk-P3SSH5JE.js +1 -0
- package/dist/ui/{chunk-DWBJCNC7.js → chunk-PTNXJKIX.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-PL3BEVQI.js → main-ZNXBC7R5.js} +3 -3
- package/migrations/001_initial.sql +45 -0
- package/package.json +2 -2
- package/dist/ui/chunk-4ITL7E6U.js +0 -1
- package/dist/ui/chunk-VUNP5KNI.js +0 -3
package/dist/kernel/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// kernel/i18n/registry.texts.ts
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="12d40092-5030-5aa9-ba9b-939af94ed740")}catch(e){}}();
|
|
4
4
|
var REGISTRY_TEXTS = {
|
|
5
5
|
duplicateExtension: "Extension already registered: {{kind}}:{{qualifiedId}}",
|
|
6
6
|
unknownKind: "Unknown extension kind: {{kind}}",
|
|
@@ -102,7 +102,7 @@ import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
|
|
|
102
102
|
// package.json
|
|
103
103
|
var package_default = {
|
|
104
104
|
name: "@skill-map/cli",
|
|
105
|
-
version: "0.
|
|
105
|
+
version: "0.57.0",
|
|
106
106
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
107
107
|
license: "MIT",
|
|
108
108
|
type: "module",
|
|
@@ -1269,8 +1269,49 @@ function runActionProjections(actions, nodes, links, emitter) {
|
|
|
1269
1269
|
return { contributions, contributionErrors };
|
|
1270
1270
|
}
|
|
1271
1271
|
|
|
1272
|
+
// kernel/orchestrator/confidence-score.ts
|
|
1273
|
+
function foldConfidence(base, ops) {
|
|
1274
|
+
let running = base;
|
|
1275
|
+
for (const op of ops) {
|
|
1276
|
+
if (op.kind === "set") running = op.value;
|
|
1277
|
+
}
|
|
1278
|
+
for (const op of ops) {
|
|
1279
|
+
if (op.kind === "delta") running += op.value;
|
|
1280
|
+
}
|
|
1281
|
+
for (const op of ops) {
|
|
1282
|
+
if (op.kind === "floor") running = Math.max(running, op.value);
|
|
1283
|
+
}
|
|
1284
|
+
for (const op of ops) {
|
|
1285
|
+
if (op.kind === "ceil") running = Math.min(running, op.value);
|
|
1286
|
+
}
|
|
1287
|
+
return clamp01(running);
|
|
1288
|
+
}
|
|
1289
|
+
function clamp01(n) {
|
|
1290
|
+
if (n < 0) return 0;
|
|
1291
|
+
if (n > 1) return 1;
|
|
1292
|
+
return n;
|
|
1293
|
+
}
|
|
1294
|
+
function applyConfidenceAdjustments(adjustments) {
|
|
1295
|
+
if (adjustments.length === 0) return;
|
|
1296
|
+
const byLink = /* @__PURE__ */ new Map();
|
|
1297
|
+
for (const adj of adjustments) {
|
|
1298
|
+
const bucket = byLink.get(adj.link);
|
|
1299
|
+
if (bucket) bucket.push(adj);
|
|
1300
|
+
else byLink.set(adj.link, [adj]);
|
|
1301
|
+
}
|
|
1302
|
+
for (const [link, adjs] of byLink) {
|
|
1303
|
+
const ops = [...adjs].sort(compareAdjustments).map((a) => a.op);
|
|
1304
|
+
link.confidence = foldConfidence(link.confidence, ops);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function compareAdjustments(a, b) {
|
|
1308
|
+
if (a.pluginId !== b.pluginId) return a.pluginId < b.pluginId ? -1 : 1;
|
|
1309
|
+
if (a.extensionId !== b.extensionId) return a.extensionId < b.extensionId ? -1 : 1;
|
|
1310
|
+
return 0;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1272
1313
|
// kernel/orchestrator/analyzers.ts
|
|
1273
|
-
async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions,
|
|
1314
|
+
async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths, brokenLinks, nameCollisions, signals, seedIssues = []) {
|
|
1274
1315
|
const issues = [...seedIssues];
|
|
1275
1316
|
const contributions = [];
|
|
1276
1317
|
const contributionErrors = [];
|
|
@@ -1281,7 +1322,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1281
1322
|
expectedMdPath: o.expectedMdPath
|
|
1282
1323
|
}));
|
|
1283
1324
|
const scheduled = orderAnalyzersByPhase(analyzers);
|
|
1325
|
+
const scoreAdjustments = [];
|
|
1326
|
+
const scorableLinks = new Set(internalLinks);
|
|
1327
|
+
let scoresFolded = false;
|
|
1328
|
+
const foldScores = () => {
|
|
1329
|
+
if (scoresFolded) return;
|
|
1330
|
+
scoresFolded = true;
|
|
1331
|
+
applyConfidenceAdjustments(scoreAdjustments);
|
|
1332
|
+
};
|
|
1284
1333
|
for (const analyzer of scheduled) {
|
|
1334
|
+
if (analyzer.phase !== "score") foldScores();
|
|
1285
1335
|
const qualifiedId = qualifiedExtensionId(analyzer.pluginId, analyzer.id);
|
|
1286
1336
|
const declaredContributions = readDeclaredContributionRefs(analyzer);
|
|
1287
1337
|
const emitContribution = (nodePath, ref, payload) => {
|
|
@@ -1344,6 +1394,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1344
1394
|
emittedAt: Date.now()
|
|
1345
1395
|
});
|
|
1346
1396
|
};
|
|
1397
|
+
const adjustConfidence = analyzer.phase === "score" ? (link, op) => {
|
|
1398
|
+
if (scorableLinks.has(link)) {
|
|
1399
|
+
scoreAdjustments.push({
|
|
1400
|
+
link,
|
|
1401
|
+
pluginId: analyzer.pluginId,
|
|
1402
|
+
extensionId: analyzer.id,
|
|
1403
|
+
op
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
} : void 0;
|
|
1347
1407
|
const emitted = await analyzer.evaluate({
|
|
1348
1408
|
nodes,
|
|
1349
1409
|
links: internalLinks,
|
|
@@ -1355,7 +1415,6 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1355
1415
|
sidecarRoots,
|
|
1356
1416
|
annotationContributions,
|
|
1357
1417
|
viewContributions,
|
|
1358
|
-
orphanJobFiles,
|
|
1359
1418
|
// `issues` is the live accumulator, mutated by `issues.push(...)`
|
|
1360
1419
|
// below as each analyzer's emission lands. Late-phase analyzers
|
|
1361
1420
|
// (`core/issue-counter`) read it to compute cross-analyzer
|
|
@@ -1365,7 +1424,9 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1365
1424
|
...cwd ? { cwd } : {},
|
|
1366
1425
|
...reservedNodePaths ? { reservedNodePaths } : {},
|
|
1367
1426
|
...brokenLinks ? { brokenLinks } : {},
|
|
1427
|
+
...nameCollisions && nameCollisions.size > 0 ? { nameCollisions } : {},
|
|
1368
1428
|
...signals && signals.length > 0 ? { signals } : {},
|
|
1429
|
+
...adjustConfidence ? { adjustConfidence } : {},
|
|
1369
1430
|
emitContribution
|
|
1370
1431
|
});
|
|
1371
1432
|
for (const issue of emitted) {
|
|
@@ -1376,13 +1437,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1376
1437
|
emitter.emit(evt);
|
|
1377
1438
|
await hookDispatcher.dispatch("analyzer.completed", evt);
|
|
1378
1439
|
}
|
|
1379
|
-
|
|
1440
|
+
foldScores();
|
|
1441
|
+
return { issues, contributions, contributionErrors, linkScores: scoreAdjustments };
|
|
1380
1442
|
}
|
|
1381
1443
|
function orderAnalyzersByPhase(analyzers) {
|
|
1382
1444
|
return analyzers.slice().sort((a, b) => phaseRank(a) - phaseRank(b));
|
|
1383
1445
|
}
|
|
1384
1446
|
function phaseRank(a) {
|
|
1385
|
-
|
|
1447
|
+
if (a.phase === "score") return 0;
|
|
1448
|
+
if (a.phase === "aggregate") return 2;
|
|
1449
|
+
return 1;
|
|
1386
1450
|
}
|
|
1387
1451
|
function validateIssue(analyzer, issue, emitter) {
|
|
1388
1452
|
const severity = issue.severity;
|
|
@@ -1405,6 +1469,13 @@ function validateIssue(analyzer, issue, emitter) {
|
|
|
1405
1469
|
return { ...issue, analyzerId: issue.analyzerId || analyzer.id };
|
|
1406
1470
|
}
|
|
1407
1471
|
|
|
1472
|
+
// kernel/orchestrator/frontmatter-issue-ids.ts
|
|
1473
|
+
var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
|
|
1474
|
+
"frontmatter-invalid",
|
|
1475
|
+
"frontmatter-malformed",
|
|
1476
|
+
"frontmatter-parse-error"
|
|
1477
|
+
]);
|
|
1478
|
+
|
|
1408
1479
|
// kernel/orchestrator/cache.ts
|
|
1409
1480
|
function indexPriorSnapshot(prior) {
|
|
1410
1481
|
const priorNodesByPath = /* @__PURE__ */ new Map();
|
|
@@ -1433,17 +1504,6 @@ function indexPriorLinks(links, priorNodePaths, byOriginating) {
|
|
|
1433
1504
|
else byOriginating.set(key, [link]);
|
|
1434
1505
|
}
|
|
1435
1506
|
}
|
|
1436
|
-
var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
|
|
1437
|
-
"frontmatter-invalid",
|
|
1438
|
-
"frontmatter-malformed",
|
|
1439
|
-
// Audit L1: parser parse-error is emitted by
|
|
1440
|
-
// `buildFreshNodeAndValidateFrontmatter` from `raw.parseIssues`. The
|
|
1441
|
-
// raw.parseIssues only flows through the non-cache path; a cached
|
|
1442
|
-
// node skips the rebuild, so the prior issue MUST survive the
|
|
1443
|
-
// incremental scan or the warning silently disappears on a clean
|
|
1444
|
-
// re-scan of an unchanged file.
|
|
1445
|
-
"frontmatter-parse-error"
|
|
1446
|
-
]);
|
|
1447
1507
|
function indexPriorFrontmatterIssues(issues, byNode) {
|
|
1448
1508
|
for (const issue of issues) {
|
|
1449
1509
|
if (!FRONTMATTER_ISSUE_ANALYZERS.has(issue.analyzerId)) continue;
|
|
@@ -1641,15 +1701,47 @@ function readDirname(node) {
|
|
|
1641
1701
|
const base = pathPosix.basename(dir);
|
|
1642
1702
|
return base.length > 0 ? base : null;
|
|
1643
1703
|
}
|
|
1704
|
+
function collectNameCollisions(nodes, kindRegistry) {
|
|
1705
|
+
const byName = indexNameClaims(nodes, kindRegistry);
|
|
1706
|
+
const collisions = /* @__PURE__ */ new Map();
|
|
1707
|
+
for (const [name, claims] of byName) {
|
|
1708
|
+
const distinct = dedupeClaimsByPath(claims);
|
|
1709
|
+
if (distinct.length >= 2) collisions.set(name, distinct);
|
|
1710
|
+
}
|
|
1711
|
+
return collisions;
|
|
1712
|
+
}
|
|
1713
|
+
function indexNameClaims(nodes, kindRegistry) {
|
|
1714
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1715
|
+
for (const node of nodes) {
|
|
1716
|
+
const name = resolvableName(node, kindRegistry);
|
|
1717
|
+
if (name === null) continue;
|
|
1718
|
+
const bucket = byName.get(name) ?? [];
|
|
1719
|
+
bucket.push({ path: node.path, kind: node.kind });
|
|
1720
|
+
byName.set(name, bucket);
|
|
1721
|
+
}
|
|
1722
|
+
return byName;
|
|
1723
|
+
}
|
|
1724
|
+
function resolvableName(node, kindRegistry) {
|
|
1725
|
+
const descriptor = kindRegistry.get(`${node.provider}/${node.kind}`);
|
|
1726
|
+
if (!descriptor?.identifiers?.includes("frontmatter.name")) return null;
|
|
1727
|
+
const raw = node.frontmatter?.["name"];
|
|
1728
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
1729
|
+
const normalised = normalizeTrigger(raw);
|
|
1730
|
+
return normalised.length > 0 ? normalised : null;
|
|
1731
|
+
}
|
|
1732
|
+
function dedupeClaimsByPath(claims) {
|
|
1733
|
+
return [...new Map(claims.map((c) => [c.path, c])).values()].sort(
|
|
1734
|
+
(a, b) => a.path.localeCompare(b.path)
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1644
1737
|
|
|
1645
1738
|
// kernel/orchestrator/lift-resolved-link-confidence.ts
|
|
1646
|
-
var RESERVED_TARGET_CONFIDENCE = 0.1;
|
|
1647
|
-
var BROKEN_TARGET_CONFIDENCE = 0.5;
|
|
1648
1739
|
function liftResolvedLinkConfidence(links, nodes, ctx) {
|
|
1649
|
-
if (
|
|
1740
|
+
if (links.length === 0) return;
|
|
1650
1741
|
const indexes = buildIndexes(nodes, ctx);
|
|
1651
1742
|
for (const link of links) {
|
|
1652
|
-
|
|
1743
|
+
link.confidence = 1;
|
|
1744
|
+
applyResolution(link, indexes, ctx);
|
|
1653
1745
|
}
|
|
1654
1746
|
}
|
|
1655
1747
|
function collectBrokenLinks(links, nodes, ctx) {
|
|
@@ -1663,15 +1755,8 @@ function collectBrokenLinks(links, nodes, ctx) {
|
|
|
1663
1755
|
}
|
|
1664
1756
|
function applyResolution(link, indexes, ctx) {
|
|
1665
1757
|
const resolution = resolve5(link, indexes, ctx);
|
|
1666
|
-
if (resolution === "none")
|
|
1667
|
-
if (isGenuinelyBroken(link, indexes)) {
|
|
1668
|
-
link.confidence = Math.min(link.confidence, BROKEN_TARGET_CONFIDENCE);
|
|
1669
|
-
}
|
|
1670
|
-
return;
|
|
1671
|
-
}
|
|
1758
|
+
if (resolution === "none") return;
|
|
1672
1759
|
link.resolvedTarget = resolution;
|
|
1673
|
-
if (indexes.nodeByPath.get(resolution)?.virtual) return;
|
|
1674
|
-
link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
|
|
1675
1760
|
}
|
|
1676
1761
|
function buildIndexes(nodes, ctx) {
|
|
1677
1762
|
const byPath2 = /* @__PURE__ */ new Set();
|
|
@@ -3143,6 +3228,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
3143
3228
|
const postWalkCtx = buildPostWalkTransformCtx(exts.providers, walked.nodes, activeProviderId);
|
|
3144
3229
|
walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
|
|
3145
3230
|
const brokenLinks = collectBrokenLinks(walked.internalLinks, walked.nodes, postWalkCtx);
|
|
3231
|
+
const nameCollisions = collectNameCollisions(walked.nodes, postWalkCtx.kindRegistry);
|
|
3146
3232
|
recomputeLinkCounts(walked.nodes, walked.internalLinks);
|
|
3147
3233
|
recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
|
|
3148
3234
|
await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
|
|
@@ -3157,7 +3243,6 @@ async function runScanInternal(_kernel, options) {
|
|
|
3157
3243
|
walked.sidecarRoots,
|
|
3158
3244
|
options.annotationContributions ?? [],
|
|
3159
3245
|
options.viewContributions ?? [],
|
|
3160
|
-
options.orphanJobFiles ?? [],
|
|
3161
3246
|
options.referenceablePaths,
|
|
3162
3247
|
options.cwd,
|
|
3163
3248
|
registeredActionIds,
|
|
@@ -3165,6 +3250,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
3165
3250
|
hookDispatcher,
|
|
3166
3251
|
postWalkCtx.reservedNodePaths,
|
|
3167
3252
|
brokenLinks,
|
|
3253
|
+
nameCollisions,
|
|
3168
3254
|
walked.signals,
|
|
3169
3255
|
// Seed the accumulator with orchestrator-emitted frontmatter
|
|
3170
3256
|
// issues so the aggregate phase (`core/issue-counter`) counts
|
|
@@ -3187,7 +3273,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
3187
3273
|
const scanCompletedEvent = makeEvent("scan.completed", { stats });
|
|
3188
3274
|
emitter.emit(scanCompletedEvent);
|
|
3189
3275
|
await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
|
|
3190
|
-
return buildScanReturn(walked, issues, renameOps, stats, options, setup);
|
|
3276
|
+
return buildScanReturn(walked, issues, renameOps, stats, options, setup, analyzerResult.linkScores);
|
|
3191
3277
|
}
|
|
3192
3278
|
function buildPostWalkTransformCtx(providers, nodes, activeProvider) {
|
|
3193
3279
|
const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(providers);
|
|
@@ -3315,7 +3401,7 @@ function buildScanStats(walked, issues, start) {
|
|
|
3315
3401
|
durationMs: Date.now() - start
|
|
3316
3402
|
};
|
|
3317
3403
|
}
|
|
3318
|
-
function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
3404
|
+
function buildScanReturn(walked, issues, renameOps, stats, options, setup, linkScores) {
|
|
3319
3405
|
return {
|
|
3320
3406
|
result: {
|
|
3321
3407
|
schemaVersion: 1,
|
|
@@ -3337,6 +3423,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
|
3337
3423
|
enrichments: walked.enrichments,
|
|
3338
3424
|
contributions: walked.contributions,
|
|
3339
3425
|
contributionErrors: walked.contributionErrors,
|
|
3426
|
+
linkScores,
|
|
3340
3427
|
freshlyRunTuples: walked.freshlyRunTuples
|
|
3341
3428
|
};
|
|
3342
3429
|
}
|
|
@@ -3766,4 +3853,4 @@ export {
|
|
|
3766
3853
|
runScanWithRenames
|
|
3767
3854
|
};
|
|
3768
3855
|
//# sourceMappingURL=index.js.map
|
|
3769
|
-
//# debugId=
|
|
3856
|
+
//# debugId=12d40092-5030-5aa9-ba9b-939af94ed740
|
|
@@ -472,6 +472,51 @@ CREATE TABLE scan_contribution_errors (
|
|
|
472
472
|
CREATE INDEX ix_scan_contribution_errors_plugin_id ON scan_contribution_errors(plugin_id);
|
|
473
473
|
CREATE INDEX ix_scan_contribution_errors_node_path ON scan_contribution_errors(node_path);
|
|
474
474
|
|
|
475
|
+
-- scan_link_scores: per-op confidence-attribution audit trail. One row
|
|
476
|
+
-- per attributed `ctx.adjustConfidence(link, op)` call buffered by a
|
|
477
|
+
-- `score`-phase analyzer during the scan (the kernel's own built-in
|
|
478
|
+
-- `core/name-reserved` / `core/reference-broken` detectors dogfood the
|
|
479
|
+
-- API, applying penalty deltas on top of the kernel's 1.0 baseline). Lets
|
|
480
|
+
-- an operator answer "why is this link at 0.3?" by listing the plugin /
|
|
481
|
+
-- extension / op that moved it, with the FOLDED final value denormalised
|
|
482
|
+
-- onto every row (`result_confidence` mirrors `scan_links.confidence`).
|
|
483
|
+
--
|
|
484
|
+
-- The link is identified by its structural identity fields
|
|
485
|
+
-- (`source_path`, `target`, `kind`, `normalized_trigger`), the same key
|
|
486
|
+
-- `scan_links` dedups on; `normalized_trigger` is NULL for path-style
|
|
487
|
+
-- links that carry no trigger. `op_kind` is the algebra bucket
|
|
488
|
+
-- (`set` / `delta` / `ceil` / `floor`) and `op_value` its operand.
|
|
489
|
+
--
|
|
490
|
+
-- Belongs to the `scan_*` family. Plain REPLACE-ALL per scan (delete
|
|
491
|
+
-- all, then insert), the same posture as `scan_issues` and
|
|
492
|
+
-- `scan_contribution_errors` — NOT the sweep model `scan_contributions`
|
|
493
|
+
-- uses. A score adjustment is a transient scan finding re-derived in
|
|
494
|
+
-- full on every analyzer pass, so there is no cached-node row to
|
|
495
|
+
-- preserve and no compound PK (multiple ops can land on one link). Index
|
|
496
|
+
-- on `source_path` for the per-node "why this link?" lookup + the rename
|
|
497
|
+
-- heuristic-adjacent reads.
|
|
498
|
+
CREATE TABLE scan_link_scores (
|
|
499
|
+
plugin_id TEXT NOT NULL,
|
|
500
|
+
extension_id TEXT NOT NULL,
|
|
501
|
+
source_path TEXT NOT NULL,
|
|
502
|
+
target TEXT NOT NULL,
|
|
503
|
+
kind TEXT NOT NULL,
|
|
504
|
+
-- NULL for path-style links that carry no trigger (the structural
|
|
505
|
+
-- identity key mirrors `scan_links`'s dedup tuple).
|
|
506
|
+
normalized_trigger TEXT,
|
|
507
|
+
-- Confidence-algebra bucket: `set` / `delta` / `ceil` / `floor`. Kept
|
|
508
|
+
-- open at the SQL layer (no CHECK) so the op catalog can evolve as a
|
|
509
|
+
-- kernel + spec change without a DDL migration.
|
|
510
|
+
op_kind TEXT NOT NULL,
|
|
511
|
+
op_value REAL NOT NULL,
|
|
512
|
+
-- Denormalised FOLDED final `link.confidence` after every op for this
|
|
513
|
+
-- link was applied. Equal across all rows for one link; carried per
|
|
514
|
+
-- row so the audit read needs no join back to `scan_links`.
|
|
515
|
+
result_confidence REAL NOT NULL,
|
|
516
|
+
emitted_at INTEGER NOT NULL
|
|
517
|
+
);
|
|
518
|
+
CREATE INDEX ix_scan_link_scores_source_path ON scan_link_scores(source_path);
|
|
519
|
+
|
|
475
520
|
-- scan_node_tags: tag system. One row per (node_path, tag) pair.
|
|
476
521
|
-- Projected at persist time from `sidecar.annotations.tags`. Tags are
|
|
477
522
|
-- a skill-map concept (no vendor carries `tags` in frontmatter), so the
|