Skip to content

feat: bring Tibi's general backend work from commitment-pool-experiment onto dev - #183

Merged
Soushi888 merged 14 commits into
devfrom
feat/cp-backend-sync
Nov 11, 2026
Merged

Soushi888 merged 14 commits into
devfrom
feat/cp-backend-sync

Conversation

@Soushi888

@Soushi888 Soushi888 commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

SoushAI analysis. Drafted by Soushi's AI assistant, reviewed and posted by @Soushi888.

Summary

Brings the general backend work from Tibi's commitment-pool-experiment branch onto dev, so the v0.1 line and the Grassroots Economics MVP share one backend. Quantities become a ValueFlows Measure, each NDO indexes its commitments (with hash-paired reads a UI can act on), commitment fulfillment closes atomically with a real counterparty countersignature, and ResourceSpecification gains the optional Layer 1 foreshadow fields. The commitment pool itself (CommitmentAnchor on the Group DNA, admit, withdraw and pool UI) stays on the experiment branch.

Tibi's commits keep his authorship. On top: two small ports to Holochain 0.7.1, and fixes from an independent review of the fulfillment closure (its receipts failed the PPR signature check, the counterparty signed whatever hash it was handed, and a commitment could be fulfilled repeatedly), each its own commit with Sweettests.

Consent rule (new, please check). The party who did not author a commitment initiates its fulfillment, and the author countersigns. Writing the commitment is the author's consent, initiating is the other party's. A commitment naming an agent who never wrote it can no longer collect that agent's signature.

Intent

Tibi's branch forked from dev at 7faf650 and several of its commits are protocol-general rather than pool-specific (his own split, shared with Soushi on 2026-11-10). Landing them now keeps the two lines from drifting apart, and gives the v0.1 UI work the Measure shape and commitment reads it will build on.

Changes
  • Measure (dcbc019, 0fc0ab3): nondominium_shared::types::Measure { numerical_value, has_unit } with one validate(), replacing quantity: f64 plus unit: String on commitments, economic events and economic resources; the TypeScript mirror in packages/shared-types and the NDO forms (commitment with an explicit receiver, economic event) follow.
  • Commitments per NDO (f7e06a2): NdoToCommitments link type, written by propose_commitment, read by get_commitments_for_ndo.
  • Hash-paired reads (backend slice of 033a63a): CommitmentRecord { action_hash, commitment } from get_commitments_for_ndo_detailed and get_all_commitments_detailed, plus its TS type. The admit, fulfill and pool modals of that commit are not included.
  • Atomic fulfillment (11085b5, 09c86a1): fulfillment.rs with fulfill_commitment_closure, which logs the fulfilling event, writes the Claim with the correct fulfilled_by, and issues both parties' participation receipts, the counterparty countersigning through call_remote on an unrestricted countersign_fulfillment grant created in init (the function itself checks the caller is the counterparty). Sweettest coverage included.
  • Review fixes (c58860d, 2c1b730): the initiator signs signed_data_hash like the counterparty, so both receipts pass validate_participation_claim_signature; countersign_fulfillment rebuilds the payload from the commitment, the observed quantity and the event time and signs its own hash; only the non-author initiates; a commitment with a CommitmentToClaim link is refused on both sides; the commitment form's numeric inputs no longer call .trim() on a number, and a Measure of 0 stays 0 in the event form.
  • Layer 1 foreshadow (backend, shared-types and docs slice of 3156120): InventoryIntent, IdentificationPattern, DigitalLocatorKind and the optional fields on ResourceSpecification, validated in validate_spec_foreshadow, with Sweettests. The UI redesign that rode on that commit (GovernanceTab, ResourcesTab, AgentPubkeyField and others) is left for the v0.1 UI pass.
  • Holochain 0.7.1 ports: the fulfillment test uses await_consistency_s(20, …); the countersign grant uses the 0.7 CapGrant { constraint: GrantConstraint::Unrestricted, capability: Capability::ZomeCall(..) }.
