Skip to content

feat: Platforma API v3#1381

Merged
gramkin merged 25 commits intomainfrom
ivanov/MILAB-2913-api-v3-1
Jan 21, 2026
Merged

feat: Platforma API v3#1381
gramkin merged 25 commits intomainfrom
ivanov/MILAB-2913-api-v3-1

Conversation

@gramkin
Copy link
Copy Markdown
Contributor

@gramkin gramkin commented Jan 14, 2026

No description provided.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 14, 2026

🦋 Changeset detected

Latest commit: 059b7d3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 33 packages
Name Type
@platforma-sdk/block-tools Patch
@milaboratories/milaboratories.pool-explorer.model Minor
@milaboratories/milaboratories.ui-examples Minor
@milaboratories/milaboratories.ui-examples.model Minor
@milaboratories/milaboratories.ui-examples.ui Minor
@milaboratories/pl-middle-layer Minor
@milaboratories/pl-model-middle-layer Minor
@milaboratories/ts-helpers Minor
@milaboratories/pl-model-common Minor
@platforma-sdk/ui-vue Minor
@platforma-sdk/model Minor
@platforma-sdk/test Minor
@milaboratories/milaboratories.monetization-test.model Patch
@milaboratories/milaboratories.monetization-test Patch
@milaboratories/milaboratories.pool-explorer Patch
@milaboratories/milaboratories.pool-explorer.ui Patch
@milaboratories/pf-driver Patch
@milaboratories/ts-helpers-oclif Patch
@milaboratories/ts-helpers-winston Patch
@milaboratories/pl-errors Patch
@milaboratories/computable Patch
@milaboratories/pl-client Patch
@milaboratories/pl-tree Patch
@milaboratories/pl-drivers Patch
@milaboratories/pl-deployments Patch
@milaboratories/pl-config Patch
@platforma-sdk/tengo-builder Patch
@platforma-open/milaboratories.software-ptabler.schema Patch
@milaboratories/milaboratories.monetization-test.ui Patch
@milaboratories/uikit Patch
@milaboratories/pl-model-backend Patch
@platforma-sdk/bootstrap Patch
@milaboratories/ptabler-expression-js Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@notion-workspace
Copy link
Copy Markdown

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @gramkin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a major architectural upgrade to the Platforma API, moving towards a more robust and maintainable block development ecosystem. The introduction of a unified, versioned block state with built-in migration capabilities addresses long-standing challenges in managing block data evolution and ensuring backward compatibility. This change significantly enhances the platform's stability and developer experience by centralizing state management and providing declarative migration paths. Furthermore, the new API streamlines argument derivation and optimizes staging execution, contributing to more efficient block processing.

Highlights

  • Platforma API v3 Introduction: A new version of the Platforma API is introduced, fundamentally changing how block state is managed and interacted with.
  • Unified Block State: Block data is now stored in a single, versioned 'BlockStorage' object, replacing separate 'args' and 'uiState' fields for improved consistency and maintainability.
  • Declarative State Migrations: Blocks can now define explicit migration functions to automatically transform their state from older versions to newer ones, ensuring backward compatibility and smooth upgrades.
  • Optimized Staging Execution: Staging (pre-run) execution is now more efficient, only re-running if derived pre-run arguments have actually changed, preventing unnecessary computations.
  • New Block Development API: A 'BlockModelV3' builder is provided for creating blocks that leverage the new unified state, argument derivation, and migration capabilities.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant update with the new Platforma API v3. The changes are extensive, touching upon the core model, middle layer, and UI components to support a new unified state management system with BlockModelV3, state migrations, and argument derivation from state. The introduction of new test blocks and updates to existing ones to align with this new API is a great addition. My review focuses on ensuring the correctness, security, and maintainability of these new features. I've identified a critical issue related to a self-admitted bug in the migration logic, a few high-severity bugs that could lead to runtime errors, and several medium-severity suggestions to improve code quality and remove temporary workarounds.

