Some checks failed
Security / Security check (push) Failing after 1s
The same single-select choice pattern appeared as four widgets: audit's hover pills, the store's SegmentedButton, the store filter dialog's ChoiceChips, and the approvals TabBar (usertest finding #14 / night-log decision 'pill segment as canon'). The audit pattern is promoted to a shared ChainSegments widget (optional icons, hover, selected border, button+selected semantics) and all four sites use it; approvals switches lists via IndexedStack so both stay alive and switching does not refetch. Guard per the no-bugfix-without-a-guard rule: widget tests for selection + semantics, plus a canon sweep that bans TabBar/TabBarView/TabController/SegmentedButton/ChoiceChip from lib/ (comments exempt). Deliberately out of scope: the flow editor's Graph/Text/Run tabs live in the separate editor package. Studio 0.75.0; guide images regenerated, dark + light verified. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
26 KiB
26 KiB
Changelog
All notable changes to chain_studio recorded here. Pubspec
version + kStudioVersion in lib/data/about_info.dart stay in
lockstep.
Unreleased
Changed (0.75.0)
- One segment control everywhere. The same single-select
choice pattern used to appear as four different widgets: the
audit page's hover pills, the store's Material SegmentedButton
(Modules / Studio & Designs), the store filter dialog's
ChoiceChips and the approvals page's TabBar. All of them now use
the canonical
ChainSegmentspill control (the audit pattern promoted to a shared widget, with icons and a11y semantics); the approvals page keeps both lists alive in an IndexedStack so switching does not refetch. A canon-guard test bans TabBar/SegmentedButton/ChoiceChip from lib/ for good. Guide images + wording updated (dark and light verified).
Hardening round (test strategy, 2026-07-19)
- Hermetic widget suites.
HubService.instanceis injectable; a scriptable fake (test/support/fake_hub.dart) answers every member the pages touch and scripts per-RPC failures. The a11y and responsive sweeps run against it — results no longer depend on whether a hub happens to listen on the operator's machine (which was the root of the historic a11y flake). - State-matrix sweep (
state_matrix_test.dart): every sidebar page × hub condition (healthy / gone / too old / feature off) with app-wide invariants — no "unreachable" claims while the hub answers, no raw error text in the UI, classified states only. - Shared load-error view. Store, Doctor, Audit, Approvals and
Federation no longer fold every load failure into "hub not
reachable";
HubLoadErrorViewclassifies into unreachable / needs-newer-hub / load-failed-with-copyable-detail (new DE+EN strings). Also fixed: the approvals page's hidden tab surfaced load failures as uncaught async errors; the audit status bar rendered the raw gRPC error wall instead of the friendly headline. - Version-skew gate.
integration_test/skew_smoke_test.dart(run via the platform repo'sscripts/skew-smoke.sh) boots the released hub binary and walks every page with the same invariants — the dev-Studio-against-old-hub combination is now a release gate instead of a live-bug generator.
Added (0.74.0)
- Doctor findings deep-link to their page. Summary tiles and panel rows jump to where the finding is actioned: modules → store, "approvals waiting for review" → approvals inbox, audit chain → audit log (chevron affordance, tooltip + semantics button). The host-services empty state gains a "view the configuration" button, and the update banner's release-notes URL is a real link now.
Fixed (0.74.0)
- Runs page no longer contradicts the sidebar. Load failures are classified instead of all reading "hub not reachable": an older hub without the ListInvocations RPC gets "this view needs a newer hub version" with a doctor link, the detached-off refusal shows the regular feature-off empty state, and unknown errors surface a copyable detail box. "Not reachable" is reserved for genuine connection failures.
- Audit page timer leak. The live-stream reconnect timer is held and cancelled on dispose.
- a11y suite flake killed at the root. The pending-timer failures came from the gRPC channel's 5-minute idle timer being armed when the last stream closes; the suite now closes the channel and pumps past the idle timeout (6 consecutive full runs green).
Added
- Full-history audit export. The audit page's actions menu gains
"Export full log as JSONL" next to the current-view export: fetches
the complete event history of the active project scope (independent
of the type chip, the search field and the page's 100-event window)
and writes it as JSONL. The current-view export is unchanged; the
CLI
chain admin events --jsonremains the canonical tool for WORM-guaranteed exports (a stale code comment still advertised the never-shippedchain audit export— fixed).
Changed (usertest low-findings tail)
- Honest hero badge. The store hero wears "TODAY"/"HEUTE" only for an operator-accepted story; the compiled-in fallback deck has no date binding and now says "FEATURED"/"EMPFOHLEN".
- Audit filter chips in UI type. The Alle/Flow/Schritt/Modul chips drop the monospace styling — mono stays reserved for paths and identifiers.
- One verb for the chain check (DE). "Hash-Kette geprüft" is the confirmation everywhere (audit header, doctor pill); "intakt" remains the state headline. English was already consistent.
- Readable sealed-area status. The "stopped" label in the workspace switcher gets a modest contrast bump.
Changed (usertest panel 2026-07-17, 14 personas — all confirmed findings)
- Install trust gate. One confirmation dialog before every module install (store card, detail sheet, flow quick-fix): source, version, license, maturity, required services — plus an honest signature note (the hub does not report per-entry signature status yet; no fake badge).
- Settings → About. Product, Studio + hub version (live), vendor Flemming.AI / Dr. Stefan Flemming, Apache 2.0, contact, docs link — every value copyable.
- Discoverable sidebar. Instant tooltips with the ⌘1–9/^1–9 shortcut, semantics labels, a visible "Search & commands ⌘K" row, and a setting to keep the rail always expanded.
- Plain-language empty states. Runs page explains background runs
in plain words and — via the hub's new
detached_enabledflag — says truthfully whether the feature is off or simply unused; approvals inbox explains human approvals without raw capability syntax; welcome cards lead with everyday language (tech detail behind a toggle). - One term per concept. "Fähigkeiten" is the German lead term
(welcome, integrations, federation); "Registrierungs-Token" instead
of "Enrollment-Token"; category and source-kind labels localized
(no lowercase wire tokens like
document,1 system). - Audit page. Free-text search over the event list; JSONL export of the current view; the dev-only clear action moved from a bare trash icon into a labeled overflow menu.
- Doctor page. Copy button on every daemon path row; "n of m
events verified" instead of "n/m chain"; hash-chain wording unified.
The module tile no longer counts the built-in
systempseudo-module (a fresh hub shows 0 modules, matching the welcome checklist); the daemon-files panel warns when the audit DB lives in an OS-cleanable temp directory; the daemon card states endpoint, transport security, and token status (length only) in one line. - Federation page. Primary action in the app bar and in the empty state (FAB removed); plain-language empty text.
- Store. License pill on the module card; maturity pills explain themselves on hover; carousel shows a textual position; German tab says "Studio & Designs".
- Formal address guard. A test now rejects informal German forms including reader-addressed imperatives; literal markdown backticks are gone from both catalogs.
- Setup. The wizard replaces the Settings dialog instead of stacking on it, with a stronger scrim; the try-out profile names the upgrade path to a regulated profile.
- Welcome checklist. The "start a saved flow" tick is sticky instead of silently unticking once the event leaves the recent-events window.
Changed (setup lives before the app)
- First-run gate. A fresh install starts inside the setup: a dedicated screen hosts the wizard before the app appears (embedded mode + explicit "Später einrichten" skip). The Welcome page loses its setup button entirely; re-running the setup lives in Settings → General ("Run setup again…"). Wording de-ad-ified: "Einrichtung starten" instead of "In 3 Fragen loslegen".
- Preview before permission. The plan preview now calls the new PlanSetup RPC over the live hub connection instead of spawning the chain CLI — whose first run could pop the macOS file-access prompt BEFORE the operator ever saw the plan. CLI remains the no-hub fallback; applying stays the explicit separate step.
- Native file dialog for flow file inputs (with flow-editor v0.23.0): the Run tab's file inputs open a real picker; typing an absolute path is now only the no-host fallback.
Fixed (startup + build time)
- Black window on launch. A corrupt preference value (
hub.securestored as int0by an externaldefaults write) madeSharedPreferences.getBoolthrow insidemain()before the first frame — the app sat as a black window with no visible error. Pref reads now tolerate wrong types (int coerces to bool, garbage falls back to the default), and every pre-frame restore step is failure-isolated so nothing can preventrunAppagain. Regression tests reproduce the corrupt store. - CocoaPods integration removed (macOS). The project builds via
Swift Package Manager; the leftover Pods wiring (Podfile,
[CP]script phases, Pods framework refs, xcconfig includes) made every build run both dependency managers — exactly what Flutter's own "will improve the project's build time" warning was about.
Added
- Settings → Security shows the hub's auth policy. New panel
backed by the hub's read-only
AuthStatusRPC: active token validator (static / JWT-RS256 with issuer, audience and JWKS source), anonymous-access warning, and per-token cards with scope grants, env-var presence and rate limits — T4/T5 security administration finally visible outside YAML. Non-admin tokens get a localized denied story instead of an error. - Permanent accessibility + responsive test gates. Every page
must pass WCAG text contrast and labeled-tap-target guidelines
in both themes (
test/a11y_test.dart) and lay out without overflow from 800 to 1920 px (test/responsive_test.dart).
Fixed
- Daemon start with a wrong token no longer misreports. Both start paths (welcome CTA, sidebar) treated an auth-rejected hub as "daemon dead" and showed a start-failure dialog while the banner above correctly blamed the token; an auth rejection now counts as "daemon alive".
- Token fixed outside Studio heals the connection. On an
auth-rejected poll the shell re-reads
~/.chain/hub-auth-tokenand reconnects when the file changed — following the banner's own advice no longer requires re-saving in Settings or a restart. An endpoint switch also resets the failure streak, so a stale in-flight probe can't blame the new endpoint. - Security panel stays fresh. The auth-policy view re-queries
after saving or clearing the hub token in the panel above, and
renders the hub's new
reload_requiredflag as a plain-language pending-reload warning (DE+EN). - Auth-rejected hub no longer reported as "unreachable". With
token auth active, a wrong or rotated token got UNAUTHENTICATED
from a perfectly reachable hub, but the sustained-failure banner
said "can't reach the hub" — pointing the operator at the
endpoint instead of the token. The shell now probes with the
SDK's failure-kind-aware
probe()and switches the banner to "rejected the sign-in — check the access token" (key-off icon). - Light theme accent was below WCAG contrast. Filled buttons and the active sidebar label rendered white-on-sky-500 (2.8:1); the light scheme now uses sky-700 (~5.9:1). FABs follow the same accent instead of Material 3's tonal default.
- Audit page at narrow window widths. The app-bar filter chips collapse into a checkmark menu below 900 px, and the live-status bar shrinks gracefully (copyable disconnect error gets the full row width).
- Consistent formal address in German. ~20 strings still used du-forms next to the Sie-forms on welcome/setup; the audit event-type chip "Step" is now "Schritt"; the doctor page's event count pluralises correctly ("1 Ereignis") in both languages.
- Stored tokens reached the wrong directory.
~/.fai/rename leftovers: the hub-auth token and registry token were read from / written to~/.fai/while the hub reads~/.chain/— a stored registry token never reached the hub. Today-stories and UI texts still advertising the retired.faibundle extension fixed too.
Fixed (wizard live-run findings 2026-07-14)
Field test of the setup wizard surfaced three trust breaks in one run; all were reproduced against a stale CLI and fixed:
- Errors surfaced behind the wizard.
chain initfailures were shown as a SnackBar, which lands BEHIND the wizard's modal barrier: dimmed, clipped, its copy button unreachable — and the operator's click at it hit the barrier, which (dismissible by default) closed the whole wizard with all answers. Now: failures open a modal error dialog ABOVE the wizard (copy button works, verbatim CLI output behind "Details"), and the wizard is no longer barrier-dismissible — leaving it is explicit via Abbrechen/Zurück. - CLI version skew explained. When the resolved
chainbinary is older than Studio and rejects--plan-json, the wizard now names the skew in plain language — which binary was executed, that it predates the assistant, and the update path — instead of leaking a raw clap usage error. A missing binary gets the same treatment plus a hint on step 3 before anything runs. - macOS folder prompt pre-explained. Step 3 now states which
chainbinary the preview will execute; when that binary physically lives (symlinks resolved) in a TCC-protected folder (Documents/ Desktop/Downloads), the wizard says up front that macOS may ask for folder access — instead of a bare permission prompt appearing in the middle of setup. FriendlyErrorvalues now pass throughfriendlyError()unchanged so call sites can route precise, localized stories through the shared error presentation;SystemActionsgained a publicresolvedChainBinary()and test seams for the run/resolve paths.
Added (guided setup on grade-1 — steps A4/A5/B1 + doc automation)
- Clickable next steps. After apply, the wizard renders real Studio actions instead of CLI text: start-hub button (polls until the daemon answers), per-module install buttons with progress/done states (capability-name install via the hub's store index), and an open-the-starter-flow button navigating to Flows.
- Signature dead end resolved. Regulated plans explain in plain
language that modules come from a signed source; the preview offers
"allow installing from the public store" as one deliberate,
reversible switch (
allow_unsigned_modules) that re-assembles the plan. Air-gapped plans point to the offline-bundle path instead. - Fresh-install auto-open + honest framing. On a fresh hub (no
config, no
setup-plan.yaml) the wizard opens by itself, once per run; the welcome CTA is now "In 3 Fragen loslegen" / "Get started in 3 questions". After the wizard closes, the onboarding checklist re-probes and states what the assistant already covered (applied profile fromsetup-plan.yaml). - Free-text AI path (phase 1.2). "Or just describe what you want to do": the goal goes to the configured system AI, the reply is validated against strict enum whitelists and comes back as an editable "this is how I read your task" reflection feeding the same preview/apply. Privacy line states local vs. provider processing; without a system AI the menu path stands alone.
- Nav manifest guard.
test/nav_manifest_test.dartgeneratesdocs/nav.generated.jsonfrom the sidebar truth (ids, order = Cmd numbers, DE+EN labels); the platform repo checks the operator guide against the mirrored copy. - Guide screenshot harness.
integration_test/guide_shots_test.dartboots a hermetic hub, seeds demo projects, walks every nav page, the workspace switcher and the setup wizard, and writes the guide PNGs — driven by the platform repo'sscripts/regen-studio-guide.sh. - Fixed: the integration-test hub fixture still looked for the
pre-rename
faibinary andchain_platform/path, so its tests silently skipped since the rename; it now resolves$CHAIN_BIN,chainon PATH, and../fai_chain/target/{release,debug}/chain.
Added (guided setup — persona re-audit fixes, grade-1 round)
- Regulated path finishes without a terminal. The post-apply signed-source state now offers "Add a signed source…" (the stores dialog with its pin-a-key field) plus the per-module install buttons, instead of a hint with no affordance; a plain-language trust hint explains why pinning the publisher's key matters.
- Apply warnings surface. Warning lines from
chain init --apply(e.g. the empty-trusted-publishers caveat) are shown selectable in the done state instead of being swallowed on success. - Truthful preview. New plan lines state which machine is being set up (server/container targets configure THIS machine — said explicitly), that regulated profiles get the hash-chained audit log even when WORM is off, and that a curated reading list is stored with the setup record.
- Language pass. Onboarding checklist switched to Sie-form and "System-KI" (was du-form + "System-AI" next to the formal wizard); "Audit-Sperre" jargon replaced with "Schreibschutz für das Prüfprotokoll"; answers file now lives in a private per-dialog temp dir instead of a fixed world-readable name.
Added (multi-project, stage ③ — sealed areas)
- Sealed-area connection switch. The workspace switcher now lists
the operator's sealed areas (read from
~/.chain/sealed/manifests, the same source the CLI uses) below the shared projects, each with a lock icon and a running/stopped status. Selecting one is a real connection switch: Studio reconnects its hub client to the area's own port with a full state reload — one window, one truth. A stopped area is started first (chain project start) with a visible notice; a failure surfaces as a copyable error and rolls back to the shared hub. - Identity bar. While connected to a sealed area, a strip under the AppBar is painted in the area's accent colour and names it, with a one-click Leave back to the shared hub. The area colour is marking, not theming — Studio's blue stays the app accent. (The window-title tint is a small follow-up; the identity bar is the primary signal.)
- Selecting a shared project or "All projects" from inside a sealed area switches the connection back to the shared hub first. The sealed connection is never persisted across restarts — Studio always launches on the shared hub and the operator re-enters an area deliberately.
Added (detached-runs monitor — T3 parity)
- Runs page. A new sidebar destination lists detached invocations
(submitted with
detach: true) with their phase, current step, project and a Cancel button while pending/running. Workspace- scoped like Audit and Approvals; polls every 2 s. Detached runs are opt-in (detached.enabled), so the empty state explains how to turn them on. Inline help doc (DE+EN). Backed by the SDK'slistInvocations()+cancelInvocation().
Added (multi-project, stages ① + ②)
- Workspace switcher. The Audit and Approvals AppBars carry a
workspace control listing the hub's project registry (colour dot per
project, a shield for
protected, an honesty tooltip). "All projects" stays reachable — a filter, not a jail. The selection is persisted and shared across pages; it re-scopes the audit list AND live stream hub-side, scopes approvals (pending + history), and drives the sidebar approval badge. Runs launched from the editor are stamped with the active workspace — unless the flow file declares its ownproject:, in which case the file wins (CLI semantics). - Editor project chip + file-wins guard. A flow file's own
project:shows as a chip; on mismatch with the active workspace an amber pill offers a one-click switch (the file still wins for the run). Backed by editor package 0.22.0.
Fixed (usertest 2026-07-10 findings)
- Approval prompts localize. An approval whose flow step gave no
prompt:(and legacy rows carrying the hub's old baked-in English sentence) now renders the localized fallback "Freigabe für diesen Schritt erforderlich" / "Approval required for this step" — no more English inside the German approvals UI. - Approving without review data asks first. When the approval step
attached no
show:payload, "Freigeben" opens a calm confirmation ("Ohne Prüfdaten freigeben?") explaining that the flow deliberately attached no data, with an explicit "Trotzdem freigeben". - Studio error log moved to
~/.chain/logs/. Writes went to the pre-rename~/.fai/logs/studio-errors.logwhile the Doctor page andchain doctorread~/.chain/…. Studio now writes to.chainand migrates the old file (+ rotation sibling) over once. - Honest audit wording (legal review). DE strings no longer claim "manipulationssicher" — the audit log is manipulationserkennend (tamper-evident); "warum WORM-1 für KRITIS reicht" became a neutral what-it-does-and-does-not sentence (EN too); the Doctor chain pill says "Integritätskette v1" instead of "WORM-1"; the federation enrollment hint says the CA authenticates the first connect.
- WCAG-AA secondary text on dark. De-emphasised text was 3.7:1 on cards; the muted token is now ≥ 4.5:1 against canvas, cards and elevated surfaces.
Added
- Live audit feed. The Audit page subscribes to
streamEventsand refreshes instantly on each new event (debounced); the 2 s poll stays as the safety net and re-subscribes after a clean stream close. - Channel switcher in the sidebar. The active-channel pill (and the
collapsed chip) is now click-to-switch: a menu of every channel with
its running state + a check on the active one; switching writes
~/.chain/current-channel, restarts that channel's daemon, and Studio repoints to it. - Module-store manager is prominent + bilingual. The store page gains a labelled "Add store" button (was a bare icon) opening a fully localized dialog: configured stores, a curated Suggested stores shelf with one-click add/remove (probed for reachability — shows "not available yet" until a store's index is published), and an optional per-store pinned public key field.
- Approval payload clarity. The approval card always shows the
payload section: a present payload scrolls inside a height-capped
copyable box; an absent one explains that the flow's approval step
chooses what to surface via its
show:field.
Fixed
- Errors are copyable everywhere. System-AI test-connection, the
Settings dialog, and the Audit status bar rendered failures as
non-copyable text; all now route through
ChainErrorBox/SelectableText. - Filter dialog crash on the store page — a
SpacerinsideAlertDialog.actions(anOverflowBar, not a Flex) threw; the buttons now sit in aRow. - Welcome docs grid tidied into equal-height paired rows.
- Approval card leads with the human prompt; the
flow › stepid is demoted to a metadata line. - Pulsing sidebar connection dot restored when connected.
0.70.0 — 2026-06-13
Added
- Federation panel. A new "Föderation" destination shows the
satellites connected to this hub (name, region, version, wire
version, advertised capabilities) and adds them in one step: press
Add satellite, name it, and the hub issues a single-use
bootstrap token bundled with its CA as a ready-to-paste satellite
config — the bundled CA makes the satellite's first connect
tamper-proof. Localized (EN + DE) with an in-app help doc. Backed
by new
HubClient.listSatellites/issueBootstrapTokenin the Dart SDK.
0.68.0 — 2026-06-09
Added
- Inline approval driver.
StudioFlowRunDriverimplements the three new methods the editor 0.21.0 introduced (pendingApprovalIdForStep,approveApproval,rejectApproval) — all delegate to the existingHubServiceapprovals RPCs. End result: the Run tab now hosts a complete Approve / Reject form inline, removing the tab-switch detour to the standalone Approvals page.
0.67.0 — 2026-06-09
Added
- Inline help icons in the Approvals, Audit, and Doctor
app-bars open the matching bundled doc in the existing
bottom-sheet reader via the new public helper
showFaiDoc(BuildContext, slug)exported fromwelcome.dart. - New
assets/docs/approvals.md(+_de.md) explains the approval concept end-to-end with a YAML example. - friendlyError hub-pattern matching. Six hub-specific failure shapes (approval rejected / timed out, output too large, host service not declared, missing value reference, MCP unreachable) get specific localised headlines + hints before falling through to the gRPC-code default. Five new test cases pin the matchers.
Changed
- Settings dialog sidebar fully localised (Allgemein / Darstellung / System-KI / Integrationen / Sicherheit / Wartung). Per-panel titles + descriptions also.
- Daemon action labels localised:
enable autostart,disable autostart, restart / start / stop / status + the OK / Failed result line.
0.66.0 — 2026-06-08
Added
- Add-module-source dialog for private modules that
aren't in the public store. Asks for URL or local
.faibundle path; carries an explainer block +chain install --linkexample. - Store catalogue passed to the flow editor so the analyzer can decide between Install (in store) and Add source (not in store).
0.65.x
- Editor 0.18.0 pickup; analyzer-error block on Run; diagnostic strip persistence across tabs.
0.64.0 — 2026-06-08
Added
- Flow editor quick-fix install handler.
_onInstallCapabilitywires the editor's "Install " button toHubService.installModuleand refreshes the capability list on success.
0.63.0 — 2026-06-04
Changed
- Settings dialog refactored from one 800-line vertical scroll into a macOS-style sidebar with six categories.
0.62.x — 2026-06-03
Added
FaiLog+ central error helpers (showFaiErrorSnack,showFaiErrorDialog).- Inline
FaiLogViewermodal for tail-viewing log files. - Today CTAs in the Store carousel actually re-run search
after a
filterCategory/runQuerystory.
0.61.x and earlier
See git log.