mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
refactor(state): consolidate wide rows, plugin index, workspace attestations, and shared auth singletons at schema v13 (#130466)
* refactor(state): make cron and subagent rows JSON-canonical * refactor(state): make gateway origin device tokens canonical at v13 The lazy ensure predates the table joining the canonical schema; at the v13 bump the schema owns creation, so the feature-local DDL, WeakSet dedupe, and lazy-list entry retire. The legacy-file guard the ensure carried stays at each call site. * test: drop obsolete lazy-ensure coverage for origin device tokens The table is canonical at v13; same-version lazy creation no longer exists to protect. Origin CRUD, isolation, and rotation coverage remains in the surviving cases. * refactor(state): fold installed_plugin_index into config_machine_state The singleton index row becomes one JSON value under plugins.installedIndex with its rollback-fencing revision inside the value; reads, CAS restore, and the lease-held write transactions use direct Kysely on config_machine_state so the state_leases assertion stays in-transaction. The v13 migration imports the row and drops the table; the additive workspace_dir entry folds with it. Doctor guidance, docker staging, and the e2e probes name the machine-state row. * refactor(state): merge workspace_attestations into workspace_setup_state One row per workspace now carries both setup milestones and the attestation clock: nullable setup columns represent attestation-only workspaces (replaceWorkspaceAttestation can precede any setup write) and setupExists derives from a non-null version. The bootstrap-hash FK repoints to the merged table; migration receipts keep the historical workspace_attestations discriminator string. The v13 migration grows and rebuilds the table, merges attestation rows (orphans without a path alias drop — their hashes re-derive at the next bootstrap attestation), and the consolidation kind is renamed state-consolidation-v13 to cover the batch. * test(state): cover the workspace merge and consolidation fallout The v12-to-v13 regression seeds merged, attestation-only, and orphan attestation workspaces; the 13-to-12 downgrade fixture recreates workspace_attestations and installed_plugin_index from the folded data; the fold-in migration gates the additive workspace_dir column for pre-additive rows; the workspace merge now triggers on the setup table's own shape so stable-era databases without an attestations table still reshape; the consolidation applied-message covers the batch. * refactor(state): fold shared auth profile singletons into config_machine_state The shared-state auth_profile_stores/auth_profile_state rows (fixed key 'shared') become authProfiles.store/authProfiles.state machine-state values; the agent-DB tables of the same names are untouched. Git-backup redaction moves from table-drop to the authProfiles. secret prefix with seeded-secret absence proof; migration receipts keep the historical table-name discriminators; the shared-auth relocation and receipt verification project the KV cells back to the receipt-era row shapes so persisted digests stay byte-compatible. mcp_oauth_stores stays a table — its multi-key fold is a named follow-up. * test(state): finish shared-auth fold coverage and annotate boundary casts Auth seeders and assertions across the e2e/scripts/secrets suites target the authProfiles machine-state cells; the v12-to-v13 regression proves payload-byte fidelity, non-shared-row drop, and insert-if-absent precedence; the downgrade fixture recreates and repopulates both v12 tables. Boundary type assertions in the plugin-index store carry SAFETY invariants per the ratchet. * chore: shrink assertion-safety baseline for plugin-index store * refactor(doctor): delete the dead onboarding-recommendations migration Its input — the unscoped 'primary' onboarding row — existed only between9a93a52a8aand473962b7de, a two-day beta window; no shipped stable can produce it and the runtime table folded away at v12. The audit backup list keeps recognizing system-agent.jsonl artifacts because beta installs that ran that import may still carry its backups. * docs: sync the 13-to-12 downgrade example with the executable fixture * style: format the synced downgrade example * style: drop unused import and duplicate union constituent * fix(state): keep orphan attestations across the v13 workspace merge The merged workspace_setup_state required a workspace path, but legacy orphan hashed-key attestations never recorded one. workspace_path is now nullable (setup rows still enforce it via CHECK), the v13 migration and the doctor file import keep orphans with a NULL path that heals on the next live access, and the 13-to-12 downgrade keeps attestation-owned hashes. Doctor test seeds move to the folded KV row. * perf(state): retire unused cron indexes * fix(state): preserve v13 migration recovery * fix(state): preserve v12 lazy-table upgrade * docs(state): document v13 auth relocation --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
committed by
GitHub
parent
dff2d26820
commit
1ea2640f54
@@ -203,7 +203,7 @@ without exceptions outside doctor/import/export/debug boundaries.
|
||||
- No active session files.
|
||||
- No fake JSONL test fixtures except doctor legacy migration tests.
|
||||
- No raw SQLite access where Kysely is expected.
|
||||
- No new file-era runtime stores. The current global schema is version `12`, and
|
||||
- No new file-era runtime stores. The current global schema is version `13`, and
|
||||
the current per-agent schema is version `17`; older supported databases move
|
||||
through the bounded forward migrations listed in
|
||||
[Database schemas](/reference/database-schemas).
|
||||
@@ -310,20 +310,19 @@ The branch already has a real shared SQLite base:
|
||||
- Runtime stores derive selected and inserted row types from those generated
|
||||
Kysely `DB` interfaces instead of shadowing SQLite row shapes by hand. Raw SQL
|
||||
remains limited to schema application, pragmas, and migration-only DDL.
|
||||
- The global SQLite schema is at `user_version = 12`. The per-agent schema is at
|
||||
- The global SQLite schema is at `user_version = 13`. The per-agent schema is at
|
||||
version `17`; their openers apply bounded forward migrations from supported
|
||||
older schemas. File-to-database import remains in Doctor code.
|
||||
- Relational ownership is enforced where the ownership boundary is canonical:
|
||||
source migration rows cascade from `migration_runs`, task delivery state
|
||||
cascades from `task_runs`, and transcript identity rows cascade from
|
||||
transcript events.
|
||||
- Current shared tables include `agent_databases`,
|
||||
`auth_profile_stores`, `auth_profile_state`,
|
||||
- Current shared tables include `config_machine_state`, `agent_databases`,
|
||||
`plugin_state_entries`, `plugin_blob_entries`,
|
||||
`skill_uploads`, `capture_sessions`, `capture_events`, `capture_blobs`,
|
||||
`sandbox_registry_entries`, `cron_jobs`,
|
||||
`delivery_queue_entries`,
|
||||
`workspace_setup_state`, `workspace_path_aliases`, `workspace_attestations`,
|
||||
`workspace_setup_state`, `workspace_path_aliases`,
|
||||
`workspace_generated_bootstrap_hashes`, `native_hook_relay_bridges`,
|
||||
`current_conversation_bindings`, `plugin_binding_approvals`,
|
||||
`acp_sessions`, `acp_replay_sessions`,
|
||||
@@ -349,7 +348,7 @@ The branch already has a real shared SQLite base:
|
||||
site.
|
||||
- Global and per-agent databases record a `schema_meta` row with database role,
|
||||
schema version, timestamps, and agent id for agent databases. The global DB
|
||||
currently uses `user_version = 9`; per-agent DBs use version `17`.
|
||||
currently uses `user_version = 13`; per-agent DBs use version `17`.
|
||||
- Per-agent session identity now has a canonical `sessions` root table keyed by
|
||||
`session_id`, with `session_key`, `session_scope`, `account_id`,
|
||||
`primary_conversation_id`, timestamps, display fields, model metadata,
|
||||
@@ -443,8 +442,8 @@ The branch already has a real shared SQLite base:
|
||||
legacy path resolver lives in the doctor migration module.
|
||||
- Secret target metadata now talks about stores instead of pretending every
|
||||
credential target is a config file. `openclaw.json` remains the config store;
|
||||
auth-profile targets use typed SQLite `auth_profile_stores` rows with
|
||||
provider-shaped credentials kept as JSON payloads.
|
||||
shared auth-profile snapshots use the `authProfiles.store` and
|
||||
`authProfiles.state` keys in `config_machine_state`.
|
||||
- Secret audit no longer scans retired per-agent `auth.json` files. Doctor owns
|
||||
warning about, importing, and removing that legacy file.
|
||||
- Legacy auth profile path helpers now live in doctor legacy code. Core auth
|
||||
@@ -465,9 +464,9 @@ The branch already has a real shared SQLite base:
|
||||
define VFS, tool-artifact, or run-artifact tables.
|
||||
- Workspace bootstrap completion, attestation recency, and generated bootstrap
|
||||
hashes now live in typed shared `workspace_setup_state`,
|
||||
`workspace_path_aliases`, `workspace_attestations`, and
|
||||
`workspace_generated_bootstrap_hashes` rows keyed by canonical workspace
|
||||
identity. Persisted lexical and real-path aliases keep vanished-workspace
|
||||
`workspace_path_aliases`, and `workspace_generated_bootstrap_hashes` rows
|
||||
keyed by canonical workspace identity. Attestation timestamps are owned by
|
||||
`workspace_setup_state`. Persisted lexical and real-path aliases keep vanished-workspace
|
||||
protection stable after a configured symlink disappears; repointed aliases
|
||||
fail closed. Runtime no longer reads or writes
|
||||
`openclaw-workspace-state.json`, `.openclaw/workspace-state.json`, state-dir
|
||||
@@ -482,7 +481,7 @@ The branch already has a real shared SQLite base:
|
||||
`device_identities` and `device_auth_tokens` rows. Gateway startup may import
|
||||
a valid retired primary identity under the startup migration lease; invalid
|
||||
canonical identity repair remains Doctor-only. Gateway-origin-scoped tokens
|
||||
use the lazy additive `gateway_origin_device_tokens` table.
|
||||
use the canonical `gateway_origin_device_tokens` table.
|
||||
- GitHub Copilot token exchange cache uses the shared SQLite plugin-state table
|
||||
under `github-copilot/token-cache/default`. It is provider-owned cache state,
|
||||
so it intentionally does not add a host schema table.
|
||||
@@ -1299,10 +1298,10 @@ sessionId})`; create, branch, continue, list, and fork flows live in their
|
||||
- Hermes secret migration plans and applies imported API-key profiles directly
|
||||
into the SQLite auth-profile store. It no longer writes or verifies
|
||||
`auth-profiles.json` as an intermediate target.
|
||||
- User-facing auth docs now describe
|
||||
`state/openclaw.sqlite#table/auth_profile_stores/<agentDir>` instead of
|
||||
telling users to inspect or copy `auth-profiles.json`; legacy OAuth/auth JSON
|
||||
names remain documented only as doctor-import inputs.
|
||||
- User-facing auth docs distinguish shared auth snapshots in
|
||||
`config_machine_state` under `authProfiles.store` and `authProfiles.state`
|
||||
from the per-agent `auth_profile_store` and `auth_profile_state` tables.
|
||||
Legacy OAuth/auth JSON names remain documented only as doctor-import inputs.
|
||||
- MCP OAuth sessions now use versioned `mcp_oauth_stores` rows in shared
|
||||
`state/openclaw.sqlite`. SDK-owned token, client-registration, and discovery
|
||||
objects remain one validated JSON payload so dependency extension fields
|
||||
@@ -1353,9 +1352,9 @@ sessionId})`; create, branch, continue, list, and fork flows live in their
|
||||
state objects rather than file-shaped lockfile/origin abstractions. Doctor
|
||||
imports the legacy sidecars from configured agent workspaces and removes them
|
||||
after a clean import.
|
||||
- The installed plugin index now reads and writes the typed shared SQLite
|
||||
`installed_plugin_index` singleton row instead of `plugins/installs.json`; the
|
||||
legacy JSON file is only a doctor migration input and is removed after import.
|
||||
- The installed plugin index now reads and writes `config_machine_state` under
|
||||
`plugins.installedIndex` instead of `plugins/installs.json`; the legacy JSON
|
||||
file is only a doctor migration input and is removed after import.
|
||||
- The legacy `plugins/installs.json` path helper now lives in doctor legacy
|
||||
code. Runtime plugin-index modules expose only SQLite-backed persistence
|
||||
options, not a JSON file path.
|
||||
@@ -1504,7 +1503,7 @@ agent_databases(agent_id, path, schema_version, last_seen_at, size_bytes)
|
||||
task_runs(...)
|
||||
task_delivery_state(...)
|
||||
flow_runs(...)
|
||||
subagent_runs(run_id, child_session_key, requester_session_key, controller_session_key, created_at, ended_at, cleanup_handled, payload_json)
|
||||
subagent_runs(run_id, child_session_key, controller_session_key, requester_session_key, created_at, payload_json)
|
||||
current_conversation_bindings(binding_key, binding_id, target_agent_id, target_session_id, target_session_key, channel, account_id, conversation_kind, parent_conversation_id, conversation_id, target_kind, status, bound_at, expires_at, metadata_json, updated_at)
|
||||
plugin_binding_approvals(plugin_root, channel, account_id, plugin_id, plugin_name, approved_at)
|
||||
plugin_state_entries(plugin_id, namespace, entry_key, value_json, created_at, expires_at)
|
||||
@@ -1517,9 +1516,8 @@ apns_registration_tombstones(node_id, deleted_at_ms)
|
||||
device_identities(identity_key, device_id, public_key_pem, private_key_pem, created_at_ms, updated_at_ms)
|
||||
device_auth_tokens(device_id, role, token, scopes_json, updated_at_ms)
|
||||
macos_port_guardian_records(pid, port, command, mode, timestamp)
|
||||
workspace_setup_state(workspace_key, workspace_path, version, bootstrap_seeded_at, setup_completed_at, updated_at)
|
||||
workspace_setup_state(workspace_key, workspace_path, version, bootstrap_seeded_at, setup_completed_at, updated_at, attested_at_ms, attestation_updated_at_ms)
|
||||
workspace_path_aliases(alias_key, alias_path, workspace_key, workspace_path, updated_at_ms)
|
||||
workspace_attestations(workspace_key, attested_at_ms, updated_at_ms)
|
||||
workspace_generated_bootstrap_hashes(workspace_key, filename, sha256)
|
||||
native_hook_relay_bridges(relay_id, pid, hostname, port, token, expires_at_ms, updated_at_ms)
|
||||
managed_outgoing_image_records(attachment_id, session_key, agent_id, message_id, created_at, updated_at, retention_class, alt, original_media_id, original_media_subdir, original_content_type, original_width, original_height, original_size_bytes, original_filename, record_json, cleanup_pending)
|
||||
@@ -1528,19 +1526,21 @@ channel_pairing_requests(channel_key, account_id, request_id, code, created_at,
|
||||
channel_pairing_allow_entries(channel_key, account_id, entry, sort_order, updated_at)
|
||||
config_health_entries(config_path, last_known_good_json, last_promoted_good_json, last_observed_suspicious_signature, updated_at_ms)
|
||||
sandbox_registry_entries(registry_kind, container_name, session_key, backend_id, runtime_label, image, created_at_ms, last_used_at_ms, config_label_kind, config_hash, cdp_port, no_vnc_port, entry_json, updated_at)
|
||||
cron_jobs(store_key, job_id, name, description, enabled, delete_after_run, created_at_ms, agent_id, session_key, schedule_kind, schedule_expr, schedule_tz, every_ms, anchor_ms, at, stagger_ms, session_target, wake_mode, payload_kind, payload_message, payload_model, payload_fallbacks_json, payload_thinking, payload_timeout_seconds, payload_allow_unsafe_external_content, payload_external_content_source_json, payload_light_context, payload_tools_allow_json, delivery_mode, delivery_channel, delivery_to, delivery_thread_id, delivery_account_id, delivery_best_effort, failure_delivery_mode, failure_delivery_channel, failure_delivery_to, failure_delivery_account_id, failure_alert_disabled, failure_alert_after, failure_alert_channel, failure_alert_to, failure_alert_cooldown_ms, failure_alert_include_skipped, failure_alert_mode, failure_alert_account_id, next_run_at_ms, running_at_ms, last_run_at_ms, last_run_status, last_error, last_duration_ms, consecutive_errors, consecutive_skipped, schedule_error_count, last_delivery_status, last_delivery_error, last_delivered, last_failure_alert_at_ms, job_json, state_json, runtime_updated_at_ms, schedule_identity, sort_order, updated_at)
|
||||
cron_jobs(store_key, job_id, declaration_key, owner_agent_id, name, description, enabled, agent_id, payload_kind, job_json, state_json, runtime_updated_at_ms, schedule_identity, sort_order, updated_at)
|
||||
delivery_queue_entries(queue_name, id, status, entry_kind, session_key, channel, target, account_id, retry_count, last_attempt_at, last_error, recovery_state, platform_send_started_at, entry_json, enqueued_at, updated_at, failed_at)
|
||||
migration_runs(id, started_at, finished_at, status, report_json)
|
||||
migration_sources(source_key, migration_kind, source_path, target_table, source_sha256, source_size_bytes, source_record_count, last_run_id, status, imported_at, removed_source, report_json)
|
||||
backup_runs(id, created_at, archive_path, status, manifest_json)
|
||||
```
|
||||
|
||||
`config_machine_state` owns the `skills.curatorState`, `update.checkState`,
|
||||
`config_machine_state` owns the `authProfiles.store`, `authProfiles.state`,
|
||||
`plugins.installedIndex`, `skills.curatorState`, `update.checkState`,
|
||||
`clawhub.promotionsFeed`, `modelCatalog.remote`, `voicewake.triggers`,
|
||||
`voicewake.routing`, `onboarding.recommendations.<workspaceKey>`,
|
||||
`tui.lastSession.<scopeKey>`, `sidebar.sectionOrder`, `nodeHost.config`, and
|
||||
`webPush.vapidKeys` snapshots. Secret-excluding Git backups omit the `nodeHost.`
|
||||
and `webPush.vapidKeys` key prefixes without dropping other machine state.
|
||||
`webPush.vapidKeys` snapshots. Secret-excluding Git backups omit the
|
||||
`authProfiles.`, `nodeHost.`, and `webPush.vapidKeys` key prefixes without
|
||||
dropping other machine state.
|
||||
|
||||
Agent database:
|
||||
|
||||
@@ -1956,7 +1956,7 @@ manifest asset from the verified extracted payload.
|
||||
|
||||
1. Add database registry APIs.
|
||||
- Resolve global DB and per-agent DB paths.
|
||||
- The global schema now uses `user_version = 9`; per-agent DBs use version
|
||||
- The global schema now uses `user_version = 13`; per-agent DBs use version
|
||||
`17`, with bounded forward migrations from supported older versions.
|
||||
- Add close/checkpoint/integrity helpers used by tests, backup, and doctor.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user