Files
session-history/0013/SESSION-0013.1-TRANSCRIPT-2026-05-28T05-30--2026-05-28T05-40.md
T
Ben Stull d5125190ae Session 0018.0 (Wave 9): rewrite legacy session refs in transcript bodies + README scoping
- Rewrite every legacy `Session L` / `Session M.1` etc. reference inside
  transcript bodies to the numeric form (`Session 0012.0` / `Session 0013.1`),
  via a mechanical Python sed pass scoped to canonical-filename transcripts
  only (502 replacements across 39 files; 21 files in this published repo +
  18 sibling files in `~/git/ohm-infra/`). The §23 rename was originally
  filename-only — session 0018.0 reverses that and rewrites the bodies too,
  so cross-references inside a transcript match the filename you'd browse
  to. The mapping table (`A → 0001` … `N → 0014`) lives in
  `SESSION-PROTOCOL.md` §1 (also amended this session) for anyone hitting
  an old external link.

- Amend README.md:
  - New "Where the record begins" section noting OHM started with two
    vibe-coded prototypes (no transcripts; the discipline that produced this
    record didn't exist yet). The transcripts here begin at the
    spec-driven-development phase — not at the literal beginning of OHM.
  - Update the existing "Sessions 0001 through 0013 originally shipped
    under a letter-form naming" paragraph to reflect that body refs are
    now also in numeric form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 09:40:06 -07:00

23 KiB

Session 0013.1 — Subsession transcript

Parent: SESSION-0013.0-TRANSCRIPT-2026-05-28T05-26--<end>.md Date: 2026-05-28 Goal: Draft rfc-app/CONTRIBUTING.md, the rfc-app/SPEC.md analytics chapter, and the ohm-rfc/CONTRIBUTING.md roadmap-guide extension — landing roadmap items #19 (CONTRIBUTING guides + transcript-linked onboarding) and #21 Part B (standing analytics instrumentation discipline). Push feature branches; do NOT tag, do NOT bump VERSION, do NOT move the pin, do NOT deploy.

Outcome: All three deliverables shipped on feature branches; both branches pushed to canonical remotes; one open question settled inline.

  • rfc-app feature/contributing-and-spec-analytics at 213f686 — pushed to origin (git.wiggleverse.org) + benstull (git.benstull.org). One commit: CONTRIBUTING.md (new, ~370 lines) + SPEC.md §21 (new chapter, ~470 lines including the new §15 forward- pointer to §21).
  • ohm-rfc feature/contributing-roadmap-guide at f26fae4 — pushed to origin (git.wiggleverse.org, the only remote). One commit: CONTRIBUTING.md extended with a new "Proposing a change to the OHM roadmap" section (~80 added lines on top of the existing 130-line RFC-content guide).
  • Open question on Gitea anonymous-PR posture: settled inlinehttps://git.wiggleverse.org/user/sign_up returns "Registration is disabled. Please contact your site administrator." The ohm-rfc CONTRIBUTING text reflects this with two paths (Issue-first default + request-account for repeat contributors) and is phrased so the operator can update if registration policy changes.

Pre-subsession state

  • rfc-app: main at 1456c8b (Release 0.17.0). Tags through v0.17.0. No CONTRIBUTING.md existed. SPEC.md 4302 lines, chapter sequence §1..§20.
  • ohm-rfc: main at 8cce148. .rfc-app-version = 0.17.0. CONTRIBUTING.md existed (130 lines, RFC-content guide); no roadmap-change section.
  • ohm-infra (local): most recent transcripts Session 0012.0 (SESSION-0012.0-TRANSCRIPT-2026-05-28T04-22--2026-05-28T05-17.md) + Session 0013.0's main transcript in-progress (SESSION-0013.0-TRANSCRIPT-2026-05-28T05-26--INPROGRESS.md).
  • Branches at start: both repos on main, both clean working trees.

Turn-by-turn arc

Arc 1 — Reconnaissance

Read in order: ohm-rfc/ROADMAP.md (#19 at L405-456, #21 at L549-731, particularly Part B at L625-655 and Part C at L657-731); ohm-rfc/CONTRIBUTING.md (existing 130-line file — RFC-content oriented, no roadmap-change section); ohm-infra/SESSION-PROTOCOL.md (§1 naming, §2 transcript shape, §5 subagent-transcript amendment — binding for this subsession); ohm-infra/SESSION-0011.0-TRANSCRIPT-…md (whole file — clean-small- release + multi-feature-wave + paused-on-secret patterns; the Arc-6 hard-rule incident around secret bytes); ohm-infra/SESSION-0012.0-TRANSCRIPT-…md (whole file — squash-merge integration with #21 Part C identity-lifecycle wiring folded inline across three releases; the addendum cycles around "transcript is the LAST step" discipline); rfc-app/SPEC.md selectively (top, §15 around L2259-2732, §16 + §17 boundaries, §19 around L3183, §20 ending around L4132-4302); the §15 → §16 transition was the candidate insertion-point for the new analytics chapter; rfc-app/CHANGELOG.md opening + the v0.17.0 / v0.16.0 / v0.15.0 entries (lines 1-413) for the strict-descending convention and RFC 2119 keyword usage examples; rfc-app/frontend/src/lib/analytics.js end-to-end (the v0.15.0 wrapper extended in Session 0012.0 with { user_id, properties } identify signature, applyProperties with __setOnce__ sentinel, setUserProperties, anonymize-clears-cache); rfc-app/frontend/src/App.jsx lines 40-90 (the App-level identify call with viewer-derived set + setOnce property bag); rfc-app/frontend/src/components/InviteClaim.jsx lines 40-90 (the v0.17.0 identify-BEFORE-track pattern for the admin-create invite claim).

Arc 2 — Placement decision for the SPEC chapter (settled inline)

The roadmap (and the dispatch brief) said "Place AFTER §15 notifications" and "numbering becomes §16 or whatever's next available." The straightforward read is "insert as §16 and renumber existing §16..§20 to §17..§21." A grep for §16 through §20 references in SPEC.md surfaced 50+ cross-references across the file, many of them to §19.2 and §19.3 specifically.

§19.2 specifically is a load-bearing project noun: it's the defer-decisions queue, named that way in CLAUDE.md, in SESSION-PROTOCOL.md §3, in every session transcript ("§19.2 candidates surfaced"), and in commit messages going back to Slice 5. Renumbering §19 → §20 would invalidate every external reference and require coordinated edits across at least: rfc-app CLAUDE.md, ohm-rfc-app-flotilla CLAUDE.md, ohm-infra SESSION-PROTOCOL.md, all 12 published session transcripts, the auto-memory files. None of those are within the scope of this subsession's docs-PR.

The "or whatever's next available" hedge in the brief covers this case. Settled inline: place the new chapter as §21 (after §20 versioning), with a forward-pointer added at the end of §15's preamble naming §21 as the peer cross-cutting analytics chapter. The new chapter's opening explicitly states the placement reasoning so a future reader knows why §21 isn't between §15 and §16. This is a deliberate deferral of the "right" numbering to a future cleanup session that scopes the cross-repo renumber properly — flagged in the report-back to the driver.

Arc 3 — rfc-app/CONTRIBUTING.md draft

Branched rfc-app at feature/contributing-and-spec-analytics off origin/main at 1456c8b. Drafted CONTRIBUTING.md (~370 lines) covering, in order:

  • Project framing — what rfc-app is, what a deployment is, the difference between framework-PR and content-PR.
  • "How the project actually evolves" with explicit wiggleverse/ohm-session-history pointer + worked-example links into Sessions E (clean small release), I (recovery from deploy fault), K (multi-feature wave + paused-on-secret), L (squash-merge across three parallel features + #21 Part C wiring inline). The session links are to the repo root rather than specific transcript filenames so they don't break when transcripts get renamed via roadmap #23.
  • Contribution flow — Issue-first for structural changes, branch naming convention (matched against the driver session's feature/v<target>-<slug> shape), explicit "do not bump VERSION, do not tag, do not deploy, do not touch any .rfc-app-version pin."
  • CHANGELOG strict-descending convention with a worked entry template (mirroring v0.15.0/v0.16.0/v0.17.0 actual shapes) and the operator-fills-version-at-merge-time note.
  • RFC 2119 keyword discipline per SPEC §20.4 — MUST / MUST NOT / SHOULD / SHOULD NOT / MAY — with the cross-version-upgrade composition rule cited.
  • §19.2 candidate discipline — explicit "don't scope-creep, name the deferral." Cited v0.11.0's three new candidates (Session 0011.0) and v0.15.0's two (Session 0012.0) as worked examples.
  • Test-coverage expectations characterized from the actual ~250-test backend suite. Named specific vertical files (test_admin_create_user_invite_vertical.py, etc.) and the PYTHONPATH=. .venv/bin/pytest -q ergonomic (still §19.2). Noted that there is no frontend test runner today — the discipline is build-clean + backend HTTP contract coverage.
  • Analytics instrumentation checklist (the #21 Part B CONTRIBUTING artifact bullet): (1) named events, (2) autocapture-friendly DOM, (3) replay masking, (4) PR description discipline. Plus a pointer to SPEC §21.6 identity-lifecycle contract for any new claim/sign-in/invite path.
  • Operator-only gestures explicitly enumerated, with the hard no-secret-bytes-in-conversation rule named (Session 0011.0 Arc 6 origin cited).
  • "When in doubt" closer.

The CONTRIBUTING file uses MIT License as the rfc-app LICENSE shape; checked ls rfc-app/LICENSE showed it exists.

Arc 4 — rfc-app/SPEC.md §21 chapter draft

Appended new §21 "Analytics instrumentation and identity" (~440 lines) at the end of SPEC.md (after §20.7), structured as:

  • §21 preamble — what this chapter codifies, framework-neutral posture, the placement-as-§21 reasoning (the cross-ref-preservation rationale from Arc 2).
  • §21.1 event-taxonomy conventions — Title Case "Subject Verb", stability + dashboard-name-match, opaque-ids-only-in-props, casing consistency. The starting v0.17.0 taxonomy (13 events) laid out verbatim.
  • §21.2 required prop families — navigation / auth-state / authored- action / admin-action / invite-side / claim-side. The hashed target_email convention (SHA-256 of normalized lowercased email) named for the #12 per-RFC invite case where the invitee isn't yet a user.
  • §21.3 autocapture-friendly DOM patterns — stable visible text, aria-label on icon-only buttons, data-amp-track-* for repeated rows, data-amp-track-suppress for noise surfaces, with a worked HTML example.
  • §21.4 session-replay masking — credentials MUST mask, PII SHOULD mask, privacy-policy alignment MUST hold, selective redaction preferred over whole-form. The .amp-mask / data-amp-mask convention named with the qualifier "whichever the wrapper's SDK version uses" (acknowledging that the Amplitude SDK's masking attribute name has varied across versions; the wrapper's bootstrap comment is the live source of truth).
  • §21.5 consent-gate contract — five MUSTs: pre-consent no init/no network/no recording; denied→granted init at consent moment; granted→denied setOptOut(true) within one tick; no double-init on re-grant; build-time env-var resolution with one-warn no-op when unset.
  • §21.6 identity lifecycle (per #21 Part C) — sign-in / state-change / sign-out / invite-claim / inviter-side identification, each with MUST language. The User-Signed-Out track-BEFORE-anonymize ordering called out as load-bearing.
  • §21.6.1 set vs setOnce taxonomy — explicit classification rule with worked examples on each side (role / permission_state / passcode_set / device_trusted = set; first_sign_in_at / account_created_at / invited_by_admin_id / invited_at / claim_method = setOnce).
  • §21.7 cohort-shape implications (informative) — four worked questions the dashboard can now answer with the conventions: admin-invite vs OTC funnel by week; passcode-set rate in first session by claim path; per-RFC owner-invited-contributor counts; invite-send-to-claim gap by inviter.
  • §21.8 secret-vs-public framing — overlay binding for the public Amplitude key, secret binding for the Turnstile siteverify secret half. The pbpaste-pipe canonical gesture for OHM-shape deployments named.
  • §21.9 §19.2 candidates surfaced — four (session-replay-specific consent category; bundle-size budget measurement; property-shape CI lint; centralized email-hash helper).
  • §21.10 open question — consent-category split timing tied to the next privacy-policy revision.

Then added a forward-pointer paragraph at the end of §15's preamble (the "section commits the surface..." paragraph) noting §21 as the peer cross-cutting analytics chapter and explicitly saying the two surfaces don't overlap (notifications = signals-of-others-acting; analytics = observability of use).

The chapter uses RFC 2119 keywords precisely throughout. No "should probably" / "might want to" weasel-words inside MUST/ SHOULD steps. Cited frontend/src/lib/analytics.js, App.jsx, InviteClaim.jsx, AcceptInvitation.jsx as worked-example references.

Arc 5 — ohm-rfc/CONTRIBUTING.md extension

Branched ohm-rfc at feature/contributing-roadmap-guide off origin/main at 8cce148. Strategy: extend the existing 130-line RFC-content guide with a new section rather than create a competing file. The existing sections (RFC discussions, RFC PR format, RFC numbering, values, license) are preserved verbatim; the roadmap-change section appends after the License block as a new "Proposing a change to the OHM roadmap" heading + subsections.

Section structure:

  • What kinds of roadmap changes are welcome (5 bullets — add, reshape, claim a version slot, strike-through on ship, §19.2 candidate at the OHM layer).
  • How OHM actually evolves — wiggleverse/ohm-session-history pointer + worked-example links into Sessions J (mid-build version-slot reshuffle when docs-feature took v0.14.0), K (mid-session capture of #16/#17/#18/#19), L (mid-build capture of #20/#21/#22 + Part C wiring + #23).
  • How to submit a roadmap PR — including the now-settled Gitea registration-disabled question.
  • The operator-only gestures — phrased with the operator's "I'm the only one that gets to yolo" quote. Six bullets: flotilla deploy, .rfc-app-version pin bump, secret-set, overlay-set on OHM live, repo rename, Gitea account provisioning, PR merge. Hard no-secret-bytes-in-conversation rule named.
  • The two-layer rule — framework change → upstream rfc-app PR; OHM-specific change → here.
  • "When you're not sure" closer.

Arc 6 — Open question on Gitea registration posture, settled

Per the dispatch brief, probed git.wiggleverse.org:

  • https://git.wiggleverse.org/api/v1/version returned {"version":"1.26.2"} — confirming the instance is up.
  • https://git.wiggleverse.org/user/sign_up returned HTTP 200 but the body contained <p>Registration is disabled. Please contact your site administrator.</p> — definitive answer.

Registration is disabled, meaning outside contributors without a Gitea account cannot directly open PRs. The ohm-rfc CONTRIBUTING text settles on two paths: Issue-first (default; the operator or next driver session turns it into a roadmap entry or opens discussion in the issue thread), or request-account-from-operator (for repeat contributors). The text is phrased so the operator can edit it down to one path if they choose to flip registration policy later.

The rfc-app CONTRIBUTING file doesn't carry this question explicitly — its operator-gestures section already covers "contributors do not have direct push access," and the Issue-first path is the default mode for PRs the operator hasn't expected.

Arc 7 — Commits + push

rfc-app:

  • Staged CONTRIBUTING.md (new) + SPEC.md (modified).
  • Committed 213f686 "docs: CONTRIBUTING.md + SPEC.md §21 analytics chapter" with a HEREDOC commit body naming the deliverables and the placement-as-§21 reasoning. Identity defaulted to Ben Stull <benstull@mac.lan> (matches the operator's prior commits on this repo; no git config edit). Pushed to both remotes: origin (git.wiggleverse.org) and benstull (git.benstull.org) with -u flag; both succeeded.

ohm-rfc:

  • Staged CONTRIBUTING.md (modified).
  • Committed f26fae4 "CONTRIBUTING: add roadmap-change guide + operator-only boundary" with a HEREDOC commit body. Same operator identity. Pushed to origin (the only remote on this repo) with -u; succeeded.

No tags, no VERSION bump, no .rfc-app-version pin move, no flotilla deploy. All operator-only gestures untouched.

Arc 8 — Transcript

Wrote this subsession transcript at ~/git/ohm-infra/SESSION-0013.1-TRANSCRIPT-2026-05-28T05-30--2026-05-28T05-40.md per the §5 subagent-transcript convention. Parent reference in the header. The driver publishes this alongside its own Session-M transcript via ~/git/ohm-infra/scripts/publish-transcript.sh.


Cut state (end of subsession)

rfc-app feature/contributing-and-spec-analytics at 213f686; pushed to origin + benstull. main unchanged at 1456c8b. Nothing tagged.
ohm-rfc feature/contributing-roadmap-guide at f26fae4; pushed to origin. main unchanged at 8cce148. .rfc-app-version unchanged at 0.17.0.
OHM live unchanged — deploys.id=21, v0.17.0. No deploy gesture performed.
ohm-rfc-app-flotilla unchanged at 65c0e55.
Operator-only gestures none touched (no tag, no version bump, no pin move, no deploy, no secret-set).
Subsession M.1 ledger Status
#19 rfc-app CONTRIBUTING.md drafted on feature branch, pushed (origin + benstull)
#19 ohm-rfc CONTRIBUTING.md (extension) drafted on feature branch, pushed (origin)
#21 Part B SPEC.md §21 analytics chapter drafted on feature branch, pushed (origin + benstull); rides the rfc-app CONTRIBUTING commit
#19 anonymous-PR open question settled — registration disabled on the Gitea instance; documented inline with two contributor paths

§19.2 candidates surfaced

  1. SPEC.md §16..§20 renumbering vs. §21-at-end placement. The roadmap brief's "place AFTER §15" naturally implies insert- as-§16-and-shift-§16..§20-down, but renumbering would cascade through 50+ cross-references, including §19.2 (the project's defer-decisions noun, used in CLAUDE.md, the session protocol, 12 published transcripts, and historical commit messages). This subsession chose the lower-risk placement-as-§21 with a §15 forward-pointer, and documented the choice in the new chapter's preamble. A future cleanup session that wants to do the numerically-clean §16 placement needs to scope: rfc-app SPEC renumber + rfc-app CLAUDE.md update + ohm-rfc-app-flotilla CLAUDE.md cross-ref update + ohm-infra SESSION-PROTOCOL.md reference sweep + all 12 published transcript header notes (in wiggleverse/ohm-session-history) + the auto-memory feedback files. None of those are within this subsession's docs-PR scope; flagged for operator's call.

  2. Centralized email-hash helper. §21.2 specifies SHA-256 of the normalized lower-cased email as the hashing function for the per-RFC target_email fingerprint, but no helper exists in the framework today. A small frontend/src/lib/hash.js or backend/app/hash.py that centralizes normalization + hashing would make the contract enforceable rather than relying on per-callsite re-implementation. Captured in SPEC §21.9 as well.

  3. Property-shape CI lint. The conventions in SPEC §21.1 / §21.2 are review-enforced today. A small lint (grep track( / identify( callsites with a property-key allowlist + a PII-name denylist) would catch drift mechanically. Captured in SPEC §21.9.

  4. Frontend test runner. rfc-app/frontend has no test runner today (no vitest, no jest, no playwright — only dev / build / preview scripts). The discipline that the CONTRIBUTING file documents (backend vertical tests carry the regression boundary; frontend ships build-clean) is honest about the current state but is itself a §19.2 candidate worth flagging for a future session — a small vitest setup + a few smoke tests against the wrapper modules (analytics.js, consent.js, api.js) would catch the kind of structural breakage a frontend-only release would otherwise discover at deploy time.


What the driver needs to know

  1. Both branches are pushed and ready for PR. The driver/operator can open PRs by visiting:
    • https://git.wiggleverse.org/ben.stull/rfc-app/pulls/new/feature/contributing-and-spec-analytics
    • https://git.benstull.org/benstull/rfc-app/pulls/new/feature/contributing-and-spec-analytics (the mirror; merge here too if the operator's release flow normally syncs both — Session 0011.0/L precedent is that operator pushes tags to both but PR-opens on one and merges the merge- commit to both. The operator's call.)
    • https://git.wiggleverse.org/ben.stull/ohm-rfc/pulls/new/feature/contributing-roadmap-guide
  2. The SPEC chapter is §21, not §16. This is a deliberate docs-PR-scope-only choice (Arc 2 / §19.2 candidate #1 above). The new chapter's preamble explains the placement to readers. If the operator prefers the §16 insertion with full renumber, that's a separate larger PR that touches CLAUDE.md files and transcript headers across multiple repos — too large for this subsession.
  3. Anonymous-PR question settled inline. Registration is disabled on git.wiggleverse.org (confirmed via the sign-up page). The ohm-rfc CONTRIBUTING text is phrased to update easily if the operator changes that posture later.
  4. No operator gestures were performed. No tag, no VERSION bump, no pin move, no deploy, no secret-set, no overlay-set. Both branches are drafts ready for operator review + merge at the operator's chosen cadence.
  5. No secret bytes in either commit body or in this transcript. The hard rule was honored throughout. The SPEC chapter and both CONTRIBUTING files reference secrets by name only (SMTP_PASSWORD, AMPLITUDE_API_KEY, CLOUDFLARE_TURNSTILE_SECRET).
  6. Suggested PR descriptions (operator can paste verbatim into the new-PR form):
    • rfc-app PR: "Lands roadmap item #19 (CONTRIBUTING + transcript-linked onboarding) and #21 Part B (standing analytics instrumentation discipline) as a single docs commit. Adds CONTRIBUTING.md (~370 lines) covering PR shape, CHANGELOG strict-descending convention, RFC 2119 upgrade-steps discipline, §19.2 candidate practice, test-coverage expectations from the real ~250-test backend suite, the operator-only-gestures boundary, and the #21 Part B analytics-instrumentation checklist (named events / autocapture-friendly DOM / replay masking / PR-description discipline). Adds SPEC.md §21 'Analytics instrumentation and identity' (~440 lines) codifying event taxonomy, required prop families, autocapture DOM patterns, session-replay masking conventions, the consent-gate contract, the #21 Part C identity lifecycle (identify-with-properties on sign-in; setUserProperties on state change; reset on sign-out; identify-BEFORE-track on invite-claim), the set-vs-setOnce taxonomy with classification rule, cohort-shape implications, and four new §19.2 candidates. Placed as §21 rather than §16 to preserve the load-bearing §19.2 / §19.3 cross-reference graph; reasoning in the chapter preamble. §15 carries a new forward- pointer naming §21 as the peer cross-cutting analytics chapter. No code change; no VERSION bump; rides a future release or lands as a no-bump docs commit at operator discretion."
    • ohm-rfc PR: "Lands roadmap item #19's OHM-side artifact. Extends the existing 130-line RFC-content CONTRIBUTING.md with a new 'Proposing a change to the OHM roadmap' section (~80 lines) covering roadmap-change kinds, the wiggleverse/ohm-session-history pointer with worked-example links into Sessions J/K/L, the PR-submission gesture (with the open question on Gitea registration settled inline: git.wiggleverse.org currently has registration disabled, so contributors choose between Issue-first and request-account paths), the explicit operator-only-gestures boundary with the 'I'm the only one that gets to yolo' quote, and the two-layer rule. No version target."

Files written

  • /Users/benstull/git/rfc-app/CONTRIBUTING.md (new)
  • /Users/benstull/git/rfc-app/SPEC.md (modified — new §21 chapter
    • §15 forward-pointer paragraph)
  • /Users/benstull/projects/wiggleverse/ohm-rfc/CONTRIBUTING.md (modified — new "Proposing a change to the OHM roadmap" section appended after the License block)
  • /Users/benstull/git/ohm-infra/SESSION-0013.1-TRANSCRIPT-2026-05-28T05-30--2026-05-28T05-40.md (this file)