Repository navigation
Conversation
A composition spike before the API freeze (slice 1.11): ModelPicker and EffortPicker built with only @ephemeral-ai/mayfly-ui, compiled by the real renderer, compared with scene 23's goldens, and measured with the work counters. Records the gaps in docs/design/spike-model-picker.md. No source file changed and nothing is wired into the product. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Spike: the model picker as a pure component
A composition spike before the
@ephemeral-ai/mayfly-uifreeze (slice 1.11): are the public basic components enough tobuild a real Mayfly component?
packages/mayfly/tests/design/spike/model-picker.tsholdsModelPickerandEffortPickerin the Phase 2a style:
defineMayflyComponent(withmemo), plain facts shaped likecatalogRowsandcurrentModelSelection, a translatort, and only@ephemeral-ai/mayfly-uiimports.model-picker.spec.tscompiles themwith the real renderer (
createRealSurface) and compares scene 23's goldens. No source changed; nothing is wired in.Base:
e0d4d04.1. What composed cleanly
ui.surface+ui.listwithgroup,detail,badge, and a per-rowsegmentwithinheritedId.No
patterns.*fits (it is a list, not a rail, split view, status page, or decision card).(default),Delete use default, the numbered/effortlist,[current · high],Provider default (high) [current], the filter header, and the 62-column ladder all come from the list painter. There is no button: withno
acceptActionIdthe list still emitsselection-acceptwithsegmentId(absent = unpinned, roadmap 2a); the spec checks it.‹ high ›and accept reportshigh, so an explicithighand anunpinned selection stay distinguishable, as
sameSelectionneeds./skillsand/renamealready hand an overlay a surface-rooted node, sochrome: 'overlay'is enough (not mounted here).2. Gaps and workarounds, by severity
Blocking: none. Awkward:
selectedIds: []is required on everyui.list(roadmap 3.1), so every Phase 2 component repeats it.MayflyTranslate(frontend/), so the spikeredeclares
(key, values?) => string; every component would.memo: truecompares props shallowly, butinteractionTranslator(ctx)returns a new closure per call, so the memonever hits unless the owner hoists
t(the spec shows both cases).formatContextWindowlives ininteraction/, off limits to a component. Phase 2a moves it intocomponents/or puts aformatted
contextLabelin the fact (the spike copies it).openModelPickerignores thedefaultEffortthatcatalogRowsreturns, andswitchEffortnever readsinfo.reasoning.defaultEffort.inheritedIdandProvider default (high)need both.{size} context,current · {effort},Provider default ({level})); the zh catalog needs them.assertion covers it. A
live-rowwalk (cursor on the current model) would pin it in the goldens.Cosmetic:
8.
acceptVerbis a closed enum, so the component cannot localize the hint verb (core does).9. The kit's
empty: 'No models match'is unreachable: a filter with no match shows core'sNo matches, andemptyshows only for an empty catalog, so the component uses the real
No models advertised.3. Before the freeze (slice 1.11)?
Nothing blocks it, and every fix is additive, so none must precede it. The smallest worth taking: (a) default
selectedIdsto[]inui.list(item 1); (b) a type-onlyMayflyTranslateexport (item 2). Item 3 is Phase 2guidance (hoist
tper locale revision); the rest is Phase 2a work.4. Parity per walk (
golden/23-model-and-effort)initial(84),pages(Ctrl+N),narrow(62),thinking(→ →),default(Delete),filterframe 0filterframes 1, 2 (/,d)▌in the field is Δ27 (waived, 1 cell); the hint row has a leading←/→ thinking ·the golden lacks (49 cells per frame)The hint row cannot be composed away: the kit steps the strip with
←/→while searching (ui-kit.mjsline 1046) but doesnot hint it; the renderer hints it ("the cue is true", like Δ29). The spec pins the row's text and fails if the difference
disappears. It needs a new accepted difference (Δ33) or a kit fix.
5. Work of one key (counters of
tests/perf/work-budget.spec.ts)A warmed, framed picker; the last key of each sequence is counted. Cells are
rowsPainted / stringsMeasured;nodesValidatedandunitsCompiledare 0 everywhere.↓→(strip)/d(keeps all)9(narrows)EnterWithin W3's rows budget (at most 2 painted, nothing validated or compiled), whatever the catalog size. Strings exceed W3's
40 because the overlay frame re-measures its rows on every key (bare list: 8 at 6 rows, 40 at 400; framed: 26, 198). That is
constant from 400 to 4,000 rows, but no budget covers a framed list; a
W3-framedrow would.Ran:
vitest run packages/mayfly/tests/design packages/mayfly/tests/perf(154 tests),design:golden:check,check:agent-docs,lint(no finding in the spike),typecheck(tsc -bdoes not includetests/). No full gate.Draft spike, not for merge: no source changed. The report is also in
docs/design/spike-model-picker.md.🤖 Generated with Claude Code