Draft quote (legacy v2 contract)
Before R549, the platform had a thin draft_quote row in workflow_definitions with the v1 schema. R549's migration 118 used draft_quote as the row to upgrade with the canonical worked example, then R550's migration 119 added customer_quote as the renamed-forward replacement.
The draft_quote row still exists for historical traceability — it carries the bid_price_update contract values (trigger spec, fan-out, verify checks) so the "first v2 contract" history is preserved. New work should target customer_quote.
Risk level 3 (medium). Mostly a documentation row at this point.
Trigger conditions
- Historical reference — do not trigger directly in new code.
- Migration verification — confirms R549's upgrade landed.
- Use
customer_quotefor active quote drafting.
If you find yourself dispatching to draft_quote, dispatch to customer_quote instead. The runner doesn't prevent it, but the v2 fan-out is more complete on the renamed-forward row.
The 7 beats
-
01
NS itempricing update (legacy)
The legacy fan-out target queued
itempricingwrites toNS_PUSH_QUEUE. Same semantics as bid_price_update. -
02
D1 pricing_master + pricing_history
D1 pricing_master is updated and pricing_history captures the prior value and change metadata.
-
03
bid_lines update (conditional)
If bid_id is present, the matching bid_lines row gets the new price + updated_at.
-
04
Regenerate bid PDF artifact
POST
/api/bids/:bid_id/regeneraterebuilds the bid response PDF. -
05
Invalidate hub UI cache
Keys
hub:nycdoe:bid_{bid_id}andhub:nycdoe:summaryare deleted. -
06
Spec sheet review flag
If
abs(price_change_pct) > 5, a row inserts intoproposed_actionswithaction_type=spec_review_needed. -
07
Customer notification draft
If the customer has an open quote and the change is a price increase, draft an email via
propose_email_to_customer.
What's different after the workflow runs
- Mirrors bid_price_update semantics one-for-one.
- Retained for migration history traceability.
- New code should target
customer_quote. - Removing this row would require a schema migration; not worth the churn.
What can go wrong and how to recover
If a chat tool emits action_type=draft_quote, the runner accepts it and runs the legacy contract. Functionally identical to bid_price_update for the price path, but customer_quote is preferred for explicit quote drafting.
These rows have overlapping intent. Always check workflow_type in workflow_runs to know which one ran.
Adjacent workflows + diagrams
Code paths + invariants
| Concern | Where |
|---|---|
| Workflow contract | workflow_definitions WHERE workflow_type='draft_quote' |
| Status | Legacy — use customer_quote |
| Origin migration | 118_workflow_contracts_v2.sql (R549) |
| Replacement | workflow_type='customer_quote' (R550) |
| Contract version | 2 |
| Risk level | 3 |
| Expected duration | ~5 min |
| Trigger | hitl_approval · proposed_actions approved with action_type=bid_price_update |