Support DMS antibody modality - #23
Open
mzueva wants to merge 7 commits into
Open
Conversation
Output of the canonical `structure refresh` flow on block-tools 2.14.3:
structure refresh --update-deps-only
pnpm install
structure refresh
pnpm install
pnpm fmt
SDK bumps: model/ui-vue 1.79.20 -> 1.83.0/1.83.1, workflow-tengo 6.6.5 ->
6.8.3, tengo-builder 4.0.11 -> 4.0.23, ts-builder 1.6.0 -> 1.7.1, ts-configs
1.3.0 -> 1.4.0, test 1.79.23 -> 1.83.2, block-tools 2.11.6 -> 2.14.3.
Structural changes:
- `kind/` scaffolded (mandatory fourth component). `src/index.ts` still holds
the `NEEDS_BLOCK_PARAMS` sentinel; the contract is resolved in the next
commit.
- `block/` becomes the slim facade: `dependencies: {}`, a bundled `dist/` plus
`block-pack/`, and the from-pack-v2 `SequencePropertiesBlockPointer` export.
Every sibling package is now `private: true`.
- Root build scripts move off `PL_PKG_DEV` onto `PL_BUILD_CHANNEL` /
`PL_BUILD_VARIANT` / `PL_BUILD_LOCATION`. `build` and `build:dev` are
replaced by `build:dev-local`, `build:dev-remote`, `build:dev-no-software`,
`build:dev-binary-existing` and `build:release`. The root gains
`upgrade-sdk`, so later SDK upgrades are one command.
- `software/` builds via `block-tools software build` instead of `pl-pkg`.
- CI (`build.yaml`) is now scaffold-owned: hz-ubuntu-dind runners, node 22,
turbo remote cache, and `require-package-path-bump`.
- Legacy config removed: `.prettierrc`, `test/eslint.config.mjs`, the
hand-written `block/index.js` and `workflow/index.js` entry stubs.
- The test scope is lint- and fmt-checked now, so its sources were reformatted.
One hand edit was needed to make `pnpm fmt` pass: `test/src/wf.test.ts`
carries 46 `it.todo`/`it.skip` placeholders that document unimplemented
scenarios, and the new test-scope lint runs with `--deny-warnings`. Added a
file-level `oxlint-disable vitest/warn-todo` with the reason, rather than
dropping the documented gaps.
pnpm was downgraded 9.15.0 -> 9.12.0 by the structurer's canonical pin.
…e build
Author-code work the structurer cannot do, on top of the previous commit.
Kind contract. `BlockParams` is `{ inputAnchor?: PlRef }` — the upstream
dataset a new instance computes properties on, and the only field a creator or
a project template supplies. Optional, because `templateParams` hands live
state back untouched and a block whose input is not picked yet holds
`undefined`; requiring it would make the block export a file its own kind
refuses to apply. `parseInitializationParams` checks that one field with the
SDK's own `isPlRef`, so the kind does not restate a type it does not own. The
model consumes it in `init(({ params }) => …)` and projects the same single
field back through `.templateParams`. Everything else in `BlockData` is view
state that always defaults.
Facade build. `block/dist/index.d.ts` inlines every type in the model's public
surface (the facade config is `external: () => false`), and `BlockData` holds
two `GraphMakerState` fields, which reach `@platforma-sdk/ui-vue` through
`graph-maker/dist/forms`. ui-vue 1.83.1 stopped publishing the four
`dist/components/*.vue.d.ts` files that its own `dist/lib.d.ts` re-exports, so
the bundle failed on four unresolvable `.vue` specifiers. Every version from
1.79.20 through 1.83.0 ships them, which is why blocks already migrated on
ui-vue <= 1.82.6 are unaffected. Held the catalog at 1.83.0 with the reason
recorded inline; `vue` is 3.5.24 either way, so no UI type cascade. Drop the
pin once a fixed ui-vue is published.
The model also gains its own `@platforma-sdk/ui-vue` dependency. graph-maker
declares ui-vue as a peer, and with no local declaration pnpm resolved that
peer to npm-latest rather than the catalog version — so the pin missed the
model's graph-maker instance entirely. Worth having on its own: it stops the
model's ui-vue from drifting on every install.
Cross-block test deps. Bumped samples-and-data to ^1.20.0 and
mixcr-clonotyping-2 to ^2.22.0 and dropped both `.model` deps: the upstreams
are slim facades now, so `BlockData` comes from the facade and blocks are added
by `<Block>BlockPointer` instead of the retired `blockSpec`. The old pins
dragged in second copies of `@platforma-sdk/model` (1.63.1, 1.65.4) and `zod`
(3.23.8); the lockfile now holds exactly one of each. Removed both
`satisfies <Block>BlockData` clauses — a facade bundles its own copy of the
brand symbols behind `PlId` and `CanonicalizedJson`, so those types never unify
with our catalog SDK's, and `mutateBlockStorage` takes the value as `unknown`.
The hand-rolled version-5 `tableState` literal the 2.18 pin needed is replaced
by `createPlDataTableStateV2()`.
Dropped two catalog entries the migration orphaned: `eslint` (its only
consumer was `test/eslint.config.mjs`, which the structurer deleted) and
`@platforma-sdk/blocks-deps-updater` (replaced by the root `upgrade-sdk`).
`pnpm build:dev-local` and every `check` are green, 12/12, from a
frozen-lockfile install. `structure check` is a fixpoint.
…lity vdj synthetic-repertoire-profiler runs one pipeline over both antibody/TCR parents and designed libraries, and everything it emits sits on the modality-neutral pl7.app/variantKey axis. It keeps pl7.app/repertoire/extractionRunId in both cases, so the run-id heuristic classified a VDJ run as amplicon and scanned it as a single whole sequence — the FR1-FR4 regions it emits, CDR3 included, were never read. Nothing failed; the run just produced whole-sequence properties for a V-domain. The profiler declares the kind it produced in the entity-axis domain, so read that first: `vdj` maps to antibody_tcr_universal, the branch that already existed for VDJ-on-variantKey, and `amplicon` maps to amplicon. Everything below the declaration is unchanged, so an input without one behaves exactly as before. Nothing else in the pipeline needed changing, and each step was checked against the producer rather than assumed: - The profiler's region columns are `pl7.app/sequence` with the region name in pl7.app/feature. The universalSequences bundle entry already matches those, and vdjSequences is empty for this producer, so the existing fallback finds them. Its whole-variant amplicon-sequence column is matched too and dropped by the REQUIRED_FEATURES filter. - A vdj run always carries exactly FR1-FR4: the profiler's model rejects a vdj-scheme parent with any other region set, and germline auto-detect hardcodes the same seven. Coverage lands on full_chain. - No scClonotypeChain is emitted, so the existing bulk-without-chain default gives one chain "A". hasFv needs both chains, and the profiler frames variants against one parent with no VH/VL pairing, so Fv columns stay absent. - pipeline.py branches on mode == "peptide" against everything else, so antibody_tcr_universal reaches run_antibody_tcr with no Python change. R13b wording: a declared vdj input arrives with no receptor, and the profiler cannot emit one — germline auto-detect builds its reference from the user's own parents, so there is no library locus to read. The existing notice tells the user to pick a MiXCR preset that emits the annotation, which is a dead end for this data. Added receptorNotDeclared for that case; receptorNotDetected keeps its text for MiXCR input, where the advice is actionable. Per spec R13a the receptor affects labels only, so the antibody default mislabels without changing column identity. detectMode moved out of main.tpl.tengo into modality.lib.tengo so it could be unit-tested — pure synchronous logic, no resources. modality.test.tengo covers all four producers, both declared modalities, an unrecognised modality value, the declaration-beats-run-id ordering, and the undeclared back-compatibility path. Verified by mutation: moving the declaration read below the run-id checks fails exactly the two tests that assert the ordering. The workflow test script is `pl-tengo test`, matching blocks/repertoire-labeling; the dead vitest placeholder (one it.skip) is gone, and the structurer dropped the now-unused vitest config and tsconfig with it. Recorded as SD-010, including why this block keeps the soft partial-region messages where antibody-sequence-liabilities hard-asserts CDR3 presence. Spec: synthetic-repertoire-profiler/dms-modality.md (atom A-0060).
The entry said receptor affects labels only. It does not: hasFv requires receptor == "IG" and so gates whether the Fv columns exist, and the R11c VHH heuristic reads it too. Neither changes column identity, which was the part that was right. Records that a declared vdj profiler run satisfies two of the three VHH conditions by construction, so the heuristic can fire on a designed library whose single chain is an artifact of the producer emitting no chain key — flagged as an open question rather than changed.
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.
Greptile Summary
The PR migrates Sequence Properties to the canonical structurer layout, upgrades its Platforma SDK/build toolchain, and introduces typed initialization parameters for template-based block creation.
inputAnchor.BlockParams) — values supplied when creating a block from a template; introduced withinputAnchor?: PlRef, while table, graph, and label fields remain ordinary view state.addBlock; replaces the legacyblockSpecloader withSequencePropertiesBlockPointer, referencing the packagedblock-pack.BlockContract,BlockData, andBlockOutputs.block-tools; adds thekindpackage, generated facade surfaces, new build targets, and coordinated development/release variants.Confidence Score: 5/5
The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking defects identified.
The structurer migration keeps component paths aligned with generated artifacts, orders workspace dependencies before block packing, and preserves the optional-input idle state while adding template initialization support.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR Template[Project template] -->|BlockParams: optional inputAnchor| Kind[Versioned block kind] Kind --> Model[Data model initialization] Model --> Workflow[Sequence Properties workflow] Workflow --> Software[Python property computation] Model --> UI[Table and graph UI] Kind --> Facade[Published block facade] Model --> Facade Workflow --> Pack[block-pack] Software --> Workflow UI --> Pack Facade -->|SequencePropertiesBlockPointer| Consumer[Platforma consumer] Consumer --> PackReviews (1): Last reviewed commit: "chore: add changeset for the structurer ..." | Re-trigger Greptile
Context used (5)