Skip to content

Commit ecefeec

Browse files
docs(notion-md): spec — correct dispatch table to the stateless reality
The dispatch table's drift-REFUSE rows ("remote moved underneath", "local hand-edited") are not realizable for single-source pages: with no stored base (R31) the engine cannot distinguish "I edited" from "the other side moved" — both are just `local ≢ remote`. Per R31/R32 the declared `source` decides the winner unconditionally (local- or remote-authoritative mirror); concurrent-edit detection/refusal is exclusively the `source: shared` story. Aligns the spec with the implementation (PR #775) and the grilled statelessness invariant. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 40573fb commit ecefeec

1 file changed

Lines changed: 27 additions & 16 deletions

File tree

  • packages/@overeng/notion-md/docs/vrs

packages/@overeng/notion-md/docs/vrs/spec.md

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,33 @@ git's staging, commits, and branches are rejected entirely — there is no `add`
9999
#### `sync` dispatch table (per file)
100100

101101
The action is decided per file from `source`, the presence of `page_id`, and a
102-
live compare (R33). This refuse-on-wrong-direction is what makes a
103-
wrong-direction push **structurally impossible** (R30): a `remote` file has no
104-
push path; a `local` file refuses rather than clobbering.
105-
106-
| `source` | `page_id` | live compare (R33) | action |
107-
| -------- | ----------- | ------------------------------------ | -------------------------------------------------------------------------------- |
108-
| local | null/absent || create remote page under `parent`, write `page_id` back |
109-
| local | set | equivalent | noop |
110-
| local | set | local changed, remote == last render | push (guarded live re-read, R11) |
111-
| local | set | remote moved underneath | REFUSE (would clobber unseen remote edit); suggest `clone --as shared` |
112-
| remote | set | equivalent | noop |
113-
| remote | set | remote changed | pull (overwrite local body) |
114-
| remote | set | local hand-edited | REFUSE + warn ("source: remote; local edits aren't pushed — set source: shared") |
115-
| remote | absent || error (a remote-tracked file must carry `page_id`) |
116-
| shared | set | 3-way merge vs base | noop / merge / `conflict.roughdraft` |
117-
| shared | absent || error (`shared` requires an established `page_id`) |
102+
live compare (R33). Wrong-direction push is **structurally impossible** (R30):
103+
direction is the file's `source`, so a `remote` file has no push branch and a
104+
`local` file's write is the declared mirror operation, never a flag-decided
105+
clobber.
106+
107+
| `source` | `page_id` | live compare (R33) | action |
108+
| -------- | ----------- | ------------------ | ------------------------------------------------------- |
109+
| local | null/absent || create remote page under `parent`, write `page_id` back |
110+
| local | set | equivalent | noop |
111+
| local | set | local ≢ remote | push (mirror local → remote) |
112+
| remote | set | equivalent | noop |
113+
| remote | set | local ≢ remote | pull (mirror remote → local body) |
114+
| remote | absent || error (a remote-tracked file must carry `page_id`) |
115+
| shared | set | 3-way merge vs base | noop / merge / `conflict.roughdraft` |
116+
| shared | absent || error (`shared` requires an established `page_id`) |
117+
118+
> **Statelessness boundary (R31/R32).** Single-source pages carry no stored base,
119+
> so the engine cannot distinguish "I edited locally" from "the other side moved"
120+
> — both present as `local ≢ remote`. The declared `source` therefore decides the
121+
> winner unconditionally: `local` is authoritative (a `local` page silently
122+
> mirrors over any remote drift), `remote` is authoritative (a `remote` page
123+
> silently refreshes the local mirror, discarding stray local edits — recoverable
124+
> from git). **Concurrent-edit *detection and refusal* is exclusively the
125+
> `source: shared` story** — it is the one mode with a stored base able to tell
126+
> the two cases apart, and is the safety net a user opts into when both sides
127+
> genuinely author. Attempting drift-refusal for single-source would require the
128+
> very stored marker R31 forbids (and that caused the poisoned-`noop`).
118129
119130
#### Frontmatter schema (one file shape for all three `source` values)
120131

0 commit comments

Comments
 (0)