Skip to content

Reshape StateSyncWorkflow config-patch into a typed ConfigMigration union (GigaStore first) #479

Description

@bdchatham

Refines the SeiNodeTaskWorkflow state-sync payload. Design note: bdchatham-designs/designs/seinode-task/config-migration-reshape.md (reviewed with the systems + kubernetes specialists, 2026-07-12).

Problem

StateSyncWorkflow.ConfigPatch is an opaque map[string]map[string]apiextensionsv1.JSON TOML merge-patch. It can mutate any seid config key during a destructive (post-wipe) flow, its only real use is the giga migration, and its shape implies more structure than it enforces.

Change

Replace ConfigPatch with a typed discriminated union — enshrine the migration, not each value:

StateSyncWorkflow {
    Migration  *ConfigMigration  // OPTIONAL; nil => plain re-bootstrap, config unchanged
    RpcServers []string          // OPTIONAL; empty => inherit node.status.resolvedStateSyncers
}
ConfigMigration { Kind ConfigMigrationKind; GigaStore *GigaStoreMigration }   // +Enum=GigaStore
GigaStoreMigration {
    Backend string  // +default=pebbledb +Enum=pebbledb;rocksdb -> [state-store] ss-backend
    // type sets fixed flags: [state-store] ss-enable=true, evm-ss-split=true; [state-commit] sc-enable=true
}

Planner translates the typed migration into the existing generic task.ConfigPatchTask{Files} (sidecar unchanged).

Scope

  • GigaStore arm only. Defer seidb/seidb_archive/seiv2 until each is validated against its sei-chain doc AND has a caller.
  • Keep the RpcServers name (NOT RpcServerWitnessesrpc_servers[0] is the primary, not a witness; and it flows 1:1 through the pipeline). Lift SnapshotSource.RpcServers' godoc onto it.

Guardrails

  • Enum on Kind; CEL exactly-one-payload + kind↔payload on ConfigMigration (fire only when Migration non-nil). No per-field immutability CEL — parent self.stateSync == oldSelf.stateSync already freezes the subtree.
  • Add the admission markers the workflow RpcServers lacks today (present only on SnapshotSource.RpcServers): +listType=set, MinItems=2, host:port Pattern.
  • Planner fail-closed: non-nil migration → empty patch must hard-error; unknown Kind hard-errors; translate in BuildPlan so a bad migration fails before reset-data.
  • Fixed flags stay controller-side (that's the abstraction); document them in godoc, note they're observable in status.plan, and pin them to the giga_store_migration.md version.

Layers (land together) + one-way door

api/v1alpha1/seinodetaskworkflow_types.go · sdk/sei/workflow.go · sdk/sei/provider/k8s/render.go · internal/planner/workflow.go, then make manifests generate.

One-way door: removing served spec.stateSync.configPatch + its SDK mirror is a served-v1alpha1 field removal. Defensible pre-GA (alpha, feature in one PR #460, no external consumers, apply-once workflows) — needs explicit operator sign-off in the implementation PR + confirm no live workflow carries configPatch before merge.

Follow-on (separate)

After this ships + releases, a /workstream to re-align seictl (--config-patch → typed --migration), the SDK, and harbor-dev to the same named-migration UX.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions