Working principles
The scope and the runtime are separate objects.
The Intervention holds the scope and the M&V plan. The strategy is the runtime that delivers it. Keeping them apart lets a hardware retrofit verify under the same scope with no strategy at all, lets a partner algorithm replace a Wattif-written one without re-papering, and lets a strategy be paused or retuned without touching the verification record. One scope; zero, one, or many runtimes.
One control surface across three entity kinds.
A strategy binds to an asset (a fan-coil), a space (a refrigerated zone), or a process (a CIP step). We model these as three columns on the same row, with a CHECK constraint enforcing exactly one is set, instead of three parallel tables. The lifecycle, the audit trail, the authority ladder, and the executor pipeline all gain one implementation to maintain instead of three.
Authority belongs to the strategy, not the building.
A control loop's risk profile is local to the loop. The same site can run an FCU setback at Dispatch — fully autonomous — and a chiller-plant sequencer at Recommend, because the cost of a wrong move differs by orders of magnitude. The authority level lives on the strategy row and is the only thing standing between a Decision and equipment movement.
Replay precedes commissioning.
Before a strategy reaches Enabled, the operator sees the last thirty days of their telemetry re-played through it — every Decision it would have emitted, the energy delta against the baseline, the comfort excursions. The executor is a pure function with no side effects, so the replay uses the exact same code path as live operation. The preview is faithful, not approximate, and trust transfers against evidence the customer already owns.
The decision stream is the audit trail.
Every executor tick writes one row to control_strategy_decisions — including the ticks that decided to do nothing, so gaps in the stream mean cron incidents, not silent ambiguity. Each row carries the state it was evaluated against and forward links to the Case or control_command it produced. The table is append-only at the database level; corrections come from new rows, never from edits.
Approving the contract creates the strategy.
When the customer accepts an Intervention's scope, the state-machine transition fires a commissioning hook in the same call. The hook walks target_entities, looks up matching policies in the registry, and writes one disabled control_strategies row per eligible pair with default config and an intervention back-link. The operator never files paperwork to enable a strategy — they choose when to flip a row that's already pre-configured and waiting.
Three delivery modes
Every Intervention delivers its savings through exactly one of three modes. Picking the right mode is upstream of every downstream decision in the lifecycle — it determines whether a strategy row comes into existence, whose code runs the loop, and which artifacts the verifier will read at settlement. The Intervention's category and delivery mode together encode the choice; the commissioning hook in lib/control-strategies/commissioning.ts acts on it without anyone having to remember.
The platform–partner boundary deserves a sentence. The distinction is not who pays for the algorithm; it's where the algorithm runs and whose data it sees. A partner brings their intelligence into Wattif's perimeter, registers it as a strategy_type, and reads telemetry through the same fetcher our own executors use. The customer's data never leaves us. That is the deal — partners get access to a market they otherwise couldn't reach with the trust profile it requires; Wattif gets algorithms it didn't have to build and retains the customer relationship, the boundary meter, and the settlement record. Physical retrofit is its own mode because no software loop is involved — replacing a pressure-dependent VAV with an adaptive-flow VAV is a hardware change, and the savings come from the new equipment's behaviour rather than from a strategy operating it.
What a strategy binds to
A strategy attaches to exactly one entity. The entity is the thing the strategy controls and the thing whose telemetry the executor reads. The schema is polymorphic across three kinds; the device_channels CHECK constraint enforces that any single channel binds to exactly one of asset, space, or process.
asset
A single piece of equipment — fan-coil unit, exhaust fan with VFD, single compressor, single refrigeration case. The most common binding. Used when the strategy's measurement boundary is one sub-circuit.
space
A zone, room, or floor — refrigerated warehouse rack, hotel guest room, retail trading floor. Used when a single sensor + actuator combination governs a multi-asset comfort or storage outcome.
process
A process_flows row — a clean-in-place loop, a batch step, a production line. Used in food processing and other industrial contexts where the relevant control point is a process, not an asset.
The eight-stage lifecycle
A strategy progresses through a fixed sequence of stages, each anchored to a transition on the Intervention it serves. The shape is deliberate: every stage has a single responsible owner, an artifact it produces, and a precondition the next stage checks before it begins. Running and Verified overlap in calendar time — a long-lived strategy is in Running every minute and in Verified once a cadence — but they remain distinct in the audit record so each can be queried independently.
Scoped
A diagnosis writes an Intervention row with the category, the entities it would attach to, and a sized opportunity. The strategy doesn't exist yet — only the contract sketch does. Owner: diagnostic agent.
Approved
The customer accepts scope. The state-machine transition fires synchronously; the commissioning hook in the same call reads the registry, walks the target entities, and writes one disabled control_strategies row per eligible pair with default config and an intervention_id back-link. Owner: customer.
Commissioning (run-up)
Telemetry accumulates against the boundary meter while the strategy sits disabled. The baseline window is strategy-specific — fourteen days for an FCU loop, twenty-eight for whole-facility — and the Strategy tab refuses the disabled-to-enabled flip until that window is met and an mv_baselines row is built. The customer doesn't need to know this is happening; the platform tracks the gate. Owner: platform.
Replay review
The operator opens the Strategy tab. The executor is invoked in dry-mode over the last thirty days of state, producing a hypothetical decision stream and the energy delta against the baseline. Sliders for the config parameters re-run the replay under a second. Commissioning happens only when the operator's judgement and the replay agree. Owner: operator.
Enabled
The operator flips status to enabled and chooses an initial authority — Recommend by default. The platform stamps commissioned_at. From this timestamp forward the reporting period is running and every tick is part of the settlement record. Owner: operator.
Running
The executor cron evaluates the strategy every minute. Each tick reads state through the same fetcher the replay used, calls the pure decision function, routes the decision by authority, and appends a row to the stream. Per-strategy failures never block other policies; per-tick failures preserve the strategy's vacancy memory so the next tick recovers without manual intervention. Owner: strategy executor.
Verified (per cadence)
On the Intervention's M&V cadence, the verifier cron reconstructs the period: the boundary meter, the baseline model, the decision stream cross-referenced with telemetry to confirm the strategy caused what it claimed to cause. The result is an immutable intervention_verifications row, hash-chained, with a method-version stamp. Settlement reads from here. Owner: verifier (agent or human).
Archived
Operator-initiated retirement or Intervention end-of-life. decommissioned_at is stamped; the stream stays. Ticks stop, but every prior decision remains queryable for audit and for the next pass at the strategy if the customer comes back. Owner: operator.
How the operator sees it
Five screens, one per operator-facing stage of the lifecycle. The data is taken from the end-to-end smoke test on the Acme test facility — every figure traces to a real row, including the finding identifier, the intervention prefix, the savings band, the decisions table, and the verifier method version. The point of showing them in sequence is to make visible that the operator never has to leave the platform's primary surfaces to move a control loop from observation to settlement.
FCU L3-East runs 24/7 in a zone vacant 09:00–18:00 weekdays
Estimated annual savings
AUD 540
at current tariff · ±18%
Eligible strategy
fcu_occupancy_optimizer
delivery_mode: platform
Investment
AUD 0
no capex · uses existing controls
Evidence · 30-day occupancy vs setpoint trace
The zone holds 22 °C continuously while occupancy data shows it is vacant ~9 h on weekdays and the full weekend. Raising the setpoint by 1.5 °C during vacant windows recovers 51 kWh/month with no comfort impact.
FCU occupancy setback — L3-East
Customer economics
M&V plan
target_entities
On approve, the commissioning hook will materialise 1 control_strategies row of type fcu_occupancy_optimizer in status disabled.
FCU L3-East · asset
category · fcu · floor 3 · east wing · linked to iv-136c8884
Replay · last 30 days
Replay result
Configuration
Tune any slider · replay re-runs in under one second. When the configuration matches your judgment, commission at Recommend authority; promote to Dispatch after observing a few cycles.
FCU L3-East · asset
linked to iv-136c8884 · commissioned 2026-05-29 · 12 days running
Room temp
24.49 °C
↑ 0.04 last 15 min
Setpoint
24.50 °C
raised by strategy 14:22
Occupied
false
vacant 1 h 12 min
Valve
92 %
active cooling
Recent decisions
live · refreshes every minuteFCU occupancy setback — June 2026 verification
Reporting period: 2026-06-01 → 2026-06-30 · IPMVP Option B
Adjusted baseline energy
142 kWh
from mv_baselines · normalised for ambient
Reporting period energy
91 kWh
from boundary meter · 99.4% coverage
Verified savings
AUD 14.10
51 kWh · ± AUD 2.30 (90% CI)
Attribution evidence
Verifier identity
Verified saving
The whole of it. Wattif takes no percentage of a verified saving; the fee for the work is fixed and invoiced separately.
The authority ladder
Authority is the explicit risk contract between the operator and the strategy. It exists because algorithmic confidence and operational consequence aren't the same axis: a strategy can be statistically excellent and still wrong about a single freezer at 03:00. The ladder lets the operator grant autonomy where mistakes are recoverable, withhold it where they aren't, and change their mind without code changes. The default for every new strategy is Recommend; promotion is an explicit operator action recorded on the decision stream alongside the decisions themselves. The registry imposes ceilings: a strategy whose action touches a HACCP-monitored variable, a safety boundary, or any quantity where overshoot has real consequence is refused promotion past Recommend by the platform, not by convention.
observe
inform
report
recommend
adjust
dispatch
emergency
Authority is set per strategy. The default for every new strategy is Recommend. Promotion past the registry-defined ceiling for the strategy's safety class is refused.
observe
The executor runs, decisions are logged, nothing is surfaced and nothing is dispatched. Used during shadow commissioning when the operator wants telemetry-driven sanity-checking before the strategy becomes visible to anyone else.
inform
Decisions land in the operator's feed but never become Cases or commands. Useful when the operator wants a passive stream of what the strategy is thinking without a queue to triage.
report
Decisions roll up into daily or weekly reports rather than appearing interactively. Suitable for policies whose decisions are advisory by design — tariff-window strategy notes, monthly comfort-band reviews.
recommend
The default for every new strategy. Each non-trivial decision creates a Case for operator review; nothing reaches the equipment until the operator approves. Equivalent to a human technician proposing a change in person.
adjust
Decisions write control_commands within explicit guard-rails declared on the registry entry (setpoint may move at most 2.0 °C from base, fan_mode may not jump more than one step). The dispatch worker delivers commands to the bound device's transport — but the strategy can't escape its declared box.
dispatch
Decisions write control_commands without per-decision guard-rail clamping. The registry's hard limits still apply, but inside those limits the strategy is autonomous. Reached only after the operator has watched a few cycles match intent at the lower levels.
emergency
Reserved for safety- and grid-critical interventions — demand-response dispatch, equipment-protective shutdowns. Decisions execute immediately and notify the operator after. The registry restricts which strategy types can be promoted here; for most loops this level is not user-toggleable at all.
Replay-first commissioning
The hardest moment in deploying any algorithm into customer equipment is the leap of faith between "we ran a model" and "we trust it on your chiller." Replay closes that gap by paying it in evidence rather than reputation: the operator sees the past thirty days of their own telemetry re-played through the strategy, with every Decision the strategy would have emitted, the energy delta against the baseline model, and the comfort excursions that would have resulted. The engineering move that makes this clean is the executor's purity — a (state, config, now) → Decision function with no side effects, so live and replay share the exact same code path.
Purity is the precondition
The executor is a pure function: (state, config, now) → Decision. No I/O, no clocks except the one passed in, no hidden state. Purity is what lets the same code that decides live at 14:22 decide the same way again when replayed in dry-mode at midnight against the state of 14:22 — which is what makes replay a faithful preview rather than an approximation.
State as a time series, not a snapshot
The replay reconstructs the state the executor would have seen at each tick. For simulator-backed entities that's a read from simulator_devices.state at one-minute resolution. For real devices it's an interpolation across load_telemetry and context_telemetry. Either way, the executor sees the same shape of input it sees live, which is the only way to trust the output.
Output is the same shape the operator will live with
Replay emits a list of Decision objects identical in shape to control_strategy_decisions rows. The operator inspects the same data structure they will see in the Recent Decisions table once the strategy is enabled, including the action='none' ticks. There is no separate 'preview format' to learn.
Energy delta through the baseline model
Each replay decision is run through the same baseline model the live verifier uses, producing a per-tick kWh delta. The summed delta is the figure the operator approves against; the confidence band scales the baseline's residual error by tick count and is honest about how much of the headline number is signal versus noise.
Sub-second tuning
Configuration sliders re-run the replay under a second. The interaction is closer to scrubbing a clip than to filling a form: the operator drags vacancy_window from fifteen to ten minutes, the timeline redraws with more setback events, the savings tile updates, the comfort excursion count is still zero — keep, or revert. Convergence on a config that matches operator judgement takes minutes, not weeks.
Replay becomes the first verification's anchor
On commissioning, the chosen replay result is captured as the predicted savings the first live verification will be measured against. Predicted-versus-actual ratio is one of the cheapest sanity checks for an algorithm changing behaviour: if the first month diverges from replay by more than the model's residual band, something material changed and the verifier surfaces it before settlement.
The typical alternative is a two-to-four-week pilot where the algorithm runs live and the customer evaluates results. Replay-first compresses that to seconds against data the customer already owns, with no commands sent and no risk taken. The operator's first commission is a decision they've already validated.
The strategy registry
Every strategy_type the platform can deliver is declared once, in code, with the fields the commissioning hook, the replay engine, and the Strategy tab all read. Adding a new strategy is a registry entry plus an executor function — every other surface picks it up automatically.
entity_types
Which entity kinds the strategy may bind to. fcu_occupancy_optimizer accepts entity_type='asset' only; cip_schedule_optimizer accepts 'process' only; zone_setback accepts 'space'.
applies_to_*_types
Sub-filter by category. fcu_occupancy_optimizer.applies_to_asset_types = [fcu, vav, split_ac, minisplit, ahu]. The commissioning hook refuses to attach a strategy to an entity whose category is outside this list.
intervention_category_ids
Which intervention_categories.id values trigger this strategy on commissioning. fcu_occupancy_optimizer registers operational_optimization. A new strategy that delivers electrification adds 'electrification' here and the commissioning hook picks it up without further wiring.
telemetry_required
The columns the executor's state fetcher expects non-null. Used by the replay engine to refuse policies whose state cannot be reconstructed from history.
baseline_min_days
Minimum days of pre-commissioning telemetry needed for a defensible mv_baselines row. The Strategy tab will not allow the flip from Disabled to Enabled until this window is met.
default_config
Sensible starting parameters. Merged over by intervention-specific tuning at commissioning. Visible to the operator in the Strategy tab; editable before commissioning.
default_authority
The authority a new strategy commissions at. Every entry in the registry today defaults to 'recommend'. Promotion to Adjust or Dispatch is an explicit operator action recorded on the Decision Stream.
The commissioning hook
When transitionIntervention fires Scoped → Approved, the commissioning hook in lib/control-strategies/commissioning.ts runs synchronously inside the same call. It is idempotent: re-running for the same Intervention is a clean no-op against existing rows. Failures are logged and do not roll back the Intervention transition.
Read the intervention
Pulls category_id, target_entities, facility_id. Refuses if category_id is null (no strategy can be selected) or target_entities is empty (no entity to bind to).
Look up matching policies
strategiesForCategory(category_id) returns every StrategyMetadata whose intervention_category_ids includes this category. Empty list means the category is fully external (e.g. building_envelope) — commissioning is a clean no-op.
Filter target entities by strategy applicability
For each matching strategy, iterate target_entities. Skip entries whose type is not in strategy.entity_types or whose category is not in the appropriate applies_to_* list. The skip is recorded in the commissioning result for audit.
Upsert one control_strategies row per eligible pair
Insert with status='disabled', authority_level=strategy.default_authority, config=strategy.default_config, intervention_id=intervention.id. The UNIQUE (entity_type, entity_id, strategy_type) constraint makes re-runs safe; existing rows are left untouched (operator tuning is never clobbered).
Return per-pair audit
The commissioning function returns a CommissioningResult with created and skipped arrays. Failures of one entity do not block others; each failure carries its reason string.
The measurement boundary
Every shipped strategy declares its measurement boundary and the IPMVP option under which its savings are settled. Mixing options within a single Intervention is not supported; bundled work is split into separate Interventions with their own boundaries.
Option B boundaries are documented exhaustively in /overview/mv-option-b-method. Option C and partner-attributed boundaries follow the same engine with method-specific calculation paths.
The decision stream
Every executor tick writes one row. Over a year of running, a single strategy emits half a million rows; over a hundred policies, fifty million. The stream is what the operator's recent-decisions timeline reads from, what the verifier reconstructs the period from, and what an auditor reaches for when asked to defend a settlement years after the fact. Three properties make it useful: every tick is captured (including the unremarkable ones), every row carries the state it was evaluated against (so the audit doesn't depend on retained telemetry), and the table is append-only at the database level (so a corrupted row can't quietly become a different row).
One tick, one row, no gaps
The executor writes to control_strategy_decisions every minute for every enabled strategy. The action='none' ticks are written too — that's deliberate, because the absence of a row means the cron didn't run, not that the strategy decided nothing. Gaps surface as cron incidents in monitoring, not as silent uncertainty in the audit trail.
Frozen state snapshot per row
Each row carries the state the executor evaluated against — temperature, setpoint, occupied, vacancy_since — copied into the row, not referenced. Re-running the executor against historical rows produces the same Decision the cron made; the audit doesn't depend on the original telemetry still being available at original resolution.
Bidirectional links to side effects
When a Decision routed to a Case, case_id on the decision row points to it. When it routed to a control_command, command_id points to that. The graph of (Decision → Case → operator action) and (Decision → control_command → device transport) is fully queryable in both directions — useful when an auditor asks how a specific equipment movement came about, and useful when a verifier asks which Decisions actually reached the equipment.
Append-only by RLS, not by convention
The table grants no UPDATE strategy to any role; service-role inserts only. Corrections are appends with supersedes metadata, never mutations. A row that lands in the stream is in the audit trail forever — the engineering equivalent of a financial journal's ink.
Attribution evidence for verification
The verifier cron reads the stream filtered by intervention_id and the verification window. The presence and count of action-bearing decisions inside the window is the primary evidence that the strategy did the work — distinguishing 'savings appeared and we ran' from 'savings appeared because we ran'. The two are not the same and a defensible settlement requires we tell them apart.
How verified savings settle
A common failure mode in M&V systems is to bolt a second verification pipeline onto a new delivery shape and end up with two slightly different definitions of 'savings.' We don't: strategy-delivered Interventions settle through the same ledger, the same baseline builder, the same uncertainty engine, and the same crons that settle hardware-retrofit Interventions. What the strategy contributes is the decision stream, which gives the verifier attribution evidence that a meter alone cannot — the contemporaneous record that the savings followed the strategy's actions rather than coinciding with them.
One verification engine, two delivery shapes
Hardware-retrofit Interventions and strategy-delivered Interventions settle through the same ledger writer, the same uncertainty calculation, the same baseline builder, and the same hourly verifier cron. There is no parallel pathway, no second M&V code path to maintain, and no second method version to keep aligned with the first. A reviewer who has accepted the Option B engine has accepted ours.
Decision stream becomes attribution evidence
Baselines tell you what should have happened. Boundary meters tell you what did happen. Neither tells you why — and 'why' is what attribution requires. The decision stream provides the contemporaneous record of the strategy's actions, so the verifier can prove the savings followed the strategy's behaviour rather than coinciding with it. For setpoint-class policies this is decisive: the setpoint trace itself is the action proof.
Boundary coherence
The mv_baselines row for a strategy-delivered Intervention is built against the same meter that defines the strategy's measurement boundary. This sounds obvious; it's a frequent source of error in less disciplined M&V systems where the baseline is built from one signal and the verification reads another. The platform enforces the equality at the schema level so the mismatch can't happen.
Tick count is not the point
What the customer is shown is intervention_verifications.verified_savings_amount on the ledger. Not how many ticks a strategy emitted, not how many control_commands it wrote, not any platform usage metric. Wattif charges a fixed fee for the work and takes no percentage of the saving, so the whole of it belongs to the customer and the ledger exists to prove the number rather than to bill against it.
Roles
Every role is named. Wattif's AI is the diagnostic and the executor; the customer is the operator. Where an ecosystem partner is involved, the partner provides optimisation logic and Wattif retains the M&V boundary and the customer relationship.
Diagnostic agent (Wattif AI)
Identifies opportunities, scopes Interventions, populates target_entities, writes the Brief or Report.
Customer (operator)
Approves Intervention scope. Opens the Strategy tab. Reviews replay. Tunes configuration. Sets initial authority. Promotes, pauses, or archives policies as the relationship matures.
Strategy executor (Wattif platform)
Runs every minute. Emits Decisions. Routes per authority. Never exceeds authority. Writes the Decision Stream.
Dispatch worker (Wattif platform)
Delivers commands from policies at Adjust+ authority to the bound device's transport (LoRaWAN, MQTT, Modbus, BACnet). Until Phase 4 lands, the simulator stands in for this layer for development.
Verification cron (Wattif platform)
Settles on the Intervention's cadence by reading the Decision Stream and the boundary meter through the engine documented in /overview/mv-option-b-method.
Ecosystem partner
Ships an algorithm — model weights, an inference container, a runtime contract — into Wattif's infrastructure and registers it as a strategy_type. Does not receive customer telemetry; reads through Wattif's fetcher inside our perimeter. Wattif retains the M&V boundary, the boundary meter, and the customer relationship.
The crons that drive the engine
Four scheduled writers move a strategy through its lifecycle. All are registered in vercel.json. Per-strategy failures never block other policies; per-Intervention failures never block other Interventions.
strategy-executor
Every minute. Walks every control_strategies WHERE status='enabled', fetches state, calls the executor, routes the decision per authority, writes the decision stream row. Per-strategy failures never block other policies.
normalize (simulator hook)
Every minute. Ticks any active simulator_devices before its channel loop. Until Phase 4 of the build sequence lands, the simulator drains pending control_commands inline and applies downlinks; that integration retires when the dispatch worker is generalised.
mv-baseline-builder
Nightly at 02:30 SGT. Builds the pre-commissioning baseline for any Intervention in Deploying or Live without an mv_baseline_id. Documented in /overview/mv-option-b-method.
mv-verifier
Hourly. Settles the Intervention's verification cadence by reading the Decision Stream and the boundary meter. Documented in /overview/mv-option-b-method.
Failure modes
Every failure mode is named, returns a structured error or skipped-row reason, and either writes a Case or returns to the cron for the next pass. The system never silently degrades a strategy or skips a tick without an audit record.
missing_target_entities
Intervention approved with empty target_entities. Commissioning records the failure on its result; the Intervention stays Approved without any strategy rows. Operator action: add entities and re-fire the commissioning hook, or manually create the strategy from the Strategy tab.
no_platform_strategy_for_category
Intervention's category_id has no entry in any StrategyMetadata.intervention_category_ids. This is not a bug — it is the case for delivery_mode='external' categories. Commissioning is a clean no-op.
strategy_not_applicable_to_entity_category
Target entity's category is outside the strategy's applies_to_* list (e.g. a 'chiller' entity targeted by fcu_occupancy_optimizer). The pair is skipped with a recorded reason; other eligible pairs in the same intervention still commission.
baseline_min_days_unmet
Operator attempts to flip status from Disabled to Enabled before baseline_min_days of pre-commissioning telemetry has accumulated. The Strategy tab refuses the transition; commissioned_at remains unstamped.
executor_crash
Per-strategy failure during a tick. The cron continues to the next strategy; the failed strategy's tick is recorded as routed_to='skipped' with the error string. The vacancy_since memory is preserved so the next tick recovers.
authority_exceeded_attempt
Operator attempts to promote authority past the registry's hard ceiling for that strategy type (e.g. promoting an HACCP-class strategy to Dispatch). The Strategy tab refuses; the attempt is recorded as a Case for audit.
How a reviewer reconstructs a settlement
Any strategy-delivered settlement can be reconstructed from five reads against the database, left to right. The first three reads cover the strategy lifecycle; the right two cover the M&V engine documented in /overview/mv-option-b-method.
interventions
the anchor
control_strategies
one row per (entity, type) pair
control_strategy_decisions
append-only stream
mv_baselines
the reference
intervention_verifications
settlement ledger
Five reads, left to right. Every strategy-delivered settlement is reconstructible from these five tables. The /overview/mv-option-b-method document covers the right two in detail; this document covers the left three.
- Find the intervention. interventions.id is the anchor.
- Read the target entities. interventions.target_entities lists the assets/spaces/processes the policies bind to.
- Read the policies. control_strategies WHERE intervention_id = <id> returns one row per (entity, strategy_type) pair the commissioning hook created. Each row carries entity_type, entity_id, config, authority_level, commissioned_at, decommissioned_at, and last_decision.
- Read the decision stream. control_strategy_decisions WHERE strategy_id IN (...) AND decided_at BETWEEN baseline_end AND verification_end is the full record of every tick during the verification window.
- Read the baseline. mv_baselines WHERE intervention_id = <id> is the reference any verification row was measured against. Documented in /overview/mv-option-b-method.
- Read the verifications. intervention_verifications WHERE intervention_id = <id> ordered by created_at is the append-only settlement ledger. Documented in /overview/mv-option-b-method.
What is not yet in scope
The methodology document is honest about its boundaries. The following items are deliberately deferred and are documented here so a reviewer is not surprised.
- Partner-mode first claim. The DeliveryMode union now includes 'partner' but no INTERVENTION_CATEGORIES entry currently maps to it — the first claim happens when the first partner algorithm (Resync chiller-plant model, BrainBox HVAC agent) lands in the registry. Today every category is either platform (operational_optimization, flexibility_dr) or physical_retrofit (everything else).
- Partner algorithm sandbox. The runtime contract for a partner-shipped executor — image format, fetcher API, decision schema, resource limits, secrets handling — is being specified jointly with the first partner. Until that contract is stable we register partner policies as platform-typed shims that proxy to a partner endpoint.
- Replay-first commissioning UI. The replay engine specification and the Strategy tab design exist (project_strategy_replay_first_creation). The component and the dry-mode executor wrapper are unbuilt.
- Dispatch worker. Phase 4 of the control-strategies-and-bidirectional-devices.md build sequence. The simulator's inline command-drain is the stand-in; the generalised worker that resolves asset_id → bound device → adapter.buildControlPayload → transport publish is unbuilt.
- Segment-aware authority defaults and class-based promotion locks. The registry records default_authority but does not yet enforce class-based promotion ceilings for HACCP, life-safety, or grid-critical classes.
- Real device adapters. McLimate FCT-LRW (LoRaWAN FCU controller) ships in Phase 6. VFD adapter (Modbus) ships in Phase 7. The contract for both is the controlPoints + buildControlPayload interface added in Phase 1.
- Verification cron's Decision-Stream pathway. The cron exists for boundary-meter Option B settlements; the path that reads control_strategy_decisions to enrich the attribution evidence is scoped but not yet wired.
- Strategy-level Recent Decisions timeline UI. Last-N decisions with intent → observed effect → verification result render on the Strategy tab. Phase 5 of the build sequence.
- External CMVP review of the methodology. Scheduled for Q3 2026 jointly with the Option B engine. Until then alignment claims here are the engineering team's, not an independent reviewer's.
Standards alignment
The Wattif control-strategies engine settles under the same standards that govern the Option B ledger. The Q3 2026 CMVP review will formally validate the methodology mapping; until then the alignment claims here are the engineering team's, not an independent reviewer's.
IPMVP Core Concepts (Volume I, 2022). Options A through D defined; Annex F treats uncertainty. Strategy-delivered Interventions settle under Option B (entity-scoped) or Option C (whole-facility demand).
Efficiency Valuation OrganizationASHRAE Guideline 14-2014: Measurement of Energy, Demand, and Water Savings. Informs the platform's coverage rule and uncertainty conventions.
ASHRAEISO 50001: Energy management systems. The platform's strategy lifecycle is aligned with the plan-do-check-act loop; Wattif Pte Ltd self-certification scheduled for late 2026.
ISO