Finish the wonderland: System told truthfully, in eight tabs instead of ten
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
+1
-1
@@ -87,7 +87,7 @@ Found on **Shell › Control Center**.
|
||||
|
||||
## datetime
|
||||
|
||||
Found on **System › Date & Time**.
|
||||
Found on **System › Date, Time & Region**.
|
||||
|
||||
| Setting | Default | What it does |
|
||||
|---|---|---|
|
||||
|
||||
@@ -1672,3 +1672,235 @@ settings generator writes 38 of them).
|
||||
`search-routing-contract`, `ipc-targets-contract`, `settings-jump-contract`,
|
||||
`settings-docs-contract`, `readme-contract`, all eight of `tests/hypr/`),
|
||||
then the sandboxed-harness ones, then the live settings window last.
|
||||
|
||||
## Phase 15 (System) — the last one
|
||||
|
||||
Spec: `2026-08-24-system-redesign.md`. System went from ten tabs to eight:
|
||||
Region & Language merged into **Date, Time & Region** — a date format and the
|
||||
clock that shows it are one subject, and splitting them meant changing how a
|
||||
date is written on a page that never showed one — and the Manual became a
|
||||
routable leaf with no tab, opened from About's Manual card, a deep link, or the
|
||||
search box rather than found by scanning a strip. With that, the settings
|
||||
redesign is complete: fourteen categories, thirty-eight leaves, every one of
|
||||
them rebuilt.
|
||||
|
||||
The bug list this phase carried was longer than the layout change. The
|
||||
hardcoded Quickshell version, the auto-download switch nested inside the
|
||||
Firmware card, `CHECK_TITLES` missing `panama.updates`, two Health actions with
|
||||
no target, RegionPage's stale "Open appearance" handoff, `panama-updates`'
|
||||
stale dnf-automatic comment, the backup colour gap, Restore without
|
||||
confirmation, and four pieces of dead code.
|
||||
|
||||
Three agents edited the tree concurrently; everything below was reconciled
|
||||
against the landed files rather than against the spec's pinned shapes, and
|
||||
every contract named here was **run**.
|
||||
|
||||
### No new contracts (175 → 175)
|
||||
|
||||
Every pin fitted a file that already existed, so the suite did not grow. That
|
||||
was the judgement call this phase offered and it went the honest way: a
|
||||
`system-pages-contract` would have been a new file holding assertions that
|
||||
belong beside the ones they are variations of — the nav counts beside the nav
|
||||
taxonomy, the repair command beside the repair, the single-check verb beside
|
||||
the scan. `setup/readme-contract` — RUN, PASS ("175 contracts, as documented").
|
||||
|
||||
### What each contract gained, and why
|
||||
|
||||
- **`quickshell/settings-nav-contract` — RUN, PASS** (14 categories, 38 leaves
|
||||
of which 1 hidden, 3 retired ids). It learned the third leaf shape:
|
||||
`SettingsRoutes.hiddenLeaves`, which is how the manual stays addressable
|
||||
without a tab. A hidden leaf that is also a tab, or also a category, now
|
||||
fails — that overlap is the one the existing checks could not see, because
|
||||
the hidden half draws no row anywhere. Then: the System strip is pinned at
|
||||
exactly eight tabs in order (the number IS the point — it is the horizontal
|
||||
space one row has, and an eleventh subject needs a decision, not another
|
||||
entry), `region` is pinned to resolve specifically to `datetime` rather than
|
||||
merely to *a* leaf, `RegionPage.qml` must be gone, and the manual must be a
|
||||
leaf and must not be a tab.
|
||||
It also grew the check that would have caught the retired search entries:
|
||||
every page id in `SettingsSearch` — extra entries and group routes alike —
|
||||
must be a live leaf, with a distinct failure message when it is a retired id,
|
||||
since that is the case that still opens a window and lands somewhere else.
|
||||
Plus a table of the fifteen subjects the consolidation moved, each asserted
|
||||
to be findable by its own name on the tab that now owns it.
|
||||
- **`quickshell/settings-pages-contract` — RUN, PASS** (production PIDs
|
||||
preserved). `Updates`, `DateTime`, `Containers` and `Manual` joined the
|
||||
page-scaffold sweep; Containers is the one that was waiting for it, since its
|
||||
root was a bare `Item` and every convention the scaffold carries was
|
||||
hand-rolled there. The live routing list gained `updates`, `datetime` and
|
||||
`containers`, and the retired `region` id is now driven through the real IPC
|
||||
and asserted to land on `datetime`.
|
||||
- **`quickshell/updates-contract` — RUN, PASS** (2 dnf, 3 flatpak, 0 firmware).
|
||||
Three additions. **Download sizes add up or are not offered**: a total is
|
||||
present only when every pending item was priced, because a partial figure
|
||||
shown as the download understates it, and understating it is the direction
|
||||
that costs somebody money on a metered connection. **A changelog is a read**,
|
||||
proved by construction rather than by inspection: `dnf5`, `flatpak`,
|
||||
`fwupdmgr`, `pkexec` and `systemctl` are replaced with stubs that record
|
||||
their argv and answer nothing, and the recorded argv is then checked for
|
||||
mutating tokens — which also exercises the honest-absence path, the common
|
||||
case on a machine with third-party repositories. Names outside
|
||||
`NAME_PATTERN` must be refused before anything is launched. **One
|
||||
application, by name**: the per-app argv is asserted exactly
|
||||
(`flatpak update -y --noninteractive <id>`) against a stub, and an ID the
|
||||
last scan did not list must be refused without running flatpak at all.
|
||||
- **`quickshell/panama-doctor-contract` — RUN, PASS.** The `CHECK_TITLES`
|
||||
KeyError is pinned twice: as the invariant (every id in `CHECK_ORDER` has a
|
||||
title, asserted by importing the module) and as the path (a probe forced to
|
||||
raise must come back as a titled warning row rather than taking the report
|
||||
with it). Worth both — the bug needed the updates probe to fail, which it
|
||||
almost never does, and the containment that was supposed to catch it *was*
|
||||
the KeyError, raised inside the `except` handling the original failure.
|
||||
Then: the updates action's `target: "updates"`, driven by a fixture cache
|
||||
with a security count; `repairCommand` asserted against `REPAIR_COMMANDS`
|
||||
itself rather than restated, so an argv change cannot leave the row
|
||||
describing the old one; and the `check CHECK_ID` verb — full snapshot
|
||||
envelope, exactly one check, summary arithmetic covering only that check,
|
||||
refusal of unauthored ids with no report and no filesystem mutation, and no
|
||||
second output mode.
|
||||
The fixture also gained `XDG_CACHE_HOME`, which was leaking: `check_updates`
|
||||
reads the Updates cache from the environment rather than through
|
||||
`DoctorConfig`, so the contract had been reading the real machine's pending
|
||||
updates.
|
||||
- **`quickshell/health-service-contract` — RUN, PASS.** The both-sides pin is
|
||||
derived from both files: every `open`/`instructions` target the doctor emits
|
||||
must appear in Health's `settingsTargets`/`instructionTargets`. This is the
|
||||
one where half a change does not degrade a row, it blanks the page —
|
||||
`validAction` false makes `validCheck` false makes `consumeSnapshot` reject
|
||||
the whole report. Live fixtures either side of it: a check targeting
|
||||
`updates` is accepted intact, and one targeting `storage` — a real page the
|
||||
list deliberately omits — is rejected, which is what makes the allow-list an
|
||||
allow-list. Also `repairCommand` surviving the projection (a new known key is
|
||||
dropped silently unless it is added, and the failure is invisible: the repair
|
||||
still works, only the sentence saying what it runs is gone), a check without
|
||||
one still accepted, `refreshCheck` asking for `check <id>` and never `--json`
|
||||
while leaving the other rows and recomputing the headline counts, an unknown
|
||||
id starting no process, and `saveReport` writing the same redacted projection
|
||||
to a named file.
|
||||
- **`quickshell/health-ui-contract` — RUN, PASS.** The Colour profiles handoff
|
||||
assertion is inverted rather than deleted (Displays owns colour profile, bit
|
||||
depth, SDR brightness and saturation per output, which is more than GNOME's
|
||||
panel can say in a session it does not manage); Digital wellbeing stays. The
|
||||
repair command must be shown, and must not be gated on `lastRepair`,
|
||||
`repairingId` or a working state — after the fact is not the same answer,
|
||||
because by then the decision is made. A per-row re-check and a save-report
|
||||
row must exist. The fixture grew a `panama.updates` check whose action is
|
||||
followed for real through `requestHealthAction`, landing on `updates`: the
|
||||
third piece of the chain the doctor and the service each pin one end of.
|
||||
- **`quickshell/settings-backup-contract` — RUN, PASS.** Named snapshots
|
||||
(fifteen rows reading `2026-08-24 11:03:07` are fifteen rows nobody can
|
||||
choose between), with the name reaching a filename — which is the oldest way
|
||||
a helper gets talked into writing outside its own directory. Seven hostile
|
||||
names, each of which must either fail or produce a file inside the backup
|
||||
directory. Delete gets the same confinement as restore in the other
|
||||
direction, and a worse failure mode: restore reading the wrong file
|
||||
overwrites settings, delete resolving the wrong name destroys something that
|
||||
is not a backup. Traversal, absolute paths, an escaping symlink, an
|
||||
already-deleted name and an empty name all refused. `bytes` per row, checked
|
||||
against `stat`.
|
||||
- **`quickshell/settings-backup-live-contract` — RUN, PASS.** The colour gap,
|
||||
both halves. `layoutFromStoredDisplays` must carry `vrrMode`,
|
||||
`colorProfile`, `bitdepth`, `sdrBrightness`, `sdrSaturation` and `mirrorOf`
|
||||
through, and must still accept a record written before they existed.
|
||||
`layoutsEqual` must detect a difference in each of them — **this is the
|
||||
assertion the shipped behaviour fails**, and the reason the restore silently
|
||||
did nothing: the seven-field comparison called a snapshot with different
|
||||
colour settings equal, so the restore took the early return and reported
|
||||
success while leaving HDR off. Plus the inverse for the two float fields: a
|
||||
value that came back one ulp different is the same value, or every restore
|
||||
reapplies the layout it already has.
|
||||
Two harness seams were added for this (`layoutFor`, `layoutsMatch`), because
|
||||
the colour half is invisible from `handleRestoreOutput` — geometry restores
|
||||
perfectly and success is reported either way.
|
||||
- **`quickshell/settings-sync-contract` — RUN, PASS.** The preview's `changes`
|
||||
must be `{key, from, to}` with both sides already text, a `changeCount`
|
||||
agreeing with what would be applied, a rendered list no longer than that
|
||||
count, and no side over 200 characters — with a bundle carrying a 4000-
|
||||
character `weatherLocation` proving the cap is real rather than incidental.
|
||||
Stringifying in the helper rather than in QML is what makes the cap
|
||||
enforceable at all. Observed on this machine: 115 changes, 40 rendered,
|
||||
absent values rendered as "not set".
|
||||
- **`quickshell/manual-contract` — RUN, PASS** (5 chapters). Titles now come
|
||||
from the files: the chapter list moved to `ManualChapters.qml`, which both
|
||||
the reader and About's card instantiate, and the contract fails on any
|
||||
`label:` beside a filename — the drift it is guarding against had already
|
||||
happened, under a comment claiming it could not. It also fails if either page
|
||||
names chapter files itself. In-app links: the handler must route
|
||||
`panama://settings/<page>` through `ShellState.openSettings` while still
|
||||
sending everything else out of the desktop, asserted by following the call
|
||||
(inline block or named function, brace-matched) rather than by reading one
|
||||
line, and every such link written in a chapter must name a real leaf. Plus
|
||||
the taxonomy check inverted: the manual must be a hidden leaf and must NOT be
|
||||
a System tab.
|
||||
- **`quickshell/gnome-handoff-contract` — RUN, PASS** (6 handoffs checked
|
||||
against 37 pages). Two panels joined `OWNED`: `system region`, because Date,
|
||||
Time & Region now offers a language picker, four per-category format
|
||||
dropdowns backed by the installed locales, and a live preview of what each
|
||||
renders; and `color`, because Displays has offered a colour profile per
|
||||
output for some time. Both are derived rather than hand-asserted, so the door
|
||||
cannot come back under a name nobody thought to list. Plus two inverses:
|
||||
`RegionPage.qml` must stay gone, and `DateTimePage` must not open a GNOME
|
||||
panel for something it now does itself.
|
||||
- **`quickshell/search-routing-contract` — RUN, PASS** (146 routed settings).
|
||||
Unchanged; run because `SettingsSearch` moved.
|
||||
|
||||
### Search entries
|
||||
|
||||
Two moved: Language and Regional formats, from `region` to `datetime`. Fifteen
|
||||
added: the seven About facts nobody could search for (Hostname, Kernel version,
|
||||
Device model, Installed memory, Uptime, Serial number, BIOS version — none of
|
||||
them the label of a preference, all of them things people arrive looking for by
|
||||
name, and "Installed memory" rather than "Memory" because that one IS already a
|
||||
schema label on Bar); the two Sync verbs (Export settings, Import settings —
|
||||
"Carry settings to another machine" was the only entry, and nobody searches for
|
||||
a sentence); and six format subjects on the merged tab (Date format, Number
|
||||
format, Currency, Measurement units, Paper size, First day of the week) plus
|
||||
"Set the clock by hand".
|
||||
|
||||
### Schema docs and launcher commands regenerated
|
||||
|
||||
`quickshell/scripts/panama-settings-docs` and `panama-settings-commands` both
|
||||
run without `--check` and their output committed. `docs/settings.md` stays at
|
||||
**174 settings across 36 groups** — no preference was added this phase — but
|
||||
the `datetime` group is now "Found on **System › Date, Time & Region**", which
|
||||
is the whole point of a generated document: the tab was renamed in one place.
|
||||
|
||||
The launcher went 38 generated commands to **37**: `settings-region` was
|
||||
removed, and `settings-manual` survives because the generator learned about
|
||||
`hiddenLeaves` — a leaf with no tab is the one leaf that cannot be found by
|
||||
scanning, so it is the one that most needs a launcher entry. Keywords picked up
|
||||
the new search entries on their own: `settings-about` gained hostname, kernel
|
||||
version, device model, installed memory, uptime, serial number and BIOS
|
||||
version; `settings-datetime` gained language, regional formats and the six
|
||||
format subjects; `settings-sync` gained export and import.
|
||||
|
||||
`quickshell/settings-docs-contract` — RUN, PASS (174 settings documented).
|
||||
`quickshell/panama-commands-contract` — RUN, PASS (76 commands), after teaching
|
||||
its own leaf derivation about `hiddenLeaves` too: it counted 75 and found 76,
|
||||
which is the generator and the contract disagreeing about what a leaf is
|
||||
rather than a stale command. `quickshell/qmldir-registration-contract` — RUN,
|
||||
PASS (189 components), covering the two new ones, `ManualChapters` and
|
||||
`FieldActionRow`.
|
||||
|
||||
### Deferred, and why
|
||||
|
||||
- **`quickshell/settings-search-contract` — NOT RUN.** It daemonizes a
|
||||
Quickshell instance against the user's real XDG directories rather than a
|
||||
scratch set, and constructing `SettingsSearch` calls
|
||||
`DesktopStyle.ensureStarted()`, which replays application preferences to the
|
||||
live GTK configuration. Every case it pins was checked statically instead:
|
||||
none of the fifteen new labels equals or prefixes any of the twenty-one
|
||||
pinned queries, so none can outrank one, and every schema label is still
|
||||
reachable because the schema half of the index did not change. The new static
|
||||
page-id sweep in `settings-nav-contract` covers the failure this phase could
|
||||
actually have introduced.
|
||||
- **Nobody has typed a locale into the four format dropdowns.** The category
|
||||
round-trip is A's, through `panama-locale`; no `localectl` write was made
|
||||
from any contract here, and none should be.
|
||||
- **The manual's in-app links have not been clicked.** The handler is pinned
|
||||
structurally and every link a chapter writes is checked against the taxonomy,
|
||||
but no chapter currently writes one, so the routing has been proven correct
|
||||
and never exercised.
|
||||
- **No backup has been restored against the real store**, and no update has
|
||||
been applied. Both are pinned through stubs and scratch directories, which is
|
||||
the sanctioned path and the only one that should ever run here.
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# System redesign — the finale, 10 tabs become 8
|
||||
|
||||
Approved mock: `home-mocks/system.html` (scratchpad, :8642). Spec wins over mock on conflict.
|
||||
Storage, Snapshots, Containers keep their shipped designs (Containers gets the root-type fix
|
||||
only). TEST GRANT ACTIVE: agents may RUN contracts related to their work as they build; the
|
||||
full suite stays the orchestrator's call.
|
||||
|
||||
## Consolidation (pinned)
|
||||
|
||||
System tabs become: About · Software Update · System Health (`services`) · Storage ·
|
||||
Snapshots · Containers · **Date, Time & Region** (`datetime`) · Sync & Backup. The `region`
|
||||
tab retires (retired-map → `datetime`). The `manual` tab retires as a TAB but `manual` stays
|
||||
a routable leaf (opened from About's Manual card and existing deep links) — B determines the
|
||||
mechanism (hidden-leaf list or equivalent) and C reconciles `settings-nav-contract`'s
|
||||
category/leaf counts.
|
||||
|
||||
## Bug kills (all in scope)
|
||||
|
||||
`SystemSettings.quickshellVersion` hardcoded "0.3.0" → read `qs --version`; the auto-download
|
||||
switch nested in the Firmware card; Health's target-less "Open Software Update" actions (add
|
||||
`target: "updates"` AND extend `Health.settingsTargets` in the same change — adding one
|
||||
without the other invalidates whole snapshots); `CHECK_TITLES` missing `panama.updates`
|
||||
(KeyError on timeout); the `SettingsShell.healthDiagnostics` TypeError (guard the binding on
|
||||
`typeof item.uiDiagnostics === "function"`); RegionPage's stale "Open appearance" handoff;
|
||||
`panama-updates`' stale dnf-automatic comment; the backup **color gap**
|
||||
(`layoutFromStoredDisplays` + `layoutsEqual` extended to `vrrMode`, `colorProfile`,
|
||||
`bitdepth`, `sdrBrightness`, `sdrSaturation`, `mirrorOf` — optional/back-compat like
|
||||
`Displays.isPersistedLayoutEntry`); Restore without confirmation; stray `settings.json.*`
|
||||
temp files (clean once, and if the writer can leak them, fix the leak); dead code
|
||||
(`Containers.wouldExpose`, `SettingsSync.left`, `SettingsBackup.lastAction`,
|
||||
`HealthPage.statusLabel`; `DateTime.localTime/universalTime/rtcTime` become USED by the
|
||||
manual-set flow rather than deleted).
|
||||
|
||||
## A — services & scripts (pinned APIs)
|
||||
|
||||
- `scripts/panama-about`: rows gain `Firmware` (DMI `bios_version` + `bios_date`, bootctl
|
||||
only as fallback — it reports "n/a" here) and `Secure Boot` (mokutil, absent-tolerant); a
|
||||
`Panama` row (`git describe --tags --always --dirty` + `%cr`, absent-tolerant outside a
|
||||
checkout), placed right after `Operating system`. `SystemSettings.quickshellVersion` now
|
||||
parsed from `qs --version`, kept as a one-shot Process started from `refresh()` and
|
||||
guarded by `quickshellVersionRead` — so a plain binding on `quickshellVersion` is enough
|
||||
and B needs no extra call. The literal stays as the fallback only.
|
||||
- `scripts/panama-updates`: `changelog <source> <name>` → `{source, name, kind, text, error}`
|
||||
where `kind` is `advisory` | `changelog` | `none` (dnf: `dnf5 advisory info --json
|
||||
--updates --contains-pkgs=` first, else `dnf5 changelog --upgrades` with dnf's two header
|
||||
lines stripped; flatpak: `remote-info --cached --log` History, which Flathub does not
|
||||
populate, so in practice the honest "publishes no release notes"; firmware: the fwupd
|
||||
release notes cached by `check`). Names constrained by `NAME_PATTERN` before argv.
|
||||
`check` gains per-item `bytes` and per-source `downloadBytes`, present only when EVERY
|
||||
item in that source was priced (dnf from `dnf5 repoquery --queryformat %{downloadsize}`,
|
||||
flatpak parsed from its rendered `download-size` column — its `--json` omits the column).
|
||||
`apply flatpak <app-id>` appends one ID, checked against the last scan. Stale
|
||||
dnf-automatic comments fixed; `DNF_TIMER` named. `services/Updates.qml`:
|
||||
`changelogFor(source, name)` → record or `null`, cached by `source/name`, serial queue,
|
||||
reactive via `changelogRevision` (read it in the binding, DesktopPreferences.get pattern);
|
||||
`applyFlatpakApp(id)`; `downloadBytes` + `downloadSize` (string) + `sourceDownloadSize(s)`
|
||||
+ `formatBytes(n)`; `loadingChangelog`.
|
||||
- `scripts/panama-doctor`: `CHECK_TITLES["panama.updates"]`; updates actions get
|
||||
`target: "updates"`; snapshot gains `repairCommand` (a joined argv string) on the five ids
|
||||
in REPAIR_COMMANDS only — the three in-process repairs have no command line and claim
|
||||
none; new `panama-doctor check <id>` verb printing a FULL snapshot envelope holding that
|
||||
one check (same schema, same summary arithmetic, so callers reuse `validSnapshot`).
|
||||
`services/Health.qml`: `settingsTargets` gains "updates"; `refreshCheck(id)` (splices one
|
||||
validated row in, recomputes the summary, drops a reply the newer full scan superseded)
|
||||
with `refreshingId` / `refreshingCheck`; `saveReport(path)` via `tee` (default
|
||||
`defaultReportPath` = `~/panama-health-report.txt`) reporting through `lastSaveResult`,
|
||||
and `reportText()` for the plain-text body; `safeCheck`/`validCheck` carry `repairCommand`.
|
||||
- `services/DateTime.qml`: `setTime(iso)` via `timedatectl set-time` (validated against
|
||||
`timePattern` = `YYYY-MM-DD HH:MM[:SS]` AND round-tripped through Date, refused while NTP
|
||||
is on AND while `statusRead` is still false — "not looked yet" is not "off"); `localTime`
|
||||
/ `universalTime` / `rtcTime` wired from `TimeUSec`/`RTCTimeUSec`, advanced locally once a
|
||||
second while `DateTime.tracking` is true (B sets it while the Clock card is on screen; no
|
||||
process per tick).
|
||||
- `scripts/panama-locale` + `services/SystemLocale.qml`: `get [cat]` / `set <cat> <locale|"">`
|
||||
/ `categories` / `overrides` (one JSON object for all five) — `LC_TIME`, `LC_NUMERIC`,
|
||||
`LC_MONETARY`, `LC_MEASUREMENT`, `LC_PAPER`. "Match language" is `""` and is implemented by
|
||||
re-issuing `localectl set-locale` with every OTHER assignment, since localectl replaces
|
||||
locale.conf with exactly what it is given. Service exposes `categories`,
|
||||
`categoryValue(cat)` (`""` = match language), `categoryLabel(cat)`, `setCategory(cat,
|
||||
locale)`, `categoryRevision` (read it in bindings), `busy`, and the pendingRestart
|
||||
discipline.
|
||||
- `scripts/panama-settings-backup`: `create [name] [homeState]` (label sanitized by
|
||||
`LABEL_RE`, stored INSIDE the envelope — the filename stays the timestamp SNAPSHOT_RE
|
||||
pins, since that is what ordering, pruning and restore confinement rely on), `delete
|
||||
<name>` (through `snapshot_source`, the same confinement gate restore uses), list gains
|
||||
`bytes` and `label`. Stale-temp sweep extended to Quickshell's QSaveFile leftovers
|
||||
(`settings.json.XXXXXX`, no leading dot) with a one-hour age guard so an in-flight write
|
||||
is never destroyed. `services/SettingsBackup.qml`: `create(name)`, `deleteBackup(name)`,
|
||||
dead `lastAction` removed, the color-gap fix per above (`storedDisplayFields`,
|
||||
`validStoredField`, both used by `layoutFromStoredDisplays` and `layoutsEqual`).
|
||||
- `services/SettingsSync.qml` + helper: preview output gains `changes: [{key, from, to}]`
|
||||
with both values rendered to text by the helper (`render()`, `VALUE_LIMIT` 120), capped at
|
||||
`CHANGE_LIMIT` 40 with a `changeCount` for what is not shown; the import still applies
|
||||
everything. Service gains `changeCount`; dead `left` removed.
|
||||
- `modules/settings/SettingsShell.qml`: the healthDiagnostics guard (A owns this single
|
||||
edit — B is told hands-off that binding).
|
||||
|
||||
## B — UI
|
||||
|
||||
`AboutPage.qml` showpiece per mock (hero, truthful versions block, Hardware card with
|
||||
GraphicsDevices joined, Device-name → Sharing row, Manual card listing chapters with titles
|
||||
READ FROM THE FILES (first heading), Read → `openSettings("manual")` + section); Design
|
||||
principles card dropped (the manual carries the philosophy). `ManualPage.qml`: chapter titles
|
||||
from file first-headings (make the old comment true); `onLinkActivated` routes
|
||||
`panama://settings/<page>` (or equivalent scheme) links through `ShellState.openSettings`,
|
||||
everything else external; keep the tabs/reader shape. `UpdatesPage.qml`: restructure per
|
||||
mock (headline; System packages with changelog expanders + download size; Automatic card
|
||||
with BOTH switches; Applications & firmware rows with per-app flatpak updates when present;
|
||||
history kept). `DateTimePage.qml` becomes the merged tab (Clock card with manual-set
|
||||
revealed when NTP off; Timezone; Language & formats card — language picker, four category
|
||||
dropdowns [Match language + installed locales], first-day-of-week fact row, live preview
|
||||
grid from `Qt.locale()` for the *chosen* format locales); `RegionPage.qml` DELETED (retired
|
||||
route). `HealthPage.qml`: repair rows show `repairCommand` in the detail before running,
|
||||
per-check Re-check button (`refreshCheck`), Save-report row, Color-profiles handoff row
|
||||
REMOVED (Digital wellbeing stays), the updates action now navigating. `SyncPage.qml`:
|
||||
preview diff list from `changes` (mono-ish tabular rows, del/add tones), Restore + Reset
|
||||
two-stage confirms (the house danger pattern), backup rows with name field on create +
|
||||
size + Delete…, reset subtitle mentions themes. `ContainersPage.qml`: root becomes
|
||||
`SettingsPage` per convention (logs drill-in preserved). `SettingsRoutes.qml`: the 8-tab
|
||||
strip + region retired + manual leaf mechanism (KEEP the categories array literal-shaped).
|
||||
|
||||
## C — periphery
|
||||
|
||||
Search: hostname/kernel/model/memory/uptime/serial → about; export settings/import
|
||||
settings → sync; currency/formats/measurement/paper/first day → datetime; region retired
|
||||
routing verified; manual entries keep working (leaf). Contracts: `settings-nav-contract`
|
||||
(counts + retired map), `settings-pages-contract` (routing list: add updates/containers/
|
||||
datetime, drop region), `updates-contract` (changelog verb read-only pins; per-app flatpak
|
||||
apply argv), health contracts (target "updates" validity BOTH sides, repairCommand shown
|
||||
before run, single-check verb full-shape, KeyError fixture), `settings-backup-contract` +
|
||||
`-live` (extended fields round-trip — a stored record with color fields restores them and
|
||||
`layoutsEqual` detects color-only drift; delete confinement; name sanitation),
|
||||
`settings-sync-contract` (changes shape, no secrets in stringified values), `manual-contract`
|
||||
(titles-from-files, in-app link routing), `gnome-handoff-contract` (region handoffs gone —
|
||||
consider OWNED), NEW `system-pages-contract` if the pins don't fit existing files (C's
|
||||
judgment; keep count growth honest). Backlog Phase 15. README count line. Docs/commands
|
||||
regen at the end. RUN the contracts you write/touch as you go (grant active); report results.
|
||||
|
||||
Hard rules still: no live mutations of system state (no dnf/flatpak installs, no
|
||||
timedatectl/localectl writes, no backup restores against the real store — the
|
||||
scratch-daemonizing harness pattern and hermetic stubs are the sanctioned test paths, and
|
||||
the grant means you may RUN those freely). Valid QML at every save. B programs against A's
|
||||
pinned APIs; A updates this spec before changing them.
|
||||
Reference in New Issue
Block a user