diff --git a/openspec/changes/use-platform-native-graph-paths/.openspec.yaml b/openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/.openspec.yaml similarity index 100% rename from openspec/changes/use-platform-native-graph-paths/.openspec.yaml rename to openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/.openspec.yaml diff --git a/openspec/changes/use-platform-native-graph-paths/design.md b/openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/design.md similarity index 100% rename from openspec/changes/use-platform-native-graph-paths/design.md rename to openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/design.md diff --git a/openspec/changes/use-platform-native-graph-paths/proposal.md b/openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/proposal.md similarity index 100% rename from openspec/changes/use-platform-native-graph-paths/proposal.md rename to openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/proposal.md diff --git a/openspec/changes/use-platform-native-graph-paths/specs/graph-location/spec.md b/openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/specs/graph-location/spec.md similarity index 100% rename from openspec/changes/use-platform-native-graph-paths/specs/graph-location/spec.md rename to openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/specs/graph-location/spec.md diff --git a/openspec/changes/use-platform-native-graph-paths/tasks.md b/openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/tasks.md similarity index 100% rename from openspec/changes/use-platform-native-graph-paths/tasks.md rename to openspec/changes/archive/2026-08-03-use-platform-native-graph-paths/tasks.md diff --git a/openspec/specs/graph-location/spec.md b/openspec/specs/graph-location/spec.md new file mode 100644 index 0000000..ee4e83a --- /dev/null +++ b/openspec/specs/graph-location/spec.md @@ -0,0 +1,144 @@ +# graph-location Specification + +## Purpose +TBD - created by archiving change use-platform-native-graph-paths. Update Purpose after archive. +## Requirements +### Requirement: Explicit graph override has highest precedence +Trawler SHALL use a present, non-empty `TRAWLER_GRAPH_DIR` instead of platform-default or +legacy graph selection. It SHALL preserve arbitrary OS-native path values, resolve an explicit +ordinary relative value against the launch working directory without dereferencing symlinks, +reject Windows drive-relative and rooted-without-prefix forms actionably, enforce that the +selected path is absolute, and reject a present empty value before opening or creating storage. + +#### Scenario: Absolute override wins +- **WHEN** `TRAWLER_GRAPH_DIR` names an absolute path and native or legacy graphs also exist +- **THEN** Trawler selects the override without acquiring cwd or the native data root +- **AND** does not inspect default graph candidates + +#### Scenario: Relative override is intentional +- **WHEN** `TRAWLER_GRAPH_DIR` contains a non-empty relative path +- **THEN** Trawler selects its absolute equivalent under the launch working directory +- **AND** does not treat it as an accidental default + +#### Scenario: Unsafe Windows-relative override is refused +- **WHEN** `TRAWLER_GRAPH_DIR` is drive-relative or rooted without a drive or UNC prefix on Windows +- **THEN** Trawler exits before acquiring cwd or graph storage +- **AND** reports how to provide an absolute or ordinary relative path + +#### Scenario: Relative override requires cwd +- **WHEN** `TRAWLER_GRAPH_DIR` is relative and the launch working directory cannot be obtained +- **THEN** Trawler exits before graph storage starts +- **AND** reports that an absolute override can be used instead + +#### Scenario: Empty override is refused +- **WHEN** `TRAWLER_GRAPH_DIR` is present but empty +- **THEN** Trawler exits before GPUI or graph storage starts +- **AND** reports that the override must be removed or set to a non-empty path + +### Requirement: Default graph uses the platform data directory +Without an explicit override or selected legacy compatibility graph, Trawler SHALL use +an absolute `/trawler/graph`: roaming AppData on Windows, Application Support on +macOS, and XDG data home with the standard home fallback on Linux. Trawler MUST NOT create a +default graph relative to the process working directory. + +#### Scenario: First launch creates the native default +- **WHEN** no override, native graph, or valid legacy graph exists +- **THEN** Trawler selects the platform-native `trawler/graph` path for creation +- **AND** leaves `/trawler-graph` absent + +#### Scenario: Existing native graph opens normally +- **WHEN** no override is present and the native default contains a valid graph while no valid legacy graph exists +- **THEN** Trawler selects the native graph + +#### Scenario: Native data root is unavailable or relative +- **WHEN** no override is present and the operating system cannot provide an absolute native data directory +- **THEN** Trawler exits before graph storage starts +- **AND** instructs the user to set `TRAWLER_GRAPH_DIR` +- **AND** does not select a legacy graph as a substitute + +#### Scenario: Default selection requires cwd +- **WHEN** no override is present and the launch working directory cannot be obtained for legacy detection +- **THEN** Trawler exits before inspecting or opening graph storage +- **AND** instructs the user to set an absolute `TRAWLER_GRAPH_DIR` + +#### Scenario: Interrupted first creation is retryable +- **WHEN** the native graph directory has no recognized graph marker and contains only `meta.json` and/or `snapshot.loro.tmp` +- **THEN** Trawler may select it for a retry of first creation +- **AND** any unrelated entry or `updates.log` instead keeps the directory occupied + +#### Scenario: Occupied native directory is not adopted +- **WHEN** the native graph directory is non-empty, has no recognized graph marker, and is not the narrowly recoverable partial-init set +- **THEN** Trawler exits before creating or modifying files there +- **AND** identifies the occupied path without advising the user to empty the directory + +### Requirement: Legacy cwd graphs remain accessible without automatic migration +Without an explicit override, Trawler SHALL recognize a graph candidate only when its +`snapshot.loro` marker is a regular file. Candidate inspection MUST distinguish not-found from +filesystem errors and MUST fail closed on dangling symlinks, permission, traversal, +wrong-file-type, canonicalization, or other inspection failures. A candidate path that is a +symlink to an existing directory SHALL remain eligible for marker probing and alias detection. +Resolution MUST NOT copy, move, delete, open, or otherwise mutate +either candidate while deciding which path to select. + +#### Scenario: Legacy-only graph remains accessible +- **WHEN** a recognized legacy graph exists and no recognized native graph exists +- **THEN** Trawler selects the legacy graph +- **AND** warns that compatibility behavior was used +- **AND** names both the legacy path and the preferred native path + +#### Scenario: Native and legacy graphs are ambiguous +- **WHEN** recognized graphs exist at both native and legacy paths and resolve to different existing directories +- **THEN** Trawler exits before opening either graph +- **AND** reports both absolute paths +- **AND** instructs the user to select one explicitly with `TRAWLER_GRAPH_DIR` + +#### Scenario: Aliased candidates are one graph +- **WHEN** native and legacy paths both have graph markers and canonicalize to the same directory +- **THEN** Trawler selects the native path spelling +- **AND** warns that the legacy path aliases the selected graph + +#### Scenario: Merely named directory is not legacy data +- **WHEN** `/trawler-graph` exists without a regular graph marker +- **THEN** Trawler does not select or mutate it as a legacy graph +- **AND** selects the native default according to ordinary rules + +#### Scenario: Candidate inspection fails closed +- **WHEN** Trawler cannot inspect or canonicalize a candidate needed for selection +- **THEN** it exits before opening or creating either graph +- **AND** reports the affected path and operating-system error + +### Requirement: Active graph selection is diagnosable +Trawler SHALL report the selected absolute graph path and resolution source before opening +storage, and SHALL continue to show the selected path in the application titlebar after +startup. Selection failures MUST identify the relevant candidate paths and corrective action. +The selected `PathBuf` MUST preserve non-UTF-8 values exactly even if a human-facing display is +lossy; startup diagnostics SHALL use an escaped representation that distinguishes underlying bytes. + +#### Scenario: Successful startup reports source +- **WHEN** Trawler selects an override, platform default, or legacy compatibility graph +- **THEN** startup diagnostics state the absolute path and corresponding source + +#### Scenario: Ambiguity is actionable +- **WHEN** path selection refuses an ambiguous native-plus-legacy state +- **THEN** diagnostics provide enough path and override information to relaunch without guessing + +#### Scenario: Diagnostics precede storage access +- **WHEN** startup resolves a graph path successfully +- **THEN** it emits the selected path and source before opening or creating graph storage +- **AND** any resolution error exits before GPUI or graph storage starts + +### Requirement: Graph-location behavior is documented and regression-tested +The repository SHALL document platform-native paths, override precedence, legacy warnings, +ambiguous-state recovery, and manual migration. Deterministic tests MUST cover the resolver's +precedence and lazy acquisition, native suffix and absolute-root validation, empty/missing inputs, +candidate probe errors and aliases, the legacy decision matrix, startup ordering, and diagnostic +source without mutating shared process environment or cwd. + +#### Scenario: Contributor verifies path policy +- **WHEN** the graph-location test suite runs in parallel with other tests +- **THEN** it exercises synthetic resolver inputs without changing global environment variables or working directory + +#### Scenario: User follows migration documentation +- **WHEN** a user has a legacy cwd graph or both legacy and native graphs +- **THEN** the documentation explains how to close Trawler, back up, move or copy the complete directory, verify via an explicit override, retire the complete legacy directory, and select a graph without ambiguity +