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 RpcServerWitnesses — rpc_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
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.ConfigPatchis an opaquemap[string]map[string]apiextensionsv1.JSONTOML 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
ConfigPatchwith a typed discriminated union — enshrine the migration, not each value:Planner translates the typed migration into the existing generic
task.ConfigPatchTask{Files}(sidecar unchanged).Scope
RpcServersname (NOTRpcServerWitnesses—rpc_servers[0]is the primary, not a witness; and it flows 1:1 through the pipeline). LiftSnapshotSource.RpcServers' godoc onto it.Guardrails
EnumonKind; CEL exactly-one-payload + kind↔payload onConfigMigration(fire only when Migration non-nil). No per-field immutability CEL — parentself.stateSync == oldSelf.stateSyncalready freezes the subtree.RpcServerslacks today (present only onSnapshotSource.RpcServers):+listType=set,MinItems=2, host:portPattern.BuildPlanso a bad migration fails before reset-data.status.plan, and pin them to thegiga_store_migration.mdversion.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, thenmake 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 carriesconfigPatchbefore 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