ICN Federation Demo System — Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Build a canonical "A Federation in Motion" demo system with four cooperative personas, three modular flows, presenter runbook, and self-serve handoff path.
Architecture: Four live K3s coop nodes (alpha/beta/gamma/delta) are reseeded with canonical personas and story data. Bash flow scripts use kubectl port-forward to access each coop's gateway (ClusterIP-only, no NodePort on port 8080). A shared port library handles setup/teardown so each flow script stays focused on narration.
Tech Stack: Bash, kubectl, curl, icnctl CLI, K3s cluster at 10.8.30.40, coop gateways behind ClusterIP services
Design doc: docs/plans/2026-03-07-demo-system-design.md
Cluster Topology Reference
| Persona | Node | K8s Namespace | ClusterIP | Local port (port-forward) |
|---|---|---|---|---|
| BrightWorks Cooperative (worker) | icn-alpha | icn-coop-alpha | 10.43.97.80:8080 | 18081 |
| River City Tool Library (resource) | icn-beta | icn-coop-beta | 10.43.194.7:8080 | 18082 |
| Harbor Homes Cooperative (housing) | icn-gamma | icn-coop-gamma | 10.43.12.70:8080 | 18083 |
| Finger Lakes CDN (intermediate org) | icn-delta | icn-coop-delta | 10.43.110.197:8080 | 18084 |
Use ports 18081–18084 to avoid collision with the main icn-daemon NodePort (30080).
Before You Start
# Confirm cluster is healthy
kubectl get pods -A | grep -E "icn-(alpha|beta|gamma|delta)" | grep -v Succeeded
# Confirm you can reach the main gateway
curl -s http://10.8.30.40:30080/v1/health | python3 -m json.tool
# Confirm kubectl works
kubectl get nodes
Task 1: Discover Gateway API Shape
Before writing flow scripts, map what endpoints actually exist.
Files:
- Create:
demo/docs/api-map.md
Step 1: Port-forward to alpha and probe the API
kubectl port-forward -n icn-coop-alpha svc/icn-alpha 18081:8080 &
PF=$!
sleep 2
curl -s http://localhost:18081/v1/health | python3 -m json.tool
Expected: JSON with status: "ok" or similar.
Step 2: Discover available routes
# Try OpenAPI spec
curl -s http://localhost:18081/v1/openapi.json 2>/dev/null | python3 -m json.tool | grep '"/"' | head -40
# Or enumerate known endpoints
for ep in /v1/health /v1/coops /v1/governance/proposals /v1/ledger/balance /v1/members; do
code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:18081$ep)
echo "$code $ep"
done
kill $PF
Step 3: Write api-map.md
Document each endpoint that returns 200 or 401 (exists but needs auth). Format:
# Gateway API Map (as of YYYY-MM-DD)
| Endpoint | Method | Auth | Notes |
|---|---|---|---|
| /v1/health | GET | No | Always returns 200 |
| /v1/coops | GET | Yes | List all coops |
| ... | | | |
Step 4: Kill port-forward and commit
kill $PF 2>/dev/null || true
git add demo/docs/api-map.md
git commit -m "docs(demo): add gateway API map for flow scripting"
Task 2: Create Shared Port-Forward Library
All flow scripts need the same port-forward setup/teardown. Build it once.
Files:
- Create:
demo/scripts/lib-demo-ports.sh
Step 1: Write the library
cat > /home/ubuntu/projects/icn/demo/scripts/lib-demo-ports.sh << 'EOF'
#!/usr/bin/env bash
# Shared port-forward management for federation demo scripts.
# Source this file; do not execute directly.
#
# Usage:
# source demo/scripts/lib-demo-ports.sh
# demo_ports_up # start all 4 port-forwards
# demo_ports_down # kill all port-forwards
# demo_wait_ready # block until all 4 gateways respond
BRIGHTWORKS_PORT=18081 # icn-coop-alpha
RIVERCITY_PORT=18082 # icn-coop-beta
HARBOR_PORT=18083 # icn-coop-gamma
FINGERLAKES_PORT=18084 # icn-coop-delta
BRIGHTWORKS_URL="http://localhost:${BRIGHTWORKS_PORT}"
RIVERCITY_URL="http://localhost:${RIVERCITY_PORT}"
HARBOR_URL="http://localhost:${HARBOR_PORT}"
FINGERLAKES_URL="http://localhost:${FINGERLAKES_PORT}"
_PF_PIDS=()
_pf_start() {
local ns="$1" svc="$2" local_port="$3" remote_port="$4"
kubectl port-forward -n "$ns" "svc/$svc" "${local_port}:${remote_port}" \
>/tmp/pf-${local_port}.log 2>&1 &
_PF_PIDS+=($!)
}
demo_ports_up() {
echo "Starting port-forwards..."
_pf_start icn-coop-alpha icn-alpha "${BRIGHTWORKS_PORT}" 8080
_pf_start icn-coop-beta icn-beta "${RIVERCITY_PORT}" 8080
_pf_start icn-coop-gamma icn-gamma "${HARBOR_PORT}" 8080
_pf_start icn-coop-delta icn-delta "${FINGERLAKES_PORT}" 8080
trap demo_ports_down EXIT INT TERM
}
demo_ports_down() {
for pid in "${_PF_PIDS[@]:-}"; do
kill "$pid" 2>/dev/null || true
done
_PF_PIDS=()
}
demo_wait_ready() {
local urls=("$BRIGHTWORKS_URL" "$RIVERCITY_URL" "$HARBOR_URL" "$FINGERLAKES_URL")
local names=("BrightWorks" "River City Tool Library" "Harbor Homes" "Finger Lakes CDN")
local max_wait=30
local waited=0
for i in "${!urls[@]}"; do
local url="${urls[$i]}" name="${names[$i]}"
echo -n " Waiting for ${name}..."
while ! curl -fsS "${url}/v1/health" >/dev/null 2>&1; do
sleep 1
waited=$((waited+1))
if [ "$waited" -ge "$max_wait" ]; then
echo " TIMEOUT"
return 1
fi
done
echo " ready"
done
}
# Authenticated curl helper
# Usage: demo_curl <url> <method> [body] [token]
demo_curl() {
local url="$1" method="$2" body="${3:-}" token="${4:-${DEMO_TOKEN:-}}"
local args=(-sS -X "$method" -H "Accept: application/json")
[ -n "$token" ] && args+=(-H "Authorization: Bearer $token")
[ -n "$body" ] && args+=(-H "Content-Type: application/json" -d "$body")
curl "${args[@]}" "$url"
}
EOF
Step 2: Verify syntax
bash -n /home/ubuntu/projects/icn/demo/scripts/lib-demo-ports.sh
echo $? # expect 0
Step 3: Commit
git add demo/scripts/lib-demo-ports.sh
git commit -m "feat(demo): add shared port-forward library for federation flows"
Task 3: Create Canonical Seed Data
Four sets of fixture files — one per coop. These define the stable world the demo always starts from.
Files:
- Create:
demo/data/brightworks-members.json - Create:
demo/data/rivercity-members.json - Create:
demo/data/harborhomes-members.json - Create:
demo/data/fingerlakes-members.json - Create:
demo/data/federation-proposals.json - Create:
demo/data/federation-history.json
Step 1: Write BrightWorks member data
{
"organization": "BrightWorks Cooperative",
"type": "worker",
"coop_id": "brightworks-cooperative",
"members": [
{ "name": "Yusuf Okafor", "role": "Board Secretary", "labor_hours": 120 },
{ "name": "Camille Tran", "role": "Member-Worker", "labor_hours": 98 },
{ "name": "Devraj Singh", "role": "Member-Worker", "labor_hours": 115 },
{ "name": "Rosa Mendez", "role": "Treasurer", "labor_hours": 87 },
{ "name": "Anton Kowalski", "role": "Member-Worker", "labor_hours": 104 }
]
}
Save to demo/data/brightworks-members.json.
Step 2: Write River City Tool Library member data
{
"organization": "River City Tool Library",
"type": "community",
"coop_id": "river-city-tool-library",
"members": [
{ "name": "Priya Sharma", "role": "Coordinator", "contribution_hours": 45 },
{ "name": "Marcus Webb", "role": "Member", "contribution_hours": 32 },
{ "name": "Fatima Al-Amin", "role": "Member", "contribution_hours": 28 },
{ "name": "Lucas Ferreira", "role": "Member", "contribution_hours": 19 },
{ "name": "Aiko Nakamura", "role": "Maintenance Lead", "contribution_hours": 51 }
]
}
Save to demo/data/rivercity-members.json.
Step 3: Write Harbor Homes member data
{
"organization": "Harbor Homes Cooperative",
"type": "housing",
"coop_id": "harbor-homes-cooperative",
"members": [
{ "name": "Delphine Moreau", "role": "Board Chair", "units": 1 },
{ "name": "James Okafor", "role": "Board Member", "units": 1 },
{ "name": "Sunita Kapoor", "role": "Treasurer", "units": 1 },
{ "name": "Patrick Brennan", "role": "Member", "units": 2 },
{ "name": "Mei-Ling Chen", "role": "Secretary", "units": 1 }
]
}
Save to demo/data/harborhomes-members.json.
Step 4: Write Finger Lakes CDN member data
{
"organization": "Finger Lakes Cooperative Development Network",
"type": "intermediate",
"coop_id": "fingerlakes-cdn",
"members": [
{ "name": "Amara Diallo", "role": "Executive Director" },
{ "name": "Thomas Kowalczyk", "role": "Program Officer" },
{ "name": "Rebecca Nwosu", "role": "Federation Liaison" }
]
}
Save to demo/data/fingerlakes-members.json.
Step 5: Write canonical proposals fixture
{
"proposals": [
{
"coop": "harbor-homes-cooperative",
"title": "Authorize roof repair — Building A",
"description": "The inspection report dated 2026-02-15 identified water intrusion at the Building A flat roof. This proposal authorizes up to $12,000 from the capital reserve fund for repairs. Work will be performed by Harbor Roofing LLC per quote #HH-2026-14.",
"type": "treasury_spend",
"amount": 12000,
"unit": "usd",
"status": "pending",
"demo_role": "flow1_subject"
},
{
"coop": "brightworks-cooperative",
"title": "Q1 patronage distribution",
"description": "Distribute Q1 surplus proportionally to member labor hours. Total distributable: 3,840 credits across 524 labor hours.",
"type": "patronage_distribution",
"status": "approved",
"demo_role": "flow2_subject"
},
{
"coop": "fingerlakes-cdn",
"title": "River City Tool Library — BrightWorks equipment access agreement",
"description": "Authorize a 90-day equipment-sharing agreement. River City provides access to metalworking tools; BrightWorks contributes 20 maintenance hours per quarter.",
"type": "federation_agreement",
"status": "pending",
"demo_role": "flow3_subject"
}
]
}
Save to demo/data/federation-proposals.json.
Step 6: Write transaction history fixture
Create demo/data/federation-history.json with 5–8 realistic cross-coop transactions showing prior coordination between the coops (equipment sharing, maintenance hours, support contributions).
{
"transactions": [
{
"from": "BrightWorks Cooperative",
"to": "River City Tool Library",
"type": "maintenance_contribution",
"amount": 8,
"unit": "hours",
"description": "Quarterly tool maintenance — lathe and drill press",
"date": "2026-01-15T10:00:00Z"
},
{
"from": "River City Tool Library",
"to": "BrightWorks Cooperative",
"type": "equipment_access",
"amount": 40,
"unit": "commons_credits",
"description": "Equipment access credits — Q4 2025",
"date": "2026-01-20T09:00:00Z"
},
{
"from": "Finger Lakes CDN",
"to": "Harbor Homes Cooperative",
"type": "technical_assistance",
"amount": 4,
"unit": "hours",
"description": "Governance setup support — new treasurer onboarding",
"date": "2026-02-03T14:00:00Z"
}
]
}
Step 7: Commit
git add demo/data/brightworks-members.json demo/data/rivercity-members.json \
demo/data/harborhomes-members.json demo/data/fingerlakes-members.json \
demo/data/federation-proposals.json demo/data/federation-history.json
git commit -m "feat(demo): add canonical seed data for four federation personas"
Task 4: Create reseed-federation-demo.sh
Reset all four nodes to canonical demo state. This is the "clear the deck" command.
Files:
- Create:
demo/scripts/reseed-federation-demo.sh
Step 1: Understand what seeding requires
Before writing the script, verify what API calls actually create proposals and load members. Run:
# From Task 1 API map — adapt these to real endpoints
source demo/scripts/lib-demo-ports.sh
demo_ports_up
demo_wait_ready
# Try creating a proposal on Harbor Homes (Flow 1 subject)
# Replace /v1/governance/proposals with actual endpoint from api-map.md
TOKEN="<get from kubectl exec or icnctl>"
curl -X POST http://localhost:18083/v1/governance/proposals \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"test","description":"test","type":"text"}' | python3 -m json.tool
Document the actual endpoint in demo/docs/api-map.md before proceeding.
Step 2: Write reseed-federation-demo.sh
Template — fill in actual endpoints discovered in Step 1:
#!/usr/bin/env bash
# Reset all four federation demo nodes to canonical state.
# Usage: ./demo/scripts/reseed-federation-demo.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib-demo-ports.sh"
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
echo "=== ICN Federation Demo — Reseed ==="
echo
demo_ports_up
demo_wait_ready
# Helper: get a demo token for a coop
# Adjust to actual token endpoint from api-map.md
get_token() {
local url="$1" coop_id="$2"
# TODO: replace with actual token generation call
# e.g.: curl -sS -X POST "$url/v1/auth/token" -d "{\"coop_id\":\"$coop_id\",...}"
echo "PLACEHOLDER_TOKEN"
}
seed_coop() {
local name="$1" url="$2" coop_id="$3" data_file="$4"
echo -n " Seeding ${name}..."
local token; token=$(get_token "$url" "$coop_id")
# Load member display names (API endpoint TBD from api-map.md)
# curl -sS -X PUT "$url/v1/coops/$coop_id/members" \
# -H "Authorization: Bearer $token" \
# -H "Content-Type: application/json" \
# --data-binary "@${SCRIPT_DIR}/../data/${data_file}"
echo -e " ${GREEN}done${NC}"
}
seed_coop "BrightWorks Cooperative" "$BRIGHTWORKS_URL" "brightworks-cooperative" "brightworks-members.json"
seed_coop "River City Tool Library" "$RIVERCITY_URL" "river-city-tool-library" "rivercity-members.json"
seed_coop "Harbor Homes Cooperative" "$HARBOR_URL" "harbor-homes-cooperative" "harborhomes-members.json"
seed_coop "Finger Lakes Cooperative Development Network" "$FINGERLAKES_URL" "fingerlakes-cdn" "fingerlakes-members.json"
echo
echo -e "${GREEN}Federation demo world reseeded.${NC}"
echo "Run flows:"
echo " ./demo/scripts/flow-1-governance.sh"
echo " ./demo/scripts/flow-2-patronage.sh"
echo " ./demo/scripts/flow-3-federation.sh"
Step 3: Make executable and test
chmod +x /home/ubuntu/projects/icn/demo/scripts/reseed-federation-demo.sh
./demo/scripts/reseed-federation-demo.sh
# Expected: all four coops report "done", no errors
Step 4: Commit
git add demo/scripts/reseed-federation-demo.sh
git commit -m "feat(demo): add reseed-federation-demo.sh for canonical world reset"
Task 5: Flow 1 — Governance Legitimacy (Flow 1A)
Harbor Homes votes on a roof repair, the treasury action follows, provenance is shown.
Files:
- Create:
demo/scripts/flow-1-governance.sh
Step 1: Write Flow 1A script
#!/usr/bin/env bash
# Flow 1: Governance Legitimacy and Action Traceability
# Narrative: Harbor Homes Cooperative — roof repair authorization
#
# What this demonstrates (Flow 1A — current scope):
# - Proposal creation
# - Member voting
# - Approval result
# - Treasury action initiation
# - Provenance context
#
# What this does NOT yet claim (Flow 1B — pending PR #1327):
# - ExecutionReceiptGate enforcement
# - Machine-verifiable governance-to-execution binding
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib-demo-ports.sh"
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
narrate() { echo -e "\n${BLUE}▶${NC} $*\n"; }
result() { echo -e " ${GREEN}✓${NC} $*"; }
aside() { echo -e " ${YELLOW}→${NC} $*"; }
demo_ports_up
demo_wait_ready
# --- Act ---
narrate "Harbor Homes Cooperative — Roof Repair Authorization"
echo " The board has received an inspection report:"
echo " water intrusion detected at Building A flat roof."
echo " A proposal to authorize \$12,000 from the capital reserve is pending."
echo
narrate "Step 1: Show the pending proposal"
PROPOSAL=$(demo_curl "$HARBOR_URL/v1/governance/proposals?status=pending" GET "" "$HARBOR_TOKEN")
echo "$PROPOSAL" | python3 -m json.tool
result "Proposal visible to all members"
aside "Anyone in the coop can see this — not just the board"
narrate "Step 2: Members vote"
# Vote yes as Delphine Moreau (Board Chair)
demo_curl "$HARBOR_URL/v1/governance/proposals/${PROPOSAL_ID}/votes" POST \
'{"vote":"yes","member":"did:icn:delphine"}' "$HARBOR_TOKEN" | python3 -m json.tool
# Vote yes as James Okafor
demo_curl "$HARBOR_URL/v1/governance/proposals/${PROPOSAL_ID}/votes" POST \
'{"vote":"yes","member":"did:icn:james"}' "$HARBOR_TOKEN" | python3 -m json.tool
result "Votes recorded — 2 yes, quorum reached"
aside "Delphine Moreau, James Okafor — names visible, not raw DIDs"
narrate "Step 3: Proposal passes — treasury action authorized"
APPROVAL=$(demo_curl "$HARBOR_URL/v1/governance/proposals/${PROPOSAL_ID}" GET "" "$HARBOR_TOKEN")
echo "$APPROVAL" | python3 -m json.tool
result "Status: approved"
narrate "Step 4: Show provenance"
PROVENANCE=$(demo_curl "$HARBOR_URL/v1/ledger/provenance?ref=proposal:${PROPOSAL_ID}" GET "" "$HARBOR_TOKEN")
echo "$PROVENANCE" | python3 -m json.tool
result "Provenance chain links proposal to authorized allocation"
echo
echo "================================================================"
echo " FLOW 1A COMPLETE: Governance leading to authorized action"
echo " with provenance context."
echo
echo " NOTE: The final receipt-gated execution proof is being"
echo " finalized (PR #1327 — ExecutionReceiptGate). Once merged,"
echo " the system will provide machine-verifiable binding between"
echo " the approved vote and the resulting execution."
echo "================================================================"
echo
Save to demo/scripts/flow-1-governance.sh.
Step 2: Replace placeholder API calls with real endpoints from api-map.md
This is the critical step. Do not proceed until the curl calls return real data.
For each call:
- Run it manually against
$HARBOR_URL - Verify the response shape
- Update the script to extract the right fields (proposal ID, status, etc.)
Step 3: Test the full flow end-to-end
chmod +x demo/scripts/flow-1-governance.sh
./demo/scripts/flow-1-governance.sh 2>&1 | tee /tmp/flow1-output.txt
grep -E "(COMPLETE|ERROR|✓)" /tmp/flow1-output.txt
Expected: all ✓ lines, no errors, ends with FLOW 1A COMPLETE.
Step 4: Commit
git add demo/scripts/flow-1-governance.sh
git commit -m "feat(demo): add flow-1-governance.sh (Flow 1A — Harbor Homes roof repair)"
Task 6: Flow 2 — Patronage and Contribution Legibility
BrightWorks distributes Q1 patronage. Any member can see why allocations look the way they do.
Files:
- Create:
demo/scripts/flow-2-patronage.sh
Step 1: Write the script
#!/usr/bin/env bash
# Flow 2: Patronage, Contribution, and Value Legibility
# Narrative: BrightWorks Cooperative — Q1 patronage distribution
#
# What this demonstrates:
# - Commons credit / contribution accounting
# - Provenance-backed balances
# - PatronageTracker logic
# - Member-visible explanation of allocations
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib-demo-ports.sh"
BLUE='\033[0;34m'; GREEN='\033[0;32m'; NC='\033[0m'
narrate() { echo -e "\n${BLUE}▶${NC} $*\n"; }
result() { echo -e " ${GREEN}✓${NC} $*"; }
aside() { echo -e " → $*"; }
demo_ports_up
demo_wait_ready
narrate "BrightWorks Cooperative — Q1 Patronage Distribution"
echo " Q1 is closing. 3,840 credits are distributable."
echo " The question every member asks: 'Why did I get this amount?'"
echo
narrate "Step 1: Show contribution ledger"
# Endpoint TBD from api-map.md
CONTRIBUTIONS=$(demo_curl "$BRIGHTWORKS_URL/v1/ledger/contributions" GET "" "$BRIGHTWORKS_TOKEN")
echo "$CONTRIBUTIONS" | python3 -m json.tool
result "Labor hours per member visible to the whole coop"
aside "Yusuf: 120h, Devraj: 115h, Camille: 98h, Anton: 104h, Rosa: 87h"
narrate "Step 2: Show patronage calculation (PatronageTracker)"
PATRONAGE=$(demo_curl "$BRIGHTWORKS_URL/v1/ledger/patronage?period=2026-Q1" GET "" "$BRIGHTWORKS_TOKEN")
echo "$PATRONAGE" | python3 -m json.tool
result "Allocation = (member hours / total hours) * distributable surplus"
aside "Each member can verify the math. No black box."
narrate "Step 3: Show provenance-backed balance for one member"
BALANCE=$(demo_curl "$BRIGHTWORKS_URL/v1/ledger/balance?member=did:icn:yusuf" GET "" "$BRIGHTWORKS_TOKEN")
echo "$BALANCE" | python3 -m json.tool
result "Balance includes provenance reference to the patronage receipt"
echo
echo "================================================================"
echo " FLOW 2 COMPLETE: Patronage and contribution legibility"
echo " Any member can inspect why they received what they received."
echo "================================================================"
echo
Step 2: Fill in real API calls
Same process as Task 5 Step 2. Verify against $BRIGHTWORKS_URL.
Step 3: Test
chmod +x demo/scripts/flow-2-patronage.sh
./demo/scripts/flow-2-patronage.sh 2>&1 | grep -E "(COMPLETE|ERROR|✓)"
Step 4: Commit
git add demo/scripts/flow-2-patronage.sh
git commit -m "feat(demo): add flow-2-patronage.sh (BrightWorks Q1 patronage distribution)"
Task 7: Flow 3 — Federation Coordination
River City shares equipment with BrightWorks. Finger Lakes CDN facilitates. Cross-coop commons credits settle.
Files:
- Create:
demo/scripts/flow-3-federation.sh
Step 1: Write the script
#!/usr/bin/env bash
# Flow 3: Federation Coordination Across Autonomous Coops
# Narrative: River City Tool Library + BrightWorks equipment access agreement,
# facilitated by Finger Lakes CDN
#
# What this demonstrates:
# - Multiple live nodes, separate identities
# - Cross-coop proposal and agreement
# - Commons credit settlement across orgs
# - Federation without centralization
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib-demo-ports.sh"
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
narrate() { echo -e "\n${BLUE}▶${NC} $*\n"; }
result() { echo -e " ${GREEN}✓${NC} $*"; }
aside() { echo -e " ${YELLOW}→${NC} $*"; }
demo_ports_up
demo_wait_ready
narrate "A Federation in Motion"
echo " Three separate cooperatives. Three separate nodes."
echo " No central authority. Each controls its own data."
echo " Today: River City and BrightWorks are forming an equipment-sharing agreement."
echo
narrate "Step 1: Show each coop's identity — they are independent"
for url_var in BRIGHTWORKS_URL RIVERCITY_URL FINGERLAKES_URL; do
url="${!url_var}"
info=$(demo_curl "$url/v1/health" GET)
echo " $url_var: $(echo "$info" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("coop_id","unknown"))')"
done
result "Three separate nodes — separate governance, separate ledgers"
narrate "Step 2: Finger Lakes CDN proposes a federation agreement"
# CDN initiates on behalf of the two coops (federation proposal pattern)
AGREEMENT=$(demo_curl "$FINGERLAKES_URL/v1/federation/agreements" POST \
'{"parties":["river-city-tool-library","brightworks-cooperative"],
"terms":"River City provides metalworking equipment access; BrightWorks contributes 20 maintenance hours/quarter",
"duration_days":90}' "$FINGERLAKES_TOKEN")
echo "$AGREEMENT" | python3 -m json.tool
result "Agreement proposed — each party must accept independently"
aside "Finger Lakes CDN facilitates. It does not control."
narrate "Step 3: Both coops accept"
demo_curl "$RIVERCITY_URL/v1/federation/agreements/${AGREEMENT_ID}/accept" POST \
'{}' "$RIVERCITY_TOKEN" | python3 -m json.tool
demo_curl "$BRIGHTWORKS_URL/v1/federation/agreements/${AGREEMENT_ID}/accept" POST \
'{}' "$BRIGHTWORKS_TOKEN" | python3 -m json.tool
result "Agreement active — both parties accepted independently"
narrate "Step 4: BrightWorks contributes maintenance hours — commons credits settle"
SETTLEMENT=$(demo_curl "$BRIGHTWORKS_URL/v1/ledger/commons-credit" POST \
'{"recipient":"river-city-tool-library",
"amount":8,
"unit":"hours",
"description":"Q1 maintenance contribution — lathe and drill press",
"agreement_ref":"'"${AGREEMENT_ID}"'"}' "$BRIGHTWORKS_TOKEN")
echo "$SETTLEMENT" | python3 -m json.tool
result "Settlement recorded — cross-coop, provenance-backed"
narrate "Step 5: Show the cross-coop settlement at Finger Lakes CDN"
FEDERATION_VIEW=$(demo_curl "$FINGERLAKES_URL/v1/federation/settlements?agreement=${AGREEMENT_ID}" GET "" "$FINGERLAKES_TOKEN")
echo "$FEDERATION_VIEW" | python3 -m json.tool
result "CDN can see settlement status across the federation"
aside "Read-only visibility. No ability to override either coop's ledger."
echo
echo "================================================================"
echo " FLOW 3 COMPLETE: Federation coordination across autonomous coops"
echo " Independent coops coordinated without a central authority."
echo "================================================================"
echo
Step 2: Fill in real API calls
Pay special attention to federation/agreement endpoints — these may be different. Verify from api-map.md and update.
Step 3: Test
chmod +x demo/scripts/flow-3-federation.sh
./demo/scripts/flow-3-federation.sh 2>&1 | grep -E "(COMPLETE|ERROR|✓)"
Step 4: Commit
git add demo/scripts/flow-3-federation.sh
git commit -m "feat(demo): add flow-3-federation.sh (River City + BrightWorks equipment agreement)"
Task 8: Flow 4 — Federation Reporting (Optional Capstone)
Finger Lakes CDN shows cross-federation visibility to a funder, without controlling any coop.
Files:
- Create:
demo/scripts/flow-4-reporting.sh
This is a lighter script — mostly read-only queries against the CDN node showing governance evidence and settlement summaries.
#!/usr/bin/env bash
# Flow 4: Federation Oversight and Institutional Reporting (optional capstone)
# Audience: funders, grant reviewers, ecosystem orgs
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/lib-demo-ports.sh"
BLUE='\033[0;34m'; GREEN='\033[0;32m'; NC='\033[0m'
narrate() { echo -e "\n${BLUE}▶${NC} $*\n"; }
result() { echo -e " ${GREEN}✓${NC} $*"; }
demo_ports_up
demo_wait_ready
narrate "Finger Lakes CDN — Federation Grant Report"
echo " A funder asks: 'Show us that governance and spending are linked.'"
echo " The CDN can produce this without having control over any member coop."
echo
# Show governance activity across federation
narrate "Step 1: Governance activity summary"
demo_curl "$FINGERLAKES_URL/v1/federation/governance-summary" GET "" "$FINGERLAKES_TOKEN" | python3 -m json.tool
result "Proposals, votes, approvals — across all member coops"
# Show settlements
narrate "Step 2: Cross-coop settlement summary"
demo_curl "$FINGERLAKES_URL/v1/federation/settlements" GET "" "$FINGERLAKES_TOKEN" | python3 -m json.tool
result "Settlement records with provenance — exportable for grant reporting"
echo
echo "================================================================"
echo " FLOW 4 COMPLETE: Institutional trust without centralization"
echo " The CDN can report. It cannot command."
echo "================================================================"
Follow same steps: fill in real endpoints, test, commit.
git add demo/scripts/flow-4-reporting.sh
git commit -m "feat(demo): add flow-4-reporting.sh (Finger Lakes CDN federation audit view)"
Task 9: Presenter Runbook
Files:
- Modify:
docs/demo/DEMO_SCRIPT.md(replace existing with federation version)
Step 1: Read the existing file first
wc -l /home/ubuntu/projects/icn/docs/demo/DEMO_SCRIPT.md
Step 2: Replace with federation runbook
The new runbook should cover:
# ICN Federation Demo — Presenter Runbook
**Versions:** 5 min (lightning) / 12 min (standard) / 20 min (full)
## Pre-Demo Setup (2 min)
./demo/scripts/reseed-federation-demo.sh
# Verify: all four coops show "ready"
## Opening (all versions)
"Cooperatives are supposed to be more democratic than firms.
But in practice, they often inherit the same old problems..."
## 5-Minute Version
- Opening (1 min)
- Flow 1A: roof repair governance + provenance (3 min)
- Closing: "This is running on four separate nodes, each
coop controls its own data" (1 min)
## 12-Minute Version
- Opening (1 min)
- Flow 1A (4 min)
- Flow 2: patronage legibility (4 min)
- Flow 3: federation clip (2 min)
- Closing (1 min)
## 20-Minute Version
- Opening (2 min)
- Flow 1A (5 min)
- Flow 2 (5 min)
- Flow 3 (5 min)
- Flow 4 optional (2 min)
- Closing / Q&A setup (1 min)
## Audience Pivots
[section per audience type with 1 sentence reframe]
## Fallback Plan
[prerecorded video link / static screenshots]
## Reset
./demo/scripts/reseed-federation-demo.sh
Write the full version of each section (not just this skeleton).
Step 3: Commit
git add docs/demo/DEMO_SCRIPT.md
git commit -m "docs(demo): replace demo script with federation runbook (5/12/20 min variants)"
Task 10: Self-Serve Quickstart
Files:
- Create:
demo/SELF_SERVE.md
This is the handoff document. A stranger should be able to run the demo from this file alone.
Sections:
- What this demonstrates (3 sentences)
- Prerequisites (kubectl, cluster access)
- Start (
./demo/scripts/reseed-federation-demo.sh) - Run the flows (one command each, expected output description)
- What you're seeing (one paragraph per flow)
- Troubleshooting (port-forward stalls, token errors, reseed)
git add demo/SELF_SERVE.md
git commit -m "docs(demo): add self-serve quickstart (handoff-survivable)"
Task 11: Flow 1B Upgrade (Gated on PR #1327)
Do not start this task until PR #1327 is merged to main.
Files:
- Modify:
demo/scripts/flow-1-governance.sh - Modify:
docs/demo/DEMO_SCRIPT.md(upgrade proof language)
Step 1: Confirm #1327 is merged
gh pr view 1327 --json state,mergedAt | python3 -m json.tool
# Expected: state: "MERGED"
Step 2: Add ExecutionReceiptGate call to flow-1 script
After the treasury action step, add:
narrate "Step 5: Execution receipt — governance-to-execution proof"
RECEIPT=$(demo_curl "$HARBOR_URL/v1/execution/receipts?proposal=${PROPOSAL_ID}" GET "" "$HARBOR_TOKEN")
echo "$RECEIPT" | python3 -m json.tool
result "Execution receipt bound to approved governance event"
aside "This action could not have run without the approved proposal"
Step 3: Update narrative footer in the script
Remove the NOTE: The final receipt-gated execution proof is being finalized... block.
Replace with:
================================================================
FLOW 1B COMPLETE: Governance to execution proof
The treasury action is cryptographically bound to the approved
governance event via ExecutionReceiptGate.
================================================================
Step 4: Update presenter narration in DEMO_SCRIPT.md
Find the Flow 1 section and update to the stronger claim:
This proposal was approved through cooperative governance. The resulting action is not merely recorded after the fact — it is bound through the execution receipt path, so the system can prove the action corresponds to approved governance.
Step 5: Test
./demo/scripts/flow-1-governance.sh 2>&1 | grep -E "(COMPLETE|ERROR|✓|receipt)"
Expected: FLOW 1B COMPLETE in output, receipt data in results.
Step 6: Commit
git add demo/scripts/flow-1-governance.sh docs/demo/DEMO_SCRIPT.md
git commit -m "feat(demo): upgrade Flow 1 to 1B — ExecutionReceiptGate proof (PR #1327)"
Verification Checklist
Run these before calling the demo presentation-ready:
# 1. Reseed works cleanly
./demo/scripts/reseed-federation-demo.sh
echo "Exit: $?"
# 2. Flow 1 runs without errors
./demo/scripts/flow-1-governance.sh 2>&1 | tail -5
# 3. Flow 2 runs without errors
./demo/scripts/flow-2-patronage.sh 2>&1 | tail -5
# 4. Flow 3 runs without errors
./demo/scripts/flow-3-federation.sh 2>&1 | tail -5
# 5. Run all three in sequence (simulates full 20-min demo)
./demo/scripts/reseed-federation-demo.sh && \
./demo/scripts/flow-1-governance.sh && \
./demo/scripts/flow-2-patronage.sh && \
./demo/scripts/flow-3-federation.sh
echo "Full run exit: $?"
# 6. Reseed and run again (determinism check)
./demo/scripts/reseed-federation-demo.sh && \
./demo/scripts/flow-1-governance.sh 2>&1 | grep COMPLETE
All checks must pass before the demo is considered presentation-ready.
What to Watch Out For
Port-forward instability: kubectl port-forward can drop under load. If a flow dies mid-way, demo_ports_down && demo_ports_up && demo_wait_ready resets cleanly. Add this as a fallback step in the runbook.
Token expiry: JWTs expire. The reseed script should regenerate tokens as part of setup. Don't hardcode tokens in scripts.
Non-deterministic IDs: If proposal IDs are UUIDs generated fresh each run, the flow scripts must dynamically extract them from API responses. Do not hardcode IDs.
API endpoint drift: If the gateway API changes, update demo/docs/api-map.md first, then update the flow scripts. Keep the map as the source of truth.