diff --git a/Sources/MacDocCLI/MacDoc+Word.swift b/Sources/MacDocCLI/MacDoc+Word.swift index a65d8804..8e212a9e 100644 --- a/Sources/MacDocCLI/MacDoc+Word.swift +++ b/Sources/MacDocCLI/MacDoc+Word.swift @@ -40,7 +40,7 @@ extension MacDoc.Word { var toMdocx: String @Flag(name: .customLong("from-oplog"), - help: "強制使用 oplog sidecar(.oplog.jsonl;找不到時報錯)") + help: "強制使用 oplog sidecar(優先 .oplog.jsonl;缺少時可讀 legacy .oplog.jsonl;兩者皆無則報錯)") var fromOplog = false @Flag(help: "覆寫既有的輸出檔案") diff --git a/openspec/specs/ooxml-word-sync/spec.md b/openspec/specs/ooxml-word-sync/spec.md index a506547e..956cbdb6 100644 --- a/openspec/specs/ooxml-word-sync/spec.md +++ b/openspec/specs/ooxml-word-sync/spec.md @@ -1106,12 +1106,12 @@ code: --- ### Requirement: Sidecar persistence of snapshot and log -The orchestrator SHALL persist the operation log as `.oplog.jsonl` and the most-recently-imported snapshot tree as `.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 `.oplog.jsonl` and the most-recently-imported snapshot tree as `.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** `.oplog.jsonl` is created (initially empty) and `.snapshot.json` is created with the initial tree snapshot +- **THEN** `.oplog.jsonl` is created (initially empty) and `.snapshot.json` is created with the initial tree snapshot #### Scenario: docx contains zero sync metadata @@ -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 @@ -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 ---> \ No newline at end of file +-->