Chapter 33 / 40

Annex: decisions log

Status: Live

This annex is the full decision log for the engagement. Over the course of five weeks, 152 named decisions (D-001 through D-152) were surfaced, deliberated, and either locked, left open, or marked out of scope. Every one was annotated by Tom in the source files; the table below is that log in compact form.

The annex exists for two reasons. First, the earlier ANNOTATED files that held these annotations lived outside the handoff artifact and were not visible to anyone reading this manual — anyone wanting to know why a given chapter says what it says had no way to trace it back. The annex closes that gap. Second, the decisions are the project’s archaeological record: when a future engineer looks at a quadlet, a table, or a workflow and wonders why it was shaped that way, the D-number in this log is the primary-source answer.

How to read the table. Each row is one decision. The ID column is the D-number assigned when the decision surfaced. The Decision column is a short restatement of the question. The Annotation column is Tom’s actual call, transcribed (lightly trimmed to fit; sensitive or out-of-scope commentary is marked [redacted]). The Status column reduces the outcome to one of four buckets: locked (a call was made and it is reflected elsewhere in the manual), open (still to be resolved, usually at a specific later moment such as “during the email migration”), or out-of-scope (explicitly dropped or deferred past the engagement). The Related column points at the chapter where the decision lands, when one exists.

D-001 through D-082 come from the Monday ANNOTATED pass at end of Week 1. D-083 through D-152 come from the Tuesday ANNOTATED pass that closed Week 2 architecture. Cross-domain dependency notes are omitted from this table for readability; they are in the source files.


Decisions table

