@productbrain/mcp 0.0.1-beta.3391 → 0.0.1-beta.3399
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.
|
@@ -11756,11 +11756,87 @@ async function handleAuditRun(entryId, phase) {
|
|
|
11756
11756
|
};
|
|
11757
11757
|
}
|
|
11758
11758
|
|
|
11759
|
+
// src/tools/spine-check.ts
|
|
11760
|
+
async function handleSpineCheck(story, refresh = false) {
|
|
11761
|
+
const scheduleResult = await kernelMutation(
|
|
11762
|
+
"quality.scheduleSpineCheck",
|
|
11763
|
+
{ includeStory: story, refresh }
|
|
11764
|
+
);
|
|
11765
|
+
const row = await kernelQuery("quality.getLatestSpineVerdict", {});
|
|
11766
|
+
const stillRunning = scheduleResult.scheduled;
|
|
11767
|
+
if (!row) {
|
|
11768
|
+
const text = stillRunning ? "Spine check started \u2014 no prior result exists yet. It runs asynchronously (LLM calls can take 25s+ each); re-run this in a few seconds to read the result." : "No spine check has been run yet, and none is currently running. Pass refresh:true to start one.";
|
|
11769
|
+
return {
|
|
11770
|
+
content: [{ type: "text", text }],
|
|
11771
|
+
structuredContent: success(text, { hasVerdict: false, checkStarted: stillRunning })
|
|
11772
|
+
};
|
|
11773
|
+
}
|
|
11774
|
+
const { verdict } = row;
|
|
11775
|
+
if (verdict.noSpineEntries) {
|
|
11776
|
+
return {
|
|
11777
|
+
content: [{ type: "text", text: "No spine entries yet \u2014 nothing to check." }],
|
|
11778
|
+
structuredContent: success("No spine entries yet.", { hasVerdict: true, noSpineEntries: true })
|
|
11779
|
+
};
|
|
11780
|
+
}
|
|
11781
|
+
const lines = ["## Spine Check"];
|
|
11782
|
+
if (stillRunning) {
|
|
11783
|
+
lines.push(`> A new check was just triggered and is still running asynchronously \u2014 the result below is from the PREVIOUS run (${new Date(row.createdAt).toISOString()}). Re-run in a few seconds for the fresh result.`, "");
|
|
11784
|
+
} else if (scheduleResult.reason === "already-in-flight") {
|
|
11785
|
+
lines.push(`> A check is already running (started earlier, not by this call) \u2014 showing the best available result (${new Date(row.createdAt).toISOString()}). Re-run in a few seconds.`, "");
|
|
11786
|
+
} else if (row.stale) {
|
|
11787
|
+
lines.push(`> STALE \u2014 ${row.staleMemberIds.length} member entry(ies) changed since this was computed. Pass refresh:true to recompute.`, "");
|
|
11788
|
+
}
|
|
11789
|
+
const s = verdict.structural;
|
|
11790
|
+
lines.push(`Structural completeness: ${s.passed ? "PASS" : "FAIL"}`);
|
|
11791
|
+
if (s.missing.length > 0) lines.push(`Missing: ${s.missing.join(", ")}`);
|
|
11792
|
+
if (s.duplicateSingletons.purpose) lines.push(`Duplicate purpose singletons (which is canonical?): ${s.duplicateSingletons.purpose.join(", ")}`);
|
|
11793
|
+
if (s.duplicateSingletons.vision) lines.push(`Duplicate vision singletons (which is canonical?): ${s.duplicateSingletons.vision.join(", ")}`);
|
|
11794
|
+
if (s.unconnectedStrategyIds.length > 0) lines.push(`Unconnected strategies (no informs edge to any vision): ${s.unconnectedStrategyIds.join(", ")}`);
|
|
11795
|
+
if ((s.strategiesWithUnknownConnectivity ?? []).length > 0) {
|
|
11796
|
+
lines.push(`Connectivity unknown (relation set truncated \u2014 not confirmed disconnected): ${s.strategiesWithUnknownConnectivity.join(", ")}`);
|
|
11797
|
+
}
|
|
11798
|
+
if (s.visionConnectedToPurpose === false) lines.push("No vision informs any purpose.");
|
|
11799
|
+
if (s.visionPurposeConnectivityTruncated) lines.push("Vision\u2192purpose connectivity unknown (relation set truncated).");
|
|
11800
|
+
if (verdict.strategiesTruncated) lines.push("Strategy set truncated \u2014 not every strategy was graded this pass.");
|
|
11801
|
+
if (verdict.perStrategy.length > 0) {
|
|
11802
|
+
lines.push("", `Per-strategy refusal heuristic (${verdict.perStrategy.length}):`);
|
|
11803
|
+
for (const p of verdict.perStrategy) {
|
|
11804
|
+
const refusal = p.refusal.hasRefusalSignal ? "names an explicit alternative it declines" : "no explicit refusal language detected";
|
|
11805
|
+
const rm = p.rogerMartin ? `; Roger Martin test: ${p.rogerMartin.isStrategicChoice ? "genuine strategic choice" : "NOT a genuine strategic choice"}` : "; Roger Martin test: FAILED TO EVALUATE (timeout, budget limit, or malformed response) \u2014 not scored";
|
|
11806
|
+
lines.push(`- ${p.entryId}: ${refusal}${rm}`);
|
|
11807
|
+
}
|
|
11808
|
+
}
|
|
11809
|
+
if (verdict.story) {
|
|
11810
|
+
lines.push("", `One-story judgment [unvalidated, on-demand]: ${verdict.story.passed ? "PASS" : "FAIL"}`);
|
|
11811
|
+
if (!verdict.story.passed && verdict.story.failedCriterion) lines.push(`Failed criterion: ${verdict.story.failedCriterion}`);
|
|
11812
|
+
} else if (row.includesStoryPass) {
|
|
11813
|
+
lines.push("", "One-story judgment: requested, but the LLM pass did not return a usable result (timeout or parse failure). Re-run to retry.");
|
|
11814
|
+
} else {
|
|
11815
|
+
lines.push("", "One-story judgment: not run this pass \u2014 pass story=true to run it.");
|
|
11816
|
+
}
|
|
11817
|
+
return {
|
|
11818
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
11819
|
+
structuredContent: success(
|
|
11820
|
+
`Spine check: structural ${s.passed ? "PASS" : "FAIL"}${verdict.story ? `, story ${verdict.story.passed ? "PASS" : "FAIL"} [unvalidated]` : ""}${stillRunning ? " (new run still in progress \u2014 showing previous result)" : ""}.`,
|
|
11821
|
+
{
|
|
11822
|
+
hasVerdict: true,
|
|
11823
|
+
noSpineEntries: false,
|
|
11824
|
+
structuralPassed: s.passed,
|
|
11825
|
+
storyPassed: verdict.story?.passed ?? null,
|
|
11826
|
+
stale: row.stale,
|
|
11827
|
+
stillRunning,
|
|
11828
|
+
scheduled: scheduleResult.scheduled,
|
|
11829
|
+
scheduleReason: scheduleResult.reason
|
|
11830
|
+
}
|
|
11831
|
+
)
|
|
11832
|
+
};
|
|
11833
|
+
}
|
|
11834
|
+
|
|
11759
11835
|
// src/tools/quality.ts
|
|
11760
|
-
var QUALITY_ACTIONS = ["check", "re-evaluate", "verify-chain", "audit"];
|
|
11836
|
+
var QUALITY_ACTIONS = ["check", "re-evaluate", "verify-chain", "audit", "spine-check"];
|
|
11761
11837
|
var qualitySchema = z22.object({
|
|
11762
11838
|
action: z22.enum(QUALITY_ACTIONS).describe(
|
|
11763
|
-
"'check': read the entry's server quality verdict (tier + criteria). 're-evaluate': trigger fresh evaluation. 'verify-chain': verify entries against the codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. 'audit': hygiene audit for a bet entry \u2014 absorbs `audit`."
|
|
11839
|
+
"'check': read the entry's server quality verdict (tier + criteria). 're-evaluate': trigger fresh evaluation. 'verify-chain': verify entries against the codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. 'audit': hygiene audit for a bet entry \u2014 absorbs `audit`. 'spine-check': structural completeness of the purpose+vision+strategy spine \u2014 story:true also runs the on-demand one-story judgment."
|
|
11764
11840
|
),
|
|
11765
11841
|
entryId: z22.string().max(200).optional().describe("For 'check'/'re-evaluate'/'audit': entry ID, e.g. 'TEN-graph-db', '<PREFIX>-<n>'."),
|
|
11766
11842
|
context: z22.enum(["capture", "commit", "review"]).default("review").optional().describe("For re-evaluate: evaluation context"),
|
|
@@ -11768,6 +11844,10 @@ var qualitySchema = z22.object({
|
|
|
11768
11844
|
mode: z22.enum(["report", "fix"]).optional().describe("For 'verify-chain': 'report' = read-only trust report (default). 'fix' = also update drifted codeMapping statuses."),
|
|
11769
11845
|
phase: z22.enum(["shaping", "handoff"]).optional().describe(
|
|
11770
11846
|
"For 'audit': 'shaping' checks shaping-phase fields only (default). 'handoff' checks all required fields including buildContract/buildSequence/exclusions/risks."
|
|
11847
|
+
),
|
|
11848
|
+
story: z22.boolean().optional().describe("For 'spine-check': also run the on-demand one-story LLM judgment (never scheduled; result labelled [unvalidated])."),
|
|
11849
|
+
refresh: z22.boolean().optional().describe(
|
|
11850
|
+
"For 'spine-check': force a new run even if a fresh verdict already exists. Default false \u2014 a plain call NEVER re-triggers work just to read the last result; it auto-schedules only when no run is already in flight AND the stored verdict is absent/stale/missing the requested story pass."
|
|
11771
11851
|
)
|
|
11772
11852
|
});
|
|
11773
11853
|
var qualityCheckVariant = z22.object({ action: z22.literal("check"), entryId: z22.string().max(200) });
|
|
@@ -11786,17 +11866,24 @@ var qualityAuditVariant = z22.object({
|
|
|
11786
11866
|
entryId: z22.string().max(200),
|
|
11787
11867
|
phase: z22.enum(["shaping", "handoff"]).optional().default("shaping")
|
|
11788
11868
|
});
|
|
11869
|
+
var qualitySpineCheckVariant = z22.object({
|
|
11870
|
+
action: z22.literal("spine-check"),
|
|
11871
|
+
story: z22.boolean().optional().default(false),
|
|
11872
|
+
refresh: z22.boolean().optional().default(false)
|
|
11873
|
+
});
|
|
11789
11874
|
var qualityActionUnion = z22.discriminatedUnion("action", [
|
|
11790
11875
|
qualityCheckVariant,
|
|
11791
11876
|
qualityReEvaluateVariant,
|
|
11792
11877
|
qualityVerifyChainVariant,
|
|
11793
|
-
qualityAuditVariant
|
|
11878
|
+
qualityAuditVariant,
|
|
11879
|
+
qualitySpineCheckVariant
|
|
11794
11880
|
]);
|
|
11795
11881
|
var QUALITY_ACTION_SPECS = {
|
|
11796
11882
|
check: { params: ["entryId"], description: "entryId is required." },
|
|
11797
11883
|
"re-evaluate": { params: ["entryId", "context"], description: "entryId is required." },
|
|
11798
11884
|
"verify-chain": { params: ["collection", "mode"], description: "All params optional; collection defaults to 'glossary'." },
|
|
11799
|
-
audit: { params: ["entryId", "phase"], description: "entryId is required." }
|
|
11885
|
+
audit: { params: ["entryId", "phase"], description: "entryId is required." },
|
|
11886
|
+
"spine-check": { params: ["story", "refresh"], description: "All params optional; story and refresh default to false \u2014 a plain call never re-triggers work, it just reads back the latest verdict (auto-refreshing only when stale/absent)." }
|
|
11800
11887
|
};
|
|
11801
11888
|
var qualityCheckOutputSchema = z22.object({
|
|
11802
11889
|
entryId: z22.string(),
|
|
@@ -11820,18 +11907,26 @@ var qualityReevaluateOutputSchema = z22.object({
|
|
|
11820
11907
|
maxScore: z22.number(),
|
|
11821
11908
|
improved: z22.boolean()
|
|
11822
11909
|
});
|
|
11910
|
+
var qualitySpineCheckOutputSchema = z22.object({
|
|
11911
|
+
hasVerdict: z22.boolean(),
|
|
11912
|
+
noSpineEntries: z22.boolean().optional(),
|
|
11913
|
+
structuralPassed: z22.boolean().optional(),
|
|
11914
|
+
storyPassed: z22.boolean().nullable().optional(),
|
|
11915
|
+
stale: z22.boolean().optional()
|
|
11916
|
+
});
|
|
11823
11917
|
function registerQualityTools(server) {
|
|
11824
11918
|
const qualityHandlers = {
|
|
11825
11919
|
check: (data) => handleCheck(data.entryId),
|
|
11826
11920
|
"re-evaluate": (data) => handleReEvaluate(data.entryId, data.context ?? "review"),
|
|
11827
11921
|
"verify-chain": (data) => handleVerifyChain(server, { collection: data.collection ?? "glossary", mode: data.mode ?? "report" }),
|
|
11828
|
-
audit: (data) => handleAuditRun(data.entryId, data.phase ?? "shaping")
|
|
11922
|
+
audit: (data) => handleAuditRun(data.entryId, data.phase ?? "shaping"),
|
|
11923
|
+
"spine-check": (data) => handleSpineCheck(data.story ?? false, data.refresh ?? false)
|
|
11829
11924
|
};
|
|
11830
11925
|
server.registerTool(
|
|
11831
11926
|
"quality",
|
|
11832
11927
|
{
|
|
11833
11928
|
title: "Quality",
|
|
11834
|
-
description: "Assess, re-evaluate, and verify entry/bet quality.
|
|
11929
|
+
description: "Assess, re-evaluate, and verify entry/bet quality. Five actions:\n\n- **check**: Read the entry's server quality verdict (tier + criteria) \u2014 it does not re-score. Suggests links when the entry has no relations.\n- **re-evaluate**: Trigger a fresh quality evaluation. Returns heuristic verdict immediately, schedules LLM evaluation in background.\n- **verify-chain**: Verify knowledge entries against the actual codebase (codeMapping drift, cross-references) \u2014 absorbs `verify`. Produces a trust report with a trust score.\n- **audit**: Run hygiene audit on a bet entry (13/18 gates) \u2014 absorbs `audit`.\n- **spine-check**: Structural completeness of the purpose+vision+strategy spine \u2014 duplicate singletons, connectedness, per-strategy refusal heuristic; story:true also runs the on-demand one-story LLM judgment (never scheduled, result labelled [unvalidated]). Async: a plain call reads back the latest stored verdict and auto-schedules a new run ONLY when none is already in flight AND the stored one is absent/stale/missing the requested story pass \u2014 repeated polling never re-triggers work. Pass refresh:true to force a fresh run regardless.",
|
|
11835
11930
|
inputSchema: qualitySchema,
|
|
11836
11931
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
11837
11932
|
},
|
|
@@ -16309,4 +16404,4 @@ export {
|
|
|
16309
16404
|
createProductBrainServer,
|
|
16310
16405
|
initFeatureFlags
|
|
16311
16406
|
};
|
|
16312
|
-
//# sourceMappingURL=chunk-
|
|
16407
|
+
//# sourceMappingURL=chunk-CY3YQR26.js.map
|