@smartmemory/compose 0.2.16-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.
@@ -300,6 +300,15 @@ function finding(severity, kind, code, detail, source) {
300
300
  return f;
301
301
  }
302
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
+
303
312
  // ---------------------------------------------------------------------------
304
313
  // Per-feature checks
305
314
  // ---------------------------------------------------------------------------
@@ -373,7 +382,7 @@ function runSchemaChecks(fctx, ctx, findings) {
373
382
  }
374
383
  }
375
384
  }
376
- if (roadmap) {
385
+ if (roadmap && !isExternalCode(code, ctx)) {
377
386
  const v = getValidator(ROADMAP_ROW_SCHEMA);
378
387
  const r = v.validateRoot(roadmap);
379
388
  if (!r.valid) {
@@ -401,8 +410,11 @@ function projectToVisionStatus(s) {
401
410
  return s === 'PARTIAL' ? 'IN_PROGRESS' : s;
402
411
  }
403
412
 
404
- function runStateMismatchChecks(fctx, findings) {
413
+ function runStateMismatchChecks(fctx, ctx, findings) {
405
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;
406
418
  const rStatus = normalizeStatus(roadmap?.status);
407
419
  const fStatus = normalizeStatus(featureJson?.status);
408
420
  const vStatus = normalizeStatus(vision?.status);
@@ -471,21 +483,18 @@ function runFolderRoadmapLinkageChecks(fctx, ctx, findings) {
471
483
  const { code, folder, roadmap, vision, featureJson } = fctx;
472
484
  const rStatus = normalizeStatus(roadmap?.status);
473
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
+
474
491
  if (roadmap && !folder) {
475
- // Externally-owned rows (code matches an externalPrefix, e.g. STRAT-*) are
476
- // cross-repo references whose folder lives in the owning project — folder
477
- // linkage does not apply, so emit nothing. (Asymmetric with the external
478
- // *folder* case below, which downgrades to info: an external folder present
479
- // locally is unusual; an external row without a local folder is the norm.)
480
- const isExternal = ctx.externalPrefixes.some((p) => code.startsWith(p));
481
- if (isExternal) {
482
- // no finding — out of scope for folder-linkage validation
483
- } else if (rStatus === 'IN_PROGRESS') {
484
- // Severity model for missing folder:
485
- // IN_PROGRESS → error (active work without a tracking artifact)
486
- // PARTIAL / BLOCKED → warning (sub-tickets may live elsewhere; partial progress)
487
- // PLANNED → warning (un-started work)
488
- // COMPLETE / SUPERSEDED / KILLED / PARKED / unknown → warning (historical baseline)
492
+ // Severity model for missing folder:
493
+ // IN_PROGRESS → error (active work without a tracking artifact)
494
+ // PARTIAL / BLOCKED → warning (sub-tickets may live elsewhere; partial progress)
495
+ // PLANNED → warning (un-started work)
496
+ // COMPLETE / SUPERSEDED / KILLED / PARKED / unknown warning (historical baseline)
497
+ if (rStatus === 'IN_PROGRESS') {
489
498
  findings.push(finding('error', 'ROADMAP_ROW_WITHOUT_FOLDER', code,
490
499
  `ROADMAP row status is IN_PROGRESS (active work) but no folder exists`));
491
500
  } else {
@@ -519,6 +528,8 @@ function runFolderRoadmapLinkageChecks(fctx, ctx, findings) {
519
528
  function runArtifactLinkChecks(fctx, ctx, findings) {
520
529
  const { code, folder, featureJson } = fctx;
521
530
  if (!folder) return;
531
+ // External features keep their design/report/artifacts in the owning repo.
532
+ if (isExternalCode(code, ctx)) return;
522
533
  const featureRootArg = ctx.paths.features;
523
534
  const am = new ArtifactManager(featureRootArg);
524
535
  let assessment = null;
@@ -607,6 +618,9 @@ function runCrossFeatureRefChecks(fctx, ctx, findings) {
607
618
 
608
619
  function runCoherenceChecks(fctx, ctx, findings) {
609
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;
610
624
  // COMPLETION_WITHOUT_CHANGELOG — check at project level, but per-feature too
611
625
  const status = effectiveStatus(fctx, ctx);
612
626
  if (status === 'COMPLETE' || status === 'PARTIAL') {
@@ -663,6 +677,9 @@ function runChangelogReferenceCheck(ctx, findings) {
663
677
  let m;
664
678
  while ((m = headerRe.exec(text))) {
665
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;
666
683
  if (!ctx.roadmapByCode.has(code) && !ctx.foldersByCode.has(code) && !ctx.visionByCode.has(code)) {
667
684
  // Downgraded from error: many shipped features have CHANGELOG entries without
668
685
  // ROADMAP rows or vision-state items (legacy pattern where CHANGELOG is the
@@ -729,7 +746,7 @@ export async function validateFeature(cwd, code, options = {}) {
729
746
  }
730
747
 
731
748
  runSchemaChecks(fctx, ctx, findings);
732
- runStateMismatchChecks(fctx, findings);
749
+ runStateMismatchChecks(fctx, ctx, findings);
733
750
  runFolderRoadmapLinkageChecks(fctx, ctx, findings);
734
751
  runArtifactLinkChecks(fctx, ctx, findings);
735
752
  runCrossFeatureRefChecks(fctx, ctx, findings);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartmemory/compose",
3
- "version": "0.2.16-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",