package brief import ( "path/filepath" "strings" "testing" "github.com/ajhahnde/eeco/internal/config" ) // writeMalformedFact drops a .md with broken frontmatter (opening '---', no // closing '---') into the memory dir so memory.LoadAll's ParseFact step aborts // the whole load. Named *.md and not dot-prefixed so LoadAll does not skip it. func writeMalformedFact(t *testing.T, cfg *config.Config) { t.Helper() writeFile(t, filepath.Join(cfg.Workspace, "memory", "broken.md"), "---\nname: broken\n") } // TestBoundary_BriefFailsClosedOnMalformedMemory pins the foreground arm of // the H1.6 degrade matrix: a deliberately-invoked `eeco go` fails LOUD on a // corrupt knowledge layer (exit 1) rather than silently distilling a // misleading brief. Paired with internal/hooks // TestBoundary_SessionEmitDegradesOpenOnMalformedMemory, which pins the // background hook's fail-OPEN posture. The asymmetry is intentional (Option A, // H1.6): each boundary degrades-open cleanly OR fails-loud cleanly, never the // dangerous middle of a wrong/partial result. No production change. func TestBoundary_BriefFailsClosedOnMalformedMemory(t *testing.T) { cfg := sampleRepo(t) writeMalformedFact(t, cfg) if _, err := Collect(cfg); err == nil || !strings.Contains(err.Error(), "load memory") { t.Fatalf("Collect must fail closed with a load-memory error, got %v", err) } if _, err := Render(cfg); err == nil { t.Fatalf("Render must fan the load-memory failure (eeco go exit 1), got nil") } }