ธีม
2026-08-08 (late) — 0128–0131, fifteen reports in one pass
Archived out of STATE.md. All applied, deployed to the VM and verified from the SERVED bundle. Chronology: git log --oneline (1b9f63c … a5c28fd).
Live proofs, all both-directional: node tools/house0128-cohort.mjs · node tools/house0128-requests.mjs · node tools/house0131-year-offset.mjs.
The 0128–0130 pass — fourteen reports
Applied, committed, pushed, DEPLOYED and verified from the served bundle (year_override absent from the live admin JS; house-pickrow / adminMySeat / houseFilterSai present).
⚠️ The lesson of this deploy, and it was live for ~20 minutes: 0129 dropped five columns while the SERVED bundle still named them in select=, and PostgREST 400s on an unknown column — so ระบบบ้าน's admin tab died with 42703 column students.year_override does not exist the moment the migration applied. A column drop is only safe AFTER the bundle that stopped reading it is the one being served. Drop-then-deploy is a window; deploy-then-drop is not.
- 0128 §1 — a DERIVED column that was filled once and never re-derived.
students_fill_cohortusedif cohort_year is null, true exactly once per row, so a corrected รหัสนักศึกษา left the old รุ่น behind and every reader'scoalesce(copy, source)preferred the stale copy. 1 of 3 live rows was wrong. Now re-derives on every รหัส change; an explicitcohort_yearin the same statement still wins. Proof:node tools/house0128-cohort.mjs(5 steps across a row's whole life — an insert-only probe scores the bug as a pass). - 0128 §2 — the admin's decision reaches the student.
decision_notewent into an admin-only table with no read path back to the person it addressed. It now travels insideget_my_student_record(); newapplied_valuerecords what was actually saved when an admin corrects the value on approval. Proof:node tools/house0128-requests.mjs— allow AND deny. - 0128 §3 —
advisors.titledropped (folded intofirst_name_th, as 0113 did for ทีม SAMO);emailnow published to the students of that อาจารย์'s house. - 0129 — five vestigial columns off
students:year_override,is_listed,sai_locked,sai_self_edits,verified_at. Each was the leftover of a feature removed in 0123–0125, and the CSV export was handing all five to a human as data. Verified first: no function body, no trigger, no non-default value.house_settingsis the same shape and is NOT dropped — it is a table, and that needs asking. - 0130 —
lookup_student_by_kkumail(): the ทีม SAMO member form fills itself from ระบบบ้าน. Exact match only, one row, named columns, no anon grant. ⚠️ A deliberate widening:teamalone can now resolve one address againststudents. The full merge is designed indocs/PERSON-REGISTRY.mdand is NOT built. - Admin landing now carries a card for every
SIDE_FEATUREkey —team,house,order,analyticswere sidebar-only, so an admin holding just one of those landed on an empty page. Pinned bysrc/js/admin-landing.test.js(verified to FAIL when a card is removed). ข้อมูลของฉัน moved out of the ทีม SAMO tab onto that landing — behind theteamgrant it was unreachable for an admin whose grants are e.g.pr+samoshop. - Import preview is now the file row-by-row (skipped rows included — they were the only ones the old preview could not show); export carries one
nickname, plushouseandcohortas words.
Debugging note that cost twenty minutes here, now in mistakes.md class 7:current_user_has_permission() reads the UNION of permissions AND managed_permissions (0081). A probe subject picked by permissions = '{}' alone may hold master through the ทีม SAMO tree, and reads exactly like a fail-open RLS policy. Filter on BOTH columns.