diff --git a/.changeset/add-acknowledgement-lexicon.md b/.changeset/add-acknowledgement-lexicon.md new file mode 100644 index 00000000..802401cf --- /dev/null +++ b/.changeset/add-acknowledgement-lexicon.md @@ -0,0 +1,5 @@ +--- +"@hypercerts-org/lexicon": minor +--- + +Add org.hypercerts.acknowledgement lexicon for bidirectional inclusion links between records across PDS repos diff --git a/ERD.puml b/ERD.puml index 7d06514e..574e502f 100644 --- a/ERD.puml +++ b/ERD.puml @@ -200,6 +200,17 @@ dataclass collection { !endif } +' org.hypercerts.acknowledgement +dataclass acknowledgement { + !if (SHOW_FIELDS == "true") + subject + context + acknowledged + comment? + createdAt + !endif +} + 'together { ' Funders are represented by DIDs or human-readable strings @@ -296,6 +307,11 @@ collection::items --> activity collection::items --> collection : "recursive\nnesting" collection::location --> location +acknowledgement::subject --> activity +acknowledgement::subject --> contributorInformation +acknowledgement::context --> collection +acknowledgement::context --> activity + activity::contributors -l--> contributorInformation activity::contributors --> contributionDetails activity::rights --> rights diff --git a/README.md b/README.md index bf469e78..a4f9a033 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,73 @@ const collectionRecord = { are optional and support either embedded image blobs or URI references to external images. +### Acknowledging Inclusion + +The `org.hypercerts.acknowledgement` record enables bidirectional +linking between records that live in different PDS repositories. When +one user includes another user's record (e.g. adding an activity to a +collection), the owner of the included record can create an +acknowledgement to confirm or reject the inclusion. This forms a +two-way link that an AppView can verify. + +Each acknowledgement uses `com.atproto.repo.strongRef` fields to +reference both the **subject** (the record being included) and the +**context** (the record it's being included in). + +See [SCHEMAS.md](SCHEMAS.md) for the full property reference. + +#### Use Case: Activity Included in a Collection + +A project organizer (Alice) creates a collection and adds Bob's +activity to it via a `strongRef` in the collection's `items[]` array. +Bob then creates an acknowledgement in his own repo to confirm: + +```typescript +import { ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon"; + +// Bob acknowledges that his activity is included in Alice's collection +const ack = { + $type: ACKNOWLEDGEMENT_NSID, + subject: { + uri: "at://did:plc:bob/org.hypercerts.claim.activity/3k2abc", + cid: "bafy...", + }, + context: { + uri: "at://did:plc:alice/org.hypercerts.claim.collection/7x9def", + cid: "bafy...", + }, + acknowledged: true, + createdAt: new Date().toISOString(), +}; +``` + +#### Use Case: Contributor Included in an Activity + +Alice creates an activity that lists Bob as a contributor. Bob creates +an acknowledgement in his own repo to confirm his participation: + +```typescript +const ack = { + $type: ACKNOWLEDGEMENT_NSID, + subject: { + // Bob's contributor information record + uri: "at://did:plc:bob/org.hypercerts.claim.contributorInformation/abc123", + cid: "bafy...", + }, + context: { + // Alice's activity that lists Bob as contributor + uri: "at://did:plc:alice/org.hypercerts.claim.activity/3k2abc", + cid: "bafy...", + }, + acknowledged: true, + comment: "Confirming my contribution to this reforestation project", + createdAt: new Date().toISOString(), +}; +``` + +Setting `acknowledged: false` explicitly rejects inclusion, which an +AppView can use to flag disputed associations. + ### Adding Locations to Activities The `locations` field in activity records is an array of strong references diff --git a/SCHEMAS.md b/SCHEMAS.md index 8591248c..a638d21b 100644 --- a/SCHEMAS.md +++ b/SCHEMAS.md @@ -7,6 +7,24 @@ Hypercerts-specific lexicons for tracking impact work and claims. +### `org.hypercerts.acknowledgement` + +**Description:** Acknowledges the inclusion of one record (subject) within another (context). Typically created in the subject owner's repo to form a bidirectional link. For example, a contributor acknowledging inclusion in an activity, or an activity owner acknowledging inclusion in a collection. + +**Key:** `tid` + +#### Properties + +| Property | Type | Required | Description | Comments | +| -------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `subject` | `ref` | ✅ | The record whose inclusion is being acknowledged (e.g. an activity, a contributor information record). | | +| `context` | `ref` | ✅ | The record that includes the subject (e.g. a collection/project that includes an activity, or an activity that includes a contributor). | | +| `acknowledged` | `boolean` | ✅ | Whether inclusion is acknowledged (true) or rejected (false). | | +| `comment` | `string` | ❌ | Optional comment providing additional context or reasoning. | maxLength: 1000 | +| `createdAt` | `string` | ✅ | Client-declared timestamp when this record was originally created. | | + +--- + ### `org.hypercerts.claim.activity` **Description:** A hypercert record tracking impact work. diff --git a/lexicons/org/hypercerts/acknowledgement.json b/lexicons/org/hypercerts/acknowledgement.json new file mode 100644 index 00000000..21137bf0 --- /dev/null +++ b/lexicons/org/hypercerts/acknowledgement.json @@ -0,0 +1,41 @@ +{ + "lexicon": 1, + "id": "org.hypercerts.acknowledgement", + "defs": { + "main": { + "type": "record", + "description": "Acknowledges the inclusion of one record (subject) within another (context). Typically created in the subject owner's repo to form a bidirectional link. For example, a contributor acknowledging inclusion in an activity, or an activity owner acknowledging inclusion in a collection.", + "key": "tid", + "record": { + "type": "object", + "required": ["subject", "context", "acknowledged", "createdAt"], + "properties": { + "subject": { + "type": "ref", + "ref": "com.atproto.repo.strongRef", + "description": "The record whose inclusion is being acknowledged (e.g. an activity, a contributor information record)." + }, + "context": { + "type": "ref", + "ref": "com.atproto.repo.strongRef", + "description": "The record that includes the subject (e.g. a collection/project that includes an activity, or an activity that includes a contributor)." + }, + "acknowledged": { + "type": "boolean", + "description": "Whether inclusion is acknowledged (true) or rejected (false)." + }, + "comment": { + "type": "string", + "description": "Optional comment providing additional context or reasoning.", + "maxLength": 1000 + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "Client-declared timestamp when this record was originally created." + } + } + } + } + } +}