Migrate to structure v2 and declare a block kind - #130
Merged
Conversation
Output of `block-tools structure refresh`, plus the catalog entry for @platforma-sdk/block-kind and the kind/ workspace member the refresh needs to discover. block-tools 2.11.6 -> 2.13.0, model/ui-vue 1.79.20 -> 1.81.1, workflow-tengo 6.6.5 -> 6.8.2, tengo-builder 4.0.11 -> 4.0.22. Software packages move from pl-pkg to `block-tools software build`; build scripts move to the PL_BUILD_* channel scheme.
Every block must declare a kind; this one's init-params contract is the study setup a project template supplies — the metadata columns the study collects, the name of the sample column, and how its datasets are configured — plus whichever of its data can be resolved from where the block lands. Either the whole study travels or none of its data does. Block state is one connected thing: datasets key their files by sample or by group, sample groups and multiplexing rules name those samples, metadata values are keyed by them, and args holds the pieces to each other. So when every file is a storage reference (index:// names a storage and a path) the state goes as it stands; when any file is a local upload — a machine-local path signed with the installation's own secret — only the setup goes, and the new project imports its own data. Carrying part of it would mean picking which invariant to break. metadataUploadHandle stays out of the contract: it is not a link to the metadata table but scaffolding for one import dialog, cleared as soon as the parsed values land in metadata. The dataset and metadata types move into the kind package and are re-exported from the model, so every existing import keeps resolving. Also replaces the removed TreeNodeAccessor.resolveAny with traverse, which the SDK upgrade requires.
Temporary. @platforma-sdk/block-kind is not published to npm yet, so the catalog entry only resolves through these overrides — drop this commit once it is published.
@platforma-sdk/model 1.82.0 depends on pl-model-common 1.48.0, while the catalog range resolved the kind's direct dependency to 1.47.3. PlId is branded there, so the two copies gave the model two incompatible PlId types and multiplexing-rules-validation.ts failed to compile. Pin the catalog to the version the SDK uses. The lockfile still carried the local file: overrides after they were removed from package.json, which fails the frozen-install gate. Also puts deriveTemplateParams above its helpers.
Comment on lines
+27
to
+28
| h5adFilesToPreprocess: data.h5adFilesToPreprocess, | ||
| seuratFilesToPreprocess: data.seuratFilesToPreprocess, |
There was a problem hiding this comment.
Preprocessing handles bypass portability check
When the datasets are portable or empty but either preprocessing queue still contains a local upload handle, deriveTemplateParams copies that handle into the template because its portability check examines only dataset contents. The destination block restores the queue and attempts to import the installation-local handle during prerun, preventing the corresponding preprocessing outputs from resolving.
Prompt To Fix With AI
This is a comment left during a code review.
Path: model/src/template_params.ts
Line: 27-28
Comment:
**Preprocessing handles bypass portability check**
When the datasets are portable or empty but either preprocessing queue still contains a local upload handle, `deriveTemplateParams` copies that handle into the template because its portability check examines only dataset contents. The destination block restores the queue and attempts to import the installation-local handle during prerun, preventing the corresponding preprocessing outputs from resolving.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
AStaroverov
marked this pull request as draft
August 19, 2026 17:14
Splits the kind into types/params/index like every sibling block, and replaces the hand-rolled primitive checks with es-toolkit predicates: isPlainObject for the object envelopes — hand-written it is wrong three ways, since typeof null is "object", Object.keys(5) is [] and Object.keys(["a"]) is ["0"] — plus isString and isBoolean for the fields. The file-handle check now uses the SDK's own prefix guards instead of accepting any string. Adds the CONTRACT table with the satisfies drift guard the other kinds carry, which this one lacked: every field being optional means a parser that simply forgot one would otherwise return a valid BlockParams and say nothing. Numeric and array guards stay native on purpose. es-toolkit only ships those in its lodash-compat layer, where isInteger returns a plain boolean and cannot be a type guard at all, and isNumber accepts NaN and boxed Numbers — both looser than Number.isInteger and Array.isArray. The per-item error messages get coarser: a bad metadata column now names the field rather than the row index. That is what the shared shape costs, and what the five sibling kinds already accept.
… the contract isArray comes from es-toolkit/compat, which is where the narrowing version lives; the root entry ships none. BlockParams was appended at the end of types.ts, under 240 lines of the dataset and metadata types that support it. It is what the file exists to declare, so it now leads — as it does in every sibling kind.
AStaroverov
marked this pull request as ready for review
August 20, 2026 12:03
Publishing goes to the normal channel. The flag was carried while the batch was in flight; the structurer strips it on every refresh, so keeping it also meant `structure check` reporting this one field as drift forever.
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.
What
Brings
samples-and-dataonto the current canonical block layout and gives it the now-mandatory kind, whose init-params contract is what a project template supplies to seed a new instance.Structure v2 + SDK upgrade
block-tools structure refreshoutput: block-tools 2.14.0, model/ui-vue 1.82.x, workflow-tengo 6.8.2, tengo-builder 4.0.23. Software packages move frompl-pkgtoblock-tools software build; build scripts move to thePL_BUILD_*channel scheme; CI moves to thehz-ubuntu-dindrunner.The kind and its init-params contract
The contract is the study setup a template carries — the metadata columns the study collects, the name of the sample column, how its datasets are configured — plus whichever of its data can be resolved from where the block lands.
Either the whole study travels or none of its data does. Block state is one connected thing: datasets key their files by sample or by group, sample groups and multiplexing rules name those samples, metadata values are keyed by them, and
argsholds the pieces to each other. So:index://names a{storageId, path}) → the state goes as it stands;Carrying part of it would mean picking which invariant to break — in particular
validateDatasets, which requires as many sample groups as file groups.metadataUploadHandleis deliberately outside the contract: it is not a link to the metadata table but scaffolding for one import dialog, cleared as soon as the parsed values land inmetadata.The dataset and metadata types move into the kind package and are re-exported from the model, so every existing import keeps resolving. The projection lives in
model/src/template_params.tsas the exportedderiveTemplateParams.Two fixes the upgrade forced
TreeNodeAccessor.resolveAnywas removed from the SDK; themetadataFileoutput now usestraverse, its alias.@platforma-sdk/model1.82.0 depends onpl-model-common1.48.0 while the catalog range resolved the kind's direct dependency to 1.47.3.PlIdis branded there, so two copies gave the model two incompatiblePlIdtypes. The catalog is now pinned to the version the SDK uses.Verification
turbo run build— 13/13 green;pnpm install --frozen-lockfileclean.validateDatasets' invariant holds on every outcome, and the kind's parser accepts what the projection emits.content.type, badvalueType, non-string roster entries, …).collectDatasetHandlesis exhaustive overDSContent— verified by removing a case and gettingTS2345 ... not assignable to parameter of type 'never'.Not run: the block's integration tests, which need a live backend on
PL_ADDRESS.BlockData's shape is unchanged, sotest/src/wf.test.tsshould pass as is — assumption, not a check.Before merge
Commit
22891f1("pin SDK deps to local monorepo builds") was the temporaryfile:overrides needed while@platforma-sdk/block-kindwas unpublished. It is published now (1.1.0) and58d8a58already removed the overrides — the earlier commit is left in history only as the record.Greptile Summary
The PR migrates the block to structure v2, upgrades its SDK and software-build tooling, and introduces a block-kind contract used to initialize instances from project templates.
kindpackage and connected to both the data model and block model.PL_PKG_DEVbuild flow for local and release builds.Confidence Score: 4/5
The PR is not yet safe to merge because templates can still restore installation-local preprocessing handles on a destination where they cannot resolve.
The template projection checks portability only inside datasets, then copies both preprocessing queues unchanged; destination initialization feeds those handles into prerun imports, leaving the previously reported portability failure reachable.
Files Needing Attention: model/src/template_params.ts
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Current block state] --> B[deriveTemplateParams] B --> C{All dataset handles portable?} C -->|Yes| D[Copy datasets, metadata, samples, and preprocessing queues] C -->|No| E[Keep dataset setup and clear sample/group data] D --> F[Kind parser validates params] E --> F F --> G[Data model initializes destination block] G --> H[Prerun imports queued preprocessing handles]Reviews (2): Last reviewed commit: "refactor: take the array guard from es-t..." | Re-trigger Greptile
Context used: