docs: harden alpha product UX design
This commit is contained in:
parent
a6d349f188
commit
f59af601d6
|
|
@ -31,6 +31,8 @@ designs:
|
||||||
- Passive browser activity records only a normalized hostname and measured
|
- Passive browser activity records only a normalized hostname and measured
|
||||||
duration. It never records a page URL, title, selection, page content,
|
duration. It never records a page URL, title, selection, page content,
|
||||||
keystrokes, or browsing history.
|
keystrokes, or browsing history.
|
||||||
|
- Passive browser tracking is disabled on a new installation. It starts only
|
||||||
|
after explicit, informed consent in extension settings.
|
||||||
- Passive browser activity counts only the active tab in a focused browser
|
- Passive browser activity counts only the active tab in a focused browser
|
||||||
window. Background tabs and unfocused browser windows contribute no time.
|
window. Background tabs and unfocused browser windows contribute no time.
|
||||||
- Activity can suggest a Journal record, but the user reviews and saves it.
|
- Activity can suggest a Journal record, but the user reviews and saves it.
|
||||||
|
|
@ -52,37 +54,117 @@ retry queue remain separate from passive activity data.
|
||||||
|
|
||||||
### Domain activity tracker
|
### Domain activity tracker
|
||||||
|
|
||||||
The extension adds a small persisted tracker:
|
Passive tracking is an opt-in extension setting, `passiveActivityEnabled`, with
|
||||||
|
a default of `false`. The first extension settings view includes a concise
|
||||||
|
consent card and an unchecked switch. It states that the feature sends only a
|
||||||
|
normalized hostname and duration, and explicitly states that it does **not**
|
||||||
|
collect or send URLs, titles, page content, selections, keystrokes, or browser
|
||||||
|
history. The same explanation remains next to the switch after onboarding.
|
||||||
|
|
||||||
|
Until the user enables that switch, the extension does not subscribe to
|
||||||
|
tracking events, create activity state, or send activity records. Disabling it
|
||||||
|
stops tracking immediately, clears only the mutable unflushed accumulator, and
|
||||||
|
leaves already acknowledged Desktop activity unchanged. The user can either
|
||||||
|
retry or discard already-created pending batches through an explicit settings
|
||||||
|
action; disabling tracking never silently loses them.
|
||||||
|
|
||||||
|
When enabled, the extension uses a persisted tracker:
|
||||||
|
|
||||||
1. When an HTTP(S) page becomes the active tab of a focused browser window,
|
1. When an HTTP(S) page becomes the active tab of a focused browser window,
|
||||||
start timing its normalized lowercase hostname.
|
start timing its normalized lowercase hostname.
|
||||||
2. On tab activation, hostname change, window focus loss, or a five-minute
|
2. On tab activation, hostname change, window focus loss, browser idle/lock,
|
||||||
alarm, calculate elapsed time and add it to that hostname's local total.
|
or a five-minute alarm, write a checkpoint and calculate elapsed time. The
|
||||||
|
idle detection threshold is explicitly ten minutes; a locked state pauses
|
||||||
|
immediately.
|
||||||
3. Ignore browser-internal pages, invalid URLs, and excluded hostnames. An
|
3. Ignore browser-internal pages, invalid URLs, and excluded hostnames. An
|
||||||
exclusion `youtube.com` matches that hostname and every subdomain; the same
|
exclusion `youtube.com` matches that hostname and every subdomain; the same
|
||||||
rule applies to `x.com`.
|
rule applies to `x.com`.
|
||||||
4. On a flush, send each accumulated hostname as a `browser.activity.domain`
|
4. On a flush, freeze one record per hostname as a `browser.activity.domain`
|
||||||
record. The payload contains a schema version, idempotency ID, observed
|
batch. The payload contains a schema version, idempotency ID, observed
|
||||||
period bounds, hostname, and `durationSeconds`; it contains no URL-like
|
period bounds, hostname, and `durationSeconds`; it contains no URL-like
|
||||||
field.
|
field.
|
||||||
5. Remove a hostname's sent total only after Desktop confirms that particular
|
|
||||||
idempotency ID. On failure, shutdown, or service-worker suspension, preserve
|
|
||||||
the timestamp and totals in extension local storage and retry later.
|
|
||||||
|
|
||||||
The extension uses timestamp arithmetic rather than an in-memory interval, so
|
The persisted state has three distinct parts:
|
||||||
the behaviour survives Chromium Manifest V3 service-worker restarts. Its
|
|
||||||
manifest gains only the `windows` and `alarms` permissions needed for this
|
```text
|
||||||
flow; existing tab access is retained. Firefox uses the equivalent WebExtension
|
activeAccumulator: mutable, unsent duration and bounds by hostname
|
||||||
events.
|
pendingBatches: immutable payloads, keyed by idempotency ID
|
||||||
|
acknowledgedIds: bounded recent acknowledgement IDs
|
||||||
|
```
|
||||||
|
|
||||||
|
Flushing copies a hostname's current accumulator into a new immutable pending
|
||||||
|
batch with a newly generated ID, then clears only that copied accumulator. New
|
||||||
|
time for the same hostname accumulates in `activeAccumulator` and can become a
|
||||||
|
later batch. It never mutates an already sent batch. Retries send the stored
|
||||||
|
payload byte-for-byte. A successful acknowledgement removes only the matching
|
||||||
|
pending batch and records its ID; it cannot remove newer time. Pending batches
|
||||||
|
are sent oldest first. `acknowledgedIds` is a 30-day bounded LRU set used to
|
||||||
|
handle replayed acknowledgement messages safely; Desktop maintains its own
|
||||||
|
idempotency store as the authority.
|
||||||
|
|
||||||
|
The tracker uses timestamp arithmetic but applies a conservative ambiguity
|
||||||
|
limit. A checkpoint contributes elapsed time only if wall-clock time is
|
||||||
|
monotonic and the gap from the previous trustworthy checkpoint is no more than
|
||||||
|
ten minutes. A negative clock delta, a gap over ten minutes, an idle/locked
|
||||||
|
state, or a browser startup after a crash discards the ambiguous interval and
|
||||||
|
establishes a fresh baseline. WebExtensions have no portable system
|
||||||
|
suspend/resume event, so the first post-suspend observation is deliberately
|
||||||
|
handled by this gap rule; platform idle/lock events add an earlier pause where
|
||||||
|
available. This can undercount ambiguous work but cannot turn an overnight
|
||||||
|
sleep or a clock change into working time. A browser startup never carries an
|
||||||
|
active interval across process death; pending batches and accumulated completed
|
||||||
|
intervals are retained.
|
||||||
|
|
||||||
|
The extension persists timestamps and the three state parts in local extension
|
||||||
|
storage, so a Manifest V3 service-worker restart can continue safely. It sets
|
||||||
|
the `idle` API detection interval to ten minutes. Its manifest gains the
|
||||||
|
`windows`, `alarms`, and `idle` permissions needed for this flow; existing tab
|
||||||
|
access is retained. Firefox uses the equivalent WebExtension events when
|
||||||
|
available and otherwise applies the same ten-minute checkpoint limit.
|
||||||
|
|
||||||
The settings page gets an **Excluded domains** list. It accepts one hostname per
|
The settings page gets an **Excluded domains** list. It accepts one hostname per
|
||||||
item, normalizes case and leading dots, rejects a scheme/path/query, and
|
item through the canonical normalization below, and explains that a hostname
|
||||||
explains that a hostname excludes its subdomains. The default list is empty.
|
excludes its subdomains. The default list is empty. Adding an exclusion stops
|
||||||
|
the matching active measurement immediately and discards only its mutable
|
||||||
|
unflushed time; immutable pending batches remain available for the user's
|
||||||
|
explicit retry or discard decision.
|
||||||
|
|
||||||
|
### Canonical hostname normalization
|
||||||
|
|
||||||
|
Every extension event, exclusion, and Desktop domain binding uses
|
||||||
|
`hostname-normalization-v1`. It is a normative shared contract, not an
|
||||||
|
implementation detail of one component:
|
||||||
|
|
||||||
|
1. An activity source must be an HTTP(S) URL. Its port, user info, path, query,
|
||||||
|
and fragment are discarded before hostname normalization. A binding or
|
||||||
|
exclusion must be a bare hostname; schemes, paths, queries, fragments, and
|
||||||
|
ports are rejected.
|
||||||
|
2. Trim surrounding whitespace, lowercase, and remove exactly one DNS root
|
||||||
|
trailing dot. `example.com.` therefore becomes `example.com`.
|
||||||
|
3. Convert DNS names using non-transitional UTS #46 / IDNA lookup processing to
|
||||||
|
an ASCII A-label. The canonical stored and compared form of `пример.рф` is
|
||||||
|
its punycode A-label; the settings UI may render the Unicode display form.
|
||||||
|
4. IPv4 addresses are accepted in canonical dotted-decimal form. IPv6 literals
|
||||||
|
are accepted (bracketed only at URL/settings input), stored without brackets
|
||||||
|
in canonical lower-case RFC 5952 form, and never include a port. `localhost`
|
||||||
|
and syntactically valid single-label internal names are also accepted.
|
||||||
|
5. Reject empty values, malformed IP literals, invalid labels, empty labels,
|
||||||
|
labels over 63 ASCII bytes, DNS names over 253 ASCII bytes, and any input
|
||||||
|
that fails URL/IDNA parsing. Invalid activity is not counted; invalid
|
||||||
|
settings input gets an inline validation error and is not saved.
|
||||||
|
|
||||||
|
The SDK owns a versioned `hostname-normalization-v1` test-vector corpus. Desktop
|
||||||
|
and the browser extension vendor the byte-identical corpus in their tests; the
|
||||||
|
coordinated `build-all` verification checks its hash. Go and JavaScript have
|
||||||
|
separate implementations, but both must pass every vector, including trailing
|
||||||
|
dots, Unicode/punycode equivalence, IPv4, IPv6, localhost, internal names,
|
||||||
|
ports, malformed input, and excessive lengths.
|
||||||
|
|
||||||
### Desktop receiver
|
### Desktop receiver
|
||||||
|
|
||||||
Desktop exposes an authenticated activity receiver separate from the capture
|
Desktop exposes an authenticated activity receiver separate from the capture
|
||||||
receiver. It validates a bounded hostname, positive bounded duration, ISO time
|
receiver. It normalizes and validates a hostname with
|
||||||
|
`hostname-normalization-v1`, validates a positive bounded duration, ISO time
|
||||||
fields, schema version, and idempotency ID before it publishes
|
fields, schema version, and idempotency ID before it publishes
|
||||||
`browser.activity.domain`. Invalid and duplicate records do not enter Activity.
|
`browser.activity.domain`. Invalid and duplicate records do not enter Activity.
|
||||||
The existing local pairing token gates the endpoint; the token is never placed
|
The existing local pairing token gates the endpoint; the token is never placed
|
||||||
|
|
@ -102,11 +184,16 @@ loaded when the plugin host starts, not only while the plugin view is mounted.
|
||||||
The Activity service subscribes once to public events, normalizes and persists
|
The Activity service subscribes once to public events, normalizes and persists
|
||||||
them, rebuilds candidates, and releases subscriptions on host teardown.
|
them, rebuilds candidates, and releases subscriptions on host teardown.
|
||||||
|
|
||||||
The platform provides unsubscribe-capable event subscriptions. Activity writes
|
The platform provides unsubscribe-capable event subscriptions. Command
|
||||||
use the existing atomic plugin-settings update primitive, preventing concurrent
|
registration is owned by the background service so commands remain available
|
||||||
browser/file events from overwriting each other. Command registration is also
|
without opening the Activity view.
|
||||||
owned by the background service so commands remain available without opening
|
|
||||||
the Activity view.
|
Raw Activity data is not held in `settings.json`. The Desktop storage layer
|
||||||
|
provides a lifecycle-safe, plugin-scoped append-only event log for
|
||||||
|
`verstak.activity` under plugin data. Appending one event does not rewrite the
|
||||||
|
whole log. Plugin settings retain only compact preferences; plugin data retains
|
||||||
|
candidate watermarks and indexes. Appends and compaction are serialized by the
|
||||||
|
storage layer, preventing lost updates.
|
||||||
|
|
||||||
### Candidate rules
|
### Candidate rules
|
||||||
|
|
||||||
|
|
@ -114,17 +201,43 @@ Activity presents chronological sessions rather than a raw log by default. A
|
||||||
browser activity session displays, for example, `admin.client-site.ru · 1 ч
|
browser activity session displays, for example, `admin.client-site.ru · 1 ч
|
||||||
32 мин`; it exposes no hidden URL/title data.
|
32 мин`; it exposes no hidden URL/title data.
|
||||||
|
|
||||||
A candidate is scoped to one existing Дело and local calendar day. It is ready
|
A logical session is scoped to one existing Дело and is split only by a
|
||||||
when either:
|
different Дело, a 20-minute idle gap, or 120 minutes of total session span. It
|
||||||
|
is not split merely because midnight passes. A session is ready when either:
|
||||||
|
|
||||||
- meaningful events in its session cover at least ten minutes and include at
|
- meaningful events in its session cover at least ten minutes and include at
|
||||||
least two events; or
|
least two events; or
|
||||||
- it contains one or more browser-domain records totaling at least ten minutes.
|
- it contains one or more browser-domain records totaling at least ten minutes.
|
||||||
|
|
||||||
`workspace.selected`, `file.opened`, and `note.opened` are diagnostic context,
|
`workspace.selected`, `file.opened`, and `note.opened` are diagnostic context,
|
||||||
not meaningful work by themselves. Candidate identity is stable by case, local
|
not meaningful work by themselves.
|
||||||
day, and source event IDs. Accepted and dismissed state is persisted, so an
|
|
||||||
already handled candidate does not reappear after a restart.
|
Each logical session receives a stable `sessionId` derived from its case and
|
||||||
|
first ordered event; the service stores that ID on each appended event and
|
||||||
|
preserves the session-start metadata through log compaction. It persists an
|
||||||
|
ordered handled watermark
|
||||||
|
`{ occurredAt, activityId }` and optional state for the latest reviewed slice.
|
||||||
|
A candidate contains only source events after that watermark:
|
||||||
|
|
||||||
|
- **Accepting** a candidate stores its `sessionId` and handled watermark on the
|
||||||
|
Journal entry. Later activity can create a candidate only for the additional
|
||||||
|
interval after that watermark and only when that new interval reaches the
|
||||||
|
normal threshold.
|
||||||
|
- **Dismissing** consumes the current candidate slice through its watermark.
|
||||||
|
`A+B` therefore cannot reappear as `A+B+C`; only qualifying new work after
|
||||||
|
`B` may later be suggested.
|
||||||
|
- A dismissal is not a permanent ban on future work in the same logical
|
||||||
|
session. At least ten new meaningful minutes are required before it can be
|
||||||
|
suggested again.
|
||||||
|
|
||||||
|
An event arriving late at or before a handled watermark remains in the raw
|
||||||
|
diagnostic log but never reopens an accepted or dismissed candidate slice.
|
||||||
|
|
||||||
|
An across-midnight logical session remains one candidate. The review displays
|
||||||
|
its time apportioned by local date, preselects the date containing the largest
|
||||||
|
share of the duration (ties use the start date), and lets the user choose the
|
||||||
|
Journal date. This preserves a 23:50–00:30 session instead of losing its first
|
||||||
|
ten minutes to an artificial threshold.
|
||||||
|
|
||||||
The Journal review action opens the existing journal editor with candidate
|
The Journal review action opens the existing journal editor with candidate
|
||||||
duration, date, and a concise domain/event summary. The user may edit all
|
duration, date, and a concise domain/event summary. The user may edit all
|
||||||
|
|
@ -137,6 +250,20 @@ Activity has two clear views:
|
||||||
- **Сессии** — default, with candidate cards and activity summaries;
|
- **Сессии** — default, with candidate cards and activity summaries;
|
||||||
- **События** — a secondary diagnostic stream for technical event inspection.
|
- **События** — a secondary diagnostic stream for technical event inspection.
|
||||||
|
|
||||||
|
### Retention and deletion
|
||||||
|
|
||||||
|
The alpha retains raw Activity events for at most 60 days, 10,000 events, or
|
||||||
|
8 MiB of log data, whichever limit is reached first. On append and at service
|
||||||
|
startup, bounded compaction removes the oldest entries until all limits hold;
|
||||||
|
it does not block the UI. Candidate state is pruned once its session and every
|
||||||
|
related Journal source watermark are older than 60 days.
|
||||||
|
|
||||||
|
Saving a Journal entry does not delete its source Activity events. The Journal
|
||||||
|
entry retains the compact source session/watermark reference after raw-event
|
||||||
|
retention removes those events. **Clear activity for this Дело** removes only
|
||||||
|
that case's raw events, sessions, and candidate state after confirmation.
|
||||||
|
**Clear all activity** is a separate global confirmed operation.
|
||||||
|
|
||||||
## Browser Inbox lifecycle
|
## Browser Inbox lifecycle
|
||||||
|
|
||||||
### Record state
|
### Record state
|
||||||
|
|
@ -145,7 +272,9 @@ A capture remains one canonical record with independent fields:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
globalState: active | archived
|
globalState: active | archived
|
||||||
workspaceRootPath: optional existing Дело
|
workspaceRef: active | trashed | unavailable | orphaned
|
||||||
|
workspaceRootPath: optional active or historical Дело path
|
||||||
|
workspaceTrashId: optional stable trash identity
|
||||||
```
|
```
|
||||||
|
|
||||||
Existing records migrate to `globalState: active`; their current assignment is
|
Existing records migrate to `globalState: active`; their current assignment is
|
||||||
|
|
@ -159,16 +288,25 @@ non-destructive for an alpha user vault.
|
||||||
- **Убрать из общих входящих** changes `globalState` to `archived`. It never
|
- **Убрать из общих входящих** changes `globalState` to `archived`. It never
|
||||||
removes the assignment, so an assigned capture remains available from its
|
removes the assignment, so an assigned capture remains available from its
|
||||||
Дело.
|
Дело.
|
||||||
- **Открепить от дела** removes only `workspaceRootPath`. If the capture is
|
- **Открепить от дела** removes only the `workspaceRef` and
|
||||||
|
`workspaceRootPath`. If the capture is
|
||||||
still globally active it returns to the global Inbox; otherwise it remains in
|
still globally active it returns to the global Inbox; otherwise it remains in
|
||||||
archive.
|
archive.
|
||||||
- **Удалить везде** removes the canonical capture and its assignment. It is a
|
- **Удалить везде** removes the canonical capture and its assignment. It is a
|
||||||
separate destructive action and requires confirmation that names the affected
|
separate destructive action and requires confirmation that names the affected
|
||||||
Дело when assigned.
|
Дело when assigned.
|
||||||
- **Сохранить ссылку в деле** creates an independent `.url` file under the
|
- **Сохранить ссылку в деле** is available only for a valid HTTP(S) capture URL.
|
||||||
case's `Links/` directory, creating that directory first. Success does not
|
It opens a small save dialog with an editable proposed filename derived from
|
||||||
depend on retaining the capture record; later Inbox deletion cannot remove
|
the capture title, then its hostname, then `Link`. The stem is sanitized for
|
||||||
the written file.
|
cross-platform forbidden characters and control characters, limited to 96
|
||||||
|
characters, and receives `.url`. The file uses InternetShortcut format and
|
||||||
|
is created through the plugin `files.write` capability under the case's
|
||||||
|
`Links/` directory, creating that directory first. A name collision never
|
||||||
|
overwrites silently: the dialog offers an explicit `name (2).url` alternative
|
||||||
|
or cancellation. Read-only/error cases leave the capture unchanged and show
|
||||||
|
the failure. Success publishes the normal safe file/link Activity event; the
|
||||||
|
written file opens through the existing user-initiated OS-default-browser
|
||||||
|
file action.
|
||||||
|
|
||||||
Bulk actions operate only on the visibly filtered capture set, show the count,
|
Bulk actions operate only on the visibly filtered capture set, show the count,
|
||||||
and use archive rather than permanent deletion. Every permanent deletion and
|
and use archive rather than permanent deletion. Every permanent deletion and
|
||||||
|
|
@ -178,14 +316,54 @@ When a Дело is renamed, the Inbox service migrates its capture assignments a
|
||||||
exact domain bindings from the old root to the new root. It does not migrate a
|
exact domain bindings from the old root to the new root. It does not migrate a
|
||||||
binding that has been manually changed to another Дело during that operation.
|
binding that has been manually changed to another Дело during that operation.
|
||||||
|
|
||||||
|
When a Дело goes to Trash, assignments and bindings become `trashed` with the
|
||||||
|
Desktop trash ID. They remain visible as unavailable historical context but are
|
||||||
|
not used for automatic routing. A restore event carrying that trash ID restores
|
||||||
|
the assignment/binding, including a restored path changed by a collision. A
|
||||||
|
permanent trash purge changes captures to unassigned and changes bindings to a
|
||||||
|
visible `orphaned` state that the user can reassign or remove. Activity remains
|
||||||
|
historical and labels the case as deleted. If a case disappears by external
|
||||||
|
filesystem change, active references become `unavailable`, automatic routing is
|
||||||
|
disabled, and the user must explicitly reassign or remove them; a newly created
|
||||||
|
folder with the same name never steals those references.
|
||||||
|
|
||||||
|
### Archive and filters
|
||||||
|
|
||||||
|
Global Browser Inbox has **Active**, **Archive**, and **All** status filters;
|
||||||
|
Active is the default. Search applies within the chosen filter, so Archive is
|
||||||
|
searchable deliberately through Archive or All rather than unexpectedly
|
||||||
|
appearing in the normal queue. **Restore to Inbox** changes `globalState` back
|
||||||
|
to `active`. Archive supports a visible filtered bulk restore with a count and
|
||||||
|
confirmation. A capture assigned to a Дело remains visible in that Дело's Inbox
|
||||||
|
regardless of its global archive state, with an Archive badge.
|
||||||
|
|
||||||
## Alpha interface
|
## Alpha interface
|
||||||
|
|
||||||
- Use Russian product labels consistently: **Дела**, **Входящие**,
|
- Use Russian product labels consistently: **Дела**, **Входящие**,
|
||||||
**Активности**, and **Журнал**. User-facing dates use the local time zone.
|
**Активности**, and **Журнал**. User-facing dates use the local time zone.
|
||||||
- The overview contains only useful, properly scoped items: continuation for
|
- With a selected Дело, the overview reads only records explicitly scoped to
|
||||||
the selected Дело, new Inbox records, Journal candidates, and real recent
|
that Дело; an unscoped global event never leaks into every case. With no
|
||||||
changes. It excludes repeated `file.changed`, `workspace.selected`, and
|
selected Дело, it shows a short prompt to select/create one plus up to five
|
||||||
unrelated-case events.
|
active unassigned Inbox records; it does not fabricate a blended continuation
|
||||||
|
feed.
|
||||||
|
- **Needs attention** shows at most five entries: ready Journal candidates,
|
||||||
|
active unprocessed Inbox records, and existing urgent Todos, in that order
|
||||||
|
within their respective priority. An Inbox record is new/needs attention
|
||||||
|
while it is active and unprocessed, without an arbitrary age cutoff.
|
||||||
|
- **Continue work** shows at most four distinct case-scoped entities from the
|
||||||
|
last 14 days: unfinished Todo, unprocessed capture, and the most recent
|
||||||
|
note/file/Journal entity. Every item carries `lastMeaningfulAt`; items sort
|
||||||
|
descending by that value, with an unprocessed capture, Todo, Journal, note,
|
||||||
|
then file as deterministic ties. Multiple `file.changed` events for the same
|
||||||
|
entity collapse to one item. Opening an item does not mark it complete. Its
|
||||||
|
overflow action **Hide recommendation** stores a non-destructive
|
||||||
|
entity/event dismissal; a later meaningful change to that entity makes it
|
||||||
|
eligible again.
|
||||||
|
- **Recent changes** shows at most eight distinct case-scoped records from the
|
||||||
|
last seven days. Included events are note save/create, file create/rename or
|
||||||
|
last change per file, saved browser link, and Journal create. Technical
|
||||||
|
selection/open events are excluded. The empty state says that there were no
|
||||||
|
changes in that period.
|
||||||
- Empty states give a next action, not an empty pane.
|
- Empty states give a next action, not an empty pane.
|
||||||
- Clear, delete, and archive actions name their scope and consequences.
|
- Clear, delete, and archive actions name their scope and consequences.
|
||||||
|
|
||||||
|
|
@ -202,8 +380,8 @@ plugin permissions, or release behaviour.
|
||||||
## Error handling and privacy
|
## Error handling and privacy
|
||||||
|
|
||||||
- A failed extension delivery keeps the accumulated hostname time locally and
|
- A failed extension delivery keeps the accumulated hostname time locally and
|
||||||
reports a non-blocking retry state in extension settings; it never falls back
|
reports the pending-batch count and a non-blocking retry state in extension
|
||||||
to Browser Inbox capture.
|
settings; it never falls back to Browser Inbox capture.
|
||||||
- Receiver authentication/validation errors provide a safe status to the
|
- Receiver authentication/validation errors provide a safe status to the
|
||||||
extension without echoing the pairing token or untrusted payload.
|
extension without echoing the pairing token or untrusted payload.
|
||||||
- Activity never manufactures a case from missing assignment data.
|
- Activity never manufactures a case from missing assignment data.
|
||||||
|
|
@ -213,18 +391,21 @@ plugin permissions, or release behaviour.
|
||||||
|
|
||||||
Automated checks must cover:
|
Automated checks must cover:
|
||||||
|
|
||||||
- browser tracker start/stop, focused-tab-only accounting, exclusions,
|
- browser tracker explicit consent/disable behaviour, focused-tab-only
|
||||||
coalescing, acknowledgement-only reset, retry persistence, and payload
|
accounting, exclusions, canonical hostname vectors, immutable pending
|
||||||
privacy;
|
batches, acknowledgement-only reset, retry persistence, payload privacy,
|
||||||
- Desktop activity receiver authentication, validation, idempotency, binding,
|
negative clock changes, long gaps, restart, lock, and suspend/resume;
|
||||||
and event publication;
|
- Desktop activity receiver authentication, canonical normalization,
|
||||||
- atomic Activity persistence, background subscription lifecycle, candidate
|
validation, idempotency, binding, and event publication;
|
||||||
threshold/state, Journal handoff, local dates, and missing-Journal feedback;
|
- append-only Activity log retention/compaction, background subscription
|
||||||
- assigning, archiving, unlinking, permanent deletion, `.url` creation,
|
lifecycle, handled watermarks, across-midnight review, Journal handoff,
|
||||||
filtered bulk operations, and renaming an assigned Дело;
|
local dates, case-scoped clear, and missing-Journal feedback;
|
||||||
|
- assigning, archiving, restoring, unlinking, permanent deletion, `.url`
|
||||||
|
naming/collision/readonly behaviour, filtered bulk operations, rename, trash
|
||||||
|
restore/purge, and external-workspace unavailability;
|
||||||
- normal and debug-mode plugin tab labels;
|
- normal and debug-mode plugin tab labels;
|
||||||
- the corrected frontend Wails mock, plus the end-to-end flows
|
- the corrected frontend Wails mock, deterministic Overview limits/scoping,
|
||||||
activity-to-Journal and Inbox-to-Дело.
|
plus the end-to-end flows activity-to-Journal and Inbox-to-Дело.
|
||||||
|
|
||||||
Manual GUI smoke testing verifies Russian normal-mode labels, hidden plugin
|
Manual GUI smoke testing verifies Russian normal-mode labels, hidden plugin
|
||||||
IDs, candidate review, Inbox preservation, and extension domain exclusions in
|
IDs, candidate review, Inbox preservation, and extension domain exclusions in
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue