Initial push

This commit is contained in:
2026-06-07 14:19:45 -04:00
parent 9ec04c9879
commit 11bd101087

298
CRY01-SPEC.md Normal file
View File

@@ -0,0 +1,298 @@
# CRY01 — Value Layer Specification
**Project:** kane-diagnostics
**Version:** 2.0
**Prerequisite reading:** README.md, ADDON-SKELETON-SPEC.md, ASSOCIATION-CHANNEL-MODEL.md, FOR-PARTICIPANTS-AND-PROFESSIONALS.md
---
## Purpose
`cry01` is a value layer. It is not a payment processor, an escrow, a marketplace, or an intermediary. The platform is never a party to any transaction. What participants do with the signals recorded here is entirely between them.
The Civic Infrastructure contributes one thing: verified identity. Every signal on this platform is backed by a real name, a real address, and a real property — vouched for through the SASE process. That is the product.
---
## The Pilot Asset: Ğ1 (June)
The first and only asset implemented in this skeleton is Ğ1 (June), the currency of the Duniter network.
June is chosen first because its legitimacy is constructed the same way the Civic Infrastructure's legitimacy is constructed — through a web of trust. Bitcoin's value comes from computation. ETH's value comes from network utility. June's value comes from people vouching for each other. The Civic Infrastructure is already a vouching system. Deploying June first means the platform generates its own credibility rather than borrowing it from another network.
June also prevents the Civic Infrastructure from launching on nothing but a good idea. If June transactions are occurring — real excess capacity being exchanged for real June between verified participants — the platform has economic activity before it has a single attorney listed or a single case filed. A transaction on a public blockchain cannot be faked.
All other assets (ETH, SHIB, BAT, BTC, Pi, and others) are future versions. The skeleton is June only.
---
## What June Denominated in the Civic Infrastructure Means
June is exchanged for **excess capacity** — surplus time, surplus physical space, surplus skill, surplus trust. These are things any homeowner understands and any homeowner has.
Examples of what a signal might record:
- "I have 200 square feet of dry storage available for four weeks. 500 Ğ1."
- "I can notarize documents on weekday evenings. 50 Ğ1 per session."
- "I have a truck available two Saturdays per month. 150 Ğ1 per use."
- "I will store your goods for two additional weeks beyond the agreed date. 100 Ğ1."
The platform records the signal. It does not evaluate it, price it, escrow it, or intermediate it. The participant who posted it and the participant who responds negotiate directly. The Civic Infrastructure's contribution is that both parties are verified.
---
## The Ğ1 Web of Trust Bridge
### Why this works
Ğ1 requires web of trust certification to participate. A member must be certified by a minimum number of existing members who know them in real life and vouch for their unique identity.
The SASE process satisfies this requirement exactly. A homeowner verified through SASE has been vouched for by a real person, at a real address, about a real property. The chain of vouching is documented, time-stamped, and stored in the Hubzilla privacy group membership record.
The Civic Infrastructure can therefore export a SASE participant's attestation in a Duniter-compatible format, signed by the operator's Ğ1 key, and broadcast it to the Duniter network as a certification event. The participant receives Ğ1 certification without any friction beyond the SASE process they have already completed.
### Fediverse implication
Hubzilla's Zot6/Nomad protocol is a federated identity system. A SASE guest token is a portable, verifiable identity claim across nodes. When the Civic Infrastructure federates to additional Hubzilla nodes, SASE participants on those nodes are equally eligible for Ğ1 certification through the same bridge. The Civic Infrastructure becomes a federated Ğ1 onramp — the first of its kind.
### What the skeleton implements
The skeleton implements the attestation document builder only. It does not automate the Duniter certification transaction — that requires the operator's Ğ1 private key and is a deliberate manual step. The skeleton:
- Renders a certification candidate list for the operator — all SASE participants who have registered a Ğ1 public key
- Builds the attestation document for each candidate in the Duniter-compatible format
- Presents it for operator review and manual certification via the Duniter CLI or Cesium wallet
Automated certification signing is a future version feature, pending operator decision on key management.
---
## Three Functions
### 1. Display
The operator's verified Ğ1 balance is shown publicly on the association channel. This is read-only from the Duniter blockchain. No keys are involved. No custody changes. The balance is cached locally and refreshed on a schedule defined in `config.json`.
If the Duniter node is unreachable, the display renders the last cached balance with a staleness timestamp. It does not fail silently. It does not show zero.
### 2. Capacity Signal Registration
A SASE-verified participant registers a capacity signal against their verified identity. The signal describes what they are offering or seeking, denominated in Ğ1. The platform records the signal. No transaction occurs at registration time.
A signal contains:
- The participant's Ğ1 public key (self-reported, linked to their SASE xchan)
- A plain-language description of the capacity being offered or sought
- A Ğ1 denomination (the amount the participant considers fair exchange)
- A duration (how long the capacity is available)
- An optional service category tag from the operator-defined list
Signals are visible to all SASE participants on the association channel. They are not visible to public (unauthenticated) visitors.
### 3. Ğ1 Certification Bridge
The operator sees a candidate list of all SASE participants who have registered a Ğ1 public key. For each candidate, the addon builds a Duniter-compatible attestation document. The operator reviews it and certifies manually via their Ğ1 wallet. The platform does not sign anything automatically.
---
## Route Structure
```
/cry01/[association-slug]/ — Ğ1 balance display + signal board (public read, participant signal)
/cry01/[association-slug]/signal — signal registration form (participant access)
/cry01/[association-slug]/g1 — Ğ1 certification candidate list (operator only)
/cry01/[association-slug]/manage — operator cache refresh and config (operator only)
```
---
## Access Model
| Route | Public | Participant | Professional | Operator |
|---|---|---|---|---|
| Balance display | ✓ read | ✓ read | ✓ read | ✓ read |
| Signal board | — | ✓ read | ✓ read | ✓ read |
| Signal registration | wall | ✓ submit | ✓ submit | ✓ submit |
| Ğ1 candidate list | — | — | — | ✓ only |
| Manage / cache refresh | — | — | — | ✓ only |
Access state resolution follows the same pattern as `vs01`, `dsc01`, and `scn01`: direct `pgrp_member` queries using `get_observer_hash()`, group IDs from `addon/vs01/config.json`. No addon-local association or group data.
---
## Skeleton File Structure
```
hubzilla/addon/cry01/
cry01.php — entry point: hooks, routing, access state, CSRF
cry01_renderer.php — balance display, signal board, signal form, Ğ1 candidate list
cry01_spool.php — POST handler: signal registration, cache refresh trigger
cry01_chain.php — on-chain read layer: Duniter RPC calls, cache read/write
cry01.apd — app descriptor
mod_cry01.pdl — PDL layout: aside, content, right_aside
config.json.template — all config fields documented
Widget/
Cry01.php — sidebar widget: institutional directory (standard pattern)
view/
css/
cry01.css
js/
cry01.js
contracts/
signal-v1.json — the capacity signal spool envelope contract
attestation-v1.json — the Ğ1 attestation document contract
README.md
```
**Note on `cry01_chain.php`:** This is the only file in the project that makes outbound network calls. All Duniter RPC calls, all cache reads, all cache writes happen here and nowhere else. If the node infrastructure changes, only this file changes.
---
## Config Template Fields
```json
{
"_note": "Copy to config.json. Do not commit config.json — it contains installation-specific values.",
"g1_rpc_endpoint": "REPLACE — local Duniter node endpoint, e.g. http://localhost:10901",
"operator_g1_pubkey": "REPLACE — operator Ğ1 public key (not private key — never store private keys)",
"cache_file": "REPLACE — absolute path to balance cache JSON on the host",
"cache_max_age_seconds": 3600,
"signal_categories": [
{
"_note": "Operator-defined capacity categories. Participants tag their signals with these.",
"id": "storage",
"label": "Storage",
"description": "Physical storage space — dry, climate-controlled, or outdoor."
},
{
"id": "transport",
"label": "Transport",
"description": "Vehicle availability for moving goods or people."
},
{
"id": "skill",
"label": "Skill",
"description": "Professional or trade skill offered on a time-available basis."
},
{
"id": "time",
"label": "Time",
"description": "General availability — labor, assistance, or presence."
}
],
"receiver_url": "REPLACE — orchestrator receiver endpoint",
"node_token": "REPLACE — shared secret for node-to-orchestrator auth",
"listings_file": "REPLACE — absolute path to listings.json on the host",
"directory_default_tab": "core"
}
```
---
## Capacity Signal Contract — `contracts/signal-v1.json`
```json
{
"_meta": {
"contract": "cry01-signal",
"version": "1.0",
"purpose": "Capacity signal registration by a verified SASE participant."
},
"_header": {
"addon": "cry01",
"association_slug": "The association this signal is registered against.",
"participant_xchan": "The xchan hash of the signaling participant.",
"submitted_at": "ISO 8601 timestamp.",
"node_token_hash": "SHA-256 of the node token — not the token itself."
},
"_payload": {
"g1_pubkey": "The participant's Ğ1 public key. Required — this is the payment address.",
"capacity_description": "Plain-language description of what is being offered or sought.",
"g1_denomination": "The amount in Ğ1 the participant considers fair exchange.",
"duration_days": "How many days this capacity is available from submission date.",
"category_id": "One of the operator-defined signal_categories ids from config.json.",
"direction": "offer or seek — whether the participant is providing or requesting this capacity."
}
}
```
---
## Ğ1 Attestation Contract — `contracts/attestation-v1.json`
```json
{
"_meta": {
"contract": "cry01-g1-attestation",
"version": "1.0",
"purpose": "Duniter-compatible attestation document for SASE-to-Ğ1 web of trust certification."
},
"_header": {
"operator_g1_pubkey": "The operator's Ğ1 public key — the certifier.",
"participant_g1_pubkey": "The participant's Ğ1 public key — the certifiee.",
"participant_xchan": "The participant's Hubzilla xchan hash — links to SASE record.",
"association_slug": "The association whose SASE membership is the basis of certification.",
"attested_at": "ISO 8601 timestamp of attestation document generation.",
"sase_admitted_at": "ISO 8601 timestamp of SASE admission — from pgrp_member record."
},
"_payload": {
"attestation_statement": "This participant has been verified as a current resident member of the named association through the SASE process, which requires real-name, real-address verification by the association channel operator.",
"duniter_cert_document": "The raw Duniter certification document, generated by cry01_chain.php in the Duniter document format, ready for operator signature and broadcast."
}
}
```
---
## civicnav.json Entry
When `cry01` is installed, the operator adds one entry to `addon/vs01/civicnav.json`:
```json
{
"id": "cry01",
"label": "Value Layer",
"module": "cry01",
"icon": "currency-exchange",
"enabled": true
}
```
No changes to `CivicNav.php` or any PDL are required.
---
## What the Operator Will Decide Before This Is Built
1. **Duniter node setup** — the operator must run a local Duniter node. Duniter is lightweight and can run on the existing Hubzilla host. The operator confirms the node is running and the RPC endpoint is accessible before any code is written.
2. **Operator Ğ1 keypair** — the operator needs a Ğ1 keypair. Cesium wallet is the standard tool. The public key goes in `config.json`. The private key never leaves the operator's wallet and is never stored on the server.
3. **Signal category list** — the four categories in the config template (storage, transport, skill, time) are proposals. The operator confirms, modifies, or extends this list before the skeleton is built.
4. **Signal visibility** — signals are visible to SASE participants by default. The operator decides whether signals should also be visible to civic professionals, or restricted further.
5. **Signal duration policy** — when a signal's duration expires, does it disappear automatically or remain marked as expired? The operator decides.
---
## Build Sequence Within cry01
1. `cry01_chain.php` — Duniter RPC stubs, cache read/write
2. `cry01.php` — entry point, routing, access state
3. `cry01_renderer.php` — balance display, signal board, signal form, Ğ1 candidate list
4. `cry01_spool.php` — signal POST handler
5. Widget, PDL, CSS, JS
6. Ğ1 attestation builder — last, after all other functions confirmed working
---
## What Not To Do
- Do not implement any asset other than Ğ1 in this skeleton.
- Do not connect to any commercial API, exchange, or third-party node. Ever.
- Do not store, transmit, or log any private key. Ever.
- Do not implement automatic Duniter certification signing — manual operator step only.
- Do not make the platform a party to any transaction.
- Do not exceed 500 lines in any PHP file.
- Do not hardcode any address, endpoint, or token.
- Do not push from the host. Gitea is the SSOT.