DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/phase-51-marketing-site-and-companion-email/loomworks-phase-51-cr-drafting-handoff-v0_1.md

Loomworks — Phase 51 CR Drafting Handoff

Version. 0.1 Date. 2026-05-09 Audience. A fresh Claude.ai chat (same project, so project knowledge is shared) that drafts the Phase 51 CR. The current chat may also draft the CR directly per the Phase 50 compressed-analog precedent. Provenance. Produced after loomworks-phase-51-scoping-note-v0_2.md (which absorbed phase-51-step-0-findings-v0_1.md). All architectural decisions are settled in v0.2 of the scoping note (P51-D1 through P51-D16, with P51-D5 stack and P51-D15 domain marked [Operator confirms] as settle-at-CR-or-Step-4 questions); this handoff transposes those decisions into drafting instructions.


1. What this is

The Phase 51 scoping note v0.2 is CR-ready. The Step 0 findings are absorbed. Most v0.1 §11 open questions are resolved (P51-Shape-D1 → Option A; P51-D2 → confirmed; P51-D7 → option (a); V8 → out-of-scope items confirmed). Two decisions remain [Operator confirms] (P51-D5 stack: Astro recommended; P51-D15 domain: production / staging / preview URL); these settle at CR drafting time or sub-arc 3 Step 4 kickoff and don't block CR drafting from beginning. There is no more scoping work to do — the next deliverable is a single CR document.

The receiving chat reads this handoff, then the scoping note v0.2, then the Step 0 findings. Then it drafts the CR. The CR specifies architectural decisions firmly; substrate field names, function signatures, table names, model identifiers, route paths, and module locations are marked with [CC verifies at Step 0] where the CR drafter could not read live ground truth or where Step 0 findings flagged naming-only divergences worth re-confirming at CR-time.

The CR target filename: phase-51-cr-marketing-site-and-companion-email-v0_1.md.

The CR's structural template: phase-50-cr-companion-as-authority-and-public-form-v0_1.md in the engine repo's docs/phase-crs/. Mirror its section shape — pre-flight items, build steps with Step-0-equivalent inspection blocks, acceptance gates, halt conditions, kickoff prompt at the end. Adapt to Phase 51's three-sub-arc / two-empty-sub-arc-2 shape: the CR has fewer substrate sections than Phase 50 (smaller substrate scope per §6.2 of v0.2), an empty frontend section (per V7), and a new marketing-site section.


2. Decisions the CR implements

