okengine 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/package.json +1 -1
  2. package/site/content/docs/ai/mcp.mdx +0 -1
  3. package/site/content/docs/elements/ai.mdx +0 -6
  4. package/site/content/docs/elements/channel.mdx +0 -6
  5. package/site/content/docs/elements/clock.mdx +0 -6
  6. package/site/content/docs/elements/flow.mdx +0 -7
  7. package/site/content/docs/elements/gate.mdx +0 -6
  8. package/site/content/docs/elements/signal.mdx +0 -6
  9. package/site/content/docs/elements/store.mdx +8 -15
  10. package/site/content/docs/elements/vault.mdx +0 -6
  11. package/site/content/docs/get-started/basic-usage.mdx +0 -6
  12. package/site/content/docs/get-started/why.mdx +1 -2
  13. package/site/content/docs/index.mdx +0 -1
  14. package/site/content/docs/meta.json +0 -1
  15. package/site/content/docs/reference/fx.mdx +3 -3
  16. package/src/cli/ai-setup/ai-setup.test.ts +3 -1
  17. package/src/cli/build.ts +7 -8
  18. package/src/cli/dev.test.ts +88 -1
  19. package/src/cli/dev.ts +15 -13
  20. package/src/cli/doctor.ts +98 -5
  21. package/src/cli/load-config.images.test.ts +31 -1
  22. package/src/cli/load-config.ts +2 -2
  23. package/src/cli/safe-defaults.test.ts +1 -1
  24. package/src/compiler/extract.ts +12 -0
  25. package/src/compiler/fixtures/skyport/oke.config.ts +4 -2
  26. package/src/compiler/generate-adopt.ts +27 -1
  27. package/src/config/driver-defaults.test.ts +122 -0
  28. package/src/config/driver-defaults.ts +186 -0
  29. package/src/config/index.ts +97 -7
  30. package/src/docker/images-config.test.ts +168 -0
  31. package/src/kernel/boot-bind/channel.ts +12 -4
  32. package/src/kernel/boot-bind/clock.ts +3 -3
  33. package/src/kernel/boot-bind/gate.ts +7 -4
  34. package/src/kernel/boot-bind/journal.ts +3 -3
  35. package/src/kernel/boot-bind/signal.ts +3 -1
  36. package/src/kernel/boot-bind/store.test.ts +19 -0
  37. package/src/kernel/boot-bind/store.ts +24 -9
  38. package/src/kernel/boot-bind/vault.ts +3 -3
  39. package/site/content/docs/console/access.mdx +0 -29
  40. package/site/content/docs/console/ai.mdx +0 -35
  41. package/site/content/docs/console/architecture.mdx +0 -35
  42. package/site/content/docs/console/channels.mdx +0 -37
  43. package/site/content/docs/console/clock.mdx +0 -51
  44. package/site/content/docs/console/flows.mdx +0 -31
  45. package/site/content/docs/console/gates.mdx +0 -73
  46. package/site/content/docs/console/index.mdx +0 -54
  47. package/site/content/docs/console/manifest-diff.mdx +0 -34
  48. package/site/content/docs/console/meta.json +0 -24
  49. package/site/content/docs/console/overview.mdx +0 -40
  50. package/site/content/docs/console/plugins.mdx +0 -41
  51. package/site/content/docs/console/privacy.mdx +0 -32
  52. package/site/content/docs/console/runs.mdx +0 -50
  53. package/site/content/docs/console/signals.mdx +0 -40
  54. package/site/content/docs/console/store.mdx +0 -32
  55. package/site/content/docs/console/tenancy.mdx +0 -32
  56. package/site/content/docs/console/traces.mdx +0 -38
  57. package/site/content/docs/console/vault.mdx +0 -41
