Summary
After a clean local-authoritative tree sync (#747), plan reports some pages as update forever, even though their content on Notion is correct. The delta is pure round-trip canonicalization, not a real change, so the noop oracle never fires for those pages and trees can't reach a clean state.
Two distinct, reproducible canonicalization gaps:
Case A — emphasis-marker style (* vs _)
Local body uses *emphasis*; Notion's enhanced-markdown GET returns _emphasis_. The canonical comparison (semanticEquivalent) does not fold the two emphasis-marker styles, so the page is permanently update.
local : the grammar is *closed*
remote: the grammar is _closed_
Case B — paragraph following a bullet list
A paragraph written after a bullet list (blank-line separated) is attached to the last list item by Notion's enhanced-markdown parser on push. GET then returns one merged block, while the local body has two blocks. They never converge.
local:
- read state through the built-in tools.
Reads run immediately; writes route to approval.
remote (after round-trip):
- read state through the built-in tools. Reads run immediately; writes route to approval.
Repro
- Author an
.nmd page containing either shape, bind it, sync (local-authoritative).
plan the same tree again → the page is still classified update.
- Pull the page back (
sync <page-id> out.nmd) and diff against the local body → the only difference is the canonicalization above.
Impact
Benign for content fidelity (Notion holds the intended text), but:
- defeats the pushed-hash noop oracle / a clean
plan,
- forces authors to contort source markdown to dodge it, or live with always-dirty trees,
- makes "tree is in sync" unobservable for affected pages.
Proposed directions
- Case A: extend the canonical comparison to treat
*x*/_x_ (and **x**/__x__) as equivalent.
- Case B: either canonicalize "trailing paragraph adopted into preceding list item" as equivalent on comparison, or treat paragraph-after-list as a push-fidelity violation that
plan/validate warns on (so it's an authoring error, not silent perpetual churn).
Refs #673.
Posted on behalf of @schickling
| field |
value |
agent_name |
🌵 cl2-acacia |
agent_session_id |
83deaad9-b22c-455d-9e36-90816d4ac54c |
agent_tool |
Claude Code |
agent_tool_version |
2.1.165 |
agent_runtime |
Claude Code 2.1.165 |
agent_model |
claude-opus-4-8 |
worktree |
effect-utils/main |
machine |
dev3 |
tooling_profile |
dotfiles@unknown-dirty |
Summary
After a clean local-authoritative tree
sync(#747),planreports some pages asupdateforever, even though their content on Notion is correct. The delta is pure round-trip canonicalization, not a real change, so the noop oracle never fires for those pages and trees can't reach a clean state.Two distinct, reproducible canonicalization gaps:
Case A — emphasis-marker style (
*vs_)Local body uses
*emphasis*; Notion's enhanced-markdown GET returns_emphasis_. The canonical comparison (semanticEquivalent) does not fold the two emphasis-marker styles, so the page is permanentlyupdate.Case B — paragraph following a bullet list
A paragraph written after a bullet list (blank-line separated) is attached to the last list item by Notion's enhanced-markdown parser on push. GET then returns one merged block, while the local body has two blocks. They never converge.
Repro
.nmdpage containing either shape, bind it,sync(local-authoritative).planthe same tree again → the page is still classifiedupdate.sync <page-id> out.nmd) and diff against the local body → the only difference is the canonicalization above.Impact
Benign for content fidelity (Notion holds the intended text), but:
plan,Proposed directions
*x*/_x_(and**x**/__x__) as equivalent.plan/validate warns on (so it's an authoring error, not silent perpetual churn).Refs #673.
Posted on behalf of @schickling
agent_nameagent_session_idagent_toolagent_tool_versionagent_runtimeagent_modelworktreemachinetooling_profile