home / skills / happenings-community / requests-and-offers / hrea-integration

hrea-integration skill

/.claude/skills/hrea-integration

This skill helps you integrate hREA GraphQL mappings with ValueFlows, enabling proposal creation, prerequisite management, and automatic retry of queued items.

npx playbooks add skill happenings-community/requests-and-offers --skill hrea-integration

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
6.3 KB
---
name: hREA Integration
description: This skill should be used when working with hREA GraphQL integration, ValueFlows ontology mapping, proposal/intent creation, prerequisite management, or the pending queue system
---

# hREA Integration

Patterns for the hREA (Holochain Resource-Event-Agent) GraphQL integration layer that maps local entities to ValueFlows economic ontology.

## Key Reference Files

- **hREA service**: `ui/src/lib/services/hrea.service.ts`
- **hREA store**: `ui/src/lib/stores/hrea.store.svelte.ts`
- **Request→Proposal mapper**: `ui/src/lib/services/mappers/request-proposal.mapper.ts`
- **Offer→Proposal mapper**: `ui/src/lib/services/mappers/offer-proposal.mapper.ts`
- **GraphQL queries**: `ui/src/lib/graphql/queries/`
- **GraphQL mutations**: `ui/src/lib/graphql/mutations/`
- **GraphQL fragments**: `ui/src/lib/graphql/fragments/`
- **hREA types**: `ui/src/lib/types/hrea.ts`
- **hREA store test**: `ui/tests/unit/stores/hrea.store.test.ts`

## Architecture Overview

```
Local Entities          hREA Store (mapping layer)        hREA DNA (GraphQL)
─────────────          ──────────────────────────        ──────────────────
UIUser          →  createPersonFromUser()          →  Agent
UIOrganization  →  createOrganizationFromOrg()     →  Agent
UIServiceType   →  createResourceSpecFromST()      →  ResourceSpecification
UIMediumOfExch  →  createResourceSpecFromMoE()     →  ResourceSpecification
UIRequest       →  createProposalFromRequest()     →  Proposal + 2 Intents
UIOffer         →  createProposalFromOffer()       →  Proposal + 2 Intents
```

The GraphQL layer uses `@valueflows/vf-graphql-holochain` + Apollo Client with `SchemaLink`.

## Three Prerequisites for Proposals

Proposals require **all three** prerequisites to exist before creation:

1. **User agent** — created when user is approved (`handleUserAccepted` event)
2. **Service type resource specs** — created when service type is approved
3. **Medium of exchange resource specs** — created when MoE is approved

If any prerequisite is missing, the request/offer is **queued** in `pendingRequestQueue` / `pendingOfferQueue`.

## Pending Queue Mechanism

```typescript
// When createProposalFromRequest fails due to missing prerequisites:
// → request is added to pendingRequestQueue
// → E.catchAll returns null (no error propagation)

// When ANY prerequisite is created (agent, resource spec):
// → retryPendingProposals() is called
// → all queued items are retried

// Event flow:
// user approved → createPerson() → retryPendingProposals()
// service type approved → createResourceSpec() → retryPendingProposals()
// MoE approved → createResourceSpec() → retryPendingProposals()
```

## Request→Proposal Mapping (Two-Intent Reciprocal Pattern)

Each request/offer creates a Proposal with TWO intents:

```
Request "I need web development"
  → Proposal: name="Request: I need web development"
  → Intent 1 (primary): action="transfer", provider=requester's agent
      resourceConformsTo = service type resource spec
  → Intent 2 (reciprocal): action="transfer", receiver=requester's agent
      resourceConformsTo = medium of exchange resource spec
```

The intent linking uses `proposeIntent` mutation with `reciprocal: false` for primary intent and `reciprocal: true` for payment intent.

## Action Hash Reference Format

Mappings between local entities and hREA entities use `note` fields:

```
ref:user:<actionHash>              — on Agent.note
ref:organization:<actionHash>      — on Agent.note
ref:serviceType:<actionHash>       — on ResourceSpecification.note
ref:mediumOfExchange:<actionHash>  — on ResourceSpecification.note
```

Lookup: `extractActionHashFromNote(note, entityType)` extracts the hash.

## Error Handling

- **Missing zome functions**: hREA DNA may not have `get_all_intents` / `get_all_proposals` — service uses `E.catchAll` to return empty arrays
- **Prerequisite detection**: `createProposalFromRequest` / `createProposalFromOffer` use `E.catchAll` (not `E.tapError`) — queue on failure, return `null`
- **Initialization**: `createPerson()` calls `initialize()` internally — don't call separately
- **GraphQL normalization**: Responses need `normalizeIntentResponse()` / `normalizeProposalResponse()` because GraphQL returns nested objects

