Deployment Cost & TCO — methodology

Method version 1.2.5 · engine /engines/deployment-cost-tco/ · API POST /api/v1/deployment-cost-tco

Input rules

Inputs (WP-01). A field that is not stated takes its documented default and is listed in provenance.defaulted; a field that is stated but invalid — a count of 0, a negative, a fraction or a non-number, true in place of a count, an unknown value of an enumerated input, or an empty string — is rejected with VALIDATION_ERROR naming the field, never replaced by a default.

Input keys (WP-02). The engine accepts one list of input keys — the inputs documented here and their declared backward-compatible aliases. Unknown input keys are rejected with VALIDATION_ERROR naming the key: an invented or misspelt key is never silently ignored, a __ test hook never reaches the engine, and an alias sent together with the key it stands for is rejected too (the engine would read only one of them). export_json.inputs echoes every input the engine honoured, so replaying it reproduces the result.

Two different defaulted lists. provenance.defaulted names the input fields this engine filled with its own documented default because the request did not state them (horizon_years, energy_rate_usd_per_kwh, duty_hours_per_day, camera_class). results.defaulted is something else: the page defaults the caller declares in the defaulted input (the preselected carrier_id and psu_rating_key), published as {field, value, rule} rows with the rule that chose them. One never feeds the other.

What is priced

