[{"data":1,"prerenderedAt":1612},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fmigration\u002Fmigration-tool":334,"\u002Fdocs\u002Fmigration\u002Fmigration-tool-surround":1607},[4,43,91,154,181,224,262,293],{"title":5,"path":6,"stem":7,"children":8,"icon":42},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17,22,27,32,37],{"title":10,"path":6,"stem":7,"icon":11},"Getting started","i-lucide-flag",{"title":13,"path":14,"stem":15,"icon":16},"Modules overview","\u002Fdocs\u002Fgetting-started\u002Fmodules-overview","1.docs\u002F1.getting-started\u002F2.modules-overview","i-lucide-boxes",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F3.installation","i-lucide-download",{"title":23,"path":24,"stem":25,"icon":26},"License configuration","\u002Fdocs\u002Fgetting-started\u002Flicense-configuration","1.docs\u002F1.getting-started\u002F4.license-configuration","i-lucide-key-round",{"title":28,"path":29,"stem":30,"icon":31},"Your first app","\u002Fdocs\u002Fgetting-started\u002Ffirst-app","1.docs\u002F1.getting-started\u002F5.first-app","i-lucide-square-play",{"title":33,"path":34,"stem":35,"icon":36},"Project setup","\u002Fdocs\u002Fgetting-started\u002Fproject-setup","1.docs\u002F1.getting-started\u002F6.project-setup","i-lucide-package",{"title":38,"path":39,"stem":40,"icon":41},"AI assistants","\u002Fdocs\u002Fgetting-started\u002Fai-assistants","1.docs\u002F1.getting-started\u002F7.ai-assistants","i-lucide-bot",false,{"title":44,"path":45,"stem":46,"children":47,"icon":50},"Core Concepts","\u002Fdocs\u002Fconcepts","1.docs\u002F2.concepts\u002F1.index",[48,51,56,61,66,71,76,81,86],{"title":49,"path":45,"stem":46,"icon":50},"Core concepts","i-lucide-book-open",{"title":52,"path":53,"stem":54,"icon":55},"Architecture","\u002Fdocs\u002Fconcepts\u002Farchitecture","1.docs\u002F2.concepts\u002F2.architecture","i-lucide-layers",{"title":57,"path":58,"stem":59,"icon":60},"Exactly-once semantics","\u002Fdocs\u002Fconcepts\u002Fexactly-once","1.docs\u002F2.concepts\u002F3.exactly-once","i-lucide-shield-check",{"title":62,"path":63,"stem":64,"icon":65},"Lanes and parallelism","\u002Fdocs\u002Fconcepts\u002Flanes-and-parallelism","1.docs\u002F2.concepts\u002F4.lanes-and-parallelism","i-lucide-split",{"title":67,"path":68,"stem":69,"icon":70},"State and thread-safety","\u002Fdocs\u002Fconcepts\u002Fstate-and-thread-safety","1.docs\u002F2.concepts\u002F5.state-and-thread-safety","i-lucide-lock",{"title":72,"path":73,"stem":74,"icon":75},"Event time and watermarks","\u002Fdocs\u002Fconcepts\u002Fevent-time-and-watermarks","1.docs\u002F2.concepts\u002F6.event-time-and-watermarks","i-lucide-clock",{"title":77,"path":78,"stem":79,"icon":80},"The configuration model","\u002Fdocs\u002Fconcepts\u002Fconfiguration-model","1.docs\u002F2.concepts\u002F7.configuration-model","i-lucide-sliders-horizontal",{"title":82,"path":83,"stem":84,"icon":85},"The error-handling model","\u002Fdocs\u002Fconcepts\u002Ferror-handling-model","1.docs\u002F2.concepts\u002F8.error-handling-model","i-lucide-triangle-alert",{"title":87,"path":88,"stem":89,"icon":90},"How StoatFlow differs from Kafka Streams","\u002Fdocs\u002Fconcepts\u002Fhow-stoatflow-differs-from-ks","1.docs\u002F2.concepts\u002F9.how-stoatflow-differs-from-ks","i-lucide-arrow-left-right",{"title":92,"path":93,"stem":94,"children":95,"icon":98},"Building Topologies","\u002Fdocs\u002Fbuilding","1.docs\u002F3.building\u002F1.index",[96,99,104,109,114,119,124,129,134,139,144,149],{"title":97,"path":93,"stem":94,"icon":98},"Building topologies","i-lucide-blocks",{"title":100,"path":101,"stem":102,"icon":103},"Error handling and DLQ","\u002Fdocs\u002Fbuilding\u002Ferror-handling-dlq","1.docs\u002F3.building\u002F10.error-handling-dlq","i-lucide-circle-x",{"title":105,"path":106,"stem":107,"icon":108},"State stores","\u002Fdocs\u002Fbuilding\u002Fstate-stores","1.docs\u002F3.building\u002F11.state-stores","i-lucide-database",{"title":110,"path":111,"stem":112,"icon":113},"Testing topologies","\u002Fdocs\u002Fbuilding\u002Ftesting","1.docs\u002F3.building\u002F12.testing","i-lucide-flask-conical",{"title":115,"path":116,"stem":117,"icon":118},"Sources and sinks","\u002Fdocs\u002Fbuilding\u002Fstreams-builder","1.docs\u002F3.building\u002F2.streams-builder","i-lucide-import",{"title":120,"path":121,"stem":122,"icon":123},"KStream and KTable operations","\u002Fdocs\u002Fbuilding\u002Fkstream-ktable","1.docs\u002F3.building\u002F3.kstream-ktable","i-lucide-waypoints",{"title":125,"path":126,"stem":127,"icon":128},"Aggregations","\u002Fdocs\u002Fbuilding\u002Faggregations","1.docs\u002F3.building\u002F4.aggregations","i-lucide-sigma",{"title":130,"path":131,"stem":132,"icon":133},"Windowing","\u002Fdocs\u002Fbuilding\u002Fwindowing","1.docs\u002F3.building\u002F5.windowing","i-lucide-calendar-clock",{"title":135,"path":136,"stem":137,"icon":138},"Joins","\u002Fdocs\u002Fbuilding\u002Fjoins","1.docs\u002F3.building\u002F6.joins","i-lucide-git-merge",{"title":140,"path":141,"stem":142,"icon":143},"The Processor API","\u002Fdocs\u002Fbuilding\u002Fprocessor-api","1.docs\u002F3.building\u002F7.processor-api","i-lucide-cpu",{"title":145,"path":146,"stem":147,"icon":148},"Scheduled sources","\u002Fdocs\u002Fbuilding\u002Fscheduled-sources","1.docs\u002F3.building\u002F8.scheduled-sources","i-lucide-timer",{"title":150,"path":151,"stem":152,"icon":153},"Serdes and Avro","\u002Fdocs\u002Fbuilding\u002Fserdes","1.docs\u002F3.building\u002F9.serdes","i-lucide-binary",{"title":155,"path":156,"stem":157,"children":158,"icon":80},"Configuration","\u002Fdocs\u002Fconfiguration","1.docs\u002F4.configuration\u002F1.index",[159,161,166,171,176],{"title":160,"path":156,"stem":157,"icon":80},"How configuration works",{"title":162,"path":163,"stem":164,"icon":165},"Engine configuration (:core)","\u002Fdocs\u002Fconfiguration\u002Fcore-config","1.docs\u002F4.configuration\u002F2.core-config","i-lucide-settings-2",{"title":167,"path":168,"stem":169,"icon":170},"Runtime configuration (:runtime)","\u002Fdocs\u002Fconfiguration\u002Fruntime-config","1.docs\u002F4.configuration\u002F3.runtime-config","i-lucide-server-cog",{"title":172,"path":173,"stem":174,"icon":175},"Defaults, adaptivity, and presets","\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets","1.docs\u002F4.configuration\u002F4.defaults-and-presets","i-lucide-gauge",{"title":177,"path":178,"stem":179,"icon":180},"Kafka client configuration","\u002Fdocs\u002Fconfiguration\u002Fkafka-client-config","1.docs\u002F4.configuration\u002F5.kafka-client-config","i-lucide-plug",{"title":182,"path":183,"stem":184,"children":185,"icon":188},"Running in Production","\u002Fdocs\u002Fruntime","1.docs\u002F5.runtime\u002F1.index",[186,189,194,199,204,209,214,219],{"title":187,"path":183,"stem":184,"icon":188},"The runtime","i-lucide-server",{"title":190,"path":191,"stem":192,"icon":193},"The REST API","\u002Fdocs\u002Fruntime\u002Frest-api","1.docs\u002F5.runtime\u002F2.rest-api","i-lucide-globe",{"title":195,"path":196,"stem":197,"icon":198},"Health checks","\u002Fdocs\u002Fruntime\u002Fhealth-checks","1.docs\u002F5.runtime\u002F3.health-checks","i-lucide-heart-pulse",{"title":200,"path":201,"stem":202,"icon":203},"Metrics","\u002Fdocs\u002Fruntime\u002Fmetrics","1.docs\u002F5.runtime\u002F4.metrics","i-lucide-activity",{"title":205,"path":206,"stem":207,"icon":208},"Pause and resume","\u002Fdocs\u002Fruntime\u002Fpause-unpause","1.docs\u002F5.runtime\u002F5.pause-unpause","i-lucide-pause",{"title":210,"path":211,"stem":212,"icon":213},"Plugins and lifecycle hooks","\u002Fdocs\u002Fruntime\u002Fplugins","1.docs\u002F5.runtime\u002F6.plugins","i-lucide-puzzle",{"title":215,"path":216,"stem":217,"icon":218},"Docker images","\u002Fdocs\u002Fruntime\u002Fdocker","1.docs\u002F5.runtime\u002F7.docker","i-lucide-container",{"title":220,"path":221,"stem":222,"icon":223},"GraalVM native image","\u002Fdocs\u002Fruntime\u002Fnative-image","1.docs\u002F5.runtime\u002F8.native-image","i-lucide-zap",{"title":225,"path":226,"stem":227,"children":228,"icon":231},"Deploying & Operating","\u002Fdocs\u002Foperating","1.docs\u002F6.operating\u002F1.index",[229,232,237,242,247,252,257],{"title":230,"path":226,"stem":227,"icon":231},"Deploying and operating","i-lucide-life-buoy",{"title":233,"path":234,"stem":235,"icon":236},"Running on Kubernetes","\u002Fdocs\u002Foperating\u002Fkubernetes","1.docs\u002F6.operating\u002F2.kubernetes","i-lucide-ship",{"title":238,"path":239,"stem":240,"icon":241},"High availability","\u002Fdocs\u002Foperating\u002Fhigh-availability","1.docs\u002F6.operating\u002F3.high-availability","i-lucide-copy",{"title":243,"path":244,"stem":245,"icon":246},"Liveness and readiness probes","\u002Fdocs\u002Foperating\u002Fprobes","1.docs\u002F6.operating\u002F4.probes","i-lucide-stethoscope",{"title":248,"path":249,"stem":250,"icon":251},"Observability","\u002Fdocs\u002Foperating\u002Fobservability","1.docs\u002F6.operating\u002F5.observability","i-lucide-telescope",{"title":253,"path":254,"stem":255,"icon":256},"Tuning under load","\u002Fdocs\u002Foperating\u002Ftuning","1.docs\u002F6.operating\u002F6.tuning","i-lucide-sliders",{"title":258,"path":259,"stem":260,"icon":261},"Production checklist","\u002Fdocs\u002Foperating\u002Fproduction-checklist","1.docs\u002F6.operating\u002F7.production-checklist","i-lucide-clipboard-check",{"title":263,"path":264,"stem":265,"children":266,"icon":90},"Migrating from Kafka Streams","\u002Fdocs\u002Fmigration","1.docs\u002F7.migration\u002F1.index",[267,268,273,278,283,288],{"title":263,"path":264,"stem":265,"icon":90},{"title":269,"path":270,"stem":271,"icon":272},"Automated port","\u002Fdocs\u002Fmigration\u002Fautomated-port","1.docs\u002F7.migration\u002F2.automated-port","i-lucide-wand-sparkles",{"title":274,"path":275,"stem":276,"icon":277},"Migration without carrying state","\u002Fdocs\u002Fmigration\u002Fwithout-data-migration","1.docs\u002F7.migration\u002F3.without-data-migration","i-lucide-sparkles",{"title":279,"path":280,"stem":281,"icon":282},"Migration carrying state","\u002Fdocs\u002Fmigration\u002Fwith-data-migration","1.docs\u002F7.migration\u002F4.with-data-migration","i-lucide-database-backup",{"title":284,"path":285,"stem":286,"icon":287},"The migration tool","\u002Fdocs\u002Fmigration\u002Fmigration-tool","1.docs\u002F7.migration\u002F5.migration-tool","i-lucide-truck",{"title":289,"path":290,"stem":291,"icon":292},"Reusing your Kafka Streams dashboards","\u002Fdocs\u002Fmigration\u002Freusing-kafka-streams-dashboards","1.docs\u002F7.migration\u002F6.reusing-kafka-streams-dashboards","i-lucide-line-chart",{"title":294,"path":295,"stem":296,"children":297,"icon":299},"Reference","\u002Fdocs\u002Freference","1.docs\u002F8.reference\u002F1.index",[298,300,305,310,315,320,325,329],{"title":294,"path":295,"stem":296,"icon":299},"i-lucide-list",{"title":301,"path":302,"stem":303,"icon":304},"Configuration reference","\u002Fdocs\u002Freference\u002Fconfiguration-reference","1.docs\u002F8.reference\u002F2.configuration-reference","i-lucide-table",{"title":306,"path":307,"stem":308,"icon":309},"REST API reference","\u002Fdocs\u002Freference\u002Frest-api-reference","1.docs\u002F8.reference\u002F3.rest-api-reference","i-lucide-network",{"title":311,"path":312,"stem":313,"icon":314},"Gradle plugin reference","\u002Fdocs\u002Freference\u002Fgradle-plugin-reference","1.docs\u002F8.reference\u002F4.gradle-plugin-reference","i-lucide-box",{"title":316,"path":317,"stem":318,"icon":319},"Maven reference","\u002Fdocs\u002Freference\u002Fmaven-reference","1.docs\u002F8.reference\u002F5.maven-reference","i-simple-icons-apachemaven",{"title":321,"path":322,"stem":323,"icon":324},"Kafka Streams compatibility matrix","\u002Fdocs\u002Freference\u002Fks-compatibility-matrix","1.docs\u002F8.reference\u002F6.ks-compatibility-matrix","i-lucide-table-2",{"title":326,"path":327,"stem":328,"icon":175},"Metrics reference","\u002Fdocs\u002Freference\u002Fmetrics-reference","1.docs\u002F8.reference\u002F7.metrics-reference",{"title":330,"path":331,"stem":332,"icon":333},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","1.docs\u002F8.reference\u002F8.glossary","i-lucide-book-a",{"id":335,"title":284,"body":336,"description":1600,"extension":1601,"meta":1602,"navigation":1603,"pageType":1604,"path":285,"seo":1605,"stem":286,"__hash__":1606},"docs\u002F1.docs\u002F7.migration\u002F5.migration-tool.md",{"type":337,"value":338,"toc":1583},"minimark",[339,355,408,413,424,530,537,541,544,865,892,913,917,1024,1031,1037,1188,1191,1197,1216,1223,1229,1252,1258,1265,1289,1293,1296,1427,1515,1519,1525,1531,1535,1579],[340,341,342,346,347,350,351,354],"p",{},[343,344,345],"code",{},"stoatflow-migration-tool"," is a standalone, offline CLI that carries Kafka Streams state into StoatFlow: it reads your KS app's changelog topics, writes byte-translated StoatFlow changelog topics under the new ",[343,348,349],{},"application-id",", seeds the emit-frontier companions where asked, and carries the input consumer-group offsets over — so the StoatFlow app's first start is a normal full restore that resumes exactly where KS stopped. When to choose this path over reprocessing is covered on ",[352,353,279],"a",{"href":280},"; this page is the how-to.",[356,357,358],"tldr-panel",{},[359,360,361,390,397,405],"ul",{},[362,363,364,365,371,372,377,378,383,384,389],"li",{},"One YAML config drives four discrete, re-runnable commands: ",[366,367,368],"strong",{},[343,369,370],{},"plan"," (verify everything, write nothing) → ",[366,373,374],{},[343,375,376],{},"translate"," (seed the changelogs) → ",[366,379,380],{},[343,381,382],{},"seed-offsets"," (carry the input offsets) → ",[366,385,386],{},[343,387,388],{},"verify"," (compare the seeded topics against a re-read).",[362,391,392,393,396],{},"All steps run inside ",[366,394,395],{},"one quiesce window"," with the KS app cleanly stopped.",[362,398,399,400,404],{},"The tool only ",[401,402,403],"em",{},"reads"," KS topics — before the first StoatFlow start, rollback is simply restarting the KS app.",[362,406,407],{},"It needs a JVM 17+ host with network access to the brokers; it never touches the engine, RocksDB, or your application code.",[409,410,412],"h2",{"id":411},"getting-the-tool","Getting the tool",[340,414,415,416,419,420,423],{},"Your Reposilite credentials (the same ones your build uses for StoatFlow artifacts) fetch the fat jar directly — match the tool version to the StoatFlow version you are migrating ",[366,417,418],{},"to"," (currently ",[421,422],"stoatflow-version",{},"):",[425,426,431],"pre",{"className":427,"code":428,"language":429,"meta":430,"style":430},"language-bash shiki shiki-themes vitesse-light","curl -u customer-\u003Cslug>:\u003Ctoken> -O \\\n  \"https:\u002F\u002Fmaven.stoatflow.io\u002Freleases\u002Fio\u002Fstoatflow\u002Fstoatflow-migration-tool\u002F\u003Cversion>\u002Fstoatflow-migration-tool-\u003Cversion>-all.jar\"\n\njava -jar stoatflow-migration-tool-\u003Cversion>-all.jar --help\n","bash","",[343,432,433,483,496,503],{"__ignoreMap":430},[434,435,438,442,446,450,454,457,461,464,467,469,472,475,477,480],"span",{"class":436,"line":437},"line",1,[434,439,441],{"class":440},"sySUi","curl",[434,443,445],{"class":444},"sEi1f"," -u",[434,447,449],{"class":448},"spphp"," customer-",[434,451,453],{"class":452},"si04Y","\u003C",[434,455,456],{"class":448},"slu",[434,458,460],{"class":459},"suHK_","g",[434,462,463],{"class":452},">",[434,465,466],{"class":448},":",[434,468,453],{"class":452},[434,470,471],{"class":448},"toke",[434,473,474],{"class":459},"n",[434,476,463],{"class":452},[434,478,479],{"class":444}," -O",[434,481,482],{"class":444}," \\\n",[434,484,486,490,493],{"class":436,"line":485},2,[434,487,489],{"class":488},"sSP4y","  \"",[434,491,492],{"class":448},"https:\u002F\u002Fmaven.stoatflow.io\u002Freleases\u002Fio\u002Fstoatflow\u002Fstoatflow-migration-tool\u002F\u003Cversion>\u002Fstoatflow-migration-tool-\u003Cversion>-all.jar",[434,494,495],{"class":488},"\"\n",[434,497,499],{"class":436,"line":498},3,[434,500,502],{"emptyLinePlaceholder":501},true,"\n",[434,504,506,509,512,515,517,520,522,524,527],{"class":436,"line":505},4,[434,507,508],{"class":440},"java",[434,510,511],{"class":444}," -jar",[434,513,514],{"class":448}," stoatflow-migration-tool-",[434,516,453],{"class":452},[434,518,519],{"class":448},"versio",[434,521,474],{"class":459},[434,523,463],{"class":452},[434,525,526],{"class":448},"-all.jar",[434,528,529],{"class":444}," --help\n",[340,531,532,533,536],{},"Teams that prefer resolving through their build can depend on ",[343,534,535],{},"io.stoatflow:stoatflow-migration-tool:\u003Cversion>:all"," and copy the artifact — it is a plain executable jar, JVM 17+.",[409,538,540],{"id":539},"the-migration-config","The migration config",[340,542,543],{},"One YAML file drives all commands:",[425,545,549],{"className":546,"code":547,"language":548,"meta":430,"style":430},"language-yaml shiki shiki-themes vitesse-light","kafka:\n  bootstrap.servers: broker:9092\n  # + optional security client props passthrough (security.protocol, sasl.*, ssl.*)\n\nsource:                       # the Kafka Streams app being migrated FROM\n  applicationId: my-ks-app\n  processingGuarantee: exactly_once     # REQUIRED: exactly_once | at_least_once\n  inputTopics: [orders, customers]      # topics whose group offsets carry over\n  ignoreStores: []                      # KS stores deliberately left behind (e.g. a drained suppress buffer)\n\ntarget:                       # the StoatFlow app being migrated TO\n  applicationId: my-sf-app\n  changelogNumPartitions: 1             # must match the SF app's config (default 1)\n  replicationFactor: 3\n\nstores:\n  - ksName: order-totals                # KS store name (changelog: {ks-app}-order-totals-changelog)\n    sfName: order-totals                # SF store name (default = ksName; set when the port renamed a store)\n    type: kv-timestamped                # kv | kv-timestamped | window | window-timestamped | window-duplicates |\n                                        #   session | versioned | fk-subscription | outer-join\n    extraTopicConfigs: {}               # optional per-store topic-config overrides\n    recordHeaders: false                # true iff the store is headers-aware (KIP-1271) — carries the\n                                        #   KS changelog's native record headers through\n    emitFrontier: true                  # OnWindowClose aggregations only: seed the {sfName}-emitfrontier\n                                        #   companion so migrated closed windows aren't re-emitted\n  - ksName: my-table-source\n    type: kv                            # SF table() source stores are plain KV — see the classification table\n    sourceTopic: customers              # declares a source-KTable materialization; plan resolves its path\n","yaml",[343,550,551,561,571,577,581,592,603,617,643,657,662,673,683,698,709,714,722,739,752,766,772,786,801,807,821,827,839,852],{"__ignoreMap":430},[434,552,553,557],{"class":436,"line":437},[434,554,556],{"class":555},"su6XF","kafka",[434,558,560],{"class":559},"sYZai",":\n",[434,562,563,566,568],{"class":436,"line":485},[434,564,565],{"class":555},"  bootstrap.servers",[434,567,466],{"class":559},[434,569,570],{"class":448}," broker:9092\n",[434,572,573],{"class":436,"line":498},[434,574,576],{"class":575},"s8zF2","  # + optional security client props passthrough (security.protocol, sasl.*, ssl.*)\n",[434,578,579],{"class":436,"line":505},[434,580,502],{"emptyLinePlaceholder":501},[434,582,584,587,589],{"class":436,"line":583},5,[434,585,586],{"class":555},"source",[434,588,466],{"class":559},[434,590,591],{"class":575},"                       # the Kafka Streams app being migrated FROM\n",[434,593,595,598,600],{"class":436,"line":594},6,[434,596,597],{"class":555},"  applicationId",[434,599,466],{"class":559},[434,601,602],{"class":448}," my-ks-app\n",[434,604,606,609,611,614],{"class":436,"line":605},7,[434,607,608],{"class":555},"  processingGuarantee",[434,610,466],{"class":559},[434,612,613],{"class":448}," exactly_once",[434,615,616],{"class":575},"     # REQUIRED: exactly_once | at_least_once\n",[434,618,620,623,625,628,631,634,637,640],{"class":436,"line":619},8,[434,621,622],{"class":555},"  inputTopics",[434,624,466],{"class":559},[434,626,627],{"class":559}," [",[434,629,630],{"class":448},"orders",[434,632,633],{"class":559},",",[434,635,636],{"class":448}," customers",[434,638,639],{"class":559},"]",[434,641,642],{"class":575},"      # topics whose group offsets carry over\n",[434,644,646,649,651,654],{"class":436,"line":645},9,[434,647,648],{"class":555},"  ignoreStores",[434,650,466],{"class":559},[434,652,653],{"class":559}," []",[434,655,656],{"class":575},"                      # KS stores deliberately left behind (e.g. a drained suppress buffer)\n",[434,658,660],{"class":436,"line":659},10,[434,661,502],{"emptyLinePlaceholder":501},[434,663,665,668,670],{"class":436,"line":664},11,[434,666,667],{"class":555},"target",[434,669,466],{"class":559},[434,671,672],{"class":575},"                       # the StoatFlow app being migrated TO\n",[434,674,676,678,680],{"class":436,"line":675},12,[434,677,597],{"class":555},[434,679,466],{"class":559},[434,681,682],{"class":448}," my-sf-app\n",[434,684,686,689,691,695],{"class":436,"line":685},13,[434,687,688],{"class":555},"  changelogNumPartitions",[434,690,466],{"class":559},[434,692,694],{"class":693},"s-TwI"," 1",[434,696,697],{"class":575},"             # must match the SF app's config (default 1)\n",[434,699,701,704,706],{"class":436,"line":700},14,[434,702,703],{"class":555},"  replicationFactor",[434,705,466],{"class":559},[434,707,708],{"class":693}," 3\n",[434,710,712],{"class":436,"line":711},15,[434,713,502],{"emptyLinePlaceholder":501},[434,715,717,720],{"class":436,"line":716},16,[434,718,719],{"class":555},"stores",[434,721,560],{"class":559},[434,723,725,728,731,733,736],{"class":436,"line":724},17,[434,726,727],{"class":559},"  -",[434,729,730],{"class":555}," ksName",[434,732,466],{"class":559},[434,734,735],{"class":448}," order-totals",[434,737,738],{"class":575},"                # KS store name (changelog: {ks-app}-order-totals-changelog)\n",[434,740,742,745,747,749],{"class":436,"line":741},18,[434,743,744],{"class":555},"    sfName",[434,746,466],{"class":559},[434,748,735],{"class":448},[434,750,751],{"class":575},"                # SF store name (default = ksName; set when the port renamed a store)\n",[434,753,755,758,760,763],{"class":436,"line":754},19,[434,756,757],{"class":555},"    type",[434,759,466],{"class":559},[434,761,762],{"class":448}," kv-timestamped",[434,764,765],{"class":575},"                # kv | kv-timestamped | window | window-timestamped | window-duplicates |\n",[434,767,769],{"class":436,"line":768},20,[434,770,771],{"class":575},"                                        #   session | versioned | fk-subscription | outer-join\n",[434,773,775,778,780,783],{"class":436,"line":774},21,[434,776,777],{"class":555},"    extraTopicConfigs",[434,779,466],{"class":559},[434,781,782],{"class":559}," {}",[434,784,785],{"class":575},"               # optional per-store topic-config overrides\n",[434,787,789,792,794,798],{"class":436,"line":788},22,[434,790,791],{"class":555},"    recordHeaders",[434,793,466],{"class":559},[434,795,797],{"class":796},"sbBg2"," false",[434,799,800],{"class":575},"                # true iff the store is headers-aware (KIP-1271) — carries the\n",[434,802,804],{"class":436,"line":803},23,[434,805,806],{"class":575},"                                        #   KS changelog's native record headers through\n",[434,808,810,813,815,818],{"class":436,"line":809},24,[434,811,812],{"class":555},"    emitFrontier",[434,814,466],{"class":559},[434,816,817],{"class":796}," true",[434,819,820],{"class":575},"                  # OnWindowClose aggregations only: seed the {sfName}-emitfrontier\n",[434,822,824],{"class":436,"line":823},25,[434,825,826],{"class":575},"                                        #   companion so migrated closed windows aren't re-emitted\n",[434,828,830,832,834,836],{"class":436,"line":829},26,[434,831,727],{"class":559},[434,833,730],{"class":555},[434,835,466],{"class":559},[434,837,838],{"class":448}," my-table-source\n",[434,840,842,844,846,849],{"class":436,"line":841},27,[434,843,757],{"class":555},[434,845,466],{"class":559},[434,847,848],{"class":448}," kv",[434,850,851],{"class":575},"                            # SF table() source stores are plain KV — see the classification table\n",[434,853,855,858,860,862],{"class":436,"line":854},28,[434,856,857],{"class":555},"    sourceTopic",[434,859,466],{"class":559},[434,861,636],{"class":448},[434,863,864],{"class":575},"              # declares a source-KTable materialization; plan resolves its path\n",[340,866,867,868,871,872,875,876,880,881,884,885,888,889,891],{},"The ",[343,869,870],{},"type"," values and the ",[343,873,874],{},"ksName → sfName"," mapping follow the ",[352,877,879],{"href":878},"\u002Fdocs\u002Fmigration\u002Fwith-data-migration#classifying-your-stores","classification table"," — get ",[343,882,883],{},"kv"," vs ",[343,886,887],{},"kv-timestamped"," right, it is byte-silent if wrong (and ",[343,890,370],{},"'s heuristics cannot catch that particular pair; the post-start spot-check below can).",[340,893,894,900,901,904,905,908,909,912],{},[366,895,896,899],{},[343,897,898],{},"source.processingGuarantee"," is required"," because it changes what a safe quiesce means: under ",[343,902,903],{},"at_least_once",", a ",[366,906,907],{},"clean shutdown is mandatory"," — a crashed ALO app passes the group-empty check after its session timeout with changelog state ",[401,910,911],{},"ahead"," of its committed input offsets, and migrating that snapshot bakes at-least-once duplication into the carried state. Exactly-once snapshots are crash-safe.",[409,914,916],{"id":915},"the-four-commands","The four commands",[425,918,920],{"className":427,"code":919,"language":429,"meta":430,"style":430},"java -jar stoatflow-migration-tool-\u003Cv>-all.jar plan         -c migration.yaml\njava -jar stoatflow-migration-tool-\u003Cv>-all.jar translate    -c migration.yaml [--force]\njava -jar stoatflow-migration-tool-\u003Cv>-all.jar seed-offsets -c migration.yaml\njava -jar stoatflow-migration-tool-\u003Cv>-all.jar verify       -c migration.yaml\n",[343,921,922,948,976,1000],{"__ignoreMap":430},[434,923,924,926,928,930,932,935,937,939,942,945],{"class":436,"line":437},[434,925,508],{"class":440},[434,927,511],{"class":444},[434,929,514],{"class":448},[434,931,453],{"class":452},[434,933,934],{"class":459},"v",[434,936,463],{"class":452},[434,938,526],{"class":448},[434,940,941],{"class":448}," plan",[434,943,944],{"class":444},"         -c",[434,946,947],{"class":448}," migration.yaml\n",[434,949,950,952,954,956,958,960,962,964,967,970,973],{"class":436,"line":485},[434,951,508],{"class":440},[434,953,511],{"class":444},[434,955,514],{"class":448},[434,957,453],{"class":452},[434,959,934],{"class":459},[434,961,463],{"class":452},[434,963,526],{"class":448},[434,965,966],{"class":448}," translate",[434,968,969],{"class":444},"    -c",[434,971,972],{"class":448}," migration.yaml",[434,974,975],{"class":459}," [--force]\n",[434,977,978,980,982,984,986,988,990,992,995,998],{"class":436,"line":498},[434,979,508],{"class":440},[434,981,511],{"class":444},[434,983,514],{"class":448},[434,985,453],{"class":452},[434,987,934],{"class":459},[434,989,463],{"class":452},[434,991,526],{"class":448},[434,993,994],{"class":448}," seed-offsets",[434,996,997],{"class":444}," -c",[434,999,947],{"class":448},[434,1001,1002,1004,1006,1008,1010,1012,1014,1016,1019,1022],{"class":436,"line":505},[434,1003,508],{"class":440},[434,1005,511],{"class":444},[434,1007,514],{"class":448},[434,1009,453],{"class":452},[434,1011,934],{"class":459},[434,1013,463],{"class":452},[434,1015,526],{"class":448},[434,1017,1018],{"class":448}," verify",[434,1020,1021],{"class":444},"       -c",[434,1023,947],{"class":448},[1025,1026,1028,1030],"h3",{"id":1027},"plan-verify-everything-write-nothing",[343,1029,370],{}," — verify everything, write nothing",[340,1032,1033,1034,466],{},"Runs every preflight and prints the migration plan. Each check exists because the failure it catches is otherwise ",[366,1035,1036],{},"silent",[1038,1039,1040,1053],"table",{},[1041,1042,1043],"thead",{},[1044,1045,1046,1050],"tr",{},[1047,1048,1049],"th",{},"Check",[1047,1051,1052],{},"Failure it prevents",[1054,1055,1056,1076,1084,1092,1100,1108,1124,1136,1154,1172,1180],"tbody",{},[1044,1057,1058,1062],{},[1059,1060,1061],"td",{},"Changelog discovery cross-check",[1059,1063,1064,1065,1068,1069,1072,1073],{},"An undeclared changelog (easily an auto-named FK ",[343,1066,1067],{},"-subscription-store"," or ",[343,1070,1071],{},"OUTERSHARED"," outer store) would silently not migrate — every discovered changelog must be declared or explicitly listed in ",[343,1074,1075],{},"ignoreStores",[1044,1077,1078,1081],{},[1059,1079,1080],{},"KS group is EMPTY",[1059,1082,1083],{},"Migrating while the KS app still runs captures a moving snapshot",[1044,1085,1086,1089],{},[1059,1087,1088],{},"Repartition-topic lag = 0",[1059,1090,1091],{},"In-flight re-keyed records would be lost — StoatFlow repartitions in memory and will never read KS repartition topics",[1044,1093,1094,1097],{},[1059,1095,1096],{},"ALO clean-shutdown warning",[1059,1098,1099],{},"See above — a crashed ALO snapshot inherits duplication",[1044,1101,1102,1105],{},[1059,1103,1104],{},"Structural type heuristics",[1059,1106,1107],{},"Samples each changelog and checks every record against the declared type (window\u002Fsession key shapes, seqnum-vs-duplicates, FK CombinedKey bounds, outer-store list envelopes). A misclassified type is byte-silent at translate time",[1044,1109,1110,1113],{},[1059,1111,1112],{},"Source-KTable path resolution",[1059,1114,1115,1116,1119,1120,1123],{},"Prints free \u002F translate \u002F ",[343,1117,1118],{},"materializeFromSourceTopic"," per ",[343,1121,1122],{},"sourceTopic"," store",[1044,1125,1126,1129],{},[1059,1127,1128],{},"Target partition-count assert",[1059,1130,1131,1132,1135],{},"The engine does ",[366,1133,1134],{},"not"," validate a changelog topic's partition count against its config — a mismatch would mis-place keys silently",[1044,1137,1138,1147],{},[1059,1139,1140,1143,1144],{},[343,1141,1142],{},"message.timestamp.type"," = ",[343,1145,1146],{},"CreateTime",[1059,1148,1149,1150,1153],{},"The timestamped\u002Fversioned rules consume record timestamps; ",[343,1151,1152],{},"LogAppendTime"," would substitute broker time",[1044,1155,1156,1162],{},[1059,1157,1158,1159],{},"Headers-presence vs ",[343,1160,1161],{},"recordHeaders",[1059,1163,1164,1165,1168,1169],{},"A headers-aware store seeded without ",[343,1166,1167],{},"recordHeaders: true"," restores with ",[366,1170,1171],{},"all header data silently dropped",[1044,1173,1174,1177],{},[1059,1175,1176],{},"Target preconditions",[1059,1178,1179],{},"Target changelogs absent\u002Fempty, target group empty — catches leftovers from a previous attempt",[1044,1181,1182,1185],{},[1059,1183,1184],{},"Consistency point",[1059,1186,1187],{},"Prints per-partition changelog LSOs + the KS group's committed input offsets",[340,1189,1190],{},"Run it as a dry run while the KS app is still up (expect only the \"group not empty\" error), and again for real inside the quiesce window.",[1025,1192,1194,1196],{"id":1193},"translate-seed-the-stoatflow-changelogs",[343,1195,376],{}," — seed the StoatFlow changelogs",[340,1198,1199,1200,1203,1204,1207,1208,1211,1212,1215],{},"Per store: creates ",[343,1201,1202],{},"{sf-app-id}-{store}-changelog"," with StoatFlow's exact topic configs, consumes the KS changelog (",[343,1205,1206],{},"read_committed",", from earliest to the captured stable offset), applies the store type's byte-translation rule, and produces with the default partitioner — reproducing StoatFlow's own changelog placement. For every store marked ",[343,1209,1210],{},"emitFrontier: true"," it additionally seeds the ",[343,1213,1214],{},"{sfName}-emitfrontier"," companion with that store's own max changelog record timestamp.",[340,1217,1218,1219,1222],{},"Re-run semantics: a re-run requires an empty target topic or ",[343,1220,1221],{},"--force"," (delete + recreate + reseed). There is no partial resume.",[1025,1224,1226,1228],{"id":1225},"seed-offsets-carry-the-input-offsets",[343,1227,382],{}," — carry the input offsets",[340,1230,1231,1232,1235,1236,1239,1240,1243,1244,1247,1248,1251],{},"Copies the KS group's committed offsets for the configured ",[343,1233,1234],{},"inputTopics"," into the (empty) target group. Must run ",[366,1237,1238],{},"before"," the StoatFlow app's first start. Recommendation: set ",[343,1241,1242],{},"AutoOffsetReset.none()"," on migrated sources for the first start — a partial or failed seeding then fails loud instead of silently reprocessing from ",[343,1245,1246],{},"earliest"," or skipping to ",[343,1249,1250],{},"latest",".",[1025,1253,1255,1257],{"id":1254},"verify-prove-the-seeding-is-faithful",[343,1256,388],{}," — prove the seeding is faithful",[340,1259,1260,1261,1264],{},"Per store: record count + an order-independent streaming checksum of the seeded topic versus a ",[366,1262,1263],{},"re-read of the KS source through the same translation",", plus per-partition spot byte-comparisons, the partition-count assert, and the emit-frontier seed check.",[340,1266,1267,1268,1270,1271,1274,1275,1278,1279,1281,1282,1284,1285,1288],{},"Division of labor worth understanding: ",[343,1269,388],{}," proves the seeding is a ",[401,1272,1273],{},"faithful, complete application of the tool's translation",". Translation ",[401,1276,1277],{},"correctness"," is pinned by the tool's own test suite against the real Kafka Streams classes — and a misclassified ",[343,1280,870],{}," reproduces identically on both sides of ",[343,1283,388],{},"'s comparison, which is why the ",[366,1286,1287],{},"post-start spot-check below is a required gate",", not a nicety.",[409,1290,1292],{"id":1291},"the-cutover-runbook","The cutover runbook",[340,1294,1295],{},"The shape of the whole thing — and, more importantly, where it stops being reversible. The tool never writes to a Kafka Streams topic; it reads them and writes new StoatFlow ones, which is exactly why every step before the first StoatFlow start can be abandoned for free.",[425,1297,1301],{"className":1298,"code":1299,"language":1300,"meta":430,"style":430},"language-mermaid shiki shiki-themes vitesse-light","sequenceDiagram\n    participant O as Operator\n    participant KS as Kafka Streams app\n    participant T as Migration tool\n    participant K as Kafka\n    participant SF as StoatFlow app\n\n    O->>T: 1 · plan — dry run, KS still serving\n    note over T,K: the tool only ever READS the KS topics —\u003Cbr\u002F>every write lands on new StoatFlow topics\n    O->>KS: 2 · quiesce — drain repartition topics,\u003Cbr\u002F>close windows, clean shutdown\n    KS->>K: final commit, group EMPTY\n    O->>T: 3 · plan — preflights green,\u003Cbr\u002F>consistency point captured\n    O->>T: 4 · translate\n    K-->>T: read the KS changelogs (read_committed)\n    T->>K: write the StoatFlow store changelogs\u003Cbr\u002F>+ emit-frontier companions\n    O->>T: 5 · seed-offsets — KS committed input\u003Cbr\u002F>offsets into the empty StoatFlow group\n    O->>T: 6 · verify — counts, checksums, partition asserts\n    note over O,SF: still fully reversible — restart KS,\u003Cbr\u002F>drop the seeded topics and group\n    O->>SF: 7 · first start\n    K-->>SF: forced full restore of every seeded changelog\n    SF->>SF: required spot-check — queries against\u003Cbr\u002F>the still-stopped KS state\n    SF->>K: first transactional commit into shared sinks\n    note over SF,K: the point of no return\n    O->>SF: 8 · validate side by side, switch downstream\n    O->>KS: 9 · retire — deployment, group, internal topics\n","mermaid",[343,1302,1303,1308,1313,1318,1323,1328,1333,1337,1342,1347,1352,1357,1362,1367,1372,1377,1382,1387,1392,1397,1402,1407,1412,1417,1422],{"__ignoreMap":430},[434,1304,1305],{"class":436,"line":437},[434,1306,1307],{"class":459},"sequenceDiagram\n",[434,1309,1310],{"class":436,"line":485},[434,1311,1312],{"class":459},"    participant O as Operator\n",[434,1314,1315],{"class":436,"line":498},[434,1316,1317],{"class":459},"    participant KS as Kafka Streams app\n",[434,1319,1320],{"class":436,"line":505},[434,1321,1322],{"class":459},"    participant T as Migration tool\n",[434,1324,1325],{"class":436,"line":583},[434,1326,1327],{"class":459},"    participant K as Kafka\n",[434,1329,1330],{"class":436,"line":594},[434,1331,1332],{"class":459},"    participant SF as StoatFlow app\n",[434,1334,1335],{"class":436,"line":605},[434,1336,502],{"emptyLinePlaceholder":501},[434,1338,1339],{"class":436,"line":619},[434,1340,1341],{"class":459},"    O->>T: 1 · plan — dry run, KS still serving\n",[434,1343,1344],{"class":436,"line":645},[434,1345,1346],{"class":459},"    note over T,K: the tool only ever READS the KS topics —\u003Cbr\u002F>every write lands on new StoatFlow topics\n",[434,1348,1349],{"class":436,"line":659},[434,1350,1351],{"class":459},"    O->>KS: 2 · quiesce — drain repartition topics,\u003Cbr\u002F>close windows, clean shutdown\n",[434,1353,1354],{"class":436,"line":664},[434,1355,1356],{"class":459},"    KS->>K: final commit, group EMPTY\n",[434,1358,1359],{"class":436,"line":675},[434,1360,1361],{"class":459},"    O->>T: 3 · plan — preflights green,\u003Cbr\u002F>consistency point captured\n",[434,1363,1364],{"class":436,"line":685},[434,1365,1366],{"class":459},"    O->>T: 4 · translate\n",[434,1368,1369],{"class":436,"line":700},[434,1370,1371],{"class":459},"    K-->>T: read the KS changelogs (read_committed)\n",[434,1373,1374],{"class":436,"line":711},[434,1375,1376],{"class":459},"    T->>K: write the StoatFlow store changelogs\u003Cbr\u002F>+ emit-frontier companions\n",[434,1378,1379],{"class":436,"line":716},[434,1380,1381],{"class":459},"    O->>T: 5 · seed-offsets — KS committed input\u003Cbr\u002F>offsets into the empty StoatFlow group\n",[434,1383,1384],{"class":436,"line":724},[434,1385,1386],{"class":459},"    O->>T: 6 · verify — counts, checksums, partition asserts\n",[434,1388,1389],{"class":436,"line":741},[434,1390,1391],{"class":459},"    note over O,SF: still fully reversible — restart KS,\u003Cbr\u002F>drop the seeded topics and group\n",[434,1393,1394],{"class":436,"line":754},[434,1395,1396],{"class":459},"    O->>SF: 7 · first start\n",[434,1398,1399],{"class":436,"line":768},[434,1400,1401],{"class":459},"    K-->>SF: forced full restore of every seeded changelog\n",[434,1403,1404],{"class":436,"line":774},[434,1405,1406],{"class":459},"    SF->>SF: required spot-check — queries against\u003Cbr\u002F>the still-stopped KS state\n",[434,1408,1409],{"class":436,"line":788},[434,1410,1411],{"class":459},"    SF->>K: first transactional commit into shared sinks\n",[434,1413,1414],{"class":436,"line":803},[434,1415,1416],{"class":459},"    note over SF,K: the point of no return\n",[434,1418,1419],{"class":436,"line":809},[434,1420,1421],{"class":459},"    O->>SF: 8 · validate side by side, switch downstream\n",[434,1423,1424],{"class":436,"line":823},[434,1425,1426],{"class":459},"    O->>KS: 9 · retire — deployment, group, internal topics\n",[1428,1429,1430,1442,1453,1460,1467,1474,1481,1503,1509],"ol",{},[362,1431,1432,1435,1436,1439,1440,1251],{},[366,1433,1434],{},"Prepare (KS still running)."," Port the code (",[352,1437,1438],{"href":270},"automated port","); name all migrated stores explicitly on both sides; write the migration config; dry-run ",[343,1441,370],{},[362,1443,1444,1447,1448,1452],{},[366,1445,1446],{},"Quiesce."," Stop input production if the SLA requires; let KS drain its repartition topics; if suppress is in play, reach a windows-closed point first so the buffer drains (stream time only advances with records — see the ",[352,1449,1451],{"href":1450},"\u002Fdocs\u002Fmigration\u002Fwith-data-migration#semantics-caveats-at-the-cutover-boundary","caveats","); cleanly stop the KS app. Under ALO, a clean shutdown is mandatory.",[362,1454,1455,1459],{},[366,1456,1457],{},[343,1458,370],{}," — all checks green; consistency point captured.",[362,1461,1462,1466],{},[366,1463,1464],{},[343,1465,376],{}," — seed all store changelogs (+ emit-frontier companions). Duration is proportional to total changelog bytes; the KS app stays down.",[362,1468,1469,1473],{},[366,1470,1471],{},[343,1472,382],{}," — carry input offsets into the target group.",[362,1475,1476,1480],{},[366,1477,1478],{},[343,1479,388],{}," — counts, checksums, partition counts green.",[362,1482,1483,1486,1487,1490,1491,1494,1495,1498,1499,1502],{},[366,1484,1485],{},"First StoatFlow start"," — a forced full restore of all seeded changelogs. Watch the ",[343,1488,1489],{},"stoatflow.restoration.*"," meters; ",[343,1492,1493],{},"\u002Fhealth\u002Fready"," gates traffic until restoration completes; confirm ",[343,1496,1497],{},"\u002Foffsets",". Then the ",[366,1500,1501],{},"required spot-check",": interactive-query reads against the still-stopped KS state (counts match, a sampled key returns the expected value). This is the only check that catches a misclassified store type end-to-end.",[362,1504,1505,1508],{},[366,1506,1507],{},"Validate & switch."," Bounded side-by-side output inspection where the topology allows, then point downstream at the StoatFlow outputs (or simply let it continue producing to the same sinks).",[362,1510,1511,1514],{},[366,1512,1513],{},"Retire."," After sign-off: delete the KS deployment, its group, and its internal topics.",[409,1516,1518],{"id":1517},"the-rollback-line","The rollback line",[340,1520,1521,1524],{},[366,1522,1523],{},"Before step 7, the KS side is untouched"," — the tool only reads KS topics; it writes only new StoatFlow topics and the new group. Rollback = restart the KS app; delete the seeded topics and group at leisure.",[340,1526,1527,1530],{},[366,1528,1529],{},"The point of no return is the first StoatFlow transactional commit into shared sinks"," (step 7 onward). Rolling back to KS after that means KS resumes from its own older committed offsets and re-produces output StoatFlow already produced — downstream duplication that exactly-once cannot dedupe across two applications. Keep the KS deployment deployable until sign-off.",[409,1532,1534],{"id":1533},"where-to-go-next","Where to go next",[359,1536,1537,1544,1555,1564,1571],{},[362,1538,1539,1543],{},[366,1540,1541],{},[352,1542,279],{"href":280}," — when to translate vs reprocess, the per-store support matrix, the classification table, and the boundary caveats.",[362,1545,1546,1550,1551,1554],{},[366,1547,1548],{},[352,1549,38],{"href":39}," — the ",[343,1552,1553],{},"stoatflow-port-from-ks"," skill walks the tool's commands and store classification with you.",[362,1556,1557,1563],{},[366,1558,1559],{},[352,1560,1562],{"href":1561},"\u002Fdocs\u002Fconcepts\u002Farchitecture#lifecycle-startup-restart-recovery","Architecture: lifecycle"," — the per-store restore decision the first start runs.",[362,1565,1566,1570],{},[366,1567,1568],{},[352,1569,289],{"href":290}," — watch the restore and the cutover on the dashboards you already have.",[362,1572,1573,1574,1578],{},"Suppress-heavy topology or versioned stores at scale? ",[352,1575,1577],{"href":1576},"\u002Fcontact","Get in touch"," — those are the shapes we still migrate hands-on.",[1580,1581,1582],"style",{},"html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .sEi1f, html code.shiki .sEi1f{--shiki-default:#A65E2B}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .suHK_, html code.shiki .suHK_{--shiki-default:#393A34}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .su6XF, html code.shiki .su6XF{--shiki-default:#998418}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}html pre.shiki code .s-TwI, html code.shiki .s-TwI{--shiki-default:#2F798A}html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}",{"title":430,"searchDepth":485,"depth":485,"links":1584},[1585,1586,1587,1597,1598,1599],{"id":411,"depth":485,"text":412},{"id":539,"depth":485,"text":540},{"id":915,"depth":485,"text":916,"children":1588},[1589,1591,1593,1595],{"id":1027,"depth":498,"text":1590},"plan — verify everything, write nothing",{"id":1193,"depth":498,"text":1592},"translate — seed the StoatFlow changelogs",{"id":1225,"depth":498,"text":1594},"seed-offsets — carry the input offsets",{"id":1254,"depth":498,"text":1596},"verify — prove the seeding is faithful",{"id":1291,"depth":485,"text":1292},{"id":1517,"depth":485,"text":1518},{"id":1533,"depth":485,"text":1534},"How to run stoatflow-migration-tool — the offline Kafka Streams changelog translator. Config reference, the plan \u002F translate \u002F seed-offsets \u002F verify commands, the cutover runbook, and the rollback line.","md",{},{"icon":287},"how-to",{"title":284,"description":1600},"7Gq7k2vBVk3BLq6jAVa7fBBOw3oPkzPKBQBm-TqEnyQ",[1608,1610],{"title":279,"path":280,"stem":281,"description":1609,"icon":282,"children":-1},"The supported paths for carrying Kafka Streams state into StoatFlow — the reprocess | translate | engage matrix, per-store-type support, the classification table for the migration tool, and the semantics caveats at the cutover boundary.",{"title":289,"path":290,"stem":291,"description":1611,"icon":292,"children":-1},"Turn on Kafka Streams-compatible metrics so your existing Grafana dashboards, Prometheus rules, and alerts light up against a StoatFlow app with at most threshold-level edits.",1786987429451]