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
12 changes: 8 additions & 4 deletions docs/adr/0004-cloud-multi-kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ Two deployable applications:

### 2. `KernelManager` + `ProjectKernelFactory` (new in `@objectstack/runtime`)

- **`KernelManager`** ([`packages/runtime/src/kernel-manager.ts`](../../packages/runtime/src/kernel-manager.ts)): LRU+TTL cache of `Map<projectId, CachedKernel>`. Exposes `getOrCreate(projectId)` (concurrent-safe, single-flight per id) and `evict(projectId)` (calls `kernel.shutdown()`). Configurable `maxSize` and `ttlMs`.
- **`DefaultProjectKernelFactory`** ([`packages/runtime/src/project-kernel-factory.ts`](../../packages/runtime/src/project-kernel-factory.ts)): given a `projectId`, reads project + credential + package-install rows from the control-plane driver, clones the base stack config, overrides the `default` datasource mapping to point at the project's driver, instantiates an `AppPlugin` per installed bundle, and calls `kernel.bootstrap()`.
> **Path note (2026-08):** the two paths below are historical and deliberately unlinked — neither file is in this repository any more. `kernel-manager.ts` was moved to `packages/runtime/src/cloud/` on 2026-05-18 (`7dcde27c1`, "decouple runtime from service-cloud"), where `project-kernel-factory.ts` was also superseded by `cloud/artifact-kernel-factory.ts`; the whole `packages/runtime/src/cloud/` tree was then removed by #1600 (`feat(runtime)!: remove multi-tenant runtime; keep single-env + contracts`). Multi-kernel runtime code is no longer maintained here.

- **`KernelManager`** (`packages/runtime/src/kernel-manager.ts`): LRU+TTL cache of `Map<projectId, CachedKernel>`. Exposes `getOrCreate(projectId)` (concurrent-safe, single-flight per id) and `evict(projectId)` (calls `kernel.shutdown()`). Configurable `maxSize` and `ttlMs`.
- **`DefaultProjectKernelFactory`** (`packages/runtime/src/project-kernel-factory.ts`): given a `projectId`, reads project + credential + package-install rows from the control-plane driver, clones the base stack config, overrides the `default` datasource mapping to point at the project's driver, instantiates an `AppPlugin` per installed bundle, and calls `kernel.bootstrap()`.

Both are exported from `@objectstack/runtime`. Self-hosted mode never imports `KernelManager`.

