Files
kane-diagnostics/CRY01-SPEC.md
2026-06-07 16:04:40 -04:00

404 lines
21 KiB
Markdown

# CRY01 — Value Layer Specification
**Project:** kane-diagnostics
**Version:** 3.0
**Prerequisite reading:** README.md, ADDON-SKELETON-SPEC.md, ASSOCIATION-CHANNEL-MODEL.md, FOR-PARTICIPANTS-AND-PROFESSIONALS.md
---
## Purpose
`cry01` is a value layer and a credential infrastructure layer. It serves two distinct functions that reinforce each other.
**As 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.
**As a credential infrastructure layer:** `cry01` provides the cryptographic underpinning that makes significant diagnostic results independently verifiable — by attorneys, courts, regulators, and the general public — without trusting the Civic Infrastructure at all. This is the foundational service that `poll01` and all future significant diagnostic result addons depend on.
---
## The Credential Stack
Every significant diagnostic result produced by the Civic Infrastructure — a poll result, a quorum determination, a bylaw amendment vote — is anchored by the following credential stack. Each layer adds independent verifiability.
### Layer 1 — SASE Identity
The participant's identity has been verified as a current resident member of a specific association through the SASE process. Real name, real address, real property. Vouched for by the association channel operator. Stored in the Hubzilla `pgrp_member` table with a timestamp.
This is the foundation. Without it, no other layer has meaning.
### Layer 2 — Ğ1 Web of Trust Certification
The SASE process satisfies the requirements for Ğ1 (June) web of trust certification. A verified SASE participant can be certified as a Ğ1 member by the operator, linking their Hubzilla identity to their Duniter public key. This certification is broadcast to the Duniter network and is permanently recorded on the Ğ1 blockchain.
A Ğ1-certified participant's identity is now vouched for by two independent systems: the Civic Infrastructure's SASE process and the Duniter network's web of trust. These are structurally equivalent vouching mechanisms that arrived at the same conclusion independently.
### Layer 3 — W3C Verifiable Credential
Each significant diagnostic result — a ballot cast, a poll result, a SASE admission — is issued as a W3C Verifiable Credential by the Civic Infrastructure. The VC is cryptographically signed by the operator, identifies the subject by their Hubzilla xchan expressed as a `did:web` identifier, and contains the structured claim.
A VC is machine-readable and independently verifiable by any system that implements the W3C VC standard. It does not require contacting the Civic Infrastructure to verify. An attorney receiving a poll result VC can verify its authenticity offline.
### Layer 4 — OpenTimestamps
Every significant diagnostic result is timestamped against the Bitcoin blockchain via OpenTimestamps at the moment it enters the orchestrator spool. The timestamp proof anchors the SHA-256 hash of the result document to a specific Bitcoin block. No one can claim the document was produced after the fact.
OpenTimestamps requires no account, no token, no Bitcoin transaction fee (proofs are aggregated by public calendar servers), and no understanding of the Civic Infrastructure. Any person with the document and the proof file can verify the timestamp independently using the `ots` command line tool or the OpenTimestamps web verifier.
### Layer 5 — DANE (DNS-Based Authentication of Named Entities)
The domain serving the Civic Infrastructure's diagnostic records is bound to its TLS certificate via TLSA records in DNS, secured by DNSSEC. A document served from `directory.diagnostics.kane-il.us` cannot be impersonated — the DNS record cryptographically identifies the server. This prevents man-in-the-middle attacks and domain spoofing when attorneys or regulators retrieve diagnostic records.
---
## 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.
---
## Four Functions
### 1. Display
The operator's verified Ğ1 balance is shown publicly on the association channel. This is read-only from the Duniter blockchain via the local Duniter mirror node on the orchestrator. 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.
At signal registration, the orchestrator:
- Accepts the signal via the spool receiver
- Issues a W3C Verifiable Credential for the signal
- Generates an OpenTimestamps proof anchoring the signal to the Bitcoin blockchain
- Stores the signal, VC, and OTS proof together in the spool
### 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.
### 4. Credential Service (shared infrastructure)
`cry01` exposes a credential issuance endpoint on the orchestrator that other addons (`poll01` and future significant diagnostic result addons) call to issue VCs and OTS proofs for their own results. This endpoint is internal — accessible only over the Wireguard tunnel — and authenticated with the node token.
This is the function that makes `cry01` a dependency of `poll01`. A poll result is not just a count of votes. It is a VC issued by the Civic Infrastructure, timestamped on Bitcoin, carried by verified identities that have been independently certified through SASE and optionally through Ğ1.
---
## 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.
---
## Orchestrator Components
The orchestrator node (`orchestrator1`) runs two services that support `cry01` and all future credential-dependent addons:
**`duniter-mirror.service`** — Duniter v2 mirror node, synced to Ğ1 mainnet. Provides the RPC endpoint at `ws://127.0.0.1:9944` for balance queries and attestation document construction. Accessible to the Hubzilla node via Wireguard tunnel at `http://10.0.0.105:9944`.
**`civic-orchestrator.service`** — FastAPI spool receiver. Accepts signal POST requests from `cry01_spool.php`, validates the node token, issues VCs, generates OTS proofs, and writes the complete spool entry. Listens on `http://10.0.0.105:8700`. The credential issuance endpoint (`/cry01/credential/issue`) is the shared service that `poll01` and future addons call.
---
## 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
vc-v1.json — the W3C Verifiable Credential envelope contract
ots-v1.json — the OpenTimestamps proof envelope 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 — Duniter node RPC over Wireguard, e.g. http://10.0.0.105:9944",
"orchestrator_url": "REPLACE — spool receiver base URL, e.g. http://10.0.0.105:8700",
"operator_g1_pubkey": "REPLACE — operator Ğ1 public key (not private key — never store private keys)",
"operator_did": "REPLACE — operator did:web identifier, e.g. did:web:directory.diagnostics.kane-il.us",
"cache_file": "REPLACE — absolute path to balance cache JSON on the host",
"cache_max_age_seconds": 3600,
"ots_calendar_url": "https://alice.btc.calendar.opentimestamps.org",
"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 spool 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"
}
```
---
## W3C Verifiable Credential Contract — `contracts/vc-v1.json`
```json
{
"_meta": {
"contract": "cry01-vc",
"version": "1.0",
"purpose": "W3C Verifiable Credential envelope for Civic Infrastructure diagnostic results."
},
"_note": "This contract describes the VC structure. The actual VC is a JSON-LD document signed by the operator. The _payload field contains the claim specific to the issuing addon (signal, ballot, poll result, etc.).",
"vc_structure": {
"@context": ["https://www.w3.org/2018/credentials/v1"],
"type": ["VerifiableCredential"],
"issuer": "did:web:directory.diagnostics.kane-il.us",
"issuanceDate": "ISO 8601 timestamp",
"credentialSubject": {
"id": "did:web:directory.diagnostics.kane-il.us/channel/{xchan}",
"association": "association slug",
"claim_type": "signal | ballot | poll_result | sase_admission",
"claim": "addon-specific structured claim — see issuing addon spec"
},
"proof": {
"type": "Ed25519Signature2020",
"created": "ISO 8601 timestamp",
"verificationMethod": "did:web:directory.diagnostics.kane-il.us#operator-key",
"proofValue": "base58-encoded signature"
}
}
}
```
---
## OpenTimestamps Contract — `contracts/ots-v1.json`
```json
{
"_meta": {
"contract": "cry01-ots",
"version": "1.0",
"purpose": "OpenTimestamps proof envelope anchoring a diagnostic result to the Bitcoin blockchain."
},
"_header": {
"document_hash": "SHA-256 hash of the document being timestamped.",
"hash_algorithm": "sha256",
"timestamped_at": "ISO 8601 timestamp of OTS submission to calendar server.",
"calendar_url": "The OTS calendar server used.",
"addon": "The addon that generated this document (cry01, poll01, etc.)",
"association_slug": "The association this document pertains to."
},
"_payload": {
"ots_proof_base64": "Base64-encoded .ots proof file. Verifiable offline with the ots tool.",
"bitcoin_block": "Bitcoin block number in which the timestamp was confirmed. Null until confirmed.",
"confirmed_at": "ISO 8601 timestamp of Bitcoin confirmation. Null until confirmed."
}
}
```
---
## 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."
},
"_credentials": {
"vc": "The W3C Verifiable Credential issued for this signal. See contracts/vc-v1.json.",
"ots": "The OpenTimestamps proof for this signal. See contracts/ots-v1.json."
}
}
```
---
## Ğ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.
---
## 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. Credential issuance — VC and OTS — integrated into spool receiver on orchestrator
7. Ğ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.