@skill-map/cli 0.55.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 +2108 -1477
- package/dist/index.js +140 -33
- package/dist/kernel/index.d.ts +181 -66
- package/dist/kernel/index.js +140 -33
- package/dist/migrations/001_initial.sql +45 -0
- package/dist/ui/chunk-5MK5Y6FQ.js +1844 -0
- package/dist/ui/{chunk-LREXXX7T.js → chunk-EEDP2D5A.js} +1 -1
- package/dist/ui/chunk-EL6RUV24.js +3 -0
- package/dist/ui/{chunk-GBKHMJ4B.js → chunk-H6O2DYVT.js} +13 -13
- package/dist/ui/chunk-HDKR6XHG.js +917 -0
- package/dist/ui/{chunk-GEI6INVH.js → chunk-JA4Z74I3.js} +1 -1
- package/dist/ui/chunk-P3SSH5JE.js +1 -0
- package/dist/ui/chunk-PTNXJKIX.js +2 -0
- package/dist/ui/chunk-RS3ANRT5.js +1 -0
- package/dist/ui/chunk-YHJL5LP3.js +913 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/{main-7YXBWYHE.js → main-ZNXBC7R5.js} +3 -3
- package/dist/ui/{styles-HRJG67XW.css → styles-RHEEXRHQ.css} +1 -1
- package/migrations/001_initial.sql +45 -0
- package/package.json +2 -2
- package/dist/ui/chunk-CN6IOM67.js +0 -2
- package/dist/ui/chunk-HPKRDGLH.js +0 -123
- package/dist/ui/chunk-JXRIGHET.js +0 -552
- package/dist/ui/chunk-RGB5FBZL.js +0 -2205
- package/dist/ui/chunk-WFLPMCK4.js +0 -392
- package/dist/ui/chunk-XAM6VKXM.js +0 -1
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",
|
|
@@ -745,6 +745,10 @@ function matchesFilter(hook, event) {
|
|
|
745
745
|
function buildHookContext(_hook, trigger, event) {
|
|
746
746
|
const data = event.data ?? {};
|
|
747
747
|
const ctx = {
|
|
748
|
+
// `settings` is always populated (possibly empty) so hooks can read
|
|
749
|
+
// `ctx.settings.<id>` without a presence check. The composer
|
|
750
|
+
// populated `resolvedSettings` on each composed hook.
|
|
751
|
+
settings: _hook.resolvedSettings ?? {},
|
|
748
752
|
event: {
|
|
749
753
|
type: trigger,
|
|
750
754
|
timestamp: event.timestamp,
|
|
@@ -1265,8 +1269,49 @@ function runActionProjections(actions, nodes, links, emitter) {
|
|
|
1265
1269
|
return { contributions, contributionErrors };
|
|
1266
1270
|
}
|
|
1267
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
|
+
|
|
1268
1313
|
// kernel/orchestrator/analyzers.ts
|
|
1269
|
-
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 = []) {
|
|
1270
1315
|
const issues = [...seedIssues];
|
|
1271
1316
|
const contributions = [];
|
|
1272
1317
|
const contributionErrors = [];
|
|
@@ -1277,7 +1322,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1277
1322
|
expectedMdPath: o.expectedMdPath
|
|
1278
1323
|
}));
|
|
1279
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
|
+
};
|
|
1280
1333
|
for (const analyzer of scheduled) {
|
|
1334
|
+
if (analyzer.phase !== "score") foldScores();
|
|
1281
1335
|
const qualifiedId = qualifiedExtensionId(analyzer.pluginId, analyzer.id);
|
|
1282
1336
|
const declaredContributions = readDeclaredContributionRefs(analyzer);
|
|
1283
1337
|
const emitContribution = (nodePath, ref, payload) => {
|
|
@@ -1340,14 +1394,27 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1340
1394
|
emittedAt: Date.now()
|
|
1341
1395
|
});
|
|
1342
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;
|
|
1343
1407
|
const emitted = await analyzer.evaluate({
|
|
1344
1408
|
nodes,
|
|
1345
1409
|
links: internalLinks,
|
|
1410
|
+
// `settings` is always populated (possibly empty) so analyzers can
|
|
1411
|
+
// read `ctx.settings.<id>` without a presence check. The composer
|
|
1412
|
+
// populated `resolvedSettings` on each composed analyzer.
|
|
1413
|
+
settings: analyzer.resolvedSettings ?? {},
|
|
1346
1414
|
orphanSidecars: analyzerOrphans,
|
|
1347
1415
|
sidecarRoots,
|
|
1348
1416
|
annotationContributions,
|
|
1349
1417
|
viewContributions,
|
|
1350
|
-
orphanJobFiles,
|
|
1351
1418
|
// `issues` is the live accumulator, mutated by `issues.push(...)`
|
|
1352
1419
|
// below as each analyzer's emission lands. Late-phase analyzers
|
|
1353
1420
|
// (`core/issue-counter`) read it to compute cross-analyzer
|
|
@@ -1356,7 +1423,10 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1356
1423
|
...referenceablePaths ? { referenceablePaths } : {},
|
|
1357
1424
|
...cwd ? { cwd } : {},
|
|
1358
1425
|
...reservedNodePaths ? { reservedNodePaths } : {},
|
|
1426
|
+
...brokenLinks ? { brokenLinks } : {},
|
|
1427
|
+
...nameCollisions && nameCollisions.size > 0 ? { nameCollisions } : {},
|
|
1359
1428
|
...signals && signals.length > 0 ? { signals } : {},
|
|
1429
|
+
...adjustConfidence ? { adjustConfidence } : {},
|
|
1360
1430
|
emitContribution
|
|
1361
1431
|
});
|
|
1362
1432
|
for (const issue of emitted) {
|
|
@@ -1367,13 +1437,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
|
|
|
1367
1437
|
emitter.emit(evt);
|
|
1368
1438
|
await hookDispatcher.dispatch("analyzer.completed", evt);
|
|
1369
1439
|
}
|
|
1370
|
-
|
|
1440
|
+
foldScores();
|
|
1441
|
+
return { issues, contributions, contributionErrors, linkScores: scoreAdjustments };
|
|
1371
1442
|
}
|
|
1372
1443
|
function orderAnalyzersByPhase(analyzers) {
|
|
1373
1444
|
return analyzers.slice().sort((a, b) => phaseRank(a) - phaseRank(b));
|
|
1374
1445
|
}
|
|
1375
1446
|
function phaseRank(a) {
|
|
1376
|
-
|
|
1447
|
+
if (a.phase === "score") return 0;
|
|
1448
|
+
if (a.phase === "aggregate") return 2;
|
|
1449
|
+
return 1;
|
|
1377
1450
|
}
|
|
1378
1451
|
function validateIssue(analyzer, issue, emitter) {
|
|
1379
1452
|
const severity = issue.severity;
|
|
@@ -1396,6 +1469,13 @@ function validateIssue(analyzer, issue, emitter) {
|
|
|
1396
1469
|
return { ...issue, analyzerId: issue.analyzerId || analyzer.id };
|
|
1397
1470
|
}
|
|
1398
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
|
+
|
|
1399
1479
|
// kernel/orchestrator/cache.ts
|
|
1400
1480
|
function indexPriorSnapshot(prior) {
|
|
1401
1481
|
const priorNodesByPath = /* @__PURE__ */ new Map();
|
|
@@ -1424,17 +1504,6 @@ function indexPriorLinks(links, priorNodePaths, byOriginating) {
|
|
|
1424
1504
|
else byOriginating.set(key, [link]);
|
|
1425
1505
|
}
|
|
1426
1506
|
}
|
|
1427
|
-
var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
|
|
1428
|
-
"frontmatter-invalid",
|
|
1429
|
-
"frontmatter-malformed",
|
|
1430
|
-
// Audit L1: parser parse-error is emitted by
|
|
1431
|
-
// `buildFreshNodeAndValidateFrontmatter` from `raw.parseIssues`. The
|
|
1432
|
-
// raw.parseIssues only flows through the non-cache path; a cached
|
|
1433
|
-
// node skips the rebuild, so the prior issue MUST survive the
|
|
1434
|
-
// incremental scan or the warning silently disappears on a clean
|
|
1435
|
-
// re-scan of an unchanged file.
|
|
1436
|
-
"frontmatter-parse-error"
|
|
1437
|
-
]);
|
|
1438
1507
|
function indexPriorFrontmatterIssues(issues, byNode) {
|
|
1439
1508
|
for (const issue of issues) {
|
|
1440
1509
|
if (!FRONTMATTER_ISSUE_ANALYZERS.has(issue.analyzerId)) continue;
|
|
@@ -1632,28 +1701,62 @@ function readDirname(node) {
|
|
|
1632
1701
|
const base = pathPosix.basename(dir);
|
|
1633
1702
|
return base.length > 0 ? base : null;
|
|
1634
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
|
+
}
|
|
1635
1737
|
|
|
1636
1738
|
// kernel/orchestrator/lift-resolved-link-confidence.ts
|
|
1637
|
-
var RESERVED_TARGET_CONFIDENCE = 0.1;
|
|
1638
|
-
var BROKEN_TARGET_CONFIDENCE = 0.5;
|
|
1639
1739
|
function liftResolvedLinkConfidence(links, nodes, ctx) {
|
|
1640
|
-
if (
|
|
1740
|
+
if (links.length === 0) return;
|
|
1641
1741
|
const indexes = buildIndexes(nodes, ctx);
|
|
1642
1742
|
for (const link of links) {
|
|
1643
|
-
|
|
1743
|
+
link.confidence = 1;
|
|
1744
|
+
applyResolution(link, indexes, ctx);
|
|
1644
1745
|
}
|
|
1645
1746
|
}
|
|
1747
|
+
function collectBrokenLinks(links, nodes, ctx) {
|
|
1748
|
+
const broken = /* @__PURE__ */ new Set();
|
|
1749
|
+
if (links.length === 0) return broken;
|
|
1750
|
+
const indexes = buildIndexes(nodes, ctx);
|
|
1751
|
+
for (const link of links) {
|
|
1752
|
+
if (isGenuinelyBroken(link, indexes)) broken.add(link);
|
|
1753
|
+
}
|
|
1754
|
+
return broken;
|
|
1755
|
+
}
|
|
1646
1756
|
function applyResolution(link, indexes, ctx) {
|
|
1647
1757
|
const resolution = resolve5(link, indexes, ctx);
|
|
1648
|
-
if (resolution === "none")
|
|
1649
|
-
if (isGenuinelyBroken(link, indexes)) {
|
|
1650
|
-
link.confidence = Math.min(link.confidence, BROKEN_TARGET_CONFIDENCE);
|
|
1651
|
-
}
|
|
1652
|
-
return;
|
|
1653
|
-
}
|
|
1758
|
+
if (resolution === "none") return;
|
|
1654
1759
|
link.resolvedTarget = resolution;
|
|
1655
|
-
if (indexes.nodeByPath.get(resolution)?.virtual) return;
|
|
1656
|
-
link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
|
|
1657
1760
|
}
|
|
1658
1761
|
function buildIndexes(nodes, ctx) {
|
|
1659
1762
|
const byPath2 = /* @__PURE__ */ new Set();
|
|
@@ -3124,6 +3227,8 @@ async function runScanInternal(_kernel, options) {
|
|
|
3124
3227
|
walked.signals = resolved.resolvedSignals;
|
|
3125
3228
|
const postWalkCtx = buildPostWalkTransformCtx(exts.providers, walked.nodes, activeProviderId);
|
|
3126
3229
|
walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
|
|
3230
|
+
const brokenLinks = collectBrokenLinks(walked.internalLinks, walked.nodes, postWalkCtx);
|
|
3231
|
+
const nameCollisions = collectNameCollisions(walked.nodes, postWalkCtx.kindRegistry);
|
|
3127
3232
|
recomputeLinkCounts(walked.nodes, walked.internalLinks);
|
|
3128
3233
|
recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
|
|
3129
3234
|
await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
|
|
@@ -3138,13 +3243,14 @@ async function runScanInternal(_kernel, options) {
|
|
|
3138
3243
|
walked.sidecarRoots,
|
|
3139
3244
|
options.annotationContributions ?? [],
|
|
3140
3245
|
options.viewContributions ?? [],
|
|
3141
|
-
options.orphanJobFiles ?? [],
|
|
3142
3246
|
options.referenceablePaths,
|
|
3143
3247
|
options.cwd,
|
|
3144
3248
|
registeredActionIds,
|
|
3145
3249
|
emitter,
|
|
3146
3250
|
hookDispatcher,
|
|
3147
3251
|
postWalkCtx.reservedNodePaths,
|
|
3252
|
+
brokenLinks,
|
|
3253
|
+
nameCollisions,
|
|
3148
3254
|
walked.signals,
|
|
3149
3255
|
// Seed the accumulator with orchestrator-emitted frontmatter
|
|
3150
3256
|
// issues so the aggregate phase (`core/issue-counter`) counts
|
|
@@ -3167,7 +3273,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
3167
3273
|
const scanCompletedEvent = makeEvent("scan.completed", { stats });
|
|
3168
3274
|
emitter.emit(scanCompletedEvent);
|
|
3169
3275
|
await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
|
|
3170
|
-
return buildScanReturn(walked, issues, renameOps, stats, options, setup);
|
|
3276
|
+
return buildScanReturn(walked, issues, renameOps, stats, options, setup, analyzerResult.linkScores);
|
|
3171
3277
|
}
|
|
3172
3278
|
function buildPostWalkTransformCtx(providers, nodes, activeProvider) {
|
|
3173
3279
|
const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(providers);
|
|
@@ -3295,7 +3401,7 @@ function buildScanStats(walked, issues, start) {
|
|
|
3295
3401
|
durationMs: Date.now() - start
|
|
3296
3402
|
};
|
|
3297
3403
|
}
|
|
3298
|
-
function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
3404
|
+
function buildScanReturn(walked, issues, renameOps, stats, options, setup, linkScores) {
|
|
3299
3405
|
return {
|
|
3300
3406
|
result: {
|
|
3301
3407
|
schemaVersion: 1,
|
|
@@ -3317,6 +3423,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
|
3317
3423
|
enrichments: walked.enrichments,
|
|
3318
3424
|
contributions: walked.contributions,
|
|
3319
3425
|
contributionErrors: walked.contributionErrors,
|
|
3426
|
+
linkScores,
|
|
3320
3427
|
freshlyRunTuples: walked.freshlyRunTuples
|
|
3321
3428
|
};
|
|
3322
3429
|
}
|
|
@@ -3746,4 +3853,4 @@ export {
|
|
|
3746
3853
|
runScanWithRenames
|
|
3747
3854
|
};
|
|
3748
3855
|
//# sourceMappingURL=index.js.map
|
|
3749
|
-
//# 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
|