upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/C1.md
blob: 8137b8e58a7d9e516efe18a27d0738f62c23f9f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
NIP-C1
======

Collaborative Ownership
-----------------------

`draft` `optional`

This NIP defines a mechanism for multiple pubkeys to collaboratively maintain events.

## Motivation

Certain applications require shared ownership where:

1. **Attribution matters**: Each collaborator signs with their own key
2. **Dynamic membership**: Owners can be added or removed
3. **Backwards compatibility**: Non-supporting clients see normal events

## Specification

### Collaborative Pointer Event

An addressable event kind `39382` serves as a pointer to collaboratively-owned content:

```jsonc
{
  "kind": 39382,
  "pubkey": "<creator-pubkey>",
  "tags": [
    ["d", "<identifier>"],
    ["k", "<target-kind>"],
    ["p", "<owner-1-pubkey>"],
    ["p", "<owner-2-pubkey>"],
    ["p", "<owner-3-pubkey>"]
  ],
  "content": "",
  "created_at": 1234567890
}
```

#### Tag Definitions

| Tag | Required | Description |
|-----|----------|-------------|
| `d` | Yes | Shared identifier for the collaborative content |
| `k` | Yes | Target event kind (any kind) |
| `p` | Yes | Owner pubkeys (one or more) |

The creator's pubkey is implicitly an owner and SHOULD NOT appear in `p` tags.

### Target Events

Any event kind MAY be a target of collaborative ownership. All target events:

- MUST include a `d` tag matching the pointer's `d` tag
- MUST include an `a` tag referencing the `39382` pointer event

```jsonc
{
  "kind": <target-kind>,
  "pubkey": "<owner-pubkey>",
  "tags": [
    ["d", "<identifier>"],
    ["a", "39382:<pointer-creator-pubkey>:<identifier>"]
  ],
  "content": "..."
}
```

The `d` tag is required regardless of whether the target kind is normally addressable. For addressable event kinds (30000-39999), the `d` tag serves its usual role. For all other kinds, the `d` tag enables grouping and correlation with the pointer.

### Resolution Algorithm

To resolve the current state of collaboratively-owned content:

1. Parse the `39382` pointer event to extract owners (`p` tags) and target kind (`k` tag)
2. Extract the identifier from the `d` tag
3. Query: `{"kinds": [<target-kind>], "authors": [<all-owners>], "#d": ["<identifier>"]}`
4. For addressable target kinds: return the event with the highest `created_at`
5. For non-addressable target kinds: return all matching events that contain a valid `a` tag backlinking to the pointer

### Initial Discovery

Clients that do not yet have any version of the event MUST query by `#d` tag alone or by known owner pubkeys.

## Client Behavior

### Co-Author Attribution

Clients SHOULD NOT display co-author attribution for a target event unless:

1. The event contains an `a` tag referencing a `39382` pointer event, **and**
2. The event's author pubkey appears in that pointer's `p` tags (or is the pointer's creator)

An event without a verifiable `a` tag backlink to a `39382` pointer MUST NOT be presented as collaboratively authored. This prevents spoofed co-authorship claims.

### Display Recommendations

- Clients SHOULD display which pubkey signed each version
- Clients SHOULD indicate when an event is part of a collaborative set
- Clients MAY show the full owner set from the pointer event alongside the signing pubkey

## Examples

### Pointer Event

```jsonc
{
  "kind": 39382,
  "pubkey": "alice-pubkey",
  "tags": [
    ["d", "collaborative-guide"],
    ["k", "30023"],
    ["p", "bob-pubkey"],
    ["p", "carol-pubkey"]
  ],
  "content": ""
}
```

### Addressable Target (kind 30023)

```jsonc
{
  "kind": 30023,
  "pubkey": "bob-pubkey",
  "tags": [
    ["d", "collaborative-guide"],
    ["title", "A Collaborative Guide"],
    ["a", "39382:alice-pubkey:collaborative-guide"]
  ],
  "content": "..."
}
```

### Non-Addressable Target (kind 4199)

```jsonc
{
  "kind": 4199,
  "pubkey": "carol-pubkey",
  "tags": [
    ["d", "collaborative-guide"],
    ["a", "39382:alice-pubkey:collaborative-guide"]
  ],
  "content": "..."
}
```

### Client Resolution

1. Client receives `naddr` for the `39382` pointer
2. Parses owners: `[alice, bob, carol]`, target kind: `30023`
3. Queries: `{"kinds": [30023], "authors": ["alice", "bob", "carol"], "#d": ["collaborative-guide"]}`
4. Filters results: only events with `["a", "39382:alice-pubkey:collaborative-guide"]` are considered collaborative
5. Returns most recent version (for addressable kinds) or full set (for non-addressable kinds)

## Security Considerations

- Owners can unilaterally modify content
- An `a` tag backlink alone is insufficient — clients MUST verify the referenced pointer event includes the author in its `p` tags
- Owner changes on the pointer event take effect immediately; old target events from removed owners are no longer authoritative