Sales Proposals Workspace — Implementation Plan (Arm a)
Sales Proposals Workspace — Implementation Plan (Arm a)
Section titled “Sales Proposals Workspace — Implementation Plan (Arm a)”Stage 3 deliverable. Decomposes the Stage 2 spec
(docs/specs/sales-proposals-workspace-spec-arm-a.md) into ordered, verifiable
tasks. Every spec acceptance criterion (AC-1 through AC-41) maps to at least one
task. Tasks are sized S/M; any L candidate is split before landing.
§1 Overview
Section titled “§1 Overview”Build a Knowledge Hub-native sales-proposals workspace covering the seven §9.2 components (ROI calculator, case-study selector, quote picker, pricing configurator, templates, assembly logic, export), the pre-send QA gate, the Account Brief MCP App, three sales-persona prompts, and the OPS-26 plugin- reuse policy. Phasing follows spec §13: foundation → templates+content → pricing+ROI → assembly+editor → export+QA → Account Brief+prompts → hardening → optional PDF.
§2 Architecture decisions (locked from spec)
Section titled “§2 Architecture decisions (locked from spec)”- Single-Supabase-project tenancy scoped via
client_id; no multi-tenant RLS row sharing (spec Assumption 1). - DB-first storage — 7 tables + JSON templates on disk; reject the JSON-on-disk runtime model (spec Assumption 2).
- Tiptap canonical, Markdown serialised on read —
block_datastores the Tiptap JSON; round-trip stability enforced by AC-16 (spec FR-6.5). - DOCX primary, PDF secondary — DOCX always v1.0; PDF v1.0 if effort allows, else v1.5 (spec Assumption 4 + Phasing v0.5/v1.5).
- OPS-26 reuse modes — Wrap / Compose / Adapt / Build native; documented verdict per reused asset (spec §10).
- proposal-writer doctrine canonical — assembly, exec summary, pricing, ROI,
structure rules defer to
.claude/skills/proposal-writer/rules/*(spec Assumption 10).
§3 Open questions to resolve before kickoff
Section titled “§3 Open questions to resolve before kickoff”These are spec §17 questions Liam must answer before Phase 1 starts. Phase 0 captures the resolutions; without them, downstream tasks are blocked or scoped ambiguously.
| # | Question | Blocks |
|---|---|---|
| Q1 | §C.3 case-study tab dependency: ship before v0.2, or workspace ships with empty-state? | T7 (case-study selector) |
| Q2 | PDF in v1.0 or v1.5? | T22 / T38 |
| Q3 | sales_author role granularity (single role vs author+reviewer split) | T1 (migration), T4 (auth gating) |
| Q4 | Multi-client tenancy model — confirm one Supabase project per client | T1 (RLS) |
| Q5 | Templates: locked v1 / extensible v2 / extensible v1 | T6 (template loader) |
| Q6 | T&Cs source — bundled UK SMB library or per-client supplied | T6 (template defaults), T34 (docs) |
| Q7 | Handover surface — live workspace + starter zip, or live only | T35 (handover pack) |
| Q8 | Cover image storage — per-proposal Supabase Storage or shared brand bucket | T1 (storage paths), T21 (DOCX) |
| Q9 | QA gate numerics tolerance — ±0.5% confirmed or pilot-tunable | T23 (QA rules) |
| Q10 | proposal_shortcut grounding — wait for P1-15 Phase 2 or ship static | T17 (prompt) |
§4 Task list
Section titled “§4 Task list”Phase 0 — Pre-flight (S, sequential)
Section titled “Phase 0 — Pre-flight (S, sequential)”T0 — Resolve §17 open questions
Section titled “T0 — Resolve §17 open questions”Description: Liam dispositions Q1–Q10 from spec §17. Update spec with
canonical answers; mark §17 status resolved. No code changes.
Acceptance criteria:
- Each of Q1–Q10 has a recorded answer in spec §17.
- Spec frontmatter
statusflips fromdrafttoresolved-questions.
Verification:
- Spec diff shows §17 status change + per-question answer block.
- Plan §3 table updated to “resolved” with answer summary.
Dependencies: None.
Files likely touched:
docs/specs/sales-proposals-workspace-spec-arm-a.md(§17 only)
Estimated scope: S (1 file).
ACs covered: none directly (unblocks all).
Phase 1 — Foundation (v0.1, M, mostly sequential)
Section titled “Phase 1 — Foundation (v0.1, M, mostly sequential)”Goal: data layer + minimal workspace shell + 3 stub MCP tools. End state = listing renders and a draft proposal can be created with empty sections.
T1 — DB migration (7 tables + RLS + new role)
Section titled “T1 — DB migration (7 tables + RLS + new role)”Description: Create one Supabase migration adding proposals,
proposal_sections, proposal_revisions, proposal_pricing_tiers,
proposal_roi_inputs, proposal_assets, proposal_qa_gate_runs. Add
sales_author role; extend get_user_role(). RLS per spec §6.3. All new
PL/pgSQL functions SET search_path = public, extensions. Storage bucket
provisioned for proposals/<id>/... paths.
Acceptance criteria:
- Migration applies cleanly via the Supabase CLI on a shadow project.
- RLS verified:
sales_authorcan write own draft;viewerreads onlysent/won/lost; admin reads all. - Storage path policy created with signed-URL TTL per spec §9.1.
Verification:
supabase db pushsucceeds against shadow project.- Integration test (added in T5) covers RLS matrix.
- AC-34 (RLS) and AC-35 (
search_path) verified.
Dependencies: T0.
Files likely touched:
supabase/migrations/<yyyymmdd>_proposals.sql(new)supabase/types/database.types.ts(regenerated at the deliberate reconciliation point only — not mid-session).
Estimated scope: M (1 large SQL file + types regen).
ACs covered: AC-34, AC-35.
T2 — Types + Zod schemas
Section titled “T2 — Types + Zod schemas”Description: Author types/sales-proposals.ts with all spec §6 row types,
ROIInputs / ROIOutputs, template definition schema, embed-ref discriminated
union, QA-gate finding schema. Zod schemas mirror DB enums. No barrel re-exports
per CLAUDE.md.
Acceptance criteria:
- TS compiles against regenerated
database.types.ts. - Zod schemas reject invalid enum values + non-negative numerics.
- Direct file import path documented (no
index.tsre-export).
Verification:
bun run test __tests__/lib/sales-proposals/types.test.tspasses (Zod schema round-trip).bun lintclean.
Dependencies: T1.
Files likely touched:
types/sales-proposals.ts(new)__tests__/lib/sales-proposals/types.test.ts(new)
Estimated scope: S (2 files).
ACs covered: none directly (foundation for many).
T3 — MCP tool stubs (proposal.create, proposal.update, proposal.add_section)
Section titled “T3 — MCP tool stubs (proposal.create, proposal.update, proposal.add_section)”Description: Register three foundational MCP tools under
lib/mcp/tools/sales-proposals/. Tools accept Zod-validated inputs and write to
the new tables via getAuthorisedClient(); check auth.success and use
authFailureResponse(auth) per CLAUDE.md. Empty block_data seeded.
Acceptance criteria:
- All three tools registered in MCP server inventory.
- Layer 1 protocol-compliance check passes for the three tool names.
- Layer 4 functional-correctness asserts a created proposal has the correct template’s section list seeded.
Verification:
bun run test:mcp-evalLayer 1 + Layer 4 pass for the new tools.bun run generate:mcp-inventoryreflects the additions.
Dependencies: T2.
Files likely touched:
lib/mcp/tools/sales-proposals/create.ts(new)lib/mcp/tools/sales-proposals/update.ts(new)lib/mcp/tools/sales-proposals/add-section.ts(new)lib/mcp/tools/sales-proposals/index.ts(registration only — direct re-imports per CLAUDE.md no-barrel rule)__tests__/integration/sales-proposals/mcp-create.test.ts(new)
Estimated scope: M (5 files).
ACs covered: partial AC-2 (proposals row + sections seeded).
T4 — Workspace shell + listing + new-proposal modal
Section titled “T4 — Workspace shell + listing + new-proposal modal”Description: Build app/sales-proposals/page.tsx (listing) and
app/sales-proposals/[id]/page.tsx (empty edit page with section navigator
skeleton). New-proposal modal posts to proposal.create. Auth gating:
unauthenticated → /login; viewer sees only sent/won/lost. TanStack Query for
listing with key ['sales-proposals', clientId, filters].
Acceptance criteria:
- AC-1:
/sales-proposalslisting renders forsales_author; viewer filtered; unauthenticated redirected. - AC-2: New-proposal flow creates row + sections; navigates to
[id]. - Listing card shows: title, target entity, deal-stage type, status, last- edited timestamp; recommended pricing tier and ROI% slots present (filled in later phases).
Verification:
- Component test: listing role-matrix + filter tests.
- Manual:
bun dev, sign in assales_author, run the create flow. bun run knipclean for the new files.
Dependencies: T3.
Files likely touched:
app/sales-proposals/page.tsx(new)app/sales-proposals/[id]/page.tsx(new)app/sales-proposals/new/page.tsx(new modal route)components/sales-proposals/ProposalListing.tsx(new)components/sales-proposals/NewProposalModal.tsx(new)components/sales-proposals/SectionNavigator.tsx(skeleton)lib/query/query-keys.ts(extend)lib/query/fetchers.ts(extend)
Estimated scope: M (5 files + 2 extensions).
ACs covered: AC-1, AC-2.
T5 — Foundation tests (CRUD round-trip + auth gating + RLS matrix)
Section titled “T5 — Foundation tests (CRUD round-trip + auth gating + RLS matrix)”Description: Integration tests under
__tests__/integration/sales- proposals/ covering: proposal CRUD via MCP tools;
RLS matrix (admin/sales_author/viewer/anon); empty-state listing.
Acceptance criteria:
bun run test:integration __tests__/integration/sales-proposals/passes.- RLS write-denied for unauthenticated requests asserted.
Verification:
- Run with
dangerouslyDisableSandbox: trueper CLAUDE.md (Bun fetch + 204). - Coverage of
lib/sales-proposals/≥ 50% at this phase milestone.
Dependencies: T1–T4.
Files likely touched:
__tests__/integration/sales-proposals/crud-roundtrip.test.ts(new)__tests__/integration/sales-proposals/rls-matrix.test.ts(new)
Estimated scope: S (2 files).
ACs covered: AC-34 verified.
Checkpoint — End of Phase 1 (v0.1)
Section titled “Checkpoint — End of Phase 1 (v0.1)”bun run testgreen.bun buildgreen.- Manual: create + list a proposal end-to-end.
- AC-1, AC-2, AC-34, AC-35 verified.
- Liam sign-off before Phase 2.
Phase 2 — Templates + content selection (v0.2, M, parallelisable)
Section titled “Phase 2 — Templates + content selection (v0.2, M, parallelisable)”Goal: templates load real section lists; case-study selector + quote picker
populate embedded_block_refs. End state = author can configure a draft with
selected case studies and quotes, but no editing yet.
T6 — Five template JSON definitions + loader
Section titled “T6 — Five template JSON definitions + loader”Description: Author 5 templates in lib/sales-proposals/templates/*.json
per spec §8.5 table. Each defines section list, required flags, default block
content (placeholders to proposal-writer doctrine), recommended length per
deal_size_band. Build a typed loader; template-swap logic preserves
overlapping sections, archives orphans (display_order = NULL), seeds new
sections empty.
Acceptance criteria:
- AC-14: All 5 JSON files exist and parse.
- AC-15: Swap from
full_proposal→solution_briefpreserves Cover, Exec Summary, Understanding, Solution; orphans archived; new sections empty. - Soft-target word counts per section keyed by
deal_size_band.
Verification:
bun run test __tests__/lib/sales-proposals/templates.test.tspasses (loader + swap matrix).
Dependencies: T2 (types).
Files likely touched:
lib/sales-proposals/templates/one-pager.jsonlib/sales-proposals/templates/solution-brief.jsonlib/sales-proposals/templates/full-proposal.jsonlib/sales-proposals/templates/rfp-response.jsonlib/sales-proposals/templates/sow.jsonlib/sales-proposals/templates/loader.tslib/sales-proposals/templates/swap.ts__tests__/lib/sales-proposals/templates.test.ts
Estimated scope: M (8 files).
ACs covered: AC-14, AC-15.
T7 — Case-study selector UI + relevance scoring
Section titled “T7 — Case-study selector UI + relevance scoring”Description: Build components/sales-proposals/CaseStudySelector.tsx. Query
content_items where content_type = 'case_study' AND client_id matches.
Rank by 0.5 × sector_match + 0.5 × use_case_tag_overlap. Render top 10 cards.
Selection appends embedded_block_refs entry. Empty-state copy per FR-2.5.
Filters: free-text, sector, tag chips.
Acceptance criteria:
- AC-6: 5 case studies (3 sector-match, 2 not) → 3 matches in top 3.
- AC-7: Empty state when 0 indexed.
- AC-8: Selection appends ref + section navigator increments count.
Verification:
- Component test: relevance ordering + empty state + selection.
- Manual: open a draft, select 2 case studies.
- Radix Select shims via
installRadixPointerShims()per CLAUDE.md.
Dependencies: T6 (templates), T2 (types). Phase 0 Q1 resolution governs empty-state expectation.
Files likely touched:
components/sales-proposals/CaseStudySelector.tsx(new)components/sales-proposals/CaseStudyCard.tsx(new)lib/sales-proposals/relevance.ts(new — scoring fn)__tests__/components/sales-proposals/CaseStudySelector.test.tsx(new)__tests__/lib/sales-proposals/relevance.test.ts(new)
Estimated scope: M (5 files).
ACs covered: AC-6, AC-7, AC-8.
T8 — Quote picker UI + filters
Section titled “T8 — Quote picker UI + filters”Description: Build components/sales-proposals/QuotePicker.tsx. Queries
q_a_pairs, content_items where
content_type IN ('certification', 'evidence'), and entity_mentions for
holder/supplier metadata. Filters: source type, tag, relevance vs active
section. Selection inserts a structured quote block; per-line justification
field optional.
Acceptance criteria:
- AC-9:
source_type = certificationreturns only those rows. - AC-10: Selecting a Q&A pair embeds question + answer + source link in
block_data. - Sort options: relevance / recency / alphabetical.
Verification:
- Component test: filter + sort + selection.
- Manual: select a cert + a Q&A pair into a draft.
Dependencies: T6, T2.
Files likely touched:
components/sales-proposals/QuotePicker.tsx(new)components/sales-proposals/QuoteCard.tsx(new)__tests__/components/sales-proposals/QuotePicker.test.tsx(new)
Estimated scope: M (3 files).
ACs covered: AC-9, AC-10.
T9 — Selector MCP tools (proposal.select_case_studies, proposal.select_quotes)
Section titled “T9 — Selector MCP tools (proposal.select_case_studies, proposal.select_quotes)”Description: Register two MCP tools that accept proposal_id, section_id,
and a list of refs. Validate refs exist, append to embedded_block_refs, write
a revision with change_reason = manual_edit.
Acceptance criteria:
- Both tools registered; Layer 1 + Layer 4 pass.
- Citation integrity warning fires when a ref does not resolve.
Verification:
bun run test:mcp-eval:fcpasses for both tools.- Integration test asserts revision row created with the canonical
change_reasonvalue.
Dependencies: T7, T8.
Files likely touched:
lib/mcp/tools/sales-proposals/select-case-studies.ts(new)lib/mcp/tools/sales-proposals/select-quotes.ts(new)__tests__/integration/sales-proposals/select-tools.test.ts(new)
Estimated scope: S (3 files).
ACs covered: none net-new (supports AC-8, AC-10 via API surface).
Checkpoint — End of Phase 2 (v0.2)
Section titled “Checkpoint — End of Phase 2 (v0.2)”- AC-6 through AC-10 + AC-14, AC-15 verified.
- All 5 templates load.
- Two selectors operational.
bun run testgreen;bun run test:mcp-evalgreen.
Phase 3 — Pricing + ROI (v0.3, M, parallelisable)
Section titled “Phase 3 — Pricing + ROI (v0.3, M, parallelisable)”Goal: pricing tiers + ROI calculator with hand-computed reference fixtures. End state = pricing and ROI panels persist and recompute live.
T11 — Pricing configurator UI + DB writes + constraint enforcement
Section titled “T11 — Pricing configurator UI + DB writes + constraint enforcement”Description: Build components/sales-proposals/PricingConfigurator.tsx with
2–3 tier cards, recommended-flag uniqueness, GBP formatting, inclusions list,
payment terms, value-summary slot, anchor-strategy slot, discount-trade matrix,
objection-prevention slot. DB constraint (partial unique index) enforces ≤1
recommended tier per proposal.
Acceptance criteria:
- AC-11: Marking tier 2 unchecks any other recommended; DB rejects two- recommended states.
- AC-12: Prices render as
£24,000.00(UK formatting, two decimals). - AC-13: Inclusions list 0–20 rows; over-20 soft warning.
Verification:
- Component test: recommended-uniqueness + GBP formatting.
- Integration test asserts DB constraint rejects duplicate
is_recommended.
Dependencies: T2 (types).
Files likely touched:
components/sales-proposals/PricingConfigurator.tsx(new)components/sales-proposals/PricingTierCard.tsx(new)lib/sales-proposals/pricing/format.ts(new — GBP formatter)__tests__/components/sales-proposals/PricingConfigurator.test.tsx(new)__tests__/integration/sales-proposals/pricing-constraint.test.ts(new)
Estimated scope: M (5 files).
ACs covered: AC-11, AC-12, AC-13.
T12 — ROI math (lib/sales-proposals/roi/compute.ts) + reference fixtures
Section titled “T12 — ROI math (lib/sales-proposals/roi/compute.ts) + reference fixtures”Description: Implement computeROI per spec §5.3 example. Pure function;
Zod-validated inputs; scenario weights 0.6 / 0.85 / 1.0; outputs
grossValueGBP, netValueGBP, paybackMonths, roiPct, costOfInactionGBP.
Fixture file roi-references.json stores hand-computed truth (AC-3 reference).
Acceptance criteria:
- AC-3:
investment=24000,revenue=60000,cost=30000, others=0, scenario=moderate→gross=76500,net=52500,payback≈3.76,roi≈218.75. - Edge cases: zero investment, all-zero drivers, conservative scenario.
Verification:
bun run test __tests__/lib/sales-proposals/roi/compute.test.tspasses with exact reference fixtures.
Dependencies: T2.
Files likely touched:
lib/sales-proposals/roi/compute.ts(new)__tests__/lib/sales-proposals/fixtures/roi-references.json(new)__tests__/lib/sales-proposals/roi/compute.test.ts(new)
Estimated scope: S (3 files).
ACs covered: AC-3.
T13 — ROI panel UI + scenario toggle + persistence
Section titled “T13 — ROI panel UI + scenario toggle + persistence”Description: Build components/sales-proposals/ROIPanel.tsx. Five
value-driver inputs, investment input, cost-of-inaction input, scenario selector
(default moderate). Real-time output recomputation ≤100ms debounced. Narrative
notes ≤2000 chars. Outputs render: investment table, value-drivers table,
sensitivity matrix, payback period, ROI%, cost-of- inaction summary. Persists
proposal_roi_inputs on debounced edit.
Acceptance criteria:
- AC-4: Switching scenario recomputes in ≤100ms.
- AC-5: Save persists row; reload restores all field values exactly.
- Layout follows
proposal-writer/rules/pricing-roi-business-case.mdshapes.
Verification:
- Component test: scenario toggle + save/load round-trip.
- Manual: enter inputs, toggle scenarios, refresh page, confirm restore.
Dependencies: T12.
Files likely touched:
components/sales-proposals/ROIPanel.tsx(new)components/sales-proposals/ROITable.tsx(new)components/sales-proposals/SensitivityMatrix.tsx(new)__tests__/components/sales-proposals/ROIPanel.test.tsx(new)
Estimated scope: M (4 files).
ACs covered: AC-4, AC-5.
T14 — Pricing + ROI MCP tools (proposal.configure_pricing, proposal.compute_roi)
Section titled “T14 — Pricing + ROI MCP tools (proposal.configure_pricing, proposal.compute_roi)”Description: Register two MCP tools. configure_pricing writes tier rows
(atomic transaction enforcing recommended uniqueness). compute_roi runs
computeROI server-side and persists proposal_roi_inputs.
Acceptance criteria:
- Both tools registered; Layer 1 + Layer 4 pass.
- AC-31 (GBP formatting on substituted strings) groundwork present.
Verification:
bun run test:mcp-eval:fcpasses.- Integration test asserts DB state after tool invocations.
Dependencies: T11, T12.
Files likely touched:
lib/mcp/tools/sales-proposals/configure-pricing.ts(new)lib/mcp/tools/sales-proposals/compute-roi.ts(new)__tests__/integration/sales-proposals/pricing-roi-tools.test.ts(new)
Estimated scope: S (3 files).
ACs covered: none net-new (API surface).
Checkpoint — End of Phase 3 (v0.3)
Section titled “Checkpoint — End of Phase 3 (v0.3)”- AC-3, AC-4, AC-5, AC-11, AC-12, AC-13 verified.
- ROI hand-computed reference fixture green.
- Pricing constraint enforced at DB layer.
Phase 4 — Assembly + editor (v0.4, M, partially parallelisable)
Section titled “Phase 4 — Assembly + editor (v0.4, M, partially parallelisable)”Goal: Tiptap editor wired; assembly prompt produces drafts; round-trip stable. End state = author edits inline and re-assembles per section.
T16 — Tiptap block editor + section navigator wiring
Section titled “T16 — Tiptap block editor + section navigator wiring”Description: Tiptap editor in
components/sales-proposals/SectionEditor.tsx, bound to
proposal_sections.block_data. Use @tiptap/markdown per the CLAUDE.md note
(editor.getMarkdown(), setContent with { contentType: 'markdown' }).
Section navigator drives editor target. Save creates a revision with
change_reason = manual_edit. Reset local state via key prop on section
switch (no setState in effect).
Acceptance criteria:
- Editor mounts per section; switch preserves draft via
block_datawrite. - Inline edits create revision rows.
Verification:
- Component test: switch sections + persist edits.
- Manual: edit Solution section → switch to Investment → return → content present.
Dependencies: T2.
Files likely touched:
components/sales-proposals/SectionEditor.tsx(new)components/sales-proposals/SectionNavigator.tsx(extend skeleton from T4)__tests__/components/sales-proposals/SectionEditor.test.tsx(new)
Estimated scope: M (3 files).
ACs covered: none directly (foundation for AC-16/17/18).
T17 — proposal_shortcut prompt registration + Zod IO schema
Section titled “T17 — proposal_shortcut prompt registration + Zod IO schema”Description: Register prompt at
lib/mcp/prompts/sales-proposals/proposal-shortcut.ts. Inputs: deal-stage type,
target entity profile, embedded blocks (compact refs), pricing summary, ROI
summary, doctrine excerpts. Output: per-section Markdown with placeholders
({{block:case_study:<id>}}, {{roi.payback_months}}, etc.). UK English + GBP
enforced. Output validated by Zod before persistence.
Acceptance criteria:
- AC-29 partial: prompt listed under
sales-proposalsnamespace. - AC-30 partial: Zod rejects malformed output.
- AC-31: GBP-formatted substitutions emitted.
Verification:
bun run generate:mcp-inventorylists the prompt.- Unit test: malformed-output rejection + GBP formatting.
Dependencies: T2 (types). Phase 0 Q10 resolution determines grounding (static P1-15 Phase 1 only, or dynamic P1-15 Phase 2).
Files likely touched:
lib/mcp/prompts/sales-proposals/proposal-shortcut.ts(new)lib/mcp/prompts/sales-proposals/index.ts(registration)__tests__/lib/sales-proposals/prompts/proposal-shortcut.test.ts(new)
Estimated scope: S (3 files).
ACs covered: AC-29 partial, AC-30 partial, AC-31.
T19 — Assembly parser (Markdown ↔ Tiptap JSON, block-placeholder substitution)
Section titled “T19 — Assembly parser (Markdown ↔ Tiptap JSON, block-placeholder substitution)”Description: Implement lib/sales-proposals/assembly/parser.ts. Convert
prompt-output Markdown to Tiptap JSON; substitute placeholders with referenced
content (case studies, quotes, pricing tier blocks, ROI symbolic references).
Preserve Tiptap node types per spec §8.6. Use @tiptap/markdown official API
only.
Acceptance criteria:
- AC-16: Round-trip: assemble → export-to-Markdown → reassemble → emitted Tiptap JSON matches modulo timestamps.
- AC-18: Substituted block-ref content present at placeholder positions.
Verification:
bun run test __tests__/lib/sales-proposals/assembly/parser.test.tspasses (round-trip golden fixtures).
Dependencies: T2.
Files likely touched:
lib/sales-proposals/assembly/parser.ts(new)lib/sales-proposals/assembly/placeholders.ts(new — placeholder regex + substitutor)__tests__/lib/sales-proposals/assembly/parser.test.ts(new)__tests__/lib/sales-proposals/assembly/fixtures/(golden Markdown + JSON pairs)
Estimated scope: M (4 files).
ACs covered: AC-16, AC-18.
T18 — proposal.assemble_draft MCP tool + section-level granularity
Section titled “T18 — proposal.assemble_draft MCP tool + section-level granularity”Description: Register MCP tool. Pulls section list, embedded refs, pricing
tiers, ROI outputs, target entity profile. Invokes the prompt. Parses output via
T19. Writes per-section block_data; sets last_assembled_at; records revision
with change_reason = assembled_draft. Section-level granularity: re-assembling
one section does not modify siblings.
Acceptance criteria:
- AC-17: Re-assembling one section leaves siblings’
block_dataandlast_edited_atunchanged. - Layer 1 + Layer 4 pass for the tool.
Verification:
- Integration test: full-proposal assemble → mutate one section → re-assemble that section only → siblings unchanged (timestamps + content).
Dependencies: T17, T19.
Files likely touched:
lib/mcp/tools/sales-proposals/assemble-draft.ts(new)__tests__/integration/sales-proposals/assemble-draft.test.ts(new)
Estimated scope: S (2 files).
ACs covered: AC-17.
Checkpoint — End of Phase 4 (v0.4)
Section titled “Checkpoint — End of Phase 4 (v0.4)”- AC-16, AC-17, AC-18, AC-31 verified.
- AC-29 / AC-30 partial (one of three prompts registered).
- Round-trip stability proven on golden fixtures.
Phase 5 — Export + QA gate (v0.5, L → split, parallelisable)
Section titled “Phase 5 — Export + QA gate (v0.5, L → split, parallelisable)”Goal: DOCX export production-ready; PDF export shipped or deferred per Q2; QA
gate operational. End state = Liam exports a buyer-ready .docx and runs the QA
gate.
T21 — DOCX export adapter + asset persistence
Section titled “T21 — DOCX export adapter + asset persistence”Description: Adapt ai-smb-playbook/app/src/lib/docx-export.ts into
lib/sales-proposals/export/docx.ts. Apache-2.0 notice preserved. Block-type
coverage extended per FR-7.1: cover, headings H1–H4, paragraph, bullet/ordered
list, separator, table (pricing + ROI), embedded image, footer with page
numbers. Persist to Supabase Storage at proposals/<id>/export_docx-<rev>.docx;
row in proposal_assets.
Acceptance criteria:
- AC-19: Full proposal
.docx< 2 MB; opens in LibreOffice 7 (CI). - AC-20: TOC, page numbers, pricing/ROI tables match live values.
- AC-22: Asset row has correct
mime_type,size_bytes, signed-URL.
Verification:
- CI step: LibreOffice headless conversion check.
- Integration test: byte-stability with golden file (timestamp tolerance).
- Manual: open the export in Microsoft Word 2021 (Liam pre-v1.0 sign-off).
Dependencies: T11 (pricing), T13 (ROI), T19 (parser).
Files likely touched:
lib/sales-proposals/export/docx.ts(new)lib/sales-proposals/export/docx-blocks.ts(block renderers)lib/sales-proposals/export/asset-store.ts(Storage upload + asset row)__tests__/integration/sales-proposals/docx-export.test.ts(new)
Estimated scope: M (4 files).
ACs covered: AC-19, AC-20, AC-22.
T22 — PDF export adapter (conditional on Q2)
Section titled “T22 — PDF export adapter (conditional on Q2)”Description: If Q2 = v1.0: build lib/sales-proposals/export/pdf.ts using
Playwright print over app/sales-proposals/[id]/print/page.tsx (print-optimised
render route). Otherwise: skip; defer to T38 in v1.5.
Acceptance criteria:
- AC-21 (conditional): PDF content matches DOCX numerics; file ≤ 2 MB.
Verification:
- Integration test: PDF render + numerics-cross-check.
Dependencies: T21 (shared block model).
Files likely touched:
lib/sales-proposals/export/pdf.ts(new — if v1.0)app/sales-proposals/[id]/print/page.tsx(new — print route)__tests__/integration/sales-proposals/pdf-export.test.ts(new)
Estimated scope: M (3 files).
ACs covered: AC-21 (conditional).
T23 — QA gate rule executors (10 rules)
Section titled “T23 — QA gate rule executors (10 rules)”Description: Implement each rule under
lib/sales-proposals/qa-gate/rules/*.ts: numerics consistency, client name
spelling, ROI sanity, brand voice, completeness, UK English, currency
consistency, date format, citation integrity, length. Each rule returns
{rule, severity, findings[]}. Dispatcher composes verdict per FR-8.2. Pattern
adapted from playbook-review skill harness.
Acceptance criteria:
- AC-23: Acme Ltd vs “Acme Limited” → Fail on client-name-spelling.
- AC-24: Pricing 24000 vs “£24,500” → Fail on numerics consistency.
- AC-25: “color” → Fail on UK English; “colour” passes.
- Citation integrity warns when ref missing.
Verification:
bun run test __tests__/lib/sales-proposals/qa-gate/rules.test.tspasses; one fixture per rule.
Dependencies: T11, T12, T19. Phase 0 Q9 sets numerics tolerance.
Files likely touched:
lib/sales-proposals/qa-gate/rules/numerics-consistency.tslib/sales-proposals/qa-gate/rules/client-name-spelling.tslib/sales-proposals/qa-gate/rules/roi-sanity.tslib/sales-proposals/qa-gate/rules/brand-voice.tslib/sales-proposals/qa-gate/rules/completeness.tslib/sales-proposals/qa-gate/rules/uk-english.tslib/sales-proposals/qa-gate/rules/currency-consistency.tslib/sales-proposals/qa-gate/rules/date-format.tslib/sales-proposals/qa-gate/rules/citation-integrity.tslib/sales-proposals/qa-gate/rules/length.tslib/sales-proposals/qa-gate/dispatcher.ts__tests__/lib/sales-proposals/qa-gate/rules.test.ts
Estimated scope: L → split if needed (12 files; rule executors independent so split at file granularity is trivial — author 3 sub-tasks T23a/T23b/T23c if a single agent runs over budget).
ACs covered: AC-23, AC-24, AC-25.
T24 — QA gate UI panel + run history persistence + MCP tool
Section titled “T24 — QA gate UI panel + run history persistence + MCP tool”Description: Build components/sales-proposals/QAGatePanel.tsx. Renders
findings checklist; each finding deep-links to the offending block. Register
proposal.run_qa_gate MCP tool. Persist runs in proposal_qa_gate_runs keyed
to a revision snapshot.
Acceptance criteria:
- AC-26: Run history persists with verdict + findings JSON.
- Findings checklist UI renders per FR-8.3.
Verification:
- Component test: findings render + deep-link target.
- Integration test: run inserts row.
Dependencies: T23.
Files likely touched:
components/sales-proposals/QAGatePanel.tsx(new)lib/mcp/tools/sales-proposals/run-qa-gate.ts(new)__tests__/integration/sales-proposals/qa-gate-run.test.ts(new)
Estimated scope: S (3 files).
ACs covered: AC-26.
T25 — Export MCP tool (proposal.export) + LibreOffice CI step
Section titled “T25 — Export MCP tool (proposal.export) + LibreOffice CI step”Description: Register proposal.export MCP tool that wraps T21 + T22. CI
workflow step runs LibreOffice headless conversion against a fixture proposal
export to verify rendering integrity.
Acceptance criteria:
- Tool registered; Layer 1 + Layer 4 pass.
- CI step runs on every push touching
lib/sales-proposals/export/**.
Verification:
bun run test:mcp-eval:fcgreen.- CI run on a sample PR shows the LibreOffice step passing.
Dependencies: T21, T22.
Files likely touched:
lib/mcp/tools/sales-proposals/export.ts(new).github/workflows/<existing>.yml(extend with LibreOffice step)__tests__/integration/sales-proposals/export-tool.test.ts(new)
Estimated scope: S (3 files).
ACs covered: none net-new (wraps T21/T22).
Checkpoint — End of Phase 5 (v0.5)
Section titled “Checkpoint — End of Phase 5 (v0.5)”- AC-19, AC-20, AC-22, AC-23, AC-24, AC-25, AC-26 verified.
- AC-21 verified or deferred to v1.5.
- DOCX CI gate live.
Phase 6 — Account Brief MCP App + remaining prompts (v0.6, S, parallelisable)
Section titled “Phase 6 — Account Brief MCP App + remaining prompts (v0.6, S, parallelisable)”Goal: Account Brief MCP App ships inline + standalone; two remaining prompts registered. End state = AC-27, AC-28, AC-29 (full), AC-30 (full) green.
T27 — Account Brief MCP App (Vite single-file build)
Section titled “T27 — Account Brief MCP App (Vite single-file build)”Description: Create mcp-apps/account-brief/. Vite single-file build per
existing pattern; built via bun run build:mcp-apps. Renders entity profile,
recent KB activity (last 10 referenced content_items), last contact
touchpoints, prior proposals snapshot. Inline panel inside KH; standalone for
Claude Desktop / Claude.ai plugin route.
Acceptance criteria:
- AC-27: Sub-2s LCP for entity with ≤50 referenced content_items.
- AC-28: Standalone build < 500 KB minified; renders same data.
Verification:
- Lighthouse-equivalent on inline panel; manual standalone load test.
bun run build:mcp-appsproduces the artefact.
Dependencies: T2 (types); P1-15 Phase 1 Company Profile (existing).
Files likely touched:
mcp-apps/account-brief/index.htmlmcp-apps/account-brief/src/main.tsxmcp-apps/account-brief/src/AccountBrief.tsxmcp-apps/account-brief/vite.config.tslib/mcp/inline-bundle/account-brief.ts(regen by build script)
Estimated scope: M (5 files).
ACs covered: AC-27, AC-28.
T28 — account_brief prompt registration
Section titled “T28 — account_brief prompt registration”Description: Register account_brief prompt at
lib/mcp/prompts/sales-proposals/account-brief.ts. Inputs: target entity ID;
outputs: structured Markdown brief. UK English. Wired to T27 panel.
Acceptance criteria:
- AC-29 (full): prompt listed under namespace.
- AC-30 (full): malformed output rejected.
Verification:
bun run generate:mcp-inventorylists; unit test for Zod validation.
Dependencies: T2.
Files likely touched:
lib/mcp/prompts/sales-proposals/account-brief.ts(new)__tests__/lib/sales-proposals/prompts/account-brief.test.ts(new)
Estimated scope: S (2 files).
ACs covered: AC-29 progressed.
T29 — case_study_assembly prompt registration
Section titled “T29 — case_study_assembly prompt registration”Description: Register prompt at
lib/mcp/prompts/sales-proposals/case-study-assembly.ts. Inputs: case-study
ref + deal context; outputs: Markdown insertion narrative with relevance-
justification framing.
Acceptance criteria:
- AC-29 (full): all three prompts listed.
- AC-30 (full): all three Zod-validated.
Verification:
bun run generate:mcp-inventoryshows all three.
Dependencies: T2.
Files likely touched:
lib/mcp/prompts/sales-proposals/case-study-assembly.ts(new)__tests__/lib/sales-proposals/prompts/case-study-assembly.test.ts(new)
Estimated scope: S (2 files).
ACs covered: AC-29, AC-30.
T30 — Inline workspace panel for Account Brief
Section titled “T30 — Inline workspace panel for Account Brief”Description: Mount the Account Brief MCP App inline in
/sales-proposals/[id] alongside the section navigator.
Acceptance criteria:
- Panel renders inline; deal context loads on page mount.
Verification:
- E2E covers the inline render path (later in Phase 7 Journey A).
Dependencies: T27.
Files likely touched:
app/sales-proposals/[id]/page.tsx(extend)components/sales-proposals/AccountBriefPanel.tsx(new)
Estimated scope: S (2 files).
ACs covered: AC-27 partial.
Checkpoint — End of Phase 6 (v0.6)
Section titled “Checkpoint — End of Phase 6 (v0.6)”- AC-27, AC-28, AC-29, AC-30 verified.
- All three prompts live; inline panel rendering.
Phase 7 — Hardening + handover (v1.0, M, parallelisable)
Section titled “Phase 7 — Hardening + handover (v1.0, M, parallelisable)”Goal: full E2E green; documentation complete; cross-cutting ACs verified; first-client handover pack assembled. End state = v1.0 ready for sign-off.
T31 — Playwright E2E Journey A
Section titled “T31 — Playwright E2E Journey A”Description: Cover Journey A (full proposal end-to-end) per spec §4.2. Open
new full-proposal → set deal context → review Account Brief panel → load
template → select 2–3 case studies → select 4–6 quotes → configure 3 pricing
tiers → enter ROI inputs → assemble draft → run QA gate → export DOCX. No
conditional if (visible) fallbacks per CLAUDE.md.
Acceptance criteria:
- AC-39: Journey A passes locally and in CI.
Verification:
bun run test:e2e e2e/tests/sales-proposals/journey-a.spec.tsgreen.
Dependencies: T1–T30.
Files likely touched:
e2e/tests/sales-proposals/journey-a.spec.ts(new)e2e/fixtures/sales-proposals.ts(test data setup)
Estimated scope: M (2 files but heavy logic).
ACs covered: AC-39.
T32 — Playwright E2E Journey C (one-pager)
Section titled “T32 — Playwright E2E Journey C (one-pager)”Description: Compressed authoring flow: cover + solution + pricing + single case study. Authoring time target ~15 minutes ⇒ test runs the path without the longer-tail steps.
Acceptance criteria:
- E2E path completes;
.docxexport downloads.
Verification:
bun run test:e2e e2e/tests/sales-proposals/journey-c.spec.tsgreen.
Dependencies: T1–T30.
Files likely touched:
e2e/tests/sales-proposals/journey-c.spec.ts(new)
Estimated scope: S (1 file).
ACs covered: none net-new (operational coverage).
T33 — MCP eval Layer 4 + Layer 3 updates (10 new tools, 3 new prompts)
Section titled “T33 — MCP eval Layer 4 + Layer 3 updates (10 new tools, 3 new prompts)”Description: Extend Layer 4 (functional correctness) with one check per new tool (10 tools: create, update, add_section, select_case_studies, select_quotes, configure_pricing, compute_roi, assemble_draft, run_qa_gate, export). Extend Layer 3 (response quality) with prompt-output checks.
Acceptance criteria:
- AC-40: Layer 4 passes for all 10 new tools.
- Layer 3 quality checks for the three prompts pass.
Verification:
bun run test:mcp-eval(Layer 1) +:rq+:fcall green.
Dependencies: T3, T9, T14, T18, T24, T25, T28, T29.
Files likely touched:
__tests__/mcp-eval/sales-proposals.fc.ts(new)__tests__/mcp-eval/sales-proposals.rq.ts(new)
Estimated scope: M (2 files but 13 checks).
ACs covered: AC-40.
T34 — Documentation (4 pages)
Section titled “T34 — Documentation (4 pages)”Description: Author docs/product-functionality/sales-proposals/:
overview.md, authoring-guide.md, template-reference.md,
roi-methodology.md. UK English; DD/MM/YYYY any dates; Warm Meridian-
compatible diagrams.
Acceptance criteria:
- All four pages exist and link from
docs/reference/documentation- inventory.md.
Verification:
- Manual review by Liam; doc-freshness guard test passes.
Dependencies: T31, T32 (so screenshots and walkthroughs reflect final UI).
Files likely touched:
docs/product-functionality/sales-proposals/overview.md(new)docs/product-functionality/sales-proposals/authoring-guide.md(new)docs/product-functionality/sales-proposals/template-reference.md(new)docs/product-functionality/sales-proposals/roi-methodology.md(new)docs/reference/documentation-inventory.md(extend)
Estimated scope: M (5 files).
ACs covered: none net-new (documentation gate).
T35 — Roadmap + state-of-product + handover pack
Section titled “T35 — Roadmap + state-of-product + handover pack”Description: Update docs/reference/product-roadmap.md §9.2 entry to
“shipped”; docs/reference/state-of-the-product.md entry on first-client
handover; assemble first-client onboarding pack per Phase 0 Q7 disposition.
Sentry observability check (assembly + export breadcrumbs).
Acceptance criteria:
- Roadmap §9.2 status = “shipped”; SoTP capability folded in (no Phase-N block per CLAUDE.md feedback).
- Handover pack present (live workspace + zip if Q7 = both).
Verification:
- Doc diff review.
- Sentry breadcrumb visible in a smoke run.
Dependencies: T31, T34.
Files likely touched:
docs/reference/product-roadmap.md(extend)docs/reference/state-of-the-product.md(extend)docs/handover/first-client-sales-proposals.md(new — if Q7 = both)
Estimated scope: S (3 files).
ACs covered: none net-new.
T36 — Schema reference update
Section titled “T36 — Schema reference update”Description: Document the 7 new tables in
docs/reference/SCHEMA-QUICK-REFERENCE.md.
Acceptance criteria:
- Each table has a row with FK list + RLS summary.
Verification:
- Manual review.
Dependencies: T1.
Files likely touched:
docs/reference/SCHEMA-QUICK-REFERENCE.md(extend)
Estimated scope: S (1 file).
ACs covered: none net-new.
T37 — Cross-cutting verification (lint, knip, coverage, UK English ESLint, regen artefacts)
Section titled “T37 — Cross-cutting verification (lint, knip, coverage, UK English ESLint, regen artefacts)”Description: Run bun run knip, bun lint, bun run test:coverage,
bun run generate:mcp-inventory, bun run build:plugin,
bun run sync:taxonomy (if any taxonomy touched), bun run stats. Fix findings
inline. Verify no raw Tailwind colour classes (lint rule); confirm UK English
ESLint allowlist gates author-visible strings; confirm coverage ≥ 80% on
lib/sales-proposals/.
Acceptance criteria:
- AC-36: No raw Tailwind colour classes.
- AC-37: ESLint blocks US spellings.
- AC-38: Coverage ≥ 80% on
lib/sales-proposals/. - AC-41:
bun run knipzero unused exports introduced. - AC-32, AC-33: spec §10 + §11 verdicts present (already in spec; verify no drift after impl).
Verification:
- All commands above run green.
Dependencies: All prior tasks.
Files likely touched:
docs/generated/codebase-stats.md(regen)docs/generated/mcp-inventory.md(regen)lib/mcp/plugin-bundle.ts(regen)
Estimated scope: S (artefact regen only; fix-time depends on findings).
ACs covered: AC-32, AC-33, AC-36, AC-37, AC-38, AC-41.
Checkpoint — End of Phase 7 (v1.0)
Section titled “Checkpoint — End of Phase 7 (v1.0)”- All 41 ACs green except AC-21 (if Q2 deferred to v1.5).
- E2E suites green in CI.
- MCP eval all layers green.
- Knip + coverage + lint clean.
- Liam manual sign-off on 3 exported
.docxin Microsoft Word 2021.
Phase 8 — PDF deferral (v1.5, conditional, S)
Section titled “Phase 8 — PDF deferral (v1.5, conditional, S)”T38 — PDF export adapter (deferred from T22)
Section titled “T38 — PDF export adapter (deferred from T22)”Description: Run only if Q2 = v1.5. Implement Playwright print over
/sales-proposals/[id]/print route.
Acceptance criteria:
- AC-21: PDF content matches DOCX numerics; file ≤ 2 MB.
Verification:
- Integration test green.
Dependencies: T21.
Files likely touched:
lib/sales-proposals/export/pdf.ts(new)app/sales-proposals/[id]/print/page.tsx(new)__tests__/integration/sales-proposals/pdf-export.test.ts(new)
Estimated scope: S (3 files).
ACs covered: AC-21.
§5 Dependency graph
Section titled “§5 Dependency graph”T0 └── T1 (migration) └── T2 (types) ├── T3 (3 stub MCP tools) │ └── T4 (workspace shell) │ └── T5 (foundation tests) ──┐ │ │ ├── T6 (templates) ──┐ │ │ ├── T7 (case-study selector) ─┐ │ └── T8 (quote picker) ────────┤ │ └── T9 (selector tools) │ ├──────────────┐ ├── T11 (pricing) ──┐ │ │ │ └── T13 (ROI panel) ←── T12 (ROI math) │ │ │ │ │ │ │ └── T14 (pricing+ROI tools) │ │ │ ├── T16 (Tiptap editor) ──┐ │ ├── T17 (proposal_shortcut prompt) ──┐ │ │ │ │ └── T19 (assembly parser) ────────────┴── T18 (assemble_draft tool) │ │ │ └── T21 (DOCX) ──┐ │ │ │ T22 (PDF cond) │ │ │ │ T23 (QA rules) ──── T24 (QA panel + tool) │ │ │ T25 (export tool) ──┐ │ │ │ T27 (MCP App) ─┐ │ │ T28 (account_brief prompt)│ T29 (case_study_assembly) │ T30 (inline panel) ───────┤ │ T31 (E2E A) ──────────────┤ T32 (E2E C) ──────────────┤ T33 (MCP eval) ───────────┤ T34 (docs) ────────────────┤ T35 (roadmap+SoTP) ───────┤ T36 (schema ref) ─────────┤ T37 (cross-cutting verify) ┘
Conditional: T38 (PDF v1.5 if T22 deferred)§6 Parallelisation analysis
Section titled “§6 Parallelisation analysis”Tasks in the same group below can run as parallel agents with disjoint file ownership. Each group is followed by its own checkpoint before launching the next.
Group A — Phase 2 selectors (after T6)
Section titled “Group A — Phase 2 selectors (after T6)”| Task | Files (disjoint) |
|---|---|
| T7 | components/sales-proposals/CaseStudy* + lib/sales-proposals/relevance.ts |
| T8 | components/sales-proposals/Quote* |
T9 sequential (depends on both).
Group B — Phase 3 pricing+ROI (after Phase 1)
Section titled “Group B — Phase 3 pricing+ROI (after Phase 1)”| Task | Files (disjoint) |
|---|---|
| T11 | components/sales-proposals/Pricing* + lib/sales-proposals/pricing/* |
| T12 | lib/sales-proposals/roi/* |
T13 depends on T12; T14 depends on T11+T12 (sequential after group).
Group C — Phase 4 prep (after Phase 1)
Section titled “Group C — Phase 4 prep (after Phase 1)”| Task | Files (disjoint) |
|---|---|
| T16 | components/sales-proposals/SectionEditor.tsx + SectionNavigator.tsx |
| T17 | lib/mcp/prompts/sales-proposals/proposal-shortcut.ts |
| T19 | lib/sales-proposals/assembly/* |
T18 depends on T17+T19; T16 independent.
Group D — Phase 5 export+QA (after Phase 4)
Section titled “Group D — Phase 5 export+QA (after Phase 4)”| Task | Files (disjoint) |
|---|---|
| T21 | lib/sales-proposals/export/docx* + asset-store.ts |
| T22 | lib/sales-proposals/export/pdf.ts + print/page.tsx (conditional) |
| T23 | lib/sales-proposals/qa-gate/rules/* |
T24, T25 sequential after the group.
T23 itself splittable into T23a/T23b/T23c (3-4 rules each) if a single agent runs over budget — rule executors are independent.
Group E — Phase 6 prompts + MCP App (after Phase 5)
Section titled “Group E — Phase 6 prompts + MCP App (after Phase 5)”| Task | Files (disjoint) |
|---|---|
| T27 | mcp-apps/account-brief/* |
| T28 | lib/mcp/prompts/sales-proposals/account-brief.ts |
| T29 | lib/mcp/prompts/sales-proposals/case-study-assembly.ts |
T30 depends on T27.
Group F — Phase 7 hardening (after Phase 6)
Section titled “Group F — Phase 7 hardening (after Phase 6)”| Task | Files (disjoint) |
|---|---|
| T31 | e2e/tests/sales-proposals/journey-a.spec.ts + fixtures |
| T32 | e2e/tests/sales-proposals/journey-c.spec.ts |
| T33 | __tests__/mcp-eval/sales-proposals.*.ts |
| T34 | docs/product-functionality/sales-proposals/* |
| T36 | docs/reference/SCHEMA-QUICK-REFERENCE.md |
T35 depends on T31 + T34; T37 depends on all.
Sequential constraints
Section titled “Sequential constraints”- T1 must complete before any other task (DB foundation).
- T2 must complete before any task touching types.
- T6 must complete before T7/T8 (template-derived section schema).
- T19 must complete before T18 (parser feeds assembly tool).
- T21 must complete before T22 and T25 (shared block model + tool wrapper).
- T31/T32 must complete before T34/T35 (docs reflect shipped UI).
- T37 last (verifies the whole).
Worktree discipline
Section titled “Worktree discipline”Per CLAUDE.md: parallel agent branches must cherry-pick (not merge) onto main;
agents must git reset --hard main as their first action; verify file content
after merging worktree branches from later waves; check git status on main
before each cherry-pick. Defensive cd <main-repo-path> && prefix on git
operations after any Read on worktree files.
§7 Verification cadence
Section titled “§7 Verification cadence”- Every task: per-task verification block above.
- Every phase: phase checkpoint listed.
- After every parallel group:
bun run test+bun run knip+git statuson main + cherry-pick each agent branch sequentially. - Pre-merge per phase:
bun run test:integration+ relevant E2E specs. - Pre-v1.0: full
bun run test,bun run test:e2e, all three MCP eval layers,bun run build,bun run knip, manual DOCX review.
§8 Risks and mitigations (plan-level addendum)
Section titled “§8 Risks and mitigations (plan-level addendum)”These extend spec §16 with task-execution risks specific to this plan.
| Risk | Impact | Mitigation |
|---|---|---|
| T0 question dispositions delayed — Liam not available for §17 answers | Blocks Phase 1 | Plan §3 lists all 10 questions upfront; capture answers async via spec edit. |
| T1 migration overrun — 7 tables + RLS + role + storage = larger than typical migration | Phase 1 slip | Pre-author the SQL in a draft; review separately before applying; shadow project first. |
| T19 assembly parser drift — Tiptap ↔ Markdown round-trip subtleties | AC-16 fail | Strict golden fixtures; per-block-type round-trip tests; reference feedback_tiptap_markdown_api.md. |
T21 DOCX byte-stability — golden-file noise from docx library version bumps | CI flaky | Tolerance band on Last-Modified metadata only; pin docx version; document the pin. |
| T23 rule explosion — 10 rule executors at once oversizes a single agent | Agent context overrun | Split T23 into T23a/T23b/T23c as needed; rule executors are independent. |
| T27 MCP App standalone build > 500 KB | AC-28 fail | Existing MCP App pattern keeps single-file builds tight; tree-shaking enabled; budget alarm in build script. |
| T31 E2E flakiness — 13+ steps in Journey A | CI red | Worker-scoped fixtures + multi-role auth; hard expect() assertions only (no conditional fallbacks per CLAUDE.md). |
| T37 coverage shortfall on QA-gate rules | AC-38 fail | Per-rule fixture in T23 already covers; verify lib/sales-proposals/ aggregate ≥ 80%. |
| Cherry-pick conflicts across parallel groups | Phase slip | Sequence groups (A → B → C → D → E → F); never run two groups concurrently; verify git status clean on main before each cherry-pick. |
bun fetch 204 hang in tests | Integration test red | Always run integration tests with dangerouslyDisableSandbox: true per CLAUDE.md. |
§9 AC → task mapping (rollup)
Section titled “§9 AC → task mapping (rollup)”| AC | Task(s) |
|---|---|
| AC-1 | T4 |
| AC-2 | T3 + T4 |
| AC-3 | T12 |
| AC-4 | T13 |
| AC-5 | T11 + T13 |
| AC-6 | T7 |
| AC-7 | T7 |
| AC-8 | T7 |
| AC-9 | T8 |
| AC-10 | T8 |
| AC-11 | T11 |
| AC-12 | T11 |
| AC-13 | T11 |
| AC-14 | T6 |
| AC-15 | T6 |
| AC-16 | T19 |
| AC-17 | T18 |
| AC-18 | T19 |
| AC-19 | T21 |
| AC-20 | T21 |
| AC-21 | T22 (v1.0) or T38 (v1.5) |
| AC-22 | T21 |
| AC-23 | T23 |
| AC-24 | T23 |
| AC-25 | T23 |
| AC-26 | T24 |
| AC-27 | T27 + T30 |
| AC-28 | T27 |
| AC-29 | T17 + T28 + T29 |
| AC-30 | T17 + T28 + T29 |
| AC-31 | T17 |
| AC-32 | T37 (verifies §10) |
| AC-33 | T37 (verifies §11) |
| AC-34 | T1 + T5 |
| AC-35 | T1 |
| AC-36 | T37 |
| AC-37 | T37 |
| AC-38 | T37 |
| AC-39 | T31 |
| AC-40 | T33 |
| AC-41 | T37 |
Every AC has at least one task. AC-21 is conditional on Q2.
§10 Cross-references
Section titled “§10 Cross-references”- Input spec:
docs/specs/sales-proposals-workspace-spec-arm-a.md(Stage 2). - Input research:
docs/research/sales-proposals-reuse-audit-arm-a.md(Stage 1). - Spec §13 phasing drives plan Phase 1–8 mapping.
- Spec §15 file-touch boundaries govern every task’s “Files likely touched” list; deviations flagged in commit messages.
- Spec §17 open questions mapped to plan §3 + Phase 0 Task T0.
- CLAUDE.md feedback memories flagged at relevant tasks: Tiptap (T19), E2E discipline (T31, T32), no-mid-session type regen (T1), barrel re-exports (T2, T3, T9, etc.), worktree cherry-pick discipline (Group parallelisation).
Workflow notes
Section titled “Workflow notes”- Phase 5 is the natural place for scope pressure — DOCX + PDF + QA gate + CI step all in one phase. The plan keeps T22 (PDF) explicitly conditional on Q2 and pre-stages T38 in v1.5; the CI assertion (T25) attaches to the DOCX path which is non-negotiable. Splitting T23 by rule executor is cheap and worth doing pre-emptively if any agent shows context-budget warnings — rules are mutually independent.
- The dependency graph has one structural pinch point: T6 (templates) gates both T7 (case-study selector) and T8 (quote picker). It is the only reason Group A is not larger; if T6 ships fast (the JSON files are mostly transcription), Group A scales out cleanly.
- The plan deliberately mirrors spec phasing v0.1 → v1.5 rather than proposing a different decomposition. Re-slicing would invite drift between spec milestones and impl tasks; the cost of that drift across a 6–8 week Phase 2 dominates any micro-optimisation.
- AC-32 and AC-33 are documentation ACs; they verify spec §10/§11 still match the implementation’s reused assets list. T37 owns this — without a verification task, a renamed file or a swapped reuse mode would silently break alignment.
- Worktree discipline applies hardest to Phase 7 because that is where the most parallelism converges (Group F: T31, T32, T33, T34, T36). The sequencing constraint (T35 after T31+T34, T37 last) reduces concurrent branches in flight at any one moment to four — well within the cherry-pick + verify-after-each-merge cadence the project has been using.