IDDecisionTom’s annotationStatusRelated
D-001Purge plaintext password from git history before public pushleave as islocked
D-002D1 as canonical source vs Postgres mirror for Power BIdrop PowerBI completely; D1 on a CF Worker is the canonical dblockedch23, ch32
D-003MCP transport protocol (Streamable HTTP only vs dual)100% Cloudflare MCP host; D1 retrieval + long-run CRM; self-hosted email accessiblelockedch42
D-004MCP auth layering (Worker-only vs CF Access + bearer bypass)most Cloudflare-native path; maximally CF-sidelockedch42
D-005Tailscale tag/ACL topologyTailscale is a dev tool for now; already installed on harness, sufficientopench31
D-006Sodiwin ingest: SFTP only vs SFTP + email fallbackFTP only at Florian’s rolling window; one-time historical dump; written to D1 via ETLlockedch14, ch21
D-007Upsert path split (Pattern A seeds vs Pattern B hot tables)depends on shape of Sodiwin data; decision postponedopench23
D-008Router exposure surface (internal vs router.sodimo.eu)MCP done = the principal connects the Claude.ai sub and controls everythinglockedch42
D-009Rupture/stockout source (Florian declined rup* fields)compute ourselves; ETL repo concern; option Clockedch23
D-010Sodiwin-native CRM vs custom TS-on-CF-Workerscustom TS on CF; inspired by Twenty + Pipedrive; centerpiece; unlocks CF-gated dashboardslockedch53
D-011Repo naming convention inside sodimo orgoption B — drop prefix inside orglockedch51
D-012Repo visibility matrixall private until final deployment; exception for sodimo/harnesslockedch51
D-013REPO.md frontmatter schema (10 fields vs 5)use whatever the handbook schema already haslockedch51
D-014What folds into sodimo/harness vs lives separateno Terraform; harness is anything in the Linux server that’s not a dotfile — it programslockedch35
D-015Skills library canonical homechezmoi dotfiles-backed; users consume via releases; may add a changelog sectionopench43
D-016Release tag convention (calver vs semver)calver only across all sodimo/* repos; semver droppedlockedch51
D-017Harness fork strategysodimo/harness already donelockedch35
D-018sodimo-repo-template end-to-end readiness gatetest E2E with harness release as first test, tied to changeloglockedch51
D-019Side-quest repo sequencing while pillars blockedone bite at a timelockedch51
D-020Ship v2 Cedar/Sumac brand as productionreal nice-to-have; not before Week 3-4; not shown to team until more is shippedout-of-scope
D-021Icon library (custom commission vs Lucide)Lucidelocked
D-022Self-host fonts vs Google Fonts CDNoption A fine; hold off on further brand/design; will use new Claude design laterlocked
D-023Fedora bootc version (41 vs 44)F44, pinned, resolvedlockedch35
D-024NAS mount protocol (NFSv4.1 vs SMB vs both)big blocker; needs in-person resolution mid-Week 2opench35
D-025Network topology to Halo (repatch vs wifi interim)ideal handoff: harness in the server rack next to NAS, on company intranetlockedch31
D-026UPS specsame UPS as current server; not my concern, resolved for a decadelockedch35
D-027Mail retention default (10y vs 7y)indefinite, redundant backups; still need to resolve “email sent during reboot”lockedch34
D-028”Deployed = 5 days” instrumentationpurpose of the manual; nothing fancy needed; the principal sees completed work not progresslockedch28
D-029Admin identity bootstrap sequenceCF/Gmail/GitHub/Tailscale set up; domain + email transfer in one day when server arriveslockedch35
D-030ISP ticket escalation ladderno external SMTP provider; this was relevant to email, revisit during migrationopench34
D-031Canonical table count (20 vs 21)built around the Sodiwin data dumps we receiveopench24
D-032Temporal window on document tablesFriday sent spec (full history forever)lockedch23
D-033One-time historical dump still owedone-time done by Florian; we work around thatlockedch14
D-034ETL failure notification recipientthe ERP admin; forward to Florian once admin is set uplockedch23
D-035base-clients column widening (35 to ~130 cols)ETL concern when buildingopench23
D-036SCD-2 scope (3 hubs vs 4 vs 5)ETL concernopench23
D-037Idempotency key for document_linesETL concernopench23
D-038ETL run cadence (03:00 timer vs inotify)ETL concernopench23
D-039D1 snapshot cadence + R2 retentionD1 daily with time-travel and clear rollback procedure; belongs in the manuallockedch23
D-040Parity gate: which 2 tables must matchETL concern, to be decided lateropench23
D-041Team password manager selectionneither hosted option; self-manage; important keys written on paper; Google Password Manager OKlocked
D-042MX cutover ordermake email addresses available to others; easy since we own the email serveropench34
D-043External SMTP smarthost: always-on vs fallback-onlyno external smarthost; defeats the purposelockedch34
D-044DMARC ramp on sodimo.euoption C (skip quarantine; none to reject once DKIM clean)lockedch34
D-045Piler access model (Tailscale UI + CF Tunnel REST)service token; Claude.ai programmatic access; middle layer on harness possiblelockedch34
D-046Shared inbox mechanism (Dovecot ACL vs Sieve vs alias-fanout)tbd; want the most feature-rich; aiming for podman quadlet for emailopench34
D-047BCC archive pattern (always_bcc inbound + journal outbound)tbd when we build emailopench34
D-048Strato retention post-cutover4 weeks extra safetylockedch34
D-049CNIL employee transparency noticedefer to Chapter 6 handoff; ensure employees read it oncelockedch34
D-050orders@ / commandes@ inbox topologyMCP always uses English; preserve existing email aliaseslockedch34, ch42
D-051BCC pattern for Sodiwin order emails (rep outbound)existing mechanism; keep for lateropench34
D-052Model routing for recouvrement draftscurrent local models today, new model tomorrow; manage in harness; testing requiredlockedch41
D-053Model tier for the principal’s monthly commentary skilltbdopench41
D-054Cloud fallback per-user monthly ceilingcloud fallback is the Claude Code subscription; issue for lateropen
D-055Cloud model selection (Anthropic-only vs +OpenAI)Claude only by design until further noticelockedch41
D-056API key ownership (Sodimo billing vs Thomas-transfer)[redacted — commercial]out-of-scope
D-057Cloud inference org-wide cap[redacted — commercial]out-of-scope
D-058Validator design for cloud escalationcloud escalation is described on the Sodimo websiteopench41
D-059MCP tool count discrepancy (27 vs 18)tbd final count, feature by featureopench42
D-060Kanban in CRMyes Kanban; feature parity and beyond; absorb Pipedrive workflows; CRM is the crown jewellockedch53
D-061Pipedrive decommission timelineprogressive rollout; real-world testinglockedch53
D-062MCP bearer-token rotation policyto be discussed on MCP repo; most Cloudflare-native wayopench42
D-063Sales-lead shell alias set (5 vs 7 vs 3)CRM concernopench43
D-064Photo thumbnail in MCP pre-call brieftbdopench42
D-065OpenWebUI deployment scopeanother podman quadlet on harness, documented to the teamlockedch36
D-066Admin cadence content (structured vs open)the ERP admin decides; we build the infralocked
D-067Principal Friday-report delivery channelteach team to edit dashboards with Claude Code and deploy to CF Pages themselveslockedch43
D-068[commercial posture][redacted — commercial]out-of-scope
D-069Recouvrement auto-send threshold for Tier 1set up with good CRM; add to CRM features (think like an engineer)lockedch53
D-070[commercial][redacted — commercial]out-of-scope
D-071[commercial][redacted — commercial]out-of-scope
D-072[Claude.ai subscription transfer]drop fully; the sales lead has his own subscriptionout-of-scope
D-073Draco engagement scoping cadence[redacted — commercial]out-of-scope
D-074Manual chapter count (7 vs 6 vs 5)flexible; revise in a focused session on handbookopen
D-075”Deployed” checklist execution mechanismdashboard specifics come way lateropench28
D-076Regression-discipline enforcementconvention only is fine; no need to overcomplicatelocked
D-077Daily engagement logbook formatdaily engagement goes into the daily releases on the changeloglocked
D-078Friday team demo formatdrop; the changelog does thatlocked
D-079PR ticker visibility cadenceall PRs renderlocked
D-080ETL failure runbook + escalation pathERP-admin email; escalates to Florian; debugs with Claude; texts me if issueslockedch23
D-081Florian relationship toneoption A (arm’s-length)lockedch14
D-082”10 Unknowns” scope trimmingsome point during the engagement; not priority at allopen
D-083Paperclip AI scope and identityPaperclip = tool to visualise agent runs dashboard-style; observability on agent runslockedch44
D-084Paperclip scope — agents only vs agents + humansoption C (agent now, human T+30); see paperclip doclockedch44
D-085Paperclip read-only vs approvals-queuepreferred read-only for observabilitylockedch44
D-08620 vs 21 canonical D1 tablesagent queue/other mechanisms discussed later; prefer D1 airgapped for ERP mirrorlockedch24
D-087Sodiwin export window (full vs 18-month rolling)already resolved with Florian; done when we build the ETL pipelinelockedch14
D-0888-to-20 file schema collapse confirmationleave for later; finalise D1 tables when Florian gives us data and we write ETLopench23
D-089sodiwin-agent queue table namingsodiwin agents are not the same as the MCP server; MCP delivers data and wraps opsopench45
D-090Paperclip repo visibilitywill be explained better in the dedicated paperclip filelockedch44
D-091sodiwin-agent remote protocolcomputer-use agent for the Sodiwin Windows VM; nice to have onlyopench45
D-092sodiwin-agent pilot ramp criterionbuild and deploy early; let people within the company test itopench45
D-093sodimo/paperclip vs sodimo/observability namingsee paperclip fileopench44
D-094Collapse email repos to single sodimo-runbooksoverwritten into sodimo/mail; DNS thing tbd during mail repo worklockedch51
D-095SEO agent for sodimo.euSEO is not my concern; team changes their website themselves once CF is setout-of-scope
D-096OpenWebUI deployment scopeyes, another quadlet on harness; harness documentation must be strongest point of manuallockedch36
D-097OpenWebUI auth posturekeep OpenWebUI dead simple; no auth; admin-level for everyone; CF Pages and/or Tailscalelockedch36
D-098OpenWebUI users & per-user bearer tokensOpenWebUI only for local AI models hosted on the device, optionally connecting to MCPlockedch36
D-099OpenWebUI sees PaperclipOpenWebUI is chat for local models; Paperclip covers background agent runslockedch36, ch44
D-100Moonlight/Sunshine for human VNC on harnessyes, Moonlight installed on harness; more a backup if things go wrong than daily toollockedch35
D-101External smarthost as email fallbackdrop completely; all Sodimo email hosted locally until further noticelockedch34
D-102Secrets manager replacementto be discussed later; favor on-premise free OSS toolsopen
D-103MX cutover order + T-schedule confirmationto be discussed during the email migrationopench34
D-104Fallback MX destinationStrato while we phase out; self-hosted primary; CF Routing 99% not neededlockedch34
D-105PTR delegation from upstream IP providerto be resolved during email migrationopench34
D-106Retention 7y vs 10y (vs tripartite)hold all emails, ever; full archive; ~100 GB cap for decades is not a problemlockedch34
D-107ETL failure alert recipientETL issues are near-fatal; I remain available to deploy emergency fixeslockedch23
D-108v_cultural_calendar view in final D1 schemavestigial from initial research; drop completelyout-of-scope
D-109DDMRP Red/Yellow/Green buffer systemvestigial; dropout-of-scope
D-110Dual-calendar demand forecastingvestigial; dropout-of-scope
D-111MailerLite + Shopify/Oxatis SPF reconciliationMailerLite fully unused; kill entirely; make self-hosted; Shopify is the company’s scopelockedch34
D-112Halo-IP reputation reusepart of email transition; agreed re: warmupopench34
D-113Cold-outreach separate domain patterndecided NOT to do cold outreach; no cold outbound from the harness that carries the inboxlockedch34
D-114Shared-inbox implementation (Dovecot ACL vs forwarder)Postfix virtual aliases good enough; Dovecot ACL also fine; explain, don’t finalizeopench34
D-115imapsync batching order confirmationgets done once, over the weekend; not a big problemlockedch34
D-116Deliverability monitor stackthinnest defensible stacklockedch34
D-117Primary local-inference runtimellama.cpp in a toolbox; final decision; no alternative runtime whatsoeverlockedch41
D-118MoA ensemble build scopedense vs MoA doesn’t matter; only constraint is best available model on our hardwarelockedch41
D-119Voice ecosystem stagingdrop voice ecosystem completely; WhatsApp gets a scoped bot with strong guardrailslockedch54
D-12024 canonical skill IDs — 15 production vs 9 stubs splitleave that granularity for later; my job is infrastructure for skill sharingout-of-scopech43
D-121Monthly commentary skill template + samples sequencingjust another skill; not importantout-of-scope
D-122Skill-level validator coveragedrop; skills are not my responsibility until perhaps the final weekout-of-scope
D-123Eval set cadenceevals are not something Sodimo must do itself; teach them to upgrade LLMsout-of-scope
D-124”Claude default” Tuesday leak cleanupheuristic to teach the team, not enforced at UI/UX levelopench41
D-125CRM Kanban scopeyes Kanban; spending a full week refining the final CRM versionlockedch53
D-126Sodimo delta-alert toolyes, this is indeed neededlockedch53
D-127Recouvrement auto-send Tier 1 thresholdauto-send + escalation to management are CRM-side concernslockedch53
D-128Sodiwin Kanban-in-CRM — specific sales-lead viewsno sodiwin-in-CRM; clear layer of separation; sodiwin-as-blackbox matters herelockedch53
D-129Twenty CRM + Pipedrive features to absorbdedicated one-on-one with the sales lead; he is scoping his CRM of dreams; not a major blockeropench53
D-130Research-corpus ideas triageideas + admin feedback become a Sodimo SOUL.md; three-year plan for the principal; purge researchopen
D-131Pre-opening restaurant detectionsales strategy to incorporate into the CRMopench53
D-132Halal certification decisionnot my problemout-of-scope
D-133Admin institutional-memory topic sessionsneeds doing before I leave; not crucial to my successopen
D-134Per-repo Tuesday pass on all 28 reposlist of repos still being finalized; issues added to repos we created; list finalized todaylockedch51
D-135”Deployed” formal definition adoptionsemantics; not sending energy on thatopench28
D-136Hypothesis-space dashboard ownerI teach the team to build dashboards; I don’t build themlockedch43
D-137[political posture][redacted — commercial]out-of-scope
D-138Weekly digest — existence + deliverythis is what the changelog and manual are forlocked
D-139Paperclip identity scope (Claude.ai users vs all authenticated users)will explain clearly what I mean with paperclipopench44
D-140Sodiwin read-path vs write-path coexistencewriting to Sodiwin may be explored later; for now keep the black-box conceptlockedch14, ch45
D-141sodiwin-agent cloud vs local computer-use modeldeferred; nice to have, not the cornerstoneout-of-scopech45
D-142sodiwin-agent post-engagement maintainerI build self-healing parts; tech choice (bootc + quadlets + backups + rollbacks) minimises risklockedch35, ch45
D-143sodiwin-agent nightly smoke-test harnesssame as above — self-healing + robust tech minimises risklockedch45
D-144Bot I1-I4 meta-bot layerresolve with paperclipopench44
D-145Per-secret storage remapto be determined later; leanest possible setupopen
D-146DMARC ramp cadenceto be determined as we do the mail migration; add a noteopench34
D-147Strato retention post-flipStrato retention in place until I leave; detail; not thinking about 2 vs 4 weekslockedch34
D-148CNIL notice priority (Chapter 3 block vs Chapter 6 defer)part of the email transition; easylockedch34
D-149Voicemail-to-order (J1) ship vs deferextremely secondary; dropout-of-scope
D-150Live voice-agent (J2) T+30 evaluation criteriondrop never-ship; add as option for laterout-of-scope
D-151DKIM signing — rspamd vs OpenDKIMtaken as part of the investigation for mail setupopench34
D-152MX topology active/active vs active/passiveproblem for when I build email; CF Routing as fallback when harness is down is goodopench34
D-153Twenty CRM adoption (supersedes D-010’s “custom TS-on-CF-Workers CRM”)adopt Twenty v2.0.0 as pinned quadlet; Sodimo builds the MCP interaction surface, not the CRM itself; commodity tooling is adopt-as-pinned (Pivot 1)lockedch53
D-154Twenty interaction: direct-Postgres (turbular) vs REST/GraphQL APIuse Twenty’s REST + GraphQL API directly; turbular / direct-Postgres dropped — schema is a private implementation detail that would couple Sodimo to every Twenty migration; API is versioned, documented, webhook-capablelockedch53, ch38, ch42
D-155Recouvrement split: Twenty-Workflow vs Worker-Claudetier-1 (scheduled search + templated email) stays in Twenty Workflows; tier-2 (Claude-drafted letters, cross-system augmentation) runs on the Worker and pushes back via crm_add_activity / crm_upsert_contactlockedch53
D-156Sodiwin push on Export Clients stage change: REST API vs FTP+CSV fallbackAPI-first; fall back to the Supli 2020 FTP+CSV pattern if Christian Semat confirms Sodiwin exposes no REST/GraphQL API; both routes write the run_ledger row before the Sodiwin handoffopench53
D-157Delta-alert definition and thresholdsopen — Rani to confirm which of the five delta kinds (new SKU drop, volume change, cadence break, price anomaly, range change) matter and at what thresholds; blocks DeltaAlert custom-object rolloutopench53
D-158Pipedrive decommission windowtwo-week parallel-running period with Pipedrive read-only after Twenty cutover; then decommission the €1,058/yr subscription; cutover gated on Rani confirming template re-authoring completelockedch53
D-160bootc over traditional Fedora provisioningatomic swap + rollback is non-negotiable; one OS image rebuilt in CI beats Ansible drift across reprovisioning eventslockedch35
D-161chezmoi over Ansible for app-layer quadletsAnsible is push-model and stateful; chezmoi is user-scope, declarative, already the leger-labs upstream pattern; one-line chezmoi apply after every quadlet editlockedch35
D-162App-layer in a separate sodimo/dotfiles repo vs single sodimo/harness monorepoapp versions churn weekly, OS versions monthly; splitting lets a Twenty bump land without rebuilding the bootc image; precedent: leger-labs already runs 12 quadlets this waylockedch35
D-163Rename llm.network to sodimo.network (leger-labs lift adaptation)leger-labs is a workstation pattern (“llm”); Sodimo is a production harness — the network name should reflect the product, not the upstream’s opinionlockedch35
D-164WantedBy=scroll-session.targetWantedBy=multi-user.target (leger-labs lift adaptation)leger-labs units target a workstation login session; Sodimo is headless-server — units must start at boot without a login, hence multi-user.target (or a sodimo.target that depends on it)lockedch35
D-165Twenty MCP wrapper: turbular DB-introspection vs Twenty API direct (infra framing; see D-154 for product framing)drop turbular; call the Twenty REST + GraphQL API directly — Twenty already exposes a typed API surface, turbular adds a second translation layer (schema-from-Postgres) that can drift from the UI contractlockedch38
D-166llama-swap GPU backend on Strix Halo (ROCm vs Vulkan)Vulkan — the :vulkan tag, not :rocm. gfx1151 on ROCm is upstream-bleeding-edge; RADV token-gen + AMDVLK long-context per-model is the production-stable posture, validated on the mecattaf asr-toolbox referencelockedch38
D-167Image pinning discipline across every quadlet (no :latest in production)pin every production image by digest; cockpit:latest is the one deliberate exception (slow cadence, strong compat story) and is called out as such. :main-stable, v2.0.0, 3.9.1 etc. are tag-pinned today; digest-pinning is the next hardening passlockedch38
D-168System-scope vs user-scope quadlet split rulesystem-scope when the service must come up before login, owns a privileged daemon role, or the OS image would be incomplete without it (tailscaled, cloudflared, cockpit); everything else is user-scope in dotfiles — smaller blast radius, rootless by defaultlockedch35
D-170MCP backend for CRM tools: hybrid (Postgres-direct via turbular + REST) vs Twenty API direct (MCP-surface framing; cross-ref D-154, D-165)Twenty API direct is the whole surface — REST for reads/writes, GraphQL for crm_search, webhooks for inbound. Supersedes D-003’s implicit “Postgres-direct” framing. Twenty’s REST API is versioned independently of schema, which makes it the stable surface across minor-version bumps; Postgres-direct re-entangles the Worker with Twenty’s schema and defeats static-at-handofflockedch42, ch53
D-171Claude.ai bearer-token-after-OAuth bug class: workaround strategyrequire a per-user bearer token on top of CF Access for Claude.ai clients; token lives in Vaultwarden, rotates per D-062. Paperclip and server-side callers use CF Access alone. Upstream bugs tracked at claude-code#46140 and claude-ai-mcp#49 — revisit when either closes. Not a CF-native workaround, a Sodimo-side onelockedch42
D-172Cloudflare Portals / MCP gateway productdefer. None of the Cloudflare MCP product landscape (Managed MCP, SDK, Code Mode, Portals) is load-bearing for Sodimo day-one. Principle 1 says do not adopt a young upstream in the hot path. sodimo-core is a hand-written Worker with hand-written tool files under src/tools/; no Portal in front, no gateway, no aggregator. Revisit if the CF MCP category stabilizes AND a second MCP surface ever becomes justifiablelocked (defer)ch42
D-173MCP tool count for v113 tools: erp_read_accounts, erp_read_orders, crm_list_deals, crm_get_contact, crm_upsert_contact, crm_advance_stage, crm_add_activity, crm_search, email_send, email_status, ledger_write, doc_search_piler, whatsapp_send. Other tools (AR aging, depot stock, margin query, revenue query) are erp_read_* specializations — views on D1 on top of erp_read_orders/erp_read_accounts, not distinct tools. Resolves D-059lockedch42
D-174Ledger emission: tool-call vs sidecarthe Worker emits run_ledger rows as the first action of every tool-dispatch, not via a sidecar process or a Twenty-audit-log scrape. Pre-write before side-effect, post-write after. Fails closed if the ledger insert fails — the tool is not dispatched. A sidecar is a second moving part that can drift; Principle 2 invariant is surface-wide, not opportunistic. Twenty’s native audit log covers row-level changes; the ledger covers which run_id drove each writelockedch42, ch53
D-178Principle 1 formalized: conceptual-fork-over-upstream with static-at-handoff classification testWeek 2 pivot: default is adopt-as-pinned-quadlet for commodity tooling (Twenty, OpenWebUI, Paperclip, Vaultwarden, Postfix, Dovecot, rspamd, Piler, future Prometheus/Grafana); default is conceptual fork for differentiating surface (sodimo-core Worker + MCP tool surface, run_ledger schema, Sodiwin ETL adapter, Sodiwin black-box FTP+CSV adapter, email-drain systemd service). Reverses week-1 framing which treated conceptual fork as universal default. Both defaults preserve pinned versions + aggressive scope-down + no continuous synclockedch15, ch38, ch51
D-179Principle 2 formalized: run_ledger append-only in D1, emitted by every AI invocation across every surfaceFull schema locked: run_id, ts, surface, user_id, agent_id, model, provider, tokens_in, tokens_out, tokens_cached, latency_ms, outcome, cost_eur, cost_eur_if_cloud. The cost_eur_if_cloud counterfactual column carries the savings narrative — summed across surfaces, counterfactual minus real is the dashboard number. Emission discipline applies uniformly to interactive chat, scheduled agents, email auto-reply, MCP tool calls. Every new quadlet, MCP tool, or skill must answer the emission question before shippinglockedch15, ch36, ch42, ch60
D-180Principle 3 supersedes earlier hybrid-MCP architecture: Cloudflare is the single MCP surface, on-prem reached via native UIs or pull-based wiringthree compounding reasons: (1) on-prem MCP inventory walk found nothing that must run on-prem for data-gravity, must be agent-callable (not human), and cannot be satisfied by a pull-queue; (2) Claude.ai OAuth handshake to self-hosted MCP servers behind tunnels drops the bearer token — recommended workaround (CF Access fronting) is equivalent to not self-hosting; (3) MCP gateway tooling on the 2026 market is too young to pin statically. Symmetric-application clause preserved: agents on the harness call the Worker email_send tool rather than shortcut to local sendmail. “Single MCP surface” is not “single HTTP surface” — Cloudflare Tunnel + Access for human browser traffic to on-prem services is legal and does not add an MCP endpointlockedch15, ch31, ch33, ch42, ch44
D-181kyuz0 amd-strix-halo-toolboxes adopted as the canonical Strix-Halo llama.cpp runtime referencepin kyuz0 upstream SHA 1421e8706020e8d7e797f71b9f28cd3072e7f868; llama-swap model cmd: flag sets are derived verbatim from kyuz0’s Dockerfiles and README; resync runbook lives at docs/resync-runbook.md in sodimo/dotfiles. Replaces the generic leger-labs llama-swap config with a Strix-Halo-specific, battle-tested reference path — removes a class of “does it work on this silicon?” questionslockedch38, ch41
D-182llama-swap gateway runs raw /app/llama-server (not ramalama)discovered during kyuz0 integration that ghcr.io/mostlygeek/llama-swap:vulkan does NOT ship a ramalama binary — the prior ramalama --runtime llama.cpp run cmd: blocks would have failed at first model load. Invoking /app/llama-server directly matches kyuz0’s toolbox invocation pattern and removes a latent-bug classlockedch38, ch41
D-183proxy: target in llama-swap.yaml uses http://127.0.0.1:NNNN, never container-self DNSllama-swap and the spawned llama-server share a netns; hitting the container-self DNS name (http://llama-swap:NNNN) forces a netavark round-trip that produces 502s under the adguard DNAT hijack after the first request. Loopback form was verified fixed in the Wednesday-evening smoke test (5.4 s cold, 0.08 s warm). Applies to every proxy: URL in the filelockedch38, ch41
D-184local-heavy alias = gpt-oss-120b (unsloth UD-Q8_K_XL, 2-shard GGUF, 65k ctx, reasoning_effort=high)supersedes the earlier gpt-oss-20b wiring in litellm.yaml. gpt-oss-120b at Q8 fits the unified-memory budget of the Framework Desktop 128 GB and is the weight class that makes the “local inference is first-class” pitch credible to Michel. First runtime validation deferred to prod harness (100 GB download + kyuz0 kernel cmdline gate)lockedch41
D-185Rootless podman 5.8.2 group-posture: GroupAdd=video onlydropped GroupAdd=keep-groups and PodmanArgs=--group-add=render from llama-swap.container. Under rootless podman 5.8.2 the combination is incompatible and blocks llama-swap from reaching Active. video alone is sufficient for RADV on gfx1151. /dev/kfd + HSA_OVERRIDE_GFX_VERSION=11.0.0 kept for ROCm forward-compat as vestige candidates (see sodimo/dotfiles#14)lockedch38
D-186Container image references must be fully-qualifiedtwenty.container + twenty-worker.container pinned to docker.io/twentycrm/twenty:v2.0.0. Short-name policy fails under non-TTY auto-update paths (podman auto-update, bootc first-boot) because there is no prompt to disambiguate the registry. Applies to every quadlet; digest-pinning is the follow-up hardening pass (D-167)lockedch38
D-187Sodimo-built derived images live under docker/<name>/Dockerfile, tagged ghcr.io/sodimo/<name>:v<upstream>-pi<resolved>first instance is docker/paperclip/Dockerfile layering @mariozechner/pi@latest on ghcr.io/paperclipai/paperclip:sha-b8725c5; local build landed as ghcr.io/sodimo/paperclip:v2026.416.0-pi0.x.y (2.55 GB). Establishes the pattern for any future Sodimo-built image: top-level docker/ dir, upstream-SHA-pinned base, calver + resolved-dep tag. GHA publish path + org write:packages tracked in sodimo/dotfiles#12lockedch38, ch44
D-188Default LLM routing is local-first; cloud (Claude Opus via cloud-heavy alias) is opt-in escalation per-invocation, not the defaultToken-savings discipline under Principle 2: cost_eur is 0 for every local run; cost_eur_if_cloud records the counterfactual. Starting at Opus and falling back to local inverts the economics — the savings number becomes a claim about an exception case rather than the baseline. Four escalation triggers are enumerated in ch41; nothing escalates silently without an explicit escalate: "cloud-heavy" flag in the tool invocation. gpt-oss-120b at UD-Q8_K_XL on 128 GB Strix Halo has closed the capability gap for a large share of work as of 2026-04-22 kyuz0 integrationlockedch15, ch41
D-189Local-AI usage counter is ledger-backed via Worker ledger_writerun_ledger; Prometheus/Grafana not activated at v1every llama-swap run emits a run_ledger row with cost_eur=0 and cost_eur_if_cloud set to the counterfactual cloud price. SUM(cost_eur_if_cloud) - SUM(cost_eur) across all local rows is the headline savings number — one SQL query, no separate metric pipeline. A Grafana-backed dashboard would require a D1-to-Prometheus bridge with no additional analytical value at v1. Surface: cumulative counter on the launchpad tile (ch61) + rolling 7-day chart on a progress-adjacent page (exact placement open). Grafana/Prometheus revisit deferred as Pivot 5alockedch41, ch42, ch61

How to use this log

The table above is the authoritative decision index; the manual chapters are where those decisions land. If a chapter seems to contradict the table, the table wins until the chapter is updated to match. If a decision is marked open, it has not yet been resolved — the related chapter (where one exists) describes the current best understanding, and the resolution lives with the work identified in the annotation.

Three reading patterns are worth knowing:

  • “Why is it like this?” Start with the related chapter, find the D-number it references, read the row here, and the source ANNOTATED file at ~/sodimo/secondweek/ if you need the longer context.
  • “What is still open?” Filter the Status column to open. Those are the live questions.
  • “What got dropped and why?” Filter to out-of-scope. These are the scope trims that kept the engagement shippable; the annotation explains the reason.