spine-framework 0.4.4 → 0.5.0-rc.5

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 (305) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/install-app.ts +183 -13
  8. package/.framework/cli/commands/migrate.ts +36 -30
  9. package/.framework/cli/commands/migrations.ts +16 -56
  10. package/.framework/cli/commands/upgrade.ts +35 -0
  11. package/.framework/cli/commands/validate-app.ts +127 -1
  12. package/.framework/cli/commands/validate-schema.ts +147 -0
  13. package/.framework/cli/context.ts +223 -110
  14. package/.framework/cli/index.ts +6 -0
  15. package/.framework/cli/lib/project-files.ts +241 -1
  16. package/.framework/functions/_shared/app-manifest.ts +2 -0
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/logging.ts +562 -224
  19. package/.framework/functions/_shared/middleware.ts +47 -44
  20. package/.framework/functions/_shared/permissions.ts +4 -0
  21. package/.framework/functions/admin-data.ts +51 -28
  22. package/.framework/functions/ai-agents.ts +10 -6
  23. package/.framework/functions/api-keys.ts +301 -122
  24. package/.framework/functions/apps.ts +63 -29
  25. package/.framework/functions/cil-ingest.ts +48 -15
  26. package/.framework/functions/debug-auth.ts +14 -8
  27. package/.framework/functions/deliveries.ts +39 -12
  28. package/.framework/functions/embeddings.ts +149 -78
  29. package/.framework/functions/integration-outbound.ts +67 -27
  30. package/.framework/functions/integrations.ts +254 -127
  31. package/.framework/functions/logs.ts +273 -133
  32. package/.framework/functions/observability.ts +278 -148
  33. package/.framework/functions/pipeline-executions.ts +1 -1
  34. package/.framework/functions/pipelines.ts +14 -9
  35. package/.framework/functions/prompt-configs.ts +7 -4
  36. package/.framework/functions/roles.ts +8 -5
  37. package/.framework/functions/security.ts +30 -17
  38. package/.framework/functions/system-cron.ts +240 -127
  39. package/.framework/functions/tests.ts +7 -6
  40. package/.framework/functions/timers.ts +310 -107
  41. package/.framework/functions/triggers.ts +28 -13
  42. package/.framework/functions/types.ts +13 -10
  43. package/.framework/migrations/069_log_stats_window.sql +54 -0
  44. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  45. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  46. package/.framework/migrations/072_slug_autofill.sql +77 -0
  47. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  48. package/.framework/migrations/074_app_route_prefix_domains.sql +168 -0
  49. package/.framework/migrations/075_security_definer_grants.sql +157 -0
  50. package/.framework/src/apps/admin/index.tsx +1141 -775
  51. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  52. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  53. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  54. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  55. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  56. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  57. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  58. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  59. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  60. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  61. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  62. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  63. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  64. package/.framework/src/components/ui/sheet.tsx +24 -26
  65. package/.framework/src/components/ui/textarea.tsx +74 -48
  66. package/.framework/src/contexts/AppContext.tsx +5 -12
  67. package/.framework/src/contexts/AuthContext.tsx +17 -9
  68. package/.framework/src/hooks/useApps.ts +18 -22
  69. package/.framework/src/hooks/useEntityList.ts +12 -9
  70. package/.framework/src/hooks/useListSchema.ts +108 -58
  71. package/.framework/src/instructions/README.md +74 -0
  72. package/.framework/src/instructions/accounts.md +97 -0
  73. package/.framework/src/instructions/ai-agents.md +69 -0
  74. package/.framework/src/instructions/alerts.md +80 -0
  75. package/.framework/src/instructions/api-keys.md +87 -0
  76. package/.framework/src/instructions/apps.md +77 -0
  77. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  78. package/.framework/src/instructions/concepts/apps-and-renderers.md +228 -0
  79. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  80. package/.framework/src/instructions/concepts/automation.md +186 -0
  81. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  82. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  83. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  84. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  85. package/.framework/src/instructions/concepts/observability.md +116 -0
  86. package/.framework/src/instructions/concepts/permissions.md +150 -0
  87. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  88. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  89. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  90. package/.framework/src/instructions/deliveries.md +59 -0
  91. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  92. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  93. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  94. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  95. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  96. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  97. package/.framework/src/instructions/integrations.md +96 -0
  98. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  99. package/.framework/src/instructions/internal/docs-contract.md +158 -0
  100. package/.framework/src/instructions/invites.md +60 -0
  101. package/.framework/src/instructions/kb.md +80 -0
  102. package/.framework/src/instructions/logs.md +77 -0
  103. package/.framework/src/instructions/notifications.md +77 -0
  104. package/.framework/src/instructions/observability.md +61 -0
  105. package/.framework/src/instructions/operations/deployment.md +115 -0
  106. package/.framework/src/instructions/operations/migrations.md +125 -0
  107. package/.framework/src/instructions/operations/security-checklist.md +170 -0
  108. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  109. package/.framework/src/instructions/operations/upgrade.md +116 -0
  110. package/.framework/src/instructions/people.md +91 -0
  111. package/.framework/src/instructions/pipeline-executions.md +62 -0
  112. package/.framework/src/instructions/pipelines.md +78 -0
  113. package/.framework/src/instructions/prompts.md +95 -0
  114. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  115. package/.framework/src/instructions/reference/api/auth.md +113 -0
  116. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  117. package/.framework/src/instructions/reference/app-manifest.md +184 -0
  118. package/.framework/src/instructions/reference/cli.md +124 -0
  119. package/.framework/src/instructions/reference/database.md +132 -0
  120. package/.framework/src/instructions/reference/design-schema.md +280 -0
  121. package/.framework/src/instructions/reference/env-vars.md +133 -0
  122. package/.framework/src/instructions/reference/frontend-sdk.md +207 -0
  123. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  124. package/.framework/src/instructions/reference/functions/admin-data.md +197 -0
  125. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  126. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  127. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  128. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  129. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  130. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  131. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  132. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  133. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  134. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  135. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  136. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  137. package/.framework/src/instructions/reference/functions/index.md +103 -0
  138. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  139. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  140. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  141. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  142. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  143. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  144. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  145. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  146. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  147. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  148. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  149. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  150. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  151. package/.framework/src/instructions/reference/functions/security.md +140 -0
  152. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  153. package/.framework/src/instructions/reference/functions/system.md +106 -0
  154. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  155. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  156. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  157. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  158. package/.framework/src/instructions/reference/functions/types.md +146 -0
  159. package/.framework/src/instructions/reference/seeds.md +126 -0
  160. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  161. package/.framework/src/instructions/reference/spine-config.md +114 -0
  162. package/.framework/src/instructions/roles.md +80 -0
  163. package/.framework/src/instructions/runtime-collaboration.md +106 -0
  164. package/.framework/src/instructions/runtime-detail.md +70 -0
  165. package/.framework/src/instructions/runtime-list.md +77 -0
  166. package/.framework/src/instructions/security.md +67 -0
  167. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  168. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  169. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  170. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  171. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  172. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  173. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  174. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  175. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  176. package/.framework/src/instructions/tasks/document-your-app.md +117 -0
  177. package/.framework/src/instructions/tasks/package-and-install-an-app.md +136 -0
  178. package/.framework/src/instructions/tasks/register-an-app.md +137 -0
  179. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  180. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  181. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  182. package/.framework/src/instructions/testing.md +59 -0
  183. package/.framework/src/instructions/timers.md +84 -0
  184. package/.framework/src/instructions/triggers.md +69 -0
  185. package/.framework/src/instructions/types.md +93 -0
  186. package/.framework/src/lib/app-mount.ts +88 -0
  187. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  188. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  189. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  190. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  191. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  192. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  193. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  194. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  195. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  196. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  197. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  198. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  199. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  200. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  201. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  202. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  203. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  204. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  205. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  206. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  207. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  208. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  209. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  210. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  211. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  212. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  213. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  214. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  215. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  216. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  217. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  218. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  219. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  220. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  221. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  222. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  223. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  224. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  225. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  226. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  227. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  228. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  229. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  230. package/.framework/src/pages/auth/LoginPage.tsx +3 -2
  231. package/.framework/src/pages/auth/RegisterPage.tsx +16 -8
  232. package/.framework/templates/agent/AGENTS.md +167 -0
  233. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  234. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  235. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  236. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  237. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +79 -0
  238. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  239. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +79 -0
  240. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +71 -0
  241. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +72 -0
  242. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  243. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  244. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  245. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  246. package/.framework/templates/project.json +4 -1
  247. package/.framework/tests/unit/account-scoping-gates.test.ts +394 -0
  248. package/.framework/tests/unit/agent-files.test.ts +355 -0
  249. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  250. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  251. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  252. package/.framework/tests/unit/app-mount.test.ts +80 -0
  253. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  254. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  255. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  256. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  257. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  258. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  259. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  260. package/.framework/tests/unit/security-definer-grants.test.ts +154 -0
  261. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  262. package/.framework/tests/unit/system-cron.test.ts +240 -0
  263. package/.framework/tests/unit/timers.test.ts +159 -0
  264. package/README.md +125 -166
  265. package/config/tsconfig.cli.json +2 -2
  266. package/package.json +15 -4
  267. package/templates/project/package-lock.json +2 -2
  268. package/.framework/docs/admin-routes.md +0 -76
  269. package/.framework/docs/api-docs-progress.md +0 -38
  270. package/.framework/docs/api-governance.md +0 -146
  271. package/.framework/docs/api-testing-results.md +0 -212
  272. package/.framework/docs/assembly-launch-guide.md +0 -138
  273. package/.framework/docs/audit-results.md +0 -590
  274. package/.framework/docs/db-api-inventory.md +0 -95
  275. package/.framework/docs/gap-remediation-backlog.md +0 -103
  276. package/.framework/docs/ui-adoption-verification.md +0 -111
  277. package/.framework/docs/ui-api-coverage.md +0 -84
  278. package/.framework/docs/v2-compatibility-audit.md +0 -228
  279. package/.framework/mcp/index.ts +0 -133
  280. package/.framework/mcp/load-env.ts +0 -60
  281. package/.framework/mcp/shared/app-manifest.ts +0 -275
  282. package/.framework/mcp/shared/db.ts +0 -477
  283. package/.framework/mcp/shared/kb.ts +0 -118
  284. package/.framework/mcp/tools/architect.ts +0 -431
  285. package/.framework/mcp/tools/cil/context.ts +0 -345
  286. package/.framework/mcp/tools/cil/graph.ts +0 -242
  287. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  288. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  289. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  290. package/.framework/mcp/tools/cil/project.ts +0 -791
  291. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  292. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  293. package/.framework/mcp/tools/cil/search.ts +0 -97
  294. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  295. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  296. package/.framework/mcp/tools/kb/delete.ts +0 -139
  297. package/.framework/mcp/tools/kb/index.ts +0 -52
  298. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  299. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  300. package/.framework/mcp/tools/kb/publish.ts +0 -100
  301. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  302. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  303. package/.framework/mcp/tools/kb/search.ts +0 -101
  304. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  305. package/.framework/mcp/tools/observability.ts +0 -510
