Found while running MOTIR-3294 (motir run on the parent, branch parent/MOTIR-3294-lesson-axes in motir-ai). The defect is in the PLAN, not in shipped code; the correction is already applied to MOTIR-3301 on the record.
The prose, three times:
types does not constrain kinds or phases."The fixture table, in MOTIR-3301, seeds five rows and lists an expected set per query. Three of those five expected sets are only reachable under the OPPOSITE semantics — that a lesson is universal only when it is unconstrained on ALL THREE axes, and otherwise must overlap on whichever axis is queried:
| assertion | card expects | correct under the prose | the difference |
|---|---|---|---|
2 · types: [chore] | C, D | C, D, E | E carries no types, so it is unconstrained on that axis |
3 · phases: [skeleton] | E, D | C, D, E | C carries no phases |
5 · kinds: [bug] | E, D | A, B, C, D, E | A, B and C carry no kinds |
Assertions 1 and 4 are identical under both readings, which is why the table looks coherent read top to bottom.
Not a preference — the fixture's reading inverts the epic:
notes.html #37 (tagged types: [test]) becomes invisible to every kinds or phases query, and the more precisely a lesson is tagged the less of the corpus a planner can reach.captureMistake has ever written carries all three axes empty. Those keep working under either reading, but under the fixture's reading they are the ONLY rows a filtered query can ever reach.So tagging the corpus would REDUCE retrieval, which is the over-injection this epic exists to remove, rebuilt inside the mechanism meant to fix it.
listForInjection implements the prose: per axis, AND (cardinality(col) = 0 OR col::text[] && ARRAY[…]::text[]), and the clause is omitted entirely when the QUERY leaves that axis empty. Empty means unconstrained on BOTH sides.tests/lessonAxisFiltering.test.ts so a later reader meets it where the numbers are.notes.html entry recording this is linked from the rule.motir-meta prompts/plan-rules/phase-deepen.md — where an authoring bar for a card's own acceptance table belongs.motir-ai tests/lessonAxisFiltering.test.ts — the amended table and the reasoning, as shipped.