Skip to content
Merged
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
62 changes: 62 additions & 0 deletions .changeset/environment-artifact-dual-source-c10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
"@objectstack/spec": major
---

BREAKING(spec): `EnvironmentArtifact` 信封收敛为单一声明 —— `@objectstack/spec/system` 持有活的 wire 形状,`@objectstack/spec/cloud` re-export;从未实现的 v0 家族(`functions` / `manifest` / `payloadRef` 及其 8 个子 schema)退役 (#4740, #4535 C10)

`EnvironmentArtifact` / `EnvironmentArtifactInput` / `EnvironmentArtifactSchema` 过去被两个入口导出,但**不是同一个声明**,拿到哪个形状只取决于 import 路径 —— #4411 陷阱:

| 入口 | 声明位置(旧) | 形状 | 状态 |
|:--|:--|:--|:--|
| `@objectstack/spec/cloud` | `cloud/environment-artifact.zod.ts` | **活的 wire 形**:`checksum` 为 64 位 hex **字符串**,`metadata` = `ObjectStackDefinitionSchema` | **活**:全仓唯一 runtime Zod parse(`packages/metadata/src/plugin.ts` `_parseAndRegisterArtifact`)与 cloud 仓全部 type import 都用这侧 |
| `@objectstack/spec/system` | `system/environment-artifact.zod.ts` | 文档化「v0」:`checksum` 为 `{ algorithm, value }` **对象**、分类袋 `metadata`、内联 `functions[]`、必填 `manifest`、保留位 `payloadRef` | **declared-only**:三仓(objectstack / cloud / objectui)零代码消费者,从未有任何 producer 产出过该形状 |

两侧互相解析不过(checksum 类型硬冲突)。按维护者裁决(#4740,路线 A′):**单一声明落 `./system`、取活的 wire 形状,`./cloud` 改为 re-export 同一声明** —— 两个入口现在解析到同一批符号,对活消费者零迁移。

## FROM → TO

```ts
// 不变 —— cloud 入口的名字与形状都没变,只是声明搬家(re-export)
import { EnvironmentArtifactSchema, type EnvironmentArtifact } from '@objectstack/spec/cloud';

// 不变(形状变了!)—— system 入口同名导出仍在,但现在是活的 wire 形:
// checksum: string(64 hex) 而非 { algorithm, value } 对象
// metadata: ObjectStackDefinition 而非分类袋
import { EnvironmentArtifactSchema, type EnvironmentArtifact } from '@objectstack/spec/system';
```

```ts
// FROM —— 编译期起将以 TS2305 失败(实测三仓零命中,预期无人受影响)
import {
EnvironmentArtifactChecksumSchema, EnvironmentArtifactFunctionSchema,
EnvironmentArtifactManifestSchema, EnvironmentArtifactMetadataSchema,
EnvironmentArtifactPayloadRefSchema, EnvironmentArtifactRequirementSchema,
EnvironmentArtifactHashAlgorithmEnum, EnvironmentArtifactFunctionLanguageEnum,
} from '@objectstack/spec/system';
// TO —— 无替代物:v0 家族从未被任何 producer/consumer 实现。
// 校验 checksum 用 Sha256DigestSchema(现同时从 ./system 与 ./cloud 导出);
// 校验 metadata 用 ObjectStackDefinitionSchema(根入口)。
```

## ⚠️ wire 形状警示(#4666 盲区:key 级门禁不可见的类型变更)

- `EnvironmentArtifact['checksum']`:对 `./system` 侧 import 者是 **`{ algorithm, value }` 对象 → 64 位 hex 字符串** 的类型变更(`./cloud` 侧一直是字符串,不变)。线上 wire 从来只有字符串形;pin 测试钉住「旧对象形 → 拒;hex 字符串 → 过」。
- `EnvironmentArtifact['metadata']`:对 `./system` 侧 import 者从宽松分类袋(passthrough)变为受 `ObjectStackDefinitionSchema` 校验的编译产物。
- 退役键 `functions` / `manifest` / `payloadRef` 走 `retiredKey()` tombstone:作者写入即得升级指引(tsc 处 `never`,parse 处 prescription),不是静默剥离。

## 退役论证(#4734 先例逐条评估,不照抄)

**无 ADR-0087 D2/D3 conversion**:信封是**传输形状**,不是 authorable 元数据 —— 不作为 `sys_metadata` 行落库、不在 conversion walker 走的 stack 树上;且 `objectstack compile` 与控制面从未产出过这三个键(cloud 仓 `cloud-artifact-helpers.ts` 一直写 hex 字符串 checksum;函数代码走独立 runtimeModule,从不内联)。存量行**不可能携带**,conversion 写不出能跑到的 fixture(`converge-activation-event-schema` 同款论证)。tombstone prescription 即迁移文档。

## 定级理由(逐条自证)

定 **major**:`./system` 的 16 个已发布导出名(8 schema const + 8 type)消失,外部 import 将以 TS2305 失败 —— 与 C14 / C16 同形,但**实测三仓 import 级零命中**。同时:

- **零元数据迁移**:被删 9 个 def(`system/EnvironmentArtifact` 全家)均不从 `BUILTIN_METADATA_TYPE_SCHEMAS` 元数据根可达,#4650 门禁对 `authorable-surface.json` 被删 46 行的实跑判定是 7 组「def no longer emitted by this build」自证路径(输出见 PR);无 conversion / migration,`spec-changes.json` / upgrade-guide 零变化。
- **runtime 零行为变化**:`packages/metadata/src/plugin.ts` 的 parse 目标形状就是收敛后的形状,一字未动。
- cloud 仓 3 处 type import(`artifact-api-client.ts` / `file-artifact-api-client.ts` / `registry-reader.ts`,均 `spec/cloud`)名字与形状均不变。
- JSON Schema 产物:`system/EnvironmentArtifact*` 9 个 def 停止发布(`json-schema.manifest.json` 同步删键,#2978 蓄意移除通道);新增 `system/Sha256Digest`(声明随家搬迁,`./cloud` 仍导出)。

## 基线 6 → 3

`dual-source-exports.baseline.json` 删掉 `EnvironmentArtifact` / `EnvironmentArtifactInput` / `EnvironmentArtifactSchema` 三行,其余行一字未动。
12 changes: 6 additions & 6 deletions content/docs/concepts/north-star.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,18 @@ development live outside this repo.
validated against `ObjectStackDefinitionSchema`). When published to Cloud it is
wrapped in the immutable environment artifact envelope defined by
`EnvironmentArtifactSchema` in
`packages/spec/src/system/environment-artifact.zod.ts`.
`packages/spec/src/system/environment-artifact.zod.ts` (the single
declaration; `@objectstack/spec/cloud` re-exports it).

The artifact contains:

- `schemaVersion`
- `environmentId`
- `commitId`
- `checksum`
- `metadata`
- `functions`
- `manifest`
- optional provenance and payload-reference fields
- `checksum` — a SHA-256 hex digest (string) of the canonical `metadata`
serialization
- `metadata` — the compiled `ObjectStackDefinition` itself
- optional `builtAt` / `builtWith` provenance

The artifact is enough to describe what the runtime should load. It is not
enough to deploy by itself; the host still supplies deployment config.
Expand Down
20 changes: 13 additions & 7 deletions content/docs/references/cloud/environment-artifact.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ description: Environment Artifact protocol schemas

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}

# Environment Artifact Envelope (M1)
# Environment Artifact Envelope — re-export (#4740, #4535 C10)

Describes the response shape of `GET /api/v1/cloud/environments/:environmentId/artifact`
The envelope has exactly ONE declaration:

— the assembled artifact ObjectOS pulls from the control plane.
`../system/environment-artifact.zod` (maintainer route A′ on #4740 —

Distinct from the marketplace `PackageArtifactSchema` (a .tgz file listing).
`./system` holds the live wire shape, `./cloud` re-exports it). Importing

This envelope wraps the compiled `ObjectStackDefinitionSchema` produced by
from `@objectstack/spec/cloud` and `@objectstack/spec/system` yields the

`objectstack compile` together with control-plane assigned identity
SAME symbols, so the import path can never change the shape a consumer

(`commitId`, `checksum`).
gets (the #4411 dual-source trap, closed for this name).

Do NOT re-declare the envelope here. A second declaration under this name

is exactly what `check:dual-source-exports` and the symbol-identity pin in

`../system/environment-artifact.test.ts` exist to reject.

<Callout type="info">
**Source:** `packages/spec/src/cloud/environment-artifact.zod.ts`
Expand Down
208 changes: 44 additions & 164 deletions content/docs/references/system/environment-artifact.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,210 +5,90 @@ description: Environment Artifact protocol schemas

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}

# Environment Artifact Format Protocol (v0)
# Environment Artifact Envelope

Defines the immutable envelope produced by `objectstack compile` and consumed
THE single declaration of the environment artifact envelope (#4740,

by the ObjectStack runtime at boot. The artifact carries everything a runtime instance
#4535 C10 — maintainer route A′). `@objectstack/spec/cloud` re-exports

needs to hydrate an environment kernel without reading control-plane DB rows
this file; both entry points resolve to these exact symbols, so the

directly.
chosen entry point can never change the shape a consumer gets (the

## Boundary

- **Artifact (this schema):** environment metadata + inlined function code +

plugin/driver requirements. Immutable, content-addressable via `commitId`

and `checksum`.

- **Deployment Config (NOT in this schema):** business DB coordinates,

credentials, environment identity, secrets. Injected at runtime.
#4411 dual-source trap, closed for this name).

See `content/docs/concepts/north-star.mdx` §6.3 for the runtime-inputs
Describes the response shape of

boundary, and `ROADMAP.md` M1 for the milestone definition.
`GET /api/v1/cloud/environments/:environmentId/artifact` — the assembled

## Storage / Distribution

v0 stores the full payload inline. Future revisions may swap `metadata` /

`functions` for a `payloadRef` that points at out-of-band storage (S3,

signed URL). The envelope shape preserves room for that indirection without

a breaking schema bump.

<Callout type="info">
**Source:** `packages/spec/src/system/environment-artifact.zod.ts`
</Callout>
artifact ObjectOS pulls from the control plane, and the shape the runtime

## TypeScript Usage

```typescript
import { EnvironmentArtifactSchema, EnvironmentArtifactChecksumSchema, EnvironmentArtifactFunctionSchema, EnvironmentArtifactFunctionLanguageEnum, EnvironmentArtifactHashAlgorithmEnum, EnvironmentArtifactManifestSchema, EnvironmentArtifactMetadataSchema, EnvironmentArtifactPayloadRefSchema, EnvironmentArtifactRequirementSchema } from '@objectstack/spec/system';
import type { EnvironmentArtifact, EnvironmentArtifactChecksum, EnvironmentArtifactFunction, EnvironmentArtifactManifest, EnvironmentArtifactMetadata, EnvironmentArtifactPayloadRef, EnvironmentArtifactRequirement } from '@objectstack/spec/system';

// Validate data
const result = EnvironmentArtifactSchema.parse(data);
```

---

## EnvironmentArtifact

ObjectStack Environment Artifact envelope (v0)

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **schemaVersion** | `'0.1'` | ✅ | Environment artifact envelope schema version |
| **environmentId** | `string` | ✅ | Environment identifier (control-plane scoped) |
| **commitId** | `string` | ✅ | Content-addressable revision id |
| **checksum** | `{ algorithm: Enum<'sha256' \| 'sha384' \| 'sha512'>; value: string }` | ✅ | Artifact integrity checksum |
| **builtAt** | `string` | optional | ISO-8601 timestamp of when the artifact was built |
| **builtWith** | `string` | optional | Build tool identifier |
| **metadata** | `Record<string, any>` | ✅ | Compiled environment metadata grouped by category |
| **functions** | `{ name: string; language: Enum<'javascript' \| 'typescript'>; code: string; source?: object; … }[]` | ✅ | Inlined function code packaged with the artifact |
| **manifest** | `{ plugins?: { id: string; version?: string }[]; drivers?: { id: string; version?: string }[]; engine?: object }` | ✅ | Plugin/driver requirements baked into the artifact |
| **payloadRef** | `{ url: string; expiresAt?: string; checksum: object }` | optional | Out-of-band payload reference (reserved for future use) |


---
metadata loader parses at boot (`packages/metadata/src/plugin.ts`,

## EnvironmentArtifactChecksum
`_parseAndRegisterArtifact` — the one runtime Zod parse of this envelope).

Artifact integrity checksum
Distinct from the marketplace `PackageArtifactSchema` (a .tgz file

### Properties
listing). This envelope wraps the compiled `ObjectStackDefinitionSchema`

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **algorithm** | `Enum<'sha256' \| 'sha384' \| 'sha512'>` | ✅ | Hash algorithm used for the artifact checksum |
| **value** | `string` | ✅ | Hex-encoded digest of the artifact body |
produced by `objectstack compile` together with control-plane assigned

identity (`commitId`, `checksum`).

---

## EnvironmentArtifactFunction

A single inlined function

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **name** | `string` | ✅ | Function machine name (snake_case) |
| **language** | `Enum<'javascript' \| 'typescript'>` | ✅ | Source language of the function code |
| **code** | `string` | ✅ | Inlined function source |
| **source** | `{ path?: string; exportName?: string }` | optional | Source-map metadata for the function |
| **hash** | `string` | optional | Hex SHA-256 of the inlined code |


---

## EnvironmentArtifactFunctionLanguageEnum

Source language of the function code

### Allowed Values

* `javascript`
* `typescript`
## Boundary

- **Artifact (this schema):** compiled environment metadata plus

---
provenance. Immutable, content-addressable via `commitId` and

## EnvironmentArtifactHashAlgorithmEnum
`checksum`.

Hash algorithm used for the artifact checksum
- **Deployment Config (NOT in this schema):** business DB coordinates,

### Allowed Values
credentials, environment identity, secrets. Injected at runtime.

* `sha256`
* `sha384`
* `sha512`
See `content/docs/concepts/north-star.mdx` §6.3 for the

runtime-inputs boundary.

---
## History (#4740)

## EnvironmentArtifactManifest
This file previously documented a richer "v0" envelope — a

Plugin/driver requirements baked into the artifact
`\{ algorithm, value \}` checksum object, a category-bag `metadata`, inlined

### Properties
`functions[]`, a required plugin/driver `manifest`, and a reserved

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **plugins** | `{ id: string; version?: string }[]` | optional | |
| **drivers** | `{ id: string; version?: string }[]` | optional | |
| **engine** | `{ objectstack: string }` | optional | |
`payloadRef` indirection — that NO producer or consumer ever implemented:

`objectstack compile` ships function code as standalone runtime modules

---
referenced from the compiled definition, and the control plane has always

## EnvironmentArtifactMetadata

Compiled environment metadata grouped by category

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **objects** | `any[]` | optional | |
| **fields** | `any[]` | optional | |
| **views** | `any[]` | optional | |
| **apps** | `any[]` | optional | |
| **pages** | `any[]` | optional | |
| **dashboards** | `any[]` | optional | |
| **reports** | `any[]` | optional | |
| **flows** | `any[]` | optional | |
| **workflows** | `any[]` | optional | |
| **triggers** | `any[]` | optional | |
| **agents** | `any[]` | optional | |
| **tools** | `any[]` | optional | |
| **skills** | `any[]` | optional | |
| **permissions** | `any[]` | optional | |
| **permissionSets** | `any[]` | optional | |
| **positions** | `any[]` | optional | |
| **translations** | `any[]` | optional | |
| **datasources** | `any[]` | optional | |
| **datasets** | `any[]` | optional | |
| **actions** | `any[]` | optional | |
| **apis** | `any[]` | optional | |
served the wire shape below (string SHA-256 checksum, `metadata` = the

compiled definition). The declaration converged to the live wire shape;

---
the never-implemented keys are tombstoned below (ADR-0049

## EnvironmentArtifactPayloadRef
enforce-or-remove: declared = enforced, or absent).

Out-of-band payload reference (reserved for future use)
<Callout type="info">
**Source:** `packages/spec/src/system/environment-artifact.zod.ts`
</Callout>

### Properties
## TypeScript Usage

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **url** | `string` | ✅ | Signed URL pointing at the artifact payload |
| **expiresAt** | `string` | optional | ISO-8601 expiry timestamp |
| **checksum** | `{ algorithm: Enum<'sha256' \| 'sha384' \| 'sha512'>; value: string }` | ✅ | Checksum of the referenced payload |
```typescript
import { Sha256DigestSchema } from '@objectstack/spec/system';
import type { Sha256Digest } from '@objectstack/spec/system';

// Validate data
const result = Sha256DigestSchema.parse(data);
```

---

## EnvironmentArtifactRequirement

A plugin or driver dependency declaration

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **id** | `string` | ✅ | Plugin/driver package id |
| **version** | `string` | optional | SemVer range required by the environment |


---

Loading
Loading