@@ -0,0 +1,168 @@
1
+ /**
2
+ * `ImagesConfig` (config surface, nested) → internal flat role map.
3
+ *
4
+ * Two guarantees:
5
+ * 1. Every built-in image recipe is reachable through the nested shape,
6
+ * correctly placed under its owning element (or flat, for roles with no
7
+ * driver counterpart) — the type-safety gap this closes.
8
+ * 2. A nested config produces byte-identical `deriveInfrastructure()` output
9
+ * (Dockerfile / compose / stack env) to the flat-shape equivalent it
10
+ * replaces — nesting is a config-surface change only, never an internal
11
+ * representation change.
12
+ */
13
+
14
+ import { describe, expect, test } from "bun:test";
15
+ import { flattenImagesConfig, type ImagesConfig } from "../config/index.ts";
16
+ import { deriveInfrastructure } from "./derive.ts";
17
+ import { builtinRecipes, recipeFor } from "./recipes/index.ts";
18
+ import type { ServiceCredentials } from "./types.ts";
19
+
20
+ describe("ImagesConfig nesting — recipe coverage", () => {
21
+ test("every built-in recipe id is reachable, correctly nested/flat by role", () => {
22
+ const cases: ReadonlyArray<{ images: ImagesConfig; role: string; image: string }> = [
23
+ // store.sql — postgres-family
24
+ {
25
+ images: { store: { sql: "postgres:18-alpine" } },
26
+ role: "store.sql",
27
+ image: "postgres:18-alpine",
28
+ },
29
+ {
30
+ images: { store: { sql: "cockroachdb/cockroach:v24.1.0" } },
31
+ role: "store.sql",
32
+ image: "cockroachdb/cockroach:v24.1.0",
33
+ },
34
+ {
35
+ images: { store: { sql: "yugabytedb/yugabyte:2024.1.0.0-b1" } },
36
+ role: "store.sql",
37
+ image: "yugabytedb/yugabyte:2024.1.0.0-b1",
38
+ },
39
+ {
40
+ images: { store: { sql: "timescale/timescaledb:2.15.0-pg16" } },
41
+ role: "store.sql",
42
+ image: "timescale/timescaledb:2.15.0-pg16",
43
+ },
44
+ {
45
+ images: { store: { sql: "supabase/postgres:15.1.0.117" } },
46
+ role: "store.sql",
47
+ image: "supabase/postgres:15.1.0.117",
48
+ },
49
+ // store.kv — redis-family
50
+ { images: { store: { kv: "redis:8-alpine" } }, role: "store.kv", image: "redis:8-alpine" },
51
+ {
52
+ images: { store: { kv: "valkey/valkey:8-alpine" } },
53
+ role: "store.kv",
54
+ image: "valkey/valkey:8-alpine",
55
+ },
56
+ {
57
+ images: { store: { kv: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.24.0" } },
58
+ role: "store.kv",
59
+ image: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.24.0",
60
+ },
61
+ // store.files / store.index
62
+ {
63
+ images: { store: { files: "rustfs/rustfs:1.0.0-beta.11" } },
64
+ role: "store.files",
65
+ image: "rustfs/rustfs:1.0.0-beta.11",
66
+ },
67
+ {
68
+ images: { store: { index: "getmeili/meilisearch:v1.37" } },
69
+ role: "store.index",
70
+ image: "getmeili/meilisearch:v1.37",
71
+ },
72
+ // channel.email
73
+ {
74
+ images: { channel: { email: "axllent/mailpit:v1.22.3" } },
75
+ role: "channel.email",
76
+ image: "axllent/mailpit:v1.22.3",
77
+ },
78
+ // flat roles — no driver counterpart in DriversConfig
79
+ {
80
+ images: { vault: "openbao/openbao:2.6.1" },
81
+ role: "vault",
82
+ image: "openbao/openbao:2.6.1",
83
+ },
84
+ {
85
+ images: { ai: "ghcr.io/ggml-org/llama.cpp:server-b10290" },
86
+ role: "ai",
87
+ image: "ghcr.io/ggml-org/llama.cpp:server-b10290",
88
+ },
89
+ { images: { ai: "vllm/vllm-openai:v0.26.0" }, role: "ai", image: "vllm/vllm-openai:v0.26.0" },
90
+ {
91
+ images: { ai: "lmsysorg/sglang:v0.5.16-runtime" },
92
+ role: "ai",
93
+ image: "lmsysorg/sglang:v0.5.16-runtime",
94
+ },
95
+ { images: { ai: "ollama/ollama:0.32.6" }, role: "ai", image: "ollama/ollama:0.32.6" },
96
+ {
97
+ images: { pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51" },
98
+ role: "pgdog",
99
+ image: "ghcr.io/pgdogdev/pgdog:v0.1.51",
100
+ },
101
+ { images: { proxy: "caddy:2-alpine" }, role: "proxy", image: "caddy:2-alpine" },
102
+ { images: { proxy: "traefik:v3.1" }, role: "proxy", image: "traefik:v3.1" },
103
+ ];
104
+
105
+ const matchedIds = new Set<string>();
106
+ for (const { images, role, image } of cases) {
107
+ // The nested literal flattens to exactly the dotted/flat role key the
108
+ // rest of the pipeline (buildSpecs, credentials, env prefixes) expects.
109
+ expect(flattenImagesConfig(images)).toEqual({ [role]: image });
110
+ matchedIds.add(recipeFor(image).id);
111
+ }
112
+
113
+ expect(matchedIds).toEqual(new Set(builtinRecipes.map((r) => r.id)));
114
+ });
115
+ });
116
+
117
+ describe("ImagesConfig nesting — compose output parity", () => {
118
+ test("nested config derives byte-identical output to its flat-shape equivalent", () => {
119
+ const flatImages: Readonly<Record<string, string>> = {
120
+ "store.sql": "postgres:18-alpine",
121
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
122
+ "store.kv": "redis:8-alpine",
123
+ "store.files": "rustfs/rustfs:1.0.0-beta.11",
124
+ "channel.email": "axllent/mailpit:v1.22.3",
125
+ vault: "openbao/openbao:2.6.1",
126
+ };
127
+
128
+ const nestedImages: ImagesConfig = {
129
+ store: {
130
+ sql: "postgres:18-alpine",
131
+ kv: "redis:8-alpine",
132
+ files: "rustfs/rustfs:1.0.0-beta.11",
133
+ },
134
+ channel: { email: "axllent/mailpit:v1.22.3" },
135
+ vault: "openbao/openbao:2.6.1",
136
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.51",
137
+ };
138
+
139
+ // Same nested→flat set, written in a different field order — proves the
140
+ // parity holds independent of source object key order.
141
+ expect(flattenImagesConfig(nestedImages)).toEqual(flatImages);
142
+
143
+ const credentials: Readonly<Record<string, ServiceCredentials>> = {
144
+ "store.sql": { user: "oke", password: "fixed-pw-sql", database: "oke" },
145
+ "store.kv": { user: "oke", password: "fixed-pw-kv", database: "oke" },
146
+ "store.files": { user: "oke", password: "fixed-pw-files", database: "oke" },
147
+ "channel.email": { user: "oke", password: "fixed-pw-email", database: "oke" },
148
+ vault: { user: "oke", password: "fixed-pw-vault", database: "oke" },
149
+ pgdog: { user: "oke", password: "fixed-pw-pgdog", database: "oke" },
150
+ };
151
+
152
+ const fromFlat = deriveInfrastructure({
153
+ images: flatImages,
154
+ app: "images-nesting-parity",
155
+ credentials,
156
+ });
157
+ const fromNested = deriveInfrastructure({
158
+ images: flattenImagesConfig(nestedImages),
159
+ app: "images-nesting-parity",
160
+ credentials,
161
+ });
162
+
163
+ expect(fromNested.specs).toEqual(fromFlat.specs);
164
+ expect(fromNested.files).toEqual(fromFlat.files);
165
+ expect(fromNested.stackEnv).toEqual(fromFlat.stackEnv);
166
+ expect(fromNested.composeFiles).toEqual(fromFlat.composeFiles);
167
+ });
168
+ });
@@ -3,6 +3,11 @@
3
3
  */
4
4
 
5
5
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
+ import {
7
+ CHANNEL_EMAIL_DEFAULTS,
8
+ CHANNEL_SMS_DEFAULTS,
9
+ dockerFlagDefaults,
10
+ } from "../../config/driver-defaults.ts";
6
11
  import { openConsoleChannel } from "../../drivers/channel-console.ts";
7
12
  import { openMsegatChannel } from "../../drivers/channel-msegat.ts";
8
13
  import { openResendChannel } from "../../drivers/channel-resend.ts";
@@ -81,9 +86,12 @@ export function resolveEmailDriverId(
81
86
  env: ConfigEnv,
82
87
  docker: boolean,
83
88
  ): string {
84
- return (
85
- resolveDriverId(options.config?.drivers?.channel?.email, env) ?? (docker ? "smtp" : "console")
86
- );
89
+ // Defaults cover every ConfigEnv key, so this is never undefined.
90
+ return resolveDriverId(
91
+ options.config?.drivers?.channel?.email,
92
+ env,
93
+ dockerFlagDefaults(CHANNEL_EMAIL_DEFAULTS, docker),
94
+ )!;
87
95
  }
88
96
 
89
97
  /**
@@ -93,7 +101,7 @@ export function resolveEmailDriverId(
93
101
  * @param env - Active environment
94
102
  */
95
103
  export function resolveSmsDriverId(options: BootOptions, env: ConfigEnv): string | undefined {
96
- return resolveDriverId(options.config?.drivers?.channel?.sms, env);
104
+ return resolveDriverId(options.config?.drivers?.channel?.sms, env, CHANNEL_SMS_DEFAULTS);
97
105
  }
98
106
 
99
107
  /**
@@ -15,6 +15,7 @@ import {
15
15
  } from "../../elements/clock.ts";
16
16
  import { createPostgresCronStore } from "../../drivers/clock-postgres.ts";
17
17
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
18
+ import { CLOCK_DEFAULTS } from "../../config/driver-defaults.ts";
18
19
  import type { BootOptions } from "../boot.ts";
19
20
 
20
21
  /** Result of binding a clock runtime. */
@@ -33,9 +34,8 @@ export const DEFAULT_FILE_CRON_PATH = ".oke/crons.json";
33
34
  * @param env - Active environment
34
35
  */
35
36
  export function resolveClockDriverId(options: BootOptions, env: ConfigEnv): string {
36
- const resolved = resolveDriverId(options.config?.drivers?.clock, env);
37
- if (resolved) return resolved;
38
- return env === "test" ? "frozen" : "memory";
37
+ // Defaults cover every ConfigEnv key, so this is never undefined.
38
+ return resolveDriverId(options.config?.drivers?.clock, env, CLOCK_DEFAULTS)!;
39
39
  }
40
40
 
41
41
  /**
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
+ import { dockerFlagDefaults, STORE_KV_DEFAULTS } from "../../config/driver-defaults.ts";
6
7
  import { memoryDrivers } from "../../drivers/memory.ts";
7
8
  import { redisDriver } from "../../drivers/redis.ts";
8
9
  import type { KvClientLike } from "../../drivers/types.ts";
@@ -27,10 +28,12 @@ export function resolveGateKvDriverId(
27
28
  const fromEnv = process.env.OKE_KV_DRIVER?.trim();
28
29
  if (docker && fromEnv === "redis") return "redis";
29
30
  if (docker && fromEnv === "memory") return "memory";
30
- const resolved = resolveDriverId(options.config?.drivers?.store?.kv, env);
31
- if (resolved === "redis") return "redis";
32
- if (resolved === "memory") return "memory";
33
- return docker ? "redis" : "memory";
31
+ const resolved = resolveDriverId(
32
+ options.config?.drivers?.store?.kv,
33
+ env,
34
+ dockerFlagDefaults(STORE_KV_DEFAULTS, docker),
35
+ );
36
+ return resolved === "redis" ? "redis" : "memory";
34
37
  }
35
38
 
36
39
  function kvUrlFor(docker: boolean): string {
@@ -12,6 +12,7 @@ import {
12
12
  } from "../journal.ts";
13
13
  import { createPostgresJournalStore } from "../../drivers/journal-postgres.ts";
14
14
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
15
+ import { JOURNAL_DEFAULTS } from "../../config/driver-defaults.ts";
15
16
  import type { BootOptions } from "../boot.ts";
16
17
 
17
18
  /** Bound journal runtime — store + this instance's lease identity. */
@@ -37,9 +38,8 @@ export const DEFAULT_FILE_JOURNAL_PATH = ".oke/journal.json";
37
38
  * @param env - Active environment
38
39
  */
39
40
  export function resolveJournalDriverId(options: BootOptions, env: ConfigEnv): string {
40
- const resolved = resolveDriverId(options.config?.drivers?.journal, env);
41
- if (resolved) return resolved;
42
- return "memory";
41
+ // Defaults cover every ConfigEnv key, so this is never undefined.
42
+ return resolveDriverId(options.config?.drivers?.journal, env, JOURNAL_DEFAULTS)!;
43
43
  }
44
44
 
45
45
  /**
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
+ import { SIGNAL_DEFAULTS } from "../../config/driver-defaults.ts";
6
7
  import { memorySignalDriver } from "../../drivers/signal-memory.ts";
7
8
  import { createBunSignalRedisClient, redisSignalDriver } from "../../drivers/signal-redis.ts";
8
9
  import type { SignalRedisClientLike } from "../../drivers/signal-types.ts";
@@ -17,7 +18,8 @@ import type { BootOptions } from "../boot.ts";
17
18
  * @param env - Active environment
18
19
  */
19
20
  export function resolveSignalDriverId(options: BootOptions, env: ConfigEnv): string {
20
- return resolveDriverId(options.config?.drivers?.signal, env) ?? "memory";
21
+ // Defaults cover every ConfigEnv key, so this is never undefined.
22
+ return resolveDriverId(options.config?.drivers?.signal, env, SIGNAL_DEFAULTS)!;
21
23
  }
22
24
 
23
25
  function redisUrlFor(docker: boolean): string | undefined {
@@ -78,6 +78,25 @@ describe("bindStore driver resolution", () => {
78
78
  expect(resolveKvDriverId({}, "docker", true)).toBe("redis");
79
79
  expect(resolveFilesDriverId({}, "docker", true)).toBe("s3");
80
80
  });
81
+
82
+ test("pinning only `local` never leaks into docker/test/prod — each keeps its real default", () => {
83
+ const options = {
84
+ config: {
85
+ drivers: {
86
+ store: {
87
+ sql: { local: "pglite" },
88
+ },
89
+ },
90
+ },
91
+ };
92
+ expect(resolveSqlDriverId(options, "local", false)).toBe("pglite");
93
+ expect(resolveSqlDriverId(options, "docker", true)).toBe("postgres");
94
+ expect(resolveSqlDriverId(options, "test", false)).toBe("memory");
95
+ expect(resolveSqlDriverId(options, "prod", true)).toBe("postgres");
96
+ // kv / files are untouched by the sql-only override.
97
+ expect(resolveKvDriverId(options, "local", false)).toBe("memory");
98
+ expect(resolveKvDriverId(options, "docker", true)).toBe("redis");
99
+ });
81
100
  });
82
101
 
83
102
  describe("bindStore files fs multi-instance warn", () => {
@@ -3,6 +3,12 @@
3
3
  */
4
4
 
5
5
  import { resolveDomainDdlMode, resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
+ import {
7
+ dockerFlagDefaults,
8
+ STORE_FILES_DEFAULTS,
9
+ STORE_KV_DEFAULTS,
10
+ STORE_SQL_DEFAULTS,
11
+ } from "../../config/driver-defaults.ts";
6
12
  import { fsDriver } from "../../drivers/fs.ts";
7
13
  import { libsqlDriver, libsqlIndexDriver } from "../../drivers/libsql.ts";
8
14
  import { meilisearchDriver } from "../../drivers/meilisearch.ts";
@@ -138,9 +144,12 @@ function resolveAutoPush(options: BootOptions): boolean {
138
144
  export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker: boolean): string {
139
145
  const fromEnv = process.env.OKE_SQL_DRIVER?.trim();
140
146
  if (docker && fromEnv) return fromEnv;
141
- const resolved = resolveDriverId(options.config?.drivers?.store?.sql, env);
142
- if (resolved) return resolved;
143
- return docker ? "postgres" : "memory";
147
+ // Defaults cover every ConfigEnv key, so this is never undefined.
148
+ return resolveDriverId(
149
+ options.config?.drivers?.store?.sql,
150
+ env,
151
+ dockerFlagDefaults(STORE_SQL_DEFAULTS, docker),
152
+ )!;
144
153
  }
145
154
 
146
155
  /**
@@ -151,9 +160,12 @@ export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker:
151
160
  export function resolveKvDriverId(options: BootOptions, env: ConfigEnv, docker: boolean): string {
152
161
  const fromEnv = process.env.OKE_KV_DRIVER?.trim();
153
162
  if (docker && fromEnv) return fromEnv;
154
- const resolved = resolveDriverId(options.config?.drivers?.store?.kv, env);
155
- if (resolved) return resolved;
156
- return docker ? "redis" : "memory";
163
+ // Defaults cover every ConfigEnv key, so this is never undefined.
164
+ return resolveDriverId(
165
+ options.config?.drivers?.store?.kv,
166
+ env,
167
+ dockerFlagDefaults(STORE_KV_DEFAULTS, docker),
168
+ )!;
157
169
  }
158
170
 
159
171
  /**
@@ -168,9 +180,12 @@ export function resolveFilesDriverId(
168
180
  ): string {
169
181
  const fromEnv = process.env.OKE_FILES_DRIVER?.trim();
170
182
  if (docker && fromEnv) return fromEnv;
171
- const resolved = resolveDriverId(options.config?.drivers?.store?.files, env);
172
- if (resolved) return resolved;
173
- return docker ? "s3" : "memory";
183
+ // Defaults cover every ConfigEnv key, so this is never undefined.
184
+ return resolveDriverId(
185
+ options.config?.drivers?.store?.files,
186
+ env,
187
+ dockerFlagDefaults(STORE_FILES_DEFAULTS, docker),
188
+ )!;
174
189
  }
175
190
 
176
191
  /**
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
+ import { VAULT_DEFAULTS } from "../../config/driver-defaults.ts";
6
7
  import { createVaultRuntime, type VaultRuntime } from "../../elements/vault.ts";
7
8
  import { buildVaultBootChain, normalizeVaultDriverId } from "../../elements/vault/boot-chain.ts";
8
9
  import type { BootOptions } from "../boot.ts";
@@ -14,9 +15,8 @@ import type { BootOptions } from "../boot.ts";
14
15
  * @param env - Active environment
15
16
  */
16
17
  export function resolveVaultDriverId(options: BootOptions, env: ConfigEnv): string {
17
- const resolved = resolveDriverId(options.config?.drivers?.vault, env);
18
- if (resolved) return resolved;
19
- return env === "test" ? "memory" : "env";
18
+ // Defaults cover every ConfigEnv key, so this is never undefined.
19
+ return resolveDriverId(options.config?.drivers?.vault, env, VAULT_DEFAULTS)!;
20
20
  }
21
21
 
22
22
  /**
@@ -1,29 +0,0 @@
1
- ---
2
- title: "Access"
3
- description: "Identities, roles, API keys."
4
- icon: "Users"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **identities, roles, API keys**
9
-
10
- <Callout title="Governing rule">
11
- Granting an application scope to an operator is impossible in the UI — taught by absence, not
12
- refusal.
13
- </Callout>
14
-
15
- ## What this panel shows
16
-
17
- <Cards>
18
- <Card title="Two planes" description="Operators and application users never mix." />
19
- <Card title="Key creation" description="Value shown once; attenuation to creator scopes only." />
20
- <Card title="Revocation" description="Blast radius plus honest JWT validity delay." />
21
- <Card title="Hygiene" description="Unused keys, never-signed-in operators, expired invites." />
22
- </Cards>
23
-
24
- ## Catalog
25
-
26
- <Cards>
27
- <Card title="Dev" description="✓" />
28
- <Card title="Prod" description="✓ (admin)" />
29
- </Cards>
@@ -1,35 +0,0 @@
1
- ---
2
- title: "AI"
3
- description: "Prompt versions, eval scores, cost, agent runs."
4
- icon: "Sparkles"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **prompt versions, eval scores, cost, agent runs**
9
-
10
- <Callout title="Governing rule">
11
- Everything else in the Console is deterministic; this panel is built on distributions, not single
12
- values.
13
- </Callout>
14
-
15
- ## What this panel shows
16
-
17
- <Cards>
18
- <Card title="Prompt versions" description="A version bump is Manifest Diff blast radius." />
19
- <Card title="Eval + shape" description="Schema-validation failure is its own class." />
20
- <Card
21
- title="Agent tools"
22
- description="Tools are the app’s own flows — undeclared reach is denied and shown."
23
- />
24
- <Card
25
- title="Budgets"
26
- description="Cost, semantic cache, and `allowPii` as standing review surfaces."
27
- />
28
- </Cards>
29
-
30
- ## Catalog
31
-
32
- <Cards>
33
- <Card title="Dev" description="full" />
34
- <Card title="Prod" description="read + budgets" />
35
- </Cards>
@@ -1,35 +0,0 @@
1
- ---
2
- title: "Architecture"
3
- description: "How it all connects — the diagram that is the code."
4
- icon: "Network"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **how it all connects — the diagram that _is_ the code**
9
-
10
- <Callout title="Governing rule">
11
- Flows answers “which one”; Architecture answers “what shape”. Never shows the whole system by
12
- default.
13
- </Callout>
14
-
15
- ## What this panel shows
16
-
17
- <Cards>
18
- <Card title="Unit clusters" description="Default aggregated edges; focus one or two hops." />
19
- <Card title="Element layers" description="Toggle data, messaging, time, external edges." />
20
- <Card
21
- title="Live traffic"
22
- description="Edge thickness from real traffic; dashed = never traversed."
23
- />
24
- <Card
25
- title="Pathologies"
26
- description="Cycles, god nodes, orphan signals, SPOFs — computed from the graph."
27
- />
28
- </Cards>
29
-
30
- ## Catalog
31
-
32
- <Cards>
33
- <Card title="Dev" description="✓" />
34
- <Card title="Prod" description="✓" />
35
- </Cards>
@@ -1,37 +0,0 @@
1
- ---
2
- title: "Channels"
3
- description: "Templates, delivery receipts, bounces, opt-outs."
4
- icon: "Mailbox"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **templates, delivery receipts, bounces, opt-outs, deliverability (SPF/DKIM/DMARC)**
9
-
10
- <Callout title="Governing rule">
11
- Suppression is not failure — the taxonomy of “did not arrive” has seven states with verdicts.
12
- </Callout>
13
-
14
- ## What this panel shows
15
-
16
- <Cards>
17
- <Card title="Dev inbox" description="`console` driver lands every medium locally." />
18
- <Card
19
- title="Deliverability"
20
- description="SPF/DKIM/DMARC, bounces, complaints, suppression list."
21
- />
22
- <Card
23
- title="Fallback chains"
24
- description="Recorded as chains (e.g. WhatsApp → SMS), not single outcomes."
25
- />
26
- <Card
27
- title="Locale previews"
28
- description="Template data bound to schema; RTL-accurate previews."
29
- />
30
- </Cards>
31
-
32
- ## Catalog
33
-
34
- <Cards>
35
- <Card title="Dev" description="full + console inbox" />
36
- <Card title="Prod" description="send test, inspect delivery" />
37
- </Cards>
@@ -1,51 +0,0 @@
1
- ---
2
- title: "Clock"
3
- description: "Upcoming crons, sleeping durable flows, journal."
4
- icon: "Clock"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **upcoming crons, sleeping durable flows, journal**
9
-
10
- <Callout title="Governing rule">
11
- Looks like time — a forward timeline for schedules and pending wakes, not a flat grid.
12
- </Callout>
13
-
14
- ## What this panel shows
15
-
16
- <Cards>
17
- <Card title="Schedules" description="Drift, overdue, missed runs · catch-up one, lease holder." />
18
- <Card title="Pending wakes" description="Every sleeping durable flow and when it wakes." />
19
- <Card
20
- title="DST warnings"
21
- description="Gap or overlap badge — detect only, no schedule rewrite."
22
- />
23
- <Card title="Actions" description="Run now, wake early, pause; edit when overridable." />
24
- </Cards>
25
-
26
- ## Health numbers
27
-
28
- Each cron row projects four numbers plus the lease holder:
29
-
30
- | Field | Meaning |
31
- | --------------- | ----------------------------------------------------------------- |
32
- | Drift | How far the last run sat from the expected slot |
33
- | Overdue | Whether the schedule is past due |
34
- | Missed + policy | Slot count while down · always catch-up `"one"` (one fire, not N) |
35
- | Lease | Which instance holds the leader lease (empty when none) |
36
-
37
- ## Actions
38
-
39
- | Action | When |
40
- | ------------- | ---------------------------------------------------------------------- |
41
- | Pause | Any cron — not gated by `overridable` |
42
- | Edit schedule | Only when the declaration has `overridable: true`; else loud refuse |
43
- | Wake early | Sleeping durable run — advances `wakeAt` and can resume the journal |
44
- | Run now | Still requires the leader lease across replicas that share a CronStore |
45
-
46
- ## Catalog
47
-
48
- <Cards>
49
- <Card title="Dev" description="full" />
50
- <Card title="Prod" description="trigger/pause; edit if `overridable`" />
51
- </Cards>
@@ -1,31 +0,0 @@
1
- ---
2
- title: "Flows"
3
- description: "What exists; call it; read its contract."
4
- icon: "GitBranch"
5
- source: "docs/spec/console.md"
6
- ---
7
-
8
- Answers: **what exists; call it; read its contract**
9
-
10
- <Callout title="Governing rule">
11
- Renders the one law as three columns: `Causes ← Flows → Effects` — not a tree.
12
- </Callout>
13
-
14
- ## What this panel shows
15
-
16
- <Cards>
17
- <Card title="Causes column" description="Triggers and callers — what runs this." />
18
- <Card title="Flows column" description="Context-adaptive centre with contracts and invoke." />
19
- <Card title="Effects column" description="What changes — store, signal, channel, AI, vault." />
20
- <Card
21
- title="Flow drawer"
22
- description="Workshop peek/expand — save as bun:test from a real response."
23
- />
24
- </Cards>
25
-
26
- ## Catalog
27
-
28
- <Cards>
29
- <Card title="Dev" description="full + source links" />
30
- <Card title="Prod" description="read + invoke per gates" />
31
- </Cards>