Skip to content

[HYPER-181] add cryptographic signature support to record lexicons (resubmission of #170)#219

Merged
aspiers merged 17 commits into
mainfrom
feat/signature-support-v2
Jun 24, 2026
Merged

[HYPER-181] add cryptographic signature support to record lexicons (resubmission of #170)#219
aspiers merged 17 commits into
mainfrom
feat/signature-support-v2

Conversation

@aspiers

@aspiers aspiers commented May 21, 2026

Copy link
Copy Markdown
Contributor
  • Inspect PR review threads and identify @copilot comments to address
  • Inspect repository scripts and relevant files
  • Make the smallest required code changes
  • Run targeted validation for touched areas
  • Run final review/security validation and report results

@changeset-bot

changeset-bot Bot commented May 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cb4cd1f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hypercerts-org/lexicon Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@aspiers, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 22 minutes and 7 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b63ac103-c464-4b91-946c-2c01c3c7f761

📥 Commits

Reviewing files that changed from the base of the PR and between b40da9f and cb4cd1f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (42)
  • .agents/skills/building-with-hypercerts-lexicons/SKILL.md
  • .changeset/add-signature-support.md
  • .github/workflows/lint.yml
  • .github/workflows/pr-check.yml
  • .github/workflows/release.yml
  • .github/workflows/style.yml
  • .github/workflows/test.yml
  • .gitignore
  • .prettierignore
  • AGENTS.md
  • ERD.puml
  • README.md
  • SCHEMAS.md
  • eslint.config.mjs
  • lexicons/app/certified/actor/organization.json
  • lexicons/app/certified/actor/profile.json
  • lexicons/app/certified/badge/award.json
  • lexicons/app/certified/badge/definition.json
  • lexicons/app/certified/badge/response.json
  • lexicons/app/certified/graph/follow.json
  • lexicons/app/certified/link/evm.json
  • lexicons/app/certified/location.json
  • lexicons/app/certified/signature/defs.json
  • lexicons/app/certified/signature/proof.json
  • lexicons/org/hyperboards/board.json
  • lexicons/org/hyperboards/displayProfile.json
  • lexicons/org/hypercerts/claim/activity.json
  • lexicons/org/hypercerts/claim/contribution.json
  • lexicons/org/hypercerts/claim/contributorInformation.json
  • lexicons/org/hypercerts/claim/rights.json
  • lexicons/org/hypercerts/collection.json
  • lexicons/org/hypercerts/context/acknowledgement.json
  • lexicons/org/hypercerts/context/attachment.json
  • lexicons/org/hypercerts/context/evaluation.json
  • lexicons/org/hypercerts/context/measurement.json
  • lexicons/org/hypercerts/funding/receipt.json
  • lexicons/org/hypercerts/workscope/tag.json
  • package.json
  • tests/validate-signature-defs-inline.test.ts
  • tests/validate-signature-defs.test.ts
  • tests/validate-signature-proof.test.ts
  • tests/validate-signing-example.test.ts
📝 Walkthrough

Walkthrough

This PR adds optional cryptographic signatures to all record lexicons in the lexicon repository. Two new signature lexicons define inline ECDSA signatures and remote attestation proofs; 21 existing records gain an optional signatures field. Comprehensive documentation, validation tests, and an end-to-end signing example test demonstrate the feature.

Changes

Cryptographic Signature Support

Layer / File(s) Summary
Signature schema definitions
lexicons/app/certified/signature/defs.json, lexicons/app/certified/signature/proof.json
New app.certified.signature.defs with defs.list (union of inline signatures and strongRef references) and defs.inline (ECDSA signature + key reference); new app.certified.signature.proof record for remote attestation proofs.
Signature fields in record lexicons
lexicons/org/hypercerts/claim/*.json, lexicons/org/hypercerts/collection.json, lexicons/org/hypercerts/context/*.json, lexicons/org/hypercerts/funding/*.json, lexicons/org/hypercerts/workscope/*.json, lexicons/app/certified/actor/*.json, lexicons/app/certified/badge/*.json, lexicons/app/certified/graph/follow.json, lexicons/app/certified/link/evm.json, lexicons/app/certified/location.json, lexicons/org/hyperboards/*.json, SCHEMAS.md
Optional signatures property (ref to app.certified.signature.defs#list) added to 21 record schemas; SCHEMAS.md updated with new signature lexicon documentation.
Signature validation tests
tests/validate-signature-defs-inline.test.ts, tests/validate-signature-defs.test.ts, tests/validate-signature-proof.test.ts
Unit tests for inline signature validation, signature list union (inline + strongRef), and proof record validation with success and error cases.
End-to-end signing workflow test
tests/validate-signing-example.test.ts
Integration test extracting TypeScript code blocks from documentation, validating CID computation, ECDSA signature generation, inline and remote attestation construction, record assembly, lexicon compliance, and cryptographic verification.
Documentation and guides
.agents/skills/building-with-hypercerts-lexicons/SKILL.md, README.md
Updated guide and reference docs describing signature concepts, attestation model, inline vs. remote patterns, ECDSA low-S algorithm, and step-by-step construction/verification examples; lexicon map entries added for new signature types.
Changeset and infrastructure
.changeset/add-signature-support.md, package.json, AGENTS.md, ERD.puml, .gitignore
Changeset documenting non-breaking minor addition; @atproto/crypto and viem dependency updates; test naming guidance; diagram updates with linkEvm and signature-relationship notes; gitignore for extracted test artifacts.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #217: Both add cryptographic signature support with optional signatures arrays across records and introduce signature defs/proof lexicons; this PR directly fulfills that request with inline ECDSA and remote attestation patterns.

Possibly related PRs

Suggested labels

P1 (high)

Suggested reviewers

  • s-adamantine

Poem

🐰 Signatures squared—both inline and far,
ECDSA keys unlock the door ajar,
CIDs and proofs now dance as one,
256-bit trust beneath the sun! 🔐✨


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Lexicon Documentation Sync ❌ Error ERD.puml linkEvm dataclass missing signatures field (present in JSON); signature/defs.json inline signature bytes missing maxLength: 64 constraint per BIP-0062. Add signatures to ERD.puml linkEvm dataclass; add maxLength: 64 to signature field in signature/defs.json.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Lexicons Styleguide Compliance ⚠️ Warning The signature field in app.certified.signature.defs lacks maxLength constraint, allowing any-length byte arrays instead of enforcing the required 64-byte ECDSA signature size per styleguide. Add "maxLength": 64 to signature field in lexicons/app/certified/signature/defs.json to enforce proper byte-length validation.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and specifically describes the main change: adding cryptographic signature support to record lexicons, including a note that it's a resubmission.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/signature-support-v2

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aspiers aspiers changed the title feat: add cryptographic signature support to record lexicons (resubmission of #170) [HYPER-181] add cryptographic signature support to record lexicons (resubmission of #170) May 21, 2026
@aspiers
aspiers force-pushed the feat/signature-support-v2 branch from 426553f to b40da9f Compare May 25, 2026 12:22
@aspiers
aspiers marked this pull request as ready for review May 25, 2026 12:22
Copilot AI review requested due to automatic review settings May 25, 2026 12:22

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in cryptographic attestation support across the Hypercerts record lexicon surface area, plus documentation and tests to keep the signing procedure and schema shape from drifting.

Changes:

  • Introduces new signature lexicons: app.certified.signature.defs (shared #list / #inline) and app.certified.signature.proof (remote proof record).
  • Extends all 21 record lexicons with an optional signatures field referencing app.certified.signature.defs#list.
  • Adds docs + tests, including an integration-style test that extracts the “Cryptographic Signatures” docs code blocks and executes them.

Reviewed changes

Copilot reviewed 34 out of 36 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/validate-signing-example.test.ts Extracts/executes the docs signing example and asserts CID/signature/validation behavior.
tests/validate-signature-proof.test.ts Validates app.certified.signature.proof record shape and required fields.
tests/validate-signature-defs.test.ts Validates app.certified.signature.defs#list union/array semantics via an activity carrier record.
tests/validate-signature-defs-inline.test.ts Validates the app.certified.signature.defs#inline object def requirements.
README.md Documents the new signature lexicons and adds a “Cryptographic Signatures” usage section.
SCHEMAS.md Regenerated schema tables to include the new signatures property and new signature lexicons.
lexicons/app/certified/signature/defs.json New shared defs lexicon for inline signatures and signature lists.
lexicons/app/certified/signature/proof.json New proof record lexicon for remote attestations.
lexicons/org/hypercerts/claim/activity.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/claim/contribution.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/claim/contributorInformation.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/claim/rights.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/collection.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/context/acknowledgement.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/context/attachment.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/context/evaluation.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/context/measurement.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/funding/receipt.json Adds optional signatures ref to signature defs list.
lexicons/org/hypercerts/workscope/tag.json Adds optional signatures ref to signature defs list.
lexicons/org/hyperboards/board.json Adds optional signatures ref to signature defs list.
lexicons/org/hyperboards/displayProfile.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/badge/award.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/badge/definition.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/badge/response.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/actor/profile.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/actor/organization.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/location.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/graph/follow.json Adds optional signatures ref to signature defs list.
lexicons/app/certified/link/evm.json Adds optional signatures ref to signature defs list (and clarifies its relationship to proof).
package.json Adds dev deps for signing/docs test support and bumps viem.
package-lock.json Locks new deps (@atproto/crypto, @ipld/dag-cbor, transitive updates).
.agents/skills/building-with-hypercerts-lexicons/SKILL.md Adds signature lexicon docs and signing procedure example (used by extraction test).
.changeset/add-signature-support.md Publishes a minor version changeset describing signature support across lexicons.
AGENTS.md Updates testing guidance to allow cross-cutting tests that don’t map 1:1 to a lexicon file.
ERD.puml Notes that signature relationships are intentionally omitted from the ERD to avoid clutter.
.gitignore Ignores tests/extracted/ output directory created by the docs-extraction test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread package.json
Comment thread tests/validate-signing-example.test.ts
Comment thread tests/validate-signing-example.test.ts
Comment thread tests/validate-signing-example.test.ts
Comment thread README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/validate-signature-defs-inline.test.ts (1)

1-41: ⚡ Quick win

Consolidate shared defs tests into the canonical defs test file.

This standalone file adds shared app.certified.signature.defs coverage that should live in tests/validate-signature-defs.test.ts to keep one canonical defs test target and avoid drift between parallel suites.

Based on learnings: For this repository’s tests, when validating a shared defs lexicon, keep a single validate-<lexicon-slug>.test.ts file with a representative carrier.

🤖 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 `@tests/validate-signature-defs-inline.test.ts` around lines 1 - 41, This file
duplicates shared tests for app.certified.signature.defs; remove these tests
from tests/validate-signature-defs-inline.test.ts and merge them into the
canonical tests/validate-signature-defs.test.ts: copy the three cases (valid
inline object using validateInline and two validate(...) calls that assert
missing required fields) into the canonical defs test file, keeping the same
assertions and using validateInline and validate from generated imports, then
delete the standalone validate-signature-defs-inline.test.ts to avoid
parallel/duplicated coverage.
🤖 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 `@ERD.puml`:
- Around line 254-262: The ERD's dataclass linkEvm is missing the optional
property "signatures" defined in lexicons/app/certified/link/evm.json; update
the dataclass linkEvm in ERD.puml to include signatures alongside address,
proof, and createdAt (ensure it follows the SHOW_FIELDS conditional like the
other fields and marks it as optional if your ERD convention supports that).

In `@lexicons/app/certified/signature/defs.json`:
- Around line 22-25: The "signature" property currently allows arbitrary-length
byte arrays; constrain it to the exact ECDSA raw (r,s) length by adding length
limits to the "signature" field in lexicons/app/certified/signature/defs.json
(the "signature" property): set minLength and maxLength to 64 (32-byte r +
32-byte s) so only 64-byte signatures pass schema validation.

---

Nitpick comments:
In `@tests/validate-signature-defs-inline.test.ts`:
- Around line 1-41: This file duplicates shared tests for
app.certified.signature.defs; remove these tests from
tests/validate-signature-defs-inline.test.ts and merge them into the canonical
tests/validate-signature-defs.test.ts: copy the three cases (valid inline object
using validateInline and two validate(...) calls that assert missing required
fields) into the canonical defs test file, keeping the same assertions and using
validateInline and validate from generated imports, then delete the standalone
validate-signature-defs-inline.test.ts to avoid parallel/duplicated coverage.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d24334cf-05ff-4c03-b58c-b0e4d952183b

📥 Commits

Reviewing files that changed from the base of the PR and between ca8408d and b40da9f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (35)
  • .agents/skills/building-with-hypercerts-lexicons/SKILL.md
  • .changeset/add-signature-support.md
  • .gitignore
  • AGENTS.md
  • ERD.puml
  • README.md
  • SCHEMAS.md
  • lexicons/app/certified/actor/organization.json
  • lexicons/app/certified/actor/profile.json
  • lexicons/app/certified/badge/award.json
  • lexicons/app/certified/badge/definition.json
  • lexicons/app/certified/badge/response.json
  • lexicons/app/certified/graph/follow.json
  • lexicons/app/certified/link/evm.json
  • lexicons/app/certified/location.json
  • lexicons/app/certified/signature/defs.json
  • lexicons/app/certified/signature/proof.json
  • lexicons/org/hyperboards/board.json
  • lexicons/org/hyperboards/displayProfile.json
  • lexicons/org/hypercerts/claim/activity.json
  • lexicons/org/hypercerts/claim/contribution.json
  • lexicons/org/hypercerts/claim/contributorInformation.json
  • lexicons/org/hypercerts/claim/rights.json
  • lexicons/org/hypercerts/collection.json
  • lexicons/org/hypercerts/context/acknowledgement.json
  • lexicons/org/hypercerts/context/attachment.json
  • lexicons/org/hypercerts/context/evaluation.json
  • lexicons/org/hypercerts/context/measurement.json
  • lexicons/org/hypercerts/funding/receipt.json
  • lexicons/org/hypercerts/workscope/tag.json
  • package.json
  • tests/validate-signature-defs-inline.test.ts
  • tests/validate-signature-defs.test.ts
  • tests/validate-signature-proof.test.ts
  • tests/validate-signing-example.test.ts

Comment thread ERD.puml
Comment thread lexicons/app/certified/signature/defs.json
Copilot AI review requested due to automatic review settings May 26, 2026 14:54
@aspiers
aspiers removed the request for review from Copilot May 26, 2026 14:54
aspiers added a commit that referenced this pull request Jun 9, 2026
…fied set

app.certified.signature.proof does not exist as a record lexicon on main — it
is added by PR #219 (feat/signature-support-v2, HYPER-181). Including it here
made app.certified.permissions.crud reference a non-existent collection
(correctly flagged in review). Drop it, leaving the 8 app.certified.* record
collections that actually exist on main.

Documents in the Maintenance section that the set must gain
app.certified.signature.proof once #219 merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aspiers

aspiers commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Heads-up: cross-PR dependency with #222 (permission sets).

#222 adds an app.certified.permissions.crud permission set that enumerates every app.certified.* record collection (the spec forbids wildcards inside a permission set, so collections are listed explicitly). This PR adds a new record lexicon — app.certified.signature.proof — which is not on main yet, so #222 deliberately does not include it.

When this PR (#219) merges, app.certified.signature.proof must be added to app.certified.permissions.crud's collection list and the set re-published, otherwise write access to that collection won't be grantable via the set's include: scope.

The two PRs touch disjoint files, so merge order doesn't matter — whichever lands second (or a small follow-up) just needs to reconcile the set. This is documented in #222's docs/design/permission-sets.md Maintenance section.

🤖 Generated with Claude Code

Comment thread .agents/skills/building-with-hypercerts-lexicons/SKILL.md Outdated
aspiers added 11 commits June 24, 2026 13:15
Add optional cryptographic signature support to record lexicons,
enabling platform attestation and verification that records were
created through trusted services.

Inspired by:
- ATProtocol Attestation Specification by Nick Gerakines
- The platformAttestation pattern from app.bumicerts.link.evm

New lexicons:
- app.certified.signature.inline: Inline signature with JOSE algorithm
  identifiers (ES256K, ES256, Ed25519) per ATProto convention
- app.certified.signature.defs: Shared type definitions providing the
  `#list` array def (an open union of inline signatures and strongRefs
  to remote attestation proofs). Follows the atproto convention of
  putting reusable defs in a dedicated `*.defs` lexicon; see the
  lexicon spec section on "Lexicon Files" and the style guide's
  recommendation for `.defs` schemas.
- app.certified.signature.proof: Remote attestation proof record
  holding the CID of attested content, hosted in the attestor's
  repository

19 record lexicons gain an optional `signatures` property (a flat
array referencing app.certified.signature.defs#list) so callers access
them as record.signatures[] with no wrapper nesting. This matches the
ATProtocol Attestation Specification while keeping the array
definition DRY via a single shared lexicon def.

Lexicons updated:
- org.hypercerts.claim.* (activity, contribution, contributorInformation,
  rights)
- org.hypercerts.collection
- org.hypercerts.context.* (acknowledgement, attachment, evaluation,
  measurement)
- org.hypercerts.funding.receipt
- org.hypercerts.workscope.tag
- org.hyperboards.* (board, displayProfile)
- app.certified.badge.* (award, definition, response)
- app.certified.actor.* (profile, organization)
- app.certified.location

app.certified.link.evm is deliberately excluded: it already carries
its own EIP-712 wallet-ownership proof in the `proof` field, which is
the integrity mechanism for its semantic DID ↔ wallet claim. The
EIP-712 signature is incompatible with the ATProto attestation spec
(different preimage, hash function, signature format, and binding
model), and adding a second signing mechanism on the same record
would provide no additional trust while inviting confusion about
which signature is authoritative.

Includes validation tests for inline signatures, proof records, and
signatures attached to records, plus regenerated SCHEMAS.md, ERD.puml,
README.md, and a changeset.
…tion

Tighten the signature lexicons added in this PR to conform strictly to the
ATProtocol Attestation Specification, rather than carrying speculative
extensions inherited from the original design draft.

- Remove signatureType from app.certified.signature.inline. The spec has no
  such field; the signing curve is canonically derived from the multicodec
  prefix on the verification method's publicKeyMultibase. A separate tag
  was redundant in the happy path and a downgrade-attack vector in the
  adversarial path (could disagree with the multicodec).

- Drop Ed25519 from the documented algorithm story. EdDSA isn't excluded
  by normative MUST/SHALL language in the spec but the spec's signing
  primitive is ECDSA + BIP-0062 low-S and the multicodec->curve table
  only covers 0xE701 (K-256) and 0x1200 (P-256). Ed25519-signed records
  would be schema-valid but unverifiable by spec-conforming verifiers.

- Remove maxLength: 100 cap on app.certified.signature.defs#list. No
  rationale was ever recorded for the bound and the spec does not
  restrict array length.

- Update lexicon descriptions to use spec terminology: 36-byte CIDv1,
  canonical DAG-CBOR, BIP-0062 low-S, \$sig repository binding.

- Rewrite README signatures section to claim conformance explicitly,
  drop the now-stale JOSE algorithm-identifiers table, add a brief
  signing/verification procedure summary, and explain replay defense
  via CID + \$sig.repository.

- Update changeset language from "inspired by" to "conforms to".

- Drop signatureType usages from tests and remove the now-meaningless
  open-knownValues test case.

- Regenerate SCHEMAS.md.
Align with the per-lexicon naming convention in AGENTS.md
("one file per lexicon, named validate-<lexicon-slug>.test.ts").
The tests cover the array def at app.certified.signature.defs#list
(open union of inline + strongRef, optional/empty/mixed array
semantics), so signature-defs is the lexicon under test. Activity
is just the representative carrier — all 19 record lexicons share
the same def.

Addresses CodeRabbit feedback on PR #170.
…g tests

The "one file per lexicon" rule is a default, not a strict requirement.
When a test exercises behavior that spans multiple lexicons or code
files (shared *.defs lexicons, cross-cutting union semantics, etc.),
pick the clearest name for what's under test rather than duplicating
near-identical tests across every carrier.

Cite validate-signature-defs.test.ts as an illustrative example.

Surfaced by CodeRabbit feedback on PR #170.
…gnatures to all records

Two coupled changes:

1. Move inline signature object from its own lexicon
   (app.certified.signature.inline) into signature.defs#inline. Aligns
   with the earlier signature.list -> signature.defs#list move:
   non-record helper defs belong in the *.defs lexicon, not as
   standalone lexicons. Matches ATProto convention (e.g.
   app.bsky.embed.defs, app.bsky.richtext.facet#mention).

2. Add the signatures property to graph.follow and link.evm,
   bringing all 21 record lexicons under the signature umbrella.

   On link.evm specifically: the original PR deliberately excluded
   this record on the rationale that its EIP-712 proof field already
   provides integrity. That conflated two orthogonal trust statements.
   The EIP-712 proof proves wallet consent (the EVM key holder agreed
   to be linked to the DID). The signatures array proves record
   provenance (e.g. that a platform UI minted the record, defending
   against replay of harvested EIP-712 signatures). Both are useful
   and they do not conflict, so signatures applies here too.

Test changes:
- Rename tests/validate-signature-inline.test.ts to
  validate-signature-defs-inline.test.ts (the lexicon under test
  is now signature.defs).
- Switch to the generated validateInline() helper instead of the
  generic validate() + cast, removing an `as unknown` smell.
- Update inline $type strings from app.certified.signature.inline
  to app.certified.signature.defs#inline throughout.

Regenerate SCHEMAS.md.
The signatures property is uniform across all ~20 record lexicons, so
drawing the relationships individually would just be a thicket of
identical "signatures" edges without communicating any additional
structure. Replace the partial activity-only depiction with a comment
explaining the deliberate omission; signature lexicons remain
documented in SCHEMAS.md and README.md.
Bring the agent-facing skill guide in line with the rest of the
signature work on this PR. Adds:

- Signatures subsection in Lexicon Overview covering signature.defs
  and signature.proof
- Note in the EVM Link row that link.evm can additionally carry
  signatures[] for record provenance on top of EIP-712 wallet consent
- Updated Relationship Map listing signature/defs and signature/proof,
  with a note explaining why the per-record signatures arrows aren't
  drawn
- "Attaching Cryptographic Signatures" example showing mixed inline
  + remote-attestation usage, plus a short signing-procedure summary
  pointing at the ATProto Attestation Specification
- "Creating a Remote Attestation Proof" example for the proof record
The Leaflet URL is a useful background blog post but not the
normative specification document. Update all doc references so the
primary link is the canonical spec at tangled.org and the blog post
appears as a secondary "see also" link. Affects README, changeset,
and the building-with-hypercerts-lexicons skill.
Previously the cryptographic signatures example presented a record
with signatures already embedded, using a placeholder comment for the
ECDSA bytes and explaining the signing procedure only afterward. That
reads backwards: a developer wanting to attach a signature needs to
see how the bytes are produced first.

Rewrite both README and SKILL.md so the example walks step by step:

1. Build the inline signature object — compute the spec-defined CID
   over the record (insert temporary \$sig with repository DID, encode
   canonical DAG-CBOR, hash to 36-byte CIDv1) and ECDSA-sign with
   @atproto/crypto's Secp256k1Keypair.sign() which enforces low-S
   automatically.
2. Build a remote attestation strongRef (optional).
3. Attach either or both to the record via spread.

Uses canonical ATProto + IPLD libraries (@atproto/crypto,
@ipld/dag-cbor, multiformats) rather than placeholder pseudocode.
multiformats is already a runtime dep of this package; the others
are shown as consumer imports.
Defends against docs/test divergence by making the docs themselves
the test source. The new test reads README.md and the
building-with-hypercerts-lexicons skill, finds the "Cryptographic
Signatures" section in each, extracts every fenced TypeScript code
block under it, concatenates them into one ESM module (deduping
imports and appending synthetic exports for the identifiers we want
to inspect), writes the result to tests/extracted/ (gitignored), and
dynamically imports.

For each source file, asserts:

- Extraction + execution succeeds without throwing
- The produced CID is a 36-byte CIDv1 with the dag-cbor/SHA-256 prefix
- Secp256k1Keypair.sign() returns 64 raw r,s bytes
- The inline signature has the correct \$type and references the
  signature bytes
- The remote-attestation strongRef has the correct \$type and at://
  URI
- Both signatures attach to the final record in order
- The resulting record (with a syntactically valid CID substituted
  for the "bafy..." placeholder) passes lexicon validation
- The produced signature verifies via @atproto/crypto verifySignature

Adds @atproto/crypto and @ipld/dag-cbor to devDependencies (only used
by this test; not exposed to package consumers).
Line 51 restated what line 13's #inline description already says
about ECDSA + low-S + multicodec-derived curve. Addresses review
comment on PR #170.
Copilot AI and others added 6 commits June 24, 2026 13:15
Local git worktree directories live under .git-worktrees/ and contain
checked-out copies of other branches. ESLint was descending into them
and producing parser errors for files outside the active tsconfig.
Drop the long lexicon enumeration and design-notes block, restructure
into a short lead + bullet list, and add a bullet mentioning the new
"Cryptographic Signatures" sections in README, SCHEMAS.md, and the
building-with-hypercerts-lexicons skill.
Address review feedback that the signing example encouraged a
throwaway-key anti-pattern (Secp256k1Keypair.create({ exportable:
false }) on every signature). Restructure the example to introduce
the keypair as a long-lived, persisted identity:

- Add a "Key management" callout before the procedure explaining
  why the platform signing key must be generated once, persisted in
  secure storage, and reused across every signed record.
- Introduce a new "Step 1: load (or create) the platform signing
  keypair" block that uses exportable: true, demonstrates
  export()/import(), and points to KMS/sealed-secret integration.
- Renumber the existing steps (inline signature build, remote
  attestation, attach to record) to 2/3/4 and reuse the persisted
  keypair from Step 1 instead of creating a fresh one inline.

Mirrors the change in both README.md and the
building-with-hypercerts-lexicons agent skill so the
docs-extraction test exercises the same persisted-key flow.
Post-rebase chores bundled together because the pre-commit hook
requires SCHEMAS.md to be regenerated and staged in the same commit
as any lexicon-affecting change.

- Regenerate SCHEMAS.md to pick up the `signatures` property entries
  on the carrier records and table-width shifts from main.
- Add .git-worktrees/ to .prettierignore (mirrors the .git-worktrees/
  entry added to eslint.config.mjs earlier on this branch).
Copilot AI review requested due to automatic review settings June 24, 2026 13:24
@aspiers
aspiers force-pushed the feat/signature-support-v2 branch from 35493c5 to cb4cd1f Compare June 24, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@aspiers

aspiers commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Discussed with @s-adamantine, @Ashex, and @holkexyz, and agreed to merge now. Non-breaking change which has been hanging around for too long already and is a straightforward implementation of Nick's upstream attestation spec.

@aspiers
aspiers requested a review from Ashex June 24, 2026 15:53
@s-adamantine
s-adamantine requested review from s-adamantine and removed request for Ashex June 24, 2026 15:56
@aspiers
aspiers merged commit 3491959 into main Jun 24, 2026
6 checks passed
@aspiers
aspiers deleted the feat/signature-support-v2 branch June 24, 2026 15:57
aspiers added a commit that referenced this pull request Jun 25, 2026
…fied set

app.certified.signature.proof does not exist as a record lexicon on main — it
is added by PR #219 (feat/signature-support-v2, HYPER-181). Including it here
made app.certified.permissions.crud reference a non-existent collection
(correctly flagged in review). Drop it, leaving the 8 app.certified.* record
collections that actually exist on main.

Documents in the Maintenance section that the set must gain
app.certified.signature.proof once #219 merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers pushed a commit that referenced this pull request Jun 25, 2026
… set

PR #219 (signature support, HYPER-181) has now merged to main, adding the
app.certified.signature.proof record lexicon. This was the documented follow-up:
app.certified.authWrite must enumerate every app.certified.* record collection,
so the newly-landed collection has to be added or it is not grantable via the
published set.

Add it (the set now lists all 9 app.certified.* records, verified identical to
the type:"record" defs on disk), sync the JSONC example in the design doc, and
drop the now-resolved "Known pending update (#219)" note from the Maintenance
section. SCHEMAS.md regenerated. npm run check passes (182 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers added a commit that referenced this pull request Jul 1, 2026
…fied set

app.certified.signature.proof does not exist as a record lexicon on main — it
is added by PR #219 (feat/signature-support-v2, HYPER-181). Including it here
made app.certified.permissions.crud reference a non-existent collection
(correctly flagged in review). Drop it, leaving the 8 app.certified.* record
collections that actually exist on main.

Documents in the Maintenance section that the set must gain
app.certified.signature.proof once #219 merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers pushed a commit that referenced this pull request Jul 1, 2026
… set

PR #219 (signature support, HYPER-181) has now merged to main, adding the
app.certified.signature.proof record lexicon. This was the documented follow-up:
app.certified.authWrite must enumerate every app.certified.* record collection,
so the newly-landed collection has to be added or it is not grantable via the
published set.

Add it (the set now lists all 9 app.certified.* records, verified identical to
the type:"record" defs on disk), sync the JSONC example in the design doc, and
drop the now-resolved "Known pending update (#219)" note from the Maintenance
section. SCHEMAS.md regenerated. npm run check passes (182 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers added a commit that referenced this pull request Jul 6, 2026
…fied set

app.certified.signature.proof does not exist as a record lexicon on main — it
is added by PR #219 (feat/signature-support-v2, HYPER-181). Including it here
made app.certified.permissions.crud reference a non-existent collection
(correctly flagged in review). Drop it, leaving the 8 app.certified.* record
collections that actually exist on main.

Documents in the Maintenance section that the set must gain
app.certified.signature.proof once #219 merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers pushed a commit that referenced this pull request Jul 6, 2026
… set

PR #219 (signature support, HYPER-181) has now merged to main, adding the
app.certified.signature.proof record lexicon. This was the documented follow-up:
app.certified.authWrite must enumerate every app.certified.* record collection,
so the newly-landed collection has to be added or it is not grantable via the
published set.

Add it (the set now lists all 9 app.certified.* records, verified identical to
the type:"record" defs on disk), sync the JSONC example in the design doc, and
drop the now-resolved "Known pending update (#219)" note from the Maintenance
section. SCHEMAS.md regenerated. npm run check passes (182 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hypercerts-release-bot hypercerts-release-bot Bot mentioned this pull request Jul 6, 2026
aspiers added a commit that referenced this pull request Jul 6, 2026
…fied set

app.certified.signature.proof does not exist as a record lexicon on main — it
is added by PR #219 (feat/signature-support-v2, HYPER-181). Including it here
made app.certified.permissions.crud reference a non-existent collection
(correctly flagged in review). Drop it, leaving the 8 app.certified.* record
collections that actually exist on main.

Documents in the Maintenance section that the set must gain
app.certified.signature.proof once #219 merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers pushed a commit that referenced this pull request Jul 6, 2026
… set

PR #219 (signature support, HYPER-181) has now merged to main, adding the
app.certified.signature.proof record lexicon. This was the documented follow-up:
app.certified.authWrite must enumerate every app.certified.* record collection,
so the newly-landed collection has to be added or it is not grantable via the
published set.

Add it (the set now lists all 9 app.certified.* records, verified identical to
the type:"record" defs on disk), sync the JSONC example in the design doc, and
drop the now-resolved "Known pending update (#219)" note from the Maintenance
section. SCHEMAS.md regenerated. npm run check passes (182 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aspiers added a commit that referenced this pull request Jul 7, 2026
… set

PR #219 (signature support, HYPER-181) has now merged to main, adding the
app.certified.signature.proof record lexicon. This was the documented follow-up:
app.certified.authWrite must enumerate every app.certified.* record collection,
so the newly-landed collection has to be added or it is not grantable via the
published set.

Add it (the set now lists all 9 app.certified.* records, verified identical to
the type:"record" defs on disk), sync the JSONC example in the design doc, and
drop the now-resolved "Known pending update (#219)" note from the Maintenance
section. SCHEMAS.md regenerated. npm run check passes (182 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants