Home app-side state in the shared App Group container
Every edition declares group.dev.rzen.indie.Kanban and homes its
app-side state there from day one (12-editions.md ruling 2026-07-29):
- AppGroup namespace: container resolution with per-edition fallback
when unprovisioned, shared UserDefaults suite, edition identity, and
a unit-test-host redirect (the test host IS the app — its launch
sweep and recents refresh must not touch the real shared container).
- BoardRecord: bookmark/isOpenNow replaced by per-edition grants and
openNow keyed by bundle id; hand-written Codable keeps legacy keys
decoding (adopted in memory as the running edition's slots, upgraded
on first save); every other field stays common.
- RecentBoard gains needsReopen: no grant of ours but somebody's —
first click runs an open panel pre-anchored at the recorded path,
prompt "Grant"; recordOpen mints this edition's slot onto the
matched shared record (path fallback only after identity fails and
only against records holding no grant of ours, so re-granting never
forks the record).
- Cross-edition freshness: stat-cheap mtime+size stamp re-reads the
registry when the sibling edition wrote it, so one edition's save
never erases the other's records wholesale.
- restorables() filters on this edition's open-now flags; the board
popover gains BoardEditionPresence ("Also open in Lanework Pro"),
pid-liveness-checked so crash residue never lies.
- Clipboard staging store moves to the group container; the sweep
claims doomed trees by atomic rename into .sweeping/ then deletes,
so the sibling's concurrent sweep is a non-event.
- Template store re-homed to the group container per the 09-templates
re-ruling; scalars (quick-style recents, window size) move to the
shared suite.
- verify-editions.sh: 30 checks (each edition carries exactly the
family group). No pathfinder 1.x migrator: 1.x predates the
registry; state starts fresh in the group container.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -19,8 +19,9 @@ import Testing
|
||||
///
|
||||
/// Plus the promise that makes the copy safe to run at all: a cancelled save leaves nothing behind.
|
||||
///
|
||||
/// Every test drives an explicit store URL. **No test may touch Application Support** — `userStore`
|
||||
/// is named here only to prove the engine never creates it on its own.
|
||||
/// Every test drives an explicit store URL. **No test may touch the real store** — which since the
|
||||
/// 2026-07-29 re-homing is in the shared App Group container, so it would be the sibling edition's
|
||||
/// template store too. `userStore` is named here only to prove the engine never creates it on its own.
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
@@ -438,14 +439,18 @@ struct SaveAsTemplateAtomicityTests {
|
||||
@Suite("Save as Template — the user store")
|
||||
struct UserTemplateStoreTests {
|
||||
|
||||
@Test("The user store is named inside the app container and is never created by naming it")
|
||||
@Test("The user store is named beside the registry in the shared home, and is never created by naming it")
|
||||
func theStoreIsNamedNotCreated() {
|
||||
let store = TemplateEngine.userStore
|
||||
|
||||
#expect(store.lastPathComponent == TemplateEngine.storeFolderName)
|
||||
#expect(store.deletingLastPathComponent().lastPathComponent
|
||||
== (Bundle.main.bundleIdentifier ?? "dev.rzen.indie.Kanban"))
|
||||
#expect(store.path.contains("Application Support"))
|
||||
// Beside the registry and the clipboard's staging store, in the App Group container
|
||||
// (09-templates.md ▸ Storage, re-homed 2026-07-29 — templates cross editions). Compared against
|
||||
// the one shared home rather than spelled out, so the assertion follows it wherever it goes —
|
||||
// including the scratch redirect a test host gets (`AppGroup.isUnitTestHost`). `AppGroup` rather
|
||||
// than the two stores' own defaults because those are `@MainActor` and this suite is not; that
|
||||
// the three agree is `AppGroupContainerTests`' assertion.
|
||||
#expect(store.deletingLastPathComponent() == AppGroup.stateDirectory)
|
||||
// Nothing here creates it, and no test may: `createUserStore(at:)` is Save as Template's and
|
||||
// Reveal in Finder's, and both are driven with an explicit store in this suite.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user