gasp-standard-mcp 1.7.1 → 1.8.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/README.md +1 -0
- package/build/loader.js +51 -0
- package/build/standard-data.json +1 -1
- package/build/standard-version.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ Restart your MCP client after adding the config.
|
|
|
56
56
|
- 60 temporal mappings (grain, frequency, period for every metric node)
|
|
57
57
|
- Access control classifications for every graph metric (sensitivity tier + access scope)
|
|
58
58
|
- CEL `change_nature` field for revenue quality analysis (Adjusted NRR/GRR)
|
|
59
|
+
- Per-department cross-references (e.g. NRR under Customer Success, Gross Margin under Finance) now resolve to the full canonical content via slug lookup
|
|
59
60
|
- Sources: the canonical [GASP Standard](https://gaspwiki.com) files
|
|
60
61
|
|
|
61
62
|
## Examples
|
package/build/loader.js
CHANGED
|
@@ -97,6 +97,57 @@ export function loadStandard() {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
// Enrich cross-reference stubs with canonical content fields.
|
|
101
|
+
//
|
|
102
|
+
// Some metrics intentionally appear in multiple department files — e.g. NRR
|
|
103
|
+
// is defined canonically in core.md and listed as a "See [Core](core.md#...)"
|
|
104
|
+
// stub in customer-success.md. Per-department records are needed to drive
|
|
105
|
+
// department-scoped routes (e.g. /v1/metrics/customer-success/...), but
|
|
106
|
+
// consumers of standard.json that look up by slug expect every record to
|
|
107
|
+
// carry full content. Without this pass, Map-based lookups silently get the
|
|
108
|
+
// empty stub instead of the canonical record.
|
|
109
|
+
//
|
|
110
|
+
// Strategy: keep stub identity (department, category, name, slug, rawMarkdown)
|
|
111
|
+
// but copy any content field that's empty on the stub from the canonical.
|
|
112
|
+
const canonicalBySlug = new Map();
|
|
113
|
+
for (const m of metrics) {
|
|
114
|
+
if (m.slug && m.definition && !canonicalBySlug.has(m.slug)) {
|
|
115
|
+
canonicalBySlug.set(m.slug, m);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const m of metrics) {
|
|
119
|
+
if (m.definition)
|
|
120
|
+
continue; // already canonical or non-stub
|
|
121
|
+
const seeMatch = m.rawMarkdown.match(/See \[([^\]]+)\]\(([^)]+)\)/);
|
|
122
|
+
if (!seeMatch)
|
|
123
|
+
continue;
|
|
124
|
+
const link = seeMatch[2];
|
|
125
|
+
const anchor = link.includes("#") ? link.split("#")[1] : null;
|
|
126
|
+
if (!anchor)
|
|
127
|
+
continue;
|
|
128
|
+
const canon = canonicalBySlug.get(anchor) ||
|
|
129
|
+
canonicalBySlug.get(m.slug) ||
|
|
130
|
+
[...canonicalBySlug.values()].find((c) => c.slug.includes(anchor));
|
|
131
|
+
if (!canon || canon === m)
|
|
132
|
+
continue;
|
|
133
|
+
if (!m.definition)
|
|
134
|
+
m.definition = canon.definition;
|
|
135
|
+
if (!m.formulas?.length)
|
|
136
|
+
m.formulas = [...canon.formulas];
|
|
137
|
+
if (!m.benchmarks)
|
|
138
|
+
m.benchmarks = canon.benchmarks;
|
|
139
|
+
if (!m.insight)
|
|
140
|
+
m.insight = canon.insight;
|
|
141
|
+
if (!m.commonMistakes?.length && canon.commonMistakes)
|
|
142
|
+
m.commonMistakes = [...canon.commonMistakes];
|
|
143
|
+
if (!m.sources?.length)
|
|
144
|
+
m.sources = [...canon.sources];
|
|
145
|
+
if (!m.aliases?.length)
|
|
146
|
+
m.aliases = [...canon.aliases];
|
|
147
|
+
// dualLens and dualLensNote are intentionally NOT enriched — they are a
|
|
148
|
+
// Core-only construct (asserted by data-integrity tests). Consumers that
|
|
149
|
+
// need dual-lens content should resolve via slug to the Core record.
|
|
150
|
+
}
|
|
100
151
|
// Load query templates
|
|
101
152
|
const queryTemplatePath = join(standardDir, "query-templates.json");
|
|
102
153
|
let queryTemplates;
|