1. The market in one picture
The participant volume (V9) teaches what a Balance Responsible Party does with a bid after it leaves the book. This volume is the other chair: the Market Operator. You accept declarations, run the auction, publish one price for the country, write the chalkboard, and later raise the invoice. You do not write a participant’s prices. You do not throw a switch.
Think of SAWEM as a produce market that opens the day before.
Farmers (generators) write sealed notes: “I can sell this many crates, and I will not go below this price.” Buyers (loads) write sealed notes: “I will take this many crates if the price is at most this.” You open every note, fill demand from cheapest supply upward, and announce one crate price for that hour. Every accepted crate trades at that price — not at the number on the farmer’s note. The note only got them into the market.
That auction is the Day-Ahead Market (DAM). It runs once, the day before delivery. Its price is the System Marginal Price (SMP) — one number per hour for the whole country, not one number per zone.
The next morning the weather changes. A solar farm that promised 75 crates can now only deliver 20. The market does not reopen the whole auction. It runs five smaller Intra-Day Market (IDM) auctions that only move the hours still left. The original crate price (the SMP) stays. The intraday auction has its own price, used only for the megawatt-hours that actually moved.
%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"nodeSpacing": 36, "rankSpacing": 40, "padding": 16}}}%%
flowchart LR
subgraph yesterday ["Yesterday (D−1)"]
A["BRPs submit DAM bids<br/>by 10:00"] --> B["MO clears<br/>and publishes by 14:00"]
B --> C["One SMP per hour<br/>+ two schedules"]
end
subgraph today ["Trading Day D"]
C --> D["Five IDM auctions<br/>revise remaining hours"]
D --> E["Meters and instructions"]
end
subgraph later ["After delivery"]
E --> F["Indicative statement"]
F --> G["Initial statement<br/>+ invoice"]
G --> H["Money moves"]
end
Three facts that stop most confusion:
- The DAM price is not per zone. Zones belong to the System Operator. They limit how much can actually flow. They do not set a local energy price. See §6.6.
- Clearing is not paying. You publish schedules and prices at 14:00 on D−1. The cash leaves bank accounts weeks later, on the Settlement Calendar. See §8.
- The IDM does not rewrite the DAM bid. It re-uses the day-ahead price curve and changes volume for hours that have not yet started. See §9.
1.1 How to read this volume
If you have twenty minutes, read this chapter, §3, and §11. That is the story: one auction yesterday, five smaller auctions as the day unfolds, money that is calculated immediately and paid later.
If you are answering a participant who says “why was I charged this?”, start at §7 and §8, then walk the same hour in §11.
The current /mo console — panels,
queues, Bidding tabs — is §12–§26. Chapter 12 is the map; Market Desk and Bidding
share §13; each later chapter is one
sidebar room.
Where this is taught. The BRP primer is V9 §1. The System Operator seat is V12. The authority for the numbers in this volume is Market Code Rev 2.3 §§9–10, §14 and §15, written for this chair in
docs/references/market/spec/market-dam.md. Nothing here invents a rule. Where the platform has had to interpret a silent clause, the interpretation is named ([D-nn]) and pointed at V9 §17.
1.2 Time and money
Every clock in this volume is SAST, a fixed
UTC+02:00 with no daylight saving. D is the Trading
Day — the calendar day the energy is actually produced or
consumed. D−1 is the day before. A Trading Period is one
hour, written as its start: 2026-07-15T18:00:00+02:00 means
the hour from 18:00 to 19:00.
Money sign. Positive means the Market Operator pays the participant. Negative means the participant pays the Market Operator. Energy sign: positive means produced, negative means consumed.
The numeric worked day is the same golden fixture every other document uses: Trading Day 2026-07-15, hour 18:00.
2. The people and the things they own
Before a single number, the seats. Confusing them is the fastest way to misread a statement.
| Seat | Everyday job | What they do not do |
|---|---|---|
| Balance Responsible Party (BRP) | The participant who bids. One organisation, one market seat. Owns Trading Units. Pays and is paid. | Does not set the SMP. Does not dispatch the grid. |
| Market Operator (MO) | Auctioneer, rulebook and clearing bank. Accepts bids, runs the auction, publishes prices, issues statements and invoices. | Does not tell a plant to ramp for frequency. Does not invent a bid if a BRP is silent — except the rollover, which copies yesterday. |
| System Operator (SO) | The grid. Forecasts demand, sets reserve requirements, publishes corridor limits, issues dispatch instructions. | Does not set the SMP. Does not collect energy-market money. |
| Trading Unit | One registered machine or load the market can schedule: a coal set, a solar farm, a factory, a battery. Bids are per Trading Unit, not per company. | — |
| Market Governance Committee (MGC) | Publishes the cap, the floors, the gate times. | Does not pick tomorrow’s SMP. |
Metaphor. The BRP is the stallholder. The Trading Unit is the stall. You are the market master who rings the bell and writes the day’s price on the board. The System Operator is the traffic police who decide which trucks may use which road. The MGC is the town council that set the stall fees and the closing time.
Where this is taught. What a BRP does with those objects is V9. What the System Operator does with the wires is V12 §1. This chapter only names the seats so the rest of the volume can use them without repeating the job descriptions.
3. The clock — when things happen
One table. Times are SAST. D is the Trading Day the
energy is delivered.
| When | Who | What | Why it matters |
|---|---|---|---|
| 08:00 D−1 | BRP | Last chance to change standing data (nameplate, Mingen, MCR) that will apply on D | A bid’s elbows must match the registry. Change the registry after this and an already-accepted bid can be invalidated. |
| 10:00 D−1 | SO | Publishes demand forecast and reserve requirements for D | The auction needs to know how much reserve to hold back. |
| 10:00 D−1 | BRP | DAM gate closes. Availability and price curves for D and the following six days must be in. | A second late is a missed day. You then roll the unit forward from its previous submission. |
| after the gate | MO | Generates rolled-over submissions for any Trading Unit that did not submit | The market must have a declaration for every registered unit. Silence is not “offer nothing”; it is “keep yesterday’s remaining plan”. |
| 13:30 D−1 | SO | Interconnection schedule for D (how much is imported or exported on the ties) | Arrives after the bid gate and before price publication. Imports are treated as a fixed, zero-cost injection. |
| 14:00 D−1 | MO | Publish SMP, four reserve system prices, unconstrained and constrained schedules, unit prices, daily adequacy report | This is the moment the plan becomes the plan. Solving and publishing are two different buttons. |
| 18:00 D−1 | MO / BRP | IDM iteration 1 gate. Whole of D can still move. | First chance to correct the day-ahead plan. |
| 00:00 D | MO / BRP | IDM iteration 2 | Hours already being delivered cannot be re-declared. |
| 06:00 D | MO / BRP | IDM iteration 3 | |
| 12:00 D | MO / BRP | IDM iteration 4 | The worked example’s cloud arrives here. |
| 18:00 D | MO / BRP | IDM iteration 5. Only 19:00–23:00 remain. | A re-declaration for 18:00 at 18:00 is a re-declaration of the past. Refused. |
| +1 hour after each IDM gate | MO | Publish the revised schedule and the Intra-Day Price | |
| 17:00 D+1 | MO | Balancing payment calculations (after meters) | Not DAM settlement. Different market, different price. |
| 17:00, SD+1 working day | MO | Indicative Settlement Statement. Check the figures; they are not yet a bill. | |
| 17:00, SD+7 working days | BRP | Data Verification Period closes | Argue about data now, not after the invoice. |
| 12:00, Billing Period + 5 working days | MO | Initial Settlement Statement, Invoice (if the participant owes), Self-Billing Invoice (if the MO owes) | This is when a DAM hour becomes a line on a bill. |
| 12:00, invoice + 3 business days | BRP | Invoice due. Pay in full, no set-off. | Shortfall if they pay less. |
| 17:00, self-billing + 4 business days | MO | MO pays creditors | The extra day is the cash-flow buffer: collect first, then pay out. |
- 10:00 D−1 DAM gate · SO demand and reserve
- 14:00 D−1 You publish SMP and both schedules
- 18:00 IDM iteration 1 (D−1) and iteration 5 (D)
The DAM bid itself is not settled at 14:00 on D−1. What is published then is the arithmetic of the day — volumes × prices, already visible on the schedule report. The cash waits for the Billing Period. Treat 14:00 as the chalkboard and the invoice date as the till.
Where this is taught. The participant’s day is V1 §4 and V9 §4. Cadence on
/mo/cadenceis §14 — due / ran / missed for every callable on this table.
4. How DAM bids are submitted
Your problem at intake is simple: every registered Trading Unit must have a declaration at the gate, and none of those declarations may be ones you wrote.
4.1 Who submits
The Balance Responsible Party submits, for each of its Trading Units. You do not write a participant’s prices. You accept, validate, store, and — if the participant is silent at the gate — roll over the last valid declaration.
A bid is not “the company’s bid for Tuesday”. It is “Trading Unit
TU-COAL1’s declaration for Trading Day 2026-07-15 and the
six days after it”. One company with five units sends five
submissions.
| Party state | May submit? | Why |
|---|---|---|
ACTIVE |
Yes | Ordinary case. |
| Commissioning (not yet a Party) | Yes | Market Code §6.2(10) lets a commissioning applicant bid so the unit can be tested in the market. |
DEFAULT |
Yes | A default is a money problem, not a bidding ban. |
| Suspended | No | SUB_PARTY_NOT_ACTIVE. A suspended unit may not bid
(§6.4.1). |
| Deregistered unit | No | The unit’s own status, not the party’s. |
4.2 Three doors into the same room
From your side, every accepted declaration is a
WB.Sawem.Submission. How it got there is one of three
doors.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 36, "padding": 12, "subGraphTitleMargin": {"top": 8, "bottom": 26}}}}%%
flowchart TB
subgraph door1 ["Door 1 — automatic, this platform as BRP"]
S["Nightly strategy run"] --> W["SubmitDamBids · 03:00 D−1"]
W --> G["MO Gateway"]
end
subgraph door2 ["Door 2 — the participant's own systems"]
API["PUT /v1/dam/submissions/{date}/{tuid}"] --> I["Intake"]
end
subgraph door3 ["Door 3 — your act, not theirs"]
MISS["Unit silent at 10:00"] --> R["Rollover: yesterday's day 2<br/>becomes today's day 1"]
end
G --> SUB["WB.Sawem.Submission<br/>168 periods, stored forever"]
API --> I
I --> SUB
R --> SUB
SUB --> V["Validation"]
V -->|accepted| GATE["Counts at the gate"]
V -->|rejected| ERR["Nothing stored"]
Door 1 — automatic. The organisation using this
application has strategy books. Each night those books compute a net
position. WB.Brp.BidBuilder turns that into a price curve.
An Oban worker runs at 03:00 on D−1 and submits through
the same gateway a third-party BRP would use. Those are still the
BRP’s bids. You did not choose the volumes.
Door 2 — the Code path. Any BRP may PUT
a conformant body to
/v1/dam/submissions/{trading_date}/{tuid} as many times as
it likes until the gate. Each replace is a new
submission_seq. The newest valid version at the gate is the
one that clears. The automatic door is just a client of this door.
Door 3 — rollover. If a Trading Unit has no accepted
submission at 10:00, you must generate one (§9.3(2)).
You do not invent prices. You take the unit’s previous submission and
slide the horizon forward one day: previous day 2
becomes new day 1, …, previous day 7 is repeated as the
new day 7. The new row is stored with source: :ROLLED_OVER,
a pointer at the submission it was copied from, and a
staleness_days counter. A unit that misses seven gates in a
row is still offering its original day-7 profile. That is legal. It is
also how a forgotten outage becomes a live schedule.
Rollover is not a bid the BRP made. It is the market’s rule for silence. The participant can still correct the day in the IDM.
Where this is taught. How a book chooses those reservation prices is V9 §4. The API contract is V13.
4.3 What “submit” actually does
WB.Sawem.Submission.Intake.put/1 is the only write path.
It is a single database transaction: all 168 periods, or none; energy
limits, or none; a new submission_seq, or a replay of the
same seq with the same body.
| Result | Meaning | What you do |
|---|---|---|
| Created | New sequence, body accepted | Store. Supersede the previous version. Keep the old one for disputes. |
| Replayed | Same sequence, identical body (an
Idempotency-Key retry after a timeout) |
Return the existing row. Do not create a second version. |
| Sequence conflict | Same sequence, different body | Reject. They have lost track of what they sent. Tell them to increment the sequence. |
A late submission (after 10:00, no extension in force) is not
stored. The API returns 409 gate_closed and the
identifier of the rolled-over submission that was generated instead,
plus the next IDM gate as the next opportunity.
A rejected submission is not stored. Validation errors come back with the Market Code clause, a JSON pointer at the offending field, the value, the constraint, and where useful a remedy.
4.4 Blind, binding, replaceable until the bell
- Blind. Nobody sees anyone else’s curve before the gate.
- Binding. An accepted submission is a financial commitment.
- Replaceable until the gate.
PUTof the whole 168-period series. Partial patches are refused: a half-applied week is unrecoverable. - Every version is kept. The operative submission is
the highest
submission_seqthat has not been invalidated. The losers stay, because a dispute about “what did we declare at 09:12?” reads the losers.
4.5 What you do not do at intake
You do not fill in a missing price curve, “fix” an elbow that does not match the registry, accept a 24-period body and pad the other six days, accept a bid for a suspended party, or publish anyone’s curve to anyone else.
You do validate against the registry and the Code, stamp
received_at (that instant decides the gate, even if the
gate is later extended), keep every version, roll over silence, and tell
the participant which rule broke and what to
change.
5. The DAM bid, field by field
A DAM “bid” in conversation is three nested things. Name them or the screens will lie.
| Layer | What it is | Who sees it |
|---|---|---|
WB.Brp.Bid + BidLine |
This platform’s BRP-side ledger: book, strategy run, flat opportunity-cost ladder, MO reference. | The organisation’s Bid Desk. |
WB.Sawem.Submission |
The Market Code object: 168 periods, structured curves, energy limits, consent flag. | You. This is what clears. |
| The API body | The JSON a participant PUTs. Same information as the
Submission, in the wire shape. |
Both. |
The rest of this chapter is the Submission. That is
what the market determines prices from. The BRP Bid is how
this platform produced one — V9 §4.
5.1 The envelope
PUT /v1/dam/submissions/2026-07-15/TU-COAL1
| Field | Required | Plain meaning |
|---|---|---|
market_code_version |
Yes | Which edition of the rulebook this body claims to satisfy. Today
"2.3". A body written to a withdrawn edition is not
silently reinterpreted. |
idm_rescheduling_consent |
Yes (defaults true) |
“May the Market Operator move my day-ahead schedule in the five
intraday auctions?” false = hold my DAM schedule unless the
System Operator imposes a new network constraint. See §9.3. |
periods |
Yes | Exactly 168 hourly rows: the Trading Day and the following six days. A 24-period body is the most common mistake and is rejected as a horizon fault, not as 144 missing hours. |
production_curves |
When the unit generates | One or more generation price curves, each effective from a named period onward. |
consumption_curves |
When the unit consumes | One or more willingness-to-pay curves, same effective-from rule. |
energy_limits |
Mandatory for energy-constrained units; otherwise
null |
Daily and weekly energy caps. null for a coal set or a
solar farm that is not energy-constrained. |
Headers the participant must send: Authorization (own
Trading Units only), Idempotency-Key (retries are one
submission), X-Sawem-Signature (a financially binding body
without a signature is not a submission).
What you store in addition, which they do not send:
submission_id, tuid,
trading_date, submission_seq,
source (:PARTICIPANT or
:ROLLED_OVER), received_at (the instant that
decides the gate), signature, the rollover chain
(rolled_over_from_submission_id,
staleness_days), supersession and invalidation stamps,
gate_id, and provenance (strategy_run_id,
market_rules_id, bid_id) when this platform
built the body.
Invalidation is not supersession. A registry change can break an already-accepted future submission. The participant must be told before the next gate. There may be no replacement.
5.2 One period
Each of the 168 rows is one Trading Period.
| Field | Plain meaning |
|---|---|
trading_period |
The hour’s start, on the hour, in SAST. A bare Z (UTC)
at midnight is two hours out and is rejected. |
declared_available_capacity_mw |
“How many megawatts can I produce this hour?” Capped by the registry
MCR. null means “this unit does not generate”;
0.000 means “I will produce nothing”. A solar farm at night
sends 0.000. |
declared_consumption_mw |
“How many megawatts will I draw this hour?” A battery or a mixed unit sends both fields in the same hour. |
flexible |
F — the market may move this unit and
this unit may set the SMP.
I — a commitment to the declared figure.
An inflexible unit cannot set the SMP. |
instantaneous_reserve / regulating_reserve
/ ten_minute_reserve |
A or U. A is refused if the
System Operator has certified 0 MW for that category. Offline units may
still offer Ten-Minute Reserve. |
preferred_run |
On energy-constrained units only: prefer this hour (Y)
or not (N). The energy limit says how much; this
says when. |
Idle is legal. A period with no capacity, no consumption and no reserve offer is a declaration of absence. “The unit submitted nothing” and “the unit submitted 168 declarations of zero” look the same on a summary and are different compliance positions. The desk must be able to name both.
5.3 The production price curve — a staircase
A generator does not say “my price is R900”. It says “the first 200 MW cost me R350, the next 100 cost R420, …” — a staircase. The market walks up the stairs until demand is filled. The last step it stood on is the SMP.
| Field | Plain meaning |
|---|---|
effective_from_period |
This staircase applies from this hour onward, until a later curve supersedes it. You denormalise the curve onto every period it covers at write time, so a dispute about 14:00 on the 9th has one row as its answer. |
mingen_mw |
Minimum Stable Generation. Must equal the registry Mingen. The must-run block (0 → Mingen) is priced at Cost Increment 0 and never sets the SMP. |
elbow1_mw / elbow2_mw /
elbow3_mw |
Bends. Elbow 3 must equal the registry MCR. The BRP does not invent a nameplate in a bid. |
el1_mw |
Emergency limit, above MCR. |
cost_increment_0 … 3 /
el1_cost |
Prices of each step. CI0 may be higher than CI1 — that looks upside-down and is legal, because must-run cannot set the price. Flexible stairs (CI1 onward) only go up. |
Zero-width blocks are dropped, not rejected. A solar
farm submits Mingen = E1 = E2 = 0 and E3 = MCR
— one step, often at R0/MWh. That is the ordinary renewable bid.
The curve is clamped to the hour’s Declared Available Capacity before it enters the stack.
Price-taker. A registration that has chosen to be a price-taker emits a floor-priced curve. It still has to send a legal staircase; the stairs just sit on the floor.
5.4 The consumption price curve
A generator’s curve answers one question: what does it cost me to make the next megawatt? (§5.3). A buyer’s curve answers the mirror question: what is the next megawatt worth to me?
The market needs that answer for a blunt reason. When there is not enough generation to go round, somebody has to stop drawing. Without prices on the demand side the only tool left is a blackout, which takes power away from the people who need it most and the people who barely notice, in equal measure. A consumption price curve lets a site say, in advance and in Rands: this much I will drop readily, this much only at real cost, this much only at severe cost, and this much I cannot drop at all. The market then sheds in that order, cheapest first, and pays for what it sheds.
The four numbers. One Declared Consumption and three cut lines beneath it.
| Field | Plain meaning |
|---|---|
effective_from_period |
This ladder applies from this hour onward, until a later curve supersedes it. Denormalised onto every period it covers at write time, exactly as a production curve is. |
declared_consumption_mw (DC) |
The whole draw for the hour — the same field as §5.2. Every ladder starts here and cuts downward. |
elbow1_mw (E1) |
The first cut, counting down from DC.
The slice between E1 and DC is the one you
would give up first. |
elbow2_mw (E2) |
The second cut, below E1. |
elbow3_mw (E3) |
The floor. Everything below E3 is
must-serve: the market may not take it away at any
price. |
cost_increment_1_r_mwh … 3 |
What each slice is worth to you, in Rand per MWh. CI1
prices the top slice, CI3 the deepest one. |
Why it looks upside down. A production curve climbs:
the elbows run from Mingen up to MCR, and the prices climb with them. A
consumption curve does the opposite — the elbows
descend from DC, and the prices
rise as they descend. Both shapes obey the same single
rule: the market always takes the cheapest option next. Read
from the buyer’s side, the slice nearest DC is the last
megawatt you added and the one you would miss least, so it is the
cheapest to shed. The deeper the cut, the more it hurts, so the price
goes up. Written as the Code writes it: E1 ≤ DC,
E2 ≤ E1, 0 ≤ E3 ≤ E2, and
CI3 ≥ CI2 ≥ CI1 ≥ 0.
So four slices come out of four numbers:
| Slice | Band | Priced at | What you are saying |
|---|---|---|---|
| Top | E1 → DC |
CI1 |
Take this first. I will manage. |
| Middle | E2 → E1 |
CI2 |
This one costs me something real. |
| Deep | E3 → E2 |
CI3 |
Only in a genuine emergency, and it will be expensive. |
| Must-serve | 0 → E3 |
unpriced | Not at any price. |
A worked ladder — TU-IND1, the 90 MW
factory.
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. The same factory the worked example clears in §11.
The factory sends DC 90, E1 70,
E2 50, E3 40, and three prices:
| Slice | Band | Width | Priced at | Shed order |
|---|---|---|---|---|
| Top | 70 → 90 MW | 20 MW | R 1,500 | first |
| Middle | 50 → 70 MW | 20 MW | R 2,600 | second |
| Deep | 40 → 50 MW | 10 MW | R 4,800 | third |
| Must-serve | 0 → 40 MW | 40 MW | — | never |
The widths must account for the whole declared draw:
20 + 20 + 10 + 40 = 90 = DC ✓. If they did not, the market
would be shedding megawatts the factory never said it would take.
Now walk the price up and watch the factory shrink. Each slice keeps drawing while it is worth more than the clearing price, and stops once the price climbs past it:
| If the hour clears at | The factory draws | Because |
|---|---|---|
| R 900 | 90 MW | Every slice is worth more than R 900 — this is what happens in §11 |
| R 2,000 | 70 MW | The top slice was only worth R 1,500, so it drops out |
| R 3,000 | 50 MW | The middle slice was worth R 2,600 |
| R 5,000 | 40 MW | Only must-serve is left |
| R 5,396.40 (the cap) | 40 MW | Still 40 MW. Nothing takes a site below its E3 |
That is the whole mechanism. The elastic slices behave as bids in the same auction the generators offer into — a generator bids to supply the next megawatt, a consumer bids to keep it — and the clearing price decides which bids stand.
Must-serve comes from E3 itself, not
from the priced slices. That distinction matters when a curve has no
priced slices at all: the floor is still E3, so a site that
declares no flexibility has its entire draw protected.
The fully inelastic declaration is
E1 = E2 = E3 = DC. Every slice collapses to zero width, so
there are no priced blocks — nothing to shed, nothing
to price. This is the correct form for most industrial sites and for a
distributor, and it is a one-field declaration: give the consumption and
the platform builds the rest. TU-DIST1 in the worked
example is exactly this: 440 MW, no stairs. Zero-width slices are
dropped, not rejected — the mirror image of the solar
farm’s single-step production curve in §5.3.
Two more mechanical facts, then the judgement call:
- The ladder is clamped to the hour’s
DCbefore it enters the stack, exactly as a production curve is clamped to Declared Available Capacity. - A consumer marked
Iis fixed at its wholeDC, whatever the ladder says. Flexibility on the period (§5.2) and flexibility in the curve have to agree;Iwins.
Choosing the numbers is a commercial decision, not a
calculation. The shape above is settled by the Code. What a
megawatt-hour is actually worth to a factory is not, and no
amount of engineering will tell you. There are three defensible ways to
answer it, plus the answer that declines the question — and
which one was used is recorded on every curve, as
curve_basis on the site’s demand-side profile
(WB.Sawem.DemandSideProfile):
| Recorded basis | Where the numbers come from | Why you would use it | What it costs you |
|---|---|---|---|
inflexible |
No ladder at all — E1 = E2 = E3 = DC |
The default, and the right answer for most industrial loads | Forgoes demand-response revenue |
site_declared |
You asked the site and it answered | The strongest basis there is | The slowest; many sites genuinely do not know |
tariff_ladder |
Multiples of the site’s own retail energy rate at the applicable time of use | Mechanical and defensible; the default derivation where a category has one | Ignores that some processes are worth far more than the tariff |
alternative_cost |
The cost of the alternative — a diesel generator, or a stopped production line | Closest to the truth | Much harder to obtain |
The platform implements the shape and leaves the
numbers to a configured policy per off-taker category.
Recording the basis is what makes a curve auditable: two sites
with identical ladders and different bases are not making the same
claim, and if a curtailment is ever disputed, which question
was answered is the first thing anybody will ask. The safe direction to
be wrong in is inflexible — which is why it is the
default.
Careful. Both ways of getting this wrong cost the participant, and they are not symmetrical. A site published as inflexible when it could in fact shed load forgoes demand-response revenue — quietly, forever. A site that publishes flexibility it does not have is worse: it gets shed, and it cannot comply.
What you check at intake. The consumption codes in
§5.6 are all
shape checks — CON_ELBOW1_GT_DC (you priced a slice you
never said you would take), CON_ELBOW2_GT_ELBOW1 /
CON_ELBOW3_GT_ELBOW2 / CON_ELBOW3_NEGATIVE
(the elbows do not descend), and CON_CI1_NEGATIVE /
CON_CI2_LT_CI1 / CON_CI3_LT_CI2 (the prices go
the wrong way). You cannot check whether R 1,500 is the right
number for that factory. Nobody at this desk can.
Where this is taught. The ladder turning into money — curtailment paid at
max(own block price, IDP)— is §11.4. On screen, a submitted ladder is the Consumption curtailment order staircase in the declaration drawer (§13.8).
5.5 Energy limits — the reservoir, not the sum
Only energy-constrained units send this: hydro, a battery, a fuel-limited OCGT. For those units the block is mandatory.
| Field | Plain meaning |
|---|---|
day_limits_mwh |
Exactly seven figures, day 1 … day 7. |
seven_day_limit_mwh |
How much energy is in the reservoir for the whole week. |
basis |
How the figures were derived — audit, not a commercial input. |
The weekly figure is not the sum of the dailies. It
is allowed to be less, and for a reservoir it usually
is. Σ daily > weekly is rejected
(EC_DAY_EXCEEDS_TOTAL). Rollover shifts the array
by position: yesterday’s day 2 becomes today’s day 1.
5.6 Validation — every code you will fire
A rejection is a list of these, never a shrug. Each carries its clause, a JSON pointer, the offending value, the constraint, and where useful a remedy.
| Code | Everyday reading |
|---|---|
SUB_GATE_CLOSED |
The bell has rung. |
SUB_HORIZON |
You sent a day, not a week — or you left a hole. |
SUB_PERIOD_ALIGNMENT |
The clock is SAST. UTC midnight is 02:00 here. |
SUB_UNIT_NOT_REGISTERED |
You cannot bid a stall that is not on the plan. |
SUB_PARTY_NOT_ACTIVE |
A suspended seat may not bid. |
CRV_MINGEN_MISMATCH |
The stairs must start where the machine actually can. |
CRV_ELBOW1_LT_MINGEN /
CRV_ELBOW2_LT_ELBOW1 / CRV_ELBOW3_LT_ELBOW2 /
CRV_EL1_LT_ELBOW3 |
Stairs cannot go backwards. |
CRV_ELBOW3_NOT_MCR |
You do not get to change your nameplate in a bid. Change the registry by 08:00 D−1. |
CRV_CI0_NEGATIVE / CRV_CI1_NEGATIVE |
You cannot offer to pay the market to take your energy by writing a negative price here. |
CRV_CI2_LT_CI1 / CRV_CI3_LT_CI2 /
CRV_EL1_COST_LT_CI3 |
Flexible stairs go down. “Cheapest next” becomes meaningless. |
CON_ELBOW1_GT_DC |
You priced a slice you never said you would take. |
CON_ELBOW2_GT_ELBOW1 /
CON_ELBOW3_GT_ELBOW2 /
CON_ELBOW3_NEGATIVE |
Consumption elbows do not descend. |
CON_CI1_NEGATIVE / CON_CI2_LT_CI1 /
CON_CI3_LT_CI2 |
Willingness-to-pay stairs go the wrong way. |
AVL_DAC_EXCEEDS_MCR |
You cannot offer more than the machine. |
AVL_INDICATOR_INVALID |
Flexible is F/I; reserve is
A/U. |
AVL_RESERVE_NOT_CERTIFIED |
You cannot sell a service the grid has not qualified you for. |
EC_LIMIT_MISSING |
A hydro without a reservoir figure is offering an unbounded week. |
EC_DAY_EXCEEDS_TOTAL |
The dam is smaller than seven full days. |
EC_PREFERRED_RUN_MISSING |
The limit says how much; the flag says when. |
STG_LEVEL_INFEASIBLE |
The battery cannot be in two states at once. |
Two rules you must not add, even though they look tidy:
CI1 ≥ CI0. The Code never requires it. Must-run may be priced above the first flexible block.- A 24-period submission is “close enough”. It is not. The horizon is seven days.
6. How the market determines the prices
6.1 Who sets the price
Nobody picks a number. You run an auction. The last megawatt-hour needed sets the System Marginal Price. The Market Governance Committee published the cap and the reserve floors months ago; those bound the auction, they do not replace it.
The market master does not decide that tomatoes are R20. The master stacks every seller’s crates from cheapest to dearest, serves every buyer who will pay at least that, and the last crate that was needed is today’s price. A farmer who offered R8 still receives R20 if that is where the last crate sat. How those two piles are actually stacked — crate by crate, for one hour — is §6.3.
6.2 Two schedules, one price
The architecture is the order of the runs. Swap them and somebody is paid twice or not at all.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 36, "padding": 12}}}%%
flowchart TB
SUB["Accepted submissions<br/>+ SO interconnect + SO reserve"] --> UC["Unconstrained run<br/>ignores the wires"]
UC --> SMP["SMP and the four<br/>reserve system prices"]
UC --> CS["Constrained run<br/>respects corridor limits"]
CS --> UNIT["Per-unit reserve costs<br/>and constrained volumes"]
SMP --> PUB["You review"]
UNIT --> PUB
PUB --> BOARD["Publish by 14:00 D−1"]
| Run | What it ignores / respects | What it is for |
|---|---|---|
| Unconstrained | Ignores the network. Energy must still balance
(Σ generation + imports = Σ consumption). |
Prices the market. The SMP is read off this
schedule. Energy payments (EPM) are struck on these
volumes. |
| Constrained | Respects the System Operator’s corridor and zonal limits. | Runs the system. What units actually generate. Reserve unit costs are read off this schedule. The difference versus unconstrained is a separate money line, not a different SMP. |
Solving and publishing are two buttons. An operator who has just re-run a day must be able to look at it first. A pipeline that published as a side-effect of solving would make “let me check that” impossible.
6.3 Building the stacks
This section answers one question: who runs and who draws in each hour. It does not yet produce the published number — reading the price off the result is §6.4.
The whole job is four moves, repeated for each of the 24 hours:
- Collect the offers. Take every generator’s price staircase (§5.3) and cut it down to what the unit said it could actually do this hour. Add the interconnection import as one free block.
- Collect the needs. Take every consumer’s protected must-serve load, then the slices it put a price on (§5.4).
- Match them, cheapest first. Keep taking the cheapest offered megawatt until every remaining need is met. The result is the unconstrained schedule — the plan the country would run if every cable were infinite.
- Solve it again with the wires on. Where a cable cannot carry the cheap plan, cut the trapped unit back and lift the next-cheapest machine that can get through. The result is the constrained schedule — the plan that actually runs.
Two players do not obey “cheapest first”, and both are deliberate:
- A unit that declared
I(inflexible) is placed first, whatever it costs. It promised an exact figure, and the auction does not re-negotiate a promise. - Must-serve load is never cut. It has no price because it is not for sale. Nothing in this auction is allowed to switch it off.
Two piles of crates
Keep the produce-market picture from §6.1, and make it specific to the stacks.
Imagine the trading floor as a warehouse with two piles, rebuilt every hour.
The supply pile is every crate a farmer will sell, stacked cheap on the floor, dear on top. A coal set does not send one crate labelled “R 900”. It sends a staircase of crates — a cheap bottom shelf, then dearer shelves above (§5.3). A solar farm usually sends one shelf of free crates. The interconnector sends a fixed bundle that costs nothing. You always lift from the floor.
The demand pile is every buyer standing in a queue. At the front: people who must eat — a distributor’s must-serve load, a factory’s protected floor. They have no walk-away price. Behind them: buyers who will pay a lot, then buyers who will pay less (§5.4). If crates run short you do not thin everyone equally. You send home the buyer who values the crate least — the top of the demand pile — and you keep feeding the people who must eat.
You keep lifting supply crates until every remaining buyer is fed. The last crate you actually lifted is that hour’s price. A farmer whose floor crate was R 350 still receives that last-crate price. A peaker whose crate stayed on the floor sells nothing.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 32, "padding": 12}}}%%
flowchart LR
subgraph recipe ["Each hour"]
A["Clamp every staircase<br/>to that hour's declaration"] --> B["Stack supply<br/>cheap → dear"]
A --> C["Stack demand<br/>must-serve, then willing"]
B --> D["Lift from the floor<br/>until the queue is fed"]
C --> D
D --> E["Meeting =<br/>unconstrained schedule"]
E --> F["Re-solve with the wires on<br/>= constrained schedule"]
end
Three stacking rules that stop most mistakes:
- Clamp first, then stack. A solar farm whose registry MCR is 75 MW but whose Declared Available Capacity this hour is 60 MW contributes a 60 MW crate, not 75. The emergency shelf above MCR only enters if the hour’s declaration reaches it.
- A promise sits in the pile even when it is
expensive. An inflexible (
I) unit is a must-take lump. You do not leave its crates on the floor because a flexible neighbour is cheaper. It promised. - Must-serve has no price, and is never shed. The factory’s protected floor is not “a very high bid”. It is not a bid. Nothing in the auction is allowed to take it away.
Worked hour — stack the golden 18:00
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. The same cast §11 takes from the door to the chalkboard. Here we only build the piles.
Step 1 — lay every staircase on the bench.
| Who | What they sent for 18:00 | How it enters a pile |
|---|---|---|
| Interconnector | +20 MWh import | One free supply crate. Not a Trading Unit. |
TU-PV1 |
0–75 MW @ R 0, declared I, available 75 |
One must-take supply crate, already cheap. |
TU-COAL1 |
0–200 @ R 350, 200–300 @ R 420, 300–400 @ R 640, 400–500 @ R 900;
F; available 500 |
Four supply shelves. The R 6,000 emergency shelf is above MCR and this hour’s 500 MW declaration, so it is clamped off. |
TU-OCGT1 |
0–60 @ R 2,800 and up; F; available |
The expensive top of the supply pile. |
TU-DIST1 |
440 MW must-serve, declared I |
One demand crate that cannot leave. |
TU-IND1 |
40 MW must-serve; then 10 @ R 4,800, 20 @ R 2,600, 20 @ R 1,500;
F |
Protected floor, then three priced crates. The R 1,500 crate is the first to walk away if supply runs short. |
Step 2 — stack supply, cheap on the floor.
Read the pile from the floor upward. Row 1 is the floor — the cheapest crate, and the first you lift. Cumulative is how high the pile has grown after that crate is placed.
| Place | Crate | MW | R / MWh | Cumulative MW |
|---|---|---|---|---|
| 1 · floor | Import, free | 20 | 0 | 20 |
| 2 |
TU-PV1, must-take
|
75 | 0 | 95 |
| 3 |
TU-COAL1 0→200
|
200 | 350 | 295 |
| 4 |
TU-COAL1 200→300
|
100 | 420 | 395 |
| 5 |
TU-COAL1 300→400
|
100 | 640 | 495 |
| 6 |
TU-COAL1 400→500
|
100 | 900 | 595 |
| 7 · top |
TU-OCGT1 0→60
|
60 | 2,800 | 655 |
Offered supply 655 MW.
20 + 75 + 200 + 100 + 100 + 100 + 60 = 655 ✓.
Step 3 — stack demand, must-eat at the front.
Most willing first. Must-serve has no Rand number. Priced crates follow from dearest to cheapest — that is willingness. Shed order is the mirror: the cheapest priced crate leaves first. Row 1 is the floor of the queue — must-serve, never shed. Row 5 is the top — first to walk away.
| Place | Crate | MW | Worth (R / MWh) | If crates run short |
|---|---|---|---|---|
| 1 · floor |
TU-DIST1 must-serve
|
440 | — | Never leaves |
| 2 |
TU-IND1 must-serve
|
40 | — | Never leaves |
| 3 |
TU-IND1 deep slice
|
10 | 4,800 | Last priced crate to leave |
| 4 |
TU-IND1 middle slice
|
20 | 2,600 | Leaves after the R 1,500 crate |
| 5 · top |
TU-IND1 top slice
|
20 | 1,500 | First to walk away |
Must-serve 480 MW (440 + 40). Elastic
50 MW (10 + 20 + 20). Total demand
530 MW. 440 + 40 + 10 + 20 + 20 = 530
✓.
Step 4 — lift from the floor until the queue is fed.
Every remaining buyer this hour will pay at least R 1,500. That is above every coal shelf and far above the free crates, so nobody walks away. You only stop when 530 MW have been lifted.
| Lift | Crate taken | Running total | Still hungry |
|---|---|---|---|
| 1 | Import 20 @ R 0 | 20 | 510 |
| 2 | Solar 75 @ R 0 | 95 | 435 |
| 3 | Coal 200 @ R 350 | 295 | 235 |
| 4 | Coal 100 @ R 420 | 395 | 135 |
| 5 | Coal 100 @ R 640 | 495 | 35 |
| 6 | Coal 35 of 100 @ R 900 | 530 | 0 |
Taken: 20 + 75 + 200 + 100 + 100 + 35 = 530 ✓. Left on
the floor: 65 MW of the R 900 coal shelf, and the whole 60 MW peaker.
530 + 65 + 60 = 655 ✓.
The last crate you needed came from coal’s R 900 shelf, 35 MW into a
100 MW step — not on an elbow. That volume (TU-COAL1 at
435 MW) is what §6.4 will read. The meeting
itself is 530 MW served.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 20, "rankSpacing": 28, "padding": 12}}}%%
flowchart TB
subgraph supply ["Supply pile — cheap on the floor"]
direction TB
S1["Import 20 MW @ R 0 — taken"]
S2["TU-PV1 75 MW @ R 0 — taken"]
S3["Coal 200 MW @ R 350 — taken"]
S4["Coal 100 MW @ R 420 — taken"]
S5["Coal 100 MW @ R 640 — taken"]
S6["Coal 35 of 100 MW @ R 900 — last crate"]
S7["Coal 65 MW leftover + OCGT 60 MW — still on the floor"]
S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7
end
subgraph demand ["Demand pile — must-eat at the front"]
direction TB
D1["TU-DIST1 440 MW must-serve — fed"]
D2["TU-IND1 40 MW must-serve — fed"]
D3["Factory 10 MW @ R 4,800 — fed"]
D4["Factory 20 MW @ R 2,600 — fed"]
D5["Factory 20 MW @ R 1,500 — fed"]
D1 --> D2 --> D3 --> D4 --> D5
end
S6 -->|"piles meet · 530 MW"| D5
- Lift from the floor
Read it: each step is a crate shelf. The red tick is where the queue was fed. Everything to the right stayed on the floor — leftover coal at R 900, then the peaker.
- Who was fed
Read it: import and solar are the short cheap bars; coal is the bulk; the last sliver is the 35 MW that set the meeting. The peaker has no bar.
Step 5 — write the unconstrained schedule from the meeting.
The piles do not publish a price. They publish volumes.
| TUID | Unconstrained MWh | Why |
|---|---|---|
| Interconnector | +20 | Floor crate, all taken |
TU-PV1 |
+75 | Must-take crate, all taken |
TU-COAL1 |
+435 | Three full shelves + 35 MW of the R 900 shelf |
TU-OCGT1 |
0 | Still on the floor |
TU-DIST1 |
−440 | Must-serve, fed |
TU-IND1 |
−90 | Must-serve and every priced crate, all fed |
| Σ | 0 | 20 + 75 + 435 = 530 and 440 + 90 = 530
✓ |
Energy payments in §7 are struck on these volumes, at the SMP §6.4 reads from the last flexible crate. In this hour that reading is R 900.00 — the walk to the chalkboard is §11.2.
Step 6 — the same piles, a narrower door.
The constrained run does not rebuild different crates. It walks the
same warehouse with the wires on. This hour the System Operator says
zone Z1 may not export more than 60 MW.
TU-PV1’s 75 free crates cannot all fit through that door.
Fifteen stay in the warehouse; coal lifts fifteen extra crates from the
same R 900 shelf (435 → 450).
That is a different volume, not a different SMP. Energy is still paid on the unconstrained meeting. The fifteen megawatt-hours the wire moved are a separate money line (§6.2, §6.6).
Where this is taught. The full hour — reserve floors, the R 0 constrained-off charge, publish — is §11. The staircases themselves are §5.3 and §5.4.
What you will not see on a public board. This chapter names TUIDs so you can learn the stacking. A published stack — the IDM increment board, the balancing sold/bought piles — shows price and volume only. A TUID on a public stack would publish another participant’s curve.
6.4 The System Marginal Price
§6.3 decided who runs. This section reads the number.
The idea fits in three sentences. Find the machines that had a real choice this hour: they ran, and they could have run a little more or a little less. Among those, find the most expensive one. What that machine charges for the megawatts it was actually given — read off its own staircase, nobody else’s — is the hour’s price, and everyone trades at it.
Said the way Market Code §9.7.2 says it: the System Marginal Price is the incremental price, at the scheduled unconstrained volume, of the most expensive flexible Trading Unit scheduled to run.
Why is the cheap solar farm paid the same number? Because the SMP is not a reward for what you offered. It is the market’s measure of what one more megawatt-hour would have cost. Solar offered R 0 and is paid the SMP; the distributor pays the SMP; the farmer in §6.1 who offered R 8 still received R 20.
Three words in the Code sentence do all the work.
| Word | Plain meaning | Why it is there |
|---|---|---|
| Unconstrained | The meeting from §6.3, before the wires. | The country price must not include a jammed corridor. The wire is a different money line (§6.2). |
| Flexible | The machine could still have moved. | A unit that promised a fixed output, or is stuck at its minimum, or cannot ramp, did not make the last decision. It cannot set the price. |
| Incremental | The price of that unit’s shelf at the megawatts it was given. | You do not average its cheaper shelves. You do not use the peaker that never started. You read one step on one staircase. |
The SMP is one number for the country, for that hour. It is not per zone, not per Trading Unit, not per BRP.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 24, "rankSpacing": 30, "padding": 12}}}%%
flowchart TB
A["Unconstrained volumes<br/>from the two piles"] --> B["Keep units that actually ran<br/>volume not zero"]
B --> C["Throw out anyone stuck<br/>I · at Mingen · ramp · reg-down"]
C --> D["Read each leftover unit's<br/>own shelf at its volume"]
D --> E["Take the highest of those<br/>shelf prices"]
E --> F{"Above the cap?"}
F -->|no| G["That number is the SMP"]
F -->|yes| H["SMP = cap<br/>and raise the capped flag"]
C --> I{"Nobody leftover?"}
I -->|yes| J["SMP = R 0.00<br/>all-inflexible flag"]
The six checks
Do these in order. Do not skip to “last crate on the pile = price” — that shortcut fails at a bend, and it fails when the last crate sat on a machine that was not allowed to set the price.
- Use the before-the-wires volumes. Read from the unconstrained schedule, never the constrained one. A jammed cable must not leak into the country’s price.
- Keep only machines that ran. Volume not zero. The idle peaker is out, however expensive its first shelf is.
- Throw out every machine that had no choice. There
are four ways to have no choice:
- it sits at or below Minimum Stable Generation — on its must-run floor, unable to come down;
- it declared
Ifor the hour — it promised a fixed figure; - it is ramp-bound — it physically cannot move any faster (a fact of the solution, not of the bid);
- it is held up for Regulation downwards — kept high so it can drop if the grid surges.
- Ask each survivor one question: what does your own staircase say at the volume you were given? Do not average its cheaper shelves. Do not look at anyone else’s stairs. If the volume lands exactly on a bend, use the bend rule below.
- Take the highest answer. That is the uncapped SMP. If two units tie to the Rand, the lower Trading Unit identifier is named as the setter — the name must be stable; the price is the same either way.
- Cap it. Never publish above the Market Price Cap
(Annexure 2; this worked day R 5,396.40/MWh). If the
raw number was higher, publish the cap and the flag
smp_capped— a capped price without the flag is a scarcity signal that has been switched off.
If step 3 emptied the list, stop. The SMP is R 0.00,
not the dearest stuck machine, and not “no price” (§9.7.2(5)). Publish
all_units_inflexible. An hour in which nothing flexible ran
has no marginal cost to show.
Worked hour — read 18:00
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10.2. The piles that produced these volumes are §6.3.
Step 1 — the volumes the piles already wrote.
| Who | Unconstrained MWh | Ran? |
|---|---|---|
| Interconnector | +20 | Yes, but it is not a Trading Unit. It cannot set the SMP. |
TU-PV1 |
+75 | Yes |
TU-COAL1 |
+435 | Yes |
TU-OCGT1 |
0 | No |
TU-DIST1 |
−440 | Yes |
TU-IND1 |
−90 | Yes |
Step 2 — throw out anyone who may not set the price.
| Who | Why they drop out — or stay |
|---|---|
| Interconnector | Not a Trading Unit. |
TU-PV1 |
Declared I. A promise. Out. |
TU-OCGT1 |
Did not run. Out. |
TU-DIST1 |
Declared I, and the whole 440 MW is must-serve.
Out. |
TU-IND1 |
Flexible, and it ran — but it was fully served (90 of 90). Nothing of its priced load was shed, so it did not make the last decision. Out. See the factory rule below. |
TU-COAL1 |
Declared F. Scheduled 435, well above Mingen 200. No
ramp bind, no regulation-down bind. Stays. |
One candidate remains.
Step 3 — read coal’s own shelves at 435 MW.
TU-COAL1 does not have “a” price. It has four energy
shelves (§5.3):
| Shelf | Band | Width | R / MWh | 435 sits here? |
|---|---|---|---|---|
| Must-run | 0 → 200 | 200 | 350 | no |
| 1 | 200 → 300 | 100 | 420 | no |
| 2 | 300 → 400 | 100 | 640 | no |
| 3 | 400 → 500 | 100 | 900 | yes — 35 MW into this shelf |
435 is not a bend. It is inside the top energy shelf. The incremental price is R 900.
Read the shelf, not the average
Read it: the gold band is the R 900 shelf. The red tick is 435. Cheaper shelves to the left were taken first; they do not pull the SMP down.
Same unit, three places on the stairs
Read it: 435 is this hour. 400 and 200 are the same stairs, to show the bend rule — they are not two other auctions.
Step 4 — the highest leftover shelf is the uncapped SMP.
One reading: R 900. Highest of a list of one is R 900. No tie to break.
Step 5 — the cap.
R 900 is below R 5,396.40. The cap does not bind.
smp_capped is false.
Step 6 — write the public number.
| Field | Value | Meaning |
|---|---|---|
| SMP(18:00) | R 900.00/MWh | One number for the country |
| Marginal unit | TU-COAL1 |
Told to that BRP, not on the public board |
smp_capped |
false | This is a real clear, not a switched-off scarcity flag |
all_units_inflexible |
false | Someone flexible ran |
The chalkboard in §11.2 now multiplies every unconstrained megawatt-hour by this R 900. Cheap solar is paid R 900. The distributor pays R 900. Coal is paid R 900 on all 435 MWh, including the cheap shelves.
Do not re-read the price on the constrained volumes. This hour coal moved 435 → 450 and would still sit on the R 900 shelf — same number, wrong reason. Another hour the wire would change the shelf. The Code keeps that out of the SMP on purpose.
The bend on the stairs
A bend (an elbow) is where one shelf stops and the next starts: 200, 300, 400, and nameplate 500 on this coal set. The Code needs a rule for “exactly on the corner”, because two shelves touch there.
Think of the corner of a staircase. You have just finished a tread.
The rule for the SMP is: price the tread you are standing on,
not the riser you have not climbed. That is “take the step
below” — the platform’s :below elbow
convention.
| If coal had been given… | On a bend? | What you read | Why |
|---|---|---|---|
| 435 MW (this hour) | no | R 900 | Inside the 400–500 shelf |
| 400 MW | yes (E2) | R 640 | The shelf you just finished, not the R 900 shelf you have not started |
| 500 MW (nameplate) | yes (MCR) | R 900 | Nameplate counts as a bend; the shelf below is still CI3 |
| 200 MW (Mingen) | yes | unit is out | Sitting on the must-run floor is inflexible. You never read the shelf. If someone read it anyway, the Code says take the step above (R 420), so the must-run block still cannot set the price. |
The must-run block (0 → Mingen, R 350 here) never sets the SMP. That is why Mingen is the one bend that is treated the other way, and why a unit sitting there is thrown out in check 3 before the ruler comes out.
When a factory can set the price
The Code sentence is written about generators. It never says whether a factory that was asked to use less may be the dearest leftover unit.
[D-08]. The platform’s shipped default
(smp_demand_setting: true) says yes — but only if
some of its priced load was actually shed. Then the factory
was the last decision. A factory that got every megawatt it
asked for is not at the edge, and must not set the price. That is why
TU-IND1 was out at 18:00: it drew the full 90 MW.
Every clearing also stores the other reading. The Market Governance Committee can see how often the two disagree, instead of arguing after the fact.
The disagreement is large on the next hour of the same fixture.
Data. Same day, hour 19:00 — SAWEM-SPEC §10.6, the tight hour. Sun down.
TU-PV1is 0.TU-DIST1declares 520.TU-COAL1is pushed to nameplate 500.TU-OCGT1is on at its minimum 60. Import 20. The factory is cut from 90 to 60. Balance:500 + 60 + 20 = 580 = 520 + 60✓.
Who is leftover at 19:00:
| Who | Volume | Flexible? | Shelf if read |
|---|---|---|---|
TU-COAL1 |
500 | yes — at nameplate, not at Mingen | bend → R 900 (step below) |
TU-OCGT1 |
60 | no — sitting on Mingen | cannot set |
TU-PV1 |
0 | — | did not run |
TU-IND1 |
−60 of 90 | yes, and partly shed | the cut sits in the R 2,600 slice |
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart LR
subgraph on ["Shipped default — factory may set"]
A1["Coal shelf R 900"] --> M1["highest = R 2,600"]
A2["Factory shed slice R 2,600"] --> M1
end
subgraph off ["Literal — generators only"]
B1["Coal shelf R 900"] --> M2["highest = R 900"]
B2["Factory ignored"] --> M2
end
| Reading | SMP(19:00) | What a participant would think |
|---|---|---|
Default (true) |
R 2,600.00 | Energy was scarce. The last thing the market did was turn off load worth R 2,600. |
Literal (false) |
R 900.00 | Same as a comfortable hour. The factory lost load it valued at R 2,600 while the price says R 900. |
The gap is R 1,700/MWh. Both numbers are stored. The default is the one that makes scarcity visible.
When nobody flexible ran
If every unit that ran is stuck — all I, or all sitting
on Mingen — there is no leftover shelf to read. The SMP is R
0.00. You do not take the dearest stuck machine. You do not
leave the hour blank. You publish zero and the all-inflexible flag.
That is rare. It is also the rule. An hour with no flexible machine has no last decision to price.
Where this is taught. The 18:00 chalkboard that uses this R 900 is §11.2. The four reserve prices that sit on their floors when the last energy unit still has headroom are §6.5.
6.5 The four reserve system prices
Reserve is a standby promise. The System Operator tells a unit: “stand ready to move at short notice — and because you are standing ready, do not sell that part of yourself as energy.”
Standing ready is work, so it is paid. The only question is how much.
The standby taxi. You ask a taxi driver to wait outside your door all evening, engine running, taking no fares. What do you owe him? At the very least, what the fares he turned away would have paid him. And if the street was empty — there were no fares to be had anyway — he gave up nothing, and you owe him the agreed minimum call-out fee.
| In the story | In the market |
|---|---|
| The fares he turned away | The SMP earnings the held-back unit gave up — its cost of lost opportunity |
| An empty street | The unit had spare megawatts that were not going to sell anyway |
| The minimum call-out fee | The floor the MGC published for that category |
That is the whole formula. Per category, per hour:
system price = the dearest unit’s lost earnings, or the floor — whichever is higher.
Four standby promises, four prices:
| System price | Category | The promise |
|---|---|---|
SMPIRC |
Instantaneous | React within seconds. |
SMPRURC |
Regulating Up | Be held below your energy schedule, so you can push up if the grid sags. |
SMPRDRC |
Regulating Down | Be held above, so you can come down if the grid surges. |
SMPMRC |
Ten-Minute | Be delivering within ten minutes. Can sit on a machine that is not even running. |
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 26, "rankSpacing": 34, "padding": 12}}}%%
flowchart TB
REQ["SO reserve requirement<br/>for the hour"] --> Q{"Did anyone give up an<br/>energy sale to stand ready?"}
Q -->|"no — spare capacity covered it"| FLOOR["Price = the MGC floor<br/>flag reserve_prices_at_floor"]
Q -->|"yes"| LOSS["Price = the dearest unit's loss<br/>never below the floor"]
Worked hour — 18:00 is an empty street
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. The same hour whose piles are §6.3.
The SO wants held ready: Regulating Up 15 MW, Regulating Down 10 MW, Instantaneous 20 MW, Ten-Minute 25 MW. The MGC floors are R 50, R 50, R 50 and R 0 per MW.
Now look back at the meeting. Coal was taken to 435 of its 500 MW, so 65 MW of it stayed on the floor, unsold. The peaker never started at all. Every standby megawatt the SO wants can come out of capacity that was not going to earn anything anyway. Nobody gives up a sale. The street is empty.
So the lost-earnings number is R 0 in every category, and every price lands on its floor:
| Price | max(lost earnings, floor) | Published |
|---|---|---|
SMPRURC — Regulating Up |
max(0, 50) | R 50/MW |
SMPRDRC — Regulating Down |
max(0, 50) | R 50/MW |
SMPIRC — Instantaneous |
max(0, 50) | R 50/MW |
SMPMRC — Ten-Minute |
max(0, 0) | R 0/MW |
The board also raises the flag reserve_prices_at_floor
(§6.7), so a participant
reading R 50 knows it is a quiet hour, not a computed scarcity.
When the street is busy. In a tight hour — think 19:00, when coal is pushed to nameplate and the factory is being cut — every megawatt would have sold. Holding a machine back then costs it real money: the SMP it would have been paid, less what those megawatts would have cost it to make. The dearest such loss in each category becomes the system price, and the floor stops mattering.
Who sees which number. The four system prices are public. Each unit’s own lost-earnings figures are computed on the constrained schedule and go only to that unit’s BRP — publishing them would hand the unit’s cost curve to its competitors.
6.6 Zones do not set the price
A Network Zone is a patch of the grid with a name (Z1
Northern Corridor, Z6 Highveld Load, …). The System
Operator may say “this zone may not export more than 60 MW this hour”.
That changes the constrained schedule. It does
not produce a “Z1 SMP”.
Energy is still paid at the system SMP on the unconstrained volume. Being constrained off is a separate line, settled at the unit’s own offer, not at a local price. In the worked hour a solar farm cut from 75 to 60 MW keeps 75 × R 900 and pays back 15 × R 0 = R 0. That is the Code, not a bug.
Where this is taught. What a zone is, and why the map is provisional, is V12 §2.
6.7 What is published at 14:00 D−1
| Artefact | Who may see it | Contents |
|---|---|---|
| System prices | Public | Per hour: SMP, four reserve system prices, smp_capped,
all_units_inflexible,
reserve_prices_at_floor. |
| Own schedule | The unit’s BRP | Unconstrained MWh, constrained MWh, reserve allocated, whether the unit was marginal, which constraints bound it, and the day-ahead settlement lines for that hour. |
| Own unit prices | The unit’s BRP | That unit’s four reserve opportunity-cost prices. |
| Impacted Network / Distribution Operators | Those operators | Scheduled generation and consumption per Point of Delivery / zone. |
| Daily general adequacy report | Public | Expected demand, reserve, capacity, sent-out, consumption, system prices. No participant names. |
Events on the stream: prices.published,
schedule.published. A BRP that is listening does not need
to poll.
6.8 Residual clearing — registered schedules are constants
From stage 11 the day-ahead market clears the residual. A registered forward schedule is a C16-style constant on the energy balance (C1) and is subtracted from each zonal export limit (C17) before spot terms compete for the headroom that is left. It is not a decision variable, and it is not a tie-break: priority over spot is a consequence of the arithmetic.
The published formulation version moves when those expressions change
(MO-SPEC-4.3/2026-08). That is a §9.5(7) amendment — the
comment window is one month from the publication date, and the
formulation may not take effect inside it.
Do not expect the System Marginal Price to stay still when a schedule is registered. Taking volume off both sides of the pool moves the residual merit order. What must stay still is the identity, per Trading Period: registered + residual spot = what the unit cleared with no register. On a binding corridor the schedule is delivered in full and the spot trade is cut to the remaining headroom. If the register alone exceeds the limit, the constrained run is infeasible on C17 — a loud failure, never a silent curtailment of a firm bilateral.
The day-ahead Solution reports residual spot only.
Contracted Energy adds the forward base back, which is how §13 still
measures deviations against the physical position. The balancing engine
is not touched.
7. How the market settles the day-ahead
“Settle the bids” is two clocks sharing one word. Separate them.
| Clock | When | What it is |
|---|---|---|
| Commercial settlement of the hour | Computed with the clearing; visible on the schedule report at 14:00 D−1 | Volumes × prices, signed, tagged with an account. This is the chalkboard. |
| Financial settlement of the month | Indicative on SD+1 WD; billable on BP+5 WD | Those lines, plus IDM, metering, balancing, fees, rolled into a statement and an invoice. This is the till. |
This chapter is the chalkboard. §8 is the till.
7.1 The three pots
Every line lands in exactly one account. The kind of the line decides the pot; a caller cannot file an energy payment on the fee account.
| Account | What goes in it | Does it net to zero? |
|---|---|---|
| Energy | Day-ahead energy payments
(EPM = scheduled unconstrained MWh × SMP) |
Yes, exactly R 0.00 per hour, across all participants. You are a conduit, not a counterparty. Generators are paid what loads are charged. |
| Market Balancing | Constrained-schedule adjustments, additional energy above the cap, reserve capacity, all IDM money, later balancing | No. A surplus or deficit is recovered by the System Operator as an ancillary service. |
| MO Charge | The Market Operator’s own fees | Ring-fenced. Not mixed with energy. |
A fourth pot, Bad Debt, is for unpaid invoices and default interest. It is not a DAM calculation.
Where this is taught. The participant’s reading of the same three pots is V9 §13. This chapter is the operator’s invariant: the energy pot must print R 0.00 or the day must not publish.
7.2 Energy payment —
EPM
EPM = SG × SMP
SG is the unconstrained scheduled
volume, signed: plus means produced (you are paid),
minus means consumed (you pay). SMP is
that hour’s one system price (§6.4).
In crate language: every accepted crate trades at the last-crate price. The note on the farmer’s crate got them into the pile. It does not set what they are paid.
Two things that catch people:
- Use the unconstrained volume. If the System
Operator later cut you from 75 to 60, you are still paid
75 × SMP. The cut is a different line (§7.3). - The same price for everyone. A coal plant that offered R 350 and a gas plant that offered R 880 are both paid R 900 if that is where the market cleared. The offer decided whether they cleared, not what they are paid.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 24, "rankSpacing": 30, "padding": 12}}}%%
flowchart LR
SG["SG<br/>unconstrained MWh<br/>+ produced · − consumed"] --> MUL["×"]
SMP["SMP<br/>one number<br/>for the country"] --> MUL
MUL --> EPM["EPM<br/>one signed Rand line<br/>on the Energy pot"]
Worked hour — six lines at 18:00
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. Volumes from §6.3. Price from §6.4: SMP = R 900.00/MWh.
Write one line per name. Same multiplication every time.
1. Coal — the last crate, paid like everyone else.
TU-COAL1 was scheduled +435 MWh
unconstrained. Its cheap shelves were R 350, R 420, R 640. The last 35
MW sat on the R 900 shelf, so it set the SMP. It is still paid the SMP
on all 435 MWh, not only the dear ones.
EPM = +435 × 900 = +R 391,500.00
The Market Operator pays the coal BRP.
2. Solar — offered R 0, paid R 900.
TU-PV1 offered one free crate. That got it into the
pile. The payment is still the system price.
EPM = +75 × 900 = +R 67,500.00
The offer decided whether the 75 MWh cleared (it did — it was free). It did not decide the Rand number.
3. The peaker that did not run.
TU-OCGT1 stayed on the floor. Volume is zero.
EPM = 0 × 900 = R 0.00
An expensive unused crate is not a line you pay. It is a blank.
4. The import — not a Trading Unit, still a line.
The System Operator owns the interconnector. The 20 MWh still has to
be paid, or the Energy pot would be short by 20 × 900.
EPM = +20 × 900 = +R 18,000.00
Without this row the account holes by −R 18,000.00. Imports are a settlement subject. They are not a TUID.
5. The distributor — a load pays the same R 900.
TU-DIST1 drew 440 MWh of must-serve.
Sign is negative: the participant pays the Market Operator.
EPM = −440 × 900 = −R 396,000.00
6. The factory — fully served, still pays the SMP.
TU-IND1 asked for 90 MWh and got 90. Its own priced
slices were worth R 1,500, R 2,600, R 4,800. Those numbers decided it
would stay in the queue. They are not what it pays.
EPM = −90 × 900 = −R 81,000.00
7. Add them up — the Energy pot must print R 0.00.
Paid out (plus):
391,500 + 67,500 + 18,000 = R 477,000.00
Taken in (minus): 396,000 + 81,000 = R 477,000.00
Volumes: 435 + 75 + 20 = 530 and
440 + 90 = 530. Σ SG = 0. Then
Σ EPM = 900 × 0 = R 0.00. ✓
That is the operator’s invariant. The platform checks it on the exact products, before rounding. If it fails, the market cleared wrongly and you must not publish.
| Who | SG (MWh) | Arithmetic | EPM |
|---|---|---|---|
TU-COAL1
|
+435 | 435 × 900 |
|
TU-PV1
|
+75 | 75 × 900 |
|
TU-OCGT1
|
0 | 0 × 900 | R 0.00 |
| Interconnector | +20 | 20 × 900 |
|
TU-DIST1
|
−440 | 440 × 900 | − R 396,000.00 |
TU-IND1
|
−90 | 90 × 900 | − R 81,000.00 |
| Σ | 0 MWh | R 0.00 ✓ | |
You are a conduit. Generators and the import are paid what the loads are charged. The peaker is on the board so a zero is visible, not missing.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart LR
DIST["TU-DIST1 pays<br/>R 396,000"] --> POT["Energy pot<br/>R 0.00"]
IND["TU-IND1 pays<br/>R 81,000"] --> POT
POT --> COAL["TU-COAL1 is paid<br/>R 391,500"]
POT --> PV["TU-PV1 is paid<br/>R 67,500"]
POT --> IMP["Import is paid<br/>R 18,000"]
8. The wire does not rewrite this chalkboard.
After the piles met, the System Operator said zone Z1
may export only 60 MW. TU-PV1 is cut 75 → 60. Coal rises
435 → 450.
Solar’s EPM stays +R 67,500.00 — still
75 × 900. The 15 MWh the wire moved is §7.3, at
solar’s own offer of R 0, and it lands on the Market
Balancing pot, not here.
| What changed | What you write | What you do not write |
|---|---|---|
| Solar 75 → 60 on the wires | EPM still 75 × 900 |
60 × 900 on this pot |
| Coal 435 → 450 on the wires | EPM still 435 × 900 |
450 × 900 on this pot |
That is catch 1 with numbers. The Energy pot is the unconstrained meeting × the SMP. Nothing else.
Rounding is applied once, to the Rand amount. You do not round 435 or 900 first. Each line also keeps the exact product, because rounding twenty lines on their own can leave a one-cent residual on a set whose exact products sum to zero.
Where this is taught. The same six lines sit on the door-to- chalkboard walk in §11.2. The participant’s reading of the Energy pot is V9 §13.
7.3
Constrained-schedule adjustment — CPP /
CSC
§7.2 already paid the plan. This section pays the move.
The Energy pot used unconstrained volumes × the SMP. Then the wires spoke. Some units cannot do what the plan said. Other units have to do more. That difference is not rewritten on the Energy pot. It is a new line, on the Market Balancing pot, at the unit’s own stairs — not at the SMP.
In crate language: you already paid the solar farm for 75 crates at R 900. The door only lets 60 through. You buy 15 crates back. The buy-back price is the number on the farmer’s own note, not today’s crate price. The note said R 0. Buying them back costs R 0. The farm keeps the R 900 on those 15. Coal has to send 15 extra crates. You pay coal’s own shelf for just those 15.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart TB
A["Energy pot already written<br/>SG × SMP"] --> B["Wires move a unit<br/>SG ≠ CG"]
B --> C["Walk that unit's own stairs<br/>between the two volumes"]
C --> D{"Moved up on its own axis?"}
D -->|yes| E["CPP — Market Balancing<br/>pays the integral"]
D -->|no| F["CSC — participant<br/>pays the integral"]
B --> G{"SG = CG?"}
G -->|yes| H["No line at all"]
| Direction, on the unit’s own axis | Kind | Who pays whom |
|---|---|---|
| Constrained above unconstrained — a generator asked to make more, or a load asked to take less | CPP — Constrained Purchases Payment | Market Balancing pays the participant |
| Constrained below unconstrained — a generator cut back, or a load forced to take more | CSC — Constrained Sales Charge | The participant pays Market Balancing |
“Own axis” means megawatts produced for a generator and megawatts consumed for a load. A factory cut from 90 to 70 has a signed volume that rose (−90 → −70) but it lost 20 MW it wanted. That is a CPP — it is compensated — not a CSC.
If nobody moved, there is no line. Do not write R 0.00 for a unit that stayed put. A R 0.00 CSC means “they moved, and their own stairs were worth nothing.”
How to walk one unit
Do these in order.
- Write SG (unconstrained) and CG (constrained). Same sign convention as §7.2.
- If they are equal, stop. No line.
- Face the unit’s own axis. For a generator, compare the two positive megawatts. For a load, compare how much it draws.
- Walk that unit’s own staircase from one volume to
the other. Each shelf: width × that shelf’s price. Add the shelves. That
sum is the integral. It is not
ΔMW × SMP. - Name the kind from the direction (table above). Put the Rand on Market Balancing.
A unit that sent no day-ahead price is walked on a flat R 0 curve (§9.8.2(2)). The integral is still R 0. The sentence on the board is different: no day-ahead price submitted, not own offer was zero.
Worked hour — the wire moves 15 MWh
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. Energy lines from §7.2. Zone
Z1may export at most 60 MW.
1. Who moved?
| Who | SG | CG | Moved? |
|---|---|---|---|
TU-PV1 |
+75 | +60 | Yes — cut 15 |
TU-COAL1 |
+435 | +450 | Yes — lifted 15 |
TU-OCGT1 |
0 | 0 | no |
| Interconnector | +20 | +20 | no |
TU-DIST1 |
−440 | −440 | no |
TU-IND1 |
−90 | −90 | no |
Fifteen megawatt-hours left the solar farm and landed on coal. That is the whole constrained adjustment for this hour. Two lines.
2. Solar — walk 75 down to 60 on its own stairs.
TU-PV1 has one shelf: 0–75 MW at R 0.
From 75 to 60 is 15 MW on that shelf.
15 × 0 = R 0.00 → CSC, because a
generator was cut.
The board must show the sentence own offer was zero, not a blank. A blank looks like “we forgot the line.”
3. That R 0.00 is the curtailment windfall.
The Energy pot already paid 75 × 900 = R 67,500. The
buy-back is R 0. Net for the hour, before IDM:
| Line | Amount | Why |
|---|---|---|
| EPM | +R 67,500.00 | 75 MWh × R 900, never rewritten |
| CSC | R 0.00 | 15 MWh × own R 0 |
| Net | +R 67,500.00 | For 60 MWh actually generated |
67,500 − 0 = 67,500 ✓. The fifteen megawatt-hours it
will not make are still worth R 13,500 at the SMP
(15 × 900). The Code keeps that with the farm (§9.8.2). It
is not a bug.
4. Coal — walk 435 up to 450 on its own stairs.
| Shelf | Band | R / MWh | 435→450 sits here? |
|---|---|---|---|
| Must-run | 0 → 200 | 350 | no |
| 1 | 200 → 300 | 420 | no |
| 2 | 300 → 400 | 640 | no |
| 3 | 400 → 500 | 900 | yes — the whole 15 MW |
Both 435 and 450 are inside the R 900 shelf. One shelf, no bend.
15 × 900 = +R 13,500.00 → CPP, because
a generator was lifted.
Not 15 × SMP as a separate idea — it happens to
be R 900 because that is coal’s own shelf here. If the extra megawatts
had sat on the R 640 shelf, the CPP would be 15 × 640.
One shelf, no bend
Read it: the gold sliver is the only part this CPP walks. Cheaper shelves to the left are already inside the EPM. They are not walked again.
5. What if the walk crossed a bend?
This hour it does not. Same coal stairs, two other volumes, to show the ruler — not another auction.
Walk 390 → 410:
| Piece | Width | Shelf | Rand |
|---|---|---|---|
| 390 → 400 | 10 | R 640 | 6,400 |
| 400 → 410 | 10 | R 900 | 9,000 |
| Σ | 20 | R 15,400 |
20 × 900 would be wrong. You add the shelves you
actually cross. That is all “integral” means here.
6. Who has no line?
TU-DIST1, TU-IND1, TU-OCGT1,
the import: SG = CG. Nothing to walk. Leave them off this pot.
7. A load, on its own axis — same factory stairs, not this hour.
This hour the factory was not moved. The axis still matters, so walk the fixture curve as if the wires had said “draw 70, not 90.”
TU-IND1 draws 90, with a top slice 70→90 at R
1,500 (§5.4).
Forced down to 70:
- On its own axis it is taking less. That is a CPP.
- Walk 90 → 70:
20 × 1,500 = +R 30,000.00. - Signed energy went −90 → −70. If you keyed the kind off that rise you would label a compensation a charge. Do not.
The factory would be paid for the 20 MWh it was not allowed to use, at what those megawatts were worth to it, not at the SMP.
8. Write the two lines, then look at the pots.
| Who | SG → CG | Walk | Line |
|---|---|---|---|
TU-PV1
|
+75 → +60 | 15 × R 0 | CSC R 0.00 |
TU-COAL1
|
+435 → +450 | 15 × R 900 | CPP + R 13,500.00 |
| Market Balancing net this hour |
|
||
The Energy pot is still R 0.00. This R 13,500 is a different pot. The System Operator recovers it as an ancillary service.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart LR
MBA["Market Balancing"] -->|"CPP R 13,500"| COAL["TU-COAL1<br/>made 15 extra"]
PV["TU-PV1<br/>cut 15"] -->|"CSC R 0"| MBA
SO["System Operator"] -->|"recovers R 13,500<br/>as ancillary"| MBA
Solar keeps R 13,500 of SMP on energy it will not generate. Coal is paid R 13,500 for energy it will generate extra. The windfall and the CPP are the same Rand amount this hour because solar’s own offer was zero and coal’s extra shelf was R 900. They are still two lines, two reasons.
9. The System Operator cut is free. Cutting yourself is not.
If TU-PV1 later re-declares 60 → 20 in the IDM, those 40
MWh are priced at the Intra-Day Price, not at its own R 0. In the golden
hour that charge is −R 37,800. Walked in §11.4.
That is the commercial fact this section exists to teach: the DAM pays you for the plan; the wire taking it away at your own R 0 costs you nothing; you taking it away yourself does.
Where this is taught. The same two lines sit in §11.2 step 4. The participant’s reading of the windfall is V9 §13.4.
7.4 Additional energy
payment — AEPM
The Energy pot pays everyone the capped SMP (§7.2). A machine that offered
above the Market Price Cap, and was still told to run,
would otherwise be short the difference. AEPM makes that
machine whole for the excess of its own stairs over a
reference price. It lands on Market Balancing, not on
Energy.
AEPM = Σ width × max(shelf − reference, 0)
over every scheduled shelf, from 0 to SG
The shipped reference is the SMP
([D-02]). The SMP itself cannot go above the cap (§6.4), so when that unit
set the price the two readings agree. They only split when a
unit above the cap ran as a cheaper neighbour set the SMP.
Three gates. Fail any one and there is no line — not a R 0.00.
- It must be a production staircase. A factory’s willingness to pay is not an offer. Paying a load the excess of what it would have paid is a different deal the Code does not have.
- The unit must be flexible (
F). AnIunit promised a figure. It is not made whole for a high note. - Some scheduled shelf must sit above the cap. Walk
only the megawatts that were actually scheduled (
SG, unconstrained).
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart TB
A["Unconstrained SG"] --> B{"Production · flexible ·<br/>a scheduled shelf above the cap?"}
B -->|no| N["No AEPM line"]
B -->|yes| C["Walk 0 → SG<br/>keep only shelf − reference"]
C --> D["AEPM on Market Balancing"]
Worked hour — nobody is above the cap
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00. Cap R 5,396.40/MWh. SMP R 900.00.
1. Who could even be a candidate?
| Who | Flexible? | Highest scheduled shelf | Above R 5,396.40? | AEPM |
|---|---|---|---|---|
TU-COAL1 |
F | R 900 (at 435 MW) | no | none |
TU-PV1 |
I | R 0 | no | none |
TU-OCGT1 |
F | did not run | — | none |
TU-DIST1 |
I | consumption | — | none |
TU-IND1 |
F | consumption | — | none |
| Interconnector | — | not a bid | — | none |
This hour AEPM is absent. That is the ordinary uncongested day. Do not write six R 0.00 lines.
2. Same coal stairs, if emergency had run — not this hour.
TU-COAL1 has an emergency shelf 500–530 MW at R
6,000 (§5.3). This
hour’s declaration stopped at 500, so that shelf was clamped off. If 20
MW of it had been scheduled (SG = 520), the shipped walk is
against the SMP of R 900:
| Piece | Width | Shelf | max(shelf − 900, 0) | Rand |
|---|---|---|---|---|
| 0 → 500 | 500 | R 350 … R 900 | 0 | 0 |
| 500 → 520 | 20 | R 6,000 | 5,100 | 102,000.00 |
| Σ AEPM | +R 102,000.00 |
520 × 900 on the Energy pot would still be the EPM. The
extra R 102,000 is only the excess of that machine’s own note over the
SMP. The Energy pot does not move.
The other [D-02] reading uses the cap instead of the
SMP. Same 20 MW: 20 × (6,000 − 5,396.40) = R 12,072.00. The
two readings agree only when the SMP itself is sitting on the cap.
3. A factory must not be paid this.
If you walked TU-IND1’s R 4,800 slice against the SMP
you would “owe” a served load tens of thousands of Rand. The first gate
stops that. Consumption is out.
Where this is taught.
[D-02]is on §25.4. This hour’s empty line sits on the schedule report in §7.6.
7.5 Reserve capacity payments
Reserve is the standby promise from §6.5. This section is the pay cheque: each megawatt that actually qualified, times that hour’s system price, times a performance factor.
PAYRURC = SMPRURC × qualifying MW × PerfAdj
PAYRDRC = SMPRDRC × qualifying MW × PerfAdj
PAYIRC = SMPIRC × qualifying MW × PerfAdj
PAYMRC = SMPMRC × qualifying MW
Ten-Minute has no performance factor in the Code.
The other three use PerfAdj = 1.0 when the System Operator
has not said otherwise.
Qualifying megawatts are read on the constrained schedule. A failed band (sitting outside the window the category needs) qualifies zero, not the contracted amount. They land on Market Balancing. The System Operator recovers them.
| Kind | Category | Everyday meaning |
|---|---|---|
PAYRURC |
Regulating Up | Paid to be held below so you can push up |
PAYRDRC |
Regulating Down | Paid to be held above so you can come down |
PAYIRC |
Instantaneous | Paid for the very fast reserve |
PAYMRC |
Ten-Minute | Paid for the slower reserve. May sit on a machine that is not running |
Worked hour — four hold-backs, one cheque
Data. Same 18:00. Requirements: RU 15, RD 10, IR 20, TM 25. Floors R 50 / R 50 / R 50 / R 0. Street empty (§6.5) → every system price is on its floor.
1. Who was asked to stand ready?
| Category | MW wanted | Held on | Why that unit |
|---|---|---|---|
| Regulating Up | 15 | TU-COAL1 |
Headroom above 435 toward 500 |
| Regulating Down | 10 | TU-COAL1 |
Footroom down toward Mingen 200 |
| Instantaneous | 20 | TU-COAL1 |
Certified and available |
| Ten-Minute | 25 | TU-OCGT1 |
Offline is allowed for this category |
Coal energy + up-reserves: 435 + 15 + 20 = 470 of 500.
Feasible.
2. Coal’s three payments.
PerfAdj = 1.0. Prices are the floors.
| Kind | MW | Price | Arithmetic | Amount |
|---|---|---|---|---|
PAYRURC |
15 | R 50 | 15 × 50 × 1.0 |
+R 750.00 |
PAYRDRC |
10 | R 50 | 10 × 50 × 1.0 |
+R 500.00 |
PAYIRC |
20 | R 50 | 20 × 50 × 1.0 |
+R 1,000.00 |
| Coal reserve | 45 | +R 2,250.00 |
750 + 500 + 1,000 = 2,250 ✓. That is the R 2,250 on
coal’s chalkboard in §11.2.
3. The peaker’s Ten-Minute line.
TU-OCGT1 holds 25 MW offline. The system price is
R 0 (floor).
PAYMRC = 25 × 0 = R 0.00
The hold is real. The cheque is zero because this hour’s Ten-Minute floor is zero and nobody gave up a sale. Write the allocation on the schedule. Do not invent a R 50.
4. Who is not paid.
TU-PV1 declared reserve U.
TU-DIST1 likewise. TU-IND1 offered some
reserve but was not allocated this hour. No contracted megawatts → no
line.
5. The pot.
Reserve this hour: +R 2,250.00 on Market Balancing
(all coal). Add the §7.3 CPP of R
13,500. MBA energy-side net before IDM:
13,500 + 2,250 = R 15,750. The Energy pot is still R
0.00.
| Who | Kind | MW | R / MW | Amount |
|---|---|---|---|---|
TU-COAL1
|
PAYRURC | 15 | 50 |
|
TU-COAL1
|
PAYRDRC | 10 | 50 |
|
TU-COAL1
|
PAYIRC | 20 | 50 |
|
TU-OCGT1
|
PAYMRC | 25 | 0 | R 0.00 |
| Market Balancing · reserve |
|
|||
System prices are public. Each unit’s own lost-opportunity figures stay with its BRP.
Where this is taught. How the four prices are found is §6.5. The same R 2,250 sits in §11.2 step 4 and on the schedule report in §7.6.
7.6 When the chalkboard is written — the schedule report
The day-ahead lines travel inside the schedule report (§9.10(2)). They are computed when the day is solved. You review them. Then you publish. A pipeline that published as a side-effect of solving would make “let me check that” impossible (§6.2).
They are not an invoice. They are the ingredients of next month’s invoice (§8). A BRP that fetches its schedule already has the chalkboard for that day. The till comes later.
What the report is
One Trading Day. Twenty-four hours. Two audiences:
| Face | Who | What they may see |
|---|---|---|
| Public strip | Everyone | SMP, four reserve system prices, smp_capped,
all_units_inflexible, reserve_prices_at_floor,
the adequacy totals. No TUID. |
| Own hour | That unit’s BRP | SG, CG, reserve held, whether they were marginal, which constraint bound them, and every DAM line for that hour. |
| Operator board | You | Both faces, every unit, both pots. This is what you read before you press publish. |
Events after publish: prices.published,
schedule.published.
Worked report — 18:00, as you review it
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10. Numbers from §7.2–§7.5.
1. Public strip — what the country is told.
| Field | Value | How to read it |
|---|---|---|
| Trading period | 2026-07-15T18:00:00+02:00 |
SAST. The hour 18:00–19:00 |
| SMP | R 900.00/MWh | One number. Set by TU-COAL1 at 435 MW |
smp_capped |
false | Not a switched-off scarcity signal |
all_units_inflexible |
false | Someone flexible ran |
SMPRURC / SMPRDRC / SMPIRC /
SMPMRC |
R 50 / 50 / 50 / 0 | Floors. Empty street |
reserve_prices_at_floor |
true | Those R 50s are minima, not computed losses |
| Marginal unit | TU-COAL1 |
On the operator board and that BRP’s own hour — not on the public wall |
2. Own hours — volumes and why.
| TUID | SG | CG | Bound by | Marginal? | Reserve held |
|---|---|---|---|---|---|
TU-COAL1 |
+435 | +450 | — | yes | RU 15 · RD 10 · IR 20 |
TU-PV1 |
+75 | +60 | zonal_export_limit:Z1 |
no | none |
TU-OCGT1 |
0 | 0 | — | no | TM 25 (offline) |
| Interconnector | +20 | +20 | SO schedule | no | — |
TU-DIST1 |
−440 | −440 | — | no | none |
TU-IND1 |
−90 | −90 | — | no | none |
Σ SG = 0 ✓. The Z1 door is the only binding
constraint.
3. DAM lines on the same report — Energy pot.
| Who | Kind | Qty | Price | Amount | Pot |
|---|---|---|---|---|---|
TU-COAL1 |
EPM | +435 | 900 | +R 391,500.00 | Energy |
TU-PV1 |
EPM | +75 | 900 | +R 67,500.00 | Energy |
TU-OCGT1 |
EPM | 0 | 900 | R 0.00 | Energy |
| Interconnector | EPM | +20 | 900 | +R 18,000.00 | Energy |
TU-DIST1 |
EPM | −440 | 900 | −R 396,000.00 | Energy |
TU-IND1 |
EPM | −90 | 900 | −R 81,000.00 | Energy |
| Σ Energy | 0 | R 0.00 ✓ |
If that last cell is not R 0.00, do not publish.
4. DAM lines — Market Balancing.
| Who | Kind | Walk / MW | Amount | Note |
|---|---|---|---|---|
TU-PV1 |
CSC | 75 → 60 · 15 × R 0 | R 0.00 | own offer was zero |
TU-COAL1 |
CPP | 435 → 450 · 15 × R 900 | +R 13,500.00 | Extra energy at own shelf |
TU-COAL1 |
PAYRURC | 15 × R 50 | +R 750.00 | |
TU-COAL1 |
PAYRDRC | 10 × R 50 | +R 500.00 | |
TU-COAL1 |
PAYIRC | 20 × R 50 | +R 1,000.00 | |
TU-OCGT1 |
PAYMRC | 25 × R 0 | R 0.00 | Held; floor is zero |
| — | AEPM | — | none | Nobody above the cap |
| Σ Market Balancing | +R 15,750.00 | SO recovers |
13,500 + 2,250 = 15,750 ✓. This pot does
not have to be zero.
| Pot | What it holds this hour | Net |
|---|---|---|
| Energy | Six EPM lines at R 900 | R 0.00 ✓ |
| Market Balancing | CPP + CSC + reserve + no AEPM |
|
| MO Charge | Fees — not a DAM hour line | — |
Solve wrote these cells. Publish makes them the thing every participant settles against. They are still not cash.
5. What each seat is allowed to see after you publish.
| Who | On their schedule report |
|---|---|
| Everyone | The public strip. SMP R 900, floors, flags, adequacy. |
TU-COAL1’s BRP |
SG 435, CG 450, you were marginal, EPM +391,500, CPP +13,500, reserve +2,250. |
TU-PV1’s BRP |
SG 75, CG 60, bound by zonal_export_limit:Z1, EPM
+67,500, CSC R 0.00 (own offer was zero). |
TU-DIST1’s BRP |
−440 both sides, EPM −396,000. No constrained line. |
TU-IND1’s BRP |
−90 both sides, EPM −81,000. |
TU-OCGT1’s BRP |
0 energy, TM 25 held, PAYMRC R 0.00. |
| Network Operator for Z1 | TU-PV1 constrained to 60. |
They must not see another unit’s stairs or another unit’s lost-opportunity prices.
6. What you check, in this order, before publish.
- Energy pot R 0.00 on the exact products.
- Every CSC of zero has a sentence, not a blank.
- Flags match the hour (
smp_capped,all_units_inflexible,reserve_prices_at_floor). - The Z1 door is named on solar’s own hour.
- Reserve megawatts match the SO requirement (15+10+20+25).
- Then publish. Events fire. Participants fetch.
The same hour, as a follow-along on the Settlement tab, is §13.10 and §11.2 step 5.
Where this is taught. Who may see which artefact is §6.7. The till that later uses these lines is §8.
8. After settlement — charges and notices
8.1 From chalkboard to till
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 28, "rankSpacing": 36, "padding": 12}}}%%
flowchart TB
P["14:00 D−1<br/>schedule + DAM lines published"] --> IDM["IDM lines accrue<br/>through the five auctions"]
IDM --> M["Meters + instructions<br/>after delivery"]
M --> BAL["Balancing lines<br/>17:00 D+1 / official D+7"]
BAL --> IND["Indicative statement<br/>17:00, SD+1 WD"]
IND --> VER["Data Verification<br/>closes SD+7 WD 17:00"]
VER --> INI["Initial statement<br/>12:00, BP+5 WD"]
INI --> INV["Invoice if participant owes<br/>Self-Billing Invoice if MO owes"]
INV --> PAY["EFT only<br/>participant +3 BD 12:00<br/>MO +4 BD 17:00"]
| Document | When | What it is | Can it take money? |
|---|---|---|---|
| Schedule report (own) | 14:00 D−1 | Your hours, both schedules, DAM lines | No. Preview. |
| Public prices / adequacy | 14:00 D−1 | The country’s hour-by-hour SMP | No. Information. |
| IDM schedule + prices | +1 h after each IDM gate | What moved, at what Intra-Day Price | No. Preview of IDM lines. |
| Indicative Settlement Statement | 17:00, Settlement Date + 1 working day | The month’s lines so far, for checking | No. Raising an invoice from an indicative statement is refused. |
| Initial Settlement Statement | 12:00, Billing Period + 5 working days | The billable statement | Yes — this is what the invoice is raised from. |
| Invoice | Same moment, if the participant’s net is negative (they owe) | Pay this, in full, no set-off, by EFT | Yes. Due 12:00, +3 business days. |
| Self-Billing Invoice | Same moment, if the net is positive (the MO owes them) | You raise it on the participant’s behalf and pay it | Yes. Paid 17:00, +4 business days. |
| Debit Note | If a creditor must be clawed back because someone else did not pay | The cascade | Yes. |
A statement whose net is exactly zero produces neither document. There is nothing to collect and nothing to pay.
Pay now, argue later. A Settlement Query or a dispute does not hold the invoice. The invoice engine never waits. If the query is later upheld, a correcting document follows. A participant who pays less than the invoice has not made a smaller payment — they have created a Shortfall, whatever they believe they are owed.
Where this is taught. The BRP query journey is V9 §8. The inbox on
/mo/disputeis §20. The issued register is §19. The party tax document, the Debit Note Excess, and supply-only refusal: V15 §14. A rerun or a validated dispute arrives as a note, not a replacement invoice: V15 §17.
8.2 How a party is charged — the sign on the statement
Walk one hour for one unit, then zoom out to the month.
- Energy (
EPM). Generator: positive (you pay). Load: negative (they pay). Same SMP. - Constrained adjustment. Own-offer integral. Often R 0 for a renewable that was cut.
- Reserve. Positive if the unit was held for reserve.
- IDM legs. Accrue through the day; see §9.
- Balancing. After meters. Not this volume’s subject, but they land on the same statement.
- MO Charge. Your fee, on its own pot.
- Net the month. Negative → Invoice. Positive → Self-Billing Invoice.
VAT is applied on the document, not on each line.
8.3 How parties are notified
You do not rely on a person remembering to phone.
| Channel | What travels | When |
|---|---|---|
Public API GET /dam/prices/{date} |
SMP and reserve system prices | From publication. No token. |
Authenticated API
GET /dam/schedules/{date}?tuid= |
Own volumes, constraints, DAM lines | From publication. |
Authenticated API
GET /dam/settlement/{date}?tuid= |
Own day-ahead lines | From publication. |
| Event stream | gate.closing (T−30 and T−5),
gate.extended, submission.rolled_over,
schedule.published, prices.published,
idm.cleared, statement.issued,
invoice.issued, credit-cover notices |
As they happen. |
| Indicative / Initial statements | The month’s lines, by account and kind, with the clause on each kind | On the Settlement Calendar. |
| Invoice / Self-Billing Invoice | Gross, VAT, due-at, the statement they were raised from | With the Initial statement. |
| MO Notices board | GENERAL, SYSTEM_STRESS,
PRICE_CAP_EVENT |
When you broadcast. A capped SMP hour should be visible here as well as on the price flag. |
| Credit Cover Increase / Warning | Recalculated cover | 17:00 daily when the numbers move. |
| Invalidation notice | An accepted future submission was broken by a registry change | Before the next gate. Different from a rejection: they thought they were done. |
The schedule report itself is a notification: §9.10(2) requires the settlement in it, so a BRP that fetched its schedule already has the chalkboard for that day.
8.4 What you must be able to answer
A participant will ask, in this order:
- Did you receive my bid? Which version counted?
- What was the SMP, and who set it? Was it capped?
- What was I scheduled unconstrained vs constrained, and why (which constraint)?
- Show me the
EPM, theCPP/CSC, the reserve lines. - What did the IDM then do to me?
- Where is that hour on my statement, and which invoice did it ride on?
- When is the money due, and has it been paid?
Every panel in §12–§26 exists so those seven questions have a clickable answer.
9. How the IDM touches the DAM
The Intra-Day Market does not change the DAM bid, does not change the DAM price curve, and does not change the SMP. It changes how much of the remaining day is scheduled, using the same stairs the BRP already sent, and it prices only the megawatt-hours that actually moved.
Yesterday you booked a 75-seat coach at a fare of R 900 a seat. This
morning only 20 passengers can travel. The original booking is not torn
up. A smaller auction reallocates the 55 empty seats. You still have a
75-seat booking on yesterday’s ticket (that is the EPM).
What you do about the 55 empties depends on who
cancelled. If the traffic police closed the road, you keep the
fare and pay back nothing (constrained sales at your own offer of R 0).
If you cancelled, you buy the seats back at this morning’s
price (against-instruction, Intra-Day Price flat).
Where this is taught. The BRP Intraday Desk is V9 §5. This chapter is what that desk does to your chalkboard.
9.1 What the IDM is allowed to move
Five fixed auctions, not a rolling “one hour before delivery” window.
| Iteration | Gate | Hours it may still move |
|---|---|---|
| 1 | 18:00 D−1 | The whole of D |
| 2 | 00:00 D | 01:00–23:00 |
| 3 | 06:00 D | 07:00–23:00 |
| 4 | 12:00 D | 13:00–23:00 |
| 5 | 18:00 D | 19:00–23:00 |
A re-declaration for an hour whose delivery has started is refused. It is not a late submission; it is a re-declaration of the past.
The IDM re-clears the remaining hours from the last standing schedule (DAM constrained, or the previous iteration), with updated availability and any new SO constraints. Instantaneous Reserve scheduled day-ahead is not re-optimised, except to replace what a unit has actually lost; replacements earn the day-ahead category price, not a new intraday one.
9.2 What a participant sends — not a new bid
The participant does not send a new staircase. The DAM curve stands. What they send is a new Declared Available Capacity and/or Declared Consumption for remaining hours, optionally a change to the day’s rescheduling-consent flag, and a reason. That is a re-declaration, not a re-bid. See §10.
9.3 The consent flag — the DAM bid that reaches into the IDM
idm_rescheduling_consent on the DAM
submission is the standing answer to “may the intraday auction move
me?”
| Flag | Ordinary IDM re-clear | SO imposes an additional network constraint |
|---|---|---|
Willing (true, default) |
Yes, the unit may be moved | Yes |
Non-willing (false) |
No — hold the DAM constrained schedule | Yes anyway. A participant cannot hold a corridor hostage by opting out of a security re-clear. |
The volumes look the same either way. The reason must travel with the movement: “not moved because you asked” and “moved anyway because the SO imposed a constraint” are two different facts.
The flag can also be updated for the day via
PUT /idm/rescheduling-consent/{date}/{tuid} without sending
a new DAM week.
9.4 On instruction versus against instruction
This is the most misread part of §10. The test is not what happened to the schedule. The test is whether the participant changed its own declaration.
| Schedule moved | Did the participant change its declaration? | Classification | Price |
|---|---|---|---|
| Down | Yes — reduced available capacity, or raised declared consumption | Purchase against instruction | Intra-Day Price, flat |
| Down | No — the MO / SO moved them | Purchase on instruction | The better of own offer and Intra-Day Price (they keep the good one) |
| Up | Yes — raised capacity while inflexible, or lowered declared consumption | Sale against instruction | Intra-Day Price, flat |
| Up | No, or in excess of the declaration change | Sale on instruction | The better of own offer and Intra-Day Price |
A single hour can carry both legs. A unit that raises capacity by 10 MW and is then scheduled up by 15 has 10 against (it asked) and 5 on (the market took more). Returning one tag for the hour silently overcharges the 5.
Raising capacity is against-instruction only while declared inflexible. A flexible unit that raises capacity and is scheduled up offered the market a choice; the market took it — on instruction.
Ramping spillover counts. A re-declaration at 18:00 that forces a ramp change at 17:00 makes 17:00 against-instruction too, even though nothing was declared for 17:00.
9.5 The Intra-Day Price
Volume-weighted average of the on-instruction increments only, then collared at SMP ± 5 %.
Against-instruction volumes do not enter the stack. A unit that re-declared itself down does not get to drag the price it will then be charged at.
If nothing on-instruction moved, or the signed on-instruction volumes cancel to zero, the Intra-Day Price is the SMP.
The collar is implemented symmetrically
([D-03]): [0.95 × SMP, 1.05 × SMP]. Both the
indicative (un-collared) and the applied (collared) prices are
published, plus a flag if the collar bound.
9.6 What the IDM does to DAM money
| DAM line | Does the IDM change it? |
|---|---|
EPM (unconstrained × SMP) |
No. The chalkboard for yesterday’s auction stays. |
| SMP | No. |
| DAM price curve | No. Re-used as-is. |
Constrained adjustment (CPP/CSC) |
Can be reversed, in part, if an IDM movement walks back toward the unconstrained volume. §10(15) credits the reversed portion. A unit returned all the way to its DAM constrained schedule has a net IDM position of R 0.00. |
| Reserve capacity (day-ahead) | Instantaneous Reserve is carried forward. Other categories may be re-allocated; Instantaneous replacements keep the day-ahead price. |
New money is new lines on the Market Balancing
Account (IDPM_ON, IDC_ON,
IDPM_AGAINST, IDC_AGAINST,
IDM_REVERSAL). They do not rewrite the DAM energy
account.
9.7 Should a BRP even use the IDM?
Not automatically. Re-declaring a zero-priced renewable converts a
deviation that would have been free (SO instruction, or inside the
Metering Accuracy Band) into one that costs the Intra-Day Price. The
platform’s WB.Sawem.Participant.IdmDecision answers, in
this order:
- If an SO instruction is already expected — carry. Instructed deviation settles at own offer (often R 0).
- If the deviation is inside the Metering Accuracy Band — carry. It settles at the SMP with no penalty.
- Past the band, compare
magnitude × IDPagainstmagnitude × max(balancing price, SMP)and take the cheaper.
The desk should show that recommendation beside a lodged re-declaration, because the participant will ask “should I have?”.
10. The IDM input, field by field
Two shapes share one lodgement table
(WB.Sawem.Mo.IdmLodgement). They are one decision seen
twice: what may this iteration do with my unit?
10.1 Re-declaration
PUT /v1/idm/redeclarations/2026-07-15/TU-PV1
| Field | Required | Plain meaning |
|---|---|---|
iteration |
Yes | Which of the five auctions this lodgement is for. A body sent at 11:47 is for iteration 4 (gate 12:00). Sending iteration 3 after 06:00 is a closed gate. |
periods |
Yes | Only the hours you are changing, and only hours this iteration may still move. You do not resend the whole day. |
periods[].trading_period |
Yes | The hour. Must be strictly after this iteration’s gate. |
periods[].declared_available_capacity_mw |
When generation is what changed | The new “I can produce this much”. Same MCR cap as the DAM. Omitting it means “leave the previous declaration”. |
periods[].declared_consumption_mw |
When consumption is what changed | The new “I will draw this much”. A factory that suddenly needs more raises it — and that raise is against-instruction on the purchase side. |
reason_code |
Strongly expected | A short, stable token so the desk can filter:
FORECAST_REVISION, FORCED_OUTAGE,
DERATE, FUEL_CONSTRAINT,
SOC_REVISION, LOAD_REVISION,
OTHER. The Code does not enumerate these; the platform
should. |
reason_note |
Optional | Free text. “Convective cloud, 11:30 nowcast”. Kept forever. |
What is not on a re-declaration, and must not be added:
| Absent field | Why it is absent |
|---|---|
| Price curve / cost increments | The DAM staircase stands. The IDM is not a second bid. |
flexible / reserve indicators |
Those were the DAM hour’s commitment. Changing them mid-day would be a different product. |
| Energy limits | The weekly reservoir does not get rewritten every six hours. |
| The other 20 hours of the day | Only remaining, changed hours. |
The API’s most useful response field is
estimated_classification: before the gate,
it tells the participant that this reduction will be charged at the
Intra-Day Price rather than compensated at their own offer. The price is
not known yet; the classification is deterministic from §10(6)–(9).
Last lodgement for the same
(unit, date, iteration, period, kind) wins. Two rows for
one hour would leave the clearing choosing between them.
10.2 Rescheduling consent
PUT /v1/idm/rescheduling-consent/2026-07-15/TU-PV1
| Field | Plain meaning |
|---|---|
rescheduling_consent |
WILLING or NON_WILLING. Same meaning as
the DAM boolean, restated for the day. NON_WILLING still
yields to a new SO constraint. |
reason_code / reason_note |
Why they are opting out (or back in). |
A consent has no Trading Period. It is a statement about the day.
10.3 What you add after the auction
The participant does not send these. The desk must still show them against the lodgement.
| Output | Plain meaning |
|---|---|
| Intra-Day Price, indicative and applied | The auction’s price, and whether the ±5 % collar bound. |
| On / against split | The pair of volumes, not a single tag. |
Legs (IDC_AGAINST, IDPM_ON, …) |
The money, with the clause. |
| Reversal credits | Ground this movement walked back over, negating an earlier DAM or IDM line. |
| Revised schedule | The new standing instruction for remaining hours. |
| Instantaneous Reserve carry / replacement | What was held, what was replaced, at the day-ahead category price. |
11. Worked example — Trading Day 2026-07-15, hour 18:00
Every number below is the golden fixture in SAWEM-SPEC §10. Same day, same hour, same units. If a screen or a test disagrees with this chapter, the screen or the test is wrong.
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10 /
docs/references/market/spec/market-dam.md§11.
11.1 The cast, and what they sent
Five Trading Units, plus a 20 MWh import.
| TUID | What it is | Zone | Flexibility | What it offered for 18:00 |
|---|---|---|---|---|
TU-COAL1 |
500 MW coal | — | F |
Stairs: 0–200 @ R 350, 200–300 @ R 420, 300–400 @ R 640, 400–500 @ R
900, emergency @ R 6,000. Available 500 MW. All three reserves
A. |
TU-PV1 |
75 MW solar | Z1 Northern Corridor |
I |
One step, 0–75 @ R 0. Available 75 MW. No reserve. |
TU-OCGT1 |
60 MW peaker | — | F |
Stairs from R 2,800 upward. Available. Instantaneous and Ten-Minute
A. |
TU-DIST1 |
440 MW distributor | Z6 Highveld Load |
I |
440 MW must-serve. No priced blocks. |
TU-IND1 |
90 MW factory | Z6 |
F |
40 MW must-serve; then 10 @ R 4,800, 20 @ R 2,600, 20 @ R 1,500. |
| Interconnector | Import | — | — | +20 MWh, treated as a free fixed injection. |
SO reserve requirements for 18:00: Regulating Up 15 MW, Regulating Down 10 MW, Instantaneous 20 MW, Ten-Minute 25 MW. Market Price Cap R 5,396.40. Reserve floors R 50 / R 50 / R 50 / R 0.
11.2 Door-to-chalkboard, step by step
%%{init: {"themeVariables": {"fontSize": "16px"}}}%%
sequenceDiagram
participant BRP as BRPs
participant MO as Market Operator
participant SO as System Operator
participant PUB as Public / BRP APIs
Note over BRP,SO: D−1 (14 July)
BRP->>MO: PUT DAM submissions (by 10:00)
SO->>MO: Demand, reserves (10:00)
SO->>MO: Interconnect +20 MWh (13:30)
MO->>MO: Unconstrained solve
MO->>MO: Constrained solve (Z1 export 60 MW)
MO->>MO: SMP = R 900 (TU-COAL1 at 435 MW)
MO->>PUB: Publish schedules + prices (14:00)
Note over BRP,SO: D (15 July) 12:00 — IDM iteration 4
BRP->>MO: TU-PV1 re-declares 18:00 DAC 60 → 20
MO->>MO: Re-clear remaining hours
MO->>MO: IDP indicative R 1,412.50, collared R 945
MO->>PUB: Revised schedule + IDM prices
Step 1 — intake. Each BRP’s body is validated.
TU-PV1’s single-block R 0 curve is legal.
TU-DIST1’s collapsed consumption curve is legal. Nothing is
published yet.
Step 2 — unconstrained stack, 18:00.
How the two piles are stacked, crate by crate, is §6.3. The roll-up for this hour:
Supply, cheapest first:
| Rung | Source | Block | MW | Price | Cumulative |
|---|---|---|---|---|---|
| 1 | Import | fixed | 20 | 0 | 20 |
| 2 | TU-PV1 |
0→75 | 75 | 0 | 95 |
| 3 | TU-COAL1 |
0→200 | 200 | 350 | 295 |
| 4 | TU-COAL1 |
200→300 | 100 | 420 | 395 |
| 5 | TU-COAL1 |
300→400 | 100 | 640 | 495 |
| 6 | TU-COAL1 |
400→500 | 100 | 900 | 595 |
| 7 | TU-OCGT1 |
0→60 | 60 | 2,800 | 655 |
Demand: 440 (TU-DIST1) + 40 (TU-IND1
must-serve) = 480 must-serve, then every elastic block
of TU-IND1 (all worth more than R 900). Total demand
530. Generation needed 530 − 20 = 510:
TU-PV1 75 + TU-COAL1 435.
TU-COAL1 at 435 MW is not an elbow, and the unit is
flexible → it sets the price. How that reading is done — who is thrown
out, which shelf, the cap — is §6.4.
SMP(18:00) = R 900.00/MWh. Not capped. Not
all-inflexible. Marginal unit: TU-COAL1.
Reserve: the coal set has headroom, so every lost-opportunity cost is zero. All four system reserve prices sit on their floors: R 50, R 50, R 50, R 0. Ten-Minute (25 MW) is held on the offline OCGT.
Step 3 — energy chalkboard.
How each line is written — SG × SMP, the import, the R
0.00 invariant — is §7.2. The
roll-up:
| TUID | SG (MWh) | EPM (R) |
|---|---|---|
TU-COAL1 |
+435 | +391,500.00 |
TU-PV1 |
+75 | +67,500.00 |
TU-OCGT1 |
0 | 0.00 |
| Interconnector | +20 | +18,000.00 |
TU-DIST1 |
−440 | −396,000.00 |
TU-IND1 |
−90 | −81,000.00 |
| Total | 0 | 0.00 |
Step 4 — constrained run. The SO flags
Z1 exports. TU-PV1 may inject at most
60 MW. 15 MWh moves onto TU-COAL1 (435 →
450). How those two lines are walked — own stairs, not the SMP — is §7.3.
| TUID | SG | CG | Line | Arithmetic | Amount |
|---|---|---|---|---|---|
TU-PV1 |
75 | 60 | CSC | 15 MWh × R 0 | R 0.00 |
TU-COAL1 |
435 | 450 | CPP | 15 MWh × R 900 | +R 13,500.00 |
TU-PV1 keeps R 67,500 on 75 MWh it will not all
generate. That is the R 13,500 windfall. The Market Balancing Account
pays the coal set R 13,500; the SO recovers it as an ancillary
service.
Reserve capacity: TU-COAL1 (15+10+20) × R 50 = R
2,250 → Market Balancing Account. How those four cheques are
walked is §7.5.
AEPM is absent this hour — nobody scheduled a shelf above
the cap (§7.4).
Step 5 — publish. You review both schedules, the R 0 CSC (rendered with the sentence “own offer was zero”, not as a blank), the SMP flags, and press publish. Events fire. Participants fetch. The full hour as it sits on the schedule report is §7.6.
11.3 What each party sees at 14:00 D−1
| Who | What they are told |
|---|---|
| Everyone | SMP R 900, reserve system prices, adequacy report. |
TU-PV1’s BRP |
Unconstrained 75, constrained 60, binding constraint
zonal_export_limit:Z1, EPM +67,500, CSC 0.00 (zero-priced
curve). |
TU-COAL1’s BRP |
Unconstrained 435, constrained 450, EPM +391,500, CPP +13,500, reserve +2,250, you were marginal. |
TU-DIST1’s BRP |
−440 both schedules, EPM −396,000. |
| Network Operator for Z1 | TU-PV1 constrained to 60. |
11.4 Intraday iteration 4 — the cost of changing your own mind
Heavy cloud. At 11:47 on D, TU-PV1 lodges:
- iteration 4
- 18:00 declared available capacity 20.000 (was 60 on the constrained DAM)
- 19:00 declared available capacity 0.000
- reason
FORECAST_REVISION/ “Convective cloud, 11:30 nowcast”
The API’s estimated classification for 18:00:
PURCHASE_AGAINST_INSTRUCTION, pricing basis
intra_day_price, clause 10(6)(i). The participant is told,
before 12:00, that this will not be free.
The re-clear must replace 40 MWh. Coal can rise 15 (to 465, leaving
room for the up-reserve it still holds). The other 25 come from
curtailing TU-IND1 (90 → 65) — cheaper than starting the
OCGT.
| TUID | Change vs DAM constrained | Declaration changed? | Classification |
|---|---|---|---|
TU-COAL1 |
+15 | no | Sale on instruction |
TU-IND1 |
+25 (consumption 90→65; signed energy rose) | no | Sale on instruction |
TU-PV1 |
−40 | yes (DAC 60→20) | Purchase against instruction |
On-instruction stack (only):
| Increment | ΔV | IP | IP × ΔV |
|---|---|---|---|
| Coal 450→465 @ R 900 | 15 | 900 | 13,500 |
| Factory 90→70 @ R 1,500 | 20 | 1,500 | 30,000 |
| Factory 70→65 @ R 2,600 | 5 | 2,600 | 13,000 |
| Σ | 40 | 56,500 |
Indicative IDP = 56,500 / 40 = R 1,412.50. Collar
around SMP 900 is [855.00, 945.00]. Applied IDP = R
945.00. collared? is true. Both numbers are
published.
| TUID | Leg | Rule | Price | Amount |
|---|---|---|---|---|
TU-COAL1 |
+15 on | max(own 900, IDP 945) |
945 | +R 14,175.00 |
TU-IND1 |
+20 on | max(1,500, 945) |
1,500 | +R 30,000.00 |
TU-IND1 |
+5 on | max(2,600, 945) |
2,600 | +R 13,000.00 |
TU-PV1 |
−40 against | IDP flat | 945 | −R 37,800.00 |
| MBA net | −R 19,375.00 |
11.5
TU-PV1’s running position for 18:00
| Line | Amount | Why |
|---|---|---|
DAM energy EPM |
+67,500 | 75 MWh × R 900, unconstrained, never rewritten |
| DAM constrained sales | 0 | 15 MWh × own offer R 0 — SO cut, free |
| IDM against-instruction | −37,800 | 40 MWh × R 945 — they cut |
| Net for the hour | +29,700 | For 20 MWh actually scheduled |
Effective R 1,485/MWh against an SMP of R 900. Still favourable — because the SO’s 15 MWh cut was free. Had they re-declared the first 15 themselves as well, those 15 would also have cost R 945.
That is the whole DAM–IDM relationship in one unit: the DAM pays you for the plan; the IDM charges you for changing your own mind; the SO changing it for you does not.
11.6 What happens to that hour on the till
The +29,700 does not leave a bank on 15 July. It sits on the
chalkboard with every other hour of the Billing Period. On the Initial
Settlement Statement it appears as three lines (EPM,
CSC, IDC_AGAINST) on two pots (Energy, Market
Balancing). If TU-PV1’s BRP is a net creditor for the
month, those lines ride a Self-Billing Invoice you pay four business
days after issue. If the BRP is a net debtor, they ride an Invoice due
in three.
A Settlement Query about the R 37,800 does not stop that invoice. Pay now, argue later. If the query is upheld, a correcting document follows.
Follow along. Seat:
mo@webill.net/supersecret. Path: §13.13 walks the same hour on the current Bidding tabs.
12. The sidebar — four operating groups
§§1–11 are the market from
this seat — who bids, when the bell rings, how a price is found, and how
money is written. This chapter is the current
/mo console: the map of fourteen rooms. Market Desk and
Bidding are two sidebar items and one chapter (§13); every other later chapter is one
sidebar item, tab by tab and field by field.
The Market Operator console is one application with fourteen rooms. They share a left-hand sidebar, branded SAWEM MO. Every room is a first-class route. Nothing important hides behind a second kitchen write. From here on the pages are the thing you press.
Screen: Market Operator (/mo) lands on
Bidding → Daily for the current Trading Day. Registry,
pairing and standing-data review live one click away at
/mo/registry. Fourth landing card when you sign in as MO.
This is the other side of every BRP screen in V9 §§2–8.
Follow along. Seat:
mo@webill.netwith passwordsupersecret. Path:/→ Market Operator. You land on Bidding → Daily. You should see four group headings: Market day, Settlement, Eligibility, Reference. Only the group you are working in is open — landing on Daily opens Market day and folds the other three away.
12.1 Why the menu is grouped this way
The sidebar is not an alphabet. It follows the operating clock.
- Market day — what you do before and during delivery: land, run the cadence, clear the auctions, tell the market.
- Settlement — what you do after 14:00 and at month-end: meters, stacks, the three bank accounts, queries.
- Eligibility — who may trade and where they sit: registrations, the register, generator plants, zones.
- Reference — what the arithmetic is allowed to assume: published parameters, and every immutable run.
Frequent desks sit at the top of each group. Each group is a
module row — an icon tile, the module name and a
chevron — and the row is a button: click it to open or close that
module. Its desks are indented beneath it on a hairline rail, and the
desk you are in is a solid amber chip (#mo-nav-metering,
#mo-nav-cadence, and so on). The module holding your desk
opens itself, so the chip is never hidden, and the console remembers
your open/closed shape in this browser. Collapse the whole sidebar with
the chevron and the module rows disappear: an 80 px rail of desk icons
with hover tooltips.
The action bar sits under the brand: Switch application (the squares icon) back to the landing cards, Sign out, and the chevron that narrows the sidebar.
Quick jump is the search box under it. Type and the
sidebar filters as you go — matching desks, or every desk of a module
whose name matches, with the matching modules opened for you.
Esc or the × clears it and hands the
sidebar back to your remembered shape.
Air-traffic metaphor. Market day is the tower radio for today’s flights. Settlement is the airport accounts office after the last wheel is on the ground. Eligibility is the licensing desk — who is allowed to fly, and from which runway. Reference is the published rulebook and the black-box flight recorder: you read it; you do not rewrite yesterday.
Eligibility is drawn third because that is when you notice it on a busy day. In life it runs continuously: a plant filed on Tuesday still changes Wednesday’s solve.
12.2 Shared chrome on every page
Every room reuses the same shell. Learn it once.
| Piece | What it is | How to read it |
|---|---|---|
| Brand | SAWEM MO in the sidebar; SAWEM on the page header | You are on the Market Operator seat, not a BRP book |
| Module row | Icon tile + uppercase label + chevron — Market day, Settlement, Eligibility, Reference | Click to open or close that module; the one you are working in opens itself |
| Quick jump | Search box above the modules | Filters desks and modules as you type; Esc clears |
| Page title | One noun — Bidding, Cadence, Participants | The room |
| Page description | One sentence under the title | The job of this room |
| Flash | Green info or red error after a write | Read it before you press again |
| SIMULATED ribbon | Amber strip when a Scenario Lab run is live | Lab, not the live market (V14) |
| Date / month picker | Trading day or Billing Period | Shared across Bidding tabs; Cadence, Metering and Balancing have their own |
A Trading Day is one calendar day in SAST for which the market sold energy. A Billing Period is a calendar month. They are not synonyms. Daily work picks a day; month work picks a month. Default trading date: before 10:00 SAST the picker offers tomorrow (you are still in D−1); from 10:00 it offers today. Default billing month: the previous calendar month.
12.3 Market day — the four items
Path prefix: /mo. Group heading: Market
day.
| Sidebar | Icon | Lands on | Taught in |
|---|---|---|---|
| Market Desk | computer-desktop | /mo/bidding → Daily — six tabs |
§13 · §13.5 |
| Cadence | clock | /mo/cadence |
§14 |
| Forward | arrow-trending-up | /mo/forward |
§27 |
| Notices | bell | /mo/notices |
§15 |
Market Desk is not a second workbench. It is the
landing pad. Press it and you are on Daily for the current Trading Day,
same page as Bidding. There is no hidden Market Desk
LiveView at /mo. The module named
MarketDeskLive is the Registry (§22).
Cadence is the timetable. Every Market Code §1.2 callable as due, ran or missed. Run the day and Run the month live here. A miss is a row.
Bidding is the auction room. Six tabs share one date ribbon: Daily, Submissions, IDM, Settlement, Month, Clear.
Notices is the tannoy. GENERAL / SYSTEM_STRESS / PRICE_CAP_EVENT to every participating BRP. Not a System Operator instruction (V12 §3).
12.4 Settlement — the five items
Group heading: Settlement. After 14:00 the chalkboard is done.
| Sidebar | Icon | Lands on | Taught in |
|---|---|---|---|
| Metering | signal | /mo/metering |
§16 |
| Balancing | adjustments-horizontal | /mo/balancing |
§17 |
| Accounts | wallet | /mo/accounts |
§18 |
| Billing | document-chart-bar | /mo/billing |
§19 |
| Dispute | exclamation-triangle | /mo/dispute |
§20 |
Metering is pairing and the D+7 vintage gate. Empty registry is unready, not 100 % of nothing.
Balancing is anonymised stacks, BPB/BPS, the Market Balancing Account. Official is disabled while vintage is unverified.
Accounts is the till: three market bank pots, this month’s cash, who cannot pay, cover, and the cascade. Month is a Billing Period.
Billing is the issued-documents room: register,
remittances, corrections, read-only run status. The register names the
organisation, writes the period as 1 June 2026, and shows
amounts in rands. The eye opens the stored PDF. Issuing still happens on
Cadence (§14 — Run the
month). The till is Accounts (§18).
The walkthrough is §19.
Dispute is one inbox with the org Recon: Data Query, Settlement Query, Settlement Dispute. Pay now, argue later.
12.5 Eligibility — the five items
Group heading: Eligibility. Who may bid, what they filed, where they sit, and who may stand on the carbon venue.
| Sidebar | Icon | Lands on | Taught in |
|---|---|---|---|
| Participants | building-office-2 | /mo/participants — six tabs |
§21 |
| Carbon activations | clipboard-document-check | /mo/carbon-activations |
V18 §1 |
| Registry | book-open | /mo/registry |
§22 |
| IPPs | bolt | /mo/ipps |
§23 |
| Zones | map-pin | /mo/zones — two tabs |
§24 |
Participants is two boards that are not duplicates. Registrations asks may this seat bid today? Issued Suspension Orders sit on that board as Enforcement, not as extra tabs. Accession register is the §6.2(9) publication clock. Pending Clocks (and Extension Requests, Open Default, Balancing Groups) is the joining and enforcement lifecycle.
Carbon activations is the Q3 / CTD4 queue. A
PENDING_APPROVAL carbon participant profile cannot trade,
file a pack, or raise a bill until you Activate it (or
Refuse it with a reason). Path:
/mo/carbon-activations
(#mo-carbon-activations).
Registry is Trading Units in force for tomorrow, pairing, and standing-data review.
IPPs is generator sites filed through the standing-data wizard. Certify, Chase, Suspend unit. The Market Operator does not file Trading Units.
Zones is the register in force, coverage, and sites the model cannot place. The CSV goes to the System Operator.
12.6 Reference — the two items
Group heading: Reference.
| Sidebar | Icon | Lands on | Taught in |
|---|---|---|---|
| Rules | code-bracket-square | /mo/rules |
§25 |
| Runs | play-circle | /mo/runs |
§26 |
Rules publishes the twenty-four market parameters and the eight defect switches. A new version is compose → review → confirm. There is no inline edit of the live table.
Runs is every clearing and settlement computation as an immutable record: inputs hash, parameter hash, supersedes, kind. Two runs that differ by one intended input are not the same run.
12.7 How to walk the sidebar on a working day
Do not hop at random. The safe order is eligibility first (is anyone allowed?), then intake, then solve/publish, then the afternoon desks.
Cadence is the scoreboard for the same day. Notices can go out whenever the market needs context. Rules and Runs are reference — you do not operate a day from them.
| If you need to… | Open | Not |
|---|---|---|
| See whether today’s gate closed | Cadence | Bidding’s gate chip alone |
| Inspect a received bid | Bidding → Submissions | the BRP Bid Desk |
| Solve then publish | Bidding → Daily or Clear | a second “make it look clear” button |
| Pair meters after 14:00 | Metering | Daily |
| Run official prices | Balancing (Official, vintage verified) | Daily Publish |
| See who cannot pay | Accounts | Dispute |
| Open an issued invoice PDF | Billing | Accounts cash position |
| Decide an extension | Participants → Extension Requests | Registry |
| Acknowledge the SO model | Zones | Rules |
12.8 What you will not find in the sidebar
Three rooms people look for here and that live elsewhere.
| Looking for | Where it actually is |
|---|---|
| System Operator dispatch, flags, reserve certification | /so — V12 |
| The BRP Bid Desk, Registration wizard, Recon | /org/brp — V9 |
| Scenario Lab / live meters | /org/sim — V14 ·
live meters V21
§6 |
Handbook bookmarks /mo/dam,
/mo/dam/submissions, /mo/dam/idm,
/mo/dam/settlement and /mo/dam/month are
301 redirects onto the Bidding tabs.
/mo/bid-desk is a 302 onto Daily. They are
not extra rooms.
Where this is taught. The Market Code mechanics (why SMP is one price, why the energy pot nets to R 0.00, why a query never holds an invoice) stay in V9. This volume teaches the screens that operate those mechanics.
Data. full_demo · seed 42 · stage S08 (market loop). Demo seat
mo@webill.net/supersecret. Worked Trading Day 2026-07-15.
13. Market Desk
The first item in the Market day group is
Market Desk. The path is /mo. The icon is
a signal. When you pick the Market Operator card on
/ and sign in as mo@webill.net, this is where
you land.
There is no separate Market Desk page. /mo is a
302 onto Bidding → Daily for the
current Trading Day. This chapter is the landing hop
and the six tabs you land on, so you stop looking for a
second room.
13.1 The operator’s problem
You open the console at 09:10 on a Tuesday. You need today’s (or tomorrow’s) pulse in one click: is the gate open, have the System Operator parcels arrived, has anyone solved? You do not want a dashboard of every queue. You want the chalkboard.
That is why Market Desk is a hop, not a home of its own.
13.2 What the hop does
| You typed | Handler | Result |
|---|---|---|
/mo |
BiddingRedirectController.desk/2 |
302 → /mo/bidding?date={date} |
/mo/bid-desk |
same | 302 → /mo/bidding?date={date} |
/mo?date=2026-07-15 |
same | 302 → /mo/bidding?date=2026-07-15 |
Query params are preserved: date, month,
tuid, seq, iteration,
period. If date is omitted, the default
Trading Day is used — before 10:00 SAST, tomorrow (you
are still in D−1); from 10:00, today.
Handbook paths are permanent redirects, not rooms:
| Old bookmark | Status | Lands on |
|---|---|---|
/mo/dam |
301 | /mo/bidding |
/mo/dam/submissions |
301 | /mo/bidding/submissions |
/mo/dam/idm |
301 | /mo/bidding/idm |
/mo/dam/settlement |
301 | /mo/bidding/settlement |
/mo/dam/month |
301 | /mo/bidding/month |
13.3 What you see after the hop
The browser title is Bidding. The header sentence is National day-ahead desk — gates, intake, the hourly SMP, and settlement pots. The Daily tab is active. The date ribbon shows the Trading Day the hop chose.
Read Daily as §13.7. In short: four pulse cards in two rows (Clock and gates · Intake health, then Energy and settlement · Notifications), then the Price board — status badge, Low / High / Average / Spread when a curve exists, Solve / Publish…, and the hourly SMP step chart. The energy-account pot must read R0.00 once the day is published.
After Market Desk /mo → /mo/bidding
| You pressed 1 | Address bar 2 | Active tab 3 | Date 4 |
|---|---|---|---|
| Market Desk | /mo/bidding?date=2026-07-15 | Daily | 2026-07-15 |
- 1Market Desk is the sidebar landing, not a LiveView.
- 2Address bar always shows a Bidding path after the hop.
- 3Daily is the pulse — same page as Bidding.
- 4Date in the address bar is ISO. Clock and gates shows it as 15 Jul’ 2026.
13.4 Do not confuse two names
The Elixir module WB.WheelingWeb.Mo.MarketDeskLive is
not this sidebar item. That module is the
Registry at /mo/registry (§22). The landing card still says “Market Desk”
in older copy; the sidebar item named Market Desk is the hop to
Daily.
BidDeskLive is gone. /mo/bid-desk redirects
like /mo. There is no second Clear-day button hiding behind
that URL.
Follow along. Seat:
mo@webill.net. Path:/→ Market Operator, or sidebar Market Desk. You should see/mo/biddingand the Daily tab. Change the date and you stay on Daily. Open Bidding in the sidebar: same page.
Where this is taught. The six tabs, Solve vs Publish, and the 2026-07-15 hour are §13.5–§13.13.
13.5 The six tabs
Path: Market Operator → Bidding
(/mo/bidding). Third item in Market day.
/mo and /mo/bid-desk land here on
Daily (this chapter’s hop, §13.1–§13.4).
One parent, six tabs. The date on the ribbon is shared: change it and
you stay on the tab you were on. Handbook bookmarks
/mo/dam* land on the matching tab.
This is the auction room. You inspect what arrived, you solve, you publish, you watch the five intraday patches, you read the chalkboard, you roll the month. You cannot type a price.
Where this is taught. Why a bid is 168 periods, why Solve is not Publish, and how the BRP Bid Desk produces the payload: V9 §4. Intraday mechanics: V9 §5. Day-ahead money: V9 §13. This chapter is the screen you press.
13.6 Shared chrome — ribbon and tabs
Browser title: Bidding. Header:
Bidding — National day-ahead desk — gates, intake,
the hourly SMP, and settlement pots. Icon:
hero-presentation-chart-line. Tab bar:
#bidding-tabs.
| Tab | Icon | Address | Component id | What it is |
|---|---|---|---|---|
| Daily | calendar-days | /mo/bidding |
bidding-daily |
Pulse cards + Price board |
| Submissions | clipboard-document-list | /mo/bidding/submissions |
bidding-submissions |
What arrived, what was refused |
| IDM | bolt | /mo/bidding/idm |
bidding-idm |
Five patches, anonymised stack |
| Settlement | banknotes | /mo/bidding/settlement |
bidding-settlement |
Hour chalkboard, energy pot |
| Month | chart-bar | /mo/bidding/month |
bidding-month-board |
Billing Period roll-up |
| Clear | play | /mo/bidding/clear |
bidding-clear |
G5 ledger + the same Solve |
Active tab uses tab tab-active font-semibold. Deep links
keep the date: /mo/bidding/submissions?date=2026-07-15,
/mo/bidding/idm?date=2026-07-15&iteration=4,
/mo/bidding/settlement?date=2026-07-15&period=18.
Ribbon (Bidding.Chrome.bar) is a
rounded white bar under the header, not a second page title:
| Control | Id | Shown on | What it does |
|---|---|---|---|
| Trading date | #bidding-date |
All tabs except Month | type="date". Change patches the current tab |
| Billing period | #bidding-month |
Month and Clear | type="month" |
| Gate chip | #bidding-gate |
Always | See below |
| Market Code 2.3 | #bidding-code-version |
Always | Uppercase tracking on the right |
Gate chip. Future day: DAM gate
(D−1) — open or closed, plus
#mo-gate-countdown and {n} silent. Today:
Next IDM gate (open), countdown to 10 / 12 / 14 / 16 /
18 SAST. Past: Gate closed, no countdown.
Solve is not publish. Daily, Settlement and Clear
each show both buttons, and they are the same Solve —
WB.Sawem.Cycles. On Daily they sit in the Price board
toolbar, above the chart, to the right of the day/night
key (#dam-price-board-actions). Solve is
the emerald play control. Settlement and Clear keep the pair on their
own card. After Solve the public noticeboard is still empty. After
Publish it is not.
| Control | Id | Enabled when | Flash on success |
|---|---|---|---|
| Solve | #dam-solve |
Always | Both schedules solved and settled. Nothing is published yet. |
| Publish… | #dam-publish |
Latest run is :SOLVED |
Opens confirm |
| Publish this run | inside #dam-publish-confirm |
Confirm open | Published. Every participant now settles against this run. |
| Cancel | same panel | Confirm open | Closes confirm |
Confirm copy: Publishing makes this the schedule and price set every participant settles against (clause 9.10(1)). It supersedes anything already published for this Trading Day.
Status sentence (@status.sentence):
- This day has not been solved.
- Solved, not published.
- Published at HH:MM. (SAST)
- Published.
A miss on Solve: Solve recorded a miss — a prior step is un-run or an SO input is absent (or there are no accepted submissions for this Trading Day). A miss on Publish: Publish recorded a miss — prices have not been calculated.
You cannot edit a price curve from this seat. If a curve is wrong, the BRP fixes the registry or sends a new sequence.
13.7 Daily — the pulse
Path: /mo/bidding. This is what Market Desk opens.
From md the page is two rows of two pulse
cards, then the Price board full-width underneath. Narrow
screens stack. Card titles are the ones on the screen, not the old
four-across names.
| Section | Id | How to read it |
|---|---|---|
| Pulse | #dam-daily-pulse |
Two-by-two from md. Row 1: Clock and gates · Intake
health. Row 2: Energy and settlement · Notifications and
exceptions. |
| Clock and gates | #clock-and-gates |
Badge All present / Waiting / {n} late. Date as Trading date 15 Jul’ 2026. Three SO lights. Constraint note at the foot. |
| SO inputs | #so-inputs |
Demand · Reserves · Interconnect — each a chip present / unknown / late |
| Constraint note | #constraint-binding-note |
Why constrained matched unconstrained — or how many constraints bind |
| Intake health | #dam-daily-intake |
Header Units: {n}. Expected / Received / Rolled over (unit counts, links to Submissions). Declarations received bar when expected > 0 |
| Energy and settlement | #dam-daily-money-column |
One card stacking Energy account pot, Intraday (IDM), Adequacy. Header ZAR (R) |
| Energy account pot | #dam-daily-energy-net |
The energy pot only. Chip Unpublished / Balanced / Open. Every possible reading is below |
| Intraday (IDM) | #dam-daily-idm-now |
Whether any IDM iteration has cleared. Every possible reading is below |
| Adequacy report (§9.10(4)) | #adequacy-report |
Public after publish; #adequacy-report-empty before.
Every possible reading is below |
| Notifications and exceptions | #dam-daily-exceptions |
Chip {n} notices. Risk bullets +
#notification-ledger. Below |
| Price board | #dam-daily-price-board |
Status badge, SMP stats, day/night key, Solve / Publish, step chart, status sentence. Below |
Three traffic lights. Each answers one question only: has the System Operator sent this fact yet? It is not a score of how healthy the numbers look.
Hover on a light lifts it. Each light is a row with a present / unknown / late chip on the right (check, ellipsis, or warning triangle). The lights are not links. The Clock and gates card also carries a summary badge: All present (all three green), Waiting (none late, at least one still unknown), or {n} late.
| Light | Id | Everyday name | Due |
|---|---|---|---|
| Demand | #so-input-demand |
How much the country will take | 10:00 D−1 |
| Reserves | #so-input-reserves |
How much must stand ready | 10:00 D−1 |
| Interconnect | #so-input-interconnect |
What the neighbours will send or take | 13:30 D−1 |
| State | Colour | Meaning |
|---|---|---|
| unknown | Yellow | Pigeonhole empty and the due time has not come |
| present | Green | A message is in the store — even if the box is empty |
| late | Red | Due time passed and still empty. 14:00 publication is at risk |
If the parcel arrives after the due time, the light flips to present. Late means still missing, not arrived late. The teaching of those lights is V12 §1.4.
Constraint note — three honest sentences, never an invented corridor:
- No security constraints have been published. Constrained and unconstrained will match because nothing bound — not because the network was clear.
- Published constraints are empty. The schedules matched because nothing bound, not because the network was clear.
- {n} published security constraint(s) will bind the constrained run.
Intake tiles: Expected,
Received, Rolled over. Click any to
open Submissions. Hover lifts the row. Counts are
units, not MW. The card header shows Units:
{n} (expected census). When expected is greater than zero, a
Declarations received bar shows
received / expected as a percentage. Each row is
colour-coded. What a submission is, the other three tiles, and what to
look for live on §13.8.
| Tile | Everyday name | Colour | Meaning |
|---|---|---|---|
| Expected | How many units should have sent | Sky | Census |
| Received | Who sent a declaration | Green / amber / red | Participant submissions vs expected: complete, partial, or none |
| Rolled over | Who was silent and carried forward | Amber when > 0, green at 0 | Carry-forward is amber, not alarm-red |
Energy account
On the pulse, inside Energy and settlement
(#dam-daily-money-column) — Energy, then Intraday, then
Adequacy. The inner card #dam-daily-energy-net is labelled
Energy account pot, with Three pots isolated
on the right and Must read R0.00 under the figure. The
whole card is coloured and is a link to Settlement — hover lifts it;
there is no “click through” sentence. This is only the
energy pot (EPM — scheduled unconstrained MWh × SMP). It is
not Market Balancing, not the MO Charge, and not the three pots added
together. The invariant and the arithmetic live in §7.1. Daily asks one question: does
the closed loop still close?
A chip next to the Rand figure names the state: Unpublished, Balanced, or Open.
| What you see | Colour | Chip | When | What it means |
|---|---|---|---|---|
| — | Amber (:warn) |
Unpublished | Nothing has been published for this Trading Day, or the published run has an empty settlement | There is no energy account yet. Solve without Publish does not write a net. It is not R0.00 pretending to be empty. The card still opens Settlement. |
| R0.00 | Green (:ok) |
Balanced | A published settlement whose energy lines sum to zero | The loop closed. Generators were paid what loads were charged. R0.00 is data — the energy pot nets to zero. It is not “nothing happened.” |
R{n.nn} (any non-zero, including negative
R-n.nn) |
Red (:incident) |
Open | A published settlement whose energy lines do not sum to zero | An incident. The market must not have been published in this state — settlement raises before it gets here, so a red card is a confirmation that something bypassed the invariant, not a statistic to live with. Open Settlement from the card and do not treat the day as done. |
The amount is Chrome.money: R then the
exact two-decimal figure, no thousands separator and no space
(R0.00, R13500.00, R-12.50). Zero
is Decimal equal to 0, so R0.00 and
R0.0 do not both appear — it is always
R0.00.
Daily does not show the §16(2)(g) rounding residual
or the Market Balancing net. Those sit on Settlement
(#dam-settlement-mba-net, the rounding residual on the
legacy board). Mixing this tile with Balancing or with IDM’s MBA net is
how operators invent a “total settlement” that the Code does not
have.
Intraday now
In that same stack, below Energy account pot. The inner card is
labelled Intraday (IDM). The whole
card #dam-daily-idm-now is coloured and is a link
to the IDM tab — hover lifts it. There is no Open IDM
control. This is whether the intraday market has cleared at
least one iteration for the selected Trading Day — not whether
the DAM is solved. The DAM constrained schedule stands until an IDM
iteration publishes.
| What you see | Colour | When | What it means |
|---|---|---|---|
| DAM constrained still standing. | Amber (:warn) |
No IDM day is stored, or the stored day has zero iterations | No patch has cleared. Participants are still on the DAM constrained schedule. This is the ordinary morning, and it is also a quiet afternoon if nobody moved. It is not an error. |
| MBA net R0.00 | Green (:ok) |
Iterations exist and the signed net is zero | The account neither paid out nor took in, net. A unit walked all the way back to its DAM constrained schedule has a net IDM position of R0.00 (§9). |
| MBA net R-n.nn or Rn.nn (not zero) | Sky (:info) |
Iterations exist and the account has a signed position | The Market Balancing Account’s own IDM position for the day. Negative means the account paid participants (recovered as ancillary, clause 10(17)). Positive means it took in. The golden teaching hour is −R19375.00. This is not the energy pot. |
The Rand format is the same as Energy account (R0.00,
R-19375.00). There is no third empty state — if the board
loaded, you get an MBA net, including R0.00. Click the card to open §13.9. Daily does not list
lodgements, the next gate, collars, or a per-iteration stack.
Adequacy report (§9.10(4))
In that same stack, below Intraday (IDM). The card
is coloured (hover lifts it). It is not a link. The
public daily general adequacy report. No participant names. Publish
writes it; Solve does not. Daily shows a summary, not
the hour-by-hour table. The two DOM ids are exclusive:
#adequacy-report or
#adequacy-report-empty.
Empty (#adequacy-report-empty, amber,
dashed border, warning triangle):
| What you see | Colour | When | What it means |
|---|---|---|---|
| No public adequacy report has been published. | Amber (:warn) |
No AdequacyPublication row for this Trading Date |
Participants do not yet have the public shape of the day. This is the state before Publish, and it stays the state if Publish never ran. |
Published (#adequacy-report):
The first sentence is always Public. then the stamp, then a punctuality word.
| Piece | Possible values | What it means |
|---|---|---|
| Public. | Always, when the card is the populated one | Clause 9.10(4) — this artefact is public. Daily will not show a private schedule report here. |
| Published {dd Mon yyyy, HH:MM} | SAST stamp of published_at
(Chrome.sast_stamp,
e.g. 15 Jul 2026, 13:52) |
When the Market Operator published. The deadline for “on time” is 14:00 SAST on D−1, the same clock as schedule publication. |
| On time. | Green card (:ok) |
on_time? is true — published at or before 14:00 SAST on
D−1 |
| Late. | Red card (:incident) |
on_time? is false — published after 14:00 SAST on
D−1 |
| {n} period(s) reported. | n = length of payload["periods"], or
0 if that list is missing |
How many Trading Periods the stored report covers. A normal day is
24. 0 means a row exists but carries no
periods — the report was persisted empty, not that the day has no
hours. |
| Contingency reserve is reported and never paid. | Always, on the populated card | Clause 9.1(5). Contingency is headroom after energy and reserve scheduling. It is not a settlement line. Daily states the rule; it does not print a Rand figure for it. |
Daily does not print expected demand, sent-out,
consumption, capacity available, capacity allocated to reserves, or SMP
from the payload. Those fields exist on the stored report (and on
GET adequacy). This card is the pulse: public, when, on
time or late, how many periods, contingency unpaid.
Notifications and exceptions
On the pulse, to the right of Energy and settlement.
Card #dam-daily-exceptions, titled Notifications
and exceptions, with a chip {n} notices
(n is the ledger length, including zero). Two lists:
exception bullets (risks that are true right now) and
the notification ledger (who was told what). They are
not the same list. A quiet day can have an empty bullet list and an
empty ledger.
Exception bullets — each appears only when its condition is true. All three can show together. There is no “all clear” sentence; silence is the all-clear.
| Bullet | When it appears | What it means |
|---|---|---|
| Unpublished past 13:30 on D−1 — 14:00 publication is at risk. | The selected Trading Date’s D−1 is today, SAST clock is 13:30 or later, and this day is not published | You are on the afternoon before delivery and the 14:00 publish has not happened. It does not appear when you browse a past Trading Date from a later calendar day, even if that day published late or never. It does not appear before 13:30 on D−1. |
| {n} unit(s) invalidated and awaiting resubmit. | n ≥ 1 distinct Trading Units whose last row for this
date is invalidated |
A registry change broke an already-accepted declaration and there
may be no replacement. They think they are done. Chase them before the
gate. n is the count of those units, not of versions. |
| {n} event delivery(ies) failed. | n ≥ 1 ledger rows for this date with delivery
failed |
§16(2)(f) — someone was not told. n is failed
rows, not distinct parties. The same event retried to
success stays on the ledger as a later recorded row (or
the failed row is resolved to recorded); the bullet counts whatever is
still :failed now. |
Notification ledger
(#notification-ledger) — every notice stored for this
Trading Date, oldest first. The Market Operator seat sees the full list,
including party-scoped rows. A BRP inbox only sees public rows plus rows
that name that BRP.
Empty ledger: a centred check in a green ring and
No notices have been recorded for this day. Publish has not
written schedule.published, and nothing else has been
recorded.
Populated ledger — one row per stored notice
(#notification-{id}). Four columns; every value each column
can hold:
Time
| Value | Meaning |
|---|---|
{dd Mon yyyy, HH:MM} |
SAST (Chrome.sast_stamp of occurred_at).
Same clock as Adequacy’s published stamp. |
Event (monospace). The stored event name. Daily does not rewrite it.
| Value | Meaning |
|---|---|
| schedule.published | Publish ran. One public row (Day-ahead schedule
published., clause 9.10(1)) plus one party row per
settlement party (Your schedule report is published.).
Event-delivery may write further schedule.published rows as
receipts. |
| PRICE_CAP_EVENT | A party-scoped market notice about the price cap. The named BRP receives it; a BRP that was not named does not. |
| Any other stored string | Whatever NotificationLedgers.record /
EventIncidents.deliver wrote (invalidation notices, other
§16(2)(f) types). The column is the name, not a pick-list. |
Audience
| Value | Meaning |
|---|---|
| public | Broadcast. Every participant may see it. party_id is
empty. |
| party {uuid} | Named one registration. {uuid} is that party’s id. |
| network operator | Scoped to a network operator (same naming rule as party when an id is present). |
| — | A row whose audience_kind is none of the three. Should
not appear; if it does, the store is dirty. |
Delivery
| Value | Colour | Meaning |
|---|---|---|
| recorded | Emerald | The notice was written as delivered (or a failed row was later resolved to recorded). Default for a successful Publish row. |
| failed | Red | Delivery did not land. A failed schedule.published is a
row, not an omitted success. The exception bullet
counts these. |
Daily does not show channel
(event_stream / api / notices /
statement) or failure_reason. Failed detail
lives on the event incident queue; this table is the receipt list.
Price board
Below the pulse. Card #dam-daily-price-board. Read it
top to bottom, as the screen is laid out:
- Title row. Price board plus a
status badge (
#dam-daily-price-board-badge): Not solved, Solved, not published, or PUBLISHED. Subtitle: 24-hour system marginal price (R/MWh) · daylight 07:00–18:00 SAST. - Stat cards (only when a curve exists): Low, High, Average, Spread — explained card by card below. Hidden when the chart is empty.
- Toolbar. Sun/moon key
#dam-daily-smp-day-night-legendwhen a curve is drawn (Daylight (07:00–18:00) · Night). Solve (emerald play) and Publish… on the right (#dam-price-board-actions). - Chart
#dam-daily-smp-chart(380 px). Empty sentence, or the ECharts step line#dam-daily-smp-chart-line. When the run is published and the line is drawn, a green PUBLISHED pill sits on the chart (#dam-daily-smp-published-mark). - Footer. Status sentence
#dam-daily-price-board-statuson the left; Resolution: 1 hour · Currency: ZAR (R) · Timezone: SAST (UTC+2) on the right.
There is no second card repeating the status.
Think of the System Marginal Price (SMP) as yesterday’s tomato price: one number for the whole country, for one hour. Nobody types it. The auction finds the last crate that was needed, and that crate’s price is the hour’s SMP. How the stacks are built is §6. Daily does not re-run that arithmetic. It draws the 24 hourly prices as one anonymous line, and the four cards in the header summarise those same hours.
The four stat cards
The four cards sit in the Price board header, to the right of the
title on a wide screen and under the title on a narrow one
(grid-cols-2 then sm:grid-cols-4). They appear
only when at least one hour has an SMP. If the chart is
empty they are absent — not zero. Hours with no price are dropped before
any of the four is calculated, so a one-hour teaching run still fills
the cards from that one hour.
Every Rand figure is Chrome.money: R then
two decimals, no thousands separator and no space (R900.00,
R0.00). These are not named TOU bands
(Peak / Standard / Off-peak). They are statistics of this
Trading Day’s hourly SMPs, the same numbers the step chart
draws.
What they share. All four read only the solved (or published) hours on the ribbon’s date. They do not mix yesterday. They are not energy-weighted: a cheap overnight hour and an expensive evening hour count equally, whether 50 MWh or 5,000 MWh cleared. Settlement’s hour table is where you read a single hour; these cards are the day’s envelope.
Low
Slate card. Label Low. Figure in ink. Unit line / MWh.
Low is the cheapest hour of the day — the smallest hourly SMP that was drawn. On a normal day that is a night or early-morning shelf. It is not “the off-peak tariff” and it is not a floor the auction is forced to. If every hour is the same price, Low equals High.
Read it as: the quietest the tomato stall got. A very low Low next to a very high High is a peaky day, not a data error.
High
Amber card. Label High. Figure in amber. Unit line / MWh.
High is the dearest hour of the day — the largest hourly SMP that was drawn. On the teaching day that is the evening shelf (§11 — 18:00 at R 900). It is not the Market Price Cap unless the auction actually hit the cap that hour (capped hours are badged on Settlement, not here).
Read it as: the most expensive crate that was still needed. Hover the chart’s highest shelf to see which clock hour it was; the card does not print the hour.
Average
Slate card. Label Average. Figure in emerald. Unit line / MWh.
Average is the unweighted mean of the hours that have an SMP: add those hourly prices, divide by how many hours were added. Twenty-four priced hours ⇒ sum ÷ 24. A one-hour run ⇒ that hour’s SMP. It is not the median, not a TOU “standard” band, and not MWh-weighted (a 3 000 MWh peak hour does not pull the average more than a 200 MWh night hour).
Read it as: if every hour of this day had been the same price, this is that price. Compare it to Low and High: sitting near Low means most hours were cheap; sitting near High means the expensive hours dominated the clock, not the megawatts.
Spread
Slate card. Label Spread. Figure in sky. Unit line Delta (not “/ MWh” — it is a difference of two prices).
Spread is High minus Low. A flat day is R0.00 (Low = High = Average). A peaky day is a wide Rand gap between the cheapest night shelf and the dearest evening shelf. It is not volatility, not a standard deviation, and not a TOU peak/off-peak ratio. It does not tell you how long the expensive hours lasted — only how far the top of the stairs sits above the bottom.
Read it as: how much the day’s price moved, peak to trough. Average tells you the middle; Spread tells you the height of the staircase.
| Card | How it is made | Unit line | Hidden when |
|---|---|---|---|
| Low | Minimum of this day’s hourly SMPs | / MWh | No hour has an SMP |
| High | Maximum of this day’s hourly SMPs | / MWh | No hour has an SMP |
| Average | Sum of those SMPs ÷ number of priced hours | / MWh | No hour has an SMP |
| Spread | High − Low | Delta | No hour has an SMP |
On the teaching day the evening High is R 900. Low, Average and Spread follow whatever other hours that solve produced — they are not typed; they are computed from the same curve you see.
What the four cards are not. They are not a forecast. They are not the three pots. They do not change when you Publish (the numbers were already the draft SMPs). They disappear rather than show R0.00 when there is nothing to summarise.
What you are looking at. A 24-hour step
chart drawn with ECharts. The x-axis is
Hour (SAST) (00:00 → 23:00). The
y-axis is R/MWh, from zero up. The
stroke is ink #212a34, not a coloured series. The line is a
step, not a slope: the price is flat for the whole hour, then
it jumps (or drops) at the next hour. There are no participant names, no
TUIDs, no farm labels. A public wallboard could show the same picture.
The plot is washed amber for daylight (07:00–18:00
SAST) and slate for night. Settlement’s
24-hour curve uses a tighter daylight window
(07:00–17:00).
What Daily does not draw. Capped hours and all-inflexible hours are not marked here — those badges live on Settlement’s hour table. The y-axis starts at R 0, so a day that is R 900 every hour is a flat line at R 900, not a line glued to the top of the box.
| What you see | When | How to read it |
|---|---|---|
| Badge Not solved; grey sentence This day has not been solved. inside the chart | No clearing run stored | The auction has not been run for this date. A table of zeroes would be a lie, so the board stays empty. Low / High / Average / Spread and the day/night key are hidden. |
| Badge Solved, not published or PUBLISHED; grey sentence This run has no hourly SMP to draw. | A run exists, but it has no hourly price to plot (a one-hour teaching fixture still draws a shelf) | The status sentence under the chart is the authority. Open Settlement’s hour table. |
Ink step line (#dam-daily-smp-chart-line) |
A solved run exists (even if you have not published yet) or a published run exists | Those are the SMPs on the ECharts canvas. Left → right is midnight through evening. Hover a shelf to read the hour and R/MWh. A single hour is a dot on the axes, not an empty box. |
Green PUBLISHED pill on the chart
(#dam-daily-smp-published-mark) |
The run is published and the line is drawn | Official. Same word as the title badge. |
| Sentence under the chart: This day has not been solved. | No clearing run stored | Same as the empty chart. |
| Solved, not published. | Solve succeeded; Publish has not | You can see the curve. Participants still cannot settle against it. Energy account is still — / Unpublished. Adequacy is still empty. |
| Published at HH:MM. | Publish succeeded, and the run has a SAST stamp | The curve is now the official one. HH:MM is when you
published, not when the auction ran. |
| Published. | Publish succeeded but the stamp is missing | Rare. Treat it as published. |
How to read a step. Each shelf is one Trading Period. The price holds until the next hour. If 17:00 is R 640 and 18:00 is R 900, the line runs flat, then up, then flat again. You are not looking at a smooth “demand curve”. You are looking at 24 auction results glued together.
A picture — empty, then the teaching day
Data. full_demo · seed 42 · Trading Day 2026-07-15. Demo clearing uses deterministic TOU SMP bands. Same date ⇒ same stairs.
On that teaching day the evening hour 18:00 is R 900 / MWh, set by coal’s last shelf (§11). The Price board does not write “R 900” on the line. You read shape: night lower, evening higher. Settlement’s hour table is where you read the number.
- Before Solve
Read it: no auction, no line. The board refuses to invent a price.
- After Solve (and after Publish)
Read it: each flat is an hour. The peak shelf is evening. No farm names on the line.
A few hours from the same teaching day, so you can match the peak on the sketch to a number:
| Hour (SAST) | What the board is saying | In words |
|---|---|---|
| 03:00 | A low shelf | Overnight. Cheap. The line sits low. |
| 12:00 | A middle shelf | Midday. Not the peak. |
| 18:00 | The high shelf — R 900 | Evening. Coal’s last crate set the price. Energy payments for this hour all use R 900. |
| 22:00 | Down again | After the evening peak the line drops. |
If you Solve a second time, the line is redrawn from the new run. Until you Publish, the public (participants, the adequacy card, the energy account) still treat the previous published day — or nothing — as official.
You cannot drag the line. If an hour looks wrong, the BRP fixes the declaration or the registry and you Solve again. This seat does not edit prices.
Solve and Publish
The two buttons sit on the Price board, in the toolbar above the
chart, to the right of the day/night key (#dam-solve,
#dam-publish). Solve is emerald with a
play icon. Settlement and Clear show the same pair (§13.6). One click here is
one click there.
Solve is not Publish. Solve is you running the auction in the back room and looking at the answer. Publish is you pinning that answer on the town noticeboard. Until you pin it, nobody settles against it.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 22, "rankSpacing": 28, "padding": 12}}}%%
flowchart LR
A["1. Solve<br/>run the auction"] --> B["You look<br/>Price board fills"]
B --> C["2. Publish…<br/>confirm"]
C --> D["Town noticeboard<br/>everyone settles"]
What Solve does
Solve (#dam-solve) is always on the
Price board. It does three jobs, in order, for the Trading Date on the
ribbon:
- Unconstrained clear — “If the wires could take everything, who would run?” That schedule sets the SMP.
- Constrained clear — “What may the wires actually carry?” That schedule is what injects. It does not rewrite the SMP.
- Calculate prices — write the hourly SMP (and the money lines) onto a solved run. Nothing is public yet.
If a System Operator parcel is missing and the run cannot proceed, the flash is Solve recorded a miss — a prior step is un-run or an SO input is absent. The Price board stays empty.
If there are no accepted submissions for the Trading Date, Solve is also a miss (there are no accepted submissions for this Trading Day) — it does not write an empty run and it does not fill the board with a fake flat line. Publish of a run with no hourly prices is likewise a miss, so a blank solve cannot replace a curve that was already on the noticeboard.
If it works, the flash is Both schedules solved and settled. Nothing is published yet.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 20, "rankSpacing": 26, "padding": 12}}}%%
flowchart TB
S["You press Solve"] --> U["Auction ignoring the wires<br/>this sets the SMP"]
U --> C["Auction with the wires<br/>this sets who actually runs"]
C --> P["Write a solved run<br/>still private"]
P --> Y["Price board: ink step line<br/>Badge: Solved, not published<br/>Publish… appears"]
P --> N["Energy account pot still —<br/>Adequacy still empty<br/>Participants not told"]
Worked example — you Solve 2026-07-15 at 13:10.
You are mo@webill.net. Date ribbon: 15 Jul’ 2026. Clock
and gates shows Trading date 15 Jul’ 2026. Demand / Reserves /
Interconnect are present. Badge Not
solved. Chart says This day has not been solved. There
is no Publish… button. Low / High / Average / Spread
are hidden.
You press Solve. The three jobs run. Flash: Both schedules solved and settled. Nothing is published yet.
| On Daily after Solve | What changed |
|---|---|
| Price board | The ink step line appears. Badge Solved, not published. Low / High / Average / Spread fill. 18:00 is the high shelf (R 900 in the teaching set). |
| Status sentence | Solved, not published. |
| Publish… | Now visible. Latest run is solved. |
| Energy account pot | Still — / Unpublished. Publish has not closed the energy pot for the public. |
| Adequacy | Still No public adequacy report has been published. |
| Notification ledger | Still empty of schedule.published. |
| Participant seats | They do not yet see this as the plan. |
You have a draft. You can open Settlement and read the chalkboard. You have not yet made it the plan.
What Publish does
Publish… (#dam-publish) only appears
when the latest run is solved. After a successful
publish the run is published, so the button
hides until you Solve again.
It never publishes on the first click. It opens the amber confirm
#dam-publish-confirm:
Publishing makes this the schedule and price set every participant settles against (clause 9.10(1)). It supersedes anything already published for this Trading Day.
| Control | What it does |
|---|---|
| Publish this run | Pins this solved run as official. |
| Cancel | Closes the confirm. Nothing is published. |
Publish this run then:
- Stamps the run published (SAST time on the status sentence).
- If this date already had a published run, that old run is superseded, not edited — so “why did my statement change?” still has an answer.
- Writes the public adequacy report.
- Writes schedule.published on the notification ledger (a public row plus a row per party) and tries to deliver those events.
- Makes Energy account read the published energy pot (R0.00 on a good day).
Success flash: Published. Every participant now settles against this run.
Miss flash: Publish recorded a miss — prices have not been calculated. (You pressed Publish without a solved price run.) If there is no solved run at all: There is nothing solved to publish.
%%{init: {"themeVariables": {"fontSize": "16px"}, "flowchart": {"nodeSpacing": 20, "rankSpacing": 26, "padding": 12}}}%%
flowchart TB
P["You press Publish…"] --> Q{"Confirm?"}
Q -->|Cancel| X["Nothing changes"]
Q -->|Publish this run| Y["Pin this run<br/>supersede any older published run"]
Y --> A["Adequacy card fills<br/>On time or Late"]
Y --> E["Energy account pot gets a net<br/>R0.00 Balanced or red Open"]
Y --> N["Ledger: schedule.published<br/>participants are told"]
Y --> S["Status: Published at HH:MM<br/>Publish… hides"]
Worked example — you Publish the same day at 13:40.
Status still says Solved, not published. You press Publish…, read the amber warning, press Publish this run.
| On Daily after Publish | What changed |
|---|---|
| Price board | Same step line — it was already drawn at Solve. Badge PUBLISHED. Green PUBLISHED pill on the chart. |
| Status sentence | Published at 13:40. |
| Publish… | Gone, until you Solve again. |
| Energy account pot | R0.00, green, chip Balanced. The closed loop is now the published pot. |
| Adequacy | Public. Published 15 Jul 2026, 13:40. On time. (13:40 is before 14:00 D−1.) |
| Notification ledger | schedule.published rows. Audience public and each
party. Delivery recorded if the event landed. |
| Participant seats | They now settle this day against this SMP and these schedules. |
If you had published at 14:10, Adequacy would say Late. The prices would still be published. Late is a fact about this chair, not a second button.
If you Solve again after publish, you get a new solved run. The Price board follows the new draft. The public still sits on the old published run until you Publish the new one (which supersedes).
Follow along. Seat:
mo@webill.net/supersecret. Path: Market Operator → Bidding → Daily?date=2026-07-15→ Solve → read the Solved, not published badge and the ink step line → Publish… → Publish this run. You should see badge PUBLISHED, a green PUBLISHED pill on the chart, Energy R0.00 / Balanced, and Adequacy Public.
The control table, ids, and flashes are listed once in §13.6. Daily is where you use them.
Daily /mo/bidding
| Pulse 1 | Price board 2 | Solve 3 | Publish 4 |
|---|---|---|---|
| 2×2 cards | badge · stats · ink steps | emerald play | confirm |
- 1Pulse is Clock and gates, Intake health, Energy and settlement, Notifications — two rows, not four tiles across.
- 2Price board is the status badge, Low/High/Average/Spread, then 24 anonymous ink steps. Empty until Solve. PUBLISHED on the chart after you pin it.
- 3Solve is the emerald play on the toolbar. It runs the auction in the back room. It does not pin the noticeboard.
- 4Publish needs the confirm control; then everyone settles against this run.
13.8 Submissions — silent and rejected
Path: /mo/bidding/submissions. Date on the ribbon is the
Trading Day you are inspecting. Daily’s Intake health
card is the three-number headline; this tab is the ledger behind it.
This is intake, not a second Bid Desk. You cannot type a price, add an increment, or “fix” a curve. If a declaration is wrong, the BRP sends a new sequence (before the gate) or corrects in the IDM (after). You accept, refuse, roll silence, and read what was stored.
Where this is taught. Who may submit, the three doors, why a late PUT is not stored, and why every version is kept: §4. The 168-period body, consent, idle hours, energy limits, and every validation code: §5. This section is the screen you press, and what to look for on it.
What a submission is
A submission is one registered Trading Unit’s
financially binding declaration for this Trading Day and the
following six days — exactly 168 hourly
periods. It is not “the company’s bid for Tuesday”. One BRP with five
units sends five submissions. The market clears from the
operative body: the highest submission_seq
for that unit and date that has not been invalidated.
It arrived through one of three doors (§4.2):
- Participant — a
PUTthe BRP sent (this platform’s nightly worker is still a BRP client of the same door). - Rolled over — the unit was silent at 10:00, so you generated today’s body from yesterday’s remaining horizon (§9.3(2)). You did not invent prices.
- Nothing stored — they never got in. A rejected or late attempt is not a submission. It lives in Rejected / late attempts below the table. Telling a BRP “we have nothing” when they have a 409 is an operational lie.
Accepted bodies are blind (nobody else sees the curve before the gate), binding, and replaceable until the bell. A 24-period body is refused as a horizon fault, not padded. A financially binding body without a signature is not a submission.
The main table shows one row per unit that has anything stored for the ribbon date — the newest sequence. Older sequences stay in the drawer under Version history. Solve reads the operative rows. If there are none, Daily’s Solve is a miss (there are no accepted submissions for this Trading Day).
What this tab is not. It is not the Price board, not Settlement, not the BRP Bid Desk, and not a place to publish. Filter Superseded is almost always empty on this table: the row is already the newest sequence, so “superseded” is a status you read in the drawer history, not a second row here.
Read the page top to bottom, as the screen is laid out:
- Six tiles — census, who sent, who was carried, who is broken, how many versions, who is still missing. Explained tile by tile below.
- Filters — search, source, status, CSV, and Extend (only while the DAM gate is still open). They hide rows; they do not change the tiles.
- Main table — stored declarations. Empty sentence plus jump links when this date has none.
- Rejected / late attempts — the intake audit. A 409 is a row.
- Declaration drawer — one version, read-only.
The Extend the DAM gate form is not a card on this page. It opens from Extend on the filter row, and only while the DAM gate is still open.
The six tiles
Counts are units (or versions), not MW and not Rand.
The six cards sit in one row
(#dam-submissions-tiles). Daily’s Intake health repeats
Expected, Received, and Rolled
over and links here. The other three exist only on this
tab.
Colours are the same traffic lights as Daily, plus
indigo for versions. data-tone on each card is the
authority: info sky, ok green,
warn amber, incident red,
accent indigo.
The tiles do not all add to Units expected. Received and Rolled over count only operative newest rows. An invalidated unit is covered (it has a stored body) so it is not silent — it sits in Invalidated awaiting resubmit. Before you Solve, the identity to hold in your head is:
expected ≈ received + rolled over + invalidated + silent
A leftover of one is worth a look (a newest row that is somehow superseded). A leftover of many means the census and the store have drifted.
Units expected
Tile #dam-submissions-expected. Always sky
(info). How many registered Trading Units
the market owes a declaration. This is the census, the same
Units: {n} on Daily. It does not care whether they have
sent yet.
If this is 0, the registry is empty for SAWEM — intake has nothing to count, and Solve has nothing to clear.
Received (participant)
Tile #dam-submissions-received. Unique units whose
newest stored body is operative and
Participant. They sent (or this platform sent on their
behalf). Green when this equals expected; amber when some; red when none
— same lights as Daily.
Replaces before the gate do not inflate this tile — five sequences
for TU-COAL1 still count as one unit received. The extra
sequences sit in Versions today.
Rolled over
Tile #dam-submissions-rolled. Unique units whose newest
stored body is operative and Rolled
over. Amber when this is greater than zero — carry-forward is a
look, not an incident. Zero rolled is green: everyone who is covered
sent.
A rolled row is still a real submission. Solve will use it. The BRP can still correct the day in the IDM. What you look for is staleness on the row, not the badge colour.
Invalidated awaiting resubmit
Tile #dam-submissions-invalidated. Red when the count is
above zero, otherwise green. Unique units whose newest stored body was
broken by a registry change after it was accepted. They
thought they were done. There may be no replacement.
Daily’s Notifications card repeats this as {n} unit(s) invalidated
and awaiting resubmit when the count is above zero.
Invalidation is not supersession and not a 409. Filter Status → Invalidated and open the row: the Operative? cell carries the clause-7.1(5) sentence and the codes. The participant must be told before the next gate (§8.3).
Versions today
Tile #dam-submissions-versions. Always indigo
(accent) — a count, not an alarm. How many submission
records are stored for this Trading Date — every
sequence, every unit. If Received is 40 and Versions is 40, nobody
replaced. If Versions is 90, they iterated. That is ordinary before the
gate. After the gate it is a look: who was still replacing, and did a
late PUT bounce into the rejected table instead?
Silent at last snapshot
Tile #dam-submissions-silent. Amber when anyone is
missing, otherwise green. Registered units with no stored
submission at all for this date. The ribbon’s gate chip on a
future day shows the same count as {n} silent.
Before 10:00 on D−1, silence is ordinary — they have not sent yet. After the gate, silence is the thing rollover is supposed to have filled. A number still above zero means either rollover has not run, or the unit had no previous valid body to roll (new registration, never submitted). Those units will not appear in the main table. They also will not appear in Rejected / late attempts unless they tried and failed. Filter will not find them. The tile is the list length; open Registry if you need the names.
What to look for
Walk the tiles first, then the rejected table, then the amber rows. Do not start in the drawer.
| Look for | Where | When it matters | What you do |
|---|---|---|---|
| Silent > 0 after the gate | Silent tile; gate chip {n} silent |
Rollover should already have written | Confirm Cadence ran the rollover step (§14). A unit that never had a previous body cannot be rolled — that is a participant problem, not a missing button on this desk. |
| Received + Rolled over = 0 | Received and Rolled tiles | Any time you are about to Solve | Solve will miss. There is nothing to clear. |
| Invalidated > 0 | Invalidated tile; Daily exceptions | Before the next gate | Filter Invalidated. Tell the BRP. A registry change broke a body they thought was in. |
| Rejected / late rows | #submissions-rejected |
All day, especially around 10:00 | They tried. Read Reason and Codes.
A gate_closed 409 means the rollover (if any) is what will
clear, not this PUT. A horizon fault means they sent 24 periods. A seq
conflict means they reused a sequence with a different body. |
| Staleness missed {n} gates, especially n ≥ 4 | Staleness column; drawer | Rolled-over rows | Four days is the escalation threshold: most of the horizon is now the original day 7 repeated. Each individual rollover was legal; the week no longer describes this week. Notify — §9.3(2) is not a courtesy. |
Horizon {n} / fault |
Horizon column | Any accepted row | Stored bodies should be 168. A 24-period attempt never lands here; it lands in Rejected. A fault on a stored row is a store that does not match the Code — do not Solve past it as if it were a display quirk. |
| Amber Rolled over rows | Source badge; whole row wash | After the gate, every day | Expected. Open Rollover chain if you need the dates. Do not treat amber as alarm-red. |
| Idle hours high on a thermal or demand unit | Idle hours column | After you have coverage | Idle is legal (§5.2): a solar farm at night is 24 − daylight. Twenty-four idle hours on a coal set that should have offered is a declaration of absence, not a missing row. |
| Consent non-willing | Consent column | Before IDM | Standing flag on the DAM envelope: the MO may not move them in the five patches unless the System Operator imposes a new constraint. Not an error. |
| Versions ≫ Received | Versions vs Received tiles; Seq replaced {n} times | Before the gate, curiosity; after, a look | They iterated. Open Version history for a dispute about “what did we declare at 09:12?”. |
| Empty table | #dam-submissions-empty |
Wrong date, or a date before anyone sent | Sentence: No submissions were stored for {long date}. The
table headers and CSV are hidden. Cards
#dam-submissions-jump-{ISO} under
#dam-submissions-intake are days that do
have intake, grouped Monday–Sunday — use them; do not assume the ribbon
date is empty because the market is empty. |
What you can ignore. A Participant badge. Seq 1 with no replaced note. Staleness 0. Horizon 168. Energy limits n/a on a coal or solar unit that is not energy-constrained. willing consent. Those are the ordinary healthy row.
What this tab will not show you. Capped hours, the SMP, the three pots, or who set the price — that is Daily and Settlement. Who is suspended and may not bid — that is Registry; their PUT never becomes a row here (it becomes a rejected attempt).
Filters (#dam-submissions-filters):
| Control | Id | Options |
|---|---|---|
| Search | #dam-submissions-search |
Placeholder TUID, BRP, party |
| Source | #dam-submissions-source |
All · Participant · Rolled over |
| Status | #dam-submissions-status |
All · Operative · Superseded · Invalidated |
Main table
(#dam-submissions-table):
| Column | How to read it |
|---|---|
| TUID | Link #dam-tuid-{tuid} → Registry card. The row id is
dam-unit-{tuid}. |
| BRP | Registration code, with the organisation name underneath |
| Class | Coloured badge: generation (emerald) · demand (sky) · storage (violet) · mixed (fuchsia) |
| Source | Badge Participant or Rolled over. A rolled row is washed amber — not alarm-red |
| Seq | Newest version for this date; replaced {n} times if more than one sequence exists |
| Received at | SAST stamp. That instant decides the gate, even if you later extend it |
| Consent | willing / non-willing — on the envelope, not implied from the IDM tab |
| Staleness | 0 (current) or missed {n} gates (how many times this profile has been rolled) |
| Operative? | Green tick if the newest body is operative; red cross otherwise. Hover the cross for the supersession or clause-7.1(5) sentence |
| Horizon | Sortable (#dam-sort-horizon). 168 or
{n} / fault — a 24-period attempt is not stored
here |
| Idle hours | Sortable (#dam-sort-idle-hours). Hours on this
Trading Day with zero DAC and zero DC. Night solar is expected;
a full idle thermal day is a declaration of absence |
| Energy limits | Week MWh, or n/a. dailies have slack means the seven daily caps sum to more than the week reservoir — allowed, and usual for hydro |
| Actions | Indigo clipboard View declaration, sky clock Version history, amber path Rollover chain (rolled-over rows only). Icon buttons; tooltip opens to the left |
Empty: No submissions were stored for {long date}. The table
(and its column headers) and CSV are gone. When other
dates have intake, #dam-submissions-intake lists them as
cards grouped by weekday Monday–Sunday
(#dam-submissions-intake-monday … -sunday).
Each card #dam-submissions-jump-{ISO} reads
{day} {Mon} '{yy} — 24 Aug ’26, not the ISO
date.
CSV (#submissions-csv) sits on the
right of the Search / Source / Status card, with
Extend (#dam-submissions-extend)
immediately after it while the ribbon date is today or the DAM gate is
still open. CSV is hidden when this date has no stored submissions. CSV
exports accepted and refused rows:
/mo/bidding/submissions.csv?date=…. Columns: kind, tuid,
brp, source, seq, status, received_at, reason, codes. Kind is
submission or rejected. Use this when a BRP
says they sent something you cannot see — the refused line is the
receipt.
Extend is amber, same height as CSV. It is shown
while the ribbon date is today (the chrome then reads
the next IDM gate) or still in D−1 with the DAM gate
open. Once the DAM gate chip reads closed, or the
Trading Date has passed, the button is gone and there is no
Extend the DAM gate card at the bottom of the page.
Clicking Extend opens the modal
(#gate-extension-form). Cancel, the X, the backdrop, or
Escape close it.
Rejected / late attempts
(#submissions-rejected): Time · TUID · Reason · Codes.
These are not submissions. A 409
gate_closed is a row; so is a horizon fault and a sequence
conflict. Empty: No rejected or late attempts for this Trading
Date. This is the intake audit. Row ids are
intake-audit-{id}. The TUID (when known) links to
Registry.
Extend the DAM gate (§9.3(3)) lives in that modal,
not as a card under Rejected / late. Reason, authoriser and
published_at are required. An extension is judged at
receipt — it cannot resurrect an earlier rejection.
| Field | Id | Required |
|---|---|---|
| Extends to | #gate-extends-to |
yes (datetime-local) |
| Reason | #gate-reason |
yes |
| Authoriser | #gate-authorised-by |
yes |
| Published at | #gate-published-at |
yes |
Submit: Extend gate. Success: Gate extended
under clause 9.3(3). A save without published_at
fails.
Declaration drawer
(#submission-drawer). Open from a row or
?tuid=&seq=. Branded header
(#submission-drawer-header) in Webill indigo with the amber
clipboard mark, sticky — the panel is long and the
header stays put while the body scrolls under it, so you never lose
track of which declaration you are reading. Eyebrow
Declaration, then {TUID} · seq {n}, then a
sub-line reading {Participant | Rolled over} · Trading Date {weekday
d Mon yyyy} · {received stamp} — the Trading Date is spelled out in
full, e.g. Wednesday 19 Aug 2026, because the weekday is what
tells you whether the day is a business day.
| Section | What you see |
|---|---|
| Envelope | Source, Received, Consent (IDM willing / non-willing), Staleness, Strategy run, Bid, Market rules, Signature (verified / not present) |
| Horizon day | Day 1–7 buttons; 24-block hour band
(#submission-hour-band), each block numbered by its SAST
start hour — 0 is 00:00, 23 is 23:00 |
| Pinned hour | DAC, DC, Flexible, Instantaneous / Regulating / Ten-minute reserve; production & consumption staircases. Every label carries its definition on hover; every coded letter is spelled out beside it |
| Energy limits | Week MWh + basis, or n/a — this unit is not energy-constrained. |
| Validation | Accepted against the registry at {stamp}. |
| Version history | seq · source · operative · stamp |
| Rollover chain | Dates, or This version was not rolled over from another day. |
Footer: Registry Mingen {mwh} · MCR {mwh}. Increments are not editable on this desk. Empty curves: No production curve. / Must-serve only — no priced blocks.
Nothing on this drawer is left as an abbreviation. Three affordances, and you need only one of them:
- Hover a label. Every
dtin Envelope and Pinned hour carries an information mark and a one-sentence definition — DAC gives you Declared Available Capacity — megawatts this unit says it can produce this hour. - Read the value. A coded letter is never left bare:
Fis followed by Flexible,Iby Inflexible,Aby Available,Uby Unavailable, each in a badge tinted by what it means (Iamber,Agreen,Ugrey).Stalenessreads 0 — current or 3 gates missed rather than a naked integer. - Open the legend. What these labels and letters
mean (
#submission-drawer-legend) sits under the pinned hour, collapsed. It spells out DAC, DC,F,I,A,U, the three reserve categories, Consent, Staleness, and Mingen / MCR in full — including thatIis a commitment and not a ceiling, and that anAagainst a category the System Operator certified at 0 MW is refused at intake. Use this one on a touch screen, where hovering is not available.
The F / I sentences are the same text the
BRP’s own submission desk shows, so a dispute about what was declared
cannot turn on the two seats having been told different things.
Hour-band colours. A block is one Trading Period,
addressable as #submission-hour-{h} where h is
the SAST start hour. Declared hours are split by the sun:
amber for daylight (06:00–18:00) and
indigo for night. State outranks the clock — an
inflexible :I hour stays dark grey and an idle hour stays
light grey whatever the time, so a solar unit reads as grey night
shoulders around an amber day. The pinned hour carries an indigo ring.
The legend under the band names all four. Hovering gives {HH:MM} ·
{day | night | idle | inflexible}.
Follow along. Seat:
mo@webill.net/supersecret. Path: Market Operator → Bidding → Submissions?date=2026-07-15. Read the six tiles, then findTU-PV1. Horizon 168, Source Participant, no increment form. Open View declaration. You should see seven horizon-day buttons and a 24-block hour band. Golden units:TU-COAL1,TU-PV1,TU-OCGT1,TU-DIST1,TU-IND1. Then open Rejected / late attempts — on a clean teaching day it is empty; that emptiness is the receipt that nobody bounced.
Submissions /mo/bidding/submissions
| Tiles 1 | TUID 2 | Source 3 | Rejected 4 |
|---|---|---|---|
| expected · received · silent | TU-PV1 | Participant | audit, not a bid |
- 1Tiles are the census. Silent after the gate is the first look; Received + Rolled over = 0 means Solve will miss.
- 2TUID opens a read-only drawer — no increment form.
- 3Source badges rollover in amber; it is not alarm-red. Staleness on that row is the look.
- 4Rejected / late is the intake audit. A 409 is a row. It is not stored as a submission.
13.9 IDM — five patches, no names
Path: /mo/bidding/idm. Optional
?iteration=4. Optional &period=18:00 opens
the auction drawer.
The DAM has locked tomorrow’s (or today’s) schedule. Weather and load still move. The Intra-Day Market is five short auctions that patch the remaining hours — they do not tear up yesterday’s ticket. You do not type a price here. You do not lodge a re-declaration. You watch whether the five bells rang, who asked to move, what the market actually moved, and whether the Market Balancing Account paid out or took in.
That is a different job from Daily. Daily’s Solve / Publish are the day-ahead pair. This tab has neither. The five auctions fire from the clock. Your chair is to see them, explain them, and chase a miss.
Where this is taught. What a BRP sends, why re-declaring your own capacity costs money, the ±5 % collar, and carry-versus-re-declare: V9 §5. What the IDM is allowed to move, consent, on- versus against-instruction, and why EPM and SMP do not change: §9. Daily’s pulse card is §13.7 Intraday now. This section is the screen you press, what the clock already did, and what — if anything — you still have to do by hand.
What the IDM is
The IDM is not a second day-ahead market. It is not a rolling “one hour before delivery” window. It is five fixed auctions on the Trading Day (the first of them the evening before), each of which may still move only the hours whose delivery has not started.
| Iteration | Gate (SAST) | Hours it may still move |
|---|---|---|
| 1 | 18:00 D−1 | The whole of D |
| 2 | 00:00 D | 01:00–23:00 |
| 3 | 06:00 D | 07:00–23:00 |
| 4 | 12:00 D | 13:00–23:00 |
| 5 | 18:00 D | 19:00–23:00 |
Iteration 4 is the golden-hour gate: 18:00 can still move; after 18:00 it cannot. The 18:00 SAST bell is both iteration 5 for today and iteration 1 for tomorrow.
A re-declaration for an hour whose delivery has started is refused. It is not a late DAM submission; it is a re-declaration of the past.
What a participant sends is a patch, never a new staircase. The DAM price curve stands. They change Declared Available Capacity and/or Declared Consumption for remaining hours, optionally the day’s rescheduling-consent flag, and a reason. You cannot re-price mid-day. If you could, you could watch the stack form and then move the price you are about to be paid at.
The IDM re-clears the remaining hours from the last standing schedule (the DAM constrained schedule, or the previous iteration), with updated availability and any new System Operator constraints. Instantaneous Reserve scheduled day-ahead is not re-optimised except to replace what a unit has actually lost; replacements keep the day-ahead category price.
What the IDM does not change. The DAM bid. The DAM
price curve. The SMP. The energy-account pot (EPM). New
money is new lines on the Market Balancing Account. A
unit walked all the way back to its DAM constrained schedule has a
net IDM position of R 0.00.
What this tab is not. It is not the BRP Bid Desk. It is not Daily’s Price board. It is not Settlement’s chalkboard. It is not a place to Solve or Publish the day-ahead run. Filter All vs Iteration n hides rows and stacks; it does not re-run an auction.
How it is managed
The IDM is a clocked market, not a button on this tab. Compare that with the DAM, where you (or Cadence Run the day) must Solve and then Publish. For the IDM, the five gates fire whether you are looking or not. Your job is to confirm they did, and to read the result.
What the clock already does
These run in the background. You do not press them on
/mo/bidding/idm.
| What | When (SAST) | What it does | Where you prove it |
|---|---|---|---|
Clear each IDM auction
(:clear_idm) |
18:00 D−1, then 00:00 / 06:00 / 12:00 / 18:00 D | Screens lodgements for that iteration, re-clears remaining hours, collars the Intra-Day Price at SMP ± 5 %, writes MBA lines, records the iteration | Cadence ledger, callable :clear_idm with
/iteration. A miss is a rose row, not a missing stack |
| Screen late / past-hour patches | Inside that clear | A lodgement for a closed hour is rejected (or belongs to the next gate). The clear does not lodge | Cadence outcome carries accepted / rejected counts |
| This platform’s BRP patches | The same five bells | The BRP worker lodges a re-declaration when the Bid Desk’s carry / re-declare decision says so. It writes a TUID patch, not a book-level bid | Lodgements on this tab |
| External BRP patches | Any time before the iteration’s gate | PUT through the same door the Bid Desk uses |
Same lodgements table. A 409 is not a lodgement |
| Standing DAM body | Always, until patched | Price curves, technical parameters, availability carry into every iteration automatically | You will not see a “copy bid” control. There isn’t one |
| Consent hold | At re-clear | A non-willing unit is not moved in an ordinary IDM re-clear | Consent table. The volumes look the same either way; the reason must travel |
| SO security override | When the System Operator imposes an additional network constraint | A non-willing unit moves anyway. A participant cannot hold a corridor hostage | Consent column SO override reads
overridden |
| Collar | At price formation | Indicative IDP (on-instruction average) is clamped to
[0.95 × SMP, 1.05 × SMP]. Against-instruction volume does
not enter the stack |
Period line: indicative → applied, collared badge when they differ |
| Reversals | Later iteration undoes an earlier movement | Earlier IDM charge is credited for the part that was undone (§10(15)) | Per-iteration {n} reversal(s); kinds table
IDM_REVERSAL |
| Quiet iteration | Gate fires, nothing on-instruction moved (or signed on-instruction volumes cancel) | The Intra-Day Price is the SMP. The DAM constrained schedule still stands | Board populated, stack empty or net zero, Daily card may still read DAM constrained still standing if no iteration has been stored |
Prerequisite the clock cannot invent.
:clear_idm needs a published day-ahead
run. If you have not Published the DAM, the auction is a recorded
miss (dam_not_published, clause 10(1)) —
not a skipped healthy day, and not an empty sentence pretending the gate
never came. Iteration 1 at 18:00 D−1 is the first that can bite: Publish
is due 14:00 D−1. Four hours is plenty; it is also
enough to miss if Solve never ran.
Run the day does not run the IDM. Cadence
Run the day walks gate → rollover → unconstrained →
constrained → prices → publish. It stops there. The five
:clear_idm rows are a different timetable. Do not read a
green Run the day as “the patches ran”.
18:00 SAST is two auctions. The same clock fires iteration 5 for today (hours 19:00–23:00) and iteration 1 for tomorrow (the whole of D+1). Cadence on today’s date shows iteration 5; Cadence on tomorrow’s date shows iteration 1. They are not the same row.
What you still do by hand
There is no Clear IDM and no Publish IDM on this tab. The operator actions that remain are these.
| You do this | Where | When | What it is not |
|---|---|---|---|
| Publish the DAM | Daily (or Cadence Run the day) | By 14:00 D−1, before 18:00 iteration 1 | Not an IDM button. Without it every later :clear_idm
misses |
| Watch the five rows | Cadence | After each gate, and if Daily’s IDM card stays amber into the afternoon | Not “open IDM and press play”. :clear_idm
ran / missed is the proof |
| Read this tab | /mo/bidding/idm |
After an iteration has been published for the ribbon date | Not a control. Filter, open a stack, read lodgements |
| Explain a movement to a BRP | Lodgements + Consent + Cadence; not the stack | When they ask “why was I moved?” | The stack has no TUID. Naming a rung would publish their offer |
Chase dam_not_published |
Daily → Publish, then wait for the next gate (or internal
POST /api/v1/internal/cycles/clear_idm) |
Cadence :clear_idm is missed with that
reason |
Re-Publishing the DAM does not resurrect a missed iteration by itself |
Retry a failed idm.cleared
delivery |
Cadence Event-delivery incidents | A participant’s event stream dropped the publication | Retry is not a re-clear |
| Take a new SO constraint | The System Operator’s feed, then the next IDM gate | A corridor appears after 14:00 | You do not type the constraint on this tab. The next re-clear
consumes it; non-willing units may show overridden |
What you must not do from this chair
- Lodge a re-declaration for a unit. That is the BRP’s Bid Desk (or
their
PUT). Doing it from the MO console would be writing their patch. - Change consent. The standing flag travelled on the DAM envelope; a
same-day update is a participant
PUT. - Re-price an increment. The DAM stairs stand.
- Treat Daily Solve as an IDM clear. Solve is unconstrained then constrained for the day-ahead run.
- Add Daily’s energy pot to
#idm-account-netand call it “total settlement”. They are different accounts (§13.7).
Publish within the hour (clause 10(5)). The Code
obliges the revised schedule and the Intra-Day Price to be published
within one hour of clearing. Clearing
records the iteration; the board you are reading is the
published day. There is no Publish IDM
control on this screen — unlike Daily, where Solve and Publish are two
buttons on purpose. If Cadence shows :clear_idm
ran and this board still says No intraday iteration
has cleared for this Trading Day, the run is recorded and not yet
on the published board. That is a Cadence / Runs finding. It is not a
missing play button here. Internal automation may POST
:clear_idm at
/api/v1/internal/cycles/clear_idm (operator / internal
party header; a participant token is 404 — V13).
How you work a day — five pictures
These are the days you will actually have. Each one says what the clock already did and what you do.
1. Ordinary morning — nobody has patched yet
Ribbon date is today. Iteration 1 rang last night;
maybe it moved nothing. Daily’s IDM card is amber: DAM constrained
still standing. This tab: #idm-board-empty — No
intraday iteration has cleared for this Trading Day. Lodgements
empty. Consent empty.
Clock. Iteration 1 cleared (or missed). If it cleared with zero on-instruction movement and was not published, you still see the empty sentence. Participants are on the DAM constrained schedule. That is the ordinary morning. It is also a quiet afternoon if nobody moved. It is not an error.
You. Confirm Cadence :clear_idm /1
ran (or is still pending if you opened
the page at 17:00 D−1). Do not invent a clearing from the empty
sentence. Click Daily’s IDM card only when you want this tab — there is
no Open IDM control.
2. Cloud at 11:30 — iteration 4, the teaching hour
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00. Seat:
mo@webill.net/supersecret.
Heavy cloud. The solar farm re-declares from 60 MW to 20 MW before the 12:00 gate (iteration 4 can still move 13:00–23:00, including 18:00).
Clock. The BRP worker (or their PUT)
lodged the patch. At 12:00 :clear_idm /4 screened it,
re-cleared remaining hours, built an on-instruction stack from the units
the market moved, averaged those offers to an
indicative IDP, and collared it at SMP + 5 %.
You. Open
/mo/bidding/idm?date=2026-07-15&iteration=4.
| What you should see | Why |
|---|---|
| Applied IDP R 945, badge collared | Indicative wanted R 1,412.50; SMP is R 900; ±5 % pulls it to R 945 |
Stack of increment prices and ΔV, no
TU- |
An increment price is the unit’s offer. Naming the rung
would publish every cost curve to whoever can read /mo |
| MBA net not the energy pot | The farm’s IDM charge is −R 37,800 (40 MWh × R 945). EPM on Settlement is still 75 × R 900 = R 67,500 |
Lodgement for TU-PV1, new DAC 20,
reason (cloud) |
The named fact lives here, not on the stack |
| Estimated / Cleared columns filled | Classification: purchase against instruction (they changed their own declaration) |
Σ check: 67,500 − 0 − 37,800 = 29,700 — the farm keeps R
29,700 for the 20 MWh it actually generates. Constrained-off at a zero
offer was free; this re-declaration was not. That arithmetic is §9.4 and V9
§5.2. You are here to see that it happened, not to
key the 20 MW.
Follow along. Path: Market Operator → Bidding → IDM
?date=2026-07-15&iteration=4. You should see collared, R 945, a stack with prices and volumes and noTU-PV1. Then open Lodgements and find the named patch.
3. Publish never ran — iteration 1 is a miss
It is 18:05 D−1. Daily still says This day has not been
solved (or Solved, not published). Cadence
:clear_idm /1 is missed, reason
dam_not_published.
Clock. The worker fired on time. It refused to invent a day-ahead schedule. That refusal is the row.
You. Publish the DAM (Daily
Publish…, after Solve). The missed iteration does
not auto-replay. Internal automation can POST
:clear_idm for that iteration once the DAM is published;
this tab still has no button. Until a later iteration (or a manual
callable) succeeds, participants stay on whatever DAM schedule you
eventually publish — which at 18:05 D−1 you have not.
This is the one miss you can cause from the DAM chair. Four hours after 14:00 is not “the IDM is broken”; it is “you never pinned the noticeboard”.
4. Non-willing, then the System Operator moves them anyway
A thermal unit set idm_rescheduling_consent to
non-willing on the DAM envelope (or updated it for the
day). Iteration 3 re-clears. The ordinary IDM must hold
their DAM constrained schedule. The Consent table shows the flag and a
reason. SO override is blank.
Later the System Operator imposes an additional network constraint.
Iteration 4 re-clears with that constraint. The same
unit moves. Consent SO override reads
overridden.
Clock. Consent hold and SO override are both automatic. You did not tick a box.
You. When the BRP phones: the volumes look the same
either way. The sentence that must travel is “not moved because you
asked” versus “moved anyway because the SO imposed a constraint”. Read
#idm-consents-table, not the anonymised stack. The stack
will not name them.
5. Lodged, screened, not cleared
A BRP sends a patch for 18:00 at 18:01. Iteration 5’s gate has shut; 18:00 is an hour whose delivery is beginning. The lodgement is rejected as a re-declaration of the past. It may appear as a refused attempt in their API. It is not a stored DAM submission, and it is not a row this auction will move.
Clock. Screening is inside :clear_idm.
You do not moderate a queue.
You. If they say “we sent it”, check the timestamp against the gate, then Cadence rejected counts. Do not “accept it from the console”. There is no such control.
The screen, top to bottom
Read it in this order. The ribbon date is the Trading Day you are inspecting. Daily’s IDM card is the one-line pulse; this tab is the ledger behind it.
- Iteration filter — which of the five bells, or all of them.
- Cleared board — MBA net, per-iteration movement, per-hour IDP and stack, kinds table. Empty sentence when nothing is published.
- Lodgements — named patches. Can have rows while the board is still empty (they lodged; the auction has not published).
- Consent — standing flags and SO override.
- Auction drawer — one iteration × one hour, still anonymised.
Iteration filter
#idm-iteration-tabs. All, then
Iteration 1 … Iteration 5
(#idm-iteration-all, #idm-iteration-1 …
#idm-iteration-5). The active chip is indigo. This is a
filter, not a run control. It patches
?iteration=n (or drops the param for All). Lodgements
follow the filter; Consent is the day’s standing flags (not per
iteration).
Cleared board
Empty (#idm-board-empty): No intraday iteration has
cleared for this Trading Day. Honest. A zero table would look like
“the market moved nothing and netted R 0.00”, which is a different fact
— and that fact only exists once an iteration is on the published
board.
When populated (#idm-board):
| Piece | Id / where | How to read it |
|---|---|---|
| Market Balancing Account | #idm-account-net |
The account’s own IDM position for the day. Negative means the account paid participants out. Recovered by the System Operator as an ancillary service (clause 10(17)). Not the energy pot. Golden teaching net −R 19,375.00 on Daily’s card; this board shows the same account |
| Per iteration | heading Iteration {n} | {moved} unit-periods moved · {lines} lines · {reversals} reversal(s) plus that iteration’s MBA net |
| Per period | {HH:MM} line |
indicative {R} → applied {R} · SMP {R}.
collared when applied ≠ indicative. Hours with basis
NO_CHANGE are omitted — the board is the hours that
moved |
| Stack | #idm-stack-{iter}-{HH:MM} |
Increment price · ΔV (MWh). On-instruction increments only (clause 10(10)) — anonymised, because an increment price is the unit’s own offer. Sorted cheap to dear |
| Kinds table | #idm-board-kinds |
Line kind · Clause · Lines · Total. These are MBA kinds
(IDPM_ON, IDC_ON, IDPM_AGAINST,
IDC_AGAINST, IDM_REVERSAL, …), not
EPM/CSC |
The stack never shows a TUID. That is the point. If you need the name, it is in Lodgements.
Lodgements
#idm-lodgements-table (inside
#idm-lodgements-scroll). One row per stored
re-declaration for the filter. The header and
TUID / BRP column stay put while you scroll. Rows
highlight on hover (pointer cursor). Empty: No re-declarations were
lodged for this filter.
| Column | How to read it |
|---|---|
| Iteration | Which gate they aimed at |
| TUID / BRP | Sticky left. TUID, then BRP code, then the organisation name under
the cell (#idm-lodge-org-{id}). This is the column the
stack refuses to have |
| Period | Sortable (#idm-sort-period). SAST clock of the hour
patched. Default ascending |
| New DAC / DC | The patch — available capacity / declared consumption. Amounts are
bold (#idm-dac-{id}) |
| Reason | Code; the sentence is on title |
| Estimated | #idm-estimated-{id} — classification headline
before the auction (what they asked). The MWh amount is
bold |
| Cleared | #idm-cleared-{id} — what the auction did with it. The
MWh amount is bold |
| Consent | Willing / non-willing on that lodgement |
Lodgements without a published board are still lodgements. Do not
tell a BRP “we have nothing” because #idm-board-empty is
showing; look here first.
Consent
#idm-consents-table. Heading Consent.
Empty: No standing consent changes for this day. (The DAM
envelope’s flag can still be non-willing with no row here — a same-day
change is what this table lists.)
| Column | How to read it |
|---|---|
| TUID | Named |
| Consent | WILLING / NON_WILLING |
| Reason | Why they changed the flag |
| SO override | #idm-override-{id}. overridden when a
non-willing unit still moved. Blank is blank — not an em-dash pretending
at a value |
Auction drawer
#idm-auction-drawer when the URL has both
iteration and period
(e.g. ?date=2026-07-15&iteration=4&period=18:00).
Click a period on the board. Close returns to the IDM tab without the
period param.
| Field | What it is |
|---|---|
| Title | Iteration {n} · {HH:MM} |
| Indicative IDP | Un-collared on-instruction average |
| Applied IDP | What they are charged at, with collared when the cap bound |
| SMP | That hour’s day-ahead System Marginal Price — the collar’s centre |
| Basis | Why this hour has a price at all |
On-instruction stack
(#idm-auction-stack) |
Same anonymised rungs. Subtitle: Price and volume only — a rung is an offer. |
There is no TUID in the drawer either.
IDM /mo/bidding/idm
| Iteration 1 | IDP 2 | Stack 3 | Net 4 |
|---|---|---|---|
| 4 · clocked | R 945 collared | prices · MW · no TUID | MBA, not EPM |
- 1Iteration is one of the five gates. The clock clears it. There is no Solve on this tab.
- 2IDP shows indicative and applied when collared.
- 3Stack has no TUID. Named patches live in Lodgements.
- 4Net is the IDM account, not the energy pot. Publish the DAM by 14:00 or iteration 1 misses.
13.10 Settlement — the chalkboard
Path: /mo/bidding/settlement. Date on the ribbon is the
Trading Day whose money you are reading. Optional
?period=18:00 opens that hour’s lines in the drawer.
Daily’s Energy account pot is the one-number pulse. This tab is the chalkboard behind it: every hour’s price, who set it, the energy lines that must sum to R 0.00, the constrained-schedule charge when the wires cut a unit, and the party totals that will ride the month. You do not type a price here. You do not send a bid. You Solve (the same auction as Daily), then you read.
Where this is taught. The three pots,
EPM = SG × SMP, constrained adjustment, why energy must print R 0.00, and why that is not the invoice: §7. Daily’s pulse card: §13.7 Energy account. Solve’s three jobs (unconstrained, constrained, prices): §13.7 Solve and Publish. This section is the screen you press, how to read it, and when Solve is allowed — including after the DAM gate has closed.
What Settlement is
Settlement, on this tab, is the commercial settlement of the hour — volumes × prices, signed, tagged with an account. It is computed with the clear. It becomes the official chalkboard when you Publish (by 14:00 SAST on D−1). It is not the month’s invoice. The till is Month and §8.
Think of it as the school chalkboard after the auction, before anyone goes to the bank:
- Every accepted MWh that hour trades at one system price (the SMP).
- Generators are paid what loads are charged. That closed loop is the
Energy pot (
EPM). Across the market it must read R 0.00. - If the wires then cut a unit, that cut is a different
line (
CSC/CPP) on the Market Balancing pot. It does not rewrite the SMP and it does not have to net to zero. - The Market Operator’s own fee (
MO Charge) is a third pot. It is usually empty on this day-ahead screen until the month.
What this tab is not. It is not Submissions (who
sent a body). It is not Daily’s Price board (the ink step line). It is
not the IDM stack (patches do not rewrite EPM). It is not
Accounts, Metering, or Dispute. A Settlement Query about a line does not
live here.
The only action you press to fill a draft is
Solve (#dam-solve) — emerald, play icon,
on the top row beside the status sentence
(#dam-settlement-actions). It is the same
WB.Sawem.Cycles run as Daily. After a successful Solve,
Publish… appears next to it when there is a solved run
to pin; it is not a second auction. Until you Publish, participants
still settle against the last published run — or against nothing. There
is no Solve card at the bottom of the page.
What it displays
Top to bottom, in reading order.
Status sentence
(#dam-settlement-status) sits on the top
row, with Solve (and Publish…
when a run is solved) on the right. There is no second copy of the
sentence on a footer card.
| Sentence | Meaning |
|---|---|
| This day has not been solved. | No run. Tiles are empty. Hours table is empty. |
| Solved, not published. | You have a draft chalkboard. The public energy pot is still —. |
| Published at HH:MM. (SAST) | This run is official. The energy pot is allowed to show R 0.00. |
| Published. | Official, without a stamp on the latest row. |
Summary tiles (#dam-settlement-tiles):
one coloured row of five (grid-cols-5).
White cards with a left-edge accent (emerald / sky / indigo / emerald /
amber). Tones still follow Daily’s traffic lights
(data-tone).
| Id | Label | What it is showing | Empty |
|---|---|---|---|
#dam-settlement-energy-net |
Energy Account Net | Signed sum of energy lines for the published day.
Badge Balanced at R 0.00. Details
(#dam-settlement-clause-981) opens the §9.8.1 note. |
— until Publish. Solve alone does not write this tile. |
#dam-settlement-mba-net |
Market Balancing | The MBA position for the published day — constrained adjustments, reserve capacity, later IDM money. Not the energy pot. | — / R 0.00 from the published board |
#dam-settlement-mo-charge |
MO Charge (Day) | The Market Operator fee pot. Hint: Usually empty until month-end. | R 0.00 |
#dam-settlement-hours |
Hours Published | Count with a / 24 hrs suffix and a completion bar.
Counts published hours, not draft hours on a
solved-but-unpublished run. |
0 / 24 |
#dam-settlement-smp |
SMP Price Range | min – max of hourly SMPs. Badge Peak Spike when max is above R 1 000. | — when there are no hour rows |
Day-ahead Settlement Clearing
(#settlement-board) is the published confirmation board.
Empty (#settlement-board-empty): Nothing has been
published and settled for this Trading Day. When published,
Energy Account Residual, §16(2)(g) Rounding
Residual, and the kinds table
(#settlement-board-lines) sit on one row.
Market Balancing is the tile above, not a fourth residual.
24-hour Market Price Curve
(#dam-settlement-curve, chart
#dam-settlement-smp-chart): SMP as an amber line against
Σ|SG| as sky bars. Hidden until there are hour rows. The plot reuses the
Strategy Chart day/night wash: amber daylight 07:00–17:00
SAST, slate night. The sun/moon key
(#dam-settlement-smp-day-night-legend) sits just above the
canvas. The SMP / Σ|SG| series legend is centred on the
plot, a little below the top. The peak markPoint on the SMP
curve uses white label text so it stays readable on the
brown pin.
Hours table
(#dam-settlement-hours-table inside
#dam-settlement-hours-scroll). Sticky column headers
(thead.sticky). Search
(#dam-settlement-hour-search) and a Peak / Binding filter
(#dam-settlement-hour-filter). Export CSV
(#dam-settlement-export-csv) downloads the visible rows.
Each header has an info icon
(#dam-hours-hint-{period,smp,marginal,sg,epm,csc,binding});
hover opens the tip to the right. One row per Trading
Period (#dam-hour-{HH:MM}). Peak hours (SMP > R 1 000)
highlight amber. Click a period to open the drawer
(?period=).
| Column | How to read it |
|---|---|
| Period | SAST clock label (18:00) |
| SMP | That hour’s one system price. Badge capped (red) if the cap bound; all-inflexible (grey) if every unit was inflexible and SMP printed R 0.00 |
| Marginal unit | Official name of the unit that set the price, with the organisation under it, or —. Amber [D-08] {counterfactual R} when a Demand Side Unit would have set the SMP and the default switch forbids it |
| Σ |SG| | Gross unconstrained scheduled MWh that hour (absolute). Header and values are centred |
| EPM | Energy-payment total for the hour. Header and values are centred |
| CSC | Constrained-schedule charge total for the hour. Header and values are centred |
| Binding | Constraint ids that bound the constrained run; empty if none. Each
id is a coloured badge (data-constraint):
declared_capacity sky,
declared_consumption amber, security ids
(zonal_export_limit:… and other kind:id atoms)
indigo, other known grounds (ramp, mingen, inflexible, …) each their own
chip, unknown ids slate and still readable |
Charges that will ride the month and
Notifications
(#dam-settlement-notifications) sit on one
row (#dam-settlement-lower). Charges empty: No
party totals until the day is solved. Columns:
Party · EPM ·
Constrained (CPP minus CSC) ·
Reserve · IDM. These are named
parties. They are not the anonymised IDM stack. IDM money here is MBA
kinds, not a rewrite of EPM. Notifications empty: No
notices have been recorded for this day. Columns: Time · Event ·
Audience · Delivery.
Hour lines drawer (#hour-lines-drawer,
table #dam-hour-lines): branded header
(#hour-lines-drawer-header). Every settlement line for that
hour. Kind (label + clause) · TUID
(unit official name, with the organisation under it) ·
Qty (two decimal places) · Price ·
Amount. Column headers stay sticky in
#hour-lines-scroll. Rows highlight on hover. A CSC of
R 0.00 is not a blank — it carries a sentence: own
offer was zero, no day-ahead price submitted, or
constrained-schedule charge is R0.00.
How to read it
- Status sentence first. Unsolved means there is no chalkboard yet — do not treat — as R 0.00.
- Energy account net. After Publish it must be R 0.00. After Solve only, this tile stays —; look at the Hours table for the draft instead.
- Hours published.
24 / 24is a published day.0 / 24with a full Hours table is a draft you have not pinned. - SMP range against Daily’s Price board. They are the same hours. Capped and all-inflexible badges live here, not on Daily’s chart.
- Click 18:00 (or the hour you care about). Read Kind
/ TUID / Qty / Price / Amount. Check that
EPMuses unconstrained MWh × SMP, and that a wire cut shows asCSC, not a quieter SMP. - Party rollup for “who will see this on the month”.
- Notifications last — who was told, not what the money is.
| Look for | Where | When it matters | What you do |
|---|---|---|---|
| Energy tile — after you thought you were done | #dam-settlement-energy-net |
After Solve, before Publish | You have a draft. Publish… is beside the status sentence. |
| Energy R 0.00 | Same tile; #energy-residual |
After Publish | The loop closed. This is data, not “nothing happened.” |
| Energy R{n.nn} (not zero) | Same | After Publish | Incident. Do not treat the day as done. |
| Hours 0 / 24 with a filled table | #dam-settlement-hours vs the table |
Solved, not published | Draft. Pin it if this is the plan. |
| capped on an hour | Hours · SMP | Scarcity / cap bound | Expected as a flag; also on Notices as a price-cap event when you broadcast. |
| all-inflexible | Hours · SMP | Every unit inflexible | SMP is R 0.00 that hour. Not a missing price. |
| [D-08] amber | Marginal unit | Demand-side would have set SMP | Counterfactual is shown; the published SMP followed the switch. |
| CSC R 0.00 with a sentence | Drawer | Zero-priced offer or deemed no price | Read the sentence. Do not “fix” a blank. |
| Party totals empty | No party totals until the day is solved. | Unsolved | Solve first. |
| MBA net mixed into Energy | Two different tiles | Any time | They are different pots (§7.1). |
What you can ignore. MO Charge at R 0.00 on a Trading Day. A rounding residual of a few cents next to an energy residual of R 0.00. An empty notifications list on a quiet morning.
Solve
Solve (#dam-solve) is the only control
that runs the auction from this tab. It sits beside the
status sentence (#dam-settlement-actions). There is no
“gate still open” grey-out.
It does the same three jobs as Daily, in order, for the ribbon date:
- Unconstrained clear — who would run if the wires could take everything. This sets the SMP.
- Constrained clear — what the wires may actually carry. This sets who injects. It does not rewrite the SMP.
- Calculate prices — write the hourly SMP and the money lines onto a solved run.
Success flash: Both schedules solved and settled. Nothing is published yet. The Hours table and party rollup fill from that draft. The public energy tile stays — until Publish.
A miss does not write an empty run:
| Miss flash | Typical cause |
|---|---|
| Solve recorded a miss — there are no accepted submissions for this Trading Day. | Nobody stored a 168-period body (and rollover has not written). |
| Solve recorded a miss — this Trading Day has no hourly periods to clear. | The date has no Trading Periods. |
| Solve recorded a miss — a prior step is un-run or an SO input is absent. | Cadence order or a System Operator parcel the run still needs. |
You cannot edit a curve from this seat. If an hour looks wrong, the BRP fixes the declaration or the registry and you Solve again. A second Solve redraws the draft. Until you Publish, the last published chalkboard (or nothing) remains official.
When you may Solve
The DAM gate closing is not a lock on Solve. The gate is when intake stops (§13.8). The auction is meant to run after that bell.
| Clock | May you press Solve? | What you are looking at |
|---|---|---|
| Before 10:00 D−1 — DAM gate still open | The button works. This is a rehearsal. | The stack is still moving. A later PUT is not in this run until you Solve again. Rollover has not yet written silent units. Do not Publish this as the day’s plan. |
| After 10:00 D−1 — DAM gate closed | Yes. This is the intended window. | Intake is frozen (unless you extended the gate). Rollover should have written. Demand and reserves were due at 10:00. You Solve, read this chalkboard, and Publish by 14:00. |
| After 14:00 D−1, or on the Trading Date itself | Still allowed. It does not reopen the DAM gate. | A new solved run. Participants still settle on the last published run until you Publish again. IDM patches do not require you to re-Solve the DAM. |
| A past Trading Date | The button is still there. | Re-solving yesterday does not, by itself, unwind published money. Publish of a new run would supersede. That is a deliberate act, not a refresh. |
You can Solve after the DAM gate is closed. You are supposed to. Closing the gate is what makes the stack the stack. Solving while the gate is still open is allowed by the button and refused by good operations.
Solve does not wait for interconnect (due 13:30). If that parcel is late, Cadence records it; you still Solve when the energy stack and the 10:00 SO facts are in. Solve does not wait for IDM iteration 1 (18:00 D−1) — that auction patches a published DAM.
Settlement /mo/bidding/settlement
| Energy 1 | CSC 2 | Solve 3 | Ledger 4 |
|---|---|---|---|
| R 0.00 after Publish | zero-priced curve | after the DAM gate | honest empty |
- 1Energy nets to R 0.00 across the market once published. Solve alone leaves the tile —.
- 2CSC is a sentence when the amount is zero.
- 3Solve runs the auction; it does not publish. The gate closing does not disable it — that is when you use it.
- 4Ledger uses a sentence when the event store is empty.
13.11 Month — the Billing Period
Path: /mo/bidding/month. This is the month’s
books, not a day’s chalkboard. Settlement answers “did
this Trading Day clear?” Month answers “did this Billing
Period add up, and has anyone been paid?”
The picker on the ribbon is a month
(#bidding-month), not a day. Default: the previous
calendar month — the period you are most likely still closing.
Query: ?month=2026-07.
The billing board on this tab is the same board as
Accounts §18.4. It is a real
Mo.Settlement.Month after Run the month,
not an empty shell.
What this tab is for
A Trading Day is 24 hours. A Billing Period is a calendar month of those days. Invoices, self-billing invoices, credit cover, and “who still owes whom” are monthly artefacts. You cannot see that from one hour’s SMP.
Come here to:
- Confirm the energy pot still nets to R 0.00 across every published day in the month (the same closed loop as Settlement, added up).
- See who the month touched — named parties, and whether the document they were sent is an invoice (they pay) or a self-billing invoice (they are paid).
- Read the settlement calendar clocks, the statement / invoice runs, any bad-debt cascade, credit cover, and the query inbox.
- Declare Administered Settlement only when the ordinary pipeline cannot be used — and only with the Market Governance Committee’s prior written approval.
Run the month is not on this tab.
It lives on Cadence
(#mo-run-the-month). This page shows the result;
Cadence walks statements → verification → initial → invoices.
If the billing board says No Billing Period has been settled,
go to Cadence first.
What it displays
Three bands, top to bottom, matching the screen.
- Calendar and status — full width.
#dam-month-stats— four of twelve columns: Energy market stacked above Curtailment windfall. Eight of twelve: SMP duration.#dam-month-lower— six of twelve: Billing Period settlement (first, left). Six of twelve: Parties (right, no taller than the billing card).
Calendar and status
(#dam-month-calendar). Brand mark, title, and the
gate-miss pill (#gate-miss-rate) on one
line; the Billing Period sentence underneath. Billing Period {Month
YYYY} · {start} – {end}. {n} published Trading Day(s). That count
is published days only — a solved-but-unpublished day
does not join the month’s energy pot. The month picker stays on the
Bidding chrome (#bidding-month); it is not duplicated on
this card. Admin (#dam-month-admin) is the
SAWEM navy/gold control on the right of this header. It opens the
Administered Settlement modal (clause 15.11) — not a
clause-15.3.3 info dialog, and not an Export.
Gate-miss rate (#gate-miss-rate):
Gate-miss rate {n.n}% from the cadence ledger. Emerald when the
rate is 0.0%; amber otherwise. How often a §1.2 callable for this period
was a miss rather than a run. It is a health number, not a Rand
amount.
Energy market (EPM Exact Net)
(#dam-month-epm-net) is the upper card in the left column
of #dam-month-stats. The signed sum of every
EPM line on every published day in the
month. Headline is the same money string as Settlement’s energy tile.
Under it:
| Row | Id | How to read it |
|---|---|---|
| Target basis | #dam-month-epm-target |
Always R0.00 — the exact-basis closed loop |
| Variance | #dam-month-epm-variance |
The same signed headline. Zero is success; anything else is the open loop |
Hint: Must be R0.00 on the exact basis. Not added to the other pots. Emerald when the headline is R 0.00; rose if the loop is open. Do not add this number to constrained, IDM, or MO Charge; those are other pots.
Curtailment windfall
(#dam-month-windfall) sits below Energy
market in that same left column — not beside it. Constrained-off MWh
that carried a R 0.00 CSC (the classic case: a
zero-priced offer that was cut by the wires). The headline is the MWh.
Under it: Estimated value (the Rand those MWh would
have been worth at the hour’s SMP) and SMP reference: Hourly
rate. The footer repeats Would have been worth {R} at the
hour’s SMP. That Rand is what the energy would have been
worth, counted so NERSA and the operator can see it. It is
not added into the energy pot. Golden teaching:
15.000 MWh that would have been worth R
13,500.00.
SMP duration is the right-hand card of
#dam-month-stats. Title and the daylight sentence (Mean
system price by hour of day (SAST) across published days. Daylight
07:00–17:00.) sit with the legend
(#dam-month-smp-day-night-legend) in the card header. The
chart (#dam-month-smp-duration) is an ECharts step line:
Hour (SAST) on X, R/MWh on Y. Each
point is the mean SMP for that clock hour across
published days. Hover Mean SMP to two decimal places.
Amber wash is daylight 07:00–17:00; slate is night. The
footer (#dam-month-smp-metrics) is four figures from those
same hourly means:
| Figure | Id |
|---|---|
| Peak SMP | #dam-month-smp-peak |
| Min SMP | #dam-month-smp-min |
| Daylight avg (07:00–17:00) | #dam-month-smp-day-avg |
| Night avg | #dam-month-smp-night-avg |
Empty chart: No published hours in this period.
Billing Period settlement
(#billing-board) is first on
#dam-month-lower (left). Empty
(#billing-board-empty): No Billing Period has been
settled. After Cadence has run the month, the card is a calendar
panel beside four coloured run pots, then cascade /
cover / inbox when they have rows. The administered switch is
not on this board on Month — it lives in the
Admin modal. On Accounts the same board hides the
calendar, cascade, and administered cards; NERSA
Publish and Administered Settlement open the
calendar and administered as modals. The debit-note cascade,
credit-cover operations, and replenishment window live on Accounts →
Credit/Debit.
| Panel | Id | How to read it |
|---|---|---|
| Settlement calendar | #board-calendar |
Clause 15.3.3 clocks (initial-statement, invoice-due, self-billing-due, timetabled-rerun) in SAST |
| Runs | #board-runs |
Four pots: #run-statements (sky, {n} issued),
#run-invoices (indigo, due 12:00 +3BD),
#run-self-billing (emerald, paid 17:00 +4BD),
#run-shortfalls (amber; rose if > 0, {n} credit
call(s)). Invoice and self-billing counters open
/mo/billing Invoices and
Remittances (SB) for that month — the tax documents,
not an empty count |
| Cascade | #board-cascade |
Debit notes when someone did not pay. #cascade-none =
No Unsecured Bad Debt this Billing Period. |
| Excess Participants | #cascade-excess |
{party} owes {R} in cash within {n} business days — their debit note was larger than the self-billing invoice they were due, so they receive nothing this period and must pay the balance. That is a phone call |
| Credit cover | #board-credit-cover |
Required · Posted · Headroom (red if negative) · Notices |
| Query inbox | #board-query-inbox |
Tier · Participant · Raised · Deadline · Escalates to |
| Footer | — | Ledger clearing mode: Official balancing or Timetabled exact, plus SAST (+02:00) |
Parties (#dam-month-parties) is
second on #dam-month-lower (right). The
card does not grow taller than the billing board; the table body
scrolls. Header and the Party column stay sticky.
#dam-month-party-search (form
#dam-month-party-filter) filters name / MPID / document.
Empty table: No published DAM hours in this Billing Period. No
matches: No parties match this filter. Footer: Showing {n}
entries (#dam-month-party-count) and a
Settlement link to the month’s first day. A party name
is the same hop. Negative DAM EPM is rose.
| Column | How to read it |
|---|---|
| Party | Name / MPID |
| DAM EPM | Their energy-market position for the month |
| Constrained net | Constrained-schedule money (cuts and related charges) |
| IDM net | Intra-day money on the Market Balancing Account — not a rewrite of EPM |
| Document | #party-document-{id} — none (nothing
issued yet), Invoice (they owe the market), or
SBI (self-billing invoice: the market owes them) |
How to read it
- Pick the Billing Period you are closing, not
today’s Trading Day. The ribbon month picker
(
#bidding-month) and any Trading Date on other tabs are different controls. - Gate-miss pill. 0.0% emerald is healthy cadence; amber means callables were misses. It is not a Rand amount.
- EPM net first — headline, then Variance. If it is not R 0.00, a published day in this month has an open energy loop. That is an incident, not a rounding curiosity. Open Settlement for the days in the period and find which chalkboard is not closed.
- Published-day count. If it is less than the days you think you traded, someone has not pressed Publish yet. Month does not invent those days.
- Windfall is a count, not a pot. A large MWh with a large estimated value and a still-zero EPM net is coherent: the wires cut a zero-priced offer; the closed loop is intact; the windfall is disclosed separately.
- SMP duration. Peak / Min are the month’s mean-by-hour extremes. Daylight avg is 07:00–17:00; Night avg is the rest. Hover shows Mean SMP to two decimals.
- Document column.
Invoicemeans chase payment.SBImeans the market pays them.nonemeans Run the month has not issued that party’s document yet. Filter the table when the list is long. - Billing board empty means Cadence has not run this month. Do not treat that as “nobody traded.”
- Cascade / Excess Participants is the month’s bad news. An Excess Participant is a creditor being asked to send money back. Read it before anyone phones you.
- Admin is Administered Settlement (clause 15.11), not the settlement calendar. The calendar clocks stay on the billing card.
Worked month: §18.11 on Accounts (July 2026, full_demo, seed 42).
Administered Settlement — the form
The Admin button (#dam-month-admin)
sits on Calendar and status. It opens
#administered-modal. The form
#administered-switch-form is inside the
modal, not at the bottom of the billing board. Submit is
Switch to administered
(#administered-switch). Fields: MGC approval
reference (#administered-approval-ref) and
Methodology
(#administered-methodology-text). Close:
#administered-modal-close-x, the backdrop, or Escape.
What it is, in ordinary English
In a normal month the market is settled from real numbers: the day-ahead schedule, the intra-day moves, the meters. Everyone is paid (or pays) from that chain.
Sometimes that chain is broken.
Administered Settlement (Market Code clause 15.11) is the emergency setting: “we cannot settle this period the ordinary way, so we reconstruct it as honestly as we can — and we still put those reconstructed numbers through the same settlement calculator.” It is not a second, secret engine that only exists in a crisis. A calculator that only ran in a crisis would be a calculator nobody had ever tested, and the crisis is the worst moment to find that out.
The Code names two triggers. The teaching lives in full at V9 §16 and in the glossary (Administered Settlement, Administered Schedule).
| What went wrong | What the reconstruction does | Why |
|---|---|---|
| System Failure — the systems that run the market failed, so you do not have a trustworthy schedule or price set | Compute an Administered Schedule: quantities per Trading Unit per period, and prices per period. Prices default to the Wholesale Tariff unless the Market Governance Committee says otherwise | Downstream settlement then uses those figures, as close as practicable to what the ordinary algorithm would have produced |
| Electrical System Collapse — the grid itself collapsed | Set both scheduled energy and instructed energy to what the meter showed at the moment of collapse | Imbalance is “what you were told to do minus what you did.” If all three numbers are the same, every difference is zero, so nobody is charged a balancing penalty for a blackout they did not cause. Resetting only the schedule would leave every participant holding that penalty |
This tab’s form declares the Billing Period as administered (the board then shows mode system_failure) after the two required fields are filled. It does not ask you to type quantities and prices by hand. The substitution is the engine’s job. The form is the governance gate.
When you would use it — and when you would not
Use it only when ordinary settlement is actually impossible: the market systems failed, or the electrical system collapsed, and you cannot produce a truthful ordinary run for the period.
Do not use it because a day looks ugly, a participant is unhappy, a gate was missed, or you want to “smooth” a price. Missed gates belong on Cadence. Ugly hours belong on Settlement. Unhappy participants belong in the query inbox. Administered Settlement is not a discretionary override of a month that otherwise worked.
You also cannot use it as a shortcut around Run the month. If no month row exists yet, the switch refuses: Run the month before switching to administered settlement.
Why the two fields exist
Clause 15.11.1(d) and (e) are the reason the form is shaped this way.
The Market Governance Committee (the market’s governing body — not the operator acting alone) must give prior written approval of the detailed calculations and the methodology before the administered run, not after it. “We reconstructed the day and will explain later” is exactly what that clause exists to prevent. The MGC approval reference is that written approval, recorded on the switch so the switch cannot be thrown first and justified afterwards.
The methodology is then published (clause 15.11.1(e)) so every participant can see how the reconstruction was done. An administered month with no published method is a reconstruction nobody can check.
Leave either field blank and the switch does nothing. Error flash: Administered settlement requires the Market Governance Committee’s prior written approval and a published methodology (clause 15.11.1(d),(e)).
While the period is still ordinary, the board reads
(#administered-off): Mode: normal — the ordinary
pipeline. Switching to an administered mode requires the Market
Governance Committee’s prior written approval reference (clause
15.11.1(d)); the switch will not act without one.
What happens if you switch — the consequences
If both fields are filled and a month row exists, the period is
marked administered. Success flash: Administered settlement is
on. The form is replaced by #administered-on:
- Mode badge (error-coloured) plus trigger and clause.
- MGC approval reference
(
#administered-approval) in mono, with the approval stamp when present. - Methodology published:
{stamp}(clause 15.11.1(e)) (#administered-methodology).
There is no switch-back on this form. Ordinary mode is the default until this declaration; once it is on, the record is that this Billing Period was administered.
Consequences that matter to people, not only to the ledger:
- Participants settle against the reconstructed figures for that period, not against a pretend “nothing happened.” Money still moves. Statements and invoices still issue. The clocks in the settlement calendar still apply.
- The same calculator still runs. The energy account must still net to R 0.00. Administered is a mode of the ordinary pipeline, not a forgiveness of the closed loop.
- Query and dispute rights are untouched. A
participant who disagrees with the reconstruction uses the same inbox
(
#board-query-inbox). Administered is not “no complaints.” - When the failure is corrected, the period is rerun properly. Settlement Reruns produce the ordinary answer as soon as reasonably possible. The difference between the reconstruction and the real answer is settled through revised statements and their invoices — not by silently editing a closed period. Nobody should be surprised by a later true-up; that true-up is the design.
- The methodology is public. Anyone reading
#administered-oncan see that an approval exists and when the method was published. That is the transparency the clause demanded in exchange for letting the operator reconstruct a broken day.
Treat the switch as a declared state with a paper trail, not a toggle you try because the chalkboard looks wrong.
Month /mo/bidding/month
| Calendar 1 | Pots + SMP 2 | Billing board 3 | Parties 4 |
|---|---|---|---|
| gate-miss pill · Admin | EPM above windfall · duration chart | calendar | four pots | filter · sticky Party |
- 1Calendar and status is the header: published-day count, gate-miss pill, branded Admin (clause 15.11 modal). The month picker stays on the ribbon.
- 2Pots + SMP stacks Energy market (target / variance) above Curtailment windfall; SMP duration sits beside them with Peak / Min / Daylight avg / Night avg.
- 3Billing Period settlement is first on the lower row: clause 15.3.3 calendar beside Statements / Invoices / Self-billing / Shortfalls. No administered form on the board.
- 4Parties is beside billing, no taller than that card. Filter name / MPID / document; the Party column stays put while the rows scroll.
13.12 Clear — the G5 ledger
Path: /mo/bidding/clear. Date on the ribbon is the
Trading Day you are clearing
(#bidding-date). The month picker
(#bidding-month) is also here: it is the default month for
Settle, not the day-ahead run.
Daily is the pulse and the price board. Settlement is the hour chalkboard. Clear is the run room. It is where you see the two auctions the Code actually requires — unconstrained, then constrained — and where you pin that pair as the official day-ahead plan. It is also where you hand a month’s settlement file to reconciliation. Those are two different jobs on one tab. Mixing them up is the usual way to mis-operate this screen.
There is no second day-ahead engine. Run
both schedules and Publish… are the same
WB.Sawem.Cycles jobs as Daily’s Solve and
Publish. This tab does not list bids and does not fetch
a participant DAM schedule. It shows what G5 did.
What Clear is for
The Market Code does not clear “a schedule.” It clears twice:
- Unconstrained — if the wires could take everything,
who would run? That run sets the SMP and the energy-pot
volumes (
SG). - Constrained — given the System Operator’s security constraints, who may actually inject? That run sets the physical schedule. It does not rewrite the SMP.
Daily’s Price board shows you one ink line. Settlement shows you the money. Neither places the two schedules next to each other with the binding constraints on the same row. Clear does. That is why the tab exists.
Use it when you need to:
- See whether the wires moved anyone — constrained
against unconstrained, unit by unit
(
#clear-day-differences). Matching schedules are not proof the network was clear; the constraint note tells you whether anything was even published to bind. - Read the G5 cadence ledger for this Trading Day —
which callable ran, which missed, at what time
(
#clear-day-cadence). Cadence (§14) is the month’s health of those rows; Clear is today’s. - Run and pin the day-ahead plan with eyes on both schedules before every participant starts settling against them (clause 9.10(1), publish by 14:00 D−1).
- Publish the MO settlement file for one registration and month and reconcile it immediately — the §4 artefact, not a second auction.
What this tab is not. It is not Submissions. It is
not the IDM stack. It is not Month’s invoice. It is not a place to type
a price. Embedded #settlement-board and
#idm-board are the same boards as those tabs, parked here
so you can review money and patches without leaving the run room.
Why you should use it
Pressing Solve on Daily and never opening Clear will still clear the day — the jobs are the same. You should still come here because:
- Publishing is a deliberate act. Solving does not
pin the plan. An operator who has just re-run a day has to be able to
look at it before every participant settles against it. A screen where
solving published would make “let me check that” impossible. Clear’s
four steps (
#clear-day-steps) make that order visible: Unconstrained Ran → SO Constraints applied → Constrained Ran → Published. The last step stays unlit until you pin. The run time sits under each step when G5 recorded it. - The wires are a second truth. If a unit was cut,
you will see it here as a difference (MWh unconstrained → constrained)
and as binding constraint badges. Settlement will show the
CSCline; Clear shows why the two schedules diverged. - A miss needs a ledger, not a feeling. Empty cadence is No cadence rows for this Trading Day. Solve writes the G5 run here. After a run, a miss is a row with an outcome — the same honesty Cadence teaches.
- The monthly file is a different clock. Waiting for 07:00 on the 3rd is the automatic join. Publish & reconcile is how you issue (or re-issue) that file now, for one BRP registration, when the month’s internal lines exist.
What it displays
| Section | Id | What it is |
|---|---|---|
| Clear day panel | #clear-day-panel |
First on the tab. Title Clear day — 15 ’Jul ’26
(#clear-day-date). Status badge
(#clear-day-status) sits under the title
(SOLVED / PUBLISHED /
SUPERSEDED) |
| Steps | #clear-day-steps |
Unconstrained Ran → SO Constraints applied → Constrained Ran → Published. DaisyUI numbers the circles 1–4. Run time under a step when G5 has it |
| Run both schedules | #clear-day-solve |
Same row as the title, to the right. Disabled while solving
(Solving…) |
| Settle | #clear-day-settle |
Same row, after Run both. Opens the settlement-file modal |
| Publish… | #clear-day-publish |
Only when latest status is :SOLVED. Pins the DAM.
Confirm: #clear-day-publish-confirm |
| Security notice | #clear-day-network-notice |
After the steps, when the run carries a network-model notice. Info
alert (bg-info/10) labelled Security
Notice:. Emphasis words (degenerate,
assumed) are underlined; clause refs sit in a mono
chip. |
| Timelines | #clear-day-timelines |
Two equal-width cards after the Clear day panel
(md:grid-cols-2): Published Hours |
G5 Run Ledger |
| Published hours | #clear-day-schedules |
Card header Published Hours. Body is the daisyUI vertical timeline: bold hour · SMP · Marginal unit · binding count. After Publish |
| Binding modal | #clear-binding-modal |
Click a binding count greater than 0. Each constraint is coloured by
its title (declared_capacity,
declared_consumption, …) |
| Differences | #clear-day-differences |
Constrained against unconstrained — or no unit was moved by a security constraint. |
| G5 run ledger | #clear-day-cadence |
Card header G5 Run Ledger with a
{n} Callables badge. Body is the daisyUI vertical timeline:
bold start time · Callable · Outcome.
Empty: No cadence rows for this Trading Day. Solve writes the G5 run
here. |
| Constraint note | #clear-day-constraint-note |
Same three sentences as Daily: nothing published / empty published list / {n} published security constraint(s) will bind the constrained run. |
| Embedded boards | #settlement-board, #idm-board |
Same boards as those tabs |
| Settlement file (§4) | #clear-settle-modal ·
#clear-settlement-file |
Settle opens this. Registration + month → Publish & reconcile. This is not a second day-ahead clear. |
Empty panel: Nothing has been solved for this Trading Day yet.
Run both schedules
Run both schedules (#clear-day-solve)
is Daily’s Solve with the name that tells the truth. It
runs both day-ahead auctions for the ribbon Trading
Day, then writes prices onto a solved run. It does
not publish.
Where this is taught. The two auctions and why solving does not publish: §13.7 Solve and Publish. When the DAM gate is a lock on intake but not on Solve: §13.10 When you may Solve. This section owns what Clear is for, and the two buttons that are easy to mix up: Run both schedules (day-ahead) and Publish & reconcile (the monthly file).
The three jobs, in order:
- Unconstrained clear — who would run if the wires could take everything. This sets the SMP and the energy-pot volumes.
- Constrained clear — apply the System Operator’s security constraints; who may actually inject. This does not rewrite the SMP.
- Calculate prices — write the hourly SMP and the money lines onto a solved run.
Success flash: Both schedules solved and settled. Nothing is published yet. The first three steps light. Publish… appears. The fourth step (Publish) stays unlit. Participants still settle against the last published run — or against nothing.
A miss does not write an empty published plan:
| Miss flash | Typical cause |
|---|---|
| Solve recorded a miss — there are no accepted submissions for this Trading Day. | Nobody stored a 168-period body (and rollover has not written). |
| Solve recorded a miss — this Trading Day has no hourly periods to clear. | The date has no Trading Periods. |
| Solve recorded a miss — a prior step is un-run or an SO input is absent. | Cadence order or a System Operator parcel the run still needs. |
When you must use it
The DAM gate closing is not a lock on this button. The gate is when intake stops. The auction is meant to run after that bell.
| Clock | May you press it? | What you are doing |
|---|---|---|
| Before 10:00 D−1 — DAM gate still open | The button works. This is a rehearsal. | The stack is still moving. Do not Publish this as the day’s plan. |
| After 10:00 D−1 — DAM gate closed | Yes. This is the intended window. | Intake is frozen (unless you extended the gate). Rollover should have written. You run both schedules, read the two results, and Publish by 14:00. |
| After 14:00 D−1, or on the Trading Date | Still allowed. It does not reopen the DAM gate. | A new solved draft. The last published run remains official until you Publish again. IDM patches do not require you to re-run the DAM. |
| A past Trading Date | The button is still there. | Re-solving yesterday does not, by itself, unwind published money. |
You must use it (or Daily’s Solve — same jobs) whenever this Trading Day has no solved run and you intend to publish a plan. You must use it again after a miss, after late SO constraints arrive, or after a BRP has corrected a declaration you accepted — a second press draws a new run. It does not edit the previous one.
Do not use it as an IDM clear. Do not treat a successful press as “everyone is on this schedule.” That is Publish.
Consequences of using it
- A draft exists. Status badge
SOLVED (warning-coloured until published). Cadence rows
for the unconstrained, constrained, and price callables appear on
#clear-day-cadence. - The public energy pot, adequacy report, and participant schedules do not change. Flash is explicit: nothing is published yet.
- Publish… becomes available. You can open Settlement and read the chalkboard from that draft.
- Solving again produces another solved run. The previous solved (unpublished) run is not the one Publish will pin unless it is still latest.
- If the run is a miss, there is still no plan to pin. Fix intake or SO inputs; press again.
Publish… — pin the day-ahead plan
Publish… (#clear-day-publish) is not
Publish & reconcile. It only appears when the
latest run is SOLVED. It never publishes on the first
click. Confirm (#clear-day-publish-confirm):
Publishing makes this the schedule and price set every participant settles against (clause 9.10(1)). It supersedes anything already published for this Trading Day, and the superseded run stays readable. Solving again afterwards produces a new run rather than editing this one.
| Control | What it does |
|---|---|
Publish this run
(#clear-day-publish-confirmed) |
Pins this solved pair as official. |
| Cancel | Closes the confirm. Nothing is published. |
When you must use it. After a successful Run
both schedules, once you have read the two schedules and the
differences, by 14:00 D−1. That is the Code’s
publication obligation. A solved run that never publishes is a rehearsal
the market cannot settle against. Re-publishing a later solved run is
allowed; it supersedes the previous published run
(status SUPERSEDED) rather than editing it — so “why did my
statement change?” still has an answer.
Consequences. Success flash: Published. Every
participant now settles against this run. The Publish step lights.
#clear-day-schedules fills (Period · SMP · Marginal unit ·
Binding constraints). Energy account on Daily/Settlement may now show
R 0.00. Adequacy and schedule.published
notices go out. Until this press, they do not.
Miss: Publish recorded a miss — prices have not been calculated. Or There is nothing solved to publish.
After Publish, the two-schedule table is what you came to Clear to see. Empty differences: no unit was moved by a security constraint. Read the constraint note before you treat that as a healthy network.
Publish & reconcile — the monthly file
Publish & reconcile lives on Settlement
file (§4) (#clear-settlement-file), opened by
Settle (#clear-day-settle) — not a card at
the bottom of the tab. It is a monthly control. Form
#clear-settlement-form: pick a
Registration (BRP code) and a Month,
then submit. Close: #clear-settle-modal-close-x, backdrop,
Escape.
It does two things in one press:
- Publish an MO settlement file for that registration and month — the §4 artefact — built from the platform’s internal expectation (the lines the books already hold).
- Reconcile immediately — the same join the clock runs at 07:00 on the 3rd: internal lines against that file. Success flash: Settlement file published and reconciled — {n} % matched.
The card’s own sentence: This is not a second day-ahead
clear. It does not run unconstrained or constrained. It does not
set an SMP. It does not pin #clear-day-panel.
When you must use it
| Situation | Use it? |
|---|---|
| The day-ahead plan is unsolved or unpublished | No. That is Run both schedules then Publish…. |
| Cadence has not run this Billing Period (no internal lines) | It will refuse: Could not publish/reconcile (no internal
lines?). Run the month first (§14,
#mo-run-the-month). |
| A registration needs the §4 file now (or again after a correction) | Yes. Do not wait for 07:00 on the 3rd if the month is ready. |
| You selected no registration | Refuses: Choose a registration first. |
| You want to see match-% on Reconciliation | Yes — that view shows the newest run, so do this last in a demo if an older injected-error month should stay on screen. |
The automatic 3rd-of-month job still runs. This button is the operator-initiated issue (and re-issue) of the same file for one BRP.
Consequences of using it
- A settlement file is stored for that registration and month. The reconciliation run hangs off that file (matched lines, net variance, classified mismatches).
- SMP, DAM schedules, EPM, and the Clear-day status badge do not change. You have not re-cleared 15 July by reconciling July.
- If the file was built from internal expectation, a clean month matches at 100%. That is expected — you published the books’ own lines. Real mismatches come from a file that disagrees (error injections in the Scenario Lab, or a later true-up). Do not treat 100% as proof the market was perfect; treat it as proof this file agrees with what the platform already thought.
- The participant’s Reconciliation screen updates to this newest run. A previous run is no longer what that screen leads with.
- Query and dispute rights are untouched. A variance line can still become a dispute. This button is not “no complaints.”
Clear /mo/bidding/clear
| Clear day 1 | Run both 2 | Settle 3 | Hours | G5 4 |
|---|---|---|---|
| title · status · steps | unconstrained + constrained | file modal | two vertical timelines |
-
1Clear day is first on the tab. The date reads
15 ’Jul ’26. The status badge sits under the title. Steps stay on the header: Unconstrained Ran → SO Constraints applied → Constrained Ran → Published, with the run time under each step when G5 has it. - 2Run both schedules is on the title row, to the right — Daily’s Solve. Nothing is published yet.
- 3Settle opens the §4 file modal. Publish & reconcile inside it is not a second day-ahead clear.
- 4Hours and G5 sit beside each other as equal-width cards. Left Published Hours: bold hour · SMP · Marginal unit · a binding-constraint count (click for the coloured list). Right G5 Run Ledger: bold start time · Callable · Outcome.
13.13 Operate 2026-07-15 18:00
Data. full_demo · seed 42 · Trading Day 2026-07-15 · hour 18:00 · SAWEM-SPEC §10 / market-dam.md §11.
Seat: mo@webill.net / supersecret.
- Open Submissions with
?date=2026-07-15. FindTU-PV1. Open the drawer. You should see 168 periods and no edit form. Golden units:TU-COAL1,TU-PV1,TU-OCGT1,TU-DIST1,TU-IND1. - Open Settlement for that date, hour 18:00. Unconstrained 75 / constrained 60. Energy pot R 0.00. CSC R 0.00 with the zero-priced-curve sentence (own offer was zero on TU-PV1). SMP R 900.
- Solve if the day is unsolved; confirm the public board is still empty. Publish. The status sentence becomes Published at HH:MM.
- Open IDM, iteration 4. Applied IDP R
945, collared. The stack has prices and
volumes and no
TU-. The farm’s IDM charge is −R 37,800. - Open Month for July 2026. EPM nets to R 0.00. Windfall 15.000 MWh, would have been worth R 13,500 at the hour’s SMP. It is not added into the energy pot.
Follow along. Path: Market Operator → Bidding → Submissions
?date=2026-07-15→ Settlement → Daily/Clear Publish → IDM iteration 4 → Month. You should see R 0.00 on the energy account, a collared R 945, and a drawer that will not let you type a price.
Demo clearing is deterministic (TOU SMP bands). Same trading date ⇒ same curve — reproducibility for screenshots and gates.
14. Cadence
Path: Market Operator → Cadence
(/mo/cadence). Second item in Market day.
The icon is a clock.
This is the §1.2 operating-cadence ledger: every Market Operator callable as due, ran or missed. A miss is a row. A missed 14:00 publish is not a green day. Stopping after publish without allocate is visible as un-run.
Think of it as the station clock and the delay board. Bidding is the platform. Cadence is whether the 14:00 actually left.
What this page is not. It is not a roster of BRPs, Trading Units or bids. There is no search, no TUID column, no silent-unit tile. You hunt callables and failed deliveries here, then jump to the desk that names the party (§14.4).
14.1 Why Cadence is significant
Cron will run the callables. You still need to see them. Did gate close? Did rollover write? Did unconstrained run before constrained? Did publish happen on time? Did allocate ever run? If a §16(2)(f) delivery failed, who still has not been told?
Without this page those questions hide in logs. With it they are rows.
What it is for
The Market Code’s day is a timetable, not a mood.
§1.2 names every callable and when it is due. Cadence is the operator
view of that table for one Trading Day: the same names the Oban shells
and POST /api/v1/internal/cycles/:callable fire, written as
pending / due / ran / missed with the Outcome the
engine recorded.
Bidding Solve and Publish call the
same WB.Sawem.Cycles wrappers. They do not replace this
page. A chalkboard that looks solved is not proof the 14:00 left, that
IDM iteration 1 rang, or that allocate ever ran. Cadence is that
proof.
Why it matters on a trading day
A Trading Day is a chain. Each callable has a predecessor and a clock. If you only watch Daily, you watch the auction room. Cadence watches whether the bells rang, in order.
| Clock (SAST) | Callable you must see move | If it does not |
|---|---|---|
| 10:00 D−1 | #mo-cadence-close_dam_gate then
#mo-cadence-generate_rolled_over_submissions |
Intake never froze. Silent units still have no body. Daily Solve can
miss (no_submissions) or clear an incomplete stack. |
| after the gate | #mo-cadence-clear_unconstrained |
No economic solve. The System Operator’s reserve parcel is a
recorded miss (so_reserve_requirements_absent), not
invented zeros. |
| 13:30 D−1 | #mo-cadence-clear_constrained |
Wires and interconnect never applied. Downstream prices miss with
prior_clear_missing /
unconstrained_not_run. |
| 14:00 D−1 | #mo-cadence-calculate_prices and
#mo-cadence-publish_schedule_reports |
The plan never became the plan. A missed 14:00 is a rose
row, not a green day. Every later
#mo-cadence-clear_idm-{n} can miss with
dam_not_published. |
| 18:00 D−1, then 00:00 / 06:00 / 12:00 / 18:00 D | Five #mo-cadence-clear_idm-{1..5} rows |
The patches never rang. The IDM tab is the board; these rows are whether the bell fired. Not inside Run the day. |
| D and D+1 | #mo-cadence-ingest_metering,
#mo-cadence-allocate_metering |
Empty ingest is a miss (empty_ingest), not a skipped
healthy day. Official balancing cannot become official. |
| D+1 … D+7 17:00 | #mo-cadence-run_balancing-d{1..7} |
Preliminary then official never computed. D+7 VERIFIED can run and still refuse if vintage is unverified — emerald is not “official is out”. |
| SD+1 WD / BP+5 WD / BP+1M | Statements, invoices, rerun, credit cover, calendar | The month never closed. Accounts and Billing show the board; they do not have Run the month. |
The clocks are in §3. This page is whether they actually rang.
What goes wrong if you ignore it
You will believe Daily. Daily can look finished while Cadence is not.
- You never look at the header counts. Rose
missedand darkduesit in#mo-cadence-ledger. A solved Price board does not clear them. - Gate and rollover stay un-run. Submissions still shows Silent after 10:00 (§13.8). Units with no previous body cannot be rolled — that is a participant problem, but you only know rollover ran by this row.
- You Publish from Daily and walk away. Run
the day and Daily Publish stop at
publish_schedule_reports.#mo-cadence-allocate_meteringstays pending. That is an honest unfinished day, not success. - IDM stays amber. Five
:clear_idmrows are a different timetable. A green Run the day is not “the patches ran”. - A BRP asks “where is our schedule?” Publish can be
ran while
#mo-event-incidentsstill shows an openschedule.publisheddelivery. They were not told. That is a row here, not a missing line on Daily Panel C. - Month-end surprises Accounts. Indicative / initial
/ invoices never issued (
no_parties,no_statements,settlement_calendar_not_published). Run the month lives only on this page.
A miss is a row so you cannot skip it as healthy silence. Empty ingest, absent SO reserves, a Saturday credit-cover pass, official balancing on unverified metering — each is recorded.
14.2 How the page is laid out
Browser title: Cadence. Header: Operating cadence — Every Market Code §1.2 callable as due, ran or missed. A miss is a row.
No tabs. No filters. Three blocks, top to bottom. If a simulation is active, the simulated-clock ribbon sits under the header — same ribbon as Daily.
| Block | DOM id | Job |
|---|---|---|
| Date and actions | #mo-cadence-date-form |
Pick the Trading Day; run the day or the month |
| Ledger | #mo-cadence-ledger |
Every callable for that day |
| Event-delivery incidents | #mo-event-incidents |
Failed §16(2)(f) deliveries |
Reading order
Read the page the way the clock bites, not the way the table is sorted.
- Confirm the Trading Day
(
#mo-cadence-date). Wrong date, wrong bells. Before 10:00 SAST the default is tomorrow (you are still in D−1); from 10:00 it is today — same rule as Bidding. - Read the four header counts on
#mo-cadence-ledger— pending, due, ran, missed. Start with missed (rose) and due (dark). Do not start by scrolling for a favourite name. - Open the rose and dark rows. Outcome plus the rose
— {reason}is the finding. A blank Outcome on a missed row means the deadline passed and nothing was recorded — still a miss. - Then Event-delivery incidents.
{n} openin rose is who was not told, even if publish ran. - Only then press a button. Run the day is the six day-ahead steps. It will not allocate, will not clear IDM, and will not issue invoices.
A day runs to a couple of dozen callables (six day-ahead, five IDM,
ingest + allocate, seven balancing vintages, then the settlement
cluster). The ledger scrolls inside
#mo-cadence-ledger-scroll; the column headers are
sticky.
14.3 Trading day and the two run buttons
| Control | Id | What it does |
|---|---|---|
| Trading day | #mo-cadence-date |
Date input. Change it and the address becomes
/mo/cadence?date=YYYY-MM-DD. An invalid date is
ignored. |
| Run the day | #mo-run-the-day |
Left branch of #mo-cadence-run-actions. Walks gate →
rollover → unconstrained → constrained → prices → publish. Hover lifts
and paints brand amber. Flash: Run the day — {ok} ok, {miss}
miss(es). Allocate is a separate row. |
| Run the month | #mo-run-the-month |
Right branch of the same pair. Walks indicative → initial → invoices → timetabled rerun → credit cover (the same G5 job) for the Billing Period that contains the selected day, then persists the month run the billing board reads. Hover lifts and paints indigo. Flash: Run the month — {ok} step(s) recorded. |
Help text under the buttons:
Run the day walks gate → rollover → unconstrained → constrained → prices → publish. Stopping after publish without allocate is visible as un-run, not success. A missed 14:00 publish is a row, not a green day.
Run the day does not allocate.
:allocate_metering is a later ledger row. A green publish
with allocate still pending is an honest unfinished day.
Run the day does not clear the IDM. The five
:clear_idm rows stay on their own clocks.
Run the month is the month trigger. Bidding → Month and Accounts show the billing board; they do not have this button.
External automation POSTs each MO-SPEC §1.2 name at
/api/v1/internal/cycles/:callable. A participant token is
404 (V13).
14.4 The ledger — how to read a row
Header counts, left to right, are filters
(#mo-cadence-status-filters): All,
{n} pending (amber), {n} due,
{n} ran (emerald), {n} missed (rose). Click a
status to show only that chip’s rows; click it again or
All to restore the full ledger. The counts still
describe the whole day, not the filtered slice.
| Column | What it is |
|---|---|
| Callable | The §1.2 name. May append /iteration (IDM) or a vintage
(PROVISIONAL / VERIFIED) |
| Trigger | When the engine expected it — the §1.2 sentence, not a wall-clock you type |
| Due | SAST clock as 23 'Aug '26 00:00
(#mo-cadence-{callable}-due), or blank. Click
Due (#mo-cadence-sort-due) to sort
earliest first, click again for latest first. Rows with no due time sink
to the end on earliest-first and rise to the top on latest-first. |
| Status | pending · due · ran ·
missed |
| Outcome | What was recorded (ok, miss,
error, refused, skipped). A miss,
error, refuse or skip appends — {reason} in rose when the
engine stored one |
Row ids: #mo-cadence-{callable} —
e.g. #mo-cadence-close_dam_gate,
#mo-cadence-publish_schedule_reports,
#mo-cadence-allocate_metering. IDM adds the iteration:
#mo-cadence-clear_idm-1 …
#mo-cadence-clear_idm-5. Balancing adds the offset:
#mo-cadence-run_balancing-d1 … -d7.
A day runs to dozens of callables, so the ledger scrolls inside its
own box (#mo-cadence-ledger-scroll) rather than dragging
the page down, and the column headers are sticky — they
stay put while the rows pass under them. You can be forty rows in and
still know which column the rose chip is sitting in.
| Status | Colour | Meaning |
|---|---|---|
| pending | Amber | Not yet due |
| due | Dark chip, white text | Deadline reached, not yet run |
| ran | Emerald | Completed (ok, refused, or
skipped — it ran) |
| missed | Rose | Due time passed without success, or outcome :miss /
:error |
Emerald is not always good news.
refused and skipped count as
ran. Official balancing that refused unverified
metering is a green chip with Outcome refused. Read the
Outcome column; do not stop at the counts.
Metaphor. Pending is the train still in the timetable. Due is the announced departure with no movement. Ran is a departure logged — even if the destination refused the train. Missed is an empty platform after the clock.
Day-ahead callables you will see on a normal D−1:
| Callable | Everyday name |
|---|---|
:close_dam_gate |
Freeze intake |
:generate_rolled_over_submissions |
Fill silence with yesterday |
:clear_unconstrained |
Economic solve |
:clear_constrained |
Apply the wires |
:calculate_prices |
SMP and pots |
:publish_schedule_reports |
14:00 publication |
:allocate_metering |
After 14:00 — not inside Run the day |
:clear_idm /iteration |
Five IDM auctions — 18:00 D−1 then 00:00 / 06:00 / 12:00 / 18:00 D.
Not inside Run the day. A miss with
dam_not_published means Daily never Published. The IDM tab
is the board; this row is whether the bell rang (§13.9) |
- 10:00 DAM gate · demand & reserves due
- 13:30 Interconnect due
- 14:00 Publish — a miss is a rose row
Who to look for
Cadence does not name a BRP or a TUID. You look for which bell failed, then take the names from the desk that holds them.
Walk missed and due first, then any
ran row whose Outcome is refused or
skipped. The hunts below are the ones this screen can
actually raise.
| Hunt | Row on this page | Who / what you are after | Where the names live |
|---|---|---|---|
| Gate never froze | #mo-cadence-close_dam_gate due or
missed |
Intake is still moving. Late PUTs may still land. | Bidding → Daily gate chip; Submissions Rejected / late for the 409s that did bounce (§13.8) |
| Silent units | #mo-cadence-generate_rolled_over_submissions still
pending after 10:00, or missed |
Registered units with no body at the gate. Rollover is supposed to copy yesterday. | Submissions Silent at last snapshot and Rolled over tiles. A unit that never had a previous body cannot be rolled — Registry, not a missing Cadence button. |
| Late submissions | Gate row ran, plus the clock past 10:00 | They tried after the bell. Cadence will not list those PUTs. | #submissions-rejected — gate_closed is the
usual code. The operative body (if any) is the rollover, not the late
PUT. |
| Nobody to clear | #mo-cadence-clear_unconstrained Outcome
— no_submissions |
The stack is empty. Received + Rolled over = 0. | Submissions tiles. Do not Solve past this as a display quirk. |
| System Operator reserve parcel | #mo-cadence-clear_unconstrained Outcome
— so_reserve_requirements_absent |
The SO, not a BRP. The engine will not invent zeros. An operator Run the day may proceed with the absence recorded in the inputs hash. | Daily / Clear — reserve input state. Chase the SO feed, not a participant. |
| Wires / 13:30 interconnect | #mo-cadence-clear_constrained due
after 13:30, or — unconstrained_not_run |
Constrained waits on unconstrained and the
interconnect clock. Absent security constraints are a recorded input
state, not a silent []. |
Clear / Daily constrained notice. The SO and the ties, not a TUID. |
| Prices or 14:00 publish | #mo-cadence-calculate_prices,
#mo-cadence-publish_schedule_reports
missed (prior_clear_missing,
prices_not_calculated) |
The plan never pinned. This is the finding — not a solved chalkboard. | Daily Publish. Then come back: publish ran is the Cadence row, not the ink on the Price board. |
| IDM gate failures | #mo-cadence-clear_idm-1 … -5
missed, especially
— dam_not_published |
Iteration that never cleared. Iteration 1 at 18:00 D−1 needs a Published DAM. | IDM tab is the board (§13.9). Today’s date shows iteration 5; tomorrow’s date shows that day’s iteration 1 — they are not the same row. |
| Missing metering | #mo-cadence-ingest_metering or
#mo-cadence-allocate_metering missed with
— empty_ingest |
Network Operator feed / no batch. Empty ingest is a desk state, not a skipped healthy day. Run the day will not fix this. | Metering — Re-ingest, Allocate, unpaired points, exception inbox. |
| Balancing vintages | #mo-cadence-run_balancing-d1 … -d7
(Callable shows PROVISIONAL or VERIFIED) |
D+1–D+6 preliminary; D+7 official. Official refused is still ran. | Balancing. Official stays gated on verified vintage. |
| Statements / invoices / cover | #mo-cadence-issue_indicative_statements,
#mo-cadence-issue_initial_statements,
#mo-cadence-issue_invoices,
#mo-cadence-run_timetabled_rerun,
#mo-cadence-recalculate_credit_cover,
#mo-cadence-publish_settlement_calendar |
Parties with no lines (no_parties,
no_statements), or a year with no calendar
(settlement_calendar_not_published). Credit cover is every
business day by 17:00. |
Accounts and Billing. Press Run the month here, then read the board there and open the PDFs on Billing. |
| Who was not told | #mo-event-incidents — {n} open in
rose |
Failed §16(2)(f) machine delivery. Typical event
schedule.published. The mono event id is
{event}:{source} — for publish, the source includes the
Trading Day and the party. |
This list. Retry (#retry-event-{id})
is the control. Notices (§15) is the tannoy, a
different channel. |
What you will not find on this screen. A TUID, a BRP code, a silent count, a rejected PUT, a meter point, or a credit-cover headroom figure. Those desks exist. Cadence tells you which job failed so you know which desk to open.
What you can ignore (for a moment). Amber pending rows whose Due is still in the future. IDM iterations 2–5 on a morning D−1. D+7 balancing on a day that has not happened. They are the timetable, not the delay board.
14.5 Event-delivery incidents
Heading: Event-delivery incidents. A failed
schedule.published (or any §16(2)(f) delivery) appears here
— not as a missing chalkboard line. Publish writes one delivery per
party that settled the day, plus the public row. A down webhook is an
incident, not a quiet gap.
| State | Copy |
|---|---|
| Empty | No failed §16(2)(f) deliveries. A miss is a row, not a missing
Panel C line. (#mo-event-incidents-empty) |
| Open | Header shows {n} open in rose |
Each open incident is #mo-event-incident-{safe-id}:
| You see | What it is |
|---|---|
| Mono event id | {event}:{source} — shared with the org day board. Dots
and colons are not CSS-safe; Retry uses the sanitised
id. |
{event} · {reason} |
Event name (schedule.published, and any other §16(2)(f)
type that failed) and failure_reason, or delivery
failed. |
| Retry | #retry-event-{id} |
Success flashes Delivery retried. and the row clears.
Failure shows the incident’s failure_reason. Retry is
not a re-publish and not a re-clear.
The schedule already left; this is the doorbell.
If publish is ran and this list is not empty, start here before you tell a BRP the noticeboard is up.
14.6 Worked day — 2026-07-15
Data. full_demo · seed 42 · Trading Day 2026-07-15.
Open /mo/cadence?date=2026-07-15. You should see the
day-ahead rows. Press Run the day. Gate, rollover,
unconstrained, constrained, prices and publish move to
ran. Allocate stays off that list — look for
#mo-cadence-allocate_metering still pending or due.
If you freeze the clock at D−1 14:30 SAST with publish un-run, the publish row is missed. That is the finding. Do not read a solved Daily chalkboard as a green cadence day.
Then look down the same date for the hunts in §14.4: five IDM rows, ingest / allocate, seven balancing offsets, and the settlement cluster. Run the day will not have touched them.
Follow along. Path: Market Operator → Cadence → set
2026-07-15→ Run the day. Then open Bidding → Daily for the same date. Solve/Publish on Daily call the sameWB.Sawem.Cycleswrappers. Cadence is how you prove they ran.
Careful. A participant token cannot POST a callable. Internal automation uses the internal party header (V13).
14.7 How to act
You do not “fix a unit” from this chair. You prove which callable failed, then act on the matching desk — or fire the missing step.
| Finding | What you press or open |
|---|---|
| Day-ahead chain still pending / missed before 14:00 | Run the day (#mo-run-the-day), or
Daily Solve / Publish — same wrappers. Then re-read the six rows. |
| Publish ran, allocate still pending | Leave it. Allocate is #mo-cadence-allocate_metering /
Metering Allocate. Do not read Run the
day as done. |
:clear_idm missed
dam_not_published |
Publish the DAM on Daily first. Re-publishing does not resurrect a missed iteration by itself. |
empty_ingest |
Metering Re-ingest, then Allocate. Not Run the day. |
| Open event incidents | Retry on the row. If it fails again, the
failure_reason is the ticket. |
| Month rows missed | Run the month (#mo-run-the-month),
then Accounts / Billing. |
| Silent > 0 after rollover ran | Submissions / Registry — those units had nothing to roll. |
Do not treat a second Run the day as a way to hide a miss. Each press records rows. The ledger is the product; the buttons are how it becomes true.
15. Notices
Path: Market Operator → Notices
(/mo/notices). Fourth item in Market day.
The icon is a megaphone.
A notice is a dated message the market keeps so someone can prove they were told. It is words (or a named event) with a time, an audience, and a record. It is not a price. It is not a bid. It is not a System Operator order that moves a plant.
This page is the tannoy: New + opens a modal, you type a sentence, pick a type, and Publish. Every participating BRP (Balance Responsible Party — the firm that bids and settles) hears the same text. The table is how you prove you said it.
Other screens keep other messages. Those are also “notices” in the Code. They are not this form. This chapter first teaches the tannoy. Then it lists every kind the product actually issues or records, and says which console holds it.
Metaphor. Daily’s notification ledger is the
pigeonholes for machine events
(schedule.published). This page is the station
announcement: words a human wrote, heard by every BRP notice feed.
Where this is taught. What a notice is, and how a BRP reads it: V9 §9. System Operator orders and
SYSTEM_CONDITION: V12 §3. Event-delivery failures: §14.5. Daily’s receipt list: §13.7. This chapter is the send form and the catalogue.
15.1 The operator’s problem
The market needs context that is not a price. A gate was held. The grid is stressed. The price cap bound. Every BRP must see the same text, and you must be able to prove you sent it — including last month’s wording.
You also need to know the other messages that are not this tannoy. A credit-cover call is a notice. A default is a notice. A schedule that failed to reach a webhook is a notice. Mixing them up is how a party says “nobody told us” when you told them on a different desk.
15.2 What a notice is — and what it is not
In plain words: someone was told something, on the record.
| It is | It is not |
|---|---|
| A dated row with a type (or event name), a body or payload, and an audience | A change to Instructed Energy |
| Proof you broadcast, or proof a machine event left | A bid, a schedule, or a price |
| Something a BRP can open on Market → Notices when you used this form | A System Operator plant order |
| Searchable later | A delete |
Three audiences appear in this product:
| Audience | Everyday meaning |
|---|---|
| Public / broadcast | Every participating BRP (and the public feed, when the event is public) |
| Party | One named registration. A BRP that was not named does not see it |
| Network operator | One named network operator — same naming rule as party |
This tannoy always broadcasts. The form has no party picker. A
party-scoped PRICE_CAP_EVENT is written on Daily’s ledger,
not here.
15.3 Why one is created
Someone creates a notice because a fact needs to travel before the next decision. Typical triggers:
| Trigger | Everyday example |
|---|---|
| You need every BRP to read the same sentence | Gate held to 10:15 under §9.3(3) |
| The room is stressed, or a cap bound | High demand; SMP hit the Market Price Cap |
| A machine event happened | 14:00 publish; an IDM auction cleared; a bid was rolled over |
| Money or eligibility moved | Credit cover short; an account was opened; a party is in default |
| The registry changed | A meter point was added; a balancing group was designated |
| Delivery failed | A schedule.published webhook did not land |
| The System Operator missed a parcel | Reserve requirements late — specified as a
SYSTEM_STRESS notice |
If nobody needed to act or know, you would not write one.
15.4 Who issues, and to whom — the map
Only list what this app actually writes or names. This
console means /mo/notices. Other rows live on
other desks.
| Issuer | Typical audience | Where you see it |
|---|---|---|
| You (MO) on this form | Every participating BRP | This page; the BRP Market → Notices inbox; event
notice.published |
| Cadence / Publish (automated) | Public + each settlement party | Daily / Settlement #notification-ledger; Cadence
incidents if delivery failed |
| Daily credit-cover job (17:00, business days) | The named party | Accounts / Billing Credit cover · Notices; the
party’s cover dashboard; events
credit_cover.increase_notice /
credit_cover.warning |
| The party (written notice) | You (MO) | Accounts #mo-account-notifications — they tell you an
account exists |
| You (MO) on Participants | The named party | Open Default — a Default Notice |
| The registry write (same transaction as the change) | System Operator | SO Registry Inbox — a
RegistrationNotice |
| The registry write (§7.1(6)) | The other party at the meter | That party’s counterparty inbox; event
registry.counterparty_change |
| System Operator | Target BRP, or every Bid Desk | Not this page — V12 §3 |
Cadence does not publish tannoy text. It records whether a callable ran, and whether a machine event failed to arrive (§14.5).
15.5 How this page is laid out
Browser title: Notices. Header: Notices — Broadcast market notices to every participating BRP and search the month.
One card, #mo-notice-log, headed Market
notices. The table is the log. New +
(#mo-notices-new) opens the publish modal.
Default range: the current SAST month (first day
through last day of the month on the market clock). Change
From / To
(#mo-notices-period, #mo-notices-from,
#mo-notices-to) to another period. To
cannot precede From — if you pick an end before the
start, the end snaps to the start. The end date’s min is
the start date.
Type chips (#mo-notices-type-filters):
All, General, System
stress, Price-cap event. Click a type to show
only that badge; click it again or All to restore.
Read the page top to bottom: period → type chips → table → New + when you need to speak.
15.6 The table
#mo-notices-table, sticky headers, scrolls inside
#mo-notices-scroll. Empty: No notices in this
period. (#mo-notices-empty).
| Column | What it is |
|---|---|
| Type | Coloured badge — General (slate), System
stress (amber), Price-cap event (violet).
#mo-notice-{id}-type |
| Date/Time | SAST clock as 24 'Aug '26 10:20. Click
Date/Time (#mo-notices-sort-published) to
toggle oldest-first / newest-first. Default is newest first.
#mo-notice-{id}-at |
| Notice | The text that was published.
#mo-notice-{id}-message |
Row id: #mo-notice-{id}. There is no twenty-notice cap
on this console. The period is the window.
A BRP still archives for themselves on their inbox. That does not hide a row here. Their archive is “I have filed this.” Yours is “this period.”
15.7 New + — the publish modal
New + opens #mo-notice-new-modal
(Escape, the X, Cancel, or the backdrop close it).
Title: New notice — Market day.
phx-submit="publish_notice" on
#mo-notice-new-form.
| Control | Id | What it means |
|---|---|---|
| Type | #mo-notice-type |
General (GENERAL) · System
stress (SYSTEM_STRESS) · Price-cap
event (PRICE_CAP_EVENT) |
| Notice | #mo-notice-text |
Placeholder Publish a notice to all BRPs… — required |
| Submit | Publish (#mo-notice-publish) |
Writes one row and fans it to every participating BRP |
| Outcome | Flash |
|---|---|
| Empty text | Notice text is required. |
| Success | Market notice published to all BRPs. — modal closes; the table returns to the current month |
| Failure | Could not publish the notice. |
There is no party field. party_id on the stored row
stays empty. That is a broadcast.
A PRICE_CAP_EVENT on this form is a
broadcast. Party-scoped price-cap events that name one BRP are recorded
on Daily’s #notification-ledger. A BRP that was not named
does not receive those.
The same publish also becomes event notice.published on
the public event feed (type + message, clause §9.3(3)).
15.8 Period and type — how to hunt
Need last month’s wording? Set From to that month’s first day and To to its last. Need only stress? Press System stress. Need the first announcement of the month? Sort Date/Time oldest-first.
The chips do not change the period. The period does not change the type filter until you press All or a different type.
15.9 The three types this form can send
These are the only types the Type select offers. They are the only types this console records.
| Type | When you would send it | Who hears it | What they must do | If they ignore it |
|---|---|---|---|---|
General (GENERAL) |
Any operational sentence that is not stress and not a cap | Every participating BRP | Read it before they change a clock, chase a variance, or assume a gate | They miss why a gate moved or a band looks wrong. The bid they already lodged is unchanged |
System stress (SYSTEM_STRESS) |
Grid or market stress you need every BRP to see in the same words | Every participating BRP | Treat it as context for the day | They may misread a thin or volatile hour. No MWh, no curtailment, no Instructed Energy. Only an SO order does that |
Price-cap event (PRICE_CAP_EVENT) |
A cap or floor that changes how a clearing result should be read | Every participating BRP (this form) | Look at the price flag and the notice together | They may not understand why SMP sat on the cap. Settlement still uses the capped price |
The Code also specifies a SYSTEM_STRESS notice
when the System Operator misses reserve requirements by 10:00 D−1 (carry
the last equivalent period, and tell people). Cadence
records that miss as a row. This form is how you put the sentence on the
tannoy. Cycles does not auto-write a Market Notice row today. If the
reserves were carried forward and you did not broadcast, the
substitution can still have been used — the honesty gap is yours.
Careful. A
SYSTEM_STRESSnotice here is context. It has no target MWh and creates no curtailment line. Only a System Operator instruction does that (V12 §3).
15.10 Every other notice this product issues or records
The rest of the product uses the word “notice” for several families. Each family has a home. This console only stores the three types above.
How to read the Where column. This console
= /mo/notices. Daily / Settlement = the
notification ledger. Cadence = event incidents.
Specified = named in the Code or the event vocabulary, not
issued from this form (and, where said, not yet in the feed).
A. Machine receipts — Daily and Settlement
After Publish on Daily, the chalkboard is pinned.
The notification ledger
(#notification-ledger on Daily;
#dam-settlement-notifications on Settlement) is who was
told what for that Trading Date. Oldest first. You see every row. A
BRP sees public rows plus rows that name them.
| Event name | Who issues | To whom | Trigger | Consequence if ignored |
|---|---|---|---|---|
| schedule.published | Publish (automated) | One public row (Day-ahead schedule published., §9.10(1)) plus one party row per settlement party (Your schedule report is published.) | You pin the 14:00 noticeboard | The schedule still exists. A party that never fetched it still settles against it. A failed delivery is a row, not a missing success — retry on Cadence |
| PRICE_CAP_EVENT (party-scoped) | Ledger write that names a party_id |
That BRP only | A cap event recorded for one party | Other BRPs do not see it. The named BRP should read it with the price flag |
| Any other stored string | NotificationLedgers.record /
EventIncidents.deliver |
Public or the named party | Invalidation, a retry, any §16(2)(f) type that was delivered or failed | The Event column is the name, not a pick-list. Failed detail is on Cadence |
Empty ledger: No notices have been recorded for this day.
Publish has not written schedule.published, and nothing
else has been recorded.
Delivery recorded (emerald) vs failed (red): §13.7. Retry: §14.5.
B. The event stream — named kinds
The Market Code requires you to publish how events travel, and what
happens when they fail (§16(2)(f)). The feed is
GET /api/v1/events (live stream or a JSON poll). There is
no event table. Each kind is projected from a row the
market already wrote.
In the feed today (projected from a persisted row):
| Event | Who issues | To whom | Trigger | What the recipient should do | If they ignore it |
|---|---|---|---|---|---|
| notice.published | You, on this form | Public feed | A tannoy publish | Read the type and message | Same as §15.9 |
| schedule.published | Publish | Public | A clearing run is published | Fetch their schedule | They still settle; they may miss the hours until they poll |
| prices.published | Publish | Public | Same instant as schedule — a second event | Read SMP / reserve prices | Settlement still uses the published prices |
| idm.cleared | IDM publish | Public | An intra-day auction published | Read the new volumes and Intra-Day Price | Their contracted position may have moved without them looking |
| balancing.prices.published | Balancing publish | Public | A balancing run published | Read the vintage (provisional vs official) | Official D+7 is what money follows |
| submission.rolled_over | Gate / rollover callable | That party | They were silent; yesterday’s body was copied | Check the rolled-over bid before the next gate | They trade on stale volume. Staleness can escalate |
| registry.counterparty_change | Registry write (§7.1(6)) | The notified party | A Point of Delivery was ADDED or REMOVED | Confirm or Dispute | Silence leaves the meter at pending reciprocity. Energy at that node may not reconcile |
| credit_cover.increase_notice | Daily 17:00 cover job (or an opened cover window) | That party | Posted cover is short of required | Post more cover or pay an outstanding invoice early, by 17:00 on the second working day | Path toward default. A Default Notice can follow. Suspension is a later, gated step |
| credit_cover.warning | Same daily job | That party | Headroom has fallen to the Warning Limit — they are still covered | Top up or reduce exposure before it becomes a call | The next business day can be an Increase Notice |
| invoice.issued | Billing issue | The recipient organisation | A tax invoice (or self-billing invoice, same event name unless it is a credit note) | Pay in full by EFT on the due clock — pay now, argue later | Shortfall. A query does not hold the invoice |
| credit_note.issued | Billing issue | The recipient | A credit note | Apply it to the account | The ledger still moved |
| document.received | Billing issue | The recipient | Another issued document kind | Open the document | Same as any issued paper they did not open |
Named in the vocabulary, not yet in the feed (specified; a participant waiting forever should be told these will not arrive yet):
| Event | Intended trigger | Why it is listed |
|---|---|---|
| gate.closing | T−30 and T−5 before a gate | Specified reminder. Not projected today |
| gate.extended | You extend a gate on Submissions | The desk can show extended. The event is not in the feed yet |
| statement.issued | Indicative or Initial statement | Specified. Statements exist on Accounts / the party desk; this event name is not projected |
| bill.updated | A bill line changed | Specified; not projected |
| credit_call.made | You draw posted cover | The call is computed on the billing month. The event name is not projected |
| query.resolved | A settlement query closes | Specified; not projected |
Note. The stream is a speed-up, never the system of record. If a party’s webhook drops at 09:58, they can still poll. A failed
schedule.publishedis an incident on Cadence, not a missing chalkboard line.
C. Credit cover and money
These are not tannoy types. Accounts and the billing board show Required · Posted · Headroom · Notices.
| Kind | Who issues | To whom | Trigger | What they must do | If they ignore it |
|---|---|---|---|---|---|
| Credit Cover Increase Notice | Daily recalculation, by 17:00 on a business day | The named party | Posted < Required | Post additional cover, or pay an unpaid invoice early (§15.10.2(3)), by 17:00 +2 working days | They can fall into default. You may then issue a Default Notice. A Suspension Order is not automatic, and cannot be solely because cover was absent in a lawful replenishment window |
| Warning Notice | Same job | The named party | Headroom ≤ Warning Limit, cover still enough | Treat it as the last quiet warning | Next shortfall is an Increase Notice, then a possible call |
| Credit Call | Settlement / cover engine when cover is drawn | The named party (rapid means in the Code) | Posted cover is called for a shortfall | Re-establish cover within two business days | Remaining cover falls. Further default grounds can open |
| Replenishment window / new-provider window | You, on Accounts | That party (and the enforcement engine) | You open a window so cover may lawfully be absent | Replenish, or appoint a new Credit Cover Provider (ten business days) | When the window lapses, a cover-only Suspension Order can become lawful |
A party that pays an invoice early shrinks Actual Exposure, so the requirement falls. That is a real way to satisfy an Increase Notice without new cash.
D. Accounts, default, and who may trade
| Kind | Who issues | To whom | Trigger | What they must do | If they ignore it |
|---|---|---|---|---|---|
| Account notice (§6.2(11)) | The party | You | They opened a Collateral Reserve or Trading Clearing Account | You Review, then Remove from the inbox once read | Opening the account is not enough. Until they tell you in writing, the Code’s notice has not happened. Remove dismisses the inbox item; it does not un-notify the account. Home: §18.4 |
| Default Notice (§6.3.1) | You | The named party | Material default (Code, another Code, licence, MPA, Balancing Agreement, credit-cover shortfall, payment, insolvency) | Remedy by the stored date — at least two business days. Do anything else you wrote on the notice | After the deadline you may escalate. A Suspension Order may issue no earlier than one business day after the notice, and not solely for cover-absent-in-a-window. Home: §21.9 |
| Party’s own default report (§6.3(3)) | The party | You | They became aware they were in default | Tell you as soon as reasonably practicable | The gap between “knew” and “said” is the finding. It is recorded on the notice, not guessed |
| Suspension Order | You, from an open Default Notice | The party (then each Trading Unit) | Remedy expired / you choose to order, after the floors | Stop when Enforcement is in effect — not when the badge first appears | They may still bid in the delay period. Once in effect, those units are out. Home: §21.10 |
Participants at risk on Accounts (owes / short by) is an early warning, not a Default Notice.
E. Registry notes — System Operator share
When the books change, the System Operator must be told in the same write — not as a side-effect of the public event feed. That row is a registration notice. It lands on the SO Registry Inbox. Acknowledge is a signed receipt.
| Kind | Trigger | Who else feels it | If the SO ignores the inbox |
|---|---|---|---|
| TRADING_UNIT_REGISTERED | A unit finishes registration | The unit exists for tomorrow’s solve. Reserve stays 0.000 until they certify | No signed receipt. The unit can still be on the MO register |
| TRADING_UNIT_MODIFIED | Standing data changed, or you Chase an IPP
(#ipp-chase-{id} — Chase recorded for
{tuid}.) |
Completeness / certification may still be open | The chase is recorded; the SO still has to act |
| POD_ADDED / POD_REMOVED | A Point of Delivery was added or taken off | The other party also gets a §7.1(6) notice (below) | Pairing can stall |
| CERTIFICATION_REQUESTED | You Certify on IPPs | Certified MW stays 0.000 until the SO agrees a figure | They cannot truthfully offer reserve |
| BALANCING_GROUP_DESIGNATED / AMENDED / CANCELLED | A group is named, changed, or ended | Members net (or stop netting). Participants shows Notified vs overdue | An uncommunicated designation is a finding against you |
| ZONE_CONSTRAINT_RAISED / LIFTED | The SO raises or lifts a runtime zone flag | Members pushing that direction drop out of a balancing group for those hours only | Settlement still uses the flag. The notice is the receipt that they were told |
Home for the SO inbox: V12 §3 and §22 / §23 / §24.
F. The other party at the meter
§7.1(6): when a change adds or removes a Point of Delivery, you must tell the other Party. That row is a counterparty notification.
| Kind | Who issues | To whom | What they must do | If they ignore it |
|---|---|---|---|---|
| ADDED | The registry write (MO duty) | The notified party | Confirm the same electrical node, or Dispute with a reason | Status stays PENDING. The pairing is one-sided. It is not a settlement basis |
| REMOVED | Same | The notified party | Acknowledge that the pairing is gone | They may still think the node is live. Energy stops reconciling on their side |
PENDING is silence. DISPUTED is “we looked and this is wrong”. Only CONFIRMED promotes the point out of pending reciprocity.
G. System Operator notices — not this page
Do not issue a tannoy SYSTEM_STRESS to obtain
curtailment treatment. The SO desk issues orders that
change Instructed Energy.
| Kind | Everyday name | Audience | Money / eligibility |
|---|---|---|---|
| CURTAILMENT | Do not generate above this cap | Target BRP | Instructed Energy drops. 5 % slack off for instructed hours |
| DISPATCH_CONSTRAINT | Stay inside these MW / ramp bounds | Target BRP | Yardstick is the instructed path |
| OUTAGE_PLANNED / OUTAGE_UNPLANNED | This site is offline | Target BRP | Instructed Energy is the outage |
| RESERVE_ACTIVATION | Move the reserve you were holding | Target BRP | Reserve settlement, not a new SMP |
| SYSTEM_CONDITION | The grid is stressed (LOW / MEDIUM / HIGH) | Every Bid Desk | Banner only. No MWh |
Full teaching: V12 §3.
H. Nearby things that look like notices
| Thing | What it actually is | This console? |
|---|---|---|
Clear Security Notice
(#clear-day-network-notice) |
An on-screen alert about the network model on that run (degenerate / assumed). Not a BRP inbox item | No |
| Network-model Acknowledge (§24) | Two-month notice before a new SO model binds. You record the ack | No |
| Silent units on Submissions | They did not bid. Rollover may copy yesterday. Not a tannoy | No |
| Invalidated units on Daily | A registry change broke an accepted future bid. They think they are done. Chase them before the next gate. The exception bullet is the count. A party-scoped ledger row can be stored; this form cannot send one | No |
| Event-delivery incidents | Machine doorbell failed. Retry is not a re-publish | No — Cadence |
| Indicative / Initial statement | The month’s lines. Not this tannoy. statement.issued is
specified, not yet in the feed |
No |
| Schedule report itself | §9.10(2) puts settlement in the schedule. Fetching the schedule is being notified of that day’s chalkboard | No |
15.11 Consequences — a short list you can defend
A notice’s job is to change what the recipient does next. Money and eligibility change only when the underlying fact changes — the notice is how they were told.
| If this was ignored | What can happen in this market |
|---|---|
| Tannoy General / System stress / Price-cap event | They trade without the context. Prices, gates, and Instructed Energy do not move because of the ignore |
| schedule.published (especially failed) | They may not have pulled their hours. They still settle. You still have an incident to retry |
| submission.rolled_over | They run yesterday’s volume. Wrong for a changed plant |
| Increase Notice | Cover stays short. Default grounds open. Suspension is later and gated |
| Warning Notice | They get no second quiet day. The next print can be a call |
| Default Notice | Remedy clock runs out. You may escalate and, after the floors, order a suspension |
| Account notice (they never sent it) | The account exists at the bank but the Code’s written notice to you did not |
| ADDED / REMOVED at a meter | Pairing stays pending or disputed. That node is not a settlement basis |
| ZONE_CONSTRAINT_RAISED | Balancing-group netting already changed for those hours. The notice was the receipt |
| SO CURTAILMENT (wrong desk) | If they ignore an order, Instructed Energy still moved. Imbalance is priced against the cap they did not follow |
Pay now, argue later still holds. A Settlement Query does not hold an invoice. A notice about a query is not a stay of payment (§8).
15.12 How to prove a BRP saw the tannoy
Publish, then open a BRP seat (trader_1@webill.net) →
Market → Notices. The same text is there. That equality
is the check.
Cadence’s event-delivery incidents are a different channel — machine
delivery of schedule.published, retried from §14.5.
A BRP can Archive a card on their inbox. That is their filing. It does not retract your log.
Follow along. Seat:
mo@webill.net. Path: Notices → type General → textGate held to 10:15 under §9.3(3)→ Publish. You should see the card on Recent. Thentrader_1@webill.net→ Market → Notices. Same sentence.
Careful. Do not use this page to dispatch a plant, to invalidate a bid, to call credit cover, or to start a default. Those have their own desks. This page is the sentence every BRP was supposed to hear.
16. Metering
Path: Market Operator → Metering
(/mo/metering). First item in Settlement.
The icon is a queue-list.
After 14:00 the job moves here. The chalkboard is done. This desk is
pairing, verification, and the D+7 vintage gate.
Re-ingest and Allocate are the two
jobs that turn a Network Operator batch into Actual Energy the balancing
desk can price. They are the same callables Cadence and the cron fire
(ingest_metering, allocate_metering). No
Network Operator batch is an empty-ingest desk state, not a missing
page.
Where this is taught. How a meter becomes an interval and how pairing works: V9 §14. This chapter is the inbox.
16.1 The operator’s problem
Energy was sold. Now the meters have to confess. Until every Point of Delivery is paired, and until readings are verified inside seven business days, you cannot publish official balancing prices. An empty registry that looks “100 % paired of nothing” is the most dangerous green of all.
16.2 How the page is laid out
Browser title: Metering. Header: Metering — After 14:00 the job moves to meters. Pairing, verification, and the D+7 vintage gate.
No tabs. Query param: ?date=YYYY-MM-DD (same default
Trading Day as Bidding). Previous / next
(#mo-metering-prev, #mo-metering-next) step
that date by one day. The selected window is always 00:00 –
23:59 SAST for that Trading Day.
| Block | Id | Job |
|---|---|---|
| Action bar | #mo-metering-date-form |
Date. Previous/next (#mo-metering-prev,
#mo-metering-next) sit beside the input, not inside the
form. Re-ingest / Allocate on the right. |
| Intake banner | #metering-feed-status |
Feed label, note, batch id when present |
| Last ingest / allocate | #metering-last-ingest,
#metering-last-allocate |
Outcome chips and the last run |
| Metering and allocation | #allocation-status-board |
Verification, pairing, exceptions |
16.3 Controls — date, ingest, allocate
| Control | Id | What it does |
|---|---|---|
| Trading day | #mo-metering-date |
Patches ?date=. Both buttons run against this day, not
“today” on the wall. Previous / next step one day. |
| Re-ingest | #reingest-metering |
Pull the Network Operator’s readings into the day
(Cycles.ingest_metering/2). Flash Re-ingest {tag}.
or Re-ingest recorded a miss ({reason}). Empty ingest is the
state. |
| Allocate | #allocate-metering |
Turn those readings into Actual Energy per Trading Unit
(Cycles.allocate_metering/2). Flash Allocate
{tag}. |
| Status chip | Id | How to read it |
|---|---|---|
| Feed | #metering-feed-status |
Label + note from the desk |
| LAST INGEST | #metering-last-ingest |
Stamp, or No ingest run for this day. |
| LAST ALLOCATE | #metering-last-allocate |
Stamp, vintage, and how many actuals, or No allocate run for this day. |
| Feed label | Meaning |
|---|---|
| Network Operator feed absent | No production adapter; demo overlay is labelled in the spec |
| Empty ingest | A miss / no batch — #metering-ingest-empty says
Empty ingest is a desk state, not a missing page. |
The two buttons are not one job with two names. Ingest collects. Allocate assigns. Pressing the wrong one, or only one, is how a day looks busy on Cadence while Balancing still has nothing to price.
Metaphor. Re-ingest is collecting the meter books from the Network Operator. Allocate is writing each kilowatt-hour twice — once for the party at the point, once (sign reversed) for the party on the other side — so someone can be billed and someone can be paid.
What Re-ingest does
Re-ingest asks: did this Trading Day receive meter readings?
The Network Operator (not you, not a BRP) owns the meters and submits
the batch for points in its area. The market settles by the hour, so the
job counts and records what arrived for the selected day. Cadence writes
a row on #mo-cadence-ingest_metering.
| Outcome | What it means |
|---|---|
| ok | At least one reading exists for the day. Last ingest shows accepted / rejected counts. |
miss (empty_ingest) |
Zero readings. The desk stays on empty ingest. That is a recorded miss, not a skipped healthy day. |
What it does not do: it does not pair points, it does not write Actual Energy, it does not invent meters when the feed is absent, and it does not run balancing. A green Re-ingest with Allocate still pending is an honest unfinished day.
Cron already calls the same job on a continuous / daily cadence (in the seeded month: D+1 06:00). The button is for when you cannot wait for the next bell, or when a late or corrected batch arrived after the bell had already rung.
When you should Re-ingest — and why
| Situation | Why you press it |
|---|---|
Cadence #mo-cadence-ingest_metering is
pending, due, or
missed with empty_ingest |
The day never received a batch. Official balancing cannot become official on silence. |
| The Network Operator sent a late or replacement batch | The last ingest is stale. A new count must be on the record before Allocate sees it. |
| Last ingest is No ingest run for this day | Nobody has called the job for this date yet — cron missed it, or you are walking a day by hand. |
| Feed says Empty ingest and you believe a batch exists | Prove it. If Re-ingest still misses, the feed really is empty; hunt the Network Operator, not Balancing. |
Do not press Re-ingest because pairing is Unready or
an exception names REGISTRY. That is not a missing batch;
that is a missing counterparty. Re-ingest will not register a party. Fix
the registry, then Allocate.
Do not press it as a substitute for Run the day. Run the day stops at publish. It never ingests.
What Allocate does
Allocate asks: who does each metered hour belong to?
It takes the day’s ingested readings, rolls them to Trading Periods, and for every hour at every Point of Delivery writes two legs (Market Code §12.3(1)):
- The point’s own Trading Unit, with the signed megawatt-hours.
- The counterparty’s Trading Unit, with the sign reversed.
The net across a unit’s points is that unit’s Actual Energy — the number Balancing subtracts from the schedule. Allocation always runs. One unpaired point must not halt the market: every other unit still gets its figure, and the broken point becomes an exception (sorted by MWh at risk on the board below). An empty ingest still produces an empty allocation and a miss, not a skipped healthy day.
Cadence writes a row on #mo-cadence-allocate_metering.
Last allocate shows the vintage
(PROVISIONAL / VERIFIED /
REVISED) and how many actuals were written.
| Vintage | When it appears | What it may feed |
|---|---|---|
| Provisional | From D+1, while any reading is still an estimate | Preliminary balancing, indicative statements. Never invoiced. |
| Verified | Once every reading in force is an actual, by D+7 | Official balancing prices, initial statements. |
| Revised | After a query, dispute, or meter test | A settlement rerun. The old vintage stays readable. |
Official balancing refuses unverified vintage. That
refusal is a Cadence row (refused), not a missing page.
Allocate is how the vintage gets onto the record so Balancing can see
it.
Cron already calls the same job daily and again at verification (seeded month: D+1 06:30 provisional, D+7 06:30 verified). The button is the same callable, on this day, now.
What it does not do: it does not fetch a new Network Operator batch, it does not net across a party’s Trading Units (that is a Balancing Group), and it does not add network losses (those are the Network Operator’s own purchase).
When you should Allocate — and why
| Situation | Why you press it |
|---|---|
| Re-ingest just ok’d, and last allocate is missing or older than last ingest | Actual Energy is still yesterday’s (or nobody’s). Balancing will price the wrong meters, or none. |
Cadence #mo-cadence-allocate_metering is
pending / due /
missed |
The D+1 (or D+7) bell was skipped. Preliminary or official prices cannot be honest without this row. |
| You paired a Point of Delivery that was Unready | Ingest already had the kWh. Allocate is what writes the two legs now that both names exist. |
| Readings moved from estimate to actual (the D+7 verification) | Vintage must move from provisional to verified. Official balancing
stays disabled until this run says VERIFIED. |
| A revised batch landed after a query | Allocate again so the new vintage is a new row, not an overwrite. |
Do not Allocate before there is anything to ingest.
You will get a miss (empty_ingest) and an empty board.
Re-ingest first.
Do not Allocate to “clear” a registry exception. If
the point still has one BRP, Allocate will raise
:single_brp_at_point again. The hunt is Participants /
Registry, then Allocate.
Run the day does not allocate. A green publish with allocate still pending is unfinished. Cadence will show it; this button is how you finish it.
Order, and what happens if you skip a step
The honest sequence for a day is:
- Network Operator batch exists (or you accept empty ingest as the state).
- Re-ingest — the day has readings on the record.
- Pairing is ready enough that Allocate can write legs (unpaired points become exceptions; they do not halt the rest).
- Allocate — Actual Energy exists at a vintage.
- Balancing can run. Official waits for verified.
| If you… | What you get |
|---|---|
| Skip Re-ingest, press Allocate | Miss. Empty allocation. Board: No metering has been submitted for this Trading Day. |
| Re-ingest and stop | Cadence ingest ran, allocate still pending. No Actual Energy. Balancing has nothing new. |
| Allocate, then a late batch arrives, and you do not Re-ingest + Allocate again | Balancing prices the previous meters. Last allocate is a lie about “now”. |
| Only watch Daily / Publish | The chalkboard can look solved while meters never arrived. |
Read Last ingest and Last allocate after every press. Then read Cadence for the same two rows. Then read the allocation board.
16.4 The allocation board — how to read it
Empty (#allocation-status-empty): No metering has
been submitted for this Trading Day.
| Stat | Id | How to read it |
|---|---|---|
| Verification | #verification-progress |
State PENDING / VERIFIED /
OVERDUE, verify-by date, days remaining or days past
(clause 12.2(2)) |
| Not yet actual | #unverified-readings |
Count still unverified |
| Interrogation failures | #failed-interrogations |
Count |
| Deadline alert | #deadline-risk |
Only when OVERDUE — This Trading Day is past its
clause 12.2(2) deadline with {n} reading(s) still unverified. Official
balancing prices cannot be published on it, and an estimate carried past
the deadline becomes an official figure. |
| Pairing | #registry-readiness |
data-ready="true|false" |
| Exceptions by class | #exceptions-by-class |
Sorted by MWh at risk, not by count |
Pairing sentences:
- Empty registry: Unready — The finding is the zero. An empty registry is silent, not healthy — 0 SAWEM Trading Units and 0 Points of Delivery means allocation has nothing to pair and raises no exceptions.
- With points: {paired} of {points} points paired · {unpaired} unpaired — Every unpaired point is a settlement that cannot happen — for the participant that owns it and for whoever is on the other side of the meter.
Exceptions table: Class · Clause · Owner · Points ·
MWh at risk. Row #mo-class-{reason}. Footnote: Sorted
by megawatt-hours at risk, not by count: one unpaired point carrying 400
MWh matters more than forty carrying a tenth of one each.
Metaphor. Pairing is matching two names on a hotel register — the meter’s name and the market’s name. Verification is the night audit within seven days. Official balancing will not check out a guest whose bill is still a pencil estimate.
16.5 Worked day — 2026-07-15
Data. full_demo · seed 42 · Trading Day 2026-07-15.
| Field | What you should see |
|---|---|
| Verification | PENDING, verify by 2026-07-22,
4 day(s) remaining |
| Unverified | 3 |
| Failed interrogations | 1 |
| Exception | :single_brp_at_point, clause §12.3(1),
owner REGISTRY, 400.000 MWh at
risk |
| Pairing (3 points) | 1 of 3 points paired · 2 unpaired |
Official on Balancing stays disabled until this vintage is verified. That is the same refusal G5 already enforces.
Follow along. Path: Metering
?date=2026-07-15. Read#registry-readinessbefore you celebrate a quiet exceptions table. Press Re-ingest only if you mean to call the same job cron calls — a missing batch, a late batch, or no ingest row yet. Press Allocate after ingest (and after a pairing fix) so Actual Energy exists; D+7 official balancing will not run on a provisional vintage. Do not press either as a substitute for Run the day.
17. Balancing
Path: Market Operator → Balancing
(/mo/balancing). Second item in
Settlement. The icon is a chart-bar.
The day-ahead and intra-day markets settled what was
scheduled. This desk settles what the meters did
instead. After 14:00 the chalkboard is finished; the job is
stacks, two prices, and a residual that does not net to zero.
Run preliminary then Run official —
the same callable Cadence and the cron fire
(run_balancing). Official is disabled while metering
vintage is unverified — the same refusal G5’s job already enforces.
Where this is taught. Imbalance arithmetic, BPB/BPS, the against-instruction split, and the eleven payment legs: V9 §6. This chapter is the Market Operator board: what you press, when, and how to read the result.
17.1 What balancing is, and why it is required
A Trading Day sold energy at a System Marginal Price and patched it five times on the intra-day market. None of that asked the meters. By the next morning, some units over-produced, some under-consumed, some followed a System Operator instruction and some did not. The difference between Contracted Energy (the last IDM schedule, else the DAM constrained schedule) and Actual Energy (what Metering allocated) is imbalance. Someone is long. Someone is short. The market has to price that gap.
Balancing is that price, hour by hour, under Market Code §13. It is not a rewrite of yesterday’s SMP, and it is not the PPA till. Contract settlement prices delivered energy under a deal; balancing prices schedule error on the wholesale ledger. They share meters. They are not the same invoice.
Without it:
- A participant who under-forecasts would keep cheap scheduled energy and dump the rest on the system for free.
- A participant who over-forecasts would be paid as if the energy existed.
- The System Operator would have no residual account for the energy that does not net between buyers and sellers.
The mechanism builds two merit orders from submitted offer curves, not from what happened in real time:
| Stack | What it is | Price it feeds |
|---|---|---|
| Sold | What the System Operator could have bought to raise generation or cut consumption | Balancing Price (Buying) — BPB |
| Bought | The mirror, floored at Minimum Stable Generation | Balancing Price (Selling) — BPS |
Both prices are market-wide. You were 1.5 MWh short; you pay the price computed over the market’s shortfall that hour. Both stacks are published anonymised: an increment price is a unit’s own offer, and a named stack is every competitor’s cost curve. This desk is the view that gets screenshotted. TUIDs stay off it.
The Market Balancing Account is the residual. A positive figure is paid out to participants; a negative one is collected from them; what is left accrues to the System Operator (clause 13.3(4)). It does not net to zero the way the energy account does. Mixing this tile with Daily’s R 0.00 energy pot is how people invent a third invoice.
Prices come in two vintages because meters do. Preliminary is the pencil total the morning after, from provisional readings — what BRPs plan against. Official is ink on day seven, once readings are verified — what they are invoiced on. A dispute does not hold either up: payment first, argument after; a correction is a Settlement Rerun, not an erase.
Eleven payment legs cannot be operated from the DAM chalkboard. This is the room that produces them.
17.2 The operator’s problem
Meters arrived. Allocate wrote Actual Energy. You need a price for the gap that is not a quiet SMP, and you must not publish official prices on unverified readings. A button that inks a scorecard whose wickets are still under review would close the query window before the data exists (§12.2(2), §13.1(1)).
You also need to see when the penalty vanished. A period where the Out of Merit Energy allowance excluded the whole Sold stack settles perfectly normally and produces no penalty at all — BPB falls to the SMP. Nothing else on this screen would say so. That is the [D-07] alarm, and it is why the board exists.
17.3 How the page is laid out
Browser title: Balancing. Header: Balancing — After 14:00 the job moves to stacks. Preliminary then official, gated on verified vintage.
Query params: date (Trading Day) and stage
(PRELIMINARY default, or OFFICIAL). Example:
/mo/balancing?date=2026-07-15&stage=PRELIMINARY.
Previous / next (#mo-balancing-prev,
#mo-balancing-next) step the date by one day and keep the
selected stage.
The stage switch and the run buttons are not the same control. Preliminary / Official shows which published run you are reading. Run preliminary / Run official compute that run.
| Block | Id | Job |
|---|---|---|
| Trading-day card | #mo-balancing-date-form |
Date. Previous/next sit beside the input, not inside the form. Stage switch and the two run buttons. Last-run cards on the right. |
| Vintage gate | #official-vintage-gate |
Why Run official is disabled (when it is) |
| Balancing mechanism | #balancing-board |
Date badge, status badges, alarm/metric counts, 24 hour buttons, day-level MBA |
| Hour drawer | #balancing-hour-drawer |
One hour: SMP / BPB / BPS, volumes, Sold / Bought stacks |
| Reserve performance-factor inbox | #reserve-performance-inbox |
SO [S11] judgements; default 1.0 |
17.4 Controls — date, stage, last run
| Control | Id | What it does |
|---|---|---|
| Trading day | #mo-balancing-date |
Patches ?date=. Both run buttons fire against this day,
not “today” on the wall. Previous / next step one day and keep
stage. |
| Preliminary | #balancing-stage-preliminary |
Patches stage=PRELIMINARY — shows the preliminary
publication for that day |
| Official | #balancing-stage-official |
Patches stage=OFFICIAL — shows the official
publication, if one exists |
| Run preliminary | #run-preliminary-balancing |
Computes and publishes a preliminary run (see §17.5) |
| Run official | #run-official-balancing |
Computes and publishes an official run — disabled
when @desk.official_disabled? (see §17.6) |
Last-run cards: #balancing-last-preliminary,
#balancing-last-official. Outcome as a lowercase chip with
a colour dot (emerald ok, amber miss,
rose error / refused). Clock is SAST
HH:MM:SS. Empty: No preliminary run for this day.
/ No official run for this day.
The cards answer did this button already fire for this date?
They do not select the stage. A day can have an ok
preliminary and a refused official at the same time —
Cadence will show the official row as ran with outcome
refused. Emerald on Cadence is not “official is out”.
Metaphor. The stage switch is which scorecard you are holding. Run preliminary is the pencil total at close of play. Run official is ink. You do not ink a scorecard whose wickets are still under review.
17.5 Run preliminary
Run preliminary asks: given the meters we have today, what would §13 charge for this Trading Day?
It calls Cycles.run_balancing/3 with vintage
PROVISIONAL and status PRELIMINARY.
The engine builds both stacks, both prices, the market-wide imbalance
volumes, and the Market Balancing Account, then records a publication
the board can show. Flash: Preliminary balancing {tag}. Cadence
writes #mo-cadence-run_balancing-d{1..6} with callable
vintage PROVISIONAL.
What it does not do: it does not ingest meters, it does not allocate Actual Energy, it does not verify vintage, and it does not invoice anyone. A green preliminary with Allocate still pending is an honest unfinished day — the prices are a sketch over whatever AE exists.
Cron already calls the same job at 17:00 SAST on D+1 through D+6 (Market Code: a preliminary figure by 17:00 the day after the Trading Day). The button is for when you cannot wait for the next bell, or when the inputs moved after the bell had already rung.
When you should Run preliminary — and why
| Situation | Why you press it |
|---|---|
Cadence #mo-cadence-run_balancing-d1 (or d2…d6) is
pending, due, or
missed |
The timetable expected a sketch and did not get one. BRPs have nothing to plan against. |
| You just Allocated (or Re-ingested then Allocated) | Last night’s sketch is stale. The new Actual Energy must be priced before anyone trusts the board. |
| Last preliminary is No preliminary run for this day | Nobody has called the job for this date yet — cron missed it, or you are walking a day by hand. |
| You are inspecting a teaching hour or a dispute before 17:00 | The drawer is empty until a run exists. Preliminary is the legal way to fill it on unverified meters. |
| A late meter batch changed AE on a day that already had a sketch | Re-run so the stacks and MBA match the meters now in force. The old preliminary stays readable as history; the latest fill the board. |
Do not press Run preliminary because Run official is disabled. That is a vintage problem, not a missing sketch. Hunt Metering — Allocate until vintage is VERIFIED — then official.
Do not press it as a substitute for Run the day. Run the day stops at publish. It never balances.
Do not press it to “fix” an unpaired meter. Balancing prices the Actual Energy Allocate wrote. An unpaired point is an exception on Metering, not a missing stack rung.
17.6 Run official
Run official asks: are the meters verified, and if so, what does §13 charge for the invoice?
It calls Cycles.run_balancing/3 with status
OFFICIAL. Vintage is VERIFIED when
Metering says so, otherwise PROVISIONAL — and the
engine refuses that combination. The refusal is the row
(official_artefact_requires_verified_metering, clauses
§12.2(2) and §13.1(1)). Flash on refuse: Official refused —
{reason}. The same refusal G5’s job already enforces. Flash on
success: Official balancing {tag}.
Cadence’s D+7 row is #mo-cadence-run_balancing-d7 with
vintage VERIFIED. Official refused is
still ran. The button is disabled
(#run-official-balancing[disabled]) while
@desk.official_disabled? — while vintage is unverified.
When it is disabled, #official-vintage-gate says:
Official balancing is gated on verified vintage. The same refusal G5’s job already enforces (§12.2(2), §13.1(1)). A button that publishes unverified prices would close the query window before the data exists.
Cron already calls the same job at 17:00 SAST on D+7. Clause 12.2(2) wants verified data within seven days of the Trading Day; clause 13.1(1) builds official balancing prices on it. The button is for when D+7 has arrived, Allocate has moved vintage to VERIFIED, and you cannot wait for 17:00 — or the bell ran and refused, and you are retrying after fixing Metering.
The one exception is administered settlement (clause 15.11.2): a declared state that permits an official artefact from estimated data because the alternative is not settling at all. It is not a fallback this button invents. When an official run is administered, the board adds Administered settlement — clause 15.11.2. (instruction log not verified). The declaration itself is on Bidding → Month, not here.
When you should Run official — and why
| Situation | Why you press it |
|---|---|
Cadence #mo-cadence-run_balancing-d7 is
due or missed, and Metering vintage is
VERIFIED |
The invoice clock arrived. Preliminary is no longer the figure money follows. |
| Cadence D+7 ran with outcome refused | The bell tried. Vintage was still provisional. Allocate (D+7 verification), then press here so the refusal is not the last word. |
| Last official is No official run for this day, vintage is verified, and it is D+7 or later | The sketch exists; ink does not. Statements and invoices will follow the official publication, not the pencil. |
| A revised meter batch landed after official was already out | That is a Settlement Rerun, not a silent overwrite. The old official stays readable. Do not expect this button to erase it. |
Do not press Run official to hurry verification. The button cannot turn estimates into actuals. If it is disabled, the gate copy is the finding — go to Metering, Re-ingest / Allocate until the last-allocate chip says VERIFIED.
Do not press it on D+1 because the preliminary numbers look final. They are not. Official on unverified meters would close queries before the Data Verification Period exists.
Do not press it as a substitute for Run the month. Official balancing is a Trading Day artefact. Statements, invoices and cover are a Billing Period job on Cadence.
17.7 The balancing board — how to read a day
Empty (#balancing-board-empty): No balancing run has
been produced for this Trading Day. Press Run
preliminary (or wait for D+1 17:00) before hunting a missing
hour.
Header: date badge #balancing-board-date as
YYYY/MM/DD. Status badges
(#balancing-board-stage) for the selected
stage and vintage — no number, not clickable. They describe the
publication you are looking at, not the last-run cards.
| Badge | Id | Colour | What it shows |
|---|---|---|---|
| Stage | #balancing-badge-status |
slate | Selected PRELIMINARY / OFFICIAL |
| Vintage | #balancing-badge-vintage |
amber provisional / emerald verified | Selected PROVISIONAL / VERIFIED |
| Alarms | #balancing-badge-alarms |
rose | Count of [D-07] and other integrity events — click the
number |
| Metrics | #balancing-badge-metrics |
amber | Count of warning metrics — click the number |
Alarms and metrics (when present) are titled count
badges. Click #balancing-badge-{kind}-count to
open #balancing-badge-modal (unique badges, branded
header). [D-07] is on Alarms: the balancing penalty
does not exist — Out of Merit Energy excluded the whole Sold stack,
so BPB fell to the SMP.
Administered official still adds Administered settlement — clause 15.11.2.
Hours (#balancing-hours): two equal
rows of twelve (#balancing-hours-row-0 = 00:00–11:00,
#balancing-hours-row-1 = 12:00–23:00). Button
#board-period-{HHMM}. Daylight hours (07:00–17:00) are sky
with a sun; night hours are dark slate with a moon. The selected hour is
sky with a ring. Click opens the right-hand drawer —
not a per-hour MBA card. Day-level MBA stays below the grid.
Market Balancing Account
(#market-balancing-account) does not net to
zero. Net Settlement is the day’s
total_r. Footnote: Clause 13.3(4). A positive figure is
paid out to participants and a negative one collected from them; the
residual accrues to the System Operator and does not net to zero the way
the energy account does.
D-10 sits on #board-unpriced: {mwh}
of deviation across the day is unpriced (D-10). or No unpriced
deviation (D-10). That is the gap the Code does not price
(instruction vs contract vs delivery). It is reported, not invented into
a twelfth leg.
17.8 The hour drawer
Click an hour. #balancing-hour-drawer opens from the
right.
Branded header (#balancing-hour-drawer-header): the
hour, SMP / BPB / BPS (#board-prices-{HHMM}), and imbalance
volumes (#board-volumes-{HHMM}) — Bought and Sold
megawatt-hours across how many Trading Units (clause 13.2). Close
(#balancing-hour-drawer-close) or Escape-equivalent via the
control; changing date or stage also clears the drawer.
Two tabs — Sold stack
(#balancing-stack-tab-sold) and Bought
stack (#balancing-stack-tab-bought). Both tables
stay in the document (one hidden) so a screenshot of either side still
has no TUID. Stacks: #stack-sold-{HHMM},
#stack-bought-{HHMM}. Caption: Sold stack — anonymised
(clause 13.1).
Price and Volume headers
(#stack-{sold,bought}-sort-price, -volume) are
sortable. First click is ascending, second is descending; opening a new
hour restores merit order. Column headers are sticky
while the rungs scroll. The two columns sit on the
left.
Degenerate copy lives in the drawer
(#board-degenerate-{HHMM}): the indicative price is
undefined and the clause 13.7(4) floor is the whole answer.
Stacks never show a TUID. Screenshot-safe by construction. The per-unit decomposition lives in the run, one query away, for the person who actually needs it.
17.9 Reserve performance-factor inbox
#reserve-performance-inbox — read-only. The System
Operator’s performance-adjustment judgement ([S11]). The
factor is consumed as a plain input at whatever grain arrives. It is
never interpolated and never derived. The desk cannot type a factor the
System Operator did not send.
Absent criteria show as an amber notice (1 Notice / Default applied). There is no clause-modal button.
| State | Copy |
|---|---|
| Absent criteria | #reserve-performance-absent — Factor 1.0 —
absent criteria (clause 9.8.3(2)). Every contracted resource is
deemed to have performed acceptably. The counterfactual “would have
performed” cannot be derived. |
| Filed | #reserve-performance-judgements — Grain · Factor ·
Source · Note |
Never MO-authored. If the factor looks wrong, hunt the System Operator, not a missing field on this page.
17.10 Worked hour — 2026-07-15 18:00
Data. full_demo · seed 42 · §10.5 teaching hour (component fixture). A live demo day may already show last-run ok and a verified vintage; the empty last-run copy is for a date nobody has called.
| Field | Value |
|---|---|
| Imbalance Energy Bought | 3.734 MWh |
| Sold | 3.000 MWh |
| SMP / BPB (degenerate hour) | R 900.00 / MWh |
| Sold stack rungs (anonymised) | R 900, R 2,600, R 4,800 / MWh |
| Market Balancing Account | R 8,550.00 |
| Unpriced deviation (D-10) | 1.234 MWh |
| Reserve factor | 1.0 absent |
A tight hour (§10.6) with 20 MW Out-of-Merit: BPB R 2,600.00 / MWh, no D-07 alarm.
Follow along. Path: Balancing
?date=2026-07-15&stage=PRELIMINARY. Confirm the stage switch is Preliminary and the board badge says PRELIMINARY. If#run-official-balancingis disabled, read#official-vintage-gateand open Metering — that is the finding, not a broken button. Click 18:00: drawer with SMP / BPB / BPS, Sold stack prices and MW, noTU-. Sort Price / Volume; headers stay put. Click the Alarms number for[D-07]. Previous / next keep the stage. Switch Official only to read an official publication — press Run official only when vintage is verified and you mean to ink the day.
18. Accounts
Path: Market Operator → Accounts
(/mo/accounts). Third item in Settlement.
The icon is banknotes.
This is the till. Bidding wrote tickets. Metering said what happened. Balancing priced the gap. Someone now has to hold the cash, match the ledger to the bank, collect from the short, pay the long, and notice who cannot pay — without dipping into the Market Operator’s own fee to paper over a default.
The auctions do not move rands. A participant who bought energy does not pay the seller. They pay you. You pay the seller. That is the whole job of this desk: three bank accounts in the Market Operator’s name, and the month’s story of who paid, who is owed, and who is short.
Where this is taught. Which money is whose, and why MO Charge is ring-fenced: V9 §3.16 · V9 §15. This chapter is the operator’s board: what you read, in which order, and what each number is for.
Follow along. Seat:
mo@webill.netwith passwordsupersecret. Path:/→ Market Operator → Accounts. You land on Billing Period Settlement.
18.1 What Accounts are for
Wholesale electricity is cleared through a central counterparty. Every invoice and every payment goes through the Market Operator. If Buyer A owes Seller B, A does not send B a transfer. A pays the market. The market pays B. That way a default is your problem to contain, not a private argument between two participants.
To do that work the Code gives you three pots at one bank — the Market Bank — all in your name:
| Pot | Everyday name | What it is for |
|---|---|---|
| Trading Clearing | The coffee tin | Energy and imbalance money in and out this month |
| Collateral Reserve (the Central Reserve tab) | The rental deposit | Posted credit cover you may draw if someone does not pay |
| MO Charge | The shop’s own till | Your fee. Walled off. Never used to plug a hole |
They look like one account with three labels. They are not. Mixing them is how an operator accidentally underwrites the market with its own income.
Coffee-tin metaphor. Everyone who owes for coffee drops money in; the person who bought the beans takes money out. The tin is one tin. Whose money is whose is a list stuck to the lid — a designation — not a separate tin per participant. The deposit jar on the shelf is not the coffee tin. The shopkeeper’s own till is not either of those.
Without this desk you would discover a shortfall from the complaint, a broken ledger from the auditor, and an Excess Participant from the creditor who was asked to send money back. The board exists so those facts are visible before anyone phones you.
18.2 How the desk informs the operator
Read left to right, then down. The questions are in a fixed order because later numbers are meaningless if an earlier one is wrong.
- Does the ledger match the bank? If a money event wrote one layer and not the other, every figure below is scenery. That is the green or red reconciliation banner.
- Did this month collect what it billed? Expected in, received, the gap, owed out, paid out, still to pay. That is cash position. It tells you whether a cascade is coming.
- Who cannot pay, while there is still time? Participants whose own balance is short of their invoices, before the due date. That is at risk — an early warning, not a Default Notice.
- Has the month been invoiced? Four pots on the billing board: statements, invoices, self-billing invoices, shortfalls.
- Is anyone’s cover thin? Required versus posted, market-wide on the billing board; party operations on Credit/Debit.
- If someone did not pay, who takes the haircut? Debit notes on Credit/Debit. MO Charge is never in that arithmetic.
What you do not do here: rewrite yesterday’s SMP, pair a meter, or hold an invoice because someone raised a query. Payment first, argument after (V9 §15.2). The PDFs live on Billing. The query lifecycle lives on Dispute.
Run the month is not on this page. It lives on Cadence (#mo-run-the-month). This
desk shows the result.
18.3 How the page is laid out
Browser title: Accounts. Header: Accounts — Billing-period cash, the three market accounts, deposits, and the movement audit.
Seven icon tabs (#mo-accounts-tabs), same pattern as
Bidding (bordered tabs, heroicon, label). Default is Billing
Period Settlement. Query params: ?tab=,
?month= (ledger YYYY-MM), and ?settle=
(Billing Period YYYY-MM). Ledger tabs default to the
current calendar month; their month picker loads a
previous one. Billing Period Settlement defaults to the
previous calendar month
(Load.default_settle_month/0) — the same month as
Bidding → Month — and its own picker
(#mo-billing-month) opens an earlier period.
| Tab | Id | What it answers |
|---|---|---|
| Billing Period Settlement | #mo-accounts-tab-billing |
Did this month get paid? Calendar, cash, notices, the billing board |
| Trading Clearing | #mo-accounts-tab-trading_clearing |
The energy pot — balance and every movement this month |
| Central Reserve | #mo-accounts-tab-central_reserve |
Posted cover — balance and every movement this month |
| MO Charge | #mo-accounts-tab-mo_charge |
Your fee pot, the monthly tariff, and its ledger |
| Recent Deposits | #mo-accounts-tab-deposits |
Collateral that arrived into Central Reserve this month |
| Movement Audit | #mo-accounts-tab-movement |
Every money event, filterable, across the three pots |
| Credit/Debit | #mo-accounts-tab-credit_debit |
Cover operations, the debit-note cascade, replenishment windows |
Empty market (#mo-accounts-empty): No market
accounts have been opened yet. / The Trading Clearing,
Collateral Reserve and MO Charge accounts appear here once the money
layer is in use.
18.4 Billing Period Settlement
This is the month-end room. Come here after Cadence has run the month. The tab does not hold the three ledgers — those have their own tabs — it holds the story of the Billing Period: did we collect, did we pay, who is short, which documents went out, and which clocks are gazetted.
Billing period (#mo-billing-month) sits
at the left of the action bar. It is a month picker, labelled
Billing period, same control as Bidding → Month. Changing it
reloads cash position and the billing board for that month. A period
Cadence has not run shows No Billing Period has been settled.
The choice is kept in ?settle= when you move to another
tab, so Credit/Debit shows the same month’s cascade.
The three action buttons
#mo-accounts-billing-actions is the top row: picker on
the left, three buttons on the right. The buttons used to be cards
stacked under the board; they are now doors into modals so the board can
stay the month’s scorecard.
| Button | Id | Opens | What it is for |
|---|---|---|---|
| NERSA Publish | #mo-accounts-nersa-publish |
#mo-calendar-modal |
Write the clause 15.3.3 clocks for a year |
| Download NERSA Pack | #mo-accounts-nersa-pack |
#mo-nersa-pack-modal |
The Market Operator half of the regulator pack |
| Administered Settlement | #mo-accounts-administered |
#administered-modal |
Switch off the ordinary pipeline, with MGC approval |
Close any modal with #…-close-x, the backdrop, or
Escape.
NERSA Publish (#mo-settlement-calendar
inside the modal). The Code requires the settlement calendar
four months before the year starts. Year
(#calendar-year) + Publish
(#calendar-publish) writes the dates. Once published:
Published for {year} (#calendar-published). Under
the form, #board-calendar lists the gazetted clocks for the
open Billing Period (SAST, clause 15.3.3):
| Row id | Clock | In ordinary English |
|---|---|---|
#calendar-initial-statement |
initial-statement | When the month’s Initial Settlement Statement is due out |
#calendar-invoice-due |
invoice-due | When participants must have paid their invoices (12:00, three business days) |
#calendar-self-billing-due |
self-billing-due | When you must have paid the longs (17:00, four business days) |
#calendar-timetabled-rerun |
timetabled-rerun | The scheduled Settlement Rerun for the month |
You pay in four business days; they pay in three. That lag is deliberate: you have to have collected before you can distribute.
Download NERSA Pack (#mo-nersa-pack).
Copy on the card is the honest split: The System Operator report
side is not mounted. This is the Market Operator half.
Download curtailment-with-cost
(#nersa-pack-download) →
/mo/nersa/curtailment-cost.csv?trading_date={month}.
Administered Settlement
(#board-administered). Ordinary mode
(#administered-off): badge normal — the
pipeline Cadence already ran. Switching requires the Market Governance
Committee’s prior written approval (clause 15.11.1(d)).
The switch will not act without both fields:
| Field | Id | What you type |
|---|---|---|
| MGC approval reference | #administered-approval-ref |
The Committee’s written reference. Empty refuses |
| Methodology | #administered-methodology-text |
The published methodology (clause 15.11.1(e)). Empty refuses |
| Switch to administered | #administered-switch |
Throws the switch |
Once on (#administered-on): mode badge, trigger, clause,
the stored approval (#administered-approval), and when the
methodology was published (#administered-methodology). This
is not a calendar publish, and it is not “make the numbers nicer”. It is
the Code’s escape hatch when the ordinary pipeline cannot be used.
Reconciliation banner
#mo-accounts-reconciliation sits above cash. Read it
first. A cash position computed from a ledger that does not match the
bank is a number with no meaning.
| State | Copy | Colour |
|---|---|---|
| Reconciled | Reconciled — every account’s balance equals the designations inside it. | Green |
| Not reconciled | Not reconciled. A money event has written one layer and not the other; the figures below cannot be relied on until it is found. | Red |
When it is out, the banner lists each unbalanced pot: {label}: bank {R} against {R} designated — {R} out, and how many bank transactions have no matching entry on the other side. If this banner is red, stop. Find the unpaired write. Do not pay, draw cover, or explain the cash tiles to anyone until it is green.
The same banner repeats above each of the three ledger tabs. It is the same fact, not a second reconciliation.
Cash position
#mo-accounts-cash-position — Cash position —
{Month Year}. The month is the Billing Period on
#mo-billing-month, not the ledger month. This is the
period’s two-way till tape: what you asked for, what arrived, what you
must pay, what you have paid.
Empty: No invoices raised for this period yet. After invoices exist, six rows:
| Row | What it means | How to use it |
|---|---|---|
| Expected in from participants | The sum of invoices you raised | The ask |
| Received | What has actually arrived in Trading Clearing | The take |
| Shortfall | Expected − received. Bold rose when greater than zero | Someone has not paid. This is the hole |
| Owed out to participants | Self-billing invoices you must pay | The promise |
| Paid out | What you have already paid | The keep |
| Still to pay | Owed − paid | What is left to send on +4BD |
A cascade is needed
(#mo-accounts-cascade-needed) appears in amber when
collected is less than owed and money is still to pay
out. The copy tells you the next act: draw the defaulters’ posted cover
first; whatever remains comes off the creditors pro rata (§15.3.4).
The MO Charge Account is not available for this. That
sentence is the whole point of ring-fencing.
Participants short of what they owe
#mo-accounts-at-risk only renders when someone is short.
It is visible before the due date, which is the only
time it is useful — after due date the shortfall is already a fact.
| Column | What it is |
|---|---|
| Party | The BRP code |
| Owes | Outstanding invoices |
| Own balance | What sits in their own bank account, not in posted cover |
| Short by | Owes − own balance, in rose |
| Cover posted | Credit cover already in Central Reserve — the next place you draw |
This is not a Default Notice and
not a Suspension Order. It is the list of people you
may need to call. Row id: #mo-at-risk-{party_id}.
Account notices
#mo-account-notifications. Clause 6.2(11) requires a
written notice that a Collateral Reserve Account or
Trading Clearing Account has been established. Opening the account is
not enough. Until they tell you in writing, the Code’s notice has not
happened.
The heading carries a count
(#mo-account-notifications-count). Empty: No
outstanding account notices
(#mo-account-notifications-empty).
Each row (#mo-account-notification-{id}):
| You see | What it is |
|---|---|
| Subject | The notice title |
| BRP · notified {date time} | Who, and when the written notice landed |
| Review | Opens the body of the form |
| Remove | Clears it from the inbox once it is registered. It does not un-notify the account |
Home for the notice kind: §15.
The billing board
#billing-board. Same component as Bidding →
Month. Empty (#billing-board-empty): No
Billing Period has been settled. Press Run the
month on Cadence, then come back.
Title: Billing Period settlement. Footer: ledger clearing mode (Official balancing or Timetabled exact) and SAST (+02:00).
On this tab the board hides the calendar, the cascade, and the administered switch — those live in the buttons and on Credit/Debit. What remains is the month’s count.
Runs (#board-runs) — four coloured
pots:
| Pot | Id | Colour | Number | Subtitle | Click |
|---|---|---|---|---|---|
| Statements | #run-statements |
Sky | How many settlement statements were issued | {n} issued | Display only |
| Invoices | #run-invoices |
Indigo | Tax invoices on the billing register for the month | due 12:00 +3BD | Opens /mo/billing?month={YYYY-MM}&tab=invoices |
| Self-billing invoices | #run-self-billing |
Emerald | Self-billing invoices on the register | paid 17:00 +4BD | Opens
/mo/billing?month={YYYY-MM}&tab=remittances |
| Shortfalls | #run-shortfalls |
Amber; rose if any | How many invoices were not paid in full | {n} credit call(s) | Display only |
An invoice is a bill to a participant (they pay the market). A self-billing invoice is a bill the market writes to itself, on the participant’s behalf (the market pays them). You do not wait for sellers to invoice you. How those tax documents are raised: V15 §14. The register that lists them: §19. Empty register means the month has not been invoiced yet.
Credit cover, market-wide
(#board-credit-cover) — a snapshot, not the operations
desk. Party-level calls live on Credit/Debit.
| Column | What it is |
|---|---|
| Participant | Party id |
| Required | Cover the daily job says they must hold |
| Posted | What is actually in Central Reserve |
| Headroom | Posted − required. Red if negative |
| Notices | Warning and/or Increase Notice kinds outstanding |
Queries and disputes
(#board-query-inbox) — only when the inbox has rows. This
is a clock, not the Dispute room.
| Column | What it is |
|---|---|
| Tier | Data Query, Settlement Query, or Settlement Dispute |
| Participant | Who raised it |
| Raised | When |
| Deadline | Effective deadline (or the MO deadline) |
| Escalates to | What happens if they miss it |
Pay now, argue later. A query does not pause an invoice.
18.5 Trading Clearing
The energy and imbalance pot. Everyone who owes the market pays in; everyone the market owes is paid out. The money is held on trust — it is theirs, you control the movements, you may not mix it with MO Charge (V9 §3.16).
Come here to see the running balance and the month’s tape. The reconciliation banner is above the card; if it is red, the balance below is not to be trusted.
The account card
#mo-account-TRADING_CLEARING.
| You see | What it is |
|---|---|
| Label | Trading Clearing Account |
| Large figure | Bank balance — what the Market Bank says is in the pot |
| designated {R} | Sum of labels inside the pot. A green tick if it equals the bank balance; a rose cross if it does not |
| participants’ own positions {R} | Only if this differs from designated. The gap is cascade write-offs, which move no money |
There is no designation list under the total. The tape below is the detail.
Transactions
#mo-account-TRADING_CLEARING-statement. Every movement
on this Market Bank account for the selected month.
| Control | Id | What it does |
|---|---|---|
| Month | #mo-ledger-month-TRADING_CLEARING |
Loads that calendar month. Shared with the other ledger tabs |
| Search | #mo-ledger-search-TRADING_CLEARING |
Organisation name or BRP, 300 ms debounce |
Empty: No transactions on this account for {Month Year}.
| Column | What it is |
|---|---|
| Date | Value date as 10 'Aug '26. Sticky. Sortable
(#mo-TRADING_CLEARING-sort-date) — click toggles
newest-first / oldest-first |
| BRP | BRP code on top, organisation underneath. If the identifier is a Trading Unit, the TUID is on top instead. A dash if the row has no party (rare) |
| What Happened | Human label (see below) and a one-line narrative |
| Amount | Signed rands. Inflows +R … in green; outflows
−R … |
| Balance | Running balance on this pot after the row |
Rows highlight on hover. Date is sticky as you scroll sideways. The same table shape is on Central Reserve and MO Charge — only the pot changes.
What Happened labels you will see:
| Label on the tape | In ordinary English |
|---|---|
| Opening balance | The pot at the start of the month |
| Market invoice paid | A participant paid an invoice into Trading Clearing |
| Market payment received | You paid a self-billing invoice out |
| Credit cover posted | Cover arriving — usually on Central Reserve, not here |
| Credit cover drawn | You pulled posted cover into Trading Clearing to fund a shortfall |
| Credit cover released | Cover going back to the participant |
| Interest | Interest earned on their money, credited to them |
| Market Operator charge | A fee movement — usually on MO Charge |
| Debit-note reversal | A cascade haircut being put back after a late payment |
| Shortfall recovered | A late payment filling a hole |
| Set-off against amounts owed | The MO’s set-off right against a defaulter |
Interest and other non-EFT rows still name the BRP and organisation. The tape is the legal story, not only the bank’s EFT list.
18.6 Central Reserve
The locked jar. This tab is the Collateral Reserve
Account (#mo-account-COLLATERAL_RESERVE) — posted
credit cover.
Participants cannot withdraw it on request. You may draw it if they
default. Interest on it is still theirs.
Rental-deposit metaphor. The landlord holds the deposit in their name. You cannot ask for it back to pay the grocer. If you skip the rent, the landlord may apply it. That is this pot.
The card and the Transactions table are the same shape as Trading
Clearing (#mo-account-COLLATERAL_RESERVE-statement, month
#mo-ledger-month-COLLATERAL_RESERVE, search
#mo-ledger-search-COLLATERAL_RESERVE, date sort
#mo-COLLATERAL_RESERVE-sort-date). Typical rows here are
Credit cover posted, Credit cover
drawn, Credit cover released, and
Interest.
A draw is your act, not theirs: cover leaves this pot and lands in Trading Clearing to fund their unpaid invoice. After that, if a hole remains, it is Unsecured Bad Debt — and that is the cascade on Credit/Debit.
18.7 MO Charge
Your fee pot. Ring-fenced — walled off from every shortfall, every cascade, every “just this once”. The card says so in amber: Ring-fenced — never applied to a shortfall.
Shop-till metaphor. Customers’ layby money is in one drawer. The shop’s own takings are in another. When a customer vanishes, you do not make the other customers whole from the takings drawer. That is this tab.
#mo-account-MO_CHARGE repeats the balance / designated /
tick-or-cross pattern, then a Monthly tariff block
(#mo-charge-tariff).
| You see | What it is |
|---|---|
| Tariff copy | Each organisation is billed R {amount} a month. {n} issued this month, {n} paid. |
| No tariff yet | No monthly tariff yet. Set the amount charged to every organisation. Demo: R 5,000 / month |
| Set Monthly Charge | #mo-charge-tariff-open — opens the modal |
| Issue this month’s invoices | #mo-charge-tariff-issue — only if a tariff is already
set |
The modal (#mo-charge-tariff-modal):
| Control | Id | What it does |
|---|---|---|
| Amount in Rands | #mo-charge-tariff-amount |
Number, minimum 0.01 |
| Save and charge this month | #mo-charge-tariff-save |
Sets the monthly tariff and issues this month |
| Close | #mo-charge-tariff-modal backdrop / Escape |
Leaves the tariff unchanged |
Transactions (#mo-account-MO_CHARGE-statement) are the
same five columns. Typical What Happened:
Market Operator charge. Month and search ids follow the
same MO_CHARGE suffix.
18.8 Recent Deposits
Collateral arriving into Central Reserve, for the selected month only. This is not the full Central Reserve tape — it is the inflows of cover, so you can see who posted what without reading every interest line.
#mo-recent-deposits. Heading includes the count. Month
picker #mo-deposits-month. Empty: No collateral
deposits yet.
| Column | What it is |
|---|---|
| Date | When the cover landed (10 'Aug '26) |
| BRP | BRP on top, organisation underneath |
| Designation | The label inside Collateral Reserve this money sits under
({BRP}/COLLATERAL_RESERVE) |
| Amount | Always an inflow, shown +R … in green |
Row id: #mo-deposit-{id}.
18.9 Movement Audit
The combined tape. Trading Clearing, Central Reserve, and MO Charge each tell one pot’s story. This tab tells every money event in the month, so you can answer “what moved for this BRP?” without hopping pots.
#mo-movement-audit. Month picker
#mo-movement-month (same shared ledger month as the other
tabs). Empty: No movements match.
(#mo-movement-audit-empty).
Filters (#mo-movement-filter) apply
together:
| Filter | Id | What it matches |
|---|---|---|
| Party | #movement-party |
BRP, organisation name, or trading unit. Search, 300 ms debounce |
| Kind | select#movement-kind |
Which pot or source. Prompt All kinds |
| Reason | select#movement-reason |
Why the money moved. Prompt All reasons |
Kind options: Trading Clearing, Collateral Reserve, MO Charge, Market invoice, Credit cover call, Cascade, EFT payment, Interest run, Manual.
Reason options: Opening balance, Market invoice paid, Market payment received, Credit cover posted / drawn / released, Interest, Cascade reduction, Debit-note reversal, Market Operator charge, Shortfall recovered, Set-off against amounts owed.
| Column | What it is |
|---|---|
| Date | Value date (10 'Aug '26) |
| Party | BRP or Trading Unit on top, organisation underneath |
| Kind | Source kind, or the account kind if source is blank |
| Reason | Why it moved |
| Amount | Rands |
Cells are centred. Row id: #movement-{id}. Default order
is newest date first.
18.10 Credit/Debit
Last tab (#mo-accounts-tab-credit_debit). This is the
bad-news room: who must post more cover, who takes a
haircut when someone does not pay, and the dated grace in which a party
may lawfully be short of cover.
The billing board on the first tab still shows a market-wide cover
snapshot. Operations — the call, the cascade, the window — live here.
The cascade follows ?settle=, the same Billing Period as
the first tab’s picker.
Credit Cover Operations
#mo-credit-cover-ops. Cover is the bond you hold so that
if a participant does not pay, there is something to draw before you
touch creditors. It is assessed every business day by
17:00.
Warning Limit is the yellow line on a fuel gauge. Below it, a Warning Notice. Below required, a Credit Cover Increase Notice — post more cover, or pay an unpaid invoice early (that shrinks actual exposure) by 17:00 on the second working day (clause 15.10.2(3)).
| Column | What it is |
|---|---|
| Party | Name / MPID |
| Required | What the daily job says they must hold |
| Posted | What is in Central Reserve |
| Warning | The Warning Limit in rands |
| Notices | Outstanding kinds. An Increase Notice also spells out how to satisfy
it (#cover-satisfy-{party_id}) |
Row id: #cover-ops-{party_id}.
Instruments
(#mo-cover-instruments):
| Instrument | State |
|---|---|
| Cash | Enabled |
Letter of credit
(#mo-cover-lc-disabled) |
Disabled — [S28] |
Cash only. A letter of credit is specified; it is not mounted.
Debit-note cascade
#mo-debit-note-cascade. When an invoice is not paid, you
draw that party’s posted cover first. Whatever is still unpaid is
Unsecured Bad Debt. The Code does not leave that hole
sitting until next month, and it does not take it out of MO Charge. It
takes it off the people the market was about to pay.
Haircut metaphor. Ten creditors were due R 1,000,000 in total. One debtor left a R 100,000 hole after cover was drawn. Each creditor’s self-billing invoice is reduced by their share of R 100,000, in proportion to what they were paid this month. They still get paid — just less. That reduction is a debit note.
If no Billing Period has been settled: No Billing Period has been
settled (#board-cascade-empty). After a run with
nothing unpaid: No Unsecured Bad Debt this Billing Period
(#cascade-none).
When there is a hole (#board-cascade,
#cascade-total): {R} of Unsecured Bad Debt, allocated
on total payments in the month (clause 15.7); recovered {R}.
Column (#cascade-notes) |
What it is |
|---|---|
| Participant | Who takes the haircut |
| Debit note | Their share of the hole |
| Net receipt | What they still receive this period (self-billing minus debit) |
Excess Participants (#cascade-excess)
is the phone call. Their debit note is larger than the
self-billing invoice it was meant to come off. They receive
nothing this period and must pay the balance in cash
within two business days. Copy: {party} owes {R} in cash within {n}
business days ({clause}). An Excess Participant is a creditor being
asked to send money back. A total would hide them.
Over-recovery (#cascade-over-recovery), if the
arithmetic overshoots: Over-recovery of {R} plus the stored
note.
Replenishment Window
#mo-replenishment-window. A dated grace in which a party
may lawfully have too little cover while they top it up. Clause 6.4(4)
bars a Suspension Order solely because cover was missing during
this window. The window is the defence; the form is how you
record it.
The Code does not set how long the window lasts. That period comes from clause 15.10 and the Market Governance Committee. The form will not invent a close date.
Open a replenishment window
(#mo-open-replenishment-window):
| Field | Id | What you supply |
|---|---|---|
| Party id | #cover-window-party |
The party |
| Opened-on | #cover-window-opened-on |
Start date |
| Closes-on | #cover-window-closes-on |
Required. Empty is refused
(#mo-cover-window-error) |
| Open window | #cover-window-open |
Writes the record |
The card foot: {n} window(s) on record. There is no window table on this screen — the count is the audit that a later cover-only suspension can be shown to have been unlawful.
18.11 Worked month — July 2026
Data. full_demo · seed 42 · Billing Period 2026-07 · §10.7 golden month.
MP-ZETA does not pay. Cover does not cover the hole. The remainder is Unsecured Bad Debt and is taken off the creditors. MO Charge is not touched.
| Participant | Statement net | Paid | Cascade |
|---|---|---|---|
| MP-ALPHA | R 600,000 | R 600,000 | Debit R 250,000 · net R 350,000 |
| MP-BETA | R 300,000 | R 300,000 | Debit R 150,000 · net R 150,000 |
| MP-GAMMA | R 60,000 | R 60,000 | Excess: owes R 40,000 in 2 BD |
| MP-ZETA | − R 500,000 | R 0 | Starts the cascade |
| Unsecured bad debt | R 500,000 | ||
Initial statement example: 07 Aug 2026, 12:00. Debits 250 + 150 + 100 = 500. GAMMA’s R 100,000 debit eats the whole R 60,000 self-bill and leaves R 40,000 to pay in cash. MO Charge is not available to plug the hole.
Conservation: ALPHA 250 + BETA 150 + GAMMA 100 = 500 = ZETA’s unpaid. GAMMA was owed R 60,000 and is asked for R 100,000 — that is the Excess Participant, and that is the phone call.
A second demo on the cash tile (load/1 with a payer and a broke party): expected in R 5,100,000, received R 100,000, shortfall R 5,000,000; an at-risk party short R 2,000,000 on R 5,000,000 owed vs R 3,000,000 own balance.
Follow along. Path: Cadence → Run the month for a July date → Accounts. Read the reconciliation banner on Billing Period Settlement, then Trading Clearing / Central Reserve / MO Charge, then Credit/Debit until you see
#cascade-excess. Do not add MO Charge into the shortfall.
19. Billing
Path: Market Operator → Billing
(/mo/billing). Fourth item in Settlement.
The icon is a document with a currency sign.
This is the issued-documents room. Cadence ran the month. Accounts holds the cash. Here you open what that run actually put out: every tax invoice, self-billing invoice, debit note and credit note the Market Operator issued.
You do not raise documents on this page. Run the month lives on Cadence. The till, the cascade and who cannot pay live on Accounts. The PDFs live here.
Where this is taught. Why a party gets an invoice or a remittance, the two clocks, VAT, debit-note excess, and supply-only BRPs: V15 §14. This chapter is the operator’s register: what you click, in which order, and what each column is for.
Follow along. Seat:
mo@webill.netwith passwordsupersecret. Path:/→ Market Operator → Billing. Default month is the previous calendar month — the same Billing Period as Accounts → Billing Period Settlement and Bidding → Month. Overview ignores that picker: it is to date. The other tabs use it.
19.1 The operator’s problem
A participant phones and names a number. You need to find that document, see whether it was paid, open the PDF they hold, and — if it is a note — walk back to the original. You also need a lifetime picture: how much has been invoiced, remitted, and debit-noted, month by month, that agrees with the pots on the Accounts billing board.
Mixing that hunt into the till is how an operator loses the document in the cash. This room is the filing cabinet. Accounts is the safe.
19.2 How the page is laid out
Browser title: Billing. Header:
Billing — Every document the Market Operator issued
— invoices, remittances, notes. Page id:
#mo-billing-page.
Query params: ?month= (YYYY-MM), ?tab=
(overview · invoices ·
remittances · debit_notes · notes
· corrections · run), plus the document-tab
facets (q, direction, status). An
old ?tab=register&kind=TAX_INVOICE still opens
Invoices.
| Block | Id | Job |
|---|---|---|
| Month picker | #mo-billing-month-picker |
Which Billing Period the document tabs use |
| Export CSV | #mo-billing-csv |
On tabs 2–6. Same rows as that tab,
GET /mo/billing.csv |
| Tabs | #mo-billing-tabs |
Seven icon tabs, same chrome as Accounts |
| Default tab | #mo-billing-overview |
Lifetime roll-up |
19.3 The month picker
#mo-billing-month-picker. Same control the operator
Billing hub uses: previous (#mo-billing-month-picker-prev),
a month input (#mo-billing-month-picker-input), next
(#mo-billing-month-picker-next). Changing it reloads the
document tabs for that period. Overview stays to date.
Default is the previous calendar month
(Format.default_month/0). Today in August 2026 opens July
2026.
19.4 The seven tabs
Bordered icon tabs (#mo-billing-tab-{id}), same pattern
as Accounts and Bidding: an icon plus a label, not a pill of the tab
id.
| Tab | Id | Icon | What it answers |
|---|---|---|---|
| Overview | #mo-billing-tab-overview |
squares | Lifetime invoiced / remitted / debit-noted, by month |
| Invoices | #mo-billing-tab-invoices |
document | Tax invoices for the picker month |
| Remittances (SB) | #mo-billing-tab-remittances |
banknotes | Self-billing invoices, with utility acknowledgement |
| Debit Notes | #mo-billing-tab-debit_notes |
triangle | Debit notes for the picker month |
| Notes | #mo-billing-tab-notes |
document-minus | Credit notes for the picker month |
| Correction | #mo-billing-tab-corrections |
arrow-path | Notes that name the original they correct |
| Run | #mo-billing-tab-run |
play | Cadence rows for the month — read-only |
There is no combined Register tab. Each kind is its own room so the totals strip is only that kind. The Accounts billing board’s Invoices and Self-billing invoices pots open Invoices and Remittances (SB) for that month.
19.5 Overview
#mo-billing-overview. Three coloured cards, then a month
table newest-first from the last billed month. Void, draft and reissued
rows are left out so a replacement does not double-count.
| Card | Id | Colour | Figure |
|---|---|---|---|
| Total Invoiced to date | #mo-billing-stat-invoiced |
Indigo | Tax invoices, incl VAT (excl and VAT underneath) |
| Total Remitted to date | #mo-billing-stat-remitted |
Emerald | Self-billing invoices |
| Total Debit Noted to date | #mo-billing-stat-debit-notes |
Amber | Debit notes |
Table (#mo-billing-overview-table). Row id:
#mo-billing-overview-row-{YYYY-MM-DD}.
| Group | Columns | Background |
|---|---|---|
| Month | Written July 2026 |
White |
| Invoiced | Ex. VAT · VAT · Total Invoiced | Indigo |
| Remitted | Ex. VAT · VAT · Total Remitted | Emerald |
| Debit Notes | Ex. VAT · VAT · Total Debit Noted | Amber |
Footer (#mo-billing-overview-totals):
Totals, summing every numeric column. The three cards
are the same three Total columns. Empty
(#mo-billing-overview-empty): No billed months
yet.
Credit notes are not on this table. They live on Notes and Correction.
19.6 Document tabs
Invoices, Remittances (SB), Debit Notes, Notes, and Correction share
the same documents card — the totals strip and table the old register
used — filtered to that tab’s kind. Totals
(#mo-billing-invoices-totals and the matching id on each
tab) are Documents, Excl VAT,
VAT, Incl VAT for that kind
only, in rands, matching the visible (unpaged) set and the CSV to
the cent.
| Tab | Panel id | Kind |
|---|---|---|
| Invoices | #mo-billing-invoices |
TAX_INVOICE |
| Remittances (SB) | #mo-billing-remittances |
SELF_BILLING_INVOICE |
| Debit Notes | #mo-billing-debit-notes |
DEBIT_NOTE |
| Notes | #mo-billing-notes |
CREDIT_NOTE |
| Correction | #mo-billing-corrections |
Credit and debit notes that name an original |
Export CSV (#mo-billing-csv) on each of
these tabs. GET /mo/billing.csv?tab=invoices&month=…
(and the matching tab for the others). Facets ride on the query
string.
Facets (#mo-billing-facets):
| Facet | Id | What it filters |
|---|---|---|
| Search | #mo-facet-q |
BRP, trading unit, organisation name, or document number |
| Direction | #mo-facet-direction |
Invoice or Credit |
| Status | #mo-facet-status |
Issued · Paid · Short paid |
Empty (#mo-billing-invoices-empty on Invoices, and the
matching empty id on the other tabs): No documents for
{YYYY-MM}.
The table is paged at 50 rows. Invoice / debit-note / note row id:
#mo-doc-{id}. Remittance rows keep the older ids so a
utility acknowledge still has a stable hook: #mo-remit-{id}
(utility) or #mo-remit-part-{id} (participant). Correction
rows: #mo-correction-{id}.
| Column | What it is |
|---|---|
| Number | Gapless tax-invoice number. Opens
/mo/billing/documents/{id} |
| Kind | Coloured chip (#mo-doc-kind-{id}):
Invoice, Remittance (SBI),
Debit note, Note |
| Party / entity | BRP or Trading Unit label, not a uuid if the directory knows it |
| Organization | Legal name |
| Type / Ack | On Invoices, Remittances (SB), and Debit Notes — the same columns on
all three. Utility or Participant. A
utility remittance shows acknowledged or
unacknowledged (#mo-remit-ack-{id}); other
rows show — |
| Original | Correction only. The number of the document the note corrects, as a link |
| Period | Written 1 June 2026, not 2026-06-01 |
| Excl / VAT / Incl | Rands |
| Due | Date, plus an aging chip (#mo-doc-aging-{id}): paid ·
current · 1–30 · 31–60 · 61–90 · 90+ |
| Status | Badge (#mo-doc-status-{id}): Issued · Paid · Short paid
· Void · Reissued · Draft. Under it, payment state
(#mo-doc-pay-{id}) |
| Delivery | #mo-doc-delivery-{id} — pending or delivered |
| Action | Eye (#mo-doc-view-{id}) opens the stored PDF on this
page |
The eye opens #mo-billing-document-modal with
#mo-billing-document-modal-viewer. Close it and you are
still on the tab. The number itself navigates to the document page.
Kind chips say both the Code term and the plain word on remittances (Remittance (SBI)). That is B8 as shipped.
A utility remittance is one whose recipient organisation is the supply-only org on an Eskom or municipal issuer. Participants are everyone else. Acknowledgement is the same timestamp the utility sets on Received.
Where this is taught. A rerun or a validated dispute arrives as a note, not a replacement invoice: V15 §17.
19.7 Run status
#mo-billing-run. Read-only. The copy says so: issuing
still happens on Accounts. What you see are
Cadence rows for this Billing Period (#mo-cadence-{id}):
callable · outcome, and in rose when the outcome is a miss, the
reason.
This is the same timetable as Cadence, scoped to the month on the picker. You do not press Run the month here. There is no CSV on this tab.
19.8 The document page
Path: /mo/billing/documents/:id. Only documents this
Market Operator issued — another issuer’s row redirects home with
not found.
Header: the document number. Description: The artifact the
counterparty holds. Body id: #mo-document-{id}.
| Block | Id | What it is |
|---|---|---|
| Header | #mo-document-header |
Kind chip, number, issuer → recipient, period, version, status,
payment state (#mo-document-payment) |
| Supersedes / successor / references / original | #mo-document-supersedes ·
#mo-document-successor ·
#mo-document-references ·
#mo-document-original |
Version chain and the note’s parent, when they exist |
| Lines | #mo-document-lines |
Grouped (wheeling energy, UoS, credits, …). Each
#mo-document-line-{id}: description, TOU, unit, market line
kind, amount + VAT |
| Annexures | #mo-document-annexures |
Trading Unit and Balancing Group pro formas attached to the party tax document |
| File | /mo/billing/documents/{id}/file |
The stored PDF |
Where this is taught. What is on the face, why the bank reference is not the tax number, and why a Trading Unit document is an annexure: V15 §14. The issued register that this room shares a lens with: V15 §9.
19.9 How this room sits next to Accounts
| You need to… | Open |
|---|---|
| Raise the month’s invoices | Cadence → Run the month |
| See whether they were paid | Accounts → Billing Period Settlement, cash position |
| See lifetime invoiced / remitted / debit-noted | Billing → Overview |
| Open the PDF / filter one kind | Billing Invoices, Remittances (SB), Debit Notes, or Notes |
| Argue a line | Dispute — the invoice was never paused |
The four pots on Accounts (#run-invoices,
#run-self-billing) are counts into these kind tabs. A count
that disagrees with its own drill-down is worse than no count.
Follow along. From Accounts, click Invoices on the billing board. You land here with
?tab=invoicesfor that month. Open an eye. The PDF is the artefact the participant holds.
20. Dispute
Path: Market Operator → Dispute
(/mo/dispute). Fifth item in Settlement.
The icon is a scale.
Mo.Settlement.Query tiers: Data Query, Settlement Query,
Settlement Dispute. Clocks, materiality, recalculation-threshold gate.
Pay now, argue later — a query never holds an invoice.
This is one resource with the org Recon. There is not a second inbox.
Where this is taught. How a BRP raises a query and what evidence looks like: V9 §8. This chapter is the MO side.
### 20.1 The operator’s problem
A participant disagrees with a line. The invoice is still due. You have a deadline, a materiality test, and — if the change is big enough — a rerun that applies to every participant, not just the complainant. You must not pause cash to be polite.
### 20.2 How the page is laid out
Browser title: Dispute. Header: Queries and disputes — Data Query, Settlement Query, Settlement Dispute — one resource with the org Recon.
No tabs. No URL params. The first query is selected for you.
| Block | Id | Job |
|---|---|---|
| Policy banner | #due-notwithstanding-dispute |
The rule, in one sentence |
| Query inbox | #query-inbox |
Every open (and recently moved) query |
| Query detail | #query-workflow |
Clock, evidence, resolve, rerun |
### 20.3 The policy banner
Pay now, argue later. Amounts fall due notwithstanding any query or dispute (clause 15.5(1)). Resolving a query does not pause an invoice.
The detail repeats it as Invoice held? {yes|no} — clause 15.5(1) forbids it. Expect no.
Metaphor. The restaurant bill is paid tonight. The complaint about the wine is a letter tomorrow. Holding the bill hostage is not a remedy the Code allows.
### 20.4 The inbox — how to read a row
Empty: No queries.
Each #query-row-{id} is a button. Click selects it.
| Piece | What it is |
|---|---|
| Tier badge | DATA_QUERY · SETTLEMENT_QUERY ·
SETTLEMENT_DISPUTE |
| Status badge | Open / resolved / written off — as stored |
| Subject | What they dispute |
| Party id | Mono — who raised it |
A query opened from org Recon appears here as a Settlement Query. Watch the BRP kanban move to RESOLVED when you resolve it.
### 20.5 The detail — clock, evidence, actions
#query-clock:
| Row | Id | How to read it |
|---|---|---|
| Market Operator’s deadline | #query-mo-deadline |
SAST datetime — yours |
| Materiality | #query-materiality |
Class, or — . Engine default threshold R 50.00 |
| Correction / statement | #query-correction |
{correction_r} / {statement_value_r} |
#query-lines shows the evidenced charge line when one is
attached. You should not resolve an aggregate difference: a decision
refers to one identified line.
| Control | Id | What it does |
|---|---|---|
| Resolve | #resolve-query-{id} |
Closes the query. Flash: Query resolved. The invoice was never paused. |
| Settlement Recalculation Threshold (%) | #rerun-threshold |
Required to request a rerun |
| Rerun for all participants | #request-rerun |
A diff statement (clause 15.3.5(4)), applied to every participant |
Rerun refused (#rerun-refused): Rerun refused
({reason}) — e.g. threshold_not_determined if the box
is empty. Success flash: Rerun is a diff and applies to every
participant. #query-rerun-diff shows the total
difference and the changed line count.
You should not resolve a case that has no evidence pack. You should not treat Resolve as a payment holiday.
### 20.6 Worked query
Data. Recon console tests · internal −R 2,793.50 vs MO −R 3,108.00.
| Field | Example |
|---|---|
| Tier | SETTLEMENT_QUERY |
| Variance | Those two numbers — the correction context |
| Threshold typed | 5 → #query-rerun-diff appears |
| Billing-board sibling | DATA_QUERY, party MP-BETA, deadline
03 Aug 2026, 17:00 SAST, escalates to
SETTLEMENT_DISPUTE |
Accounts’ #board-query-inbox is the summary of
the same objects. This page is where you work them.
Follow along. Raise a query from a BRP Recon seat (V9 §8). Open
/mo/dispute. Select the row. Read#due-notwithstanding-dispute. Resolve only after the evidence pack names the line. The invoice was never paused.
21. Participants
Path: Market Operator → Participants
(/mo/participants). First item in
Eligibility. The icon is a user-group.
Two boards sit above each other and they are not duplicates.
Registrations is the operational question — may
this registration bid today? Pending Clocks (and
the rest of the board) is the joining and enforcement lifecycle. A party
can be DEFAULT on the enforcement queue and
ACTIVE on Registrations, and both are correct.
Where this is taught. Every joining status, every screen, and every agreement step is V9 §3.13A. This chapter is the Market Operator’s queues.
### 21.1 The operator’s problem
Someone wants in. The Code gives them clocks, and you clocks, in business days. An undecided extension is itself a finding. A suspension that cannot bite looks complete from every angle and does nothing. You need worklists because your next action differs on each — but issued suspensions and blocked units are status on Registrations, not separate queues.
### 21.2 How the page is laid out
Browser title: Participants. Header: Participants — BRP admission, accession publication, enforcement clocks, and D2 registration status transitions.
Tab bar #mo-participants-nav. Eight
tabs — there is no Suspension Queue tab and no Blocked
Suspensions tab. Each tab is #mo-participants-tab-{id}.
Worklist tabs show a count (unpublished accessions, pending clocks,
extensions, open notices, balancing groups).
| Tab | Path | live_action |
Tab id | What it is |
|---|---|---|---|---|
| Registrations | /mo/participants |
:registrations |
#mo-participants-tab-registrations |
D2 seats. Defaults to Active — may they bid today? |
| Accession register | /mo/participants/accession |
:accession |
#mo-participants-tab-accession |
Who acceded and is still unpublished (§6.2(9)) |
| Pending Clocks | /mo/participants/clocks |
:clocks |
#mo-participants-tab-clocks |
Every running admission clock |
| Extension Requests | /mo/participants/extensions |
:extensions |
#mo-participants-tab-extensions |
Undecided written requests |
| Open Default | /mo/participants/defaults |
:defaults |
#mo-participants-tab-defaults |
Default notices and remedy dates |
| Balancing Groups | /mo/participants/balancing-groups |
:balancing_groups |
#mo-participants-tab-balancing_groups |
Every party’s designation — who nets with whom |
| Credentials | /mo/participants/credentials |
:credentials |
#mo-participants-tab-credentials |
Issue, rotate and revoke OAuth, mTLS and HMAC credentials (§21.12) |
| Vesting | /mo/participants/vesting |
:vesting |
#mo-participants-tab-vesting |
The vesting book: who is vested, on which unit, against which counterparty (§21.13) |
Bookmarks to /mo/participants/suspensions and
/mo/participants/blocked still resolve; they patch to
Registrations. Those are not tabs.
Above every tab: the Registration board header
(#mo-registration-board) and the seven-state cards. There
is no #accession-sla-summary under the stats — the
Accession register is the tab, not a card.
### 21.3 The seven states — orientation, not a worklist
Heading: The seven states (§6.2, §6.3, §6.4, §6.5).
#mo-registration-as-of stamps as at {date}. Empty:
No parties registered yet.
| Card id | State | Everyday name |
|---|---|---|
#mo-registration-state-APPLICANT |
APPLICANT | applicant |
#mo-registration-state-OFFERED |
OFFERED | agreements issued |
#mo-registration-state-ACTIVE |
ACTIVE | active |
#mo-registration-state-DEFAULT |
DEFAULT | in default |
#mo-registration-state-SUSPENDED |
SUSPENDED | suspended |
#mo-registration-state-TERMINATED |
TERMINATED | terminated |
#mo-registration-state-WITHDRAWN |
WITHDRAWN | withdrawn |
Counts only. Work happens on the tabs. The tiles use the same tinted chrome as the registry standing-data cards: sky applicant, violet agreements issued, emerald active, amber in default, orange suspended, rose terminated, slate withdrawn.
Do not press Activate on a freshly filed PENDING row; that move is refused. Work Pending Clocks.
Days remaining is in business days. A clock five days out can be a calendar week away. Whose clock it is, is shown. Two of the five admission clocks are yours and three are the applicant’s.
One clock is a window, not a duty. §6.2(4) says you may request further information within ten business days. Letting it lapse breaches nothing — the application is simply complete as filed. §6.2(6) is a shall.
21.4 Registrations — may they bid today?
#mo-brp-status-board — Registrations
(D2). Defaults to Active. Change
Status for Pending, Suspended, or Revoked — or
All statuses. In-flight applications are also on
Pending Clocks. Issued Suspension Orders show on the row as
scheduled, in effect, or
blocked (§21.10,
§21.11) — not as extra tabs.
Totals #mo-brp-registration-totals: N
registration(s) and N trading unit(s), with (M
shown) when a search or status filter hides some. Form
#mo-brp-registrations-filters.
| Control | Id | What it does |
|---|---|---|
| Search | #mo-brp-registrations-search-input |
Placeholder Search BRP REF or Organization |
| Status | #mo-brp-filter-status |
All statuses · PENDING · ACTIVE · SUSPENDED · REVOKED. Default ACTIVE |
| Sort BRP REF | #mo-brp-sort-brp-code |
Toggle asc/desc |
| Sort Organization | #mo-brp-sort-organization |
Same |
| Expand units | #mo-brp-registration-{id}-units |
Chevron + count. Detail
#mo-brp-registration-{id}-units-detail |
| View | #mo-brp-registration-view-{id} |
Opens the clock drawer (§21.6).
ACTIVE: Suspend / Revoke. SUSPENDED: Activate / Revoke. REVOKED:
Reactivate only
(#mo-application-action-{id}-ACTIVE). A revoked seat cannot
be suspended. |
Each row #mo-brp-registration-{id}.
| Column | Meaning |
|---|---|
| BRP REF | Registration code |
| Organization | Name + status badge |
| Registered | Date + N months in status (Less than 1 month in status when under a month) |
| Trading Units | Count; expands TUID · Official name · Class · Zone · Status ·
Enforcement · Site / Pool. Unit row
#mo-brp-registration-{id}-unit-{unit id} |
| Enforcement | #mo-brp-registration-{id}-enforcement — compact badges
for issued Suspension Orders: scheduled, in
effect (rose), blocked (amber). Dash if
none. |
| API auth | #mo-brp-registration-{id}-adoption — most recent
successful /api/v1 call: Bearer or
Header, and when. Dash if the party has not called yet.
Header-only is sandbox/test; production callers present a token (V13 §2). |
| Actions | View |
Expanded unit cell
#mo-brp-registration-{id}-unit-{unit id}-enforcement: delay
period ({N} business days ({parameter})), takes-effect ISO
date, and (when blocked) the reason. A unit on both the issued-order
list and the blocked list shows blocked, not
scheduled.
Class labels: Demand side, Generating, Storage, Mixed, Interconnector. Empty: No BRP registrations. Filter miss: No registrations match the current filters. Demo: BRP-T1-DEMO.
You should not activate a registration merely because it is needed for a demo day: verify the code, roles and guarantee first.
21.5 Accession register — the 7-business-day SLA
Path: /mo/participants/accession. Widget
#accession-sla. Tab badge is the unpublished count. There
is no #accession-sla-summary card under the seven-state
tiles — this tab is the register.
What an accession is
An applicant who has paid the fee and signed both agreements is still an applicant. They become a Party on the agreements’ effective date (§6.2(8)) — not when they apply, not when they sign. That step is the accession. Until it happens they cannot trade (commissioning aside). After it, they are in the market.
On this console, Activate on Registrations is the accession. The clocks, the two agreements, and the account notification that lead there are V9 §3.13. Reinstating a suspended participant is not an accession: nothing new is being acceded to.
What the table is
§6.2(9) obliges you to publish every accession on a public register within seven business days of that effective date. Weekends and gazetted public holidays do not count.
That register is not this table. The public surface is
GET /api/v1/registry/accession-register (V13 §5.1):
MPID, legal name, party type, qualifying criterion, acceded-on date,
published-at. No credit cover, no Warning Limit, no account numbers —
§6.2(9) makes the accession public, not the exposure.
This table is your compliance clock against that duty. It lists parties that already have an agreement effective date and shows whether you have stamped them onto the public register yet. Overdue first, then awaiting, then published.
Worklist tabs (Pending Clocks, Extension Requests, Open Default, Balancing Groups) carry an Accession badge on the party they already list, so you do not have to leave a chase to see the publication finding. Registrations does not — publication lives on this tab. Issued Suspension Orders and blocked units are Enforcement status on Registrations, not worklist tabs.
What each row means
Header summary: {unpublished} acceded, unpublished. {overdue}
past the seven-business-day SLA. Empty: No parties with an
agreement effective date yet.
(#accession-sla-empty)
Each #accession-sla-{party_id}:
| Column | Meaning |
|---|---|
| BRP REF | Registration code |
| Organization | Name |
| Effective date | agreement_effective_date — §6.2(8) |
| Acceded on | acceded_on — the day Activate actually
ran (may be later) |
| Publish by | Effective date + seven business days |
| Status | #accession-sla-status-{id} — awaiting publication /
overdue / published |
| Published at | published_at, or — |
| Actions | View #accession-sla-view-{id} — clock
drawer, read-only |
| Status | Meaning |
|---|---|
| awaiting publication | Acceded (effective date set). Still within the seven business days. Not yet on the public register. |
| overdue | Same, but today is past the deadline. A compliance finding against you, not against the participant. |
| published | published_at is set. They appear on the public
accession register. |
Metaphor. The licensing office issued the licence. The Code says the register must show it within seven business days. Overdue is not “the party is inactive” — it is you have not published the accession. Activate on Registrations makes them a Party; publication is the separate stamp that lets anyone else verify that they are one.
How to remedy it
- Finish accession first if they are not yet
ACTIVE— work Pending Clocks, then Activate when the agreements and effective date allow it. - Publish within seven business days of the effective
date. Publishing stamps
published_at. Until that stamp exists, the public register omits them and this table keeps counting. - Treat overdue as your queue, not theirs. Chase your own publication backlog. Calling the participant does not clear an overdue row — only publishing does.
- Re-check the public surface. After publication,
GET /api/v1/registry/accession-registermust include them. Anyone considering trading with that party uses that endpoint to confirm standing.
Note. This panel is observational — it has no Publish button. It exists so you see the SLA before someone else notices the gap. Late publication is still a finding (
publishedbut not on time); the overdue flag clears oncepublished_atis set, but the on-time record remains in the party’s publication status.
21.6 Pending Clocks
Path: /mo/participants/clocks.
#mo-registration-clocks — applications still in the
admission machine. ACTIVE seats are on Registrations, not
here.
Where this is taught. The four Code clocks and the fifteen application states are V9 §3.13 and V9 §3.13A. This section is the Market Operator’s worklist and the View drawer.
Every period is in business days (§2.3(2)(a)). A deadline five days away can be a calendar week. The panel names the three lapses the daily clock will take for you: unanswered information requests expire, reviewed applications become contractable, and contractable ones have agreements issued.
Empty: No pending application is on file.
(#mo-registration-clocks-empty) Overdue rows sort first and
tint rose (bg-rose-50).
Chasing a participant over your §6.2(6) deadline to issue the agreements sends the wrong person after the wrong thing.
The table
Each #mo-registration-clock-{id}:
| Column | How to read it |
|---|---|
| Party | BRP REF + organisation name |
| Accession | #mo-registration-clock-accession-{id} — awaiting
publication / overdue / published / — |
| State | Application-state badge (the fifteen-state machine) |
| Whose | Market Operator (amber) or applicant (slate) — who owns the next move |
| Deadline | Long date (%-d %B %Y). Then N business days left of
P, overdue — the daily clock will move it to {STATE},
overdue — nothing happens automatically, or no
clock |
| Actions | Eye #mo-registration-clock-view-{id} — tooltip
View pending application. Opens the drawer |
Whose is whose clock is running, not who may act. You may still Decline or ask for information while the badge says applicant.
A Market Operator overdue with nothing happens
automatically (PENDING, CONTRACTS_ISSUED,
CONTRACTS_SIGNED, APPROVED) is your
finding. An applicant overdue on
INFO_REQUESTED is taken by the daily clock to
EXPIRED.
The clock drawer
#mo-clock-drawer —
#mo-clock-drawer-backdrop click or
#mo-clock-drawer-close closes it. Header
#mo-clock-drawer-header: eyebrow SAWEM · Pending
application, title #mo-clock-drawer-title (BRP
REF), application-state badge, organisation · MPID.
The same drawer opens from Registrations and Accession register, but those tabs set it read-only except D2 status buttons (Activate / Suspend / Revoke / Reactivate). The header eyebrow is SAWEM · Registration on those tabs, SAWEM · Pending application on Pending Clocks. Pending Clocks is where you work the application.
| Tab | Id | When |
|---|---|---|
| Application details | #mo-clock-drawer-tab-details |
Always |
| Files | #mo-clock-drawer-tab-files |
Always |
| History | #mo-clock-drawer-tab-history |
Always |
| Ask for information | #mo-clock-drawer-tab-ask |
Writable drawer, and state PENDING or
INFO_SUBMITTED |
Jargon labels carry an i
(hero-information-circle). Hover for the definition. Ids
#mo-clock-drawer-hint-{field}. The details grid is two
columns. Left-column hints open to the
right (tooltip-right) so they are not clipped off
the drawer edge. Right-column hints open to the
left (tooltip-left). Full-width labels (Current
clock, Agreements, the note modal, Ask-tab textarea) sit on the left and
also open right.
Application details
#mo-clock-drawer-details. Four blocks, then the actions
footer.
Current clock. Hint
#mo-clock-drawer-hint-clock. Empty: No period is
running. Otherwise: state label,
§{clause} · Market Operator|applicant, Deadline
{long date}, then the same remaining / overdue sentence as the
table.
Information request
(#mo-clock-drawer-correspondence). One pair per round:
Question (your note + when) and
Response (theirs, or a dashed empty). Hidden when there
has been no round.
Standing fields.
#mo-clock-drawer-field-{id} — i on each
label (#mo-clock-drawer-hint-{id}).
| Label | Field id | Column | Hint | What it is |
|---|---|---|---|---|
| Organisation | organisation |
left | tooltip-right |
Applicant organisation name |
| BRP code | brp-code |
right | tooltip-left |
Registration reference |
| MPID | mpid |
left | tooltip-right |
Market Participant ID; on the public accession register |
| Roles | roles |
right | tooltip-left |
Generator / load / trader / distributor |
| Party type | party-type |
left | tooltip-right |
Entity kind under §2.1 |
| Qualifying criterion | qualifying-criterion |
right | tooltip-left |
Annexure 1 ground |
| Market participant | market-participant |
left | tooltip-right |
Yes / no — not the same as “may bid today” |
| Balance responsible | balance-responsible |
right | tooltip-left |
Yes / no — who settlement holds for imbalance |
| Registration status | registration-status |
left | tooltip-right |
D2: PENDING / ACTIVE / SUSPENDED / REVOKED |
| Application state | application-state |
right | tooltip-left |
Fifteen-state machine — the field you work |
| Party state | party-state |
left | tooltip-right |
Seven §6 states |
| Applied | applied |
right | tooltip-left |
Date received (§6.2(2)) |
| VAT number | vat-number |
left | tooltip-right |
As declared |
| Guarantee type | guarantee-type |
right | tooltip-left |
Form of credit cover declared |
| Guarantee amount | guarantee-amount |
left | tooltip-right |
Cover in rand |
| Warning limit | warning-limit |
right | tooltip-left |
Exposure warning threshold in rand |
| Clarification requested | clarification-requested |
left | tooltip-right |
Last §6.2(4) ask |
| Clarification received | clarification-received |
right | tooltip-left |
Last §6.2(5) answer |
Agreements.
#mo-clock-drawer-agreements-{party id}, hint
#mo-clock-drawer-hint-agreements. Empty (writable,
contracts may be prepared): Prepare the Market Participation
Agreement and Balancing Agreement, then digitally sign both to issue
them to the applicant. Empty (read-only): No agreements on
file.
Each #mo-clock-drawer-agreement-{id}:
MPA or BA badge
(#mo-clock-drawer-agreement-view-{id}) opens the PDF modal;
title; status (Draft — awaiting Market Operator signature /
Signed by the Market Operator / Sent to the applicant
/ Signed by both parties); optional sent {date};
#mo-clock-drawer-agreement-mo-sign-{id} /
#mo-clock-drawer-agreement-applicant-sign-{id}.
Digitally sign
#mo-clock-drawer-agreement-sign-{id} — only while the
agreement is GENERATED and you have not signed. Hidden on
read-only tabs.
PDF modal #mo-participation-agreement-pdf-modal: Close,
Download, Digitally sign when still
unsigned. Viewer
#mo-participation-agreement-pdf-modal-viewer.
Actions footer
#mo-clock-drawer-actions-{id}. Buttons that are lawful
from this application state for the Market Operator. Id
#mo-application-action-{id}-{TARGET}. Hover
title is the state’s one-line description. A refusal from
the Code is shown verbatim — it names what is missing
and which clause requires it.
Empty: Waiting on the applicant — no Market Operator move is available. After Prepare contracts and before both signatures: Digitally sign both agreements to issue them to the applicant.
There is no Issue contracts button. Issuing is
Prepare → digitally sign both. CONTRACTS_ISSUED is withheld
from this footer on purpose.
| Button | Target / id suffix | When | Note modal? |
|---|---|---|---|
| Prepare contracts | PREPARE_CONTRACTS |
You may issue contracts and no pair exists yet | No |
| Request information | INFO_REQUESTED |
PENDING or INFO_SUBMITTED |
Yes |
| Mark contractable | CONTRACTABLE |
PENDING or INFO_SUBMITTED |
No |
| Approve | APPROVED |
CONTRACTS_SIGNED |
No |
| Activate | ACTIVE |
APPROVED — this is accession (§6.2(8)) |
No |
| Decline | DECLINED |
Lawful non-admission from this state | Yes |
| Revoke | REVOKED |
After contracts are out / live participation | Yes |
| Suspend | SUSPENDED |
Needs an open Default Notice / Suspension Order (§6.4) | Yes |
On Registrations / Accession (read-only drawer) the footer is D2
only, as RegistrationStatus.mo_transitions allows:
| Current D2 status | Buttons |
|---|---|
PENDING |
Activate |
ACTIVE |
Suspend, Revoke |
SUSPENDED |
Activate, Revoke |
REVOKED |
Reactivate only
(#mo-application-action-{id}-ACTIVE) |
A revoked seat cannot be suspended. Participation has ended; the only
D2 move is back to ACTIVE. The applicant may also
Request reinstatement on their Registration page
(§6).
Moves that need a note open #mo-application-note-modal.
Title is {action} — {BRP REF}. Field Note
(#mo-application-note-text) with i
#mo-application-note-hint (tooltip-right — the
label sits on the left of a centred modal). Placeholder is the prompt
for that move. Cancel /
#mo-application-note-submit (label is the action,
e.g. Decline).
Files
#mo-clock-drawer-files. Files the applicant attached
when answering an information request. Empty
#mo-clock-drawer-files-empty: No files have been
uploaded yet.
Each #mo-clock-drawer-file-{id}: title, original
filename, optional description. View
#mo-clock-drawer-file-view-{id} (new tab) and
Download
#mo-clock-drawer-file-download-{id}.
History
#mo-clock-drawer-history. The same trail the applicant
sees under History on Registration. Empty
#mo-clock-drawer-history-empty: No history has been
recorded yet. Timeline #mo-clock-drawer-history-list —
each circle has a state icon; the box is {from} → {to} (or
Application opened at {to}), date, actor, frozen deadline,
note.
Ask for information
#mo-clock-drawer-ask — only while PENDING
or INFO_SUBMITTED on the writable drawer. Form
#mo-clock-clarification-form.
| Control | What it is |
|---|---|
| Information requested | Required textarea. i on the label
(tooltip-right): what you type is the whole of what the
applicant is told |
| Cancel | Returns to Application details |
Send request
#mo-clock-clarification-submit |
Moves to INFO_REQUESTED under §6.2(4). The applicant
then has 20 business days, unless extended |
The tab disappears once the state leaves PENDING /
INFO_SUBMITTED. Request information in the
footer is the same move via the note modal.
Careful. An unanswered information request that runs out is taken by the daily clock to
EXPIRED— deemed withdrawn, not declined. Do not ask for a document you cannot describe; the note is the request.
### 21.7 The clock drawer
The View drawer is documented under §21.6. Pending Clocks is writable. Registrations and Accession register open the same chrome read-only except Activate / Suspend / Revoke / Reactivate.
### 21.8 Extension Requests
Path: /mo/participants/extensions.
#mo-registration-extensions. Only
undecided requests. Heading: Extension requests
awaiting a decision (§6.2(5)/(7)). Empty: No extension
request is outstanding.
(#mo-registration-extensions-empty)
Each #mo-registration-extension-{id}.
When an applicant submits Request more time on
BRP / Market → Registration, the row appears
without refreshing. The applicant’s due date has
not moved yet — only a grant changes it. They can only
ask on INFO_REQUESTED or CONTRACTS_ISSUED.
They cannot file a second request for that clock while one is pending,
and they cannot ask again for that clock after you
decline.
| Column | What it is |
|---|---|
| BRP REF | Registration code |
| Organization | Applicant |
| Accession | #mo-registration-extension-accession-{id} |
| Status | INFO_REQUESTED or CONTRACTS_ISSUED |
| Deadline | Clock still in force + business days + clause |
| Days asked | Business days beyond that deadline |
| Reason | Why they need longer |
| Actions | Grant / Grant with days… / Decline |
| Action | Id | Effect |
|---|---|---|
| Grant | #mo-extension-grant-{id} |
Accept the days asked. Row leaves. Deadline moves. Applicant’s page updates live. |
| Grant with days… | #mo-extension-grant-custom-{id} |
Modal: 1–60 business days from the current deadline; optional note |
| Decline | #mo-extension-decline-{id} |
Modal: mandatory reason. Original deadline stays. Applicant cannot ask again for this clock. |
Modal #mo-extension-decision-form:
#mo-extension-business-days,
#mo-extension-decision-note, submit Grant
extension or Decline extension. Decline
without a reason: A refusal must give a reason (§6.2(5)).
Decided requests do not remain on this tab. After a grant, a later second extension for the same clock may appear (extensions stack). After a decline, no further row for that clock until the application moves.
Careful. Leaving a request undecided is itself the finding the Code warns about: the applicant’s clock is still running on the old date. An applicant who asked in good time and heard nothing can be deemed withdrawn while waiting for you.
21.9 Open Default
Path: /mo/participants/defaults. Tab
#mo-participants-tab-defaults.
#mo-registration-notices — Open Default Notices
(§6.3.1). Empty: No Default Notice is open.
(#mo-registration-notices-empty)
Each #mo-registration-notice-{id}:
{mpid|brp_code} — remedy by {ISO date}, nature, optional
Also required: …, the Accession badge
(#mo-registration-notice-accession-{id}), and if expired:
remedy time expired — a Suspension Order may issue (rose).
Escalate the expired ones.
21.10 Issued suspensions on Registrations
Not a tab. Path: /mo/participants — the
Enforcement column on Registrations.
Bookmarks to /mo/participants/suspensions still resolve and
patch here. Empty is a dash on
#mo-brp-registration-{id}-enforcement, not a dedicated
panel. There is no #mo-participants-tab-suspensions and no
#mo-registration-suspensions worklist.
Where this is taught. Default → notice → order → delay → suspended is V9 §3.14. This section is the Code: who is on a Suspension Order, per Trading Unit, and whether it has bitten. The console shows that as Enforcement on the BRP row and on each expanded unit.
A default does not stop a party bidding. Neither does issuing the order. The gap is deliberate. §6.3.1 gives at least two business days to remedy; §6.4(2) forbids an order until one further business day after the notice; §6.4(3) then adds an MGC delay period before any unit actually stops. This is the stretch after the order exists and before — or after — it bites. Watch the dates. Do not read a badge as “they cannot trade today” unless Enforcement is in effect.
This status is observational. There is no Issue, Lift, Amend, or Activate on the Enforcement cell. You issue from the enforcement path (an open Default Notice on Open Default); the Market Governance Committee lifts or amends; Activate on Registrations is D2 seating after the party is allowed to bid again.
What the status is
One issued Suspension Order, exploded onto
each Trading Unit the order covers. BRP badges
#mo-brp-registration-{id}-enforcement. Unit cell
#mo-brp-registration-{id}-unit-{unit id}-enforcement.
That split is the point of §6.4(3). The MGC may amend or lift any or all of a party’s units. Demand-side and generating units use different delay parameters, so two units of the same party take effect on different dates. A Demand Side Unit may be covered by the order and still unable to bite — that unit is also blocked.
Every unit on an order whose status is still ISSUED
shows a badge. A unit that has already bitten reads in
effect. A unit the MGC lifted alone stays
scheduled / listed while the rest of the order stands
(LIFTED on that unit). Enforcement clears
when the whole order is lifted (LIFTED) —
then none of its units appear.
Who shows under Enforcement
Not every party in DEFAULT. Not every expired Default
Notice. The path is:
- They are a Party who may be suspended. Typically
ACTIVE, then recorded in default (§6.3(2)). They keep trading. That is on the seven-state tiles and on Open Default. Enforcement stays a dash until an order issues. - An open Default Notice exists (§6.3.1). Remedy time at least two business days. Open Default is the chase list until an order issues.
- At least one business day after that notice (§6.4(2)). Earlier is refused.
- The order is not barred by §6.4(4). No suspension solely because credit cover was absent during a permitted replenishment window, or during the ten business days to appoint a new Credit Cover Provider. Solely: another live ground is not protected.
- A Suspension Order is issued. Every registered Trading Unit of that party shows under Enforcement.
Who you will not see under Enforcement:
- an applicant on Pending Clocks — they are not in the market yet;
- a party in default without an issued order — that is Open Default;
- a Balancing Group pause (§21.12) — that is an administrative window on a group, not a §6.4 order;
- an order the MGC has already lifted in full — it is no longer
ISSUED.
A generating, storage, mixed or interconnector unit lands as
SCHEDULED for issued-on + Generator Suspension Delay
Period (business days). A Demand Side Unit with a Default Retailer
direction in force is SCHEDULED for the
later of its DSU delay and the direction’s date. A
Demand Side Unit without that direction, or any unit
whose MGC delay parameter is unset, lands as WITHHELD —
blocked on the unit (preferred over scheduled when both
lists apply).
What each cell means
| On the row | Meaning |
|---|---|
| BRP Enforcement badges | #mo-brp-registration-{id}-enforcement —
scheduled, in effect (rose),
blocked (amber). Dash if no issued order. |
| Unit Enforcement | #mo-brp-registration-{id}-unit-{unit id}-enforcement —
badge plus delay {N} business days ({parameter}),
takes-effect ISO date, and blocked reason when withheld |
| Delay period | dsu_suspension_delay_days or
generator_suspension_delay_days, stored so a later MGC
revision cannot rewrite the date this unit was given |
| Takes effect | ISO date, or omitted if the unit cannot bite yet (withheld, or no delay parameter) |
in effect is the only badge that means the unit has stopped for today. scheduled with a future date means they are still trading on that unit. blocked means the order covers them and is doing nothing — see §21.11.
When the first unit actually bites, the party’s §6 state becomes
SUSPENDED. Until then they can still be
DEFAULT on the seven-state tiles and still
scheduled on Registrations. Both are correct.
How to get out
Leaving Enforcement and leaving suspension are not always the same step.
Before it bites (badge is scheduled or
blocked). The Market Governance Committee may, per
unit or for the whole order (§6.4(3)):
- Lift this unit — it will never bite. The cell stays
while the order is still issued; stored state becomes
LIFTED. - Amend this unit’s date — Takes effect moves. Still on the row.
- Lift the whole order — order status
LIFTED. Enforcement clears. Units that had not bitten are lifted; units that had already bitten are released going forward (settled days are not rewritten). A party who had becomeSUSPENDEDreturns toACTIVE.
A blocked Demand Side Unit. Recording a Default Retailer direction does not take the unit off Registrations. It stops being blocked (§21.11) and can then take effect on the later of the delay and the direction. That is how they enter enforcement, not how they leave it.
After it has bitten (badge is
in effect). The unit is suspended. The party
cannot bid on it. Ways out:
- MGC lifts the order — as above; in-effect units are
released from today; the party is
ACTIVEagain on the seven-state tiles. - Termination (§6.5) — ends participation. Money still due: V9 §3.15.
- D2 Activate on Registrations — only after they are allowed to bid again. Coming back from a §6 suspension is the Market Operator’s Activate, not an applicant self-service (V9 §3.13A).
There is no “undo the order from this table.” If Enforcement still reads in effect, they are still under that order.
Careful. Issuing the order is not the same as stopping the party. If Takes effect is tomorrow, they may still be in the DAM today. If a demand-side unit shows blocked, the load is still being served by nobody the Code has named — that is a blocked-enforcement finding, not a successful enforcement.
21.11 Blocked units on Registrations
Not a tab. Path: /mo/participants — amber
blocked on
#mo-brp-registration-{id}-enforcement and on
#mo-brp-registration-{id}-unit-{unit id}-enforcement.
Bookmarks to /mo/participants/blocked still resolve and
patch to Registrations. Empty is a dash. There is no
#mo-participants-tab-blocked and no
#mo-registration-blocked panel.
A suspension against a demand-side unit cannot take effect at all until the Market Governance Committee has directed that the demand will be met by a Default Retailer. Without this status the order looks complete — it issued, the default stands, the paperwork is filed — and does nothing. The unit cell names the reason (clause 6.4(3), Default Retailer, would leave it with no supplier). The action is an MGC direction, not anything on this screen.
Careful. Do not read a missing blocked badge as “no suspensions pending”. It means every issued order can take effect on its date. scheduled / in effect is where you see the dates.
21.12 Balancing Groups
Path: /mo/participants/balancing-groups. Tab
#mo-participants-tab-balancing_groups (badge is the number
of groups). Heading on the board: Balancing Groups.
Intro: Every party’s designation. You may suspend or cancel; you may
not compose membership (§13.10(1)).
Where this is taught. What a group is, why a BRP asks for one, and the worked hour, are V9 §3.6 and V9 §6.7. This section is your market-wide board: who designated, whether the System Operator was told, whether cover will hold tomorrow, and the two acts that are yours.
Why this tab is here
A Balancing Group is a settlement overlay. The market, left to itself, balances each Trading Unit alone. Being long in one zone does not cancel being short in another. Two or more of one party’s units, designated together, net against each other so a mismatch that cancelled out inside that portfolio is not penalised twice.
The BRP designates. You do not. §13.10(1) makes membership their act. They file on Trading Units; the API does the same for a machine. You still need this tab, because three jobs sit with you after they file:
- See every designation in the market — not one party’s registry card. When a BRP asks “why did my cover lapse?”, this is the picture that answers it.
- Tell the System Operator — §7.1(2). A designation that has no communicated notice is overdue. That is a finding against you, not against the BRP.
- Pause or end a group you did not compose — an administrative suspension (a window and a reason), or a cancellation with a mandatory reason. You cannot add or remove members.
It lives on Participants, not on Registry. Registry is Trading Units in force for tomorrow and the pairing board (§22). A group is a fact about a Party — who they asked to net with whom. The seven-state cards stay above the tab because the party is still the subject. A Balancing Group pause is not a §6.4 Suspension Order (§21.10): the seat can still bid; only the netting overlay is off inside the window.
What it is for
| Question you are answering | Where on this tab |
|---|---|
| Who has asked to net, and on which units? | The table — Party, Group, Members, Zones, Window |
| Is that party even in the market yet? | Accession badge — same publication clock as the other worklists |
| Did we tell the System Operator? | Notified — ✓ date, or overdue |
| Will cover hold tomorrow? | Cover line under the group name |
| Is the overlay actually on today? | Status |
| Should netting stop for a while, or for good? | Suspend / Cancel |
| Is a congested zone knocking members out this hour? | §3.3(6) flags in force, below the table |
Empty: No Balancing Groups designated.
(#mo-balancing-groups-empty)
Overdue-notice rows sort first, then administratively suspended, then the rest by BRP REF and name. Work the rose overdue cells before you admire the green in force ones.
What each row means
Widget #mo-balancing-groups. Table
#mo-balancing-groups-table. Each
#mo-balancing-group-{id}.
| Column | How to read it |
|---|---|
| Party | Who designated — BRP REF (row.party_code) |
| Accession | #mo-balancing-group-accession-{id} — awaiting
publication / overdue / published / — |
| Group | Name. Under it, #mo-balancing-group-cover-{id}:
Cover forecast (expectation): full cover expected next Trading
Day or exclusions expected in hours … |
| Members | Count of Trading Units in the designation. A live group needs two or more (§2.1(21)). One remaining unit is a registry failure (§22.4) |
| Zones | Distinct network zones those members sit in, joined with
· |
| Window | from {ISO date} — effective_from. Duration
to a date is effective_to on the record, not a fifth
status |
| Status | in force (emerald) · designated (not yet in the window, or past it) · suspended (amber — your administrative pause) · cancelled (slate) |
| Notified | #mo-balancing-group-notified-{id} — ✓
{YYYY-MM-DD} when the §7.1(2) designation notice has
communicated_at; otherwise overdue
(rose) |
| Actions | Suspend
#mo-balancing-group-suspend-{id} · Cancel
#mo-balancing-group-cancel-{id} |
Cover forecast is an expectation for the next Trading Day. It uses the scheduled position as a direction proxy because actuals do not exist yet. Full cover expected does not promise the hour will clear that way; a zone constraint flag raised later still knocks members out. Exclusions expected in hours … is the honest answer to “why might cover lapse” before the day runs.
Status is not one knob. Four ways a group stops, kept distinct (V9 §3.6):
| What you see | What happened |
|---|---|
| in force | Designated, inside the window, no administrative suspension today |
| designated | Filed, but not in force on today’s date (window has not started, or has ended by duration) |
| suspended | You paused it. The group is still the current designation; it is not in force inside that window |
| cancelled | Ended early, with a reason. Designate a fresh group if they still need one |
A §3.3(6) exclusion does not change this Status. The group stays in force (or designated). Members pushing in the constrained direction drop out for those Trading Periods only. That is why the flags panel sits under the table — so you do not read a green badge as “cover is intact this hour”.
Suspend and Cancel
You cannot designate or amend. Composing a group from this console would be an act the Code does not authorise. The BRP adds a live unit or files a successor group. You only pause or end.
| Action | Modal | What it is |
|---|---|---|
| Suspend | #mo-bg-modal / #mo-bg-suspend-form — title
Suspend {name}. From
#mo-bg-suspend-from (defaults today), To
#mo-bg-suspend-to, Reason
#mo-bg-suspend-reason (mandatory). Submit
#mo-bg-suspend-submit. Back closes |
Administrative pause. The group stays the current designation; it is not in force inside the window. Not a §6.4 Suspension Order. Not a §3.3(6) exclusion |
| Cancel | #mo-bg-cancel-form — title Cancel {name}.
Reason #mo-bg-cancel-reason (mandatory).
Submit #mo-bg-cancel-submit (Cancel group) |
End the group from a date. The Code does not say you may; we read that you may, with a reason (V9 §17.12) |
Use Cancel when the group can no longer do its job — typically it has fallen below two live units after a member deregistered. Leaving it designated until the BRP notices is a settlement dispute waiting for a night. Use Suspend when you expect it to resume.
Backdrop #mo-bg-modal-backdrop closes without
writing.
Careful. Do not press Suspend because a zone is congested. That is the System Operator’s flag. An administrative pause stops the whole overlay for every hour in the window. A flag stops only the members pushing in the constrained direction, and only for those periods.
§3.3(6) flags in force
#mo-zone-constraint-flags. Heading: §3.3(6)
flags in force. Read-only. The System Operator raises and
lifts these on /so/network-model (Map). Empty: None in
force.
This panel is the other half of “why did cover lapse”. A zone constraint flag is a
temporary lane closed sign. It is not a change
to the published network model, not an administrative
Suspend on the table above, and not a
§6.4 Suspension Order. The System Operator puts it up; you watch it
here. Raise and lift live on /so/network-model?tab=map (V12
§5.5).
In force means: not lifted, and the clock is inside
the flag’s window (from inclusive, to
exclusive; a missing from or to means
open-ended that way). A flag from 17:00 to 20:00 does not appear at
00:00. A lifted flag leaves this list — lifting is a dated event, not a
delete.
Each #mo-zone-flag-{id}:
{zone_code} · {direction} · {reason}
| Piece | What it is |
|---|---|
| Zone | The network zone the sign is on (network_zone_code).
Only members in that zone can be excluded. Members in
other zones stay in the group |
| Direction | EXPORT, IMPORT, or BOTH. That
is the whole closed set. There is no fourth direction |
| Reason | Free text the System Operator typed when they raised it. Required on their form. There is no pick-list of reasons on this platform — the clause is whatever they wrote |
Two flags on the same zone at once do not cancel. Export and import bits OR together, and the tightest window wins — a second flag cannot silently widen the first.
The three flags, and who drops out of the group
Exclusion is per Trading Period and per
member. It is computed from actual minus scheduled
(AE − SE). A member exactly on schedule is
never excluded: there is no direction to a deviation of nothing. A
member in an unflagged zone is never excluded.
The group row’s Status does not change. Members who drop out balance alone for those hours; the others still net.
| Flag on the row | What the System Operator is saying | Who loses Balancing Group cover in that zone, that period |
|---|---|---|
EXPORT |
The zone cannot push more power out. Too much trying to leave | Anyone who would increase net export: a generator
delivering above schedule, or a load consuming
below schedule (AE − SE > 0). A member
who is short (helping the constraint) stays in |
IMPORT |
The zone cannot draw more power in. Too much trying to enter | Anyone who would increase net import: a load consuming
above schedule, or a generator delivering
below schedule (AE − SE < 0). A member
who is long (helping the constraint) stays in |
BOTH |
Too much trying to leave and to enter — both directions at once | Both of the above: anyone off schedule in that zone. Only a member exactly on schedule stays in |
The Cover forecast line on the group is an expectation for tomorrow using schedule as a direction proxy. This flags panel is now: which signs are actually up. If the list is empty, no sign is up — that is not the same as “the network is unconstrained forever”.
You do not raise, lift, or edit a flag from Participants. If a BRP asks why cover vanished for three hours, read this list first, then the group’s cover line. If the sign should come down, that is a System Operator Lift with a reason, not your Suspend.
Follow along. Seat:
mo@webill.net/ passwordsupersecret. Path: Participants → Balancing Groups. Scroll to §3.3(6) flags in force. Empty is None in force. If a row is present, read zone ·EXPORT/IMPORT/BOTH· reason, and do not confuse it with Suspend on the table. Raising a flag is V12 §5.5.
21.12 Credentials
Path: /mo/participants/credentials. Panel
#mo-participants-credentials.
This is the Market Operator’s view of every credential Stage 7 issues. One row per registration; three kinds; issue, rotate and revoke are the same lifecycle on each. Rotation is a new row plus a revoke of the old — never an overwrite — so a secret that later fails is two facts, and the first one’s record is why the second exists.
| Kind | What it proves | Issue |
|---|---|---|
| OAuth client secret | Who is calling. Exchanged at POST /api/v1/oauth/token
for a short-lived JWT whose mpid claim is the party. |
#mo-cred-issue-oauth_client_secret-{id}. The plaintext
is shown once (#mo-credential-plaintext) and never stored
in recoverable form. |
| mTLS fingerprint | What is calling. SHA-256 of the DER-encoded client certificate, pinned on the dedicated API listener. Opt-in: a registration with no pin is unaffected. | Pin fingerprint #mo-cred-pin-open-{id}
then form #mo-cred-pin-form-{id}. |
| HMAC signing key | That this write is the one that was signed. Required on unsafe methods only after the registration opts in. | #mo-cred-issue-hmac_signing_key-{id}. Shown once, like
the client secret. The Market Operator retains the key material so
signatures can be verified. |
Rotate (#mo-cred-rotate-{kind}-{id}) and Revoke
(#mo-cred-revoke-{kind}-{id}) on an active row. There is no
destroy: WB.Brp.RegistrationCredentialEvent is
append-only.
Audit #mo-credential-events. Every issue, rotation and
revocation, and every authentication failure this stage introduced —
expired or wrong-issuer token, header refused as retired, certificate
mismatch or revoked certificate, missing / tampered / stale signature —
carries the same clause the refusal itself named. An operator sees
why a participant is failing, not only that it is.
Where this is taught on the wire. V13 §2.
Follow along. Seat:
mo@webill.net/ passwordsupersecret. Path: Participants. Confirm an ACTIVE seat (e.g. BRP-T1-DEMO) or work a pending application through Pending Clocks — do not press Activate on a freshly filed PENDING row. Change Status to see Suspended or Revoked (Reactivate only). Issued Suspension Orders show under Enforcement. There is no Suspension Queue tab and no Blocked Suspensions tab. Open Accession register and read unpublished / overdue. Open Extension Requests and decide anything sitting there. Open Balancing Groups and read Notified and the cover line — do not designate from that tab. Open Credentials and issue an OAuth secret for a demo seat; copy it once. Open Vesting and read the illustrative Mpumalanga Mid-Merit contract: determination, CPA counterparty, declining curve. A dormant badge names the activating phase, not zero MW.
21.13 Vesting book
Path: /mo/participants/vesting. Panel
#mo-participants-vesting.
A plant that sold power under a long, regulated tariff cannot be dumped onto the spot market overnight. Lenders priced that tariff; staff and fuel contracts assumed it. The day SAWEM starts, every megawatt-hour clears at the System Marginal Price — which can be far above or far below the old number. Something has to walk that plant from the old world to the new one without a cliff.
That walk is a vesting contract: a regulator-imposed two-way contract for difference on a named Trading Unit. It is not a Bid Desk trade, not a PPA you negotiate in the deal wizard, and not a price the generator and a buyer agree. A published determination (typically NERSA, recorded on the book with its document reference) names four things:
- which unit is vested
- how many MW vest in each time-of-use block (
PEAK/STANDARD/OFF) - the vesting price in R/MWh
- who sits on the other side of the difference — by default the
Central Purchasing Agency (
BRP-CPA-SAWEM), unless the determination names somebody else
For each Trading Period the platform takes the lesser of the scheduled vested MWh and what the unit actually delivered, then multiplies that quantity by (vesting price − SMP). If the result is positive, the Market Operator pays the generator and the counterparty is charged the same amount. If it is negative, the generator pays and the counterparty receives. Energy above the vested cap trades merchant at spot, like any other unhedged megawatt-hour. Energy the unit did not produce does not vest at all.
The schedule declines. Year 1 may vest most of the plant; later years vest less, until the asset is mostly merchant. That declining curve is the instrument: its job is to hand the plant its spot exposure in instalments. A later period that raises vested MW for a block is refused — that would re-hedge the plant, which is the opposite of vesting. A genuine increase is a new determination, written as its own contract with its own source reference.
When one is created. A vesting contract is created when a determination is published and ingested — typically at market opening, or when a later determination covers a unit that was left out or that needs a new price or a new end date. You do not create one from this console. You do not amend MW, price, or counterparty here. The book is read-only on purpose: a console that let an operator type a vested MW would put the platform’s number and the regulator’s number out of step with no document between them.
When one is not created. A new merchant plant that entered SAWEM without a regulated legacy tariff has no vesting contract. An ordinary physical or virtual PPA between an IPP and an off-taker is a commercial deal, not vesting. A seat with no contract on this book is simply not vested.
A one-hour picture. The demo estate’s Mpumalanga
Mid-Merit unit (BRP-SIM-IPP-12) is vested at R
650/MWh. In the first step of its curve the peak block is 180
MW. Take one peak hour in which the unit actually delivered 180 MWh:
- SMP prints R 800/MWh. Difference = 180 × (650 − 800) = −R 27,000. The generator pays R 27,000; the CPA receives R 27,000. The extra R 150/MWh above the vesting price is the spot the plant is being walked toward.
- SMP prints R 500/MWh. Difference = 180 × (650 − 500) = +R 27,000. The CPA pays the generator. The vesting price is the floor that determination promised.
- The same hour, but the unit only delivered 100 MWh. Only 100 MWh vests. The other 80 MW on the schedule do not pay and are not owed — you cannot vest energy that was not produced.
Three years on the same book the peak step is 60 MW, not 180. Same price, same counterparty, less hedge: that is the curve doing its job.
The settlement kinds, the delivered-energy cap, missing-SMP carry-forward, and the participant’s hedged-versus-merchant panel are taught in V9 §19. A vested BRP reads that month on Month → Published results → Explain vesting (V10 §13.5). This page is the Market Operator’s register of every contract on file: who is vested, on which Trading Unit, under which determination, against which counterparty, and how far down the declining curve each contract has travelled.
Each contract #mo-vesting-contract-{id} shows:
- the vested unit’s official name and the party’s BRP code
- the determination
#mo-vesting-determination-{id} - the counterparty
#mo-vesting-counterparty-{id}— its own column, because the default is the Central Purchasing Agency and a determination that named somebody else must be visible on the face of the book - the declining curve
#mo-vesting-curve-{id}— vested MW per TOU block across the schedule’s effective periods, drawn as a shape from the stored schedule rows. Changing a row changes the bars. - Active, or Dormant — Phase N
#mo-vesting-dormant-{id}when the contract’s period is live but the phase matrix has vesting off. Dormant is not zero vested MW.
The CPA has no separate book: it settles like any party and reads its statements like any party.
Empty #mo-vesting-empty: No vesting contracts on
file. The demo estate seeds one illustrative contract on Mpumalanga
Mid-Merit (BRP-SIM-IPP-12) against
BRP-CPA-SAWEM under
NERSA-VEST-ILLUSTRATIVE-2026.
Follow along. Seat:
mo@webill.net/ passwordsupersecret. Path: Participants → Vesting. Confirm the mid-merit unit, the illustrative determination, the CPA counterparty, and three steps on the curve (180 / 140 / 90 MW peak-standard-off, then 120 / 90 / 60, then 60 / 45 / 30) at R 650/MWh.
Data. full_demo · seed 42 · stage S08. Gallery codes BRP-CODEX-PENDING / SUSPENDED / REVOKED are not all on Registrations — status filter.
22. Registry
Path: Market Operator → Registry
(/mo/registry). Second item in
Eligibility. The icon is a clipboard. Optional
?tuid=TU-PV1 highlights
#mo-registry-unit-TU-PV1 and survives tab changes.
Trading Units, Points of Delivery, reciprocity state, and
standing-data review for the next trading day. This is the
module named MarketDeskLive — not the Market Desk sidebar
hop (§13). The accession-register 7-BD SLA
lives on Participants (§21.5).
Where this is taught. What a Trading Unit is, and the participant wizards: V9 §3.9B. What accession is, and the joining clocks: V9 §3.13. The accession publication SLA: §21.5. Counterparty pairing from the BRP’s chair: V9 §3.4–§3.5. The System Operator’s inbox for the same share: V12 §6. Public accession register API: V13 §5.1.
### 22.1 The operator’s problem
Tomorrow’s solve will treat every registered plant as real. You need to know who is in force tomorrow, whether every meter has two owners, whether §7.2 fields are assumed, incomplete, or waiting on the System Operator. Today is too late. Who has acceded, and whether you have published that fact, is Participants → Accession register (§21.5).
### 22.2 How the page is laid out
Browser title: Registry. Header: Registry — Trading-unit registry and standing-data review for the next trading day.
Three icon tabs (#mo-registry-tabs), same
tabs tabs-bordered chrome as Bidding and Zones.
| Tab | Path | What it holds |
|---|---|---|
| Trading Units | /mo/registry |
Registry board |
| Counter Party | /mo/registry/counterparty |
Waiting on a declaration · no counterparty derived |
| Standing Data | /mo/registry/standing-data |
Incomplete filings · SO certification queue |
| Section | Id | Tab | Job |
|---|---|---|---|
| Registry board (§7.1, §7.2) | #mo-registry-board |
Trading Units | Units in force for tomorrow, standing-data cards |
| Counterparty pairing (§7.1(6), §12.3(1)) | #mo-registry-counterparty |
Counter Party | Two exception lists — chase vs commercial gap |
| Waiting on a declaration | #mo-registry-pending-reciprocity |
Counter Party | Reciprocity not yet filed — §7.1(6) |
| No counterparty derived | #mo-registry-pending-counterparty |
Counter Party | Nothing to derive from — §12.3(1) |
| Standing-data review (§7.2) | #mo-standing-data |
Standing Data | Incomplete / SO certification queue |
### 22.3 Accession register — moved to Participants
The §6.2(9) publication SLA is a party clock, not a unit clock. It lives on Participants → Accession register (§21.5). This page is the §7 register of Trading Units, pairing, and standing data.
22.4 The registry board — units and today’s failures
Trading Units tab. Section
#mo-registry-board.
Re-assert for tomorrow
(#mo-registry-refresh) re-runs the checks for the
next Trading Day, not today. The quiet line
#mo-registry-model-version names that day, the zone-model
version, how many units were checked, and §7.1(5). There is no red
pairing banner — failures sit on the unit they belong to.
Standing-data cards
(#mo-standing-data-summary) sit above the Trading
Units table: units, fully evidenced, on assumptions, incomplete. The
lists themselves stay in §22.6.
Find a unit. #mo-registry-units-filters
searches TUID or name (#mo-registry-search) and filters by
class (#mo-registry-filter-class), zone
(#mo-registry-filter-zone), and Today’s
failures (#mo-registry-filter-failures). Failures:
all units, has a failure, no failure, or a Code clause that is on the
board right now (§7.2(1)(i), §12.3(1), …).
Combine with search, class, and zone.
Trading Units
(#mo-registry-unit-count). The header stays in view as you
scroll. Sort name, MCR (MW), and effective with
#mo-registry-sort-name, -mcr,
-effective.
| Column | How to read it |
|---|---|
| TUID | Row #mo-registry-unit-{tuid}. An
assumed badge
(#mo-registry-assumed-{tuid}) opens the yellow assumption
card in #mo-registry-assumption-modal. |
| Name | Official name — sortable |
| Class | Coloured badge: generating, demand side, storage, interconnector, mixed |
| Zone | Colour swatch, then the code. Provisional models keep the honesty
note on the swatch — they do not add * |
| MCR (MW) | Maximum continuous rating — sortable by megawatts |
| Status | Badge: registered / suspended / deregistered |
| Effective | 1 Jan' 2026 — sortable |
| Today’s failures | Centred Code clauses
#mo-registry-failure-clause-{tuid}-{i} when the nightly
re-assertion failed this unit. Hover
#mo-registry-failure-tip-{tuid}-{i} on
each clause for that failure’s message. An em-dash
means this unit passed |
Empty: No Trading Units registered yet. / None in force for this day.
The two Point-of-Delivery exception lists do not live on this tab. They are on Counter Party (§22.5). The same pairing failures also appear in Today’s failures on the unit — the lists are the worklist; the cell is the unit’s score.
What the clauses mean
Each red clause is one registry rule this Trading Unit currently breaks for tomorrow. Hover that clause for the sentence that explains it. Several clauses can sit on the same unit at once — fixing one does not clear the others. The same clause can appear twice when two meters fail the same rule; each hover names its own meter.
An em-dash (—) means this unit passed. It does not mean the network is clear, the pairing lists are empty, or standing data is fully evidenced. Read the cell, then Counter Party, then Standing Data.
The check is re-run against time, not against a save. A zone map published today with effect from tomorrow, a counterparty suspended this afternoon, or a bid accepted yesterday that no longer matches the plant — none of those need anyone to edit the unit. That is why you re-assert every morning, and why a unit that was clean yesterday can fail today.
The D−1 08:00 cutoff (§7.1(5)) is the last moment a registry change can take effect for tomorrow. A failure you find after that sits until the day after.
After you fix something
You do not type the remedy on this board. The BRP files standing data and meters; the named counterparty confirms pairing; the System Operator covers a location or certifies a rating. Your move is to chase the right person, then press Re-assert for tomorrow and watch the clause leave — or the cell go back to an em-dash.
Finder — every failure that can sit in the cell
These are the only failures the nightly re-assertion can put here. The hover on each clause is the source of truth; the names below match what that text is saying.
| Clause | In plain words | Who usually fixes it |
|---|---|---|
| 7.2(1)(i) | The unit has no meters | BRP — register and pair at least one Point of Delivery |
| 3.3(4)(a) | A meter sits off the published zone map | System Operator — extend or publish the model |
| 7.2(d) | The named zone is not where the meters sit | BRP — re-file the declared zone |
| 2.1(212)(a) | Meters sit in more than one zone | BRP — split into one unit per zone |
| 2.1(212)(b) | Generator bigger than 1 000 MW, no SO letter | BRP with SO — approval reference, or lower MCR |
| 7.2 | Standing-data fields still blank | BRP and/or SO — whoever owns each missing field |
| 7.2(f) | Minimum generation is below zero | BRP — file a non-negative floor |
| 7.2(e) | Nameplate is smaller than the floor | BRP — raise MCR or lower Mingen |
| 9.3(4)(c)(vi) | Emergency Level 1 is below nameplate | BRP — raise EL1 to at least MCR |
| 7.2(h) | Called storage, no storage form — or the reverse | BRP — tick and file together, or clear both |
| 7.2(g) | Called energy-constrained, no energy budget — or the reverse | BRP — tick and file together, or clear both |
| 12.1 | A factory in this unit has no meter | BRP — fit or link a conforming meter |
| 9.3(4)(c) | An accepted bid no longer matches the plant | BRP — resubmit the curve |
| 12.3(1) | A meter has no other owner | Commercial — signed physical PPA, then re-assert |
| 7.1(6) | Named itself; named party cannot take energy; or the other side has not said yes | BRP / named counterparty — see pairing below |
| 2.1(21) | A balancing group has fewer than two live units | BRP — add a live unit or cancel the group |
| 3.3(5) | A grouped unit moved zone after a new map | BRP — re-designate the group |
| 13.10 | A unit sits in two groups at once | BRP — close the overlap |
No meters on the unit — §7.2(1)(i)
What it means. The Trading Unit has no Points of Delivery. The market schedules and settles energy at meters. A plant with no meter is a name on a list — nothing can be dispatched, and nothing can be billed.
What it is not. It is not “the meters exist but pairing is incomplete.” That is a different failure (pairing, below). Here there is no meter on the unit at all. It is also not “this BRP may not bid”: the auction till can still pay the schedule. Why those two tills are different, and how an off-taker, IPP, or trader pool attaches a meter: V9 §3.4.
How to remedy it
- Send the BRP back to the Trading Unit registration wizard (V9 §3.9B).
- They register at least one Point of Delivery and complete pairing (§22.5).
- Re-assert for tomorrow. The cell should lose this line.
Meters the map cannot place — §3.3(4)(a)
What it means. One or more meters sit in a location the published zone model does not cover. Under a provisional model that is common — the map may cover only part of the country. The platform will not guess a zone. Guessing would put the plant in the wrong traffic jam and the wrong balancing group.
What it is not. It is not a typing error on the unit, and it is not “the unit spans two zones.” The unit does not span zones; it has a pin the map cannot see.
How to remedy it
- Read the hover — it names the affected Point of Delivery ids.
- This is a System Operator problem. Chase Zones / the SO to cover that location and publish the model (V12 §6).
- Do not invent a zone on the unit to clear the cell.
- Re-assert after the model that covers the pin is in force for tomorrow.
The named zone is not where the meters sit — §7.2(d)
What it means. The form says the plant is in one zone; the meters sit in another. The market schedules the unit against the declared zone’s congestion. A mismatch means the plant is treated as if it sits on the wrong road.
How to remedy it
- The BRP must re-file standing data so the declared zone matches the meters.
- After the §7.1(5) cutoff, that change waits until the day after tomorrow.
- Re-assert and confirm the zones agree.
One plant, two zones — §2.1(212)(a)
What it means. The unit’s meters fall in more than one network zone. One Trading Unit may not straddle two zones. It would be scheduled as if it were in one place while its energy appeared in two.
How to remedy it
- The BRP splits the plant into one Trading Unit per zone.
- Those units can later share a Balancing Group if the party wants to net imbalance (§21.12).
- You do not merge zones on this board to keep one TUID.
Plant bigger than 1 000 MW with no SO letter — §2.1(212)(b)
What it means. A generating unit’s maximum continuous rating is above 1 000 MW, and nobody has recorded a System Operator approval reference. The Code caps generators at that size unless the SO has said otherwise. Demand, storage, and interconnectors are not judged against this ceiling.
How to remedy it
- The BRP obtains an SO approval reference and files it on the unit, or lowers MCR to 1 000 MW or below.
- Re-assert. The hover names the megawatt figure that breached.
Standing data not filled in — §7.2
What it means. Required nameplate fields are still blank. A blank field is read as zero. Zero is a true answer for a solar farm’s minimum run time and a lie for a coal plant — so the platform will not treat “we left it empty” as zero. Until the fields are supplied, the unit cannot be treated as registered for tomorrow.
The hover names how many fields, who owns them (the party or the System Operator), and the first few labels.
How to remedy it
- Open Standing Data (§22.6). See who owns each missing field.
- Chase that owner — the BRP for party fields, the SO for certification fields.
- Incomplete cannot be papered over on this board. Re-assert when the cards move off incomplete.
Minimum generation is negative — §7.2(f)
What it means. The floor of the plant’s output is below zero. You cannot generate minus megawatts. The number is a floor for how little the plant can run, not a sign error.
How to remedy it
- The BRP files a Mingen of zero or more.
- Re-assert.
Nameplate smaller than the floor — §7.2(e)
What it means. Maximum Continuous Rating is below minimum generation. The ceiling is under the floor — the plant would have no operating range at all. The market cannot schedule a machine that must run at 80 MW and must not exceed 50 MW.
How to remedy it
- The BRP raises MCR, or lowers Mingen, so that MCR ≥ Mingen ≥ 0.
- Re-assert. If a bid was already accepted against the old numbers, you may also see the submission failure below.
Emergency Level 1 is below nameplate — §9.3(4)(c)(vi)
What it means. Emergency Level 1 is the top step of the production curve. It must sit at or above MCR. If EL1 is lower, the stairs stop short of the rating the market requires the curve to equal — every bid on that unit would be invalid.
How to remedy it
- The BRP raises EL1 so it equals or exceeds MCR, and aligns the bid elbows to match.
- Re-assert.
Called storage, no storage form — §7.2(h)
What it means. The unit is ticked as storage (a battery or pumped scheme) but has no §7.4 storage profile. The market is told it stores energy and has no charge rating, no tank levels, and no efficiency to schedule it with.
How to remedy it
- The BRP files the storage profile, or unticks storage if the tick was a mistake.
- Re-assert.
Storage form, not called storage — §7.2(h)
What it means. The §7.4 numbers exist, but the storage tick is off. The profile will never be read. It looks like data and behaves like nothing.
How to remedy it
- The BRP ticks storage, or removes the stray profile.
- Re-assert. Tick and profile must travel together.
Called energy-constrained, no energy budget — §7.2(g)
What it means. The unit is ticked as energy-constrained (limited fuel, water, or sun budget) but has no §7.3 profile. The market would dispatch it all day on its megawatt rating, and it would run out of energy partway through.
How to remedy it
- The BRP files the energy-constrained profile, or unticks the flag.
- Re-assert.
Energy budget, flag off — §7.2(g)
What it means. A §7.3 budget exists, but the unit is not designated energy-constrained, so the budget will not be applied.
How to remedy it
- The BRP ticks the flag, or removes the stray profile.
- Re-assert.
A factory in the unit has no meter — §12.1
What it means. An off-taker site belongs to this Trading Unit and has no metering installation. A site can exist as an ordinary customer without a wholesale meter. The moment it is part of a market registration, §12.1 applies: the market settles against a meter, not against a factory name. The hover names the site.
How to remedy it
- The BRP fits or links a conforming meter on that off-taker site.
- Re-assert. Do not drop the site from the unit just to clear the cell unless that is the real commercial answer.
Yesterday’s bid no longer matches the plant — §9.3(4)(c)
What it means. A day-ahead curve was already accepted. Standing data then changed (or is about to, for tomorrow). The bid’s elbows no longer match Mingen or MCR. Clearing would reject it. The hover says how many submissions are now stale.
How to remedy it
- The BRP must resubmit a curve that matches the registered ratings.
- You cannot edit the old bid on this board, and you cannot ignore it — the unit remains failed until a consistent sequence is in.
- Re-assert after the new submission is accepted.
Meter has no other owner — §12.3(1)
What it means. Every metered megawatt-hour must leave one party and arrive at another. This Point of Delivery names nobody on the other side. Usually there is no signed, active physical PPA to derive a counterparty from. Energy through that meter cannot be settled for anyone.
This is the same finding as Counter Party → No counterparty
could be derived (PENDING_COUNTERPARTY). The cell
puts it on the unit; the tab is the chase list.
How to remedy it
Follow §22.5 — get a governing physical contract in force, then re-assert. Do not type a name to clear the row.
The plant named itself as the other side — §7.1(6)
What it means. A Point of Delivery names its own party as counterparty. You cannot sell to yourself through the meter. The clause requires two different parties, one on each side.
How to remedy it
- The BRP names a different active BRP as counterparty — the real taker or supplier at that node.
- That party must then reciprocate (next failure).
- Re-assert.
The named other side cannot take the energy — §7.1(6)
What it means. A counterparty is named, but they are not an active balance-responsible party. Suspended, not a BRP, or inactive — they cannot carry the other half of the meter.
How to remedy it
- Check Participants → Registrations (§21.4) for that party’s status.
- Either they return to ACTIVE, or the declaring BRP names a different active BRP.
- Re-assert. Do not keep a suspended name in place “until they are back” if tomorrow’s day still needs a live pairing.
The other side has not said yes — §7.1(6)
What it means. A counterparty has been named and notified. They have not yet declared the same electrical node in their own registry (or confirmed the notification). The pairing is one-sided. A one-sided pairing is not a settlement basis.
This is the same finding as Counter Party → Waiting on a
counterparty’s declaration
(PENDING_RECIPROCITY).
How to remedy it
Follow §22.5 — chase Confirm (or a reasoned Dispute) on their counterparty inbox. Do not invent a substitute. Re-assert after they confirm.
Balancing group shrunk below two live units — §2.1(21)
What it means. A Balancing Group exists to net two or more live Trading Units against each other. This group has fallen to one — or none. Usually a member deregistered after the group was designated. One plant has nothing to net against, so the group no longer does its job. The failure is attached to a member unit’s cell.
How to remedy it
- Open Participants → Balancing Groups (§21.12).
- The BRP adds another live unit, or cancels the group.
- You cannot compose membership on the registry board. Re-assert after they file.
A grouped plant moved zone — §3.3(5)
What it means. The System Operator republished the zone map. A Trading Unit that belongs to a Balancing Group moved from one zone to another. The group’s cover is still designated, but the mix of zones inside it has changed. The hover names the unit and the from / to zones.
How to remedy it
- The BRP re-designates the group against the new zones (§21.12).
- Acknowledge the published model on Zones if that is still outstanding.
- Re-assert. Do not keep the old designation and hope the map reverts.
Plant in two groups at once — §13.10
What it means. The same Trading Unit sits in two Balancing Groups whose effective windows overlap. A unit may only be in one in-force group at a time. An amendment with a start date in the future can create an overlap that the original save could not see. The hover names the other group.
How to remedy it
- The BRP amends or cancels one group so the windows no longer overlap (§21.12).
- Do not pick a winner in the registry. Re-assert after the overlap is gone.
Careful. Four refusals happen on the form, not in this cell: creating a group with fewer than two units, grouping two different parties, adding a unit that is already grouped for that window, or registering a generator site that is already a Trading Unit. Those never appear as Today’s failures — the save is rejected on the spot.
Careful. Pairing failures on this cell and the two lists on Counter Party are the same facts. Clearing the wrong list with the wrong action wastes a day you do not have after the §7.1(5) cutoff. Read §22.5 before you chase.
22.5 Counter Party — pairing exceptions
Tab: Counter Party
(/mo/registry/counterparty). Section
#mo-registry-counterparty.
Header: Counterparty pairing (§7.1(6), §12.3(1)) — Every Point of Delivery needs two owners. One list is a chase; the other is a commercial gap. They are kept apart so the remedy is not mixed.
Re-assert for tomorrow
(#mo-registry-counterparty-refresh) is the same
re-assertion as on Trading Units — tomorrow’s Trading Day, not
today.
§12.3(1) requires every metered megawatt-hour to be exported by exactly one party and imported by exactly one other. A Point of Delivery missing its other half cannot be settled — not for the party that declared it, and not for its counterparty either. The platform derives the counterparty from signed / active physical PPAs; it does not invent one (V9 §3.4).
Two lists. Same columns on both: pod_id ·
electrical_node · tuid · message.
Empty state: None.
Waiting on a counterparty’s declaration — §7.1(6)
List: #mo-registry-pending-reciprocity. Status behind
the row: PENDING_RECIPROCITY.
What it signifies. A counterparty has already been named — usually because derivation found a signed contract, or because a party declared one — and that counterparty has been notified. Until they declare the same electrical node in their own registry (or confirm the notification), the pairing is one-sided. A one-sided pairing is not a settlement basis.
The Code obliges you to inform the other party when a Point of Delivery is added or removed (§7.1(6)). This list is the open half of that handshake: notified, not yet answered.
What it is not. It is not “we do not know who the other party is.” You do know. The other party has not reciprocated yet.
How to remedy it
- Identify the named counterparty from the row (electrical node + declaring TUID + message).
- Chase that party — they clear it on BRP / Market → Market registry via the counterparty inbox: Confirm (pairing goes live) or Dispute with a written reason (V9 §3.5).
- Do not invent a substitute or re-derive past the named party. Confirmation is the reciprocal declaration for §7.1(6).
- Escalate silence. An unanswered declaration leaves both sides unsettleable at that node. If the declaration looks wrong, a dispute with a usable reason (“that busbar feeds the plant next door”) is faster than letting it sit.
- Re-assert for tomorrow after they confirm, and
confirm the row leaves
#mo-registry-pending-reciprocity.
No counterparty could be derived — §12.3(1)
List: #mo-registry-pending-counterparty. Status behind
the row: PENDING_COUNTERPARTY.
What it signifies. No active contract names anyone at this Point of Delivery, so there was nothing to derive a counterparty from. The platform leaves the point empty and lists it here. That emptiness is the finding: either an unregistered commercial arrangement, a missing / unsigned physical PPA, or a Virtual PPA that never creates a wheeling pairing while the plant still injects real energy that needs a real taker.
What it is not. It is not a data-entry typo you fix by typing a name. It is not reciprocity waiting on a known party. Collapsing this list with the one above would send you to chase a counterparty who does not exist.
Only SIGNED and ACTIVE physical contracts
count for derivation. NEGOTIATING or agreed-but-unsigned
PPAs govern nothing yet. Ambiguous derivation (two active contracts
naming different counterparties at the same point) is a registry
conflict, not something the desk papers over.
How to remedy it
- Treat it as a commercial worklist. Ask: who is actually taking / supplying energy at this meter?
- Get a governing physical contract in force — signed
and active — that names exactly one counterparty for that site and side.
Then re-assert; derivation should name them and move the point to
PENDING_RECIPROCITY(the chase list above). - If only a Virtual PPA exists, remember it creates no Point of Delivery pairing. The injection still needs whoever physically takes the energy under a physical arrangement (V0 §5).
- If two contracts disagree, resolve the commercial conflict — §12.3(1) allows exactly one importer and one exporter per megawatt-hour. Do not pick a winner in the registry by hand.
- Never invent a counterparty to clear the row. A plausible-looking name would settle real energy against a party that never agreed to take it.
| List | Status | Meaning | Your move |
|---|---|---|---|
| Waiting on a counterparty’s declaration — §7.1(6) | PENDING_RECIPROCITY |
Named and notified; reciprocity not filed | Chase / confirm via their counterparty inbox |
| No counterparty could be derived — §12.3(1) | PENDING_COUNTERPARTY |
No active contract to derive from | Commercial fix — signed physical PPA (or resolve conflict) |
Careful. Both exceptions block settlement at that node for everyone on the meter. Clearing the wrong list with the wrong action wastes a day you do not have after the §7.1(5) D−1 cutoff.
22.6 Standing-data review
Tab: Standing Data
(/mo/registry/standing-data). Section
#mo-standing-data.
Refresh standing data
(#mo-standing-data-refresh). The four summary cards
(#mo-standing-data-summary, -evidenced-count,
-assumed-count, -incomplete-count) sit
only above Trading Units (§22.4).
This tab is the incomplete list and the SO certification queue
(#mo-standing-data-queue-count).
| Panel | Id | How to read it |
|---|---|---|
| Incomplete — §7.2 | #mo-standing-data-incomplete |
Cannot register: missing count
(#mo-standing-data-incomplete-count), by owner |
| System Operator certification queue — §7.2(q)–(t) | #mo-standing-data-certification-queue |
Unit · Capability · Clause · Requested · Effective from · Status |
Assumed standing data is flagged on the Trading Units table (amber assumed badge → detail modal), not as a separate yellow-card list.
You can see certification; you cannot make it.
Until the SO certifies, capacity is 0.000 and
availability indicators are U (V12 §6). Empty queue:
Nothing awaiting a decision.
Follow along. Path: Registry. If you came from Submissions, the address already has
?tuid=. Confirm the highlighted row on Trading Units. Then open Counter Party and read both exception lists — they are different chases. Then read Today’s failures — a blank cell is invariants for that unit, not “the network is clear.”
23. IPPs
Path: Market Operator → IPPs
(/mo/ipps). Third item in Eligibility. The
icon is a bolt.
Generator sites filed through the standing-data wizard — organisation, BRP ref, TUID (deep-link to Submissions), fields supplied. Actions are icons with hover tooltips and distinct colours. View is first and expands certified reserve and the §7.2 field cards; then Certify, Chase, and Suspend unit (or Restore when the unit is already suspended). The Market Operator does not file Trading Units.
Where this is taught. The three participant wizards: V9 §3.9B. Reserve certification is the System Operator’s: V12 §6.
### 23.1 The operator’s problem
A plant exists in the org app. You need the market’s view of that plant: who owns it, which BRP speaks for it, how complete the §7.2 filing is, whether reserve is certified, a chase when the filing is stale, and a confirmed suspend when the unit must stop.
### 23.2 How the page is laid out
Browser title: IPPs. Header: IPPs — Generator sites registered with the market — organisation, BRP ref, and the §7.2 standing data filed for each plant.
No tabs. One table #mo-ipp-registry headed IPPs
— {count}. Empty: No generator sites have been registered
with the market yet. Search #mo-ipp-registry-search
filters by IPP / site, organisation, or BRP ref. Sort headers: IPP /
site (#mo-ipp-registry-sort-site) and MCR
(#mo-ipp-registry-sort-mcr) by MW. The MCR header has an i
icon #mo-ipp-registry-mcr-info whose tooltip is Maximum
continuous rating.
### 23.3 The table — how to read a row
Row #ipp-row-{id}.
| Column | Meaning |
|---|---|
| IPP / site | Generator site name |
| Organisation | Who owns the plant |
| BRP ref | The registration that bids it |
| TUID | #ipp-tuid-{id} — navigates to
/mo/bidding/submissions?tuid= |
| MCR | Maximum continuous rating — i icon
#mo-ipp-registry-mcr-info |
| Fields | {supplied}/{total} §7.2 completeness
(#ipp-fields-{id}) |
| Actions | Coloured icons with hover tooltips. View · Certify · Chase · Suspend unit (or Restore) |
| Button | Id | Colour | What it does |
|---|---|---|---|
| View | #ipp-view-{id} |
Brand purple | Expands #ipp-expand-{id} |
| Certify | #ipp-certify-{id} |
Amber | Requests SO regulating-reserve certification. Flash on failure: Could not request certification: … |
| Chase | #ipp-chase-{id} |
Sky | Emits a registration notification. Chase recorded for {tuid}. |
| Suspend unit | #ipp-suspend-unit-{id} |
Rose | Opens confirm #ipp-suspend-confirm. Only after you OK:
{tuid} is suspended. |
| Restore | #ipp-restore-unit-{id} |
Emerald | Shown instead of Suspend when the unit is already suspended. {tuid} is restored. |
Suspend is not one click. #ipp-suspend-unit-{id} opens
the confirm modal; #ipp-suspend-confirm writes the
suspension. Back (#ipp-suspend-cancel)
leaves the unit registered. Once suspended the row stays on the register
and the icon becomes Restore.
Certify is a request. The SO still has to agree a MW figure and a reference. Until then certified capacity is 0.000.
### 23.4 The expanded card
| Block | Id | How to read it |
|---|---|---|
| Completeness gate | #standing-data-completeness |
{tuid} cannot be registered: N of M fields have not been supplied. |
| Certified reserve capability §7.2(q)–(t) | #standing-data-reserve |
Capability · Clause · Certified · Status · SO reference · Indicator (A or U) |
| {tuid} — every §7.2 field | #standing-data-editor |
Grouped as the Code groups them. Field · Clause · Value · Provenance · Data owner |
Storage / energy-constrained edit forms appear only when
editable: true — not on this seat. You inspect; the
participant files.
Demo rows: IPP2 Atlantis Wind, IPP1 Sandton Solar, IPP3 Midrand Hybrid.
Follow along. Path: IPPs. Open IPP2 Atlantis Wind → View. Read the Fields ratio, then reserve indicators. Click the TUID to land on Submissions for that unit.
24. Zones
Path: Market Operator → Zones
(/mo/zones). Fourth item in Eligibility.
The icon is a map.
Network Zone coverage, the gap list, the CSV that goes to the System Operator, and MO acknowledgement of the SO network-model version (§3.3(5)). Two tabs.
Where this is taught. What a zone is, and why a book can become three registrations: V12 §2. Editing corridors and flags: V12 §5. This chapter is the Market Operator’s coverage desk.
### 24.1 The operator’s problem
Tomorrow’s constrained solve needs every Trading Unit in exactly one zone. Sites the model cannot place are silent failures until someone exports the gap list. An SO model version you have not acknowledged is not yet the register you will clear against.
### 24.2 How the page is laid out
Browser title: Zones. Header: Zones — Network-zone register in force, coverage, and sites the model cannot place.
Tab bar #mo-zones-nav.
| Tab | Path | live_action |
What it is |
|---|---|---|---|
| Zones | /mo/zones |
:zones |
Register in force, coverage, ack |
| Unplaced Sites ({N}) | /mo/zones/unplaced |
:unplaced |
Gaps + overlaps + CSV |
CSV (not a LiveView): GET /mo/zones/gaps.csv.
### 24.3 Zones tab — acknowledge, then read the register
SO network-model version (§3.3(5))
(#network-model-ack):
| Control | Id | What it does |
|---|---|---|
| Acknowledged by | #network-model-ack-by |
Authoriser — required |
| Effective from | #network-model-ack-from |
Date — required |
| Acknowledge | #network-model-ack-form |
Records the ack. Two-month notice before the model binds. |
No SO version yet: No SO network-model version has been received. The register below is provisional until one is. Errors: Acknowledgement needs an authoriser and an effective date.
Network zones (§3.3(4))
(#mo-zones-panel). Recompute coverage
(#mo-zones-refresh). Banner is either
#mo-zones-provisional-banner (Mutually exclusive,
Not exhaustive, no inter-zonal capability figures) or
#mo-zones-published-banner.
Coverage stats: Zones · Total Trading
Units · Market sites ·
Allocated (#mo-zones-stat-zones,
-stat-trading-units, -stat-total,
-stat-assigned). Only ACTIVE BRP units
count.
| Column | How to read it |
|---|---|
| Zone | Code; row #mo-zone-{code} |
| Name | Everyday name (Northern Corridor, Highveld Load, …) |
| Sites | Click #mo-zone-{code}-site-count to expand |
| Trading Units | Click #mo-zone-{code}-tu-count |
| Dominant character | What the zone mostly is |
| Core nodes | e.g. Apollo, Minerva, Kendal |
| Market implication | What a constraint here does to clearing |
| Effective | From when |
Expanded sites: Organization · Site Name · Type (Generator / OffTaker) · Address (opens the map modal) · Meter Number.
Expanded units: TUID · Name · Organization · Kind (IPP / OffTaker / Trader Pool) · Site / Pool · Class · Status · MCR · BRP.
No model: No zone model loaded. The provisional register lives in docs/references/market/spec/zones/fullspec.json.
Nine provisional zones Z1–Z9 until the SO publishes. The areas do not overlap (good); they cover only about a fifth of the country (not good). Every corridor figure is an estimate until declared (V12 §2.3).
### 24.4 Unplaced Sites — gaps, overlaps, include
#mo-zones-unplaced-panel — Sites the model
cannot place. Recompute coverage
(#mo-zones-unplaced-refresh). Export for the
SO (#mo-zones-gap-export) →
/mo/zones/gaps.csv.
All placed: Every market site falls inside a zone. No model: No zone model loaded — coverage (and therefore unplaced sites) cannot be computed yet.
| Column | Meaning |
|---|---|
| Organization | Who |
| Site | Name |
| Kind | Generator / OffTaker |
| Address | Opens #mo-zone-site-map-modal (Leaflet — pin + distance
line to nearest zone) |
| Nearest zone | Best guess |
| Distance | How far the pin sits outside |
| Which way | Direction of the miss |
| Action | Include
(#mo-zone-gap-{site_id}-include) — expands the nearest zone
polygon |
Include is a Market Operator action. Overlay
#mo-zones-include-overlay: Including site in nearest
zone… Failures flash (overlap, already allocated, no nearest
zone).
Overlaps (#mo-zones-overlaps): {n}
site(s) fall in more than one zone — the model overlaps and allocation
is undecidable there. That is a model bug, not a site bug.
Follow along. Path: Zones. If the banner is provisional, read it before you plan a corridor. Open Unplaced Sites. If the count is zero, every market site is inside a zone — not “the network is unconstrained.” Export the CSV only when you mean to send it to the SO.
25. Rules
Path: Market Operator → Rules
(/mo/rules). First item in Reference. The
icon is a book.
Publish market parameter versions — gates, floor and cap, and the
eight [D-nn] defect switches with their clause. A published
version with effective scope is the safe completion signal. There is no
inline edit of the live table.
Where this is taught. Why the eight switches exist: V9 §17. This chapter is the publish ceremony.
### 25.1 The operator’s problem
Tomorrow’s solve will hash the parameters it used. If you quietly change the price cap on the live table, yesterday’s run and tomorrow’s run pretend to share a rulebook. A new version must be composed, reviewed, and confirmed — with an effective date — so two runs that differ by one intended input are visible as different.
### 25.2 How the page is laid out
Browser title: Rules. Header: Rules — Market Code parameters, defect switches, and confirmed version publishing.
No route tabs. Three stages: :closed
(read) → :edit (compose) → :confirm (review).
Panel #mo-rules-panel — Market rules — all
twenty-four parameters. Empty: No parameter version
published yet.
Metadata strip: Effective from
(#mo-rules-effective-from) · Stated until
· Determined by · Snapshot hash
(#mo-rules-snapshot-hash). Badge
#mo-rules-carried-forward: Carried forward past its
stated period (§2.3(r)) — values stay live after
effective_to.
View Market rules (#mo-rules-view-pdf)
opens #mo-rules-pdf-modal with Market Code Rev 2.3 in a PDF
viewer. Tabs switch to the four SAWEM Rules (conduct, CPA, disputes,
BRPs). Close, print, or download from the footer.
Publish new version…
(#mo-rules-publish-open) opens the compose form. You cannot
type into the read table.
### 25.3 The twenty-four parameters — how to read a row
Eight groups. Each row #mo-param-{key}: Label
[D-nn] · Value · Unit · Clause · Effective date. Sentinels:
MGC determines, not set,
—.
| Group | What lives here |
|---|---|
| Prices and caps | Market Price Cap [D-18], Price Floor, IDM collar (% of
SMP) |
| Reserve floor prices | Instantaneous / Regulating / Ten-minute floors (R/MW) |
| Gates and auctions | DAM gate (SAST, D−1), five IDM gate times |
| Metering and balancing | Accuracy band, Out of Merit Energy [D-07], Balancing
Penalty Factor [D-04] |
| Settlement and disputes | Materiality (R), Recalculation threshold (%), Default interest, Risk period |
| Credit cover | Undefined Exposure Factor, Warning Limit max, Adjustment trigger |
| Registry thresholds | DSU / Generator suspension delay (days), MCR ceiling, participant threshold (kW) |
| Market grain and bid format | Trading Period length (minutes), Maximum bid lines |
Shipped commencement (tests): effective 2026-01-01, Market Price Cap R 5,396.40 / MWh (not the legacy 32,000). A staged future version may show cap R 5,800.00 and gate 09:30:00.
25.4 The eight defect switches
Table Defect switches — which setting is live. Row
#mo-switch-{key}: [D-nn] · Label · Live
setting · Clause · Effective date.
| Defect | Question the switch answers |
|---|---|
| D-08 | May a flexible Demand Side Unit set the SMP? |
| D-09 | Which volume the on-instruction balancing leg prices |
| D-07 | Fraction of the Out of Merit Energy allowance that binds |
| D-06 | How the Balancing Price Selling is clamped to the SMP |
| D-11 | Must a unit be deliverable to enter the balancing stack? |
| D-13 | How the debit-note cascade recovers an excess |
| D-02 | Reference price for the additional energy payment |
| D-10 | Pricing of the gap in the against-instruction leg |
Defaults include true, delivered,
1.0, floor_at_smp, sequential,
smp, none. Changing a switch is a new
version, not a toggle on today’s run.
### 25.5 Compose → review → confirm
Compose (#mo-rules-publish-form): every
parameter (number / text / time; IDM gates are five time fields,
captions Iter 1 D−1 …), every switch, Effective
from (default tomorrow), Stated until
(optional), Determined by (default MGC
determination). MGC-determined params carry placeholder MGC
determines — leave blank.
Review version… (#mo-rules-review)
opens #mo-rules-publish-review. Changed rows only:
Parameter · Clause · In force · Proposed
(#mo-rules-change-{key}). No diffs: No parameter
differs from the version in force. Publishing will record a new version
with identical values.
Confirm and publish version
(#mo-rules-confirm-publish). Flash: Parameter version
published, effective {date}. Failure: Could not publish the
parameter version — check the values. Back to edit
returns to compose. Cancel abandons.
Cancel from edit or review returns to closed. The live table never becomes a spreadsheet.
Follow along. Path: Rules. Read
#mo-rules-snapshot-hash— that hash is what Runs pins. Do not publish a version whose effective date is today unless you mean today’s remaining callables to see it.
Careful. Rules changes the future validation boundary. They do not rewrite a published schedule.
26. Runs
Path: Market Operator → Runs
(/mo/runs). Second item in Reference. The
icon is a rectangle-stack.
Every Mo.Run: inputs hash, parameter hash, supersedes,
kind. Two runs that differ by one intended input are not the same run.
Read-only. No refresh button — the list follows the month (and optional
kind) in the URL.
### 26.1 The operator’s problem
Someone will ask which solve produced this SMP? Cadence tells you whether publish ran. Daily tells you the sentence Published at 13:40. Runs tells you the fingerprint: the inputs that went in, the parameter version that bound the arithmetic, and whether this run superseded another. That is the flight recorder.
### 26.2 How the page is laid out
Browser title: Runs. Header: Runs — Every clearing and settlement computation as an immutable run: inputs hash, parameter hash, supersedes, kind.
One table #mo-run-browser. You land on the
current SAST month (label like August
2026). ‹ (#mo-runs-month-prev)
and › (#mo-runs-month-next) step a month;
next is disabled once you are on the current month. Deep-link with
?month=2026-07. The header row stays visible while you
scroll (#mo-run-browser-scroll, sticky
th).
Empty is month-aware: There are no runs in August 2026. when that month is quiet; No runs recorded yet. only when the browser has nothing at all. A load error also presents as empty.
Kind filter #mo-runs-kind-filter —
eleven coloured chips, one per kind, plus All. Default
is every kind in the selected month. Click a chip to keep that family;
click more to combine; All clears back to the full
month. Optional ?kind=dam-prices. If the month has rows but
none match, you see No runs of the selected kind in August
2026.
Click Date (#mo-runs-sort-date) to
toggle newest-first and oldest-first on trading_date (then
started_at). Default is newest-first. Dates read 18
Aug 2026, not ISO.
| Column | How to read it |
|---|---|
| Kind | Coloured badge #run-kind-{run_id} — DAM (sky), IDM
(violet), metering (amber), balancing (emerald), settlement (orange),
administered (zinc) |
| Date | The Trading Day or Billing Period the run is about
(%-d %b %Y) |
| Inputs hash | #run-inputs-{run_id} — click to open the stored
intended-inputs payload (#mo-run-payload-modal). The hex is
a seal, not a cipher. |
| Parameters hash | #run-parameters-{run_id} — click to open the stored
Rules-snapshot payload in the same modal |
| Supersedes | The prior run this one replaced, or — |
Row #run-{run_id}. Matching inputs hash and
parameters hash means Run.reproduces?/2 — same answer if
you ran it again. A correction chain is the Supersedes
column, not a silent overwrite.
Metaphor. Cadence is whether the train left. Daily is the arrival board. Runs is the sealed logbook: locomotive number, timetable version, and which earlier logbook this one replaces.
You cannot delete a run. You cannot edit a hash. If a curve is wrong, the BRP sends a new sequence and you solve again — a new row, a new inputs hash, and (after publish) a supersede.
Follow along. After you Solve then Publish on Daily for 2026-07-15, open Runs and step back to July 2026 (or open
/mo/runs?month=2026-07) — the default month is today, so July is one click behind. You should see a new row whose parameters hash matches#mo-rules-snapshot-hashon Rules. Two solves with the same submissions and the same rules reproduce; change one offer and the inputs hash moves.
Where this is taught. Publication, hashes and the sandbox: V9 §12 · V13.
27. The forward register
Path: Market Operator → Forward
(/mo/forward). Third item in Market day,
after Cadence. The icon is a calendar.
This is the book of physical bilateral schedules registered before the day-ahead gate, and the transfer capability they consume. Residual clearing — why a registered schedule is a constant, not a bid — is §6.8. The instrument, the gate and the participant API are V9 §20.
27.1 The register
Screen: /mo/forward (#mo-forward-register).
Pick a delivery day. Every schedule whose horizon covers that day is
listed: seller Trading Unit, buyer, horizon, version,
status, and the per-period profile.
Status is a closed machine. You do not skip steps.
| Status | What you may do |
|---|---|
| SUBMITTED | Validate (#mo-forward-validate-…). The
remaining-capability check. |
| VALIDATED | Register (#mo-forward-register-…).
Your act, not the participant’s. |
| REGISTERED | Live. Consumes transmission. Enters the day-ahead run as a C1 constant. |
| SUPERSEDED | History. The profile is kept so a Settlement Rerun can say what the register was. |
A skip from SUBMITTED to REGISTERED is refused: validation cannot be skipped. A participant caller registering is Isolation’s 404, never a 403.
If validate refuses, the flash names the Trading
Period, the edge (for example
zone Z1 export), the megawatts over, and
any earlier registrations that already took the room.
Capability is consumed first-come. Nothing is pro-rated.
27.2 The capacity view
Screen: /mo/forward/capacity
(#mo-forward-capacity). Same delivery day.
Remaining transfer capability is capability minus registered flow, per Trading Period, per edge. The definition is written down in V9 §20.6 and nowhere else — stage 13 inherits this figure as the “remaining” half of available transfer capability.
Each row stamps provenance on its face:
| Stamp | Meaning |
|---|---|
| DECLARED | The underlying capability is a System Operator declaration. The remaining figure may be published as a network limit if the rest of the model is publishable. |
| ASSUMED | The underlying capability is the corridor roll-up (or an assumed interconnector). The remaining figure is not publishable as a network limit. |
An assumed stamp that fell off on the way to a quoted ATC would be a number nobody can stand behind. The stamp stays on the screen.
The platform still implements exactly one security-constraint kind,
:ZONAL_EXPORT_LIMIT. This view does not invent a
corridor-flow constraint. Corridor remaining is reported; it is not a
new LP family.
27.3 Why the stamp matters
Provisional.publishable?/1 still decides whether the
network model may be published as a limit. Remaining capability inherits
that verdict. Publishing an ASSUMED remaining figure as if it were
declared capability would tell a neighbouring operator — and, later, a
SAPP counterparty — a number this System Operator cannot stand
behind.
If the figure you need is not on this screen, the model does not have it. Do not copy a corridor sum into a declaration by hand.
