Skip to content

feat: adapt the methodology's dimensions and factors to the Dominican context - #618

Open
mrivas00 wants to merge 18 commits into
feat/mati/rd-organization-formfrom
feat/mati/rd-methodology
Open

feat: adapt the methodology's dimensions and factors to the Dominican context#618
mrivas00 wants to merge 18 commits into
feat/mati/rd-organization-formfrom
feat/mati/rd-methodology

Conversation

@mrivas00

@mrivas00 mrivas00 commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Why

Three of MMARN's observations are about the methodology offering options the
country does not have and omitting the ones it does: no passenger rail but a
cable car and a metro; waste that mostly reaches dumps rather than sanitary
landfills; a grid that is not one grid. Tip of the RD stack, based on
feat/mati/rd-organization-form.

What changes

Commuting. Adds Teleférico — as an option with no factor, see below —
drops both rail options, keeps the metro,
spells out Bicicleta, and renames the ride-hailing option to
Taxi/vehículo de transporte individual — one value, not three, until the
factors actually distinguish taxi, motoconcho and platform vehicles.

Solid waste. Adds Vertedero a cielo abierto and Vertedero controlado
alongside the sanitary landfill, plus an Otro.

Electricity. Replaces the single national value with the SENI, isolated
systems and Otro.

The new values ship without factors. Pricing them is MMARN's: a number
derived here is a foreign estimate wearing a national badge, and once seeded it
stops travelling with the reasoning that produced it. So the isolated-system
diesel factor, the two IPCC-MCF multipliers over the DEFRA landfill figure per
material, and every Otro that carried the highest factor of its dimension are
all gone — thirty-two rows. The values remain as options.

What the platform already had is untouched. Relleno sanitario,
Incineración and Reciclaje keep their DEFRA 2025 factors, and both commuting
renames carry the same rows under new names. Nothing that worked before this
branch calculates differently after it, with the one exception below.

A first pass also obliged a line selecting Otro to carry a comment, enforced
server-side and surfaced as a red badge on the comment action. That is
removed too. The rule matched dimension values by name, and exactly two
values are named Otro — the waste destination and the electricity system — so
it could not be relaxed for one without becoming a per-dimension rule. Comments
are optional everywhere again; the subcategory explanations still ask for one,
they just no longer claim the line cannot be saved without it.

What this gives up: a registrant selecting one of the new values has to supply
a factor to close the line, and nothing obliges them to explain an Otro. Both
are the intended reading of a gap — an empty factor asks a question where a
derived one answered it wrongly — but they are friction, and worth knowing before
this reaches registrants.

The one factor this branch changes

The SENI grid factor moves from 0.177 to 0.53495 kgCO₂e/kWh. The old value
is a UK figure inherited from the demo dataset — it understated Dominican grid
emissions roughly threefold, and it prices Scope 2 for every organization in the
country. Changing it is beyond what the tasks asked for; I judged that shipping a
national registry with a UK grid factor was worse than replacing it with an
order-of-magnitude-correct national one. Confirm it against what the CNE / MEM
publishes before the first reporting cycle closes.

It is the only number the branch touches. Everything else it adds is an option
whose factor MMARN supplies, documented in
docs/development/rd-methodology-factors.md
— which also keeps the question the dropped waste multipliers raised, because it
is the one to answer before any number goes in: is the disposal-route ranking
driven by methane generation, or by net emissions after capture?
DEFRA's
landfill figure is net of gas capture, so the two readings rank dumps on opposite
sides of the sanitary landfill.

The cable car is the same story: a drafted 0.04 kWh per passenger-km × the
grid factor, dropped because the 0.04 is a mid-range for an urban aerial cableway
anywhere, not a measurement of the Santo Domingo system. Ask the operator.

Because all active factors of a subcategory must share one source string, each
touched subcategory states its basis there — and because that string is also the
label of the factor-source selector in capture, it stays short enough to read in
the control: DEFRA 2025 for commuting and waste, SENI for electricity.

Also

  • The three subcategory explanations describe the new options — the Scope 2 text
    was promising a national-grid selection the dimension no longer offers.
  • Three worked examples still priced in Chilean pesos become Dominican pesos.
  • The dimension-value input stays a bare string: no maintainer payload changes.

