I2 (Ruling 17): `refresh_from` used to `FAMILIES.clear()` before loading the derived table, so any hand family the derivation table doesn't reach (e.g. only CCM got re-derived) vanished from the live registry. Seed from HAND_FAMILIES first, then let derived rows extend/override per key — a hand key present in the table gets the derived (superset) codes, HAND_FAMILIES' own name/synonyms carry through via `load_families`; a hand key absent from the table survives untouched. I3: the live table has 627 stem-derived keys shared by >= 2 unrelated components (`GENE` x13, `ADM` x12) — `load_families` silently merged them under one key. `derive_families` now appends the group's representative code to a colliding non-hand key (`GENE-81105`) and rejects members that aren't code-shaped (`CODE_RE.fullmatch`) before deriving anything, so a corpus artifact like a bare `\x1a` can't become a family. I7: `FAMILIES`'s docstring claimed the chat/notebooks see the derived registry too; only the `stack pfs` CLI calls `refresh_from` today (the spec's import-time-load ask is blocked by the no-DuckDB-at-import constraint — controller to file a follow-up). Also adds a public `FR_CITE_RE` alias for `pfs.lineage` to reuse (M1, next commit). Claude-Session: https://claude.ai/code/session_01Aum3pEMAM3yQVdFSdVe6Gc
19 KiB
19 KiB