Skip to content

About

Open-source rule processors that power Carrot's dMRV — deterministic verification of recycling supply chains to issue environmental credits

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Latest commit

 

History

1,967 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Carrot Methodology Rules

CI codecov License: LGPL-3.0

Open-source rule processors that power the Carrot dMRV (digital Measurement, Reporting and Verification) pipeline. Each rule processor validates a specific aspect of supply chain data against a Methodology Verification Framework, producing deterministic, auditable verification results that underpin the issuance of environmental credits.

How It Works

flowchart LR
    A[Supply Chain Data] --> B[MassID Documents]
    B --> C[Rule Processors]
    C --> D{All Rules Pass?}
    D -->|Yes| E[Certificate Issued]
    D -->|No| F[Verification Failed]
    E --> G[Credit Tokenization]
Loading

Every methodology in the Carrot Network has three layers:

Layer What Where
Methodology Scientific foundation (e.g., UNFCCC CDM) docs.carrot.eco
MvF (Methodology Verification Framework) Specification translating the methodology into concrete verification rules docs.carrot.eco
MvA (Methodology Verification Application) Open-source rule processors implementing the MvF This repository · docs

Rule processors are the core units of the MvA. Each one evaluates MassID documents — digital records tracking material type, weight, and chain of custody — and returns PASSED, FAILED, or REVIEW_REQUIRED with a traceable explanation.

Project Structure

methodology-rules/
├── apps/methodologies/          # Methodology applications (Lambda deployments)
│   ├── bold-carbon/             #   BOLD Carbon CH₄
│   └── bold-recycling/          #   BOLD Recycling
├── libs/
│   ├── methodologies/bold/
│   │   └── rule-processors/     # Shared BOLD rule processors
│   │       └── mass-id/         #   MassID verification rules
│   └── shared/                  # Shared libraries across methodologies
├── tools/                       # CLI tooling
│   ├── create-rule.js           #   Scaffold new rule processors
│   ├── rule-runner-cli/         #   Run rules locally against test data
│   ├── document-extractor-cli/  #   Extract data from documents
│   ├── mass-id-generator-cli/   #   Emit the MassID event data the docs site syncs
│   ├── apply-methodology-rule.js #  Apply rules to a methodology
│   └── versioning/              #   Rule version management
├── scripts/                     # Build & generation scripts
└── docs/                        # Internal documentation

Getting Started

Prerequisites

  • Node.js v24.14.1 (see .nvmrc)
  • pnpm v10.18.3 (see packageManager in package.json)

Installation

pnpm install

Common Commands

# Testing
pnpm test <project-name>            # Test a single project
pnpm test:affected                   # Test only changed projects
pnpm test:all                        # Test all projects

# Linting & type-checking
pnpm lint <project-name>             # Lint a single project
pnpm lint:affected                   # Lint and auto-fix changed projects
pnpm ts <project-name>              # Type-check a single project

# Building
pnpm build-lambda <project-name>     # Build a Lambda package
pnpm build-lambda:affected           # Build only changed Lambdas

# Run a single test file
pnpm nx test <project-name> --testFile=<relative-path>

Tooling

pnpm create-rule                     # Scaffold a new rule processor
pnpm run-rule <args>                 # Run a rule locally against test data
pnpm apply-methodology-rule          # Apply a rule to a methodology
pnpm generate:event-data             # Emit MassID event data to dist/methodology-event-data

Rule Runner Dry Runs

Use one processor-path mode per dry run.

Supply AUDIT_URL and SMAUG_API_GATEWAY_ASSUME_ROLE_ARN through shell variables or an operator-managed --env-file. The tracked test configuration is deliberately non-routable.

# Local mode: runs the processor from the supplied path against an explicit dataset.
pnpm run-rule dry-run libs/methodologies/bold/rule-processors/mass-id/privacy-flags --data-set-name TEST --document-id <massid-document-id>

