8.3 KiB
Session 0091.0 — Transcript
App: ohm Start: 2026-06-08T21-52 (PST) Type: planning-and-executing Status: PLACEHOLDER — claimed at session start; finalized at session end.
This file reserves session ID 0091 for ohm. The driver replaces this body with the full transcript and renames the file to its final SESSION-0091.0-TRANSCRIPT-2026-06-08T21-52--.md form at session end.
Launch prompt
Fix G-15: make the branch/edit/body subsystem three-tier (collection/project) aware.
§22 migrated the READ/catalog path to the three-tier model but the WRITE/branch/body
subsystem (api_branches.py, api_graduation.py, bot.py) is still hardcoded to the default
project's default collection. _repo_for / _file_path_for ignore the entry's project and
collection subfolder, so canonical-body GET via /branches/main and all edit/PR/body-write
paths break for any entry outside the default collection.
Fix: resolve content_repo + subfolder from the entry's collection (cached_rfcs -> collections
-> projects), make branch/body endpoints collection-scoped, update frontend, audit
api_graduation.py + bot.py. Ship to OHM after.
Plan
G-15 — three-tier-aware branch/edit/body subsystem. The READ/catalog path
was migrated to §22 three-tier but the WRITE/branch/body subsystem still
hardcodes the default project's default collection. Root cause confirmed:
api_branches._repo_for/_file_path_for return default_content_repo +
rfcs/<slug>.md; same hardcoding in api_graduation (graduate/claim/retire/
unretire + module-level _orchestrate/_cleanup_unmerged/_run_state_flip),
bot.open_metadata_pr (hardcodes rfcs/<slug>.md), and a latent one in
api_metadata._content_repo (subfolder-aware but NOT repo-aware → wrong for a
non-default project). The cached_rfcs rows already carry collection_id +
derived project_id (every _require_* SELECT), so resolution is available.
Approach — resolution-correctness everywhere + collection-scoped body reads:
- Shared resolver:
projects.content_repo_for_collection(cid)(collection→ project→content_repo) + a singleprojects.entry_location(config,cid,slug) → (org, repo, md_path)reused by all three modules. TDD. api_branches._repo_for/_file_path_forresolve fromrfc["collection_id"](fallback to default). Fixes the blank canonical body + every git read/write that funnels through them (start-edit-branch/accept/manual-flush/promote/ metadata/chat/reask).bot.open_metadata_pr: addfile_pathparam (drop hardcoded path).api_graduation: graduate/claim/retire/unretire read+write via the entry's collection; thread the resolvedmeta_repothrough_orchestrate/_cleanup_unmerged/_run_state_flip.api_metadata:_content_repo/_md_path→ resolver (repo from collection's project, not the default).- Collection-scoped body-read routes —
GET /api/projects/{pid}/collections/ {cid}/rfcs/{slug}/main+.../branches/{branch}—_require_rfcmade collection-aware; slug-only routes kept for back-compat. - Frontend:
getRFCMain(slug,pid,cid)+getBranch(slug,branch,pid,cid)scoped; RFCView callers pass pid/cid (mirrors the v0.52.1 getRFC fix). - Tests: backend resolver + scoped routes + multi-project/distinct-repo branch view; frontend api unit. Bump version + CHANGELOG. Deploy to OHM.
Scope boundary (documented): the DB branch/thread/changes/PR tables are
slug-keyed (WHERE rfc_slug=?), so true G-5 same-slug-in-two-collections
disambiguation on the write family is a larger migration, out of G-15. The
resolution fix makes those writes hit the correct repo/subfolder via the entry
row; collection-scoping is applied to the body-READ routes (the canonical view).
Outcome
G-15 SHIPPED → v0.53.0, deployed to OHM prod. PR #47 merged (origin
main=ff88be2); tagged v0.53.0 + mirrored to git.benstull.org; OHM pin
(ben/ohm-rfc/.rfc-app-version) bumped 0.52.3→0.53.0; flotilla-core deploy
deploys.id=28 all 9 phases + edge green. Live /api/health=0.53.0.
Live verification of the dogfood entry
(2026-06-08-scoped-admin-ia, rfc-app project/collection):
- slug-only
GET …/branches/mainbody_len=36979 (was""/blank pre-fix). - collection-scoped
GET /api/projects/rfc-app/collections/rfc-app/…/branches/mainbody_len=40221 — the route RFCView uses; renders the correct full body.
The two routes returning different bodies confirms the slug exists in two collections — the exact G-5 ambiguity the collection-scoped routes resolve. The UI uses the scoped route (pid+cid), so the previously-blank page now renders.
Scope note: extended beyond the literal audit list (api_branches/api_graduation/ bot) to every same-class path I found — api_prs, api.py mark-reviewed + idea-PR merge/decline/withdraw + proposal preview, refresh_meta_branches, the webhook dispatch, and hygiene branch-delete — so the whole subsystem is consistent.
Session arc
- Claimed session 0091 (two concurrent in-flight: 0080, 0090 — noted, proceeded autonomously; checkout was clean so no §5.4 worktree conflict).
- Investigated the root cause: confirmed
api_branches._repo_for/_file_path_forreturn the default repo +rfcs/<slug>.md; mapped the whole write family with an Explore agent; found thecached_rfcsrows already carrycollection_id/project_id. Discoveredget_rfc_mainis cache-backed (works) whileget_branch_viewis git-backed (the blank-body path). - TDD'd the resolver (
projects.entry_location/content_repo_for_collection) — RED → GREEN. - Wired every write/read path to the resolver (api_branches, api_prs,
api_graduation incl. module-level orchestrator/state-flip, api.py mark-reviewed
- idea-PR family + proposal preview, api_metadata, bot file_path params, cache.refresh_meta_branches, webhooks, hygiene). Added collection-scoped body-read routes + frontend scoping.
- Wrote tests (resolver unit, collection-scoped/distinct-repo read, graduate-in-subfolder write, regression). backend 677 / frontend 60 green.
- Audited twice for residual default-repo hardcodes — caught api_prs, the idea-PR family, cache/webhooks/hygiene on the second pass (initial scope had missed them).
- Shipped: PR #47 merged → v0.53.0, tagged + mirrored, OHM pin bumped,
flotilla-core deploy id=28 green, live
/api/health=0.53.0, dogfood entry body verified rendering.
Deferred decisions
Autonomous-mode low-confidence calls the driver made and would have liked operator input on.
- Shipped straight localhost→prod, skipping the §9 PPE+E2E stage. The §9 pipeline is localhost+E2E → PPE+E2E → prod. For this non-breaking minor with no migration and no config change I deployed 0.52.3→0.53.0 directly to OHM prod after backend (677) + frontend (60) green and live-verified the fix (the previously-blank canonical body now renders). PPE was the heavy stage for the 0.52.x series (which had migrations); G-15 has none. The deploy is reversible (re-pin + redeploy). Alternative: route through PPE first. Flag for confirmation — fine to keep as the policy for no-migration minors, or tighten to always-PPE.
- Scope expanded past the literal audit list. The task named api_branches / api_graduation / bot; I also fixed api_prs, api.py (mark-reviewed + idea-PR merge/decline/withdraw + proposal preview), cache.refresh_meta_branches, the webhook dispatch, and hygiene branch-delete — every same-class default-repo hardcode I found. Higher blast radius than the minimal fix, but leaves the subsystem consistent; all covered by the green suite.
- Version bump = minor (0.53.0), not patch. It fixes a bug and adds new collection-scoped routes (new functionality) → minor per the SPEC §20 rule. Non-breaking either way.
Next-session prompt
/goal Harden the two §9-surfaced framework fragilities as patch release(s)
shipped localhost→PPE→prod: (1) auth.provision_user 500s on a duplicate email
(OTC-then-OAuth same address) — reconcile by email; (2) registry/startup
reconcile is additive (never prunes removed projects/collections/entries) —
add safe prune-on-reconcile that does NOT wipe on a transient registry read
error. Both real on OHM prod (now 0.53.0). See project_rfc_app_multiproject.md.