Comment thread lib/node/pl-middle-layer/src/mutator/migration.ts Outdated
Comment thread etc/blocks/enter-numbers-v3/ui/index.html Outdated
Comment thread etc/blocks/enter-numbers-v3/ui/src/MainPage.vue Outdated
Comment thread etc/blocks/enter-numbers-v3/model/src/index.ts
Comment thread etc/blocks/enter-numbers-v3/ui/src/MainPage.vue
Comment thread etc/blocks/enter-numbers-v3/ui/src/app.ts
Comment thread etc/blocks/enter-numbers-v3/workflow/src/numbers.lib.tengo
Comment thread lib/node/pl-middle-layer/src/middle_layer/middle_layer.ts
Comment thread sdk/ui-vue/src/defineApp.ts Outdated
Comment thread sdk/ui-vue/src/plugins/Monetization/useInfo.ts Outdated
@gramkin
Copy link
Copy Markdown
Contributor Author

gramkin commented Jan 15, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the Platforma API v3, which is a significant and well-structured refactoring. It moves from separate args and uiState to a unified state model, which simplifies state management and enables features like state migrations. The changes are extensive, touching the core model, middle layer, and UI components, and include new test blocks for the v3 API. I've provided a few suggestions for code simplification and bug fixes. Overall, this is a great improvement.

Comment thread etc/blocks/enter-numbers-v3/ui/src/MainPage.vue
Comment thread etc/blocks/enter-numbers-v3/model/src/index.ts
Comment thread etc/blocks/enter-numbers-v3/ui/src/app.ts
Comment thread etc/blocks/enter-numbers-v3/workflow/src/numbers.lib.tengo Outdated
Comment thread etc/blocks/sum-numbers-v3/model/src/index.ts
Comment thread lib/node/pl-middle-layer/src/mutator/project.test.ts
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 18, 2026

Codecov Report

❌ Patch coverage is 37.58865% with 264 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.82%. Comparing base (22cf31a) to head (059b7d3).
⚠️ Report is 13 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
lib/node/pl-middle-layer/src/mutator/project.ts 45.51% 59 Missing and 20 partials ⚠️
.../pl-middle-layer/src/model/block_storage_helper.ts 0.00% 33 Missing ⚠️
...b/node/pl-middle-layer/src/model/project_helper.ts 43.75% 24 Missing and 3 partials ⚠️
lib/node/pl-middle-layer/src/mutator/migration.ts 3.84% 25 Missing ⚠️
...b/node/pl-middle-layer/src/middle_layer/project.ts 13.63% 18 Missing and 1 partial ⚠️
sdk/model/src/render/api.ts 0.00% 19 Missing ⚠️
...l-middle-layer/src/js_render/computable_context.ts 34.78% 11 Missing and 4 partials ⚠️
sdk/model/src/internal.ts 0.00% 11 Missing ⚠️
...-middle-layer/src/middle_layer/project_overview.ts 33.33% 6 Missing and 4 partials ⚠️
...node/pl-middle-layer/src/middle_layer/block_ctx.ts 68.42% 2 Missing and 4 partials ⚠️
... and 8 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1381      +/-   ##
==========================================
- Coverage   52.98%   52.82%   -0.17%     
==========================================
  Files         236      238       +2     
  Lines       12952    13323     +371     
  Branches     2643     2737      +94     
==========================================
+ Hits         6863     7038     +175     
- Misses       5216     5380     +164     
- Partials      873      905      +32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@AStaroverov AStaroverov self-requested a review January 19, 2026 16:06
@gramkin gramkin requested a review from dbolotin January 20, 2026 16:52

wf.setPreRun(assets.importTemplate(":prerun"))

mapToPValueData := func(map) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not like that we have this as a duplicate in example blocks. we should create a helper for building json pcolumns. I've made a note for myself, will do that in february

export type MigrationFn<From, To> = (prev: Readonly<From>) => To;