# Registered mode: resolves the processor against the supplied methodology.
pnpm run-rule dry-run libs/methodologies/bold/rule-processors/mass-id/document-manifest-data --methodology-slug bold-carbon-organic --document-id <massid-document-id>

MassID Event Data

tools/mass-id-generator-cli emits the canonical MassID example the docs site publishes: an events manifest, one request payload per event and one attribute dictionary per event other than the create document and the actors, once for bold-recycling and once for bold-carbon.

pnpm generate:event-data             # writes dist/methodology-event-data/

The example's content comes from one authored table, tools/mass-id-generator-cli/src/mass-id-catalog.ts. Privacy flags are read from the privacy-flags rule's own tables, so they cannot drift from the rule. Output is deterministic: the same source produces the same bytes. The emitter does not remove files a previous run left behind: delete dist/methodology-event-data before re-running.

The test-e2e target runs these rule lambdas against the catalog and expects PASSED: composting-cycle-timeframe, driver-identification, drop-off-at-recycler, hauler-identification, mass-id-qualifications, privacy-flags, processor-identification, project-period-limit, recycler-identification, regional-waste-classification, vehicle-identification, waste-origin-identification. When an intended rule change makes one fail, the published example is out of date: update the catalog. mass-id-qualifications also checks measurementUnit and currentValue, which the published create body does not carry; the test document supplies them. The test document also places every address in Brazil and leaves attachments out, and the suite runs on the real clock because project-period-limit reads it: once the Recycled event's date is before 1 January of the previous UTC year the suite fails, and the remedy is to move every date in the catalog forward by one shared interval.

Rules it does not run, and why:

Rule Needs
geolocation-and-address-precision the audit and accreditation document graph
mass-id-sorting the audit and accreditation document graph
participant-accreditations-and-verifications-requirements the audit and accreditation document graph
prevented-emissions the audit and accreditation document graph
weighing the audit and accreditation document graph
no-conflicting-certificate-or-credit certificate, credit order and MassID audit documents
document-manifest-data attachment bytes
waste-mass-is-unique Smaug over the network

version-and-sync.yaml runs the generator on each push to main (unless the head commit message contains [skip ci]) and uploads the tree as the methodology-event-data artifact of that run. The rules-manifest-updated dispatch to the docs repo carries the run id.

Rule Processor Design

Every rule processor follows a standardized pattern:

  1. loadDocument() — Fetches the documents needed for evaluation
  2. getRuleSubject() — Extracts the specific data elements to evaluate
  3. evaluateResult() — Applies verification logic, returns PASSED, FAILED, or REVIEW_REQUIRED

Complex processors may override process() with custom document loading and evaluation logic.

Schema Layering

Every rule processor follows a standardized validation flow:

  1. Load raw documents
  2. Build a rule subject
  3. Validate the rule subject schema (validateRuleSubjectOrThrow)
  4. Evaluate business logic

Document schemas are organized in 5 layers:

  • Envelope (LoadedDocumentEnvelopeSchema) — wrapper for loaded documents
  • Inbound (InboundDocumentSchema) — boundary contract, looseObject
  • Normalized (DocumentSchema) — z.object() (default), strips unknown fields on parse
  • Domain (BoldDocumentSchema, MassID*Schema) — methodology-specific
  • Rule (*RuleSubjectSchema) — exact contract per rule

Enums use const-object + z.enum() pattern with .extract() / .literal() for narrower layers.

Design principles:

  • Fidelity — Mirrors the MvF specification exactly
  • Traceability — Every result links back to source data
  • Determinism — Same input always produces the same output
  • Standard compliance — Follows Carrot dMRV Standard requirements

Contributing

Contributions are welcome. Before starting work:

  1. Read the MvA Developer Guide to understand the verification model
  2. Use pnpm create-rule to scaffold new rule processors
  3. Ensure 100% test coverage — this is enforced by CI
  4. Follow Conventional Commits for all commit messages

Documentation

License

This project is licensed under the LGPL-3.0.

About

Open-source rule processors that power Carrot's dMRV — deterministic verification of recycling supply chains to issue environmental credits

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages