docs: simplify NIP-85 to match NIP-84 style and length

- Remove verbose rationale section
- Remove excessive querying examples
- Remove privacy considerations (obvious)
- Remove implementation notes fluff
- Remove references section
- Keep only essential: format, tags, content, examples
- Match NIP-84's concise, to-the-point style

From 190 lines down to ~75 lines - much more readable
This commit is contained in:
Gigi
2025-10-19 10:54:31 +02:00
parent 9b6b14cfe8
commit c0638851c6

View File

@@ -8,33 +8,26 @@ This NIP defines kind `39802`, a parameterized replaceable event for tracking re
## Table of Contents
* [Event Kind](#event-kind)
* [Event Structure](#event-structure)
* [Format](#format)
* [Tags](#tags)
* [Content](#content)
* [Semantics](#semantics)
* [Examples](#examples)
* [Querying](#querying)
* [Privacy Considerations](#privacy-considerations)
* [Rationale](#rationale)
* [Implementation Notes](#implementation-notes)
## Event Kind
- `39802`: Reading Progress (Parameterized Replaceable)
## Event Structure
## Format
Reading progress events use NIP-33 parameterized replaceable semantics. The `d` tag serves as the unique identifier per author and target content.
### Tags
Events SHOULD tag the source of the reading progress, whether nostr-native or not. `a` tags should be used for nostr events and `r` tags for URLs.
When tagging a URL, clients generating these events SHOULD do a best effort of cleaning the URL from trackers or obvious non-useful information from the query string.
- `d` (required): Unique identifier for the target content
- For Nostr articles: `30023:<pubkey>:<identifier>` (matching the article's coordinate)
- For external URLs: `url:<base64url-encoded-url>`
- `a` (optional but recommended for Nostr articles): Article coordinate `30023:<pubkey>:<identifier>`
- `r` (optional but recommended for URLs): Raw URL of the external content
- Clients SHOULD clean URLs from tracking parameters and non-essential query strings before tagging
### Content
@@ -42,23 +35,16 @@ The content is a JSON object with the following fields:
- `progress` (required): Number between 0 and 1 representing reading progress (0 = not started, 1 = completed)
- `loc` (optional): Number representing a location marker (e.g., pixel scroll position, page number, etc.)
- `ts` (optional): Unix timestamp (seconds) when the progress was recorded. This is for display purposes only; event ordering MUST use `created_at`
- `ver` (optional): Schema version string (e.g., "1")
- `ts` (optional): Unix timestamp (seconds) when the progress was recorded
- `ver` (optional): Schema version string
### Semantics
The latest event by `created_at` per (`pubkey`, `d`) pair is authoritative (NIP-33 semantics).
- The latest event by `created_at` per (`pubkey`, `d`) pair is authoritative (NIP-33 semantics)
- Clients SHOULD implement rate limiting to avoid excessive relay traffic:
- Debounce writes (recommended: 5 seconds)
- Only save when progress changes significantly (recommended: ≥1% delta)
- Skip saving very early progress (recommended: <5%)
- Always save on completion (progress = 1) and when unmounting/closing content
- The `created_at` timestamp SHOULD match the time the progress was observed
- Event ordering and replaceability MUST use `created_at`, not the optional `ts` field in content
Clients SHOULD implement rate limiting to avoid excessive relay traffic (debounce writes, only save significant changes).
## Examples
### Nostr Article Progress
### Nostr Article
```json
{
@@ -69,13 +55,11 @@ The content is a JSON object with the following fields:
"tags": [
["d", "30023:<author-pubkey>:<article-identifier>"],
["a", "30023:<author-pubkey>:<article-identifier>"]
],
"id": "<event-id>",
"sig": "<signature>"
]
}
```
### External URL Progress
### External URL
```json
{
@@ -86,104 +70,6 @@ The content is a JSON object with the following fields:
"tags": [
["d", "url:aHR0cHM6Ly9leGFtcGxlLmNvbS9wb3N0"],
["r", "https://example.com/post"]
],
"id": "<event-id>",
"sig": "<signature>"
]
}
```
## Querying
### All progress for a user
```json
{
"kinds": [39802],
"authors": ["<user-pubkey>"]
}
```
### Progress for a specific Nostr article
```json
{
"kinds": [39802],
"authors": ["<user-pubkey>"],
"#d": ["30023:<author-pubkey>:<article-identifier>"]
}
```
Or using the `a` tag:
```json
{
"kinds": [39802],
"authors": ["<user-pubkey>"],
"#a": ["30023:<author-pubkey>:<article-identifier>"]
}
```
### Progress for a specific URL
```json
{
"kinds": [39802],
"authors": ["<user-pubkey>"],
"#r": ["https://example.com/post"]
}
```
## Privacy Considerations
Reading progress events are public by default to enable interoperability between clients. Users concerned about privacy should:
- Use clients that allow disabling progress sync
- Use clients that allow selective relay publishing
- Be aware that reading progress reveals their reading habits
A future extension could define an encrypted variant for private progress tracking, but that is out of scope for this NIP.
## Rationale
### Why a dedicated kind instead of NIP-78 application data?
While NIP-78 (kind 30078) can store arbitrary application data, a dedicated kind offers several advantages:
1. **Discoverability**: Other clients can easily find and display reading progress without knowing application-specific `d` tag conventions
2. **Interoperability**: Standard schema enables cross-client compatibility
3. **Indexing**: Relays can efficiently index and query reading progress separately from other app data
4. **Semantics**: Clear, well-defined meaning for the event kind
### Why parameterized replaceable (NIP-33)?
- Each article/URL needs exactly one current progress value per user
- Automatic deduplication by relays reduces storage and bandwidth
- Simple last-write-wins semantics based on `created_at`
- Efficient querying by `d` tag
### Why include both `d` and `a`/`r` tags?
- `d` provides the unique key for replaceability
- `a` and `r` enable efficient filtering without parsing `d` values
- Redundancy improves relay compatibility and query flexibility
## Implementation Notes
- Clients SHOULD use the event's `created_at` as the authoritative timestamp for sorting and merging progress
- The optional `ts` field in content is for display purposes only (e.g., "Last read 2 hours ago")
- For URLs, the base64url encoding in the `d` tag MUST use URL-safe characters (replace `+` with `-`, `/` with `_`, remove padding `=`)
- Clients SHOULD validate that `progress` is between 0 and 1
### URL Handling
When generating events for external URLs:
- Clients SHOULD clean URLs by removing tracking parameters (e.g., `utm_*`, `fbclid`, etc.) and other non-essential query strings
- The cleaned URL should be used for both the `r` tag and the base64url encoding in the `d` tag
- This ensures that the same article from different sources (with different tracking params) maps to the same reading progress event
## References
- [NIP-01: Basic protocol flow](https://github.com/nostr-protocol/nips/blob/master/01.md)
- [NIP-33: Parameterized Replaceable Events](https://github.com/nostr-protocol/nips/blob/master/33.md)