Commit graph

14 commits

Author SHA1 Message Date
flemming-it
64c2a77dc9 feat(workspace): one global switcher anchor in the shell sidebar
The switcher used to be embedded per page (Flows/Runs/Audit/
Approvals) — invisible on the other five pages and sitting in a
different corner depending on the page (persona review 2026-08-27,
consensus finding). It now lives ONCE in the sidebar, above the
destinations: active project/area always visible, opens the same
menu everywhere, Cmd+P from anywhere. The shell listens to the
workspace, so the sidebar endpoint label can no longer lag a
sealed switch until the next health tick.

Also in this rebuild:

* Stopped sealed areas ask before starting ("Start area X?") —
  a context switch must never boot a hub daemon as a click
  side-effect; running areas keep switching with one click.
* The switcher tooltip told a wrong scope ("filters this view") —
  it now says the choice applies everywhere and stamps new runs.
* The aggregated sealed row explains itself in place (names can
  reveal client identities) and links to the Settings toggle
  (Settings dialog gained an initialCategory jump).
* The active entry carries a checkmark in the menu.
* The Cmd+K palette knows projects and areas, ranked by recent
  use; sealed names honour the privacy setting — while hidden,
  the palette offers the guarded picker instead of the names.
* The runs empty state names the active project filter as the
  cause ("No runs in project X" + show-all action) instead of
  claiming the feature is off.

Tests updated to the anchor and made hermetic (scriptable
projects on the fake hub, sealed-area fake); new coverage for the
checkmark, the why-line, and the start confirmation.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-08-28 00:00:06 +02:00
flemming-it
ebc668d28d feat(approvals,audit): record the reviewer as the unchecked claim it is
The hub copies the reviewer string a client sends straight into
decided_by (DecideApproval, ClearEventLog); nothing on the wire ties
it to the authenticated caller. Studio filled it from the OS account,
so an export read like non-repudiation while being an arbitrary
client claim — the legal finding of the 2026-07-26 usertest panel.

The real fix is hub-side (derive decided_by from CALLER_IDENTITY);
that contract is written down in docs/reviewer-identity.md and needs
a hub release. Until then Studio does the one thing it can do
honestly and marks its own claim as a claim, inside the record:

- data/reviewer_identity.dart is the single place that produces and
  reads the value; wire() is idempotent, so page and HubService may
  both normalise. Every write path funnels through HubService, so no
  surface can send a bare handle.
- The inbox states before the decision who will be recorded, what
  that attribution is worth on this hub (from AuthStatus), and the
  literal string that lands in decided_by. An unreadable auth policy
  stays unreadable — never optimistic.
- Reading back: a marked value shows its plain name plus an
  unchecked flag; an unmarked one (legacy row, CLI decision, or a
  future hub-derived identity) is not classified either way.
- The audit wipe seeds the same kind of marked attribution into its
  chain.reset marker.

When the hub starts deriving the value it overwrites the field and
the prefix disappears by itself — no Studio release needed.

Guards: reviewer_identity_test (the value) and
approvals_reviewer_identity_test (every surface that writes or
renders it, against the hermetic fake hub). Visual proof for both
themes via the dialog-shot harness.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-08-03 23:50:34 +02:00
flemming-it
351c5a82bc feat(store): show module maintainers (0.79.0)
Some checks failed
Security / Security check (push) Failing after 2s
The detail sheet always answers 'who maintains this?': one
selectable line per maintainer from the store index's new
maintainers list, or an honest 'not specified' when the index
names nobody (StoreMaintainersSection, public for the widget
tests). The install trust gate carries the same fact when
present and stays terse otherwise. DE+EN; dialog-harness proof
captured with the maintainer row.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-22 22:06:18 +02:00
flemming-it
08227410e6 fix(flows): only offer install for capabilities the store resolves
Some checks are pending
Security / Security check (push) Waiting to run
The capability set behind the flow editor's Install quick-fix and
the flow list's install badge ingested every store entry's
requiresCapabilities (dependencies, not provided capabilities) and
ignored entry status/kind. Clicking Install on such a capability
ended in the hub's "no store entry for '<name>'" error.