Decisions
Option Rejected because
Cherry-pick 033a63a and 3156120 whole Both mix the backend change with pool modals or a UI redesign that belongs to the v0.1 UI review, not to a backend sync
Merge the experiment branch It carries the pool product (CommitmentAnchor, pool UI, the MVP shell remix) that stays experimental
Gate countersign_fulfillment with a cap token Authorisation stays semantic: the function re-fetches the commitment, refuses a caller who is not its counterparty, signs only if it authored the commitment, and signs its own rebuilt hash. The unrestricted grant still lets any agent make the author's conductor run a get
A pending-approval step before countersigning Heavier than v0.1 needs; authorship is the author's consent. Open to revisit for the pool
Let either party initiate Then a commitment written by one party, naming the other, would collect the other's signature without any act of theirs

How to test

nix develop
bun run build:happ
CARGO_TARGET_DIR=target/native-tests cargo test --package nondominium_sweettest
cd packages/shared-types && bun run build && cd ../../ui && bun run check

Follow-ups (non-blocking, from the review)

  • Whether the same-cell update_operational_state call rolls back with the closure when a later step fails (not verified).
  • Integrity has no Measure check on EconomicResource updates and no validation on Claim entries (authorship, fulfilled_by).
  • determine_claim_types_for_action duplicates the mapping in ppr.rs.
  • Comments still name the Commitment Pool and CommitmentAnchor, which are not on dev.
  • Two concurrent closures on one commitment can still race before the first claim link propagates.
  • The deprecated Tryorama suite in tests/ still uses the old quantity shapes.

Documentation

CHANGELOG.md (0.1.0, Added, including the network reset: the nondominium DNA hash changes), documentation/IMPLEMENTATION_STATUS.md and documentation/requirements/resources.md (foreshadow fields, from 3156120).

Related

TiberiusB and others added 10 commits November 10, 2026 17:50
Introduces `vf:Measure { numerical_value, has_unit }` as a shared type in
crates/shared, mirrored at the integrity + coordinator layers of both
zome_resource and zome_gouvernance.

- EconomicResource.{quantity, unit} -> quantity: Measure
- EconomicEvent.resource_quantity -> Measure (was f64)
- Commitment gains resource_quantity: Option<Measure> and
  effort_quantity: Option<Measure> to track with ValueFlows flow fields
- propose_commitment accepts explicit receiver (was hardcoded to caller),
  so third parties can author commitments on behalf of two other agents
- EconomicResourceView and TransitionContext.quantity_change kept but
  switched to Measure / documented as magnitude-only
- Measure::validate() enforces non-NaN, finite, non-negative numerical_value
  and non-empty unit; zero permitted (post-depletion observations)
- Integrity validation plumbed through on create for EconomicResource,
  EconomicEvent, and Commitment
- Sweettest mirror structs updated accordingly (resource/mod.rs,
  governance/mod.rs)

Preparing for commitment-pool-experiment:
- Grassroots-side tooling (and hREA) can read the same Measure shape
- Commitments on the pool can now carry resource/effort quantities
  without squeezing them into free-text notes

cargo build + bun run build:zomes both clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit dcbc019)
Mirrors the Rust-side Measure migration across:
- packages/shared-types: adds Measure interface, migrates
  EconomicResource.{quantity,unit} -> Measure, VfEconomicEvent /
  VfCommitment / LogEconomicEventInput / ProposeCommitmentInput to
  Measure, adds explicit receiver + resource_quantity + effort_quantity
  on ProposeCommitmentInput
- ui/schemas: adds MeasureSchema, swaps number+string pair for Measure
  in EconomicResourceInput, UIEconomicResource, UIEconomicEvent,
  CommitmentInput, UICommitment
- UI components:
  * EconomicEventCreateForm now takes quantity + unit (defaults 'each')
    and submits a Measure
  * CommitmentCreateForm now takes explicit receiver (defaults to self)
    and optional resource/effort quantity+unit pairs
  * ResourcesTab + ActivityTab render Measure.{numerical_value,has_unit}
