Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/block-model-v3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@platforma-open/milaboratories.gpu-test": minor
"@platforma-open/milaboratories.gpu-test.model": minor
"@platforma-open/milaboratories.gpu-test.ui": minor
"@platforma-open/milaboratories.gpu-test.kind": minor
---

Migrate block to BlockModelV3 with a block kind. Settings (cpu, mem, gpuMemory, seed, matrixSize) move into block data; existing projects keep them via the legacy upgrader. The kind takes no init params. UI bindings move to `app.model.data`.
9 changes: 8 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"fixed": [
[
"@platforma-open/milaboratories.gpu-test",
"@platforma-open/milaboratories.gpu-test.model",
"@platforma-open/milaboratories.gpu-test.ui",
"@platforma-open/milaboratories.gpu-test.workflow"
]
],
"linked": [],
"access": "restricted",
"baseBranch": "main",
Expand Down
6 changes: 6 additions & 0 deletions .changeset/gpu-cpu-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@platforma-open/milaboratories.gpu-test.workflow": minor
"@platforma-open/milaboratories.gpu-test": minor
---

GPU -> CPU fallback: when no GPU comes in time (GPUMissed), the detection runs again on CPU.
5 changes: 5 additions & 0 deletions .changeset/gpu-info-block-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@platforma-open/milaboratories.gpu-test.gpu-info": patch
---

Build the software package with block-tools after the SDK upgrade.
22 changes: 19 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
workflow_dispatch: {}
jobs:
init:
runs-on: ubuntu-latest
runs-on: hz-ubuntu-dind
steps:
- uses: milaboratory/github-ci/actions/context/init@v4
with:
Expand All @@ -24,8 +24,10 @@ jobs:
with:
app-name: 'Block: Gpu Test'
app-name-slug: 'block-gpu-test'
node-version: '20.x'
build-script-name: 'build'
node-version: '24.22.1'
gha-runner-label: hz-ubuntu-dind
build-script-name: 'build:dev-local'
build-before-publish-script-name: 'build:release'
pnpm-recursive-build: false

test: true
Expand All @@ -37,6 +39,11 @@ jobs:
package-path: 'block'
create-tag: 'true'

# Require the published `block` package to be bumped by a changeset on
# PRs (empty changeset or the `skip-changelog` label waives it). Needs
# the input to exist on the pinned `@v4` reusable workflow.
require-package-path-bump: true