The motoconcho was being sent to the wrong option. The commuting explanation
told registrants to declare taxi, motoconcho and platform vehicles together
under Taxi/vehículo de transporte individual because they "comparten un mismo
factor". They do not: a motoconcho is a motorcycle, and Moto carries
0.114 kg/km against the taxi option's 0.149 for a car — following that guidance
overstated a motoconcho kilometre by about a third. Observation 5 conditions the
breakdown on the factors differing, and for the motoconcho they already do, so
it sits outside the condition rather than being an exception to it. Taxi and
platform vehicles stay together, which is what the observation was about.

Teleférico was appended after Caminata, so the selector listed a
motorised mode below the two that emit nothing. It moves beside Metro, where
the explanation already lists it. Order only — no factor touched.

The acceptance fixture is repinned.
docs/development/manual-testing-emission-capture.md still priced electricity
at Sistema nacional · 0.177, a value this branch deletes, and its own rule is
that a factor edit invalidates its expected values. The inventory total moves
from 1.096,31 to 1.758,52 tCO₂e and Scope 2 from 30 % of the footprint to 56 %,
which is the point of the SENI change and worth seeing in a fixture before it is
seen in a real inventory.

Leftovers of the withdrawn comment requirement. Removing the prop left its
doc comment behind, where it had come to describe pendingFilesCount — a count
of files — as a line whose comment is mandatory. With that and a stray blank
line restored, this branch no longer touches EmissionEditorActionsCell or
useEmissionCaptureSubmit at all.

Verification

pnpm format, pnpm lint, pnpm type-check and pnpm test:web (746 tests) run
green.

The full API suite is green too: 2,304 passing, 8 skipped, 226 files across
the base, storage-azure and storage-minio projects. Its globalSetup
deploys every migration and runs the whole seed into a fresh Postgres
testcontainer, so the methodology rewrite in this PR does load — the dimension
values, the removals and the one factor change all survive a real seed.

Still unverified: what a registrant sees. That a value with no factor falls
through to Otro in Fuente factor and still saves is read from the code, not
exercised through the UI. Worth ten minutes by hand on Teleférico, a
Vertedero, Sistema aislado and either Otro before this reaches registrants.

No migration. No check runs on this PR: ci.yml triggers on
pull_request: branches: [main].