The set now mirrors the hub's install resolver (entry names only,
no planned or federated entries) via installableStoreCapabilities()
with unit tests for both classification states. Unresolvable
capabilities render the editor's 'not in store' state, which
explains the three recovery paths before any click; the editor pin
moves to 0.25.0 (commit-pinned until its tag exists) and the dialog
harness captures the badge states light+dark. Studio 0.78.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-22 13:46:08 +02:00
flemming-it
2f076ccf29 feat(store,doctor): surface the hub's trust + exposure data (0.77.0)
Some checks failed
Security / Security check (push) Failing after 1s
The trust-gate dialog replaces its generic 'no per-entry status yet
(alpha)' note with the hub's classified verification statement —
pinned store key / trusted publishers (green), installs without
signature checking (amber), install would be refused (red), bridge
entry (neutral) — via one shared describeInstallVerification mapping.
Against a pre-0.23 hub the field is empty and the old honest wording
stays (pinned by test).

Information architecture: policy-off is a GLOBAL fact, so it appears
as ONE ChainInlineHelp notice above the store grid instead of a
warning pill on every card (card noise); only 'blocked' — a genuine
per-source anomaly — earns a card pill. Doctor's host services show
the hub-classified network reach per endpoint (local only / private
network / publicly reachable with a protect-it hint / reach unknown).

Verified end-to-end against the live dev hub (guide harness): the
wire field arrives, the store page shows exactly one policy notice
and quiet cards; trust-gate variants captured via the dialog
harness. Suite 123 green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-21 13:14:13 +02:00
flemming-it
87afa4dc05 feat(docs): in-place help pattern — explain a surface where it happens
Some checks failed
Security / Security check (push) Failing after 2s
New ChainInlineHelp (intro strip: what this is + what will happen, with
an optional 'Learn more' into the doc sheet) and ChainFieldHelp /
ChainFieldLabel (a '?' affordance per field). First applied to the
add-satellite dialog, which asked for a bare 'name' with no hint of
what a satellite is or does (usertest): it now leads with a plain
explanation + a federation 'Learn more', and the name field carries a
'?'. Both widgets are quiet by design.

Verified: field_help_test covers the widgets + that the dialog explains
itself; dialog_shots_test.dart (a reusable headed dialog-capture
harness) proved the layout in light + dark. Studio 0.76.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-20 02:00:56 +02:00
flemming-it
bfd58baa75 test(skew): version-skew smoke — dev Studio against the released hub
Some checks failed
Security / Security check (push) Failing after 2s
Walks every sidebar page against an older, released chain binary
(hermetic fixture hub) and fails when any page claims 'unreachable'
although the hub answers, or renders raw error text. Run via the
platform repo's scripts/skew-smoke.sh as a Studio release gate.

Verified against the real pair hub 0.21.0 vs workspace 0.22.0: all
invariants hold. Two timing notes are handled explicitly: real-async
settles between navigations and an app teardown before the fixture
teardown keep grpc-dart's data-after-cancel race (unguarded
_responses.add, call.dart:395) from failing the walk spuriously;
the final fake-time pump drains the channel's 5-minute idle timer.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-19 02:08:48 +02:00
flemming-it
79e08c8d17 test(shots): seed demo flows so the flows page proves module logic both ways
hello.yaml needs debug.echo (not installed on the fixture hub) and
must carry the missing-module note; genehmigung-demo.yaml only uses
the hub builtin system.approval and must show a plain play button.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-18 00:00:17 +02:00
flemming-it
9cc330fca0 test(security): env-gated proof shot of the auth-policy panel (Settings -> Security)
Some checks failed
Security / Security check (push) Failing after 2s
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-17 19:26:54 +02:00
flemming-it
c81bc16eb9 test(setup): guide-shot harness opens the wizard via Settings; changelog for the setup rework
Some checks failed
Security / Security check (push) Failing after 2s
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-17 19:08:40 +02:00
flemming-it
efaa089454 feat(settings): hub auth-policy panel — T4/T5 security parity in the GUI
Some checks failed
Security / Security check (push) Failing after 1s
Settings → Security now shows the hub's effective auth policy via the
new read-only AuthStatus RPC: active token validator (static / jwt-rs256
with issuer, audience, JWKS source), anonymous-access warning, per-token
cards with scope grants, env-var presence and rate limits, plus a
localized admin-denied story for non-admin tokens. Live-reloads on
endpoint change.

