Skip to content

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_cohort used if cohort_year is null, true exactly once per row, so a corrected รหัสนักศึกษา left the old รุ่น behind and every reader's coalesce(copy, source) preferred the stale copy. 1 of 3 live rows was wrong. Now re-derives on every รหัส change; an explicit cohort_year in 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_note went into an admin-only table with no read path back to the person it addressed. It now travels inside get_my_student_record(); new applied_value records what was actually saved when an admin corrects the value on approval. Proof: node tools/house0128-requests.mjs — allow AND deny.
  • 0128 §3 — advisors.title dropped (folded into first_name_th, as 0113 did for ทีม SAMO); email now 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_settings is 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: team alone can now resolve one address against students. The full merge is designed in docs/PERSON-REGISTRY.md and is NOT built.
  • Admin landing now carries a card for every SIDE_FEATURE key — team, house, order, analytics were sidebar-only, so an admin holding just one of those landed on an empty page. Pinned by src/js/admin-landing.test.js (verified to FAIL when a card is removed). ข้อมูลของฉัน moved out of the ทีม SAMO tab onto that landing — behind the team grant 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, plus house and cohort as 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.

Working docs. STATE.md is the status file and lives at the repo root, not here.