13 KiB
| created | path | project | tags | type | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-06-21 | Sources/Dev | pbs-membership-platform-overview |
|
session-notes |
Outcome
Continuing the LOE1 push from 2026-06-19 (see pbs-membership-phases-1-2-3a-deploy). Today's chain (2026-06-20 → 2026-06-21) was supposed to be a quick fix for one pbs-api crash but became a 4-worker reconciliation of the content-hub schema across three sources of truth. Final state: sandbox is fully synced to current pbs-video-manager main — content hub schema, app, and seeder all in lockstep.
Workers run this chain (W7 → W10, plus the in-flight W11 for Phase 3b):
-
W7 —
00_base_schema.j2install + retire01(2026-06-20 → 2026-06-21). Travis provided a fresh prod dump ofpbs_automation. Placed as00_base_schema.j2(478 lines), deleted the stale01_pbs_custom_tables.j2, applied to the live sandbox after aDROP DATABASE pbs_automation(provably empty perCOUNT(*)=0). pbs-api crash-loop resolved — root cause was a signed/unsigned FK type mismatch (instagram_posts.pbs_post_idsigned BIGINT vs stale 01'spbs_recipes.post_idbigint UNSIGNED), not the reported "missing pbs_recipes". Branchfix/pbs-base-schema@3b524f9on gitea. -
W8 — enable pbs-seeder (2026-06-21). Uncommented the seeder import in
roles/dockers/tasks/main.yml, provisioned thepbs-seedercontainer. Three distinct failures fixed in-scope: (a) compose--profile seedinteraction with sharedcommon/deploy.ymldoingup -dwith no default-profile service (addedcontainer_skip_startflag); (b) vendored seeder models ahead of deployed schema; (c) stale pbs-api image whose/api/seedpredatedproject_typessupport. W8 trimmed the seeder to the 10-model subset and added a direct-DB_seed_project_typesworkaround — got data flowing but masked the deeper drift. Branchfeat/enable-pbs-seeder@5412b1aon gitea. Content hub UI started rendering populated cards. -
W9 — content hub schema sync (step 1 of 2) (2026-06-21). Derived
01_content_hub.j2frompbs-video-manager/sql/migrations/001_scene_management.sql(correctly chose authoritative SQL over the broken ORM). Added 6 tables + 2 columns + 5 FKs + a small Prep default-scene seed, all idempotent viaIF NOT EXISTSand information_schema-guarded ALTERs (because MySQL 8 doesn't supportADD COLUMN IF NOT EXISTS— that's MariaDB-only). Applied to sandbox; pbs-api still healthy. Then stopped at the upstream blocker:pbs-video-manager/pbs_manager/db/models.pyon localmainis half-reverted — the synthetic-base commit7083e2dfrom the promote-branch merge stripped 191 lines (6 scene/metadata classes +Project.outline/Project.treatment+ relationships); never restored. App boots becauseapi/routes.pydoesn't importimport_service/outline_service— they're stranded dead code. Branchfeat/content-hub-schema-sync@55ba539on gitea. -
W10 — forward-fix + close out content-hub chain (2026-06-21). Touched both repos (cwd
/opt/projects/pbs/). pbs-video-manager fix: branchfix/restore-scene-metadata-models→ merged--no-fftomainat429383d. Restored 6 classes + 2 columns + 4 relationships, AND the Phase-8STATUSEStuple (had silently lostplanned/scripted). Hand-spliced rather than 3-way merge (3-way would have deleted the instagram models — synthetic base has them, last-good statec7856d6doesn't). Pushed to giteamain+master, GitHub untouched. pbs-api rebuilt on the sandbox (force-recreate; herbylab is built-image mode, dev-mode ispbswp-group only). Recovered from a latentinit_db()create_allmulti-worker race (self-healed via docker restart; latent pre-existing flake). Re-vendored seeder models — full 9-table restoration (the 6 + 3 Phase-6 ones W8's trim had also dropped). Un-trimmed db_seeder.py, removed W8's_seed_project_typesworkaround. Extended01_content_hub.j2with 3 additive Phase-6 columns (platform_posts.title,projects.trello_card_id,projects.trello_last_synced_at) when the seed crashed onUnknown column 'title'— judged in-scope (additive, idempotent, same pattern as W9). Re-seeded withSEEDER_RESET=true. All 16 tables populated, including 4 scenes, 6 scene_items, 2 default_scenes, 6 default_scene_items, 4 project_metadata_fields, 11 project_metadata rows. Garden side unaffected (regression-checked:/the-garden/302;/api/interactions/check401). wordpress-install branchfeat/content-hub-schema-sync@af34f4con gitea. -
W11 — Phase 3b: Saved Recipes card live count (in flight at time of writing). Wires the Garden home's Saved Recipes card subtitle to a real
count(user_interactions)instead of the placeholder. Branchfeat/phase-3b-saved-countofffeat/phase-3a-garden-skeleton. Lands in thread #602.
Topics Covered
- The "MariaDB" note in 582 was wrong. No MariaDB anywhere — herbylab and prod are both MySQL 8. The 582 reference came from somewhere stale (possibly an earlier rough draft). Worth removing if 582 gets re-checkpointed.
pbs_automationschema management had three sources of truth (01_pbs_custom_tables.j2in wordpress-install, SQLAlchemy models in pbs-video-manager, plus Travis's hand modifications in prod). The mismatch chain we untangled today is the predictable outcome of that. Travis raised the Alembic-centralization conversation mid-session and asked Lovebug to consider scoping it as a separate project — answer was "yes, exhibit A is right in front of us" (the silent ORM revert that nobody noticed because dead-code services masked it). Not yet scoped into a vault plan — left open at session end.- The synthetic-base commit pattern from 585's promote-branch merge has a real failure mode: any file that exists in the synthetic base AND the last-good upstream state AND was being patched will silently end up at whichever wins the manual merge — usually the synthetic base, because it's the "newer" commit in the branch's eyes. Both
models.pyandconftest.pygot hit by this. The hand-splice diff strategy W10 used (against the last-good upstream commitc7856d6, not the synthetic base) is the right reconciliation method for future cases. - Seeder ergonomics: the seeder is a one-shot container behind
compose --profile seed. The sharedcommon/deploy.ymltask in the dockers role ranup -dwith no service argument, which fails on profile-gated services because no default-profile services exist. W8 fixed this with acontainer_skip_startflag — generic, useful for any future profile-gated containers. - MySQL 8 idempotency idioms:
CREATE TABLE IF NOT EXISTSandCREATE USER IF NOT EXISTSwork natively.ADD COLUMN IF NOT EXISTSdoes NOT (MariaDB-only); useinformation_schema.COLUMNSguarded prepared statements instead.ADD CONSTRAINT IF NOT EXISTSsimilarly doesn't exist; either guard via information_schema or accept that the patch is first-time-init-only. - W10's scope expansion within a single worker (vs the W9→W10 split originally planned) proved out the "keep interconnected work in one worker" feedback — W10's extending
01_content_hub.j2mid-flow when the seed crashed was a judgment call only possible because the same context had the schema patch, the seeder code, and the live sandbox state all in mind. A handoff to a second worker would have stalled there.
Key Learnings
- a-review picks up stale working-tree files. W10's a-review on the seeder un-trim flagged a CRITICAL + WARNING that turned out to be false positives — it had ingested a stale
ansible.logfrom before the schema patch landed and "found" the oldUnknown column 'projects.outline'crash. Verification against the live DB voided both findings. Worth knowing for future runs — if a-review flags something dramatic, check whether it's reading old logs or scratch files in the working tree before reacting. docker_compose_v2doesn't rebuild on source changes by default (already learned in W3's deploy report; reinforced this session). Member-garden hascontainer_compose_build: always; pbs-api doesn't (per W10's mechanism notes — required manualdocker compose build --no-cache && up -d --force-recreate). Worth normalizing across containers.- The github role pulls master, not main, per the dockers role's
github_repo_versiondefault. To make a "main-as-canonical-source-of-truth" workflow work, you either push to both branches or change the role default. W10 did both-branches as the lowest-friction path. - pytest can't run pbs-video-manager scene-management tests because
conftest.pylost itssession/projectfixtures in the same synthetic revert that hit models.py. Fixture reconciliation is a separate cleanup — flagged. init_db()create_allracing across gunicorn workers is a real flake in built-image mode (dev-mode bind-mount + single-process avoids it; non-dev multi-worker hits MySQL 1050 on the first boot, then docker restart policy recovers). Latent pre-existing; should be gated to a single worker or moved out of app-boot entirely (init-SQL layer authority).
Follow-ons
From W7-W10 specifically
pbs-video-manager/conftest.pyfixture reconciliation — same synthetic revert droppedsession/projectfixtures. The current conftest uses a Flask-app paradigm withmake_*fixtures only. Scene-management pytest suite cannot run until reconciled. Last good state isc7856d6for the conftest too.init_db()multi-worker race in non-dev mode — gatecreate_allto a single worker (gunicorn--preload+ first-worker-only pattern, or move schema authority entirely to the init-SQL layer).- Normalize
container_compose_build: alwaysacross the dockers role for containers that build from clones (pbs-api especially). Already in place for member-garden; pbs-api needed manual override this session. pbs-video-managertwo-branch confusion — local main, gitea main, gitea master, GitHub origin, GitHub main, GitHub master. Different things on each. Worth a cleanup pass: pickmainas canonical, retiremaster, update the github role default.
Schema management (the bigger conversation Travis raised)
- Scope an Alembic-centralization vault plan for
pbs_automation. Same pattern member-garden already uses forpbs_garden. Alembic in pbs-video-manager owns the schema; init-SQL in wordpress-install shrinks toCREATE DATABASE+CREATE USER+ grants. Drift between sandbox/prod becomes a migration backlog (alembic current), not silent column divergence. Today's session is exhibit A for why this matters. One-time cost: retro-generate Alembic baseline from current prod with--autogenerate+ manual review pass to capture Travis's hand-rolled prod changes. Maybe a half-day of work; permanent ergonomics win. Travis acknowledged the case; not yet scoped into a doc.
Carryover (from yesterday's session note, still open)
- CSRF nonce on save/unsave — Phase 2 production-readiness; needs
X-WP-Noncecontract added. - member-garden migrations not automated — bake into image OR add ansible task.
X-Forwarded-Protonot honored in member-garden Flask — ProxyFix.- WP logout confirmation nonce — needs WP-side mu-plugin route for seamless logout.
- WPCode save-button browser test — needs real recipe content on sandbox + browser session.
- Brand color + Sunnie SVG assets for save button + garden.
pbs-video-managerGitHub push — local main + gitea main/master at429383d. GitHub stays behind until Travis is ready for prod release. The merge-to-prod is its own event (with the half-revert mistake also being repaired in this same merge, archaeology-friendly).
Decisions worth keeping
- Hand-splice over 3-way merge for reverted code when the synthetic base and the last-good upstream both have legitimate-but-disjoint content. 3-way against the synthetic base would have deleted the instagram models; 3-way against c7856d6 would have deleted post-revert Phase-6 work. Hand-splicing both directions onto current HEAD is the cleaner reconciliation.
- Forward-commit-and-restore rather than history rewrite for repairing a stripped file. Mistake stays visible in
git logfor archaeology and learning; working state is fixed. Travis explicitly checked the motivation here — destructive history rewrite would have been wrong even though it'd "look cleaner". - Extending an upstream worker's patch when the dependent step crashes with an additive, in-pattern fix (W10 extending W9's
01_content_hub.j2with 3 more columns). The alternative — stop, hand off to a third worker with full context, repeat — burns wall-clock and risks context loss. Judged in-scope = additive, on-branch, same idempotent pattern as the original patch. - Sandbox-throwaway gives latitude. Drop pbs_automation DB, force-rebuild images, SEEDER_RESET=true — all routine when nothing on the sandbox is worth preserving. Snapshot rollback stays gated because it touches WP install state (different concern).
- Two-remote push policy enforced consistently across all today's commits. Gitea = test/sandbox truth; GitHub = production; Travis controls when prod gets the changes. No worker pushed to GitHub origin this session.