@@ -5,7 +5,7 @@ import { join, dirname } from "node:path";
55import { tmpdir } from "node:os" ;
66import type { LongTermMemoryEntry , WorkspaceMemoryStore } from "../src/types.ts" ;
77import { LONG_TERM_LIMITS } from "../src/types.ts" ;
8- import { workspaceMemoryPath } from "../src/paths.ts" ;
8+ import { workspaceKey , workspaceMemoryPath } from "../src/paths.ts" ;
99import {
1010 renderWorkspaceMemory ,
1111 enforceLongTermLimits ,
@@ -21,6 +21,7 @@ import {
2121 saveWorkspaceMemory ,
2222 updateWorkspaceMemoryWithAccounting ,
2323} from "../src/workspace-memory.ts" ;
24+ import { reviewerCurrent28Fixture , expectedAcceptedFixtureIds } from "./fixtures/memory-quality-current-28.ts" ;
2425
2526function entry ( id : string , text : string , type : LongTermMemoryEntry [ "type" ] = "decision" ) : LongTermMemoryEntry {
2627 const now = new Date ( ) . toISOString ( ) ;
@@ -953,6 +954,133 @@ test("runMigrationP0Cleanup marks only non-explicit project snapshots and runs o
953954 assert . equal ( twice . entries . find ( e => e . id === "project-snapshot" ) ?. updatedAt , once . entries . find ( e => e . id === "project-snapshot" ) ?. updatedAt ) ;
954955} ) ;
955956
957+ test ( "quality cleanup migration supersedes low-quality compaction memories from current-28 fixture" , async ( ) => {
958+ const root = await mkdtemp ( join ( tmpdir ( ) , "wm-quality-cleanup-" ) ) ;
959+ try {
960+ const now = new Date ( ) . toISOString ( ) ;
961+ await saveWorkspaceMemory ( root , {
962+ version : 1 ,
963+ workspace : { root, key : await workspaceKey ( root ) } ,
964+ limits : { maxRenderedChars : LONG_TERM_LIMITS . maxRenderedChars , maxEntries : LONG_TERM_LIMITS . maxEntries } ,
965+ entries : reviewerCurrent28Fixture ,
966+ migrations : [ ] ,
967+ updatedAt : now ,
968+ } ) ;
969+
970+ const loaded = await loadWorkspaceMemory ( root ) ;
971+ const activeIds = new Set ( loaded . entries . filter ( entry => entry . status === "active" ) . map ( entry => entry . id ) ) ;
972+ const supersededIds = new Set ( loaded . entries . filter ( entry => entry . status === "superseded" ) . map ( entry => entry . id ) ) ;
973+
974+ for ( const entry of reviewerCurrent28Fixture ) {
975+ if ( expectedAcceptedFixtureIds . has ( entry . id ) ) {
976+ assert . equal ( activeIds . has ( entry . id ) , true , `${ entry . id } should remain active` ) ;
977+ } else {
978+ assert . equal ( supersededIds . has ( entry . id ) , true , `${ entry . id } should be superseded` ) ;
979+ }
980+ }
981+
982+ assert . ok ( loaded . migrations ?. includes ( "2026-04-28-quality-cleanup" ) ) ;
983+ } finally {
984+ await rm ( root , { recursive : true , force : true } ) ;
985+ }
986+ } ) ;
987+
988+ test ( "quality cleanup migration dedupes tags" , async ( ) => {
989+ const root = await mkdtemp ( join ( tmpdir ( ) , "wm-quality-tags-" ) ) ;
990+ try {
991+ const now = new Date ( ) . toISOString ( ) ;
992+ await saveWorkspaceMemory ( root , {
993+ version : 1 ,
994+ workspace : { root, key : await workspaceKey ( root ) } ,
995+ limits : { maxRenderedChars : LONG_TERM_LIMITS . maxRenderedChars , maxEntries : LONG_TERM_LIMITS . maxEntries } ,
996+ entries : [ {
997+ id : "bad_with_tags" ,
998+ type : "feedback" ,
999+ text : "Wave 1 completed successfully and all tests passed" ,
1000+ source : "compaction" ,
1001+ confidence : 0.75 ,
1002+ status : "active" ,
1003+ createdAt : now ,
1004+ updatedAt : now ,
1005+ tags : [ "quality_cleanup" , "quality:progress_snapshot" ] ,
1006+ } ] ,
1007+ migrations : [ ] ,
1008+ updatedAt : now ,
1009+ } ) ;
1010+
1011+ const loaded = await loadWorkspaceMemory ( root ) ;
1012+ const tags = loaded . entries [ 0 ] . tags ?? [ ] ;
1013+ assert . equal ( tags . filter ( tag => tag === "quality_cleanup" ) . length , 1 ) ;
1014+ assert . equal ( tags . filter ( tag => tag === "quality:progress_snapshot" ) . length , 1 ) ;
1015+ } finally {
1016+ await rm ( root , { recursive : true , force : true } ) ;
1017+ }
1018+ } ) ;
1019+
1020+ test ( "quality cleanup migration does not supersede explicit memories" , async ( ) => {
1021+ const root = await mkdtemp ( join ( tmpdir ( ) , "wm-quality-explicit-" ) ) ;
1022+ try {
1023+ const now = new Date ( ) . toISOString ( ) ;
1024+ const explicitBadShape = {
1025+ id : "explicit_progress_like" ,
1026+ type : "feedback" as const ,
1027+ text : "Wave 1 completed successfully and all tests passed" ,
1028+ source : "explicit" as const ,
1029+ confidence : 1 ,
1030+ status : "active" as const ,
1031+ createdAt : now ,
1032+ updatedAt : now ,
1033+ } ;
1034+
1035+ await saveWorkspaceMemory ( root , {
1036+ version : 1 ,
1037+ workspace : { root, key : await workspaceKey ( root ) } ,
1038+ limits : { maxRenderedChars : LONG_TERM_LIMITS . maxRenderedChars , maxEntries : LONG_TERM_LIMITS . maxEntries } ,
1039+ entries : [ explicitBadShape ] ,
1040+ migrations : [ ] ,
1041+ updatedAt : now ,
1042+ } ) ;
1043+
1044+ const loaded = await loadWorkspaceMemory ( root ) ;
1045+ assert . equal ( loaded . entries [ 0 ] . status , "active" ) ;
1046+ assert . equal ( loaded . entries [ 0 ] . source , "explicit" ) ;
1047+ } finally {
1048+ await rm ( root , { recursive : true , force : true } ) ;
1049+ }
1050+ } ) ;
1051+
1052+ test ( "quality cleanup migration does not supersede manual memories" , async ( ) => {
1053+ const root = await mkdtemp ( join ( tmpdir ( ) , "wm-quality-manual-" ) ) ;
1054+ try {
1055+ const now = new Date ( ) . toISOString ( ) ;
1056+ const manualBadShape = {
1057+ id : "manual_progress_like" ,
1058+ type : "feedback" as const ,
1059+ text : "Wave 1 completed successfully and all tests passed" ,
1060+ source : "manual" as const ,
1061+ confidence : 0.9 ,
1062+ status : "active" as const ,
1063+ createdAt : now ,
1064+ updatedAt : now ,
1065+ } ;
1066+
1067+ await saveWorkspaceMemory ( root , {
1068+ version : 1 ,
1069+ workspace : { root, key : await workspaceKey ( root ) } ,
1070+ limits : { maxRenderedChars : LONG_TERM_LIMITS . maxRenderedChars , maxEntries : LONG_TERM_LIMITS . maxEntries } ,
1071+ entries : [ manualBadShape ] ,
1072+ migrations : [ ] ,
1073+ updatedAt : now ,
1074+ } ) ;
1075+
1076+ const loaded = await loadWorkspaceMemory ( root ) ;
1077+ assert . equal ( loaded . entries [ 0 ] . status , "active" ) ;
1078+ assert . equal ( loaded . entries [ 0 ] . source , "manual" ) ;
1079+ } finally {
1080+ await rm ( root , { recursive : true , force : true } ) ;
1081+ }
1082+ } ) ;
1083+
9561084test ( "renderWorkspaceMemory excludes superseded entries" , ( ) => {
9571085 const now = new Date ( ) . toISOString ( ) ;
9581086 const store : WorkspaceMemoryStore = {
0 commit comments