## Store State

```typescript
// Mapping stores (local hash → hREA ID)
userAgentMappings: Map<string, string>                    // userHash → agentId
organizationAgentMappings: Map<string, string>            // orgHash → agentId
serviceTypeResourceSpecMappings: Map<string, string>      // stHash → resourceSpecId
mediumOfExchangeResourceSpecMappings: Map<string, string> // moeHash → resourceSpecId
requestProposalMappings: Map<string, string>              // requestHash → proposalId
offerProposalMappings: Map<string, string>                // offerHash → proposalId

// Entity arrays
agents: Agent[]
resourceSpecifications: ResourceSpecification[]
proposals: Proposal[]
intents: Intent[]

// Queue (pending items waiting for prerequisites)
pendingRequestQueue: Map<string, UIRequest>
pendingOfferQueue: Map<string, UIOffer>
```

## Event-Driven Architecture

The hREA store subscribes to `storeEventBus` events:

| Event | Handler | hREA Action |
|-------|---------|-------------|
| `user:accepted` | `handleUserAccepted` | `createPerson()` → `retryPendingProposals()` |
| `organization:accepted` | `handleOrganizationAccepted` | `createOrganization()` → `retryPendingProposals()` |
| `serviceType:approved` | `handleServiceTypeApproved` | `createResourceSpec()` → `retryPendingProposals()` |
| `mediumOfExchange:approved` | `handleMediumOfExchangeApproved` | `createResourceSpec()` → `retryPendingProposals()` |
| `request:created` | `handleRequestCreated` | `createProposalFromRequest()` |
| `offer:created` | `handleOfferCreated` | `createProposalFromOffer()` |

## Testing hREA

Tests need module mocks for external dependencies:

```typescript
vi.mock('@valueflows/vf-graphql-holochain', () => ({
  createHolochainSchema: vi.fn()
}));
vi.mock('@apollo/client/link/schema', () => ({
  SchemaLink: vi.fn()
}));
```

Note: `hrea.service.ts` `createPerson()` calls `initialize()` internally — don't call it separately in tests.

Overview

This skill integrates a UI layer with the hREA GraphQL DNA to map local entities to the ValueFlows ontology and manage proposals, intents, and prerequisites. It provides mapping patterns, a pending queue mechanism for missing prerequisites, and event-driven retries to ensure eventual consistency. Use it to translate requests/offers into two-intent reciprocal proposals and to maintain agent and resource spec mappings.

How this skill works

The skill maps local entities (users, organizations, service types, mediums of exchange, requests, offers) into hREA entities (Agents, ResourceSpecifications, Proposals, Intents) via dedicated mapper functions and a central hREA store. Proposal creation enforces three prerequisites (agent, service type spec, medium-of-exchange spec); if any are missing, the request/offer is queued in a pending queue and retried automatically when prerequisites are created. GraphQL calls are made through Apollo + SchemaLink and responses are normalized to handle nested GraphQL shapes and optional missing zome functions.

When to use it

  • When creating proposals from local requests or offers that must map to ValueFlows
  • When synchronizing local users or organizations with hREA Agents
  • When registering service types or mediums of exchange as hREA ResourceSpecifications
  • When you need robust handling for missing prerequisites via a pending queue
  • When the UI must display or react to hREA proposals and intents

Best practices

  • Ensure user approval triggers createPerson() via the store event to generate the agent prerequisite
  • Create resource specs for service types and MoEs on approval so proposals do not get queued
  • Rely on retryPendingProposals() for automated retries instead of manual re-invocation
  • Use normalizeIntentResponse() and normalizeProposalResponse() to turn GraphQL nested responses into usable objects
  • Expect E.catchAll usage: failures due to missing zome functions or prerequisites return safe defaults or nulls

Example use cases

  • User submits a request for web development: map to a Proposal with a primary service intent and a reciprocal payment intent
  • On admin approval of a service type: create its ResourceSpecification and trigger retries for queued requests
  • Handle an offer creation where the MoE is not yet registered by queuing the offer and auto-retrying when MoE is approved
  • Sync an organization record to an hREA Agent when the organization is accepted to enable proposal creation
  • Run unit tests for the hREA store by mocking the GraphQL schema and SchemaLink

FAQ

What are the three prerequisites for creating a proposal?

A corresponding user agent, a service type resource specification, and a medium-of-exchange resource specification must all exist before proposal creation.

What happens if a prerequisite is missing when creating a proposal?

The request or offer is added to the pending queue (pendingRequestQueue or pendingOfferQueue) and createProposalFromRequest/Offer returns null; queued items are retried when any prerequisite is created.