/** Versioned data wrapper for persistence */
export type Versioned<T> = {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Composition over inheritance looks better in this case

export type Data<T> = {
  data: T;
};

/** Versioned data wrapper for persistence */
export type Version = {
  version: number;
};

/** Result of upgrade operation, may include warning if migration failed */
export type UpgradeResult<T> = Data<T> & Version & {
  warning?: string;
};
getDefaultData(): Data<State> & Version
...
upgrade(versioned: Data<State> & Version): UpgradeResult<State>
...
tryRegisterCallback('upgrade', (versioned: Data<State> & Version) => this.upgrade(versioned)); // TODO: rename

I tried it in a code, looks pretty good and more readable

Comment on lines +133 to +140
const startIndex = fromVersion - 1;
const migrationsToApply = this.steps.slice(startIndex);

let currentData: unknown = data;
for (let i = 0; i < migrationsToApply.length; i++) {
const stepIndex = startIndex + i;
const fromVer = stepIndex + 1;
const toVer = stepIndex + 2;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    let currentData: unknown = data;
    for (let i = fromVersion - 1; i < this.steps.length; i++) {
      const fromVer = i + 1;
      const toVer = i + 2;

Comment on lines +373 to +381
export type Expect<T extends true> = T;

export type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;

export type Merge<A, B> = {
[K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useful generics, let's move it move suitable place (lib util, something like that)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve wanted this for a long time. Let’s discuss naming for these packages

*/
export function createBlockStorage<TState = unknown>(
initialData: TState = {} as TState,
version: number = 1,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets remove default version. In future it can help use this method correctly

return raw as BlockStorage<TState>;
}
// Legacy format: raw is the state directly
return createBlockStorage(raw as TState, 1);
Copy link
Copy Markdown
Collaborator

@AStaroverov AStaroverov Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const INITIAL_VERSION = 1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About that: I'll create a key-based migration (we discussed it with Vadim) in a separate pr, numbers are really not very comprehensible

Comment thread sdk/model/src/block_storage.ts Outdated
* @param data - The new data value
* @returns A new BlockStorage with updated data
*/
export function updateStorageData<TState>(
Copy link
Copy Markdown
Collaborator

@AStaroverov AStaroverov Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not update, more likely its createUpdatedStorage

* @param version - The new version number
* @returns A new BlockStorage with updated version
*/
export function updateStorageDataVersion<TState>(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, it's not updating, it's creating new entity

Comment thread sdk/model/src/block_storage.ts
Comment on lines +48 to +51
/** Version of the block data, used for migrations */
__dataVersion: number;
/** The block's user-facing data (state) */
__data: TState;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what for we use double underscore in fields naming?

Comment on lines +48 to +51
/** Version of the block data, used for migrations */
__dataVersion: number;
/** The block's user-facing data (state) */
__data: TState;
Copy link
Copy Markdown
Collaborator

@AStaroverov AStaroverov Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly believe that default data storage should be implemented as a plugin.

It generalize common approach and will be good example/first touch for plugins.

Comment on lines +33 to +36
/** The normalized BlockStorage object */
storage: BlockStorage;
/** The extracted data (what developers see) */
data: unknown;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why data field exist? data always equal storage.__data

return `${blockId}-${fieldName}`;
}

export async function awaitBlockDone(prj: Project, blockId: string, timeout: number = 5000) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use existing helper if possible

async awaitBlockDone(blockId, timeout) {
and maybe move some of your helpers in there so others can benefit from them too?


// Normalize storage to get current data and version
const { storage: currentStorage, data: currentData } = normalizeStorage(currentStorageJson);
const currentVersion = currentStorage.__dataVersion;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getStorageDataVersion

...currentStorage,
__dataVersion: version,
__data: data,
});
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's wrap any modification of storage to pub methods(you already have updateStorageDataVersion/updateStorageData)

Comment thread sdk/model/src/block_storage_vm.ts Outdated
};

// Get the upgrade callback (registered by Migrator.registerCallbacks())
const upgradeCallback = ctx.callbackRegistry['upgrade'] as ((v: { version: number; data: unknown }) => UpgradeResult) | undefined;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx.callbackRegistry['upgrade'] - let's we use enum or const for callbacks names, It will make transparent where we are using and registering callbacks

@gramkin gramkin added this pull request to the merge queue Jan 21, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jan 21, 2026
@gramkin gramkin added this pull request to the merge queue Jan 21, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jan 21, 2026
@gramkin gramkin added this pull request to the merge queue Jan 21, 2026
Merged via the queue into main with commit 1694d1a Jan 21, 2026
17 checks passed
@gramkin gramkin deleted the ivanov/MILAB-2913-api-v3-1 branch January 21, 2026 21:09
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.

3 participants