fix(git-sync): propagate nested details open; drop dead delete-cap wiring; cover lost-lock abort + lose-prone atom round-trips

Addresses review 1863 (delta) on PR #119.

MUST-FIX:
- detailsToHtml (the raw-HTML path used for a details nested inside
  columns/spanned cells) now emits `<details${open}>`, mirroring the
  top-level case, so `open` no longer silently drops every round trip.
- Remove the dead `resolveApplyClient` delete-cap hook from the engine
  `runCycle`: the orchestrator stopped passing it, so the hook + its
  dry-run pass were inert. Deletes are soft (Trash) + always logged and
  engine convergence is the guard, so no cap is re-added — just the dead
  wiring removed.

TEST COVERAGE:
- space-lock: heartbeat refresh CAS-miss (eval -> 0) and Redis-error
  (eval throws) both abort the in-flight fn's signal.
- cycle: a pre-aborted signal (and an abort during the pull read) throws
  before the push apply / first destructive phase.
- converter: htmlEmbed source VALUE + height survive; encode/decode
  UTF-8 symmetry and '' -> ''; footnote definition body + ref/def id
  match; transclusionReference both ids survive; fix the bad
  transclusionSource fixture (wrong `pageId` attr + empty content ->
  schema `id` + a block child); nested details `open` parity test.
- orchestrator: autoMergeConflicts:true reaches engine settings; default
  false on a missing settings row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-26 17:53:18 +03:00
parent 42e618ec7f
commit e48d7720e9
7 changed files with 318 additions and 60 deletions

View File

@@ -854,9 +854,14 @@ export function convertProseMirrorToMarkdown(content: any): string {
// Emit a schema-matching <details> tree. The schema parses <details>,
// summary[data-type="detailsSummary"], and div[data-type="detailsContent"].
// The `open` (collapsed/expanded) state lives on the details node and the
// schema parses it back from the attribute, so emit it here too — mirroring
// the top-level `details` case — or a NESTED details (inside columns/cells)
// would silently drop `open:true` every round trip.
const detailsToHtml = (node: any): string => {
const open = node.attrs?.open ? " open" : "";
const inner = (node.content || []).map(blockToHtml).join("");
return `<details>${inner}</details>`;
return `<details${open}>${inner}</details>`;
};
const detailsSummaryToHtml = (node: any): string =>
`<summary data-type="detailsSummary">${inlineToHtml(node.content || [])}</summary>`;