git:20260723.567149d to git:20260922.09bd4b1

131 added, 141 removed. Audit A to A.

---
name: dossier-builder
- description: Use to generate a printed market-research dossier (8-page HTML + PDF) the buyer brings to the dealer at test drive, summarizing buyer profile, regional comps, target OTD, and cross-bid anchors. Triggers include "build dossier", "generate market research PDF", "dealer dossier", "decision document", "make dossier for dealer", "生成 dossier", "制作 PDF", and Spanish phrases "generar el dossier para el concesionario", "crear el PDF de investigacion de mercado".
+ description: Use to generate an evidence-based HTML and PDF market-research dossier for a dealer visit. Triggers include "build dossier", "generate market research PDF", "dealer dossier", "decision document", "make dossier for dealer", "生成 dossier", "制作 PDF", "generar el dossier para el concesionario", and "crear el PDF de investigacion de mercado".
---
# Decision Dossier Builder
- > **Caveat**: this skill is one author's playbook + 5-scenario stress test. Verify state fees / CPO terms / EV credits / dealer practices against current sources before quoting numbers to a dealer or making financial decisions. Not tax, legal, or financial advice.
- > **last_verified**: 2026-05-18 (Phase 3C sub-skill split from orchestrator)
-
- Narrow helper: drive `generate_dossier.py` to produce the 8-page HTML + PDF
- dossier the buyer hands the salesperson at test drive. Defers the script,
- templates, and YAML schema to the orchestrator's `scripts/` and `assets/`.
-
- ## When To Use
-
- - Buyer is ready for the in-store visit and wants a printable evidence packet
- - Need EN or CN version (CJK template available)
- - Buyer has comp anchors collected (XHS / Reddit / cross-bids) and wants
- them formalized into a single document
+ Build a purchase proposal from dated source records, a complete set of competing
+ quotes, and an itemized offer. The generator checks arithmetic, required fields,
+ source dates, and stored evidence integrity. It cannot determine whether the
+ source actually supports a claim or whether a dealer still honors its terms.
+ Read each source before describing a claim as supported.
- ## When NOT To Use
+ ## Choose the mode
- - Still in Phase 1 (criteria not locked) - too early; orchestrator first
- - Quote evidence not yet collected - delegate to `quote-evidence-collector`
- - Just need an OTD calculation - delegate to `otd-calculator`
+ - `demo` accepts only the generated synthetic EN/CN/ES fixtures. Every page is
+ labeled as a synthetic demonstration that must not be presented as real.
+ Changing a fixture to include personal information is rejected.
+ - `live` requires a current config, evidence files, and output files under the
+ proven private companion DATA directory. Missing initialization, public or
+ unknown repository visibility, and paths outside that directory fail.
- ## 3-Step Workflow
+ Do not turn the demo into a real proposal by changing only its mode. Replace
+ fictional input with researched facts and buyer-approved statements, and bind
+ those fields to the actual source artifacts. Do not claim a confirmed quote,
+ clean history, active warranty, certification, payment method, or closing
+ commitment without the matching evidence. Keep the buyer's private walk-away
+ ceiling out of this dealer-facing document.
- 1. Copy `../orchestrator/assets/dossier_config_template.yaml` to a working
- file (e.g. `my_dossier.yaml`) and fill in 8-15 fields.
- 2. Run:
- ```
- python ../orchestrator/scripts/generate_dossier.py \
- --config my_dossier.yaml \
- --output dossier.html \
- --to-pdf dossier.pdf
- ```
- 3. (Optional) Chinese template:
- ```
- python ../orchestrator/scripts/generate_dossier.py \
- --config my_dossier.yaml \
- --template ../orchestrator/assets/dossier_template_cn.html \
- --output dossier_cn.html \
- --to-pdf dossier_cn.pdf
- ```
- 4. (Optional) Spanish (US) template:
- ```
- python ../orchestrator/scripts/generate_dossier.py \
- --config my_dossier.yaml \
- --template ../orchestrator/assets/dossier_template_es.html \
- --output dossier_es.html \
- --to-pdf dossier_es.pdf
- ```
+ ## Build a synthetic demonstration
- ## Required YAML Fields
+ From the repository root, choose an output directory outside the public tool
+ repository. For example, replace `<temporary-directory>` below with a system
+ temporary directory:
- - `BUYER_NAME`, `BUYER_ADDRESS`, `DATE`
- - `YEAR`, `MAKE_MODEL`, `TRIM`, `MSRP`
- - `TARGET_OTD`, `TARGET_SALE`
- - `STATE`, `TAX_RATE`
- - At least 2 `COMP_VEH_N` entries (other dealer listings as comp anchors)
+ ```sh
+ python skills/orchestrator/scripts/generate_dossier.py --mode demo --config skills/orchestrator/assets/dossier_config_template.yaml --output <temporary-directory>/dossier.html --to-pdf <temporary-directory>/dossier.pdf
+ ```
- ## Optional YAML Fields
+ For Chinese or Spanish, select `dossier_config_template_cn.yaml` or
+ `dossier_config_template_es.yaml`. `LANGUAGE` chooses the corresponding shipped
+ HTML template. `--template` may explicitly select a shipped EN/CN/ES template.
+ The localized templates translate fixed labels; arbitrary input prose is not
+ translated. The public fixtures are formatting demonstrations and contain some
+ English sample content.
- - `WALK_AWAY_CEILING` - recommended; gives the buyer a clear stop number
- - `REGIONAL_AVERAGE` - Edmunds / TrueCar reference price
- - `REDDIT_OTD_REPORT_1`, `_2`, `_3` - real buyer-reported OTDs (up to 3)
- - `CPO_PROGRAM` - if vehicle is CPO; populates p3 with program benefits
- - `INCENTIVE_STACK` - manufacturer rebates + state credits (EV, loyalty, etc.)
+ Fixtures are regenerated by `python tools/make_fixtures.py`; do not edit their
+ output files manually. Python needs PyYAML for YAML input and pypdf to verify PDF
+ output. Use Chromium 131 or newer for printed page-margin notices. An available
+ wkhtmltopdf fallback is attempted when Chromium is absent, but output still
+ fails verification if that renderer cannot print the required notice on every
+ page.
- ## 8-Page Dossier Structure
+ ## Build a real proposal
- | Page | Contents |
- |---|---|
- | 1 | Buyer profile + target summary + close-timing claim |
- | 2 | Regional market average (Edmunds / TrueCar) |
- | 3 | Trim / option breakdown + MSRP anchors |
- | 4 | Competing OTD quotes - first 2-3 cross-bid evidence rows |
- | 5 | Competing OTD quotes - continued, plus Reddit reports |
- | 6 | Internal anchor analysis (dealer's own concurrent inventory) |
- | 7 | Proposed OTD with structured paths (best / target / walk) |
- | 8 | Conditions of sale (CARFAX request, PPI booked, plate transfer decision) |
+ 1. Resolve the private DATA directory with `tools/runtime_paths.py`. Create and
+ store the config and source artifacts there. Never use a path in the public
+ repository for real buyer information or source observations.
+ 2. Read each source. Record its date, provenance, hash, and the fields it supports.
+ Require written OTD quotes for the same registration jurisdiction, with their
+ conditions and expiration dates. A listing price is not a written OTD quote.
+ 3. Fill every placeholder field used by the chosen template, including buyer
+ payment, financing, trade-in, and plate plans. Use `DOSSIER_MODE: live`,
+ `SYNTHETIC: false`, and today's quoted `DATE`.
+ 4. Run the generator. Relative live paths resolve under private DATA, so the
+ following paths are not relative to the public working tree:
- ## Script Behaviors
+ ```sh
+ python skills/orchestrator/scripts/generate_dossier.py --mode live --config dossiers/session/config.yaml --output dossiers/session/proposal.html --to-pdf dossiers/session/proposal.pdf
+ ```
- From `../orchestrator/scripts/generate_dossier.py`:
+ 5. Open the PDF and inspect every page for legibility, clipping, broken tables,
+ and untranslated text. Recheck amounts and source references. Report the
+ actual page count; length changes with the supplied content.
- - Cross-platform Chrome / Edge auto-detection (Windows / macOS / Linux); uses
- headless Chrome for HTML-to-PDF
- - Placeholder validation: scans template for ALL `{{KEY}}` tokens BEFORE
- substitution, fails loudly if any required key is missing
- - `--allow-missing` opt-out for incomplete configs (PDF will render
- `{{KEY}}` literal text for missing keys - useful for drafts)
- - Auto-detects `CHROME_BIN` environment variable as override
+ The shell entrypoint `html_to_pdf.sh` takes the same generator arguments. It
+ regenerates the validated dossier instead of accepting arbitrary input HTML.
+ `--allow-missing` was removed: missing or unresolved content must be completed
+ before a dossier is emitted.
- ## Template Variants
+ ## Monetary contract
- - EN (default): `../orchestrator/assets/dossier_template.html`
- - CN: `../orchestrator/assets/dossier_template_cn.html` (CJK glyph support)
- - ES (US): `../orchestrator/assets/dossier_template_es.html` (US-market Spanish)
+ Use decimal strings such as `"27500.00"`. Dollar signs, scientific notation,
+ negative charges, malformed separators, nonfinite numbers, and fractions of a
+ cent are rejected. The generator checks:
- The CN and ES templates are field-for-field equivalent (identical `{{KEY}}`
- placeholder set); the same YAML config drives all three. CN is useful when the
- buyer is Chinese-American and wants to share with parents / spouse before
- signing; ES when the buyer or a co-signer is more comfortable in Spanish, or
- for a Spanish-speaking dealer. The ES template uses verified US-Latino
- automotive-finance terminology (precio final / OTD, cargo por documentacion =
- doc fee, vehiculo a cuenta = trade-in, cheque de caja = cashier's check,
- vehiculo usado certificado = CPO, titulo de salvamento = salvage title);
- pending a native-speaker / Codex review pass before high-stakes use.
+ ```
+ TARGET_OTD = PROPOSED_SALES + TAX_AMOUNT + REG_AMOUNT + TITLE_AMOUNT
+ + DOC_AMOUNT + OTHER_FEES - TRADE_IN_CREDIT - REBATE_AMOUNT
+ TAX_AMOUNT = round_half_up(TAX_BASE * TAX_RATE / 100, 2) + TAX_ADJUSTMENT
+ ```
- ## Common Errors and Fixes
+ Supply every field, including explicit zero values. `TAX_RATE` is a percentage:
+ `"8"` means 8%. `TAX_ADJUSTMENT` is signed and must be supported when used for a
+ fixed adjustment. Derive the taxable base, credits, title, and registration
+ charges from current applicable rules; this arithmetic check does not decide
+ which jurisdictional tax mechanism or exemptions apply. Consult the
+ `otd-calculator` and `state-fee-lookup` helpers first. The tax basis and adjustment
+ row in the PDF is informational and is not added to the total a second time.
- | Error | Cause | Fix |
- |---|---|---|
- | `Chrome not found` | Headless renderer can't locate browser | Install Chrome OR set `CHROME_BIN=/path/to/chrome` env var |
- | `Missing required field: TARGET_OTD` | YAML key missing | Add to YAML; re-run |
- | PDF blank / missing CSS | Chrome version too old | Upgrade Chrome to >= 90 |
- | Garbled CJK glyphs in CN PDF | Font missing | Install Noto Sans CJK or use system font |
- | YAML parse error at line N | Quoting issue | Wrap value in double quotes; commas need quoting |
+ ## Quote and evidence contract
- ## Use Case
+ `QUOTES` contains at least two distinct complete offers. Every record requires:
- Bring the printed dossier to the test drive. Hand the salesperson page 1
- (buyer profile + target) at the start. Show pages 4-5 (cross-bid evidence)
- when the dealer counters. Show page 8 (conditions of sale) when negotiating
- the final deal sheet. Signals to the dealer:
+ | Field | Required meaning |
+ |---|---|
+ | `id` | Unique letters, digits, hyphens, or underscores |
+ | `vehicle`, `vehicle_id` | Vehicle description plus VIN or dealer stock identifier |
+ | `dealer`, `mileage` | Dealer identity and vehicle mileage |
+ | `otd` | Positive final amount, including the quoted taxes and fees |
+ | `registration_state` | Same jurisdiction as the buyer's `STATE` |
+ | `conditions` | Financing, trade-in, rebates, and other conditions affecting this amount |
+ | `expires_on` | Quoted expiration date; an expired quote is rejected |
+ | `status` | `written_quote` for live input; `synthetic` only in demos |
+ | `source_id` | ID of the matching `EVIDENCE` record |
- - You've done your market research
- - Your target OTD is anchored to comps, not pulled from thin air
- - You will close fast if the terms match (close-timing claim on page 1)
- - You will walk if the conditions of sale (CARFAX, PPI) are denied
+ All quote records are rendered. Do not provide legacy `COMP_*` fields or a
+ manually asserted count of confirmed offers; those display values are derived.
- Per orchestrator Critical Rule #3: never leave the dossier behind. Take it
- back to your car. The dealer can photograph but cannot keep the physical
- copy.
+ Each `EVIDENCE` record requires `id`, `kind`, `source`, `source_date`, and
+ `supports`. Dates use quoted `YYYY-MM-DD` strings. Live evidence additionally
+ requires `artifact` (a private DATA path) and `sha256` (the actual file hash).
+ Supported live kinds are `dealer_quote`, `listing`, `official`, and
+ `buyer_statement`. Use an HTTPS provenance URL, or a descriptive provenance
+ label for a buyer statement; the artifact preserves the inspected content.
- ## Cross-References
+ `supports` lists exact scalar field names and `quote:<id>` references. Each
+ nonempty live scalar fact or buyer statement needs coverage, except proposal
+ metadata and the buyer's proposed sales price and target. Each written quote
+ must reference `dealer_quote` evidence supporting that quote ID. Offer/listing
+ sources must be no older than 14 days; official documents and buyer statements
+ must have been reviewed within 90 days. Future dates are rejected. Keep original
+ source publication dates inside the artifact when `source_date` records a fresh
+ review of an older policy.
- - `../orchestrator/scripts/generate_dossier.py` - the renderer
- - `../orchestrator/assets/dossier_template.html` - EN template
- - `../orchestrator/assets/dossier_template_cn.html` - CN template
- - `../orchestrator/assets/dossier_template_es.html` - ES (US) template
- - `../orchestrator/assets/dossier_config_template.yaml` - YAML template
- starter (copy and fill)
- - `../orchestrator/SKILL.md` Phase 8 - dossier-prep phase in the master flow
- - `../orchestrator/SKILL.md` Critical Rule #3 - never leave dossier behind
- - `../quote-evidence-collector/SKILL.md` - upstream step that produces the
- `COMP_VEH_N` and `REDDIT_OTD_REPORT_N` raw inputs
- - `../otd-calculator/SKILL.md` - upstream step that produces `TARGET_OTD`
- and `WALK_AWAY_CEILING`
+ Record sources for warranty, certification, regional statistics, and narrative
+ claims as carefully as for quotes. Presence and matching SHA-256 establish that
+ the stored artifact has not changed; they do not prove its truth or the accuracy
+ of the operator's interpretation. The PDF displays source IDs, dates, and
+ provenance without printing local artifact paths.
- ## Sample Artifacts (Phase 0 / 5 test run, CT Outback example)
+ ## PDF and output checks
- - `<working-dir>/skill-test/p0_p5_execution/sample_dossier.html`
- - `<working-dir>/skill-test/p0_p5_execution/sample_dossier.pdf`
+ - Chromium runs with a fresh temporary profile and `--no-pdf-header-footer`.
+ - The default rendering timeout is 60 seconds; `--pdf-timeout` accepts values
+ above zero through 300 seconds.
+ - A new staging PDF must parse, contain pages, repeat the exact mode notice on
+ every page, and have no printed `file:///` URL before it replaces the requested
+ output. A renderer failure or timeout
+ cannot be mistaken for success because an old PDF exists.
+ - Inserted config text is HTML-escaped. Deliberate markup belongs in the shipped
+ templates; arbitrary templates and raw config HTML are not accepted.
- These are the reference outputs to diff against when changing templates.
+ Return the mode, private config path, HTML/PDF paths, actual page count, monetary
+ validation result, evidence completeness result, and scope of visual inspection.
+ For a demo, explicitly say that no real quote or negotiation was performed. For
+ live work, distinguish source review from the generator's mechanical checks.
- ## Output Contract
+ ## Related helpers
- After every dossier build, return to the operator:
+ - `../orchestrator/scripts/generate_dossier.py`: validation and rendering
+ - `../orchestrator/assets/dossier_template*.html`: EN/CN/ES layout
+ - `../quote-evidence-collector/SKILL.md`: source collection
+ - `../otd-calculator/SKILL.md`: supported OTD calculations
+ - `../state-fee-lookup/SKILL.md`: jurisdictional tax and fee verification
- ```
- Dossier build - <timestamp>
- Vehicle: <year make model trim>
- Config YAML: <path>
- Template: EN / CN
- Required fields supplied: <n>/<n>
- Optional fields supplied: <n>
- Output HTML: <path>
- Output PDF: <path>
- Pages rendered: 8
- Placeholder validation: PASS / FAIL <missing keys>
- Chrome used: <version>
- ```
+ When installed through directory links, resolve this SKILL.md to its source directory before following relative file paths. Those paths refer to the repository layout.