@smartmemory/compose 0.2.15-beta → 0.2.17-beta
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/lib/feature-validator.js +34 -4
- package/package.json +2 -2
package/lib/feature-validator.js
CHANGED
|
@@ -249,7 +249,12 @@ function loadValidationContext(cwd, options = {}) {
|
|
|
249
249
|
visionStateRaw,
|
|
250
250
|
foldersByCode,
|
|
251
251
|
citationRows,
|
|
252
|
-
|
|
252
|
+
// Fall back to .compose/compose.json `externalPrefixes` when the caller did
|
|
253
|
+
// not pass them — the `compose validate` CLI/pre-push path does not, so without
|
|
254
|
+
// this fallback every externally-owned row (e.g. STRAT-*) trips folder-linkage.
|
|
255
|
+
externalPrefixes: (options.externalPrefixes && options.externalPrefixes.length)
|
|
256
|
+
? options.externalPrefixes
|
|
257
|
+
: loadExternalPrefixes(cwd),
|
|
253
258
|
featureJsonMode: options.featureJsonMode !== false,
|
|
254
259
|
// Narrative-owned (#39): ROADMAP.md is hand-authored, so a parsed roadmap row
|
|
255
260
|
// is NOT a canonical data source. Computed once here and consulted by checks
|
|
@@ -295,6 +300,15 @@ function finding(severity, kind, code, detail, source) {
|
|
|
295
300
|
return f;
|
|
296
301
|
}
|
|
297
302
|
|
|
303
|
+
// A code owned by another repo (matches a declared externalPrefix, e.g. STRAT-*)
|
|
304
|
+
// is a cross-repo REFERENCE. Compose can validate that the reference resolves, but
|
|
305
|
+
// not the external feature's local artifacts, completion records, folder layout,
|
|
306
|
+
// row-schema, or authoritative status — all of which live in the owning repo. The
|
|
307
|
+
// per-feature local-correspondence checks consult this and skip such codes.
|
|
308
|
+
function isExternalCode(code, ctx) {
|
|
309
|
+
return !!code && (ctx?.externalPrefixes || []).some((p) => code.startsWith(p));
|
|
310
|
+
}
|
|
311
|
+
|
|
298
312
|
// ---------------------------------------------------------------------------
|
|
299
313
|
// Per-feature checks
|
|
300
314
|
// ---------------------------------------------------------------------------
|
|
@@ -368,7 +382,7 @@ function runSchemaChecks(fctx, ctx, findings) {
|
|
|
368
382
|
}
|
|
369
383
|
}
|
|
370
384
|
}
|
|
371
|
-
if (roadmap) {
|
|
385
|
+
if (roadmap && !isExternalCode(code, ctx)) {
|
|
372
386
|
const v = getValidator(ROADMAP_ROW_SCHEMA);
|
|
373
387
|
const r = v.validateRoot(roadmap);
|
|
374
388
|
if (!r.valid) {
|
|
@@ -396,8 +410,11 @@ function projectToVisionStatus(s) {
|
|
|
396
410
|
return s === 'PARTIAL' ? 'IN_PROGRESS' : s;
|
|
397
411
|
}
|
|
398
412
|
|
|
399
|
-
function runStateMismatchChecks(fctx, findings) {
|
|
413
|
+
function runStateMismatchChecks(fctx, ctx, findings) {
|
|
400
414
|
const { code, roadmap, vision, featureJson } = fctx;
|
|
415
|
+
// Compose is not the authority on an external feature's status — its ROADMAP/
|
|
416
|
+
// vision rows are cross-repo mirrors that may legitimately lag the owning repo.
|
|
417
|
+
if (isExternalCode(code, ctx)) return;
|
|
401
418
|
const rStatus = normalizeStatus(roadmap?.status);
|
|
402
419
|
const fStatus = normalizeStatus(featureJson?.status);
|
|
403
420
|
const vStatus = normalizeStatus(vision?.status);
|
|
@@ -466,6 +483,11 @@ function runFolderRoadmapLinkageChecks(fctx, ctx, findings) {
|
|
|
466
483
|
const { code, folder, roadmap, vision, featureJson } = fctx;
|
|
467
484
|
const rStatus = normalizeStatus(roadmap?.status);
|
|
468
485
|
|
|
486
|
+
// Externally-owned codes (e.g. STRAT-*) are cross-repo references whose folder,
|
|
487
|
+
// artifacts, and row layout live in the owning project — folder-linkage does not
|
|
488
|
+
// apply, so skip the whole check (row↔folder, folder↔row, empty-folder).
|
|
489
|
+
if (isExternalCode(code, ctx)) return;
|
|
490
|
+
|
|
469
491
|
if (roadmap && !folder) {
|
|
470
492
|
// Severity model for missing folder:
|
|
471
493
|
// IN_PROGRESS → error (active work without a tracking artifact)
|
|
@@ -506,6 +528,8 @@ function runFolderRoadmapLinkageChecks(fctx, ctx, findings) {
|
|
|
506
528
|
function runArtifactLinkChecks(fctx, ctx, findings) {
|
|
507
529
|
const { code, folder, featureJson } = fctx;
|
|
508
530
|
if (!folder) return;
|
|
531
|
+
// External features keep their design/report/artifacts in the owning repo.
|
|
532
|
+
if (isExternalCode(code, ctx)) return;
|
|
509
533
|
const featureRootArg = ctx.paths.features;
|
|
510
534
|
const am = new ArtifactManager(featureRootArg);
|
|
511
535
|
let assessment = null;
|
|
@@ -594,6 +618,9 @@ function runCrossFeatureRefChecks(fctx, ctx, findings) {
|
|
|
594
618
|
|
|
595
619
|
function runCoherenceChecks(fctx, ctx, findings) {
|
|
596
620
|
const { code, featureJson } = fctx;
|
|
621
|
+
// External features record their changelog/journal in the owning repo, so
|
|
622
|
+
// compose can't (and shouldn't) assert those entries exist here.
|
|
623
|
+
if (isExternalCode(code, ctx)) return;
|
|
597
624
|
// COMPLETION_WITHOUT_CHANGELOG — check at project level, but per-feature too
|
|
598
625
|
const status = effectiveStatus(fctx, ctx);
|
|
599
626
|
if (status === 'COMPLETE' || status === 'PARTIAL') {
|
|
@@ -650,6 +677,9 @@ function runChangelogReferenceCheck(ctx, findings) {
|
|
|
650
677
|
let m;
|
|
651
678
|
while ((m = headerRe.exec(text))) {
|
|
652
679
|
const code = m[1];
|
|
680
|
+
// External codes (e.g. STRAT-*) are legitimately referenced in compose's
|
|
681
|
+
// CHANGELOG without a local folder/row — their home is the owning repo.
|
|
682
|
+
if (isExternalCode(code, ctx)) continue;
|
|
653
683
|
if (!ctx.roadmapByCode.has(code) && !ctx.foldersByCode.has(code) && !ctx.visionByCode.has(code)) {
|
|
654
684
|
// Downgraded from error: many shipped features have CHANGELOG entries without
|
|
655
685
|
// ROADMAP rows or vision-state items (legacy pattern where CHANGELOG is the
|
|
@@ -716,7 +746,7 @@ export async function validateFeature(cwd, code, options = {}) {
|
|
|
716
746
|
}
|
|
717
747
|
|
|
718
748
|
runSchemaChecks(fctx, ctx, findings);
|
|
719
|
-
runStateMismatchChecks(fctx, findings);
|
|
749
|
+
runStateMismatchChecks(fctx, ctx, findings);
|
|
720
750
|
runFolderRoadmapLinkageChecks(fctx, ctx, findings);
|
|
721
751
|
runArtifactLinkChecks(fctx, ctx, findings);
|
|
722
752
|
runCrossFeatureRefChecks(fctx, ctx, findings);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartmemory/compose",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17-beta",
|
|
4
4
|
"description": "Structured AI dev pipeline — goal-to-product orchestration with gates, iteration loops, and feature lifecycle management.",
|
|
5
5
|
"author": "SmartMemory",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dev:client": "vite",
|
|
20
20
|
"build": "vite build",
|
|
21
21
|
"preview": "vite preview",
|
|
22
|
-
"test": "node --test test/*.test.js test/comp-obs-branch/*.test.js test/integration/*.test.js && npm run test:ui && npm run test:tracker",
|
|
22
|
+
"test": "node --import ./test/suppress-expected-drift.js --test test/*.test.js test/comp-obs-branch/*.test.js test/integration/*.test.js && npm run test:ui && npm run test:tracker",
|
|
23
23
|
"test:ui": "vitest run",
|
|
24
24
|
"test:tracker": "vitest run --config vitest.tracker.config.js",
|
|
25
25
|
"test:integration": "node --test test/integration/*.test.js",
|