Migrate vj-gene-usage onto structurer + BlockModelV3 - #36
Conversation
Adopt the tool-managed block layout (oxlint/oxfmt, ts-builder, regenerated configs across model, ui, workflow, block, test) and the full SDK upgrade to latest (model/ui-vue 1.79.14, workflow-tengo 6.6.3, tengo-builder 4.0.8, block-tools 2.11.0). Remove dead test scaffolding: the empty placeholder test/src/wf.test.ts (oxlint no-empty-file) and the orphaned model/ui vitest.config.mts. CI workflows left unchanged from main (structurer drift — app-name casing, test:false->true, S3 bucket secret rename, Slack reorder — is unrelated).
Replace the V1 model (BlockModel + withArgs/withUiState/argsValid/done(2)) with BlockModelV3 + a DataModelBuilder: - model/src/types.ts: unified BlockData (datasetRef, scChain, allele, block labels, weightedFlag, three GraphMakerState plot states), workflow-facing BlockArgs (datasetRef + scChain + allele + customBlockLabel), legacy shapes. - model/src/dataModel.ts: .upgradeLegacy folds V1 args + uiState into data; .init seeds defaults. - index.ts: .args projects analysis params + customBlockLabel (the workflow's trace label) and throws on missing dataset (replaces argsValid). ctx.args-> ctx.data; .done(2)->.done(). - UI: defineApp->defineAppV3; app.model.args/ui.*->app.model.data.*. Block-label watchEffect kept (tolerated exception), repointed to data. The three graphs stay hand-rolled (<GraphMaker> + graphState in data). Dropped the dead customBlockLabel ??= '' and the redundant setInput (v-model already writes datasetRef).
There was a problem hiding this comment.
Code Review
This pull request migrates the block to the BlockModelV3 and upgrades the SDK dependencies to their latest versions. Key changes include unifying the persisted state under app.model.data and updating the UI components to bind to this new structure. The review feedback highlights three main improvement opportunities: first, using loose equality checks (== null) for datasetRef in model/src/index.ts to robustly handle both null and undefined values from the UI dropdown; and second, refining the isRunning transition check in ui/src/pages/VUsage.vue to explicitly verify a false to true transition, preventing the settings panel from closing prematurely on initial load.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Export only the public BlockData/BlockArgs from the model entry instead of `export * from './types'`, which also re-exported the internal LegacyBlockArgs/LegacyUiState (used solely by upgradeLegacy).
Migrates
vj-gene-usageonto the block-tools structurer and from V1 to BlockModelV3.Commits
chore:structurer refresh + SDK upgrade — tool-managed layout (oxlint/oxfmt, ts-builder, regenerated configs across model, ui, workflow, block, test). SDK → model/ui-vue1.79.14, workflow-tengo6.6.3, tengo-builder4.0.8, block-tools2.11.0. Removes the empty placeholdertest/src/wf.test.tsand orphanedmodel/uivitest.config.mts.feat:BlockModelV3 model — see below.chore:changeset.V3 design
datasetRef,scChain,alleleargs(analysis inputs)customBlockLabelargs— the workflow uses it as the trace labeldefaultBlockLabeldata— subtitle only (label sync no longer stales the block)weightedFlag, 3×GraphMakerStatedata— UI/view state.upgradeLegacyfolds V1args+uiStateinto unifieddata; persisted projects upgrade in place..argsthrows on missing dataset (replacesargsValid);.done(2)→.done().defineApp→defineAppV3,app.model.args/ui.*→app.model.data.*. Block-labelwatchEffectkept (tolerated exception), repointed todata. Dropped the deadcustomBlockLabel ??= ''and the redundantsetInput(the dropdown'sv-modelalready writesdatasetRef).<GraphMaker>component (graphStateindata).Verification
pnpm build:dev+check(tsc + oxlint + oxfmt) +pnpm testall green (turbo 9/9). Changeset validated (note: packages are…vj-usage.*, notvj-gene-usage).Not done: runtime legacy-upgrade check against a saved V1 project (needs a backend) — recommended before merge.
CI workflows left identical to
main(structurer drift unrelated to the migration).Greptile Summary
This PR migrates the
vj-gene-usageblock fromBlockModelV1 toBlockModelV3with the structurer toolchain, folding the previously splitargs/uiStatechannels into a single unifieddatachannel (BlockData). ADataModelBuilderwith.upgradeLegacyhandles in-place migration of persisted V1 projects, and all UI bindings move frommodel.args.*/model.ui.*tomodel.data.*.blockDataModeldeclares a "v1" versionedDataModelBuilder;.upgradeLegacymerges legacyBlockArgs+UiStateintoBlockDatawith safe nullish defaults;.args()now throws on a missingdatasetRefinstead of using.argsValid().defineApp→defineAppV3, removes the redundantsetInputfunction and the deadcustomBlockLabel ??= ''initialisation; thesyncDefaultBlockLabelwatchEffectis retained and repointed todata.BlockData(new unified V3 state — holds analysis inputs, view state, and derived labels),BlockArgs(workflow-facing projection ofBlockData,datasetRefrequired),LegacyBlockArgs/LegacyUiState(V1 on-disk shapes consumed once byupgradeLegacy),blockDataModel(DataModelBuilderinstance wiring version, upgrade, and init),platforma(the newBlockModelV3export — replacesmodel),upgradeLegacy(one-time migration from V1 split state to unifiedBlockData),defineAppV3(Vue app factory for V3, replacingdefineApp).Confidence Score: 4/5
The migration is well-executed and safe to merge; the only outstanding gap is the absence of a runtime test for the legacy upgrade path against a real persisted V1 project, which the author already flags.
The model, UI, and data-model wiring are all internally consistent. The upgradeLegacy fallback defaults are correct, initData is sound, and all model.args.* / model.ui.* references have been updated. The single comment is a style nit about migration-internal types leaking into the public API. No logic errors were found in the changed paths.
model/src/index.ts — the
export * from "./types"line inadvertently exposesLegacyBlockArgsandLegacyUiStateas public API. Worth tightening before the package version is widened.Important Files Changed
platformaexport replacesmodel, args projection added with required-field guard, subtitle/sections updated to read fromctx.data. LegacyBlockArgs and LegacyUiState inadvertently exported publicly.Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant UI as UI (Vue) participant Data as model.data (BlockData) participant Args as model.args (BlockArgs) participant WF as Workflow Note over Data: V1 Legacy Upgrade path Data->>Data: upgradeLegacy(LegacyBlockArgs, LegacyUiState) → BlockData Note over UI,WF: Normal V3 runtime path UI->>Data: v-model bindings write datasetRef, allele, scChain, customBlockLabel, weightedFlag, plotStates UI->>Data: watchEffect writes defaultBlockLabel Data->>Args: "args() lambda validates and projects (throws if datasetRef === undefined)" Args->>WF: datasetRef, scChain, allele, customBlockLabel WF-->>Data: outputs.pf, outputs.isRunning Data-->>UI: subtitle reads ctx.data.customBlockLabel or ctx.data.defaultBlockLabel%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant UI as UI (Vue) participant Data as model.data (BlockData) participant Args as model.args (BlockArgs) participant WF as Workflow Note over Data: V1 Legacy Upgrade path Data->>Data: upgradeLegacy(LegacyBlockArgs, LegacyUiState) → BlockData Note over UI,WF: Normal V3 runtime path UI->>Data: v-model bindings write datasetRef, allele, scChain, customBlockLabel, weightedFlag, plotStates UI->>Data: watchEffect writes defaultBlockLabel Data->>Args: "args() lambda validates and projects (throws if datasetRef === undefined)" Args->>WF: datasetRef, scChain, allele, customBlockLabel WF-->>Data: outputs.pf, outputs.isRunning Data-->>UI: subtitle reads ctx.data.customBlockLabel or ctx.data.defaultBlockLabelPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "chore: add changeset for structurer + V3..." | Re-trigger Greptile
Context used: