Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/monetize

.nornir/02-retiring-the-linked-plugins.md

Retiring the linked plugins — what it costs, what it buys, and what must

replace the thing it removes

For the owner to decide. Written 2026-09-23 by the lane that built the guests; the decision is not ours.

The one-line version

Every product monetize sells now exists twice: as a Rust crate linked into the deployment binary, and as a signed .wasm the open server loads behind the same factory. The two agree — that is measured, not asserted. The linked crates are also the only thing that proves the guests right, so retiring them retires the proof. That is the whole of the decision.

What changes when a product moves

One line in the deployment's config:

[products.holger]
endpoint = "127.0.0.1:50051"
guest = "/etc/monetize/products/holger.wasm"
guest_digest = "…"            # or guest_trust_roots = ["…"]
grants = ["grpc"]

guest = takes the id over from a linked plugin of the same name, because registration replaces. So it is one product at a time, and no binary change — the same vetra binary serves a linked gunnar and a guest holger in one process. Rolling back is deleting the line.

Nothing above dyn Product moves: the ledger, the transaction, the poller, the ladder, the price lists, the console, the purchase page. They cannot tell the difference, which is what the factory seam was for.

What is gained

What is lost

What must replace the proof

Not optional, and this is the recommendation's condition:

  1. Keep one appliance mock per product, outside the plugin crates. MockGunnar/MockHolger move to the guest crates (or to a small products-testing crate) and the guests keep being driven against them. Without a mock there is nothing to test either build against.
  2. Promote the live-box comparison to the thing that guards the meters. products/holger/tests/the_holger_guest_against_the_live_holger_rs.rs already reads the real estate with both builds and compares reading for reading. With the linked build gone it becomes a comparison against holger itself — the numbers the box reports versus the numbers monetize would bill — which is a stronger claim than the parity it replaces, and the only one still available.
  3. Freeze the last parity run. Before the crates go, record the meter tables, the refusal sentences and the fold outputs as fixtures the guest is held to. A transcription that drifts after the original is deleted is the failure this whole design has been avoiding.

Two open items, neither a blocker, both worth deciding with it

Recommendation

Retire them one product at a time, holger first, and not before (1) and (3) above are done.

holger first because it is the smallest surface — no key, no lanes, four meters — and because both builds have now been read against the live box and agree. gunnar last: it has the credential, three lanes and a restore that touches a box's whole data set.

And keep each linked crate for one full billing period after its guest goes live, unloaded but not deleted. The thing that would send us back to it is an invoice that disagrees, and an invoice takes a month to disagree.

What is measured, and where

claim where
the guests answer every op the server calls crates/monetize-product-wasm/tests/
gunnar's guest = gunnar's crate (12 claims) gunnar crates/gunnar-monetize-guest/tests/parity_with_the_linked_plugin.rs (gunnar-live; here 2026-09-26..28, back in gunnar 2026-09-28: a ../gunnar path in this repo made holger's builds need a gunnar checkout)
holger's guest = holger's crate products/holger/tests/parity_with_the_holger_guest.rs (the guest is holger's crates/holger-monetize-guest since 2026-09-27)
both builds read the LIVE holger.rs identically products/holger/tests/the_holger_guest_against_the_live_holger_rs.rs
a restore replay, both stream directions, refusals word for word gunnar crates/gunnar-monetize-guest/tests/the_restore_lane_runs_through_the_streaming_door.rs (same move)