Green Goods Ontology
The formal specification of the Green Goods shared vocabulary: the entities the protocol tracks, the controlled vocabularies each layer spells its own way, the EAS schemas, the constraints the contracts enforce, and the lifecycle state machines. The source of truth is the machine-readable sidecar packages/shared/src/ontology/green-goods-ontology.json; this page is generated from it and CI fails when either drifts from the code.
Entities
| Entity | Status | Definition | Layers |
|---|---|---|---|
| Garden | live | A community of gardeners rooted in a place, represented on-chain as an ERC-721 garden token whose ERC-6551 token-bound account holds the garden's treasury, role Hats, and metadata. | contracts · indexer (Garden) · shared · docs |
| Action | live | A documented activity a gardener can perform — the unit of work template (e.g. "Plant native species", "Remove invasive growth"). | contracts · indexer (Action) · shared · docs |
| Work | live | One documented instance of an Action performed by a gardener — media, notes, and metadata submitted as an EAS Work attestation for operator review; approval records a separate Work Approval attestation. | contracts · shared · docs |
| Assessment | live | An up-front baseline and strategy for a garden — domain, diagnosis, SMART outcome targets, selected Actions, reporting period — authored by an evaluator or operator before work begins, mirrored to a Karma GAP milestone when that module is active; explicitly not a review of submitted Work (that is Work Approval). | contracts · shared · docs |
| Hypercert | live | An on-chain claim of impact bundling approved Work into a fractional impact certificate. Funders hold fractions; gardeners hold contribution credit. | contracts · indexer (Hypercert) · shared · docs |
| Vault | live | The garden's treasury. Funders deposit; the garden's Tokenbound Account holds; yield splits flow to operators / gardeners / community per configured ratios. | contracts · indexer (GardenVault) · shared · docs |
| Cookie Jar | live | A garden-scoped emergency or discretionary fund with rate-limited withdrawals. Allowlisted members can claim within the configured cap. | contracts · indexer (CampaignCookieJar) · shared · docs |
| Attestation | live | An EAS (Ethereum Attestation Service) record. Used for Work submissions, Assessment outcomes, and other off-chain-verifiable claims. | contracts · shared · docs |
| Hat | live | A Hats Protocol role token. Determines on-chain authority — operator hats can approve Work; gardener hats can submit Work; evaluator hats can attest. | contracts · indexer (Garden) · shared · docs |
| Season | live | A bounded period (typically a quarter) during which a garden runs a coordinated set of Actions and Assessments. Pacing primitive — never a countdown. | docs |
| Commitment Pool | spec | A garden-anchored (or protocol root-garden) pool that registers, curates, and reconciles commitments under a charter. | spec |
| Commitment Cycle | spec | A bounded run of a pool — a Season or Campaign — seeded with timing and an immutable six-role allocation snapshot at open. | spec |
| Commitment | spec | A module-native promise record (offer or request) with one accountable lead, an optional contributor roster, repeatable action requirements, direction-aware confirmation, unit accounting in a non-transferable register, and evidence/work linkage — deliberately not an EAS attestation. | spec |
| Commitment Contributor | spec | A person on a commitment's roster whose approved Work or confirmed evidence can earn Hypercert recognition and a contributor payout; one roster member is the accountable lead. | spec |
| Commitment Payout Plan | spec | A garden-managed split of a fulfilled commitment's declared support into an explicit garden-retained amount and contributor child payouts. Its complete recognition vector is hash-bound, payment weights derive from amounts, and explicit finalization freezes it before dispatch. | spec |
Personas
| Persona | Hat | Definition |
|---|---|---|
| Gardener | gardener | A person doing regenerative Work in a garden. Submits Work, holds gardener Hats, receives credit toward Hypercerts and yield splits. |
| Operator | operator | A person who runs a garden — creates Actions, approves Work, configures Vault and Hat hierarchy. Holds operator Hats. |
| Evaluator | evaluator | A person who verifies submitted Work, makes Assessments, and attests impact. Often domain experts (botanists, soil scientists, community elders). |
| Funder | funder | A person or org who deposits into a garden's Vault, holds Hypercert fractions, receives yield distributions per configured splits. |
| Community Member | community | A local resident affected by a Garden's Work. Signals or attests that Work exists and is healthy, and helps prioritize future Actions through public signal and conviction flows. |
The on-chain hat tree has six roles; the Owner hat carries full garden control but has no dedicated persona — owners act through the Operator surfaces.
Vocabularies
Each vocabulary has one canonical member list and a declared expected spelling per layer. The drift gate compares every representation against its source file; deviations are either declared here (layer conventions like the indexer's UNKNOWN sentinel) or recorded in the burn-down baseline.
capital
Eight Forms of Capital used to tag actions and assessments by the kind of value they create.
Canonical members: SOCIAL (0) · MATERIAL (1) · FINANCIAL (2) · LIVING (3) · INTELLECTUAL (4) · EXPERIENTIAL (5) · SPIRITUAL (6) · CULTURAL (7)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/registries/Action.sol · Capital | SOCIAL, MATERIAL, FINANCIAL, LIVING, INTELLECTUAL, EXPERIENTIAL, SPIRITUAL, CULTURAL | |
| indexer | indexer | packages/indexer/schema.graphql · Capital | SOCIAL, MATERIAL, FINANCIAL, LIVING, INTELLECTUAL, EXPERIENTIAL, SPIRITUAL, CULTURAL, UNKNOWN | UNKNOWN is the indexer's permanent fallback sentinel for unmapped on-chain values — declared, not drift. |
| shared-enum | shared | packages/shared/src/types/domain.ts · Capital | SOCIAL=0, MATERIAL=1, FINANCIAL=2, LIVING=3, INTELLECTUAL=4, EXPERIENTIAL=5, SPIRITUAL=6, CULTURAL=7 | |
| capital-type | shared | packages/shared/src/types/hypercerts.ts · CapitalType | social, material, financial, living, intellectual, experiential, spiritual, cultural | Ordered deliberately: the union is declared here in canonical machine order because index-based bridges between Capital and CapitalType lists are a live bug risk. The current file deviates (living-first presentational order) — baselined until reordered or a mapping function lands. |
- Mapping
capital-enum-to-capital-type(shared-enum → capital-type; explicit; total; bijective): SOCIAL → social, MATERIAL → material, FINANCIAL → financial, LIVING → living, INTELLECTUAL → intellectual, EXPERIENTIAL → experiential, SPIRITUAL → spiritual, CULTURAL → cultural.- Code anchor: none — no runtime mapping function exists yet.
- No runtime mapping function exists yet — see known_issues.missing-capital-mapping-fn.
domain
Category of regenerative work — where the work happens. Four production domains; a domain is neither an outcome nor a capital.
Canonical members: SOLAR (0) · AGRO (1) · EDU (2) · WASTE (3)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/registries/Action.sol · Domain | SOLAR, AGRO, EDU, WASTE | |
| indexer | indexer | packages/indexer/schema.graphql · Domain | SOLAR, AGRO, EDU, WASTE, UNKNOWN | UNKNOWN is the indexer's permanent fallback sentinel — declared, not drift. |
| shared-enum | shared | packages/shared/src/types/domain.ts · Domain | SOLAR=0, AGRO=1, EDU=2, WASTE=3 | |
| action-domain | shared | packages/shared/src/types/hypercerts.ts · ActionDomain | solar, waste, agroforestry, education, mutual_credit | Long-form lowercase spellings used in hypercert metadata. mutual_credit is a product concept ahead of the on-chain enum (deferred Domain 5) — declared, not drift. |
| slug-prefix | shared | packages/shared/src/hooks/action/useActionForm.ts · DOMAIN_SLUG_PREFIX | solar, agro, edu, waste | Short lowercase prefixes baked into immutable on-chain action slugs (agro., edu.). |
-
Mapping
domain-to-action-domain(solidity → action-domain; explicit; total; unmapped on the right: mutual_credit): SOLAR → solar, AGRO → agroforestry, EDU → education, WASTE → waste.- Code anchor:
packages/shared/src/modules/data/hypercerts-filters.ts
- Code anchor:
-
Mapping
action-domain-vs-slug-prefix(action-domain → slug-prefix; identity; partial; unmapped on the left: mutual_credit): identity (same spelling on both sides).- Code anchor: none — no runtime mapping function exists yet.
- The two lowercase spellings of the same domain must converge on one word per member; agroforestry/education vs agro/edu currently diverge — baselined.
garden-role
The six per-garden Hats roles that gate every protocol permission.
Canonical members: Gardener (0) · Evaluator (1) · Operator (2) · Owner (3) · Funder (4) · Community (5)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/interfaces/IHatsModule.sol · GardenRole | Gardener, Evaluator, Operator, Owner, Funder, Community | |
| shared-ids | shared | packages/shared/src/utils/blockchain/garden-roles.ts · GARDEN_ROLE_IDS | gardener=0, evaluator=1, operator=2, owner=3, funder=4, community=5 | Key order and numeric ids must track the Solidity enum exactly — these ids go into contract calls. |
transfer-restriction
Garden NFT transfer mode.
Canonical members: Unrestricted (0) · OwnerOnly (1) · Locked (2)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/tokens/Garden.sol · TransferRestriction | Unrestricted, OwnerOnly, Locked |
badge-rule
GreenWill badge eligibility rule kinds, proven from on-chain state at claim time.
Canonical members: None (0) · Hat (1) · WorkAttestation (2) · VaultShares (3)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/registries/GreenWill.sol · BadgeRule | None, Hat, WorkAttestation, VaultShares |
ens-name-type
Kind of *.greengoods.eth subname being registered.
Canonical members: Gardener (0) · Garden (1)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/registries/ENS.sol · NameType | Gardener, Garden |
weight-scheme
Conviction-voting weight scheme selected immutably at garden mint.
Canonical members: Linear (0) · Exponential (1) · Power (2)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/interfaces/IGardensModule.sol · WeightScheme | Linear, Exponential, Power | |
| indexer | indexer | packages/indexer/schema.graphql · WeightScheme | LINEAR, EXPONENTIAL, POWER | |
| shared | shared | packages/shared/src/types/gardens-community.ts · WeightScheme | Linear=0, Exponential=1, Power=2 | Genuine raw uint8 decode path (Number(weightSchemeRaw) as WeightScheme) — ordering is load-bearing and correct. |
signal-pool-type
Solidity carries two unrelated PoolType enums: the live Gardens V2 signal-pool vocabulary (signal-pool-type, ActionSignal/HypercertSignal) and the commitment-pooling anchor vocabulary (commitment-pool-type, Garden/Protocol). They are separate vocabularies in this ontology — never merge or cross-map them.
Kind of Gardens V2 conviction signal pool attached to a garden. Distinct from the commitment-pooling PoolType (Garden/Protocol) — same Solidity identifier, different vocabulary; never merge them.
Canonical members: ActionSignal (0) · HypercertSignal (1)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| solidity | solidity | packages/contracts/src/interfaces/IGardensModule.sol · PoolType | ActionSignal, HypercertSignal | |
| indexer | indexer | packages/indexer/schema.graphql · PoolType | ACTION_SIGNAL, HYPERCERT_SIGNAL | Currently {HYPERCERT, ACTION} — inverted vs chain and referenced by zero entity fields (dead surface). Baselined; fix direction is deletion or correction alongside the shared enum. |
| shared | shared | packages/shared/src/types/gardens-community.ts · PoolType | ActionSignal=0, HypercertSignal=1 | Currently {Hypercert = 0, Action = 1} — inverted vs chain. Verified latent, not live: pool types are assigned by address identity (annotateGardenSignalPools), never decoded from a raw uint8. Baselined with a mandatory blast-radius re-check before burn-down. |
vault-event-type
Vault history event kinds recorded by the indexer.
Canonical members: DEPOSIT · WITHDRAW · HARVEST · EMERGENCY_PAUSED
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| indexer | indexer | packages/indexer/schema.graphql · VaultEventType | DEPOSIT, WITHDRAW, HARVEST, EMERGENCY_PAUSED | |
| shared | shared | packages/shared/src/types/vaults.ts · VaultEventType | DEPOSIT, WITHDRAW, HARVEST, EMERGENCY_PAUSED |
hypercert-status
Lifecycle status of an indexed hypercert.
Canonical members: ACTIVE · CLAIMED · SOLD · UNKNOWN
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| indexer | indexer | packages/indexer/schema.graphql · HypercertStatus | ACTIVE, CLAIMED, SOLD, UNKNOWN | SOLD is declared but never assigned by any handler (marketplace is outside the indexing boundary). |
| shared | shared | packages/shared/src/types/hypercerts.ts · HypercertStatus | active, claimed, sold, unknown |
work-display-status
Canonical display status for work items across the UI — protocol states plus client-derived offline/sync states.
Canonical members: approved · rejected · pending · syncing · uploading · sync_failed · offline
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared-union | shared | packages/shared/src/types/domain.ts · WorkDisplayStatus | approved, rejected, pending, syncing, uploading, sync_failed, offline | |
| enhanced-work-approval | shared | packages/shared/src/hooks/work/useWorkApprovals.ts · EnhancedWorkApproval.status | approved, rejected, pending, syncing, uploading, sync_failed, offline | Declared as the canonical union; the current file carries a divergent five-value list (failed instead of sync_failed; missing uploading/offline) — baselined. |
| offline-work-item | shared | packages/shared/src/types/offline.ts · OfflineWorkItem.status | approved, rejected, pending, syncing, uploading, sync_failed, offline | Declared as the canonical union; the current file carries a divergent four-value list — baselined pending status-union consolidation. |
| hypercert-sync-status | shared | packages/shared/src/hooks/hypercerts/useHypercerts.ts · HypercertSyncStatus | approved, rejected, pending, syncing, uploading, sync_failed, offline | Declared as the canonical union; the current file carries a divergent four-value sync list — baselined pending status-union consolidation. |
cynefin-phase
Cynefin complexity phase classifying an assessment's operating environment.
Canonical members: CLEAR (0) · COMPLICATED (1) · COMPLEX (2) · CHAOTIC (3)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared | shared | packages/shared/src/types/domain.ts · CynefinPhase | CLEAR=0, COMPLICATED=1, COMPLEX=2, CHAOTIC=3 |
confidence
Four-value verification confidence carried on work approvals (on-chain uint8, bounded to 3).
Canonical members: NONE (0) · LOW (1) · MEDIUM (2) · HIGH (3)
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared | shared | packages/shared/src/types/domain.ts · Confidence | NONE=0, LOW=1, MEDIUM=2, HIGH=3 |
verification-method
Verification method bitmask flags on work approvals (uint8, bounded to 15).
Canonical members: HUMAN · IOT · ONCHAIN · AGENT
Values are explicit (not index-derived) for this vocabulary.
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared | shared | packages/shared/src/types/domain.ts · VerificationMethod | HUMAN=1, IOT=2, ONCHAIN=4, AGENT=8 | Bitmask members declared with shift expressions (1 << n) in source; the extractor evaluates them. |
action-type
Action archetype tags used in hypercert metadata and filtering.
Canonical members: hub_session · workshop · node_deployment · cleanup · recycling · composting · planting · nursery · maintenance · training · certification · commitment · exchange
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared | shared | packages/shared/src/types/hypercerts.ts · ActionType | hub_session, workshop, node_deployment, cleanup, recycling, composting, planting, nursery, maintenance, training, certification, commitment, exchange |
job-kind
Offline job-queue mutation kinds (the write-ahead ledger's vocabulary).
Canonical members: work · approval
| Representation | Layer | Source | Expected members | Note |
|---|---|---|---|---|
| shared | shared | packages/shared/src/types/job-queue.ts · JobKindMap | work, approval |
Commitment Pooling Vocabularies (spec — not deployed)
Locked vocabulary from the commitment-pooling contract spec, encoded ahead of implementation so the August lanes consume one canonical definition. No code cross-checks run until the planned anchors land; the gate then forces each entry to flip to live.
commitment-pool-type
Solidity carries two unrelated PoolType enums: the live Gardens V2 signal-pool vocabulary (signal-pool-type, ActionSignal/HypercertSignal) and the commitment-pooling anchor vocabulary (commitment-pool-type, Garden/Protocol). They are separate vocabularies in this ontology — never merge or cross-map them.
Commitment-pooling pool anchor kind. Name-collides with the live Gardens V2 signal-pool PoolType — the sidecar keeps them as separate vocabularies on purpose.
Canonical members: Garden (0) · Protocol (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · PoolType. The drift gate flags arrival so the status flips to live with declared representations.
pool-state
Commitment pool lifecycle — every state is on-chain.
Canonical members: None (0) · NotReady (1) · Ready (2) · Open (3) · Paused (4) · Closed (5) · Composted (6)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · PoolState. The drift gate flags arrival so the status flips to live with declared representations.
cycle-type
Cycle kinds: one open Season per pool; Campaigns may overlap.
Canonical members: Season (0) · Campaign (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · CycleType. The drift gate flags arrival so the status flips to live with declared representations.
cycle-state
On-chain cycle states; Draft lives in app IndexedDB and InProgress/Reviewing are derived from events.
Canonical members: None (0) · Seeded (1) · Open (2) · Reconciled (3) · Composted (4) · Cancelled (5)
Derived states (never stored): Draft · InProgress · Reviewing
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · CycleState. The drift gate flags arrival so the status flips to live with declared representations.
commitment-direction
Whether a commitment offers capacity or requests it; drives the direction-aware default confirmer.
Canonical members: Offer (0) · Request (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · CommitmentDirection. The drift gate flags arrival so the status flips to live with declared representations.
commitment-type
Commitment archetypes; DomainImpact keeps the full Work → WorkApproval path, the others confirm via counterparty.
Canonical members: DomainImpact (0) · SupportService (1) · SeasonCampaign (2) · StewardCaptured (3)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · CommitmentType. The drift gate flags arrival so the status flips to live with declared representations.
commitment-state
On-chain commitment states; Draft is app-side and Active/EvidenceSubmitted/PartiallyApproved/Reconciled are derived from module events.
Canonical members: None (0) · Offered (1) · Requested (2) · Accepted (3) · ReadyForConfirmation (4) · Fulfilled (5) · Cancelled (6) · Expired (7) · Disputed (8)
Derived states (never stored): Draft · Active · EvidenceSubmitted · PartiallyApproved · Reconciled
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · CommitmentState. The drift gate flags arrival so the status flips to live with declared representations.
claim-type
Immutable claimant-eligibility class set at commitment creation; runtime claim kind must equal it.
Canonical members: Garden (0) · Individual (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · ClaimType. The drift gate flags arrival so the status flips to live with declared representations.
contributor-policy
How contributor membership is established before the commitment roster freezes.
Canonical members: Open (0) · LeadManaged (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · ContributorPolicy. The drift gate flags arrival so the status flips to live with declared representations.
claim-mode
Whether claiming transitions immediately (Open) or awaits operator acceptance (ApprovalGated).
Canonical members: Open (0) · ApprovalGated (1)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · ClaimMode. The drift gate flags arrival so the status flips to live with declared representations.
dispute-resolution
Steward-only dispute outcomes; RestorePrevious replays the stored pre-dispute state.
Canonical members: RestorePrevious (0) · Fulfilled (1) · Cancelled (2) · Expired (3)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · DisputeResolution. The drift gate flags arrival so the status flips to live with declared representations.
reward-rail
Reward reference rail: ArbitrumExternal records operator-paid jar/treasury rewards; CeloSettlement is consumed only by the SettlementModule.
Canonical members: None (0) · ArbitrumExternal (1) · CeloSettlement (2)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentPoolingModule.sol · RewardRail. The drift gate flags arrival so the status flips to live with declared representations.
accounting-state
CommitmentRegister unit-class accounting states (non-transferable, ERC-1155-style).
Canonical members: Registered (0) · Committed (1) · Released (2) · Fulfilled (3)
Spec-only — planned anchor packages/contracts/src/interfaces/ICommitmentRegister.sol · AccountingState. The drift gate flags arrival so the status flips to live with declared representations.
commitment-payout-plan-status
Derived progress of a frozen commitment payout plan across its contributor child disbursements.
Canonical members: Draft (0) · Pending (1) · Partial (2) · Complete (3) · Failed (4)
Spec-only — planned anchor packages/contracts/src/interfaces/ISettlementModule.sol · PayoutPlanStatus. The drift gate flags arrival so the status flips to live with declared representations.
EAS Schemas
assessment — Green Goods Assessment v2
status: live · revocable: false · resolver: packages/contracts/src/resolvers/Assessment.sol
| Field | Type |
|---|---|
| title | string |
| description | string |
| assessmentConfigCID | string |
| domain | uint8 |
| startDate | uint256 |
| endDate | uint256 |
| location | string |
work — Green Goods Work Submission
status: live · revocable: false · resolver: packages/contracts/src/resolvers/Work.sol
| Field | Type |
|---|---|
| actionUID | uint256 |
| title | string |
| feedback | string |
| metadata | string |
| media | string[] |
workApproval — Green Goods Work Approval
status: live · revocable: false · resolver: packages/contracts/src/resolvers/WorkApproval.sol
| Field | Type |
|---|---|
| actionUID | uint256 |
| workUID | bytes32 |
| approved | bool |
| feedback | string |
| confidence | uint8 |
| verificationMethod | uint8 |
| reviewNotesCID | string |
badge — GreenGoodsBadge
status: live · revocable: true · resolver: none
Registered via the standalone badge-schemas path outside config/schemas.json; the only revocable Green Goods schema, with no resolver.
| Field | Type |
|---|---|
| badgeType | string |
| recipient | address |
| earnedAt | uint40 |
| evidenceUri | string |
| tier | uint8 |
assessmentV3 — Green Goods Assessment v3
status: spec · revocable: false · resolver: none
Assessment v2 fields plus assessmentKind, cycleId, and baselineUID; one of exactly two new EAS registrations in the commitment-pooling track.
| Field | Type |
|---|---|
| title | string |
| description | string |
| assessmentConfigCID | string |
| domain | uint8 |
| startDate | uint256 |
| endDate | uint256 |
| location | string |
| assessmentKind | uint8 |
| cycleId | uint256 |
| baselineUID | bytes32 |
communityTestimony — Green Goods Community Testimony
status: spec · revocable: false · resolver: none
Community-Hat-gated testimony attached to a commitment; the second of exactly two new EAS registrations.
| Field | Type |
|---|---|
| commitmentId | uint256 |
| title | string |
| testimonyCID | string |
need — Green Goods Need
status: spec · revocable: true · planned resolver: CommunityNeedsResolver
Root Needs use EAS recipient as the canonical garden, refUID zero, and expirationTime zero. CommunityNeedsResolver authorizes the attester through the recipient garden's Community role.
| Field | Type |
|---|---|
| statementCID | string |
| desiredOutcomeCID | string |
| horizon | uint8 |
| mediaCID | string |
needSignal — Green Goods Need Signal
status: spec · revocable: true · planned resolver: CommunityNeedsResolver
Child signal records use EAS recipient as the garden, refUID as the exact live same-garden Need, and expirationTime zero. Readers derive one current direction per attester through the canonical latest-winner rule.
| Field | Type |
|---|---|
| support | bool |
needStatus — Green Goods Need Status
status: spec · revocable: false · planned resolver: CommunityNeedsResolver
Operator-authored child moderation records use EAS recipient as the garden, refUID as the exact live same-garden Need, and expirationTime zero. mergedIntoNeedUID remains custom data because it is a second Need relationship.
| Field | Type |
|---|---|
| status | uint8 |
| domains | uint8[] |
| mergedIntoNeedUID | bytes32 |
| noteCID | string |
fundingAttribution — Green Goods Funding Attribution
status: spec · revocable: false · planned resolver: FundingAttributionResolver
Ungated child funding records use EAS recipient as the garden, refUID as the exact live same-garden Need, and expirationTime zero. FundingAttributionResolver remains separate from CommunityNeedsResolver and the joined reader verifies canonical receipts before display.
| Field | Type |
|---|---|
| chainId | uint256 |
| txHash | bytes32 |
| token | address |
| amount | uint256 |
| rail | uint8 |
Constraints
Cross-layer invariants and where they are enforced. This catalog is documentation-grade: the drift gate verifies the anchors exist, not the semantics — the contracts and their tests own the semantics.
domain-closed-set· closed-set · live — Action domains form a closed four-member set; resolvers reject domain values above 3 and garden domain masks are validated as 4-bit. (enforced at:packages/contracts/src/registries/Action.sol:28-34,packages/contracts/src/resolvers/Assessment.sol:134-136)work-attester-role· domain-range · live — A Work attestation's attester must be a gardener or operator of the recipient garden, and the referenced action must exist, be started, not be expired, and belong to a domain enabled on that garden. (enforced at:packages/contracts/src/resolvers/Work.sol:87-139)approval-operator-only· domain-range · live — Only an operator of the garden may attest a Work Approval, and the approval's actionUID and recipient must match the referenced Work attestation. (enforced at:packages/contracts/src/resolvers/WorkApproval.sol:115-177)approval-no-self-attestation· disjoint · live — The approver and the work attester must be different accounts — self-approval reverts. (enforced at:packages/contracts/src/resolvers/WorkApproval.sol:153-156)assessment-author-role· domain-range · live — An Assessment attester must be an evaluator or operator of the recipient garden. (enforced at:packages/contracts/src/resolvers/Assessment.sol:118-122)yield-split-sum· sum · live — The three-way yield split (CookieJar / Hypercert fractions / Juicebox) must sum to exactly 10000 bps. (enforced at:packages/contracts/src/resolvers/Yield.sol:107,373)garden-nft-transfer-restriction· non-transferable · live — Garden NFT transfers obey the TransferRestriction mode (Unrestricted / OwnerOnly / Locked); minting is always allowed. (enforced at:packages/contracts/src/tokens/Garden.sol:43-48,513-518)resolver-schema-pinning· existence · live — Each core resolver validates that incoming attestations use its pinned schema UID. (enforced at:packages/contracts/src/resolvers/Work.sol:87-95,packages/contracts/src/resolvers/WorkApproval.sol:115-123,packages/contracts/src/resolvers/Assessment.sol:98-106)- ⚠️ Hole: Schema validation is skipped while the stored schemaUID is zero (the deployment window) — a documented gap the commitment-pooling spec explicitly refuses to inherit (its module deploys fail-closed). (
packages/contracts/src/resolvers/Work.sol:60-62,packages/contracts/src/resolvers/WorkApproval.sol:81-83,packages/contracts/src/resolvers/Assessment.sol:71-73)
- ⚠️ Hole: Schema validation is skipped while the stored schemaUID is zero (the deployment window) — a documented gap the commitment-pooling spec explicitly refuses to inherit (its module deploys fail-closed). (
pooling-allocation-bps-sum· sum · spec — The six-role allocation snapshot stored at cycle open must sum to exactly 10000 bps and is immutable for the cycle. (enforced at:.plans/active/commitment-pooling/contract-spec.md)pooling-provider-confirmation-disjoint· disjoint · spec — Every member of a commitment's accountable lead/contributor team is excluded from every fulfillment-confirmation path, including the steward fallback; confirmation defaults are direction-aware (Offer → recipient, Request → creator). (enforced at:.plans/active/commitment-pooling/contract-spec.md)pooling-recognition-allocation-sum· sum · spec — The gardener-class recognition budget is fully allocated only after every fulfilled commitment has an eligible contributor: equal budget per fulfilled commitment, then the immutable cycle-open RecognitionPolicy allocates its equal-participation and verified-contribution components through separate deterministic remainder passes before the row results are added. The protocol default and immutable cycle-less preset are 20% equal / 80% verified, but an opened cycle may select any two values summing to 10000 bps. Zero eligible contributors block certificate expansion; there is no lead fallback. (enforced at:.plans/active/commitment-pooling/contract-spec.md)pooling-payout-plan-conservation· sum · spec — An explicitly finalized commitment payout plan conserves the declared support amount exactly: garden-retained amount plus all contributor child amounts equals the parent amount. A zero-child all-retained plan completes at finalization without a transfer. (enforced at:.plans/active/commitment-pooling/settlement-spec.md)pooling-payout-plan-integrity· functional · spec — Each fulfilled commitment has at most one stable payout-plan pointer. The complete recognition vector matches its snapshot hash, payment weights derive from the atomic amount vector, finalization precedes dispatch, and child or batch cancellation never clears the parent pointer. (enforced at:.plans/active/commitment-pooling/settlement-spec.md)pooling-one-open-season· functional · spec — A pool may have at most one open Season at a time (O(1) openSeasonCycleId guard); Campaigns may overlap freely. (enforced at:.plans/active/commitment-pooling/contract-spec.md)commitment-register-non-transferable· non-transferable · spec — CommitmentRegister unit classes are non-transferable by construction — no transfer, approval, or custody surface; balances move only via the module. (enforced at:.plans/active/commitment-pooling/contract-spec.md)needs-eas-envelope-reference· domain-range · spec — All four Needs schemas use EAS recipient as the canonical garden and expirationTime zero; a Need is a root with refUID zero, while NeedSignal, NeedStatus, and FundingAttribution use refUID to reference an exact live same-garden Need. (enforced at:.plans/active/community-interface/spec.md)need-signal-latest-winner· functional · spec — For each Need and attester, readers first select the greatest unsigned (timeCreated, uid) NeedSignal tuple and then apply revocation and expiry; a revoked or expired winner clears the signal without restoring an older record, and support and non-support remain separate counts. (enforced at:.plans/active/community-interface/spec.md)needs-resolver-trust-boundaries· closed-set · spec — Exactly four Needs schemas route through two resolvers: CommunityNeedsResolver accepts only Need, NeedSignal, and NeedStatus with schema-specific Community or Operator authorization, while the ungated FundingAttribution schema routes through FundingAttributionResolver; unknown schema branches fail closed. (enforced at:.plans/active/community-interface/spec.md)
State Machines
work-display-status
The union in types/domain.ts documents itself as the single source of truth: pending/approved/rejected reflect protocol state; syncing/uploading/sync_failed/offline are client-derived from the offline job queue.
| State | Storage |
|---|---|
| pending | protocol |
| approved | protocol |
| rejected | protocol |
| syncing | client-derived |
| uploading | client-derived |
| sync_failed | client-derived |
| offline | client-derived |
Commitment pooling (spec — not deployed)
Transcribed from the locked contract spec: "on-chain" means a named module function performs the transition and emits the listed event; "derived" means the indexer/app computes the state from events and the chain never stores it.
commitment-pool
Every pool state is on-chain; transitions are rare operator-console actions.
| State | Storage |
|---|---|
| NotReady | on-chain |
| Ready | on-chain |
| Open | on-chain |
| Paused | on-chain |
| Closed | on-chain |
| Composted | on-chain |
| From | To | Layer | Mechanism |
|---|---|---|---|
| (create) | NotReady | on-chain | onGardenMinted (GardenToken-only, idempotent) or registerPool → PoolRegistered |
| NotReady | Ready | on-chain | markPoolReady — requires non-empty charter CID and a non-zero provider open-commitment cap → PoolReady |
| Ready | Open | on-chain | openPool → PoolOpened |
| Open | Paused | on-chain | pausePool with mandatory reasonCID → PoolPaused; resumePool returns to Open |
| Open | Paused | Closed | on-chain | closePool → PoolClosed |
| Closed | Composted | on-chain | compostPool → PoolComposted |
| Composted | Ready | Open | on-chain | reopenPool(toOpen) → PoolReopened |
commitment-cycle
One open Season per pool (openSeasonCycleId guard); Campaigns overlap freely. Succession between cycles is derived by pool ordering — no on-chain predecessor pointer.
| State | Storage |
|---|---|
| Draft | off-chain |
| Seeded | on-chain |
| Open | on-chain |
| InProgress | derived |
| Reviewing | derived |
| Reconciled | on-chain |
| Composted | on-chain |
| Cancelled | on-chain |
| From | To | Layer | Mechanism |
|---|---|---|---|
| Draft | Seeded | on-chain | seedCycle(poolId, cycleType, startTime, endTime, metadataCID) → CycleSeeded; no allocation stored yet |
| Seeded | Open | on-chain | openCycle(cycleId, allocation, recognitionPolicy) — six-role allocation bps and two-part recognition bps each sum to 10000, both store immutably → CycleOpened |
| Open | InProgress | derived | first CommitmentAccepted for the cycle OR block time ≥ startTime |
| InProgress | Reviewing | derived | block time > endTime, OR all cycle commitments terminal or ReadyForConfirmation; new evidence/work flips back |
| Reviewing | Reconciled | on-chain | closeCycle (the reconcile act) requires liveCommitmentCount = 0 → CycleClosed; commitment-level Reconciled derives from this event |
| Reconciled | Composted | on-chain | compostCycle → CycleComposted |
| Seeded | Open | Cancelled | on-chain | cancelCycle(reasonCID) requires liveCommitmentCount = 0 → CycleCancelled; Draft is discarded off-chain |
commitment
Direction-aware fulfillment: the party receiving the team's work confirms by default (Offer → recipient, Request → creator); every lead/contributor self-confirmation path is blocked; evidence/Work credit records only while Accepted and unfrozen; the contributor roster and credit ledger freeze atomically on the transition to ReadyForConfirmation or before a direct Fulfilled dispute resolution; Ready requires pre-freeze totalVerifiedCredits > 0, while recognition additionally requires Fulfilled plus an opened cycle policy or the immutable cycle-less 20/80 default; disputes restore an explicitly stored prior state.
| State | Storage |
|---|---|
| Draft | off-chain |
| Offered | on-chain |
| Requested | on-chain |
| Accepted | on-chain |
| Active | derived |
| EvidenceSubmitted | derived |
| PartiallyApproved | derived |
| ReadyForConfirmation | on-chain |
| Fulfilled | on-chain |
| Reconciled | derived |
| Cancelled | on-chain |
| Expired | on-chain |
| Disputed | on-chain |
| From | To | Layer | Mechanism |
|---|---|---|---|
| Draft | Offered | Requested | on-chain | createCommitment → CommitmentCreated (direction sets the initial state) |
| Offered | Requested | Accepted | on-chain | claimCommitment (runtime kind must equal immutable claimType; Open mode transitions immediately, ApprovalGated waits for operator acceptClaim) → CommitmentAccepted; register records committed units |
| Accepted | Active | derived | first WorkLinked or EvidenceAttached after acceptance |
| Active | EvidenceSubmitted | derived | any EvidenceAttached or WorkLinked event |
| EvidenceSubmitted | PartiallyApproved | derived | ApprovedWorkCounted with some requirement counters below their required counts |
| … | ReadyForConfirmation | on-chain | automatic once every repeatable action requirement is met and any declared assessment attached; submitForConfirmation for evidence-only types requires evidenceCount ≥ 1; steward markReadyForConfirmation with reason; every path requires an Open cycle when scoped or the immutable cycle-less 20/80 policy plus pre-freeze totalVerifiedCredits > 0; contributor roster and credit ledger freeze atomically before the ready event |
| ReadyForConfirmation | Fulfilled | on-chain | confirmFulfillment by named confirmer or direction-aware default; threshold N → CommitmentFulfilled; register converts units; every lead/contributor on the already-frozen roster is excluded from every confirmation path |
| Fulfilled | Reconciled | derived | CycleClosed for the commitment's cycle (or PoolClosed when cycle-less) |
| … | Cancelled | on-chain | cancelCommitment(reasonCID) — creator or steward pre-acceptance, steward-only after; Accepted releases committed units |
| … | Expired | on-chain | expireCommitment — permissionless once past dueDate (or cycle endTime); releases still-committed units |
| Accepted | ReadyForConfirmation | Expired | Disputed | on-chain | raiseDispute(reasonCID) — module stores the exact prior state in preDisputeState → CommitmentDisputed |
| Disputed | previous | Fulfilled | Cancelled | Expired | on-chain | resolveDispute steward-only; RestorePrevious replays preDisputeState; an Expired prior state can never resolve Fulfilled; a direct Fulfilled resolution requires an available recognition policy and verified contributor, then freezes an unfrozen roster before DisputeResolved |
Known Issues
report-orphan-term— v1-0.mdx §16.1 defines a "Report" entity (aggregated bundle of approved work for grants/Hypercert minting) that is absent from the canonical entity set, the ERD, and the code. Formalize or retire the term when the reporting feature is actually designed — it overlaps Hypercert bundling today. (docs/docs/builders/specs/v1-0.mdx)erd-stale-assessment-fields— The ERD's GardenAssessment shape lists only notes and mediaURIs, while the shipped assessment carries the full strategy kernel (domain, diagnosis, SMART outcomes, selected action UIDs, reporting period, assessmentConfigCID). (docs/docs/builders/architecture/erd.mdx)missing-capital-mapping-fn— No runtime mapping function exists between the numeric Capital enum and the lowercase CapitalType union; index-based bridges are unsafe because the two declared orders currently differ. (packages/shared/src/types/domain.ts,packages/shared/src/types/hypercerts.ts)
Deliberately excluded from v1
- Impact-axes taxonomy — canon is maintained outside the repo; this public file carries only the four production action domains.
- ModuleDependency and ModuleSchemaKind from the commitment-pooling spec — module wiring plumbing, not domain vocabulary.
How this page stays honest
bun run check:ontology cross-checks the sidecar against the Solidity enums, the indexer GraphQL schema, the shared TypeScript vocabularies, the EAS schema config, and the glossary tables on every relevant change. Known drift lives in scripts/data/ontology-drift-baseline.json with an owner, an expiry, and a note — new drift fails CI immediately, and fixed drift fails until its baseline entry is deleted. To change the ontology, edit the sidecar and run bun run ontology:generate.