You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[UX] Settings selects leak raw JSON ids; goal footer leaks internal enums and conflicting tones #67
A cluster of wrong-state displays in the settings form and the goal status footer.
Settings selects (UX-12)
Option ids are JSON.stringify(value) (packages/mayfly/src/interaction/settings-model.ts:76, :79). When the configured value is not among the options (e.g. a deleted agent preset still set as default, or permission.defaultPreset: custom which the preset list never contains), the collapsed select renders the raw id with literal quotes — "custom" shown as '"custom"' (packages/mayfly/src/core/ui-patterns.ts:352).
For multiselects, unknown values vanish from the display entirely (ui-patterns.ts:353) yet still trip "A selected option is unavailable" on save (packages/mayfly/src/core/ui-interaction-form.ts:258) — an error about a selection the user cannot see anywhere.
Goal status (UX-13)
The footer interpolates the raw internal enum goal.activation (packages/mayfly/src/transcript/status-goal.ts:21): users see Goal active · 2/10 · armed — armed/disarmed is a process-local continuation flag (@deepseek-ai/dsh-goallib/types/types.d.ts:58), and the 2/10 fraction has no unit.
Tone and visibility rules conflict between footer and todo pane: blocked is warning in the footer (status-goal.ts:39-45) but red ✕ danger in the pane (pane-todo.ts:202-206); paused is warning vs muted ❚❚; a complete goal is hidden by the pane (pane-todo.ts:209) yet renders "Goal complete · N/M · …" in the footer indefinitely (status-goal.ts:19-22 has no complete case).
Acceptance criteria
Off-list select values render as readable labels (not JSON-quoted ids); multiselect stale values are visible (e.g. marked unavailable) so the save error is actionable.
Goal footer uses human wording for activation/state, a labeled unit for the fraction, and consistent tone/visibility with the todo pane; a completed goal does not linger in the footer.
In progress (status:in-progress). Covered by the unified display-fidelity plan:
UX-12 — interaction/settings-model.ts: make the stored-value → label mapping total by appending off-list stored values as labeled options (select: one; multiselect: each missing value), not disabled, so the raw JSON.stringify id never reaches the renderer and the phantom "A selected option is unavailable" save error disappears. No packages/ui contract change.
UX-13 — transcript/status-goal.ts: human wording, round n/m unit, tone/visibility aligned with pane-todo.ts, complete goals hidden; empty blockedReason no longer renders a bare blocked: row.
Branch fix/display-layout-fidelity, worktree mayfly-display-layout. Evidence docs land with #77.
Implementation opened as #81 (branch fix/display-layout-fidelity). pnpm run verify:full is green (typecheck, lint, build, shots, coverage, happy smoke). Manual runtime acceptance is pending before merge.
Status after verification on current main (14e6ce7):
UX-12 (settings selects): fixed by fix(ui): display-fidelity and layout-budget hardening (#67 #68 #73 #74) #81 — off-list scalars project as readable options (optionEntries in interaction/settings-model.ts), non-scalar containers read as unset / "Managed in settings file" instead of a raw JSON id, and the phantom "A selected option is unavailable" save error is gone. settings-model.spec.ts (9 tests) passes. The first acceptance box can be checked.
UX-13 (goal footer): still open. Implementation starting on branch fix/goal-footer-ux13:
human activation wording — drop the raw armed/disarmed enum; silent when armed, a translated auto-continue off marker when disarmed;
labeled unit for the fraction — round {rounds}/{total};
tone/visibility aligned with the todo pane badge — active → accent, paused → muted, blocked → danger, and completed goals hidden instead of lingering as success;
the pane no longer renders a bare blocked: row when the reason message is empty.
Activity
GeekCmore commentedon Sep 28, 2026
In progress (
status:in-progress). Covered by the unified display-fidelity plan:interaction/settings-model.ts: make the stored-value → label mapping total by appending off-list stored values as labeled options (select: one; multiselect: each missing value), notdisabled, so the rawJSON.stringifyid never reaches the renderer and the phantom "A selected option is unavailable" save error disappears. Nopackages/uicontract change.transcript/status-goal.ts: human wording,round n/munit, tone/visibility aligned withpane-todo.ts, complete goals hidden; emptyblockedReasonno longer renders a bareblocked:row.Branch
fix/display-layout-fidelity, worktreemayfly-display-layout. Evidence docs land with #77.GeekCmore commentedon Sep 28, 2026
Implementation opened as #81 (branch
fix/display-layout-fidelity).pnpm run verify:fullis green (typecheck, lint, build, shots, coverage, happy smoke). Manual runtime acceptance is pending before merge.fix(ui): unify display values, overflow signalling, and editor-slot l…
Merge pull request #81 from Ephemeral-AI-Lab/fix/display-layout-fidelity
GeekCmore commentedon Sep 29, 2026
Status after verification on current
main(14e6ce7):optionEntriesininteraction/settings-model.ts), non-scalar containers read as unset / "Managed in settings file" instead of a raw JSON id, and the phantom "A selected option is unavailable" save error is gone.settings-model.spec.ts(9 tests) passes. The first acceptance box can be checked.fix/goal-footer-ux13:armed/disarmedenum; silent when armed, a translatedauto-continue offmarker when disarmed;round {rounds}/{total};active → accent,paused → muted,blocked → danger, and completed goals hidden instead of lingering as success;blocked:row when the reason message is empty.