Skip to content

MILAB-6648: add the mandatory block kind and migrate column access - #211

Merged
AStaroverov merged 6 commits into
mainfrom
feat/project-template-migration
Aug 20, 2026
Merged

MILAB-6648: add the mandatory block kind and migrate column access#211
AStaroverov merged 6 commits into
mainfrom
feat/project-template-migration

Conversation

@AStaroverov

@AStaroverov AStaroverov commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Brings mixcr-clonotyping onto the current block structure: it declares the mandatory kind/ component, and its model moves off the removed and deprecated column-access surface.

The kind

A block kind is a small, separately versioned package carrying the block's identity and its init-params contract — the fields a project template supplies to seed a new instance. structure check hard-fails a kind-less block, so this is what unblocks the block on the current structurer.

BlockParams covers the analysis recipe, input refs, run mode and resources, and display labels — everything in BlockData except tableState, which is view state.

Two decisions worth reviewing:

  • Every field is optional. A block with no input picked and no preset chosen is an ordinary state the UI reaches, so export has to be able to write it and apply has to take it back. A contract demanding input would stop export and apply being inverses. Whether a configuration is runnable stays gated by the model's args lambda.
  • File-valued params are narrowed to index:// handles. An upload:// handle names an import local to one machine, so it cannot survive being written to a template and applied elsewhere. The parser rejects them and templateParams drops them, rather than writing a reference that resolves nowhere. This applies to libraryFile and to a file-shaped preset.

The runtime check is a CONTRACT table validated with satisfies over keyof BlockParams, so adding a field without its guard fails to compile — which matters precisely because every field is optional, and a parser that simply forgot one would otherwise return a valid BlockParams and say nothing.

Column access

Per migrations/2026-05-20-new-column-access-mechanism.md and docs/column-access-api.md:

Before After Sites
ColumnLazy / .fromColumn DataColumn, then dropped entirely 3
resultPool.getSpecByRef(ref) Column(ref)?.getSpec() 2
accessor.getPColumns() ColumnsCollection([accessor]) 3

The collection resolves ids host-side, so clones and pt no longer materialise specs in the sandbox only to hand them straight back. rawTsvs also drops its ...pCol spread — its only consumer (ui/src/MainPage.vue) reads id and data and never touches the spec, so that output now fetches no specs at all.

Deliberately unchanged:

  • resultPool.getOptions (3 sites) — the migration doc says to stay on it: ctx.getOptions is not on RenderCtxBase yet, and it is the only entry point preserving the Option[] = { ref, label } wire shape with refsWithEnrichments.
  • sampleLabels still calls resultPool.getData(). This is the real 8 MB anti-pattern and worth fixing, but the axis-domain matching has to be reworked against a discover selector plus a getSpec() post-filter, and the data-reading tail needs narrowing off the PColumnDataUniversal union. Out of scope here — left for a separate change.

Verification

  • turbo run build — 11/11 green.
  • block-tools structure checkup to date (0 changes), i.e. a fixpoint.
  • pnpm install --frozen-lockfile — in sync.
  • The kind's parseInitializationParams exercised against the built dist/kind.js: empty params, a template-shaped { species, preset }, an unknown key (dropped), a wrong-typed field, upload:// vs index:// handles, a bad enum, and null / array envelopes all behave as intended.

No backend run — nothing here changes workflow behavior.

Greptile Summary

The PR adds the mandatory block-kind contract, connects template import/export to model state, and migrates model outputs to the current column-access APIs.

  • Block kind — a separately versioned package defining block identity and initialization parameters; this PR adds the kind/ workspace package and connects it to the model and block build.
  • BlockParams — the typed, runtime-validated initialization contract; this PR covers analysis settings, inputs, resources, run mode, and labels while excluding table view state.
  • Initialization params — template-supplied values used to seed a block; this PR parses them field-by-field and applies model defaults to omitted values.
  • Template params — the model projection serialized during template export; this PR exports the initialization fields while dropping machine-local file handles.
  • ImportFileHandleIndex — a portable index:// file reference; this PR narrows template file parameters to this type instead of retaining local upload:// references.
  • ColumnsCollection — a host-side collection that resolves column identifiers; this PR replaces direct getPColumns() calls for clone, QC-table, and raw-TSV outputs.
  • DataColumn — a column carrying accessible data; this PR uses it to identify raw-TSV columns and retrieve their file resources.
  • Column — a reference-based column accessor; this PR replaces deprecated result-pool specification lookups with Column(ref)?.getSpec().
  • CI and package metadata move to Node.js 22, update Platforma SDK dependencies, require a block-package changeset, and add unstable publishing plus stable-promotion support.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains.

