super-productivity/docs
Johannes Millan 71a9a4338a
fix(sync): freeze the conflict-review producers before the next release (#9061)
* fix(sync): freeze the conflict-review producers before the next release

The conflict-review feature (962c5bbeb1) is on master but in no release
tag, so a release cut would take it to the whole stable fleet while it is
still slated for removal. The Task 1 audit found it already ships to two
pre-release cohorts: Snap `edge` is public and built from every master
push (snapd auto-refreshes subscribers), and the Play `internal` track
auto-updates its testers. The data obligation therefore already exists —
the next tag would expand it, not create it.

Journal rows persist the discarded side of a conflict verbatim (entity
titles, arbitrary field values, raw action payloads). They are
device-local, absent from backups/exports, never uploaded, and expire at
14 days / 200 rows, so the recorded decision is: no export owed, and the
store, reader, UI and the SUP_CONFLICT_JOURNAL_CLEARED_BEFORE marker get
deleted together in the rollback.

Freeze both producers at the single production entry point into
autoResolveConflictsLWW:

- disableDisjointMerge: conflicts resolve by whole-entity LWW, which is
  the behaviour of every released version to date, so stable gains no
  merge behaviour it would later have to be migrated off.
- disableConflictJournal: no new rows are persisted. record() is the
  journal's only write and both call sites are now gated, so nothing
  produces rows behind the freeze.

Wired at the caller rather than as a global flag so ConflictResolution-
Service keeps the capability for its own tests and the freeze reverts by
deleting two lines. Covered by a spec that fails if either flag is
dropped, since that regression is otherwise silent.

Records the audit in docs/plans/2026-07-16-conflict-review-cohort-audit.md.

* fix(sync): don't offer conflict REVIEW when the journal is empty

The content-conflict banner (#8694) fires off the resolutions, not off the
journal, and its SPAP-15 REVIEW action was unconditional. With the producer
freeze the journal holds no rows, so REVIEW landed the user on the review
page's empty state — a dead end at the exact moment they are worried about a
discarded edit. v18.14.0 ships this banner WITHOUT the action (it has no
navigateToReview at all), so the next tag would have taken a permanently
broken affordance to the whole stable fleet — the opposite of what the freeze
is for.

Gate the action on the journal actually holding unreviewed rows. The count
signal reads fresh: the journal loop awaits record() (which refreshes it)
before the notification step. This also fixes a latent case that predates the
freeze — _journalResolution swallows record() failures by contract, so a
transient IndexedDB error already produced the same dead end. Mirrors
maybeShowSummaryBanner, which already stays silent on an empty journal.

Also cover the freeze's callee-side gates, which had none: the guard spec in
remote-ops-processing.service.spec.ts only asserts the production caller
PASSES the flags. Deleting `if (!options.disableConflictJournal)` in
autoResolveConflictsLWW left all 292 specs green while the fleet silently
resumed persisting the discarded side of every conflict. Both new gates are
falsification-verified: each mutation fails exactly its own spec.

* refactor(sync): simplify the conflict REVIEW action gate

Use a plain ternary to undefined instead of a conditional spread: the banner
component truthy-checks `@if (banner.action)` and exactOptionalPropertyTypes
is off, so `action: undefined` is identical to omitting the key — and reads
as the same thing. Trim the rationale comment to the load-bearing why.

No behaviour change; the gate's spec is unchanged and still passes.

* fix(sync): give the integration spec's journal mock its count signal

The content-conflict banner now reads `conflictJournal.unreviewedCount()` to
decide whether to offer REVIEW, but conflict-resolution-persistence.integration
.spec.ts mocks ConflictJournalService with `['record']` only, so resolution threw
`unreviewedCount is not a function` and took the #8997 project-recovery test down
with it.

Provide a real `signal(0)` via createSpyObj's properties arg rather than a spy:
unreviewedCount is a signal on the service, so this keeps the mock honest to the
type it stands in for.

Caught by CI, not locally: the earlier run covered only the four spec files the
change touched, and this mock lives in a fifth. Full suite now green, 12928 +
12914 across both TZ variants.

* test(sync): drop the redundant journal-on control test

'journals resolutions by default' duplicated coverage that already exists: the
#8956 multi-entity test asserts record() is called twice on the default path, so
it already fails if journaling breaks entirely — which was the only thing my
control guarded against (the freeze test passing vacuously).

Collapse the leftover one-test describe and its two single-use helpers back into
a flat spec.

Full suite green: 12927 + 12913 across both TZ variants.
2026-07-16 14:43:33 +02:00
..
long-term-plans docs(sync): note local-file rev-check/write is non-atomic (#8898) (#8902) 2026-07-10 17:31:24 +02:00
plans fix(sync): freeze the conflict-review producers before the next release (#9061) 2026-07-16 14:43:33 +02:00
promotion build: better organize stuff 2025-06-27 09:03:16 +02:00
research feat(task-repeat): RFC 5545 RRULE recurring schedules — EPIC · Phase 1/13 (Closes #4020) (#7948) 2026-06-09 11:25:35 +02:00
screens docs/wiki content v0.8 (#7068) 2026-04-01 12:40:28 +02:00
sync-and-op-log fix(sync): preserve multi-entity conflict recovery (#8990) 2026-07-14 14:10:52 +02:00
wiki fix(tasks): decode multipart and transfer-encoded eml bodies #8975 (#8999) 2026-07-15 09:55:39 +02:00
add-new-integration.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
android-edge-to-edge-keyboard.md fix(android): keyboard + status-bar follow-ups for edge-to-edge (#8508) (#8548) 2026-06-23 11:57:49 +02:00
apple-release-automation.md ci: auto-submit iOS and macOS App Store builds for review (#7857) 2026-06-01 11:42:16 +02:00
build-and-publish-notes.md fix(ci): prevent duplicate unsigned exe files in GitHub Releases 2026-03-19 18:58:52 +01:00
documentation-guide.md Housekeeping for various docs, templates, and actions (#7451) 2026-05-02 13:58:25 +02:00
ENV_SETUP.md build: final approach 2025-07-14 20:52:51 +02:00
github-access-token-instructions.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
gitlab-access-token-instructions.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
handover.md fix(locale): localize remaining ISO 8601 spelled-out date names (#8987) (#9056) 2026-07-16 11:41:34 +02:00
how-to-rate.md feat(rate-dialog): action-aware prompt with feedback split 2026-05-04 17:27:11 +02:00
howto-refresh-snap-credentials.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
i18n-script-usage.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
legacy-webview-analysis.md 16.2.1 2025-11-01 13:22:58 +01:00
mac-app-store-code-signing-guide.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
performance-project-tag-report.md docs: add performance report 2025-11-13 18:23:50 +01:00
plainspace-api-extension-plan.md feat(plainspace): create tasks directly in a Plainspace-backed project (#8676) 2026-07-01 19:36:52 +02:00
plainspace-integration-plan.md refactor(sync): remove unused error classes, dialog, and constructor-time logging (phase 1, #8325) (#8510) 2026-06-20 13:36:56 +02:00
plugin-development.md fix(electron): remove exec IPC to close GHSA-256q (#8669) 2026-07-01 17:55:35 +02:00
styling-guide.md docs: update styling breakpoint table (#8846) 2026-07-07 16:50:49 +02:00
theming-contract.md feat(theme): add Plainspace built-in theme 2026-06-15 14:06:21 +02:00
TRANSLATING.md Fix frequency translations (#8000) 2026-06-05 10:53:26 +02:00
unused-translations-analysis.md chore(i18n): remove additional 86 orphan translation keys 2026-01-09 14:59:05 +01:00
update-android-app.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
update-mac-certificates.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00