ho-06.5 — The Workshop: right-side action panel and flat grounds
Give the Workshop the chrome it should have had. ho-06.2's ratified bet — native
top-toolbar plus an overflow » menu — failed its signed-install gate ("NOT an
acceptable UI"): the toolbar could not carry the action set legibly, and the
overflow buried Add Shared Secret, Preview .env, and Jump to Directory behind a
nested menu. The rail-revisit criterion Decision 1 named was met the same day it
was written. This is the response: a collapsible right-side
action panel hosting the Workshop's verbs, the toolbar emptied to a toggle, and
the whole window moved from translucent system materials onto the flat pālana
grounds ho-06.4 defined for exactly this moment.
This is a new ho, not a reopening of 06.2. 06.2's document stands as the
record of what was believed then; this document responds to what the gate
proved. It spends what 06.4 deliberately left unconsumed: ground,
groundDeep, and panelGround are defined and tested but nothing renders
them — they exist for this ho.
Chrome only. No new vault behavior. Every verb the panel hosts already exists and keeps its exact intent, wiring, confirmation dialogs, and Touch ID posture from 06.1/06.2.
Out of scope:
- The linking picker / shared-secret browser, rotation staleness — ho-07.
- Multi-root scan management (add/remove/reconfigure roots) — ho-06.6. The panel is likely where that UI lands; this ho leaves it room but builds none of it.
- First-run wizard, age-key generation, GUI ingest — ho-06.3.
- Typography, spacing, radii, motion from pālana — still color-and-chrome only, same boundary as 06.4.
- Editing pālana — zero files under
../../../palana/change. - Zero files under
Sources/SharibakoCLI/orSources/SharibakoCore/change — pure app layer, the standing rule since ho-05.
Phase 1 —
Four decisions, ratified 2026-07-11. All four were framed in K4's 06.5 entry; two of them (idiom, grounds) were explicitly handed here by earlier hos.
Decision 1 — Idiom: a custom collapsible right panel, not .inspector, not a fixed rail
The panel is a -built trailing column beside the NavigationSplitView,
filled with panelGround, holding the Workshop's actions as always-titled
buttons in labeled groups, with a toolbar toggle to collapse and restore it.
The collapse state persists across relaunch (@AppStorage).
Why not the alternatives:
- SwiftUI
.inspectoris the native trailing-panel idiom, but it is semantically "properties of the selection" — this panel hosts verbs, not properties. It also styles itself with system materials and manages its own chrome, fighting both the flat-panelGroundfill and Decision 3's holistic grounds call. - A fixed icon rail cannot carry titles, and hover-tooltips-as-the-only- label already failed the operator at the ho-05 gate. Icons-only chrome is the same burial the overflow menu performed, rotated 90°.
The toolbar empties to the panel toggle. Every action it carried — Add Scope,
Add Secret, Materialize, Check Drift, Materialize All Stale, Sync, Rescan, and
the three the overflow buried (Add Shared Secret, Preview .env, Jump to
Directory) — moves into the panel. Nothing is reachable only through a nested
menu. Disabled logic travels with each verb unchanged (selectedScopeID,
model.activity, the preview/jump disabled reasons).
Decision 2 — Appearance control lives at the panel's base; Settings keeps the durable copy
A quiet System/Light/Dark control sits at the bottom of the panel, reading and
writing the same @AppStorage(AppAppearance.storageKey) the Settings scene
uses — one stored value, two surfaces, no divergence possible. Settings (⌘,)
stays as-is; the panel makes the control reachable without knowing it exists.
This resolves the 06.2 's reconsideration ("a panel changes the
calculus") in the panel's favor; the floated top-bar toggle is declined — it
would re-add chrome to the toolbar this ho empties.
Decision 3 — Flat pālana grounds across the whole window
The holistic call 06.4 deferred here, made: the translucent system materials
(.bar, .quaternary) are replaced by flat token fills across the window.
This is the notebook-over-Mac move — the window becomes warm paper the way
pālana's own surfaces are, and Sharibako and pālana read as siblings rather
than a native-vibrant app wearing pālana's accent.
The mapping:
- Window panes (sidebar, secret list, detail) —
ground, warm paper. - Status surface and footer-weight chrome —
groundDeep, the raised shade. The status pulses keep their and opacities; they now wash over flatgroundDeepinstead of.bar. - The action panel —
panelGround, the cooler data surface, so the panel reads as a distinct working surface against the paper.
Fallback, named now: the sidebar's native translucency (desktop showing through) is the most Mac-native thing this decision flattens. If the flat sidebar reads wrong at the visual gate, the fallback is flat-except-sidebar — everything else stays on tokens. That is a gate call, not a reopening.
Decision 4 — Destructive-verb rust folds in
Delete/remove affordances get Color.drift per pālana, closing the gap 06.4
flagged (its migration left destructive affordances neutral). Small, and the
work already touches these views. The system's role: .destructive red (the
drift-overwrite and all-stale confirmation buttons, any delete controls) is
brought onto the rust voice so success/alarm hues stay pālana's throughout.
Discovery (deferred to execution)
- Panel grouping and order. The proposed cut: selected-scope verbs (Materialize, Preview .env, Jump to Directory), vault-wide verbs (Check Drift, Materialize All Stale, Sync, Rescan), create verbs (Add Scope, Add Secret, Add Shared Secret), appearance at the base. Execution-level; tune by what reads calm.
- Collapse affordance shape. Toolbar toggle icon, panel width, whether the collapsed state leaves any edge affordance. Execution-level.
- The destructive-affordance census. Enumerate every
role: .destructiveand delete/remove control at execution time and wire each to rust; the census is a grep, not a decision. - How rust reaches dialog buttons. SwiftUI confirmation-dialog buttons take
their destructive tint from the system; whether rust lands via
.tint, a button style, or per-label foreground is an implementation find.
Phase 2 — Execute
Branch panel-chrome off main. No agent tasks — the work is one bounded
surface (chrome + grounds across a handful of view files) with no natural
seams; splitting it would force coordination where none is needed. This
document frames the session directly.
The work, in order:
Sources/Sharibako/Views/ActionPanel.swift— the panel view: grouped, always-titled action buttons; collapse handled by the parent; appearance control at the base. Any branching logic (which verbs are disabled and why) stays inWorkshopModel's tested surface — the view stays declarative.WorkshopWindow.swift— embed the panel trailing theNavigationSplitView; strip the toolbar to the panel toggle; migrate the status surface togroundDeep.- Grounds migration — replace
.bar/.quaternarysites acrossScopeSidebar,SecretList,SecretDetail, the Add sheets, and Settings with the token fills per Decision 3. - Rust wiring — the destructive-affordance census, then
Color.drifton each (Decision 4). - ci.yml — new View file(s) join the named-
EXCLUDEDregex with justification comments, the established convention.
Testing and iteration approach
Per change, the rhythm: swift package clean && swift test
directly (never clean→build→test — the SwiftPM incremental-link bug after
SharibakoCore changes) → swift build -Xswiftc -warnings-as-errors →
swift-format lint --strict --recursive Sources Tests → swiftlint lint --strict → coverage ≥90%. Logic that branches (panel-verb enablement, if any
of it moves) lives tested in WorkshopModel; declarative View bodies are
CI-excluded by name with justification. Tests never touch live user state —
injected home / roots / temp vaults only.
Done means
- Every Workshop action is reachable directly in the open panel — titled, no overflow menu, no nested menus anywhere in the chrome.
- The toolbar carries the panel toggle and nothing else; the panel collapses and restores, and the state survives relaunch.
- The appearance control at the panel base flips System/Light/Dark live, and Settings' flipper stays in agreement (same stored value).
- The window renders on flat pālana grounds —
groundpanes,groundDeepstatus surface,panelGroundpanel — in both appearances, no.bar/.quaternarymaterials remaining (or the named sidebar fallback, if the gate calls it). - Destructive affordances read rust, not system red.
- Nothing regresses from 06.2: glyphs, Check Drift, per-key drift, reconcile, Materialize All Stale, Settings, and the footer behave exactly as gated.
- The full rhythm is green; coverage ≥90% with new View exclusions named and justified in ci.yml.
- Zero files under
Sources/SharibakoCLI/orSources/SharibakoCore/change. - Dogfood gate passed (below).
Verification and the gate
-
The rhythm above, green, on the
panel-chromebranch. -
Signed-install gate — the committed Xcode project is the only real build path for the Workshop (the 06.4 lesson: not
swift run, notscripts/install.sh):xcodebuild -project xcode/Sharibako.xcodeproj -scheme Sharibako \ -configuration Release -derivedDataPath .build/xcode buildReplace
/Applications/Sharibako.appwith the product and launch from/Applicationsexplicitly (Spotlight resurfaces stale DerivedData builds). Against the real vault and Keychain:- Every verb fires from the panel: Materialize, Check Drift (one Touch ID), Materialize All Stale, Sync, Rescan, the three Adds, Preview .env, Jump to Directory.
- Collapse the panel, quit, relaunch — still collapsed; restore it — the full set is back, nothing buried.
- Flip appearance from the panel base; confirm Settings agrees; quit and relaunch — the override holds.
- Drift loop unregressed: hand-edit an owned line, Check Drift, see per-key drift, reconcile, watch it clear.
- The visual light/dark gate is the operator's eyeball on this build — flat grounds in both appearances, panel legibility, rust on destructive verbs, calm overall. Not called passed until Andrew confirms on the themed build. The sidebar fallback (Decision 3) is decided here if needed.
Phase 3 — Reflect
Recorded during the gate (2026-07-11) — scope deletion does not exist
The operator asked "how do I delete a scope?" and the answer is: nowhere.
No GUI affordance, no CLI verb, and — the real finding — no SharibakoCore
operation. The says deletion is "always an explicit user
action against the Vault Core," but the Vault Core verb was never in ho-01's
nine operations. The only path today is hand-deleting the scope directory
inside the vault and committing. Owed: a delete-scope ho across all three
surfaces (Core verb + CLI verb + GUI affordance with confirmation) — new
vault behavior, outside this chrome-only ho, flagged for the K4 overview
pass. That ho is also destructive-rust's first real in-window consumer.
Recorded during the gate — dialogs take no tint; rust cannot reach them
Decision 4's dialog wiring failed empirically, twice. With role: .destructive
plus a rust .tint, the system paints its destructive red label over the rust
fill ("icky red"). With the role dropped, the tint is ignored outright and the
button renders system-blue — confirmation dialogs render out of the view
hierarchy and inherit no tint at all, not even the moss accent. Resolution:
dialogs stay fully system-rendered (role: .destructive, no tint) and speak
the system's alarm voice; pālana rust applies to in-window destructive
affordances only — of which none exist yet. The first real consumer is the
owed delete-scope ho.
Recorded during the gate — Edit Notes now authenticates on demand
The editor opened blank over an undecrypted note (silently clearing it
on save) and, after the first fix, prefilled only when already revealed. The
operator's call: editing a note should ask for authentication. Edit Notes
now routes through the same synchronous reveal intent when the payload
isn't decrypted — Touch ID prompts, the editor opens prefilled; on auth
denial the editor does not open and the status surface announces the error.
Filled at close (2026-07-11, after the signed-install gate)
The flat-grounds bet held in full. Both appearances passed the operator's
eyeball on the signed /Applications build; the sidebar fallback never fired —
the flattened sidebar reads fine without its translucency. The window sits on
palana paper and the operator's summary was "everything works."
The panel earns its width. Every verb fired from the panel at the gate; nothing is buried, the emptied toolbar reads calm, collapse persisted across relaunch, and the panel-base appearance control stayed in agreement with Settings. The drift loop (hand-edit → Check Drift → per-key drift → reconcile → clear) ran unregressed.
Decision review. Decisions 1–3 (custom panel, panel-base appearance, flat grounds) held as ratified. Decision 4 half-failed: the destructive-verb census found no in-window destructive affordances anywhere — rust's intended consumers don't exist yet — and the only destructive controls (the two confirmation-dialog buttons) proved untintable, twice (the two gate sections above). Dialogs stay system-rendered; the operator accepted this without enthusiasm ("not thrilled, but OK") — if it keeps rankling, the escape hatch is a custom in-window confirmation surface, noted and not scheduled. Rust remains defined and waiting for the delete-scope ho.
What the tests didn't catch — view-layer, by (the gate's job):
the dialog tint behavior (dialogs render out of hierarchy; no unit test sees
that), the notes editor opening blank over an undecrypted note, and the two
rounds of dialog-color tuning. One behavior change landed from a gate
question: Edit Notes now authenticates on demand through the synchronous
reveal intent (the section above).
Answered at the gate: ScopeType (Project — dev, Service, …) is
confirmed tag-only — it drives sidebar sectioning and the ingest default
suggestion; no behavior keys off it.
Followups (for the K4 overview pass):
- The delete-scope ho — the gate's real finding (section above): no delete verb exists on any surface, Core included. Three surfaces, plus it is destructive-rust's first real consumer. The operator wants it tracked.
- ho-06.3 (first-run + age key + backup nudge + GUI ingest) — unchanged, still the Checkpoint-2 gate.
- ho-06.6 (multi-root scan management) — the panel is now the natural home for the roots UI, as K4 anticipated; nothing here changes that call.
- K4 body: mark 06.5 closed, place the delete-scope ho.
Closing this ho
Closing = fill this Reflect + flip status: complete + write the state-summary
block to the project's K6 (/kamae-6-sharibako-state-memory.md,
refreshing the block at the top, verbatim labels and order) + append a
build-record entry to K4 (ho-process/kamae-4-sharibako-ho-overview.md, ,
append-only). The block:
STATE-SUMMARY
- COMPLETED — <what this ho finished>
- NEXT — <the single pointer to what comes next>
- ACTION ITEMS / BLOCKS — <open items; blocks loudly, or
none> - PROJECT LIFECYCLE — <kamae | dev | beta | production>
Authored 2026-07-11 (Think ratified same day, four decisions; the forward-only response to ho-06.2's gate finding). Executed and closed 2026-07-11: panel + flat grounds + two gate-fix rounds (dialog rendering, notes auth-on-demand), signed-install gate passed; the missing delete-scope verb recorded as the gate's owed ho.
Rendered from the corpus, verbatim · source on GitHub →