Also fixes a batch of fai→chain rename leftovers this panel's
verification uncovered: hub_auth_token.dart and registry_token.dart
read/wrote ~/.fai/ while the hub reads ~/.chain/ (stored registry
tokens never reached the hub), today_story_loader + tools/today used
~/.fai/today, chain_log legacy ~/.fai/logs migration removed per the
no-legacy-recognisers decision, and UI strings still advertised the
retired .fai bundle extension.

Includes 5 widget tests for the panel, an integration-test screenshot
harness (auth_policy_shots_test.dart, guide-shots style), and DE+EN
l10n. flutter analyze clean, 58 tests green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-15 03:19:33 +02:00
flemming-it
ea975b3bcb test: GUIDE_SHOTS_LOCALE for the guide harness (EN-parity proof runs)
Some checks failed
Security / Security check (push) Failing after 1s
The screenshot harness already had GUIDE_SHOTS_THEME; add a matching
GUIDE_SHOTS_LOCALE=en so the English wizard/pages can be captured for
parity checks. The CTA finder accepts both locales. Verified: EN run
renders the fully-translated wizard with no leaked German and no
layout breaks.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-13 11:43:56 +02:00
flemming-it
ddac84ce8e feat: guided setup — persona re-audit fixes (grade-1 round)
- Regulated path finishes without a terminal: the signed-source
  state offers 'Add a signed source…' (stores dialog with pin-a-key)
  plus the per-module install buttons and a plain-language hint why
  pinning the publisher's key matters — instead of a hint with no
  affordance.
- Apply warnings (e.g. the empty-trusted-publishers caveat) surface
  selectable in the done state instead of being swallowed.
- Truthful preview: new lines state which machine is being set up
  (server/container targets configure THIS machine), that regulated
  profiles always get the hash-chained audit log (even with WORM
  off), and that the curated reading list is stored with the setup
  record.
- Language pass: onboarding checklist in Sie-form + 'System-KI'
  (was du-form + 'System-AI'), 'Audit-Sperre' jargon replaced,
  answers file moved to a private per-dialog temp dir.
- Screenshot harness: GUIDE_SHOTS_THEME=light for light-parity
  proof runs.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-13 01:20:59 +02:00
flemming-it
cf4024a4e2 test: deterministic operator-guide screenshot harness
integration_test/guide_shots_test.dart boots a hermetic hub
(HubFixture), seeds demo projects (open Bürgeramt; sealed
Ratsinformation and a setup.applied audit event only when the
runner confirms an isolated $HOME), launches the app in German +
dark mode, walks every sidebar page in Cmd order with
content-aware waits, opens the workspace switcher and the setup
wizard, and writes the guide PNGs via a driverless RepaintBoundary
capture. Driven by the platform repo's scripts/regen-studio-guide.sh.

Also fixes the hub fixture's binary resolution, dead since the
rename (it looked for 'fai' and ../chain_platform/): now $CHAIN_BIN,
'chain' on PATH, then ../fai_chain/target/{release,debug}/chain —
the integration tests actually run again instead of silently
skipping.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-13 00:47:41 +02:00