@@ -0,0 +1,158 @@
1
+ ---
2
+ title: "Docs contract — how the instruction book is written, tested, and kept true"
3
+ audience: developers, agents
4
+ kind: reference
5
+ verified_against: b3b3ae0
6
+ verified_on: 2026-11-01
7
+ source_files:
8
+ - scripts/docs-lint.mts
9
+ - .framework/src/instructions/README.md
10
+ - docs/audit/clean-room-walkthrough.md
11
+ - .framework/cli/commands/install-app.ts
12
+ - .framework/cli/commands/validate-app.ts
13
+ ---
14
+
15
+ # Docs contract
16
+
17
+ This file is the editorial contract for the Spine instruction book and for
18
+ the instruction books that installed apps carry at
19
+ `custom/apps/<slug>/src/instructions/`. It lives under `internal/` because it
20
+ governs the book itself rather than describing the framework.
21
+
22
+ ## The test rule
23
+
24
+ Every miss is a documentation bug — fix the book, not the test.
25
+
26
+ The book must carry a cold agent — one with zero memory of this codebase —
27
+ through installation, orientation, and building on Spine without touching
28
+ monorepo-only material. If an agent has to grep `.framework/functions/` to
29
+ answer a customer-facing question, or has to ask the user something that
30
+ isn't a real-world checkpoint (credentials, first-admin choice), the book is
31
+ missing a page, a section, or a line. Write it. Do not explain around the
32
+ gap in the moment and move on.
33
+
34
+ Corollaries:
35
+
36
+ - Retrieval beats derivation. A fact an agent can *find* is safe; a fact it
37
+ has to *derive* from source is a latent bug.
38
+ - Code is truth; docs are interpretation. When they disagree, the doc is
39
+ wrong — fix the doc and bump `verified_against`/`verified_on`.
40
+ - "It figured it out eventually" is a fail. Time-to-answer is the metric.
41
+
42
+ ## The capture contract
43
+
44
+ A code change is **incomplete until the docs covering it are re-synced**.
45
+ Docs are part of the change, not a follow-up chore. One rule, two layers:
46
+
47
+ **Core.** Every book page lists `source_files` in its frontmatter — the code
48
+ files whose behavior the page interprets. Editing any file in that set
49
+ requires re-verifying every page that lists it, in the same change, and
50
+ bumping `verified_against` (commit short hash) and `verified_on` (date).
51
+ `npm run docs:lint` is the gate.
52
+
53
+ **Custom.** Editing anything under `custom/apps/<slug>/` requires updating
54
+ that app's `src/instructions/` in the same change:
55
+
56
+ - New or changed page/route → the app's tasks doc and README route map.
57
+ - New or changed function → the app's `reference/functions` page.
58
+ - New or changed seeded type → the app's entity page for that type.
59
+ - New skill → the app's README skills list.
60
+
61
+ **Capture, not just sync.** Non-obvious decisions, cautions, and traps
62
+ discovered while doing the work are appended to the relevant page's
63
+ `## Agent notes` section — the next cold agent reads what the last one
64
+ learned. Positive-only corrections: update the source; never append
65
+ "correction notes" that contradict an untouched stale claim.
66
+
67
+ ### Relationship to CIL
68
+
69
+ CIL (Code Intelligence Layer, the `cil_*` tooling used inside this monorepo)
70
+ is **bottom-up code truth**: per-chunk contracts, `stored_hash` drift
71
+ detection, a call/import/test graph, semantic code search. The book is
72
+ **top-down narrative comprehension**: curated prose at system granularity.
73
+
74
+ Neither replaces the other:
75
+
76
+ - CIL can *prove* a doc is stale (hash recompute); the book can only *assert*
77
+ freshness (`verified_*` stamps + lint gate). The capture contract above is
78
+ the manual stand-in for CIL's automatic re-sync pipeline.
79
+ - The book carries CIL's *purpose* into shipped projects where no `cil_*`
80
+ tooling runs — it is the portable distillation, not a replacement.
81
+
82
+ The definition of done for `.framework/` edits in this repo is therefore
83
+ **both**: CIL re-sync (`cil_store_markers` → `cil_generate_embeddings` →
84
+ `cil_generate_mappings` → `cil_validate_file`) for code truth, and book
85
+ re-verify for narrative truth. Mechanical pages (`reference/functions/*`,
86
+ entity field tables) may eventually be generated/verified from CIL chunks;
87
+ narrative layers stay hand-authored.
88
+
89
+ ## Layer taxonomy — which layer answers which question
90
+
91
+ | Layer | Kind | Answers | Mandatory shape |
92
+ |---|---|---|---|
93
+ | `guide/` | guide | "Walk me through it end to end" | Numbered sequence (`00` → `05`); each step verifiable |
94
+ | `concepts/` | concept | "Why is it like this? What's the mental model?" | Model first, mechanics second; links to tasks |
95
+ | `tasks/` | task | "How do I do X?" | `## Goal` → `## Steps` → `## Verify` → `## Common mistakes` → `## Reference` |
96
+ | `reference/` | reference | "What's the exact spelling/shape?" | Tables over prose; every row verifiable against `source_files` |
97
+ | Entity pages (root) | entity | "What is this thing and how do I configure it?" | The 7-section template (enforced by docs:lint) |
98
+ | `operations/` | ui | "How do I run/diagnose it in the admin UI?" | Runbook steps anchored to real pages/endpoints |
99
+ | `internal/` | * | "How is the book itself maintained?" | Repo-only; exempt from archived-docs and cil_* reference rules |
100
+
101
+ Frontmatter on every page: `title`, `audience`, `kind`,
102
+ `verified_against`, `verified_on`, `source_files` (list). Exemption:
103
+ `status: LEGACY_UNVERIFIED` — still checked for links and paths.
104
+
105
+ ## Skills
106
+
107
+ Invocable procedures live in `.devin/skills/spine-*` (framework-owned,
108
+ dir-replaced on upgrade) and `custom/.devin/skills/<prefix>_*`
109
+ (app-owned — see below). A task doc should name its companion skill where
110
+ one exists; a skill should link its task/reference doc.
111
+
112
+ **App-shipped skills.** An installed app may ship skills under
113
+ `agent/skills/<prefix>_*/` in its package; `install-app` copies them to
114
+ `custom/.devin/skills/` and `uninstall-app` removes `custom/.devin/skills/<prefix>_*`.
115
+ `manifest.agent.skill_prefix` is required when `agent/skills/` exists and
116
+ must match `^[a-z][a-z0-9]{0,7}$` and be unique across installed apps.
117
+ See [App manifest reference](../reference/app-manifest.md) and
118
+ [Document your app](../tasks/document-your-app.md).
119
+
120
+ ## Acceptance matrix — the regression suite
121
+
122
+ The cold-agent test protocol lives in the repo at
123
+ `docs/audit/clean-room-walkthrough.md`. Each row is a verbatim prompt; the
124
+ pages listed must satisfy it **alone**. New pages earn a row; a failing row
125
+ means the book regressed, not that the agent did.
126
+
127
+ | # | Verbatim prompt (abridged) | Pages that must carry it |
128
+ |---|---|---|
129
+ | T1 | Explain this project: what's mine vs framework, how do primitives compose, where does my code go, what do I never touch | `guide/00-orientation.md`, `guide/02-project-map.md`, `concepts/core-vs-custom.md`, `concepts/spine-way.md` |
130
+ | T2 | Create a design_schema for a "task" type (fields, selects, permissions, list+detail views) and validate it | `tasks/add-a-type.md`, `reference/design-schema.md`, `concepts/design-schema.md`; skill `spine_schema_validate`/`spine-schema` |
131
+ | T3 | Create the type and register a generic app at /taskboard that lists it — visible in the UI | `tasks/register-an-app.md`, `apps.md`, `reference/app-manifest.md`, `concepts/apps-and-renderers.md` |
132
+ | T4 | Add a custom page that lists tasks with a working create form — no server-side code | `tasks/build-a-custom-page.md`, `reference/frontend-sdk.md`, `reference/api/admin-data.md` |
133
+ | T5 | Wire a pipeline on task create + a 2-minute timer; show a completed execution | `tasks/add-a-pipeline.md`, `tasks/add-a-trigger.md`, `tasks/add-a-timer.md`, `timers.md` |
134
+ | T6 | Add an AI agent with its own prompt config and send a test message | `tasks/add-an-ai-agent.md`, `ai-agents.md`, `prompts.md` |
135
+ | T7 | Package this app; install it into another Spine project; show create/list working | `tasks/package-and-install-an-app.md`, `reference/app-manifest.md`, `reference/seeds.md`; skill `spine-install-app` |
136
+ | T8 | Something broke — creating a task fails / the pipeline fails. Find and fix it | `operations/troubleshooting.md`, `pipeline-executions.md`, `logs.md`, `deliveries.md`; skill `spine-troubleshoot` |
137
+ | T9 | (cold) Create a type, register an app, wire a pipeline — from docs alone | The whole book end to end |
138
+ | M1 | Mount this app at the site root (served from `/`) | `tasks/register-an-app.md`, `apps.md`, `reference/app-manifest.md`, `concepts/apps-and-renderers.md` |
139
+ | M2 | What can I import in a custom app? Build a page using the framework's UI kit | `reference/frontend-sdk.md`, `tasks/build-a-custom-page.md` |
140
+ | M3 | Install this app, then use its shipped skill and its instruction book | `tasks/package-and-install-an-app.md`, `reference/app-manifest.md` (`agent` block), app `src/instructions/` |
141
+ | M4 | You changed file X — which docs did you update? | This contract (capture section), `AGENTS.md` verify rules |
142
+
143
+ ## Authoring checklist for a new page
144
+
145
+ - [ ] Correct `kind` + full frontmatter; `source_files` lists the real files
146
+ that produce the page's truth.
147
+ - [ ] Placed in the layer whose question it answers (taxonomy table above).
148
+ - [ ] Linked from `README.md`'s index and from at least one sibling page.
149
+ - [ ] A row in the acceptance matrix if it covers a cold-agent task.
150
+ - [ ] `npm run docs:lint` clean.
151
+
152
+ ## The gate
153
+
154
+ `npm run docs:lint` (`scripts/docs-lint.mts`, repo-only) checks: required
155
+ frontmatter, kind taxonomy, the 7-section headings on `entity`/`ui` pages,
156
+ relative-link resolution, existence of every backticked `.framework/...`
157
+ path, and (outside `internal/`) no `docs/archive` references and no `cil_*`
158
+ tool references.
@@ -0,0 +1,60 @@
1
+ ---
2
+ title: Invites & Access
3
+ audience: both
4
+ kind: entity
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/src/pages/admin/InvitesPage.tsx
9
+ - .framework/src/components/shared/InviteManager.tsx
10
+ - .framework/functions/invites.ts
11
+ ---
12
+
13
+ ## What this is for
14
+
15
+ **Invites & Access** (`/spine-framework/admin/access/invites`) manages how people join the account: generating invite links, tracking their status, re-sending or revoking them, and approving access requests. The admin page is scoped to the `system_admin` role; the shared `InviteManager` component underneath supports other role sets.
16
+
17
+ ## Fields and settings
18
+
19
+ - **Generate invite form** — name, email, and role picker (shown only when more than one role is allowed; here it is fixed to `system_admin`). Produces an `invite_url` copied to the clipboard: `{APP_BASE_URL}/register?t=<invite_token>`.
20
+ - **Invites table** — the person's name/email, assigned role, status, and actions: reinvite (new link), revoke, approve (access requests), block.
21
+ - **Status semantics** — `invited`/`pending` (link issued or request awaiting approval), `approved`, `active`/`claimed` (registered), `revoked` (`inactive`), `expired`, `blocked`. `kind` distinguishes `invite` from `access_request`.
22
+ - **Search + sortable columns** over the list from `action=list-invites` (filtered to the allowed role slugs).
23
+
24
+ **Downstream effects**
25
+
26
+ - `create-invite` inserts a stub `people` row carrying `invite_token` (16 chars) and `invite_expires_at` (7 days); the register flow consumes the token via `complete-registration` → `complete_registration_placement` RPC.
27
+ - Only `system_admin` (or an `*_admin` role on the account) can create invites; creating an invite for `role_slug: system_admin` is refused unless the caller is already `system_admin`.
28
+ - `revoke-invite` marks the person `inactive`, killing the unclaimed link; `reinvite` mints a fresh token/link. `block-invite`/`deny` handle abusive requests.
29
+ - Registration and account-creation calls are rate-limited per person and per IP.
30
+
31
+ ## Minimal configuration
32
+
33
+ Fill name + email → Generate → the invite URL lands on your clipboard; send it out of band. The invitee registers within 7 days or you reinvite.
34
+
35
+ ## Full configuration
36
+
37
+ The backing API (`/.netlify/functions/invites?action=`) also covers the public registration path and member management:
38
+
39
+ - `check-first-user`, `check-domain`, `validate-token`, `complete-registration` — anonymous signup flow
40
+ - `create-invite`, `list-invites`, `revoke-invite`, `reinvite`, `block-invite`
41
+ - `approve`, `deny` — access-request review
42
+ - `list-members`, `update-member`, `deactivate-member` — existing members
43
+
44
+ ## Example
45
+
46
+ An admin generates a `system_admin` invite for a new hire, pastes the link into chat. Until they register, the row shows `pending`; if the link is lost, Reinvite mints a new URL and invalidates the old token; if they never join, Revoke marks the stub `inactive`.
47
+
48
+ ## Core files
49
+
50
+ - `.framework/src/pages/admin/InvitesPage.tsx` — this page (scopes InviteManager to `system_admin`)
51
+ - `.framework/src/components/shared/InviteManager.tsx` — invite list/form/actions (reusable in other apps)
52
+ - `.framework/functions/invites.ts` — API (all actions above)
53
+ - Table: `public.people` (invite stub rows carry `invite_token`/`invite_expires_at`)
54
+
55
+ ## Agent notes
56
+
57
+ - The invite URL is shown/copied **once** at create/reinvite — the API never returns it again; a lost link means Reinvite, not retrieve.
58
+ - Invites expire after 7 days (`invite_expires_at`); expired rows show `expired` until reinvited or revoked.
59
+ - This admin page is hardcoded to `system_admin` invites; app-level member invites use the same `InviteManager` with a different `allowedRoles` set.
60
+ - Stub invite rows are real `people` rows — they are excluded from normal principal resolution until registration completes.
@@ -0,0 +1,80 @@
1
+ ---
2
+ title: Knowledge Base
3
+ audience: both
4
+ kind: entity
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/src/pages/admin/kb/KBAdminPage.tsx
9
+ - .framework/src/components/kb/KBArticleList.tsx
10
+ - .framework/src/components/kb/KBArticleEditor.tsx
11
+ - .framework/src/pages/admin/EmbeddingsPage.tsx
12
+ - .framework/src/pages/admin/EmbeddingDetailPage.tsx
13
+ - .framework/functions/kb.ts
14
+ - .framework/functions/embeddings.ts
15
+ - .framework/functions/admin-data.ts
16
+ ---
17
+
18
+ ## What this is for
19
+
20
+ The **KB** section (`/spine-framework/admin/kb/*`) covers three surfaces that share this doc:
21
+
22
+ - `kb/:typeSlug` — the article admin list/editor (`KBAdminPage`) for the KB item types `kb-spine-admin`, `kb-spine-internal`, `kb-spine-public`, `kb-account`. Articles are `items` records created/edited via `admin-data` and published via `kb`.
23
+ - `kb/embeddings` — the embedding record browser (`EmbeddingsPage`): every generated embedding row with its approval state.
24
+ - `kb/embeddings/:id` — single embedding detail (`EmbeddingDetailPage`): content, vector type, chunk index, model, approval/revocation timestamps, optional raw vector.
25
+
26
+ ## Fields and settings
27
+
28
+ **Articles** (`KBArticleList` / `KBArticleEditor`)
29
+
30
+ - **Type slug tabs** — the four KB type slugs above; articles are `items` records of that type.
31
+ - **List** — title, status, created date; search hits `/api/kb?action=search` (sources `['kb']`).
32
+ - **Editor** — schema-driven form from the type's `design_schema` (main fields + metadata sidebar); Save writes `admin-data` create/update; **Publish** additionally calls `/api/kb?action=publish`; Delete uses `admin-data` remove.
33
+ - **Modes** — `view` (read-only), `edit`, `new` via route (`:id`, `:id/edit`, `new`).
34
+
35
+ **Embeddings** (`EmbeddingsPage` / `EmbeddingDetailPage`)
36
+
37
+ - **List** — content/document/model search + sortable columns; status badge: `Revoked` (revoked_at set) > `Approved` (approved_at set) > `Pending`.
38
+ - **Detail** — document_id, vector_type, chunk_index, model_id, token count, content preview, approved/revoked timestamps, and a show-vector toggle for the raw embedding.
39
+
40
+ **Downstream effects**
41
+
42
+ - Articles are plain `items` records — they inherit the type's `record_permissions` and `validation_schema`; `kb?action=publish` handles the publishing step (ingest/indexing) on top.
43
+ - Embeddings are generated per type `design_schema.vector_types` (default `['semantic','structure']`) and feed `match_embeddings`/semantic search used by agents and `search_knowledge` pipeline stages.
44
+ - `embeddings` actions: list/get/create/update + `generate`, `revoke`, `approve`, `stats`, `batch-create`, `delete-document`, `cleanup`, `search-similar`, `search-semantic`. `revoke` stamps `revoked_at` (excluded from search); `approve` stamps `approved_at` and clears revocation.
45
+
46
+ ## Minimal configuration
47
+
48
+ Pick a KB type slug tab → New → fill the schema form → Save → Publish. The article is now searchable via `kb?action=search`.
49
+
50
+ ## Full configuration
51
+
52
+ ```jsonc
53
+ // article write — POST /api/admin-data?entity=items
54
+ { "type_id": "kb-account", "title": "Refund policy", "data": { "body": "..." } }
55
+ // publish — POST /api/kb?action=publish { "id": "<article uuid>" }
56
+ // regenerate vectors — POST /api/embeddings?action=generate { "item_id": "<article uuid>" }
57
+ // curate — POST /api/embeddings?action=approve|revoke { "id": "<embedding uuid>" }
58
+ ```
59
+
60
+ ## Example
61
+
62
+ A support team writes refund-policy articles under `kb-account`, publishes them, then checks `kb/embeddings` — the new chunks show `Pending` until reviewed; approving the good ones and revoking a stale `semantic` chunk changes what `search_knowledge` returns to the reply-drafting agent.
63
+
64
+ ## Core files
65
+
66
+ - `.framework/src/pages/admin/kb/KBAdminPage.tsx` — article page shell (list vs editor by mode)
67
+ - `.framework/src/components/kb/KBArticleList.tsx` / `KBArticleEditor.tsx` — list + schema-driven editor, publish call
68
+ - `.framework/src/pages/admin/EmbeddingsPage.tsx` / `EmbeddingDetailPage.tsx` — embedding browser/detail
69
+ - `.framework/functions/kb.ts` — `search`, `publish`, and KB pipeline actions
70
+ - `.framework/functions/embeddings.ts` — embedding CRUD + generate/approve/revoke/search
71
+ - `.framework/functions/admin-data.ts` — the underlying record CRUD
72
+ - Tables: `public.items` (articles), `public.embeddings` (vectors)
73
+
74
+ ## Agent notes
75
+
76
+ - `instructionKeyFor` maps every `kb/*` route to this doc — there is no separate `embeddings` page key.
77
+ - Articles are records, not files — edit them through this UI or `admin-data`, never direct table writes that skip validation/triggers.
78
+ - `Pending` embeddings still count toward `stats`; only `revoked_at` removes a vector from similarity search.
79
+ - Deleting an article does not cascade to its embedding rows — use `embeddings?action=delete-document` to clean up vectors for a removed document.
80
+ - Re-publish after large edits: publishing re-ingests; stale chunks otherwise linger until `generate`/`cleanup` runs.
@@ -0,0 +1,77 @@
1
+ ---
2
+ title: Logs
3
+ audience: both
4
+ kind: entity
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/src/pages/admin/LogsPage.tsx
9
+ - .framework/functions/logs.ts
10
+ - .framework/functions/_shared/logging.ts
11
+ - .framework/functions/system-cron.ts
12
+ - .framework/migrations/069_log_stats_window.sql
13
+ ---
14
+
15
+ ## What this is for
16
+
17
+ **Logs** (`/spine-framework/admin/observability/logs`) is the account's audit-trail and event-history viewer — every `emitLog`/`emitAudit`/`emitSpan`/`emitActivity` write lands in the `logs` table and shows up here. Use it to trace a request end-to-end (via `trace_id`), answer "who did what when", and debug trigger/pipeline/delivery failures.
18
+
19
+ ## Fields and settings
20
+
21
+ - **Stats cards** — Total Events, Event Types, Errors, User Actions over the current filter window (`/api/logs?action=stats`).
22
+ - **Search** — free text over message/actor fields; debounced 300ms.
23
+ - **Level** — `event_type` of the log row (error/audit/span/activity categories surface as selectable values from the stats payload).
24
+ - **Source / Source Type** — `action` and `target_type` of the row (e.g. `type.updated`, `item`).
25
+ - **Source ID / Actor ID / Trace ID** — UUID/prefix filters: `target_id`, `actor_id`, `trace_id`.
26
+ - **From / To dates** — `date_from`/`date_to`; defaults to the last 24h. Stats default to a 7-day window when no `date_from` is given.
27
+ - **Row click** — expands the row to show `details`, `metadata`, span info (`span_name`, `span_id`, `parent_span_id`, `duration_ms`, `outcome`).
28
+ - **Trace button** — clicking a `trace_id` filters the whole grid to that trace (all spans of one request).
29
+ - Paged at 100 rows per page; sortable columns (Time, Trace, Level, Source, Source Type, Source ID, Person, Message).
30
+
31
+ **Downstream effects**
32
+
33
+ - What gets written is gated by `system_settings` key `logging`: levels `off | timing | warnings | errors | all` (default `['timing','errors']`). Rows at unconfigured levels are dropped at write time — they never reach this page.
34
+ - Retention is `cleanup` with `days_to_keep` (default 30); `system-cron` runs `cleanup_old_logs` at 00:00 UTC. Debugging a week-old issue? Check before it ages out.
35
+ - `logs` is also a queryable `admin-data` entity, so pipelines and agents can read the same rows.
36
+ - The Observability dashboard and Security page both read this table (`threshold.breached` events, security signals).
37
+
38
+ ## Minimal configuration
39
+
40
+ Nothing to configure on the page itself. To see useful data, ensure the account's `system_settings.logging.levels` includes the level you need (e.g. `errors`), then filter:
41
+
42
+ ```
43
+ Level = error · From = <incident date> · Trace ID = <trace from a failed request>
44
+ ```
45
+
46
+ ## Full configuration
47
+
48
+ Combine all filters for a forensic query — e.g. every log row for one record by one person in a window:
49
+
50
+ ```
51
+ query = "ticket"
52
+ target_type = "items" · source_id = "<record uuid>"
53
+ actor_id = "<person uuid>" · trace_id = "<trace uuid>"
54
+ date_from = 2026-10-01 · date_to = 2026-10-30
55
+ ```
56
+
57
+ API equivalents: `/api/logs?action=account` (paged rows), `action=stats`, plus `target`, `person`, `search`, `cleanup` actions server-side.
58
+
59
+ ## Example
60
+
61
+ A user reports a failed save at 14:03. Open Logs, set From to that day, paste the `trace_id` from the error toast into Trace ID — the grid now shows the request's full span tree (`api.request` → `db.update` → `trigger.fired`), and the red `error` row's expanded `details` names the failing stage.
62
+
63
+ ## Core files
64
+
65
+ - `.framework/src/pages/admin/LogsPage.tsx` — this page
66
+ - `.framework/functions/logs.ts` — API (`account`, `target`, `person`, `stats`, `search`, `cleanup` actions)
67
+ - `.framework/functions/_shared/logging.ts` — `emitLog`, level resolution from `system_settings`
68
+ - `.framework/functions/_shared/audit.ts` / `.framework/functions/_shared/tracing.ts` — `emitAudit`/`emitSpan` writers, W3C trace context
69
+ - `.framework/functions/system-cron.ts` — daily `cleanup_old_logs` at 00:00 UTC
70
+ - Table: `public.logs`
71
+
72
+ ## Agent notes
73
+
74
+ - Empty page with active traffic almost always means log **levels** filter writes, not that nothing happened — check `system_settings.logging` first.
75
+ - `trace_id` is the fastest debugging primitive: every function request shares one, so one click reconstructs the whole call including trigger dispatch.
76
+ - System admins query across accounts via `adminDb`; everyone else sees only their account's rows.
77
+ - Cleanup is destructive and daily — export anything worth keeping before the 30-day default window closes.
@@ -0,0 +1,77 @@
1
+ ---
2
+ title: Notifications
3
+ audience: both
4
+ kind: entity
5
+ verified_against: b3b3ae0
6
+ verified_on: 2026-11-01
7
+ source_files:
8
+ - .framework/migrations/050_notifications.sql
9
+ - .framework/functions/_shared/notify.ts
10
+ - .framework/functions/_shared/pipeline-runner.ts
11
+ - .framework/functions/_shared/agent-runner.ts
12
+ ---
13
+
14
+ # Notifications
15
+
16
+ ## What this is for
17
+
18
+ A **notification** is an in-app message to a specific person — "a pipeline
19
+ wants your attention on this record." `public.notifications` (migration 050)
20
+ is written by pipeline `send_notification` stages and the agent-runner's
21
+ notification action, and read by the signed-in recipient. It is the
22
+ *inbound* counterpart to [Deliveries](deliveries.md), which tracks outbound
23
+ webhook/integration sends.
24
+
25
+ ## Fields and settings
26
+
27
+ | Column | Notes |
28
+ |---|---|
29
+ | `person_id` | required — the recipient (`people.id`). RLS scopes reads to `person_id = current_actor_id()`; users see only their own. |
30
+ | `account_id` | required — tenant scope; service role writes across accounts. |
31
+ | `source_type` / `source_id` | what produced it — default `'pipeline_execution'`; `source_id` is a text request/execution id (not always a uuid). |
32
+ | `target_type` / `target_id` | the record the notification concerns — the deep link. |
33
+ | `message` | required text body. |
34
+ | `data` | jsonb — arbitrary payload (e.g. rendered title, action hints). |
35
+ | `is_read`, `read_at` | read state; indexed `(account_id, person_id, is_read, created_at DESC)` for the unread inbox query. |
36
+
37
+ **Recipient resolution**
38
+
39
+ Pipeline/agent stages accept recipients as person UUIDs or `role:<slug>`
40
+ entries. `resolveNotificationRecipients`
41
+ (`.framework/functions/_shared/notify.ts`) expands `role:slug` → all
42
+ `people.id` in the account holding that role; unknown entries warn and are
43
+ skipped. A role matching zero people produces a valid empty insert — not an
44
+ error.
45
+
46
+ ## Minimal configuration
47
+
48
+ Written by the platform — a valid row needs `account_id`, `person_id`,
49
+ `message` (from the stage's recipients + message config).
50
+
51
+ ## Full configuration
52
+
53
+ Adds `source_type`/`source_id` attribution, `target_type`/`target_id`
54
+ deep-linking, and a `data` payload.
55
+
56
+ ## Example
57
+
58
+ A pipeline `send_notification` stage with `recipients: ["role:support_admin"]`
59
+ inserts one row per support_admin in the account; each sees it in their
60
+ inbox, scoped to their `person_id` by RLS.
61
+
62
+ ## Core files
63
+
64
+ - `.framework/migrations/050_notifications.sql` — table, indexes, RLS
65
+ - `.framework/functions/_shared/notify.ts` — `role:` → `person_id` resolver
66
+ - `.framework/functions/_shared/pipeline-runner.ts` — `send_notification` stage
67
+ - `.framework/functions/_shared/agent-runner.ts` — agent notification action
68
+
69
+ ## Agent notes
70
+
71
+ - Never write literal `role:*` strings into `person_id` — it's a uuid
72
+ column; only resolved `people.id` values may be inserted. Both writers
73
+ share the resolver — use it.
74
+ - `notifications` ≠ `deliveries`: notifications are in-app inbox rows;
75
+ deliveries are outbound webhook/integration attempts.
76
+ - RLS allows `UPDATE` where `person_id = current_actor_id()` — recipients
77
+ can mark their own rows read; they cannot read each other's.
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Observability Dashboard
3
+ audience: both
4
+ kind: entity
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/src/pages/admin/ObservabilityDashboard.tsx
9
+ - .framework/functions/observability.ts
10
+ - .framework/functions/logs.ts
11
+ - .framework/functions/_shared/logging.ts
12
+ ---
13
+
14
+ ## What this is for
15
+
16
+ The **Observability Dashboard** (`/spine-framework/admin/observability`, also `/observability/dashboard`) is the account's health console: event volume, error rate, latency percentiles, per-pipeline run stats, top actors, and recent threshold-alert breaches — all computed from the `logs` table and refreshed on an interval.
17
+
18
+ ## Fields and settings
19
+
20
+ - **Time range** — Last Hour / Last 24 Hours / Last 7 Days (`from`/`to` sent to every query; the volume chart buckets by minute/hour/day respectively).
21
+ - **Refresh interval** — auto-refetch every 10s / 30s / 1m, plus a manual Refresh Now button.
22
+ - **Stats cards** — Total Events, Error Rate (%), P95 Latency (ms, red above 2000ms), Pipelines with runs.
23
+ - **Charts** — Event Volume line chart (bucketed counts), error rate, latency percentiles (p50/p95/p99), per-pipeline success/failure/avg-duration, Top Actors (limit 5).
24
+ - **Recent alerts** — last 5 `threshold.breached` log events in the window (metric, threshold, actual value, time).
25
+
26
+ **Downstream effects**
27
+
28
+ - Everything derives from `public.logs` rows written by `emitLog`/`emitAudit`/`emitSpan` — if log levels drop a category (`system_settings.logging.levels`), it disappears from these charts too.
29
+ - Queries are account-scoped for normal users; `system_admin` principals get cross-account reads (`adminDb`).
30
+ - The metrics here are exactly what threshold alerts compare against (`error_rate`, `latency_percentiles`, `pipeline_stats` actions).
31
+ - This page is read-only — it writes nothing.
32
+
33
+ ## Minimal configuration
34
+
35
+ Open the page — defaults (24h range, 30s refresh) are sane for monitoring. There is nothing to configure.
36
+
37
+ ## Full configuration
38
+
39
+ The backing API exposes more than the charts use:
40
+
41
+ - `GET /api/observability?action=event_volume&from=&to=&bucket=minute|hour|day`
42
+ - `action=error_rate` · `action=latency_percentiles` · `action=pipeline_stats` · `action=top_actors&limit=` · `action=ai_support_metrics` · `action=cleanup` (POST)
43
+
44
+ ## Example
45
+
46
+ After deploying a new pipeline, set the range to Last Hour and refresh to 10s: Event Volume climbs with each run, the pipeline stats panel shows success vs failure counts and average duration, and a spike in the error-rate card correlates to the `error`-level rows you can drill into under Logs.
47
+
48
+ ## Core files
49
+
50
+ - `.framework/src/pages/admin/ObservabilityDashboard.tsx` — this page (recharts)
51
+ - `.framework/functions/observability.ts` — metrics API (all `action=` queries above)
52
+ - `.framework/functions/logs.ts` — the `threshold.breached` alert feed (`action=account&event=`)
53
+ - `.framework/functions/_shared/logging.ts` — the emit path and level gating that decides what reaches `logs`
54
+ - Table: `public.logs` (source of all charts)
55
+
56
+ ## Agent notes
57
+
58
+ - Flat charts with healthy traffic = log-level filtering, not broken metrics — the dashboard can only chart what `system_settings.logging.levels` allowed to be written.
59
+ - `system_admin` sees cross-account aggregates here; account members see only their own account.
60
+ - The 10s refresh is client-side polling — each tick re-runs all five metric queries; don't leave it open on a metered connection.
61
+ - Breach alerts shown here are read from `logs`, not from the alert records — see Threshold Alerts for the rules themselves.
@@ -0,0 +1,115 @@
1
+ ---
2
+ title: Netlify Deployment
3
+ audience: both
4
+ kind: reference
5
+ verified_against: e13127d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - netlify.toml
9
+ - .framework/public/_redirects
10
+ - scripts/assemble.sh
11
+ - scripts/assemble-frontend.sh
12
+ - scripts/assemble-functions.sh
13
+ - config/vite.config.ts
14
+ - .env.example
15
+ - .framework/functions/system.ts
16
+ ---
17
+
18
+ # Netlify Deployment
19
+
20
+ Spine deploys as a single Netlify site: a Vite-built SPA in `dist/` plus a
21
+ flat directory of functions in `.assembled/netlify/functions`, backed by a
22
+ Supabase (Postgres) project. Both halves are produced by the same build
23
+ command — there is no separate function deploy step.
24
+
25
+ ## `netlify.toml` anatomy
26
+
27
+ The root `netlify.toml` is partly framework-owned (regenerated on
28
+ `npx spine-framework upgrade`, preserving `[functions."custom_*"]` sections):
29
+
30
+ | Block | Contents |
31
+ |---|---|
32
+ | `[build]` | `command = "npm run assemble && npm run build"`, `publish = "dist"`, `functions = ".assembled/netlify/functions"` |
33
+ | `[build.environment]` | `SECRETS_SCAN_OMIT_KEYS` whitelists the intentionally-public vars (`VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY`, `APP_BASE_URL`, `SITE_URL`, …) so Netlify's secrets scanner does not flag them; `SECRETS_SCAN_OMIT_PATHS` covers `.framework/.xenv*` |
34
+ | `[functions]` | `directory = ".assembled/netlify/functions"`, `included_files` for `_shared/**`, `node_bundler = "esbuild"`, `external_node_modules = ["typescript"]` (the esbuild printer panic workaround — typescript.js ships unbundled) |
35
+ | `[dev]` | `netlify dev` runs `scripts/netlify-dev-wrapper.sh`, site on `8888`, Vite `targetPort` `3001`, `startTimeout 300` |
36
+ | `[functions."<name>"]` | per-function config: `trigger-scheduler` gets `schedule = "* * * * *"`; `cil-ingest`, `cil-embeddings`, `cil-callmap`, `cil-agent`, `ai-agents`, `kb` get `timeout` overrides |
37
+ | `[[redirects]]` | `/* → /index.html` with status `200` (SPA fallback) |
38
+ | `[[headers]]` | `X-Frame-Options DENY`, `nosniff`, HSTS, `Referrer-Policy`, `Permissions-Policy`, and a CSP that allows `*.supabase.co` (https+wss) and `challenges.cloudflare.com` (Turnstile) |
39
+
40
+ Dispatched trigger pipelines run as Netlify **background functions**
41
+ (`pipeline-runner-background`): the dispatcher gets a `202` immediately and
42
+ each run gets the fixed 15-minute background budget — which is why no
43
+ `timeout` entry exists for it.
44
+
45
+ ## How `.assembled/` is produced
46
+
47
+ `npm run assemble` (`scripts/assemble.sh`) runs before every dev start
48
+ (`predev:netlify`) and every build (`prebuild`). It wipes stale `dist/`,
49
+ then:
50
+
51
+ 1. `scripts/assemble-functions.sh` flattens `.framework/functions` plus
52
+ `custom/functions` and `custom/apps/*/functions` into
53
+ `.assembled/netlify/functions`. Basename collisions are a **hard error**
54
+ naming both sources — Netlify needs one flat dir, so last-wins overwrite
55
+ is forbidden. `_quarantine` and `*-test.ts`/`*.test.ts` are excluded.
56
+ 2. `scripts/assemble-frontend.sh` copies `.framework/src` as the base layer,
57
+ each `custom/apps/<slug>` verbatim to `.assembled/src/<slug>/`, fixes up
58
+ `index.html`, merges `.framework/public` + app `public/` dirs into the
59
+ project `public/` (same-path collisions are a hard error), copies
60
+ `_redirects` into `.assembled/src/` for `netlify dev`, and stages the
61
+ project `spine.config.json` into `public/`.
62
+
63
+ `config/vite.config.ts` then builds with `root: .assembled/src`,
64
+ `publicDir: public/`, `build.outDir: dist/` — matching `publish = "dist"`.
65
+ Never edit `.assembled/`; it is regenerated freely.
66
+
67
+ ## The `/api/*` URL space
68
+
69
+ Requests to `/api/*` are rewritten to `/.netlify/functions/:splat`:
70
+
71
+ - **Production:** the published `_redirects` file — sourced from
72
+ `.framework/public/_redirects`, merged into `public/` at assemble time —
73
+ carries `/api/* → /.netlify/functions/:splat 200`, plus
74
+ `/spine.config.json` passthrough and the `/* → /index.html` fallback.
75
+ - **Dev:** the Vite proxy in `config/vite.config.ts` maps `/api/*` to
76
+ `localhost:8888` with the same rewrite.
77
+
78
+ Because the SPA fallback is `/* → /index.html 200`, **any unmatched URL
79
+ returns HTTP 200 with HTML** — including typos under `/api/`. A probe that
80
+ gets HTML instead of JSON is hitting the SPA fallback, not a function.
81
+
82
+ ## Environment variables in production
83
+
84
+ Set these in the Netlify site environment (not in `netlify.toml`).
85
+ The full annotated list is [Environment Variables](../reference/env-vars.md);
86
+
87
+ | Variable | Needed for |
88
+ |---|---|
89
+ | `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` | browser bundle (public by design) |
90
+ | `SUPABASE_URL`, `SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY` | all functions — service-role key is server-only, never `VITE_`-prefixed |
91
+ | `INTERNAL_INVOKE_SECRET` | trigger-dispatched pipelines — unset means `queued` rows that never run |
92
+ | `APP_BASE_URL` | invite links, auth redirects, `base_url` allowlist |
93
+ | `SCHEDULER_API_KEY` | key-gated `system-cron`/`trigger-scheduler` invocation |
94
+ | `SITE_URL` | CORS `Access-Control-Allow-Origin`; falls back to Netlify's auto-set `URL` |
95
+ | `RESEND_API_KEY`, `EMAIL_FROM` | outbound email (invites, notification stages) |
96
+ | `OPENAI_API_KEY` | AI stage types, agents, embeddings |
97
+ | `NETLIFY_ACCESS_TOKEN`, `NETLIFY_SITE_ID` | optional — push banned IPs to the edge firewall (security function skips silently without them) |
98
+
99
+ `SUPABASE_DB_PASSWORD` is **not** a function env var — it is used locally by
100
+ `npx spine-framework migrate` to connect to Postgres directly.
101
+
102
+ ## Deploy checklist
103
+
104
+ - [ ] Supabase project exists; `SUPABASE_*` + `VITE_SUPABASE_*` vars set in Netlify.
105
+ - [ ] `INTERNAL_INVOKE_SECRET` generated (`openssl rand -hex 32`) if triggers are used; `APP_BASE_URL`/`SITE_URL` set to the production origin.
106
+ - [ ] Migrations applied: `npx spine-framework migrate` against the production DB (see [Migrations](migrations.md)).
107
+ - [ ] Deploy via git push or `netlify deploy --prod` — the build command runs `assemble` then `vite build` automatically.
108
+ - [ ] Post-deploy smoke: `/api/system?action=health` and `?action=manifest` answer; first registration grants `system_admin` (see [Install and first run](../guide/01-install-and-first-run.md)).
109
+ - [ ] If timers/triggers are used: `trigger-scheduler` ticks appear in function logs within a minute; a test record write produces a `trigger.fired` log row.
110
+
111
+ ## Related
112
+
113
+ - [Migrations](migrations.md) · [Upgrade](upgrade.md) · [Troubleshooting](troubleshooting.md)
114
+ - [Environment Variables](../reference/env-vars.md) · [CLI Reference](../reference/cli.md)
115
+ - [Anatomy of an installed project](../guide/02-project-map.md) — sealed vs customer trees