test(uok): align purpose-coherence fixtures with merged P2/P3 schema

After cherry-picking P2 (v72: slices.traces_vision_fragment) and P3
(v70: tasks.purpose_trace) onto main, the schema migration ladder
now adds those columns automatically on every openDatabase. The P4
test fixtures, which were authored when those migrations were still
in their own worktree branches, manually ALTER'd the columns —
which throws "duplicate column name" post-merge.

Two changes, both purely about exercising the same gate paths under
the new ground truth:

- makeForwardDb no longer manually ALTERs — the migration ladder
  already provides the columns. The "trace value NULL" branch is
  exercised by inserting rows with explicit NULL instead of relying
  on the column being absent.
- The "legacy DB" test no longer expects the warning to mention the
  column name (the column always exists post-migration). The
  underlying SqliteError catch in evaluatePurposeCoherence remains
  for the genuinely-legacy DB case where someone is running against
  a fixture that predates the migration; the test now exercises the
  NULL-value warn path which is the real-world signal operators see.

All 17 uok-purpose-coherence tests pass; full 5-pillar sweep
(P1+P2+P3+P4+P5 + migration) 53/53 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-15 18:54:59 +02:00
parent 008f0c685d
commit 1b3dba6e51

View file

@ -173,18 +173,15 @@ function makeLegacyDb() {
}
/**
* Open an SF DB and bolt on the columns the parallel migrations will
* eventually add. Mirrors the post-P2/P3 schema so we can exercise the
* "trace column present, value NULL" and "full chain present" branches.
* Open an SF DB. Post-P2/P3 merge the trace columns are already added
* by the schema migration ladder (v70 = tasks.purpose_trace,
* v72 = slices.traces_vision_fragment), so no manual ALTER is needed.
* Test value-NULL paths by inserting rows with explicit NULL.
*/
function makeForwardDb() {
const base = makeProject();
openDatabase(join(base, ".sf", "sf.db"));
const db = _getAdapter();
db.exec(
"ALTER TABLE slices ADD COLUMN traces_vision_fragment TEXT DEFAULT NULL",
);
db.exec("ALTER TABLE tasks ADD COLUMN purpose_trace TEXT DEFAULT NULL");
return { base, db };
}
@ -206,7 +203,11 @@ describe("evaluatePurposeCoherence (DB-backed)", () => {
db,
});
expect(verdict.outcome).toBe("warn");
expect(verdict.rationale).toMatch(/traces_vision_fragment column/);
// Post-migration the column always exists; the warn message now
// reports the NULL value rather than the absent column. The gate
// itself still keeps the column-missing SqliteError catch so
// projects that somehow predate the migration don't hard-fail.
expect(verdict.rationale).toMatch(/slice goal does not trace/);
});
test("vision missing on legacy DB → fail", () => {