Skip to content

Commit 9c1c5ef

Browse files
committed
docs: sync protocol / releases / ui docs with implementation (#1880 Wave 1, batch 6)
30 docs audited AND adversarially verified (protocol, releases, ui); 28 carry fixes — 103 fixes total, 8 of them verifier repairs (the adversarial pass caught and corrected wrong audit edits, e.g. a bad `permissionSet:` stack key → `permissions:`, and a fabricated projection "id/audit columns" claim). Highlights: - protocol/kernel/*: removed the fabricated `definePlugin()` / `defineObject()` helpers (use ObjectSchema.create) and corrected `defineView` imports to `@objectstack/spec/ui`; aspirational manifest/lifecycle blocks left in place where the page already discloses them as design-intent. - protocol/knowledge: driver-turso / knowledge-turso are cloud-only (not open-core) → replaced with open-core-appropriate driver-mongodb / llamaindex. - releases/v13,v15 + objectql/* + ui/*: import-path, key-name, and example fixes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012urEihGTAsQP2xizAqfCwt
1 parent db7b6f8 commit 9c1c5ef

28 files changed

Lines changed: 343 additions & 353 deletions

content/docs/protocol/kernel/i18n-standard.mdx

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ i18n.t('messages.welcome', 'en', { name: 'John' }); // Translation + interpolati
6969

7070
ObjectStack automatically determines the user's locale using a **fallback chain**:
7171

72+
<Callout type="warn">
73+
**Partial implementation.** The server resolves the *request* locale from the
74+
`Accept-Language` header (highest-priority entry), then a `?locale=` query
75+
parameter, then the i18n service's default locale — see `extractLocale` in
76+
`packages/rest/src/rest-server.ts`. The DB-persisted **user preference**,
77+
**tenant default**, and **IP geolocation** steps shown below are design intent:
78+
there is no geolocation or tenant-locale resolution in the runtime today.
79+
</Callout>
80+
7281
```
7382
┌─────────────────────────────────────────────────────────────┐
7483
│ 1. USER PREFERENCE │
@@ -618,7 +627,10 @@ export const Account = ObjectSchema.create({
618627

619628
industry: Field.select({
620629
label: 'account.fields.industry',
621-
options: 'account.industries', // Translation key for options array
630+
options: [
631+
{ value: 'technology', label: 'account.industries.technology' },
632+
{ value: 'finance', label: 'account.industries.finance' },
633+
],
622634
}),
623635
},
624636
});
@@ -633,10 +645,10 @@ export const Account = ObjectSchema.create({
633645
"name": "Account Name",
634646
"industry": "Industry"
635647
},
636-
"industries": [
637-
{ "value": "technology", "label": "Technology" },
638-
{ "value": "finance", "label": "Finance" }
639-
]
648+
"industries": {
649+
"technology": "Technology",
650+
"finance": "Finance"
651+
}
640652
}
641653
```
642654

@@ -651,25 +663,16 @@ locale.
651663
ObjectUI automatically translates labels, placeholders, and error messages:
652664

653665
```typescript
654-
// View definition
666+
// View definition — `defineView` takes a container of named views
667+
// ({ list, form, listViews, formViews }); a flat { name, type, ... }
668+
// object is rejected at build time.
655669
export default defineView({
656-
name: 'account_list',
657-
object: 'account',
658-
type: 'list',
659-
660-
layout: {
661-
title: 'account.list.title', // Translation key
670+
list: {
671+
type: 'grid',
672+
label: 'account.list.title', // Translation key (i18n label)
673+
data: { provider: 'object', object: 'account' },
662674
columns: [
663-
{
664-
field: 'name',
665-
// Label auto-translated from ObjectQL field definition
666-
},
667-
],
668-
actions: [
669-
{
670-
type: 'create',
671-
label: 'account.actions.create', // Translation key
672-
},
675+
'name', // Column label auto-translated from the ObjectQL field definition
673676
],
674677
},
675678
});
@@ -764,6 +767,13 @@ Output:
764767

765768
### Translation Service Integration
766769

770+
<Callout type="warn">
771+
**Design intent — not yet implemented.** `i18n.translationService` is **not** a
772+
recognized key on `TranslationConfigSchema`
773+
(`packages/spec/src/system/translation.zod.ts`), and no auto-translate provider
774+
integration ships today. The snippet below describes planned behaviour.
775+
</Callout>
776+
767777
ObjectStack integrates with professional translation services:
768778

769779
```typescript

content/docs/protocol/kernel/index.mdx

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ os package publish dist/objectstack.json --env <environment-id> --install
151151
152152
**Kernel Approach:**
153153
```yaml
154-
# plugin.manifest.yml
155-
name: @mycompany/billing
154+
# manifest block in objectstack.config.ts (via defineStack)
155+
id: com.mycompany.billing
156156
version: 2.0.0
157157
dependencies:
158158
'@objectstack/core': '^2.0.0'
@@ -212,7 +212,7 @@ const config = context.config.resolve('stripe.apiKey', {
212212
**Challenge:** Build a plugin marketplace like Salesforce AppExchange where third-party developers sell integrations.
213213

214214
**Kernel Solution:**
215-
- **Plugin Manifest:** Standardized `plugin.manifest.yml` declares what plugin provides and needs
215+
- **Package Manifest:** The `manifest` block in `objectstack.config.ts` (compiled to `objectstack.json`) declares what a package provides and needs
216216
- **Dependency Resolution:** Automatic validation that plugin versions are compatible with core platform
217217
- **Lifecycle Hooks:** `onInstall`, `onEnable`, `onDisable` hooks for setup/teardown
218218
- **Sandboxing:** Plugins can't access each other's data or crash each other
@@ -277,7 +277,7 @@ hooks in order, and exposes the resulting services through DI.
277277
278278
### 2. Request Handling
279279
```typescript
280-
// Incoming API request: GET /api/accounts/123
280+
// Incoming API request: GET /api/v1/data/account/123
281281
async function handleRequest(req) {
282282
// Kernel provides context
283283
const context = await Kernel.createContext({
@@ -354,17 +354,19 @@ permissions.grant('admin', 'accounts', 'read');
354354
355355
**Good (Declarative):**
356356
```yaml
357-
# plugin.manifest.yml
357+
# objectstack.config.ts — declared via defineStack({ ... })
358358
objects:
359359
- name: account
360360
fields:
361361
- name: name
362362
type: text
363+
# PermissionSet grants use allow* flags (not role/object/access)
363364
permissions:
364-
- role: admin
365-
object: account
366-
access: read
367-
# Kernel ensures runtime matches manifest
365+
- name: account_read
366+
objects:
367+
account:
368+
allowRead: true
369+
# Kernel ensures runtime matches the declared metadata
368370
```
369371
370372
### Idempotent Operations
@@ -375,8 +377,8 @@ Run `os package publish` 100 times → Same result.
375377
376378
### Version Control Everything
377379
All system configuration lives in Git:
378-
- Plugin manifests: `plugin.manifest.yml`
379-
- Configuration files: `objectstack.config.yml`
380+
- Stack definition & manifest: `objectstack.config.ts` (via `defineStack`)
381+
- Compiled artifact: `dist/objectstack.json`
380382
- Translation bundles: `i18n/en.json`, `i18n/de.json`
381383
382384
**Business Value:** Rollback a bad deployment by reverting Git commit. No database state to recover, no manual cleanup.
@@ -385,18 +387,15 @@ All system configuration lives in Git:
385387
386388
### Plugin Development
387389
```bash
388-
# Scaffold new plugin
390+
# Scaffold new plugin (created under packages/plugins/plugin-<name>/)
389391
os create plugin slack-integration
390392
391393
# Generated structure:
392-
slack-integration/
393-
plugin.manifest.yml # Metadata, dependencies, version
394+
packages/plugins/plugin-slack-integration/
395+
package.json # name, version, dependencies (@objectstack/spec, zod)
396+
tsconfig.json
394397
src/
395-
objects/ # ObjectQL schemas
396-
views/ # ObjectUI layouts
397-
actions/ # Business logic
398-
i18n/ # Translations
399-
tests/
398+
index.ts # default-export Plugin object (name, version, initialize, destroy)
400399
README.md
401400
```
402401

content/docs/protocol/kernel/lifecycle.mdx

Lines changed: 63 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ await kernel.bootstrap();
153153
```
154154

155155
**Resolution Strategy:**
156-
1. **failOnPluginError: true** (default): Boot fails, process exits with code 1
157-
2. **failOnPluginError: false**: Boot continues, failed plugin is disabled and logged
156+
1. **rollbackOnFailure: true** (default): Boot fails, already-started plugins roll back, process exits with code 1
157+
2. **rollbackOnFailure: false**: Boot continues, the failed plugin is skipped and logged
158158

159159
## Plugin Installation
160160

@@ -275,61 +275,45 @@ async function resolveDependencies(
275275
Plugins can define hooks that run at specific lifecycle events:
276276

277277
```typescript
278-
// plugin.manifest.ts
279-
export default definePlugin({
278+
// plugin.ts — a plugin is a plain default-exported object (there is no
279+
// `definePlugin` helper). Lifecycle hooks are top-level methods, each
280+
// receiving a single PluginContext ({ ql, os, logger, config, pluginId }).
281+
export default {
280282
name: '@vendor/salesforce',
281283
version: '3.2.1',
282-
283-
lifecycle: {
284-
// Runs before installation begins
285-
preInstall: async ({ context, transaction }) => {
286-
// Validate environment
287-
if (!context.config.get('salesforce.apiKey')) {
288-
throw new Error('Salesforce API key not configured');
289-
}
290-
},
291-
292-
// Runs after installation completes
293-
postInstall: async ({ context, transaction }) => {
294-
// Initialize default data
295-
await context.db.insert('salesforce_settings', {
296-
syncInterval: 3600, // 1 hour
297-
enabled: true,
298-
}, { transaction });
299-
300-
// Schedule sync job
301-
await context.scheduler.create({
302-
name: 'salesforce-sync',
303-
schedule: '0 * * * *', // Every hour
304-
handler: 'salesforce.sync',
305-
}, { transaction });
306-
},
307-
308-
// Runs when plugin is enabled
309-
onEnable: async ({ context }) => {
310-
logger.info('Salesforce sync enabled');
311-
await context.eventBus.publish('salesforce.enabled');
312-
},
313-
314-
// Runs when plugin is disabled
315-
onDisable: async ({ context }) => {
316-
logger.info('Salesforce sync disabled');
317-
await context.scheduler.pause('salesforce-sync');
318-
},
319-
320-
// Runs before uninstallation
321-
preUninstall: async ({ context, transaction }) => {
322-
// Clean up jobs
323-
await context.scheduler.delete('salesforce-sync', { transaction });
324-
},
325-
326-
// Runs after uninstallation
327-
postUninstall: async ({ context, transaction }) => {
328-
// Optional: Remove plugin data
329-
await context.db.delete('salesforce_settings', {}, { transaction });
330-
},
284+
285+
// Runs once, when the plugin is installed
286+
onInstall: async (context) => {
287+
// Validate environment. `config` is a plain record, not a store.
288+
if (!context.config['salesforce.apiKey']) {
289+
throw new Error('Salesforce API key not configured');
290+
}
291+
context.logger.info('Salesforce plugin installed');
331292
},
332-
});
293+
294+
// Runs when the plugin is enabled (at startup or manually)
295+
onEnable: async (context) => {
296+
context.logger.info('Salesforce sync enabled');
297+
},
298+
299+
// Runs when the plugin is disabled (at shutdown or manually)
300+
onDisable: async (context) => {
301+
context.logger.info('Salesforce sync disabled');
302+
},
303+
304+
// Runs once, when the plugin is uninstalled
305+
onUninstall: async (context) => {
306+
context.logger.info('Removing Salesforce plugin data');
307+
},
308+
309+
// Runs when the plugin version changes. Receives an UpgradeContext with
310+
// previousVersion, newVersion, and isMajorUpgrade.
311+
onUpgrade: async (context) => {
312+
context.logger.info(
313+
`Salesforce ${context.previousVersion} → ${context.newVersion}`,
314+
);
315+
},
316+
};
333317
```
334318

335319
### Installation CLI
@@ -505,10 +489,13 @@ export async function down(db: any): Promise<void> {
505489
}
506490
```
507491

508-
Run migrations through your existing Knex / driver tooling — ObjectStack does not
509-
ship its own migration runner. The intent of `os generate migration` is to give
510-
you a hand-off file you can commit, review, and execute via the database tools
511-
your team already uses.
492+
Run the generated files through your existing Knex / driver tooling — ObjectStack
493+
does not execute these generated migration files for you. (To apply
494+
metadata-driven schema changes directly, without generating files, ObjectStack
495+
does ship first-party `os migrate plan` / `os migrate apply` commands that
496+
reconcile the physical database to your object definitions.) The intent of
497+
`os generate migration` is to give you a hand-off file you can commit, review,
498+
and execute via the database tools your team already uses.
512499

513500
#### Schema safety
514501

@@ -584,18 +571,22 @@ ObjectStack includes **built-in health monitoring** to validate system state.
584571
### Health Check Endpoints
585572

586573
```
587-
GET /health/live
588-
→ 200 if process is alive
589-
→ 503 if process is dead/hung
590-
591-
GET /health/ready
592-
→ 200 if ready to accept requests
593-
→ 503 if still booting or unhealthy
574+
GET /health
575+
→ 200 with { status, version, uptime } if the process is alive (liveness)
594576
595-
GET /health/status
596-
→ Detailed health report (JSON)
577+
GET /ready
578+
→ 200 if the kernel is running and ready to accept requests (readiness)
579+
→ 503 while still booting or shutting down
597580
```
598581

582+
<Callout type="info">
583+
`GET /health` returns a compact liveness body (`status`, `version`, `uptime`) and
584+
`GET /ready` returns readiness. The richer per-subsystem report and the
585+
plugin-declared custom checks below describe the internal health-monitor model
586+
(`PluginHealthMonitor`) — they are **not yet** exposed as a dedicated HTTP
587+
endpoint or as a declarative plugin field.
588+
</Callout>
589+
599590
### Health Status Response
600591

601592
```json
@@ -639,10 +630,10 @@ GET /health/status
639630
Plugins can register custom health checks:
640631

641632
```typescript
642-
// Plugin registers health check
643-
export default definePlugin({
633+
// Plugin registers a custom health check (internal health-monitor model)
634+
export default {
644635
name: '@vendor/salesforce',
645-
636+
646637
healthChecks: {
647638
salesforce_connection: async ({ context }) => {
648639
try {
@@ -662,7 +653,7 @@ export default definePlugin({
662653
}
663654
},
664655
},
665-
});
656+
};
666657
```
667658

668659
## Shutdown Sequence
@@ -761,7 +752,7 @@ Don't assume success. Monitor health checks for 5-10 minutes after upgrade.
761752
```bash
762753
# Automated monitoring
763754
objectstack upgrade @vendor/salesforce --monitor --duration 300
764-
# Watches /health/status for 5 minutes, auto-rollback if unhealthy
755+
# Watches /health for 5 minutes, auto-rollback if unhealthy
765756
```
766757

767758
### 5. Document Breaking Changes

content/docs/protocol/kernel/metadata-service.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Loaders adapt different storage backends to a common interface.
6464
| **FilesystemLoader** | `filesystem` | Reads/Writes `.json`, `.yaml`, `.ts` files from disk. Primary for development. |
6565
| **MemoryLoader** | `memory` | Hydrates compiled artifact items into the runtime metadata registry. |
6666
| **DatabaseLoader** | `database` | Stores metadata revisions in control-plane services that explicitly configure it. Not auto-enabled by ObjectStack. |
67-
| **RemoteLoader** | `http` | Fetches metadata from a remote API or git repository. |
67+
| **RemoteLoader** | `http` | Fetches metadata from a remote HTTP API. |
6868

6969
### 3. Granular Capabilities
7070

@@ -234,6 +234,6 @@ The canonical `MetadataManagerConfigSchema` and `MetadataFallbackStrategySchema`
234234

235235
The Metadata Service is designed to power the CLI.
236236

237-
- **`objectstack compile`**: Validates TypeScript metadata and emits `dist/objectstack.json`.
238-
- **`objectstack publish`**: Uploads compiled JSON to the control plane, which creates a metadata revision and artifact.
239-
- **`objectstack dev`**: Boots ObjectStack from local files or the compiled artifact without a control-plane connection.
237+
- **`os compile`**: Validates TypeScript metadata and emits `dist/objectstack.json`.
238+
- **`os package publish`**: Uploads the compiled `dist/objectstack.json` artifact to the control plane as a versioned package.
239+
- **`os dev`**: Boots ObjectStack from local files or the compiled artifact without a control-plane connection.

0 commit comments

Comments
 (0)