add SESSION-M.1-TRANSCRIPT-2026-05-28T05-30--2026-05-28T05-40.md

This commit is contained in:
Ben Stull
2026-05-28 06:54:22 -07:00
parent 62bc259136
commit 7c7c478273
@@ -0,0 +1,460 @@
# Session M.1 — Subsession transcript
> Parent: `SESSION-M-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 inline** —
> `https://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 L
(`SESSION-L-TRANSCRIPT-2026-05-28T04-22--2026-05-28T05-17.md`) +
Session M's main transcript in-progress
(`SESSION-M-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-K-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-L-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 L 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 K)
and v0.15.0's two (Session L) 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 K 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-M.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 K/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-M.1-TRANSCRIPT-2026-05-28T05-30--2026-05-28T05-40.md`
(this file)