docs: add Certified ATProto integration spec and topology memo - #640
docs: add Certified ATProto integration spec and topology memo#640Oba-One wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 3 Skipped Deployments
|
📝 WalkthroughWalkthroughTwo new documentation pages define the Certified ATProto identity topology and the detailed integration specification, covering OAuth delegation, EAS-to-PDS mirroring, provenance signing, record mapping, privacy constraints, milestones, and validation evidence. ChangesCertified ATProto integration
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review summaryInvariants checked: 9 from CLAUDE.md / AGENTS.md Docs-only PR: two new files under Notes:
Clean docs/spec change. Nothing blocking. Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4617f4119e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| | Option | Feasibility | Benefit | Cost or loss | Recommendation | Claim | | ||
| | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --- | | ||
| | A. ERC-1271 proof variant | A deployed Kernel can validate a signature through `isValidSignature` over a defined digest | Cryptographically binds the Certified DID to the actual Green Goods account | Requires new lexicon union variant, exact digest and chain rules, deployed account, RPC verification, and upstream acceptance | Durable deployed-account path | [I] | | ||
| | B. ERC-6492 proof variant | Wrapper can prove a counterfactual smart-account signature plus deployment data | Supports links before Kernel deployment | More complex verification, factory/init-code trust, size constraints, and upstream acceptance | Durable counterfactual companion to A | [I] | | ||
| | C. Link the underlying P-256 authenticator or a session key | The authenticator controls Kernel authorization but does not equal the Kernel address | Avoids new smart-account proof at first glance | WebAuthn signs `authenticatorData | | SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. A session key is transient and binds the wrong identity | Reject for DID-to-account link | [D] | |
There was a problem hiding this comment.
Fix malformed options table rendering
When the docs site renders this page, the whole smart-account options matrix is emitted as raw pipe-delimited text instead of a table because the separator row has eight columns while the header has six, and row C adds more unescaped | characters inside the WebAuthn expression. This makes the passkey-link tradeoff section hard to read in the generated Docusaurus page even though bun run build:docs exits successfully.
Useful? React with 👍 / 👎.
|
|
||
| - a real Certified test account authorizes the Green Goods client | ||
| - client metadata and redirect URIs are accepted by `certified.one` | ||
| - exact granular create/update scopes are demonstrated with create, read-back, update, and delete cleanup in a test repository |
There was a problem hiding this comment.
Align cleanup with the requested repo scopes
This gate asks implementers to prove delete cleanup while also calling the exact create/update scopes the target permission set. In AT Protocol repo scopes, delete is a separate action qualifier, so a client authorized only for action=create&action=update should be rejected when it tries to delete test records; either request delete in a test-only scope or make cleanup use an allowed operation.
Useful? React with 👍 / 👎.
|
|
||
| | Green Goods source | Lexicon record and fields | Relationship and cross-reference | Validation or loss | Claim | | ||
| | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | ||
| | Garden | `org.hypercerts.collection`: `type = project`, `title = name`, `shortDescription` or `description`, `banner`, `createdAt`, optional `location` strongRef | Deterministic collection rkey from chain ID plus Garden address. Add Work activities as weighted or unweighted `items` strongRefs | `collection` supports multiple project records and recursive nesting. It has no GardenAccount, Hats, or role fields | [I] | |
There was a problem hiding this comment.
Wrap collection items before writing them
The v1.1.0 org.hypercerts.collection schema does not store items as direct strongRefs; each entry must be a collection#item object with itemIdentifier and optional itemWeight. If milestone-two implementation follows this crosswalk literally, Garden collection writes will fail schema validation or be unable to represent weights.
Useful? React with 👍 / 👎.
| | Work media CID | `org.hypercerts.context.attachment`: `subjects = [activity strongRef]`, `contentType = evidence`, `content = ipfs://<cid>`, title, createdAt | Attachment points to activity | Copy only media approved for public PDS visibility | [I] | | ||
| | Work metadata CID | `attachment` with `contentType = methodology` or `evidence`, `content = ipfs://<cid>` | Attachment points to activity | Use `methodology` only when the content actually describes method. Otherwise use `evidence` | [I] | | ||
| | Work numeric detail | `org.hypercerts.context.measurement`: `subjects`, `metric`, `unit`, numeric-string `value`, time, optional evidence URIs and measurer DIDs | Measurement points to activity; evaluation can later reference it | Mirror only typed numeric values with an explicit unit. Current arbitrary details are not automatically valid measurements | [I] | | ||
| | Work EAS source | `attachment`: subject activity, `contentType = evidence`, `content` contains a stable HTTPS EAS viewer URI, title contains schema identity, createdAt from chain | Deterministic rkey from `eip155:<chainId>:eas:<uid>` | This carries chain ID and UID without inventing lexicon fields | [I] | |
There was a problem hiding this comment.
Model attachment content as URI arrays
The attachment schema defines content as an array of union items such as { uri: ... }, not as a scalar URI string. Following these rows literally would produce invalid media, metadata, and EAS-source attachment records that the lexicon validator or PDS should reject.
Useful? React with 👍 / 👎.
| 5. SHA-256 hash the encoded bytes and construct CIDv1 with DAG-CBOR codec `0x71`. The result is 36 bytes: CID version, codec, multihash identifier, length, and 32-byte digest. | ||
| 6. ECDSA-sign those CID bytes with the stable P-256 key. A KMS adapter may submit the raw CID bytes with its SHA-256 ECDSA algorithm, or submit `SHA256(cidBytes)` as a digest, but it must not hash twice. | ||
| 7. Convert KMS DER output to raw 64-byte `r || s` and normalize `s` to the low-S form required by BIP-0062. | ||
| 8. Attach `{ $type: "app.certified.signature.defs#inline", signature, key }` under `signatures`. |
There was a problem hiding this comment.
Wrap inline signatures in the required list
The hypercerts lexicon defines each record's signatures field as app.certified.signature.defs#list, i.e. an array of inline signatures or strongRefs. If implementers attach the single inline object directly as written here, otherwise valid signed records will fail schema validation when the client tries to write them to the PDS.
Useful? React with 👍 / 👎.
| | Work metadata CID | `attachment` with `contentType = methodology` or `evidence`, `content = ipfs://<cid>` | Attachment points to activity | Use `methodology` only when the content actually describes method. Otherwise use `evidence` | [I] | | ||
| | Work numeric detail | `org.hypercerts.context.measurement`: `subjects`, `metric`, `unit`, numeric-string `value`, time, optional evidence URIs and measurer DIDs | Measurement points to activity; evaluation can later reference it | Mirror only typed numeric values with an explicit unit. Current arbitrary details are not automatically valid measurements | [I] | | ||
| | Work EAS source | `attachment`: subject activity, `contentType = evidence`, `content` contains a stable HTTPS EAS viewer URI, title contains schema identity, createdAt from chain | Deterministic rkey from `eip155:<chainId>:eas:<uid>` | This carries chain ID and UID without inventing lexicon fields | [I] | | ||
| | WorkApproval | `org.hypercerts.context.evaluation`: `subject = activity strongRef`, `evaluators`, `summary`, `score { min: "0", max: "3", value: confidence }`, optional content attachment | Evaluation references activity snapshot | `evaluators` require DIDs. Do not place an EVM address in a DID field. No exact approved boolean or verification-method field exists, so this mapping is lossy | [I] | |
There was a problem hiding this comment.
Serialize evaluation scores as strings
The v1.1.0 evaluation score object requires min, max, and value to be strings, while Green Goods' approval confidence field is a number. If this crosswalk is implemented literally with value: confidence, WorkApproval evaluation records will be rejected by lexicon validation instead of being written.
Useful? React with 👍 / 👎.
|
Closing this exploration PR as stale/superseded by the current |
Planning docs for a potential Green Goods x Certified (AT Protocol) identity integration: Certified owns the DID/PDS while Green Goods acts as an OAuth client that mirrors approved EAS attestations into hypercerts-lexicon records. Both are unlisted / feature_status: Planned (exploration output, implementation not approved), with [D]/[I]/[S] claim labels and cited evidence. - certified-atproto-integration-spec-2026-07.md — full integration spec. - certified-atproto-topology-memo-2026-07.md — identity topology + trust boundaries decision memo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4617f41 to
e8ee6d3
Compare
Reopened — the close on 2026-07-27 was a mistakeThis PR was closed on 2026-07-27T01:30Z as "stale/superseded by the current
The close was made by an automated agent ( What changed
Known drift to resolve before any mergeThe specs use "operator" vocabulary, which the Operator → Steward rename supersedes. Not a CI failure ( |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/docs/builders/specs/certified-atproto-integration-spec-2026-07.md`:
- Around line 375-379: Fix the Markdown table around the Option/Feasibility
headers so the separator row defines exactly six columns, matching the header.
In the row for “Link the underlying P-256 authenticator or a session key,”
replace the raw pipe within the WebAuthn expression with Markdown-safe text so
it remains within the Claim column.
- Around line 82-89: Update the unlink and cleanup scope definitions in the
certified integration specification, including the sections around the
address-link rule and the referenced later sections, to include action=delete
alongside action=create and action=update. If deletion remains outside
repository scopes, explicitly define unlink and cleanup as owner-mediated or
out-of-band flows instead.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f72bed19-fbeb-48a6-9cc6-4d4f4defb3f1
📒 Files selected for processing (2)
docs/docs/builders/specs/certified-atproto-integration-spec-2026-07.mddocs/docs/builders/specs/certified-atproto-topology-memo-2026-07.md
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: CI Gate
🧰 Additional context used
📓 Path-based instructions (1)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Before claiming a fix, setting, or behavior works, produce evidence in the same turn; if verification is unavailable, state that it cannot be verified instead of declaring success.
For destructive changes, list what will be removed and added and wait for user confirmation; do not replace requested additions or edit files when the user asks only for chat output.
Stay on the current branch unless explicitly instructed otherwise; stash unknown diffs rather than reverting or deleting them, and investigate concurrent-agent changes before destructive operations.
Remove temporary files, scripts, and helpers created during iteration before reporting completion.
Local agentic browser QA must use the authenticated Brave QA profile; if it is unreachable, report QA as blocked rather than substituting isolated Playwright, clean-room, or unauthenticated browser evidence.
Use the lightest honest validation for the user's intent: targeted proof for QA fixes, the Repo Quick Gate for shared or cross-package changes, and the Ship Gate only for explicit release or merge readiness.
Use Linear for durable backlog work and never open GitHub Issues for backlog work; respect the documented team, project, label, and privacy-routing rules.
Always call PostHogswitch-projectbefore querying; select the project based on the reported surface and keep replay URLs, session IDs, distinct IDs, wallet addresses, and reporter identifiers out of Linear bodies.
For ambiguous, multi-package, or high-risk work, research first, record evidence, plan the smallest implementation path, identify human judgment points, then edit.
For multi-issue or ambiguous cleanup work, follow the repository health ritual:/audit, scope lock,/clean,/review, and/shipas applicable.
**/*: Usebunfor repository scripts and package operations; the only npm exception isnpm run setupon a fresh machine before Bun is available.
Usebun run test, neverbun test. Never invoke rawforge; use the repo...
Files:
docs/docs/builders/specs/certified-atproto-topology-memo-2026-07.mddocs/docs/builders/specs/certified-atproto-integration-spec-2026-07.md
🔇 Additional comments (1)
docs/docs/builders/specs/certified-atproto-topology-memo-2026-07.md (1)
1-152: LGTM!
| **[S]** Address-link rule: | ||
|
|
||
| - construct a deterministic record key from the normalized address and proof variant | ||
| - require an explicit consent action by that exact account | ||
| - retain earlier records when the active mode changes | ||
| - permit a user-requested unlink by deleting or superseding the individual record, subject to Certified conventions | ||
| - never infer a Kernel link from an EOA proof, or an EOA link from an OAuth session | ||
| - show the linked mode and address before submission |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Confirm that AT Protocol repository permissions require an explicit action=delete permission for client-side record deletion.
💡 Result:
The AT Protocol repository permission system allows for granular control over client-side operations, including record deletion [1][2]. When defining permissions for a repository (typically within an OAuth scope or a Permission Set), the optional 'action' parameter is used to specify which operations are permitted [1][3]. The supported actions are 'create', 'update', and 'delete' [1][3]. If the 'action' parameter is omitted from a permission definition, all three operations—create, update, and delete—are granted by default [1][2][4]. However, if you wish to restrict a client to only specific operations (e.g., preventing record deletion), you must explicitly define the allowed actions [1][4]. In such a case, to permit deletion, 'action=delete' must be included in the permission string [1][2]. Conversely, if 'action=delete' is excluded from the list of specified actions, the client will not be authorized to perform record deletions [2][4]. In summary, while 'action=delete' is not strictly required for all repository access (as it is included by default if unspecified), it is a required explicit action if you are defining a restricted permission set that is intended to include the ability to delete records [1][4].
Citations:
- 1: https://atproto.com/specs/permission
- 2: https://github.com/ngerakines/atproto-skills/blob/main/skills/atproto-oauth/shared/scopes.md
- 3: https://atproto.com/specs/lexicon
- 4: https://underreacted.leaflet.pub/3mjfozhlhys2z
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="docs/docs/builders/specs/certified-atproto-integration-spec-2026-07.md"
echo "== file exists and line count =="
wc -l "$file"
echo "== relevant occurrences =="
rg -n "action=|scope|delete|unlink|Milestone 0|OAuth|permission" "$file" || true
echo "== sections around proposed lines =="
sed -n '70,105p' "$file"
echo "---"
sed -n '180,210p' "$file"
echo "---"
sed -n '515,535p' "$file"Repository: greenpill-dev-guild/green-goods
Length of output: 19446
Add action=delete to the unlink/cleanup scopes.
The link rule lets unlink via deletion, and Milestone 0 requires delete cleanup, but the requested repo scopes only include action=create&action=update. Since granular action-qualified scopes restrict repository operations outside the allowed value, add action=delete to the unlink-related collections or explicitly define unlink and cleanup as owner-mediated/out-of-band flows.
Also applies to Lines: 192-199, 527 and Lines: 521-527.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/docs/builders/specs/certified-atproto-integration-spec-2026-07.md`
around lines 82 - 89, Update the unlink and cleanup scope definitions in the
certified integration specification, including the sections around the
address-link rule and the referenced later sections, to include action=delete
alongside action=create and action=update. If deletion remains outside
repository scopes, explicitly define unlink and cleanup as owner-mediated or
out-of-band flows instead.
Source: MCP tools
| | Option | Feasibility | Benefit | Cost or loss | Recommendation | Claim | | ||
| | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --- | | ||
| | A. ERC-1271 proof variant | A deployed Kernel can validate a signature through `isValidSignature` over a defined digest | Cryptographically binds the Certified DID to the actual Green Goods account | Requires new lexicon union variant, exact digest and chain rules, deployed account, RPC verification, and upstream acceptance | Durable deployed-account path | [I] | | ||
| | B. ERC-6492 proof variant | Wrapper can prove a counterfactual smart-account signature plus deployment data | Supports links before Kernel deployment | More complex verification, factory/init-code trust, size constraints, and upstream acceptance | Durable counterfactual companion to A | [I] | | ||
| | C. Link the underlying P-256 authenticator or a session key | The authenticator controls Kernel authorization but does not equal the Kernel address | Avoids new smart-account proof at first glance | WebAuthn signs `authenticatorData | | SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. A session key is transient and binds the wrong identity | Reject for DID-to-account link | [D] | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the Markdown table column definition.
The header has six columns, but the separator row defines seven. Normalize the separator and avoid using a raw pipe in the WebAuthn cell so the rendered table cannot shift columns.
Proposed fix
-| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --- |
+| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
...
-| C. Link the underlying P-256 authenticator or a session key | ... | ... | WebAuthn signs `authenticatorData | SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. ... | Reject for DID-to-account link | [D] |
+| C. Link the underlying P-256 authenticator or a session key | ... | ... | WebAuthn signs `authenticatorData` concatenated with `SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. ... | Reject for DID-to-account link | [D] |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Option | Feasibility | Benefit | Cost or loss | Recommendation | Claim | | |
| | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --- | | |
| | A. ERC-1271 proof variant | A deployed Kernel can validate a signature through `isValidSignature` over a defined digest | Cryptographically binds the Certified DID to the actual Green Goods account | Requires new lexicon union variant, exact digest and chain rules, deployed account, RPC verification, and upstream acceptance | Durable deployed-account path | [I] | | |
| | B. ERC-6492 proof variant | Wrapper can prove a counterfactual smart-account signature plus deployment data | Supports links before Kernel deployment | More complex verification, factory/init-code trust, size constraints, and upstream acceptance | Durable counterfactual companion to A | [I] | | |
| | C. Link the underlying P-256 authenticator or a session key | The authenticator controls Kernel authorization but does not equal the Kernel address | Avoids new smart-account proof at first glance | WebAuthn signs `authenticatorData | | SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. A session key is transient and binds the wrong identity | Reject for DID-to-account link | [D] | | |
| | Option | Feasibility | Benefit | Cost or loss | Recommendation | Claim | | |
| | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | |
| | A. ERC-1271 proof variant | A deployed Kernel can validate a signature through `isValidSignature` over a defined digest | Cryptographically binds the Certified DID to the actual Green Goods account | Requires new lexicon union variant, exact digest and chain rules, deployed account, RPC verification, and upstream acceptance | Durable deployed-account path | [I] | | |
| | B. ERC-6492 proof variant | Wrapper can prove a counterfactual smart-account signature plus deployment data | Supports links before Kernel deployment | More complex verification, factory/init-code trust, size constraints, and upstream acceptance | Durable counterfactual companion to A | [I] | | |
| | C. Link the underlying P-256 authenticator or a session key | The authenticator controls Kernel authorization but does not equal the Kernel address | Avoids new smart-account proof at first glance | WebAuthn signs `authenticatorData` concatenated with `SHA256(clientDataJSON)`, not raw EIP-712 digests or record CID bytes. A session key is transient and binds the wrong identity | Reject for DID-to-account link | [D] | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/docs/builders/specs/certified-atproto-integration-spec-2026-07.md`
around lines 375 - 379, Fix the Markdown table around the Option/Feasibility
headers so the separator row defines exactly six columns, matching the header.
In the row for “Link the underlying P-256 authenticator or a session key,”
replace the raw pipe within the WebAuthn expression with Markdown-safe text so
it remains within the Claim column.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8ee6d314d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| **[I]** The exact mirror trigger is after a confirmed receipt and successful extraction of the EAS `Attested` event UID. It must be before the Work job is deleted. The transaction hash is not an EAS UID and must not continue to be stored as though it were one. | ||
|
|
||
| **[S]** Add a shared receipt helper that waits for the receipt and parses the EAS `Attested(recipient, attester, uid, schemaUID)` event. In one IndexedDB transaction, persist the UID-to-transaction mapping and insert the mirror job, then mark or remove the Work job. If the browser stops between confirmation and that transaction, a recovery pass queries the receipt by transaction hash. |
There was a problem hiding this comment.
Resolve Safe identifiers before receipt recovery
When a wallet submission uses the supported Safe-style path, packages/shared/src/modules/transactions/wallet-sender.ts:103-115 deliberately returns a non-canonical identifier without waiting for a receipt. This helper cannot query an EVM receipt with that value, so it cannot extract the EAS UID or recover after interruption as specified; the milestone needs a Safe-specific resolution/pending path before treating the Work job as confirmed.
Useful? React with 👍 / 👎.
|
|
||
| | Green Goods source | Lexicon record and fields | Relationship and cross-reference | Validation or loss | Claim | | ||
| | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | ||
| | Garden | `org.hypercerts.collection`: `type = project`, `title = name`, `shortDescription` or `description`, `banner`, `createdAt`, optional `location` strongRef | Deterministic collection rkey from chain ID plus Garden address. Add Work activities as weighted or unweighted `items` strongRefs | `collection` supports multiple project records and recursive nesting. It has no GardenAccount, Hats, or role fields | [I] | |
There was a problem hiding this comment.
Use a TID-compatible key for collections
The same document states at line 338 that org.hypercerts.collection is keyed by TID, so a hash-derived key based on chain ID and Garden address is not valid for this record type. Implementing this row literally would make milestone-two collection writes fail key validation; use a valid TID and persist its mapping, or define a schema-supported deterministic strategy.
Useful? React with 👍 / 👎.
|
|
||
| **[S]** Derive each ATProto rkey as a lowercase base32 encoding of `SHA-256("gg-certified-v1" || chainId || easUid || recordRole)`, prefixed with a short alphabetic role marker. Validate the final value against AT Protocol record-key grammar before implementation. Do not place raw secrets or user identifiers in the rkey. | ||
|
|
||
| **[I]** This makes retry lookup deterministic without assuming the PDS supports a secondary unique index. A `putRecord` retry with the same canonical content is idempotent. Timestamps must come from the chain source or original job, not from the retry clock, or the CID changes. |
There was a problem hiding this comment.
Guard deterministic writes with a record precondition
When the deterministic rkey already contains a different CID—the conflict scenario listed at line 482—an unconditioned com.atproto.repo.putRecord overwrites that record rather than surfacing a conflict. A retry following this procedure can therefore destroy a user edit before reconciliation runs; require a read-and-compare or swapRecord precondition before each put.
Useful? React with 👍 / 👎.
|
|
||
| ```bash | ||
| bun run --filter @green-goods/shared test -- src/__tests__/hooks/garden/createGardenOperation.test.ts src/__tests__/stores/createGardenStore.test.ts src/__tests__/modules/certified-records.test.ts | ||
| bun run --filter @green-goods/admin test -- src/__tests__/components/Garden/DetailsStep.test.tsx src/__tests__/workflows/createGarden.test.ts |
There was a problem hiding this comment.
Point validation at the existing garden workflow test
The repository test is packages/admin/src/__tests__/workflows/createGarden.test.ts, but this command filters for createGarden.test.tsx. Once the new DetailsStep test exists, the command can still succeed while silently omitting the existing garden workflow regression suite, so the filter should use the actual .ts path.
Useful? React with 👍 / 👎.
|
|
||
| **[I]** This milestone is a contract and deployment change and therefore requires the contract skill, deployment-path review, and human approval. It must not be folded into the client-only first slice. | ||
|
|
||
| **[S] Validation:** use the repository's Bun contract scripts for focused resolver tests, dry-run schema registration, shared encoder tests, `bun run check:indexing-boundary`, and the full Ship Gate. Never invoke raw `forge`. |
There was a problem hiding this comment.
Invoke the registered indexing-boundary script
From the repository root, bun run check:indexing-boundary exits with Script not found; that name exists only in packages/indexer/package.json, while the root script is bun run indexer:check-boundary. As written, milestone-four validation stops before the boundary check or Ship Gate, so use the root alias or explicitly run the package-local command.
Useful? React with 👍 / 👎.
| schemaUid: `0x${string}`; | ||
| txHash: `0x${string}`; | ||
| }; | ||
| visibilityDecision: "public"; |
There was a problem hiding this comment.
Persist the approved publication snapshot before EAS
The mirror payload records only a generic "public" decision, but the policy later distinguishes a user-approved summary from raw feedback that must remain denied by default, and the mirror job is not created until after EAS confirmation. The signer therefore has no durable copy or digest of the exact summary and fields approved before submission, and a delayed/offline job can publish content derived under a different policy or Certified account; persist the target DID and exact approved field/content snapshot on the original Work job before sending EAS, then carry it into this payload.
Useful? React with 👍 / 👎.
|
|
||
| ### Milestone 2: Flow A garden prefill and Garden collection | ||
|
|
||
| **[S] Scope:** bring the same Certified session into admin, prefill blank garden fields after draft restore, and create a Garden collection after deployment. |
There was a problem hiding this comment.
Require a separate admin OAuth authorization
In production the client and admin run on greengoods.app and admin.greengoods.app, while the proposed browser OAuth client keeps DPoP and refresh state in IndexedDB. Browser storage is origin-scoped, so opening admin cannot restore the client PWA's "same Certified session" merely by mounting the shared provider; milestone two must specify a separate admin authorization/callback and client-metadata redirect, or change to a topology that can securely broker the session.
Useful? React with 👍 / 👎.
|
|
||
| ### 4.4 EAS path and trigger point | ||
|
|
||
| **[D]** Work and WorkApproval are encoded in shared code and sent through `TransactionSender`. The current job executors return only the transaction hash. The EAS transaction builder sets `refUID` to zero for Work, WorkApproval, and their batch variants. |
There was a problem hiding this comment.
Route online wallet Works through the mirror trigger
For an online wallet submission, packages/shared/src/hooks/work/useWorkMutation.ts:193-232 calls submitWorkDirectly; only offline wallet and non-wallet submissions enter the job queue. That direct function confirms the transaction and returns its hash without creating a queue job, so the milestone-one external-EOA path can finish EAS successfully while the queue-owned mirror trigger never runs; parse the UID and atomically enqueue the mirror from the direct path, or converge this path on the queue.
Useful? React with 👍 / 👎.
| - `packages/client/src/routes/AppShell.tsx` | ||
| - `packages/client/src/views/Login/index.tsx` |
There was a problem hiding this comment.
Mount the OAuth provider above the login callback route
The current router mounts the Login route as a sibling of the protected AppShell, so adding CertifiedSessionProvider only through the listed AppShell.tsx cannot make it available while Login handles the OAuth callback. Wrapping Login separately would also violate the spec's initialize-once requirement; include PwaRuntime.tsx, Root.tsx, or another common ancestor in the plan and mount one provider above both Login and AppShell.
Useful? React with 👍 / 👎.
Important
DO NOT CLOSE — this PR is deliberately parked open as a tracking artifact.
It is not stale. It tracks planned identity work that has not been scheduled yet.
Automated agents and repo-hygiene sweeps must leave it open; only a human may close it.
Durable tracker: PRD-761 · label:
keep-openSummary
Adds two planning docs for a potential Green Goods × Certified (AT Protocol) identity integration — the output of a research/spec exploration. Both are
unlistedandfeature_status: Planned(implementation not approved).Docs
certified-atproto-integration-spec-2026-07.md— full integration spec: Certified owns the DID/PDS, Green Goods acts as an AT Protocol OAuth client that mirrors approved EAS attestations into hypercerts-lexicon records. Covers executive decisions, premise corrections, schema mapping, and evidence.certified-atproto-topology-memo-2026-07.md— the shorter identity-topology + trust-boundaries decision memo (Pattern A, user-delegated PDS writes), with a mermaid topology, OAuth dependency analysis, and approval gates.Both use
[D]/[I]/[S]claim labels (Documented / Inferred / Speculative) and cite repo + upstream (hypercerts-lexicon v1.1.0, Certified, AT Protocol) evidence.Validation
bun run build:docs✅ — Docusaurus build succeeds; the relative cross-link between the two specs resolves.develop2026-07-28 (e8ee6d3): Build Docs ✅ · CI Gate ✅, zero conflicts.Notes
unlisted, so they don't appear in site navigation.docs/docs/builders/specs/, so this branch cannot textually conflict withdevelop.🤖 Generated with Claude Code