This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/CHANGELOG.md
Jeffrey Smith dba718b914
Some checks failed
CI/CD / detect-changes (push) Successful in 21s
CI/CD / test-frontend (push) Has been skipped
CI/CD / test-go-pg (push) Failing after 2m24s
CI/CD / test-sqlite (push) Successful in 2m54s
CI/CD / build-and-deploy (push) Has been skipped
Feat v0.3.3 public entry background jobs (#17)
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
2026-03-27 23:07:55 +00:00

22 KiB
Raw Blame History

Changelog

All notable changes to Switchboard Core are documented here.

v0.3.3 — Public Entry + Background Jobs

Added

  • Public workflow entry: Unauthenticated routes for anonymous workflow participation. POST /api/v1/public/workflows/:id/start creates an instance with started_by = "public:<uuid>" and returns an entry token. GET .../resume/:token and POST .../advance/:token allow continuation. Only stages with audience = "public" can be advanced anonymously.
  • SLA scanner: Background goroutine (5-minute interval) checks active instances against per-stage sla_seconds. Fires workflow.sla_breach event on first breach, marks sla_breached: true in instance metadata (idempotent).
  • Staleness sweep: New staleness_timeout_hours column on workflows. Scanner marks instances as stale when updated_at exceeds the threshold, cancels open assignments, fires workflow.stale event.
  • New store methods: ListActiveInstances(), MarkInstanceStale().
  • New events: workflow.sla_breach, workflow.stale.
  • 3 new store tests: MarkStale, ListActive, StalenessTimeoutHours round-trip.

v0.3.0 — Workflow Schema Redesign

Changed

  • workflow_stages schema modernized: Dropped chat-era columns (persona_id, history_mode). Renamed transition_rulesstage_config. Updated stage_mode CHECK from (form_only, form_chat, review, custom) to (form, review, delegated, automated).
  • New stage fields: Added audience (team | public | system), stage_type (simple | dynamic | automated), starlark_hook (package_id:entry_point), and branch_rules (JSONB array of routing conditions).
  • Routing engine: ResolveNextStage now reads branch_rules (flat array) instead of transition_rules.conditions (nested object). Cleaner separation between routing rules and stage config.
  • Hook handler: FireOnAdvanceHook reads from stage_config instead of transition_rules. Renamed channelID parameter to instanceID.
  • Stage CRUD validation: New fields validated on create/update. delegated mode requires surface_pkg_id. dynamic/automated stage_type requires starlark_hook.
  • Package export/import: Updated to use new field names. Workflow packages now include audience, stage_type, starlark_hook, branch_rules, stage_config.
  • Starlark workflow module: Stage dicts now include audience and stage_type keys. Removed history_mode and persona_id.
  • Frontend stage editor: Both admin and team-admin surfaces updated with new mode values, audience selector, stage type selector, and conditional Starlark hook input. Fixed pre-existing bug in admin workflows.js where STAGE_MODES still contained chat_only.

Removed

  • persona_id column from workflow_stages (personas are extension concerns)
  • history_mode column from workflow_stages (chat-era context management)
  • StageModeCustom, StageModeFormOnly, StageModeFormChat Go constants

v0.2.9 — Builtin Extension Retirement

Changed

  • 6 builtin extensions → standard packages: csv-table, diff-viewer, js-sandbox, katex-renderer, mermaid-renderer, and regex-tester moved from extensions/builtin/ to packages/ with standard js/ layout. Each manifest now declares "requires": ["chat"] and "type": "extension". Built via build.sh like all other packages — no auto-install.

Removed

  • SeedBuiltinPackages seeder: Deleted seed_packages.go (function, builtinManifest struct, buildFullManifest helper) and the startup call in main.go. Extensions are no longer auto-seeded into the DB.
  • extensions/builtin/ directory: Removed from repo and Dockerfile COPY.
  • Seed tests: Removed 8 TestSeed_* functions and makeSeedDir helper from extension_test.go (~220 lines).
  • Stale comments: Removed SeedBuiltinPackages references from package_iface.go and trigger_sync.go.

v0.2.8 — Team Admin Settings Audit (Pass 1)

Removed

  • Dead HasPrivateProviderRequirement: Store method checked team settings for require_private_providers (BYOK vestige). Removed from interface, PostgreSQL, and SQLite implementations. No callers existed.
  • Dead UserRole field on TeamMember: Joined users.role column (deprecated in v0.2.0 RBAC migration). Removed from model, ListMembers and GetMember queries in both stores. Frontend never consumed it.
  • Dead allow_team_providers policy: Removed from PolicyDefaults, both test seed data blocks, and ICD test assertions. No handler or UI read it.
  • Dead personas in workflow stage UI: Removed sw.api.teams.personas() call (endpoint doesn't exist), personas state, persona dropdown in StageForm, and persona badge in stage list.
  • Dead history_mode in stage UI: Removed history mode selector and state from StageForm. Backend column retained for v0.3.x schema migration.
  • Dead ICD tests: Removed assertions for /teams/:teamId/personas, /teams/:teamId/providers, and /teams/:teamId/models — endpoints were removed in Phase 0 fork.
  • Stale chat_only stage mode: Frontend STAGE_MODES updated from ['chat_only', 'form_only', 'form_chat', 'review'] to ['form_only', 'form_chat', 'review', 'custom'] matching the backend CHECK constraint.
  • Stale comments: Removed references to deleted team_providers.go, personas.go, and apiconfigs.go files.

v0.2.7 — User Settings Audit

Changed

  • localStorage namespace: Renamed cs-appearance key to sb-appearance across appearance settings, base template, and workflow template. One-time migration preserves existing user preferences.
  • Policy-gating tests: Replaced stale allow_user_byok / allow_user_personas assertions with allow_registration check (the only policy still in admin UI).

Removed

  • Dead BYOK nav section in user settings: empty BYOK_ITEMS array, byokEnabled state, "BYOK Enabled" footer badge, and the nav group that rendered an empty section.
  • Dead personas gate: personasEnabled state and .filter() on NAV_ITEMS for a gate property no items have. auth.permissions.changed listener removed (existed solely for BYOK + personas state).
  • Dead Message Font Size: Slider, msgFont state, and --msg-font CSS variable application from appearance section and base template.
  • Dead policy defaults: allow_user_byok and allow_user_personas removed from PolicyDefaults, profile bootstrap, permissions handler, and PublicSettings. Test seed data cleaned.

v0.2.6 — Admin Settings Audit

Changed

  • Roadmap reorder: Extension Lifecycle moved from v0.2.6 to v0.3.x (Workflows series). Settings audit milestones renumbered: v0.2.7→v0.2.6, v0.2.8→v0.2.7, v0.2.9→v0.2.8. Added v0.2.9 for builtin extension retirement (chat-centric extensions dormant until chat surface ships).

Removed

  • Dead admin section categories in sectionCategory(): AI (providers, models, personas, roles, knowledgeBases, memory), routing (health, routing, capabilities), and channels. Default category changed from ai to system.
  • Dead PublicSettings fields: system_prompt/has_admin_prompt, retention_ttl_days, paste_to_file_chars, allow_user_personas policy — all chat-era with no frontend consumers.
  • Dead PolicyDefaults: allow_raw_model_access, default_model.
  • Dead policy lookups: allow_raw_model_access and kb_direct_access from profile bootstrap and permissions handlers.
  • Dead test seed data: model_roles global setting, allow_raw_model_access policy from test helper.
  • Dead CORE_IDS entry: Removed chat from packages admin page.

[Unreleased] — v0.2.5

Added

  • Welcome surface: New core surface shown as fallback. Detects whether extensions exist (shows "Set Default Surface") vs truly empty install (shows "Go to Packages"). Topbar + UserMenu included.
  • User default surface: Users can set a personal landing page in Settings > General, overriding the admin-configured global default.
  • UserMenu in admin topbar: Replaced Back button with UserMenu, providing consistent surface navigation and eliminating infinite loops.
  • Package manifest icons: Added emoji icons to hello-dashboard, icd-test-runner, sdk-test-runner, and team-activity-log manifests.
  • PoC documentation: README.md for tasks and schedules packages documenting Proof of Concept status and graduation criteria.

Changed

  • Default surface resolution: Priority chain is now user preference → global config → first extension → /welcome. User preference read from JWT cookie on unauthenticated / route. Correctly resolves type: "full" extension packages (not just type: "surface").
  • User settings General section: Replaced dead chat fields (Default Model, System Prompt, Max Tokens, Temperature, Show Thinking) with a Default Surface dropdown.
  • Admin settings: Removed dead chat sections (System Prompt, Default Model, Policies, Web Search, Auto-Compaction, Memory Extraction).
  • Roadmap restructured: Workflows → v0.3.x (includes team roles), Notes → v0.4.0, MVP → v0.5.0. Added settings audit milestones (v0.2.7 admin, v0.2.8 user, v0.2.9 team-admin pass 1).
  • Updated bus doc examples and test labels from chat.* to workflow.*.
  • Renamed channel- prefixed test paths to test- in storage tests.
  • Updated doc comments throughout to remove references to gutted surfaces.

Removed

  • ~500 lines of dead CSS: Orphaned classes for gutted chat, channel, project, notes, editor-chat, sidebar, and router-picker features from layout.css and surfaces.css.
  • Dead Go types: Grant struct (persona-era), CompositeModelKey func, comment-only stubs for NoteGraph, ProjectChannel, etc.
  • Dead event code: chat.typing.* / channel.typing.* condition in WS subscriber, empty Chat/Channel event route table sections.
  • Dead test helpers: seed_helpers.go (SeedTestMessage, SeedTestMessages, SeedTestCursor — all callerless).
  • Stale template refs: CSS link tags for non-existent sw-chat-pane.css, sw-notes-pane.css, chat.css. Orphaned chat-pane.html component.
  • Vestigial guards: "chat" surface checks in IsSurfaceEnabled() and DisablePackage() (chat is no longer a surface).
  • Dead settings UI: Chat defaults from user settings, System Prompt / Default Model / Policies / Web Search / Compaction / Memory from admin.
  • Unused fmt.Sprintf references in team stores.

[Unreleased] — v0.2.4

Added

  • sw.shell.Topbar: Standard navigation bar component for surfaces. Composes title + extension slot + NotificationBell + UserMenu into a consistent 44px bar. Surfaces use <${sw.shell.Topbar} title="..."> with children rendered in the extension slot. Graceful fallback if unavailable.
  • Schedules surface (packages/schedules/): New package wrapping the kernel /api/v1/schedules API. Table view with cron badge + human-readable preview, next fire time, enable/disable toggle, manual run, and execution logs panel. Create/edit dialog with live cron-to-english preview.
  • Manifest icon field: Packages can declare an emoji icon in manifest.json ("icon": "⏰"). Served via the surfaces API icon field. Rendered in the UserMenu flyout next to each surface name.

Changed

  • UserMenu: Surface list now driven entirely by the /api/v1/surfaces API. Removed hardcoded Chat, Notes, Projects links (gutted in Phase 0). Core surfaces (Admin, Settings, Team Admin, Workflow) filtered from the API list and handled as dedicated menu items with RBAC gating.
  • Tasks surface: Replaced custom .tasks-header with sw.shell.Topbar. View tabs and create button rendered in the extension slot.

Fixed

  • sw.isAdmin RBAC regression: isAdmin() in can.js was checking the deprecated user.role === 'admin' field instead of the v0.2.0 RBAC grant surface.admin.access. Admin menu item and admin-gated features now appear correctly for users in the Admins group.

[Unreleased] — v0.2.2

Added

  • Event bus subscriptions: Extensions declare event triggers in manifest ("triggers": [{"type": "event", "pattern": "workflow.completed", ...}]). Wired via bus.Subscribe() on startup. Handlers fire asynchronously.
  • Webhook triggers: Inbound HTTP at /api/v1/hooks/:package_id/:slug. HMAC-SHA256 verification via X-Switchboard-Signature header. Synchronous Starlark handler can return custom HTTP status and body.
  • Scheduled tasks: User-created cron-scheduled Starlark scripts with restricted sandbox (no raw HTTP, no DB table creation, connections-only outbound). Runs as creator identity with RBAC scoping. Admin-created tasks can opt into system context. Creator deactivation auto-pauses schedule.
  • Schedule templates: Extensions ship pre-built schedule templates in manifest (schedule_templates array) with configurable params and default cron expressions.
  • triggers.register extension permission — required for event/webhook triggers
  • triggers table — extension-declared event and webhook trigger definitions
  • scheduled_tasks table — user-created cron tasks with script, template, and identity fields
  • trigger_logs table — unified execution audit log for both tiers
  • TriggerStore + ScheduledTaskStore interfaces (postgres + sqlite)
  • Trigger engine (server/triggers/) — orchestrates event subscriptions, webhook resolution, and cron scheduling via robfig/cron/v3
  • SyncManifestTriggers() — declarative sync of event/webhook triggers from manifest. Hooked into seed, admin install, and package install flows.
  • Admin trigger API: GET/PUT/DELETE /admin/triggers, /admin/triggers/:id/logs, /admin/packages/:id/triggers
  • Admin schedule API: GET /admin/schedules, enable/disable/delete
  • User schedule API: full CRUD at /api/v1/schedules, manual run, execution logs
  • trigger.fired and trigger.error event bus labels (DirLocal) for observability
  • OpenAPI spec: Trigger, ScheduledTask, TriggerLog schemas + all new endpoints

[v0.2.1] — 2026-03-26

Added

  • Default surface routing: / redirects to configurable default surface. Fallback chain: configured default → first enabled extension surface → /admin. First installed extension surface auto-becomes default. Admin can change via Settings > Default Surface dropdown.
  • default_surface global config key (JSON {"id": "slug"})
  • Admin settings UI: Default Surface dropdown (extension surfaces only)
  • ICD (API contract): Full OpenAPI 3.0.3 spec covering all 160 kernel endpoints. 22 tag groups (System, Auth, Profile, Workflows, Packages, Connections, Teams, Groups, Extensions, and Admin subsections). Reusable component schemas for User, Team, Group, Workflow, Package, Extension, etc. Served at /api/docs (Swagger UI) and /api/docs/openapi.yaml.

Changed

  • disabledRedirect() now redirects to /admin instead of / to prevent redirect loops when the default surface is disabled
  • Disabled extension surfaces (/s/:slug) redirect to /admin instead of /

Fixed

  • Gin route param conflict causing backend startup hang: team-scoped package settings routes used :pkgId while sibling routes used :id. Gin's radix tree entered an infinite loop on the conflicting param names. Unified to :id across all /teams/:teamId/packages/ routes.
  • Docker entrypoint: increased health check timeout (10s → 60s), added stale process cleanup and crash detection to prevent zombie backends on restart

[v0.2.0] — 2026-03-26

Added

  • Full RBAC: all authorization flows through group membership and permission grants. No magic roles, no implicit group membership, no special-casing.
  • surface.admin.access permission — any group can grant admin panel access
  • Admins system group seeded with all platform permissions
  • Everyone system group — all users explicitly added on creation
  • EnsureEveryoneGroup(), AddToAdminsGroup(), RemoveFromAdminsGroup() helpers
  • SeedAdminsGroupMember(), SeedEveryoneGroupMember() test helpers
  • System groups re-seeded after TruncateAll in test helper
  • OIDC isIdPAdmin() — maps IdP role claims to Admins group membership
  • Settings cascade: three-tier resolution (global → team → user) with user_overridable flag per manifest setting key. Admins can lock settings that team admins and users cannot override.
  • package_team_settings table for team-scoped package setting overrides
  • Team admin API: GET/PUT/DELETE /api/v1/teams/:teamId/packages/:pkgId/settings
  • RunContext.TeamID for team-aware Starlark settings resolution
  • store.ResolveSettings() / store.FilterOverridableKeys() pure functions
  • store.ParseSettingsSchema() extracts user_overridable from manifests

Changed

  • RequireAdmin() / RequireAdminPage() check surface.admin.access grant
  • RequirePermission() no longer bypasses for admin role
  • ResolvePermissions() unions explicit group memberships only (no implicit Everyone)
  • All user creation paths (builtin, OIDC, mTLS, admin, bootstrap, seed) add to Everyone group. Admin users added to Admins group.
  • JWT claims no longer include role field
  • Login response no longer includes role in user object
  • Profile endpoint no longer returns role
  • Profile bootstrap resolves permissions from groups (no admin shortcut)
  • Middleware auth cache tracks isActive only (no role)
  • Admin create user accepts is_admin bool (not role string)
  • Admin update role endpoint accepts is_admin bool, manages Admins group directly
  • Demotion/deletion safeguards check Admins group member count
  • Notifications RoleFallbackHandler queries Admins group members
  • OIDC syncs Admins group on login (no role column writes)
  • Kernel permissions: 6 → 7 (added surface.admin.access)
  • Admin users UI: role dropdown removed, admin managed through groups
  • Starlark settings.get() uses cascade resolver instead of naive merge
  • User settings save (POST /extensions/:id/settings) strips non-overridable keys

Removed

  • users.role column — dropped from schema, model, JWT, all handlers
  • UserRoleAdmin, UserRoleUser constants
  • CountByRole() store method
  • DefaultRole config for OIDC and mTLS providers
  • SyncAdminsGroupMembership() (replaced by AddToAdminsGroup/RemoveFromAdminsGroup)
  • OIDC resolveRole() (replaced by isIdPAdmin())
  • Token budgets from groups: columns, ResolveTokenBudget(), all store/handler/UI
  • Allowed models from groups: column, ResolveModelAllowlist(), UI
  • Admin groups UI: Token Budgets section, Allowed Models section

Migration notes

  • 001_core.sql (both dialects): removed role column from users table
  • 002_teams.sql (both dialects): added Admins group seed, removed token_budget_daily, token_budget_monthly, allowed_models columns
  • No new migration files — edited in place per pre-MVP policy

[v0.1.0] — 2026-03-26

Forked from chat-switchboard v0.38.5. Gutted to a pure extension platform.

Removed

  • AI/Chat system: providers, model catalog, routing policies, personas, channels, messages, completion streaming, tool loop, compaction, memory, knowledge bases, notes, workspaces, projects, folders, files, export/import
  • Task scheduler: entire scheduler package, task store, task handlers. Tasks will be rebuilt as a Starlark extension with three trigger primitives (time, webhook, event)
  • Session system: channel-based anonymous sessions. Workflow instances will get new storage in v0.2.0
  • Health accumulator: provider health windows, tool health tracking. Replaced with kernel-only Prune (ws_tickets, rate_limit_counters, presence)
  • 15 Go packages: tools, compaction, extraction, roles, mentions, notelinks, export, memory, knowledge, providers, routing, capabilities, filters, retention, workspace
  • 29 handler files, 6 test files, ~44K lines total

Fixed

  • CI deploy: k8s resource quantity vars (BE_MEMORY_REQUESTMEMORY_REQUEST) aligned with CI workflow outputs — envsubst was producing empty strings
  • CI deploy: image var (BE_IMAGEIMAGE) — caused InvalidImageName in pods
  • CI rollout: deployment name (switchboardswitchboard-be) — rollout verification was looking for wrong deployment name
  • Nginx BASE_PATH: regex cache-header locations intercepted static asset requests before alias could strip the sub-path prefix — moved inside alias block
  • Post-login blank page: dead Go template references (surface-chat, surface-notes, surface-projects) caused html/template to silently produce Content-Length: 0 responses
  • Login branding: "Chat Switchboard" → "Switchboard Core", updated tagline and feature pills to reflect platform pivot

Changed

  • Module renamed: chat-switchboardswitchboard-core
  • VERSION: 0.1.0
  • Default DB name: switchboard_core
  • Fresh migrations: 9 files × 2 dialects (postgres + sqlite), 27 tables
  • Store interfaces: 40 → 20 (13 in interfaces.go + 7 in separate iface files)
  • Stage modes: chat_only removed, custom added
  • Task output modes: channel|note|webhooknotification|webhook|log
  • Kernel permissions: 16 → 6 (extension.use, extension.install, workflow.create, workflow.submit, admin.view, token.unlimited)
  • Everyone group seed: ["extension.use","workflow.submit"]
  • Global settings seed: site name "Switchboard Core"
  • Config: removed 7 dropped fields (SessionExpiryDays, WorkflowStaleHours, ProviderAutoDisableThreshold, ExtractionConcurrency, etc.)
  • Health stores rewritten: kernel-only Prune for stale tickets, counters, presence
  • Maintenance goroutine replaces scheduler for background cleanup

Retained

  • Identity & auth (builtin, mTLS, OIDC)
  • Teams, groups, permissions
  • Package system (surfaces, extensions, libraries, workflows)
  • Starlark sandbox with capability-gated modules
  • Extension connections & dependencies
  • Workflow definitions, stages, versions
  • Notifications & preferences
  • Audit log
  • Object storage (PVC, S3)
  • WebSocket hub & presence
  • Multi-replica HA (ws_tickets, rate_limit_counters)
  • Frontend shell (preact+htm, SDK, vendor libs)