# Contributor Sessions Log Rolling log of active sessions on the ItsGoin repository. Every contributor — Lead or Jr — appends an entry on session start and updates it on session end. Newest entries at the top. See `CONTRIBUTING.md` for the protocol. See `AGENTS.md` for the Claude-specific session-start checklist. --- ## 2026-04-24 — primary Claude (Lead) — `docs/fof-spec-layer1-bio-grants` **Started**: April 24 UTC **Instance**: Scott's primary Claude (Lead) **Issue**: none (spec refinement) **Branch**: `docs/fof-spec-layer1-bio-grants` **Scope**: Fold Scott + Opus's Layer 1 design answer into the spec. Vouch distribution moves from DM-wrapped `VouchGrant` to HPKE-sealed per-recipient wrappers carried in the voucher's bio post, leveraging existing bio-post CDN propagation and HPKE (RFC 9180) key privacy for recipient anonymity. **Key design commitments added to Layer 1**: - HPKE RFC 9180 (DHKEM X25519 + HKDF-SHA256 + ChaCha20Poly1305) for per-recipient wrappers; one ephemeral pubkey per batch; 48B per wrapper. - HKDF `info = "itsgoin/vouch-grant/v1/" || bio_post_id` — recipient-free (non-negotiable for key privacy). - No prefilter tag on grants (no prior shared secret); full X25519 trial at ~60µs per wrapper per persona is tolerable (≤90ms even at 512×3 worst case). - Scan policy: auto-scan bio posts of followed personas; manual "check bio" gesture for non-followed; scan cache keyed by `(scanner_persona, bio_author, bio_epoch)`. - Bucket-padding (64/128/256/512) and per-publish wrapper shuffle for size/position opacity. - No separate `vouches_issued` table on the wire; bio post IS the authoritative record. Local-only `own_vouch_targets` tracks what the persona has granted. - Incremental grant-as-comment path (Scott's suggestion for avoiding full republish) deferred; v1 ships with full republish per change. **Completed**: - Rewrote `docs/fof-spec/layer-1-vouch-primitive.md` end-to-end. - README updated: Layer 1 scope line + added bio-post integration bullet. - Self-merged to master. **Pending**: - Opus confirmation passes still open on other layers (WrapSlot byte layout, AEAD choice for body, padding schemes). - Layer 2–6 untouched in this pass. **Stopping point**: Scott asked to hold merges until Layers 2–6 iterations complete. Branch stays open locally and on Forgejo; continuing to stack commits on it. ### Update 2026-04-24 — Layer 2 rewrite (CDN-level verification) **Scope**: Scott shared Opus's Layer 2 design answer. Folded in. **Design commitments added**: - **Per-`V_x` signing keypair `(pub_x, priv_x)`** — replaces single per-post `pub_post/priv_post`. CDN can now verify comment signatures against a published `pub_post_set` before forwarding, killing the bandwidth-amplification DoS an admitted FoF member could otherwise mount. - **Dual-derivation wrap slot**: `read_slot → CEK`, `sign_slot → priv_x`. One unwrap yields both capabilities. Slot structure is shared with Layer 3 (canonical form lives here). - **Comment body encrypted under `CEK_comments = HKDF(CEK, "comments")`** — Mode 2 comments are genuinely FoF-read-gated now, not just FoF-sign-filtered at render (strengthening vs skeleton). - **Propagation-node four-check accept rule**: valid `pub_x_index`, not in `revocation_list`, `group_sig` verifies, `identity_sig` verifies. Any fail → drop without forwarding. - **Author-signed revocation diff** appended to post header; CDN honors on next sync. Per-chain revocation at propagation layer. - **`pub_x_index` is a per-post pseudonym** — leaks "these N comments came through the same chain" within a single post; re-randomizes across posts. Accepted tradeoff for CDN-level DoS resistance. - **v1 ships Ed25519 inline** (~77KB header at 500 vouchees). **PQ future** requires Merkle-commit over `pub_post_set` with per-comment inclusion proofs; deferred but spec shape doesn't preclude. **Files touched**: - `docs/fof-spec/layer-2-mode2-fof-comments.md` — rewritten end-to-end. - `docs/fof-spec/layer-3-mode1-fof-closed.md` — prominent "partially superseded" banner added; body retained pending reconciliation when Scott + Opus review Layer 3. - `docs/fof-spec/README.md` — glossary updated (`pub_x`/`priv_x`, `pub_post_set`, `revocation_list`); integration bullet updated for new `InlineComment` fields + CDN accept rule. **Open questions I raised back to Scott** (awaiting his answer before finalizing): 1. `(pub_x, priv_x)` lifecycle: generated at `V_x` genesis (Layer 1) and stable across posts, vs regenerated per-post by author. Lead leaning per-post. Needs confirmation. 2. `pub_post_set` padding vs `wrap_slots` padding — real/dummy alignment when dummies shouldn't be indexable by `pub_x_index`. 3. Non-FoF rendering of comment count (reveal engagement? suppress?). 4. Who holds `priv_me` (author) — generated alongside `V_me` at Layer 1, vs per-post regeneration. Same as #1 but for author's own entry. **Pending**: - Scott reviews / answers open questions. - Layer 3 reconciliation when Scott + Opus get to Mode 1. - Layers 4–6 iterations. **Stopping point**: commit `b8b38a6` (Layer 1) + new commit for Layer 2 both on branch; not merged. Awaiting Scott. ### Update 2026-05-13 — design.html FoF section (20a) added Added a new section `20a. Friend-of-Friend Visibility` to `website/design.html`, sitting between Encryption (20) and Delete Propagation (21). Marked all subsections `badge-planned`. Layer table at the bottom shows ship status per layer. **Key writing decisions**: - Up-front disambiguation note: this section's "vouch" is the cryptographic V_me primitive, distinct from the directory-vouch system in section 27. Symmetric disambiguation note added to section 27 pointing the other direction. - User-facing 4-level model (Public / Friends-only / FoF / Custom-v2) leads. Crypto primitives follow. - Mode 1 vs Mode 2 split called out via `card` divs. - CDN-level verification highlighted as the propagation-DoS resistance story. - Revocation lifecycle: three `card` blocks — per-post default, V_me rotation, opt-in cascade + key-burn. - PQ-readiness explicitly addressed (symmetric primitives PQ-safe; Ed25519 → ML-DSA-65 swap path noted). - Cross-ref to `docs/fof-spec/` for implementation detail. **Tables updated**: - Visibility variants table (in section 20) now has a `FoFClosed` row with overhead + bucketed-audience note. - New layer-status table at the bottom of section 20a shows the five ship-able layers. **Other touched**: - TOC entry added (`20a. Friend-of-Friend Visibility`). - `reference_design_index.md` auto-updated by the design-index hook on save. - Section 27 (Directory) got a reciprocal disambiguation note pointing at section 20a. **Files in this commit**: - `website/design.html` - `sessions.md` (this entry) Branch state: still `docs/fof-spec-layer1-bio-grants`, still unmerged. Implementation can now begin from a coherent public design + internal spec. ### Update 2026-05-13 — Layer 4 written (rotation + revocation + key lifecycle) Iterative session with Scott. Recap of where the model landed: **Rotation/revocation model (now in spec)**: - Default narrowing of comment authority on a post = Layer 2 revocation (existing mechanism). No new wire primitive. - Advanced narrowing of read access = full re-issue with `supersedes_post_id` link. Discouraged due to network overhead. - `V_me` rotation = the persona-wide revocation primitive. Generate new V_me, distribute via next bio-post batch to non-revoked vouchees only. Revoked person retains old V_me. - Receiver-chain model: receiver appends new V_me to `vouch_keys_received` (does NOT overwrite). Trial-unwrap iterates the chain. UX-wise the "current" key is the newest; older epochs are archived but kept for historical decrypts. - **Grandfather-by-default**: CDN is V_me-blind, so rotation does NOT auto-cascade comment deletion. Revoked vouchee keeps comment authority on old posts unless the author opts to cascade per-pub_x revocations. - **Per-post cascade is opt-in**: author can query a local `own_post_slot_provenance` table to find pub_x's sealed under V_me_old in any of their posts, then publish per-pub_x RevocationEntries to cascade. - **Key-burn primitive (new, optional)**: signed `KeyBurnDiff` swaps an old wrap_slot for a new one in-place on a specific post. Used when V_me leaked and the author wants to scrub it from the CDN copy of old posts. Body CEK unchanged; affects future fresh-decrypts only. **Cryptographic stack confirmed (Scott reconfirmed)**: - Body encryption: symmetric ChaCha20-Poly1305 under CEK. PQ-safe. - Wrap_slots: AEAD under V_x. PQ-safe. - Comment signing: **asymmetric Ed25519** (per-V_x per-post `(pub_x, priv_x)`). NOT PQ-safe; ML-DSA-65 migration deferred. Scott confirmed the asymmetric-for-signing tradeoff is intentional — it's what makes CDN-level bandwidth-DoS filtering work. **Files touched in this round**: - `docs/fof-spec/layer-4-keypair-rotation.md`: full rewrite from skeleton. - `docs/fof-spec/layer-1-vouch-primitive.md`: rotation language updated to point at Layer 4's append-only model; multi-epoch UI hook added. **Branch state**: `docs/fof-spec-layer1-bio-grants` (despite the name, holds all Layer 1–4 spec work). Commit pending. Not merged per Scott's standing instruction. **Pending**: - Layer 5 (unlock cache + prefilter): existing skeleton text still reflects single per-post keypair model. Needs reconciliation with per-V_x model from Layer 2. - Layer 3 (Mode 1): partially-superseded banner still present. Needs Scott/Opus reconciliation pass. - Layer 6 (revocation): stub still. Largely obviated by Layer 4 work. ### Update 2026-04-24 — Layer 3 round 2 (last two open questions) Two follow-up questions resolved: - **Access-grant slot ordering**: **append at tail** (not re-shuffle). I'd initially overcorrected to a "switch comments from index to pub_x bytes so shuffles are free" change; Scott reverted that and clarified the choice. Append-at-tail preserves `pub_x_index` stability across the post's lifetime — already-stored comments stay verifiable, no write amplification on grant. Accepted positional-recency leak (tail = newest grants). - **Minimum slot bucket**: **8**. Singleton/tiny-set posts pad up to 8 slots. Brand-new personas don't publish "I have no vouchees" headers. **Files touched**: - `docs/fof-spec/layer-2-mode2-fof-comments.md`: access-grant lead decision made explicit about append-at-tail and index stability. - `docs/fof-spec/layer-3-mode1-fof-closed.md`: minimum-8 floor added to padding lead decision; both open questions moved to Resolved. - `sessions.md`: this entry. ### Update 2026-04-24 — Layer 3 round 1 + cross-cutting padding rule (corrected) Scott talked to Opus and resolved Layer 3 open questions + introduced a unified padding rule that supersedes Layer 2 round 2's `rand(32..=128)`. **First-pass misread (corrected by Scott):** I initially wrote the rule as "power-of-2 up to 256, then `real + rand(0..=256)` above." That's wrong — the rule is **bucketed throughout**, not random above the threshold. **Bucketed padding rule (applies to both slot count and body size)**: - ≤256 real units → next power-of-2 bucket (8, 16, 32, 64, 128, 256). - >256 real units → next linear-step bucket: +128 step for slots (384, 512, 640, …), +256KB step for body bytes (512KB, 768KB, 1024KB, …). - Deterministic. Author publishes `next_bucket(real)`; dummies fill the gap. Why this is stronger than random: observers learn the bucket but never the position within it. Across multiple posts from the same author, the bucket is stable until the author crosses a boundary — so no "min over many posts" attack converges tighter than the bucket bound. Random padding would have leaked `min(observed) - max_noise` as a floor. Linear-step above 256 vs pure power-of-2: avoids the 2× waste of jumping 256→512 for an author with 257 vouchees. Above 256, step buckets are 128 (slots) or 256KB (body) so worst-case in-bucket overhead is bounded (~33% at the worst spot). Applies uniformly to slot count and body size. **Other resolved Layer 3 questions**: - Custom mode UI deferred. v1 ships three presets only: Public / Friends-only / FoF. - Slot dedup at `V_x` byte level. One slot per unique key. - Body-length padding adopted. **Files touched**: - `docs/fof-spec/layer-3-mode1-fof-closed.md`: Lead decisions updated (hybrid padding, dedup, three-preset UI); open questions split into still-open + Resolved; ship criteria updated. - `docs/fof-spec/layer-2-mode2-fof-comments.md`: padding rule promoted to hybrid scheme; size budget rewritten with three regime examples; privacy section rewritten for two-regime analysis; Resolved bullet superseded with pointer. - `sessions.md`: this entry. **Still-open Layer 3 questions worth flagging to Scott**: 1. Access-grant ordering — does appending a new slot re-shuffle the full `wrap_slots` / `pub_post_set` (preserves the random-order privacy property but invalidates `pub_x_index` values in already-stored comments), or is it append-only (`pub_x_index` is stable but tail-positional leak says "these are recent grants")? Lead leaning: **append-only**; index stability matters for revocation and stored-comment verification. 2. Minimum slot-count floor for tiny authors. Power-of-2-of-1 = 1, which leaks "this persona has one vouch (probably just themselves)." Lead leaning: minimum bucket of 8. **Pending**: Layers 4–6 iterations. Scott to confirm two flagged questions. ### Update 2026-04-24 — Layer 2 round 2 (Scott answers all 5 questions) Scott resolved all five open questions: 1. **Per-post `(pub_x, priv_x)`** — confirmed. 2. **Random-count dummy padding** (`rand(32..=128)`) replaces power-of-2 buckets, with dummy pubkeys in `pub_post_set` so `.len() == wrap_slots.len()`. Across multiple posts from the same author, an observer cannot even establish a reliable floor for the real vouch-set size. 3. **Non-FoF comment UX**: "Comments are private" affordance with optional "Request access via DM" button. No count leak. 4. **Author's own entry in `pub_post_set`** — confirmed. 5. **Revocation is retroactive delete + forward.** File-holders delete locally-stored comments signed by the revoked `pub_x`, then propagate the diff. Stronger than stop-forwarding — prior garbage is cleaned up as the diff sweeps the mesh. **New primitive**: **access-grant author comment**. Author can retroactively widen a post's read-set by publishing an author-signed special comment appending a new `WrapSlot` + `pub_post_set` entry. Lets a newly-vouched persona gain read + comment access without republishing the whole post. Answers the "non-FoF requests access via DM, author approves" UX loop. **Files touched**: - `docs/fof-spec/layer-2-mode2-fof-comments.md` — updated Lead decisions, post-header, revocation flow (retroactive), added Access-grant author comment section, updated Privacy tradeoff (size-leak analysis with random padding), Open questions split into unresolved + Resolved, size budget, ship criteria. - `sessions.md` — this entry. Commit pending. --- ## 2026-04-23 — primary Claude (Lead) — `docs/fof-spec-skeleton` **Started**: late April 23 UTC **Instance**: Scott's primary Claude (Lead role) **Issue**: none (spec-drafting work; hand-off to Opus for crypto fill-in) **Branch**: `docs/fof-spec-skeleton` **Scope**: Skeleton spec for Friend-of-Friend (FoF) post gating. Lays out the per-person vouch-key (`V_me`) primitive, four visibility levels (Public / Friends-only / FoF / Custom), Mode 1 (`FOF_CLOSED`) and Mode 2 (public post + FoF comments), and a six-layer implementation plan. Crypto byte layouts and algorithm specifics are marked `TBD — OPUS` for Opus to fill in. **Completed in this session**: - `docs/fof-spec/README.md` — top-level overview, user-facing model, design properties, layering plan, out-of-scope, glossary, integration with existing primitives. - `docs/fof-spec/layer-1-vouch-primitive.md` — `V_x` keys, per-persona keyring, `VouchGrant` wire format (DM-wrapped). - `docs/fof-spec/layer-2-mode2-fof-comments.md` — `CommentPolicy::FriendsOfFriends`, `pub_post` / `priv_post` / wrap-slot primitives, `group_sig` + `vouch_mac` on comments. - `docs/fof-spec/layer-3-mode1-fof-closed.md` — `PostVisibility::FoFClosed`, wrap-slot byte layout, anonymous 2B prefilter, power-of-2 slot padding. - `docs/fof-spec/layer-4-keypair-rotation.md` — `PostKeyRotation` record, explicit `pub_post_index` on comments, per-post re-gating. - `docs/fof-spec/layer-5-prefilter-and-cache.md` — `vouch_unlock_cache`, `vouch_unreadable_posts`, author-direct fast path, keyring-change retry sweep. - `docs/fof-spec/layer-6-revocation.md` — stub; candidate designs A–D; Lead leaning is coarse-rotation with UX polish (Candidate D); revisit after 30 days of production data. **Pending after this PR merges**: - Opus review pass: fill in `TBD — OPUS` markers (AEAD specifier, key sizes, WrapSlot byte layout, prefilter tag algorithm confirmation, epoch granularity, etc.). - Lead re-review after Opus fills in crypto. - Per-layer branch schedule for implementation (Layer 1 ships first, independently exercised). **Stopping point**: session ending after Lead self-merges `docs/fof-spec-skeleton` to master. Branch to be deleted locally + remote. --- ## 2026-04-23 — primary Claude (Lead) — `chore/workflow-adoption` **Started**: late April 23 UTC **Instance**: Scott's primary Claude (Lead role per `feedback_senior_role.md`) **Issue**: none yet (inaugural PR; this is the chicken-and-egg case noted in CONTRIBUTING.md) **Branch**: `chore/workflow-adoption` **Scope**: Introduce the multi-contributor workflow to the repo. Creates `CONTRIBUTING.md`, `AGENTS.md`, and this file (`sessions.md`) with a seed entry. **Pre-existing state at session start**: - v0.6.2 shipped end-to-end earlier today: APK, AppImage, CLI, anchor (PID 3475521, up since ~17:39 UTC). - Last merged-to-master commit before this branch: `2ce668a` — People-tab rewrite (recency sort, profile-post Discover, bio modal, ignore primitive, per-author feed filter). - Active artifacts on `itsgoin.com/public_html/`: `itsgoin-0.6.2.apk` (183.7 MB), `itsgoin_0.6.2_amd64.AppImage` (177.7 MB), `itsgoin-cli-0.6.2-linux-amd64` (40.8 MB). - No other contributors active. **Completed in this session (before this commit)**: - Designed the Lead role + amendments to the base workflow (hotfix carve-out, partnered build/deploy go-no-go, Lead-pulls-queue review pattern, re-evaluation triggers, Scott's contributor-alignment role, Lead self-merge authority). - Saved `feedback_senior_role.md` to instance memory. - Wrote `CONTRIBUTING.md`, `AGENTS.md`, `sessions.md` (this file). Originally drafted the agent guide as `CLAUDE.md` but that filename is `.gitignore`d at the repo root because it has historically been a credential-leak vector; switched to `AGENTS.md` with an explicit security banner. - Iterated on Scott's role: initial draft put him in the PR-routing / build-authorizer position; revised to watch contributor alignment + partner on ship, Lead self-merges. **Pending after this PR merges**: - Phase 0 prereqs from `CONTRIBUTING.md`: Forgejo CI (`cargo check --workspace` + `cargo test -p itsgoin-core` on push + PR), branch protection on master (require PR + 1 review + green CI), second Forgejo account + SSH key for Jr Claude(s). Scott coordinates. **Stopping point**: session ending — Lead self-merged this PR to master (inaugural exercise of the self-merge authority the PR itself establishes, per Amendment 6). Branch `chore/workflow-adoption` deleted locally + remote. ---