Expand All @@ -90,8 +92,10 @@ Custom domains and multi-hostname binding (ACME certificates, `sys_domain` table

### 5. Studio surfaces hostname as a first-class field

- Project list ([`apps/studio/src/routes/projects.index.tsx`](../../apps/studio/src/routes/projects.index.tsx)) renders a globe icon + hostname inline with the project card.
- Project detail ([`apps/studio/src/routes/projects.$projectId.index.tsx`](../../apps/studio/src/routes/projects.$projectId.index.tsx)) adds a **Domains** card with inline edit (Enter to save, Escape to cancel, toast on success/conflict).
> **Path note (2026-08):** the two route paths below are historical and deliberately unlinked — Studio is not in this repository any more. `apps/studio/` was collapsed to a single-package metadata browser on 2026-05-22 (`6bacbced2`) and then migrated to the upstream `@object-ui/studio` package on 2026-05-24 (`06ad57f63`); `apps/` here now holds only `docs/`.

- Project list (`apps/studio/src/routes/projects.index.tsx`) renders a globe icon + hostname inline with the project card.
- Project detail (`apps/studio/src/routes/projects.$projectId.index.tsx`) adds a **Domains** card with inline edit (Enter to save, Escape to cancel, toast on success/conflict).

---

Expand Down
6 changes: 3 additions & 3 deletions docs/adr/0020-state-machine-converge-and-enforce.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ The design intent is a **runtime guardrail**: declare which `status` transitions

**Zero enforcement — verified across `packages/{runtime,objectql,services,core,metadata*,plugins}` and the whole repo:**

- `IWorkflowService` ([`workflow-service.ts:58`](../../packages/spec/src/contracts/workflow-service.ts#L58)) has **no concrete implementation**.
- `IWorkflowService` (`packages/spec/src/contracts/workflow-service.ts:58` — unlinked: the contract file was deleted on 2026-08-01 by #4451 / #4473, which retired the `workflow` service slot outright, closing the follow-up this record left open below) has **no concrete implementation**.
- There is **no XState interpreter** anywhere (no `createMachine` / `interpret` / transition engine).
- The write-path validator [`validateRecord`](../../packages/objectql/src/validation/record-validator.ts#L198) reads only `objectSchema.fields` and validates **field data types** (string/number/date/…). It **never reads `objectSchema.validations`** at all — so *not one* of the nine validation-rule types (`state_machine`, `cross_field`, `script`, `unique`, `format`, `json_schema`, `async`, `custom`, `conditional`) is enforced by it.
- **Nothing reads `object.stateMachines`.**

So the guardrail goal is currently unmet at runtime. The only artefacts that exist are declarations — e.g. [`examples/app-crm/src/workflows/stale-opportunity.workflow.ts:19`](../../examples/app-crm/src/workflows/stale-opportunity.workflow.ts#L19) (`StateMachineConfig`), which additionally **mixes orchestration into the machine** (it carries `email_alert` / `task_creation` actions that no engine executes — that orchestration belongs to a record-triggered Flow per ADR-0019).
So the guardrail goal is currently unmet at runtime. The only artefacts that exist are declarations — e.g. `examples/app-crm/src/workflows/stale-opportunity.workflow.ts:19` (`StateMachineConfig`; unlinked — this file describes the pre-ADR state and was itself removed by this record's own implementation, see the checklist below), which additionally **mixes orchestration into the machine** (it carries `email_alert` / `task_creation` actions that no engine executes — that orchestration belongs to a record-triggered Flow per ADR-0019).

#### The prior-state plumbing gap (the real implementation constraint)

Expand Down Expand Up @@ -135,7 +135,7 @@ The transition declaration stays a flat, recognizable FSM (`field` + `{ from: [t
- [~] `spec`: `IWorkflowService` — **kept as a documented follow-up**, not removed (see Implementation notes).
- [x] `objectql`: wire the `validations` union into the write path — new [`rule-validator.ts`](../../packages/objectql/src/validation/rule-validator.ts) (`evaluateValidationRules` / `needsPriorRecord` / `legalNextStates`), with the prior record plumbed into [`engine.ts`](../../packages/objectql/src/engine.ts) on single-row update. Enforces `state_machine`, `cross_field`, and `script` together.
- [x] `metadata-collection.zod.ts`: dropped the `workflows` collection key + `workflows: 'workflow'` plural mapping ([`metadata-collection.zod.ts`](../../packages/spec/src/shared/metadata-collection.zod.ts)).
- [x] `examples/app-crm`: rewrote `src/workflows/*.workflow.ts` — transition tables already live as the `opp_stage_transitions` `state_machine` rule on the opportunity object; side-effect actions became record-triggered / scheduled Flows ([`high-value-deal.flow.ts`](../../examples/app-crm/src/flows/high-value-deal.flow.ts), [`stale-opportunity.flow.ts`](../../examples/app-crm/src/flows/stale-opportunity.flow.ts)); removed the `workflows` registration from `objectstack.config.ts`.
- [x] `examples/app-crm`: rewrote `src/workflows/*.workflow.ts` — transition tables already live as the `opp_stage_transitions` `state_machine` rule on the opportunity object; side-effect actions became record-triggered / scheduled Flows (`examples/app-crm/src/flows/high-value-deal.flow.ts`, `examples/app-crm/src/flows/stale-opportunity.flow.ts` — unlinked: both flow files were later dropped on 2026-07-05 by `751cf0161`, "refactor(crm): slim back to the loading-pipeline smoke core", which trimmed the CRM example to its loading-pipeline core; the surviving `state_machine` rule is unaffected); removed the `workflows` registration from `objectstack.config.ts`.
- [x] `examples/app-showcase`: carries the surviving shape — `state_machine` rules on `Task`, `Project`, `Account`. Predicate conditions corrected to the `record.<field>` CEL scope form so enforcement actually fires.
- [x] Tests: [`rule-validator.test.ts`](../../packages/objectql/src/validation/rule-validator.test.ts) (16 cases — allow/reject/no-op transitions, execution-control, predicate fail-open, introspection). Updated `object.test.ts`, `metadata-plugin.test.ts`, `metadata-collection.test.ts`, `overlay-precedence.test.ts` for the retired shapes.

Expand Down
54 changes: 7 additions & 47 deletions scripts/check-adr-links.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -139,54 +139,14 @@ const CONVENTION_ILLUSTRATIVE_TARGETS = [
* longer matches a live finding fails as STALE, so a fixed link cannot silently
* regress back under cover of its own grandfather clause.
*
* All 8 are ADR → source-tree links, not ADR → ADR links: the cross-record
* surface this gate was filed for is clean at the time of writing. Their fix
* is not mechanical — `apps/studio/**` moved to the `cloud` repository and the
* runtime/spec files were deleted outright — so it is tracked separately in
* **#6726** rather than guessed at here. Closing that issue empties this list.
* **The list is EMPTY, and that is the finished state.** The 8 ADR → source-tree
* links it was seeded with (#6592) were repaired under #6726: each target had
* genuinely left this repository, so each link became a plain unlinked path plus
* a short note saying where the code went. The ADR → ADR surface this gate was
* filed for was already clean. An empty baseline means the gate is now a gate
* rather than a grandfather clause — do not re-seed it.
*/
const KNOWN_DEAD_TARGETS = [
{
file: `${ADR_DIR}/0004-cloud-multi-kernel.md`,
target: '../../packages/runtime/src/kernel-manager.ts',
why: 'KernelManager was never a file at this path in this repo; cloud multi-kernel code lives in the cloud repo',
},
{
file: `${ADR_DIR}/0004-cloud-multi-kernel.md`,
target: '../../packages/runtime/src/project-kernel-factory.ts',
why: 'same move as kernel-manager.ts',
},
{
file: `${ADR_DIR}/0004-cloud-multi-kernel.md`,
target: '../../apps/studio/src/routes/projects.index.tsx',
why: 'apps/studio/ is not in this repository (apps/ holds only docs/)',
},
{
file: `${ADR_DIR}/0004-cloud-multi-kernel.md`,
target: '../../apps/studio/src/routes/projects.$projectId.index.tsx',
why: 'apps/studio/ is not in this repository (apps/ holds only docs/)',
},
{
file: `${ADR_DIR}/0020-state-machine-converge-and-enforce.md`,
target: '../../packages/spec/src/contracts/workflow-service.ts#L58',
why: 'no workflow-service.ts under packages/spec/src/contracts/ any more',
},
{
file: `${ADR_DIR}/0020-state-machine-converge-and-enforce.md`,
target: '../../examples/app-crm/src/workflows/stale-opportunity.workflow.ts#L19',
why: 'examples/app-crm has no src/workflows/ directory any more',
},
{
file: `${ADR_DIR}/0020-state-machine-converge-and-enforce.md`,
target: '../../examples/app-crm/src/flows/high-value-deal.flow.ts',
why: 'examples/app-crm/src/flows/ no longer carries this flow file',
},
{
file: `${ADR_DIR}/0020-state-machine-converge-and-enforce.md`,
target: '../../examples/app-crm/src/flows/stale-opportunity.flow.ts',
why: 'examples/app-crm/src/flows/ no longer carries this flow file',
},
];
const KNOWN_DEAD_TARGETS = [];

/**
* Blank out fenced code blocks, preserving line count so findings keep their
Expand Down
Loading