{"path":"research/dogfood-run-1-friction-log.md","content":"# Dogfood Run 1 — Friction Log (live notes)\n\n**Date**: 2026-07-06\n**Runner**: Fable (AI), using Deliberus as a real contributor via `scripts/dogfood_driver.py` (full production API surface in-process; only the OAuth handshake bypassed; writes land in the shared production stores, visible on deliberus.com)\n**Topic**: Retribution — the first residue experiment. Two genuinely opposing texts from the classic debate pair: Ernest van den Haag, \"The Ultimate Punishment: A Defense\" (Harvard Law Review 1986, PBS Frontline mirror) versus Hugo Adam Bedau, \"The Case Against the Death Penalty\" (ACLU). Chosen per the substance-over-meta testing philosophy and because the July 2026 weighting-decomposition research names retribution's residue precisely (\"culpable wrongdoing makes suffering non-instrumentally fitting\") — so we can measure whether real decomposition reaches it.\n**Standing prediction being tested**: decomposition on real material stalls at `open_sorry`, well short of typed residues, because the weighing scheme does not exist yet.\n\nThis file is a running log, written AS friction occurs, per the run's mandate: note issues, headaches, confusions; propose architectural improvements from actual use.\n\n---\n\n## Friction found BEFORE the run started\n\n**F1 — Owner-suppression never engaged on contribution notifications (BUG, fixed in-run).** All four `user_contribution` call sites and the `/extract/stream` completion call omitted `user_email`, so every contribution fired a high-priority push regardless of who made it — the Session-13 SNR design's owner-silence was dead code on these paths. A contribution sprint would have spammed the founder's phone. Fixed and deployed as part of this run's prep.\n\n**F2 — No write-path identity for AI agents (ARCHITECTURAL GAP).** The platform's thesis names AI agents as first-class readers, and the agent-readable surface serves them — but there is no way for an agent to *contribute*: all write endpoints require a Google OAuth session. Dogfooding as an agent required an in-process auth override. If agents are to be consumers of the graph, the natural next step is scoped agent credentials (API key tied to an attributed agent identity, with its contributions marked as such and rate-limited on their own tier). This also matters for the human-testing phase: \"my friend's agent read the graph and answered a CQ\" is exactly the loop the alignment-infrastructure case describes.\n\n**F3 — Rate limits are human-paced (observation, not a bug).** Extract 5/min, decompose 5/min, evidence and CQ answers 10/min. Right for humans; an engaged agent contributor hits them immediately. Fine for now — logged as a design input for any future agent write-tier.\n\n---\n\n## During the run\n\n**F4 — One capacity spike killed every extraction (BUG-CLASS, fixed in-run).** Google's pools shed load under demand spikes; during the run, `gemini-3-flash-preview` instant-503'd and `gemini-3.5-flash` slow-failed at ~52s per attempt, while the lite pool stayed healthy. The pipeline had no cross-model fallback, so one spike meant every extraction died after ~60s of single-model retries — with the SSE stream just going silent. Fixed: capacity-fallback chain in `llm_call` (capacity errors only; validation/auth errors still raise immediately), plus a `DELIBERUS_GEMINI_MODEL` operational override.\n\n**F5 — Inline extractions leave no forensics row (OPEN).** The `extraction_attempts` table (the Session-13 \"every failure leaves a row\" guarantee) is wired to the Temporal path only; `/extract/stream` failures are invisible to it. The Apr-1 lesson — persistent failure observability or the pipeline appears to work while silently losing users — has a surviving blind spot on exactly the path the landing page uses as inline fallback.\n\n**F6 — Split-brain persistence + dishonest success (BUG, fixed in-run).** Extraction 1 stored 105 claim nodes to FalkorDB, then the Postgres save died — silently — and the stream still reported *\"quality score: 100%\"* and a success result. Net user experience: told success, extraction page 404s, claim pages work. Root cause: the pooled asyncpg engine binds connections to the loop that created them, and the sync SSE generator called `asyncio.run()` from a threadpool thread (fresh loop per call) — the exact class of structural bug that fails non-deterministically in production too. Fixed: DB saves scheduled onto the app's main loop; on failure the stream now says so honestly, the result carries `postgres_saved`, and an `extraction_failed` notification fires.\n\n**F7 — Stream path has no cleanup-at-start (OPEN).** The Temporal workflow deletes a source's prior partial state before re-extracting (`cleanup_activity`); the stream path doesn't, and claim IDs are random UUIDs — so re-extracting the same URL duplicates every claim. Recovery from F6 required hand-running the cleanup Cypher. The stream path should get the same cleanup step (or store should be source-idempotent).\n\n**F8 — Never truncate the recovery artifact (self-inflicted, fixed).** The driver truncated all SSE lines to 400 chars — including the final result event, which carries the full combined payload and is the natural recovery artifact when a post-store stage fails. Both partial extractions could have been repaired from their logs without re-extraction if the result line had been kept whole.\n\n**F9 — Claim-rich, edge-poor at extraction time (OBSERVATION → analysis input).** Van den Haag: 10 arguments → 39 atomic claims but only 9 relationship edges. ACLU: 49 arguments → 201 claims, 10 edges. The relationships pass connects argument-level theses; the fine-grained claim mesh gets its structure from CQ scaffolding and embedding auto-connect (263 cross-extraction candidates on the second run), not from argued edges. Load-bearing for the residue experiment: the decomposition road from a thesis down toward a typed residue mostly does not exist at extraction time — it must be walked via the correction UX. This is the baseline the weighing scheme is meant to change.\n\n**F10 — Health checks lie during load-shedding (ops insight, generalizable).** Tiny ping calls succeeded while 24K-char extraction calls were rejected by the same model — capacity probes must be real-shaped, not one-token pings.\n\n**F11 — The pipeline's own self-eval confirms the atomicity complaint.** On the ACLU text, the self-evaluation pass reported verbatim: *\"a lack of atomicity in several claims where two distinct points are bundled together,\"* plus verbatim duplicate claims across sections and occasional hallucinated causal links (197 of 237 claims passing all checks). The founder's April judgment (\"claims aren't atomic enough\") is now confirmed by the system's own quality pass on real material — and section-chunked long texts (49 argument structures) add a duplication axis single-pass texts don't have.\n\n**F12 — CQ scaffolding dominates the reading surface (UX).** The extraction page's claim list leads with dozens of templated `cq_*` polarity claims (\"...is the most efficient means to achieve the goal of...\") before any atomic claim from the text. As a reader I had to grep past the scaffolding to find the substance. The CQ layer is philosophically right and visually dominant — presentation should separate the two claim populations.\n\n**F13 — The sorry frontier grows faster than contributions close it.** Answering one CQ generated 6 new CQs; adding one evidence claim generated 13. Philosophically correct (no copout axioms, applied to my own contributions), but the work-queue expands combinatorially with engagement. Prioritization (which open questions matter) is going to matter more than raw CQ generation. Depth-budgets or importance-ranking on the frontier are design questions worth taking seriously before human testers meet this.\n\n**F14 — No agent/delegated identity (extends F2 to writes-as-attribution).** My votes and contributions were recorded under the owner's email (deliberately, to exercise owner-suppression) — but the deeper point stands: there is no way for an agent's contributions to be honestly attributed as agent contributions. The extraction shows \"Analyzed by: Fable (AI dogfood)\" (name field), while votes show only the email. Identity granularity is a real gap for the platform's own agents-as-consumers thesis.\n\n**F15 — Manual weighing-decomposition works but produced one meta-claim.** The decompose endpoint faithfully converted my five-part weighing analysis into sub-claims — but also emitted a summary claim (\"his position is composed of...\") that is *about* the decomposition rather than *part of* it. Harmless, slightly noisy; the future weighing scheme's structured CQs would avoid this by construction.\n\n---\n\n## What the run proved (results)\n\nThe full residue-experiment loop closed, in production, in one session:\n\n1. **Two genuinely opposing texts extracted** — van den Haag's defense (8 arguments, 38 claims) and Bedau's ACLU case (49 arguments, 201 claims), both with `postgres_saved: true` after the split-brain fix, both live on deliberus.com.\n2. **Auto-connect discovered the debate**: cross-extraction ATTACKS edges now link van den Haag's dignity argument to the ACLU's cruelty cluster — the two texts argue with each other in the graph, unprompted.\n3. **The weighing claim was found where predicted**: `claim_7582f58dbae7`, \"In the context of the legal system, justice is morally more important than equality\" — a `value_premise`, the literal weighing.\n4. **Manual weighing-decomposition reached the residue**: applying the CQ1–8 schema by hand (covering value, compression check, scope, aggregation rule, residue) produced a 10-child decomposition whose leaf `claim_901c11589f34` — *culpable wrongdoing makes punishment inherently fitting* — is exactly the fittingness residue the July research named in advance.\n5. **The instruments read it correctly, live**: the claim page's Scrutiny state flags 4 unsupported value premises (the copout-axiom signal) and `partially_exposed` completeness; disagreement-preservation scores the vdH extraction 0.906 with flagged near-flat pairs; and the residue map moved from empty to its first classified terminus (1 fittingness).\n6. **The standing prediction held**: at extraction time the graph is claim-rich and edge-poor, and the road from thesis to typed residue does not exist until walked by hand. That is the empirical case for building the Argument-from-Weighing scheme — now evidence-backed, not just researched.\n\n## Architectural proposals (from use, not spec) — statuses as of Jul 6 evening\n\n1. ~~**Build the weighing scheme**~~ **SHIPPED (Jul 6, same arc)** — founder ratified the provenance split + sacredness brake; `deliberus/weighing.py` + stream pass + open-endpoint live; the corpus backfill opened 4 weighings including this run's justice-vs-equality claim. The manual descent this run required is now a paved road.\n2. **Separate CQ scaffolding from substance** — **SHIPPED for the agent surface** (extraction `.md`: atomic claims first, scaffolding folded into a labeled tail section, fully listed; the web extraction page was already scaffolding-free, rendering from the combined payload). (F12)\n3. **Port cleanup-at-start + forensics to the stream path** — **SHIPPED, live-verified end-to-end** (attempt rows started→completed/empty/failed; confession wrapper on crashes; provenance-scoped replacement). Shipping it surfaced a deeper principle: **machine output is regenerable, human work is not** — cleanup deletes only machine-provenance claims (`extracted`/`implicit`/`cq_*`); human contributions survive re-extraction, orphaned rather than destroyed. The correction endpoints were stamping user work as `extracted` (root cause fixed: decompose/evidence/CQ-answer now stamp `claim_kind='human'`; 12 past contributions migrated). The unscoped Temporal cleanup (latent corpus-wide Question deletion) now shares the same scoped function. (F5, F6, F7)\n4. **Agent identity tier**: scoped write credentials with honest attribution and own rate limits — the agents-as-consumers thesis applied to contribution, prerequisite for agent-participation experiments. (F2, F14) **Open.**\n5. **Frontier prioritization**: rank the open sorry-frontier by leverage so engaged contributors meet a queue, not an explosion. (F13) **Open** — the hinge score (shipped) is the natural ranking signal.\n6. **CQ dedup within an extraction** — **the mint-time slice SHIPPED** (concept-term normalization at mint + reads; 11 case-variant Concept nodes merged live; 71 orphan Questions swept). Cross-edge question canonicalization remains with the open claim-sameness fork per §I3. (F12's volume driver)\n7. **Hinge score** — **SHIPPED same day** (`GET /claims/{id}/hinge`; see §I2/§I4).\n\n---\n\n## Post-run deliberation insights (Jul 6 evening — from working the run's findings with the founder)\n\n**I1 — The inversion principle: the machine should hold the user's hand, not the reverse.** The hand-holding inventory decomposes into four unequal burdens: knowing *which questions* to ask (the CQ1–8 schema — most of the real work), knowing *where* to dig (spotting the load-bearing `value_premise` among scaffolding), doing the philosophy *up front* (one freeform essay the LLM merely formats — backwards from \"structure is output, never input\"), and knowing *the bottom* when hit. The reduction is not better documentation but an inversion: the system detects the weighing, asks ONE plain-language question at a time, proposes each split, and the user taps confirm / edit / redirect. Steps become taps; the essay becomes eight small answers; the terminus arrives as a proposal. The weighing scheme + terminus classifier + leverage-ranked frontier are the three pieces of that inversion (the first two shipped Jul 6; the leverage-ranked frontier remains proposed). (Honest caveat: this run dogfooded the API, not the guided web flow — the existing decomposition-readiness cues may soften the *where* burden, though nothing existing addresses the other three.)\n\n**I2 — Pebble ≠ crux ≠ double-crux, and crux-hood is computable.** A *residue* is where one branch bottoms out; a *crux* is a claim whose flip would flip a conclusion; a *double-crux* is a crux BOTH sides acknowledge — a social achievement the graph can invite but not decide. Run 1's fittingness pebble is a genuine crux for van den Haag's desert pillar, NOT the whole debate's crux (Bedau's case has independent pillars that survive granting it), and not yet a double-crux (no ACLU claim attacks that leaf; their descent hasn't been walked to meet it). The computable part shipped same-day as **the hinge score** (`GET /claims/{id}/hinge`): clamp each descendant granted/denied, measure the root's strength swing through the shipped QEM semantics. First live reading on the weighing claim: baseline 0.489, all ten children hinging equally at 0.022 — a flat ranking that truthfully reports an unengaged subtree; differentiation arrives with engagement. Candidate follow-up UX: when opposing descents approach the same pebble, the system can *invite* the double-crux (\"both sides' reasoning appears to stand on this — confirm?\").\n\n**I3 — CQ dedup sits below the philosophical waterline (the mint-time carve).** The claim-sameness fork ([claim-sameness-philosophical-readings.md](claim-sameness-philosophical-readings.md)) is deliberately open, and correctly so — its objections (the *différend*, standpoint-flattening, sense/reference collapse) all target merging *human* expressions. But the thirteen-questions-in-a-dozen-costumes problem is **system-minted templated text**: the generator holds the template ID and slot bindings at mint time, so identity is decidable *by construction* — no embeddings, no philosophy at risk. That is Option 4 of the four candidate policies (cluster by scheme + CQ-slot, not text similarity) applied to the one population where it is provably safe. Same for `Human Dignity` vs `human dignity` concept-node splits: term normalization is mint-time hygiene. The flywheel's question-basis decay therefore does NOT wait on the hard human-claim fork — canonical questions are slot-identifiable now. (Sharpens proposal 6 above; the human-claim clustering policy remains behind the open fork per [soft-canonical-clustering-and-reversible-merge-semantics.md](soft-canonical-clustering-and-reversible-merge-semantics.md).)\n\n**I4 — QEM's additivity protects pebbles from burial (test-discovered).** A wrong test assumption became a finding: QEM subclaim energy is additive, so a sibling sitting at the agnostic prior contributes zero — a pebble's hinge among nine neutral siblings equals its solo hinge *exactly*. CQ scaffolding can drown a crux in the reading experience (F12) but not in the strength math; only high-saturation sibling sets flatten the margin (the impact curve's tail). Calibration note: at shipped weights (subclaim weight 0.3), fully flipping one leaf moves a conclusion ~2 percentage points — the hinge is a *ranking* instrument at current graph maturity, and the weight is a Layer-3 knob to tune from observed engagement, not up front.\n\n**I5 — The confession principle (founder-canonized to CLAUDE.md).** *If a system has no way to tell you it failed, it will tell you it succeeded.* You are the easiest person to fool — and that goes for software double. Every subsystem needs a confession channel; any path lacking one is presumed to be lying optimistically until instrumented.\n\n---\n\n*Run conducted 2026-07-06; post-run insights same evening. Follow-up: human testing with 2–3 friends on these two extraction pages + the decomposed weighing claim as the guided entry point.*\n"}