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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions