rastrillo / idear Public

Plan: do not export Models() — it makes migration check permanently red

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev b1aecc4238b825b1ae6565185f6e5ed80ccd3904 parent f513621
2 files changed, +18 −2
  • .superpowers/sdd/2026-08-23-idear/progress.md +11 −0
  • docs/superpowers/plans/2026-08-23-idear.md +7 −2
diff --git a/.superpowers/sdd/2026-08-23-idear/progress.md b/.superpowers/sdd/2026-08-23-idear/progress.md
index 82ac401..fe1aaf2 100644
--- a/.superpowers/sdd/2026-08-23-idear/progress.md
+++ b/.superpowers/sdd/2026-08-23-idear/progress.md
@@ -47,3 +47,14 @@ Ruling: the -race requirement in T3 needs CGO_ENABLED=1, which contradicts the
global CGO_ENABLED=0. Scoped the exception to that one command in the task text,
matching how rastrillo's own CI does it. Cost if wrong: the race step is skipped
and the concurrency bugs it guards go unproven.
+Task 1: implemented DONE (d152346), controller re-verified green. Reviewer dispatched.
+Task 1: review clean — spec OK, quality approved.
+Task 1: minor (deferred): TestParseRole does not pin whitespace-padded rejection (" owner", "owner ") — behaviour correct by construction (exact-match switch), but unpinned, so a future strings.TrimSpace "helpfulness" would pass. Final review to triage.
+Task 1: complete (commits fc16de1..d152346, review clean)
+Task 2: dispatched (sonnet), BASE d152346
+Task 2: implemented DONE (f513621), controller re-verified green. Reviewer dispatched.
+Task 2: review — spec COMPLIANCE FAILED. 1 Critical, 2 Important, 1 Minor.
+Task 2: Ruling (Critical, and the error is MINE — it came from the plan text): REMOVE `Models()` from the public API. The reviewer traced rastrillo's migrate/dump.Compute and reproduced the failure: it diffs the app's OWN Schema against the app's OWN Models, so an app following idear's doc comment gets `migration check` permanently red AND `generate` writing a second GORM-flavoured CREATE TABLE that collides at boot with idear's own BootSchema migration. No core subsystem exports such a function, precisely because Schema and Models must stay a matched pair scoped to one owner. Unexport it if idear's own tests want the list. Plan text corrected at source so later tasks cannot inherit the error. Cost if wrong: an app author loses a helper nothing in the framework asks for.
+Task 2: Ruling (Important): fix the Pending(now) boundary — ExpiresAt == now must be pinned as NOT pending, matching the CAS SQL's `expires_at > ?`. An untested boundary on an expiry check is how an off-by-one ships.
+Task 2: Ruling (Important): the implementer's report describes an index-naming defect that is NOT in the shipped SQL (it claims no `idx_` prefix; the SQL has one). Correct the report — a report that misdescribes its own diff corrupts the record every later reviewer reads.
+Task 2: fix round 1 dispatched (resume original implementer), FIX_BASE f513621
diff --git a/docs/superpowers/plans/2026-08-23-idear.md b/docs/superpowers/plans/2026-08-23-idear.md
index 1b84016..3102acf 100644
--- a/docs/superpowers/plans/2026-08-23-idear.md
+++ b/docs/superpowers/plans/2026-08-23-idear.md
@@ -130,8 +130,13 @@ func (i *Invitation) Pending(now time.Time) bool // not accepted, not revoked,
// Schema is the package's migration set, merged into the app's BootSchema.
var Schema = migrate.MustFromFS(migrationFS, "idear")
-// Models is what an app hands rastrillo's migration checker.
-func Models() []any // []any{&Member{}, &Invitation{}}
+// NOTE (ruled 2026-08-24): do NOT export a Models() for apps to consume.
+// rastrillo's dump.Compute diffs the app's OWN Schema against the app's OWN
+// Models; handing it idear's models against a Schema that has no idear
+// migrations makes `migration check` permanently red and makes `generate`
+// write a second, colliding CREATE TABLE into the app's migrations. No core
+// subsystem (sessions, auth, blobs, passkey) exports one, for this reason.
+// If idear's own tests want the model list, keep it unexported.
```
`token.go` (unexported except where noted):