← back to pin list

15a. What a quote is made of

kerfmaster pin list · Estimator & quoting

intentmixedWhat we want to build. Never claimed the present, so it cannot be stale — and must never be read as a description of the code.

Content last changed 2026-08-22 — computed from the item itself, not typed.

Contract — Report stage

This contract describes a stage we intend to build — it is NOT a description of the code.

takes gcodematerial-table

makes delivery

fails if A cost line with no stated source.

Contract last changed 2026-08-06 — computed, not typed. Dated separately from the text above, so neither date can speak for the other.

1 open question blocks this pin

The line items, with where each number comes from. Anything marked SHOP is a value only Jordan or Aristide can supply (15e).

1. Machine time

2. Material

3. Assist gas

A function of cut time × pressure × nozzle size. Nitrogen on stainless and aluminium is a real line item and is routinely under-counted. SHOP: gas cost and consumption rate, or simply an all-in figure folded into the hourly rate — but say which, so it is not counted twice.

4. Consumables

Nozzles, lenses, protective windows, filter media — amortised per machine hour. Usually simplest inside the hourly rate. SHOP.

5. Labour

6. Margin and commercial policy

Minimum charge, rush multiplier, repeat-customer terms, quantity policy. Entirely SHOP. The estimator should reproduce today's pricing before it tries to improve it — a tool that disagrees with the boss on job one does not get used on job two.

Feedback loop

Each quoted job records estimated vs actual. Same discipline as the numbered slug report: the shop reports back by job number, and the table tightens. Without this the estimator is frozen at whatever we guessed on day one.

⚑ Build state, 2026-08-21: wired as the line-item list in quote.py — machine time (naive + 15b accel model), pierce, rapid, handling, material (remnant-policy aware: charged prices whole sheets, stocked/scrapped the nested fraction), tab break-off, gas, machine rate, shop minimum, margin. Each item computes from counted quantities or names its missing SHOP rows. No value is defaulted; RateMissing raises with the dotted row name.

Roll-up built, 2026-08-21 (Aristide: 'start execution on moving on without waiting for Jordan'): rollup.py composes these line items into the one figure a customer approves (Q29), by PER-SHOP POLICY -- a fixed skeleton with switchable joints, every joint a policy row in rates.json (cutting_basis, handling_bills_at, material_markup_pct, rush_multiplier, minimum_applies, rounding; all editable in the shop tables editor, seeded 'assumed'). Wired into quote.py: the printout ends with the TOTAL and its step-by-step composition. Honesty rails: any blocked input -> no total, blocked_by names the rows; one assumed input anywhere -> INDICATIVE with the culprit rows listed -- firm is only reachable when every consumed row is measured/decided. Per Aristide's flexibility ruling ('We aren't just building this for Jordan... We want our clients to have a flexible system'), his and Jordan's Q29 ruling becomes the DEFAULT CONFIG a subscribing shop inherits and adjusts; deliberately NOT a freeform formula editor. Deferred, recorded: quantity breaks (15c, needs nest part-count). The approval-artifact wiring (fast tier through the same skeleton) landed 2026-08-22 — see the 7g and 15d build states.