From c0638851c600795461eaff9893317a8a7b241121 Mon Sep 17 00:00:00 2001 From: Gigi Date: Sun, 19 Oct 2025 10:54:31 +0200 Subject: [PATCH] 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 --- public/md/NIP-85.md | 142 +++++--------------------------------------- 1 file changed, 14 insertions(+), 128 deletions(-) diff --git a/public/md/NIP-85.md b/public/md/NIP-85.md index efe918c9..84573816 100644 --- a/public/md/NIP-85.md +++ b/public/md/NIP-85.md @@ -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::` (matching the article's coordinate) - For external URLs: `url:` - `a` (optional but recommended for Nostr articles): Article coordinate `30023::` - `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::"], ["a", "30023::"] - ], - "id": "", - "sig": "" + ] } ``` -### 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": "", - "sig": "" + ] } ``` - -## Querying - -### All progress for a user - -```json -{ - "kinds": [39802], - "authors": [""] -} -``` - -### Progress for a specific Nostr article - -```json -{ - "kinds": [39802], - "authors": [""], - "#d": ["30023::"] -} -``` - -Or using the `a` tag: - -```json -{ - "kinds": [39802], - "authors": [""], - "#a": ["30023::"] -} -``` - -### Progress for a specific URL - -```json -{ - "kinds": [39802], - "authors": [""], - "#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) -