@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.
@@ -249,7 +249,12 @@ function loadValidationContext(cwd, options = {}) {
249
249
  visionStateRaw,
250
250
  foldersByCode,
251
251
  citationRows,
252
- externalPrefixes: options.externalPrefixes || [],
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.15-beta",
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",