[{"data":1,"prerenderedAt":9717},["ShallowReactive",2],{"search-sections-flume":3,"nav-flume":1798,"content-tree-flume":1852,"footer-resources":1878,"content-/v1.0.1/guides/testing":4731,"surround-/v1.0.1/guides/testing":9714},[4,10,14,20,25,31,36,41,45,50,55,60,64,69,74,79,84,88,93,98,103,108,113,118,123,128,133,138,143,148,153,158,162,167,172,177,182,187,192,197,202,207,212,217,222,226,231,236,241,245,249,253,257,262,267,271,276,281,286,291,296,301,306,310,315,320,325,329,333,337,342,347,351,356,361,365,370,375,380,385,390,394,399,404,409,413,417,422,427,432,437,441,446,450,454,459,464,469,474,478,483,488,493,497,502,507,511,516,521,526,530,535,540,545,549,554,559,563,568,573,578,582,586,590,594,598,603,608,613,617,622,627,631,636,641,645,650,655,659,664,669,673,678,683,687,692,697,702,707,711,715,719,723,728,733,738,743,747,752,757,761,765,770,774,779,783,787,792,796,800,804,808,813,817,821,825,830,835,840,845,848,853,858,863,868,873,877,882,886,891,896,901,906,911,916,921,926,931,935,940,945,950,955,960,965,969,973,977,981,985,989,994,999,1004,1009,1014,1018,1023,1028,1033,1037,1042,1047,1052,1056,1061,1066,1070,1075,1080,1085,1090,1094,1099,1103,1108,1113,1118,1123,1128,1133,1138,1143,1147,1151,1156,1160,1165,1170,1175,1180,1185,1189,1194,1199,1204,1209,1213,1218,1223,1228,1233,1237,1242,1247,1252,1257,1262,1265,1270,1275,1280,1285,1289,1294,1299,1304,1309,1314,1319,1324,1329,1334,1339,1342,1347,1352,1356,1361,1366,1371,1376,1381,1386,1391,1396,1401,1405,1410,1414,1419,1423,1427,1431,1436,1441,1445,1450,1455,1460,1465,1470,1475,1480,1485,1490,1495,1500,1505,1510,1515,1520,1525,1530,1535,1540,1544,1548,1552,1556,1560,1564,1568,1571,1575,1579,1583,1587,1591,1595,1599,1603,1607,1611,1615,1619,1623,1627,1631,1636,1640,1645,1649,1653,1658,1663,1668,1672,1677,1681,1686,1691,1696,1701,1705,1710,1715,1720,1725,1730,1735,1740,1745,1750,1755,1760,1765,1770,1774,1779,1784,1789,1794],{"id":5,"title":6,"titles":7,"content":8,"level":9},"/v1.0.1/overview","Overview",[],"Schema-driven pipeline factory for pipz with hot-reloading capabilities",1,{"id":11,"title":6,"titles":12,"content":13,"level":9},"/v1.0.1/overview#overview",[],"Building data pipelines in Go typically means hardcoding structure at compile time. Change the flow? Rebuild and redeploy. Flume offers a different approach: define pipeline structure in configuration, update it at runtime. factory := flume.New[Order]()\n\n// Register reusable components\nfactory.Add(pipz.Apply(\"validate\", validateOrder))\nfactory.Add(pipz.Transform(\"enrich\", enrichOrder))\nfactory.AddPredicate(flume.Predicate[Order]{\n    Name:      \"high-value\",\n    Predicate: func(ctx context.Context, o Order) bool { return o.Total > 1000 },\n})\n\n// Build from schema\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: enrich\n`)\n\n// Update at runtime - no restart required\nfactory.SetSchema(\"orders\", newSchema) Type-safe, hot-reloadable, zero external dependencies.",{"id":15,"title":16,"titles":17,"content":18,"level":19},"/v1.0.1/overview#architecture","Architecture",[6],"┌──────────────────────────────────────────────────────────────┐\n│                         Factory[T]                           │\n│                                                              │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │\n│  │ Processors  │  │ Predicates  │  │ Conditions  │          │\n│  │ (Chainable) │  │  (bool fn)  │  │ (string fn) │          │\n│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │\n│         │                │                │                  │\n│         └────────────────┼────────────────┘                  │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │                   Schema (YAML/JSON)                  │  │\n│  │   type: sequence                                      │  │\n│  │   children:                                           │  │\n│  │     - ref: validate                                   │  │\n│  │     - type: filter ...                                │  │\n│  └───────────────────────────────────────────────────────┘  │\n│                          │                                   │\n│                    Build │ Validate                          │\n│                          ▼                                   │\n│  ┌───────────────────────────────────────────────────────┐  │\n│  │              pipz.Chainable[T] Pipeline               │  │\n│  └───────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────┘ Register components once, compose them via schemas, build executable pipelines. Schemas validate against registered components before building.",2,{"id":21,"title":22,"titles":23,"content":24,"level":19},"/v1.0.1/overview#philosophy","Philosophy",[6],"",{"id":26,"title":27,"titles":28,"content":29,"level":30},"/v1.0.1/overview#configuration-over-code","Configuration Over Code",[6,22],"Pipeline structure belongs in configuration. Business logic belongs in code. # Configuration: structure\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process // Code: behaviour\nfactory.Add(pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n    if o.Total \u003C= 0 {\n        return o, errors.New(\"invalid total\")\n    }\n    return o, nil\n}))",3,{"id":32,"title":33,"titles":34,"content":35,"level":30},"/v1.0.1/overview#zero-magic","Zero Magic",[6,22],"Processors name themselves via pipz.NameSchemas are plain YAML/JSONValidation errors include full pathsNo reflection at runtime",{"id":37,"title":38,"titles":39,"content":40,"level":19},"/v1.0.1/overview#capabilities","Capabilities",[6],"Schema-driven pipelines open possibilities: Hot Reloading - Update pipeline behaviour without restarts. A/B test processing logic, toggle features, respond to changing requirements. Multi-tenant Processing - Different schemas per tenant. Same registered components, different compositions based on customer tier or configuration. Channel Integration - Route pipeline outputs to Go channels. Fan-out to multiple streams, integrate with async consumers. Resilience Patterns - Retry, timeout, circuit breaker, rate limiting - all declarative in schema. Change resilience strategy without code changes. Flume provides the composition layer. What pipelines you build is up to you.",{"id":42,"title":43,"titles":44,"content":24,"level":19},"/v1.0.1/overview#priorities","Priorities",[6],{"id":46,"title":47,"titles":48,"content":49,"level":30},"/v1.0.1/overview#type-safety","Type Safety",[6,43],"Full generics from factory to pipeline. The type flows through: factory := flume.New[Order]()      // Factory[Order]\nfactory.Add(orderProcessor)         // Only accepts Chainable[Order]\npipeline, _ := factory.Build(schema)\nresult, _ := pipeline.Process(ctx, order) // Returns (Order, error)",{"id":51,"title":52,"titles":53,"content":54,"level":30},"/v1.0.1/overview#validation","Validation",[6,43],"Schemas validate before building. Missing references, invalid configurations, structural errors - caught early with clear messages: 3 validation errors:\n  1. root.children[0]: processor 'missing' not found\n  2. root.children[1]: predicate 'unknown' not found\n  3. root.children[2].timeout: invalid duration \"bad\"",{"id":56,"title":57,"titles":58,"content":59,"level":30},"/v1.0.1/overview#performance","Performance",[6,43],"Built pipelines execute with zero overhead - the result is a pipz pipeline. Cost is only at build time: OperationTimePipeline execution (3-step sequence)~459 nsSchema build (10-step sequence)~6.7 µs Build once, execute many times.",{"id":61,"title":62,"titles":63,"content":24,"level":19},"/v1.0.1/overview#documentation","Documentation",[6],{"id":65,"title":66,"titles":67,"content":68,"level":30},"/v1.0.1/overview#learn","Learn",[6,62],"Quickstart - Your first pipeline in 5 minutesCore Concepts - Factories, schemas, and componentsArchitecture - How Flume works under the hoodBuilding Pipelines - From simple to complex",{"id":70,"title":71,"titles":72,"content":73,"level":30},"/v1.0.1/overview#guides","Guides",[6,62],"Schema Design - Best practices for schema structureHot Reloading - Update pipelines without restartsError Handling - Retry, fallback, circuit breakersTesting - Testing schema-driven pipelinesObservability - Monitoring with capitan events",{"id":75,"title":76,"titles":77,"content":78,"level":30},"/v1.0.1/overview#reference","Reference",[6,62],"API Reference - Factory methods and typesSchema Format - YAML/JSON specificationConnector Types - All 14 connectorsEvents - Observability signals html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}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 .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"id":80,"title":81,"titles":82,"content":83,"level":9},"/v1.0.1/learn/quickstart","Quickstart",[],"Build your first Flume pipeline in 5 minutes",{"id":85,"title":81,"titles":86,"content":87,"level":9},"/v1.0.1/learn/quickstart#quickstart",[],"Build your first schema-driven pipeline in 5 minutes.",{"id":89,"title":90,"titles":91,"content":92,"level":19},"/v1.0.1/learn/quickstart#installation","Installation",[81],"go get github.com/zoobz-io/flume",{"id":94,"title":95,"titles":96,"content":97,"level":19},"/v1.0.1/learn/quickstart#step-1-define-your-data-type","Step 1: Define Your Data Type",[81],"Your data type must implement pipz.Cloner[T]: package main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID       string\n    Customer string\n    Total    float64\n    Status   string\n}\n\nfunc (o Order) Clone() Order {\n    return Order{\n        ID:       o.ID,\n        Customer: o.Customer,\n        Total:    o.Total,\n        Status:   o.Status,\n    }\n}",{"id":99,"title":100,"titles":101,"content":102,"level":19},"/v1.0.1/learn/quickstart#step-2-create-a-factory","Step 2: Create a Factory",[81],"func main() {\n    factory := flume.New[Order]()\n}",{"id":104,"title":105,"titles":106,"content":107,"level":19},"/v1.0.1/learn/quickstart#step-3-register-processors","Step 3: Register Processors",[81],"// Validate order\n    factory.Add(pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n        if o.Total \u003C= 0 {\n            return o, fmt.Errorf(\"invalid total: %f\", o.Total)\n        }\n        return o, nil\n    }))\n\n    // Enrich with status\n    factory.Add(pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n        o.Status = \"validated\"\n        return o\n    }))\n\n    // Log order\n    factory.Add(pipz.Effect(\"log\", func(ctx context.Context, o Order) error {\n        fmt.Printf(\"Processing order: %s for %s ($%.2f)\\n\", o.ID, o.Customer, o.Total)\n        return nil\n    }))",{"id":109,"title":110,"titles":111,"content":112,"level":19},"/v1.0.1/learn/quickstart#step-4-define-schema","Step 4: Define Schema",[81],"schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: log\n`",{"id":114,"title":115,"titles":116,"content":117,"level":19},"/v1.0.1/learn/quickstart#step-5-build-and-use","Step 5: Build and Use",[81],"pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        panic(err)\n    }\n\n    order := Order{\n        ID:       \"ORD-001\",\n        Customer: \"Alice\",\n        Total:    99.99,\n    }\n\n    result, err := pipeline.Process(context.Background(), order)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"Result: %+v\\n\", result)\n}",{"id":119,"title":120,"titles":121,"content":122,"level":19},"/v1.0.1/learn/quickstart#complete-example","Complete Example",[81],"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID       string\n    Customer string\n    Total    float64\n    Status   string\n}\n\nfunc (o Order) Clone() Order {\n    return Order{ID: o.ID, Customer: o.Customer, Total: o.Total, Status: o.Status}\n}\n\nfunc main() {\n    factory := flume.New[Order]()\n\n    // Register processors\n    factory.Add(\n        pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n            if o.Total \u003C= 0 {\n                return o, fmt.Errorf(\"invalid total: %f\", o.Total)\n            }\n            return o, nil\n        }),\n        pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n            o.Status = \"validated\"\n            return o\n        }),\n        pipz.Effect(\"log\", func(ctx context.Context, o Order) error {\n            fmt.Printf(\"Order: %s ($%.2f)\\n\", o.ID, o.Total)\n            return nil\n        }),\n    )\n\n    // Define and build pipeline\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: log\n`\n\n    pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        panic(err)\n    }\n\n    // Process\n    result, err := pipeline.Process(context.Background(), Order{\n        ID:       \"ORD-001\",\n        Customer: \"Alice\",\n        Total:    99.99,\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"Final: %+v\\n\", result)\n} Output: Order: ORD-001 ($99.99)\nFinal: {ID:ORD-001 Customer:Alice Total:99.99 Status:validated}",{"id":124,"title":125,"titles":126,"content":127,"level":19},"/v1.0.1/learn/quickstart#adding-conditional-logic","Adding Conditional Logic",[81],"Add a predicate for conditional processing: factory.AddPredicate(flume.Predicate[Order]{\n        Name: \"high-value\",\n        Predicate: func(ctx context.Context, o Order) bool {\n            return o.Total > 100\n        },\n    })\n\n    factory.Add(pipz.Effect(\"premium-notify\", func(ctx context.Context, o Order) error {\n        fmt.Println(\"High-value order detected!\")\n        return nil\n    }))\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: premium-notify\n  - ref: log\n`",{"id":129,"title":130,"titles":131,"content":132,"level":19},"/v1.0.1/learn/quickstart#adding-error-handling","Adding Error Handling",[81],"Wrap processors with retry: schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: retry\n    attempts: 3\n    child:\n      ref: external-api-call\n  - ref: log\n`",{"id":134,"title":135,"titles":136,"content":137,"level":19},"/v1.0.1/learn/quickstart#merging-concurrent-results","Merging Concurrent Results",[81],"When running processors concurrently, use a reducer to merge results: // Register parallel enrichment processors\n    factory.Add(\n        pipz.Transform(\"fetch-customer\", func(ctx context.Context, o Order) Order {\n            o.Customer = \"Alice (Premium)\"\n            return o\n        }),\n        pipz.Transform(\"fetch-inventory\", func(ctx context.Context, o Order) Order {\n            o.Status = \"in-stock\"\n            return o\n        }),\n    )\n\n    // Register a reducer to merge results\n    factory.AddReducer(flume.Reducer[Order]{\n        Name: \"merge-enrichments\",\n        Reducer: func(original Order, results map[pipz.Name]Order, errors map[pipz.Name]error) Order {\n            for _, result := range results {\n                if result.Customer != \"\" {\n                    original.Customer = result.Customer\n                }\n                if result.Status != \"\" {\n                    original.Status = result.Status\n                }\n            }\n            return original\n        },\n    })\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: concurrent\n    reducer: merge-enrichments\n    children:\n      - ref: fetch-customer\n      - ref: fetch-inventory\n  - ref: log\n`",{"id":139,"title":140,"titles":141,"content":142,"level":19},"/v1.0.1/learn/quickstart#loading-from-files","Loading from Files",[81],"pipeline, err := factory.BuildFromFile(\"pipeline.yaml\")",{"id":144,"title":145,"titles":146,"content":147,"level":19},"/v1.0.1/learn/quickstart#using-named-schemas","Using Named Schemas",[81],"For hot-reloading support: // Register named schema\n    err := factory.SetSchema(\"order-processing\", schema)\n    if err != nil {\n        panic(err)\n    }\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\n    binding, err := factory.Bind(pipelineID, \"order-processing\", flume.WithAutoSync())\n    if err != nil {\n        panic(err)\n    }\n\n    // Process requests\n    result, err := binding.Process(ctx, order)\n\n    // Update schema at runtime - binding rebuilds automatically\n    newSchema := Schema{...}\n    factory.SetSchema(\"order-processing\", newSchema)",{"id":149,"title":150,"titles":151,"content":152,"level":19},"/v1.0.1/learn/quickstart#next-steps","Next Steps",[81],"Building Pipelines - Complex schema patternsCore Concepts - Deeper understandingSchema Format - Complete reference html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}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 .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"id":154,"title":155,"titles":156,"content":157,"level":9},"/v1.0.1/learn/core-concepts","Core Concepts",[],"Understanding Flume's fundamental building blocks - factories, schemas, and components",{"id":159,"title":155,"titles":160,"content":161,"level":9},"/v1.0.1/learn/core-concepts#core-concepts",[],"Flume is built around three core concepts: the Factory, Schemas, and Components.",{"id":163,"title":164,"titles":165,"content":166,"level":19},"/v1.0.1/learn/core-concepts#the-factory","The Factory",[155],"The factory is Flume's central registry. It holds all registered components and builds pipelines from schemas. factory := flume.New[Order]() The factory is generic over your data type T. This type must implement pipz.Cloner[T] to support parallel processing: type Order struct {\n    ID    string\n    Total float64\n}\n\nfunc (o Order) Clone() Order {\n    return Order{ID: o.ID, Total: o.Total}\n}",{"id":168,"title":169,"titles":170,"content":171,"level":30},"/v1.0.1/learn/core-concepts#factory-responsibilities","Factory Responsibilities",[155,164],"Component Registry - Store processors, predicates, and conditionsSchema Storage - Manage named schemas with hot-reload supportPipeline Building - Construct pipz pipelines from schemasValidation - Verify schemas before building",{"id":173,"title":174,"titles":175,"content":176,"level":19},"/v1.0.1/learn/core-concepts#components","Components",[155],"Components are the building blocks registered with the factory. There are three types:",{"id":178,"title":179,"titles":180,"content":181,"level":30},"/v1.0.1/learn/core-concepts#processors","Processors",[155,174],"Processors are pipz Chainable[T] implementations - the actual processing logic: // Using pipz constructors\nfactory.Add(\n    pipz.Apply(\"validate\", validateOrder),      // T -> (T, error)\n    pipz.Transform(\"normalize\", normalizeOrder), // T -> T\n    pipz.Effect(\"log\", logOrder),               // T -> error (no modification)\n) Reference in schemas: ref: validate",{"id":183,"title":184,"titles":185,"content":186,"level":30},"/v1.0.1/learn/core-concepts#predicates","Predicates",[155,174],"Predicates are boolean functions for conditional processing: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"is-premium\",\n    Description: \"Checks if customer has premium tier\",\n    Predicate: func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    },\n}) Used in filter nodes: type: filter\npredicate: is-premium\nthen:\n  ref: premium-handler",{"id":188,"title":189,"titles":190,"content":191,"level":30},"/v1.0.1/learn/core-concepts#conditions","Conditions",[155,174],"Conditions return strings for multi-way routing: factory.AddCondition(flume.Condition[Order]{\n    Name:        \"order-status\",\n    Description: \"Returns the current order status\",\n    Values:      []string{\"pending\", \"approved\", \"rejected\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Status\n    },\n}) Used in switch nodes: type: switch\ncondition: order-status\nroutes:\n  pending:\n    ref: handle-pending\n  approved:\n    ref: handle-approved\ndefault:\n  ref: handle-unknown",{"id":193,"title":194,"titles":195,"content":196,"level":19},"/v1.0.1/learn/core-concepts#schemas","Schemas",[155],"Schemas define pipeline structure as YAML or JSON documents.",{"id":198,"title":199,"titles":200,"content":201,"level":30},"/v1.0.1/learn/core-concepts#schema-structure","Schema Structure",[155,194],"version: \"1.0.0\"    # Optional version tracking\ntype: sequence      # Connector type\nname: my-pipeline   # Optional name override\nchildren:           # Child nodes\n  - ref: step1\n  - ref: step2",{"id":203,"title":204,"titles":205,"content":206,"level":30},"/v1.0.1/learn/core-concepts#node-types","Node Types",[155,194],"Nodes are either references or connectors: # Reference: points to registered processor\nref: validate\n\n# Connector: defines structure\ntype: sequence\nchildren:\n  - ref: step1\n  - ref: step2",{"id":208,"title":209,"titles":210,"content":211,"level":30},"/v1.0.1/learn/core-concepts#building-pipelines","Building Pipelines",[155,194],"Build from strings or files: // From YAML string\npipeline, err := factory.BuildFromYAML(yamlStr)\n\n// From JSON string\npipeline, err := factory.BuildFromJSON(jsonStr)\n\n// From file (auto-detects format)\npipeline, err := factory.BuildFromFile(\"pipeline.yaml\")\n\n// From Schema struct\npipeline, err := factory.Build(schema)",{"id":213,"title":214,"titles":215,"content":216,"level":19},"/v1.0.1/learn/core-concepts#dynamic-schema-management","Dynamic Schema Management",[155],"Flume supports named schemas that can be updated at runtime: // Register a named schema\nerr := factory.SetSchema(\"order-pipeline\", schema)\n\n// Create a binding with auto-sync enabled\npipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\n\n// Process requests (lock-free)\nresult, err := binding.Process(ctx, order)\n\n// Update the schema - auto-sync bindings rebuild automatically\nerr = factory.SetSchema(\"order-pipeline\", newSchema)\n\n// Remove a schema\nremoved := factory.RemoveSchema(\"order-pipeline\")\n\n// List all schemas\nnames := factory.ListSchemas()",{"id":218,"title":219,"titles":220,"content":221,"level":30},"/v1.0.1/learn/core-concepts#hot-reloading","Hot Reloading",[155,214],"When you update a schema: New pipeline is built and validatedAll auto-sync bindings rebuild atomicallyIn-flight requests complete with old pipelineNew requests use updated pipeline // Watcher pattern\nfor schemaChange := range watcher.Changes() {\n    if err := factory.SetSchema(schemaChange.Name, schemaChange.Schema); err != nil {\n        log.Printf(\"failed to update schema: %v\", err)\n        continue\n    }\n    log.Printf(\"schema %s updated to version %s\",\n        schemaChange.Name, schemaChange.Schema.Version)\n}",{"id":223,"title":52,"titles":224,"content":225,"level":19},"/v1.0.1/learn/core-concepts#validation",[155],"Flume validates schemas before building, catching errors early: err := factory.ValidateSchema(schema)\nif err != nil {\n    // ValidationErrors with detailed paths\n    fmt.Println(err)\n    // Output:\n    // 3 validation errors:\n    //   1. root.children[0]: processor 'missing' not found\n    //   2. root.children[1]: predicate 'unknown' not found\n    //   3. root.children[1].then: processor 'also-missing' not found\n}",{"id":227,"title":228,"titles":229,"content":230,"level":30},"/v1.0.1/learn/core-concepts#what-gets-validated","What Gets Validated",[155,52],"All processor/predicate/condition references existRequired fields are presentConnector constraints are met (e.g., fallback needs 2 children)Configuration values are valid (e.g., positive retry attempts)Duration strings are parseableNo circular references",{"id":232,"title":233,"titles":234,"content":235,"level":19},"/v1.0.1/learn/core-concepts#component-introspection","Component Introspection",[155],"Query the factory's registrations: // Check existence\nfactory.HasProcessor(\"validate\")\nfactory.HasPredicate(\"is-premium\")\nfactory.HasCondition(\"order-status\")\n\n// List all\nprocessors := factory.ListProcessors()  // []pipz.Name\npredicates := factory.ListPredicates()\nconditions := factory.ListConditions()",{"id":237,"title":238,"titles":239,"content":240,"level":19},"/v1.0.1/learn/core-concepts#component-removal","Component Removal",[155],"Remove components when no longer needed: // Remove processors (returns count removed)\nremoved := factory.Remove(\"old-processor\", \"deprecated\")\n\n// Remove predicates\nfactory.RemovePredicate(\"old-predicate\")\n\n// Remove conditions\nfactory.RemoveCondition(\"old-condition\") Note: Removing a component doesn't affect already-built pipelines, but will cause validation errors if you try to build schemas that reference them.",{"id":242,"title":150,"titles":243,"content":244,"level":19},"/v1.0.1/learn/core-concepts#next-steps",[155],"Architecture - How Flume works under the hoodQuickstart - Build your first pipelineAPI Reference - Complete method documentation html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}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 .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",{"id":246,"title":16,"titles":247,"content":248,"level":9},"/v1.0.1/learn/architecture",[],"How Flume works under the hood - from schema to pipeline",{"id":250,"title":16,"titles":251,"content":252,"level":9},"/v1.0.1/learn/architecture#architecture",[],"Understanding Flume's internal architecture helps you use it effectively and debug issues.",{"id":254,"title":6,"titles":255,"content":256,"level":19},"/v1.0.1/learn/architecture#overview",[16],"┌─────────────────────────────────────────────────────────────┐\n│                         Factory[T]                          │\n├─────────────────────────────────────────────────────────────┤\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │\n│  │ Processors  │  │ Predicates  │  │ Conditions  │         │\n│  │  map[Name]  │  │  map[Name]  │  │  map[Name]  │         │\n│  └─────────────┘  └─────────────┘  └─────────────┘         │\n│                                                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │\n│  │  Schemas    │  │  Pipelines  │  │  Channels   │         │\n│  │ map[string] │  │ atomic.Ptr  │  │ map[string] │         │\n│  └─────────────┘  └─────────────┘  └─────────────┘         │\n└─────────────────────────────────────────────────────────────┘\n                           │\n                           ▼\n              ┌────────────────────────┐\n              │    Schema Document     │\n              │  (YAML/JSON/Struct)    │\n              └────────────────────────┘\n                           │\n            ┌──────────────┼──────────────┐\n            ▼              ▼              ▼\n      ┌──────────┐  ┌──────────┐  ┌──────────┐\n      │  Parse   │  │ Validate │  │  Build   │\n      └──────────┘  └──────────┘  └──────────┘\n                           │\n                           ▼\n              ┌────────────────────────┐\n              │   pipz.Chainable[T]    │\n              │    (ready to use)      │\n              └────────────────────────┘",{"id":258,"title":259,"titles":260,"content":261,"level":19},"/v1.0.1/learn/architecture#factory-structure","Factory Structure",[16],"The factory maintains six internal maps protected by a read-write mutex: type Factory[T pipz.Cloner[T]] struct {\n    processors map[pipz.Name]processorMeta[T]\n    predicates map[pipz.Name]predicateMeta[T]\n    conditions map[pipz.Name]conditionMeta[T]\n    schemas    map[string]*Schema\n    pipelines  map[string]*atomic.Pointer[pipz.Chainable[T]]\n    channels   map[string]chan\u003C- T\n    mu         sync.RWMutex\n}",{"id":263,"title":264,"titles":265,"content":266,"level":30},"/v1.0.1/learn/architecture#thread-safety","Thread Safety",[16,259],"Read operations (lookups, list, build) acquire read locksWrite operations (add, remove, set schema) acquire write locksPipeline access uses atomic pointers for lock-free retrieval",{"id":268,"title":269,"titles":270,"content":24,"level":19},"/v1.0.1/learn/architecture#schema-processing-pipeline","Schema Processing Pipeline",[16],{"id":272,"title":273,"titles":274,"content":275,"level":30},"/v1.0.1/learn/architecture#_1-parsing","1. Parsing",[16,269],"Schemas can be loaded from multiple sources: // String parsing\nfactory.BuildFromYAML(yamlStr)\nfactory.BuildFromJSON(jsonStr)\n\n// File loading (detects format from extension)\nfactory.BuildFromFile(\"pipeline.yaml\")\n\n// Direct struct\nfactory.Build(schema) The parser converts YAML/JSON into the Schema struct: type Schema struct {\n    Version string\n    Node    // embedded\n}\n\ntype Node struct {\n    Ref       string\n    Type      string\n    Name      string\n    Children  []Node\n    Child     *Node\n    // ... connector-specific fields\n}",{"id":277,"title":278,"titles":279,"content":280,"level":30},"/v1.0.1/learn/architecture#_2-validation","2. Validation",[16,269],"Before building, the factory validates the entire schema tree: func (f *Factory[T]) ValidateSchema(schema Schema) error {\n    var errors ValidationErrors\n    f.validateNode(&schema.Node, []string{\"root\"}, &errors)\n    if len(errors) > 0 {\n        return errors\n    }\n    return nil\n} Validation traverses the tree recursively, checking: References exist - All ref: values point to registered processorsPredicates exist - All predicate: values are registeredConditions exist - All condition: values are registeredRequired fields - Each node type has its required fieldsConstraints - Type-specific rules (e.g., fallback needs exactly 2 children)No cycles - Reference chains don't loop back",{"id":282,"title":283,"titles":284,"content":285,"level":30},"/v1.0.1/learn/architecture#_3-building","3. Building",[16,269],"The builder recursively constructs pipz chainables: func (f *Factory[T]) buildNode(node *Node) (pipz.Chainable[T], error) {\n    // Handle processor reference\n    if node.Ref != \"\" {\n        return f.processors[pipz.Name(node.Ref)].processor, nil\n    }\n\n    // Handle connector types\n    switch node.Type {\n    case \"sequence\":\n        return f.buildSequence(node)\n    case \"concurrent\":\n        return f.buildConcurrent(node)\n    // ... other types\n    }\n} Each connector type has a dedicated builder that: Validates connector-specific requirementsRecursively builds child nodesConstructs the pipz connector with appropriate options",{"id":287,"title":288,"titles":289,"content":290,"level":19},"/v1.0.1/learn/architecture#connector-mapping","Connector Mapping",[16],"Flume schema types map directly to pipz constructors: Schema Typepipz Constructorsequencepipz.NewSequenceconcurrentpipz.NewConcurrentracepipz.NewRacefallbackpipz.NewFallbackretrypipz.NewRetry or pipz.NewBackofftimeoutpipz.NewTimeoutfilterpipz.NewFilter or custom routingswitchpipz.NewSwitchcircuit-breakerpipz.NewCircuitBreakerrate-limitpipz.NewRateLimiter + pipz.NewSequence",{"id":292,"title":293,"titles":294,"content":295,"level":19},"/v1.0.1/learn/architecture#hot-reload-mechanism","Hot Reload Mechanism",[16],"Named schemas support atomic updates: func (f *Factory[T]) SetSchema(name string, schema Schema) error {\n    // 1. Validate first\n    if err := f.ValidateSchema(schema); err != nil {\n        return err\n    }\n\n    // 2. Build pipeline\n    pipeline, err := f.Build(schema)\n    if err != nil {\n        return err\n    }\n\n    // 3. Atomic update\n    f.mu.Lock()\n    defer f.mu.Unlock()\n\n    f.schemas[name] = &schema\n    if ptr, exists := f.pipelines[name]; exists {\n        ptr.Store(&pipeline)  // Atomic swap\n    } else {\n        ptr := &atomic.Pointer[pipz.Chainable[T]]{}\n        ptr.Store(&pipeline)\n        f.pipelines[name] = ptr\n    }\n    return nil\n} Retrieval is lock-free after the initial lookup: func (f *Factory[T]) Pipeline(name string) (pipz.Chainable[T], bool) {\n    f.mu.RLock()\n    ptr := f.pipelines[name]\n    f.mu.RUnlock()\n\n    if ptr == nil {\n        return nil, false\n    }\n    return *ptr.Load(), true  // Atomic load\n}",{"id":297,"title":298,"titles":299,"content":300,"level":19},"/v1.0.1/learn/architecture#observability-integration","Observability Integration",[16],"Flume emits Capitan events throughout its lifecycle: // Factory events\nFactoryCreated\nProcessorRegistered\nPredicateRegistered\nConditionRegistered\n\n// Schema events\nSchemaValidationStarted\nSchemaValidationCompleted\nSchemaValidationFailed\nSchemaBuildStarted\nSchemaBuildCompleted\nSchemaBuildFailed\n\n// Dynamic schema events\nSchemaRegistered\nSchemaUpdated\nSchemaRemoved\nPipelineRetrieved Events include typed fields: capitan.Emit(ctx, SchemaRegistered,\n    KeyName.Field(name),\n    KeyVersion.Field(schema.Version))",{"id":302,"title":303,"titles":304,"content":305,"level":19},"/v1.0.1/learn/architecture#channel-integration","Channel Integration",[16],"Channels enable stream processing patterns: factory.AddChannel(\"output\", outputChan) Stream nodes wrap channels in pipz effects: func (f *Factory[T]) buildStream(node *Node) (pipz.Chainable[T], error) {\n    channel := f.channels[node.Stream]\n\n    return pipz.Effect(\n        pipz.Name(fmt.Sprintf(\"stream:%s\", node.Stream)),\n        func(_ context.Context, item T) error {\n            channel \u003C- item\n            return nil\n        },\n    ), nil\n}",{"id":307,"title":308,"titles":309,"content":24,"level":19},"/v1.0.1/learn/architecture#memory-model","Memory Model",[16],{"id":311,"title":312,"titles":313,"content":314,"level":30},"/v1.0.1/learn/architecture#component-storage","Component Storage",[16,308],"Components are stored by value in maps: type processorMeta[T any] struct {\n    processor   pipz.Chainable[T]  // Interface value\n    description string\n    tags        []string\n}",{"id":316,"title":317,"titles":318,"content":319,"level":30},"/v1.0.1/learn/architecture#pipeline-lifecycle","Pipeline Lifecycle",[16,308],"Registration - Components stored in factory mapsBuild - New pipeline created from current registrationsStorage - Pipeline stored via atomic pointer (for named schemas)Usage - Pipeline used directly, no factory reference neededUpdate - New pipeline built, pointer atomically swappedRemoval - Schema removed, pipeline garbage collected when unreferenced",{"id":321,"title":322,"titles":323,"content":324,"level":30},"/v1.0.1/learn/architecture#concurrency","Concurrency",[16,308],"Multiple goroutines can safely call Pipeline() concurrentlyBuild operations are serialized through the write lockBuilt pipelines are independent of the factory",{"id":326,"title":150,"titles":327,"content":328,"level":19},"/v1.0.1/learn/architecture#next-steps",[16],"Quickstart - Build your first pipelineSchema Design - Best practicesEvents Reference - All observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}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 .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",{"id":330,"title":209,"titles":331,"content":332,"level":9},"/v1.0.1/learn/building-pipelines",[],"From simple sequences to complex nested pipelines",{"id":334,"title":209,"titles":335,"content":336,"level":9},"/v1.0.1/learn/building-pipelines#building-pipelines",[],"Learn to construct increasingly sophisticated pipelines with Flume schemas.",{"id":338,"title":339,"titles":340,"content":341,"level":19},"/v1.0.1/learn/building-pipelines#simple-sequences","Simple Sequences",[209],"The most basic pipeline chains processors sequentially: type: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - ref: save Each processor receives the output of the previous one.",{"id":343,"title":344,"titles":345,"content":346,"level":19},"/v1.0.1/learn/building-pipelines#parallel-execution","Parallel Execution",[209],"Process data concurrently with the concurrent type: type: sequence\nchildren:\n  - ref: validate\n  - type: concurrent\n    children:\n      - ref: enrich-from-db\n      - ref: enrich-from-api\n      - ref: calculate-score\n  - ref: save All concurrent children receive cloned data and execute in parallel. Results are merged.",{"id":348,"title":349,"titles":350,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#conditional-processing","Conditional Processing",[209],{"id":352,"title":353,"titles":354,"content":355,"level":30},"/v1.0.1/learn/building-pipelines#filter","Filter",[209,349],"Execute a branch only when a condition is met: type: filter\npredicate: is-premium\nthen:\n  ref: apply-discount With else branch: type: filter\npredicate: is-premium\nthen:\n  ref: premium-handler\nelse:\n  ref: standard-handler",{"id":357,"title":358,"titles":359,"content":360,"level":30},"/v1.0.1/learn/building-pipelines#switch","Switch",[209,349],"Route to different handlers based on a condition value: type: switch\ncondition: order-type\nroutes:\n  subscription:\n    ref: handle-subscription\n  one-time:\n    ref: handle-single-purchase\n  gift:\n    type: sequence\n    children:\n      - ref: validate-gift\n      - ref: handle-gift\ndefault:\n  ref: handle-unknown Register the condition: factory.AddCondition(flume.Condition[Order]{\n    Name: \"order-type\",\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Type // \"subscription\", \"one-time\", \"gift\", etc.\n    },\n})",{"id":362,"title":363,"titles":364,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#error-handling","Error Handling",[209],{"id":366,"title":367,"titles":368,"content":369,"level":30},"/v1.0.1/learn/building-pipelines#retry","Retry",[209,363],"Retry failed operations: type: retry\nattempts: 3\nchild:\n  ref: flaky-api With exponential backoff: type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: external-service",{"id":371,"title":372,"titles":373,"content":374,"level":30},"/v1.0.1/learn/building-pipelines#fallback","Fallback",[209,363],"Use a backup handler on failure: type: fallback\nchildren:\n  - ref: primary-service\n  - ref: backup-service",{"id":376,"title":377,"titles":378,"content":379,"level":30},"/v1.0.1/learn/building-pipelines#timeout","Timeout",[209,363],"Enforce time limits: type: timeout\nduration: \"5s\"\nchild:\n  ref: slow-operation",{"id":381,"title":382,"titles":383,"content":384,"level":30},"/v1.0.1/learn/building-pipelines#circuit-breaker","Circuit Breaker",[209,363],"Prevent cascading failures: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: unreliable-service",{"id":386,"title":387,"titles":388,"content":389,"level":30},"/v1.0.1/learn/building-pipelines#rate-limiting","Rate Limiting",[209,363],"Control throughput: type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: rate-sensitive-api",{"id":391,"title":392,"titles":393,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#nesting-patterns","Nesting Patterns",[209],{"id":395,"title":396,"titles":397,"content":398,"level":30},"/v1.0.1/learn/building-pipelines#resilient-external-calls","Resilient External Calls",[209,392],"type: circuit-breaker\nfailure_threshold: 3\nrecovery_timeout: \"60s\"\nchild:\n  type: timeout\n  duration: \"10s\"\n  child:\n    type: retry\n    attempts: 3\n    backoff: \"200ms\"\n    child:\n      ref: external-api",{"id":400,"title":401,"titles":402,"content":403,"level":30},"/v1.0.1/learn/building-pipelines#conditional-with-fallback","Conditional with Fallback",[209,392],"type: filter\npredicate: has-cache\nthen:\n  type: fallback\n  children:\n    - ref: get-from-cache\n    - ref: get-from-db\nelse:\n  ref: get-from-db",{"id":405,"title":406,"titles":407,"content":408,"level":30},"/v1.0.1/learn/building-pipelines#parallel-with-error-handling","Parallel with Error Handling",[209,392],"type: concurrent\nchildren:\n  - type: retry\n    attempts: 2\n    child:\n      ref: service-a\n  - type: fallback\n    children:\n      - ref: service-b-primary\n      - ref: service-b-backup\n  - ref: service-c",{"id":410,"title":120,"titles":411,"content":412,"level":19},"/v1.0.1/learn/building-pipelines#complete-example",[209],"An order processing pipeline: version: \"2.0.0\"\ntype: sequence\nname: order-processing\nchildren:\n  # Step 1: Validate\n  - ref: validate-order\n\n  # Step 2: Parallel enrichment\n  - type: concurrent\n    name: enrich\n    children:\n      - ref: fetch-customer\n      - ref: fetch-inventory\n      - ref: calculate-tax\n\n  # Step 3: Premium handling\n  - type: filter\n    predicate: is-premium-customer\n    then:\n      type: sequence\n      children:\n        - ref: apply-loyalty-discount\n        - ref: priority-queue\n\n  # Step 4: Payment routing\n  - type: switch\n    condition: payment-method\n    routes:\n      credit:\n        type: circuit-breaker\n        failure_threshold: 3\n        recovery_timeout: \"60s\"\n        child:\n          type: retry\n          attempts: 3\n          backoff: \"500ms\"\n          child:\n            ref: charge-credit-card\n      paypal:\n        type: timeout\n        duration: \"30s\"\n        child:\n          ref: paypal-checkout\n      crypto:\n        ref: crypto-payment\n    default:\n      ref: manual-payment-review\n\n  # Step 5: Post-payment\n  - type: concurrent\n    children:\n      - ref: update-inventory\n      - ref: send-confirmation\n      - type: filter\n        predicate: requires-shipping\n        then:\n          ref: create-shipment\n\n  # Step 6: Finalize\n  - ref: complete-order Registrations: // Processors\nfactory.Add(\n    pipz.Apply(\"validate-order\", validateOrder),\n    pipz.Apply(\"fetch-customer\", fetchCustomer),\n    pipz.Apply(\"fetch-inventory\", fetchInventory),\n    // ... more processors\n)\n\n// Predicates\nfactory.AddPredicate(\n    flume.Predicate[Order]{Name: \"is-premium-customer\", Predicate: isPremium},\n    flume.Predicate[Order]{Name: \"requires-shipping\", Predicate: needsShipping},\n)\n\n// Conditions\nfactory.AddCondition(flume.Condition[Order]{\n    Name:   \"payment-method\",\n    Values: []string{\"credit\", \"paypal\", \"crypto\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.PaymentMethod\n    },\n})",{"id":414,"title":415,"titles":416,"content":24,"level":19},"/v1.0.1/learn/building-pipelines#schema-design-tips","Schema Design Tips",[209],{"id":418,"title":419,"titles":420,"content":421,"level":30},"/v1.0.1/learn/building-pipelines#_1-name-complex-nodes","1. Name Complex Nodes",[209,415],"type: sequence\nname: payment-handling  # Helps with debugging\nchildren:\n  - ref: charge\n  - ref: confirm",{"id":423,"title":424,"titles":425,"content":426,"level":30},"/v1.0.1/learn/building-pipelines#_2-keep-depth-manageable","2. Keep Depth Manageable",[209,415],"Break deeply nested schemas into named sub-pipelines: // Register sub-pipeline\nfactory.SetSchema(\"payment-flow\", paymentSchema)",{"id":428,"title":429,"titles":430,"content":431,"level":30},"/v1.0.1/learn/building-pipelines#_3-version-your-schemas","3. Version Your Schemas",[209,415],"version: \"1.2.0\"\ntype: sequence\n# ...",{"id":433,"title":434,"titles":435,"content":436,"level":30},"/v1.0.1/learn/building-pipelines#_4-document-with-comments","4. Document with Comments",[209,415],"YAML comments aren't preserved, but you can add documentation in companion files or use the description fields when registering components: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"high-value\",\n    Description: \"Orders over $1000 for premium handling\",\n    Predicate:   isHighValue,\n})",{"id":438,"title":150,"titles":439,"content":440,"level":19},"/v1.0.1/learn/building-pipelines#next-steps",[209],"Schema Design Guide - Best practicesError Handling Guide - Resilience patternsConnector Types Reference - All options html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}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 .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":442,"title":443,"titles":444,"content":445,"level":9},"/v1.0.1/guides/schema-design","Schema Design",[],"Best practices for designing maintainable Flume schemas",{"id":447,"title":443,"titles":448,"content":449,"level":9},"/v1.0.1/guides/schema-design#schema-design",[],"Best practices for designing clear, maintainable Flume schemas.",{"id":451,"title":452,"titles":453,"content":24,"level":19},"/v1.0.1/guides/schema-design#naming-conventions","Naming Conventions",[443],{"id":455,"title":456,"titles":457,"content":458,"level":30},"/v1.0.1/guides/schema-design#processor-names","Processor Names",[443,452],"Use kebab-case with verb-noun patterns: // Good\npipz.Apply(\"validate-order\", ...)\npipz.Apply(\"fetch-customer\", ...)\npipz.Apply(\"send-notification\", ...)\n\n// Avoid\npipz.Apply(\"OrderValidation\", ...)\npipz.Apply(\"customer\", ...)\npipz.Apply(\"doStuff\", ...)",{"id":460,"title":461,"titles":462,"content":463,"level":30},"/v1.0.1/guides/schema-design#predicate-names","Predicate Names",[443,452],"Use is-/has-/can- prefixes: // Good\nflume.Predicate[T]{Name: \"is-premium\", ...}\nflume.Predicate[T]{Name: \"has-discount-code\", ...}\nflume.Predicate[T]{Name: \"can-ship-internationally\", ...}\n\n// Avoid\nflume.Predicate[T]{Name: \"premium\", ...}\nflume.Predicate[T]{Name: \"check-discount\", ...}",{"id":465,"title":466,"titles":467,"content":468,"level":30},"/v1.0.1/guides/schema-design#condition-names","Condition Names",[443,452],"Use get- prefix or descriptive nouns: // Good\nflume.Condition[T]{Name: \"get-order-type\", ...}\nflume.Condition[T]{Name: \"payment-method\", ...}\nflume.Condition[T]{Name: \"customer-tier\", ...}",{"id":470,"title":471,"titles":472,"content":473,"level":30},"/v1.0.1/guides/schema-design#schema-names","Schema Names",[443,452],"Use descriptive kebab-case: factory.SetSchema(\"order-processing\", ...)\nfactory.SetSchema(\"user-onboarding\", ...)\nfactory.SetSchema(\"payment-v2\", ...)",{"id":475,"title":476,"titles":477,"content":24,"level":19},"/v1.0.1/guides/schema-design#structure-guidelines","Structure Guidelines",[443],{"id":479,"title":480,"titles":481,"content":482,"level":30},"/v1.0.1/guides/schema-design#keep-depth-shallow","Keep Depth Shallow",[443,476],"Deeply nested schemas are hard to read and debug: # Hard to follow (5+ levels)\ntype: sequence\nchildren:\n  - type: filter\n    predicate: a\n    then:\n      type: switch\n        condition: b\n        routes:\n          x:\n            type: retry\n            child:\n              type: timeout\n                child:\n                  ref: processor Break into logical sub-schemas: # Main schema\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: resilient-external-call  # Pre-composed\n  - ref: finalize // Register composed processor\nresilientCall := pipz.NewCircuitBreaker(\"resilient\",\n    pipz.NewTimeout(\"timeout\", apiCall, 5*time.Second),\n    3, 30*time.Second,\n)\nfactory.Add(resilientCall)",{"id":484,"title":485,"titles":486,"content":487,"level":30},"/v1.0.1/guides/schema-design#group-related-operations","Group Related Operations",[443,476],"Use sequence to group related steps: type: sequence\nname: payment-processing\nchildren:\n  - ref: validate-payment\n  - ref: authorize-payment\n  - ref: capture-payment\n  - ref: record-transaction",{"id":489,"title":490,"titles":491,"content":492,"level":30},"/v1.0.1/guides/schema-design#name-complex-nodes","Name Complex Nodes",[443,476],"Add names to non-trivial nodes for debugging: type: concurrent\nname: parallel-enrichment\nchildren:\n  - ref: fetch-customer\n  - ref: fetch-inventory\n\ntype: filter\nname: premium-check\npredicate: is-premium\nthen:\n  ref: premium-handler",{"id":494,"title":495,"titles":496,"content":24,"level":19},"/v1.0.1/guides/schema-design#version-management","Version Management",[443],{"id":498,"title":499,"titles":500,"content":501,"level":30},"/v1.0.1/guides/schema-design#semantic-versioning","Semantic Versioning",[443,495],"Use semantic versioning for schemas: version: \"1.0.0\"  # Initial\nversion: \"1.1.0\"  # Added new route\nversion: \"2.0.0\"  # Breaking change to structure",{"id":503,"title":504,"titles":505,"content":506,"level":30},"/v1.0.1/guides/schema-design#version-in-schema-name","Version in Schema Name",[443,495],"For A/B testing or gradual rollouts: factory.SetSchema(\"checkout-v1\", schemaV1)\nfactory.SetSchema(\"checkout-v2\", schemaV2)\n\n// Create bindings for each variant\nbindingV1, _ := factory.Bind(v1ID, \"checkout-v1\", flume.WithAutoSync())\nbindingV2, _ := factory.Bind(v2ID, \"checkout-v2\", flume.WithAutoSync())\n\n// Route traffic\nbinding := getBindingForUser(user, bindingV1, bindingV2)\nresult, _ := binding.Process(ctx, order)",{"id":508,"title":509,"titles":510,"content":24,"level":19},"/v1.0.1/guides/schema-design#error-handling-placement","Error Handling Placement",[443],{"id":512,"title":513,"titles":514,"content":515,"level":30},"/v1.0.1/guides/schema-design#wrap-at-boundaries","Wrap at Boundaries",[443,509],"Apply error handling at service boundaries: type: sequence\nchildren:\n  - ref: validate  # Internal - no wrap needed\n  - type: circuit-breaker\n    failure_threshold: 5\n    child:\n      type: retry\n        attempts: 3\n        child:\n          ref: external-api  # External - wrap\n  - ref: transform  # Internal - no wrap",{"id":517,"title":518,"titles":519,"content":520,"level":30},"/v1.0.1/guides/schema-design#dont-over-protect","Don't Over-Protect",[443,509],"Avoid redundant error handling: # Overkill\ntype: retry\nchild:\n  type: retry\n    child:\n      type: fallback\n        children:\n          - type: retry\n              child:\n                ref: processor\n          - ref: fallback",{"id":522,"title":523,"titles":524,"content":525,"level":30},"/v1.0.1/guides/schema-design#match-retry-to-operation","Match Retry to Operation",[443,509],"# Quick operation - few retries, no backoff\ntype: retry\nattempts: 2\nchild:\n  ref: cache-lookup\n\n# Slow external service - more retries with backoff\ntype: retry\nattempts: 5\nbackoff: \"500ms\"\nchild:\n  ref: payment-gateway",{"id":527,"title":528,"titles":529,"content":24,"level":19},"/v1.0.1/guides/schema-design#performance-considerations","Performance Considerations",[443],{"id":531,"title":532,"titles":533,"content":534,"level":30},"/v1.0.1/guides/schema-design#minimize-cloning","Minimize Cloning",[443,528],"concurrent and race nodes clone data. Avoid unnecessary parallelism: # Unnecessary clone\ntype: concurrent\nchildren:\n  - ref: quick-transform  # Could be sequential\n\n# Justified parallelism\ntype: concurrent\nchildren:\n  - ref: slow-api-call\n  - ref: another-slow-call",{"id":536,"title":537,"titles":538,"content":539,"level":30},"/v1.0.1/guides/schema-design#rate-limit-at-entry-points","Rate Limit at Entry Points",[443,528],"Place rate limiters early: type: sequence\nchildren:\n  - type: rate-limit\n    requests_per_second: 100.0\n    child:\n      ref: validate  # Everything after is protected\n  - ref: process\n  - ref: external-call",{"id":541,"title":542,"titles":543,"content":544,"level":30},"/v1.0.1/guides/schema-design#use-timeouts-wisely","Use Timeouts Wisely",[443,528],"Set realistic timeouts: type: timeout\nduration: \"30s\"  # Based on actual SLA\nchild:\n  ref: external-service",{"id":546,"title":547,"titles":548,"content":24,"level":19},"/v1.0.1/guides/schema-design#schema-organization","Schema Organization",[443],{"id":550,"title":551,"titles":552,"content":553,"level":30},"/v1.0.1/guides/schema-design#single-responsibility","Single Responsibility",[443,547],"Each schema should do one thing well: // Separate concerns\nfactory.SetSchema(\"order-validation\", validationSchema)\nfactory.SetSchema(\"order-payment\", paymentSchema)\nfactory.SetSchema(\"order-fulfillment\", fulfillmentSchema)",{"id":555,"title":556,"titles":557,"content":558,"level":30},"/v1.0.1/guides/schema-design#compose-larger-flows","Compose Larger Flows",[443,547],"Build complex flows from simple schemas: // High-level orchestration\nfactory.SetSchema(\"order-complete\", Schema{\n    Node: Node{\n        Type: \"sequence\",\n        Children: []Node{\n            {Ref: \"order-validation\"},   // References another pipeline\n            {Ref: \"order-payment\"},\n            {Ref: \"order-fulfillment\"},\n        },\n    },\n})",{"id":560,"title":561,"titles":562,"content":24,"level":19},"/v1.0.1/guides/schema-design#documentation-practices","Documentation Practices",[443],{"id":564,"title":565,"titles":566,"content":567,"level":30},"/v1.0.1/guides/schema-design#use-descriptions","Use Descriptions",[443,561],"Add descriptions when registering: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"high-value\",\n    Description: \"Orders exceeding $1000 threshold for premium handling\",\n    Predicate:   isHighValue,\n})\n\nfactory.AddCondition(flume.Condition[Order]{\n    Name:        \"fulfillment-type\",\n    Description: \"Determines shipping vs. digital delivery\",\n    Values:      []string{\"ship\", \"digital\", \"pickup\"},\n    Condition:   getFulfillmentType,\n})",{"id":569,"title":570,"titles":571,"content":572,"level":30},"/v1.0.1/guides/schema-design#companion-documentation","Companion Documentation",[443,561],"Maintain schema documentation alongside files: schemas/\n  order-processing.yaml\n  order-processing.md    # Documents the schema",{"id":574,"title":575,"titles":576,"content":577,"level":30},"/v1.0.1/guides/schema-design#schema-diagrams","Schema Diagrams",[443,561],"For complex pipelines, create visual diagrams: validate → [concurrent: enrich] → [filter: premium?] → [switch: payment] → complete\n                                        ↓                    ↓\n                                  premium-handler     credit|paypal|crypto",{"id":579,"title":150,"titles":580,"content":581,"level":19},"/v1.0.1/guides/schema-design#next-steps",[443],"Hot Reloading - Dynamic schema updatesTesting - Testing schema-driven pipelinesSchema Format Reference - Complete specification html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}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 .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":583,"title":219,"titles":584,"content":585,"level":9},"/v1.0.1/guides/hot-reloading",[],"Update pipeline behaviour at runtime without restarts",{"id":587,"title":219,"titles":588,"content":589,"level":9},"/v1.0.1/guides/hot-reloading#hot-reloading",[],"Update pipeline definitions at runtime without service restarts.",{"id":591,"title":6,"titles":592,"content":593,"level":19},"/v1.0.1/guides/hot-reloading#overview",[219],"Flume's hot reloading enables: Zero-downtime updates - Swap pipelines while requests continueA/B testing - Switch between pipeline variantsFeature flags - Enable/disable pipeline stages dynamicallyConfiguration-driven behaviour - Operators modify pipelines without deploys",{"id":595,"title":596,"titles":597,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#basic-usage","Basic Usage",[219],{"id":599,"title":600,"titles":601,"content":602,"level":30},"/v1.0.1/guides/hot-reloading#register-named-schemas","Register Named Schemas",[219,596],"factory := flume.New[Order]()\n\n// Register components\nfactory.Add(processors...)\nfactory.AddPredicate(predicates...)\n\n// Register named schema\nschema := flume.Schema{\n    Version: \"1.0.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"process\"},\n        },\n    },\n}\n\nerr := factory.SetSchema(\"order-pipeline\", schema)",{"id":604,"title":605,"titles":606,"content":607,"level":30},"/v1.0.1/guides/hot-reloading#create-a-binding","Create a Binding",[219,596],"// Create a binding with auto-sync enabled\npipelineID := factory.Identity(\"order-processor\", \"Processes incoming orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\nif err != nil {\n    return fmt.Errorf(\"failed to bind: %w\", err)\n}\n\n// Process requests (lock-free)\nresult, err := binding.Process(ctx, order)",{"id":609,"title":610,"titles":611,"content":612,"level":30},"/v1.0.1/guides/hot-reloading#update-at-runtime","Update at Runtime",[219,596],"newSchema := flume.Schema{\n    Version: \"1.1.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"enrich\"},  // Added step\n            {Ref: \"process\"},\n        },\n    },\n}\n\nerr := factory.SetSchema(\"order-pipeline\", newSchema)\n// New requests immediately use updated pipeline",{"id":614,"title":615,"titles":616,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#how-it-works","How It Works",[219],{"id":618,"title":619,"titles":620,"content":621,"level":30},"/v1.0.1/guides/hot-reloading#atomic-pointer-swap","Atomic Pointer Swap",[219,615],"// Internally, pipelines are stored as atomic pointers\npipelines map[string]*atomic.Pointer[pipz.Chainable[T]]\n\n// Update atomically swaps the pointer\nptr.Store(&newPipeline)\n\n// Retrieval loads atomically\nreturn *ptr.Load(), true",{"id":623,"title":624,"titles":625,"content":626,"level":30},"/v1.0.1/guides/hot-reloading#request-continuity","Request Continuity",[219,615],"Request A starts with pipeline v1Schema updates to v2Request A completes with v1 (unaffected)Request B starts with v2 No locks are held during processing - updates don't block requests.",{"id":628,"title":629,"titles":630,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#file-based-reloading","File-Based Reloading",[219],{"id":632,"title":633,"titles":634,"content":635,"level":30},"/v1.0.1/guides/hot-reloading#watch-for-changes","Watch for Changes",[219,629],"func watchSchemaFile(ctx context.Context, factory *flume.Factory[Order], path string) {\n    watcher, _ := fsnotify.NewWatcher()\n    defer watcher.Close()\n\n    watcher.Add(path)\n\n    for {\n        select {\n        case \u003C-ctx.Done():\n            return\n        case event := \u003C-watcher.Events:\n            if event.Op&fsnotify.Write == fsnotify.Write {\n                reloadSchema(factory, path)\n            }\n        }\n    }\n}\n\nfunc reloadSchema(factory *flume.Factory[Order], path string) {\n    pipeline, err := factory.BuildFromFile(path)\n    if err != nil {\n        log.Printf(\"failed to reload schema: %v\", err)\n        return\n    }\n\n    // Read file to get schema for SetSchema\n    data, _ := os.ReadFile(path)\n    var schema flume.Schema\n    yaml.Unmarshal(data, &schema)\n\n    if err := factory.SetSchema(\"main\", schema); err != nil {\n        log.Printf(\"failed to set schema: %v\", err)\n    }\n}",{"id":637,"title":638,"titles":639,"content":640,"level":30},"/v1.0.1/guides/hot-reloading#multi-schema-directory","Multi-Schema Directory",[219,629],"func watchSchemaDir(ctx context.Context, factory *flume.Factory[Order], dir string) {\n    watcher, _ := fsnotify.NewWatcher()\n    watcher.Add(dir)\n\n    for event := range watcher.Events {\n        if event.Op&fsnotify.Write == 0 {\n            continue\n        }\n\n        name := strings.TrimSuffix(filepath.Base(event.Name), filepath.Ext(event.Name))\n\n        data, _ := os.ReadFile(event.Name)\n        var schema flume.Schema\n        if err := yaml.Unmarshal(data, &schema); err != nil {\n            log.Printf(\"invalid schema %s: %v\", name, err)\n            continue\n        }\n\n        if err := factory.SetSchema(name, schema); err != nil {\n            log.Printf(\"failed to update %s: %v\", name, err)\n        }\n    }\n}",{"id":642,"title":643,"titles":644,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#remote-configuration","Remote Configuration",[219],{"id":646,"title":647,"titles":648,"content":649,"level":30},"/v1.0.1/guides/hot-reloading#http-endpoint","HTTP Endpoint",[219,643],"http.HandleFunc(\"/schemas/{name}\", func(w http.ResponseWriter, r *http.Request) {\n    name := r.PathValue(\"name\")\n\n    switch r.Method {\n    case \"GET\":\n        schema, ok := factory.GetSchema(name)\n        if !ok {\n            http.NotFound(w, r)\n            return\n        }\n        json.NewEncoder(w).Encode(schema)\n\n    case \"PUT\":\n        var schema flume.Schema\n        json.NewDecoder(r.Body).Decode(&schema)\n\n        if err := factory.SetSchema(name, schema); err != nil {\n            http.Error(w, err.Error(), 400)\n            return\n        }\n        w.WriteHeader(204)\n\n    case \"DELETE\":\n        if !factory.RemoveSchema(name) {\n            http.NotFound(w, r)\n            return\n        }\n        w.WriteHeader(204)\n    }\n})",{"id":651,"title":652,"titles":653,"content":654,"level":30},"/v1.0.1/guides/hot-reloading#polling","Polling",[219,643],"func pollSchemas(ctx context.Context, factory *flume.Factory[Order], url string) {\n    ticker := time.NewTicker(30 * time.Second)\n    defer ticker.Stop()\n\n    for {\n        select {\n        case \u003C-ctx.Done():\n            return\n        case \u003C-ticker.C:\n            resp, err := http.Get(url)\n            if err != nil {\n                continue\n            }\n\n            var schemas map[string]flume.Schema\n            json.NewDecoder(resp.Body).Decode(&schemas)\n            resp.Body.Close()\n\n            for name, schema := range schemas {\n                existing, ok := factory.GetSchema(name)\n                if ok && existing.Version == schema.Version {\n                    continue // No change\n                }\n                factory.SetSchema(name, schema)\n            }\n        }\n    }\n}",{"id":656,"title":657,"titles":658,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#version-tracking","Version Tracking",[219],{"id":660,"title":661,"titles":662,"content":663,"level":30},"/v1.0.1/guides/hot-reloading#compare-versions","Compare Versions",[219,657],"existing, ok := factory.GetSchema(\"pipeline\")\nif ok && existing.Version == newSchema.Version {\n    return // Already up to date\n}\n\nerr := factory.SetSchema(\"pipeline\", newSchema)",{"id":665,"title":666,"titles":667,"content":668,"level":30},"/v1.0.1/guides/hot-reloading#observability","Observability",[219,657],"Flume emits events on schema changes: import \"github.com/zoobz-io/capitan\"\n\ncapitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    var name, oldVersion, newVersion string\n    for _, f := range fields {\n        switch f.Key {\n        case \"name\":\n            name = f.String()\n        case \"old_version\":\n            oldVersion = f.String()\n        case \"new_version\":\n            newVersion = f.String()\n        }\n    }\n    log.Printf(\"schema %s updated: %s -> %s\", name, oldVersion, newVersion)\n})",{"id":670,"title":671,"titles":672,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#graceful-updates","Graceful Updates",[219],{"id":674,"title":675,"titles":676,"content":677,"level":30},"/v1.0.1/guides/hot-reloading#validation-first","Validation First",[219,671],"Always validate before applying: if err := factory.ValidateSchema(newSchema); err != nil {\n    return fmt.Errorf(\"invalid schema: %w\", err)\n}\n\n// Schema is valid, safe to apply\nfactory.SetSchema(name, newSchema)",{"id":679,"title":680,"titles":681,"content":682,"level":30},"/v1.0.1/guides/hot-reloading#rollback-pattern","Rollback Pattern",[219,671],"func updateWithRollback(factory *flume.Factory[Order], name string, newSchema flume.Schema, binding *flume.Binding[Order]) error {\n    // Save current\n    oldSchema, hadOld := factory.GetSchema(name)\n\n    // Apply new (auto-sync bindings rebuild automatically)\n    if err := factory.SetSchema(name, newSchema); err != nil {\n        return err\n    }\n\n    // Test with canary request\n    _, err := binding.Process(context.Background(), canaryOrder)\n\n    if err != nil && hadOld {\n        // Rollback to previous schema\n        factory.SetSchema(name, oldSchema)\n        return fmt.Errorf(\"canary failed, rolled back: %w\", err)\n    }\n\n    return nil\n}",{"id":684,"title":685,"titles":686,"content":24,"level":19},"/v1.0.1/guides/hot-reloading#best-practices","Best Practices",[219],{"id":688,"title":689,"titles":690,"content":691,"level":30},"/v1.0.1/guides/hot-reloading#_1-use-semantic-versioning","1. Use Semantic Versioning",[219,685],"version: \"1.2.3\"  # MAJOR.MINOR.PATCH",{"id":693,"title":694,"titles":695,"content":696,"level":30},"/v1.0.1/guides/hot-reloading#_2-log-all-changes","2. Log All Changes",[219,685],"log.Printf(\"schema %s updated to version %s\", name, schema.Version)",{"id":698,"title":699,"titles":700,"content":701,"level":30},"/v1.0.1/guides/hot-reloading#_3-validate-component-dependencies","3. Validate Component Dependencies",[219,685],"Before removing a processor, check if schemas reference it: for _, schemaName := range factory.ListSchemas() {\n    schema, _ := factory.GetSchema(schemaName)\n    if schemaReferencesProcessor(schema, \"old-processor\") {\n        return fmt.Errorf(\"cannot remove: schema %s uses it\", schemaName)\n    }\n}",{"id":703,"title":704,"titles":705,"content":706,"level":30},"/v1.0.1/guides/hot-reloading#_4-consider-circuit-breakers","4. Consider Circuit Breakers",[219,685],"Protect against bad schema updates: type GuardedFactory[T pipz.Cloner[T]] struct {\n    factory       *flume.Factory[T]\n    updateBreaker *circuitbreaker.CircuitBreaker\n}\n\nfunc (g *GuardedFactory[T]) SetSchema(name string, schema flume.Schema) error {\n    return g.updateBreaker.Execute(func() error {\n        return g.factory.SetSchema(name, schema)\n    })\n}",{"id":708,"title":150,"titles":709,"content":710,"level":19},"/v1.0.1/guides/hot-reloading#next-steps",[219],"Testing - Test hot reload scenariosObservability - Monitor schema changesEvents Reference - All schema events html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}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 .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"id":712,"title":363,"titles":713,"content":714,"level":9},"/v1.0.1/guides/error-handling",[],"Build resilient pipelines with retry, fallback, circuit breakers, and timeouts",{"id":716,"title":363,"titles":717,"content":718,"level":9},"/v1.0.1/guides/error-handling#error-handling",[],"Build resilient pipelines that gracefully handle failures.",{"id":720,"title":367,"titles":721,"content":722,"level":19},"/v1.0.1/guides/error-handling#retry",[363],"Retry operations that may fail transiently.",{"id":724,"title":725,"titles":726,"content":727,"level":30},"/v1.0.1/guides/error-handling#basic-retry","Basic Retry",[363,367],"type: retry\nattempts: 3\nchild:\n  ref: flaky-operation Retries up to 3 times on any error.",{"id":729,"title":730,"titles":731,"content":732,"level":30},"/v1.0.1/guides/error-handling#retry-with-backoff","Retry with Backoff",[363,367],"type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: rate-limited-api Waits backoff duration between attempts, doubling each time (exponential backoff).",{"id":734,"title":735,"titles":736,"content":737,"level":30},"/v1.0.1/guides/error-handling#when-to-use","When to Use",[363,367],"Network calls that may timeoutRate-limited APIs that return temporary errorsDatabase operations during high loadMessage queue operations",{"id":739,"title":740,"titles":741,"content":742,"level":30},"/v1.0.1/guides/error-handling#configuration","Configuration",[363,367],"FieldDefaultDescriptionattempts3Maximum retry attemptsbackoff(none)Initial backoff duration",{"id":744,"title":372,"titles":745,"content":746,"level":19},"/v1.0.1/guides/error-handling#fallback",[363],"Provide alternative handling when primary fails.",{"id":748,"title":749,"titles":750,"content":751,"level":30},"/v1.0.1/guides/error-handling#basic-fallback","Basic Fallback",[363,372],"type: fallback\nchildren:\n  - ref: primary-service\n  - ref: backup-service Tries primary first; if it errors, tries backup.",{"id":753,"title":754,"titles":755,"content":756,"level":30},"/v1.0.1/guides/error-handling#cascading-fallbacks","Cascading Fallbacks",[363,372],"type: fallback\nchildren:\n  - ref: primary-cache\n  - type: fallback\n    children:\n      - ref: secondary-cache\n      - ref: database",{"id":758,"title":735,"titles":759,"content":760,"level":30},"/v1.0.1/guides/error-handling#when-to-use-1",[363,372],"Service redundancyCache miss handlingFeature degradationDefault value provision",{"id":762,"title":377,"titles":763,"content":764,"level":19},"/v1.0.1/guides/error-handling#timeout",[363],"Enforce time limits on operations.",{"id":766,"title":767,"titles":768,"content":769,"level":30},"/v1.0.1/guides/error-handling#basic-timeout","Basic Timeout",[363,377],"type: timeout\nduration: \"5s\"\nchild:\n  ref: slow-operation Cancels operation if not complete within duration.",{"id":771,"title":740,"titles":772,"content":773,"level":30},"/v1.0.1/guides/error-handling#configuration-1",[363,377],"FieldDefaultDescriptionduration30sMaximum execution time",{"id":775,"title":776,"titles":777,"content":778,"level":30},"/v1.0.1/guides/error-handling#duration-formats","Duration Formats",[363,377],"duration: \"100ms\"   # 100 milliseconds\nduration: \"5s\"      # 5 seconds\nduration: \"2m\"      # 2 minutes\nduration: \"1h30m\"   # 1.5 hours",{"id":780,"title":735,"titles":781,"content":782,"level":30},"/v1.0.1/guides/error-handling#when-to-use-2",[363,377],"External API callsLong-running computationsUser-facing requests requiring responsivenessPreventing resource exhaustion",{"id":784,"title":382,"titles":785,"content":786,"level":19},"/v1.0.1/guides/error-handling#circuit-breaker",[363],"Prevent cascading failures by stopping calls to failing services.",{"id":788,"title":789,"titles":790,"content":791,"level":30},"/v1.0.1/guides/error-handling#basic-circuit-breaker","Basic Circuit Breaker",[363,382],"type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"60s\"\nchild:\n  ref: external-service",{"id":793,"title":615,"titles":794,"content":795,"level":30},"/v1.0.1/guides/error-handling#how-it-works",[363,382],"Closed - Normal operation, failures countedOpen - After failure_threshold failures, requests fail immediatelyHalf-Open - After recovery_timeout, one test request allowedClosed - If test succeeds, resume normal operation",{"id":797,"title":740,"titles":798,"content":799,"level":30},"/v1.0.1/guides/error-handling#configuration-2",[363,382],"FieldDefaultDescriptionfailure_threshold5Failures before openingrecovery_timeout60sTime before testing recovery",{"id":801,"title":735,"titles":802,"content":803,"level":30},"/v1.0.1/guides/error-handling#when-to-use-3",[363,382],"Calling external servicesProtecting against cascade failuresAllowing degraded operationPreventing resource exhaustion from retrying failing calls",{"id":805,"title":387,"titles":806,"content":807,"level":19},"/v1.0.1/guides/error-handling#rate-limiting",[363],"Control request throughput.",{"id":809,"title":810,"titles":811,"content":812,"level":30},"/v1.0.1/guides/error-handling#basic-rate-limit","Basic Rate Limit",[363,387],"type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: rate-sensitive-api",{"id":814,"title":740,"titles":815,"content":816,"level":30},"/v1.0.1/guides/error-handling#configuration-3",[363,387],"FieldDefaultDescriptionrequests_per_second10.0Sustained rate limitburst_size1Allowed burst above limit",{"id":818,"title":735,"titles":819,"content":820,"level":30},"/v1.0.1/guides/error-handling#when-to-use-4",[363,387],"Calling APIs with rate limitsProtecting downstream servicesEnsuring fair resource usagePreventing thundering herd",{"id":822,"title":823,"titles":824,"content":24,"level":19},"/v1.0.1/guides/error-handling#combining-patterns","Combining Patterns",[363],{"id":826,"title":827,"titles":828,"content":829,"level":30},"/v1.0.1/guides/error-handling#resilient-external-call","Resilient External Call",[363,823],"type: circuit-breaker\nfailure_threshold: 3\nrecovery_timeout: \"30s\"\nchild:\n  type: timeout\n  duration: \"10s\"\n  child:\n    type: retry\n    attempts: 3\n    backoff: \"200ms\"\n    child:\n      ref: external-api Order matters: Circuit breaker - Fails fast if service is downTimeout - Limits total wait timeRetry - Handles transient failures",{"id":831,"title":832,"titles":833,"content":834,"level":30},"/v1.0.1/guides/error-handling#fallback-with-resilience","Fallback with Resilience",[363,823],"type: fallback\nchildren:\n  - type: circuit-breaker\n    failure_threshold: 5\n    child:\n      type: retry\n      attempts: 2\n      child:\n        ref: primary-service\n  - ref: backup-service Primary has full resilience; backup is simpler.",{"id":836,"title":837,"titles":838,"content":839,"level":30},"/v1.0.1/guides/error-handling#rate-limited-with-timeout","Rate Limited with Timeout",[363,823],"type: timeout\nduration: \"30s\"\nchild:\n  type: rate-limit\n  requests_per_second: 50.0\n  burst_size: 5\n  child:\n    type: retry\n    attempts: 3\n    child:\n      ref: rate-limited-api Total request time bounded even if queued for rate limiting.",{"id":841,"title":842,"titles":843,"content":844,"level":19},"/v1.0.1/guides/error-handling#error-types","Error Types",[363],"Understand which errors trigger which behaviour: ConnectorTriggers OnRetryAny error returnedFallbackAny error from primaryTimeoutContext deadline exceededCircuit BreakerAny error (tracks count)",{"id":846,"title":685,"titles":847,"content":24,"level":19},"/v1.0.1/guides/error-handling#best-practices",[363],{"id":849,"title":850,"titles":851,"content":852,"level":30},"/v1.0.1/guides/error-handling#_1-set-realistic-timeouts","1. Set Realistic Timeouts",[363,685],"# Too short - may fail healthy requests\nduration: \"100ms\"\n\n# Too long - poor user experience\nduration: \"5m\"\n\n# Right - based on actual service SLA\nduration: \"5s\"",{"id":854,"title":855,"titles":856,"content":857,"level":30},"/v1.0.1/guides/error-handling#_2-tune-circuit-breaker-thresholds","2. Tune Circuit Breaker Thresholds",[363,685],"# Too sensitive - opens on minor issues\nfailure_threshold: 1\n\n# Too lenient - doesn't protect\nfailure_threshold: 100\n\n# Balanced - opens after pattern emerges\nfailure_threshold: 5\nrecovery_timeout: \"30s\"",{"id":859,"title":860,"titles":861,"content":862,"level":30},"/v1.0.1/guides/error-handling#_3-use-backoff-for-rate-limits","3. Use Backoff for Rate Limits",[363,685],"type: retry\nattempts: 5\nbackoff: \"1s\"  # Gives rate limit time to reset\nchild:\n  ref: rate-limited-api",{"id":864,"title":865,"titles":866,"content":867,"level":30},"/v1.0.1/guides/error-handling#_4-dont-retry-non-retryable-errors","4. Don't Retry Non-Retryable Errors",[363,685],"Some errors shouldn't be retried. Design processors to return wrapped errors: type nonRetryableError struct {\n    error\n}\n\nfunc (e nonRetryableError) Unwrap() error { return e.error }\n\n// In processor\nif isInvalidInput(err) {\n    return data, nonRetryableError{err}\n}",{"id":869,"title":870,"titles":871,"content":872,"level":30},"/v1.0.1/guides/error-handling#_5-monitor-error-rates","5. Monitor Error Rates",[363,685],"Use Capitan events to track failures: capitan.Handle(flume.SchemaBuildFailed, logFailure)\n// Also monitor your processor errors",{"id":874,"title":150,"titles":875,"content":876,"level":19},"/v1.0.1/guides/error-handling#next-steps",[363],"Testing - Test error scenariosConnector Types Reference - All options html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}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 .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}",{"id":878,"title":879,"titles":880,"content":881,"level":9},"/v1.0.1/guides/testing","Testing",[],"Testing strategies for schema-driven pipelines",{"id":883,"title":879,"titles":884,"content":885,"level":9},"/v1.0.1/guides/testing#testing",[],"Strategies for testing Flume pipelines at multiple levels.",{"id":887,"title":888,"titles":889,"content":890,"level":19},"/v1.0.1/guides/testing#testing-levels","Testing Levels",[879],"Unit Tests - Test individual processorsSchema Tests - Test schema validationIntegration Tests - Test complete pipelinesProperty Tests - Test invariants across schemas",{"id":892,"title":893,"titles":894,"content":895,"level":19},"/v1.0.1/guides/testing#unit-testing-processors","Unit Testing Processors",[879],"Test processors independently before registering: func TestValidateOrder(t *testing.T) {\n    processor := pipz.Apply(\"validate\", validateOrder)\n\n    tests := []struct {\n        name    string\n        input   Order\n        wantErr bool\n    }{\n        {\n            name:    \"valid order\",\n            input:   Order{Total: 100},\n            wantErr: false,\n        },\n        {\n            name:    \"zero total\",\n            input:   Order{Total: 0},\n            wantErr: true,\n        },\n        {\n            name:    \"negative total\",\n            input:   Order{Total: -50},\n            wantErr: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := processor.Process(context.Background(), tt.input)\n            if (err != nil) != tt.wantErr {\n                t.Errorf(\"error = %v, wantErr %v\", err, tt.wantErr)\n            }\n        })\n    }\n}",{"id":897,"title":898,"titles":899,"content":900,"level":19},"/v1.0.1/guides/testing#testing-predicates","Testing Predicates",[879],"func TestIsPremium(t *testing.T) {\n    pred := func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    }\n\n    tests := []struct {\n        tier string\n        want bool\n    }{\n        {\"premium\", true},\n        {\"standard\", false},\n        {\"\", false},\n    }\n\n    for _, tt := range tests {\n        got := pred(context.Background(), Order{CustomerTier: tt.tier})\n        if got != tt.want {\n            t.Errorf(\"isPremium(%q) = %v, want %v\", tt.tier, got, tt.want)\n        }\n    }\n}",{"id":902,"title":903,"titles":904,"content":905,"level":19},"/v1.0.1/guides/testing#schema-validation-tests","Schema Validation Tests",[879],"Test that schemas are valid before deployment: func TestSchemaValidation(t *testing.T) {\n    factory := setupFactory()\n\n    tests := []struct {\n        name      string\n        schema    string\n        wantError bool\n    }{\n        {\n            name: \"valid sequence\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process`,\n            wantError: false,\n        },\n        {\n            name: \"missing processor\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: nonexistent`,\n            wantError: true,\n        },\n        {\n            name: \"missing predicate\",\n            schema: `\ntype: filter\npredicate: missing\nthen:\n  ref: validate`,\n            wantError: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := factory.BuildFromYAML(tt.schema)\n            if (err != nil) != tt.wantError {\n                t.Errorf(\"BuildFromYAML() error = %v, wantError %v\", err, tt.wantError)\n            }\n        })\n    }\n}\n\nfunc setupFactory() *flume.Factory[Order] {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"validate\", func(_ context.Context, o Order) Order { return o }),\n        pipz.Transform(\"process\", func(_ context.Context, o Order) Order { return o }),\n    )\n    factory.AddPredicate(flume.Predicate[Order]{\n        Name:      \"is-valid\",\n        Predicate: func(_ context.Context, o Order) bool { return o.Total > 0 },\n    })\n    return factory\n}",{"id":907,"title":908,"titles":909,"content":910,"level":19},"/v1.0.1/guides/testing#cicd-schema-linting","CI/CD Schema Linting",[879],"Use ValidateSchemaStructure for CI/CD pipelines where a configured factory is not available. This validates schema syntax without checking if processors, predicates, or other references exist.",{"id":912,"title":913,"titles":914,"content":915,"level":30},"/v1.0.1/guides/testing#lint-schema-files","Lint Schema Files",[879,908],"func TestSchemaFilesStructure(t *testing.T) {\n    files, _ := filepath.Glob(\"schemas/*.yaml\")\n\n    for _, file := range files {\n        t.Run(filepath.Base(file), func(t *testing.T) {\n            data, err := os.ReadFile(file)\n            if err != nil {\n                t.Fatalf(\"failed to read file: %v\", err)\n            }\n\n            var schema flume.Schema\n            if err := yaml.Unmarshal(data, &schema); err != nil {\n                t.Fatalf(\"failed to parse YAML: %v\", err)\n            }\n\n            // Structural validation - no factory needed\n            if err := flume.ValidateSchemaStructure(schema); err != nil {\n                t.Errorf(\"invalid schema structure: %v\", err)\n            }\n        })\n    }\n}",{"id":917,"title":918,"titles":919,"content":920,"level":30},"/v1.0.1/guides/testing#ci-pipeline-example","CI Pipeline Example",[879,908],"# .github/workflows/lint-schemas.yml\nname: Lint Schemas\non: [push, pull_request]\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: '1.23'\n      - run: go test -v -run TestSchemaFilesStructure ./...",{"id":922,"title":923,"titles":924,"content":925,"level":30},"/v1.0.1/guides/testing#what-each-validation-checks","What Each Validation Checks",[879,908],"CheckValidateSchemaStructureValidateSchemaValid node typesYesYesRequired children/childYesYesValid durationsYesYesPositive numbersYesYesProcessor refs existNoYesPredicate refs existNoYesCondition refs existNoYesChannel refs existNoYesCircular referencesNoYes Use ValidateSchemaStructure in CI to catch syntax errors early, then ValidateSchema at runtime with a configured factory to catch reference errors.",{"id":927,"title":928,"titles":929,"content":930,"level":19},"/v1.0.1/guides/testing#integration-testing","Integration Testing",[879],"Test complete pipelines with realistic scenarios: func TestOrderPipeline(t *testing.T) {\n    factory := setupProductionFactory()\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: premium-handler\n  - ref: finalize`\n\n    pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        t.Fatalf(\"failed to build: %v\", err)\n    }\n\n    tests := []struct {\n        name  string\n        order Order\n        want  Order\n    }{\n        {\n            name:  \"standard order unchanged\",\n            order: Order{Total: 50},\n            want:  Order{Total: 50, Status: \"finalized\"},\n        },\n        {\n            name:  \"high value gets premium treatment\",\n            order: Order{Total: 1000},\n            want:  Order{Total: 1000, Discount: 0.1, Status: \"finalized\"},\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            result, err := pipeline.Process(context.Background(), tt.order)\n            if err != nil {\n                t.Fatalf(\"unexpected error: %v\", err)\n            }\n            if result != tt.want {\n                t.Errorf(\"got %+v, want %+v\", result, tt.want)\n            }\n        })\n    }\n}",{"id":932,"title":933,"titles":934,"content":24,"level":19},"/v1.0.1/guides/testing#testing-error-handling","Testing Error Handling",[879],{"id":936,"title":937,"titles":938,"content":939,"level":30},"/v1.0.1/guides/testing#retry-behaviour","Retry Behaviour",[879,933],"func TestRetryBehaviour(t *testing.T) {\n    attempts := 0\n    processor := pipz.Apply(\"flaky\", func(_ context.Context, o Order) (Order, error) {\n        attempts++\n        if attempts \u003C 3 {\n            return o, errors.New(\"transient failure\")\n        }\n        return o, nil\n    })\n\n    factory := flume.New[Order]()\n    factory.Add(processor)\n\n    schema := `\ntype: retry\nattempts: 5\nchild:\n  ref: flaky`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success after retries, got: %v\", err)\n    }\n    if attempts != 3 {\n        t.Errorf(\"expected 3 attempts, got %d\", attempts)\n    }\n}",{"id":941,"title":942,"titles":943,"content":944,"level":30},"/v1.0.1/guides/testing#fallback-behaviour","Fallback Behaviour",[879,933],"func TestFallbackBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(\n        pipz.Apply(\"failing\", func(_ context.Context, o Order) (Order, error) {\n            return o, errors.New(\"primary failed\")\n        }),\n        pipz.Transform(\"backup\", func(_ context.Context, o Order) Order {\n            o.Source = \"backup\"\n            return o\n        }),\n    )\n\n    schema := `\ntype: fallback\nchildren:\n  - ref: failing\n  - ref: backup`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    result, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success from fallback: %v\", err)\n    }\n    if result.Source != \"backup\" {\n        t.Error(\"expected fallback to be used\")\n    }\n}",{"id":946,"title":947,"titles":948,"content":949,"level":30},"/v1.0.1/guides/testing#timeout-behaviour","Timeout Behaviour",[879,933],"func TestTimeoutBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(pipz.Apply(\"slow\", func(ctx context.Context, o Order) (Order, error) {\n        select {\n        case \u003C-time.After(5 * time.Second):\n            return o, nil\n        case \u003C-ctx.Done():\n            return o, ctx.Err()\n        }\n    }))\n\n    schema := `\ntype: timeout\nduration: \"100ms\"\nchild:\n  ref: slow`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if !errors.Is(err, context.DeadlineExceeded) {\n        t.Errorf(\"expected deadline exceeded, got: %v\", err)\n    }\n}",{"id":951,"title":952,"titles":953,"content":954,"level":19},"/v1.0.1/guides/testing#testing-hot-reload","Testing Hot Reload",[879],"func TestHotReload(t *testing.T) {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"v1\", func(_ context.Context, o Order) Order {\n            o.Version = \"v1\"\n            return o\n        }),\n        pipz.Transform(\"v2\", func(_ context.Context, o Order) Order {\n            o.Version = \"v2\"\n            return o\n        }),\n    )\n\n    // Set initial schema\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"1.0.0\",\n        Node:    flume.Node{Ref: \"v1\"},\n    })\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"test-pipeline\", \"Test pipeline\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    // Process with v1\n    result, _ := binding.Process(context.Background(), Order{})\n    if result.Version != \"v1\" {\n        t.Error(\"expected v1\")\n    }\n\n    // Update schema - binding auto-syncs\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"2.0.0\",\n        Node:    flume.Node{Ref: \"v2\"},\n    })\n\n    // Process with v2\n    result, _ = binding.Process(context.Background(), Order{})\n    if result.Version != \"v2\" {\n        t.Error(\"expected v2\")\n    }\n}",{"id":956,"title":957,"titles":958,"content":959,"level":19},"/v1.0.1/guides/testing#concurrent-testing","Concurrent Testing",[879],"func TestConcurrentPipelineAccess(t *testing.T) {\n    factory := setupFactory()\n    factory.SetSchema(\"test\", testSchema)\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"concurrent-pipeline\", \"Concurrent test\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    var wg sync.WaitGroup\n    errors := make(chan error, 100)\n\n    for i := 0; i \u003C 100; i++ {\n        wg.Add(1)\n        go func(id int) {\n            defer wg.Done()\n            _, err := binding.Process(context.Background(), Order{ID: fmt.Sprint(id)})\n            if err != nil {\n                errors \u003C- err\n            }\n        }(i)\n    }\n\n    wg.Wait()\n    close(errors)\n\n    for err := range errors {\n        t.Error(err)\n    }\n}",{"id":961,"title":962,"titles":963,"content":964,"level":19},"/v1.0.1/guides/testing#test-helpers","Test Helpers",[879],"The flume/testing package provides utilities: import flumetesting \"github.com/zoobz-io/flume/testing\"\n\nfunc TestWithHelpers(t *testing.T) {\n    tf := flumetesting.NewTestFactory(t)\n\n    // Register test processors\n    tf.RegisterNoOpProcessors(\"validate\", \"process\", \"finalize\")\n\n    // Build and test\n    pipeline, err := tf.Factory.BuildFromYAML(schema)\n    tf.AssertNoError(err)\n\n    result, err := pipeline.Process(context.Background(), flumetesting.TestData{ID: 1})\n    tf.AssertNoError(err)\n}",{"id":966,"title":685,"titles":967,"content":968,"level":19},"/v1.0.1/guides/testing#best-practices",[879],"Test processors in isolation before integrationUse table-driven tests for schema variationsTest error paths explicitly - don't just test happy pathsTest concurrent access if using hot reloadKeep test factories minimal - only register what's needed",{"id":970,"title":150,"titles":971,"content":972,"level":19},"/v1.0.1/guides/testing#next-steps",[879],"Observability - Monitor in productionTesting Package Reference - Test utilities html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}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 .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"id":974,"title":666,"titles":975,"content":976,"level":9},"/v1.0.1/guides/observability",[],"Monitor Flume pipelines with Capitan events",{"id":978,"title":666,"titles":979,"content":980,"level":9},"/v1.0.1/guides/observability#observability",[],"Flume integrates with Capitan for comprehensive observability.",{"id":982,"title":6,"titles":983,"content":984,"level":19},"/v1.0.1/guides/observability#overview",[666],"Flume emits structured events throughout its lifecycle: Factory creation and component registrationSchema validation, building, and updatesPipeline retrieval and executionFile loading and parsing",{"id":986,"title":987,"titles":988,"content":24,"level":19},"/v1.0.1/guides/observability#event-categories","Event Categories",[666],{"id":990,"title":991,"titles":992,"content":993,"level":30},"/v1.0.1/guides/observability#factory-events","Factory Events",[666,987],"flume.FactoryCreated      // Factory instantiated\nflume.ProcessorRegistered // Processor added\nflume.PredicateRegistered // Predicate added\nflume.ConditionRegistered // Condition added\nflume.ProcessorRemoved    // Processor removed\nflume.PredicateRemoved    // Predicate removed\nflume.ConditionRemoved    // Condition removed",{"id":995,"title":996,"titles":997,"content":998,"level":30},"/v1.0.1/guides/observability#schema-events","Schema Events",[666,987],"flume.SchemaValidationStarted   // Validation began\nflume.SchemaValidationCompleted // Validation successful\nflume.SchemaValidationFailed    // Validation failed\nflume.SchemaBuildStarted        // Build began\nflume.SchemaBuildCompleted      // Build successful\nflume.SchemaBuildFailed         // Build failed",{"id":1000,"title":1001,"titles":1002,"content":1003,"level":30},"/v1.0.1/guides/observability#dynamic-schema-events","Dynamic Schema Events",[666,987],"flume.SchemaRegistered   // New schema added\nflume.SchemaUpdated      // Existing schema replaced\nflume.SchemaRemoved      // Schema deleted\nflume.PipelineRetrieved  // Pipeline accessed",{"id":1005,"title":1006,"titles":1007,"content":1008,"level":30},"/v1.0.1/guides/observability#file-events","File Events",[666,987],"flume.SchemaFileLoaded  // File read successfully\nflume.SchemaFileFailed  // File read error\nflume.SchemaYAMLParsed  // YAML parsed\nflume.SchemaJSONParsed  // JSON parsed\nflume.SchemaParseFailed // Parse error",{"id":1010,"title":1011,"titles":1012,"content":1013,"level":19},"/v1.0.1/guides/observability#event-fields","Event Fields",[666],"Events include typed fields for structured data: flume.KeyName       // string: component/schema name\nflume.KeyType       // string: data type\nflume.KeyVersion    // string: schema version\nflume.KeyOldVersion // string: previous version (updates)\nflume.KeyNewVersion // string: new version (updates)\nflume.KeyPath       // string: file path\nflume.KeyError      // string: error message\nflume.KeyDuration   // time.Duration: operation duration\nflume.KeyErrorCount // int: number of errors\nflume.KeySizeBytes  // int: file size\nflume.KeyFound      // bool: retrieval success",{"id":1015,"title":1016,"titles":1017,"content":24,"level":19},"/v1.0.1/guides/observability#setting-up-handlers","Setting Up Handlers",[666],{"id":1019,"title":1020,"titles":1021,"content":1022,"level":30},"/v1.0.1/guides/observability#basic-logging","Basic Logging",[666,1016],"import \"github.com/zoobz-io/capitan\"\n\nfunc setupLogging() {\n    // Log all schema events\n    capitan.Handle(flume.SchemaRegistered, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Schema registered: %s\", extractString(fields, \"name\"))\n    })\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Schema updated: %s (%s -> %s)\",\n            extractString(fields, \"name\"),\n            extractString(fields, \"old_version\"),\n            extractString(fields, \"new_version\"))\n    })\n\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        log.Printf(\"Build failed: %s\", extractString(fields, \"error\"))\n    })\n}\n\nfunc extractString(fields []capitan.Field, key string) string {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.String()\n        }\n    }\n    return \"\"\n}",{"id":1024,"title":1025,"titles":1026,"content":1027,"level":30},"/v1.0.1/guides/observability#metrics-collection","Metrics Collection",[666,1016],"import (\n    \"github.com/prometheus/client_golang/prometheus\"\n    \"github.com/zoobz-io/capitan\"\n)\n\nvar (\n    schemaUpdates = prometheus.NewCounterVec(\n        prometheus.CounterOpts{\n            Name: \"flume_schema_updates_total\",\n            Help: \"Total schema updates\",\n        },\n        []string{\"name\"},\n    )\n\n    buildDuration = prometheus.NewHistogramVec(\n        prometheus.HistogramOpts{\n            Name:    \"flume_build_duration_seconds\",\n            Help:    \"Schema build duration\",\n            Buckets: prometheus.DefBuckets,\n        },\n        []string{\"version\"},\n    )\n\n    buildFailures = prometheus.NewCounter(\n        prometheus.CounterOpts{\n            Name: \"flume_build_failures_total\",\n            Help: \"Total build failures\",\n        },\n    )\n)\n\nfunc setupMetrics() {\n    prometheus.MustRegister(schemaUpdates, buildDuration, buildFailures)\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        name := extractString(fields, \"name\")\n        schemaUpdates.WithLabelValues(name).Inc()\n    })\n\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        version := extractString(fields, \"version\")\n        duration := extractDuration(fields, \"duration\")\n        buildDuration.WithLabelValues(version).Observe(duration.Seconds())\n    })\n\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        buildFailures.Inc()\n    })\n}",{"id":1029,"title":1030,"titles":1031,"content":1032,"level":30},"/v1.0.1/guides/observability#distributed-tracing","Distributed Tracing",[666,1016],"import \"go.opentelemetry.io/otel/trace\"\n\nfunc setupTracing(tracer trace.Tracer) {\n    capitan.Handle(flume.SchemaBuildStarted, func(ctx context.Context, fields []capitan.Field) {\n        _, span := tracer.Start(ctx, \"flume.build\")\n        version := extractString(fields, \"version\")\n        span.SetAttributes(attribute.String(\"schema.version\", version))\n        // Store span for completion handler\n    })\n\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        // End span\n    })\n}",{"id":1034,"title":1035,"titles":1036,"content":24,"level":19},"/v1.0.1/guides/observability#common-monitoring-patterns","Common Monitoring Patterns",[666],{"id":1038,"title":1039,"titles":1040,"content":1041,"level":30},"/v1.0.1/guides/observability#schema-change-alerting","Schema Change Alerting",[666,1035],"capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    oldVersion := extractString(fields, \"old_version\")\n    newVersion := extractString(fields, \"new_version\")\n\n    if isMajorVersionChange(oldVersion, newVersion) {\n        alerting.SendAlert(alerting.Warning, fmt.Sprintf(\n            \"Major schema version change: %s from %s to %s\",\n            name, oldVersion, newVersion))\n    }\n})",{"id":1043,"title":1044,"titles":1045,"content":1046,"level":30},"/v1.0.1/guides/observability#build-performance-tracking","Build Performance Tracking",[666,1035],"capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n    duration := extractDuration(fields, \"duration\")\n\n    if duration > 100*time.Millisecond {\n        log.Printf(\"Slow schema build: %v\", duration)\n    }\n})",{"id":1048,"title":1049,"titles":1050,"content":1051,"level":30},"/v1.0.1/guides/observability#validation-error-analysis","Validation Error Analysis",[666,1035],"capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n    errorCount := extractInt(fields, \"error_count\")\n    duration := extractDuration(fields, \"duration\")\n\n    metrics.RecordValidationFailure(errorCount, duration)\n})",{"id":1053,"title":1054,"titles":1055,"content":24,"level":19},"/v1.0.1/guides/observability#debugging-with-events","Debugging with Events",[666],{"id":1057,"title":1058,"titles":1059,"content":1060,"level":30},"/v1.0.1/guides/observability#development-logging","Development Logging",[666,1054],"func setupDevLogging() {\n    // Log everything in development\n    signals := []capitan.Signal{\n        flume.FactoryCreated,\n        flume.ProcessorRegistered,\n        flume.SchemaValidationStarted,\n        flume.SchemaBuildStarted,\n        flume.SchemaBuildCompleted,\n        // ... all signals\n    }\n\n    for _, signal := range signals {\n        s := signal\n        capitan.Handle(s, func(ctx context.Context, fields []capitan.Field) {\n            log.Printf(\"[%s] %v\", s.Name, formatFields(fields))\n        })\n    }\n}",{"id":1062,"title":1063,"titles":1064,"content":1065,"level":30},"/v1.0.1/guides/observability#pipeline-access-tracking","Pipeline Access Tracking",[666,1054],"capitan.Handle(flume.PipelineRetrieved, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    found := extractBool(fields, \"found\")\n\n    if !found {\n        log.Printf(\"Pipeline not found: %s\", name)\n        metrics.PipelineMiss(name)\n    } else {\n        metrics.PipelineHit(name)\n    }\n})",{"id":1067,"title":1068,"titles":1069,"content":24,"level":19},"/v1.0.1/guides/observability#production-recommendations","Production Recommendations",[666],{"id":1071,"title":1072,"titles":1073,"content":1074,"level":30},"/v1.0.1/guides/observability#_1-monitor-build-failures","1. Monitor Build Failures",[666,1068],"Build failures indicate configuration issues: capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n    error := extractString(fields, \"error\")\n    alerting.Page(fmt.Sprintf(\"Flume build failed: %s\", error))\n})",{"id":1076,"title":1077,"titles":1078,"content":1079,"level":30},"/v1.0.1/guides/observability#_2-track-schema-versions","2. Track Schema Versions",[666,1068],"Maintain audit trail: capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    audit.Log(audit.Entry{\n        Action:     \"schema_update\",\n        Name:       extractString(fields, \"name\"),\n        OldVersion: extractString(fields, \"old_version\"),\n        NewVersion: extractString(fields, \"new_version\"),\n        Timestamp:  time.Now(),\n    })\n})",{"id":1081,"title":1082,"titles":1083,"content":1084,"level":30},"/v1.0.1/guides/observability#_3-set-up-dashboards","3. Set Up Dashboards",[666,1068],"Key metrics to display: Schema update frequencyBuild success/failure rateBuild duration percentilesPipeline retrieval hit rateValidation error trends",{"id":1086,"title":1087,"titles":1088,"content":1089,"level":30},"/v1.0.1/guides/observability#_4-alert-on-anomalies","4. Alert on Anomalies",[666,1068],"Sudden increase in build failuresUnusually long build timesHigh pipeline miss rateValidation errors after deployment",{"id":1091,"title":150,"titles":1092,"content":1093,"level":19},"/v1.0.1/guides/observability#next-steps",[666],"Events Reference - Complete event listCapitan Documentation - Event system details html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}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 .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":1095,"title":1096,"titles":1097,"content":1098,"level":9},"/v1.0.1/cookbook/common-patterns","Common Patterns",[],"Recipes and patterns for building pipelines with flume",{"id":1100,"title":1096,"titles":1101,"content":1102,"level":9},"/v1.0.1/cookbook/common-patterns#common-patterns",[],"Practical recipes for building pipelines with flume.",{"id":1104,"title":1105,"titles":1106,"content":1107,"level":19},"/v1.0.1/cookbook/common-patterns#validation-pipeline","Validation Pipeline",[1096],"A common pattern for validating input before processing: factory := flume.New[Order]()\n\nvalidateID := factory.Identity(\"validate\", \"Validates order data\")\nprocessID := factory.Identity(\"process\", \"Processes valid orders\")\nrejectID := factory.Identity(\"reject\", \"Handles invalid orders\")\nisValidID := factory.Identity(\"is-valid\", \"Checks order validity\")\n\nfactory.Add(\n    pipz.Apply(validateID, validateOrder),\n    pipz.Apply(processID, processOrder),\n    pipz.Apply(rejectID, rejectOrder),\n)\nfactory.AddPredicate(flume.Predicate[Order]{\n    Identity:  isValidID,\n    Predicate: func(ctx context.Context, o Order) bool { return o.Total > 0 },\n})\n\npipeline, _ := factory.BuildFromYAML(`\ntype: filter\npredicate: is-valid\nthen:\n  ref: process\nelse:\n  ref: reject\n`)",{"id":1109,"title":1110,"titles":1111,"content":1112,"level":19},"/v1.0.1/cookbook/common-patterns#retry-with-fallback","Retry with Fallback",[1096],"Retry an operation with a fallback on exhaustion: type: fallback\nchildren:\n  - type: retry\n    attempts: 3\n    backoff: \"100ms\"\n    child:\n      ref: primary-service\n  - ref: fallback-service",{"id":1114,"title":1115,"titles":1116,"content":1117,"level":19},"/v1.0.1/cookbook/common-patterns#fan-out-processing","Fan-Out Processing",[1096],"Process data through multiple paths concurrently: type: concurrent\nchildren:\n  - ref: save-to-database\n  - ref: send-notification\n  - ref: update-cache",{"id":1119,"title":1120,"titles":1121,"content":1122,"level":19},"/v1.0.1/cookbook/common-patterns#conditional-routing","Conditional Routing",[1096],"Route data based on type or category: type: switch\ncondition: order-type\nroutes:\n  standard:\n    ref: process-standard\n  express:\n    ref: process-express\n  priority:\n    ref: process-priority\ndefault:\n  ref: process-unknown",{"id":1124,"title":1125,"titles":1126,"content":1127,"level":19},"/v1.0.1/cookbook/common-patterns#stream-output","Stream Output",[1096],"Send processed data to a channel for async consumption: output := make(chan Order, 100)\nfactory.AddChannel(\"processed-orders\", output)\n\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n  - stream: processed-orders\n`)\n\n// Consume from channel\ngo func() {\n    for order := range output {\n        // Handle processed order\n    }\n}()",{"id":1129,"title":1130,"titles":1131,"content":1132,"level":19},"/v1.0.1/cookbook/common-patterns#circuit-breaker-protection","Circuit Breaker Protection",[1096],"Protect against cascading failures: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: external-api-call",{"id":1134,"title":1135,"titles":1136,"content":1137,"level":19},"/v1.0.1/cookbook/common-patterns#rate-limited-processing","Rate-Limited Processing",[1096],"Throttle requests to downstream services: type: rate-limit\nrequests_per_second: 100\nburst_size: 10\nchild:\n  type: sequence\n  children:\n    - ref: transform\n    - ref: send-to-api html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}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 .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",{"id":1139,"title":1140,"titles":1141,"content":1142,"level":9},"/v1.0.1/reference/api","API Reference",[],"Complete reference for Flume's public API",{"id":1144,"title":1140,"titles":1145,"content":1146,"level":9},"/v1.0.1/reference/api#api-reference",[],"Complete reference for Flume's public API.",{"id":1148,"title":1149,"titles":1150,"content":24,"level":19},"/v1.0.1/reference/api#factory","Factory",[1140],{"id":1152,"title":1153,"titles":1154,"content":1155,"level":30},"/v1.0.1/reference/api#new","New",[1140,1149],"Creates a new factory for type T. func New[T pipz.Cloner[T]]() *Factory[T] Type Constraint: T must implement pipz.Cloner[T]. Example: factory := flume.New[Order]()",{"id":1157,"title":1158,"titles":1159,"content":24,"level":19},"/v1.0.1/reference/api#processor-registration","Processor Registration",[1140],{"id":1161,"title":1162,"titles":1163,"content":1164,"level":30},"/v1.0.1/reference/api#add","Add",[1140,1158],"Registers one or more processors using their intrinsic names. func (f *Factory[T]) Add(processors ...pipz.Chainable[T]) Parameters: processors - Variadic list of pipz chainables Example: factory.Add(\n    pipz.Apply(\"validate\", validateOrder),\n    pipz.Transform(\"enrich\", enrichOrder),\n)",{"id":1166,"title":1167,"titles":1168,"content":1169,"level":30},"/v1.0.1/reference/api#addwithmeta","AddWithMeta",[1140,1158],"Registers processors with metadata for introspection. func (f *Factory[T]) AddWithMeta(processors ...ProcessorMeta[T]) Parameters: processors - Variadic list of ProcessorMeta structs Example: factory.AddWithMeta(flume.ProcessorMeta[Order]{\n    Processor:   pipz.Apply(\"validate\", validateOrder),\n    Description: \"Validates order fields\",\n    Tags:        []string{\"validation\", \"required\"},\n})",{"id":1171,"title":1172,"titles":1173,"content":1174,"level":30},"/v1.0.1/reference/api#remove","Remove",[1140,1158],"Removes processors by name. func (f *Factory[T]) Remove(names ...pipz.Name) int Parameters: names - Variadic list of processor names Returns: Number of processors removed Example: removed := factory.Remove(\"old-processor\", \"deprecated\")",{"id":1176,"title":1177,"titles":1178,"content":1179,"level":30},"/v1.0.1/reference/api#hasprocessor","HasProcessor",[1140,1158],"Checks if a processor is registered. func (f *Factory[T]) HasProcessor(name pipz.Name) bool",{"id":1181,"title":1182,"titles":1183,"content":1184,"level":30},"/v1.0.1/reference/api#listprocessors","ListProcessors",[1140,1158],"Returns all registered processor names. func (f *Factory[T]) ListProcessors() []pipz.Name",{"id":1186,"title":1187,"titles":1188,"content":24,"level":19},"/v1.0.1/reference/api#predicate-registration","Predicate Registration",[1140],{"id":1190,"title":1191,"titles":1192,"content":1193,"level":30},"/v1.0.1/reference/api#addpredicate","AddPredicate",[1140,1187],"Registers predicates for filter conditions. func (f *Factory[T]) AddPredicate(predicates ...Predicate[T]) Example: factory.AddPredicate(flume.Predicate[Order]{\n    Name:        \"is-premium\",\n    Description: \"Customer has premium tier\",\n    Predicate: func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    },\n})",{"id":1195,"title":1196,"titles":1197,"content":1198,"level":30},"/v1.0.1/reference/api#removepredicate","RemovePredicate",[1140,1187],"Removes predicates by name. func (f *Factory[T]) RemovePredicate(names ...pipz.Name) int",{"id":1200,"title":1201,"titles":1202,"content":1203,"level":30},"/v1.0.1/reference/api#haspredicate","HasPredicate",[1140,1187],"Checks if a predicate is registered. func (f *Factory[T]) HasPredicate(name pipz.Name) bool",{"id":1205,"title":1206,"titles":1207,"content":1208,"level":30},"/v1.0.1/reference/api#listpredicates","ListPredicates",[1140,1187],"Returns all registered predicate names. func (f *Factory[T]) ListPredicates() []pipz.Name",{"id":1210,"title":1211,"titles":1212,"content":24,"level":19},"/v1.0.1/reference/api#condition-registration","Condition Registration",[1140],{"id":1214,"title":1215,"titles":1216,"content":1217,"level":30},"/v1.0.1/reference/api#addcondition","AddCondition",[1140,1211],"Registers conditions for switch routing. func (f *Factory[T]) AddCondition(conditions ...Condition[T]) Example: factory.AddCondition(flume.Condition[Order]{\n    Name:        \"order-status\",\n    Description: \"Returns the order status\",\n    Values:      []string{\"pending\", \"approved\", \"rejected\"},\n    Condition: func(ctx context.Context, o Order) string {\n        return o.Status\n    },\n})",{"id":1219,"title":1220,"titles":1221,"content":1222,"level":30},"/v1.0.1/reference/api#removecondition","RemoveCondition",[1140,1211],"Removes conditions by name. func (f *Factory[T]) RemoveCondition(names ...pipz.Name) int",{"id":1224,"title":1225,"titles":1226,"content":1227,"level":30},"/v1.0.1/reference/api#hascondition","HasCondition",[1140,1211],"Checks if a condition is registered. func (f *Factory[T]) HasCondition(name pipz.Name) bool",{"id":1229,"title":1230,"titles":1231,"content":1232,"level":30},"/v1.0.1/reference/api#listconditions","ListConditions",[1140,1211],"Returns all registered condition names. func (f *Factory[T]) ListConditions() []pipz.Name",{"id":1234,"title":1235,"titles":1236,"content":24,"level":19},"/v1.0.1/reference/api#channel-registration","Channel Registration",[1140],{"id":1238,"title":1239,"titles":1240,"content":1241,"level":30},"/v1.0.1/reference/api#addchannel","AddChannel",[1140,1235],"Registers a channel for stream nodes. func (f *Factory[T]) AddChannel(name string, channel chan\u003C- T) Example: ch := make(chan Order, 100)\nfactory.AddChannel(\"orders\", ch)",{"id":1243,"title":1244,"titles":1245,"content":1246,"level":30},"/v1.0.1/reference/api#getchannel","GetChannel",[1140,1235],"Retrieves a registered channel. func (f *Factory[T]) GetChannel(name string) (chan\u003C- T, bool)",{"id":1248,"title":1249,"titles":1250,"content":1251,"level":30},"/v1.0.1/reference/api#haschannel","HasChannel",[1140,1235],"Checks if a channel is registered. func (f *Factory[T]) HasChannel(name string) bool",{"id":1253,"title":1254,"titles":1255,"content":1256,"level":30},"/v1.0.1/reference/api#listchannels","ListChannels",[1140,1235],"Returns all registered channel names. func (f *Factory[T]) ListChannels() []string",{"id":1258,"title":1259,"titles":1260,"content":1261,"level":30},"/v1.0.1/reference/api#removechannel","RemoveChannel",[1140,1235],"Removes a channel from the factory. func (f *Factory[T]) RemoveChannel(name string) bool",{"id":1263,"title":209,"titles":1264,"content":24,"level":19},"/v1.0.1/reference/api#building-pipelines",[1140],{"id":1266,"title":1267,"titles":1268,"content":1269,"level":30},"/v1.0.1/reference/api#build","Build",[1140,209],"Builds a pipeline from a Schema struct. func (f *Factory[T]) Build(schema Schema) (pipz.Chainable[T], error) Example: schema := flume.Schema{\n    Version: \"1.0.0\",\n    Node: flume.Node{\n        Type: \"sequence\",\n        Children: []flume.Node{\n            {Ref: \"validate\"},\n            {Ref: \"process\"},\n        },\n    },\n}\npipeline, err := factory.Build(schema)",{"id":1271,"title":1272,"titles":1273,"content":1274,"level":30},"/v1.0.1/reference/api#buildfromyaml","BuildFromYAML",[1140,209],"Builds a pipeline from a YAML string. func (f *Factory[T]) BuildFromYAML(yamlStr string) (pipz.Chainable[T], error) Example: schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process\n`\npipeline, err := factory.BuildFromYAML(schema)",{"id":1276,"title":1277,"titles":1278,"content":1279,"level":30},"/v1.0.1/reference/api#buildfromjson","BuildFromJSON",[1140,209],"Builds a pipeline from a JSON string. func (f *Factory[T]) BuildFromJSON(jsonStr string) (pipz.Chainable[T], error)",{"id":1281,"title":1282,"titles":1283,"content":1284,"level":30},"/v1.0.1/reference/api#buildfromfile","BuildFromFile",[1140,209],"Builds a pipeline from a file (YAML or JSON). func (f *Factory[T]) BuildFromFile(path string) (pipz.Chainable[T], error) Supported Extensions: .yaml, .yml, .json",{"id":1286,"title":1287,"titles":1288,"content":24,"level":19},"/v1.0.1/reference/api#schema-management","Schema Management",[1140],{"id":1290,"title":1291,"titles":1292,"content":1293,"level":30},"/v1.0.1/reference/api#setschema","SetSchema",[1140,1287],"Adds or updates a named schema. func (f *Factory[T]) SetSchema(name string, schema Schema) error Validates the schema, builds the pipeline, and stores both. If the schema exists, atomically updates it. Example: err := factory.SetSchema(\"order-pipeline\", schema)",{"id":1295,"title":1296,"titles":1297,"content":1298,"level":30},"/v1.0.1/reference/api#getschema","GetSchema",[1140,1287],"Retrieves a schema by name. func (f *Factory[T]) GetSchema(name string) (Schema, bool)",{"id":1300,"title":1301,"titles":1302,"content":1303,"level":30},"/v1.0.1/reference/api#removeschema","RemoveSchema",[1140,1287],"Removes a named schema. func (f *Factory[T]) RemoveSchema(name string) bool Returns: true if removed, false if not found",{"id":1305,"title":1306,"titles":1307,"content":1308,"level":30},"/v1.0.1/reference/api#listschemas","ListSchemas",[1140,1287],"Returns all registered schema names. func (f *Factory[T]) ListSchemas() []string",{"id":1310,"title":1311,"titles":1312,"content":1313,"level":30},"/v1.0.1/reference/api#bind","Bind",[1140,1287],"Creates or retrieves a binding for a schema. func (f *Factory[T]) Bind(identity pipz.Identity, schemaID string, opts ...BindingOption[T]) (*Binding[T], error) Parameters: identity - Unique identifier for this bindingschemaID - ID of schema in registry (must exist)opts - Optional configuration (e.g., WithAutoSync()) Returns: *Binding[T] on success, error if schema not found Example: pipelineID := factory.Identity(\"order-processor\", \"Processes orders\")\nbinding, err := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\nif err != nil {\n    return err\n}\nresult, err := binding.Process(ctx, order)",{"id":1315,"title":1316,"titles":1317,"content":1318,"level":30},"/v1.0.1/reference/api#get","Get",[1140,1287],"Retrieves an existing binding by identity. func (f *Factory[T]) Get(identity pipz.Identity) *Binding[T] Returns: *Binding[T] if found, nil otherwise",{"id":1320,"title":1321,"titles":1322,"content":1323,"level":19},"/v1.0.1/reference/api#binding","Binding",[1140],"A Binding[T] represents a live pipeline bound to a schema. It provides lock-free execution via atomic.Pointer.",{"id":1325,"title":1326,"titles":1327,"content":1328,"level":30},"/v1.0.1/reference/api#process","Process",[1140,1321],"Executes the pipeline with the given data. func (b *Binding[T]) Process(ctx context.Context, data T) (T, error) Lock-free operation using atomic pointer access.",{"id":1330,"title":1331,"titles":1332,"content":1333,"level":30},"/v1.0.1/reference/api#withautosync","WithAutoSync",[1140,1321],"Option to enable automatic rebuilding when the source schema changes. flume.WithAutoSync[T]() When enabled, calls to factory.SetSchema() automatically rebuild this binding.",{"id":1335,"title":1336,"titles":1337,"content":1338,"level":30},"/v1.0.1/reference/api#binding-accessors","Binding Accessors",[1140,1321],"binding.Identity()  // Returns pipz.Identity\nbinding.SchemaID()  // Returns string (schema ID)\nbinding.AutoSync()  // Returns bool\nbinding.Pipeline()  // Returns *pipz.Pipeline[T]",{"id":1340,"title":52,"titles":1341,"content":24,"level":19},"/v1.0.1/reference/api#validation",[1140],{"id":1343,"title":1344,"titles":1345,"content":1346,"level":30},"/v1.0.1/reference/api#validateschema","ValidateSchema",[1140,52],"Validates a schema against registered components without building it. func (f *Factory[T]) ValidateSchema(schema Schema) error Returns: nil if valid, ValidationErrors otherwise Checks: Schema structure (node types, required fields)All processor references existAll predicate references existAll condition references existAll reducer references existAll error handler references existAll channel references existCircular reference detection Example: if err := factory.ValidateSchema(schema); err != nil {\n    fmt.Println(err)\n    // 3 validation errors:\n    //   1. root.children[0]: processor 'missing' not found\n    //   ...\n}",{"id":1348,"title":1349,"titles":1350,"content":1351,"level":30},"/v1.0.1/reference/api#validateschemastructure","ValidateSchemaStructure",[1140,52],"Validates schema syntax without requiring registered components. Use this for CI/CD schema linting where a configured factory is not available. func ValidateSchemaStructure(schema Schema) error Returns: nil if valid, ValidationErrors otherwise This validates: Node structure (ref vs type exclusivity, non-empty nodes)Connector constraints (required children, child counts)Configuration values (valid durations, positive numbers)Unknown node types This does NOT validate: Processor references existPredicate references existCondition references existReducer references existError handler references existChannel references exist Example: // CI/CD pipeline - validate schema files without a configured factory\nschema, _ := yaml.Unmarshal(data, &flume.Schema{})\nif err := flume.ValidateSchemaStructure(schema); err != nil {\n    log.Fatalf(\"Invalid schema: %v\", err)\n}",{"id":1353,"title":1354,"titles":1355,"content":24,"level":19},"/v1.0.1/reference/api#types","Types",[1140],{"id":1357,"title":1358,"titles":1359,"content":1360,"level":30},"/v1.0.1/reference/api#schema","Schema",[1140,1354],"type Schema struct {\n    Version string `json:\"version,omitempty\" yaml:\"version,omitempty\"`\n    Node    `yaml:\",inline\"`\n}",{"id":1362,"title":1363,"titles":1364,"content":1365,"level":30},"/v1.0.1/reference/api#node","Node",[1140,1354],"type Node struct {\n    Ref               string          // Processor reference\n    Type              string          // Connector type\n    Name              string          // Optional name override\n    Children          []Node          // For sequence, concurrent, etc.\n    Child             *Node           // For retry, timeout, etc.\n    Predicate         string          // For filter\n    Then              *Node           // For filter\n    Else              *Node           // For filter\n    Condition         string          // For switch\n    Routes            map[string]Node // For switch\n    Default           *Node           // For switch\n    Attempts          int             // For retry\n    Backoff           string          // For retry\n    Duration          string          // For timeout\n    FailureThreshold  int             // For circuit-breaker\n    RecoveryTimeout   string          // For circuit-breaker\n    RequestsPerSecond float64         // For rate-limit\n    BurstSize         int             // For rate-limit\n    Stream            string          // For stream nodes\n}",{"id":1367,"title":1368,"titles":1369,"content":1370,"level":30},"/v1.0.1/reference/api#predicate","Predicate",[1140,1354],"type Predicate[T any] struct {\n    Name        pipz.Name\n    Description string\n    Predicate   func(context.Context, T) bool\n}",{"id":1372,"title":1373,"titles":1374,"content":1375,"level":30},"/v1.0.1/reference/api#condition","Condition",[1140,1354],"type Condition[T any] struct {\n    Name        pipz.Name\n    Description string\n    Values      []string  // Possible return values\n    Condition   func(context.Context, T) string\n}",{"id":1377,"title":1378,"titles":1379,"content":1380,"level":30},"/v1.0.1/reference/api#processormeta","ProcessorMeta",[1140,1354],"type ProcessorMeta[T any] struct {\n    Processor   pipz.Chainable[T]\n    Description string\n    Tags        []string\n}",{"id":1382,"title":1383,"titles":1384,"content":1385,"level":30},"/v1.0.1/reference/api#reducer","Reducer",[1140,1354],"type Reducer[T any] struct {\n    Name        pipz.Name\n    Description string\n    Reducer     func(original T, results map[pipz.Name]T, errors map[pipz.Name]error) T\n} Used with concurrent connector to merge results from parallel execution. Example: factory.AddReducer(flume.Reducer[Order]{\n    Name:        \"merge-enrichments\",\n    Description: \"Combines data from parallel enrichment sources\",\n    Reducer: func(original Order, results map[pipz.Name]Order, errors map[pipz.Name]error) Order {\n        for _, result := range results {\n            original.Metadata = append(original.Metadata, result.Metadata...)\n        }\n        return original\n    },\n})",{"id":1387,"title":1388,"titles":1389,"content":1390,"level":30},"/v1.0.1/reference/api#errorhandler","ErrorHandler",[1140,1354],"type ErrorHandler[T any] struct {\n    Name        pipz.Name\n    Description string\n    Handler     pipz.Chainable[*pipz.Error[T]]\n} Used with handle connector to process errors from child execution. The handler receives a *pipz.Error[T] containing both the original data and the error. Error Recovery Pattern: Clear the error to indicate successful recovery: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"order-recovery\",\n    Description: \"Recovers failed orders by marking them for retry\",\n    Handler: pipz.Apply(\"recover\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        e.Data.Status = \"pending-retry\"\n        e.Err = nil  // Clear error - pipeline continues normally\n        return e, nil\n    }),\n}) Error Transformation Pattern: Transform the error while preserving failure state: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"error-enricher\",\n    Description: \"Enriches errors with context before propagating\",\n    Handler: pipz.Apply(\"enrich-error\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        e.Err = fmt.Errorf(\"order %s: %w\", e.Data.ID, e.Err)\n        return e, nil  // Error still propagates\n    }),\n}) Conditional Recovery Pattern: Recover from specific errors only: factory.AddErrorHandler(flume.ErrorHandler[Order]{\n    Name:        \"transient-recovery\",\n    Description: \"Recovers from transient errors, propagates others\",\n    Handler: pipz.Apply(\"conditional-recover\", func(ctx context.Context, e *pipz.Error[Order]) (*pipz.Error[Order], error) {\n        if errors.Is(e.Err, ErrTemporaryFailure) {\n            e.Data.Status = \"retrying\"\n            e.Err = nil  // Recover\n        }\n        // Non-transient errors propagate unchanged\n        return e, nil\n    }),\n}) Schema Usage: type: handle\nerror_handler: order-recovery\nchild:\n  ref: risky-operation",{"id":1392,"title":1393,"titles":1394,"content":1395,"level":30},"/v1.0.1/reference/api#validationerror","ValidationError",[1140,1354],"type ValidationError struct {\n    Path    []string  // Path to error in schema\n    Message string\n}\n\nfunc (e ValidationError) Error() string",{"id":1397,"title":1398,"titles":1399,"content":1400,"level":30},"/v1.0.1/reference/api#validationerrors","ValidationErrors",[1140,1354],"type ValidationErrors []ValidationError\n\nfunc (e ValidationErrors) Error() string",{"id":1402,"title":1403,"titles":1404,"content":24,"level":19},"/v1.0.1/reference/api#constants","Constants",[1140],{"id":1406,"title":1407,"titles":1408,"content":1409,"level":30},"/v1.0.1/reference/api#default-values","Default Values",[1140,1403],"const (\n    DefaultRetryAttempts           = 3\n    DefaultTimeoutDuration         = 30 * time.Second\n    DefaultCircuitBreakerThreshold = 5\n    DefaultRecoveryTimeout         = 60 * time.Second\n    DefaultRequestsPerSecond       = 10.0\n    DefaultBurstSize               = 1\n)",{"id":1411,"title":150,"titles":1412,"content":1413,"level":19},"/v1.0.1/reference/api#next-steps",[1140],"Schema Format - YAML/JSON specificationConnector Types - All connector optionsEvents - Observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}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 .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sfm-E, html code.shiki .sfm-E{--shiki-default:var(--shiki-variable)}",{"id":1415,"title":1416,"titles":1417,"content":1418,"level":9},"/v1.0.1/reference/schema-format","Schema Format",[],"Complete YAML/JSON schema specification",{"id":1420,"title":1416,"titles":1421,"content":1422,"level":9},"/v1.0.1/reference/schema-format#schema-format",[],"Complete specification for Flume schema documents.",{"id":1424,"title":6,"titles":1425,"content":1426,"level":19},"/v1.0.1/reference/schema-format#overview",[1416],"Schemas can be written in YAML or JSON. This reference uses YAML examples; JSON equivalents use standard JSON syntax.",{"id":1428,"title":199,"titles":1429,"content":1430,"level":19},"/v1.0.1/reference/schema-format#schema-structure",[1416],"version: \"1.0.0\"    # Optional: schema version\ntype: sequence      # Required: connector type OR ref\nname: my-pipeline   # Optional: override connector name\nchildren:           # Depends on type\n  - ref: step1\n  - ref: step2",{"id":1432,"title":1433,"titles":1434,"content":1435,"level":19},"/v1.0.1/reference/schema-format#top-level-fields","Top-Level Fields",[1416],"FieldTypeRequiredDescriptionversionstringNoSchema version for tracking changesrefstringConditionalReference to registered processortypestringConditionalConnector typenamestringNoOverride default connector name Either ref or type is required, but not both.",{"id":1437,"title":1438,"titles":1439,"content":1440,"level":19},"/v1.0.1/reference/schema-format#processor-reference","Processor Reference",[1416],"Reference a registered processor by name: ref: validate Equivalent to calling the processor directly.",{"id":1442,"title":1443,"titles":1444,"content":24,"level":19},"/v1.0.1/reference/schema-format#connector-types","Connector Types",[1416],{"id":1446,"title":1447,"titles":1448,"content":1449,"level":30},"/v1.0.1/reference/schema-format#sequence","sequence",[1416,1443],"Sequential processing through multiple steps. type: sequence\nname: my-sequence      # Optional\nchildren:              # Required: 1+ children\n  - ref: step1\n  - ref: step2\n  - ref: step3 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"sequence\"",{"id":1451,"title":1452,"titles":1453,"content":1454,"level":30},"/v1.0.1/reference/schema-format#concurrent","concurrent",[1416,1443],"Parallel execution with data cloning. type: concurrent\nname: parallel-steps   # Optional\nchildren:              # Required: 1+ children\n  - ref: task1\n  - ref: task2 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"concurrent\" Note: Requires T to implement pipz.Cloner[T].",{"id":1456,"title":1457,"titles":1458,"content":1459,"level":30},"/v1.0.1/reference/schema-format#race","race",[1416,1443],"First successful result wins. type: race\nchildren:\n  - ref: fast-path\n  - ref: slow-path FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"race\" Note: Requires T to implement pipz.Cloner[T].",{"id":1461,"title":1462,"titles":1463,"content":1464,"level":30},"/v1.0.1/reference/schema-format#fallback","fallback",[1416,1443],"Try primary, use fallback on error. type: fallback\nchildren:\n  - ref: primary       # First child is primary\n  - ref: backup        # Second child is fallback FieldTypeRequiredDefaultchildrenNode (exactly 2)Yes-namestringNo\"fallback\"",{"id":1466,"title":1467,"titles":1468,"content":1469,"level":30},"/v1.0.1/reference/schema-format#retry","retry",[1416,1443],"Retry operation on failure. type: retry\nattempts: 5            # Optional\nbackoff: \"100ms\"       # Optional: enables exponential backoff\nchild:                 # Required\n  ref: flaky-operation FieldTypeRequiredDefaultchildNodeYes-attemptsintNo3backoffdurationNo(none)namestringNo\"retry\" or \"backoff\"",{"id":1471,"title":1472,"titles":1473,"content":1474,"level":30},"/v1.0.1/reference/schema-format#timeout","timeout",[1416,1443],"Enforce time limit. type: timeout\nduration: \"5s\"         # Optional\nchild:                 # Required\n  ref: slow-operation FieldTypeRequiredDefaultchildNodeYes-durationdurationNo\"30s\"namestringNo\"timeout\"",{"id":1476,"title":1477,"titles":1478,"content":1479,"level":30},"/v1.0.1/reference/schema-format#filter","filter",[1416,1443],"Conditional execution based on predicate. type: filter\npredicate: is-valid    # Required: registered predicate name\nthen:                  # Required\n  ref: process-valid\nelse:                  # Optional\n  ref: handle-invalid FieldTypeRequiredDefaultpredicatestringYes-thenNodeYes-elseNodeNo(passthrough)namestringNo\"filter-{predicate}\"",{"id":1481,"title":1482,"titles":1483,"content":1484,"level":30},"/v1.0.1/reference/schema-format#switch","switch",[1416,1443],"Multi-way routing based on condition. type: switch\ncondition: order-type  # Required: registered condition name\nroutes:                # Required: 1+ routes\n  subscription:\n    ref: handle-subscription\n  one-time:\n    ref: handle-single\ndefault:               # Optional\n  ref: handle-unknown FieldTypeRequiredDefaultconditionstringYes-routesmapstringNodeYes-defaultNodeNo(none)namestringNo\"switch-{condition}\" Default Routing: The default node is registered as a route with key \"default\". For default routing to work, your condition function must return the string \"default\" when no other route matches: factory.AddCondition(flume.Condition[Order]{\n    Name: \"order-type\",\n    Condition: func(ctx context.Context, o Order) string {\n        switch o.Type {\n        case \"subscription\":\n            return \"subscription\"\n        case \"one-time\":\n            return \"one-time\"\n        default:\n            return \"default\"  // Triggers the default route\n        }\n    },\n})",{"id":1486,"title":1487,"titles":1488,"content":1489,"level":30},"/v1.0.1/reference/schema-format#circuit-breaker","circuit-breaker",[1416,1443],"Circuit breaker pattern. type: circuit-breaker\nfailure_threshold: 5   # Optional\nrecovery_timeout: \"60s\"  # Optional\nchild:                 # Required\n  ref: external-service FieldTypeRequiredDefaultchildNodeYes-failure_thresholdintNo5recovery_timeoutdurationNo\"60s\"namestringNo\"circuit-breaker\"",{"id":1491,"title":1492,"titles":1493,"content":1494,"level":30},"/v1.0.1/reference/schema-format#rate-limit","rate-limit",[1416,1443],"Rate limiting with token bucket. type: rate-limit\nrequests_per_second: 100.0  # Optional\nburst_size: 10              # Optional\nchild:                      # Required\n  ref: rate-sensitive-api FieldTypeRequiredDefaultchildNodeYes-requests_per_secondfloatNo10.0burst_sizeintNo1namestringNo\"rate-limit\"",{"id":1496,"title":1497,"titles":1498,"content":1499,"level":30},"/v1.0.1/reference/schema-format#stream","stream",[1416,1443],"Send to registered channel. stream: output-channel  # Required: channel name\nstream_timeout: \"5s\"    # Optional: timeout for channel write\nchild:                  # Optional: continue processing\n  ref: next-step FieldTypeRequiredDefaultstreamstringYes-stream_timeoutdurationNo(blocks indefinitely)childNodeNo(none)childrenNodeNo(none)namestringNo\"stream:{name}\" Timeout Behaviour: Without stream_timeout, the stream blocks until the channel accepts the item or the context is cancelled. With stream_timeout, returns an error if the channel doesn't accept within the duration.",{"id":1501,"title":1502,"titles":1503,"content":1504,"level":30},"/v1.0.1/reference/schema-format#contest","contest",[1416,1443],"First result satisfying a predicate. type: contest\npredicate: is-valid      # Required: registered predicate name\nchildren:                # Required: 1+ children\n  - ref: source1\n  - ref: source2 FieldTypeRequiredDefaultpredicatestringYes-childrenNodeYes-namestringNo\"contest-{predicate}\" Note: Requires T to implement pipz.Cloner[T].",{"id":1506,"title":1507,"titles":1508,"content":1509,"level":30},"/v1.0.1/reference/schema-format#handle","handle",[1416,1443],"Wrap child with error handling. type: handle\nerror_handler: recovery  # Required: registered error handler name\nchild:                   # Required\n  ref: risky-operation FieldTypeRequiredDefaulterror_handlerstringYes-childNodeYes-namestringNo\"handle-{handler}\"",{"id":1511,"title":1512,"titles":1513,"content":1514,"level":30},"/v1.0.1/reference/schema-format#scaffold","scaffold",[1416,1443],"Structural grouping of children. type: scaffold\nname: validation-stage   # Optional\nchildren:                # Required: 1+ children\n  - ref: step1\n  - ref: step2 FieldTypeRequiredDefaultchildrenNodeYes-namestringNo\"scaffold\"",{"id":1516,"title":1517,"titles":1518,"content":1519,"level":30},"/v1.0.1/reference/schema-format#worker-pool","worker-pool",[1416,1443],"Bounded parallel execution. type: worker-pool\nworkers: 8               # Optional\nchildren:                # Required: 1+ children\n  - ref: task1\n  - ref: task2 FieldTypeRequiredDefaultchildrenNodeYes-workersintNo4namestringNo\"worker-pool\" Note: Requires T to implement pipz.Cloner[T].",{"id":1521,"title":1522,"titles":1523,"content":1524,"level":19},"/v1.0.1/reference/schema-format#duration-format","Duration Format",[1416],"Durations use Go's duration format: FormatExampleNanoseconds100nsMicroseconds50µs or 50usMilliseconds100msSeconds5sMinutes2mHours1hCombined1h30m, 2m30s",{"id":1526,"title":1527,"titles":1528,"content":1529,"level":19},"/v1.0.1/reference/schema-format#nesting","Nesting",[1416],"Nodes can be nested arbitrarily: type: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: is-premium\n    then:\n      type: retry\n      attempts: 3\n      child:\n        type: timeout\n        duration: \"5s\"\n        child:\n          ref: premium-process\n  - ref: finalize",{"id":1531,"title":1532,"titles":1533,"content":1534,"level":19},"/v1.0.1/reference/schema-format#json-format","JSON Format",[1416],"Equivalent JSON for the nested example: {\n  \"type\": \"sequence\",\n  \"children\": [\n    {\"ref\": \"validate\"},\n    {\n      \"type\": \"filter\",\n      \"predicate\": \"is-premium\",\n      \"then\": {\n        \"type\": \"retry\",\n        \"attempts\": 3,\n        \"child\": {\n          \"type\": \"timeout\",\n          \"duration\": \"5s\",\n          \"child\": {\"ref\": \"premium-process\"}\n        }\n      }\n    },\n    {\"ref\": \"finalize\"}\n  ]\n}",{"id":1536,"title":1537,"titles":1538,"content":1539,"level":19},"/v1.0.1/reference/schema-format#validation-rules","Validation Rules",[1416],"Either ref or type - Node must have exactly oneRequired fields - Each type has required fieldsRegistered components - All refs, predicates, conditions must existCorrect counts - fallback needs exactly 2 childrenValid durations - Duration strings must parsePositive values - attempts, threshold must be positiveNo cycles - Reference chains cannot loop",{"id":1541,"title":150,"titles":1542,"content":1543,"level":19},"/v1.0.1/reference/schema-format#next-steps",[1416],"Connector Types - Detailed connector behaviourAPI Reference - Factory methods html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}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 .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}",{"id":1545,"title":1443,"titles":1546,"content":1547,"level":9},"/v1.0.1/reference/connector-types",[],"Detailed reference for all Flume connector types",{"id":1549,"title":1443,"titles":1550,"content":1551,"level":9},"/v1.0.1/reference/connector-types#connector-types",[],"Detailed reference for all Flume connector types and their behaviour.",{"id":1553,"title":1554,"titles":1555,"content":24,"level":19},"/v1.0.1/reference/connector-types#flow-control","Flow Control",[1443],{"id":1557,"title":1447,"titles":1558,"content":1559,"level":30},"/v1.0.1/reference/connector-types#sequence",[1443,1554],"Processes data through multiple steps in order. Schema: type: sequence\nchildren:\n  - ref: step1\n  - ref: step2\n  - ref: step3 Behaviour: Process step1 with input dataPass step1 output to step2Pass step2 output to step3Return step3 output Error Handling: Stops on first error, returns that error. Use Cases: Multi-stage processingPipeline compositionSequential transformations",{"id":1561,"title":1452,"titles":1562,"content":1563,"level":30},"/v1.0.1/reference/connector-types#concurrent",[1443,1554],"Executes multiple steps in parallel. Schema: type: concurrent\nchildren:\n  - ref: task1\n  - ref: task2\n  - ref: task3 Behaviour: Clone input data for each childExecute all children concurrentlyWait for all to completeMerge results Error Handling: Collects all errors, returns first error encountered. Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Parallel enrichment from multiple sourcesIndependent validationsConcurrent API calls",{"id":1565,"title":1457,"titles":1566,"content":1567,"level":30},"/v1.0.1/reference/connector-types#race",[1443,1554],"Returns first successful result. Schema: type: race\nchildren:\n  - ref: fast-path\n  - ref: slow-path Behaviour: Clone input data for each childExecute all children concurrentlyReturn first successful resultCancel other executions Error Handling: Returns error only if all children fail. Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Redundant data sourcesFastest-wins scenariosSpeculative execution",{"id":1569,"title":363,"titles":1570,"content":24,"level":19},"/v1.0.1/reference/connector-types#error-handling",[1443],{"id":1572,"title":1462,"titles":1573,"content":1574,"level":30},"/v1.0.1/reference/connector-types#fallback",[1443,363],"Provides backup processing on failure. Schema: type: fallback\nchildren:\n  - ref: primary\n  - ref: backup Behaviour: Execute primary with inputIf primary succeeds, return resultIf primary fails, execute backupReturn backup result or error Requirements: Exactly 2 children. Use Cases: Service redundancyGraceful degradationDefault value provision",{"id":1576,"title":1467,"titles":1577,"content":1578,"level":30},"/v1.0.1/reference/connector-types#retry",[1443,363],"Retries on transient failures. Schema: type: retry\nattempts: 3\nchild:\n  ref: operation With backoff: type: retry\nattempts: 5\nbackoff: \"100ms\"\nchild:\n  ref: operation Behaviour without backoff: Execute childIf error, retry up to attempts timesReturn success or final error Behaviour with backoff: Execute childIf error, wait backoff durationRetry with doubled wait time (exponential)Continue until success or attempts exhausted Defaults: attempts: 3backoff: none (immediate retry) Use Cases: Network timeoutsRate limit handlingTransient service failures",{"id":1580,"title":1472,"titles":1581,"content":1582,"level":30},"/v1.0.1/reference/connector-types#timeout",[1443,363],"Enforces execution time limit. Schema: type: timeout\nduration: \"5s\"\nchild:\n  ref: operation Behaviour: Start child execution with deadline contextIf completes before deadline, return resultIf deadline exceeded, cancel and return error Default: 30 seconds Error: Returns context.DeadlineExceeded Use Cases: External API callsLong-running computationsUser-facing requests",{"id":1584,"title":1487,"titles":1585,"content":1586,"level":30},"/v1.0.1/reference/connector-types#circuit-breaker",[1443,363],"Prevents repeated calls to failing services. Schema: type: circuit-breaker\nfailure_threshold: 5\nrecovery_timeout: \"30s\"\nchild:\n  ref: service States: StateBehaviourClosedNormal operation, count failuresOpenFail immediately, don't call childHalf-OpenAllow one test request Behaviour: Closed: Execute child, count failuresAfter failure_threshold failures, open circuitOpen: Return error immediatelyAfter recovery_timeout, enter half-openHalf-Open: Execute one test requestIf test succeeds, close circuitIf test fails, reopen circuit Defaults: failure_threshold: 5recovery_timeout: 60s Use Cases: External service protectionCascade failure preventionAllowing service recovery",{"id":1588,"title":1492,"titles":1589,"content":1590,"level":30},"/v1.0.1/reference/connector-types#rate-limit",[1443,363],"Controls request throughput. Schema: type: rate-limit\nrequests_per_second: 100.0\nburst_size: 10\nchild:\n  ref: operation Behaviour: Wait for token from bucketExecute childReturn result Uses token bucket algorithm: Tokens added at requests_per_second rateUp to burst_size tokens can accumulateRequest waits if no tokens available Defaults: requests_per_second: 10.0burst_size: 1 Use Cases: API rate limit complianceResource protectionFair usage enforcement",{"id":1592,"title":1593,"titles":1594,"content":24,"level":19},"/v1.0.1/reference/connector-types#routing","Routing",[1443],{"id":1596,"title":1477,"titles":1597,"content":1598,"level":30},"/v1.0.1/reference/connector-types#filter",[1443,1593],"Conditional execution based on boolean predicate. Schema: type: filter\npredicate: is-valid\nthen:\n  ref: process\nelse:\n  ref: handle-invalid  # Optional Behaviour with else: Evaluate predicateIf true, execute then branchIf false, execute else branchReturn result Behaviour without else: Evaluate predicateIf true, execute then branchIf false, pass data through unchanged Requirements: Predicate must be registered with factory. Use Cases: Conditional processingFeature flagsValidation gates",{"id":1600,"title":1482,"titles":1601,"content":1602,"level":30},"/v1.0.1/reference/connector-types#switch",[1443,1593],"Multi-way routing based on condition value. Schema: type: switch\ncondition: category\nroutes:\n  electronics:\n    ref: handle-electronics\n  clothing:\n    ref: handle-clothing\n  food:\n    ref: handle-food\ndefault:\n  ref: handle-other Behaviour: Evaluate condition functionMatch return value to route keyExecute matched routeIf no match and default exists, execute defaultIf no match and no default, pass through unchanged Default Route: The condition function should return \"default\" for default routing. Requirements: Condition must be registered with factory. Use Cases: Multi-tenant routingCategory handlingStatus-based processing",{"id":1604,"title":1605,"titles":1606,"content":24,"level":19},"/v1.0.1/reference/connector-types#streaming","Streaming",[1443],{"id":1608,"title":1497,"titles":1609,"content":1610,"level":30},"/v1.0.1/reference/connector-types#stream",[1443,1605],"Sends data to a registered channel. Schema (terminal): stream: output-channel Schema (with timeout): stream: output-channel\nstream_timeout: \"5s\" Schema (with continuation): stream: audit-channel\nchild:\n  ref: continue-processing Behaviour (terminal): Send data to channelReturn data (unchanged) Behaviour (with child): Send data to channelExecute childReturn child result Timeout Behaviour: Without stream_timeout: Blocks until channel accepts or context cancelledWith stream_timeout: Returns error if write doesn't complete within duration Requirements: Channel must be registered with factory. Use Cases: Stream processing integrationAsync event publishingAudit loggingFan-out patterns",{"id":1612,"title":1613,"titles":1614,"content":24,"level":19},"/v1.0.1/reference/connector-types#advanced","Advanced",[1443],{"id":1616,"title":1502,"titles":1617,"content":1618,"level":30},"/v1.0.1/reference/connector-types#contest",[1443,1613],"Runs children concurrently and returns the first result satisfying a predicate. Schema: type: contest\npredicate: is-valid\nchildren:\n  - ref: source1\n  - ref: source2\n  - ref: source3 Behaviour: Clone input data for each childExecute all children concurrentlyEvaluate predicate against each result as it completesReturn first result where predicate returns trueCancel remaining executions Error Handling: Returns error if no child produces a result satisfying the predicate. Requirements: Type T must implement pipz.Cloner[T]Predicate must be registered with factory Use Cases: Find first valid response from multiple sourcesSpeculative execution with validationBest-effort data retrieval",{"id":1620,"title":1507,"titles":1621,"content":1622,"level":30},"/v1.0.1/reference/connector-types#handle",[1443,1613],"Wraps a child with custom error handling logic. Schema: type: handle\nerror_handler: recovery-handler\nchild:\n  ref: risky-operation Behaviour: Execute childIf child succeeds, return resultIf child fails, pass error to handlerHandler receives *pipz.Error[T] with original data and errorReturn handler result Error Handling: Handler can recover, transform, or propagate the error. Requirements: Error handler must be registered with factory. Use Cases: Custom error recoveryError transformationContextual error handlingCompensating transactions",{"id":1624,"title":1512,"titles":1625,"content":1626,"level":30},"/v1.0.1/reference/connector-types#scaffold",[1443,1613],"Structural wrapper that groups children for organisational purposes. Schema: type: scaffold\nname: validation-stage\nchildren:\n  - ref: validate-format\n  - ref: validate-business-rules\n  - ref: validate-permissions Behaviour: Execute children in sequencePass output of each child to the nextReturn final child's output Error Handling: Stops on first error, returns that error. Use Cases: Logical grouping of related processorsPipeline organisationNamed stages for observability",{"id":1628,"title":1517,"titles":1629,"content":1630,"level":30},"/v1.0.1/reference/connector-types#worker-pool",[1443,1613],"Distributes work across a pool of workers. Schema: type: worker-pool\nworkers: 8\nchildren:\n  - ref: task1\n  - ref: task2\n  - ref: task3 Behaviour: Create pool of workers goroutinesDistribute children across workersExecute concurrently within worker limitCollect and merge results Defaults: workers: 4 Requirements: Type T must implement pipz.Cloner[T]. Use Cases: Bounded concurrencyResource-constrained parallel processingBatch processing with limits",{"id":1632,"title":1633,"titles":1634,"content":1635,"level":19},"/v1.0.1/reference/connector-types#comparison-table","Comparison Table",[1443],"TypePurposeError BehaviourCloningsequenceChain stepsStop on errorNoconcurrentParallel executionReturn first errorYesraceFirst successError if all failYesfallbackBackup processingTry backupNoretryTransient failuresRetry n timesNotimeoutTime limitCancel on timeoutNocircuit-breakerFailure protectionFail fast when openNorate-limitThroughput controlWait for tokenNofilterConditional routingFrom branchNoswitchMulti-way routingFrom routeNostreamChannel outputFrom sendNocontestFirst valid resultError if none validYeshandleError handlingFrom handlerNoscaffoldLogical groupingStop on errorNoworker-poolBounded parallelismReturn first errorYes",{"id":1637,"title":150,"titles":1638,"content":1639,"level":19},"/v1.0.1/reference/connector-types#next-steps",[1443],"Schema Format - YAML/JSON syntaxEvents - Observability signals html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}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 .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",{"id":1641,"title":1642,"titles":1643,"content":1644,"level":9},"/v1.0.1/reference/events","Events",[],"Complete reference for Flume observability events",{"id":1646,"title":1642,"titles":1647,"content":1648,"level":9},"/v1.0.1/reference/events#events",[],"Complete reference for Flume's observability events using Capitan.",{"id":1650,"title":1651,"titles":1652,"content":24,"level":19},"/v1.0.1/reference/events#signal-categories","Signal Categories",[1642],{"id":1654,"title":1655,"titles":1656,"content":1657,"level":30},"/v1.0.1/reference/events#factory-lifecycle","Factory Lifecycle",[1642,1651],"SignalDescriptionFactoryCreatedFactory instantiatedProcessorRegisteredProcessor added to factoryPredicateRegisteredPredicate added to factoryConditionRegisteredCondition added to factoryProcessorRemovedProcessor removed from factoryPredicateRemovedPredicate removed from factoryConditionRemovedCondition removed from factory",{"id":1659,"title":1660,"titles":1661,"content":1662,"level":30},"/v1.0.1/reference/events#schema-validation","Schema Validation",[1642,1651],"SignalDescriptionSchemaValidationStartedValidation beganSchemaValidationCompletedValidation successfulSchemaValidationFailedValidation found errors",{"id":1664,"title":1665,"titles":1666,"content":1667,"level":30},"/v1.0.1/reference/events#schema-building","Schema Building",[1642,1651],"SignalDescriptionSchemaBuildStartedBuild beganSchemaBuildCompletedBuild successfulSchemaBuildFailedBuild failed",{"id":1669,"title":214,"titles":1670,"content":1671,"level":30},"/v1.0.1/reference/events#dynamic-schema-management",[1642,1651],"SignalDescriptionSchemaRegisteredNew schema added via SetSchemaSchemaUpdatedExisting schema replacedSchemaRemovedSchema removedPipelineRetrievedPipeline accessed via Pipeline()",{"id":1673,"title":1674,"titles":1675,"content":1676,"level":30},"/v1.0.1/reference/events#file-operations","File Operations",[1642,1651],"SignalDescriptionSchemaFileLoadedFile read successfullySchemaFileFailedFile read failedSchemaYAMLParsedYAML parsed successfullySchemaJSONParsedJSON parsed successfullySchemaParseFailedParse failed",{"id":1678,"title":1679,"titles":1680,"content":24,"level":19},"/v1.0.1/reference/events#field-keys","Field Keys",[1642],{"id":1682,"title":1683,"titles":1684,"content":1685,"level":30},"/v1.0.1/reference/events#string-fields","String Fields",[1642,1679],"KeyTypeDescriptionKeyNamestringComponent or schema nameKeyTypestringData type (e.g., *main.Order)KeyVersionstringSchema versionKeyOldVersionstringPrevious version (on update)KeyNewVersionstringNew version (on update)KeyPathstringFile pathKeyErrorstringError message",{"id":1687,"title":1688,"titles":1689,"content":1690,"level":30},"/v1.0.1/reference/events#duration-fields","Duration Fields",[1642,1679],"KeyTypeDescriptionKeyDurationtime.DurationOperation duration",{"id":1692,"title":1693,"titles":1694,"content":1695,"level":30},"/v1.0.1/reference/events#integer-fields","Integer Fields",[1642,1679],"KeyTypeDescriptionKeyErrorCountintNumber of validation errorsKeySizeBytesintFile size in bytes",{"id":1697,"title":1698,"titles":1699,"content":1700,"level":30},"/v1.0.1/reference/events#boolean-fields","Boolean Fields",[1642,1679],"KeyTypeDescriptionKeyFoundboolWhether pipeline was found",{"id":1702,"title":1703,"titles":1704,"content":24,"level":19},"/v1.0.1/reference/events#event-details","Event Details",[1642],{"id":1706,"title":1707,"titles":1708,"content":1709,"level":30},"/v1.0.1/reference/events#factorycreated","FactoryCreated",[1642,1703],"Emitted when flume.New[T]() is called. Fields: KeyType: The type parameter T Example: capitan.Handle(flume.FactoryCreated, func(ctx context.Context, fields []capitan.Field) {\n    dataType := extractString(fields, \"type\")\n    log.Printf(\"Factory created for type: %s\", dataType)\n})",{"id":1711,"title":1712,"titles":1713,"content":1714,"level":30},"/v1.0.1/reference/events#processorregistered","ProcessorRegistered",[1642,1703],"Emitted when a processor is added. Fields: KeyName: Processor name",{"id":1716,"title":1717,"titles":1718,"content":1719,"level":30},"/v1.0.1/reference/events#schemavalidationstarted","SchemaValidationStarted",[1642,1703],"Emitted at the start of validation. Fields: None",{"id":1721,"title":1722,"titles":1723,"content":1724,"level":30},"/v1.0.1/reference/events#schemavalidationcompleted","SchemaValidationCompleted",[1642,1703],"Emitted on successful validation. Fields: KeyDuration: Validation duration",{"id":1726,"title":1727,"titles":1728,"content":1729,"level":30},"/v1.0.1/reference/events#schemavalidationfailed","SchemaValidationFailed",[1642,1703],"Emitted when validation finds errors. Fields: KeyErrorCount: Number of errorsKeyDuration: Validation duration Example: capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n    count := extractInt(fields, \"error_count\")\n    duration := extractDuration(fields, \"duration\")\n    log.Printf(\"Validation failed with %d errors in %v\", count, duration)\n})",{"id":1731,"title":1732,"titles":1733,"content":1734,"level":30},"/v1.0.1/reference/events#schemabuildstarted","SchemaBuildStarted",[1642,1703],"Emitted at the start of building. Fields: KeyVersion: Schema version (if present)",{"id":1736,"title":1737,"titles":1738,"content":1739,"level":30},"/v1.0.1/reference/events#schemabuildcompleted","SchemaBuildCompleted",[1642,1703],"Emitted on successful build. Fields: KeyDuration: Build durationKeyVersion: Schema version (if present)",{"id":1741,"title":1742,"titles":1743,"content":1744,"level":30},"/v1.0.1/reference/events#schemabuildfailed","SchemaBuildFailed",[1642,1703],"Emitted when build fails. Fields: KeyError: Error messageKeyDuration: Duration until failureKeyVersion: Schema version (if present)",{"id":1746,"title":1747,"titles":1748,"content":1749,"level":30},"/v1.0.1/reference/events#schemaregistered","SchemaRegistered",[1642,1703],"Emitted when a new schema is added. Fields: KeyName: Schema nameKeyVersion: Schema version (if present)",{"id":1751,"title":1752,"titles":1753,"content":1754,"level":30},"/v1.0.1/reference/events#schemaupdated","SchemaUpdated",[1642,1703],"Emitted when an existing schema is replaced. Fields: KeyName: Schema nameKeyOldVersion: Previous version (if present)KeyNewVersion: New version (if present) Example: capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    oldV := extractString(fields, \"old_version\")\n    newV := extractString(fields, \"new_version\")\n    log.Printf(\"Schema %s: %s -> %s\", name, oldV, newV)\n})",{"id":1756,"title":1757,"titles":1758,"content":1759,"level":30},"/v1.0.1/reference/events#pipelineretrieved","PipelineRetrieved",[1642,1703],"Emitted when Pipeline() is called. Fields: KeyName: Schema name requestedKeyFound: Whether pipeline exists Example: capitan.Handle(flume.PipelineRetrieved, func(ctx context.Context, fields []capitan.Field) {\n    name := extractString(fields, \"name\")\n    found := extractBool(fields, \"found\")\n    if !found {\n        log.Printf(\"Pipeline not found: %s\", name)\n    }\n})",{"id":1761,"title":1762,"titles":1763,"content":1764,"level":30},"/v1.0.1/reference/events#schemafileloaded","SchemaFileLoaded",[1642,1703],"Emitted when a file is read. Fields: KeyPath: File pathKeySizeBytes: File size",{"id":1766,"title":1767,"titles":1768,"content":1769,"level":30},"/v1.0.1/reference/events#schemaparsefailed","SchemaParseFailed",[1642,1703],"Emitted when parsing fails. Fields: KeyPath: File path (if from file)KeyError: Parse error message",{"id":1771,"title":1772,"titles":1773,"content":24,"level":19},"/v1.0.1/reference/events#handler-patterns","Handler Patterns",[1642],{"id":1775,"title":1776,"titles":1777,"content":1778,"level":30},"/v1.0.1/reference/events#complete-logging-handler","Complete Logging Handler",[1642,1772],"func setupLogging() {\n    signals := map[capitan.Signal]string{\n        flume.FactoryCreated:            \"Factory created\",\n        flume.ProcessorRegistered:       \"Processor registered\",\n        flume.SchemaValidationStarted:   \"Validation started\",\n        flume.SchemaValidationCompleted: \"Validation completed\",\n        flume.SchemaValidationFailed:    \"Validation failed\",\n        flume.SchemaBuildStarted:        \"Build started\",\n        flume.SchemaBuildCompleted:      \"Build completed\",\n        flume.SchemaBuildFailed:         \"Build failed\",\n        flume.SchemaRegistered:          \"Schema registered\",\n        flume.SchemaUpdated:             \"Schema updated\",\n        flume.SchemaRemoved:             \"Schema removed\",\n        flume.PipelineRetrieved:         \"Pipeline retrieved\",\n    }\n\n    for signal, message := range signals {\n        s, m := signal, message\n        capitan.Handle(s, func(ctx context.Context, fields []capitan.Field) {\n            log.Printf(\"[FLUME] %s: %v\", m, formatFields(fields))\n        })\n    }\n}\n\nfunc formatFields(fields []capitan.Field) string {\n    parts := make([]string, 0, len(fields))\n    for _, f := range fields {\n        parts = append(parts, fmt.Sprintf(\"%s=%v\", f.Key, f.Value()))\n    }\n    return strings.Join(parts, \", \")\n}",{"id":1780,"title":1781,"titles":1782,"content":1783,"level":30},"/v1.0.1/reference/events#metrics-handler","Metrics Handler",[1642,1772],"func setupMetrics() {\n    // Build latency histogram\n    capitan.Handle(flume.SchemaBuildCompleted, func(ctx context.Context, fields []capitan.Field) {\n        for _, f := range fields {\n            if f.Key == \"duration\" {\n                metrics.RecordBuildLatency(f.Duration())\n            }\n        }\n    })\n\n    // Error counter\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        metrics.IncrBuildErrors()\n    })\n\n    capitan.Handle(flume.SchemaValidationFailed, func(ctx context.Context, fields []capitan.Field) {\n        metrics.IncrValidationErrors()\n    })\n}",{"id":1785,"title":1786,"titles":1787,"content":1788,"level":30},"/v1.0.1/reference/events#alerting-handler","Alerting Handler",[1642,1772],"func setupAlerting() {\n    capitan.Handle(flume.SchemaBuildFailed, func(ctx context.Context, fields []capitan.Field) {\n        errMsg := extractString(fields, \"error\")\n        alerting.Send(alerting.Error, fmt.Sprintf(\"Flume build failed: %s\", errMsg))\n    })\n\n    capitan.Handle(flume.SchemaUpdated, func(ctx context.Context, fields []capitan.Field) {\n        name := extractString(fields, \"name\")\n        oldV := extractString(fields, \"old_version\")\n        newV := extractString(fields, \"new_version\")\n\n        // Alert on major version changes\n        if isMajorChange(oldV, newV) {\n            alerting.Send(alerting.Warning,\n                fmt.Sprintf(\"Major version change: %s %s->%s\", name, oldV, newV))\n        }\n    })\n}",{"id":1790,"title":1791,"titles":1792,"content":1793,"level":19},"/v1.0.1/reference/events#helper-functions","Helper Functions",[1642],"func extractString(fields []capitan.Field, key string) string {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.String()\n        }\n    }\n    return \"\"\n}\n\nfunc extractInt(fields []capitan.Field, key string) int {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Int()\n        }\n    }\n    return 0\n}\n\nfunc extractBool(fields []capitan.Field, key string) bool {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Bool()\n        }\n    }\n    return false\n}\n\nfunc extractDuration(fields []capitan.Field, key string) time.Duration {\n    for _, f := range fields {\n        if f.Key == key {\n            return f.Duration()\n        }\n    }\n    return 0\n}",{"id":1795,"title":150,"titles":1796,"content":1797,"level":19},"/v1.0.1/reference/events#next-steps",[1642],"Observability Guide - Monitoring patternsCapitan Documentation - Event system html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}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 .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}",[1799],{"title":1800,"path":1801,"stem":1802,"children":1803,"page":1818},"V101","/v1.0.1","v1.0.1",[1804,1806,1819,1833,1840],{"title":6,"path":5,"stem":1805,"description":8},"v1.0.1/1.overview",{"title":66,"path":1807,"stem":1808,"children":1809,"page":1818},"/v1.0.1/learn","v1.0.1/2.learn",[1810,1812,1814,1816],{"title":81,"path":80,"stem":1811,"description":83},"v1.0.1/2.learn/1.quickstart",{"title":155,"path":154,"stem":1813,"description":157},"v1.0.1/2.learn/2.core-concepts",{"title":16,"path":246,"stem":1815,"description":248},"v1.0.1/2.learn/3.architecture",{"title":209,"path":330,"stem":1817,"description":332},"v1.0.1/2.learn/4.building-pipelines",false,{"title":71,"path":1820,"stem":1821,"children":1822,"page":1818},"/v1.0.1/guides","v1.0.1/3.guides",[1823,1825,1827,1829,1831],{"title":443,"path":442,"stem":1824,"description":445},"v1.0.1/3.guides/1.schema-design",{"title":219,"path":583,"stem":1826,"description":585},"v1.0.1/3.guides/2.hot-reloading",{"title":363,"path":712,"stem":1828,"description":714},"v1.0.1/3.guides/3.error-handling",{"title":879,"path":878,"stem":1830,"description":881},"v1.0.1/3.guides/4.testing",{"title":666,"path":974,"stem":1832,"description":976},"v1.0.1/3.guides/5.observability",{"title":1834,"path":1835,"stem":1836,"children":1837,"page":1818},"Cookbook","/v1.0.1/cookbook","v1.0.1/4.cookbook",[1838],{"title":1096,"path":1095,"stem":1839,"description":1098},"v1.0.1/4.cookbook/1.common-patterns",{"title":76,"path":1841,"stem":1842,"children":1843,"page":1818},"/v1.0.1/reference","v1.0.1/5.reference",[1844,1846,1848,1850],{"title":1140,"path":1139,"stem":1845,"description":1142},"v1.0.1/5.reference/1.api",{"title":1416,"path":1415,"stem":1847,"description":1418},"v1.0.1/5.reference/2.schema-format",{"title":1443,"path":1545,"stem":1849,"description":1547},"v1.0.1/5.reference/3.connector-types",{"title":1642,"path":1641,"stem":1851,"description":1644},"v1.0.1/5.reference/4.events",[1853],{"title":1800,"path":1801,"stem":1802,"children":1854,"page":1818},[1855,1856,1862,1869,1872],{"title":6,"path":5,"stem":1805},{"title":66,"path":1807,"stem":1808,"children":1857,"page":1818},[1858,1859,1860,1861],{"title":81,"path":80,"stem":1811},{"title":155,"path":154,"stem":1813},{"title":16,"path":246,"stem":1815},{"title":209,"path":330,"stem":1817},{"title":71,"path":1820,"stem":1821,"children":1863,"page":1818},[1864,1865,1866,1867,1868],{"title":443,"path":442,"stem":1824},{"title":219,"path":583,"stem":1826},{"title":363,"path":712,"stem":1828},{"title":879,"path":878,"stem":1830},{"title":666,"path":974,"stem":1832},{"title":1834,"path":1835,"stem":1836,"children":1870,"page":1818},[1871],{"title":1096,"path":1095,"stem":1839},{"title":76,"path":1841,"stem":1842,"children":1873,"page":1818},[1874,1875,1876,1877],{"title":1140,"path":1139,"stem":1845},{"title":1416,"path":1415,"stem":1847},{"title":1443,"path":1545,"stem":1849},{"title":1642,"path":1641,"stem":1851},[1879,3704,4152],{"id":1880,"title":1881,"body":1882,"description":24,"extension":3697,"icon":3698,"meta":3699,"navigation":2360,"path":3700,"seo":3701,"stem":3702,"__hash__":3703},"resources/readme.md","README",{"type":1883,"value":1884,"toc":3680},"minimark",[1885,1890,1958,1967,1972,2485,2488,2491,2508,2512,3113,3116,3216,3220,3267,3271,3277,3280,3387,3399,3402,3405,3546,3549,3556,3560,3586,3589,3618,3621,3629,3632,3655,3659,3667,3670,3676],[1886,1887,1889],"h1",{"id":1888},"flume","Flume",[1891,1892,1893,1904,1912,1920,1928,1936,1943,1950],"p",{},[1894,1895,1899],"a",{"href":1896,"rel":1897},"https://github.com/zoobz-io/flume/actions/workflows/ci.yml",[1898],"nofollow",[1900,1901],"img",{"alt":1902,"src":1903},"CI Status","https://github.com/zoobz-io/flume/workflows/CI/badge.svg",[1894,1905,1908],{"href":1906,"rel":1907},"https://codecov.io/gh/zoobz-io/flume",[1898],[1900,1909],{"alt":1910,"src":1911},"codecov","https://codecov.io/gh/zoobz-io/flume/graph/badge.svg?branch=main",[1894,1913,1916],{"href":1914,"rel":1915},"https://goreportcard.com/report/github.com/zoobz-io/flume",[1898],[1900,1917],{"alt":1918,"src":1919},"Go Report Card","https://goreportcard.com/badge/github.com/zoobz-io/flume",[1894,1921,1924],{"href":1922,"rel":1923},"https://github.com/zoobz-io/flume/security/code-scanning",[1898],[1900,1925],{"alt":1926,"src":1927},"CodeQL","https://github.com/zoobz-io/flume/workflows/CodeQL/badge.svg",[1894,1929,1932],{"href":1930,"rel":1931},"https://pkg.go.dev/github.com/zoobz-io/flume",[1898],[1900,1933],{"alt":1934,"src":1935},"Go Reference","https://pkg.go.dev/badge/github.com/zoobz-io/flume.svg",[1894,1937,1939],{"href":1938},"LICENSE",[1900,1940],{"alt":1941,"src":1942},"License","https://img.shields.io/github/license/zoobz-io/flume",[1894,1944,1946],{"href":1945},"go.mod",[1900,1947],{"alt":1948,"src":1949},"Go Version","https://img.shields.io/github/go-mod/go-version/zoobz-io/flume",[1894,1951,1954],{"href":1952,"rel":1953},"https://github.com/zoobz-io/flume/releases",[1898],[1900,1955],{"alt":1956,"src":1957},"Release","https://img.shields.io/github/v/release/zoobz-io/flume",[1891,1959,1960,1961,1966],{},"A dynamic pipeline factory for ",[1894,1962,1965],{"href":1963,"rel":1964},"https://github.com/zoobz-io/pipz",[1898],"pipz"," that enables schema-driven pipeline construction with hot-reloading capabilities.",[1968,1969,1971],"h2",{"id":1970},"logic-in-code-structure-in-schema","Logic in Code, Structure in Schema",[1973,1974,1978],"pre",{"className":1975,"code":1976,"language":1977,"meta":24,"style":24},"language-go shiki shiki-themes","// 1. Register components\nfactory := flume.New[Order]()\nfactory.Add(\n    pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n        if o.Total \u003C= 0 {\n            return o, fmt.Errorf(\"invalid total\")\n        }\n        return o, nil\n    }),\n    pipz.Apply(\"apply-discount\", func(ctx context.Context, o Order) (Order, error) {\n        o.Total *= 0.9 // 10% discount\n        return o, nil\n    }),\n)\nfactory.AddPredicate(flume.Predicate[Order]{\n    Name:      \"is-premium\",\n    Predicate: func(ctx context.Context, o Order) bool { return o.Tier == \"premium\" },\n})\n\n// 2. Build from schema\npipeline, _ := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: is-premium\n    then:\n      ref: apply-discount\n`)\n\n// 3. Process data\nresult, err := pipeline.Process(ctx, order)\n","go",[1979,1980,1981,1989,2018,2029,2094,2117,2143,2149,2162,2168,2216,2235,2246,2251,2256,2280,2296,2349,2355,2362,2368,2393,2399,2405,2411,2417,2423,2429,2435,2443,2448,2454],"code",{"__ignoreMap":24},[1982,1983,1985],"span",{"class":1984,"line":9},"line",[1982,1986,1988],{"class":1987},"sLkEo","// 1. Register components\n",[1982,1990,1991,1995,1998,2001,2005,2008,2011,2015],{"class":1984,"line":19},[1982,1992,1994],{"class":1993},"sh8_p","factory",[1982,1996,1997],{"class":1993}," :=",[1982,1999,2000],{"class":1993}," flume",[1982,2002,2004],{"class":2003},"sq5bi",".",[1982,2006,1153],{"class":2007},"s5klm",[1982,2009,2010],{"class":2003},"[",[1982,2012,2014],{"class":2013},"sYBwO","Order",[1982,2016,2017],{"class":2003},"]()\n",[1982,2019,2020,2022,2024,2026],{"class":1984,"line":30},[1982,2021,1994],{"class":1993},[1982,2023,2004],{"class":2003},[1982,2025,1162],{"class":2007},[1982,2027,2028],{"class":2003},"(\n",[1982,2030,2032,2035,2037,2040,2043,2047,2050,2054,2056,2060,2063,2065,2068,2070,2073,2076,2079,2082,2084,2086,2089,2091],{"class":1984,"line":2031},4,[1982,2033,2034],{"class":1993},"    pipz",[1982,2036,2004],{"class":2003},[1982,2038,2039],{"class":2007},"Apply",[1982,2041,2042],{"class":2003},"(",[1982,2044,2046],{"class":2045},"sxAnc","\"validate\"",[1982,2048,2049],{"class":2003},",",[1982,2051,2053],{"class":2052},"sUt3r"," func",[1982,2055,2042],{"class":2003},[1982,2057,2059],{"class":2058},"sSYET","ctx",[1982,2061,2062],{"class":2013}," context",[1982,2064,2004],{"class":2003},[1982,2066,2067],{"class":2013},"Context",[1982,2069,2049],{"class":2003},[1982,2071,2072],{"class":2058}," o",[1982,2074,2075],{"class":2013}," Order",[1982,2077,2078],{"class":2003},")",[1982,2080,2081],{"class":2003}," (",[1982,2083,2014],{"class":2013},[1982,2085,2049],{"class":2003},[1982,2087,2088],{"class":2013}," error",[1982,2090,2078],{"class":2003},[1982,2092,2093],{"class":2003}," {\n",[1982,2095,2097,2101,2103,2105,2108,2111,2115],{"class":1984,"line":2096},5,[1982,2098,2100],{"class":2099},"sW3Qg","        if",[1982,2102,2072],{"class":1993},[1982,2104,2004],{"class":2003},[1982,2106,2107],{"class":1993},"Total",[1982,2109,2110],{"class":2099}," \u003C=",[1982,2112,2114],{"class":2113},"sMAmT"," 0",[1982,2116,2093],{"class":2003},[1982,2118,2120,2123,2125,2127,2130,2132,2135,2137,2140],{"class":1984,"line":2119},6,[1982,2121,2122],{"class":2099},"            return",[1982,2124,2072],{"class":1993},[1982,2126,2049],{"class":2003},[1982,2128,2129],{"class":1993}," fmt",[1982,2131,2004],{"class":2003},[1982,2133,2134],{"class":2007},"Errorf",[1982,2136,2042],{"class":2003},[1982,2138,2139],{"class":2045},"\"invalid total\"",[1982,2141,2142],{"class":2003},")\n",[1982,2144,2146],{"class":1984,"line":2145},7,[1982,2147,2148],{"class":2003},"        }\n",[1982,2150,2152,2155,2157,2159],{"class":1984,"line":2151},8,[1982,2153,2154],{"class":2099},"        return",[1982,2156,2072],{"class":1993},[1982,2158,2049],{"class":2003},[1982,2160,2161],{"class":2052}," nil\n",[1982,2163,2165],{"class":1984,"line":2164},9,[1982,2166,2167],{"class":2003},"    }),\n",[1982,2169,2171,2173,2175,2177,2179,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210,2212,2214],{"class":1984,"line":2170},10,[1982,2172,2034],{"class":1993},[1982,2174,2004],{"class":2003},[1982,2176,2039],{"class":2007},[1982,2178,2042],{"class":2003},[1982,2180,2181],{"class":2045},"\"apply-discount\"",[1982,2183,2049],{"class":2003},[1982,2185,2053],{"class":2052},[1982,2187,2042],{"class":2003},[1982,2189,2059],{"class":2058},[1982,2191,2062],{"class":2013},[1982,2193,2004],{"class":2003},[1982,2195,2067],{"class":2013},[1982,2197,2049],{"class":2003},[1982,2199,2072],{"class":2058},[1982,2201,2075],{"class":2013},[1982,2203,2078],{"class":2003},[1982,2205,2081],{"class":2003},[1982,2207,2014],{"class":2013},[1982,2209,2049],{"class":2003},[1982,2211,2088],{"class":2013},[1982,2213,2078],{"class":2003},[1982,2215,2093],{"class":2003},[1982,2217,2219,2222,2224,2226,2229,2232],{"class":1984,"line":2218},11,[1982,2220,2221],{"class":1993},"        o",[1982,2223,2004],{"class":2003},[1982,2225,2107],{"class":1993},[1982,2227,2228],{"class":1993}," *=",[1982,2230,2231],{"class":2113}," 0.9",[1982,2233,2234],{"class":1987}," // 10% discount\n",[1982,2236,2238,2240,2242,2244],{"class":1984,"line":2237},12,[1982,2239,2154],{"class":2099},[1982,2241,2072],{"class":1993},[1982,2243,2049],{"class":2003},[1982,2245,2161],{"class":2052},[1982,2247,2249],{"class":1984,"line":2248},13,[1982,2250,2167],{"class":2003},[1982,2252,2254],{"class":1984,"line":2253},14,[1982,2255,2142],{"class":2003},[1982,2257,2259,2261,2263,2265,2267,2269,2271,2273,2275,2277],{"class":1984,"line":2258},15,[1982,2260,1994],{"class":1993},[1982,2262,2004],{"class":2003},[1982,2264,1191],{"class":2007},[1982,2266,2042],{"class":2003},[1982,2268,1888],{"class":2013},[1982,2270,2004],{"class":2003},[1982,2272,1368],{"class":2013},[1982,2274,2010],{"class":2003},[1982,2276,2014],{"class":2013},[1982,2278,2279],{"class":2003},"]{\n",[1982,2281,2283,2287,2290,2293],{"class":1984,"line":2282},16,[1982,2284,2286],{"class":2285},"sBGCq","    Name",[1982,2288,2289],{"class":2003},":",[1982,2291,2292],{"class":2045},"      \"is-premium\"",[1982,2294,2295],{"class":2003},",\n",[1982,2297,2299,2302,2304,2306,2308,2310,2312,2314,2316,2318,2320,2322,2324,2327,2330,2333,2335,2337,2340,2343,2346],{"class":1984,"line":2298},17,[1982,2300,2301],{"class":2285},"    Predicate",[1982,2303,2289],{"class":2003},[1982,2305,2053],{"class":2052},[1982,2307,2042],{"class":2003},[1982,2309,2059],{"class":2058},[1982,2311,2062],{"class":2013},[1982,2313,2004],{"class":2003},[1982,2315,2067],{"class":2013},[1982,2317,2049],{"class":2003},[1982,2319,2072],{"class":2058},[1982,2321,2075],{"class":2013},[1982,2323,2078],{"class":2003},[1982,2325,2326],{"class":2013}," bool",[1982,2328,2329],{"class":2003}," {",[1982,2331,2332],{"class":2099}," return",[1982,2334,2072],{"class":1993},[1982,2336,2004],{"class":2003},[1982,2338,2339],{"class":1993},"Tier",[1982,2341,2342],{"class":2099}," ==",[1982,2344,2345],{"class":2045}," \"premium\"",[1982,2347,2348],{"class":2003}," },\n",[1982,2350,2352],{"class":1984,"line":2351},18,[1982,2353,2354],{"class":2003},"})\n",[1982,2356,2358],{"class":1984,"line":2357},19,[1982,2359,2361],{"emptyLinePlaceholder":2360},true,"\n",[1982,2363,2365],{"class":1984,"line":2364},20,[1982,2366,2367],{"class":1987},"// 2. Build from schema\n",[1982,2369,2371,2374,2376,2379,2381,2384,2386,2388,2390],{"class":1984,"line":2370},21,[1982,2372,2373],{"class":1993},"pipeline",[1982,2375,2049],{"class":2003},[1982,2377,2378],{"class":1993}," _",[1982,2380,1997],{"class":1993},[1982,2382,2383],{"class":1993}," factory",[1982,2385,2004],{"class":2003},[1982,2387,1272],{"class":2007},[1982,2389,2042],{"class":2003},[1982,2391,2392],{"class":2045},"`\n",[1982,2394,2396],{"class":1984,"line":2395},22,[1982,2397,2398],{"class":2045},"type: sequence\n",[1982,2400,2402],{"class":1984,"line":2401},23,[1982,2403,2404],{"class":2045},"children:\n",[1982,2406,2408],{"class":1984,"line":2407},24,[1982,2409,2410],{"class":2045},"  - ref: validate\n",[1982,2412,2414],{"class":1984,"line":2413},25,[1982,2415,2416],{"class":2045},"  - type: filter\n",[1982,2418,2420],{"class":1984,"line":2419},26,[1982,2421,2422],{"class":2045},"    predicate: is-premium\n",[1982,2424,2426],{"class":1984,"line":2425},27,[1982,2427,2428],{"class":2045},"    then:\n",[1982,2430,2432],{"class":1984,"line":2431},28,[1982,2433,2434],{"class":2045},"      ref: apply-discount\n",[1982,2436,2438,2441],{"class":1984,"line":2437},29,[1982,2439,2440],{"class":2045},"`",[1982,2442,2142],{"class":2003},[1982,2444,2446],{"class":1984,"line":2445},30,[1982,2447,2361],{"emptyLinePlaceholder":2360},[1982,2449,2451],{"class":1984,"line":2450},31,[1982,2452,2453],{"class":1987},"// 3. Process data\n",[1982,2455,2457,2460,2462,2465,2467,2470,2472,2474,2476,2478,2480,2483],{"class":1984,"line":2456},32,[1982,2458,2459],{"class":1993},"result",[1982,2461,2049],{"class":2003},[1982,2463,2464],{"class":1993}," err",[1982,2466,1997],{"class":1993},[1982,2468,2469],{"class":1993}," pipeline",[1982,2471,2004],{"class":2003},[1982,2473,1326],{"class":2007},[1982,2475,2042],{"class":2003},[1982,2477,2059],{"class":1993},[1982,2479,2049],{"class":2003},[1982,2481,2482],{"class":1993}," order",[1982,2484,2142],{"class":2003},[1968,2486,90],{"id":2487},"installation",[1891,2489,2490],{},"Requires Go 1.24+",[1973,2492,2496],{"className":2493,"code":2494,"language":2495,"meta":24,"style":24},"language-bash shiki shiki-themes","go get github.com/zoobz-io/flume\n","bash",[1979,2497,2498],{"__ignoreMap":24},[1982,2499,2500,2502,2505],{"class":1984,"line":9},[1982,2501,1977],{"class":2007},[1982,2503,2504],{"class":2045}," get",[1982,2506,2507],{"class":2045}," github.com/zoobz-io/flume\n",[1968,2509,2511],{"id":2510},"quick-start","Quick Start",[1973,2513,2515],{"className":1975,"code":2514,"language":1977,"meta":24,"style":24},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"github.com/zoobz-io/flume\"\n    \"github.com/zoobz-io/pipz\"\n)\n\ntype Order struct {\n    ID    string\n    Total float64\n}\n\nfunc (o Order) Clone() Order { return Order{ID: o.ID, Total: o.Total} }\n\nfunc main() {\n    factory := flume.New[Order]()\n\n    // Register processors\n    factory.Add(\n        pipz.Apply(\"validate\", func(ctx context.Context, o Order) (Order, error) {\n            if o.Total \u003C= 0 {\n                return o, fmt.Errorf(\"invalid total\")\n            }\n            return o, nil\n        }),\n        pipz.Transform(\"enrich\", func(ctx context.Context, o Order) Order {\n            o.ID = \"ORD-\" + o.ID\n            return o\n        }),\n    )\n\n    // Build pipeline from YAML\n    pipeline, err := factory.BuildFromYAML(`\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: enrich\n`)\n    if err != nil {\n        panic(err)\n    }\n\n    // Process\n    result, err := pipeline.Process(context.Background(), Order{ID: \"123\", Total: 99.99})\n    fmt.Printf(\"Result: %+v, Error: %v\\n\", result, err)\n}\n",[1979,2516,2517,2525,2529,2538,2543,2548,2553,2558,2562,2566,2578,2586,2594,2599,2603,2664,2668,2679,2698,2702,2707,2717,2764,2781,2802,2807,2817,2822,2862,2887,2894,2898,2903,2908,2914,2936,2941,2946,2951,2957,2964,2980,2994,3000,3005,3011,3064,3108],{"__ignoreMap":24},[1982,2518,2519,2522],{"class":1984,"line":9},[1982,2520,2521],{"class":2052},"package",[1982,2523,2524],{"class":2013}," main\n",[1982,2526,2527],{"class":1984,"line":19},[1982,2528,2361],{"emptyLinePlaceholder":2360},[1982,2530,2531,2534],{"class":1984,"line":30},[1982,2532,2533],{"class":2052},"import",[1982,2535,2537],{"class":2536},"soy-K"," (\n",[1982,2539,2540],{"class":1984,"line":2031},[1982,2541,2542],{"class":2045},"    \"context\"\n",[1982,2544,2545],{"class":1984,"line":2096},[1982,2546,2547],{"class":2045},"    \"fmt\"\n",[1982,2549,2550],{"class":1984,"line":2119},[1982,2551,2552],{"class":2045},"    \"github.com/zoobz-io/flume\"\n",[1982,2554,2555],{"class":1984,"line":2145},[1982,2556,2557],{"class":2045},"    \"github.com/zoobz-io/pipz\"\n",[1982,2559,2560],{"class":1984,"line":2151},[1982,2561,2142],{"class":2536},[1982,2563,2564],{"class":1984,"line":2164},[1982,2565,2361],{"emptyLinePlaceholder":2360},[1982,2567,2568,2571,2573,2576],{"class":1984,"line":2170},[1982,2569,2570],{"class":2052},"type",[1982,2572,2075],{"class":2013},[1982,2574,2575],{"class":2052}," struct",[1982,2577,2093],{"class":2003},[1982,2579,2580,2583],{"class":1984,"line":2218},[1982,2581,2582],{"class":2285},"    ID",[1982,2584,2585],{"class":2013},"    string\n",[1982,2587,2588,2591],{"class":1984,"line":2237},[1982,2589,2590],{"class":2285},"    Total",[1982,2592,2593],{"class":2013}," float64\n",[1982,2595,2596],{"class":1984,"line":2248},[1982,2597,2598],{"class":2003},"}\n",[1982,2600,2601],{"class":1984,"line":2253},[1982,2602,2361],{"emptyLinePlaceholder":2360},[1982,2604,2605,2608,2610,2613,2615,2617,2620,2623,2625,2627,2629,2631,2634,2637,2639,2641,2643,2645,2647,2650,2652,2654,2656,2658,2661],{"class":1984,"line":2258},[1982,2606,2607],{"class":2052},"func",[1982,2609,2081],{"class":2003},[1982,2611,2612],{"class":2058},"o ",[1982,2614,2014],{"class":2013},[1982,2616,2078],{"class":2003},[1982,2618,2619],{"class":2007}," Clone",[1982,2621,2622],{"class":2003},"()",[1982,2624,2075],{"class":2013},[1982,2626,2329],{"class":2003},[1982,2628,2332],{"class":2099},[1982,2630,2075],{"class":2013},[1982,2632,2633],{"class":2003},"{",[1982,2635,2636],{"class":2285},"ID",[1982,2638,2289],{"class":2003},[1982,2640,2072],{"class":1993},[1982,2642,2004],{"class":2003},[1982,2644,2636],{"class":1993},[1982,2646,2049],{"class":2003},[1982,2648,2649],{"class":2285}," Total",[1982,2651,2289],{"class":2003},[1982,2653,2072],{"class":1993},[1982,2655,2004],{"class":2003},[1982,2657,2107],{"class":1993},[1982,2659,2660],{"class":2003},"}",[1982,2662,2663],{"class":2003}," }\n",[1982,2665,2666],{"class":1984,"line":2282},[1982,2667,2361],{"emptyLinePlaceholder":2360},[1982,2669,2670,2672,2675,2677],{"class":1984,"line":2298},[1982,2671,2607],{"class":2052},[1982,2673,2674],{"class":2007}," main",[1982,2676,2622],{"class":2003},[1982,2678,2093],{"class":2003},[1982,2680,2681,2684,2686,2688,2690,2692,2694,2696],{"class":1984,"line":2351},[1982,2682,2683],{"class":1993},"    factory",[1982,2685,1997],{"class":1993},[1982,2687,2000],{"class":1993},[1982,2689,2004],{"class":2003},[1982,2691,1153],{"class":2007},[1982,2693,2010],{"class":2003},[1982,2695,2014],{"class":2013},[1982,2697,2017],{"class":2003},[1982,2699,2700],{"class":1984,"line":2357},[1982,2701,2361],{"emptyLinePlaceholder":2360},[1982,2703,2704],{"class":1984,"line":2364},[1982,2705,2706],{"class":1987},"    // Register processors\n",[1982,2708,2709,2711,2713,2715],{"class":1984,"line":2370},[1982,2710,2683],{"class":1993},[1982,2712,2004],{"class":2003},[1982,2714,1162],{"class":2007},[1982,2716,2028],{"class":2003},[1982,2718,2719,2722,2724,2726,2728,2730,2732,2734,2736,2738,2740,2742,2744,2746,2748,2750,2752,2754,2756,2758,2760,2762],{"class":1984,"line":2395},[1982,2720,2721],{"class":1993},"        pipz",[1982,2723,2004],{"class":2003},[1982,2725,2039],{"class":2007},[1982,2727,2042],{"class":2003},[1982,2729,2046],{"class":2045},[1982,2731,2049],{"class":2003},[1982,2733,2053],{"class":2052},[1982,2735,2042],{"class":2003},[1982,2737,2059],{"class":2058},[1982,2739,2062],{"class":2013},[1982,2741,2004],{"class":2003},[1982,2743,2067],{"class":2013},[1982,2745,2049],{"class":2003},[1982,2747,2072],{"class":2058},[1982,2749,2075],{"class":2013},[1982,2751,2078],{"class":2003},[1982,2753,2081],{"class":2003},[1982,2755,2014],{"class":2013},[1982,2757,2049],{"class":2003},[1982,2759,2088],{"class":2013},[1982,2761,2078],{"class":2003},[1982,2763,2093],{"class":2003},[1982,2765,2766,2769,2771,2773,2775,2777,2779],{"class":1984,"line":2401},[1982,2767,2768],{"class":2099},"            if",[1982,2770,2072],{"class":1993},[1982,2772,2004],{"class":2003},[1982,2774,2107],{"class":1993},[1982,2776,2110],{"class":2099},[1982,2778,2114],{"class":2113},[1982,2780,2093],{"class":2003},[1982,2782,2783,2786,2788,2790,2792,2794,2796,2798,2800],{"class":1984,"line":2407},[1982,2784,2785],{"class":2099},"                return",[1982,2787,2072],{"class":1993},[1982,2789,2049],{"class":2003},[1982,2791,2129],{"class":1993},[1982,2793,2004],{"class":2003},[1982,2795,2134],{"class":2007},[1982,2797,2042],{"class":2003},[1982,2799,2139],{"class":2045},[1982,2801,2142],{"class":2003},[1982,2803,2804],{"class":1984,"line":2413},[1982,2805,2806],{"class":2003},"            }\n",[1982,2808,2809,2811,2813,2815],{"class":1984,"line":2419},[1982,2810,2122],{"class":2099},[1982,2812,2072],{"class":1993},[1982,2814,2049],{"class":2003},[1982,2816,2161],{"class":2052},[1982,2818,2819],{"class":1984,"line":2425},[1982,2820,2821],{"class":2003},"        }),\n",[1982,2823,2824,2826,2828,2831,2833,2836,2838,2840,2842,2844,2846,2848,2850,2852,2854,2856,2858,2860],{"class":1984,"line":2431},[1982,2825,2721],{"class":1993},[1982,2827,2004],{"class":2003},[1982,2829,2830],{"class":2007},"Transform",[1982,2832,2042],{"class":2003},[1982,2834,2835],{"class":2045},"\"enrich\"",[1982,2837,2049],{"class":2003},[1982,2839,2053],{"class":2052},[1982,2841,2042],{"class":2003},[1982,2843,2059],{"class":2058},[1982,2845,2062],{"class":2013},[1982,2847,2004],{"class":2003},[1982,2849,2067],{"class":2013},[1982,2851,2049],{"class":2003},[1982,2853,2072],{"class":2058},[1982,2855,2075],{"class":2013},[1982,2857,2078],{"class":2003},[1982,2859,2075],{"class":2013},[1982,2861,2093],{"class":2003},[1982,2863,2864,2867,2869,2871,2874,2877,2880,2882,2884],{"class":1984,"line":2437},[1982,2865,2866],{"class":1993},"            o",[1982,2868,2004],{"class":2003},[1982,2870,2636],{"class":1993},[1982,2872,2873],{"class":1993}," =",[1982,2875,2876],{"class":2045}," \"ORD-\"",[1982,2878,2879],{"class":1993}," +",[1982,2881,2072],{"class":1993},[1982,2883,2004],{"class":2003},[1982,2885,2886],{"class":1993},"ID\n",[1982,2888,2889,2891],{"class":1984,"line":2445},[1982,2890,2122],{"class":2099},[1982,2892,2893],{"class":1993}," o\n",[1982,2895,2896],{"class":1984,"line":2450},[1982,2897,2821],{"class":2003},[1982,2899,2900],{"class":1984,"line":2456},[1982,2901,2902],{"class":2003},"    )\n",[1982,2904,2906],{"class":1984,"line":2905},33,[1982,2907,2361],{"emptyLinePlaceholder":2360},[1982,2909,2911],{"class":1984,"line":2910},34,[1982,2912,2913],{"class":1987},"    // Build pipeline from YAML\n",[1982,2915,2917,2920,2922,2924,2926,2928,2930,2932,2934],{"class":1984,"line":2916},35,[1982,2918,2919],{"class":1993},"    pipeline",[1982,2921,2049],{"class":2003},[1982,2923,2464],{"class":1993},[1982,2925,1997],{"class":1993},[1982,2927,2383],{"class":1993},[1982,2929,2004],{"class":2003},[1982,2931,1272],{"class":2007},[1982,2933,2042],{"class":2003},[1982,2935,2392],{"class":2045},[1982,2937,2939],{"class":1984,"line":2938},36,[1982,2940,2398],{"class":2045},[1982,2942,2944],{"class":1984,"line":2943},37,[1982,2945,2404],{"class":2045},[1982,2947,2949],{"class":1984,"line":2948},38,[1982,2950,2410],{"class":2045},[1982,2952,2954],{"class":1984,"line":2953},39,[1982,2955,2956],{"class":2045},"  - ref: enrich\n",[1982,2958,2960,2962],{"class":1984,"line":2959},40,[1982,2961,2440],{"class":2045},[1982,2963,2142],{"class":2003},[1982,2965,2967,2970,2972,2975,2978],{"class":1984,"line":2966},41,[1982,2968,2969],{"class":2099},"    if",[1982,2971,2464],{"class":1993},[1982,2973,2974],{"class":2099}," !=",[1982,2976,2977],{"class":2052}," nil",[1982,2979,2093],{"class":2003},[1982,2981,2983,2987,2989,2992],{"class":1984,"line":2982},42,[1982,2984,2986],{"class":2985},"skxcq","        panic",[1982,2988,2042],{"class":2003},[1982,2990,2991],{"class":1993},"err",[1982,2993,2142],{"class":2003},[1982,2995,2997],{"class":1984,"line":2996},43,[1982,2998,2999],{"class":2003},"    }\n",[1982,3001,3003],{"class":1984,"line":3002},44,[1982,3004,2361],{"emptyLinePlaceholder":2360},[1982,3006,3008],{"class":1984,"line":3007},45,[1982,3009,3010],{"class":1987},"    // Process\n",[1982,3012,3014,3017,3019,3021,3023,3025,3027,3029,3031,3034,3036,3039,3042,3044,3046,3048,3050,3053,3055,3057,3059,3062],{"class":1984,"line":3013},46,[1982,3015,3016],{"class":1993},"    result",[1982,3018,2049],{"class":2003},[1982,3020,2464],{"class":1993},[1982,3022,1997],{"class":1993},[1982,3024,2469],{"class":1993},[1982,3026,2004],{"class":2003},[1982,3028,1326],{"class":2007},[1982,3030,2042],{"class":2003},[1982,3032,3033],{"class":1993},"context",[1982,3035,2004],{"class":2003},[1982,3037,3038],{"class":2007},"Background",[1982,3040,3041],{"class":2003},"(),",[1982,3043,2075],{"class":2013},[1982,3045,2633],{"class":2003},[1982,3047,2636],{"class":2285},[1982,3049,2289],{"class":2003},[1982,3051,3052],{"class":2045}," \"123\"",[1982,3054,2049],{"class":2003},[1982,3056,2649],{"class":2285},[1982,3058,2289],{"class":2003},[1982,3060,3061],{"class":2113}," 99.99",[1982,3063,2354],{"class":2003},[1982,3065,3067,3070,3072,3075,3077,3080,3084,3087,3090,3094,3097,3099,3102,3104,3106],{"class":1984,"line":3066},47,[1982,3068,3069],{"class":1993},"    fmt",[1982,3071,2004],{"class":2003},[1982,3073,3074],{"class":2007},"Printf",[1982,3076,2042],{"class":2003},[1982,3078,3079],{"class":2045},"\"Result: ",[1982,3081,3083],{"class":3082},"scyPU","%+v",[1982,3085,3086],{"class":2045},", Error: ",[1982,3088,3089],{"class":3082},"%v",[1982,3091,3093],{"class":3092},"suWN2","\\n",[1982,3095,3096],{"class":2045},"\"",[1982,3098,2049],{"class":2003},[1982,3100,3101],{"class":1993}," result",[1982,3103,2049],{"class":2003},[1982,3105,2464],{"class":1993},[1982,3107,2142],{"class":2003},[1982,3109,3111],{"class":1984,"line":3110},48,[1982,3112,2598],{"class":2003},[1968,3114,38],{"id":3115},"capabilities",[3117,3118,3119,3135],"table",{},[3120,3121,3122],"thead",{},[3123,3124,3125,3129,3132],"tr",{},[3126,3127,3128],"th",{},"Feature",[3126,3130,3131],{},"Description",[3126,3133,3134],{},"Docs",[3136,3137,3138,3152,3164,3177,3190,3203],"tbody",{},[3123,3139,3140,3144,3147],{},[3141,3142,3143],"td",{},"Schema-Driven Construction",[3141,3145,3146],{},"Define pipelines in YAML/JSON, build at runtime",[3141,3148,3149],{},[1894,3150,1416],{"href":3151},"docs/reference/schema-format",[3123,3153,3154,3156,3159],{},[3141,3155,219],{},[3141,3157,3158],{},"Update pipeline behavior without restarts",[3141,3160,3161],{},[1894,3162,219],{"href":3163},"docs/guides/hot-reloading",[3123,3165,3166,3169,3172],{},[3141,3167,3168],{},"Lock-Free Bindings",[3141,3170,3171],{},"Concurrent-safe pipeline access with auto-sync",[3141,3173,3174],{},[1894,3175,1140],{"href":3176},"docs/reference/api",[3123,3178,3179,3182,3185],{},[3141,3180,3181],{},"Comprehensive Validation",[3141,3183,3184],{},"Schema validation with detailed error messages",[3141,3186,3187],{},[1894,3188,443],{"href":3189},"docs/guides/schema-design",[3123,3191,3192,3195,3198],{},[3141,3193,3194],{},"14 Connector Types",[3141,3196,3197],{},"Sequence, filter, retry, timeout, circuit breaker, and more",[3141,3199,3200],{},[1894,3201,1443],{"href":3202},"docs/reference/connector-types",[3123,3204,3205,3208,3211],{},[3141,3206,3207],{},"Event Emission",[3141,3209,3210],{},"Built-in observability signals",[3141,3212,3213],{},[1894,3214,666],{"href":3215},"docs/guides/observability",[1968,3217,3219],{"id":3218},"why-flume","Why Flume?",[3221,3222,3223,3231,3237,3243,3249,3261],"ul",{},[3224,3225,3226,3230],"li",{},[3227,3228,3229],"strong",{},"Schema-driven",": Define pipelines in YAML/JSON, not code",[3224,3232,3233,3236],{},[3227,3234,3235],{},"Hot-reloadable",": Update pipeline behavior without restarts",[3224,3238,3239,3242],{},[3227,3240,3241],{},"Type-safe",": Full generics support with compile-time safety",[3224,3244,3245,3248],{},[3227,3246,3247],{},"Composable",": Build complex flows from simple, tested components",[3224,3250,3251,3254,3255,3260],{},[3227,3252,3253],{},"Observable",": Built-in ",[1894,3256,3259],{"href":3257,"rel":3258},"https://github.com/zoobz-io/capitan",[1898],"capitan"," event emission",[3224,3262,3263,3266],{},[3227,3264,3265],{},"Validated",": Comprehensive schema validation with detailed error messages",[1968,3268,3270],{"id":3269},"configuration-as-code","Configuration as Code",[1891,3272,3273,3274,2004],{},"Flume enables a pattern: ",[3227,3275,3276],{},"define once, reconfigure anywhere",[1891,3278,3279],{},"Register your processing components at startup. Define pipeline structure in configuration files. Update behavior at runtime without redeployment.",[1973,3281,3283],{"className":1975,"code":3282,"language":1977,"meta":24,"style":24},"// Components registered once\nfactory.Add(validate, enrich, notify, discount)\n\n// Structure defined in config\nfactory.SetSchema(\"checkout\", loadYAML(\"pipelines/checkout.yaml\"))\n\n// Behavior changes without restart\nfactory.SetSchema(\"checkout\", loadYAML(\"pipelines/checkout-v2.yaml\"))\n",[1979,3284,3285,3290,3320,3324,3329,3355,3359,3364],{"__ignoreMap":24},[1982,3286,3287],{"class":1984,"line":9},[1982,3288,3289],{"class":1987},"// Components registered once\n",[1982,3291,3292,3294,3296,3298,3300,3303,3305,3308,3310,3313,3315,3318],{"class":1984,"line":19},[1982,3293,1994],{"class":1993},[1982,3295,2004],{"class":2003},[1982,3297,1162],{"class":2007},[1982,3299,2042],{"class":2003},[1982,3301,3302],{"class":1993},"validate",[1982,3304,2049],{"class":2003},[1982,3306,3307],{"class":1993}," enrich",[1982,3309,2049],{"class":2003},[1982,3311,3312],{"class":1993}," notify",[1982,3314,2049],{"class":2003},[1982,3316,3317],{"class":1993}," discount",[1982,3319,2142],{"class":2003},[1982,3321,3322],{"class":1984,"line":30},[1982,3323,2361],{"emptyLinePlaceholder":2360},[1982,3325,3326],{"class":1984,"line":2031},[1982,3327,3328],{"class":1987},"// Structure defined in config\n",[1982,3330,3331,3333,3335,3337,3339,3342,3344,3347,3349,3352],{"class":1984,"line":2096},[1982,3332,1994],{"class":1993},[1982,3334,2004],{"class":2003},[1982,3336,1291],{"class":2007},[1982,3338,2042],{"class":2003},[1982,3340,3341],{"class":2045},"\"checkout\"",[1982,3343,2049],{"class":2003},[1982,3345,3346],{"class":2007}," loadYAML",[1982,3348,2042],{"class":2003},[1982,3350,3351],{"class":2045},"\"pipelines/checkout.yaml\"",[1982,3353,3354],{"class":2003},"))\n",[1982,3356,3357],{"class":1984,"line":2119},[1982,3358,2361],{"emptyLinePlaceholder":2360},[1982,3360,3361],{"class":1984,"line":2145},[1982,3362,3363],{"class":1987},"// Behavior changes without restart\n",[1982,3365,3366,3368,3370,3372,3374,3376,3378,3380,3382,3385],{"class":1984,"line":2151},[1982,3367,1994],{"class":1993},[1982,3369,2004],{"class":2003},[1982,3371,1291],{"class":2007},[1982,3373,2042],{"class":2003},[1982,3375,3341],{"class":2045},[1982,3377,2049],{"class":2003},[1982,3379,3346],{"class":2007},[1982,3381,2042],{"class":2003},[1982,3383,3384],{"class":2045},"\"pipelines/checkout-v2.yaml\"",[1982,3386,3354],{"class":2003},[1891,3388,3389,3390,3394,3395,3398],{},"The code defines ",[3391,3392,3393],"em",{},"what"," processors do. Configuration defines ",[3391,3396,3397],{},"how"," they combine.",[1968,3400,219],{"id":3401},"hot-reloading",[1891,3403,3404],{},"Update pipelines at runtime without restarts:",[1973,3406,3408],{"className":1975,"code":3407,"language":1977,"meta":24,"style":24},"// Register a named schema\nfactory.SetSchema(\"order-pipeline\", schema)\n\n// Create a binding with auto-sync enabled\nbinding, _ := factory.Bind(pipelineID, \"order-pipeline\", flume.WithAutoSync())\n\n// Process requests (lock-free)\nresult, _ := binding.Process(ctx, order)\n\n// Update schema - all auto-sync bindings rebuild automatically\nfactory.SetSchema(\"order-pipeline\", newSchema)\n",[1979,3409,3410,3415,3435,3439,3444,3482,3486,3491,3518,3522,3527],{"__ignoreMap":24},[1982,3411,3412],{"class":1984,"line":9},[1982,3413,3414],{"class":1987},"// Register a named schema\n",[1982,3416,3417,3419,3421,3423,3425,3428,3430,3433],{"class":1984,"line":19},[1982,3418,1994],{"class":1993},[1982,3420,2004],{"class":2003},[1982,3422,1291],{"class":2007},[1982,3424,2042],{"class":2003},[1982,3426,3427],{"class":2045},"\"order-pipeline\"",[1982,3429,2049],{"class":2003},[1982,3431,3432],{"class":1993}," schema",[1982,3434,2142],{"class":2003},[1982,3436,3437],{"class":1984,"line":30},[1982,3438,2361],{"emptyLinePlaceholder":2360},[1982,3440,3441],{"class":1984,"line":2031},[1982,3442,3443],{"class":1987},"// Create a binding with auto-sync enabled\n",[1982,3445,3446,3449,3451,3453,3455,3457,3459,3461,3463,3466,3468,3471,3473,3475,3477,3479],{"class":1984,"line":2096},[1982,3447,3448],{"class":1993},"binding",[1982,3450,2049],{"class":2003},[1982,3452,2378],{"class":1993},[1982,3454,1997],{"class":1993},[1982,3456,2383],{"class":1993},[1982,3458,2004],{"class":2003},[1982,3460,1311],{"class":2007},[1982,3462,2042],{"class":2003},[1982,3464,3465],{"class":1993},"pipelineID",[1982,3467,2049],{"class":2003},[1982,3469,3470],{"class":2045}," \"order-pipeline\"",[1982,3472,2049],{"class":2003},[1982,3474,2000],{"class":1993},[1982,3476,2004],{"class":2003},[1982,3478,1331],{"class":2007},[1982,3480,3481],{"class":2003},"())\n",[1982,3483,3484],{"class":1984,"line":2119},[1982,3485,2361],{"emptyLinePlaceholder":2360},[1982,3487,3488],{"class":1984,"line":2145},[1982,3489,3490],{"class":1987},"// Process requests (lock-free)\n",[1982,3492,3493,3495,3497,3499,3501,3504,3506,3508,3510,3512,3514,3516],{"class":1984,"line":2151},[1982,3494,2459],{"class":1993},[1982,3496,2049],{"class":2003},[1982,3498,2378],{"class":1993},[1982,3500,1997],{"class":1993},[1982,3502,3503],{"class":1993}," binding",[1982,3505,2004],{"class":2003},[1982,3507,1326],{"class":2007},[1982,3509,2042],{"class":2003},[1982,3511,2059],{"class":1993},[1982,3513,2049],{"class":2003},[1982,3515,2482],{"class":1993},[1982,3517,2142],{"class":2003},[1982,3519,3520],{"class":1984,"line":2164},[1982,3521,2361],{"emptyLinePlaceholder":2360},[1982,3523,3524],{"class":1984,"line":2170},[1982,3525,3526],{"class":1987},"// Update schema - all auto-sync bindings rebuild automatically\n",[1982,3528,3529,3531,3533,3535,3537,3539,3541,3544],{"class":1984,"line":2218},[1982,3530,1994],{"class":1993},[1982,3532,2004],{"class":2003},[1982,3534,1291],{"class":2007},[1982,3536,2042],{"class":2003},[1982,3538,3427],{"class":2045},[1982,3540,2049],{"class":2003},[1982,3542,3543],{"class":1993}," newSchema",[1982,3545,2142],{"class":2003},[1968,3547,62],{"id":3548},"documentation",[1891,3550,3551,3552,3555],{},"Full documentation is available in the ",[1894,3553,3554],{"href":3554},"docs/"," directory:",[3557,3558,66],"h3",{"id":3559},"learn",[3221,3561,3562,3568,3574,3580],{},[3224,3563,3564,3567],{},[1894,3565,81],{"href":3566},"docs/learn/quickstart"," — Your first pipeline in 5 minutes",[3224,3569,3570,3573],{},[1894,3571,155],{"href":3572},"docs/learn/core-concepts"," — Factories, schemas, and components",[3224,3575,3576,3579],{},[1894,3577,16],{"href":3578},"docs/learn/architecture"," — How Flume works under the hood",[3224,3581,3582,3585],{},[1894,3583,209],{"href":3584},"docs/learn/building-pipelines"," — From simple to complex",[3557,3587,71],{"id":3588},"guides",[3221,3590,3591,3596,3601,3607,3613],{},[3224,3592,3593,3595],{},[1894,3594,443],{"href":3189}," — Best practices for schema structure",[3224,3597,3598,3600],{},[1894,3599,219],{"href":3163}," — Runtime pipeline updates",[3224,3602,3603,3606],{},[1894,3604,363],{"href":3605},"docs/guides/error-handling"," — Retry, fallback, circuit breakers",[3224,3608,3609,3612],{},[1894,3610,879],{"href":3611},"docs/guides/testing"," — Testing strategies and CI/CD linting",[3224,3614,3615,3617],{},[1894,3616,666],{"href":3215}," — Monitoring with capitan events",[3557,3619,1834],{"id":3620},"cookbook",[3221,3622,3623],{},[3224,3624,3625,3628],{},[1894,3626,1096],{"href":3627},"docs/cookbook/common-patterns"," — Recipes and patterns",[3557,3630,76],{"id":3631},"reference",[3221,3633,3634,3639,3644,3649],{},[3224,3635,3636,3638],{},[1894,3637,1140],{"href":3176}," — Complete API documentation",[3224,3640,3641,3643],{},[1894,3642,1416],{"href":3151}," — YAML/JSON specification",[3224,3645,3646,3648],{},[1894,3647,1443],{"href":3202}," — All 14 connectors",[3224,3650,3651,3654],{},[1894,3652,1642],{"href":3653},"docs/reference/events"," — Observability signals",[1968,3656,3658],{"id":3657},"contributing","Contributing",[1891,3660,3661,3662,3666],{},"See ",[1894,3663,3665],{"href":3664},"CONTRIBUTING","CONTRIBUTING.md"," for development guidelines.",[1968,3668,1941],{"id":3669},"license",[1891,3671,3672,3673,3675],{},"MIT License - see ",[1894,3674,1938],{"href":1938}," file.",[3677,3678,3679],"style",{},"html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}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 .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}",{"title":24,"searchDepth":19,"depth":19,"links":3681},[3682,3683,3684,3685,3686,3687,3688,3689,3695,3696],{"id":1970,"depth":19,"text":1971},{"id":2487,"depth":19,"text":90},{"id":2510,"depth":19,"text":2511},{"id":3115,"depth":19,"text":38},{"id":3218,"depth":19,"text":3219},{"id":3269,"depth":19,"text":3270},{"id":3401,"depth":19,"text":219},{"id":3548,"depth":19,"text":62,"children":3690},[3691,3692,3693,3694],{"id":3559,"depth":30,"text":66},{"id":3588,"depth":30,"text":71},{"id":3620,"depth":30,"text":1834},{"id":3631,"depth":30,"text":76},{"id":3657,"depth":19,"text":3658},{"id":3669,"depth":19,"text":1941},"md","book-open",{},"/readme",{"title":1881,"description":24},"readme","LjAqx_lMY-Zlq3kuqe9-dcIyrawIt1pBffmeMtv78rE",{"id":3705,"title":3706,"body":3707,"description":24,"extension":3697,"icon":4146,"meta":4147,"navigation":2360,"path":4148,"seo":4149,"stem":4150,"__hash__":4151},"resources/security.md","Security",{"type":1883,"value":3708,"toc":4132},[3709,3713,3717,3720,3759,3763,3766,3770,3775,3778,3817,3821,3824,3873,3877,3903,3907,3910,3914,3917,4012,4016,4019,4054,4058,4061,4090,4094,4108,4112,4115,4120,4123,4129],[1886,3710,3712],{"id":3711},"security-policy","Security Policy",[1968,3714,3716],{"id":3715},"supported-versions","Supported Versions",[1891,3718,3719],{},"We release patches for security vulnerabilities. Which versions are eligible for receiving such patches depends on the CVSS v3.0 Rating:",[3117,3721,3722,3735],{},[3120,3723,3724],{},[3123,3725,3726,3729,3732],{},[3126,3727,3728],{},"Version",[3126,3730,3731],{},"Supported",[3126,3733,3734],{},"Status",[3136,3736,3737,3748],{},[3123,3738,3739,3742,3745],{},[3141,3740,3741],{},"latest",[3141,3743,3744],{},"✅",[3141,3746,3747],{},"Active development",[3123,3749,3750,3753,3756],{},[3141,3751,3752],{},"\u003C latest",[3141,3754,3755],{},"❌",[3141,3757,3758],{},"Security fixes only for critical issues",[1968,3760,3762],{"id":3761},"reporting-a-vulnerability","Reporting a Vulnerability",[1891,3764,3765],{},"We take the security of flume seriously. If you have discovered a security vulnerability in this project, please report it responsibly.",[3557,3767,3769],{"id":3768},"how-to-report","How to Report",[1891,3771,3772],{},[3227,3773,3774],{},"Please DO NOT report security vulnerabilities through public GitHub issues.",[1891,3776,3777],{},"Instead, please report them via one of the following methods:",[3779,3780,3781,3804],"ol",{},[3224,3782,3783,3786,3787],{},[3227,3784,3785],{},"GitHub Security Advisories"," (Preferred)",[3221,3788,3789,3798,3801],{},[3224,3790,3791,3792,3797],{},"Go to the ",[1894,3793,3796],{"href":3794,"rel":3795},"https://github.com/zoobz-io/flume/security",[1898],"Security tab"," of this repository",[3224,3799,3800],{},"Click \"Report a vulnerability\"",[3224,3802,3803],{},"Fill out the form with details about the vulnerability",[3224,3805,3806,3809],{},[3227,3807,3808],{},"Email",[3221,3810,3811,3814],{},[3224,3812,3813],{},"Send details to the repository maintainer through GitHub profile contact information",[3224,3815,3816],{},"Use PGP encryption if possible for sensitive details",[3557,3818,3820],{"id":3819},"what-to-include","What to Include",[1891,3822,3823],{},"Please include the following information (as much as you can provide) to help us better understand the nature and scope of the possible issue:",[3221,3825,3826,3832,3838,3844,3850,3855,3861,3867],{},[3224,3827,3828,3831],{},[3227,3829,3830],{},"Type of issue"," (e.g., race condition, schema injection, validation bypass, etc.)",[3224,3833,3834,3837],{},[3227,3835,3836],{},"Full paths of source file(s)"," related to the manifestation of the issue",[3224,3839,3840,3843],{},[3227,3841,3842],{},"The location of the affected source code"," (tag/branch/commit or direct URL)",[3224,3845,3846,3849],{},[3227,3847,3848],{},"Any special configuration required"," to reproduce the issue",[3224,3851,3852,3849],{},[3227,3853,3854],{},"Step-by-step instructions",[3224,3856,3857,3860],{},[3227,3858,3859],{},"Proof-of-concept or exploit code"," (if possible)",[3224,3862,3863,3866],{},[3227,3864,3865],{},"Impact of the issue",", including how an attacker might exploit the issue",[3224,3868,3869,3872],{},[3227,3870,3871],{},"Your name and affiliation"," (optional)",[3557,3874,3876],{"id":3875},"what-to-expect","What to Expect",[3221,3878,3879,3885,3891,3897],{},[3224,3880,3881,3884],{},[3227,3882,3883],{},"Acknowledgment",": We will acknowledge receipt of your vulnerability report within 48 hours",[3224,3886,3887,3890],{},[3227,3888,3889],{},"Initial Assessment",": Within 7 days, we will provide an initial assessment of the report",[3224,3892,3893,3896],{},[3227,3894,3895],{},"Resolution Timeline",": We aim to resolve critical issues within 30 days",[3224,3898,3899,3902],{},[3227,3900,3901],{},"Disclosure",": We will coordinate with you on the disclosure timeline",[3557,3904,3906],{"id":3905},"preferred-languages","Preferred Languages",[1891,3908,3909],{},"We prefer all communications to be in English.",[1968,3911,3913],{"id":3912},"security-best-practices","Security Best Practices",[1891,3915,3916],{},"When using flume in your applications, we recommend:",[3779,3918,3919,3940,3960,3976,3992],{},[3224,3920,3921,3924],{},[3227,3922,3923],{},"Keep Dependencies Updated",[1973,3925,3927],{"className":2493,"code":3926,"language":2495,"meta":24,"style":24},"go get -u github.com/zoobz-io/flume\n",[1979,3928,3929],{"__ignoreMap":24},[1982,3930,3931,3933,3935,3938],{"class":1984,"line":9},[1982,3932,1977],{"class":2007},[1982,3934,2504],{"class":2045},[1982,3936,3937],{"class":2052}," -u",[1982,3939,2507],{"class":2045},[3224,3941,3942,3944],{},[3227,3943,1660],{},[3221,3945,3946,3951,3957],{},[3224,3947,3948,3949],{},"Always validate schemas before deployment using ",[1979,3950,1349],{},[3224,3952,3953,3954,3956],{},"Use ",[1979,3955,1344],{}," at runtime with a configured factory",[3224,3958,3959],{},"Don't load schemas from untrusted sources without validation",[3224,3961,3962,3965],{},[3227,3963,3964],{},"Hot Reload Security",[3221,3966,3967,3970,3973],{},[3224,3968,3969],{},"Secure the source of schema updates (e.g., authenticated API endpoints)",[3224,3971,3972],{},"Log all schema changes for audit purposes",[3224,3974,3975],{},"Consider schema versioning for rollback capability",[3224,3977,3978,3981],{},[3227,3979,3980],{},"Resource Management",[3221,3982,3983,3986,3989],{},[3224,3984,3985],{},"Close channels when no longer needed",[3224,3987,3988],{},"Set appropriate timeouts for pipeline operations",[3224,3990,3991],{},"Configure circuit breakers for external dependencies",[3224,3993,3994,3997],{},[3227,3995,3996],{},"Concurrency Safety",[3221,3998,3999,4006,4009],{},[3224,4000,4001,4002,4005],{},"Ensure your data type's ",[1979,4003,4004],{},"Clone()"," method creates deep copies",[3224,4007,4008],{},"Don't share mutable state across processors without synchronization",[3224,4010,4011],{},"Be aware that concurrent/race nodes run in parallel",[1968,4013,4015],{"id":4014},"security-features","Security Features",[1891,4017,4018],{},"flume includes several built-in security features:",[3221,4020,4021,4026,4031,4037,4042,4048],{},[3224,4022,4023,4025],{},[3227,4024,47],{},": Go generics ensure compile-time type checking",[3224,4027,4028,4030],{},[3227,4029,1660],{},": Comprehensive validation catches errors before building",[3224,4032,4033,4036],{},[3227,4034,4035],{},"Reference Validation",": All processor/predicate/condition references verified",[3224,4038,4039,4041],{},[3227,4040,264],{},": Atomic operations for hot-reload scenarios",[3224,4043,4044,4047],{},[3227,4045,4046],{},"Timeout Enforcement",": Built-in timeout connector prevents runaway operations",[3224,4049,4050,4053],{},[3227,4051,4052],{},"Circuit Breakers",": Built-in circuit breaker pattern for fault isolation",[1968,4055,4057],{"id":4056},"automated-security-scanning","Automated Security Scanning",[1891,4059,4060],{},"This project uses:",[3221,4062,4063,4068,4074,4080],{},[3224,4064,4065,4067],{},[3227,4066,1926],{},": GitHub's semantic code analysis for security vulnerabilities",[3224,4069,4070,4073],{},[3227,4071,4072],{},"golangci-lint",": Static analysis including security linters (gosec)",[3224,4075,4076,4079],{},[3227,4077,4078],{},"Codecov",": Coverage tracking to ensure security-critical code is tested",[3224,4081,4082,4085,4086,4089],{},[3227,4083,4084],{},"Race Detection",": Tests run with ",[1979,4087,4088],{},"-race"," flag to detect data races",[1968,4091,4093],{"id":4092},"vulnerability-disclosure-policy","Vulnerability Disclosure Policy",[3221,4095,4096,4099,4102,4105],{},[3224,4097,4098],{},"Security vulnerabilities will be disclosed via GitHub Security Advisories",[3224,4100,4101],{},"We follow a 90-day disclosure timeline for non-critical issues",[3224,4103,4104],{},"Critical vulnerabilities may be disclosed sooner after patches are available",[3224,4106,4107],{},"We will credit reporters who follow responsible disclosure practices",[1968,4109,4111],{"id":4110},"credits","Credits",[1891,4113,4114],{},"We thank the following individuals for responsibly disclosing security issues:",[1891,4116,4117],{},[3391,4118,4119],{},"This list is currently empty. Be the first to help improve our security!",[4121,4122],"hr",{},[1891,4124,4125,4128],{},[3227,4126,4127],{},"Last Updated",": 2025-12-12",[3677,4130,4131],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}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);}",{"title":24,"searchDepth":19,"depth":19,"links":4133},[4134,4135,4141,4142,4143,4144,4145],{"id":3715,"depth":19,"text":3716},{"id":3761,"depth":19,"text":3762,"children":4136},[4137,4138,4139,4140],{"id":3768,"depth":30,"text":3769},{"id":3819,"depth":30,"text":3820},{"id":3875,"depth":30,"text":3876},{"id":3905,"depth":30,"text":3906},{"id":3912,"depth":19,"text":3913},{"id":4014,"depth":19,"text":4015},{"id":4056,"depth":19,"text":4057},{"id":4092,"depth":19,"text":4093},{"id":4110,"depth":19,"text":4111},"shield",{},"/security",{"title":3706,"description":24},"security","8Hgch7Pp-e-NyfBxgZdJF8RyzhItCJT0gGPopLjI8Wk",{"id":4153,"title":3658,"body":4154,"description":4162,"extension":3697,"icon":1979,"meta":4727,"navigation":2360,"path":4728,"seo":4729,"stem":3657,"__hash__":4730},"resources/contributing.md",{"type":1883,"value":4155,"toc":4702},[4156,4160,4163,4167,4170,4174,4212,4216,4220,4238,4241,4257,4259,4270,4274,4278,4292,4296,4307,4311,4316,4319,4336,4340,4343,4360,4364,4367,4381,4385,4413,4416,4419,4434,4437,4453,4456,4472,4475,4488,4492,4500,4504,4507,4551,4555,4559,4562,4573,4576,4590,4594,4597,4625,4629,4657,4663,4667,4670,4681,4685,4696,4699],[1886,4157,4159],{"id":4158},"contributing-to-flume","Contributing to flume",[1891,4161,4162],{},"Thank you for your interest in contributing to flume! This guide will help you get started.",[1968,4164,4166],{"id":4165},"code-of-conduct","Code of Conduct",[1891,4168,4169],{},"By participating in this project, you agree to maintain a respectful and inclusive environment for all contributors.",[1968,4171,4173],{"id":4172},"getting-started","Getting Started",[3779,4175,4176,4179,4185,4191,4194,4200,4203,4209],{},[3224,4177,4178],{},"Fork the repository",[3224,4180,4181,4182],{},"Clone your fork: ",[1979,4183,4184],{},"git clone https://github.com/yourusername/flume.git",[3224,4186,4187,4188],{},"Create a feature branch: ",[1979,4189,4190],{},"git checkout -b feature/your-feature-name",[3224,4192,4193],{},"Make your changes",[3224,4195,4196,4197],{},"Run tests: ",[1979,4198,4199],{},"go test ./...",[3224,4201,4202],{},"Commit your changes with a descriptive message",[3224,4204,4205,4206],{},"Push to your fork: ",[1979,4207,4208],{},"git push origin feature/your-feature-name",[3224,4210,4211],{},"Create a Pull Request",[1968,4213,4215],{"id":4214},"development-guidelines","Development Guidelines",[3557,4217,4219],{"id":4218},"code-style","Code Style",[3221,4221,4222,4225,4232,4235],{},[3224,4223,4224],{},"Follow standard Go conventions",[3224,4226,4227,4228,4231],{},"Run ",[1979,4229,4230],{},"go fmt"," before committing",[3224,4233,4234],{},"Add comments for exported functions and types",[3224,4236,4237],{},"Keep functions small and focused",[3557,4239,879],{"id":4240},"testing",[3221,4242,4243,4246,4251,4254],{},[3224,4244,4245],{},"Write tests for new functionality",[3224,4247,4248,4249],{},"Ensure all tests pass: ",[1979,4250,4199],{},[3224,4252,4253],{},"Include benchmarks for performance-critical code",[3224,4255,4256],{},"Aim for good test coverage",[3557,4258,62],{"id":3548},[3221,4260,4261,4264,4267],{},[3224,4262,4263],{},"Update documentation for API changes",[3224,4265,4266],{},"Add examples for new features",[3224,4268,4269],{},"Keep doc comments clear and concise",[1968,4271,4273],{"id":4272},"types-of-contributions","Types of Contributions",[3557,4275,4277],{"id":4276},"bug-reports","Bug Reports",[3221,4279,4280,4283,4286,4289],{},[3224,4281,4282],{},"Use GitHub Issues",[3224,4284,4285],{},"Include minimal reproduction code",[3224,4287,4288],{},"Describe expected vs actual behavior",[3224,4290,4291],{},"Include Go version and OS",[3557,4293,4295],{"id":4294},"feature-requests","Feature Requests",[3221,4297,4298,4301,4304],{},[3224,4299,4300],{},"Open an issue for discussion first",[3224,4302,4303],{},"Explain the use case",[3224,4305,4306],{},"Consider backwards compatibility",[3557,4308,4310],{"id":4309},"code-contributions","Code Contributions",[4312,4313,4315],"h4",{"id":4314},"adding-processors","Adding Processors",[1891,4317,4318],{},"New processor builders should:",[3221,4320,4321,4327,4330,4333],{},[3224,4322,4323,4324],{},"Follow the existing pattern in ",[1979,4325,4326],{},"builders.go",[3224,4328,4329],{},"Include comprehensive tests",[3224,4331,4332],{},"Add documentation with examples",[3224,4334,4335],{},"Update schema validation if needed",[4312,4337,4339],{"id":4338},"adding-schema-features","Adding Schema Features",[1891,4341,4342],{},"New schema features should:",[3221,4344,4345,4351,4354,4357],{},[3224,4346,4347,4348,4350],{},"Extend the ",[1979,4349,1363],{}," type appropriately",[3224,4352,4353],{},"Include validation rules",[3224,4355,4356],{},"Add builder support",[3224,4358,4359],{},"Document the YAML/JSON format",[4312,4361,4363],{"id":4362},"examples","Examples",[1891,4365,4366],{},"New examples should:",[3221,4368,4369,4372,4375,4378],{},[3224,4370,4371],{},"Solve a real-world problem",[3224,4373,4374],{},"Include tests",[3224,4376,4377],{},"Have clear documentation",[3224,4379,4380],{},"Follow the existing structure",[1968,4382,4384],{"id":4383},"pull-request-process","Pull Request Process",[3779,4386,4387,4393,4398,4403,4408],{},[3224,4388,4389,4392],{},[3227,4390,4391],{},"Keep PRs focused"," - One feature/fix per PR",[3224,4394,4395],{},[3227,4396,4397],{},"Write descriptive commit messages",[3224,4399,4400],{},[3227,4401,4402],{},"Update tests and documentation",[3224,4404,4405],{},[3227,4406,4407],{},"Ensure CI passes",[3224,4409,4410],{},[3227,4411,4412],{},"Respond to review feedback",[1968,4414,879],{"id":4415},"testing-1",[1891,4417,4418],{},"Run the full test suite:",[1973,4420,4422],{"className":2493,"code":4421,"language":2495,"meta":24,"style":24},"go test ./...\n",[1979,4423,4424],{"__ignoreMap":24},[1982,4425,4426,4428,4431],{"class":1984,"line":9},[1982,4427,1977],{"class":2007},[1982,4429,4430],{"class":2045}," test",[1982,4432,4433],{"class":2045}," ./...\n",[1891,4435,4436],{},"Run with race detection:",[1973,4438,4440],{"className":2493,"code":4439,"language":2495,"meta":24,"style":24},"go test -race ./...\n",[1979,4441,4442],{"__ignoreMap":24},[1982,4443,4444,4446,4448,4451],{"class":1984,"line":9},[1982,4445,1977],{"class":2007},[1982,4447,4430],{"class":2045},[1982,4449,4450],{"class":2052}," -race",[1982,4452,4433],{"class":2045},[1891,4454,4455],{},"Run benchmarks:",[1973,4457,4459],{"className":2493,"code":4458,"language":2495,"meta":24,"style":24},"go test -bench=. ./...\n",[1979,4460,4461],{"__ignoreMap":24},[1982,4462,4463,4465,4467,4470],{"class":1984,"line":9},[1982,4464,1977],{"class":2007},[1982,4466,4430],{"class":2045},[1982,4468,4469],{"class":2052}," -bench=.",[1982,4471,4433],{"class":2045},[1891,4473,4474],{},"Run linter:",[1973,4476,4478],{"className":2493,"code":4477,"language":2495,"meta":24,"style":24},"make lint\n",[1979,4479,4480],{"__ignoreMap":24},[1982,4481,4482,4485],{"class":1984,"line":9},[1982,4483,4484],{"class":2007},"make",[1982,4486,4487],{"class":2045}," lint\n",[1968,4489,4491],{"id":4490},"project-structure","Project Structure",[1973,4493,4498],{"className":4494,"code":4496,"language":4497},[4495],"language-text","flume/\n├── factory.go        # Core factory type and registration\n├── builders.go       # Schema node to pipeline builders\n├── schema.go         # Schema types and parsing\n├── validation.go     # Schema validation\n├── loader.go         # File/JSON/YAML loading\n├── observability.go  # Event emission\n├── spec.go           # Factory introspection\n└── *_test.go         # Tests\n","text",[1979,4499,4496],{"__ignoreMap":24},[1968,4501,4503],{"id":4502},"commit-messages","Commit Messages",[1891,4505,4506],{},"Follow conventional commits:",[3221,4508,4509,4515,4521,4527,4533,4539,4545],{},[3224,4510,4511,4514],{},[1979,4512,4513],{},"feat:"," New feature",[3224,4516,4517,4520],{},[1979,4518,4519],{},"fix:"," Bug fix",[3224,4522,4523,4526],{},[1979,4524,4525],{},"docs:"," Documentation changes",[3224,4528,4529,4532],{},[1979,4530,4531],{},"test:"," Test additions/changes",[3224,4534,4535,4538],{},[1979,4536,4537],{},"refactor:"," Code refactoring",[3224,4540,4541,4544],{},[1979,4542,4543],{},"perf:"," Performance improvements",[3224,4546,4547,4550],{},[1979,4548,4549],{},"chore:"," Maintenance tasks",[1968,4552,4554],{"id":4553},"release-process","Release Process",[3557,4556,4558],{"id":4557},"automated-releases","Automated Releases",[1891,4560,4561],{},"This project uses automated release versioning. To create a release:",[3779,4563,4564,4567,4570],{},[3224,4565,4566],{},"Go to Actions -> Release -> Run workflow",[3224,4568,4569],{},"Leave \"Version override\" empty for automatic version inference",[3224,4571,4572],{},"Click \"Run workflow\"",[1891,4574,4575],{},"The system will:",[3221,4577,4578,4581,4584,4587],{},[3224,4579,4580],{},"Automatically determine the next version from conventional commits",[3224,4582,4583],{},"Create a git tag",[3224,4585,4586],{},"Generate release notes via GoReleaser",[3224,4588,4589],{},"Publish the release to GitHub",[3557,4591,4593],{"id":4592},"manual-release-legacy","Manual Release (Legacy)",[1891,4595,4596],{},"You can still create releases manually:",[1973,4598,4600],{"className":2493,"code":4599,"language":2495,"meta":24,"style":24},"git tag v1.2.3\ngit push origin v1.2.3\n",[1979,4601,4602,4613],{"__ignoreMap":24},[1982,4603,4604,4607,4610],{"class":1984,"line":9},[1982,4605,4606],{"class":2007},"git",[1982,4608,4609],{"class":2045}," tag",[1982,4611,4612],{"class":2045}," v1.2.3\n",[1982,4614,4615,4617,4620,4623],{"class":1984,"line":19},[1982,4616,4606],{"class":2007},[1982,4618,4619],{"class":2045}," push",[1982,4621,4622],{"class":2045}," origin",[1982,4624,4612],{"class":2045},[3557,4626,4628],{"id":4627},"commit-conventions-for-versioning","Commit Conventions for Versioning",[3221,4630,4631,4636,4641,4647],{},[3224,4632,4633,4635],{},[1979,4634,4513],{}," new features (minor version: 1.2.0 -> 1.3.0)",[3224,4637,4638,4640],{},[1979,4639,4519],{}," bug fixes (patch version: 1.2.0 -> 1.2.1)",[3224,4642,4643,4646],{},[1979,4644,4645],{},"feat!:"," breaking changes (major version: 1.2.0 -> 2.0.0)",[3224,4648,4649,4651,4652,4651,4654,4656],{},[1979,4650,4525],{},", ",[1979,4653,4531],{},[1979,4655,4549],{}," no version change",[1891,4658,4659,4660],{},"Example: ",[1979,4661,4662],{},"feat(schema): add support for custom connector types",[3557,4664,4666],{"id":4665},"version-preview-on-pull-requests","Version Preview on Pull Requests",[1891,4668,4669],{},"Every PR automatically shows the next version that will be created:",[3221,4671,4672,4675,4678],{},[3224,4673,4674],{},"Check PR comments for \"Version Preview\"",[3224,4676,4677],{},"Updates automatically as you add commits",[3224,4679,4680],{},"Helps verify your commits have the intended effect",[1968,4682,4684],{"id":4683},"questions","Questions?",[3221,4686,4687,4690,4693],{},[3224,4688,4689],{},"Open an issue for questions",[3224,4691,4692],{},"Check existing issues first",[3224,4694,4695],{},"Be patient and respectful",[1891,4697,4698],{},"Thank you for contributing to flume!",[3677,4700,4701],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}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 .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}",{"title":24,"searchDepth":19,"depth":19,"links":4703},[4704,4705,4706,4711,4716,4717,4718,4719,4720,4726],{"id":4165,"depth":19,"text":4166},{"id":4172,"depth":19,"text":4173},{"id":4214,"depth":19,"text":4215,"children":4707},[4708,4709,4710],{"id":4218,"depth":30,"text":4219},{"id":4240,"depth":30,"text":879},{"id":3548,"depth":30,"text":62},{"id":4272,"depth":19,"text":4273,"children":4712},[4713,4714,4715],{"id":4276,"depth":30,"text":4277},{"id":4294,"depth":30,"text":4295},{"id":4309,"depth":30,"text":4310},{"id":4383,"depth":19,"text":4384},{"id":4415,"depth":19,"text":879},{"id":4490,"depth":19,"text":4491},{"id":4502,"depth":19,"text":4503},{"id":4553,"depth":19,"text":4554,"children":4721},[4722,4723,4724,4725],{"id":4557,"depth":30,"text":4558},{"id":4592,"depth":30,"text":4593},{"id":4627,"depth":30,"text":4628},{"id":4665,"depth":30,"text":4666},{"id":4683,"depth":19,"text":4684},{},"/contributing",{"title":3658,"description":4162},"XNSK9mlai_COIso6Z9bL54kGavHd1YbB2SBaSuGIqdk",{"id":4732,"title":879,"author":4733,"body":4734,"description":881,"extension":3697,"meta":9705,"navigation":2360,"path":878,"published":9706,"readtime":9707,"seo":9708,"stem":1830,"tags":9709,"updated":9712,"__hash__":9713},"flume/v1.0.1/3.guides/4.testing.md","zoobzio",{"type":1883,"value":4735,"toc":9683},[4736,4738,4740,4743,4769,4772,4775,5219,5222,5520,5523,5526,6202,6205,6210,6213,6560,6563,6689,6692,6794,6802,6805,6808,7349,7352,7355,7718,7721,8091,8094,8447,8450,9001,9004,9404,9407,9414,9627,9630,9662,9665,9680],[1886,4737,879],{"id":4240},[1891,4739,885],{},[1968,4741,888],{"id":4742},"testing-levels",[3779,4744,4745,4751,4757,4763],{},[3224,4746,4747,4750],{},[3227,4748,4749],{},"Unit Tests"," - Test individual processors",[3224,4752,4753,4756],{},[3227,4754,4755],{},"Schema Tests"," - Test schema validation",[3224,4758,4759,4762],{},[3227,4760,4761],{},"Integration Tests"," - Test complete pipelines",[3224,4764,4765,4768],{},[3227,4766,4767],{},"Property Tests"," - Test invariants across schemas",[1968,4770,893],{"id":4771},"unit-testing-processors",[1891,4773,4774],{},"Test processors independently before registering:",[1973,4776,4778],{"className":1975,"code":4777,"language":1977,"meta":24,"style":24},"func TestValidateOrder(t *testing.T) {\n    processor := pipz.Apply(\"validate\", validateOrder)\n\n    tests := []struct {\n        name    string\n        input   Order\n        wantErr bool\n    }{\n        {\n            name:    \"valid order\",\n            input:   Order{Total: 100},\n            wantErr: false,\n        },\n        {\n            name:    \"zero total\",\n            input:   Order{Total: 0},\n            wantErr: true,\n        },\n        {\n            name:    \"negative total\",\n            input:   Order{Total: -50},\n            wantErr: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := processor.Process(context.Background(), tt.input)\n            if (err != nil) != tt.wantErr {\n                t.Errorf(\"error = %v, wantErr %v\", err, tt.wantErr)\n            }\n        })\n    }\n}\n",[1979,4779,4780,4806,4831,4835,4850,4857,4865,4873,4878,4883,4895,4917,4929,4934,4938,4949,4967,4978,4982,4986,4997,5019,5029,5033,5037,5041,5063,5103,5140,5165,5202,5206,5211,5215],{"__ignoreMap":24},[1982,4781,4782,4784,4787,4789,4792,4795,4797,4799,4802,4804],{"class":1984,"line":9},[1982,4783,2607],{"class":2052},[1982,4785,4786],{"class":2007}," TestValidateOrder",[1982,4788,2042],{"class":2003},[1982,4790,4791],{"class":2058},"t",[1982,4793,4794],{"class":2099}," *",[1982,4796,4240],{"class":2013},[1982,4798,2004],{"class":2003},[1982,4800,4801],{"class":2013},"T",[1982,4803,2078],{"class":2003},[1982,4805,2093],{"class":2003},[1982,4807,4808,4811,4813,4816,4818,4820,4822,4824,4826,4829],{"class":1984,"line":19},[1982,4809,4810],{"class":1993},"    processor",[1982,4812,1997],{"class":1993},[1982,4814,4815],{"class":1993}," pipz",[1982,4817,2004],{"class":2003},[1982,4819,2039],{"class":2007},[1982,4821,2042],{"class":2003},[1982,4823,2046],{"class":2045},[1982,4825,2049],{"class":2003},[1982,4827,4828],{"class":1993}," validateOrder",[1982,4830,2142],{"class":2003},[1982,4832,4833],{"class":1984,"line":30},[1982,4834,2361],{"emptyLinePlaceholder":2360},[1982,4836,4837,4840,4842,4845,4848],{"class":1984,"line":2031},[1982,4838,4839],{"class":1993},"    tests",[1982,4841,1997],{"class":1993},[1982,4843,4844],{"class":2003}," []",[1982,4846,4847],{"class":2052},"struct",[1982,4849,2093],{"class":2003},[1982,4851,4852,4855],{"class":1984,"line":2096},[1982,4853,4854],{"class":2285},"        name",[1982,4856,2585],{"class":2013},[1982,4858,4859,4862],{"class":1984,"line":2119},[1982,4860,4861],{"class":2285},"        input",[1982,4863,4864],{"class":2013},"   Order\n",[1982,4866,4867,4870],{"class":1984,"line":2145},[1982,4868,4869],{"class":2285},"        wantErr",[1982,4871,4872],{"class":2013}," bool\n",[1982,4874,4875],{"class":1984,"line":2151},[1982,4876,4877],{"class":2003},"    }{\n",[1982,4879,4880],{"class":1984,"line":2164},[1982,4881,4882],{"class":2003},"        {\n",[1982,4884,4885,4888,4890,4893],{"class":1984,"line":2170},[1982,4886,4887],{"class":2285},"            name",[1982,4889,2289],{"class":2003},[1982,4891,4892],{"class":2045},"    \"valid order\"",[1982,4894,2295],{"class":2003},[1982,4896,4897,4900,4902,4905,4907,4909,4911,4914],{"class":1984,"line":2218},[1982,4898,4899],{"class":2285},"            input",[1982,4901,2289],{"class":2003},[1982,4903,4904],{"class":2013},"   Order",[1982,4906,2633],{"class":2003},[1982,4908,2107],{"class":2285},[1982,4910,2289],{"class":2003},[1982,4912,4913],{"class":2113}," 100",[1982,4915,4916],{"class":2003},"},\n",[1982,4918,4919,4922,4924,4927],{"class":1984,"line":2237},[1982,4920,4921],{"class":2285},"            wantErr",[1982,4923,2289],{"class":2003},[1982,4925,4926],{"class":2052}," false",[1982,4928,2295],{"class":2003},[1982,4930,4931],{"class":1984,"line":2248},[1982,4932,4933],{"class":2003},"        },\n",[1982,4935,4936],{"class":1984,"line":2253},[1982,4937,4882],{"class":2003},[1982,4939,4940,4942,4944,4947],{"class":1984,"line":2258},[1982,4941,4887],{"class":2285},[1982,4943,2289],{"class":2003},[1982,4945,4946],{"class":2045},"    \"zero total\"",[1982,4948,2295],{"class":2003},[1982,4950,4951,4953,4955,4957,4959,4961,4963,4965],{"class":1984,"line":2282},[1982,4952,4899],{"class":2285},[1982,4954,2289],{"class":2003},[1982,4956,4904],{"class":2013},[1982,4958,2633],{"class":2003},[1982,4960,2107],{"class":2285},[1982,4962,2289],{"class":2003},[1982,4964,2114],{"class":2113},[1982,4966,4916],{"class":2003},[1982,4968,4969,4971,4973,4976],{"class":1984,"line":2298},[1982,4970,4921],{"class":2285},[1982,4972,2289],{"class":2003},[1982,4974,4975],{"class":2052}," true",[1982,4977,2295],{"class":2003},[1982,4979,4980],{"class":1984,"line":2351},[1982,4981,4933],{"class":2003},[1982,4983,4984],{"class":1984,"line":2357},[1982,4985,4882],{"class":2003},[1982,4987,4988,4990,4992,4995],{"class":1984,"line":2364},[1982,4989,4887],{"class":2285},[1982,4991,2289],{"class":2003},[1982,4993,4994],{"class":2045},"    \"negative total\"",[1982,4996,2295],{"class":2003},[1982,4998,4999,5001,5003,5005,5007,5009,5011,5014,5017],{"class":1984,"line":2370},[1982,5000,4899],{"class":2285},[1982,5002,2289],{"class":2003},[1982,5004,4904],{"class":2013},[1982,5006,2633],{"class":2003},[1982,5008,2107],{"class":2285},[1982,5010,2289],{"class":2003},[1982,5012,5013],{"class":1993}," -",[1982,5015,5016],{"class":2113},"50",[1982,5018,4916],{"class":2003},[1982,5020,5021,5023,5025,5027],{"class":1984,"line":2395},[1982,5022,4921],{"class":2285},[1982,5024,2289],{"class":2003},[1982,5026,4975],{"class":2052},[1982,5028,2295],{"class":2003},[1982,5030,5031],{"class":1984,"line":2401},[1982,5032,4933],{"class":2003},[1982,5034,5035],{"class":1984,"line":2407},[1982,5036,2999],{"class":2003},[1982,5038,5039],{"class":1984,"line":2413},[1982,5040,2361],{"emptyLinePlaceholder":2360},[1982,5042,5043,5046,5048,5050,5053,5055,5058,5061],{"class":1984,"line":2419},[1982,5044,5045],{"class":2099},"    for",[1982,5047,2378],{"class":1993},[1982,5049,2049],{"class":2003},[1982,5051,5052],{"class":1993}," tt",[1982,5054,1997],{"class":1993},[1982,5056,5057],{"class":2099}," range",[1982,5059,5060],{"class":1993}," tests",[1982,5062,2093],{"class":2003},[1982,5064,5065,5068,5070,5073,5075,5078,5080,5083,5085,5087,5089,5091,5093,5095,5097,5099,5101],{"class":1984,"line":2425},[1982,5066,5067],{"class":1993},"        t",[1982,5069,2004],{"class":2003},[1982,5071,5072],{"class":2007},"Run",[1982,5074,2042],{"class":2003},[1982,5076,5077],{"class":1993},"tt",[1982,5079,2004],{"class":2003},[1982,5081,5082],{"class":1993},"name",[1982,5084,2049],{"class":2003},[1982,5086,2053],{"class":2052},[1982,5088,2042],{"class":2003},[1982,5090,4791],{"class":2058},[1982,5092,4794],{"class":2099},[1982,5094,4240],{"class":2013},[1982,5096,2004],{"class":2003},[1982,5098,4801],{"class":2013},[1982,5100,2078],{"class":2003},[1982,5102,2093],{"class":2003},[1982,5104,5105,5108,5110,5112,5114,5117,5119,5121,5123,5125,5127,5129,5131,5133,5135,5138],{"class":1984,"line":2431},[1982,5106,5107],{"class":1993},"            _",[1982,5109,2049],{"class":2003},[1982,5111,2464],{"class":1993},[1982,5113,1997],{"class":1993},[1982,5115,5116],{"class":1993}," processor",[1982,5118,2004],{"class":2003},[1982,5120,1326],{"class":2007},[1982,5122,2042],{"class":2003},[1982,5124,3033],{"class":1993},[1982,5126,2004],{"class":2003},[1982,5128,3038],{"class":2007},[1982,5130,3041],{"class":2003},[1982,5132,5052],{"class":1993},[1982,5134,2004],{"class":2003},[1982,5136,5137],{"class":1993},"input",[1982,5139,2142],{"class":2003},[1982,5141,5142,5144,5146,5148,5150,5152,5154,5156,5158,5160,5163],{"class":1984,"line":2437},[1982,5143,2768],{"class":2099},[1982,5145,2081],{"class":2003},[1982,5147,2991],{"class":1993},[1982,5149,2974],{"class":2099},[1982,5151,2977],{"class":2052},[1982,5153,2078],{"class":2003},[1982,5155,2974],{"class":2099},[1982,5157,5052],{"class":1993},[1982,5159,2004],{"class":2003},[1982,5161,5162],{"class":1993},"wantErr",[1982,5164,2093],{"class":2003},[1982,5166,5167,5170,5172,5174,5176,5179,5181,5184,5186,5188,5190,5192,5194,5196,5198,5200],{"class":1984,"line":2445},[1982,5168,5169],{"class":1993},"                t",[1982,5171,2004],{"class":2003},[1982,5173,2134],{"class":2007},[1982,5175,2042],{"class":2003},[1982,5177,5178],{"class":2045},"\"error = ",[1982,5180,3089],{"class":3082},[1982,5182,5183],{"class":2045},", wantErr ",[1982,5185,3089],{"class":3082},[1982,5187,3096],{"class":2045},[1982,5189,2049],{"class":2003},[1982,5191,2464],{"class":1993},[1982,5193,2049],{"class":2003},[1982,5195,5052],{"class":1993},[1982,5197,2004],{"class":2003},[1982,5199,5162],{"class":1993},[1982,5201,2142],{"class":2003},[1982,5203,5204],{"class":1984,"line":2450},[1982,5205,2806],{"class":2003},[1982,5207,5208],{"class":1984,"line":2456},[1982,5209,5210],{"class":2003},"        })\n",[1982,5212,5213],{"class":1984,"line":2905},[1982,5214,2999],{"class":2003},[1982,5216,5217],{"class":1984,"line":2910},[1982,5218,2598],{"class":2003},[1968,5220,898],{"id":5221},"testing-predicates",[1973,5223,5225],{"className":1975,"code":5224,"language":1977,"meta":24,"style":24},"func TestIsPremium(t *testing.T) {\n    pred := func(ctx context.Context, o Order) bool {\n        return o.CustomerTier == \"premium\"\n    }\n\n    tests := []struct {\n        tier string\n        want bool\n    }{\n        {\"premium\", true},\n        {\"standard\", false},\n        {\"\", false},\n    }\n\n    for _, tt := range tests {\n        got := pred(context.Background(), Order{CustomerTier: tt.tier})\n        if got != tt.want {\n            t.Errorf(\"isPremium(%q) = %v, want %v\", tt.tier, got, tt.want)\n        }\n    }\n}\n",[1979,5226,5227,5250,5281,5297,5301,5305,5317,5325,5332,5336,5350,5363,5376,5380,5384,5402,5439,5457,5508,5512,5516],{"__ignoreMap":24},[1982,5228,5229,5231,5234,5236,5238,5240,5242,5244,5246,5248],{"class":1984,"line":9},[1982,5230,2607],{"class":2052},[1982,5232,5233],{"class":2007}," TestIsPremium",[1982,5235,2042],{"class":2003},[1982,5237,4791],{"class":2058},[1982,5239,4794],{"class":2099},[1982,5241,4240],{"class":2013},[1982,5243,2004],{"class":2003},[1982,5245,4801],{"class":2013},[1982,5247,2078],{"class":2003},[1982,5249,2093],{"class":2003},[1982,5251,5252,5255,5257,5259,5261,5263,5265,5267,5269,5271,5273,5275,5277,5279],{"class":1984,"line":19},[1982,5253,5254],{"class":1993},"    pred",[1982,5256,1997],{"class":1993},[1982,5258,2053],{"class":2052},[1982,5260,2042],{"class":2003},[1982,5262,2059],{"class":2058},[1982,5264,2062],{"class":2013},[1982,5266,2004],{"class":2003},[1982,5268,2067],{"class":2013},[1982,5270,2049],{"class":2003},[1982,5272,2072],{"class":2058},[1982,5274,2075],{"class":2013},[1982,5276,2078],{"class":2003},[1982,5278,2326],{"class":2013},[1982,5280,2093],{"class":2003},[1982,5282,5283,5285,5287,5289,5292,5294],{"class":1984,"line":30},[1982,5284,2154],{"class":2099},[1982,5286,2072],{"class":1993},[1982,5288,2004],{"class":2003},[1982,5290,5291],{"class":1993},"CustomerTier",[1982,5293,2342],{"class":2099},[1982,5295,5296],{"class":2045}," \"premium\"\n",[1982,5298,5299],{"class":1984,"line":2031},[1982,5300,2999],{"class":2003},[1982,5302,5303],{"class":1984,"line":2096},[1982,5304,2361],{"emptyLinePlaceholder":2360},[1982,5306,5307,5309,5311,5313,5315],{"class":1984,"line":2119},[1982,5308,4839],{"class":1993},[1982,5310,1997],{"class":1993},[1982,5312,4844],{"class":2003},[1982,5314,4847],{"class":2052},[1982,5316,2093],{"class":2003},[1982,5318,5319,5322],{"class":1984,"line":2145},[1982,5320,5321],{"class":2285},"        tier",[1982,5323,5324],{"class":2013}," string\n",[1982,5326,5327,5330],{"class":1984,"line":2151},[1982,5328,5329],{"class":2285},"        want",[1982,5331,4872],{"class":2013},[1982,5333,5334],{"class":1984,"line":2164},[1982,5335,4877],{"class":2003},[1982,5337,5338,5341,5344,5346,5348],{"class":1984,"line":2170},[1982,5339,5340],{"class":2003},"        {",[1982,5342,5343],{"class":2045},"\"premium\"",[1982,5345,2049],{"class":2003},[1982,5347,4975],{"class":2052},[1982,5349,4916],{"class":2003},[1982,5351,5352,5354,5357,5359,5361],{"class":1984,"line":2218},[1982,5353,5340],{"class":2003},[1982,5355,5356],{"class":2045},"\"standard\"",[1982,5358,2049],{"class":2003},[1982,5360,4926],{"class":2052},[1982,5362,4916],{"class":2003},[1982,5364,5365,5367,5370,5372,5374],{"class":1984,"line":2237},[1982,5366,5340],{"class":2003},[1982,5368,5369],{"class":2045},"\"\"",[1982,5371,2049],{"class":2003},[1982,5373,4926],{"class":2052},[1982,5375,4916],{"class":2003},[1982,5377,5378],{"class":1984,"line":2248},[1982,5379,2999],{"class":2003},[1982,5381,5382],{"class":1984,"line":2253},[1982,5383,2361],{"emptyLinePlaceholder":2360},[1982,5385,5386,5388,5390,5392,5394,5396,5398,5400],{"class":1984,"line":2258},[1982,5387,5045],{"class":2099},[1982,5389,2378],{"class":1993},[1982,5391,2049],{"class":2003},[1982,5393,5052],{"class":1993},[1982,5395,1997],{"class":1993},[1982,5397,5057],{"class":2099},[1982,5399,5060],{"class":1993},[1982,5401,2093],{"class":2003},[1982,5403,5404,5407,5409,5412,5414,5416,5418,5420,5422,5424,5426,5428,5430,5432,5434,5437],{"class":1984,"line":2282},[1982,5405,5406],{"class":1993},"        got",[1982,5408,1997],{"class":1993},[1982,5410,5411],{"class":2007}," pred",[1982,5413,2042],{"class":2003},[1982,5415,3033],{"class":1993},[1982,5417,2004],{"class":2003},[1982,5419,3038],{"class":2007},[1982,5421,3041],{"class":2003},[1982,5423,2075],{"class":2013},[1982,5425,2633],{"class":2003},[1982,5427,5291],{"class":2285},[1982,5429,2289],{"class":2003},[1982,5431,5052],{"class":1993},[1982,5433,2004],{"class":2003},[1982,5435,5436],{"class":1993},"tier",[1982,5438,2354],{"class":2003},[1982,5440,5441,5443,5446,5448,5450,5452,5455],{"class":1984,"line":2298},[1982,5442,2100],{"class":2099},[1982,5444,5445],{"class":1993}," got",[1982,5447,2974],{"class":2099},[1982,5449,5052],{"class":1993},[1982,5451,2004],{"class":2003},[1982,5453,5454],{"class":1993},"want",[1982,5456,2093],{"class":2003},[1982,5458,5459,5462,5464,5466,5468,5471,5474,5477,5479,5482,5484,5486,5488,5490,5492,5494,5496,5498,5500,5502,5504,5506],{"class":1984,"line":2351},[1982,5460,5461],{"class":1993},"            t",[1982,5463,2004],{"class":2003},[1982,5465,2134],{"class":2007},[1982,5467,2042],{"class":2003},[1982,5469,5470],{"class":2045},"\"isPremium(",[1982,5472,5473],{"class":3082},"%q",[1982,5475,5476],{"class":2045},") = ",[1982,5478,3089],{"class":3082},[1982,5480,5481],{"class":2045},", want ",[1982,5483,3089],{"class":3082},[1982,5485,3096],{"class":2045},[1982,5487,2049],{"class":2003},[1982,5489,5052],{"class":1993},[1982,5491,2004],{"class":2003},[1982,5493,5436],{"class":1993},[1982,5495,2049],{"class":2003},[1982,5497,5445],{"class":1993},[1982,5499,2049],{"class":2003},[1982,5501,5052],{"class":1993},[1982,5503,2004],{"class":2003},[1982,5505,5454],{"class":1993},[1982,5507,2142],{"class":2003},[1982,5509,5510],{"class":1984,"line":2357},[1982,5511,2148],{"class":2003},[1982,5513,5514],{"class":1984,"line":2364},[1982,5515,2999],{"class":2003},[1982,5517,5518],{"class":1984,"line":2370},[1982,5519,2598],{"class":2003},[1968,5521,903],{"id":5522},"schema-validation-tests",[1891,5524,5525],{},"Test that schemas are valid before deployment:",[1973,5527,5529],{"className":1975,"code":5528,"language":1977,"meta":24,"style":24},"func TestSchemaValidation(t *testing.T) {\n    factory := setupFactory()\n\n    tests := []struct {\n        name      string\n        schema    string\n        wantError bool\n    }{\n        {\n            name: \"valid sequence\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: validate\n  - ref: process`,\n            wantError: false,\n        },\n        {\n            name: \"missing processor\",\n            schema: `\ntype: sequence\nchildren:\n  - ref: nonexistent`,\n            wantError: true,\n        },\n        {\n            name: \"missing predicate\",\n            schema: `\ntype: filter\npredicate: missing\nthen:\n  ref: validate`,\n            wantError: true,\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            _, err := factory.BuildFromYAML(tt.schema)\n            if (err != nil) != tt.wantError {\n                t.Errorf(\"BuildFromYAML() error = %v, wantError %v\", err, tt.wantError)\n            }\n        })\n    }\n}\n\nfunc setupFactory() *flume.Factory[Order] {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"validate\", func(_ context.Context, o Order) Order { return o }),\n        pipz.Transform(\"process\", func(_ context.Context, o Order) Order { return o }),\n    )\n    factory.AddPredicate(flume.Predicate[Order]{\n        Name:      \"is-valid\",\n        Predicate: func(_ context.Context, o Order) bool { return o.Total > 0 },\n    })\n    return factory\n}\n",[1979,5530,5531,5554,5566,5570,5582,5589,5596,5603,5607,5611,5622,5632,5636,5640,5644,5651,5662,5666,5670,5681,5689,5693,5697,5704,5714,5718,5722,5733,5741,5746,5751,5756,5763,5773,5777,5781,5785,5803,5839,5866,5891,5927,5931,5935,5939,5943,5947,5972,5990,6001,6048,6094,6099,6122,6135,6182,6188,6197],{"__ignoreMap":24},[1982,5532,5533,5535,5538,5540,5542,5544,5546,5548,5550,5552],{"class":1984,"line":9},[1982,5534,2607],{"class":2052},[1982,5536,5537],{"class":2007}," TestSchemaValidation",[1982,5539,2042],{"class":2003},[1982,5541,4791],{"class":2058},[1982,5543,4794],{"class":2099},[1982,5545,4240],{"class":2013},[1982,5547,2004],{"class":2003},[1982,5549,4801],{"class":2013},[1982,5551,2078],{"class":2003},[1982,5553,2093],{"class":2003},[1982,5555,5556,5558,5560,5563],{"class":1984,"line":19},[1982,5557,2683],{"class":1993},[1982,5559,1997],{"class":1993},[1982,5561,5562],{"class":2007}," setupFactory",[1982,5564,5565],{"class":2003},"()\n",[1982,5567,5568],{"class":1984,"line":30},[1982,5569,2361],{"emptyLinePlaceholder":2360},[1982,5571,5572,5574,5576,5578,5580],{"class":1984,"line":2031},[1982,5573,4839],{"class":1993},[1982,5575,1997],{"class":1993},[1982,5577,4844],{"class":2003},[1982,5579,4847],{"class":2052},[1982,5581,2093],{"class":2003},[1982,5583,5584,5586],{"class":1984,"line":2096},[1982,5585,4854],{"class":2285},[1982,5587,5588],{"class":2013},"      string\n",[1982,5590,5591,5594],{"class":1984,"line":2119},[1982,5592,5593],{"class":2285},"        schema",[1982,5595,2585],{"class":2013},[1982,5597,5598,5601],{"class":1984,"line":2145},[1982,5599,5600],{"class":2285},"        wantError",[1982,5602,4872],{"class":2013},[1982,5604,5605],{"class":1984,"line":2151},[1982,5606,4877],{"class":2003},[1982,5608,5609],{"class":1984,"line":2164},[1982,5610,4882],{"class":2003},[1982,5612,5613,5615,5617,5620],{"class":1984,"line":2170},[1982,5614,4887],{"class":2285},[1982,5616,2289],{"class":2003},[1982,5618,5619],{"class":2045}," \"valid sequence\"",[1982,5621,2295],{"class":2003},[1982,5623,5624,5627,5629],{"class":1984,"line":2218},[1982,5625,5626],{"class":2285},"            schema",[1982,5628,2289],{"class":2003},[1982,5630,5631],{"class":2045}," `\n",[1982,5633,5634],{"class":1984,"line":2237},[1982,5635,2398],{"class":2045},[1982,5637,5638],{"class":1984,"line":2248},[1982,5639,2404],{"class":2045},[1982,5641,5642],{"class":1984,"line":2253},[1982,5643,2410],{"class":2045},[1982,5645,5646,5649],{"class":1984,"line":2258},[1982,5647,5648],{"class":2045},"  - ref: process`",[1982,5650,2295],{"class":2003},[1982,5652,5653,5656,5658,5660],{"class":1984,"line":2282},[1982,5654,5655],{"class":2285},"            wantError",[1982,5657,2289],{"class":2003},[1982,5659,4926],{"class":2052},[1982,5661,2295],{"class":2003},[1982,5663,5664],{"class":1984,"line":2298},[1982,5665,4933],{"class":2003},[1982,5667,5668],{"class":1984,"line":2351},[1982,5669,4882],{"class":2003},[1982,5671,5672,5674,5676,5679],{"class":1984,"line":2357},[1982,5673,4887],{"class":2285},[1982,5675,2289],{"class":2003},[1982,5677,5678],{"class":2045}," \"missing processor\"",[1982,5680,2295],{"class":2003},[1982,5682,5683,5685,5687],{"class":1984,"line":2364},[1982,5684,5626],{"class":2285},[1982,5686,2289],{"class":2003},[1982,5688,5631],{"class":2045},[1982,5690,5691],{"class":1984,"line":2370},[1982,5692,2398],{"class":2045},[1982,5694,5695],{"class":1984,"line":2395},[1982,5696,2404],{"class":2045},[1982,5698,5699,5702],{"class":1984,"line":2401},[1982,5700,5701],{"class":2045},"  - ref: nonexistent`",[1982,5703,2295],{"class":2003},[1982,5705,5706,5708,5710,5712],{"class":1984,"line":2407},[1982,5707,5655],{"class":2285},[1982,5709,2289],{"class":2003},[1982,5711,4975],{"class":2052},[1982,5713,2295],{"class":2003},[1982,5715,5716],{"class":1984,"line":2413},[1982,5717,4933],{"class":2003},[1982,5719,5720],{"class":1984,"line":2419},[1982,5721,4882],{"class":2003},[1982,5723,5724,5726,5728,5731],{"class":1984,"line":2425},[1982,5725,4887],{"class":2285},[1982,5727,2289],{"class":2003},[1982,5729,5730],{"class":2045}," \"missing predicate\"",[1982,5732,2295],{"class":2003},[1982,5734,5735,5737,5739],{"class":1984,"line":2431},[1982,5736,5626],{"class":2285},[1982,5738,2289],{"class":2003},[1982,5740,5631],{"class":2045},[1982,5742,5743],{"class":1984,"line":2437},[1982,5744,5745],{"class":2045},"type: filter\n",[1982,5747,5748],{"class":1984,"line":2445},[1982,5749,5750],{"class":2045},"predicate: missing\n",[1982,5752,5753],{"class":1984,"line":2450},[1982,5754,5755],{"class":2045},"then:\n",[1982,5757,5758,5761],{"class":1984,"line":2456},[1982,5759,5760],{"class":2045},"  ref: validate`",[1982,5762,2295],{"class":2003},[1982,5764,5765,5767,5769,5771],{"class":1984,"line":2905},[1982,5766,5655],{"class":2285},[1982,5768,2289],{"class":2003},[1982,5770,4975],{"class":2052},[1982,5772,2295],{"class":2003},[1982,5774,5775],{"class":1984,"line":2910},[1982,5776,4933],{"class":2003},[1982,5778,5779],{"class":1984,"line":2916},[1982,5780,2999],{"class":2003},[1982,5782,5783],{"class":1984,"line":2938},[1982,5784,2361],{"emptyLinePlaceholder":2360},[1982,5786,5787,5789,5791,5793,5795,5797,5799,5801],{"class":1984,"line":2943},[1982,5788,5045],{"class":2099},[1982,5790,2378],{"class":1993},[1982,5792,2049],{"class":2003},[1982,5794,5052],{"class":1993},[1982,5796,1997],{"class":1993},[1982,5798,5057],{"class":2099},[1982,5800,5060],{"class":1993},[1982,5802,2093],{"class":2003},[1982,5804,5805,5807,5809,5811,5813,5815,5817,5819,5821,5823,5825,5827,5829,5831,5833,5835,5837],{"class":1984,"line":2948},[1982,5806,5067],{"class":1993},[1982,5808,2004],{"class":2003},[1982,5810,5072],{"class":2007},[1982,5812,2042],{"class":2003},[1982,5814,5077],{"class":1993},[1982,5816,2004],{"class":2003},[1982,5818,5082],{"class":1993},[1982,5820,2049],{"class":2003},[1982,5822,2053],{"class":2052},[1982,5824,2042],{"class":2003},[1982,5826,4791],{"class":2058},[1982,5828,4794],{"class":2099},[1982,5830,4240],{"class":2013},[1982,5832,2004],{"class":2003},[1982,5834,4801],{"class":2013},[1982,5836,2078],{"class":2003},[1982,5838,2093],{"class":2003},[1982,5840,5841,5843,5845,5847,5849,5851,5853,5855,5857,5859,5861,5864],{"class":1984,"line":2953},[1982,5842,5107],{"class":1993},[1982,5844,2049],{"class":2003},[1982,5846,2464],{"class":1993},[1982,5848,1997],{"class":1993},[1982,5850,2383],{"class":1993},[1982,5852,2004],{"class":2003},[1982,5854,1272],{"class":2007},[1982,5856,2042],{"class":2003},[1982,5858,5077],{"class":1993},[1982,5860,2004],{"class":2003},[1982,5862,5863],{"class":1993},"schema",[1982,5865,2142],{"class":2003},[1982,5867,5868,5870,5872,5874,5876,5878,5880,5882,5884,5886,5889],{"class":1984,"line":2959},[1982,5869,2768],{"class":2099},[1982,5871,2081],{"class":2003},[1982,5873,2991],{"class":1993},[1982,5875,2974],{"class":2099},[1982,5877,2977],{"class":2052},[1982,5879,2078],{"class":2003},[1982,5881,2974],{"class":2099},[1982,5883,5052],{"class":1993},[1982,5885,2004],{"class":2003},[1982,5887,5888],{"class":1993},"wantError",[1982,5890,2093],{"class":2003},[1982,5892,5893,5895,5897,5899,5901,5904,5906,5909,5911,5913,5915,5917,5919,5921,5923,5925],{"class":1984,"line":2966},[1982,5894,5169],{"class":1993},[1982,5896,2004],{"class":2003},[1982,5898,2134],{"class":2007},[1982,5900,2042],{"class":2003},[1982,5902,5903],{"class":2045},"\"BuildFromYAML() error = ",[1982,5905,3089],{"class":3082},[1982,5907,5908],{"class":2045},", wantError ",[1982,5910,3089],{"class":3082},[1982,5912,3096],{"class":2045},[1982,5914,2049],{"class":2003},[1982,5916,2464],{"class":1993},[1982,5918,2049],{"class":2003},[1982,5920,5052],{"class":1993},[1982,5922,2004],{"class":2003},[1982,5924,5888],{"class":1993},[1982,5926,2142],{"class":2003},[1982,5928,5929],{"class":1984,"line":2982},[1982,5930,2806],{"class":2003},[1982,5932,5933],{"class":1984,"line":2996},[1982,5934,5210],{"class":2003},[1982,5936,5937],{"class":1984,"line":3002},[1982,5938,2999],{"class":2003},[1982,5940,5941],{"class":1984,"line":3007},[1982,5942,2598],{"class":2003},[1982,5944,5945],{"class":1984,"line":3013},[1982,5946,2361],{"emptyLinePlaceholder":2360},[1982,5948,5949,5951,5953,5955,5957,5959,5961,5963,5965,5967,5970],{"class":1984,"line":3066},[1982,5950,2607],{"class":2052},[1982,5952,5562],{"class":2007},[1982,5954,2622],{"class":2003},[1982,5956,4794],{"class":2099},[1982,5958,1888],{"class":2013},[1982,5960,2004],{"class":2003},[1982,5962,1149],{"class":2013},[1982,5964,2010],{"class":2003},[1982,5966,2014],{"class":2013},[1982,5968,5969],{"class":2003},"]",[1982,5971,2093],{"class":2003},[1982,5973,5974,5976,5978,5980,5982,5984,5986,5988],{"class":1984,"line":3110},[1982,5975,2683],{"class":1993},[1982,5977,1997],{"class":1993},[1982,5979,2000],{"class":1993},[1982,5981,2004],{"class":2003},[1982,5983,1153],{"class":2007},[1982,5985,2010],{"class":2003},[1982,5987,2014],{"class":2013},[1982,5989,2017],{"class":2003},[1982,5991,5993,5995,5997,5999],{"class":1984,"line":5992},49,[1982,5994,2683],{"class":1993},[1982,5996,2004],{"class":2003},[1982,5998,1162],{"class":2007},[1982,6000,2028],{"class":2003},[1982,6002,6004,6006,6008,6010,6012,6014,6016,6018,6020,6023,6025,6027,6029,6031,6033,6035,6037,6039,6041,6043,6045],{"class":1984,"line":6003},50,[1982,6005,2721],{"class":1993},[1982,6007,2004],{"class":2003},[1982,6009,2830],{"class":2007},[1982,6011,2042],{"class":2003},[1982,6013,2046],{"class":2045},[1982,6015,2049],{"class":2003},[1982,6017,2053],{"class":2052},[1982,6019,2042],{"class":2003},[1982,6021,6022],{"class":2058},"_",[1982,6024,2062],{"class":2013},[1982,6026,2004],{"class":2003},[1982,6028,2067],{"class":2013},[1982,6030,2049],{"class":2003},[1982,6032,2072],{"class":2058},[1982,6034,2075],{"class":2013},[1982,6036,2078],{"class":2003},[1982,6038,2075],{"class":2013},[1982,6040,2329],{"class":2003},[1982,6042,2332],{"class":2099},[1982,6044,2072],{"class":1993},[1982,6046,6047],{"class":2003}," }),\n",[1982,6049,6051,6053,6055,6057,6059,6062,6064,6066,6068,6070,6072,6074,6076,6078,6080,6082,6084,6086,6088,6090,6092],{"class":1984,"line":6050},51,[1982,6052,2721],{"class":1993},[1982,6054,2004],{"class":2003},[1982,6056,2830],{"class":2007},[1982,6058,2042],{"class":2003},[1982,6060,6061],{"class":2045},"\"process\"",[1982,6063,2049],{"class":2003},[1982,6065,2053],{"class":2052},[1982,6067,2042],{"class":2003},[1982,6069,6022],{"class":2058},[1982,6071,2062],{"class":2013},[1982,6073,2004],{"class":2003},[1982,6075,2067],{"class":2013},[1982,6077,2049],{"class":2003},[1982,6079,2072],{"class":2058},[1982,6081,2075],{"class":2013},[1982,6083,2078],{"class":2003},[1982,6085,2075],{"class":2013},[1982,6087,2329],{"class":2003},[1982,6089,2332],{"class":2099},[1982,6091,2072],{"class":1993},[1982,6093,6047],{"class":2003},[1982,6095,6097],{"class":1984,"line":6096},52,[1982,6098,2902],{"class":2003},[1982,6100,6102,6104,6106,6108,6110,6112,6114,6116,6118,6120],{"class":1984,"line":6101},53,[1982,6103,2683],{"class":1993},[1982,6105,2004],{"class":2003},[1982,6107,1191],{"class":2007},[1982,6109,2042],{"class":2003},[1982,6111,1888],{"class":2013},[1982,6113,2004],{"class":2003},[1982,6115,1368],{"class":2013},[1982,6117,2010],{"class":2003},[1982,6119,2014],{"class":2013},[1982,6121,2279],{"class":2003},[1982,6123,6125,6128,6130,6133],{"class":1984,"line":6124},54,[1982,6126,6127],{"class":2285},"        Name",[1982,6129,2289],{"class":2003},[1982,6131,6132],{"class":2045},"      \"is-valid\"",[1982,6134,2295],{"class":2003},[1982,6136,6138,6141,6143,6145,6147,6149,6151,6153,6155,6157,6159,6161,6163,6165,6167,6169,6171,6173,6175,6178,6180],{"class":1984,"line":6137},55,[1982,6139,6140],{"class":2285},"        Predicate",[1982,6142,2289],{"class":2003},[1982,6144,2053],{"class":2052},[1982,6146,2042],{"class":2003},[1982,6148,6022],{"class":2058},[1982,6150,2062],{"class":2013},[1982,6152,2004],{"class":2003},[1982,6154,2067],{"class":2013},[1982,6156,2049],{"class":2003},[1982,6158,2072],{"class":2058},[1982,6160,2075],{"class":2013},[1982,6162,2078],{"class":2003},[1982,6164,2326],{"class":2013},[1982,6166,2329],{"class":2003},[1982,6168,2332],{"class":2099},[1982,6170,2072],{"class":1993},[1982,6172,2004],{"class":2003},[1982,6174,2107],{"class":1993},[1982,6176,6177],{"class":2099}," >",[1982,6179,2114],{"class":2113},[1982,6181,2348],{"class":2003},[1982,6183,6185],{"class":1984,"line":6184},56,[1982,6186,6187],{"class":2003},"    })\n",[1982,6189,6191,6194],{"class":1984,"line":6190},57,[1982,6192,6193],{"class":2099},"    return",[1982,6195,6196],{"class":1993}," factory\n",[1982,6198,6200],{"class":1984,"line":6199},58,[1982,6201,2598],{"class":2003},[1968,6203,908],{"id":6204},"cicd-schema-linting",[1891,6206,3953,6207,6209],{},[1979,6208,1349],{}," for CI/CD pipelines where a configured factory is not available. This validates schema syntax without checking if processors, predicates, or other references exist.",[3557,6211,913],{"id":6212},"lint-schema-files",[1973,6214,6216],{"className":1975,"code":6215,"language":1977,"meta":24,"style":24},"func TestSchemaFilesStructure(t *testing.T) {\n    files, _ := filepath.Glob(\"schemas/*.yaml\")\n\n    for _, file := range files {\n        t.Run(filepath.Base(file), func(t *testing.T) {\n            data, err := os.ReadFile(file)\n            if err != nil {\n                t.Fatalf(\"failed to read file: %v\", err)\n            }\n\n            var schema flume.Schema\n            if err := yaml.Unmarshal(data, &schema); err != nil {\n                t.Fatalf(\"failed to parse YAML: %v\", err)\n            }\n\n            // Structural validation - no factory needed\n            if err := flume.ValidateSchemaStructure(schema); err != nil {\n                t.Errorf(\"invalid schema structure: %v\", err)\n            }\n        })\n    }\n}\n",[1979,6217,6218,6241,6267,6271,6291,6335,6360,6372,6396,6400,6404,6418,6457,6480,6484,6488,6493,6521,6544,6548,6552,6556],{"__ignoreMap":24},[1982,6219,6220,6222,6225,6227,6229,6231,6233,6235,6237,6239],{"class":1984,"line":9},[1982,6221,2607],{"class":2052},[1982,6223,6224],{"class":2007}," TestSchemaFilesStructure",[1982,6226,2042],{"class":2003},[1982,6228,4791],{"class":2058},[1982,6230,4794],{"class":2099},[1982,6232,4240],{"class":2013},[1982,6234,2004],{"class":2003},[1982,6236,4801],{"class":2013},[1982,6238,2078],{"class":2003},[1982,6240,2093],{"class":2003},[1982,6242,6243,6246,6248,6250,6252,6255,6257,6260,6262,6265],{"class":1984,"line":19},[1982,6244,6245],{"class":1993},"    files",[1982,6247,2049],{"class":2003},[1982,6249,2378],{"class":1993},[1982,6251,1997],{"class":1993},[1982,6253,6254],{"class":1993}," filepath",[1982,6256,2004],{"class":2003},[1982,6258,6259],{"class":2007},"Glob",[1982,6261,2042],{"class":2003},[1982,6263,6264],{"class":2045},"\"schemas/*.yaml\"",[1982,6266,2142],{"class":2003},[1982,6268,6269],{"class":1984,"line":30},[1982,6270,2361],{"emptyLinePlaceholder":2360},[1982,6272,6273,6275,6277,6279,6282,6284,6286,6289],{"class":1984,"line":2031},[1982,6274,5045],{"class":2099},[1982,6276,2378],{"class":1993},[1982,6278,2049],{"class":2003},[1982,6280,6281],{"class":1993}," file",[1982,6283,1997],{"class":1993},[1982,6285,5057],{"class":2099},[1982,6287,6288],{"class":1993}," files",[1982,6290,2093],{"class":2003},[1982,6292,6293,6295,6297,6299,6301,6304,6306,6309,6311,6314,6317,6319,6321,6323,6325,6327,6329,6331,6333],{"class":1984,"line":2096},[1982,6294,5067],{"class":1993},[1982,6296,2004],{"class":2003},[1982,6298,5072],{"class":2007},[1982,6300,2042],{"class":2003},[1982,6302,6303],{"class":1993},"filepath",[1982,6305,2004],{"class":2003},[1982,6307,6308],{"class":2007},"Base",[1982,6310,2042],{"class":2003},[1982,6312,6313],{"class":1993},"file",[1982,6315,6316],{"class":2003},"),",[1982,6318,2053],{"class":2052},[1982,6320,2042],{"class":2003},[1982,6322,4791],{"class":2058},[1982,6324,4794],{"class":2099},[1982,6326,4240],{"class":2013},[1982,6328,2004],{"class":2003},[1982,6330,4801],{"class":2013},[1982,6332,2078],{"class":2003},[1982,6334,2093],{"class":2003},[1982,6336,6337,6340,6342,6344,6346,6349,6351,6354,6356,6358],{"class":1984,"line":2119},[1982,6338,6339],{"class":1993},"            data",[1982,6341,2049],{"class":2003},[1982,6343,2464],{"class":1993},[1982,6345,1997],{"class":1993},[1982,6347,6348],{"class":1993}," os",[1982,6350,2004],{"class":2003},[1982,6352,6353],{"class":2007},"ReadFile",[1982,6355,2042],{"class":2003},[1982,6357,6313],{"class":1993},[1982,6359,2142],{"class":2003},[1982,6361,6362,6364,6366,6368,6370],{"class":1984,"line":2145},[1982,6363,2768],{"class":2099},[1982,6365,2464],{"class":1993},[1982,6367,2974],{"class":2099},[1982,6369,2977],{"class":2052},[1982,6371,2093],{"class":2003},[1982,6373,6374,6376,6378,6381,6383,6386,6388,6390,6392,6394],{"class":1984,"line":2151},[1982,6375,5169],{"class":1993},[1982,6377,2004],{"class":2003},[1982,6379,6380],{"class":2007},"Fatalf",[1982,6382,2042],{"class":2003},[1982,6384,6385],{"class":2045},"\"failed to read file: ",[1982,6387,3089],{"class":3082},[1982,6389,3096],{"class":2045},[1982,6391,2049],{"class":2003},[1982,6393,2464],{"class":1993},[1982,6395,2142],{"class":2003},[1982,6397,6398],{"class":1984,"line":2164},[1982,6399,2806],{"class":2003},[1982,6401,6402],{"class":1984,"line":2170},[1982,6403,2361],{"emptyLinePlaceholder":2360},[1982,6405,6406,6409,6411,6413,6415],{"class":1984,"line":2218},[1982,6407,6408],{"class":2052},"            var",[1982,6410,3432],{"class":1993},[1982,6412,2000],{"class":2013},[1982,6414,2004],{"class":2003},[1982,6416,6417],{"class":2013},"Schema\n",[1982,6419,6420,6422,6424,6426,6429,6431,6434,6436,6439,6441,6444,6446,6449,6451,6453,6455],{"class":1984,"line":2237},[1982,6421,2768],{"class":2099},[1982,6423,2464],{"class":1993},[1982,6425,1997],{"class":1993},[1982,6427,6428],{"class":1993}," yaml",[1982,6430,2004],{"class":2003},[1982,6432,6433],{"class":2007},"Unmarshal",[1982,6435,2042],{"class":2003},[1982,6437,6438],{"class":1993},"data",[1982,6440,2049],{"class":2003},[1982,6442,6443],{"class":2099}," &",[1982,6445,5863],{"class":1993},[1982,6447,6448],{"class":2003},");",[1982,6450,2464],{"class":1993},[1982,6452,2974],{"class":2099},[1982,6454,2977],{"class":2052},[1982,6456,2093],{"class":2003},[1982,6458,6459,6461,6463,6465,6467,6470,6472,6474,6476,6478],{"class":1984,"line":2248},[1982,6460,5169],{"class":1993},[1982,6462,2004],{"class":2003},[1982,6464,6380],{"class":2007},[1982,6466,2042],{"class":2003},[1982,6468,6469],{"class":2045},"\"failed to parse YAML: ",[1982,6471,3089],{"class":3082},[1982,6473,3096],{"class":2045},[1982,6475,2049],{"class":2003},[1982,6477,2464],{"class":1993},[1982,6479,2142],{"class":2003},[1982,6481,6482],{"class":1984,"line":2253},[1982,6483,2806],{"class":2003},[1982,6485,6486],{"class":1984,"line":2258},[1982,6487,2361],{"emptyLinePlaceholder":2360},[1982,6489,6490],{"class":1984,"line":2282},[1982,6491,6492],{"class":1987},"            // Structural validation - no factory needed\n",[1982,6494,6495,6497,6499,6501,6503,6505,6507,6509,6511,6513,6515,6517,6519],{"class":1984,"line":2298},[1982,6496,2768],{"class":2099},[1982,6498,2464],{"class":1993},[1982,6500,1997],{"class":1993},[1982,6502,2000],{"class":1993},[1982,6504,2004],{"class":2003},[1982,6506,1349],{"class":2007},[1982,6508,2042],{"class":2003},[1982,6510,5863],{"class":1993},[1982,6512,6448],{"class":2003},[1982,6514,2464],{"class":1993},[1982,6516,2974],{"class":2099},[1982,6518,2977],{"class":2052},[1982,6520,2093],{"class":2003},[1982,6522,6523,6525,6527,6529,6531,6534,6536,6538,6540,6542],{"class":1984,"line":2351},[1982,6524,5169],{"class":1993},[1982,6526,2004],{"class":2003},[1982,6528,2134],{"class":2007},[1982,6530,2042],{"class":2003},[1982,6532,6533],{"class":2045},"\"invalid schema structure: ",[1982,6535,3089],{"class":3082},[1982,6537,3096],{"class":2045},[1982,6539,2049],{"class":2003},[1982,6541,2464],{"class":1993},[1982,6543,2142],{"class":2003},[1982,6545,6546],{"class":1984,"line":2357},[1982,6547,2806],{"class":2003},[1982,6549,6550],{"class":1984,"line":2364},[1982,6551,5210],{"class":2003},[1982,6553,6554],{"class":1984,"line":2370},[1982,6555,2999],{"class":2003},[1982,6557,6558],{"class":1984,"line":2395},[1982,6559,2598],{"class":2003},[3557,6561,918],{"id":6562},"ci-pipeline-example",[1973,6564,6568],{"className":6565,"code":6566,"language":6567,"meta":24,"style":24},"language-yaml shiki shiki-themes","# .github/workflows/lint-schemas.yml\nname: Lint Schemas\non: [push, pull_request]\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: '1.23'\n      - run: go test -v -run TestSchemaFilesStructure ./...\n","yaml",[1979,6569,6570,6575,6585,6604,6612,6619,6629,6636,6649,6660,6667,6677],{"__ignoreMap":24},[1982,6571,6572],{"class":1984,"line":9},[1982,6573,6574],{"class":1987},"# .github/workflows/lint-schemas.yml\n",[1982,6576,6577,6579,6582],{"class":1984,"line":19},[1982,6578,5082],{"class":2052},[1982,6580,6581],{"class":2536},": ",[1982,6583,6584],{"class":2045},"Lint Schemas\n",[1982,6586,6587,6590,6593,6596,6598,6601],{"class":1984,"line":30},[1982,6588,6589],{"class":2052},"on",[1982,6591,6592],{"class":2536},": [",[1982,6594,6595],{"class":2045},"push",[1982,6597,4651],{"class":2536},[1982,6599,6600],{"class":2045},"pull_request",[1982,6602,6603],{"class":2536},"]\n",[1982,6605,6606,6609],{"class":1984,"line":2031},[1982,6607,6608],{"class":2052},"jobs",[1982,6610,6611],{"class":2536},":\n",[1982,6613,6614,6617],{"class":1984,"line":2096},[1982,6615,6616],{"class":2052},"  lint",[1982,6618,6611],{"class":2536},[1982,6620,6621,6624,6626],{"class":1984,"line":2119},[1982,6622,6623],{"class":2052},"    runs-on",[1982,6625,6581],{"class":2536},[1982,6627,6628],{"class":2045},"ubuntu-latest\n",[1982,6630,6631,6634],{"class":1984,"line":2145},[1982,6632,6633],{"class":2052},"    steps",[1982,6635,6611],{"class":2536},[1982,6637,6638,6641,6644,6646],{"class":1984,"line":2151},[1982,6639,6640],{"class":2536},"      - ",[1982,6642,6643],{"class":2052},"uses",[1982,6645,6581],{"class":2536},[1982,6647,6648],{"class":2045},"actions/checkout@v4\n",[1982,6650,6651,6653,6655,6657],{"class":1984,"line":2164},[1982,6652,6640],{"class":2536},[1982,6654,6643],{"class":2052},[1982,6656,6581],{"class":2536},[1982,6658,6659],{"class":2045},"actions/setup-go@v5\n",[1982,6661,6662,6665],{"class":1984,"line":2170},[1982,6663,6664],{"class":2052},"        with",[1982,6666,6611],{"class":2536},[1982,6668,6669,6672,6674],{"class":1984,"line":2218},[1982,6670,6671],{"class":2052},"          go-version",[1982,6673,6581],{"class":2536},[1982,6675,6676],{"class":2045},"'1.23'\n",[1982,6678,6679,6681,6684,6686],{"class":1984,"line":2237},[1982,6680,6640],{"class":2536},[1982,6682,6683],{"class":2052},"run",[1982,6685,6581],{"class":2536},[1982,6687,6688],{"class":2045},"go test -v -run TestSchemaFilesStructure ./...\n",[3557,6690,923],{"id":6691},"what-each-validation-checks",[3117,6693,6694,6709],{},[3120,6695,6696],{},[3123,6697,6698,6701,6705],{},[3126,6699,6700],{},"Check",[3126,6702,6703],{},[1979,6704,1349],{},[3126,6706,6707],{},[1979,6708,1344],{},[3136,6710,6711,6721,6730,6739,6748,6758,6767,6776,6785],{},[3123,6712,6713,6716,6719],{},[3141,6714,6715],{},"Valid node types",[3141,6717,6718],{},"Yes",[3141,6720,6718],{},[3123,6722,6723,6726,6728],{},[3141,6724,6725],{},"Required children/child",[3141,6727,6718],{},[3141,6729,6718],{},[3123,6731,6732,6735,6737],{},[3141,6733,6734],{},"Valid durations",[3141,6736,6718],{},[3141,6738,6718],{},[3123,6740,6741,6744,6746],{},[3141,6742,6743],{},"Positive numbers",[3141,6745,6718],{},[3141,6747,6718],{},[3123,6749,6750,6753,6756],{},[3141,6751,6752],{},"Processor refs exist",[3141,6754,6755],{},"No",[3141,6757,6718],{},[3123,6759,6760,6763,6765],{},[3141,6761,6762],{},"Predicate refs exist",[3141,6764,6755],{},[3141,6766,6718],{},[3123,6768,6769,6772,6774],{},[3141,6770,6771],{},"Condition refs exist",[3141,6773,6755],{},[3141,6775,6718],{},[3123,6777,6778,6781,6783],{},[3141,6779,6780],{},"Channel refs exist",[3141,6782,6755],{},[3141,6784,6718],{},[3123,6786,6787,6790,6792],{},[3141,6788,6789],{},"Circular references",[3141,6791,6755],{},[3141,6793,6718],{},[1891,6795,3953,6796,6798,6799,6801],{},[1979,6797,1349],{}," in CI to catch syntax errors early, then ",[1979,6800,1344],{}," at runtime with a configured factory to catch reference errors.",[1968,6803,928],{"id":6804},"integration-testing",[1891,6806,6807],{},"Test complete pipelines with realistic scenarios:",[1973,6809,6811],{"className":1975,"code":6810,"language":1977,"meta":24,"style":24},"func TestOrderPipeline(t *testing.T) {\n    factory := setupProductionFactory()\n\n    schema := `\ntype: sequence\nchildren:\n  - ref: validate\n  - type: filter\n    predicate: high-value\n    then:\n      ref: premium-handler\n  - ref: finalize`\n\n    pipeline, err := factory.BuildFromYAML(schema)\n    if err != nil {\n        t.Fatalf(\"failed to build: %v\", err)\n    }\n\n    tests := []struct {\n        name  string\n        order Order\n        want  Order\n    }{\n        {\n            name:  \"standard order unchanged\",\n            order: Order{Total: 50},\n            want:  Order{Total: 50, Status: \"finalized\"},\n        },\n        {\n            name:  \"high value gets premium treatment\",\n            order: Order{Total: 1000},\n            want:  Order{Total: 1000, Discount: 0.1, Status: \"finalized\"},\n        },\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            result, err := pipeline.Process(context.Background(), tt.order)\n            if err != nil {\n                t.Fatalf(\"unexpected error: %v\", err)\n            }\n            if result != tt.want {\n                t.Errorf(\"got %+v, want %+v\", result, tt.want)\n            }\n        })\n    }\n}\n",[1979,6812,6813,6836,6847,6851,6860,6864,6868,6872,6876,6881,6885,6890,6895,6899,6921,6933,6956,6960,6964,6976,6983,6991,6998,7002,7006,7017,7037,7067,7071,7075,7086,7105,7141,7145,7149,7153,7171,7207,7243,7255,7278,7282,7298,7333,7337,7341,7345],{"__ignoreMap":24},[1982,6814,6815,6817,6820,6822,6824,6826,6828,6830,6832,6834],{"class":1984,"line":9},[1982,6816,2607],{"class":2052},[1982,6818,6819],{"class":2007}," TestOrderPipeline",[1982,6821,2042],{"class":2003},[1982,6823,4791],{"class":2058},[1982,6825,4794],{"class":2099},[1982,6827,4240],{"class":2013},[1982,6829,2004],{"class":2003},[1982,6831,4801],{"class":2013},[1982,6833,2078],{"class":2003},[1982,6835,2093],{"class":2003},[1982,6837,6838,6840,6842,6845],{"class":1984,"line":19},[1982,6839,2683],{"class":1993},[1982,6841,1997],{"class":1993},[1982,6843,6844],{"class":2007}," setupProductionFactory",[1982,6846,5565],{"class":2003},[1982,6848,6849],{"class":1984,"line":30},[1982,6850,2361],{"emptyLinePlaceholder":2360},[1982,6852,6853,6856,6858],{"class":1984,"line":2031},[1982,6854,6855],{"class":1993},"    schema",[1982,6857,1997],{"class":1993},[1982,6859,5631],{"class":2045},[1982,6861,6862],{"class":1984,"line":2096},[1982,6863,2398],{"class":2045},[1982,6865,6866],{"class":1984,"line":2119},[1982,6867,2404],{"class":2045},[1982,6869,6870],{"class":1984,"line":2145},[1982,6871,2410],{"class":2045},[1982,6873,6874],{"class":1984,"line":2151},[1982,6875,2416],{"class":2045},[1982,6877,6878],{"class":1984,"line":2164},[1982,6879,6880],{"class":2045},"    predicate: high-value\n",[1982,6882,6883],{"class":1984,"line":2170},[1982,6884,2428],{"class":2045},[1982,6886,6887],{"class":1984,"line":2218},[1982,6888,6889],{"class":2045},"      ref: premium-handler\n",[1982,6891,6892],{"class":1984,"line":2237},[1982,6893,6894],{"class":2045},"  - ref: finalize`\n",[1982,6896,6897],{"class":1984,"line":2248},[1982,6898,2361],{"emptyLinePlaceholder":2360},[1982,6900,6901,6903,6905,6907,6909,6911,6913,6915,6917,6919],{"class":1984,"line":2253},[1982,6902,2919],{"class":1993},[1982,6904,2049],{"class":2003},[1982,6906,2464],{"class":1993},[1982,6908,1997],{"class":1993},[1982,6910,2383],{"class":1993},[1982,6912,2004],{"class":2003},[1982,6914,1272],{"class":2007},[1982,6916,2042],{"class":2003},[1982,6918,5863],{"class":1993},[1982,6920,2142],{"class":2003},[1982,6922,6923,6925,6927,6929,6931],{"class":1984,"line":2258},[1982,6924,2969],{"class":2099},[1982,6926,2464],{"class":1993},[1982,6928,2974],{"class":2099},[1982,6930,2977],{"class":2052},[1982,6932,2093],{"class":2003},[1982,6934,6935,6937,6939,6941,6943,6946,6948,6950,6952,6954],{"class":1984,"line":2282},[1982,6936,5067],{"class":1993},[1982,6938,2004],{"class":2003},[1982,6940,6380],{"class":2007},[1982,6942,2042],{"class":2003},[1982,6944,6945],{"class":2045},"\"failed to build: ",[1982,6947,3089],{"class":3082},[1982,6949,3096],{"class":2045},[1982,6951,2049],{"class":2003},[1982,6953,2464],{"class":1993},[1982,6955,2142],{"class":2003},[1982,6957,6958],{"class":1984,"line":2298},[1982,6959,2999],{"class":2003},[1982,6961,6962],{"class":1984,"line":2351},[1982,6963,2361],{"emptyLinePlaceholder":2360},[1982,6965,6966,6968,6970,6972,6974],{"class":1984,"line":2357},[1982,6967,4839],{"class":1993},[1982,6969,1997],{"class":1993},[1982,6971,4844],{"class":2003},[1982,6973,4847],{"class":2052},[1982,6975,2093],{"class":2003},[1982,6977,6978,6980],{"class":1984,"line":2364},[1982,6979,4854],{"class":2285},[1982,6981,6982],{"class":2013},"  string\n",[1982,6984,6985,6988],{"class":1984,"line":2370},[1982,6986,6987],{"class":2285},"        order",[1982,6989,6990],{"class":2013}," Order\n",[1982,6992,6993,6995],{"class":1984,"line":2395},[1982,6994,5329],{"class":2285},[1982,6996,6997],{"class":2013},"  Order\n",[1982,6999,7000],{"class":1984,"line":2401},[1982,7001,4877],{"class":2003},[1982,7003,7004],{"class":1984,"line":2407},[1982,7005,4882],{"class":2003},[1982,7007,7008,7010,7012,7015],{"class":1984,"line":2413},[1982,7009,4887],{"class":2285},[1982,7011,2289],{"class":2003},[1982,7013,7014],{"class":2045},"  \"standard order unchanged\"",[1982,7016,2295],{"class":2003},[1982,7018,7019,7022,7024,7026,7028,7030,7032,7035],{"class":1984,"line":2419},[1982,7020,7021],{"class":2285},"            order",[1982,7023,2289],{"class":2003},[1982,7025,2075],{"class":2013},[1982,7027,2633],{"class":2003},[1982,7029,2107],{"class":2285},[1982,7031,2289],{"class":2003},[1982,7033,7034],{"class":2113}," 50",[1982,7036,4916],{"class":2003},[1982,7038,7039,7042,7044,7047,7049,7051,7053,7055,7057,7060,7062,7065],{"class":1984,"line":2425},[1982,7040,7041],{"class":2285},"            want",[1982,7043,2289],{"class":2003},[1982,7045,7046],{"class":2013},"  Order",[1982,7048,2633],{"class":2003},[1982,7050,2107],{"class":2285},[1982,7052,2289],{"class":2003},[1982,7054,7034],{"class":2113},[1982,7056,2049],{"class":2003},[1982,7058,7059],{"class":2285}," Status",[1982,7061,2289],{"class":2003},[1982,7063,7064],{"class":2045}," \"finalized\"",[1982,7066,4916],{"class":2003},[1982,7068,7069],{"class":1984,"line":2431},[1982,7070,4933],{"class":2003},[1982,7072,7073],{"class":1984,"line":2437},[1982,7074,4882],{"class":2003},[1982,7076,7077,7079,7081,7084],{"class":1984,"line":2445},[1982,7078,4887],{"class":2285},[1982,7080,2289],{"class":2003},[1982,7082,7083],{"class":2045},"  \"high value gets premium treatment\"",[1982,7085,2295],{"class":2003},[1982,7087,7088,7090,7092,7094,7096,7098,7100,7103],{"class":1984,"line":2450},[1982,7089,7021],{"class":2285},[1982,7091,2289],{"class":2003},[1982,7093,2075],{"class":2013},[1982,7095,2633],{"class":2003},[1982,7097,2107],{"class":2285},[1982,7099,2289],{"class":2003},[1982,7101,7102],{"class":2113}," 1000",[1982,7104,4916],{"class":2003},[1982,7106,7107,7109,7111,7113,7115,7117,7119,7121,7123,7126,7128,7131,7133,7135,7137,7139],{"class":1984,"line":2456},[1982,7108,7041],{"class":2285},[1982,7110,2289],{"class":2003},[1982,7112,7046],{"class":2013},[1982,7114,2633],{"class":2003},[1982,7116,2107],{"class":2285},[1982,7118,2289],{"class":2003},[1982,7120,7102],{"class":2113},[1982,7122,2049],{"class":2003},[1982,7124,7125],{"class":2285}," Discount",[1982,7127,2289],{"class":2003},[1982,7129,7130],{"class":2113}," 0.1",[1982,7132,2049],{"class":2003},[1982,7134,7059],{"class":2285},[1982,7136,2289],{"class":2003},[1982,7138,7064],{"class":2045},[1982,7140,4916],{"class":2003},[1982,7142,7143],{"class":1984,"line":2905},[1982,7144,4933],{"class":2003},[1982,7146,7147],{"class":1984,"line":2910},[1982,7148,2999],{"class":2003},[1982,7150,7151],{"class":1984,"line":2916},[1982,7152,2361],{"emptyLinePlaceholder":2360},[1982,7154,7155,7157,7159,7161,7163,7165,7167,7169],{"class":1984,"line":2938},[1982,7156,5045],{"class":2099},[1982,7158,2378],{"class":1993},[1982,7160,2049],{"class":2003},[1982,7162,5052],{"class":1993},[1982,7164,1997],{"class":1993},[1982,7166,5057],{"class":2099},[1982,7168,5060],{"class":1993},[1982,7170,2093],{"class":2003},[1982,7172,7173,7175,7177,7179,7181,7183,7185,7187,7189,7191,7193,7195,7197,7199,7201,7203,7205],{"class":1984,"line":2943},[1982,7174,5067],{"class":1993},[1982,7176,2004],{"class":2003},[1982,7178,5072],{"class":2007},[1982,7180,2042],{"class":2003},[1982,7182,5077],{"class":1993},[1982,7184,2004],{"class":2003},[1982,7186,5082],{"class":1993},[1982,7188,2049],{"class":2003},[1982,7190,2053],{"class":2052},[1982,7192,2042],{"class":2003},[1982,7194,4791],{"class":2058},[1982,7196,4794],{"class":2099},[1982,7198,4240],{"class":2013},[1982,7200,2004],{"class":2003},[1982,7202,4801],{"class":2013},[1982,7204,2078],{"class":2003},[1982,7206,2093],{"class":2003},[1982,7208,7209,7212,7214,7216,7218,7220,7222,7224,7226,7228,7230,7232,7234,7236,7238,7241],{"class":1984,"line":2948},[1982,7210,7211],{"class":1993},"            result",[1982,7213,2049],{"class":2003},[1982,7215,2464],{"class":1993},[1982,7217,1997],{"class":1993},[1982,7219,2469],{"class":1993},[1982,7221,2004],{"class":2003},[1982,7223,1326],{"class":2007},[1982,7225,2042],{"class":2003},[1982,7227,3033],{"class":1993},[1982,7229,2004],{"class":2003},[1982,7231,3038],{"class":2007},[1982,7233,3041],{"class":2003},[1982,7235,5052],{"class":1993},[1982,7237,2004],{"class":2003},[1982,7239,7240],{"class":1993},"order",[1982,7242,2142],{"class":2003},[1982,7244,7245,7247,7249,7251,7253],{"class":1984,"line":2953},[1982,7246,2768],{"class":2099},[1982,7248,2464],{"class":1993},[1982,7250,2974],{"class":2099},[1982,7252,2977],{"class":2052},[1982,7254,2093],{"class":2003},[1982,7256,7257,7259,7261,7263,7265,7268,7270,7272,7274,7276],{"class":1984,"line":2959},[1982,7258,5169],{"class":1993},[1982,7260,2004],{"class":2003},[1982,7262,6380],{"class":2007},[1982,7264,2042],{"class":2003},[1982,7266,7267],{"class":2045},"\"unexpected error: ",[1982,7269,3089],{"class":3082},[1982,7271,3096],{"class":2045},[1982,7273,2049],{"class":2003},[1982,7275,2464],{"class":1993},[1982,7277,2142],{"class":2003},[1982,7279,7280],{"class":1984,"line":2966},[1982,7281,2806],{"class":2003},[1982,7283,7284,7286,7288,7290,7292,7294,7296],{"class":1984,"line":2982},[1982,7285,2768],{"class":2099},[1982,7287,3101],{"class":1993},[1982,7289,2974],{"class":2099},[1982,7291,5052],{"class":1993},[1982,7293,2004],{"class":2003},[1982,7295,5454],{"class":1993},[1982,7297,2093],{"class":2003},[1982,7299,7300,7302,7304,7306,7308,7311,7313,7315,7317,7319,7321,7323,7325,7327,7329,7331],{"class":1984,"line":2996},[1982,7301,5169],{"class":1993},[1982,7303,2004],{"class":2003},[1982,7305,2134],{"class":2007},[1982,7307,2042],{"class":2003},[1982,7309,7310],{"class":2045},"\"got ",[1982,7312,3083],{"class":3082},[1982,7314,5481],{"class":2045},[1982,7316,3083],{"class":3082},[1982,7318,3096],{"class":2045},[1982,7320,2049],{"class":2003},[1982,7322,3101],{"class":1993},[1982,7324,2049],{"class":2003},[1982,7326,5052],{"class":1993},[1982,7328,2004],{"class":2003},[1982,7330,5454],{"class":1993},[1982,7332,2142],{"class":2003},[1982,7334,7335],{"class":1984,"line":3002},[1982,7336,2806],{"class":2003},[1982,7338,7339],{"class":1984,"line":3007},[1982,7340,5210],{"class":2003},[1982,7342,7343],{"class":1984,"line":3013},[1982,7344,2999],{"class":2003},[1982,7346,7347],{"class":1984,"line":3066},[1982,7348,2598],{"class":2003},[1968,7350,933],{"id":7351},"testing-error-handling",[3557,7353,937],{"id":7354},"retry-behaviour",[1973,7356,7358],{"className":1975,"code":7357,"language":1977,"meta":24,"style":24},"func TestRetryBehaviour(t *testing.T) {\n    attempts := 0\n    processor := pipz.Apply(\"flaky\", func(_ context.Context, o Order) (Order, error) {\n        attempts++\n        if attempts \u003C 3 {\n            return o, errors.New(\"transient failure\")\n        }\n        return o, nil\n    })\n\n    factory := flume.New[Order]()\n    factory.Add(processor)\n\n    schema := `\ntype: retry\nattempts: 5\nchild:\n  ref: flaky`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success after retries, got: %v\", err)\n    }\n    if attempts != 3 {\n        t.Errorf(\"expected 3 attempts, got %d\", attempts)\n    }\n}\n",[1979,7359,7360,7383,7393,7444,7449,7464,7486,7490,7500,7504,7508,7526,7541,7545,7553,7558,7563,7568,7573,7577,7599,7631,7635,7647,7670,7674,7686,7710,7714],{"__ignoreMap":24},[1982,7361,7362,7364,7367,7369,7371,7373,7375,7377,7379,7381],{"class":1984,"line":9},[1982,7363,2607],{"class":2052},[1982,7365,7366],{"class":2007}," TestRetryBehaviour",[1982,7368,2042],{"class":2003},[1982,7370,4791],{"class":2058},[1982,7372,4794],{"class":2099},[1982,7374,4240],{"class":2013},[1982,7376,2004],{"class":2003},[1982,7378,4801],{"class":2013},[1982,7380,2078],{"class":2003},[1982,7382,2093],{"class":2003},[1982,7384,7385,7388,7390],{"class":1984,"line":19},[1982,7386,7387],{"class":1993},"    attempts",[1982,7389,1997],{"class":1993},[1982,7391,7392],{"class":2113}," 0\n",[1982,7394,7395,7397,7399,7401,7403,7405,7407,7410,7412,7414,7416,7418,7420,7422,7424,7426,7428,7430,7432,7434,7436,7438,7440,7442],{"class":1984,"line":30},[1982,7396,4810],{"class":1993},[1982,7398,1997],{"class":1993},[1982,7400,4815],{"class":1993},[1982,7402,2004],{"class":2003},[1982,7404,2039],{"class":2007},[1982,7406,2042],{"class":2003},[1982,7408,7409],{"class":2045},"\"flaky\"",[1982,7411,2049],{"class":2003},[1982,7413,2053],{"class":2052},[1982,7415,2042],{"class":2003},[1982,7417,6022],{"class":2058},[1982,7419,2062],{"class":2013},[1982,7421,2004],{"class":2003},[1982,7423,2067],{"class":2013},[1982,7425,2049],{"class":2003},[1982,7427,2072],{"class":2058},[1982,7429,2075],{"class":2013},[1982,7431,2078],{"class":2003},[1982,7433,2081],{"class":2003},[1982,7435,2014],{"class":2013},[1982,7437,2049],{"class":2003},[1982,7439,2088],{"class":2013},[1982,7441,2078],{"class":2003},[1982,7443,2093],{"class":2003},[1982,7445,7446],{"class":1984,"line":2031},[1982,7447,7448],{"class":1993},"        attempts++\n",[1982,7450,7451,7453,7456,7459,7462],{"class":1984,"line":2096},[1982,7452,2100],{"class":2099},[1982,7454,7455],{"class":1993}," attempts",[1982,7457,7458],{"class":2099}," \u003C",[1982,7460,7461],{"class":2113}," 3",[1982,7463,2093],{"class":2003},[1982,7465,7466,7468,7470,7472,7475,7477,7479,7481,7484],{"class":1984,"line":2119},[1982,7467,2122],{"class":2099},[1982,7469,2072],{"class":1993},[1982,7471,2049],{"class":2003},[1982,7473,7474],{"class":1993}," errors",[1982,7476,2004],{"class":2003},[1982,7478,1153],{"class":2007},[1982,7480,2042],{"class":2003},[1982,7482,7483],{"class":2045},"\"transient failure\"",[1982,7485,2142],{"class":2003},[1982,7487,7488],{"class":1984,"line":2145},[1982,7489,2148],{"class":2003},[1982,7491,7492,7494,7496,7498],{"class":1984,"line":2151},[1982,7493,2154],{"class":2099},[1982,7495,2072],{"class":1993},[1982,7497,2049],{"class":2003},[1982,7499,2161],{"class":2052},[1982,7501,7502],{"class":1984,"line":2164},[1982,7503,6187],{"class":2003},[1982,7505,7506],{"class":1984,"line":2170},[1982,7507,2361],{"emptyLinePlaceholder":2360},[1982,7509,7510,7512,7514,7516,7518,7520,7522,7524],{"class":1984,"line":2218},[1982,7511,2683],{"class":1993},[1982,7513,1997],{"class":1993},[1982,7515,2000],{"class":1993},[1982,7517,2004],{"class":2003},[1982,7519,1153],{"class":2007},[1982,7521,2010],{"class":2003},[1982,7523,2014],{"class":2013},[1982,7525,2017],{"class":2003},[1982,7527,7528,7530,7532,7534,7536,7539],{"class":1984,"line":2237},[1982,7529,2683],{"class":1993},[1982,7531,2004],{"class":2003},[1982,7533,1162],{"class":2007},[1982,7535,2042],{"class":2003},[1982,7537,7538],{"class":1993},"processor",[1982,7540,2142],{"class":2003},[1982,7542,7543],{"class":1984,"line":2248},[1982,7544,2361],{"emptyLinePlaceholder":2360},[1982,7546,7547,7549,7551],{"class":1984,"line":2253},[1982,7548,6855],{"class":1993},[1982,7550,1997],{"class":1993},[1982,7552,5631],{"class":2045},[1982,7554,7555],{"class":1984,"line":2258},[1982,7556,7557],{"class":2045},"type: retry\n",[1982,7559,7560],{"class":1984,"line":2282},[1982,7561,7562],{"class":2045},"attempts: 5\n",[1982,7564,7565],{"class":1984,"line":2298},[1982,7566,7567],{"class":2045},"child:\n",[1982,7569,7570],{"class":1984,"line":2351},[1982,7571,7572],{"class":2045},"  ref: flaky`\n",[1982,7574,7575],{"class":1984,"line":2357},[1982,7576,2361],{"emptyLinePlaceholder":2360},[1982,7578,7579,7581,7583,7585,7587,7589,7591,7593,7595,7597],{"class":1984,"line":2364},[1982,7580,2919],{"class":1993},[1982,7582,2049],{"class":2003},[1982,7584,2378],{"class":1993},[1982,7586,1997],{"class":1993},[1982,7588,2383],{"class":1993},[1982,7590,2004],{"class":2003},[1982,7592,1272],{"class":2007},[1982,7594,2042],{"class":2003},[1982,7596,5863],{"class":1993},[1982,7598,2142],{"class":2003},[1982,7600,7601,7604,7606,7608,7610,7612,7614,7616,7618,7620,7622,7624,7626,7628],{"class":1984,"line":2370},[1982,7602,7603],{"class":1993},"    _",[1982,7605,2049],{"class":2003},[1982,7607,2464],{"class":1993},[1982,7609,1997],{"class":1993},[1982,7611,2469],{"class":1993},[1982,7613,2004],{"class":2003},[1982,7615,1326],{"class":2007},[1982,7617,2042],{"class":2003},[1982,7619,3033],{"class":1993},[1982,7621,2004],{"class":2003},[1982,7623,3038],{"class":2007},[1982,7625,3041],{"class":2003},[1982,7627,2075],{"class":2013},[1982,7629,7630],{"class":2003},"{})\n",[1982,7632,7633],{"class":1984,"line":2395},[1982,7634,2361],{"emptyLinePlaceholder":2360},[1982,7636,7637,7639,7641,7643,7645],{"class":1984,"line":2401},[1982,7638,2969],{"class":2099},[1982,7640,2464],{"class":1993},[1982,7642,2974],{"class":2099},[1982,7644,2977],{"class":2052},[1982,7646,2093],{"class":2003},[1982,7648,7649,7651,7653,7655,7657,7660,7662,7664,7666,7668],{"class":1984,"line":2407},[1982,7650,5067],{"class":1993},[1982,7652,2004],{"class":2003},[1982,7654,2134],{"class":2007},[1982,7656,2042],{"class":2003},[1982,7658,7659],{"class":2045},"\"expected success after retries, got: ",[1982,7661,3089],{"class":3082},[1982,7663,3096],{"class":2045},[1982,7665,2049],{"class":2003},[1982,7667,2464],{"class":1993},[1982,7669,2142],{"class":2003},[1982,7671,7672],{"class":1984,"line":2413},[1982,7673,2999],{"class":2003},[1982,7675,7676,7678,7680,7682,7684],{"class":1984,"line":2419},[1982,7677,2969],{"class":2099},[1982,7679,7455],{"class":1993},[1982,7681,2974],{"class":2099},[1982,7683,7461],{"class":2113},[1982,7685,2093],{"class":2003},[1982,7687,7688,7690,7692,7694,7696,7699,7702,7704,7706,7708],{"class":1984,"line":2425},[1982,7689,5067],{"class":1993},[1982,7691,2004],{"class":2003},[1982,7693,2134],{"class":2007},[1982,7695,2042],{"class":2003},[1982,7697,7698],{"class":2045},"\"expected 3 attempts, got ",[1982,7700,7701],{"class":3082},"%d",[1982,7703,3096],{"class":2045},[1982,7705,2049],{"class":2003},[1982,7707,7455],{"class":1993},[1982,7709,2142],{"class":2003},[1982,7711,7712],{"class":1984,"line":2431},[1982,7713,2999],{"class":2003},[1982,7715,7716],{"class":1984,"line":2437},[1982,7717,2598],{"class":2003},[3557,7719,942],{"id":7720},"fallback-behaviour",[1973,7722,7724],{"className":1975,"code":7723,"language":1977,"meta":24,"style":24},"func TestFallbackBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(\n        pipz.Apply(\"failing\", func(_ context.Context, o Order) (Order, error) {\n            return o, errors.New(\"primary failed\")\n        }),\n        pipz.Transform(\"backup\", func(_ context.Context, o Order) Order {\n            o.Source = \"backup\"\n            return o\n        }),\n    )\n\n    schema := `\ntype: fallback\nchildren:\n  - ref: failing\n  - ref: backup`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    result, err := pipeline.Process(context.Background(), Order{})\n\n    if err != nil {\n        t.Errorf(\"expected success from fallback: %v\", err)\n    }\n    if result.Source != \"backup\" {\n        t.Error(\"expected fallback to be used\")\n    }\n}\n",[1979,7725,7726,7749,7767,7771,7781,7828,7849,7853,7892,7906,7912,7916,7920,7924,7932,7937,7941,7946,7951,7955,7977,8007,8011,8023,8046,8050,8067,8083,8087],{"__ignoreMap":24},[1982,7727,7728,7730,7733,7735,7737,7739,7741,7743,7745,7747],{"class":1984,"line":9},[1982,7729,2607],{"class":2052},[1982,7731,7732],{"class":2007}," TestFallbackBehaviour",[1982,7734,2042],{"class":2003},[1982,7736,4791],{"class":2058},[1982,7738,4794],{"class":2099},[1982,7740,4240],{"class":2013},[1982,7742,2004],{"class":2003},[1982,7744,4801],{"class":2013},[1982,7746,2078],{"class":2003},[1982,7748,2093],{"class":2003},[1982,7750,7751,7753,7755,7757,7759,7761,7763,7765],{"class":1984,"line":19},[1982,7752,2683],{"class":1993},[1982,7754,1997],{"class":1993},[1982,7756,2000],{"class":1993},[1982,7758,2004],{"class":2003},[1982,7760,1153],{"class":2007},[1982,7762,2010],{"class":2003},[1982,7764,2014],{"class":2013},[1982,7766,2017],{"class":2003},[1982,7768,7769],{"class":1984,"line":30},[1982,7770,2361],{"emptyLinePlaceholder":2360},[1982,7772,7773,7775,7777,7779],{"class":1984,"line":2031},[1982,7774,2683],{"class":1993},[1982,7776,2004],{"class":2003},[1982,7778,1162],{"class":2007},[1982,7780,2028],{"class":2003},[1982,7782,7783,7785,7787,7789,7791,7794,7796,7798,7800,7802,7804,7806,7808,7810,7812,7814,7816,7818,7820,7822,7824,7826],{"class":1984,"line":2096},[1982,7784,2721],{"class":1993},[1982,7786,2004],{"class":2003},[1982,7788,2039],{"class":2007},[1982,7790,2042],{"class":2003},[1982,7792,7793],{"class":2045},"\"failing\"",[1982,7795,2049],{"class":2003},[1982,7797,2053],{"class":2052},[1982,7799,2042],{"class":2003},[1982,7801,6022],{"class":2058},[1982,7803,2062],{"class":2013},[1982,7805,2004],{"class":2003},[1982,7807,2067],{"class":2013},[1982,7809,2049],{"class":2003},[1982,7811,2072],{"class":2058},[1982,7813,2075],{"class":2013},[1982,7815,2078],{"class":2003},[1982,7817,2081],{"class":2003},[1982,7819,2014],{"class":2013},[1982,7821,2049],{"class":2003},[1982,7823,2088],{"class":2013},[1982,7825,2078],{"class":2003},[1982,7827,2093],{"class":2003},[1982,7829,7830,7832,7834,7836,7838,7840,7842,7844,7847],{"class":1984,"line":2119},[1982,7831,2122],{"class":2099},[1982,7833,2072],{"class":1993},[1982,7835,2049],{"class":2003},[1982,7837,7474],{"class":1993},[1982,7839,2004],{"class":2003},[1982,7841,1153],{"class":2007},[1982,7843,2042],{"class":2003},[1982,7845,7846],{"class":2045},"\"primary failed\"",[1982,7848,2142],{"class":2003},[1982,7850,7851],{"class":1984,"line":2145},[1982,7852,2821],{"class":2003},[1982,7854,7855,7857,7859,7861,7863,7866,7868,7870,7872,7874,7876,7878,7880,7882,7884,7886,7888,7890],{"class":1984,"line":2151},[1982,7856,2721],{"class":1993},[1982,7858,2004],{"class":2003},[1982,7860,2830],{"class":2007},[1982,7862,2042],{"class":2003},[1982,7864,7865],{"class":2045},"\"backup\"",[1982,7867,2049],{"class":2003},[1982,7869,2053],{"class":2052},[1982,7871,2042],{"class":2003},[1982,7873,6022],{"class":2058},[1982,7875,2062],{"class":2013},[1982,7877,2004],{"class":2003},[1982,7879,2067],{"class":2013},[1982,7881,2049],{"class":2003},[1982,7883,2072],{"class":2058},[1982,7885,2075],{"class":2013},[1982,7887,2078],{"class":2003},[1982,7889,2075],{"class":2013},[1982,7891,2093],{"class":2003},[1982,7893,7894,7896,7898,7901,7903],{"class":1984,"line":2164},[1982,7895,2866],{"class":1993},[1982,7897,2004],{"class":2003},[1982,7899,7900],{"class":1993},"Source",[1982,7902,2873],{"class":1993},[1982,7904,7905],{"class":2045}," \"backup\"\n",[1982,7907,7908,7910],{"class":1984,"line":2170},[1982,7909,2122],{"class":2099},[1982,7911,2893],{"class":1993},[1982,7913,7914],{"class":1984,"line":2218},[1982,7915,2821],{"class":2003},[1982,7917,7918],{"class":1984,"line":2237},[1982,7919,2902],{"class":2003},[1982,7921,7922],{"class":1984,"line":2248},[1982,7923,2361],{"emptyLinePlaceholder":2360},[1982,7925,7926,7928,7930],{"class":1984,"line":2253},[1982,7927,6855],{"class":1993},[1982,7929,1997],{"class":1993},[1982,7931,5631],{"class":2045},[1982,7933,7934],{"class":1984,"line":2258},[1982,7935,7936],{"class":2045},"type: fallback\n",[1982,7938,7939],{"class":1984,"line":2282},[1982,7940,2404],{"class":2045},[1982,7942,7943],{"class":1984,"line":2298},[1982,7944,7945],{"class":2045},"  - ref: failing\n",[1982,7947,7948],{"class":1984,"line":2351},[1982,7949,7950],{"class":2045},"  - ref: backup`\n",[1982,7952,7953],{"class":1984,"line":2357},[1982,7954,2361],{"emptyLinePlaceholder":2360},[1982,7956,7957,7959,7961,7963,7965,7967,7969,7971,7973,7975],{"class":1984,"line":2364},[1982,7958,2919],{"class":1993},[1982,7960,2049],{"class":2003},[1982,7962,2378],{"class":1993},[1982,7964,1997],{"class":1993},[1982,7966,2383],{"class":1993},[1982,7968,2004],{"class":2003},[1982,7970,1272],{"class":2007},[1982,7972,2042],{"class":2003},[1982,7974,5863],{"class":1993},[1982,7976,2142],{"class":2003},[1982,7978,7979,7981,7983,7985,7987,7989,7991,7993,7995,7997,7999,8001,8003,8005],{"class":1984,"line":2370},[1982,7980,3016],{"class":1993},[1982,7982,2049],{"class":2003},[1982,7984,2464],{"class":1993},[1982,7986,1997],{"class":1993},[1982,7988,2469],{"class":1993},[1982,7990,2004],{"class":2003},[1982,7992,1326],{"class":2007},[1982,7994,2042],{"class":2003},[1982,7996,3033],{"class":1993},[1982,7998,2004],{"class":2003},[1982,8000,3038],{"class":2007},[1982,8002,3041],{"class":2003},[1982,8004,2075],{"class":2013},[1982,8006,7630],{"class":2003},[1982,8008,8009],{"class":1984,"line":2395},[1982,8010,2361],{"emptyLinePlaceholder":2360},[1982,8012,8013,8015,8017,8019,8021],{"class":1984,"line":2401},[1982,8014,2969],{"class":2099},[1982,8016,2464],{"class":1993},[1982,8018,2974],{"class":2099},[1982,8020,2977],{"class":2052},[1982,8022,2093],{"class":2003},[1982,8024,8025,8027,8029,8031,8033,8036,8038,8040,8042,8044],{"class":1984,"line":2407},[1982,8026,5067],{"class":1993},[1982,8028,2004],{"class":2003},[1982,8030,2134],{"class":2007},[1982,8032,2042],{"class":2003},[1982,8034,8035],{"class":2045},"\"expected success from fallback: ",[1982,8037,3089],{"class":3082},[1982,8039,3096],{"class":2045},[1982,8041,2049],{"class":2003},[1982,8043,2464],{"class":1993},[1982,8045,2142],{"class":2003},[1982,8047,8048],{"class":1984,"line":2413},[1982,8049,2999],{"class":2003},[1982,8051,8052,8054,8056,8058,8060,8062,8065],{"class":1984,"line":2419},[1982,8053,2969],{"class":2099},[1982,8055,3101],{"class":1993},[1982,8057,2004],{"class":2003},[1982,8059,7900],{"class":1993},[1982,8061,2974],{"class":2099},[1982,8063,8064],{"class":2045}," \"backup\"",[1982,8066,2093],{"class":2003},[1982,8068,8069,8071,8073,8076,8078,8081],{"class":1984,"line":2425},[1982,8070,5067],{"class":1993},[1982,8072,2004],{"class":2003},[1982,8074,8075],{"class":2007},"Error",[1982,8077,2042],{"class":2003},[1982,8079,8080],{"class":2045},"\"expected fallback to be used\"",[1982,8082,2142],{"class":2003},[1982,8084,8085],{"class":1984,"line":2431},[1982,8086,2999],{"class":2003},[1982,8088,8089],{"class":1984,"line":2437},[1982,8090,2598],{"class":2003},[3557,8092,947],{"id":8093},"timeout-behaviour",[1973,8095,8097],{"className":1975,"code":8096,"language":1977,"meta":24,"style":24},"func TestTimeoutBehaviour(t *testing.T) {\n    factory := flume.New[Order]()\n\n    factory.Add(pipz.Apply(\"slow\", func(ctx context.Context, o Order) (Order, error) {\n        select {\n        case \u003C-time.After(5 * time.Second):\n            return o, nil\n        case \u003C-ctx.Done():\n            return o, ctx.Err()\n        }\n    }))\n\n    schema := `\ntype: timeout\nduration: \"100ms\"\nchild:\n  ref: slow`\n\n    pipeline, _ := factory.BuildFromYAML(schema)\n    _, err := pipeline.Process(context.Background(), Order{})\n\n    if !errors.Is(err, context.DeadlineExceeded) {\n        t.Errorf(\"expected deadline exceeded, got: %v\", err)\n    }\n}\n",[1979,8098,8099,8122,8140,8144,8199,8206,8240,8250,8266,8284,8288,8293,8297,8305,8310,8315,8319,8324,8328,8350,8380,8384,8416,8439,8443],{"__ignoreMap":24},[1982,8100,8101,8103,8106,8108,8110,8112,8114,8116,8118,8120],{"class":1984,"line":9},[1982,8102,2607],{"class":2052},[1982,8104,8105],{"class":2007}," TestTimeoutBehaviour",[1982,8107,2042],{"class":2003},[1982,8109,4791],{"class":2058},[1982,8111,4794],{"class":2099},[1982,8113,4240],{"class":2013},[1982,8115,2004],{"class":2003},[1982,8117,4801],{"class":2013},[1982,8119,2078],{"class":2003},[1982,8121,2093],{"class":2003},[1982,8123,8124,8126,8128,8130,8132,8134,8136,8138],{"class":1984,"line":19},[1982,8125,2683],{"class":1993},[1982,8127,1997],{"class":1993},[1982,8129,2000],{"class":1993},[1982,8131,2004],{"class":2003},[1982,8133,1153],{"class":2007},[1982,8135,2010],{"class":2003},[1982,8137,2014],{"class":2013},[1982,8139,2017],{"class":2003},[1982,8141,8142],{"class":1984,"line":30},[1982,8143,2361],{"emptyLinePlaceholder":2360},[1982,8145,8146,8148,8150,8152,8154,8156,8158,8160,8162,8165,8167,8169,8171,8173,8175,8177,8179,8181,8183,8185,8187,8189,8191,8193,8195,8197],{"class":1984,"line":2031},[1982,8147,2683],{"class":1993},[1982,8149,2004],{"class":2003},[1982,8151,1162],{"class":2007},[1982,8153,2042],{"class":2003},[1982,8155,1965],{"class":1993},[1982,8157,2004],{"class":2003},[1982,8159,2039],{"class":2007},[1982,8161,2042],{"class":2003},[1982,8163,8164],{"class":2045},"\"slow\"",[1982,8166,2049],{"class":2003},[1982,8168,2053],{"class":2052},[1982,8170,2042],{"class":2003},[1982,8172,2059],{"class":2058},[1982,8174,2062],{"class":2013},[1982,8176,2004],{"class":2003},[1982,8178,2067],{"class":2013},[1982,8180,2049],{"class":2003},[1982,8182,2072],{"class":2058},[1982,8184,2075],{"class":2013},[1982,8186,2078],{"class":2003},[1982,8188,2081],{"class":2003},[1982,8190,2014],{"class":2013},[1982,8192,2049],{"class":2003},[1982,8194,2088],{"class":2013},[1982,8196,2078],{"class":2003},[1982,8198,2093],{"class":2003},[1982,8200,8201,8204],{"class":1984,"line":2096},[1982,8202,8203],{"class":2099},"        select",[1982,8205,2093],{"class":2003},[1982,8207,8208,8211,8214,8217,8219,8222,8224,8227,8229,8232,8234,8237],{"class":1984,"line":2119},[1982,8209,8210],{"class":2099},"        case",[1982,8212,8213],{"class":2099}," \u003C-",[1982,8215,8216],{"class":1993},"time",[1982,8218,2004],{"class":2003},[1982,8220,8221],{"class":2007},"After",[1982,8223,2042],{"class":2003},[1982,8225,8226],{"class":2113},"5",[1982,8228,4794],{"class":1993},[1982,8230,8231],{"class":1993}," time",[1982,8233,2004],{"class":2003},[1982,8235,8236],{"class":1993},"Second",[1982,8238,8239],{"class":2003},"):\n",[1982,8241,8242,8244,8246,8248],{"class":1984,"line":2145},[1982,8243,2122],{"class":2099},[1982,8245,2072],{"class":1993},[1982,8247,2049],{"class":2003},[1982,8249,2161],{"class":2052},[1982,8251,8252,8254,8256,8258,8260,8263],{"class":1984,"line":2151},[1982,8253,8210],{"class":2099},[1982,8255,8213],{"class":2099},[1982,8257,2059],{"class":1993},[1982,8259,2004],{"class":2003},[1982,8261,8262],{"class":2007},"Done",[1982,8264,8265],{"class":2003},"():\n",[1982,8267,8268,8270,8272,8274,8277,8279,8282],{"class":1984,"line":2164},[1982,8269,2122],{"class":2099},[1982,8271,2072],{"class":1993},[1982,8273,2049],{"class":2003},[1982,8275,8276],{"class":1993}," ctx",[1982,8278,2004],{"class":2003},[1982,8280,8281],{"class":2007},"Err",[1982,8283,5565],{"class":2003},[1982,8285,8286],{"class":1984,"line":2170},[1982,8287,2148],{"class":2003},[1982,8289,8290],{"class":1984,"line":2218},[1982,8291,8292],{"class":2003},"    }))\n",[1982,8294,8295],{"class":1984,"line":2237},[1982,8296,2361],{"emptyLinePlaceholder":2360},[1982,8298,8299,8301,8303],{"class":1984,"line":2248},[1982,8300,6855],{"class":1993},[1982,8302,1997],{"class":1993},[1982,8304,5631],{"class":2045},[1982,8306,8307],{"class":1984,"line":2253},[1982,8308,8309],{"class":2045},"type: timeout\n",[1982,8311,8312],{"class":1984,"line":2258},[1982,8313,8314],{"class":2045},"duration: \"100ms\"\n",[1982,8316,8317],{"class":1984,"line":2282},[1982,8318,7567],{"class":2045},[1982,8320,8321],{"class":1984,"line":2298},[1982,8322,8323],{"class":2045},"  ref: slow`\n",[1982,8325,8326],{"class":1984,"line":2351},[1982,8327,2361],{"emptyLinePlaceholder":2360},[1982,8329,8330,8332,8334,8336,8338,8340,8342,8344,8346,8348],{"class":1984,"line":2357},[1982,8331,2919],{"class":1993},[1982,8333,2049],{"class":2003},[1982,8335,2378],{"class":1993},[1982,8337,1997],{"class":1993},[1982,8339,2383],{"class":1993},[1982,8341,2004],{"class":2003},[1982,8343,1272],{"class":2007},[1982,8345,2042],{"class":2003},[1982,8347,5863],{"class":1993},[1982,8349,2142],{"class":2003},[1982,8351,8352,8354,8356,8358,8360,8362,8364,8366,8368,8370,8372,8374,8376,8378],{"class":1984,"line":2364},[1982,8353,7603],{"class":1993},[1982,8355,2049],{"class":2003},[1982,8357,2464],{"class":1993},[1982,8359,1997],{"class":1993},[1982,8361,2469],{"class":1993},[1982,8363,2004],{"class":2003},[1982,8365,1326],{"class":2007},[1982,8367,2042],{"class":2003},[1982,8369,3033],{"class":1993},[1982,8371,2004],{"class":2003},[1982,8373,3038],{"class":2007},[1982,8375,3041],{"class":2003},[1982,8377,2075],{"class":2013},[1982,8379,7630],{"class":2003},[1982,8381,8382],{"class":1984,"line":2370},[1982,8383,2361],{"emptyLinePlaceholder":2360},[1982,8385,8386,8388,8391,8394,8396,8399,8401,8403,8405,8407,8409,8412,8414],{"class":1984,"line":2395},[1982,8387,2969],{"class":2099},[1982,8389,8390],{"class":2099}," !",[1982,8392,8393],{"class":1993},"errors",[1982,8395,2004],{"class":2003},[1982,8397,8398],{"class":2007},"Is",[1982,8400,2042],{"class":2003},[1982,8402,2991],{"class":1993},[1982,8404,2049],{"class":2003},[1982,8406,2062],{"class":1993},[1982,8408,2004],{"class":2003},[1982,8410,8411],{"class":1993},"DeadlineExceeded",[1982,8413,2078],{"class":2003},[1982,8415,2093],{"class":2003},[1982,8417,8418,8420,8422,8424,8426,8429,8431,8433,8435,8437],{"class":1984,"line":2401},[1982,8419,5067],{"class":1993},[1982,8421,2004],{"class":2003},[1982,8423,2134],{"class":2007},[1982,8425,2042],{"class":2003},[1982,8427,8428],{"class":2045},"\"expected deadline exceeded, got: ",[1982,8430,3089],{"class":3082},[1982,8432,3096],{"class":2045},[1982,8434,2049],{"class":2003},[1982,8436,2464],{"class":1993},[1982,8438,2142],{"class":2003},[1982,8440,8441],{"class":1984,"line":2407},[1982,8442,2999],{"class":2003},[1982,8444,8445],{"class":1984,"line":2413},[1982,8446,2598],{"class":2003},[1968,8448,952],{"id":8449},"testing-hot-reload",[1973,8451,8453],{"className":1975,"code":8452,"language":1977,"meta":24,"style":24},"func TestHotReload(t *testing.T) {\n    factory := flume.New[Order]()\n    factory.Add(\n        pipz.Transform(\"v1\", func(_ context.Context, o Order) Order {\n            o.Version = \"v1\"\n            return o\n        }),\n        pipz.Transform(\"v2\", func(_ context.Context, o Order) Order {\n            o.Version = \"v2\"\n            return o\n        }),\n    )\n\n    // Set initial schema\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"1.0.0\",\n        Node:    flume.Node{Ref: \"v1\"},\n    })\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"test-pipeline\", \"Test pipeline\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    // Process with v1\n    result, _ := binding.Process(context.Background(), Order{})\n    if result.Version != \"v1\" {\n        t.Error(\"expected v1\")\n    }\n\n    // Update schema - binding auto-syncs\n    factory.SetSchema(\"test\", flume.Schema{\n        Version: \"2.0.0\",\n        Node:    flume.Node{Ref: \"v2\"},\n    })\n\n    // Process with v2\n    result, _ = binding.Process(context.Background(), Order{})\n    if result.Version != \"v2\" {\n        t.Error(\"expected v2\")\n    }\n}\n",[1979,8454,8455,8478,8496,8506,8545,8558,8564,8568,8607,8620,8626,8630,8634,8638,8643,8667,8679,8705,8709,8713,8718,8744,8780,8784,8789,8819,8835,8850,8854,8858,8863,8885,8896,8919,8923,8927,8932,8962,8978,8993,8997],{"__ignoreMap":24},[1982,8456,8457,8459,8462,8464,8466,8468,8470,8472,8474,8476],{"class":1984,"line":9},[1982,8458,2607],{"class":2052},[1982,8460,8461],{"class":2007}," TestHotReload",[1982,8463,2042],{"class":2003},[1982,8465,4791],{"class":2058},[1982,8467,4794],{"class":2099},[1982,8469,4240],{"class":2013},[1982,8471,2004],{"class":2003},[1982,8473,4801],{"class":2013},[1982,8475,2078],{"class":2003},[1982,8477,2093],{"class":2003},[1982,8479,8480,8482,8484,8486,8488,8490,8492,8494],{"class":1984,"line":19},[1982,8481,2683],{"class":1993},[1982,8483,1997],{"class":1993},[1982,8485,2000],{"class":1993},[1982,8487,2004],{"class":2003},[1982,8489,1153],{"class":2007},[1982,8491,2010],{"class":2003},[1982,8493,2014],{"class":2013},[1982,8495,2017],{"class":2003},[1982,8497,8498,8500,8502,8504],{"class":1984,"line":30},[1982,8499,2683],{"class":1993},[1982,8501,2004],{"class":2003},[1982,8503,1162],{"class":2007},[1982,8505,2028],{"class":2003},[1982,8507,8508,8510,8512,8514,8516,8519,8521,8523,8525,8527,8529,8531,8533,8535,8537,8539,8541,8543],{"class":1984,"line":2031},[1982,8509,2721],{"class":1993},[1982,8511,2004],{"class":2003},[1982,8513,2830],{"class":2007},[1982,8515,2042],{"class":2003},[1982,8517,8518],{"class":2045},"\"v1\"",[1982,8520,2049],{"class":2003},[1982,8522,2053],{"class":2052},[1982,8524,2042],{"class":2003},[1982,8526,6022],{"class":2058},[1982,8528,2062],{"class":2013},[1982,8530,2004],{"class":2003},[1982,8532,2067],{"class":2013},[1982,8534,2049],{"class":2003},[1982,8536,2072],{"class":2058},[1982,8538,2075],{"class":2013},[1982,8540,2078],{"class":2003},[1982,8542,2075],{"class":2013},[1982,8544,2093],{"class":2003},[1982,8546,8547,8549,8551,8553,8555],{"class":1984,"line":2096},[1982,8548,2866],{"class":1993},[1982,8550,2004],{"class":2003},[1982,8552,3728],{"class":1993},[1982,8554,2873],{"class":1993},[1982,8556,8557],{"class":2045}," \"v1\"\n",[1982,8559,8560,8562],{"class":1984,"line":2119},[1982,8561,2122],{"class":2099},[1982,8563,2893],{"class":1993},[1982,8565,8566],{"class":1984,"line":2145},[1982,8567,2821],{"class":2003},[1982,8569,8570,8572,8574,8576,8578,8581,8583,8585,8587,8589,8591,8593,8595,8597,8599,8601,8603,8605],{"class":1984,"line":2151},[1982,8571,2721],{"class":1993},[1982,8573,2004],{"class":2003},[1982,8575,2830],{"class":2007},[1982,8577,2042],{"class":2003},[1982,8579,8580],{"class":2045},"\"v2\"",[1982,8582,2049],{"class":2003},[1982,8584,2053],{"class":2052},[1982,8586,2042],{"class":2003},[1982,8588,6022],{"class":2058},[1982,8590,2062],{"class":2013},[1982,8592,2004],{"class":2003},[1982,8594,2067],{"class":2013},[1982,8596,2049],{"class":2003},[1982,8598,2072],{"class":2058},[1982,8600,2075],{"class":2013},[1982,8602,2078],{"class":2003},[1982,8604,2075],{"class":2013},[1982,8606,2093],{"class":2003},[1982,8608,8609,8611,8613,8615,8617],{"class":1984,"line":2164},[1982,8610,2866],{"class":1993},[1982,8612,2004],{"class":2003},[1982,8614,3728],{"class":1993},[1982,8616,2873],{"class":1993},[1982,8618,8619],{"class":2045}," \"v2\"\n",[1982,8621,8622,8624],{"class":1984,"line":2170},[1982,8623,2122],{"class":2099},[1982,8625,2893],{"class":1993},[1982,8627,8628],{"class":1984,"line":2218},[1982,8629,2821],{"class":2003},[1982,8631,8632],{"class":1984,"line":2237},[1982,8633,2902],{"class":2003},[1982,8635,8636],{"class":1984,"line":2248},[1982,8637,2361],{"emptyLinePlaceholder":2360},[1982,8639,8640],{"class":1984,"line":2253},[1982,8641,8642],{"class":1987},"    // Set initial schema\n",[1982,8644,8645,8647,8649,8651,8653,8656,8658,8660,8662,8664],{"class":1984,"line":2258},[1982,8646,2683],{"class":1993},[1982,8648,2004],{"class":2003},[1982,8650,1291],{"class":2007},[1982,8652,2042],{"class":2003},[1982,8654,8655],{"class":2045},"\"test\"",[1982,8657,2049],{"class":2003},[1982,8659,2000],{"class":2013},[1982,8661,2004],{"class":2003},[1982,8663,1358],{"class":2013},[1982,8665,8666],{"class":2003},"{\n",[1982,8668,8669,8672,8674,8677],{"class":1984,"line":2282},[1982,8670,8671],{"class":2285},"        Version",[1982,8673,2289],{"class":2003},[1982,8675,8676],{"class":2045}," \"1.0.0\"",[1982,8678,2295],{"class":2003},[1982,8680,8681,8684,8686,8689,8691,8693,8695,8698,8700,8703],{"class":1984,"line":2298},[1982,8682,8683],{"class":2285},"        Node",[1982,8685,2289],{"class":2003},[1982,8687,8688],{"class":2013},"    flume",[1982,8690,2004],{"class":2003},[1982,8692,1363],{"class":2013},[1982,8694,2633],{"class":2003},[1982,8696,8697],{"class":2285},"Ref",[1982,8699,2289],{"class":2003},[1982,8701,8702],{"class":2045}," \"v1\"",[1982,8704,4916],{"class":2003},[1982,8706,8707],{"class":1984,"line":2351},[1982,8708,6187],{"class":2003},[1982,8710,8711],{"class":1984,"line":2357},[1982,8712,2361],{"emptyLinePlaceholder":2360},[1982,8714,8715],{"class":1984,"line":2364},[1982,8716,8717],{"class":1987},"    // Create binding with auto-sync\n",[1982,8719,8720,8723,8725,8727,8729,8732,8734,8737,8739,8742],{"class":1984,"line":2370},[1982,8721,8722],{"class":1993},"    pipelineID",[1982,8724,1997],{"class":1993},[1982,8726,2383],{"class":1993},[1982,8728,2004],{"class":2003},[1982,8730,8731],{"class":2007},"Identity",[1982,8733,2042],{"class":2003},[1982,8735,8736],{"class":2045},"\"test-pipeline\"",[1982,8738,2049],{"class":2003},[1982,8740,8741],{"class":2045}," \"Test pipeline\"",[1982,8743,2142],{"class":2003},[1982,8745,8746,8749,8751,8753,8755,8757,8759,8761,8763,8765,8767,8770,8772,8774,8776,8778],{"class":1984,"line":2395},[1982,8747,8748],{"class":1993},"    binding",[1982,8750,2049],{"class":2003},[1982,8752,2378],{"class":1993},[1982,8754,1997],{"class":1993},[1982,8756,2383],{"class":1993},[1982,8758,2004],{"class":2003},[1982,8760,1311],{"class":2007},[1982,8762,2042],{"class":2003},[1982,8764,3465],{"class":1993},[1982,8766,2049],{"class":2003},[1982,8768,8769],{"class":2045}," \"test\"",[1982,8771,2049],{"class":2003},[1982,8773,2000],{"class":1993},[1982,8775,2004],{"class":2003},[1982,8777,1331],{"class":2007},[1982,8779,3481],{"class":2003},[1982,8781,8782],{"class":1984,"line":2401},[1982,8783,2361],{"emptyLinePlaceholder":2360},[1982,8785,8786],{"class":1984,"line":2407},[1982,8787,8788],{"class":1987},"    // Process with v1\n",[1982,8790,8791,8793,8795,8797,8799,8801,8803,8805,8807,8809,8811,8813,8815,8817],{"class":1984,"line":2413},[1982,8792,3016],{"class":1993},[1982,8794,2049],{"class":2003},[1982,8796,2378],{"class":1993},[1982,8798,1997],{"class":1993},[1982,8800,3503],{"class":1993},[1982,8802,2004],{"class":2003},[1982,8804,1326],{"class":2007},[1982,8806,2042],{"class":2003},[1982,8808,3033],{"class":1993},[1982,8810,2004],{"class":2003},[1982,8812,3038],{"class":2007},[1982,8814,3041],{"class":2003},[1982,8816,2075],{"class":2013},[1982,8818,7630],{"class":2003},[1982,8820,8821,8823,8825,8827,8829,8831,8833],{"class":1984,"line":2419},[1982,8822,2969],{"class":2099},[1982,8824,3101],{"class":1993},[1982,8826,2004],{"class":2003},[1982,8828,3728],{"class":1993},[1982,8830,2974],{"class":2099},[1982,8832,8702],{"class":2045},[1982,8834,2093],{"class":2003},[1982,8836,8837,8839,8841,8843,8845,8848],{"class":1984,"line":2425},[1982,8838,5067],{"class":1993},[1982,8840,2004],{"class":2003},[1982,8842,8075],{"class":2007},[1982,8844,2042],{"class":2003},[1982,8846,8847],{"class":2045},"\"expected v1\"",[1982,8849,2142],{"class":2003},[1982,8851,8852],{"class":1984,"line":2431},[1982,8853,2999],{"class":2003},[1982,8855,8856],{"class":1984,"line":2437},[1982,8857,2361],{"emptyLinePlaceholder":2360},[1982,8859,8860],{"class":1984,"line":2445},[1982,8861,8862],{"class":1987},"    // Update schema - binding auto-syncs\n",[1982,8864,8865,8867,8869,8871,8873,8875,8877,8879,8881,8883],{"class":1984,"line":2450},[1982,8866,2683],{"class":1993},[1982,8868,2004],{"class":2003},[1982,8870,1291],{"class":2007},[1982,8872,2042],{"class":2003},[1982,8874,8655],{"class":2045},[1982,8876,2049],{"class":2003},[1982,8878,2000],{"class":2013},[1982,8880,2004],{"class":2003},[1982,8882,1358],{"class":2013},[1982,8884,8666],{"class":2003},[1982,8886,8887,8889,8891,8894],{"class":1984,"line":2456},[1982,8888,8671],{"class":2285},[1982,8890,2289],{"class":2003},[1982,8892,8893],{"class":2045}," \"2.0.0\"",[1982,8895,2295],{"class":2003},[1982,8897,8898,8900,8902,8904,8906,8908,8910,8912,8914,8917],{"class":1984,"line":2905},[1982,8899,8683],{"class":2285},[1982,8901,2289],{"class":2003},[1982,8903,8688],{"class":2013},[1982,8905,2004],{"class":2003},[1982,8907,1363],{"class":2013},[1982,8909,2633],{"class":2003},[1982,8911,8697],{"class":2285},[1982,8913,2289],{"class":2003},[1982,8915,8916],{"class":2045}," \"v2\"",[1982,8918,4916],{"class":2003},[1982,8920,8921],{"class":1984,"line":2910},[1982,8922,6187],{"class":2003},[1982,8924,8925],{"class":1984,"line":2916},[1982,8926,2361],{"emptyLinePlaceholder":2360},[1982,8928,8929],{"class":1984,"line":2938},[1982,8930,8931],{"class":1987},"    // Process with v2\n",[1982,8933,8934,8936,8938,8940,8942,8944,8946,8948,8950,8952,8954,8956,8958,8960],{"class":1984,"line":2943},[1982,8935,3016],{"class":1993},[1982,8937,2049],{"class":2003},[1982,8939,2378],{"class":1993},[1982,8941,2873],{"class":1993},[1982,8943,3503],{"class":1993},[1982,8945,2004],{"class":2003},[1982,8947,1326],{"class":2007},[1982,8949,2042],{"class":2003},[1982,8951,3033],{"class":1993},[1982,8953,2004],{"class":2003},[1982,8955,3038],{"class":2007},[1982,8957,3041],{"class":2003},[1982,8959,2075],{"class":2013},[1982,8961,7630],{"class":2003},[1982,8963,8964,8966,8968,8970,8972,8974,8976],{"class":1984,"line":2948},[1982,8965,2969],{"class":2099},[1982,8967,3101],{"class":1993},[1982,8969,2004],{"class":2003},[1982,8971,3728],{"class":1993},[1982,8973,2974],{"class":2099},[1982,8975,8916],{"class":2045},[1982,8977,2093],{"class":2003},[1982,8979,8980,8982,8984,8986,8988,8991],{"class":1984,"line":2953},[1982,8981,5067],{"class":1993},[1982,8983,2004],{"class":2003},[1982,8985,8075],{"class":2007},[1982,8987,2042],{"class":2003},[1982,8989,8990],{"class":2045},"\"expected v2\"",[1982,8992,2142],{"class":2003},[1982,8994,8995],{"class":1984,"line":2959},[1982,8996,2999],{"class":2003},[1982,8998,8999],{"class":1984,"line":2966},[1982,9000,2598],{"class":2003},[1968,9002,957],{"id":9003},"concurrent-testing",[1973,9005,9007],{"className":1975,"code":9006,"language":1977,"meta":24,"style":24},"func TestConcurrentPipelineAccess(t *testing.T) {\n    factory := setupFactory()\n    factory.SetSchema(\"test\", testSchema)\n\n    // Create binding with auto-sync\n    pipelineID := factory.Identity(\"concurrent-pipeline\", \"Concurrent test\")\n    binding, _ := factory.Bind(pipelineID, \"test\", flume.WithAutoSync())\n\n    var wg sync.WaitGroup\n    errors := make(chan error, 100)\n\n    for i := 0; i \u003C 100; i++ {\n        wg.Add(1)\n        go func(id int) {\n            defer wg.Done()\n            _, err := binding.Process(context.Background(), Order{ID: fmt.Sprint(id)})\n            if err != nil {\n                errors \u003C- err\n            }\n        }(i)\n    }\n\n    wg.Wait()\n    close(errors)\n\n    for err := range errors {\n        t.Error(err)\n    }\n}\n",[1979,9008,9009,9032,9042,9061,9065,9069,9093,9127,9131,9147,9170,9174,9201,9217,9236,9249,9297,9309,9319,9323,9333,9337,9341,9353,9364,9368,9382,9396,9400],{"__ignoreMap":24},[1982,9010,9011,9013,9016,9018,9020,9022,9024,9026,9028,9030],{"class":1984,"line":9},[1982,9012,2607],{"class":2052},[1982,9014,9015],{"class":2007}," TestConcurrentPipelineAccess",[1982,9017,2042],{"class":2003},[1982,9019,4791],{"class":2058},[1982,9021,4794],{"class":2099},[1982,9023,4240],{"class":2013},[1982,9025,2004],{"class":2003},[1982,9027,4801],{"class":2013},[1982,9029,2078],{"class":2003},[1982,9031,2093],{"class":2003},[1982,9033,9034,9036,9038,9040],{"class":1984,"line":19},[1982,9035,2683],{"class":1993},[1982,9037,1997],{"class":1993},[1982,9039,5562],{"class":2007},[1982,9041,5565],{"class":2003},[1982,9043,9044,9046,9048,9050,9052,9054,9056,9059],{"class":1984,"line":30},[1982,9045,2683],{"class":1993},[1982,9047,2004],{"class":2003},[1982,9049,1291],{"class":2007},[1982,9051,2042],{"class":2003},[1982,9053,8655],{"class":2045},[1982,9055,2049],{"class":2003},[1982,9057,9058],{"class":1993}," testSchema",[1982,9060,2142],{"class":2003},[1982,9062,9063],{"class":1984,"line":2031},[1982,9064,2361],{"emptyLinePlaceholder":2360},[1982,9066,9067],{"class":1984,"line":2096},[1982,9068,8717],{"class":1987},[1982,9070,9071,9073,9075,9077,9079,9081,9083,9086,9088,9091],{"class":1984,"line":2119},[1982,9072,8722],{"class":1993},[1982,9074,1997],{"class":1993},[1982,9076,2383],{"class":1993},[1982,9078,2004],{"class":2003},[1982,9080,8731],{"class":2007},[1982,9082,2042],{"class":2003},[1982,9084,9085],{"class":2045},"\"concurrent-pipeline\"",[1982,9087,2049],{"class":2003},[1982,9089,9090],{"class":2045}," \"Concurrent test\"",[1982,9092,2142],{"class":2003},[1982,9094,9095,9097,9099,9101,9103,9105,9107,9109,9111,9113,9115,9117,9119,9121,9123,9125],{"class":1984,"line":2145},[1982,9096,8748],{"class":1993},[1982,9098,2049],{"class":2003},[1982,9100,2378],{"class":1993},[1982,9102,1997],{"class":1993},[1982,9104,2383],{"class":1993},[1982,9106,2004],{"class":2003},[1982,9108,1311],{"class":2007},[1982,9110,2042],{"class":2003},[1982,9112,3465],{"class":1993},[1982,9114,2049],{"class":2003},[1982,9116,8769],{"class":2045},[1982,9118,2049],{"class":2003},[1982,9120,2000],{"class":1993},[1982,9122,2004],{"class":2003},[1982,9124,1331],{"class":2007},[1982,9126,3481],{"class":2003},[1982,9128,9129],{"class":1984,"line":2151},[1982,9130,2361],{"emptyLinePlaceholder":2360},[1982,9132,9133,9136,9139,9142,9144],{"class":1984,"line":2164},[1982,9134,9135],{"class":2052},"    var",[1982,9137,9138],{"class":1993}," wg",[1982,9140,9141],{"class":2013}," sync",[1982,9143,2004],{"class":2003},[1982,9145,9146],{"class":2013},"WaitGroup\n",[1982,9148,9149,9152,9154,9157,9159,9162,9164,9166,9168],{"class":1984,"line":2170},[1982,9150,9151],{"class":1993},"    errors",[1982,9153,1997],{"class":1993},[1982,9155,9156],{"class":2985}," make",[1982,9158,2042],{"class":2003},[1982,9160,9161],{"class":2052},"chan",[1982,9163,2088],{"class":2013},[1982,9165,2049],{"class":2003},[1982,9167,4913],{"class":2113},[1982,9169,2142],{"class":2003},[1982,9171,9172],{"class":1984,"line":2218},[1982,9173,2361],{"emptyLinePlaceholder":2360},[1982,9175,9176,9178,9181,9183,9185,9188,9190,9192,9194,9196,9199],{"class":1984,"line":2237},[1982,9177,5045],{"class":2099},[1982,9179,9180],{"class":1993}," i",[1982,9182,1997],{"class":1993},[1982,9184,2114],{"class":2113},[1982,9186,9187],{"class":2003},";",[1982,9189,9180],{"class":1993},[1982,9191,7458],{"class":2099},[1982,9193,4913],{"class":2113},[1982,9195,9187],{"class":2003},[1982,9197,9198],{"class":1993}," i++",[1982,9200,2093],{"class":2003},[1982,9202,9203,9206,9208,9210,9212,9215],{"class":1984,"line":2248},[1982,9204,9205],{"class":1993},"        wg",[1982,9207,2004],{"class":2003},[1982,9209,1162],{"class":2007},[1982,9211,2042],{"class":2003},[1982,9213,9214],{"class":2113},"1",[1982,9216,2142],{"class":2003},[1982,9218,9219,9222,9224,9226,9229,9232,9234],{"class":1984,"line":2253},[1982,9220,9221],{"class":2099},"        go",[1982,9223,2053],{"class":2052},[1982,9225,2042],{"class":2003},[1982,9227,9228],{"class":2058},"id",[1982,9230,9231],{"class":2013}," int",[1982,9233,2078],{"class":2003},[1982,9235,2093],{"class":2003},[1982,9237,9238,9241,9243,9245,9247],{"class":1984,"line":2258},[1982,9239,9240],{"class":2099},"            defer",[1982,9242,9138],{"class":1993},[1982,9244,2004],{"class":2003},[1982,9246,8262],{"class":2007},[1982,9248,5565],{"class":2003},[1982,9250,9251,9253,9255,9257,9259,9261,9263,9265,9267,9269,9271,9273,9275,9277,9279,9281,9283,9285,9287,9290,9292,9294],{"class":1984,"line":2282},[1982,9252,5107],{"class":1993},[1982,9254,2049],{"class":2003},[1982,9256,2464],{"class":1993},[1982,9258,1997],{"class":1993},[1982,9260,3503],{"class":1993},[1982,9262,2004],{"class":2003},[1982,9264,1326],{"class":2007},[1982,9266,2042],{"class":2003},[1982,9268,3033],{"class":1993},[1982,9270,2004],{"class":2003},[1982,9272,3038],{"class":2007},[1982,9274,3041],{"class":2003},[1982,9276,2075],{"class":2013},[1982,9278,2633],{"class":2003},[1982,9280,2636],{"class":2285},[1982,9282,2289],{"class":2003},[1982,9284,2129],{"class":1993},[1982,9286,2004],{"class":2003},[1982,9288,9289],{"class":2007},"Sprint",[1982,9291,2042],{"class":2003},[1982,9293,9228],{"class":1993},[1982,9295,9296],{"class":2003},")})\n",[1982,9298,9299,9301,9303,9305,9307],{"class":1984,"line":2298},[1982,9300,2768],{"class":2099},[1982,9302,2464],{"class":1993},[1982,9304,2974],{"class":2099},[1982,9306,2977],{"class":2052},[1982,9308,2093],{"class":2003},[1982,9310,9311,9314,9316],{"class":1984,"line":2351},[1982,9312,9313],{"class":1993},"                errors",[1982,9315,8213],{"class":2099},[1982,9317,9318],{"class":1993}," err\n",[1982,9320,9321],{"class":1984,"line":2357},[1982,9322,2806],{"class":2003},[1982,9324,9325,9328,9331],{"class":1984,"line":2364},[1982,9326,9327],{"class":2003},"        }(",[1982,9329,9330],{"class":1993},"i",[1982,9332,2142],{"class":2003},[1982,9334,9335],{"class":1984,"line":2370},[1982,9336,2999],{"class":2003},[1982,9338,9339],{"class":1984,"line":2395},[1982,9340,2361],{"emptyLinePlaceholder":2360},[1982,9342,9343,9346,9348,9351],{"class":1984,"line":2401},[1982,9344,9345],{"class":1993},"    wg",[1982,9347,2004],{"class":2003},[1982,9349,9350],{"class":2007},"Wait",[1982,9352,5565],{"class":2003},[1982,9354,9355,9358,9360,9362],{"class":1984,"line":2407},[1982,9356,9357],{"class":2985},"    close",[1982,9359,2042],{"class":2003},[1982,9361,8393],{"class":1993},[1982,9363,2142],{"class":2003},[1982,9365,9366],{"class":1984,"line":2413},[1982,9367,2361],{"emptyLinePlaceholder":2360},[1982,9369,9370,9372,9374,9376,9378,9380],{"class":1984,"line":2419},[1982,9371,5045],{"class":2099},[1982,9373,2464],{"class":1993},[1982,9375,1997],{"class":1993},[1982,9377,5057],{"class":2099},[1982,9379,7474],{"class":1993},[1982,9381,2093],{"class":2003},[1982,9383,9384,9386,9388,9390,9392,9394],{"class":1984,"line":2425},[1982,9385,5067],{"class":1993},[1982,9387,2004],{"class":2003},[1982,9389,8075],{"class":2007},[1982,9391,2042],{"class":2003},[1982,9393,2991],{"class":1993},[1982,9395,2142],{"class":2003},[1982,9397,9398],{"class":1984,"line":2431},[1982,9399,2999],{"class":2003},[1982,9401,9402],{"class":1984,"line":2437},[1982,9403,2598],{"class":2003},[1968,9405,962],{"id":9406},"test-helpers",[1891,9408,9409,9410,9413],{},"The ",[1979,9411,9412],{},"flume/testing"," package provides utilities:",[1973,9415,9417],{"className":1975,"code":9416,"language":1977,"meta":24,"style":24},"import flumetesting \"github.com/zoobz-io/flume/testing\"\n\nfunc TestWithHelpers(t *testing.T) {\n    tf := flumetesting.NewTestFactory(t)\n\n    // Register test processors\n    tf.RegisterNoOpProcessors(\"validate\", \"process\", \"finalize\")\n\n    // Build and test\n    pipeline, err := tf.Factory.BuildFromYAML(schema)\n    tf.AssertNoError(err)\n\n    result, err := pipeline.Process(context.Background(), flumetesting.TestData{ID: 1})\n    tf.AssertNoError(err)\n}\n",[1979,9418,9419,9429,9433,9456,9476,9480,9485,9510,9514,9519,9546,9561,9565,9609,9623],{"__ignoreMap":24},[1982,9420,9421,9423,9426],{"class":1984,"line":9},[1982,9422,2533],{"class":2052},[1982,9424,9425],{"class":2058}," flumetesting",[1982,9427,9428],{"class":2045}," \"github.com/zoobz-io/flume/testing\"\n",[1982,9430,9431],{"class":1984,"line":19},[1982,9432,2361],{"emptyLinePlaceholder":2360},[1982,9434,9435,9437,9440,9442,9444,9446,9448,9450,9452,9454],{"class":1984,"line":30},[1982,9436,2607],{"class":2052},[1982,9438,9439],{"class":2007}," TestWithHelpers",[1982,9441,2042],{"class":2003},[1982,9443,4791],{"class":2058},[1982,9445,4794],{"class":2099},[1982,9447,4240],{"class":2013},[1982,9449,2004],{"class":2003},[1982,9451,4801],{"class":2013},[1982,9453,2078],{"class":2003},[1982,9455,2093],{"class":2003},[1982,9457,9458,9461,9463,9465,9467,9470,9472,9474],{"class":1984,"line":2031},[1982,9459,9460],{"class":1993},"    tf",[1982,9462,1997],{"class":1993},[1982,9464,9425],{"class":1993},[1982,9466,2004],{"class":2003},[1982,9468,9469],{"class":2007},"NewTestFactory",[1982,9471,2042],{"class":2003},[1982,9473,4791],{"class":1993},[1982,9475,2142],{"class":2003},[1982,9477,9478],{"class":1984,"line":2096},[1982,9479,2361],{"emptyLinePlaceholder":2360},[1982,9481,9482],{"class":1984,"line":2119},[1982,9483,9484],{"class":1987},"    // Register test processors\n",[1982,9486,9487,9489,9491,9494,9496,9498,9500,9503,9505,9508],{"class":1984,"line":2145},[1982,9488,9460],{"class":1993},[1982,9490,2004],{"class":2003},[1982,9492,9493],{"class":2007},"RegisterNoOpProcessors",[1982,9495,2042],{"class":2003},[1982,9497,2046],{"class":2045},[1982,9499,2049],{"class":2003},[1982,9501,9502],{"class":2045}," \"process\"",[1982,9504,2049],{"class":2003},[1982,9506,9507],{"class":2045}," \"finalize\"",[1982,9509,2142],{"class":2003},[1982,9511,9512],{"class":1984,"line":2151},[1982,9513,2361],{"emptyLinePlaceholder":2360},[1982,9515,9516],{"class":1984,"line":2164},[1982,9517,9518],{"class":1987},"    // Build and test\n",[1982,9520,9521,9523,9525,9527,9529,9532,9534,9536,9538,9540,9542,9544],{"class":1984,"line":2170},[1982,9522,2919],{"class":1993},[1982,9524,2049],{"class":2003},[1982,9526,2464],{"class":1993},[1982,9528,1997],{"class":1993},[1982,9530,9531],{"class":1993}," tf",[1982,9533,2004],{"class":2003},[1982,9535,1149],{"class":1993},[1982,9537,2004],{"class":2003},[1982,9539,1272],{"class":2007},[1982,9541,2042],{"class":2003},[1982,9543,5863],{"class":1993},[1982,9545,2142],{"class":2003},[1982,9547,9548,9550,9552,9555,9557,9559],{"class":1984,"line":2218},[1982,9549,9460],{"class":1993},[1982,9551,2004],{"class":2003},[1982,9553,9554],{"class":2007},"AssertNoError",[1982,9556,2042],{"class":2003},[1982,9558,2991],{"class":1993},[1982,9560,2142],{"class":2003},[1982,9562,9563],{"class":1984,"line":2237},[1982,9564,2361],{"emptyLinePlaceholder":2360},[1982,9566,9567,9569,9571,9573,9575,9577,9579,9581,9583,9585,9587,9589,9591,9593,9595,9598,9600,9602,9604,9607],{"class":1984,"line":2248},[1982,9568,3016],{"class":1993},[1982,9570,2049],{"class":2003},[1982,9572,2464],{"class":1993},[1982,9574,1997],{"class":1993},[1982,9576,2469],{"class":1993},[1982,9578,2004],{"class":2003},[1982,9580,1326],{"class":2007},[1982,9582,2042],{"class":2003},[1982,9584,3033],{"class":1993},[1982,9586,2004],{"class":2003},[1982,9588,3038],{"class":2007},[1982,9590,3041],{"class":2003},[1982,9592,9425],{"class":2013},[1982,9594,2004],{"class":2003},[1982,9596,9597],{"class":2013},"TestData",[1982,9599,2633],{"class":2003},[1982,9601,2636],{"class":2285},[1982,9603,2289],{"class":2003},[1982,9605,9606],{"class":2113}," 1",[1982,9608,2354],{"class":2003},[1982,9610,9611,9613,9615,9617,9619,9621],{"class":1984,"line":2253},[1982,9612,9460],{"class":1993},[1982,9614,2004],{"class":2003},[1982,9616,9554],{"class":2007},[1982,9618,2042],{"class":2003},[1982,9620,2991],{"class":1993},[1982,9622,2142],{"class":2003},[1982,9624,9625],{"class":1984,"line":2258},[1982,9626,2598],{"class":2003},[1968,9628,685],{"id":9629},"best-practices",[3779,9631,9632,9638,9644,9650,9656],{},[3224,9633,9634,9637],{},[3227,9635,9636],{},"Test processors in isolation"," before integration",[3224,9639,9640,9643],{},[3227,9641,9642],{},"Use table-driven tests"," for schema variations",[3224,9645,9646,9649],{},[3227,9647,9648],{},"Test error paths explicitly"," - don't just test happy paths",[3224,9651,9652,9655],{},[3227,9653,9654],{},"Test concurrent access"," if using hot reload",[3224,9657,9658,9661],{},[3227,9659,9660],{},"Keep test factories minimal"," - only register what's needed",[1968,9663,150],{"id":9664},"next-steps",[3221,9666,9667,9673],{},[3224,9668,9669,9672],{},[1894,9670,666],{"href":9671},"observability"," - Monitor in production",[3224,9674,9675,9679],{},[1894,9676,9678],{"href":9677},"../reference/api#testing-package","Testing Package Reference"," - Test utilities",[3677,9681,9682],{},"html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}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 .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"title":24,"searchDepth":19,"depth":19,"links":9684},[9685,9686,9687,9688,9689,9694,9695,9700,9701,9702,9703,9704],{"id":4742,"depth":19,"text":888},{"id":4771,"depth":19,"text":893},{"id":5221,"depth":19,"text":898},{"id":5522,"depth":19,"text":903},{"id":6204,"depth":19,"text":908,"children":9690},[9691,9692,9693],{"id":6212,"depth":30,"text":913},{"id":6562,"depth":30,"text":918},{"id":6691,"depth":30,"text":923},{"id":6804,"depth":19,"text":928},{"id":7351,"depth":19,"text":933,"children":9696},[9697,9698,9699],{"id":7354,"depth":30,"text":937},{"id":7720,"depth":30,"text":942},{"id":8093,"depth":30,"text":947},{"id":8449,"depth":19,"text":952},{"id":9003,"depth":19,"text":957},{"id":9406,"depth":19,"text":962},{"id":9629,"depth":19,"text":685},{"id":9664,"depth":19,"text":150},{},"2025-12-03T00:00:00.000Z",null,{"title":879,"description":881},[9710,879,9711],"Guide","Quality","2025-12-12T00:00:00.000Z","neZ5QQDkWhJ2-9529aTxRIAw878CR31gZGLIYhCsH-Q",[9715,9716],{"title":363,"path":712,"stem":1828,"description":714,"children":-1},{"title":666,"path":974,"stem":1832,"description":976,"children":-1},1776189694725]