Compute modules from module-prices (class C where a published vendor or distributor listing exists — not class B, which is reserved for EdgeAIStack measurements). Drives, PoE switches, carriers and PSUs from their price registries with the same listing taxonomy. Cameras use resolution-class planning allowances (class E) with an optional user override. Dev-kit compute lines carry a production note when the BOM is built from developer-kit listings. Quantities come from the caller — the engine does not re-pick hardware. A PoE-powered node with poe_supply.source === 'onboard_pd' has no separate PSU line (the carrier's PD input powers the node); a vendor add_on becomes an unpriced poe_add_on line so the hardware total stays honestly incomplete. The splitter path still prices the registry splitter and notes pse_required_w.

Carrier

A chosen carrier_id is checked before it is priced: the carrier_compatible check is PASS when the production-carrier registry lists the platform among the carrier's supported modules and FAIL when it does not — a BOM component must be physically attachable to the configuration, so an incompatible carrier is a NO FIT and its line is never priced (status incompatible, no price). A carrier the registry does not list cannot be checked: the check is UNKNOWN and the line unpriced. A compatible carrier is priced from the carrier price registry with the same rules as every other line; no price on record is an unpriced line, never $0. A system listing that ships with the module (a reComputer, for example) prices the module too, so it replaces the compute line instead of counting the module twice. When the platform's package already includes a carrier (a developer kit, a single-board computer, a complete system) there is no carrier line; the chosen carrier is still checked and a note says why it is not priced. For an accelerator card, a compatible host board chosen as the carrier becomes the host line.

NVIDIA sells its developer-kit reference carriers (Jetson Orin Nano P3768, AGX Orin P3737, AGX Thor P4071) only inside the developer kit, together with the module and a supply. The carrier price registry records that as available_separately: false, citing NVIDIA’s own statements and price list, so a developer-kit carrier chosen for a bare module is an unpriced line marked available_separately: false, and a BOM note says it is not sold separately and names the kit: it is never priced as the kit minus the module. For the module the kit ships, its registry row is the kit listing, so it still replaces the compute line, and the hardware total stays an incomplete lower bound until a carrier sold on its own is chosen. A kit carrier also takes modules its kit does not ship — NVIDIA states the Orin Nano developer-kit carrier supports all Jetson Orin Nano and Orin NX modules — and the registry names those (modules_not_included): an Orin NX on the Orin Nano kit carrier is compatible, keeps its own compute line at the module price, and the carrier line stays unpriced as not sold separately. The original Jetson Nano Developer Kit carrier is a different board that takes no Orin module and is not in the registry: a carrier id naming it cannot be checked, so carrier_compatible is UNKNOWN and the line unpriced — never PASS, and never read as the Orin Nano kit carrier.

The calculator page preselects a carrier and PSU for a bare module so the default run is priced: the platform's developer-kit carrier when it has a price (NVIDIA’s do not — they are not sold separately, and the page-default rule says so), otherwise the cheapest priced bare carrier that lists the module; and the supply Jetson Power & PSU sizes for that module on that carrier, or — when that rating has no priced row — the cheapest priced barrel supply inside the carrier's input-voltage range that meets the recommended watts. Both are page defaults the reader can change: the page sends them in defaulted, and the result lists them in defaulted and as “page default” assumptions with the rule that chose them. For a package that ships its own supply (a developer kit, a complete system) the PSU choice is disabled and labelled as included in the kit; a supply sent for such a package anyway is not priced, and a BOM note names it.

Completeness

An unpriced line makes the hardware total incomplete, never zero: unit_usd: null lines contribute nothing to hardware_usd, and tco_complete stays false until every hardware line and energy OPEX inputs are complete. When capex (priced lines only) and OPEX are known but hardware is incomplete, tco_usd is still published as a lower bound (tco_lower_bound: true) with the missing lines named — it is not null and it is not a complete TCO. Since method 1.0.4 every line with a null price or quantity says so in its note, together with the reason: a PSU line for a platform with no supply sized reads “Unpriced — No supply was sized…, so there is nothing to price.”

Budgets

capex_within_budget compares capex with budget_usd and energy_within_budget compares annual OPEX with opex_budget_usd_per_year; a total exactly at the budget fits. An incomplete total is a lower bound, and unpriced lines can only add cost: when the priced lower bound already exceeds the budget the check is FAIL, with the lower bound as the required value and an assumption naming the unpriced lines. When the lower bound is at or within the budget and lines are unpriced, the check is UNKNOWN (NEEDS VALIDATION) — the missing lines could take it either way.

The calculator page sends drive fields only with a chosen drive; its drives-per-node count defaults to 0, and it preselects a priced carrier and PSU for the default platform (see Carrier), so a default run prices every line it sends. duty_hours_per_day runs from 0 to 24; a value above 24 is refused with an error naming the field.

TCO

TCO is an undiscounted sum: capex (hardware plus opt-in capital allowances) plus opex_usd_per_year × horizon_years. No discount rate, financing, carbon, ROI, cloud comparison, certification or volume discounts — each is listed under exclusions because there is no defensible source.

Composition

This engine is the sole cost owner for the site: Architecture Designer and Full Deployment Planner call it for architecture.bom, totals.cost_usd and energy OPEX — nothing is re-priced from legacy tables. Standalone calculator inputs map to the same composed path the designer uses.

Coverage gate

scripts/cost-coverage-gate.mjs scores composed pricing on designer golden architectures and three FDP-shaped workloads for registry completeness (tco_complete and BOM validity). Use it after price-registry merges; it does not gate retirement — the legacy Deployment Cost engine, page and API were retired in Package 5e-2d.

Method changelog

MethodDateChange
1.2.52026-09-30A Dell PowerEdge R360 recording pool at RAID 5 or 6 names its PERC H755 controller prerequisite on the storage-host line; the entry PERC H355 supports RAID 0, 1 and 10 only (#262). Totals unchanged.
1.2.42026-09-29Orin NX on the Jetson Orin Nano developer-kit carrier (bug #252, owner ruling 2026-09-29): the production-carrier registry lists Orin NX 16GB and 8GB on that carrier, citing NVIDIA’s carrier specification (“supports all the Jetson Orin Nano Series and Jetson Orin NX Series modules”), so carrier_compatible is PASS where it was FAIL (NO FIT). The kit ships the Orin Nano 8GB development module, and the registry names the modules its carrier takes but the kit does not ship; a kit listing now replaces the compute line only for the module it ships, so an Orin NX build on it keeps its own priced compute line, and the carrier stays unpriced as not sold separately. The original Jetson Nano Developer Kit carrier (P3449) is not a registry row: an id naming it is UNKNOWN and unpriced, never PASS. No formula changed.
1.2.32026-09-28NVIDIA’s developer-kit reference carriers (Orin Nano, AGX Orin, AGX Thor) are recorded in the carrier price registry as not sold separately: NVIDIA states the Orin Nano and AGX Orin kit carriers are not sold on their own, and its price list and product pages offer only the kits. A chosen kit carrier is an unpriced line with the new line field available_separately: false and a BOM note naming the kit, instead of “no price on record”; the carrier is never priced as the kit minus the module. The page-default rule gives the same reason, and the page’s BOM status shows it. The Orin Nano developer-kit price in the production-carrier registry is NVIDIA’s current $399 (was the $249 launch price). No formula changed.
1.2.22026-09-28A chosen supply on a package that ships its own (the Orin Nano Super developer kit, the complete edge PC) is named in a BOM note as not priced (bug #236); it was dropped without a word. The page disables the PSU choice for those packages and labels it “included in the kit”; for a bare module the chosen supply is priced as before. The catalog publishes what each package includes (deployment_cost_tco.package_includes).
1.2.12026-09-28Input rules (WP-01 remainder, WP-02): an empty camera_class is rejected instead of becoming 1080p; pool_drives, node_drives_total, psu_recommended_w, storage_required and poe_required are typed like the other inputs; provenance.defaulted now lists horizon_years, energy_rate_usd_per_kwh, duty_hours_per_day and camera_class when they were not stated (separate from results.defaulted). Unknown input keys are rejected (allowances keys included); export_json.inputs carries the pool / host keys. No formula changed.
1.2.02026-09-28The chosen carrier is checked for attachability (carrier_compatible: FAIL and never priced when the registry does not list the platform; UNKNOWN for a carrier outside the registry). A module-including system listing replaces the compute line. A compatible host board is an accelerator's host line. New optional input defaulted and result field defaulted: page-default carrier and PSU published with their rule. The page preselects them for a bare module, so its default run is complete, and caps duty hours at 24. Previously an incompatible carrier was priced, and a carrier chosen for a package that includes one changed nothing.
1.1.02026-09-27A priced lower bound above the budget is a budget FAIL (NO FIT), not UNKNOWN: capex_within_budget and energy_within_budget carry the lower bound as the required value, detail.lower_bound: true and an assumption naming the unpriced lines. The page no longer sends a drive count without a drive.
1.0.52026-09-24Onboard PoE PD: no PSU line; optional unpriced poe_add_on. Splitter: PSU line is the registry splitter with pse_required_w in the note. A PSU line is required on every BOM unless poe_supply.source === 'onboard_pd'.
1.0.42026-09-18Every null-priced line says “unpriced” in its note.