npmrc-config: |
{
"registries": {
Expand All @@ -56,6 +63,15 @@ jobs:

"AWS_CI_IAM_MONOREPO_SIMPLE_ROLE": ${{ toJSON(secrets.AWS_CI_IAM_MONOREPO_SIMPLE_ROLE) }},
"AWS_CI_TURBOREPO_S3_BUCKET": ${{ toJSON(secrets.AWS_CI_TURBOREPO_S3_BUCKET) }},

"HZ_CI_TURBO_S3_BUCKET": ${{ toJSON(vars.HZ_CI_TURBO_S3_BUCKET) }},
"HZ_CI_TURBO_S3_ENDPOINT": ${{ toJSON(vars.HZ_CI_TURBO_S3_ENDPOINT) }},
"HZ_CI_TURBO_S3_REGION": ${{ toJSON(vars.HZ_CI_TURBO_S3_REGION) }},
"HZ_CI_TURBO_S3_ACCESS_KEY": ${{ toJSON(secrets.HZ_CI_TURBO_S3_ACCESS_KEY) }},
"HZ_CI_TURBO_S3_SECRET_KEY": ${{ toJSON(secrets.HZ_CI_TURBO_S3_SECRET_KEY) }},
"HZ_CI_CACHE_S3_ACCESS_KEY": ${{ toJSON(secrets.HZ_CI_CACHE_S3_ACCESS_KEY) }},
"HZ_CI_CACHE_S3_SECRET_KEY": ${{ toJSON(secrets.HZ_CI_CACHE_S3_SECRET_KEY) }},

"PL_REGISTRY_PLATFORMA_OPEN_UPLOAD_URL": ${{ toJSON(secrets.PL_REGISTRY_PLOPEN_UPLOAD_URL) }},
"QUAY_USERNAME": ${{ toJSON(secrets.QUAY_USERNAME) }},
"QUAY_ROBOT_TOKEN": ${{ toJSON(secrets.QUAY_ROBOT_TOKEN) }} }
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/mark-stable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: milaboratory/github-ci/.github/workflows/block-mark-stable.yaml@v4
with:
app-name: 'Block: Gpu Test - Mark Stable'
node-version: '20.x'
node-version: '24.22.1'
npmrc-config: |
{
"registries": {
Expand Down
2 changes: 1 addition & 1 deletion .structure
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":1}
{"version":3}
3 changes: 2 additions & 1 deletion block/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
"scripts": {
"build": "ts-builder build --target block-facade && block-tools pack",
"prepublishOnly": "block-tools publish -r s3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1 --registry-serve-url https://blocks.pl-open.science",
"do-pack": "pnpm pack && shx mv *.tgz package.tgz",
"do-pack": "shx rm -f package.tgz && pnpm pack && shx mv *.tgz package.tgz",
"check": "ts-builder type-check --target block-facade"
},
"dependencies": {},
"devDependencies": {
"@milaboratories/ts-builder": "catalog:",
"@milaboratories/ts-configs": "catalog:",
"@platforma-open/milaboratories.gpu-test.kind": "workspace:*",
"@platforma-open/milaboratories.gpu-test.model": "workspace:*",
"@platforma-open/milaboratories.gpu-test.ui": "workspace:*",
"@platforma-open/milaboratories.gpu-test.workflow": "workspace:*",
Expand Down
4 changes: 4 additions & 0 deletions kind/.oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["node_modules/@milaboratories/ts-builder/configs/oxfmt.json"],
"ignorePatterns": ["dist", "coverage", "CHANGELOG.md"]
}
3 changes: 3 additions & 0 deletions kind/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["node_modules/@milaboratories/ts-builder/dist/configs/oxlint-node.json"]
}
36 changes: 36 additions & 0 deletions kind/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@platforma-open/milaboratories.gpu-test.kind",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"sources": "./src/index.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"scripts": {
"fmt": "ts-builder format",
"watch": "ts-builder build --target block-kind --watch",
"build": "ts-builder build --target block-kind && block-tools build-kind-manifest",
"check": "ts-builder check --target block-kind"
},
"dependencies": {
"@platforma-sdk/block-kind": "catalog:"
},
"devDependencies": {
"@milaboratories/ts-builder": "catalog:",
"@milaboratories/ts-configs": "catalog:",
"@platforma-sdk/block-tools": "catalog:"
},
"peerDependencies": {
"@types/node": "*",
"typescript": "*"
}
}
51 changes: 51 additions & 0 deletions kind/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { assertParamsObject, defineBlockKind } from "@platforma-sdk/block-kind";
import { name, version } from "../package.json" with { type: "json" };

/**
* This block's init-params contract — the shape a block of this kind receives
* at creation, and exactly what a project template serializes for it.
*
* TODO(block-kind): replace `NEEDS_BLOCK_PARAMS` with the real params shape, then
* wire the model's `init(({ params }) => …)` to consume them. If this block takes
* no author-supplied params, set it to `Record<string, never>` deliberately.
*
* This is an intentional sentinel: `NEEDS_BLOCK_PARAMS` is an undefined type, so
* the block fails to typecheck (TS2304) until the contract is chosen on purpose.
* A scaffolded-but-unmigrated block must never compile with an empty contract by
* default — see the block-kind migration recipe in the `block-dev` skill.
*/
// gpu-test takes no author-supplied params at creation: its settings are block args edited in
// the UI, so the contract is deliberately empty.
export type BlockParams = Record<string, never>;

/**
* The same contract at runtime, for params that arrive from a template file rather than
* from typed code — the only point that can catch a hand-written entry being wrong.
*
* TODO(block-kind): read each key `BlockParams` declares and say what it must be, then
* return them. Plain TypeScript is the default here: a kind owes no schema library, and a
* check written by hand is held to the contract by the return type. Reach for a validation
* library only where the shape earns it, and add it to this package's dependencies yourself.
*
* Check the fields the contract requires, and stop there. A key the contract does not name
* needs no rejection: it is dropped by not being read.
*
* This is a second intentional sentinel. The function has to return `BlockParams`, so
* `return {}` stops compiling the moment the contract declares a required field — the check
* cannot drift from the contract by being left behind. Never satisfy it with a cast: `value
* as BlockParams` compiles today and checks nothing forever.
*/
function parseInitializationParams(value: unknown): BlockParams {
assertParamsObject(value);

return {};
}

// Identity (`name`/`version`) comes from this package's own `package.json`, so
// the on-wire `{name}@{version}` reference can never drift from what npm
// publishes; the bundler inlines the JSON import.
export const kind = defineBlockKind<BlockParams>({
name,
version,
parseInitializationParams,
});
10 changes: 10 additions & 0 deletions kind/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "@milaboratories/ts-configs/block/facade",
"compilerOptions": {
"outDir": "./dist",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["src/**/*", "package.json"],
"exclude": ["dist", "node_modules"]
}
1 change: 1 addition & 0 deletions model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"check": "ts-builder check --target block-model"
},
"dependencies": {
"@platforma-open/milaboratories.gpu-test.kind": "workspace:*",
"@platforma-sdk/model": "catalog:"
},
"devDependencies": {
Expand Down
30 changes: 30 additions & 0 deletions model/src/dataModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { kind } from "@platforma-open/milaboratories.gpu-test.kind";
import { DataModelBuilder } from "@platforma-sdk/model";
import type { BlockData, LegacyBlockArgs, LegacyBlockUiState } from "./types";

const randomSeed = (): number => Math.floor(Math.random() * 2147483647);

const defaults = (): BlockData => ({
seed: randomSeed(),
matrixSize: "4000",
gpuMemory: "1GiB",
cpu: "1",
mem: "1GiB",
});

export const blockDataModel = new DataModelBuilder({ kind })
.from<BlockData>("V20261030")
// Projects saved under the V1 model keep their settings: the V1 args map 1:1 onto
// BlockData; the V1 UI state was empty. Missing fields fall back to the defaults.
.upgradeLegacy<Partial<LegacyBlockArgs> | undefined, LegacyBlockUiState>(({ args }) => {
const d = defaults();
return {
seed: args?.seed ?? d.seed,
matrixSize: args?.matrixSize ?? d.matrixSize,
gpuMemory: args?.gpuMemory ?? d.gpuMemory,
cpu: args?.cpu ?? d.cpu,
mem: args?.mem ?? d.mem,
};
})
// The kind's init-params contract is empty, so a new block always starts from defaults.
.init(() => defaults());
38 changes: 17 additions & 21 deletions model/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
import { BlockModel } from "@platforma-sdk/model";
import { kind } from "@platforma-open/milaboratories.gpu-test.kind";
import { BlockModelV3 } from "@platforma-sdk/model";
import { blockDataModel } from "./dataModel";
import type { BlockArgs } from "./types";

export type BlockArgs = {
seed: number;
matrixSize: string;
gpuMemory: string;
cpu: string;
mem: string;
};
export type { BlockArgs, BlockData } from "./types";

// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- UI state will be added in Step 8
export type UiState = {};
export const platforma = BlockModelV3.create({ dataModel: blockDataModel, kind })
// Empty init-params contract (see the kind): nothing crosses the template boundary.
.templateParams(() => ({}))

export const platforma = BlockModel.create()
.withArgs<BlockArgs>({
seed: Math.floor(Math.random() * 2147483647),
matrixSize: "4000",
gpuMemory: "1GiB",
cpu: "1",
mem: "1GiB",
})
.withUiState<UiState>({})
.argsValid(() => true)
// All settings are user-committed run parameters; the workflow consumes them unchanged.
.args<BlockArgs>((data) => ({
seed: data.seed,
matrixSize: data.matrixSize,
gpuMemory: data.gpuMemory,
cpu: data.cpu,
mem: data.mem,
}))

.output("gpuLog", (ctx) => ctx.outputs?.resolve("gpuLog")?.getLogHandle())
.output("gpuInfo", (ctx) => ctx.outputs?.resolve("gpuInfo")?.getDataAsJson<GpuReport>())
Expand All @@ -29,7 +25,7 @@ export const platforma = BlockModel.create()

.title(() => "GPU Detection")
.sections(() => [{ type: "link" as const, href: "/" as const, label: "GPU Info" }])
.done(2);
.done();

export interface GpuReport {
seed: number;
Expand Down
26 changes: 26 additions & 0 deletions model/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Persisted block state. Every field is a user-committed run setting and goes to the
* workflow as-is, so `BlockData` and the workflow args share one shape.
*/
export type BlockData = {
seed: number;
matrixSize: string;
gpuMemory: string;
cpu: string;
mem: string;
};

/** Workflow args — what `workflow/src/main.tpl.tengo` reads. */
export type BlockArgs = {
seed: number;
matrixSize: string;
gpuMemory: string;
cpu: string;
mem: string;
};

/** V1 (`BlockModel`) args as persisted by projects created before the V3 migration. */
export type LegacyBlockArgs = BlockArgs;

/** V1 UI state: always empty. */
export type LegacyBlockUiState = Record<string, never>;
23 changes: 16 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
{
"scripts": {
"build": "turbo run build",
"build:dev": "env PL_PKG_DEV=local turbo run build",
"build:dev-remote": "env PL_PKG_DEV=local PL_DOCKER_BUILD=1 PL_DOCKER_AUTOPUSH=1 turbo run build",
"build:dev-remote": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=all PL_BUILD_LOCATION=remote turbo run build",
"lint": "turbo run lint",
"type-check": "turbo run type-check",
"test": "env PL_PKG_DEV=local turbo run test --concurrency 1",
"test": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=binary PL_BUILD_LOCATION=local turbo run test --concurrency 1",
"do-pack": "turbo run do-pack",
"watch": "turbo watch build",
"changeset": "changeset",
"version-packages": "changeset version",
"update-sdk": "block-tools structure refresh --update-deps-only",
"fmt": "turbo run fmt",
"check": "turbo run check",
"test:dry-run": "env PL_PKG_DEV=local turbo run test --dry-run=json",
"test:dry-run": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=binary PL_BUILD_LOCATION=local turbo run test --dry-run=json",
"mark-stable": "turbo run mark-stable",
"upgrade-sdk": "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt"
"upgrade-sdk": "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt",
"build:dev-local": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=all PL_BUILD_LOCATION=local turbo run build",
"build:dev-no-software": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=none turbo run build",
"build:dev-binary-existing": "env PL_BUILD_CHANNEL=dev PL_BUILD_USE_PUBLISHED=true turbo run build",
"build:release": "env PL_BUILD_CHANNEL=release PL_BUILD_VARIANT=all PL_BUILD_LOCATION=remote turbo run build"
},
"devDependencies": {
"@changesets/cli": "catalog:",
Expand All @@ -29,5 +31,12 @@
"oxfmt": "*",
"oxlint": "*"
},
"packageManager": "pnpm@9.12.0"
"devEngines": {
"runtime": {
"name": "node",
"version": "24.22.1",
"onFail": "download"
}
},
"packageManager": "pnpm@12.16.1+sha512.091d1dee7927575661b25dab3c2ae31cafc1c54d6b71ed6a6600cf0c1cb10434a447eae14015f1b23e2e6bedeed79df94a932e2164d2832280dce3fb32f656d1"
}
Loading
Loading