Thames Valley Gifts — Founder Operations & Maker Payouts
DRAFT — Stage 1, with defaults applied 2026-09-28. Every "FOUNDER DECISION:" line still marked OPEN below must be answered in the Stage-2 interview before WP4 code starts; lines rewritten as "DECIDED 2026-09-28 (default adopted by orchestrator)" had a recommended default accepted on the founder's behalf, and the founder can still override any of them. See the Decision log at the end of this file. Items marked [UNVERIFIED] were not checked against code, the database, or a primary source in this pass.
0. Sources and fixed facts
Inputs, in the order read: research_notes/Thames Valley Gifts build/architecture_decision.md
(Option D, approved design: §2.1 tenancy, §2.2 data model, §2.5 HST, §2.7 routes, §2.8 AI desk,
§2.9 payout query, §2.10 deferred, §3 R7/R11, §4 WP4/WP6); research_notes/Thames Valley Gifts traffic and vendors/vendor_recruitment.md (Q2, Q3, Q7) and platform_operations.md (Q3 HST, Q4
Ontario consignment, Q5 returns, Q8 CASL); ai_front_desk_conversion.md (Q7 KPI list);
jb_creations_reference.md; knowledge/architecture/ai-bridge-principle.md;
ai-company-os/brands/engraving/BRAND.md.
Fixed facts (given by the founder's brief; not re-litigated here):
| # | Fact |
|---|---|
| F1 | The hub (ChurchWiseAI LTD, trading as Thames Valley Gifts, BIN 1001760694) is the merchant of record and an HST registrant (RT0001). |
| F2 | Consignment commission is 20% for founding makers, locked for 12 months — DECIDED 2026-09-28 (FOUNDER DECISION FINAL); implemented as per-maker commission_bps, default 2000 (0–5000 range stays available in the CHECK constraint for a future non-founding maker). All worked examples below use 20% as the brief requires. |
| F3 | Makers hold their own stock and ship their own orders. The hub never warehouses inventory. |
| F4 | Payouts by Interac e-transfer on the 1st and 16th of each month, each with a statement. |
| F5 | No exclusivity. Makers may sell anywhere else. |
| F6 | 30-day termination notice, either side. |
| F7 | The maker warrants originality of every design and product. |
| F8 | The maker fixes maker errors (production defects, wrong item) at the maker's cost; the hub fixes proof errors (a wrong proof the hub produced or approved internally) at the hub's cost. |
| F9 | Footer and every statement/invoice line: "Thames Valley Gifts is a division of ChurchWiseAI LTD." (Business Names Act). |
Conflict resolved in this spec — DECIDED 2026-09-28 (default adopted by orchestrator): the memo §2.9 describes a monthly statement; fixed fact F4 says payouts on the 1st and 16th. This spec adopts two statement periods per month — Period A (1st–15th, paid on the 16th) and Period B (16th to month-end, paid on the 1st of the next month) — plus a monthly roll-up view that must equal the sum of the two periods line for line. The memo's query is reused per period.
1. Scope and non-goals
In scope: every founder-facing screen under churchwiseai.com/founder/[token]/tvg/* and the
/api/tvg/admin/* routes behind them.
Out of scope (other specs): the public storefront and PDP (tvg-storefront.md, not yet
written), the customer proof → pay pages (tvg-proof-to-pay.md, not yet written), and the chat and
voice front desk (tvg-ai-front-desk.md).
Non-goals (v1, per memo §2.10): no maker portal or maker logins; no Stripe Connect automated payouts; no inventory counts; no cart; no cron-sent customer emails (the operator gets an action item instead); no Stripe Invoicing or Stripe Tax.
2. Auth, host and indexing (applies to every page and API in this spec)
- Every page under
/founder/[token]/tvg/*is a server component that comparesparams.tokenwithprocess.env.FOUNDER_TOKEN. A mismatch, an empty token, or an unset env var → Next.jsnotFound()(HTTP 404), never 401/403, never a redirect. Same pattern asacceptance/founder-hq.md§3. - Every
/api/tvg/admin/*route re-validates the token independently (headerAuthorization: Bearer <token>or JSON body{ token }). A mismatch → 404 with an empty body. A page render passing auth does not make the API trust the request. export const dynamic = 'force-dynamic'; no ISR, no caching.robots: noindex, nofollow(inherited fromfounder/[token]/layout.tsx) and anX-Robots-Tag: noindex, nofollowresponse header on every page and API response.- The founder token never appears in client-side JavaScript except inside the current URL; no link on these pages carries the token to a non-founder host.
- These pages live only on
churchwiseai.com. Onthamesvalleygifts.ca, any path beginning/founderreturns 404 (the brand host must not expose the ops surface). - All dates and times on these pages display in America/Toronto. All money displays as
$1,234.56CAD, computed from integer cents; no floating-point money anywhere.
| Test | Expected |
|---|---|
GET /founder/WRONG/tvg | 404, body is the site's standard 404 page |
GET /founder/<valid>/tvg | 200, X-Robots-Tag contains noindex |
POST /api/tvg/admin/makers with no token | 404 |
GET https://thamesvalleygifts.ca/founder/<valid>/tvg | 404 |
3. Page map
| Page | Purpose |
|---|---|
/founder/[token]/tvg | Action list (home) — §4 |
/founder/[token]/tvg/requests/[id] | Request detail and every request action — §7 |
/founder/[token]/tvg/makers, /makers/[id] | Maker list, create, edit, agreement gate — §5 |
/founder/[token]/tvg/catalog, /catalog/[id] | Product list, create, edit, status, schema, images — §6 |
/founder/[token]/tvg/payouts?period=YYYY-MM-A | YYYY-MM-B | ?month=YYYY-MM | Payout statements and monthly roll-up — §8 |
/founder/[token]/tvg/tax?from=YYYY-MM-DD&to=YYYY-MM-DD | HST accounting export — §9 |
/founder/[token]/tvg/kpis?week=YYYY-Www | Weekly KPI scorecard — §12 |
/founder/[token]/tvg/settings | Tax-rate table, flat shipping, pickup instructions, AI knowledge sync (sync spec lives in tvg-ai-front-desk.md §9) |
Every page shows the same top tab bar in this order: Action list · Requests · Makers · Catalogue ·
Payouts · Tax · KPIs · Settings, and a link back to /founder/[token] (the existing founder
dashboard). Founder HQ (/founder/[token]/hq) gets one new link to /founder/[token]/tvg in its
Admin tab.
4. Action list — /founder/[token]/tvg
The home page answers one question: "What do I need to do for the shop today?" It shows six queues, always in this order, each with a count badge. A queue with zero items still renders, with the text "Nothing here." (never hidden, so the founder can trust an empty queue).
| # | Queue | Rows included (server-side rule) | Sort | Row shows | Row action |
|---|---|---|---|---|---|
| Q1 | Unanswered requests | tvg_order_requests.status IN ('new','needs_info','changes_requested') | oldest first | order number, customer name, product title(s), source badge (Web / Chat / Voice / Email / Phone / In person), age in business hours, "needed by" date if set, a red Rush chip when needed_by is earlier than today + product lead_time_min_bd + 1 business day for the proof | open request |
| Q2 | Proofs awaiting approval | status = 'proof_sent' | oldest sent_at first | order number, customer, proof version, days since sent | open request; "Copy reminder text" (copies a pre-written reminder to the clipboard — no email is sent by the page or any cron) |
| Q3 | Approved, not paid | status = 'approved_awaiting_payment' | oldest approved_at first | order number, total, days since approval; rows older than 7 days (DECIDED 2026-09-28 (default adopted by orchestrator): 7) show an Expire button | open request; Expire (sets status='expired', writes an event, asks for confirmation first) |
| Q4 | In production | status IN ('paid','in_production') | earliest production_due_date first | order number, maker, due date, fulfilment (Pickup / Ship to XX) | open request |
| Q5 | Due today | production_due_date <= today (Toronto) AND status IN ('paid','in_production') | overdue first | same as Q4; overdue rows are red with "N business days late" | open request |
| Q6 | Voice and chat leads to promote | local_business_leads rows where business_id = the TVG local_businesses row, status NOT IN ('archived','lost'), not already linked to a request (metadata.tvg_order_request_id is null), and not dismissed | newest first | source (Voice / Chat), name, phone or "caller ID only — not confirmed", one-line summary, metadata.handoff_reason if present (e.g. Memorial, Complaint), received time | Create order request (§4.1); Dismiss (requires a reason) |
Below the six queues, two single-line notices appear only when true:
- "Payout due: Period YYYY-MM-A is finalized but not marked paid" (from the 16th / 1st onward).
- "Stripe dispute opened on TVG-000123" (from
charge.dispute.created; evidence bundle per memo §2.4).
4.1 One-click promotion of a lead (Q6)
- Clicking Create order request creates exactly one
tvg_order_requestsrow:source='voice'or'chat'(from the lead'ssourcevoice/chatbot),source_lead_id= the lead id,kind='retail',status='needs_info',customer_name←contact_name,customer_email←contact_email,customer_phone←contact_phone; ifcontact_phoneis null andmetadata.caller_idexists, the phone is pre-filled and the request page shows "Phone is the caller ID, not a confirmed callback number" until the operator ticks "Confirmed with customer".internal_notes← the lead'ssummary+message. An event row (actor='operator',event_type='promoted_from_lead') is written. - The lead gets
metadata.tvg_order_request_idset (our own internal row — a permitted write). - Idempotent: a second click on the same lead opens the existing request; it never creates a
second one. A double-click race produces one row (enforced by a unique index or equivalent on
source_lead_id). - The promoted request has zero items. "Send proof" stays disabled until at least one item with a product and schema-valid personalization is added (§7.2).
- The operator lands on the new request page within one click.
Should see / Should NOT see — Action list
| Should see | Should NOT see |
|---|---|
| All six queues, in order, with counts, even when empty | A "Delivered" / "Opened" email metric or any other vanity number |
| Ages in business hours/days (Mon–Fri, Ontario statutory holidays excluded) | Customer email addresses or full phone numbers in the list (shown only on the request page) |
| The Rush chip computed server-side | Any button that emails or texts a customer directly from the list |
| Voice leads with "caller ID only" labelled honestly | Leads belonging to any other local_businesses row |
| A clear empty state "Nothing here." | Leads already promoted or dismissed |
5. Maker management — /founder/[token]/tvg/makers
5.1 List
Columns: display name, town, status badge (Onboarding / Active / Paused / Ended), commission (e.g. "20%"), agreement ("Signed 2026-10-02 · v1" or a red "Not signed"), HST ("Registrant" / "Not registered" / red "Not set"), products (available / total), unpaid balance.
5.2 Create / edit form fields and inline validation
| Field | Rule (checked in the browser and again on the server) |
|---|---|
| Display name | required, 2–80 chars |
| Legal name | required, 2–120 chars; shown only on statements and the agreement, never publicly |
| Slug | required, lowercase a-z0-9-, unique; changing it after products are published shows a warning that public URLs change |
| Town, region | required; region defaults to ON |
| Story, photo, specialties, years making | optional; photo must have alt text |
| Commission | integer basis points; the form offers only the values allowed by FOUNDER DECISION F2 (2000 and/or 2500); the DB CHECK allows 0–5000 |
| Shipping passthrough | yes/no, default yes (maker ships and pays postage, so the shipping charge is paid to the maker — memo §2.2) |
| Payout method | e-transfer (default) / cheque / other |
| Payout e-transfer email | required when method is e-transfer; valid email; displayed masked (j•••@gmail.com) everywhere except the edit form |
| Contact phone / email | at least one required |
| Pickup instructions | required if the maker offers pickup through the hub |
| HST registrant | required yes/no — cannot be left blank once status is Active |
| HST number | required when registrant = yes; format 9 digits + RT + 4 digits (e.g. 123456789RT0001); inline error otherwise |
| Agreement signed date + agreement version | both set together or both empty; date cannot be in the future |
| Status | Onboarding → Active → Paused ↔ Active → Ended |
5.3 The agreement gate (memo R11 — server-side, not just UI)
- A product cannot be set to
availableunless its maker hasagreement_signed_atset,agreement_versionset,status='active', andhst_registrantnot null. The API returns 409 with the message "This maker hasn't signed the consignment agreement yet — products can't go on sale." (or the matching message for status / HST flag). The UI disables the "Available" option with the same sentence as a tooltip. - A maker cannot be set to Active without a signed agreement date and HST flag.
- Setting a maker to Paused immediately makes all their
availableproducts un-orderable (the public PDP shows "Temporarily unavailable"; the order-request API and the chat tool both refuse withnot_orderable). Open requests and paid orders are unaffected. - Setting a maker to Ended asks for the termination-notice date; on
notice date + 30 days (F6) the maker's products move to
retired. Until then they stay as they were unless the operator pauses them. Paid, unfinished orders stay on the action list until completed; the maker still receives payouts for them. - A maker's
commission_bpschange applies to future payments only: every item storescommission_bps_snapshotat payment time (memo §2.2), and statements always use the snapshot.
6. Product management — /founder/[token]/tvg/catalog
6.1 Status transitions (enforced by the API; the UI only offers legal moves)
| From → To | Server rule | Error if broken |
|---|---|---|
(new) → draft | always | — |
draft → example | product has is_demo_seed=true or its maker's agreement is not yet signed; an example product must carry the visible label "Example listing — not yet for sale" on the storefront | 409 |
draft / example / coming_soon / paused → available | maker gate (§5.3) passes and is_demo_seed=false and base_price_cents > 0 and at least one photo with kind hero and non-empty alt text and the personalization schema validates and lead_time_min_bd ≤ lead_time_max_bd, both ≥ 1 and at least one fulfilment option | 409 listing every failed rule |
draft / example → coming_soon | status_note set (e.g. "Available mid-November 2026") | 409 |
available → paused | always; open requests unaffected | — |
any → retired | always; retired is terminal | — |
retired → anything | never | 409 |
example with is_demo_seed=true → available | never — a demo seed must be replaced by a real maker product with the maker's own photos | 409 "Demo seed listings can never be sold." |
- The order-request API and the chat tool accept orders only for
availableproducts, andkind='waitlist'only forcoming_soon.example,draft,paused,retired→ refused server-side regardless of what the client sends. - Every status change writes an audit event (who, from, to, when).
6.2 Personalization schema builder
Two views of the same personalization_schema (memo §2.3): a form builder and a raw JSON
editor, kept in sync. Both run the shared validator (src/lib/tvg/personalization.ts, same
module the storefront and chat use).
| Rule (inline error shown next to the offending field) | Example error text |
|---|---|
Field key is required, snake_case, unique within the schema | "Key 'line1' is used twice." |
type is one of text, textarea, verse, monogram, image_upload, choice, date | "Unknown field type 'font_picker'." |
A text/textarea field must have max_length ≥ 1, and its label must state the limit ("up to 24 characters") | "The label must tell customers the 24-character limit." |
min_length ≤ max_length | — |
verse.translations ⊆ {KJV,WEB}; default_translation must be in the list | "Only KJV and WEB are available." |
monogram.letters = 3 and arrangement is one of the allowed options | — |
image_upload.dpi.good > dpi.ok > 0; max_mb ≤ 15 | — |
choice.options[].value unique; price_delta_cents is an integer (may be 0) | "Price change must be whole cents." |
quantity.tiers sorted by ascending min_qty; each unit_price_cents > 0; max ≥ min | — |
Preview boxes x/y/w/h are fractions between 0 and 1 | — |
| Raw JSON that does not parse | "Line 12, column 5: unexpected '}'." and Save is disabled |
- Saving a changed schema increments
version. Existing order items keep thepersonalization_schema_versionthey were captured with; the request page renders old items against their own version, never the new one. - A "Try it" panel renders the customer form from the current (unsaved) schema so the operator can type sample text and see the same limits and preview the customer sees.
6.3 Images
- Upload to the public
tvg-catalogbucket (memo §2.6), reusing the existing image validator as a pure import. JPEG/PNG/WebP only; each image requires alt text and a kind (hero,detail,scale,swatch,example_before_after); drag to reorder; exactly oneheroneeded foravailable. - Example listings: the upload form requires ticking "This photo was taken by Thames Valley Gifts
or supplied by the maker for this listing." Per
jb_creations_reference.md, no photo, price, description or review may be copied from a maker's own public pages into an example listing.
Should see / Should NOT see — Catalogue
| Should see | Should NOT see |
|---|---|
| Status badge on every row; the Example label text on example rows | An "Available" option on a product whose maker has no agreement |
| Every failed rule listed when a status change is refused | A generic "Something went wrong" on a 409 |
| Schema errors next to the field that caused them | A schema save that silently drops an invalid field |
| Prices as "$38.00 + HST" | Any HST-inclusive shelf price |
7. Request handling — /founder/[token]/tvg/requests/[id]
7.1 What the page shows
- Header: order number (
TVG-000123), status badge, kind (Retail / Bulk quote / Waitlist), source badge; for chat requests a link to the chat transcript; for voice requests a link to the source lead. - Customer: name, email, phone, organization (B2B), fulfilment (Pickup, or Ship with the full
address),
province_of_supply, needed-by date with Rush chip, gift note. - Items: product, maker, quantity, unit price, option deltas, tier applied, line subtotal, and the
personalization values rendered letter by letter in a monospace box (so "Jon" vs "John" and
doubled spaces are visible), plus whether spelling was confirmed and when
(
spelling_confirmed_at), and the verse text snapshot with its translation. - Uploads: thumbnail via a short-lived signed URL, effective DPI, quality rating (Good / OK / Low), and whether the customer acknowledged low resolution.
- Proofs: every version with status, sent time, customer response, and the change-request text.
- Payments: every payment row with method, status, amount, reference.
- Event log: every
tvg_order_eventsrow, newest first, with actor.
7.2 Actions and their server rules
| Action | Allowed from status | Server rule | Result |
|---|---|---|---|
| Edit items / personalization | new, needs_info, changes_requested | values re-validated against the product schema; price recomputed on the server | event items_edited |
| Send proof | new, needs_info, changes_requested | ≥1 item, all items schema-valid, ≥1 proof image, quote computed server-side: subtotal + shipping + tax at the §2.5 rate for province_of_supply from tvg_tax_rates; operator may edit the shipping amount only | new tvg_proofs row vN with status='sent', image sha256 stored; request → proof_sent; customer proof email (transactional template — FOUNDER DECISION: bless the template); customer page shows "Awaiting your approval" |
| Record manual payment (e-transfer / cash / cheque) | approved_awaiting_payment | amount must equal the approved proof's total_cents exactly (partial payments are not supported at launch; a mismatch is refused with the expected amount shown); reference required for e-transfer and cheque; payment date required, not in the future | tvg_payments row status='paid', recorded_by='founder'; request → paid, paid_at = payment date; commission_bps_snapshot copied from the maker; production_due_date = payment date + lead_time_max_bd business days (Ontario holidays excluded); maker job sheet (§10) sent |
| Mark in production | paid | — | in_production |
| Mark ready for pickup | paid, in_production | fulfilment = pickup; pickup instructions exist | ready_for_pickup; customer "ready" email (transactional) |
| Mark shipped | paid, in_production | fulfilment = ship; carrier and tracking number both required | shipped, shipped_at; tracking stored in the event payload; customer shipping email |
| Mark completed | ready_for_pickup, shipped | — | completed, completed_at (starts the 90-day upload-deletion clock) |
| Cancel | any status before paid | reason required: pick-list (Customer asked · No response · Can't be made · Duplicate · QA test) + free text | cancelled, cancelled_reason; no money moves |
| Refund | paid or later | founder click with a confirm dialog showing the amount; amount ≤ paid − already refunded; fault attribution required: Maker error / Hub proof error / Goodwill (no fault); reason text required. Stripe payments are refunded through Stripe; manual payments record the return e-transfer reference | payment refunded or partially_refunded, refunded_at set (memo WP1 note: add a real column, not updated_at); request → refunded if fully refunded; clawback rules in §8.3 |
| Expire | approved_awaiting_payment, proof_sent | confirm dialog; for proof_sent only after the proof's expires_at | expired |
| Decline | new, needs_info, proof_in_progress | reason required (free text) | declined, declined_reason; E12 variant sent — see tvg-proof-to-pay.md §3.2 |
- Every action writes one
tvg_order_eventsrow withactor='operator'. - Illegal transitions return 409 and name the current status.
- Nothing on this page ever charges a card. Stripe refunds are the only Stripe write, and only on a founder click.
8. Maker payout statements — /founder/[token]/tvg/payouts
8.1 Periods and dates (all America/Toronto)
| Period | Sales included (by paid_at) | Payout date |
|---|---|---|
YYYY-MM-A | 1st 00:00 to 15th 23:59:59 | 16th of the same month |
YYYY-MM-B | 16th 00:00 to last day 23:59:59 | 1st of the next month |
- A sale belongs to the period of its
paid_atin Toronto time, not UTC. - DECIDED 2026-09-28 (default adopted by orchestrator): pay on the calendar date even on weekends/holidays (e-transfer works every day), not the next business day.
- FOUNDER DECISION FINAL (2026-09-28): payout basis is completed (a maker is paid for an
order only once it is picked up or shipped, like the 14-day hold Shop Makers uses), not paid-date.
This remains implemented as a config flag (
tvg_settings.payout_basis, CHECKpaid/completed) so the founder can flip it without a code change, but the config default and the shipped behaviour are now bothcompleted. This spec's worked fixture (§8.5) is recomputed below on the completed basis, as the actual default WP4 ships.
8.2 Statement lines and arithmetic
For each maker and period, one row per item paid in the period (status in paid, in_production,
ready_for_pickup, shipped, completed, and maker_payout_status='unpaid'), plus one row per
clawback recorded in the period:
| Column | Rule |
|---|---|
| Gross | line_subtotal_cents — merchandise only, before HST, excluding shipping |
| Commission | round_half_up(gross × commission_bps_snapshot ÷ 10000), per line |
| Shipping passthrough | the order's shipping charge when the maker has shipping_passthrough=true (split pro rata by merchandise if an order ever has lines from two makers — memo §2.9); 0 for pickup |
| Refunds / clawbacks | negative lines per §8.3 |
| Net to maker | gross − commission + shipping passthrough + clawbacks |
- HST never appears in a maker's gross or net. The hub collects and remits it (F1).
- Stripe processing fees are absorbed by the hub out of its commission (memo §2.9 recommendation). DECIDED 2026-09-28 (default adopted by orchestrator): confirmed; the agreement states this.
- Statement totals are sums of the lines; no total is ever recomputed from rounded percentages.
- Negative net (clawbacks larger than new sales): the statement shows the negative balance as "Carried forward to next period"; no e-transfer is sent; the next period starts with that balance as its first line.
8.3 Refunds and clawbacks (implements F8)
| Refund fault | Effect on the maker |
|---|---|
| Maker error (defect, wrong item made) and the maker has already been paid for the item | clawback line = −(merchandise portion refunded × (10000 − commission_bps_snapshot) ÷ 10000), rounded half-up. HST refunded and shipping refunded are not clawed back unless shipping was refunded because of a maker error, in which case the passthrough shipping refunded is clawed back at 100%. |
| Maker error, item not yet paid out | the item's line is reduced before finalizing (no separate clawback line) |
| Hub proof error | no clawback — the hub absorbs it. A zero-value info line "Refund absorbed by hub (proof error) — TVG-000xxx" appears so the maker sees it. If the maker remakes at the hub's request, DECIDED 2026-09-28 (default adopted by orchestrator): the hub pays the maker for the remake at the original net. |
| Goodwill (no fault) | no clawback; hub absorbs; info line as above. DECIDED 2026-09-28 (default adopted by orchestrator): confirmed. |
| Remake instead of refund | no money line; recorded as an event; counts in the KPI "remakes" line |
8.4 Generate → Finalize → Mark paid
- Generate draft: computes the lines live. Re-running it before finalize gives identical output for identical data.
- Finalize: freezes the lines into
tvg_payout_statements.line_items(a frozen JSON copy) with totals; flips the items tomaker_payout_status='on_statement'; the statement becomes read-only. Later edits to orders, commissions or products do not change a finalized statement. A finalized item never appears on a later statement again. - Mark paid: requires the e-transfer reference (or cheque number) and the paid date; stores
etransfer_reference,paid_at; flips items topaid. Cannot mark paid a statement that is not finalized. Cannot mark paid twice. - Print / PDF: a printable statement with: "Thames Valley Gifts is a division of ChurchWiseAI LTD", the hub's GST/HST number (DECIDED 2026-09-28 (default adopted by orchestrator): supplied at runtime via an environment variable, never committed to git), the maker's legal name, the period and payout date, every line (order number, date paid, product, qty, gross, commission rate and amount, shipping, clawback, net), totals, carried-forward balance, and the payout reference once paid. No customer names, emails, phones or addresses on the statement. Emailing the PDF to the maker is a founder click (memo Phase 3), never automatic.
- Monthly roll-up (
?month=YYYY-MM): shows Period A, Period B and the month total side by side; the month total must equal A + B in every column.
8.5 Hand-computed fixture — October 2026, commission 20%, COMPLETED basis (the QA test)
Recomputed 2026-09-28 on the founder's final payout-basis decision (§8.1: completed, not
paid-date). A maker is now paid for an order only once it is picked up or shipped — so period
membership below is keyed on completed at (pickup/ship date), not paid_at. Every order's
paid_at is unchanged from the original paid-date illustration (kept for reference); each order
now also carries a completed_at. The bulk 12-unit Nova Scotia order (TVG-000103) takes longer to
produce and ships after the 15th, so — unlike the paid-date illustration — it lands in Period
B, not A, under the completed basis. This is the concrete effect the founder's decision has on a
real statement. The timezone-boundary property (TVG-000107) is preserved, now on completed_at.
Maker: TVG QA Maker (see §13 on QA isolation), commission_bps=2000,
shipping_passthrough=true, hst_registrant=false. All times America/Toronto.
Orders in the fixture:
| Order | Paid at | Completed at (picked up / shipped) | Fulfilment | Items | Merch (¢) | Shipping (¢) | Tax rate | Tax (¢) | Other facts |
|---|---|---|---|---|---|---|---|---|---|
| TVG-000101 | 2026-10-03 11:00 | 2026-10-07 10:00 (picked up) | Pickup (ON) | 1 × mug @ 1999 | 1999 | 0 | 13% | 260 | refunded in full 2026-10-25, hub proof error |
| TVG-000102 | 2026-10-09 14:20 | 2026-10-14 11:00 (shipped) | Ship ON | 2 × tumbler @ 2800 | 5600 | 1400 | 13% | 910 | one tumbler refunded 2026-10-22 (2800 merch + 364 HST), maker error, after the item was already paid out |
| TVG-000103 | 2026-10-14 09:05 | 2026-10-19 10:00 (shipped) | Ship NS | 12 × tumbler @ tier 2200 | 26400 | 1500 | 14% [UNVERIFIED NS rate] | 3906 | ships after the 15th → Period B under completed basis (was Period A under paid-date) |
| TVG-000107 | 2026-10-15 22:00 (= 2026-10-16 02:00 UTC) | 2026-10-15 23:30 (= 2026-10-16 03:30 UTC) (picked up) | Pickup (ON) | 1 × ornament @ 2400 | 2400 | 0 | 13% | 312 | timezone boundary on completed_at: Toronto date is still 10-15 → Period A |
| TVG-000108 | 2026-10-20 16:45 | 2026-10-23 10:00 (shipped) | Ship ON | 1 × slate @ 4500 | 4500 | 1400 | 13% | 767 | — |
| TVG-000104 | — | — | — | 1 × tumbler | — | — | — | — | approved_awaiting_payment → must not appear |
| TVG-000105 | 2026-10-05 | — | — | 1 × item from a different maker | — | — | — | — | must not appear |
| TVG-000106 | — | — | — | — | — | — | — | — | cancelled before payment → must not appear |
Expected statement 2026-10-A (payout date 2026-10-16):
| Order | Completed | Product | Qty | Gross | Commission 20% | Shipping | Clawback | Net |
|---|---|---|---|---|---|---|---|---|
| TVG-000101 | 10-07 | Mug | 1 | $19.99 | $4.00 (399.8 → 400) | $0.00 | — | $15.99 |
| TVG-000102 | 10-14 | Tumbler | 2 | $56.00 | $11.20 | $14.00 | — | $58.80 |
| TVG-000107 | 10-15 | Ornament | 1 | $24.00 | $4.80 | $0.00 | — | $19.20 |
| Total | $99.99 | $20.00 | $14.00 | $0.00 | $93.99 |
Check: 99.99 − 20.00 + 14.00 = 93.99. (TVG-000103 is NOT in Period A under the completed basis — it was paid 10-14 but not shipped until 10-19.)
Expected statement 2026-10-B (payout date 2026-11-01): (assumes 2026-10-A was finalized and marked paid on 2026-10-16 before the refunds; TVG-000103 was never on Statement A, so it appears here as a normal new sale, not a carry-over)
| Order | Date | Product / line | Qty | Gross | Commission 20% | Shipping | Clawback | Net |
|---|---|---|---|---|---|---|---|---|
| TVG-000103 | 10-19 | Tumbler (tier) | 12 | $264.00 | $52.80 | $15.00 | — | $226.20 |
| TVG-000108 | 10-23 | Slate | 1 | $45.00 | $9.00 | $14.00 | — | $50.00 |
| TVG-000102 | 10-22 | Refund clawback — maker error (1 tumbler) | — | — | — | — | −$22.40 | −$22.40 |
| TVG-000101 | 10-25 | Refund absorbed by hub (proof error) | — | — | — | — | $0.00 | $0.00 |
| Total | $309.00 | $61.80 | $29.00 | −$22.40 | $253.80 |
Check: 309.00 − 61.80 + 29.00 − 22.40 = 253.80.
Clawback check: 2800 × (10000 − 2000) ÷ 10000 = 2240 → −$22.40. The $3.64 HST refunded on
TVG-000102 and the $2.60 HST on TVG-000101 do not touch the maker. Both refunds are dated by
refunded_at, which is unaffected by the payout-basis choice — only the SALE lines' period
membership moved.
Expected monthly roll-up October 2026: Gross $408.99 · Commission $81.80 · Shipping $43.00 · Clawbacks −$22.40 · Net $347.79 (= $93.99 + $253.80).
Note — why the monthly total is unchanged from the paid-date illustration: every order still completes within October either way; the completed basis only moves TVG-000103 from Period A to Period B, so the monthly aggregate ($408.99 / $81.80 / $43.00 / −$22.40 / $347.79) is identical to the earlier paid-date worked example — only the two statements' individual totals differ ($93.99 + $253.80 here, versus $320.19 + $27.60 on a paid-date basis). This is expected and is itself a useful sanity check when QA-ing a real statement: the half-month split can move, the month cannot.
Commission-change control: after all fixture payments exist, change the maker's commission to
2500 and regenerate the drafts (before finalizing): every line above is unchanged, because every
line uses commission_bps_snapshot.
Unit tests: churchwiseai-web/src/lib/tvg/__tests__/payout-statement.test.ts runs this fixture
on the completed basis as the primary/default case (matching tvg_settings.payout_basis's
shipped default), plus a paid-basis case using the original paid-date numbers to prove the
alternative config still works, plus a positive control (test 25 below).
9. HST accounting export — /founder/[token]/tvg/tax
The export gives the founder (and the accountant) one table per date range to file the ChurchWiseAI LTD GST/HST return. [ACCOUNTANT] FOUNDER/ACCOUNTANT DECISION (OPEN): the filing period (monthly, quarterly or annual) — the page takes any date range and offers quarter shortcuts.
9.1 Summary by jurisdiction
One row per jurisdiction in tvg_tax_rates with activity in the range:
| Column | Rule |
|---|---|
| Jurisdiction | ON-HST, NS-HST, NB-HST, NL-HST, PE-HST, GST-only |
| Rate | from the order's stored quote_tax_rate_bps (never today's rate) |
| Taxable sales | Σ (merchandise + shipping) on orders paid in range |
| Tax collected | Σ order-level quote_tax_cents (sum of the per-order rounded amounts, never recomputed from the taxable total) |
| Refunded taxable / tax | Σ refunds recorded in range, split into taxable and tax |
| Net tax | tax collected − tax refunded |
Rate table (memo §2.5; [ACCOUNTANT] ACCOUNTANT DECISION (OPEN): confirm before any product
goes available): pickup in Ontario and ship to ON 13%; NB, NL, PE 15%; NS 14% [UNVERIFIED —
reported reduced from 15% on 2025-04-01]; AB, BC, MB, SK, QC, YT, NT, NU 5% GST only. No PST/QST is
collected ([ACCOUNTANT] ACCOUNTANT DECISION (OPEN): BC/SK/MB/QC registration thresholds
[UNVERIFIED]).
Fixture check (October 2026 orders from §8.5, all to a non-registrant maker):
| Jurisdiction | Taxable | Tax collected | Refunded taxable | Refunded tax | Net tax |
|---|---|---|---|---|---|
| ON-HST | $172.99 (19.99 + 70.00 + 24.00 + 59.00) | $22.49 (2.60 + 9.10 + 3.12 + 7.67) | $47.99 (28.00 + 19.99) | $6.24 (3.64 + 2.60) | $16.25 |
| NS-HST | $279.00 | $39.06 | $0.00 | $0.00 | $39.06 |
In this fixture the per-order sum ($22.49) happens to equal 13% of the ON taxable total (17299 × 0.13 = 2248.87 → 2249), so it cannot tell the two methods apart. The test must add one order pair where they differ — e.g. two separate $0.05 pickup orders: 1 ¢ + 1 ¢ = 2 ¢ by the per-order rule, versus round(10 × 0.13) = 1 ¢ by recomputation. The export must show 2 ¢.
9.2 Agent-versus-principal handling per maker (CRA GI-009, ETA s.177)
The export has a second table, one row per maker, because the correct treatment depends on whether the maker is a GST/HST registrant. The page shows which branch applied and never picks a branch the accountant has not approved.
| Maker status | Treatment the export shows (per platform_operations.md Q3) | Decision status |
|---|---|---|
| Not registered (small supplier) | ETA s.177(1): the hub's sale is deemed the hub's own taxable supply. The hub reports HST on the full sale in its return; no HST on the commission; the maker is paid their share with no HST. Row shows: merchandise, tax collected, commission (no tax), net paid. | Matches the research; [ACCOUNTANT] ACCOUNTANT DECISION (OPEN) to confirm. |
| Registered, option (a) purchase-and-resale framing | Maker invoices the hub for their share + HST; the hub claims that HST as an input tax credit. Row shows: maker share, HST on maker share (ITC candidate), the maker's GST/HST number. | [ACCOUNTANT] FOUNDER/ACCOUNTANT DECISION (OPEN) — note: invoicing the hub may weaken the "true consignment" position under Ontario case law (Lette criteria: consignor should not invoice the consignee). |
| Registered, option (b) s.177(1.1) joint election (form GST506) | The hub accounts for the tax on the whole sale; the hub charges HST on its commission to the maker. Row shows: tax collected on the sale, commission, HST on commission (13%), and whether a GST506 is on file. | [ACCOUNTANT] FOUNDER/ACCOUNTANT DECISION (OPEN) |
- Until the accountant picks (a) or (b), a registrant maker's products cannot be
available: the §5.3 gate adds "registrant treatment not chosen" as a 409 reason. - The export also lists, per maker, total consignment sales in the trailing 12 months, with a note when a non-registered maker passes $25,000 ("approaching the $30,000 small-supplier threshold — their consignment sales count toward it").
- [ACCOUNTANT] ACCOUNTANT DECISION (OPEN): whether the 2021 distribution-platform-operator rules apply instead of, or as well as, s.177 (the research says either path gives the same answer for unregistered makers) [UNVERIFIED].
- Download formats: CSV (one file per table) and a printable page. Integer cents in the CSV plus a formatted dollars column.
10. Maker job sheet
Sent to the maker for each paid order (on Stripe payment by the webhook handler, or on "Record manual payment"), by email from the hub's transactional address, and viewable on the request page. FOUNDER DECISION: bless the template before first send.
Must contain
- Order number, date paid, production due date ("Ship or have ready by Fri Oct 23").
- Product title and maker SKU/slug, quantity, size/colour/font choices.
- Every engraved/printed value exactly as approved, from the approved proof's
rendered_text_snapshot, shown both normally and letter-spaced, plus the verse reference, translation and full verse text. - The approved proof image (or a link to a short-lived signed URL, valid ≥ 7 days) and its version number.
- Customer photo(s) for photo products: the EXIF-stripped copy only, via signed URL.
- Fulfilment: Pickup → where and when to drop off / hand over, and the hub's instructions; or Ship → recipient name, shipping address, and the recipient phone only if the carrier label requires it; the carrier/label instructions; a link to enter the tracking number.
- Gift note, only if the customer asked for it to be included in the parcel.
- "Notes for maker" from the request (operator-reviewed).
- The rule reminders: "Make exactly what is on the proof. If you see a problem, stop and reply before making it. Maker errors are remade at your cost; proof errors are ours."
- "Thames Valley Gifts is a division of ChurchWiseAI LTD."
Must NEVER contain
- The customer's email address, or phone number (except where the carrier label needs it) — customer data belongs to the hub (agreement clause; CASL).
- Any payment detail: amount paid, card brand/last 4, Stripe ids, e-transfer references.
- HST amounts, the hub's commission, or other makers' items or prices.
- Internal notes, the chat or call transcript, AI summaries, or the source lead.
- The customer's original photo with EXIF/GPS, or any customer upload not used for this item.
- Customer-facing links: the request, proof or pay token links.
- Marketing-consent status or anything inviting the maker to contact the customer for other sales.
11. Consignment agreement — contents checklist
The agreement template must contain every item below. The ops page stores
agreement_version and agreement_signed_at; the template itself is a legal document outside
the code. [LAWYER] FOUNDER DECISION (OPEN): one-time Ontario lawyer review of the final text
(research gap: no Ontario online drop-ship consignment template exists).
- Parties: ChurchWiseAI LTD operating as Thames Valley Gifts (BIN 1001760694), and the maker's legal name and business name.
- True consignment: title stays with the maker until the customer's purchase; the hub acts as the maker's agent for the sale and for collecting payment (Lette criteria a–f).
- The maker holds and stores their own stock and ships their own orders (F3); risk of loss stays with the maker until handover to the carrier or to the customer at pickup.
- Goods held by the hub for pickup (if ever): who bears risk and insures. FOUNDER DECISION.
- Commission: 20% / 25% of the pre-tax merchandise price (F2 — FOUNDER DECISION); shipping charges passed through to the maker; Stripe fees absorbed by the hub.
- Pricing authority: who sets the retail price, and whether the hub may discount without consent. DECIDED 2026-09-28 (default adopted by orchestrator): the maker controls price (artist-form default).
- Payouts by e-transfer on the 1st and 16th, each with a statement (F4); paid-date vs completed basis (§8.1 FOUNDER DECISION); carry-forward of negative balances.
- Proceeds held separately from operating cash until paid out (Lette criterion e). [ACCOUNTANT] FOUNDER/ACCOUNTANT DECISION (OPEN): a separate bank account, or a ledger-only separation.
- No rent, no listing fees, no minimums, no obligation on the hub to buy unsold goods.
- No exclusivity (F5); the maker must pause or mark sold-out any listing they can no longer make, within 1 business day of knowing.
- 30-day termination by either side (F6); open paid orders are completed and paid out.
- Maker warrants originality (F7): original designs, no IP infringement, rights to any artwork used; the customer-supplied photo/artwork warranty sits with the customer.
- Product safety and labelling compliance; product liability insurance for higher-risk categories (candles, bath, children's items, food). FOUNDER DECISION: which categories require proof of insurance.
- Indemnity by the maker for breach of the warranties.
- Errors (F8): the maker remakes or refunds maker errors at the maker's cost; the hub bears proof errors; the approved proof is the specification.
- Production times: the maker commits to each product's lead time from payment, and to replying on proof questions within 1 business day. FOUNDER DECISION: exact numbers.
- HST status representation (registrant yes/no, number) and a duty to tell the hub within 30 days of any change; the registrant treatment chosen (§9.2).
- Customer data belongs to the hub; the maker may not use order data to market to or contact the customer except to fulfil the order (CASL, PIPEDA).
- Photo and description licence: the maker lets the hub use product photos and text on the hub's site, chat/voice front desk and marketing, during the agreement and for 30 days after.
- Monthly/semi-monthly statements as the regular accounting of sales (Lette criterion d); the maker's right to question a statement within 30 days.
- Governing law: Ontario. Agreement version number and signature date.
- Footer line: "Thames Valley Gifts is a division of ChurchWiseAI LTD."
12. Weekly KPI scorecard — /founder/[token]/tvg/kpis
One page per ISO week (Mon–Sun, Toronto). Honest metrics only: every number links to the rows it counts; a metric with no data source shows "Not measured", never 0 and never an estimate. No "Delivered" or "Opened" email metrics (OUTBOUND_PROCESS_MAP honesty rule).
| # | KPI | Definition | Source |
|---|---|---|---|
| K1 | Inquiries by channel | count of chat sessions, voice calls, web-form requests, email/phone/in-person requests created in the week | chat log, local_business_leads (source voice), tvg_order_requests.source |
| K2 | After-hours share | share of K1 created outside Mon–Fri 9:00–18:00 Toronto | timestamps |
| K3 | Capture rate | share of chat sessions and voice calls ending with a name + contact | leads + chat requests ÷ K1 (chat/voice) |
| K4 | Spec-complete rate | share of chat requests created with every required personalization field valid and spelling_confirmed_at set | tvg_order_items |
| K5 | Proof latency | median and slowest hours from request created → first proof sent; target: 100% within 1 business day | events |
| K6 | Proof approval rate | proofs approved ÷ proofs sent (first version and any version) | tvg_proofs |
| K7 | Proof-to-paid | paid ÷ approved | tvg_order_requests |
| K8 | Hand-offs by reason | count of hand-offs from the AI desk by reason (Memorial, Quote, Artwork, Rush, Complaint/Remake, Other language, Not in fact sheet) | lead metadata.handoff_reason, chat events |
| K9 | Remakes and refunds | count and $ by fault (maker / hub proof / goodwill); "caught at proof" (change requests) vs "reached production" | refunds, remake events, changes_requested |
| K10 | Per-maker activity | per maker: product views [Not measured until analytics exist], AI-desk questions naming their products, requests, paid orders, net earned | events, statements |
| K11 | Payouts on time | statements paid on or before the payout date ÷ statements due | tvg_payout_statements |
| K12 | Action-list health | items in Q1 older than 1 business day; Q5 overdue count, at the moment the week closes | action-list queries |
- Excluded from every KPI: requests cancelled with reason "QA test" and anything on the QA maker.
- The page shows the previous 6 weeks as a small table for trend, no projections.
13. QA checklist (run on the deployed URL with the founder token; evidence attached)
QA isolation — DECIDED 2026-09-28 (default adopted by orchestrator): the checks below need
orders on the production database (there is no staging). The adopted approach: one internal maker
"TVG QA Maker" (slug qa-maker, agreement version internal-qa) whose products carry a
qa_only flag (already part of the Wave A schema) that hides them from the storefront, the
catalogue API, the AI knowledge sync, KPIs, the HST export and real payouts, and QA customers use
john+tvgqa@churchwiseai.com. This isolation rule is approved; WP4 QA may write orders under it.
| # | Check | Expected | Evidence |
|---|---|---|---|
| 1 | Wrong token on every page and one admin API | 404 each; X-Robots-Tag: noindex on the valid page | curl output |
| 2 | /founder/<valid>/tvg on thamesvalleygifts.ca | 404 | curl |
| 3 | Action list with empty data | six queues, each "Nothing here." | screenshot |
| 4 | Create a maker without agreement date; try to set a product available | 409 with the agreement sentence; UI option disabled | screenshot + API response |
| 5 | Add agreement date + HST flag, retry | product becomes available | DB row |
| 6 | Try available on an is_demo_seed example | 409 "Demo seed listings can never be sold." | response |
| 7 | Schema builder: text field label without the limit; raw JSON with a missing brace | inline errors as in §6.2; Save disabled for invalid JSON | screenshot |
| 8 | Pause the maker; attempt an order via the public API and via chat | both refused not_orderable | responses |
| 9 | Promote a voice lead twice (double-click) | exactly one request; second click opens it; lead has metadata.tvg_order_request_id | DB count |
| 10 | Send proof on the promoted request with zero items | button disabled / 409 | screenshot |
| 11 | Send proof on a valid request | proof v1 sent; the customer proof page shows "Awaiting your approval" (sample the customer page before and after — status text changes) | two screenshots |
| 12 | Record a manual e-transfer with the wrong amount, then the right amount | first refused showing the expected total; second → paid, due date set, job sheet sent | DB rows + job-sheet email |
| 13 | Inspect the job sheet | contains every §10 "must contain" item; contains none of the "must never contain" items (grep the email body for the customer email, "$", "HST", "Stripe", token links) | email source |
| 14 | Mark shipped without tracking | refused; with carrier + tracking → shipped | responses |
| 15 | Cancel without a reason | refused | response |
| 16 | Build the §8.5 fixture; generate 2026-10-A | lines and totals match the fixture line by line (5 values × 4 lines + totals); TVG-000104/105/106 absent; TVG-000107 in Period A | statement vs fixture diff = empty |
| 17 | Finalize A; edit TVG-000103's quantity; regenerate | finalized A unchanged; items on_statement | frozen JSON |
| 18 | Mark A paid without a reference; then with one; then again | refused; paid; third refused | responses |
| 19 | Record the two refunds; generate 2026-10-B | matches the fixture; clawback −$22.40; hub-proof-error line $0.00 | diff = empty |
| 20 | Monthly roll-up October 2026 | net $347.79 and every column = A + B | screenshot |
| 21 | Change commission to 2500; regenerate drafts (before finalize) | all lines unchanged | diff |
| 22 | HST export for October 2026 | matches §9.1 fixture table; plus the rounding-divergence order proves sum-of-orders | CSV |
| 23 | HST export per-maker table | non-registrant row shows "no HST on commission"; a registrant maker with no chosen treatment blocks available | CSV + 409 |
| 24 | KPI page for the fixture week | QA-maker rows excluded; any metric without a source reads "Not measured" | screenshot |
| 25 | Positive control: deliberately break one fixture value (e.g. set commission snapshot 2100 on one line) | test 16 fails and names the line | failing run |
Critical-path note: WP4 does not touch middleware.ts or the Stripe webhook, but the refund
action calls Stripe — refunds are tested only in Stripe test mode until the founder approves a live
refund.
14. Open items for the Stage-2 interview
- DECIDED 2026-09-28 (FOUNDER DECISION FINAL): commission is 20% for founding makers, locked for 12 months; implemented as per-maker
commission_bps, default 2000 (a maker-level parameter, never a constant — a future maker could still be onboarded at a different rate outside the founding cohort). - DECIDED 2026-09-28 (default adopted by orchestrator): two statement periods per month (Period A / Period B), each independently generated and finalized — see §0.
- DECIDED 2026-09-28 (FOUNDER DECISION FINAL): payout basis is completed (a maker is paid for an order only once it is picked up or shipped), not paid-date; implemented as config
tvg_settings.payout_basis, defaultcompleted. The §8.5 worked fixture is recomputed on this basis. DECIDED 2026-09-28 (default adopted by orchestrator): payout dates are the calendar date even on weekends/holidays. - DECIDED 2026-09-28 (default adopted by orchestrator): Stripe fees absorbed by the hub; goodwill refunds absorbed by the hub; hub pays the maker for hub-caused remakes at the original net.
- [ACCOUNTANT] OPEN. FOUNDER/ACCOUNTANT DECISION: tax rate table incl. NS 14% [UNVERIFIED]; PST/QST duties; registrant treatment (a) vs (b); DPO rules; separate proceeds account; filing period.
- DECIDED 2026-09-28 (default adopted by orchestrator): approved-unpaid expiry at 7 days; Q1 "unanswered" threshold at 1 business day.
- OPEN — bless transactional templates before first send: proof ready, ready for pickup, shipped, maker job sheet.
- DECIDED 2026-09-28 (default adopted by orchestrator): QA isolation approach per §13 — hidden QA maker +
qa_onlyschema column (already in the Wave A schema). - DECIDED 2026-09-28 (default adopted by orchestrator): pricing authority — the maker controls price (artist-form default). Still OPEN, no default: which categories require proof of insurance; [LAWYER] one-time Ontario lawyer review of the agreement.
- Rule #14:
FEATURE_REGISTRY.mdneeds a Thames Valley Gifts row before code (memo §0.5). - [UNVERIFIED] The TVG
local_businessesrow does not exist yet; every reader oflocal_businessesmust be checked so it is not treated as a prospect or customer (memo R7).
15. Decision log (2026-09-28 editorial pass)
Defaulted (DECIDED 2026-09-28, default adopted by orchestrator; the founder can still override):
the two-period-per-month payout model (§0); the 7-day Q3/expiry threshold; calendar-date payouts on
weekends/holidays; Stripe fees, goodwill refunds and hub-caused remakes absorbed by the hub;
pricing authority (maker controls price); QA isolation approach (hidden QA maker + qa_only,
already in the Wave A schema); the GST/HST-number-via-env-var default on payout statements.
Decided FINAL 2026-09-28 (no longer open):
- F2 / commission — 20% for founding makers, locked 12 months; implemented as per-maker
commission_bps, default 2000. - Payout basis — completed (pay only once picked up/shipped), not paid-date; implemented as
config
tvg_settings.payout_basis, defaultcompleted. The §8.5 fixture is recomputed on the completed basis to match.
Left open (per explicit instruction, or no default exists):
- [ACCOUNTANT] items: filing period, the provincial tax rate table (incl. NS 14%), PST/QST duties and registration thresholds, registrant treatment (a) vs (b), the 2021 distribution-platform-operator question, and the separate-proceeds-account question.
- [LAWYER] one-time Ontario lawyer review of the consignment agreement.
- Blessing transactional templates (proof ready, ready for pickup, shipped, maker job sheet): left open until drafted.
- No default existed for: insurance categories requiring proof, and the maker's exact lead-time /
reply-time commitments (open numbers, founder's to set); the e-transfer receiving address (see
tvg-proof-to-pay.mdP8); who bears risk/insurance for goods held at the hub for pickup.
Inconsistency found and fixed: the request-handling action table (§7.2) had no "Decline" action
and no "Expire from proof_sent" path, even though tvg-proof-to-pay.md §3.2 defines both
transitions (founder "Decline" with required reason → declined; founder "Expire" on an unapproved,
expired proof → expired). Both rows have been added to §7.2 so the two specs agree.