These are settled. The CR drafter does not re-decide them; it transposes them into CR sections.

  1. Phase 51 = Sub-arc 1 (engine: SMTP wiring + voice template + inline composition + Phase 45 e2e tests) + Sub-arc 2 (Operator Layer: empty per V7) + Sub-arc 3 (marketing site: new repo DUNIN7/loomworks-marketing on Cloudflare Pages with form posting to engine endpoint). Captcha, threshold-driven autonomy, modify-the-proposal action, multi-Companion cross-checking, Phase 42 turns reconciler, reactivation in-session chrome, and impl notes §7 items 12/13 are out of Phase 51 scope (Phase 52+ or future).
  1. P51-D2 — Companion-driven email composition: post-approval automatic, NOT a second approval gate. Per V7 confirmation. The Operator approves the grant decision via <GrantDecisionApprovalCard>; that approval consents both to the grant and to the email body. No second approval gate. Sub-arc 2 = 0 vitest, 0 component changes.
  1. P51-D3 — SMTP-wired form-initiated grants by default; send_email: bool override preserved. Mirrors Phase 48 §9.7's pattern for POST /admin/grants. Default behavior on Approve is "compose + send"; Operator can set send_email=false for testing or out-of-band delivery.
  1. P51-D4 — Phase 45 e2e integration testing: fixture-replayed LLM through real dispatcher. Real LLM in tests rejected. The LLM substitution boundary is clean per V4. Tests live in the engine repo's existing test surface; [CC verifies at Step 0] exact path layout.
  1. P51-D7 — Jurisdiction field on POST /authority/grant-request: additive optional jurisdiction: str | None = None. Per V5 confirmation. The marketing-site form presents three options (US / EU / Other); engine records the value as Memory event payload context. The existing source field stays unchanged.
  1. P51-D14 — Marketing-site CORS allowlist posture: production-domain-only literal allowlist for alpha. Per V6 finding. The loomworks_cors_origins env var supports comma-separated literals only; wildcards/regex deferred. Cloudflare Pages preview URLs not allowlisted via wildcard for Phase 51 alpha; preview deployments tested via direct API calls.
  1. grant_request_received is already a routine Memory event (Phase 50 ships it; no Phase 38 declare-and-register treatment needed; no DST/DRT events; Phase 51 doesn't add to this — V8 confirms).
  1. Inline composition design in seam. Per V2 confirmation. Synchronous Companion composition between row-write commit and send_email fire-and-forget call. Pure-composition Companion call (NOT a Phase 45 dispatch — no held artifact, no approval gate per P51-D2). The post-write hook variant (V2 also accepted) is rejected in favor of inline code in the grant_kind='form_initiated' branch of seam.issue_grant.
  1. Voice template family extension. Per V3 confirmation. prompts/credit_voice/grant_email.md lands as fifth sibling in the family (three Phase 49 credit_voice templates + Phase 50's grant_proposal.md + Phase 51's grant_email.md). Same loader, same AI-invisibility carve-out comment shape, same variable-substitution mechanism. [CC verifies at Step 0] exact loader function signature and template variable surface.
  1. Sub-arc 2 (Operator Layer): empty. Per V7 confirmation. <GrantDecisionApprovalCard>.tsx (138 lines current) accommodates P51-D2 post-approval-automatic posture without changes. Email-send status surfaces through existing notification stream rather than Approve response shape. 0 vitest, 0 component changes. The Operator Layer tag for Phase 51 lands on the same commit as Phase 50's tag (a marker, not a fresh commit).
  1. Sub-arc 3 (Marketing site): new repo DUNIN7/loomworks-marketing, Astro on Cloudflare Pages, form with four fields (email, display_name, use_case, jurisdiction) posting to POST /authority/grant-request. Astro stack recommended; [Operator confirms] Hugo alternative if preferred (P51-D5). Domain choice ([Operator confirms] per P51-D15 — production loomworks.com, staging subdomain, or Cloudflare Pages preview URL).
  1. Build sequencing. Per scoping v0.2 §6.1: 5 active + 3 reserved buffer slots (P51-D13). Two checkpoints (A after Step 2, B after Step 5 final-before-tagging). Inverted-pyramid order (smallest independent slice first; foundations next; dependents on top). Tag: phase-51-marketing-site-and-companion-email per P51-D16, on engine + Operator Layer + marketing repos.
  1. P51-D11 build-time estimate. 3.5–4.5 hours total. Substrate sub-arc 1 = 1.5–2 hours. Operator Layer sub-arc 2 = 0 hours. Marketing site sub-arc 3 = 2–2.5 hours.
  1. Carry-forward. Per scoping v0.2 §8: items 3, 5, 6, 7 deferred / opportunistic; items 8, 9 continuing parallel work; items 10, 11 substrate-gap or conditional; items 12/13 correctly out-of-scope per V8. Phase 52+ candidates: modify-the-email-body extension, real-LLM e2e spike test, marketing site jurisdiction routing logic, wildcard CORS pattern support (new from V6).
  1. Halt thresholds. Per scoping v0.2 §9: inline composition concerns V2 didn't anticipate; Phase 45 dispatcher fixture-replay friction beyond V4 verdict; marketing site domain TBD blocks sub-arc 3 readiness; CORS posture under P51-D14/V6 surfaces wildcard need during sub-arc 3 testing.
  1. Voice content discipline (P51-D12). As-shipped voice baseline recorded in implementation notes. Operator iteration after Phase 51 tag is ongoing work, not a Phase 51 amendment trigger.

3. CR target shape

3.1 Sections to include (mirroring Phase 50 CR v0.1 structure)

3.2 Build step shape (per Phase 50 v0.1 precedent)

Each of the five active build steps in §15 contains:

Phase 51's build steps span three repos: Steps 1–3 + 5 (CORS update) hit the engine repo; Step 4 creates and works in DUNIN7/loomworks-marketing; Step 5 (form wiring) crosses both. The Step-0-equivalent inspection blocks reflect this — substrate steps reference engine files; marketing-site steps reference the new repo's scaffolding state.

3.3 Reserved-slot buffer language (per Phase 49/50 precedent)

Per Phase 49 v0.3 §15 and Phase 50's full carry of the convention, slots 6–8 in Phase 51's build read as "(reserved — buffer for amendments arising from steps 1–5)" and "(reserved — buffer)". Reserved-not-skipped: unconsumed if no amendment arises; the buffer's value is its presence, not its consumption. Phase 50 left all three unconsumed. CR §15 carries this language.


4. CR-drafting-time verifications

Step 0 absorbed eight verifications cleanly, so CR drafting starts from a stronger evidence base than Phase 50's drafting did. The remaining drafting-time verifications focus on details that didn't fit in Step 0 — exact line numbers, exact strings, exact import paths, exact module locations. These are smaller in count than Phase 50's 15 but follow the same discipline: live-string-from-codebase, not placeholder-from-CR.

CR drafter verifies the following at draft time (read live; substitute exact strings into CR sections):

  1. Phase 48 email_service.send_email exact import path and signature. Step 0 V1 verified the API exists; CR drafter reads the exact module path and signature so §8 can specify the import statement and call shape directly. Without re-reading: likely from loomworks.email.service import send_email with signature send_email(to: str, template_name: str, context: dict, send_email: bool = True) -> None, but the live shape is authoritative.
  1. seam.issue_grant exact module path and current grant_kind='form_initiated' branch shape. Step 0 V2 verified the seam has a clean post-write insertion point; CR drafter reads the exact branch and specifies §9's inline-composition insertion site against live line numbers.
  1. prompts/credit_voice/grant_proposal.md exact path and template loader signature. Step 0 V3 verified the family loader pattern and naming-only divergence (two parallel template systems coexist); CR drafter reads the exact loader function signature and confirms grant_email.md lands in the same family per V3, not the parallel system. §7 specifies the loader call shape against live signatures.
  1. <GrantDecisionApprovalCard>.tsx line count and Approve handler call shape. Step 0 V7 verified the component is 138 lines and accommodates post-approval-automatic posture; CR drafter doesn't modify the file but §13 explicitly cites the line count and the Approve handler's existing call shape to confirm the no-change posture.
  1. POST /authority/grant-request pydantic model exact field set and extra config. Step 0 V5 verified accepts additive optional fields; CR drafter reads the live model and specifies §11's one-line addition exactly (field name, type, default, position in field order).
  1. loomworks_cors_origins env var exact name and config field declaration site. Step 0 V6 verified comma-separated-literals-only mechanism; CR drafter reads the exact config field name (lowercase per Phase 50 V9 absorption) and the parsing logic so §12 can specify the production-domain addition exactly.
  1. Phase 45 dispatcher register_action_dispatcher exact signature and the existing fixture-replay infrastructure (if any). Step 0 V4 verified clean substitution boundary; CR drafter reads the exact dispatcher signature, the LLM client interface, and any existing fixture / replay / cassette pattern so §10 can specify the test posture exactly.
  1. Phase 50 grant-decision dispatcher's existing test surface. §10 builds on this; CR drafter reads the existing test file location and existing mocking posture so the new e2e tests are stylistically consistent.
  1. Engine repo docs/phase-crs/ directory listing. Confirms CR number ordering for Phase 51 (likely CR-2026-066 if Phase 50 was 065); CR drafter reads the directory and assigns the next number.
  1. seam.issue_grant task-lifecycle pattern for POST /admin/grants (Phase 48). Step 0 V1 verified Phase 48 fire-and-forget posture; CR drafter reads the exact post-write hook shape so §9's inline-composition + §8's SMTP wiring follow the same pattern.
  1. The grant_email.md template variable surface. §7 specifies the variables; CR drafter reads grant_proposal.md's variable surface to confirm the grant_email.md variable set (recipient_email, asset_id, amount, claim_url, expires_at, recipient_display_name, use_case_summary or similar) is consistent and within the loader's substitution mechanism.
  1. Marketing repo location and creation pattern. No existing loomworks-marketing repo; CR drafter specifies the GitHub creation steps for §14 (organization DUNIN7, name loomworks-marketing, public/private choice — likely public for marketing site, but [Operator confirms]).

If any of items 1–12 reveal architectural divergence (not just naming or exact-string), CR drafter halts and surfaces — does not draft and hope.


5. Drafting discipline

Live-string-from-codebase, not placeholder-from-CR. Same discipline as Phase 50. When the CR specifies model identifiers, table names, column names, route paths, or any concrete string that already exists in the codebase, use the live string. Step 0 absorbed this discipline at the eight-verification level; CR drafting continues it at the exact-line-number level.

Step 0 inspection blocks at each build step. Per §3.2 above. Each build step says "before implementing, CC reads {specific files} and confirms {specific facts}." This is the reads-actual-data-structure-from-live-database discipline. Phase 51's build steps lean lighter on this because Step 0 absorbed eight scoping-time verifications — but the per-step inspections remain, scoped to the step's specific touch points.

Halt thresholds per build step. Each build step carries a halt threshold. Phase 47/48/49/50 standard: ">30 tests touched" for blast-radius decisions. Phase 51 reuses this and adds: any divergence from v0.2 scoping decisions triggers halt; any V6 wildcard-CORS-need surfacing during sub-arc 3 testing triggers halt-and-amendment.

Reserved-slot buffer language. Per §3.3 above. Slots 6–8 are reserved-not-skipped.

Test posture progression. Mirror Phase 50: green-with-permissive-fixture in early steps; green-with-real-substrate-shapes by final steps. Step 1 (SMTP wiring) lands green against Phase 48 fire-and-forget posture; Step 3 (Phase 45 e2e) exercises real dispatcher path with fixture-replayed LLM.

Marketing-site testing posture. Sub-arc 3 doesn't get vitest-style automated tests on the marketing site itself. Smoke tests only: form round-trips against staging deploy; jurisdiction value lands in Memory event; privacy/terms pages serve. CR §14 is explicit about this posture so CC doesn't over-build test infrastructure on the static-site side.

Voice content posture. P51-D12: as-shipped voice baseline recorded in implementation notes; Operator iteration after the tag is ongoing work, not a Phase 51 amendment trigger. CR §7 (voice template) ships first-draft voice content; first-draft is the as-shipped baseline.


6. Scope boundaries (don't cross)

The CR drafter does not draft sections for any of the following — these are out of Phase 51:

If the CR drafter finds itself drafting any of the above, it has crossed the seam — back up.


7. Halt-and-escalate signals during drafting

The receiving chat halts drafting and reports back to the Operator (rather than continuing) if any of the following arises:

In all cases, halt-and-surface is preferred to draft-and-hope.


8. Companion documents during drafting

If the receiving chat needs project-knowledge searches mid-draft, candidates include:

The receiving chat does not need to read all of these front-loaded; pull as needed during section-specific drafting.


9. Paste-ready kickoff prompt for the new chat

Open a new Claude.ai chat with the same project (so project knowledge is shared) and paste:


Open Phase 51 CR drafting. Read first: loomworks-phase-51-cr-drafting-handoff-v0_1.md.
That document specifies the reading order, the decisions to implement, the
CR-drafting-time verifications, and the drafting discipline. Follow it.

The target output is a single CR document at
phase-51-cr-marketing-site-and-companion-email-v0_1.md. Mirror the structural
shape of phase-50-cr-companion-as-authority-and-public-form-v0_1.md. The
scoping note loomworks-phase-51-scoping-note-v0_2.md is authoritative for
scope; CC's Step 0 findings phase-51-step-0-findings-v0_1.md is authoritative
for the verified state of the codebase (already absorbed into v0.2; use the
findings document for exact-string verifications during drafting).

Do not draft sections for items in the handoff's §6 "scope boundaries" list —
those are Phase 52 or future.

Halt and surface to me rather than draft-and-hope if any of the §7
halt-and-escalate signals arise.

Begin by reading the handoff in full, then the scoping note v0.2, then the
Step 0 findings. Plan the section structure before drafting prose. Confirm the
plan with me before drafting if uncertain.

The receiving chat reads this, then begins. The CR drafts iteratively across the chat as sections build up.


10. After the CR is drafted

The receiving chat hands the Operator a downloadable phase-51-cr-marketing-site-and-companion-email-v0_1.md. The current chat's role ends with this handoff document (or, if compressed-analog path is taken, with both this handoff and the CR).

Operator workflow from there:

  1. Download the CR from the receiving chat
  2. Add to project knowledge (replaces nothing; appends as new file)
  3. Open a fresh CC session on DUNIN7-M4
  4. Paste a CC kickoff prompt referencing the CR — same shape as Phase 50's kickoff
  5. CC archives the CR at docs/phase-crs/ per CR §3.3
  6. CC runs Step 0 inspection per the CR's pre-flight items (smaller list than Phase 50's because Step 0 absorbed eight items)
  7. CC reports findings; if naming-only divergences, CC proceeds; if architectural divergences, halt and report (same discipline as Phase 49/50)
  8. CC implements per the CR; reports build summary at completion
  9. New scoping chat opens for Phase 52 with carry-forward as relevant

Standard Phase 47/48/49/50 pattern.

If a mid-build amendment surfaces (Finding 6 trajectory — Operator-elective amendment scoping), the discipline is now established: build doesn't halt; Operator decides architecturally with options + halt-threshold review; sub-step lands before continuing. Phase 49's phase-49-step-4-amendment-scoping-v0_1.md is the canonical instance; Phase 50 left all three reserved slots unconsumed (no mid-build amendment arose).


11. Companion documents


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks Phase 51 CR Drafting Handoff — v0.1 — 2026-05-09