Repository navigation
Fault injection for billing reconciler recall - #2479
Open
DylanTinianov wants to merge 8 commits into
Open
DylanTinianov wants to merge 8 commits into
DylanTinianov wants to merge 8 commits into
Conversation
…ecall (CRE-6809) Adds UsageFaultInjection (drop or perturb a deterministic sample of usage records keyed on event id) to ResourceManagerConfig, applied in the usage emit path and logged as "Injected usage fault". LOOP EnvConfig carries the settings as CL_METER_FAULT_* and MeteringConfig maps them, so capability producers get the fault with no code change. Test environments only; zero value is off. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
|
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The reconcilers recompute the sample from the rate alone, so the salt only added a value that had to match on every node of a DON. The sampler now hashes the event id directly, and the node sample hashes node id and event id. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The LOOP configuration initializer does not compile, and rate validation and parsing can silently produce unintended fault selection.
2 open issues
What changed in this PR
Adds deterministic, test-only usage fault injection so billing reconcilers can measure recall against reproducible dropped or altered records.
Changes:
- Adds event and node sampling, drop/perturb modes, validation, and fault logging.
- Connects fault settings to the usage emit path and LOOP environment configuration.
- Adds tests for sampling, validation, perturbations, drops, and durable-delta exclusion.
| File | Description |
|---|---|
pkg/resourcemanager/resourcemanager.go |
Stores fault settings and applies them to usage emission. |
pkg/resourcemanager/fault_injection.go |
Implements deterministic selection, validation, and fault application. |
pkg/resourcemanager/fault_injection_test.go |
Tests sampling and fault behavior. |
pkg/loop/metering_config.go |
Maps LOOP fault settings into resource manager configuration. |
pkg/loop/config.go |
Adds fault environment variables, serialization, and parsing. |
Review effort: Balanced
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The injector is meant to run in production against our own canary workflows, so it must never touch a real customer's records or raise a value. Mode now requires an org allowlist, only records of those orgs are dropped or perturbed, Delta must be negative, and a perturbed value is clamped at zero. CL_METER_FAULT_ORGS carries the list to LOOP plugins. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both billing reconcilers need faults at the same time, so a single Mode/Rate pair becomes DropRate and PerturbRate: two deterministic samples keyed apart on the event id, drop winning when both select. CL_METER_FAULT_MODE/RATE become CL_METER_FAULT_DROP_RATE/PERTURB_RATE. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
NaN compares false against every bound, so it passed Validate and silently disabled the sample. All three rates now test for it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
DylanTinianov
marked this pull request as ready for review
October 27, 2026 16:58
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Adds
resourcemanager.UsageFaultInjection, a deterministic sampler applied inside the resource manager's usage emit path so the billing reconcilers can measure their own recall against known faults. The zero value is off; this is for test environments only.Behaviour
DropRate,PerturbRate), keyed apart on the capability event id (drop|<id>,perturb|<id>); an event in both is dropped.FaultSelected(rate, key)hashes the key with FNV-1a 64, applies the murmur3 fmix64 finalizer so near-identical ids spread out, and takes the top 53 bits as a fraction belowrate. Every node of a DON therefore selects the same events, and a reconciler that knowsratecan recompute the sample without any shared table. Only records of the orgs inOrgs(our canaries) are ever faulted, an unresolved org is never faulted, and a rate without an allowlist fails validation, so the injector can run in production without touching a customer.drop: the selected usage record is not emitted on any node. The producer's own "Emitted capability usage meter record" line still fires, which is what lets the emit reconciler score the record as emitted-but-unbilled.perturb:Deltais added to the value on the nodes selected byFaultSelected(nodeRate, nodeID+"|"+eventID);NodeRate1 (or 0) means every node.Deltamust be negative and the result is clamped at zero, so a leak past the quorum median can only under-bill. A node rate below 1 produces node disagreement for the data reconciler; a node rate of 1 produces a wrong settled value that only the on-chain check can see.Injected usage faultwith mode, resourceType, eventID, resourceId, workflowID, executionID, orgID, nodeID, value and (perturb) originalValue. Durable delta and snapshot records are never faulted.Plumbing
ResourceManagerConfig.FaultInjectioncarries the settings.loop.EnvConfiggainsMeterFaultOrgs,MeterFaultDropRate,MeterFaultPerturbRate,MeterFaultDelta,MeterFaultNodeRate(envCL_METER_FAULT_*), round-tripped byAsCmdEnv/parseand mapped byEnvConfig.MeteringConfig, so LOOP capability producers that build their resource manager from the metering config get the fault with no code change.UsageFaultInjection.Validateis exposed for the host config layer.Tested locally
Beyond the unit tests: a Local CRE stack whose node image carried this change and the host TOML plumbing, with perturb on half the workflow DON. Compute records from the engine and gas records from the EVM write capability (configured through
loop.EnvConfig.MeteringConfig) carried the delta on exactly the nodes the sampler selected, each applied fault loggedInjected usage fault, and a reconciler recomputing the sample from the same rates identified the same records.