- holochain-records: isEconomicResource guards against the Measure shape
- resource.store: updateResourceQuantity patches numerical_value only
  (unit unchanged); documents that the backend fn is still not wired
- ndo.store: event dedup checks both numerical_value and has_unit

svelte-check: no new regressions. Error count 228 -> 224 (noise).
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 0fc0ab3)
The Group DNA's CommitmentAnchor points at commitment ActionHashes on the
Nondominium cell, but to display 'commitments attached to this NDO' or to
drive a Pool admissions UI, callers need an NDO-indexed reverse lookup
without scanning the global AllCommitments anchor.

Integrity (zome_gouvernance_integrity):
- LinkTypes::NdoToCommitments  (ndo_identity_hash -> Commitment)

Coordinator (zome_gouvernance / commitment.rs):
- propose_commitment now also writes an NdoToCommitments link in addition
  to AllCommitments, using the commitment's existing ndo_identity_hash
  field (Layer 0 anchor)
- get_commitments_for_ndo(ndo_identity_hash) reads that per-NDO index
  directly — O(links) instead of O(total commitments)

Pairs with the Group-side CommitmentAnchor so UIs can cross-reference
'commitments on this NDO' with 'pools this commitment is admitted to'
via the shared commitment_action_hash.

bun run build:zomes: clean. No new regressions.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit f7e06a2)
Single coordinator call that closes a Commitment:

1. Validates the commitment and the caller's role (provider | receiver)
2. Fetches the counterparty's REAL cryptographic signature via call_remote
   -> fixes #14: the previous issue_participation_receipts flow wrote
   Signature([0u8; 64]) as the counterparty placeholder, so every PPR
   would fail validate_participation_claim_signature. The closure now
   produces a bilateral PPR where both signatures are real and verify.
3. Writes the EconomicEvent observation
4. Writes the Claim with fulfilled_by = the real event action hash
   -> fixes the pre-existing TODO in claim_commitment where fulfilled_by
   was wrongly set to the commitment hash itself
5. Optionally updates the EconomicResource.operational_state via a
   same-agent cross-zome call into zome_resource::update_operational_state
   (the custodian check still applies — if the fulfiller isn't the
   custodian, the whole closure rolls back cleanly)
6. Writes both bilateral PrivateParticipationClaim entries with real
   co-signatures from both parties

Atomicity model:
- call_remote-based countersign chosen over full Holochain countersigning
  session: smallest unit of atomicity that produces cryptographically
  valid PPRs, matches Grassroots Pool semantics (fulfillment is a
  two-sided act), and fails cleanly when the counterparty is offline
  rather than leaving a half-session for someone to roll back later.

Shared signing payload (build_fulfillment_signing_data):
- Deterministic across initiator + counterparty.
- Binds: commitment hash, provider, receiver, resource hash,
  NDO identity hash, resource_quantity (Measure), VfAction, claim-type
  pair, timestamp.
- Blake3-hashed; both sides sign the hash so verification is cheap.

countersign_fulfillment (unrestricted cap grant via init):
- Refetches the commitment and checks that call_info().provenance ==
  the claimed initiator in the payload AND that initiator is in fact
  this agent's counterparty on the commitment.
- Signs the shared payload with its own key and returns the signature.
- Semantic authorisation (not cap-token based) — appropriate for a
  bilateral-event countersign where either party may initiate.

MVP scope: both PPR private entries land on the fulfilling agent's
source chain for now, both with real co-signatures (so cryptographic
verification works end-to-end today). Mirroring the counterparty's
copy onto their own source chain is a view/replication concern that
can land later without changing the signing protocol.

bun run build:zomes: clean (pre-existing dead_code warnings only).

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 11085b5)
Adds two Sweettests on the governance zome:

* get_commitments_for_ndo_scopes_results — writes commitments on two
  distinct NDOs by the same agent and asserts that the NdoToCommitments
  index returns only the ones linked to the queried identity.