@mrivas00 mrivas00 added priority: high High priority type: feature new user-facing capability or enhancement area: api apps/api (Fastify backend) area: web apps/web (React frontend) area: packages shared packages/* labels Aug 21, 2026
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from 1ef4e27 to 0be1de0 Compare August 24, 2026 12:25
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from 7fd1bff to 6b8216b Compare August 24, 2026 12:26
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from 0be1de0 to ecd8724 Compare August 24, 2026 15:10
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch 2 times, most recently from 6b5a9ab to c9cda4f Compare August 24, 2026 17:58
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch 2 times, most recently from c0e6b4a to 6ac727a Compare August 24, 2026 19:11
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from c9cda4f to 081f690 Compare August 24, 2026 19:11
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from 6ac727a to 6647586 Compare August 25, 2026 18:51
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from 081f690 to 0cfa545 Compare August 25, 2026 18:51
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from 6647586 to a4f3634 Compare August 25, 2026 18:52
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch 4 times, most recently from 8c24a34 to 1dba99c Compare August 25, 2026 21:05
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from a368a3f to ed205e6 Compare August 26, 2026 12:12
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from 1dba99c to ecd0aa2 Compare August 26, 2026 12:12
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from ed205e6 to dceb2a7 Compare August 26, 2026 12:36
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from ecd0aa2 to 04df5d6 Compare August 26, 2026 12:36
Three dimensions the observations name:

**Commuting.** Adds `Teleférico` (electric traction, priced at the grid factor
per passenger-kilometre), drops both rail options the country has no network
for, keeps the metro, spells out `Bicicleta`, and renames the ride-hailing
option to `Taxi/vehículo de transporte individual` — one value, not three,
until the factors actually distinguish them.

**Solid waste.** Adds the two disposal routes most Dominican waste actually
takes, open dump and controlled dump, and an `Otro` that requires a comment.
Their factors scale the landfill figure by the IPCC 2006 Vol. 5 Ch. 3 methane
correction factor for the site type. `Otro` takes the most conservative
destination of its material, so an unclassified route never understates.

**Electricity.** Replaces the single national value with the SENI, isolated
systems and `Otro`. Isolated systems are diesel generation and therefore well
above the interconnected grid; `Otro` takes the highest factor of the
dimension.

Every factor here is a proposal pending MMARN validation, which is why each
touched subcategory's source string says what it was derived from — the
single-source-per-subcategory rule means the whole subcategory carries it.
`Otro` is an escape hatch — the methodology cannot classify what the user
selected. Its line has to say what it actually was, or the registry stores an
emission nobody can audit afterwards.

Which names count as escape hatches lives in a shared constant rather than a
column on the dimension value: this deployment seeds its methodology, and a
per-value flag only earns a schema change if an administrator can toggle it,
which would mean a maintainer surface for it. Names are matched exactly, so
`Otro país` and `Otro proceso` stay ordinary options.

Checked in one query before the transaction opens, so a batch that violates it
writes nothing. Whitespace does not count as an explanation.
The comment action on a line whose selected value demands one turns red, with
a tooltip saying why, and saving stops with the offending option named rather
than letting the API reject the batch opaquely.

The front applies the same shared constant the API does, so the two cannot
disagree about which values are escape hatches.
The Scope 2 text promised a national-grid selection the dimension no longer
offers; it now names the SENI, the isolated systems and what `Otro` obliges
the user to write. The waste text gains the two dump types and the same note
on `Otro`, plus the three materials the list had been omitting. The commuting
text drops the rail modes, adds the cable car and explains why taxi,
motoconcho and platform vehicles share one option.

Also converts the three worked examples still priced in Chilean pesos to
Dominican pesos, with Dominican fuel and electricity prices.
Five cases on the capture endpoint: an escape-hatch value with no comment is
rejected and writes nothing, a whitespace-only comment is rejected too, a real
comment is accepted, an ordinary value is unaffected, and an update that clears
the comment of an existing line is rejected as well.

Also asserts the requirement is not an exemption — the methodology response
still resolves an emission factor for the value.

The fixture builds its own methodology so it cannot leak into the other suites
in the file, and tears it down in dependency order.
Each new dimension value, its derivation and the source it cites, plus the two
places the derivation is an approximation worth challenging: the grid factor
that prices Scope 2 for the whole country, and whether the disposal-route
ranking should follow methane generation or net emissions after capture.

Also documents the mandatory-comment rule in the onboarding guide, including
the one thing to watch — renaming `Otro` from the maintainer disables it,
because the rule is the name — and indexes the document in the development
README.
The source string doubles as the option label of the factor-source selector
in capture, and it was a full sentence — grid factor, diesel derivation and
the pending-validation caveat all in one line, truncated in the control and
unreadable in the dropdown. It names the source now.

Nothing is lost: `docs/development/rd-methodology-factors.md` carries the
derivation of both values and states that the figures are a proposal MMARN
has not confirmed, which is where a reader looking for provenance goes.
The 0.02366 kg/km was 0.04 kWh per passenger-kilometre times the SENI
factor, on the reasoning that the traction is electric. The 0.04 is a
plausible mid-range for an urban aerial cableway anywhere, not a measurement
of the Santo Domingo system — and once seeded, a number nobody measured
stops travelling with the caveat that says so.

The `Teleférico` option stays, because the observation asks for it. A line
that selects it now finds no factor and falls through to `Otro` in the
factor-source selector, where the registrant enters the operator's value.
That reads as the gap it is rather than as an answer.

With it goes the compound source string the remaining fourteen factors
carried: they are DEFRA 2025 and now say so, which is also what the capture
selector shows.
The requirement matched dimension values by name, and exactly two values in
the methodology are named `Otro` — the waste destination and the electricity
system. That made it impossible to relax for one of them without turning the
rule into a per-dimension one, which is more machinery to justify two options
behaving unlike every other value in capture.

So it goes entirely: the constant and its predicate, the server-side check
that ran before the transaction, the `DIMENSION_VALUE_REQUIRES_COMMENT` error
and its Spanish copy, the pre-submit guard, and the red badge on the line's
comment action. Comments are optional everywhere again.

What kept the escape hatch honest was never only the comment: `Otro` still
takes the highest factor of its dimension, so it cannot understate. The word
_especifique_ from observations 4 and 6 now lives where the registrant reads
it — the subcategory explanations still ask for the comment, they just no
longer claim the line cannot be saved without one.
The observations asked for options the country actually has — the two dump
types, isolated grids, the escape hatches. Pricing them is not this branch's
call: Dominican factors come from the Dominican authority, and a number
derived here is a foreign estimate wearing a national badge. Once seeded it
stops travelling with the reasoning that produced it, and an auditor reading
the inventory cannot tell it from a measured one.

So the derived numbers go: the isolated-system diesel factor, the two
IPCC-MCF multipliers over the DEFRA landfill figure per material, and every
`Otro` that carried the highest factor of its dimension. Thirty-two rows.

What stays is what the platform already had. The waste destinations it
already carried — relleno sanitario, incineración, reciclaje — keep their
DEFRA 2025 factors untouched, and their `source` says `DEFRA 2025` again
rather than the compound MCF sentence. Commuting is unchanged: both renames
carry the same rows under new names.

The exception is the SENI grid factor, which stays at 0.5915. It replaces a
UK figure that priced Scope 2 for the whole country roughly threefold low,
and leaving that in place was worse than replacing it with an
order-of-magnitude-correct national number flagged for confirmation.

A value with no factor is usable: the line falls through to `Otro` in the
factor-source selector, where the registrant enters the value they hold. The
gap asks a question where a derived number would have answered it wrongly.
Removing the mandatory-comment prop left its doc comment in place, where it
now describes `pendingFilesCount` — a count of files — as a line whose
comment is mandatory. Restores the blank line the same edit took out of
`useEmissionCaptureSubmit` too, so this branch stops touching two files it has
nothing to say about.
`Teleférico` was appended after `Caminata`, so the selector listed a
motorised mode below the two that emit nothing. Moves it beside `Metro`,
which is where the subcategory explanation already lists it. Dimension values
only, no factor touched.
The commuting explanation told registrants to declare taxi, motoconcho and
platform vehicles together under `Taxi/vehículo de transporte individual`
because they "comparten un mismo factor". They do not: a motoconcho is a
motorcycle, and `Moto` carries 0.114 kg/km against the taxi option's 0.149 for
a car. Following that guidance overstated a motoconcho kilometre by about a
third.

Observation 5 conditions the breakdown on the factors differing, and for the
motoconcho they already do — so it is outside the condition, not an exception
to it. Taxi and platform vehicles stay together, which is what the observation
was actually about.
The document's own rule is that a factor edit invalidates its expected values,
and this branch edits one: `Sistema nacional` at 0.177 kg/kWh is gone, replaced
by `SENI` at 0.5915. The electricity line, its rate conversion, the
subcategory and category totals, the inventory total, the scope split, the
main-activity equivalence and the SQL cross-check all moved with it.

The inventory total goes from 1.096,31 to 1.863,13 tCO₂e, and Scope 2 from
30 % of the footprint to 59 % — which is the point of the factor change, and
worth seeing in a fixture before it is seen in a real inventory.
Four statements survived the reversal and now contradict the branch:

- design 6's consequence leaned on "the conservative factor" to stop `Otro`
  understating; decision 7 removed it four paragraphs later.
- the PR table billed PR 8 as shipping "factors, comment flags" — it ships
  neither.
- task 9.5 said the conservative factor stays.
- the PR 8 note called the comment requirement final and the factors "a
  documented proposal", when the requirement is gone and the factors are
  absent rather than proposed. Its test count was stale too: PR 8's tests
  covered the requirement and went with it.
Postgres and Docker became available, so the seven tasks parked on "no
database in this environment" are settled. The full API suite runs green on
the tip — 2,304 passing across the three storage projects — and its
`globalSetup` deploys every migration and runs the whole seed against a fresh
container, which covers 2.4, 7.7, 7.8, 8.8 and 9.9 at once.

4.6 needed its own run: the harness always starts empty, and the task is about
a populated database. Two `organization_data` rows were inserted at the
migration's parent and survived it with `NULL` in both new columns; the
catalog landed 10 / 32 / 157 with Azua under El Valle and no orphans, and the
inserts proved idempotent on a second pass.

5.3 stays partial — its remaining half is a UI check.
@mrivas00
mrivas00 force-pushed the feat/mati/rd-organization-form branch from dceb2a7 to 68fd5ef Compare August 26, 2026 20:21
@mrivas00
mrivas00 force-pushed the feat/mati/rd-methodology branch from 04df5d6 to c4dcc85 Compare August 26, 2026 20:21
Replaces the 0.5915 the branch shipped. Still the one factor this branch
changes and still roughly threefold the 0.177 it displaces, so the reasoning
around it stands.

The acceptance fixture moves with it, as its own rule demands: the rate
conversion (534.95 kg/MWh), the electricity line, the Scope 2 total, the
inventory total (1.758,52 tCO₂e), the scope split and the main-activity
equivalence (95,05 gCO₂e/litro).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: api apps/api (Fastify backend) area: packages shared packages/* area: web apps/web (React frontend) priority: high High priority type: feature new user-facing capability or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant