From 676036a7d89e746dfce265d7f0fe9baf5eaf6355 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Mon, 16 Feb 2026 14:52:02 +0800 Subject: [PATCH 1/3] docs: remove all 'smart contract' references, use vague on-chain language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - overview.md: 'smart contracts' → 'on-chain logic' - portability-and-scaling.md: 'smart contracts' → 'on-chain tokens' - planned-funding-and-tokenization.md: rewritten to remove smart contract language throughout, expanded with freezing patterns and cross-layer example --- documentation/pages/architecture/overview.md | 26 ++++++++++++++++++- .../infrastructure/portability-and-scaling.md | 4 +-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/documentation/pages/architecture/overview.md b/documentation/pages/architecture/overview.md index 0e40ec1..d0fcf5e 100644 --- a/documentation/pages/architecture/overview.md +++ b/documentation/pages/architecture/overview.md @@ -45,6 +45,30 @@ A typical data flow: a user writes a record to their PDS → the PDS signs it an ![Data flow through ATProto](/images/architecture-dataflow.svg) +## Security Model + +ATProto's cryptographic properties make hypercerts tamper-evident and auditable without a central authority. + +#### Signed repositories + +Every PDS repository is a Merkle tree signed by the user's DID signing key. Any modification to a record changes the Merkle root, invalidating the signature. This means you can verify a record came from a specific DID, detect if a record was altered after creation, and audit the entire history of a repository. + +#### Strong references + +When one record references another — for example, an evaluation referencing an activity claim — the reference includes both the AT-URI and the CID (content hash). If the referenced record is modified, its CID changes and the mismatch is detectable. This makes cross-record references tamper-evident. + +#### Identity verification + +DIDs are cryptographically verifiable. A `did:plc` identifier resolves via the [PLC directory](https://plc.directory) to a DID document containing the public key for signature verification, the user's current PDS, and their handle. Always verify the DID matches the expected identity before trusting a record. + +#### Data integrity chain + +These properties combine into an auditable chain: + +1. Alice creates an activity claim. Her PDS signs the repository, producing CID `bafyA`. +2. Bob evaluates Alice's claim, referencing `{ uri: "at://alice/...", cid: "bafyA" }`. +3. Anyone can verify: Alice's signature proves she created the claim, Bob's signature proves he created the evaluation, and the CID proves Bob evaluated the exact version Alice published. + ## Ownership Layer (Planned) The ownership layer is not yet implemented. The planned design freezes ATProto records and anchors them on-chain before funding, ensuring funders know exactly what they are paying for. For the full planned design — including anchoring, tokenization, and funding mechanisms — see [Planned: Funding & Tokenization](/architecture/planned-funding-and-tokenization). @@ -69,7 +93,7 @@ Storing rich data on-chain is expensive. A single activity claim with evidence a #### Why Not Fully Off-Chain? -Mutable records are fine for collaboration, but funding requires immutability. Without on-chain anchoring, there's no way to freeze a hypercert's state and guarantee that the claim a funder evaluates is the same claim they end up funding. Additionally, funding mechanisms like retroactive public goods funding require smart contracts to distribute funds according to rules. See [Planned: Funding & Tokenization](/architecture/planned-funding-and-tokenization) for the planned freeze-then-fund design. +Mutable records are fine for collaboration, but funding requires immutability. Without on-chain anchoring, there's no way to freeze a hypercert's state and guarantee that the claim a funder evaluates is the same claim they end up funding. Additionally, funding mechanisms like retroactive public goods funding require on-chain logic to distribute funds according to rules. See [Planned: Funding & Tokenization](/architecture/planned-funding-and-tokenization) for the planned freeze-then-fund design. #### Why ATProto Over IPFS, Ceramic, or Other Alternatives? diff --git a/documentation/pages/getting-started/infrastructure/portability-and-scaling.md b/documentation/pages/getting-started/infrastructure/portability-and-scaling.md index 57afeb6..e2b0552 100644 --- a/documentation/pages/getting-started/infrastructure/portability-and-scaling.md +++ b/documentation/pages/getting-started/infrastructure/portability-and-scaling.md @@ -47,6 +47,6 @@ ATProto records are public by default. Anyone can read your activity claims, eva ATProto is adding support for encrypted records. In the future, you'll be able to create private claims visible only to specific DIDs. For example, a contributor might share sensitive evidence with an evaluator without making it public. -#### Access control via smart contracts (planned) +#### Access control via on-chain tokens (planned) -In the planned design, on-chain tokens could have access control logic — for example, granting read access to private ATProto records only to token holders. This is a potential future feature. See [Planned: Funding & Tokenization](/architecture/planned-funding-and-tokenization) for details. +In the planned design, on-chain tokens could enforce access control — for example, granting read access to private ATProto records only to token holders. This is a potential future feature. See [Planned: Funding & Tokenization](/architecture/planned-funding-and-tokenization) for details. From 1799a0cb7eaafe65c2f40eb5d075d459e2b11d14 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Mon, 16 Feb 2026 14:52:15 +0800 Subject: [PATCH 2/3] docs: merge error-handling and testing-security into testing-and-deployment, move security model to architecture --- documentation/lib/navigation.js | 3 +- .../pages/reference/error-handling.md | 267 +--------------- .../pages/reference/testing-and-deployment.md | 284 ++++++++++++++++++ .../pages/reference/testing-and-security.md | 255 +--------------- 4 files changed, 289 insertions(+), 520 deletions(-) create mode 100644 documentation/pages/reference/testing-and-deployment.md diff --git a/documentation/lib/navigation.js b/documentation/lib/navigation.js index 57a967c..2e36231 100644 --- a/documentation/lib/navigation.js +++ b/documentation/lib/navigation.js @@ -59,8 +59,7 @@ export const navigation = [ { title: 'Hypercerts Lexicons', path: '/lexicons/hypercerts-lexicons' }, ], }, - { title: 'Error Handling & Constraints', path: '/reference/error-handling' }, - { title: 'Testing & Security', path: '/reference/testing-and-security' }, + { title: 'Testing & Deployment', path: '/reference/testing-and-deployment' }, { title: 'Glossary', path: '/reference/glossary' }, { title: 'FAQ', path: '/reference/faq' }, ], diff --git a/documentation/pages/reference/error-handling.md b/documentation/pages/reference/error-handling.md index 298ee18..2739ff5 100644 --- a/documentation/pages/reference/error-handling.md +++ b/documentation/pages/reference/error-handling.md @@ -1,270 +1,7 @@ --- title: Error Handling & Constraints -description: Common errors, validation rules, and how to handle them. --- -## Overview +# Error Handling & Constraints -When creating or updating records on a PDS, various errors can occur. This page documents common error scenarios and how to handle them. - ---- - -## Record Validation Errors - -Errors occur when a record does not match its lexicon schema. - -| Error Scenario | Cause | Fix | -|----------------|-------|-----| -| Missing required field | Creating an activity claim without `title` or `startDate` | Include all required fields in the record | -| Invalid field type | Passing a number where a string is expected | Ensure field types match the lexicon definition | -| String length violation | String exceeds `maxLength` (in bytes) or `maxGraphemes` (in Unicode grapheme clusters) | Truncate or validate string length before submission | -| Array length violation | Array exceeds `maxLength` on array fields | Reduce array size to meet constraints | -| Invalid datetime format | Datetime not in ISO 8601 format | Use ISO 8601 format: `2024-01-15T10:30:00Z` | -| Invalid strong reference | Missing `uri` or `cid` in strong reference | Include both `uri` and `cid` fields | - -**Example: Missing required field** - -```typescript -// ❌ Error: missing required fields -const claim = { - description: "Built a community garden", - // Missing: title, startDate -}; - -// ✅ Correct -const claim = { - title: "Community Garden Project", - description: "Built a community garden", - startDate: "2024-01-01T00:00:00Z", -}; -``` - -**Example: Invalid datetime format** - -```typescript -// ❌ Error: invalid format -const claim = { - title: "Project", - startDate: "01/15/2024", // Wrong format -}; - -// ✅ Correct -const claim = { - title: "Project", - startDate: "2024-01-15T00:00:00Z", // ISO 8601 -}; -``` - -**Example: Invalid strong reference** - -```typescript -// ❌ Error: missing cid -const evidence = { - claim: { - uri: "at://did:plc:abc123/org.hypercerts.activityClaim/xyz", - // Missing: cid - }, -}; - -// ✅ Correct -const evidence = { - claim: { - uri: "at://did:plc:abc123/org.hypercerts.activityClaim/xyz", - cid: "bafyreiabc123...", - }, -}; -``` - ---- - -## Blob Constraints - -Size limits for uploaded blobs vary by type. - -| Blob Type | Maximum Size | Used For | -|-----------|--------------|----------| -| `smallBlob` | 10 MB | General attachments | -| `largeBlob` | 100 MB | Large documents, datasets | -| `smallImage` | 5 MB | Thumbnails, icons | -| `largeImage` | 10 MB | High-resolution images | - -**What happens when limits are exceeded:** -- The PDS rejects the blob upload -- You receive a validation error indicating the size limit -- The record creation/update fails - -**Solution:** Compress images, split large files, or use external storage with links. - ---- - -## Authentication Errors - -Common authentication issues and resolutions. - -| Error | Cause | Resolution | -|-------|-------|------------| -| Invalid credentials | Wrong username or password | Verify credentials and retry | -| Expired session | Session token has expired | Refresh the session or re-authenticate | -| Insufficient permissions | User lacks permission for the operation | Ensure user has appropriate access rights | -| Missing authentication | Request made without credentials | Include authentication token in request | - -**Refreshing sessions:** - -```typescript -try { - await agent.createRecord({ /* ... */ }); -} catch (error) { - if (error.message.includes('expired')) { - await agent.resumeSession(sessionData); - await agent.createRecord({ /* ... */ }); // Retry - } -} -``` - ---- - -## Reference Errors - -Issues with strong references between records. - -| Error | Cause | Resolution | -|-------|-------|------------| -| Referenced record does not exist | URI points to non-existent record | Verify the record exists before referencing | -| CID mismatch | Record was updated since reference was created | Fetch the latest CID and update the reference | -| Cross-PDS resolution failure | Referenced record is on an unreachable PDS | Ensure PDS is accessible or use local references | - -**Example: Handling CID mismatch** - -```typescript -// Fetch the latest version of the record -const latestRecord = await agent.getRecord({ - repo: 'did:plc:abc123', - collection: 'org.hypercerts.activityClaim', - rkey: 'xyz', -}); - -// Use the current CID -const evidence = { - claim: { - uri: latestRecord.uri, - cid: latestRecord.cid, // Current CID - }, -}; -``` - ---- - -## Rate Limits & PDS Constraints - -Operational limits imposed by PDS implementations. - -{% callout type="warning" %} -Specific limits depend on the PDS implementation. Always check your PDS documentation for exact values. -{% /callout %} - -| Constraint | Description | Handling | -|------------|-------------|----------| -| Rate limits | Maximum requests per time window | Implement exponential backoff and retry logic | -| Repository size | Total storage per user repository | Monitor usage, archive old records | -| Concurrent operations | Maximum simultaneous requests | Queue operations, process sequentially | - -**Retry with exponential backoff:** - -```typescript -async function createWithRetry(agent, record, maxRetries = 3) { - for (let i = 0; i < maxRetries; i++) { - try { - return await agent.createRecord(record); - } catch (error) { - if (error.message.includes('rate limit') && i < maxRetries - 1) { - const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s - await new Promise(resolve => setTimeout(resolve, delay)); - } else { - throw error; - } - } - } -} -``` - ---- - -## Best Practices - -General error handling recommendations. - -**1. Validate client-side before submission** - -```typescript -function validateClaim(claim) { - if (!claim.title || claim.title.length === 0) { - throw new Error('Title is required'); - } - if (!claim.startDate) { - throw new Error('Start date is required'); - } - // Validate ISO 8601 format - if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(claim.startDate)) { - throw new Error('Start date must be in ISO 8601 format'); - } -} -``` - -**2. Use try/catch around all API calls** - -```typescript -try { - const result = await agent.createRecord({ - repo: agent.session.did, - collection: 'org.hypercerts.activityClaim', - record: claim, - }); - console.log('Created:', result.uri); -} catch (error) { - console.error('Failed to create claim:', error.message); - // Handle specific error types - if (error.message.includes('validation')) { - // Show validation errors to user - } else if (error.message.includes('auth')) { - // Prompt re-authentication - } -} -``` - -**3. Log errors with context** - -```typescript -function logError(operation, record, error) { - console.error({ - operation, - collection: record.collection, - timestamp: new Date().toISOString(), - error: error.message, - stack: error.stack, - }); -} - -try { - await agent.createRecord(params); -} catch (error) { - logError('createRecord', params, error); - throw error; -} -``` - -**4. Provide user-friendly error messages** - -```typescript -function getUserMessage(error) { - if (error.message.includes('validation')) { - return 'Please check that all required fields are filled correctly.'; - } - if (error.message.includes('rate limit')) { - return 'Too many requests. Please wait a moment and try again.'; - } - if (error.message.includes('auth')) { - return 'Your session has expired. Please sign in again.'; - } - return 'An unexpected error occurred. Please try again.'; -} -``` +This content has moved to [Testing & Deployment](/reference/testing-and-deployment). diff --git a/documentation/pages/reference/testing-and-deployment.md b/documentation/pages/reference/testing-and-deployment.md new file mode 100644 index 0000000..06d4c92 --- /dev/null +++ b/documentation/pages/reference/testing-and-deployment.md @@ -0,0 +1,284 @@ +--- +title: Testing & Deployment +description: Test your integration, understand record constraints, and go live with confidence. +--- + +# Testing & Deployment + +This page covers how to test your Hypercerts integration locally, the validation rules and constraints your records must satisfy, privacy considerations, and a checklist for going live. + +--- + +## Local development + +### Set up a test PDS + +Run a local PDS to avoid polluting production data. Self-host a test instance using the [ATProto PDS distribution](https://github.com/bluesky-social/pds) and follow the [ATProto self-hosting guide](https://atproto.com/guides/self-hosting). + +Point your SDK to the local instance instead of production: + +```typescript +import { createATProtoSDK } from "@hypercerts-org/sdk-core"; + +const sdk = createATProtoSDK({ + service: "http://localhost:2583", // Local PDS + oauth: { + clientId: "https://your-app.com/client-metadata.json", + redirectUri: "https://your-app.com/callback", + scope: "atproto", + }, +}); +``` + +### Use test identities + +Create dedicated test accounts — never use production identities for testing. When running a local PDS, you can create accounts with any handle. Each test identity gets its own DID and repository, isolating test data from production. + +### Create and verify a test record + +Create a record with the SDK, then read it back to confirm it was stored correctly: + +```typescript +const session = await sdk.callback(callbackParams); +const repo = sdk.getRepository(session); + +// Create a test hypercert +const result = await repo.hypercerts.create({ + title: "Test: reforestation project Q1 2026", + description: "Integration test — safe to delete.", + workScope: "test", + workTimeframeFrom: "2026-01-01", + workTimeframeTo: "2026-03-31", + rights: { + name: "Public Display", + type: "display", + description: "Right to publicly display this contribution", + }, +}); + +console.log("Created:", result.uri); +console.log("CID:", result.cid); +``` + +The returned `cid` is a content hash. If the record changes, the CID changes — this is how you verify data integrity. + +### Clean up test data + +Delete test records when you're done to keep your repository clean: + +```typescript +await repo.hypercerts.delete(result.uri); +``` + +Deletion removes the record from your PDS. Cached copies may persist in indexers temporarily. + +--- + +## Record constraints + +When creating or updating records, the PDS validates them against the lexicon schema. Records that violate constraints are rejected. + +### Required fields + +Every record type has required fields. The PDS returns a validation error if any are missing. + +```typescript +// ❌ Rejected — missing title and workTimeframeFrom +await repo.hypercerts.create({ + description: "Built a community garden", +}); + +// ✅ Accepted +await repo.hypercerts.create({ + title: "Community Garden Project", + description: "Built a community garden", + workScope: "Urban agriculture", + workTimeframeFrom: "2026-01-01", + workTimeframeTo: "2026-06-30", + rights: { + name: "Public Display", + type: "display", + description: "Right to publicly display this contribution", + }, +}); +``` + +### Datetime format + +All datetime fields must use ISO 8601 format. + +```typescript +// ❌ Rejected +workTimeframeFrom: "01/15/2026" + +// ✅ Accepted +workTimeframeFrom: "2026-01-15T00:00:00Z" +``` + +### Strong references + +When one record references another (e.g., an evaluation referencing an activity claim), the reference must include both the AT-URI and the CID. This makes the reference tamper-evident. + +```typescript +// ❌ Rejected — missing cid +const evaluation = { + activity: { + uri: "at://did:plc:abc123/org.hypercerts.claim.activity/3k7", + }, +}; + +// ✅ Accepted +const evaluation = { + activity: { + uri: "at://did:plc:abc123/org.hypercerts.claim.activity/3k7", + cid: "bafyreiabc123...", + }, +}; +``` + +If the referenced record is updated after you create the reference, the CID will no longer match. Fetch the latest version to get the current CID: + +```typescript +const latest = await repo.hypercerts.get( + "at://did:plc:abc123/org.hypercerts.claim.activity/3k7" +); + +const evaluation = { + activity: { + uri: latest.uri, + cid: latest.cid, + }, +}; +``` + +### String and array limits + +Lexicon schemas define maximum lengths for strings (in bytes and Unicode grapheme clusters) and arrays. Check the [lexicon reference](/lexicons/hypercerts-lexicons) for specific limits on each field. + +### Blob uploads + +Blobs (images, documents, evidence files) are uploaded to the PDS separately from records. Size limits depend on the PDS implementation — check your PDS documentation for exact values. + +{% callout type="note" %} +If your evidence files are too large for blob upload, store them externally (e.g., on IPFS or a public URL) and reference them by URI in the evidence record. +{% /callout %} + +### Validation error summary + +| Error | Cause | Fix | +|-------|-------|-----| +| Missing required field | Record omits a field the lexicon marks as required | Include all required fields — see the [lexicon reference](/lexicons/hypercerts-lexicons) | +| Invalid datetime | Datetime not in ISO 8601 format | Use format: `2026-01-15T00:00:00Z` | +| Invalid strong reference | Reference missing `uri` or `cid` | Include both fields — fetch the latest CID if needed | +| String too long | String exceeds `maxLength` or `maxGraphemes` | Truncate or validate before submission | +| Array too long | Array exceeds `maxLength` | Reduce array size | +| Blob too large | File exceeds PDS size limit | Compress, split, or use external storage with a URI | + +--- + +## Rate limits + +PDS implementations impose rate limits on API requests. Specific limits vary by PDS — check your provider's documentation. + +If you hit a rate limit, retry with exponential backoff: + +```typescript +async function withRetry(fn, maxRetries = 3) { + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + return await fn(); + } catch (error) { + const isRateLimit = error.message?.includes("rate limit"); + const hasRetriesLeft = attempt < maxRetries - 1; + if (isRateLimit && hasRetriesLeft) { + const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s + await new Promise((resolve) => setTimeout(resolve, delay)); + } else { + throw error; + } + } + } +} + +// Usage +const result = await withRetry(() => + repo.hypercerts.create({ /* ... */ }) +); +``` + +--- + +## Privacy + +### Records are public by default + +{% callout type="warning" %} +All ATProto records are public. Anyone can read records from any PDS. Never store sensitive personal data in hypercert records. +{% /callout %} + +**Include in records:** +- Public work descriptions (e.g., "Planted 500 trees in Borneo") +- Aggregated impact metrics (e.g., "Reduced CO₂ by 50 tons") +- Public contributor identities (DIDs, handles) +- Links to public evidence (URLs, IPFS CIDs) + +**Keep off-protocol:** +- Personal contact information (email, phone, address) +- Proprietary methodologies or trade secrets +- Participant consent forms or private agreements +- Raw data containing PII (personally identifiable information) + +Store sensitive data in a private database and reference it by ID if needed. + +### Deletion and GDPR + +You can delete records from your PDS at any time. However: + +- Indexers (like Hypergoat) may cache records and take time to update +- Other users may have already fetched and stored copies +- The deletion event itself is visible in your repository history + +If you accidentally publish PII, delete the record immediately and contact indexer operators to request cache purging. + +--- + +## Authentication in production + +Use OAuth for production applications. OAuth lets users authorize your app without sharing credentials. See the [Quickstart](/getting-started/quickstart) for the SDK OAuth setup and the [ATProto OAuth spec](https://atproto.com/specs/oauth) for the full protocol details. + +{% callout type="warning" %} +**Never commit credentials to version control.** Use `.env` files (added to `.gitignore`) for local development and secret management tools (Vercel env vars, AWS Secrets Manager, etc.) for production. +{% /callout %} + +```bash +# .env (never commit this file) +ATPROTO_CLIENT_SECRET=your-client-secret-here +``` + +```typescript +const secret = process.env.ATPROTO_CLIENT_SECRET; +if (!secret) throw new Error("ATPROTO_CLIENT_SECRET not set"); +``` + +--- + +## Going live checklist + +Before deploying to production: + +- [ ] **Tested record creation and retrieval** — Created and read back at least one hypercert successfully in a test environment. +- [ ] **Validated records against lexicon schemas** — All required fields present, datetimes in ISO 8601, strong references include both URI and CID. +- [ ] **Verified your DID and handle** — Confirmed your DID resolves correctly and your handle matches your intended identity. +- [ ] **Stored credentials securely** — No secrets in source code. Environment variables or secret management in production. +- [ ] **Reviewed records for accidental PII** — No sensitive personal data in any record fields. +- [ ] **Tested cross-PDS references** — If your app references records from other PDSs, verified those references resolve correctly. +- [ ] **Implemented error handling** — Your app handles validation errors, rate limits, and network failures gracefully. + +--- + +## See also + +- [Quickstart](/getting-started/quickstart) — create your first hypercert +- [Lexicon reference](/lexicons/hypercerts-lexicons) — field definitions and constraints for each record type +- [Architecture Overview](/architecture/overview) — how the protocol stack fits together, including the security model +- [Data Flow & Lifecycle](/architecture/data-flow-and-lifecycle) — how records move through the system diff --git a/documentation/pages/reference/testing-and-security.md b/documentation/pages/reference/testing-and-security.md index ae528b6..f1b7045 100644 --- a/documentation/pages/reference/testing-and-security.md +++ b/documentation/pages/reference/testing-and-security.md @@ -1,258 +1,7 @@ --- title: Testing & Security -description: How to test your integration and understand the security model. --- -# {% $markdoc.frontmatter.title %} +# Testing & Security -Test your hypercerts integration locally before going live, and understand the cryptographic guarantees that protect your data. - ---- - -## Testing Your Integration - -### Local Development - -Run a local PDS for testing to avoid polluting production data. - -{% callout %} -**Recommended approach**: Self-host a test PDS using the [ATProto PDS distribution](https://github.com/bluesky-social/pds). This gives you full control over test data and allows offline development. -{% /callout %} - -Follow the [ATProto self-hosting guide](https://atproto.com/guides/self-hosting) to spin up a local instance. Point your client to `http://localhost:2583` (default PDS port) instead of `https://bsky.social`. - -### Test Identities - -Create throwaway DIDs for testing—never use production identities. - -When running a local PDS, you can create test accounts with any handle. For testing against public infrastructure, create a dedicated test account with a handle like `yourname-test.bsky.social`. - -Each test identity gets its own DID and repository. This isolation prevents test records from appearing in your production feed. - -### Sandbox Pattern - -Tag test records so they're easily identifiable and can be cleaned up later. - -Add a `workScope` tag like `"test"` or `"sandbox"` to activity claims created during testing: - -```typescript -const record = { - $type: 'org.hypercerts.activityClaim', - workScope: ['test', 'carbon-offset'], - impactScope: ['climate'], - // ... other fields -}; -``` - -This makes it trivial to filter test data from production queries. - -### Verifying Records - -Read back records after creation to confirm they match expectations. - -```typescript -import { BskyAgent } from '@atproto/api'; - -const agent = new BskyAgent({ service: 'https://bsky.social' }); -await agent.login({ identifier: 'alice.bsky.social', password: 'app-password' }); - -// Create a record -const { uri, cid } = await agent.com.atproto.repo.createRecord({ - repo: agent.session.did, - collection: 'org.hypercerts.activityClaim', - record: { - $type: 'org.hypercerts.activityClaim', - workScope: ['test'], - impactScope: ['education'], - workTimeframe: { start: '2024-01-01T00:00:00Z', end: '2024-12-31T23:59:59Z' }, - createdAt: new Date().toISOString(), - }, -}); - -// Read it back -const { data } = await agent.com.atproto.repo.getRecord({ - repo: agent.session.did, - collection: 'org.hypercerts.activityClaim', - rkey: uri.split('/').pop(), -}); - -// Verify fields -console.assert(data.value.workScope.includes('test'), 'workScope mismatch'); -console.assert(data.value.impactScope.includes('education'), 'impactScope mismatch'); -console.assert(data.cid === cid, 'CID mismatch'); -``` - -The returned `cid` is a content hash—if the record changes, the CID changes too. - -### Cleanup - -Delete test records when you're done to keep your repository clean. - -```typescript -await agent.com.atproto.repo.deleteRecord({ - repo: agent.session.did, - collection: 'org.hypercerts.activityClaim', - rkey: uri.split('/').pop(), -}); -``` - -Deletion is permanent. The record disappears from your PDS and won't appear in future queries. Cached copies may persist in indexers temporarily. - ---- - -## Security Model - -### Signed Repositories - -Every PDS repository is a signed Merkle tree, making records tamper-evident. - -Your DID's signing key cryptographically signs the repository root. Any modification to a record changes the Merkle root, invalidating the signature. This means: - -- You can verify a record came from a specific DID -- You can detect if a record was altered after creation -- Third parties can audit the entire history of a repository - -### Strong References - -References include a CID (content hash), so you can verify the referenced record hasn't changed. - -When an evaluation references an activity claim, it stores both the AT URI and the CID: - -```typescript -{ - $type: 'org.hypercerts.evaluation', - subject: { - uri: 'at://did:plc:abc123/org.hypercerts.activityClaim/xyz789', - cid: 'bafyreiabc...' - }, - // ... -} -``` - -If someone modifies the activity claim, its CID changes. Your evaluation still points to the original version, and you can detect the mismatch. - -### Identity Verification - -DIDs are cryptographically verifiable, and handles can be verified via DNS or the PLC directory. - -- **did:plc**: Resolved via the [PLC directory](https://plc.directory). The DID document contains the public key for signature verification, the user's current PDS, and their handle. - -Always verify the DID matches the expected identity before trusting a record. - -### Data Integrity - -Signed repos + CID references create an auditable chain of claims and evaluations. - -Example flow: - -1. Alice creates an activity claim. Her PDS signs the repo, producing CID `bafyA`. -2. Bob evaluates Alice's claim, referencing `{ uri: "at://alice/...", cid: "bafyA" }`. -3. Anyone can verify: - - Alice's signature proves she created the claim - - Bob's signature proves he created the evaluation - - The CID proves Bob evaluated the exact version Alice published - -This chain of cryptographic proofs makes hypercerts auditable without a central authority. - ---- - -## Authentication Best Practices - -### App Passwords - -Use app passwords, never main passwords, in code. - -App passwords are scoped tokens that can be revoked without changing your main password. Generate one in your Bluesky settings under "App Passwords". - -```typescript -await agent.login({ - identifier: 'alice.bsky.social', - password: process.env.BSKY_APP_PASSWORD, // App password, not main password -}); -``` - -### Rotation - -Rotate app passwords regularly—at least every 90 days. - -Set a calendar reminder to generate a new app password and update your environment variables. Revoke the old password immediately after deploying the new one. - -### Storage - -Store credentials in environment variables, never in source code. - -{% callout type="warning" %} -**Never commit credentials to version control.** Use `.env` files (added to `.gitignore`) for local development and secret management tools (AWS Secrets Manager, Vercel env vars, etc.) for production. -{% /callout %} - -```bash -# .env (never commit this file) -BSKY_APP_PASSWORD=your-app-password-here -``` - -```typescript -// Load from environment -const password = process.env.BSKY_APP_PASSWORD; -if (!password) throw new Error('BSKY_APP_PASSWORD not set'); -``` - -### OAuth for Production - -For production applications, use OAuth instead of app passwords. - -OAuth lets users authorize your app without sharing credentials. See the [ATProto OAuth guide](https://atproto.com/specs/oauth) for implementation details. This is especially important for multi-user applications. - ---- - -## Privacy Considerations - -### Public by Default - -All ATProto records are public—do not store sensitive personal data in hypercert records. - -{% callout type="warning" %} -**Records are public by default.** Anyone can read records from any PDS. Never include passwords, private keys, health data, financial details, or other sensitive information in hypercert fields. -{% /callout %} - -### What to Include vs. What to Keep Off-Protocol - -**Include in hypercert records:** -- Public work descriptions (e.g., "Planted 100 trees in Central Park") -- Aggregated impact metrics (e.g., "Reduced CO₂ by 50 tons") -- Public contributor identities (DIDs, handles) -- Links to public evidence (URLs, IPFS CIDs) - -**Keep off-protocol:** -- Personal contact information (email, phone, address) -- Proprietary methodologies or trade secrets -- Participant consent forms or private agreements -- Raw data containing PII (personally identifiable information) - -Store sensitive data in a private database and reference it by ID if needed. - -### GDPR Considerations - -Records can be deleted from your PDS, but cached copies may persist in indexers. - -ATProto supports the right to deletion: you can call `deleteRecord` to remove a record from your repository. However: - -- Indexers (like AppViews) may cache records and take time to update -- Other users may have already fetched and stored copies -- The deletion event itself is public (visible in your repo history) - -If you accidentally publish PII, delete the record immediately and contact major indexer operators to request cache purging. - ---- - -## Going Live Checklist - -Before deploying to production, verify: - -- [ ] **Verified your DID and handle are correct** — Confirm your DID resolves and your handle matches your intended identity. -- [ ] **Tested record creation and reading in a sandbox** — Created and retrieved at least one test record successfully. -- [ ] **Confirmed all required fields pass validation** — Your records conform to the lexicon schemas (use the [Hypercerts CLI](https://github.com/hypercerts-org/hypercerts-cli) validator). -- [ ] **Stored credentials securely (env vars, not source)** — No passwords or app passwords in your codebase. -- [ ] **Reviewed records for accidental PII** — Double-checked that no sensitive personal data is included. -- [ ] **Tested cross-PDS references if applicable** — If your app references records from other PDSs, verified those references resolve correctly. - -Once all items are checked, you're ready to create production hypercerts. +This content has moved to [Testing & Deployment](/reference/testing-and-deployment). From 94de3e49099ceb720df5434b17117dfc9d774fb4 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Mon, 16 Feb 2026 14:53:07 +0800 Subject: [PATCH 3/3] beads: close epics docs-390 and docs-yzy --- .beads/issues.jsonl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 33ddde5..78dfc21 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -3,7 +3,7 @@ {"id":"docs-150.2","title":"Sidebar: move chevron to left side, make inline, reduce size to 12px","description":"## Files\n- documentation/components/Sidebar.js (modify)\n\n## What to do\nStripe places the expand/collapse chevron to the LEFT of the link text, inline within the link element. Ours is a separate button on the right side. Also reduce chevron from 16x16 to 12x12 and change nesting indent from 16px increments to 12px.\n\nReplace the NavItem component (lines 18-89) with this version that puts the chevron inline before the text:\n\n```js\nfunction NavItem({ item, currentPath, depth = 0 }) {\n const hasChildren = item.children \u0026\u0026 item.children.length \u003e 0;\n const active = item.path \u0026\u0026 isActive(item.path, currentPath);\n const childActive = hasChildren \u0026\u0026 isChildActive(item, currentPath);\n const [expanded, setExpanded] = useState(childActive || active);\n\n useEffect(() =\u003e {\n if (childActive || active) {\n setExpanded(true);\n }\n }, [childActive, active]);\n\n const handleToggle = (e) =\u003e {\n if (hasChildren) {\n e.preventDefault();\n setExpanded(!expanded);\n }\n };\n\n const paddingLeft = `${12 + depth * 12}px`;\n\n const chevron = hasChildren ? (\n \u003csvg\n className=\"sidebar-chevron\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n transition: \"transform 0.15s ease\",\n }}\n \u003e\n \u003cpath\n d=\"M6 4l4 4-4 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n /\u003e\n \u003c/svg\u003e\n ) : null;\n\n return (\n \u003cli className=\"sidebar-nav-item\"\u003e\n {item.path ? (\n \u003cLink\n href={item.path}\n className={`sidebar-link${active ? \" sidebar-link-active\" : \"\"}${\n childActive ? \" sidebar-link-parent-active\" : \"\"\n }`}\n style={{ paddingLeft }}\n onClick={hasChildren \u0026\u0026 !item.path ? handleToggle : undefined}\n \u003e\n {chevron}\n {item.title}\n \u003c/Link\u003e\n ) : (\n \u003cspan\n className={`sidebar-link sidebar-link-toggle${\n childActive ? \" sidebar-link-parent-active\" : \"\"\n }`}\n style={{ paddingLeft }}\n onClick={handleToggle}\n \u003e\n {chevron}\n {item.title}\n \u003c/span\u003e\n )}\n {hasChildren \u0026\u0026 expanded \u0026\u0026 (\n \u003cul className=\"sidebar-nav-children\"\u003e\n {item.children.map((child) =\u003e (\n \u003cNavItem\n key={child.path || child.title}\n item={child}\n currentPath={currentPath}\n depth={depth + 1}\n /\u003e\n ))}\n \u003c/ul\u003e\n )}\n \u003c/li\u003e\n );\n}\n```\n\nKey changes:\n1. Removed the separate `.sidebar-nav-link-row` div wrapper\n2. Removed the separate `.sidebar-expand-btn` button\n3. Chevron SVG is now inline BEFORE the text inside the link/span\n4. Chevron is 12x12 (was 16x16)\n5. Indent is `12 + depth * 12` (was `16 + depth * 16`)\n6. Non-link parents with children get class `sidebar-link-toggle` and onClick to toggle\n7. Added `sidebar-chevron` class to the SVG for CSS styling\n\n## Test\n```bash\ncd documentation \u0026\u0026 node -e \"\nconst fs = require(\\\"fs\\\");\nconst src = fs.readFileSync(\\\"components/Sidebar.js\\\", \\\"utf8\\\");\nconst hasInlineChevron = src.includes(\\\"sidebar-chevron\\\");\nconst noExpandBtn = !src.includes(\\\"sidebar-expand-btn\\\");\nconst noLinkRow = !src.includes(\\\"sidebar-nav-link-row\\\");\nconst has12px = src.includes(\\\"12 + depth * 12\\\");\nconst has12x12 = src.includes(\\\"width=\\\\\\\"12\\\\\\\"\\\") \u0026\u0026 src.includes(\\\"height=\\\\\\\"12\\\\\\\"\\\");\nif (!hasInlineChevron) { console.error(\\\"FAIL: no sidebar-chevron class\\\"); process.exit(1); }\nif (!noExpandBtn) { console.error(\\\"FAIL: still has sidebar-expand-btn\\\"); process.exit(1); }\nif (!noLinkRow) { console.error(\\\"FAIL: still has sidebar-nav-link-row\\\"); process.exit(1); }\nif (!has12px) { console.error(\\\"FAIL: indent not 12px increments\\\"); process.exit(1); }\nif (!has12x12) { console.error(\\\"FAIL: chevron not 12x12\\\"); process.exit(1); }\nconsole.log(\\\"PASS\\\");\n\"\n```\n\n## Dont\n- Do not change NavSection or the Sidebar export function\n- Do not change the collapse button (sidebar-collapse-btn)\n- Do not touch globals.css (CSS handled separately)\n- Do not change the navigation data import","status":"closed","priority":1,"issue_type":"task","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-14T22:24:05.829993+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-14T22:27:45.00586+13:00","closed_at":"2026-02-14T22:27:45.00586+13:00","close_reason":"d3a98d1 - Sidebar chevron moved to left side, inline, 12px (implemented alongside docs-150.1)","dependencies":[{"issue_id":"docs-150.2","depends_on_id":"docs-150","type":"parent-child","created_at":"2026-02-14T22:24:05.831325+13:00","created_by":"Sharfy Adamantine"}]} {"id":"docs-150.3","title":"Breadcrumbs: lighter separator color, wider spacing","description":"## Files\n- documentation/components/Breadcrumbs.js (modify)\n\n## What to do\nUpdate the breadcrumb separator color and spacing to match Stripe. Currently the separator uses a dark gray; Stripe uses a lighter gray with more spacing.\n\nRead the current Breadcrumbs.js file first. Find the separator span element and update:\n1. The separator character should remain \"/\" \n2. No changes needed in the JS — the color/spacing changes are CSS-only\n\nActually, this task requires NO JS changes. The separator styling is in globals.css. Cancel this task — the CSS mega-task will handle it.\n\n## Test\nN/A — this task should be cancelled\n\n## Dont\nN/A","status":"closed","priority":2,"issue_type":"task","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-14T22:24:15.360221+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-14T22:24:21.845024+13:00","closed_at":"2026-02-14T22:24:21.845027+13:00","dependencies":[{"issue_id":"docs-150.3","depends_on_id":"docs-150","type":"parent-child","created_at":"2026-02-14T22:24:15.361244+13:00","created_by":"Sharfy Adamantine"}]} {"id":"docs-150.4","title":"Mega CSS: all 25 Stripe parity fixes in globals.css","description":"## Files\n- documentation/styles/globals.css (modify)\n\n## What to do\nApply ALL of the following CSS changes to globals.css. Each change is numbered and references the current line. Read the file first to confirm line numbers, then apply all changes.\n\n### Design Token Changes (in :root block, lines 72-136)\n\n1. **Unify heading colors** — Change line 87 `--color-text-heading: #353a44` to `--color-text-heading: #1a1b25` and line 88 `--color-text-title: #21252c` to `--color-text-title: #1a1b25`\n\n2. **Content max-width** — Change line 110 `--content-max-width: 800px` to `--content-max-width: 880px`\n\n3. **TOC width** — Change line 109 `--toc-width: 200px` to `--toc-width: 250px`\n\n### Add responsive sidebar width (after the :root closing brace, ~line 136)\n\n4. **Sidebar responsive** — Add after the `:root` block:\n```css\n@media (min-width: 1400px) {\n :root {\n --sidebar-width: 280px;\n }\n}\n```\n\n### Header Changes (lines 175-221)\n\n5. **Header background** — Change line 181 from `background: rgba(255, 255, 255, 0.95)` to `background: #f6f8fa`. Remove lines 182-183 (`backdrop-filter` and `-webkit-backdrop-filter`).\n\n6. **Logo font-size** — Change line 196 `font-size: 15px` to `font-size: 16px`\n\n### Breadcrumb Changes (lines 223-268)\n\n7. **Breadcrumb font-size** — Change line 235 `font-size: 13px` to `font-size: 14px`\n\n8. **Breadcrumb separator** — Change line 245 `margin: 0 6px` to `margin: 0 8px`. Change line 246 `color: var(--color-text-secondary)` to `color: #a3acba`\n\n### Sidebar Changes (lines 275-439)\n\n9. **Sidebar content padding** — Change line 304 `padding: var(--space-6) 0` to `padding: var(--space-3) 0`\n\n10. **Sidebar section spacing** — Change line 350 `margin-top: var(--space-5)` to `margin-top: var(--space-4)` and line 351 `padding-top: var(--space-5)` to `padding-top: var(--space-4)`\n\n11. **Sidebar section header** — Change the `.sidebar-section-header` rule (lines 362-369):\n```css\n.sidebar-section-header {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-text-secondary);\n padding: var(--space-1) var(--space-4);\n margin-bottom: var(--space-2);\n}\n```\n\n12. **Sidebar link density** — In `.sidebar-link` (lines 384-395), change `padding: 6px var(--space-3)` to `padding: 4px var(--space-2)` and change `border-radius: var(--radius-md)` to `border-radius: var(--radius-sm)`\n\n13. **Remove old sidebar-nav-link-row and sidebar-expand-btn rules** — Delete the `.sidebar-nav-link-row` rule (lines 379-382) and the `.sidebar-expand-btn` rules (lines 420-435). These are no longer used since the chevron is now inline.\n\n14. **Add sidebar-chevron styling** — Add after the `.sidebar-link` rules:\n```css\n.sidebar-chevron {\n flex-shrink: 0;\n margin-right: 4px;\n color: var(--color-text-secondary);\n}\n```\n\n15. **Add sidebar-link-toggle** — Add:\n```css\n.sidebar-link-toggle {\n cursor: pointer;\n}\n```\n\n16. **Sidebar link needs flex for inline chevron** — Add `display: flex; align-items: center;` to `.sidebar-link` (it currently has `display: block`). Change `display: block` to `display: flex` and add `align-items: center;`\n\n17. **Sidebar active link** — Change `.sidebar-link-active` (lines 403-407):\n```css\n.sidebar-link-active {\n color: var(--color-link);\n font-weight: 500;\n background: none;\n border-left: 2px solid var(--color-link);\n margin-left: -2px;\n}\n```\n\n18. **Sidebar parent-of-active** — Change `.sidebar-link-parent-active` (lines 415-418):\n```css\n.sidebar-link-parent-active {\n font-weight: 500;\n color: var(--color-text-primary);\n}\n```\n\n### Content Area Changes (lines 441-451)\n\n19. **Content padding** — Change line 446 `padding: var(--space-10) var(--space-12)` to `padding: var(--space-8) var(--space-10)` (32px top, 40px sides)\n\n### TOC Changes (lines 453-502)\n\n20. **TOC link font-size** — Change line 484 `font-size: 13px` to `font-size: 14px`\n\n21. **TOC link spacing** — Change line 483 `padding: var(--space-1) 0` to `padding: var(--space-2) 0`\n\n22. **TOC title margin** — Change line 474 `margin-bottom: var(--space-2)` to `margin-bottom: var(--space-4)`\n\n23. **Add TOC H3 indentation** — Add after the `.toc-link-active` rule:\n```css\n.toc-link-h3 {\n padding-left: 22px;\n font-size: 13px;\n}\n```\n\n24. **TOC responsive breakpoint** — Change line 878 `@media (max-width: 1100px)` to `@media (max-width: 1200px)`\n\n### Typography Changes (lines 556-705)\n\n25. **H1** — Remove `letter-spacing: -0.02em` from `.layout-content h1` (line 564)\n\n26. **H2** — Change `.layout-content h2` (lines 567-574): `font-size: 24px`, `line-height: 32px` (was 20px / 28px)\n\n27. **H3** — Change `.layout-content h3` (lines 576-583): `font-size: 16px`, `font-weight: 700` (was 18px / 600)\n\n28. **Paragraph spacing** — Change line 633 `margin-bottom: var(--space-4)` to `margin-bottom: var(--space-3)` (12px)\n\n29. **Bold text** — Change line 598 `font-weight: 600` to `font-weight: 700`\n\n30. **Inline code border** — In the inline code rule (lines 689-696), add `border: 1px solid var(--color-border)` and change `padding: 2px 6px` to `padding: 1px 4px`\n\n31. **Code blocks dark theme** — Change `.layout-content pre` (lines 671-681):\n```css\n.layout-content pre {\n background: #0a2540;\n padding: var(--space-4);\n border-radius: var(--radius-sm);\n overflow-x: auto;\n margin-bottom: var(--space-4);\n font-family: var(--font-mono);\n font-size: 13px;\n line-height: 19px;\n color: #f5fbff;\n}\n```\n\n32. **Code block scrollbar** — Update the code block scrollbar thumb colors (lines 47-54) to work on dark background: change `rgba(0, 0, 0, 0.12)` to `rgba(255, 255, 255, 0.15)` and `rgba(0, 0, 0, 0.2)` to `rgba(255, 255, 255, 0.25)`. Also update the Firefox scrollbar-color on line 70 from `rgba(0, 0, 0, 0.12)` to `rgba(255, 255, 255, 0.15)`.\n\n33. **Blockquote** — Change `.layout-content blockquote` (lines 733-738): `border-left: 1px solid #c0c8d2` (was 4px solid var(--color-border)), `padding: 5px 0 5px 10px` (was 0 16px), add `font-size: 14px; line-height: 20px`\n\n34. **Table headers** — In `.layout-content th` (lines 714-720), add `text-transform: uppercase; font-size: 13px; letter-spacing: 0.03em`\n\n35. **Scrollbar gutter** — Add `scrollbar-gutter: stable;` to `.sidebar-content` (around line 303)\n\n### Link styling\n\n36. **Content links** — Change `.layout-content a` (lines 657-662): remove `border-bottom: 1px solid transparent` and add `text-decoration: underline; text-underline-offset: 2px; text-decoration-color: rgba(5, 112, 222, 0.4)`. Change `.layout-content a:hover` (lines 664-668): remove `border-bottom-color` line, change to `text-decoration-color: var(--color-link-hover)`\n\n## Test\n```bash\ncd documentation \u0026\u0026 node -e \"\nconst fs = require(\\\"fs\\\");\nconst css = fs.readFileSync(\\\"styles/globals.css\\\", \\\"utf8\\\");\nconst checks = [\n [css.includes(\\\"--color-text-heading: #1a1b25\\\"), \\\"heading color unified\\\"],\n [css.includes(\\\"--color-text-title: #1a1b25\\\"), \\\"title color unified\\\"],\n [css.includes(\\\"--content-max-width: 880px\\\"), \\\"content max-width 880\\\"],\n [css.includes(\\\"--toc-width: 250px\\\"), \\\"toc width 250\\\"],\n [css.includes(\\\"min-width: 1400px\\\"), \\\"responsive sidebar\\\"],\n [css.includes(\\\"background: #f6f8fa\\\") || css.includes(\\\"background:#f6f8fa\\\"), \\\"header solid bg\\\"],\n [css.includes(\\\"background: #0a2540\\\"), \\\"dark code blocks\\\"],\n [css.includes(\\\"color: #f5fbff\\\"), \\\"light code text\\\"],\n [css.includes(\\\"font-size: 13px\\\") \u0026\u0026 css.includes(\\\"line-height: 19px\\\"), \\\"code block sizing\\\"],\n [css.includes(\\\"toc-link-h3\\\"), \\\"toc h3 class\\\"],\n [css.includes(\\\"sidebar-chevron\\\"), \\\"sidebar chevron class\\\"],\n [css.includes(\\\"font-weight: 500\\\") \u0026\u0026 css.includes(\\\"sidebar-link-active\\\"), \\\"active link weight 500\\\"],\n [css.includes(\\\"border-left: 2px solid var(--color-link)\\\"), \\\"active left border\\\"],\n [css.includes(\\\"text-underline-offset\\\"), \\\"link underline style\\\"],\n [css.includes(\\\"scrollbar-gutter: stable\\\"), \\\"scrollbar gutter\\\"],\n [css.includes(\\\"max-width: 1200px\\\"), \\\"toc breakpoint 1200\\\"],\n [css.match(/\\\\.layout-content h2[^}]*font-size: 24px/s), \\\"h2 24px\\\"],\n [css.match(/\\\\.layout-content h3[^}]*font-size: 16px/s), \\\"h3 16px\\\"],\n [css.match(/\\\\.layout-content h3[^}]*font-weight: 700/s), \\\"h3 weight 700\\\"],\n];\nlet pass = true;\nfor (const [ok, name] of checks) {\n if (!ok) { console.error(\\\"FAIL: \\\" + name); pass = false; }\n else { console.log(\\\"PASS: \\\" + name); }\n}\nif (!pass) process.exit(1);\nconsole.log(\\\"\\\\nAll CSS checks passed.\\\");\n\"\n```\n\n## Dont\n- Do not modify any component JS files\n- Do not change the mobile responsive rules (keep mobile padding as-is)\n- Do not remove any CSS rules that are still referenced by components (check before deleting)\n- Do not change the design token variable names, only their values","status":"closed","priority":1,"issue_type":"task","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-14T22:25:14.346526+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-14T22:31:23.234686+13:00","closed_at":"2026-02-14T22:31:23.234686+13:00","close_reason":"2fda6b5 Applied all 36 CSS changes for Stripe design parity: unified heading colors, updated layout dimensions, improved sidebar/TOC styling, dark code blocks, enhanced typography, and responsive breakpoints","dependencies":[{"issue_id":"docs-150.4","depends_on_id":"docs-150","type":"parent-child","created_at":"2026-02-14T22:25:14.348237+13:00","created_by":"Sharfy Adamantine"}]} -{"id":"docs-390","title":"Epic: Replace speculative blockchain/tokenization language with freeze-then-fund model across all docs","status":"open","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T12:19:57.096114+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T12:19:57.096114+13:00"} +{"id":"docs-390","title":"Epic: Replace speculative blockchain/tokenization language with freeze-then-fund model across all docs","status":"closed","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T12:19:57.096114+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T19:52:57.976277+13:00","closed_at":"2026-02-16T19:52:57.976277+13:00","close_reason":"Closed"} {"id":"docs-390.1","title":"Rewrite architecture/overview.md: replace blockchain ownership layer with freeze-then-fund model","description":"## Files\n- documentation/pages/architecture/overview.md (modify)\n\n## What to do\n\nUpdate all references to blockchain-based tokenization/ownership to reflect that:\n1. The tokenization layer has NOT been developed yet — it is TBD\n2. The theory and architecture are correct — freeze records, anchor on-chain, then fund\n3. The docs should present this as the intended design, not as something that exists today\n\nThe freeze-then-fund model:\n1. A hypercert starts as mutable ATProto records (activity claim + evidence + evaluations etc.)\n2. Before a hypercert can be funded, its ATProto records must be **frozen** — a snapshot of the current state is taken and anchored on-chain. This creates an immutable reference point.\n3. The reason: a funder must know exactly what they are funding. If the cert contents can still change after funding, the funder might end up paying for something different than what they signed up for.\n4. Once frozen and anchored on-chain, the hypercert can be listed for funding.\n5. Evaluations and evidence can still accumulate AFTER freezing — they are separate records that reference the frozen claim. But the core claim itself is immutable once frozen.\n\n### IMPORTANT FRAMING GUIDANCE\n- Do NOT strip out the blockchain/tokenization concept — the theory is right and the architecture is sound\n- DO make clear that the tokenization layer hasn't been built yet — it's TBD\n- Frame it as: \"the intended design is X\" or \"the planned approach is X\" — not as if it's live\n- Use phrases like \"the tokenization layer is not yet implemented\", \"this is the planned design\", \"the on-chain mechanisms are being designed\"\n- Keep the two-layer architecture (data layer + ownership/funding layer) — it's the right design\n- When describing how tokenization/funding WILL work, use future tense or \"planned\" language\n- The freeze-then-fund concept is the KEY insight to convey: you must freeze the cert before allowing funding\n\n### Specific changes needed:\n\n**Line 8:** Change \"combines AT Protocol for data portability with blockchain for ownership guarantees\" → something like \"combines AT Protocol for data portability with planned on-chain anchoring for ownership and funding guarantees.\" Make clear this is the design, not yet implemented.\n\n**Line 18 (Ownership Layer description):** Rewrite. The ownership layer is planned but not yet built. The intended design: frozen hypercert snapshots will be anchored on-chain so they can be funded. A hypercert cannot be funded while its contents are still changing — freezing ensures funders know exactly what they are paying for. Make clear this layer is TBD.\n\n**Lines 20-31 (stack diagram):** Update the bottom layer label. Add \"(planned)\" or similar to indicate it's not yet built.\n\n**Lines 63-81 (Ownership Layer Deep Dive):** Rewrite this section to describe the PLANNED design:\n- \"Anchoring\": Describe the planned approach — freezing the ATProto record state and anchoring the snapshot on-chain.\n- \"Tokenization\": Explain the planned approach — the specific on-chain mechanism (token standard, chain choice) is being designed. The concept: freeze the cert, anchor it, then enable funding.\n- \"Funding Mechanisms\": Keep the general concepts (direct purchase, retroactive funding, etc.) but frame as planned/intended, not implemented.\n- \"Multi-Chain Support\": Frame as intended design, not yet determined.\n\n**Lines 83-112 (How the Layers Connect):** Rewrite to describe the planned design:\n- The bridge will be: ATProto records are frozen, the snapshot CID is anchored on-chain, and funding operates against that frozen state.\n- Keep the cross-layer example but frame as \"how this will work\" not \"how this works.\"\n\n**Lines 114-136 (Key Design Decisions):**\n- \"Why Not Fully On-Chain?\" — Keep as-is, still valid.\n- \"Why Not Fully Off-Chain?\" — Rewrite to emphasize: without on-chain anchoring, there's no way to guarantee that what a funder pays for won't change. Freezing and anchoring provides the immutability guarantee.\n- \"Why This Separation?\" — Update to mention freeze-then-fund as the key planned mechanism.\n\n**Lines 138-148 (What This Enables):**\n- Frame enabled use cases as what the design WILL enable once the tokenization layer is built.\n\n### Key terminology:\n- Keep \"tokenization\" as a concept but mark as \"planned\" / \"not yet implemented\" / \"TBD\"\n- Use \"freeze\" / \"frozen\" / \"freezing\" to describe the new concept\n- Use future tense or \"planned\" language for anything on-chain\n- Keep \"funding\" language — the concept is real\n\n### Tone:\n- The architecture is sound, the theory is right\n- The tokenization layer just hasn't been built yet\n- Be clear about what exists (ATProto data layer) vs what's planned (on-chain ownership/funding layer)\n\n## Test\ngrep -q 'not yet\\|TBD\\|being designed\\|planned\\|will be' documentation/pages/architecture/overview.md \u0026\u0026 \\\ngrep -q 'freez' documentation/pages/architecture/overview.md \u0026\u0026 \\\ngrep -q 'funder.*know\\|know.*fund\\|change.*after\\|cannot.*funded.*changing\\|can.t.*funded.*chang\\|exactly what' documentation/pages/architecture/overview.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the blockchain/tokenization concept entirely — the theory is right, keep it as the planned design\n- Present tokenization as if it's already implemented/live\n- Invent specific smart contract details or token standards that don't exist\n- Change the Data Layer section (lines 33-61) — that's accurate as-is\n- Change the \"Why ATProto Over IPFS\" section (126-130) — that's accurate","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T12:20:42.512677+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T12:32:03.352974+13:00","closed_at":"2026-02-16T12:32:03.352974+13:00","close_reason":"9055496 Rewrite architecture/overview.md to reflect freeze-then-fund model and planned tokenization layer","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-390.1","depends_on_id":"docs-390","type":"parent-child","created_at":"2026-02-16T12:20:42.514231+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-390.2","title":"Rewrite architecture/data-flow-and-lifecycle.md: replace Stage 5 blockchain funding with freeze-then-fund","description":"## Files\n- documentation/pages/architecture/data-flow-and-lifecycle.md (modify)\n\n## What to do\n\nUpdate blockchain-centric language in the lifecycle doc. Key framing:\n1. The tokenization layer has NOT been developed yet — it is TBD\n2. The theory and architecture are correct — freeze records, anchor on-chain, then fund\n3. The docs should present this as the intended design, not as something that exists today\n\nThe freeze-then-fund model: before a hypercert can be funded, its ATProto records must be frozen (snapshotted and anchored on-chain). This protects funders — they need to know exactly what they're funding, and the cert contents must not change after funding.\n\n### IMPORTANT FRAMING GUIDANCE\n- Do NOT strip out the blockchain/tokenization concept — the theory is right and the architecture is sound\n- DO make clear that the tokenization layer hasn't been built yet — it's TBD\n- Frame it as: \"the intended design is X\" or \"the planned approach is X\" — not as if it's live\n- Use phrases like \"the tokenization layer is not yet implemented\", \"this is the planned design\", \"the on-chain mechanisms are being designed\"\n- When describing how tokenization/funding WILL work, use future tense or \"planned\" language\n- The freeze-then-fund concept is the KEY insight to convey\n\n### Specific changes:\n\n**Line 16 (Enrichment):** Change \"Rights records define what token holders receive\" → \"Rights records define what funders or stakeholders receive.\" (The concept of rights is correct, just don't assume tokens exist yet.)\n\n**Line 22 (Funding stage summary):** Rewrite. Current text presents tokenization as live. New text should describe the planned design: Before funding, the hypercert's ATProto records will be frozen — a cryptographic snapshot taken and anchored on-chain. This ensures funders know exactly what they are paying for. The cert's core content cannot change after freezing. The specific on-chain funding mechanisms are being designed.\n\n**Line 24 (Accumulation):** Update to reflect planned design. Evaluations and evidence continue accumulating around the frozen claim.\n\n**Line 29 (diagram):** Change \"Blockchain\" under Funding to \"On-chain (planned)\"\n\n**Line 69 (Rights records):** Change \"define what token holders receive\" → \"define what funders or stakeholders receive\"\n\n**Lines 146-181 (Stage 5: Funding \u0026 Ownership):** Rewrite this section to describe the PLANNED design:\n\n- **Anchoring:** Describe the planned approach — when a hypercert is ready for funding, its current ATProto state will be frozen. The snapshot CID is anchored on-chain. The reason: a funder must know exactly what they are funding.\n\n- **Tokenization → rename to \"Freezing and Immutability\":** Explain the planned concept. Once frozen, the core activity claim cannot be modified. Evidence and evaluations can still accumulate. The specific on-chain representation (token standard, contract design) is being designed. Note: the tokenization layer is not yet implemented, but the theory is sound.\n\n- **Funding Mechanisms:** Keep the general concepts but frame as planned. Various funding models are intended, including direct funding, retroactive funding, and impact certificates. The specific mechanisms are being designed.\n\n- **Multi-Chain Support:** Frame as intended design. The protocol plans to be chain-agnostic but specifics are TBD.\n\n- **Diagram:** Update to reflect planned state. Replace \"Token Contract\" / \"Token ID\" with planned equivalents like \"Frozen Snapshot\" / \"CID: bafyrei...\"\n\n**Lines 199-205 (Stage 6 - Ownership Transfers / Long-Term Value):**\n- Reframe around the planned design. The frozen on-chain anchor will persist independently. Remove language that presents token transfers as live. Frame as intended future behavior.\n\n**Line 212 (diagram):** Change \"Blockchain\" labels to \"On-chain (planned)\"\n\n### Key terminology:\n- Keep \"tokenization\" as a concept but mark as \"planned\" / \"not yet implemented\" / \"TBD\"\n- Use \"freeze\" / \"frozen\" / \"freezing\" to describe the new concept\n- \"funders\" instead of \"token holders\" where referring to people who fund\n- Use future tense or \"planned\" language for anything on-chain\n- Keep \"on-chain\" — blockchain IS the plan\n\n## Test\ngrep -q 'not yet\\|TBD\\|being designed\\|planned\\|will be' documentation/pages/architecture/data-flow-and-lifecycle.md \u0026\u0026 \\\ngrep -q 'freez' documentation/pages/architecture/data-flow-and-lifecycle.md \u0026\u0026 \\\ngrep -q 'cannot.*change\\|must not.*change\\|exactly what.*fund\\|know.*what.*pay\\|frozen' documentation/pages/architecture/data-flow-and-lifecycle.md \u0026\u0026 \\\n! grep -q 'token holder' documentation/pages/architecture/data-flow-and-lifecycle.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the blockchain/tokenization concept entirely — the theory is right, keep it as the planned design\n- Present tokenization as if it's already implemented/live\n- Change Stages 1-4 (Creation, Enrichment, Evaluation, Discovery) unless they contain token holder language\n- Invent smart contract details\n- Change the Cross-PDS References section (lines 215-234) — that's accurate\n- Change the \"What This Flow Enables\" section (lines 236-246) unless it has token language","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T12:21:20.091221+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T12:31:55.410818+13:00","closed_at":"2026-02-16T12:31:55.410818+13:00","close_reason":"5d8ba48 Replace Stage 5 blockchain funding with freeze-then-fund model","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-390.2","depends_on_id":"docs-390","type":"parent-child","created_at":"2026-02-16T12:21:20.092158+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-390.3","title":"Rewrite getting-started/the-hypercerts-infrastructure.md: replace blockchain ownership layer and integration patterns with freeze-then-fund","description":"## Files\n- documentation/pages/getting-started/the-hypercerts-infrastructure.md (modify)\n\n## What to do\n\nThis is the heaviest file — it has an entire \"ownership layer: blockchain\" section and 4 blockchain integration patterns. Update to reflect that the tokenization layer hasn't been developed yet but the theory is right.\n\n### IMPORTANT FRAMING GUIDANCE\n- Do NOT strip out the blockchain/tokenization concept — the theory is right and the architecture is sound\n- DO make clear that the tokenization layer hasn't been built yet — it's TBD\n- Frame it as: \"the intended design is X\" or \"the planned approach is X\" — not as if it's live\n- Use phrases like \"the tokenization layer is not yet implemented\", \"this is the planned design\", \"the on-chain mechanisms are being designed\"\n- Keep the two-layer architecture — it's the right design\n- The freeze-then-fund concept is the KEY insight: you must freeze the cert before allowing funding, because funders must know exactly what they're paying for\n\n### Core concept:\nBefore a hypercert can be funded, its ATProto records must be frozen — a snapshot is taken and anchored on-chain. This protects funders: they need to know exactly what they're paying for. If the cert contents could change after funding, a funder might end up paying for a different cert than what they committed to. The specific on-chain mechanisms (token standards, smart contracts, chain choices) are being designed.\n\n### Specific changes:\n\n**Line 7:** Change \"AT Protocol for data and blockchain for ownership\" → \"AT Protocol for data and planned on-chain anchoring for ownership and funding\"\n\n**Lines 19-23 (The ownership layer: blockchain):** Rewrite. Rename to something like \"The funding layer: on-chain anchoring (planned)\". Describe the intended design: when a hypercert is ready for funding, its ATProto records will be frozen and anchored on-chain. Explain WHY: funders must know exactly what they are paying for. Make clear this layer is not yet implemented but the theory is sound.\n\n**Lines 25-29 (How the layers connect):** Rewrite to describe the planned design. Keep the AT-URI example. Explain that when ready for funding, the claim's state will be frozen and its CID anchored on-chain. Note that a claim can exist on ATProto without ever being frozen for funding.\n\n**Lines 83-87 (Step 4: Ownership is anchored on-chain):** Rename to \"4. The hypercert is frozen and funded (planned)\". Describe the intended flow: Carol's funding app will freeze Alice's hypercert, anchor the snapshot on-chain, and Carol funds the frozen cert. Make clear this is the planned design. Alice's claim continues on ATProto with new evaluations referencing the frozen claim.\n\n**Lines 123-139 (Blockchain Integration Patterns):** Rewrite as \"Planned Funding Patterns\" or similar. Present as intended design patterns, not implemented features:\n- Pattern 1: Freeze-on-create — freeze immediately upon creation\n- Pattern 2: Freeze-when-ready — accumulate evidence first, freeze when ready for funding (expected default)\n- Pattern 3: Batch freezing — freeze multiple claims together periodically\n- Pattern 4: Partial freezing — freeze core claim while keeping some records mutable\nFor all patterns, note the tokenization layer is not yet implemented.\n\n**Lines 170-172 (Blockchain scalability):** Rewrite. Keep the idea that on-chain operations are expensive. Frame as planned design consideration.\n\n**Lines 184-186 (Access control via smart contracts):** Mark as future/planned. \"Token-gated data\" is a potential future feature.\n\n**Line 192:** Change \"implementing novel blockchain integration patterns\" → \"implementing freeze-then-fund patterns\"\n\n### Key terminology:\n- Keep \"tokenization\" as a concept but mark as \"planned\" / \"not yet implemented\"\n- Use \"freeze\" / \"frozen\" / \"freezing\" for the new concept\n- \"anchor on-chain\" for the planned on-chain step\n- Keep \"on-chain\" and \"blockchain\" where appropriate — it IS the plan\n- Add \"(planned)\" markers where helpful\n\n## Test\ngrep -q 'not yet\\|TBD\\|being designed\\|planned\\|will be' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\ngrep -q 'freez' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\ngrep -q 'cannot.*change\\|must not.*change\\|exactly what.*fund\\|know.*what.*pay\\|frozen' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\n! grep -q 'mints an NFT' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the blockchain/tokenization concept entirely — the theory is right, keep it as the planned design\n- Present tokenization as if it's already implemented/live\n- Change the Data Layer section (lines 13-17) — accurate as-is\n- Change DID, PDS, Lexicon, XRPC, Repository sections (lines 33-61) — accurate\n- Change Steps 1-3 of the data flow (lines 65-81) — accurate\n- Change Migration and Portability section (lines 141-158) — accurate\n- Change Privacy section (lines 174-183) except the token-gated line\n- Invent specific smart contract or token standard details","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T12:21:57.277367+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T12:31:26.421333+13:00","closed_at":"2026-02-16T12:31:26.421333+13:00","close_reason":"a51984a Rewrite infrastructure doc to use freeze-then-fund model","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-390.3","depends_on_id":"docs-390","type":"parent-child","created_at":"2026-02-16T12:21:57.279592+13:00","created_by":"sharfy-test.climateai.org"}]} @@ -72,7 +72,7 @@ {"id":"docs-xdq.3","title":"Write 'Scaffold Starter App' tools page","description":"## Files\n- documentation/pages/tools/scaffold.md (modify — replace stub)\n\n## Design language — Stripe docs (docs.stripe.com)\nStudy the real Stripe documentation at docs.stripe.com for tone and structure. Key patterns:\n\n1. **One-sentence opener**: The first line tells you what the tool is and what it does. Example from Stripe: \"The Stripe CLI lets you build, test, and manage your integration from the command line.\"\n2. **Capability bullet list**: Right after the opener, a short bullet list of what you can do with it.\n3. **Code first, explain second**: Show the command, then explain what it does.\n4. **Numbered steps** for sequential processes.\n5. **Tables for reference data**: Environment variables, config options go in tables.\n6. **Short paragraphs**: 1-3 sentences max. Scannable.\n7. **No preamble**: Never \"In this page you will learn...\"\n8. **No link dumps**: No \"See also\", \"Next steps\", or \"Related pages\" at the end.\n9. **Inline prerequisites**: Mention requirements where needed, not in a separate section.\n\nAlso study existing pages in this project for consistency:\n- `documentation/pages/getting-started/quickstart.md`\n- `documentation/pages/tutorials/creating-your-first-hypercert.md`\n\nAvailable Markdoc tags: `{% callout type=\"note\" %}...{% /callout %}`, `{% columns %}`, `{% column %}`.\n\n## What to do\nReplace the stub with a complete documentation page for the Hypercerts Scaffold starter app. Target ~100-140 lines of Markdoc.\n\n### Intro (follow Stripe pattern)\nStart with a one-sentence description, then a capability bullet list:\n\nThe Hypercerts Scaffold is a Next.js starter app for building on ATProto with the Hypercerts SDK. Clone it to bootstrap your own application. You get:\n\n- OAuth authentication with ATProto (login, session management, token refresh)\n- Profile management (read and update Certified profiles)\n- Hypercert creation and listing\n- Server-side repository access patterns with React Query on the client\n\nThen one sentence: Live demo at [hypercerts-scaffold.vercel.app](https://hypercerts-scaffold.vercel.app). Source: [github.com/hypercerts-org/hypercerts-scaffold-atproto](https://github.com/hypercerts-org/hypercerts-scaffold-atproto).\n\n### Page structure\n\n1. **Quick start** section with numbered steps:\n\n 1. Clone and install:\n ```bash\n git clone https://github.com/hypercerts-org/hypercerts-scaffold-atproto\n cd hypercerts-scaffold-atproto\n pnpm install\n ```\n\n 2. Configure environment:\n ```bash\n cp .env.example .env.local\n pnpm run generate-jwk \u003e\u003e .env.local\n ```\n\n 3. Start Redis (for session storage):\n ```bash\n docker run -d -p 6379:6379 redis:alpine\n ```\n\n 4. Run the dev server:\n ```bash\n pnpm run dev\n ```\n\n Open `http://127.0.0.1:3000`. Requires Node.js 20+ and pnpm.\n\n `{% callout type=\"note\" %}` — \"Use `127.0.0.1` not `localhost` for local development. ATProto OAuth requires IP-based loopback addresses per RFC 8252. The app auto-redirects, but your `.env.local` must use `127.0.0.1`.\"\n\n2. **Environment variables** section — a table:\n\n | Variable | Description |\n |----------|-------------|\n | `NEXT_PUBLIC_BASE_URL` | App URL (`http://127.0.0.1:3000` for local) |\n | `ATPROTO_JWK_PRIVATE` | OAuth private key (generate with `pnpm run generate-jwk`) |\n | `REDIS_HOST` | Redis hostname |\n | `REDIS_PORT` | Redis port |\n | `REDIS_PASSWORD` | Redis password |\n | `NEXT_PUBLIC_PDS_URL` | PDS URL (e.g. `https://pds-eu-west4.test.certified.app`) |\n\n3. **Architecture** section — brief text description of the stack:\n - Browser: OAuthProvider + SessionProvider + React Query\n - Next.js API routes handle auth callbacks, cert operations, profile management\n - Hypercerts SDK (`@hypercerts-org/sdk-core`) manages OAuth sessions and repository operations\n - Redis stores sessions; PDS stores user data\n\n4. **Key patterns** section — show the two main server-side auth patterns with real code:\n\n **Getting an authenticated repository:**\n ```typescript\n import { getRepoContext } from \"@/lib/repo-context\";\n\n export async function GET() {\n const ctx = await getRepoContext();\n if (!ctx) {\n return Response.json({ error: \"Not authenticated\" }, { status: 401 });\n }\n\n const profile = await ctx.scopedRepo.profile.getCertifiedProfile();\n return Response.json(profile);\n }\n ```\n\n **Creating a hypercert:**\n ```typescript\n await ctx.scopedRepo.hypercert.create({\n title: \"My Hypercert\",\n description: \"A certificate of impact\",\n });\n ```\n\n5. **Project structure** — a brief file tree:\n ```\n app/api/auth/ # OAuth endpoints\n app/api/certs/ # Hypercert CRUD\n app/api/profile/ # Profile management\n components/ # React components\n lib/ # SDK init, repo context, server actions\n providers/ # React context providers\n queries/ # TanStack Query hooks\n ```\n\n6. `{% callout type=\"note\" %}` — \"The scaffold uses a pre-release SDK version (`@hypercerts-org/sdk-core@0.10.0-beta.8`). API changes are expected before 1.0.\"\n\n## Test\n```bash\ncd documentation \u0026\u0026 npx next build --webpack 2\u003e\u00261 | tail -5\n```\nMust exit 0. Page must be \u003e80 lines and \u003c180 lines:\n```bash\nwc -l documentation/pages/tools/scaffold.md\n```\n\n## Dont\n- Do not copy the scaffold README verbatim — distill it for a documentation audience\n- Do not include ngrok setup instructions (too niche)\n- Do not start with \"In this page you will learn...\" or similar preamble\n- Do not use \"See also\", \"Next steps\", or \"Related pages\" sections\n- Do not create a standalone \"Prerequisites\" section\n- Do not modify navigation.js (done in docs-xdq.1)\n- Do not use {% figure %} tags","status":"closed","priority":1,"issue_type":"task","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-15T00:43:41.090634+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-15T00:52:31.358324+13:00","closed_at":"2026-02-15T00:52:31.358324+13:00","close_reason":"Completed scaffold documentation page with 139 lines following Stripe docs design language","dependencies":[{"issue_id":"docs-xdq.3","depends_on_id":"docs-xdq","type":"parent-child","created_at":"2026-02-15T00:43:41.091874+13:00","created_by":"Sharfy Adamantine"},{"issue_id":"docs-xdq.3","depends_on_id":"docs-xdq.1","type":"blocks","created_at":"2026-02-15T00:44:02.335743+13:00","created_by":"Sharfy Adamantine"}]} {"id":"docs-xdq.4","title":"Write 'Hyperboard' tools page","description":"## Files\n- documentation/pages/tools/hyperboard.md (modify — replace stub)\n\n## Design language — Stripe docs (docs.stripe.com)\nStudy the real Stripe documentation at docs.stripe.com for tone and structure. Key patterns:\n\n1. **One-sentence opener**: The first line tells you what the tool is and what it does.\n2. **Capability bullet list**: Right after the opener, a short bullet list of what you can do with it.\n3. **Short paragraphs**: 1-3 sentences max. Scannable.\n4. **No preamble**: Never \"In this page you will learn...\"\n5. **No link dumps**: No \"See also\", \"Next steps\", or \"Related pages\" at the end.\n\nAlso study existing pages in this project for consistency:\n- `documentation/pages/getting-started/quickstart.md`\n- `documentation/pages/getting-started/why-atproto.md`\n\nAvailable Markdoc tags: `{% callout type=\"note\" %}...{% /callout %}`, `{% columns %}`, `{% column %}`.\n\n## What to do\nReplace the stub with a documentation page for Hyperboard. Target ~60-90 lines of Markdoc.\n\nHyperboard is a visual board that showcases the contributors to a hypercert. It displays who contributed to an impact claim, making contributions visible and recognizable.\n\n### Intro (follow Stripe pattern)\nStart with a one-sentence description, then a capability bullet list:\n\nHyperboard displays the contributors to a hypercert as a visual, shareable board. Use it to:\n\n- Showcase who did the work behind an impact claim\n- Display contribution weights and roles\n- Embed contributor recognition on project websites\n- Give funders transparency into who their contributions support\n\nThen one sentence: Because the underlying data lives on ATProto, every Hyperboard is backed by cryptographically signed, publicly verifiable records.\n\n### Page structure\n\n1. **What Hyperboard shows** section — explain what information a Hyperboard displays:\n - The hypercert (activity claim) it is associated with\n - All contributors listed on that hypercert (via `org.hypercerts.claim.contributorInformation` records)\n - Contribution weights or roles (if specified in the contribution details)\n - A visual, shareable representation of impact attribution\n\n2. **How it works** section — explain the data flow in 3-4 short paragraphs:\n - A hypercert is created with contributors listed\n - Hyperboard reads the contributor data from the ATProto repository\n - It renders a visual board showing each contributor and their role\n - Because the data lives on ATProto, the board is verifiable — anyone can check the underlying records\n\n3. **Use cases** section — brief bullet list with bold labels:\n - **Project pages**: Embed a Hyperboard on your project website to showcase your team\n - **Funding transparency**: Show funders exactly who their contributions support\n - **Portfolio**: Contributors can point to Hyperboards as proof of their impact work\n - **Recognition**: Publicly acknowledge contributors in a way that is verifiable and portable\n\n4. `{% callout type=\"note\" %}` — \"Hyperboard reads contributor data directly from ATProto repositories. The underlying records are cryptographically signed and publicly verifiable — anyone can independently confirm who contributed to a hypercert.\"\n\n## Test\n```bash\ncd documentation \u0026\u0026 npx next build --webpack 2\u003e\u00261 | tail -5\n```\nMust exit 0. Page must be \u003e40 lines and \u003c120 lines:\n```bash\nwc -l documentation/pages/tools/hyperboard.md\n```\n\n## Dont\n- Do not invent URLs, repos, or API endpoints for Hyperboard — we do not have those details yet\n- Do not claim Hyperboard is open source or link to a repo (we do not know)\n- Do not start with \"In this page you will learn...\" or similar preamble\n- Do not use \"See also\", \"Next steps\", or \"Related pages\" sections\n- Do not create a standalone \"Prerequisites\" section\n- Do not modify navigation.js (done in docs-xdq.1)\n- Do not use {% figure %} tags\n- Do not speculate about features beyond what is described above","status":"closed","priority":1,"issue_type":"task","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-15T00:43:58.12274+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-15T00:51:05.921335+13:00","closed_at":"2026-02-15T00:51:05.921335+13:00","close_reason":"Completed Hyperboard tools page documentation","dependencies":[{"issue_id":"docs-xdq.4","depends_on_id":"docs-xdq","type":"parent-child","created_at":"2026-02-15T00:43:58.123763+13:00","created_by":"Sharfy Adamantine"},{"issue_id":"docs-xdq.4","depends_on_id":"docs-xdq.1","type":"blocks","created_at":"2026-02-15T00:44:02.447475+13:00","created_by":"Sharfy Adamantine"}]} {"id":"docs-yne","title":"Epic 5: Styling and Visual Design","description":"## Summary\nCreate the complete CSS styling for the documentation site following a design language inspired by Stripe's documentation (docs.stripe.com). The goal is a clean, professional, content-focused documentation site that prioritizes readability and quiet confidence.\n\n## Context\nThis project is a Next.js + Markdoc documentation site in the `documentation/` directory. By the time this epic runs:\n- Epic 1 has scaffolded the project with a minimal `styles/globals.css`\n- Epic 2 has created React components: Callout, Columns, Column, Figure\n- Epic 4 has created Layout, Sidebar, TableOfContents components\n\nAll these components need polished CSS. The styles go in `styles/globals.css` (or can be split into CSS modules if preferred).\n\n## Design Principles\n\nThe Stripe documentation design language follows these core principles:\n1. **Content is the interface** -- every visual decision makes content more scannable, never decorates\n2. **Mostly monochrome, with surgical color** -- the page is 95% grayscale; color appears only for links, callout indicators, and status badges\n3. **Generous but purposeful whitespace** -- everything breathes, nothing floats\n4. **Border, not shadow, for structure** -- 1px light gray borders define regions, not heavy shadows\n5. **Developer-first** -- code blocks are first-class citizens, typography is optimized for technical content\n\n## Typography\n\n### Font stacks\n```css\n--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';\n--font-mono: 'Source Code Pro', Menlo, Monaco, Consolas, monospace;\n```\nUse the system font stack. It loads instantly, feels native on every OS, and is what Stripe uses.\n\n### Font weights\n- Regular: 400 (body text, descriptions)\n- Semibold: 600 (section headers, emphasis, sidebar labels)\n- Bold: 700 (page titles, H1)\n\n### Type scale\n| Element | Size | Weight | Color | Line Height |\n|---------|------|--------|-------|-------------|\n| H1 | 32px | 700 | #21252c (near-black) | 1.25 |\n| H2 | 24px | 700 | #353a44 (dark charcoal) | 1.3 |\n| H3 | 20px | 600 | #353a44 | 1.4 |\n| H4 | 16px | 600 | #353a44 | 1.5 |\n| Body | 16px | 400 | #414552 (dark gray) | 1.65 |\n| Small/Caption | 13px | 400 | #687385 (medium gray) | 1.5 |\n| Code (inline) | 14px | 400 | #414552 | inherit |\n| Code (block) | 14px | 400 | #414552 | 1.55 |\n\n### Anti-aliasing\n```css\nbody {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n```\n\n## Color Palette\n\n### Neutrals (the workhorse -- 95% of the page)\n| Token | Value | Usage |\n|-------|-------|-------|\n| --color-bg | #ffffff | Page background, content area |\n| --color-bg-subtle | #f6f8fa | Code block backgrounds, sidebar hover, cards |\n| --color-border | #ebeef1 | Section dividers, sidebar border, card borders |\n| --color-border-strong | #d8dee4 | Table header bottom border, input borders |\n| --color-text-secondary | #687385 | Descriptions, metadata, TOC items, captions |\n| --color-text-primary | #414552 | Body text |\n| --color-text-heading | #353a44 | Headings (H2-H4) |\n| --color-text-title | #21252c | H1 page titles |\n\n### Accent colors (used sparingly -- only for interactive elements and semantic indicators)\n| Token | Value | Usage |\n|-------|-------|-------|\n| --color-link | #0570de | Hyperlinks, interactive text |\n| --color-link-hover | #0055bc | Link hover state (slightly darker) |\n| --color-info | #0570de | Info callout border |\n| --color-info-bg | #f0f7ff | Info callout background |\n| --color-warning | #c84801 | Warning callout border |\n| --color-warning-bg | #fef9f0 | Warning callout background |\n| --color-danger | #df1b41 | Danger callout border |\n| --color-danger-bg | #fef0f4 | Danger callout background |\n| --color-success | #228403 | Success callout border |\n| --color-success-bg | #f0fef0 | Success callout background |\n\n### Focus ring\n```css\n--focus-ring: 0 0 0 4px rgba(5, 112, 222, 0.36);\n```\n\n## Spacing System\n\nUse an 8px base grid. All spacing should be multiples of 8 (with 4px for tight spaces):\n```css\n--space-1: 4px;\n--space-2: 8px;\n--space-3: 12px;\n--space-4: 16px;\n--space-5: 20px;\n--space-6: 24px;\n--space-8: 32px;\n--space-10: 40px;\n--space-12: 48px;\n--space-16: 64px;\n```\n\n### Application:\n- Between paragraphs: 16px\n- Between heading and its first paragraph: 8-12px (tight coupling)\n- Before a new H2 section: 48px (creates visible section breaks)\n- Sidebar item vertical spacing: 4-6px between items, 20-24px between section groups\n- Content area horizontal padding: 32px on each side\n- Content area top padding: 32px below header\n\n## Component Styles\n\n### Layout\n```\nHeader: height 56px, white background, bottom border 1px solid #ebeef1\nSidebar: width 240px, fixed/sticky, right border 1px solid #ebeef1, padding 16px\nContent: max-width 720px, centered, padding 32px\nRight TOC: width 200px, sticky top, padding-left 24px\n```\n\n### Sidebar\n- Section headers: 12px, font-weight 600, color #687385, text-transform uppercase, letter-spacing 0.05em, margin-bottom 8px\n- Nav items: 14px, color #414552, padding 6px 12px, border-radius 6px\n- Active nav item: font-weight 600, background-color #f6f8fa, color #21252c\n- Hover nav item: background-color #f6f8fa\n- Nested items: padding-left +16px\n\n### Table of Contents (right side)\n- Title \"On this page\": 12px, font-weight 600, color #687385, uppercase\n- Items: 13px, color #687385, padding 4px 0\n- Active item: color #0570de (link blue)\n- Left border indicator: 2px solid #0570de on active item (optional)\n\n### Callout boxes (from Epic 2 components)\n```css\n.callout {\n border-left: 4px solid var(--callout-color);\n background: var(--callout-bg);\n border-radius: 0 6px 6px 0;\n padding: 16px;\n margin: 16px 0;\n}\n.callout-title {\n font-weight: 600;\n margin-bottom: 4px;\n}\n```\n\n### Columns layout (from Epic 2 components)\n```css\n.columns {\n display: flex;\n gap: 24px;\n margin: 16px 0;\n}\n.column {\n flex: 1;\n min-width: 0;\n}\n@media (max-width: 768px) {\n .columns { flex-direction: column; }\n}\n```\n\n### Figure (from Epic 2 components)\n```css\n.figure {\n text-align: center;\n margin: 24px 0;\n}\n.figure img {\n max-width: 100%;\n height: auto;\n border-radius: 6px;\n}\n.figure-caption {\n font-size: 13px;\n color: #687385;\n margin-top: 8px;\n}\n```\n\n### Tables\nStripe uses clean, borderless tables with only a header bottom border:\n```css\ntable {\n width: 100%;\n border-collapse: collapse;\n margin: 16px 0;\n font-size: 14px;\n}\nth {\n text-align: left;\n font-weight: 600;\n color: #353a44;\n padding: 8px 12px;\n border-bottom: 1px solid #d8dee4;\n}\ntd {\n padding: 8px 12px;\n color: #414552;\n border-bottom: 1px solid #ebeef1;\n}\ntr:last-child td {\n border-bottom: none;\n}\n```\nNo zebra striping. No outer borders. Clean and minimal.\n\n### Code blocks\n```css\npre {\n background: #f6f8fa;\n border-radius: 6px;\n padding: 16px;\n overflow-x: auto;\n font-family: var(--font-mono);\n font-size: 14px;\n line-height: 1.55;\n margin: 16px 0;\n color: #414552;\n}\n```\nOptionally install `prism-react-renderer` for syntax highlighting. The current docs only have 2 JSON code blocks, but the SDK docs will grow. If adding syntax highlighting, use a light theme that matches the neutral palette.\n\n### Inline code\n```css\ncode {\n background: #f6f8fa;\n border-radius: 4px;\n padding: 2px 6px;\n font-family: var(--font-mono);\n font-size: 0.875em; /* slightly smaller than surrounding text */\n}\n/* Don't style code inside pre blocks */\npre code {\n background: none;\n border-radius: 0;\n padding: 0;\n font-size: inherit;\n}\n```\n\n### Links\n```css\na {\n color: #0570de;\n text-decoration: none;\n}\na:hover {\n color: #0055bc;\n text-decoration: underline;\n}\n```\n\n### Headings\n```css\nh1 { font-size: 32px; font-weight: 700; color: #21252c; margin-top: 0; margin-bottom: 16px; line-height: 1.25; }\nh2 { font-size: 24px; font-weight: 700; color: #353a44; margin-top: 48px; margin-bottom: 12px; line-height: 1.3; }\nh3 { font-size: 20px; font-weight: 600; color: #353a44; margin-top: 32px; margin-bottom: 8px; line-height: 1.4; }\nh4 { font-size: 16px; font-weight: 600; color: #353a44; margin-top: 24px; margin-bottom: 8px; line-height: 1.5; }\n```\n\nNote: `h2` has 48px top margin to create strong visual section breaks (the largest gaps on the page). This is a key Stripe pattern.\n\n### Pagination (prev/next)\n```css\n.pagination {\n display: flex;\n justify-content: space-between;\n margin-top: 48px;\n padding-top: 24px;\n border-top: 1px solid #ebeef1;\n}\n.pagination a {\n color: #0570de;\n font-weight: 500;\n}\n```\n\n### Lists\n```css\nul, ol {\n padding-left: 24px;\n margin: 12px 0;\n}\nli {\n margin: 6px 0;\n line-height: 1.65;\n}\nli \u003e p { margin: 0; }\n```\n\n### Blockquotes\n```css\nblockquote {\n border-left: 4px solid #ebeef1;\n padding: 0 16px;\n margin: 16px 0;\n color: #687385;\n}\n```\n\n### Horizontal rules\n```css\nhr {\n border: none;\n border-top: 1px solid #ebeef1;\n margin: 32px 0;\n}\n```\n\n## Responsive Breakpoints\n```css\n/* Mobile: \u003c 768px - sidebar and TOC hidden, content full width */\n/* Tablet: 768px - 1040px - sidebar visible, TOC hidden */\n/* Desktop: \u003e 1040px - full three-column layout */\n```\n\nOn mobile:\n- Sidebar hidden behind hamburger menu\n- Right TOC hidden entirely\n- Content goes full-width with 16px horizontal padding\n- Tables get `overflow-x: auto` wrapper\n\n## Shadow System\nShadows are used very sparingly -- almost never on the docs site:\n- Most elements: no shadow (flat)\n- Card hover: `0px 2px 5px rgba(48, 49, 61, 0.08)` (barely perceptible)\n- Dropdown/overlay: `0px 5px 15px rgba(0, 0, 0, 0.12), 0px 15px 35px rgba(48, 49, 61, 0.08)`\n\n## Border Radius\n- Inline code: 4px\n- Code blocks, callouts, cards: 6px\n- Buttons, tags, pills: 6px or rounded (9999em for pill shape)\n\n## Acceptance Criteria\n- All CSS is in `styles/globals.css` (or organized into CSS modules)\n- CSS custom properties are defined for colors, fonts, and spacing\n- System font stack is used (no custom font downloads)\n- Anti-aliased text rendering is enabled\n- All headings (H1-H4) follow the type scale with proper size, weight, color, and spacing\n- Body text is 16px, dark gray (#414552), line-height 1.65\n- Links are blue (#0570de), darken on hover, no underline by default\n- Tables are clean: no outer borders, header has bottom border only, proper padding\n- Code blocks have light gray background, rounded corners, monospace font\n- Inline code has subtle gray background pill\n- Callout boxes have colored left border and tinted background per type\n- Columns stack on mobile, flex row on desktop\n- Layout uses three columns on desktop (sidebar 240px, content ~720px, TOC ~200px)\n- Sidebar has 1px right border, section headers in uppercase small text\n- Active nav item has bold text and subtle background\n- Right TOC has scroll spy highlighting in blue\n- Responsive: sidebar/TOC collapse below 768px/1040px breakpoints\n- Pagination has top border separator and blue link text\n- The overall feel is clean, white, professional, content-focused -- no decorative elements, no gradients, no heavy shadows\n- The page looks like it could belong to the same family as docs.stripe.com\n","status":"closed","priority":2,"issue_type":"epic","owner":"sharfy.adamantine@gmail.com","created_at":"2026-02-13T13:43:24.486687+13:00","created_by":"Sharfy Adamantine","updated_at":"2026-02-14T13:18:01.287139+13:00","closed_at":"2026-02-14T13:18:01.287141+13:00","dependencies":[{"issue_id":"docs-yne","depends_on_id":"docs-c34","type":"blocks","created_at":"2026-02-13T13:43:24.48892+13:00","created_by":"Sharfy Adamantine"},{"issue_id":"docs-yne","depends_on_id":"docs-vbw","type":"blocks","created_at":"2026-02-13T13:43:24.490264+13:00","created_by":"Sharfy Adamantine"},{"issue_id":"docs-yne","depends_on_id":"docs-7dv","type":"blocks","created_at":"2026-02-13T13:43:24.491023+13:00","created_by":"Sharfy Adamantine"}]} -{"id":"docs-yzy","title":"Epic: Separate planned funding/tokenization content into dedicated page","description":"Move all planned/TBD content about freeze-then-fund, tokenization, on-chain mechanisms, multi-chain support, and funding patterns out of the main documentation pages and into a single dedicated page. Main docs should describe what exists today (ATProto data layer) and briefly mention that on-chain funding is planned, linking to the dedicated page for details.","status":"open","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:11:36.619138+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:11:36.619138+13:00"} +{"id":"docs-yzy","title":"Epic: Separate planned funding/tokenization content into dedicated page","description":"Move all planned/TBD content about freeze-then-fund, tokenization, on-chain mechanisms, multi-chain support, and funding patterns out of the main documentation pages and into a single dedicated page. Main docs should describe what exists today (ATProto data layer) and briefly mention that on-chain funding is planned, linking to the dedicated page for details.","status":"closed","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:11:36.619138+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T19:52:57.591064+13:00","closed_at":"2026-02-16T19:52:57.591064+13:00","close_reason":"Closed"} {"id":"docs-yzy.1","title":"Create architecture/planned-funding-and-tokenization.md — the dedicated page for all planned on-chain content","description":"## Files\n- documentation/pages/architecture/planned-funding-and-tokenization.md (create)\n\n## What to do\n\nCreate a new page that consolidates ALL planned/TBD content about the on-chain funding and tokenization layer. This page is the single source of truth for what's planned but not yet built.\n\nThe page should have this structure:\n\n### Frontmatter\n```\n---\ntitle: \"Planned: Funding \u0026 Tokenization\"\ndescription: How hypercerts will be frozen, anchored on-chain, and funded. This layer is not yet implemented.\n---\n```\n\n### Page content (write this in full):\n\n**Opening paragraph:** The on-chain funding and tokenization layer is not yet implemented. This page describes the planned design. The theory and architecture are sound — the implementation is in progress. For what exists today (the ATProto data layer), see [Architecture Overview](/architecture/overview).\n\n**Section: The Freeze-Then-Fund Model**\nThe core concept: before a hypercert can be funded, its ATProto records must be frozen. Freezing means taking a cryptographic snapshot (CID) of the activity claim and all its associated records at a point in time. This snapshot is then anchored on-chain.\n\nWhy freezing is necessary: a funder must know exactly what they are funding. If the cert's contents could change after funding, the funder might end up paying for a different cert than what they committed to. A hypercert cannot be funded if its contents are still changing.\n\nWhat freezing preserves: the core activity claim — who did what, when, where. The frozen state is what funders commit to.\n\nWhat continues after freezing: evaluations and evidence can still accumulate. These are separate records that reference the frozen claim. The claim's reputation can evolve while its core content remains fixed.\n\n**Section: On-Chain Anchoring**\nWhen a hypercert is frozen, its snapshot CID will be anchored on-chain via a smart contract. The contract stores the AT-URI and the frozen snapshot CID, creating a verifiable link between the data layer and the ownership layer.\n\nThis creates an immutable reference point. Anyone can verify that the on-chain record matches the ATProto data by comparing CIDs.\n\n**Section: Tokenization**\nOnce frozen and anchored, the hypercert can be represented as a transferable token on-chain. A token could represent full ownership or fractional shares. Token holders would have rights defined in the hypercert's org.hypercerts.claim.rights record.\n\nThe specific token standard (ERC-1155, ERC-721, or a custom standard) is being designed. The protocol intends to support multiple token standards for different use cases — from non-transferable recognition to fully tradable certificates.\n\n**Section: Funding Mechanisms**\nOnce frozen and anchored, various funding models can operate on the ownership layer:\n- Direct funding — funders acquire shares directly from the contributor\n- Retroactive funding — rewarding past work based on demonstrated outcomes\n- Impact certificates — creating markets for outcomes\n- Quadratic funding — amplifying small donations through matching pools\n- Milestone-based payouts — releasing funds as work progresses\n\nSmart contracts will enforce rules and distribute payments. The specific implementations are being designed.\n\n**Section: Funding Readiness Patterns**\nDifferent applications may use different patterns for when to freeze:\n\nPattern 1: Freeze-on-create — the claim is frozen immediately upon creation. Simple but means the claim can't be enriched before funding.\n\nPattern 2: Freeze-when-ready — the claim exists on ATProto, accumulates evidence and evaluations, and is frozen only when a funder expresses interest or the contributor decides it's ready. This is the expected default pattern.\n\nPattern 3: Batch freezing — multiple claims are frozen and anchored together periodically. Cost-efficient for high-volume use cases.\n\nPattern 4: Partial freezing — some aspects of the claim are frozen (e.g., the core activity and rights) while others remain mutable (e.g., ongoing measurements). The frozen portion is what funders commit to.\n\n**Section: Multi-Chain Support**\nThe protocol is designed to be chain-agnostic. Different communities may use different chains. The ATProto data layer remains the same regardless of which chain anchors the frozen snapshot. The specific multi-chain architecture is being designed.\n\n**Section: Cross-Layer Example**\nWalk through the full planned flow:\n1. Alice creates an activity claim on her PDS → gets AT-URI\n2. Bob evaluates Alice's claim from his PDS\n3. Alice decides the claim is ready for funding → freezes it\n4. An application anchors the frozen snapshot on-chain → gets token ID\n5. Carol funds the frozen cert on-chain\n6. New evaluations continue accumulating on ATProto, referencing the frozen claim\n7. Carol can verify her funded cert matches the frozen snapshot by comparing CIDs\n\nInclude the ASCII diagram:\n```\nATProto (exists today) On-chain (planned)\n────────────────────── ──────────────────\nActivity Claim Frozen Snapshot\nat://did:alice/... CID: bafyrei...\n ↓ ↓\nEvidence, Evaluations Ownership Record\nMeasurements, Rights Funder: 0xCarol...\n Metadata: { uri, cid }\n```\n\n**Section: What This Will Enable**\n- Retroactive funding of past contributions\n- Composable funding mechanisms across platforms\n- Portable proof of funding (funders can prove what they funded)\n- Independent evolution of data and ownership layers\n\n**Closing:** For the current architecture (what exists today), see [Architecture Overview](/architecture/overview). For the data lifecycle, see [Data Flow \u0026 Lifecycle](/architecture/data-flow-and-lifecycle).\n\n## Test\ntest -f documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'not yet implemented' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Freeze-Then-Fund' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'cannot.*funded.*chang\\|can.t.*funded.*chang\\|exactly what' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Funding Readiness Patterns\\|Funding.*Pattern' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Multi-Chain' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Present any of this as implemented/live\n- Invent specific contract addresses or deployed details\n- Make it too short — this is THE comprehensive reference for all planned on-chain work\n- Forget the cross-layer example with the ASCII diagram","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:12:25.547762+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:16:00.16776+13:00","closed_at":"2026-02-16T17:16:00.16776+13:00","close_reason":"d937d10 Created comprehensive planned funding and tokenization architecture page","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.1","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:12:25.549901+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-yzy.2","title":"Update navigation and rewrite blockchain-integration.md to redirect to planned page","description":"## Files\n- documentation/lib/navigation.js (modify)\n- documentation/pages/getting-started/infrastructure/blockchain-integration.md (modify)\n- documentation/pages/getting-started/infrastructure/portability-and-scaling.md (modify)\n- documentation/pages/getting-started/the-hypercerts-infrastructure.md (modify — just the link on line 78)\n\n## What to do\n\n### 1. Update navigation.js\n\nChange line 25 from:\n```js\n{ title: 'Blockchain Integration', path: '/getting-started/infrastructure/blockchain-integration' },\n```\nto:\n```js\n{ title: 'Funding \u0026 Tokenization (Planned)', path: '/architecture/planned-funding-and-tokenization' },\n```\n\nAlso add the new page to the Understand section, after \"Data Flow \u0026 Lifecycle\" (line 30). Add:\n```js\n{ title: 'Planned: Funding \u0026 Tokenization', path: '/architecture/planned-funding-and-tokenization' },\n```\n\nWait — actually, since it's already linked as a child of \"The Hypercerts Infrastructure\", just update that child entry. Don't add a duplicate. So the only change is line 25.\n\n### 2. Rewrite blockchain-integration.md\n\nThis file currently has the old mint-on-create / lazy minting / batch anchoring / hybrid ownership patterns. Replace the entire content with a redirect notice:\n\n```markdown\n---\ntitle: Funding \u0026 Tokenization\n---\n\n# Funding \u0026 Tokenization\n\nThis content has moved to [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\n```\n\n### 3. Update portability-and-scaling.md\n\nLines 36-38 have \"Blockchain scalability\" section that says \"On-chain operations (minting, transfers, sales) are expensive...\" — this is planned content. Replace with:\n\n```markdown\n#### On-chain scalability (planned)\n\nThe on-chain funding and tokenization layer is not yet implemented. When built, on-chain operations will be expensive, so hypercerts will minimize on-chain activity by keeping rich data on ATProto. Only frozen snapshots and funding flows will touch the blockchain. For details on the planned on-chain design, see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\n```\n\nAlso lines 50-52 have \"Access control via smart contracts\" with token-gated data. Replace with:\n\n```markdown\n#### Access control via smart contracts (planned)\n\nIn the planned design, on-chain tokens could have access control logic — for example, granting read access to private ATProto records only to token holders. This is a potential future feature. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\n```\n\n### 4. Update the-hypercerts-infrastructure.md line 78\n\nChange:\n```\n- [Blockchain Integration](/getting-started/infrastructure/blockchain-integration) — minting patterns and on-chain ownership\n```\nto:\n```\n- [Funding \u0026 Tokenization (Planned)](/architecture/planned-funding-and-tokenization) — freeze-then-fund model and on-chain ownership design\n```\n\n## Test\ngrep -q 'planned-funding-and-tokenization' documentation/lib/navigation.js \u0026\u0026 \\\ngrep -q 'moved to' documentation/pages/getting-started/infrastructure/blockchain-integration.md \u0026\u0026 \\\ngrep -q 'planned-funding-and-tokenization' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\ngrep -q 'not yet implemented' documentation/pages/getting-started/infrastructure/portability-and-scaling.md \u0026\u0026 \\\n! grep -q 'mints an NFT\\|Mint-on-create\\|Lazy minting' documentation/pages/getting-started/infrastructure/blockchain-integration.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Add duplicate nav entries\n- Delete blockchain-integration.md (keep it as a redirect so old links work)\n- Change anything else in navigation.js\n- Change anything else in the-hypercerts-infrastructure.md besides line 78\n- Change anything else in portability-and-scaling.md besides the blockchain scalability and token-gated sections","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:12:50.318417+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:18:08.762614+13:00","closed_at":"2026-02-16T17:18:08.762614+13:00","close_reason":"e8dd74d Update navigation and redirect blockchain-integration to planned funding page","labels":["scope:small"],"dependencies":[{"issue_id":"docs-yzy.2","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:12:50.31972+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.2","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.044876+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-yzy.3","title":"Strip planned content from architecture/overview.md and architecture/data-flow-and-lifecycle.md — link to planned page","description":"## Files\n- documentation/pages/architecture/overview.md (modify)\n- documentation/pages/architecture/data-flow-and-lifecycle.md (modify)\n\n## What to do\n\nRemove detailed planned/TBD content from these two architecture pages. Replace with brief mentions and links to /architecture/planned-funding-and-tokenization. The main docs should describe what EXISTS TODAY (ATProto data layer) and only briefly note that on-chain funding is planned.\n\n### architecture/overview.md\n\n**Line 8:** Change to: \"The Hypercerts Protocol uses AT Protocol for data portability. On-chain anchoring for ownership and funding is [planned](/architecture/planned-funding-and-tokenization).\"\n\n**Line 18 (Ownership Layer):** Condense to 1-2 sentences max: \"The **Ownership Layer** is planned but not yet implemented. The intended design uses a freeze-then-fund model where hypercerts are frozen and anchored on-chain before funding — ensuring funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n**Lines 48-70 (Ownership Layer Deep Dive):** DELETE this entire section (Anchoring, Tokenization, Funding Mechanisms, Multi-Chain Support). Replace with a single short paragraph:\n\n\"## Ownership Layer (Planned)\n\nThe ownership layer is not yet implemented. The planned design freezes ATProto records and anchors them on-chain before funding, ensuring funders know exactly what they are paying for. For the full planned design — including anchoring, tokenization, funding mechanisms, and multi-chain support — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 72-95 (How the Layers Connect):** Keep the first paragraph about content living on ATProto (line 76). Remove lines 78-80 (detailed planned flow) and the cross-layer example (lines 86-95). Replace with:\n\n\"A hypercert's **ownership and funding state** will live on-chain once the tokenization layer is built. The planned bridge is a freeze-then-fund mechanism. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full cross-layer design.\"\n\nKeep the callout (lines 82-84) but simplify: \"The separation matters. ATProto provides data portability — users can switch servers, applications can read across the network, and records outlive any single platform. On-chain anchoring will provide ownership and funding guarantees. Neither layer can provide both properties alone.\"\n\n**Lines 105-107 (Why Not Fully Off-Chain?):** Condense. Keep the core point (mutable records are fine for collaboration but funding requires immutability) but remove the detailed freeze-then-fund explanation. Add link.\n\n**Lines 115-119 (Why This Separation):** Simplify. Remove \"through the planned freeze-then-fund mechanism\" and \"Once the tokenization layer is built\". Just say: \"Each layer does what it does best. ATProto handles identity, data portability, and schemas. On-chain anchoring will handle ownership, funding, and immutability. This separation reduces costs, increases flexibility, and maintains portability.\"\n\n**Lines 121-131 (What This Enables):** Remove \"(Planned)\" labels and the detailed planned descriptions. Keep the 4 bullet points but make them concise. For the two that work today, keep as-is. For the two that are planned, just say \"planned\" in one phrase and link to the planned page.\n\n**Add to Next Steps:** Add a link: \"For the planned on-chain funding and tokenization design, see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n### architecture/data-flow-and-lifecycle.md\n\n**Line 22 (Funding summary):** Condense to: \"**Funding** connects ownership to the claim. The on-chain funding layer is [planned but not yet implemented](/architecture/planned-funding-and-tokenization). The intended design freezes ATProto records before funding to ensure funders know exactly what they are paying for.\"\n\n**Line 24 (Accumulation):** Simplify to: \"**Accumulation** continues indefinitely. More evaluations arrive. Additional evidence gets attached. The data layer continues evolving.\"\n\n**Line 29 (diagram):** Change \"On-chain (planned)\" to just \"On-chain*\" and add a footnote: \"*On-chain layer is planned. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 146-187 (Stage 5: Funding \u0026 Ownership):** DELETE the detailed content. Replace with a short section:\n\n\"## Stage 5: Funding \u0026 Ownership (Planned)\n\nThe on-chain funding layer is not yet implemented. The planned design: before a hypercert can be funded, its ATProto records are frozen and the snapshot is anchored on-chain. This ensures funders know exactly what they are paying for — the cert's contents cannot change after freezing.\n\nFor the full planned design — including anchoring, tokenization, funding mechanisms, funding readiness patterns, and multi-chain support — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 205-218 (Ownership Transfers, Long-Term Value in Stage 6):** Remove the \"Ownership Transfers\" subsection entirely (it's all planned content). Keep \"Long-Term Value\" but simplify: \"The separation of data and ownership enables long-term value accumulation. A hypercert's reputation can grow as evaluations accumulate. The data remains portable and accessible regardless of future ownership changes.\"\n\nRemove the timeline diagram (lines 213-218) or simplify it to only show what exists today:\n```\nTime →\n─────────────────────────────────────────────────────────\nCreation Evaluation 1 Discovery Evaluation 2 Evidence Evaluation 3\n ↓ ↓ ↓ ↓ ↓ ↓\n PDS PDS-Eva1 Indexer PDS-Eva2 PDS PDS-Eva3\n```\n\n## Test\n! grep -q 'Multi-Chain Support' documentation/pages/architecture/overview.md \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/architecture/overview.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/architecture/data-flow-and-lifecycle.md | grep -qv '^0$' \u0026\u0026 \\\n! grep -q 'Anchoring (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\n! grep -q 'Tokenization (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\n! grep -q 'Funding Mechanisms (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the Data Layer sections — those describe what exists today\n- Remove the Key Design Decisions section entirely — just simplify it\n- Remove the \"What This Enables\" section — just simplify it\n- Add new planned content — we're REMOVING it and linking to the dedicated page\n- Change Stages 1-4 in data-flow-and-lifecycle.md\n- Change the Cross-PDS References or \"What This Flow Enables\" sections in data-flow-and-lifecycle.md","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:13:45.724521+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:19:22.582072+13:00","closed_at":"2026-02-16T17:19:22.582072+13:00","close_reason":"4ed89bd Strip planned content from architecture docs and link to planned page","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.3","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:13:45.725402+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.3","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.15891+13:00","created_by":"sharfy-test.climateai.org"}]}