* fulfill_commitment_closure_happy_path — Alice creates an NDO, spec,
  and resource, then proposes a commitment with Bob as receiver. Bob
  calls fulfill_commitment_closure, which call_remotes back to Alice
  via the unrestricted countersign_fulfillment grant. Asserts:
    - event_hash != claim_hash (claim.fulfilled_by is the real event
      hash, not the commitment hash)
    - provider_claim_hash != receiver_claim_hash (bilateral issuance)
    - a claim is readable where fulfills == commitment and
      fulfilled_by == event (end-to-end closure)

Also fixes the countersign_fulfillment response decode on the initiator
side: the counterparty returns CountersignFulfillmentOutput (a struct
wrapping Signature), not a bare Signature, so decode as the wrapper and
extract .signature. Without this, every two-agent fulfillment would
fail at the call_remote boundary with 'invalid type: map, expected a
byte array of length 64'.

Related: #14
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 09c86a1)
…ailed)

Backend slice of 033a63a on commitment-pool-experiment: CommitmentRecord
pairs each Commitment with its ActionHash so a UI can act on a specific
commitment (fulfill, admit, withdraw). The UI surfaces of that commit
stay on the experiment branch.

(cherry picked from commit 033a63a, backend slice only)
…rceSpecification

Adds InventoryIntent, IdentificationPattern and DigitalLocatorKind, the
optional Layer 1 foreshadow fields on ResourceSpecification, and their
validation in validate_spec_foreshadow, with Sweettest coverage and the
TypeScript mirror. The UI redesign that rode on the same commit
(GovernanceTab, ResourcesTab, AgentPubkeyField) stays on the experiment
branch for the v0.1 UI pass.

(cherry picked from commit 3156120, backend, shared-types and docs slice only)
…hape

ZomeCallCapGrant and CapAccess::Unrestricted are gone in holochain 0.7;
the grant is now CapGrant { constraint: GrantConstraint::Unrestricted,
capability: Capability::ZomeCall(..) }.
@Soushi888 Soushi888 added this to the v0.1.0 Moss pilot milestone Nov 10, 2026
@Soushi888 Soushi888 added enhancement New feature or request zome-resource Resource zome - specifications, economic resources zome-governance Governance zome - validation, economic events, commitments valueflows ValueFlows ontology compliance and integration labels Nov 10, 2026
…d the signer rebuilds

- The initiator now signs signed_data_hash, as the counterparty does and as
  validate_participation_claim_signature verifies; before, every receipt the
  closure wrote failed that check.
- countersign_fulfillment rebuilds the signing payload from the commitment it
  fetched, the observed quantity and the event time, refuses a mismatching
  hash, and signs its own hash rather than the one it is handed.
- Consent: only the party who did not author the commitment may initiate;
  the author countersigns. A commitment that names an agent who never wrote
  it can no longer collect that agent's signature.
- A commitment with a CommitmentToClaim link is refused on both sides.
- Sweettests: both PPR signatures verify, a second fulfillment is refused,
  the author cannot initiate.
The quantity inputs are type=number, so Svelte binds a number or undefined;
calling .trim() on it threw on submit. A Measure of 0 is valid, so the event
form no longer turns 0 into 1.
…nt event time

countersign_fulfillment is an unrestricted grant, so the non-author could
call it directly to collect the author's signature over any unit or a
backdated time. It now refuses an observed unit that differs from the
committed one and an event time more than five minutes from its clock.
The event form's empty quantity falls back to 1 as intended (an empty
number input binds null).
@Soushi888
Soushi888 marked this pull request as ready for review November 11, 2026 00:05
@Soushi888
Soushi888 merged commit c18e926 into dev Nov 11, 2026
12 checks passed
@Soushi888
Soushi888 deleted the feat/cp-backend-sync branch November 11, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request valueflows ValueFlows ontology compliance and integration zome-governance Governance zome - validation, economic events, commitments zome-resource Resource zome - specifications, economic resources

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants