Finish Phase 22: the half of Petal that works with the tunnel down

Grammar lite, the false-friend list, the daily invitation and the offline
miscollocations — the four remaining §5–§6 items, all client-side and all
alive on a box that cannot reach the model.

The offline collocations forced a schema change. `type` had been doubling
as the answer to "which engine found this" — `mechanics` meant offline —
and that stops being true the moment an offline rule proposes a
collocation. Migration 0013 adds `source` (llm | local) and every pass now
scopes its DELETE by engine; without it the coach silently wiped every
offline chunk on the page. Existing rows backfill by type, so a pre-0013
collocation row is claimed as the coach's, which it was: the offline list
did not exist yet.

The rule pack is hand-curated rather than mined, and the entries left out
are the point — `married with` is wrong until "married with children",
`arrive to` wants at or in depending on the noun. A pack running on every
keystroke must not correct correct writing.

Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
prosolis
2026-07-27 15:05:55 -07:00
parent e9b8595456
commit 1bbc8fc8d3
20 changed files with 1678 additions and 50 deletions
+20
View File
@@ -477,6 +477,26 @@ CREATE TABLE personal_words (
ALTER TABLE suggestions ADD COLUMN resolved_at DATETIME;
UPDATE suggestions SET resolved_at = created_at WHERE status != 'pending';
CREATE INDEX idx_suggestions_resolved ON suggestions(status, resolved_at);
`,
},
{
// Which engine proposed a row. Until now `type` doubled as that answer —
// 'mechanics' meant "the offline rule pack found this" and everything else
// meant "the model did". That breaks the moment an offline rule proposes a
// *collocation*: the miscollocation list (SUGGESTIONS §6) is the same
// family, the same rail and the same warm phrasing as the LLM coach, and it
// must stay type='collocation' so an accepted chunk still plants in the
// garden and still counts in the journal. With type no longer naming the
// engine, the two passes could not scope their own DELETEs — the coach
// would wipe the offline flags, and the offline pass would leave the
// coach's behind to accumulate.
//
// Existing mechanics rows are local by definition; everything else came
// from a model.
name: "0013_suggestion_source",
stmt: `
ALTER TABLE suggestions ADD COLUMN source TEXT NOT NULL DEFAULT 'llm';
UPDATE suggestions SET source = 'local' WHERE type = 'mechanics';
`,
},
}