No blocking failure remains.

Important Files Changed

Filename Overview
kind/src/types.ts Defines the new optional initialization contract and portable file-reference types.
kind/src/params.ts Adds exhaustive runtime guards for every initialization parameter.
kind/src/index.ts Defines the separately versioned block-kind identity and parser.
model/src/index.ts Connects the model to its kind, implements template parameter projection, and migrates column access.
block/package.json Integrates the kind package and introduces unstable publishing and stable-promotion scripts.
pnpm-workspace.yaml Registers the kind package as a workspace member.
.github/workflows/build.yaml Moves CI to Node.js 22 and enforces a changeset bump for the published block package.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  T[Project template] --> P[Kind parameter parser]
  P --> I[Model init]
  I --> D[BlockData]
  D --> A[Runtime args validation]
  D --> E[Template parameter projection]
  E -->|portable index handles only| T
  W[Workflow output trees] --> C[ColumnsCollection / Column]
  C --> O[Clone frame, QC table, labels, raw TSV outputs]
Loading

Reviews (2): Last reviewed commit: "update node version to 22.x and bump dep..." | Re-trigger Greptile

Context used:

  • Context used - Terms is a types in codebase. Provide the list of ... (source)

Adds the mandatory kind/ sibling and runs structure refresh, which wires the
facade's kind devDep, the model's kind dependency, the workspace packages list
and the canonical kind configs. Also picks up require-package-path-bump on the
published block package.

Discovery classifies a package as a kind by its @platforma-sdk/block-kind
dependency, but only enumerates workspace modules — so both the packages entry
and the catalog entry had to be added by hand before refresh could see it.
BlockParams covers the analysis recipe, input refs, run mode and resources, and
display labels — everything in BlockData except tableState, which is view state.

Every field is optional on purpose. A block with no input picked is a state the
UI reaches, so export has to be able to write it and apply has to take it back;
a contract demanding input would stop export and apply being inverses.
Runnability stays gated by the model's args lambda.

File handles are narrowed to index:// — an upload:// handle names an import
local to one machine and resolves nowhere else.

The CONTRACT table is checked with satisfies over keyof BlockParams, so adding a
field without its guard fails to compile. That matters precisely because every
field is optional: a parser that simply forgot one would otherwise return a
valid BlockParams and say nothing.
Kind wiring: DataModelBuilder({ kind }), BlockModelV3.create({ dataModel, kind }),
init consuming params with per-field defaults, and the templateParams projection
mirroring the same field set back out.

Column access moves off the removed and deprecated surface:
- ColumnLazy -> DataColumn (removed in the new mechanism)
- resultPool.getSpecByRef(ref) -> Column(ref).getSpec()
- all three getPColumns() call sites -> ColumnsCollection

The collection resolves ids host-side, so clones and pt no longer materialise
specs in the sandbox just to hand them back. rawTsvs drops its ...pCol spread —
the only consumer reads id and data, so the output now fetches no specs at all.

resultPool.getOptions stays: ctx.getOptions is not on RenderCtxBase yet, and it
is the only entry point preserving the Option[] wire shape.

sampleLabels still calls resultPool.getData() — migrating it needs the domain
matching reworked against a discover selector, left for a separate change.
@AStaroverov
AStaroverov marked this pull request as draft August 19, 2026 17:14
@AStaroverov
AStaroverov marked this pull request as ready for review August 20, 2026 12:02
@AStaroverov
AStaroverov enabled auto-merge August 20, 2026 12:18
@AStaroverov
AStaroverov added this pull request to the merge queue Aug 20, 2026
Merged via the queue into main with commit 0076b32 Aug 20, 2026
10 checks passed
@AStaroverov
AStaroverov deleted the feat/project-template-migration branch August 20, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant