Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/MacDocCLI/MacDoc+Word.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extension MacDoc.Word {
var toMdocx: String

@Flag(name: .customLong("from-oplog"),
help: "強制使用 oplog sidecar(<stem>.oplog.jsonl;找不到時報錯)")
help: "強制使用 oplog sidecar(優先 <docx-full-name>.oplog.jsonl;缺少時可讀 legacy <stem>.oplog.jsonl;兩者皆無則報錯)")
var fromOplog = false

@Flag(help: "覆寫既有的輸出檔案")
Expand Down
16 changes: 11 additions & 5 deletions openspec/specs/ooxml-word-sync/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1106,12 +1106,12 @@ code:
---
### Requirement: Sidecar persistence of snapshot and log

The orchestrator SHALL persist the operation log as `<docx-stem>.oplog.jsonl` and the most-recently-imported snapshot tree as `<docx-stem>.snapshot.json` in the same directory as the docx. The orchestrator SHALL NOT write metadata into the docx itself.
The orchestrator SHALL persist the operation log as `<docx-full-name>.oplog.jsonl` and the most-recently-imported snapshot tree as `<docx-full-name>.snapshot.json` in the same directory as the docx. For example, `report.docx` uses `report.docx.oplog.jsonl` and `report.docx.snapshot.json`. The orchestrator SHALL NOT write metadata into the docx itself. During migration, loaders SHALL fall back to the legacy stem paths (`report.oplog.jsonl` / `report.snapshot.json`) when the full-name path is absent; writers SHALL create only the full-name paths.

#### Scenario: Sidecar files created on first sync

- **WHEN** `SyncOrchestrator.bootstrapFromDocx(url:)` runs on a docx with no existing sidecar files
- **THEN** `<docx-stem>.oplog.jsonl` is created (initially empty) and `<docx-stem>.snapshot.json` is created with the initial tree snapshot
- **THEN** `<docx-full-name>.oplog.jsonl` is created (initially empty) and `<docx-full-name>.snapshot.json` is created with the initial tree snapshot

#### Scenario: docx contains zero sync metadata

Expand Down Expand Up @@ -1291,13 +1291,19 @@ The orchestrator SHALL provide `SyncOrchestrator.bootstrapFromDocx(url:)` that i

#### Scenario: Fresh docx without sidecars

- **GIVEN** `report.docx` exists with no `report.oplog.jsonl` and no `report.snapshot.json`
- **GIVEN** `report.docx` exists with none of `report.docx.oplog.jsonl`, `report.docx.snapshot.json`, `report.oplog.jsonl`, or `report.snapshot.json`
- **WHEN** `bootstrapFromDocx(url:)` runs
- **THEN** sidecars are created with the docx's current state as the snapshot and an empty log; subsequent Swift mutations append to the new log

#### Scenario: Legacy-only sidecars migrate on the next write

- **GIVEN** `report.docx`, `report.oplog.jsonl`, and `report.snapshot.json` exist, while the full-name sidecars are absent
- **WHEN** `bootstrapFromDocx(url:)` runs and the session subsequently persists sidecar state
- **THEN** the orchestrator loads the legacy history and snapshot, writes the resulting state only to `report.docx.oplog.jsonl` and `report.docx.snapshot.json`, and neither overwrites nor deletes the legacy files

#### Scenario: Existing sidecars are reused

- **GIVEN** `report.docx`, `report.oplog.jsonl` (with prior history), and `report.snapshot.json` (from prior session) all exist
- **GIVEN** `report.docx`, `report.docx.oplog.jsonl` (with prior history), and `report.docx.snapshot.json` (from prior session) all exist
- **WHEN** `bootstrapFromDocx(url:)` runs
- **THEN** the orchestrator loads the existing log and snapshot; if the docx has changed since the snapshot's timestamp, an import diff is run to capture the intervening changes

Expand Down Expand Up @@ -1992,4 +1998,4 @@ code:
- docs/stale-triage-chain-batch2-2026-05-25.md
- .remember/logs/autonomous/save-144550.log
- .remember/logs/autonomous/save-143700.log
-->
-->
Loading