[{"data":1,"prerenderedAt":361},["ShallowReactive",2],{"navigation":3,"topics-page":14,"topics":26},[4],{"title":5,"path":6,"stem":7,"children":8,"page":13},"Blog","\u002Fblog","blog",[9],{"title":10,"path":11,"stem":12},"Kubernetes 101","\u002Fblog\u002Fkubernetes-introduction","blog\u002Fkubernetes-introduction",false,{"id":15,"title":16,"body":17,"description":18,"extension":19,"links":17,"meta":20,"navigation":21,"path":22,"seo":23,"stem":24,"__hash__":25},"pages\u002Ftopics.yml","What I work on",null,"Six areas where I build, and where I have opinions worth arguing about. Each one is a primer on what is genuinely hard, not a summary of what the field already says.","yml",{},true,"\u002Ftopics",{"title":16,"description":18},"topics","TJ-ZHQhXVK2nPnyWRXbSzEpVyqsEyeA2nt6PYCBGSH4",[27,96,149,203,256,309],{"id":28,"title":29,"body":30,"description":82,"draftNotice":21,"extension":83,"meta":84,"navigation":21,"order":85,"path":86,"pillar":87,"related":88,"seo":93,"stem":94,"__hash__":95},"topics\u002Ftopics\u002Fbackbone.md","UNS at the edge",{"type":31,"value":32,"toc":73},"minimark",[33,37,42,45,49,52,56,59,63,66,70],[34,35,36],"p",{},"Every plant already moves data. Ask where the meaning lives and the answer is usually a spreadsheet, a tag naming convention nobody wrote down, and one integrator's head.",[38,39,41],"h2",{"id":40},"the-broker-is-the-easy-part","The broker is the easy part",[34,43,44],{},"Choosing MQTT or picking a broker is a weekend decision. The hard part is agreeing what a topic means, who owns it, and what breaks when it changes.",[38,46,48],{"id":47},"contracts-not-conventions","Contracts, not conventions",[34,50,51],{},"A namespace without a schema and an owner is a naming convention with better marketing. This is the argument for treating the information model as a reviewable artefact in git.",[38,53,55],{"id":54},"opc-ua-information-models-without-the-xml","OPC UA information models without the XML",[34,57,58],{},"Hand-written NodeSet2.xml is why most companion-spec work stalls. Authoring in YAML and compiling to the standard output changes who can participate.",[38,60,62],{"id":61},"i3x-and-mcp","i3X and MCP",[34,64,65],{},"Two emerging standards that matter for discoverability, and why betting on them reduced proprietary software reliance by 90% on one fleet.",[38,67,69],{"id":68},"what-it-cost","What it cost",[34,71,72],{},"The honest accounting: what replacing proprietary middleware actually took, where it was harder than promised, and what stayed proprietary on purpose.",{"title":74,"searchDepth":75,"depth":75,"links":76},"",2,[77,78,79,80,81],{"id":40,"depth":75,"text":41},{"id":47,"depth":75,"text":48},{"id":54,"depth":75,"text":55},{"id":61,"depth":75,"text":62},{"id":68,"depth":75,"text":69},"A UNS is a contract, not a broker. What actually makes plant data usable — and what it costs to stop paying for proprietary middleware.","md",{},1,"\u002Ftopics\u002Fbackbone","backbone",{"ventures":89,"oss":91},[90],"start-alpha",[92],"twin-model",{"title":29,"description":82},"topics\u002Fbackbone","J0qxmXdCFRpR5scSuhE-zfAvpd_S6rpc6Yf3TO6Bneg",{"id":97,"title":98,"body":99,"description":138,"draftNotice":21,"extension":83,"meta":139,"navigation":21,"order":75,"path":140,"pillar":141,"related":142,"seo":146,"stem":147,"__hash__":148},"topics\u002Ftopics\u002Fedge.md","Fleet management",{"type":31,"value":100,"toc":132},[101,104,108,111,115,118,122,125,129],[34,102,103],{},"One cluster is a tutorial. A hundred clusters in a hundred buildings, half of them behind a firewall an OT team controls, is a different discipline.",[38,105,107],{"id":106},"intermittent-is-the-normal-case","Intermittent is the normal case",[34,109,110],{},"Designing for a link that is usually up is how you build something that fails badly. Reconciliation has to be the default behaviour, not the recovery path.",[38,112,114],{"id":113},"the-commissioning-window","The commissioning window",[34,116,117],{},"Line commissioning is when infrastructure decisions get made under time pressure by people who will never touch them again. What you ship has to survive that.",[38,119,121],{"id":120},"resource-budgets-are-a-design-constraint","Resource budgets are a design constraint",[34,123,124],{},"If it needs a datacenter, it does not belong at the edge. What that rules out, and what it forces you to do better.",[38,126,128],{"id":127},"the-handover-test","The handover test",[34,130,131],{},"We built the fleet. Another supplier runs it now. Reversibility is not a licensing claim, it is whether the next team can actually take over — and most architectures fail this test the first time it is applied.",{"title":74,"searchDepth":75,"depth":75,"links":133},[134,135,136,137],{"id":106,"depth":75,"text":107},{"id":113,"depth":75,"text":114},{"id":120,"depth":75,"text":121},{"id":127,"depth":75,"text":128},"Running k3s across a hundred sites with intermittent connectivity — and the test almost nobody applies to their own architecture, which is whether someone else can take it over.",{},"\u002Ftopics\u002Fedge","edge",{"ventures":143,"oss":144},[90],[145],"k3s",{"title":98,"description":138},"topics\u002Fedge","H4aYowyeNQMS3ibcx-uLRmRz8wngi6JE2iK7a4UADxk",{"id":150,"title":151,"body":152,"description":191,"draftNotice":21,"extension":83,"meta":192,"navigation":21,"order":193,"path":194,"pillar":195,"related":196,"seo":200,"stem":201,"__hash__":202},"topics\u002Ftopics\u002Fobservability.md","Observability",{"type":31,"value":153,"toc":185},[154,157,161,164,168,171,175,178,182],[34,155,156],{},"A distributed application watching a critical manufacturing process across a hundred hosts generates enormous amounts of telemetry and, usually, very little understanding.",[38,158,160],{"id":159},"which-metrics-earn-their-storage","Which metrics earn their storage",[34,162,163],{},"Most metrics are collected because collecting them was easy. Cardinality is a budget, and spending it without a decision in mind is how observability bills get out of control.",[38,165,167],{"id":166},"tagsets-across-independent-modules","Tagsets across independent modules",[34,169,170],{},"The moment more than one team emits telemetry, labels drift. Enforcement has to happen at ingestion or at CI — asking politely does not work at scale.",[38,172,174],{"id":173},"the-missing-spans","The missing spans",[34,176,177],{},"Industrial systems trace almost nothing. A camera triggers, inference runs, a result reaches a display, and the only evidence is three unrelated metrics. End-to-end latency is a span problem, and treating it as a metrics problem is why bottlenecks stay invisible.",[38,179,181],{"id":180},"instrumenting-the-whole-chain","Instrumenting the whole chain",[34,183,184],{},"What it took to instrument camera to inference to display, and what surfaced immediately once the chain was visible.",{"title":74,"searchDepth":75,"depth":75,"links":186},[187,188,189,190],{"id":159,"depth":75,"text":160},{"id":166,"depth":75,"text":167},{"id":173,"depth":75,"text":174},{"id":180,"depth":75,"text":181},"Industrial systems are all metrics and no traces. Cost-controlled OpenTelemetry, tagset governance across independent modules, and knowing which signals earn their storage.",{},3,"\u002Ftopics\u002Fobservability","observability",{"oss":197},[198,199],"opentelemetry","opamp",{"title":151,"description":191},"topics\u002Fobservability","dTp_hinKxNWnB_kT2iwSyoTSugoq5xC5ZLtNZD9xcTc",{"id":204,"title":205,"body":206,"description":245,"draftNotice":21,"extension":83,"meta":246,"navigation":21,"order":247,"path":248,"pillar":249,"related":250,"seo":253,"stem":254,"__hash__":255},"topics\u002Ftopics\u002Fdecisions.md","Planning optimization",{"type":31,"value":207,"toc":239},[208,211,215,218,222,225,229,232,236],[34,209,210],{},"Planning and scheduling has an unusual failure pattern: the mathematics works, the pilot looks convincing, and the tool is abandoned within a year.",[38,212,214],{"id":213},"constraint-granularity-is-where-projects-die","Constraint granularity is where projects die",[34,216,217],{},"Almost everything written about planning is about algorithms. The decision that actually determines success is how finely constraints are modelled — too coarse and the plan is ignored, too fine and it cannot be maintained.",[38,219,221],{"id":220},"optimisation-against-live-state","Optimisation against live state",[34,223,224],{},"An optimisation API integrated with SCADA and PLCs under real-time constraints is a different engineering problem from one that reads a nightly extract.",[38,226,228],{"id":227},"mlops-at-the-edge","MLOps at the edge",[34,230,231],{},"Shipping a model where R&D can iterate daily, on infrastructure that is not allowed to be down.",[38,233,235],{"id":234},"planners-are-your-users","Planners are your users",[34,237,238],{},"Ten planners using something in production beats a better algorithm nobody opens. Change management is engineering work, and treating it as a phase afterwards is how tools die.",{"title":74,"searchDepth":75,"depth":75,"links":240},[241,242,243,244],{"id":213,"depth":75,"text":214},{"id":220,"depth":75,"text":221},{"id":227,"depth":75,"text":228},{"id":234,"depth":75,"text":235},"The solver was never the problem. Constraint granularity, real-time integration with ERP, MES & SCADA, and why planners are the users you actually have to convince.",{},4,"\u002Ftopics\u002Fdecisions","decisions",{"ventures":251},[252],"nexiplan",{"title":205,"description":245},"topics\u002Fdecisions","jZj0VVkeFMYGJFfpVG2HQGO_XXPPgZUCCot3w4QHIqQ",{"id":257,"title":258,"body":259,"description":298,"draftNotice":21,"extension":83,"meta":299,"navigation":21,"order":300,"path":301,"pillar":302,"related":303,"seo":306,"stem":307,"__hash__":308},"topics\u002Ftopics\u002Fml.md","Models under a latency budget",{"type":31,"value":260,"toc":292},[261,264,268,271,275,278,282,285,289],[34,262,263],{},"On a production line the cycle time is fixed. The model either answers inside it or it does not ship, and no amount of accuracy on a validation set changes that.",[38,265,267],{"id":266},"measure-before-you-optimise","Measure before you optimise",[34,269,270],{},"Most slow pipelines are slow in pre-processing, copies between host and device, or a Python loop around the model — not in the model itself. Profiling the whole path first is how you avoid spending a week quantising something that was never the bottleneck.",[38,272,274],{"id":273},"every-optimisation-has-a-price","Every optimisation has a price",[34,276,277],{},"FP16, INT8, pruning, distillation, smaller input resolutions. Each one trades accuracy, engineering time or maintainability for latency. The skill is knowing which trade the use case can afford, and proving it on real plant data rather than a benchmark.",[38,279,281],{"id":280},"batching-versus-latency","Batching versus latency",[34,283,284],{},"Throughput and latency pull in opposite directions. A camera triggering per part and a batch inspection of a full tray are different serving problems, and the right batch size is a property of the process, not of the GPU.",[38,286,288],{"id":287},"mlops-that-survives-the-plant","MLOps that survives the plant",[34,290,291],{},"Shipping a model where R&D can iterate daily, on infrastructure that is not allowed to be down. Versioned models, reproducible exports, and a rollback that takes seconds.",{"title":74,"searchDepth":75,"depth":75,"links":293},[294,295,296,297],{"id":266,"depth":75,"text":267},{"id":273,"depth":75,"text":274},{"id":280,"depth":75,"text":281},{"id":287,"depth":75,"text":288},"A model that is accurate in a notebook and too slow on the line is not a model, it is a demo. ML engineering for performance — and knowing which optimisation is worth what it costs.",{},5,"\u002Ftopics\u002Fml","ml",{"ventures":304,"oss":305},[],[],{"title":258,"description":298},"topics\u002Fml","ukInvv4VI67lz4vDb1AahLVUzt6Qs82UZjbJvqUR8eg",{"id":310,"title":311,"body":312,"description":351,"draftNotice":21,"extension":83,"meta":352,"navigation":21,"order":353,"path":354,"pillar":355,"related":356,"seo":358,"stem":359,"__hash__":360},"topics\u002Ftopics\u002Finference.md","GPUs on the line",{"type":31,"value":313,"toc":345},[314,317,321,324,328,331,335,338,342],[34,315,316],{},"Getting a model to run on a GPU takes an afternoon. Keeping it running on dozens of edge nodes, through driver updates and hardware refreshes, is the actual job.",[38,318,320],{"id":319},"the-driver-is-part-of-the-application","The driver is part of the application",[34,322,323],{},"Driver, CUDA, cuDNN and TensorRT versions form one compatibility matrix, and an engine built against one combination does not load on another. Treating the host driver as someone else's problem is how an OS patch takes a line down.",[38,325,327],{"id":326},"knowing-when-to-reach-for-the-nvidia-stack","Knowing when to reach for the NVIDIA stack",[34,329,330],{},"TensorRT, DeepStream and Triton are the right answer for some workloads and a heavy dependency for others. ONNX Runtime or a plain CPU path is sometimes the better call — and the decision should be made on measured latency, not on which SDK is fashionable.",[38,332,334],{"id":333},"serving-on-kubernetes-at-the-edge","Serving on Kubernetes at the edge",[34,336,337],{},"The GPU operator, device plugins, time-slicing and MIG: how several models share one card on a k3s node without starving each other, and how that gets rolled out through GitOps like everything else.",[38,339,341],{"id":340},"engines-are-build-artefacts","Engines are build artefacts",[34,343,344],{},"A TensorRT engine is tied to the GPU it was built on. Building, caching and shipping engines per hardware target belongs in the pipeline, not in a startup script that silently takes ten minutes on first boot.",{"title":74,"searchDepth":75,"depth":75,"links":346},[347,348,349,350],{"id":319,"depth":75,"text":320},{"id":326,"depth":75,"text":327},{"id":333,"depth":75,"text":334},{"id":340,"depth":75,"text":341},"Accelerated inference in production is mostly a driver problem. CUDA versions, TensorRT engines, Triton serving and GPU sharing on edge nodes that nobody is allowed to reboot.",{},6,"\u002Ftopics\u002Finference","inference",{"oss":357},[145],{"title":311,"description":351},"topics\u002Finference","qXpEvPvjEaeEUYaL3gBH9Th3s3ZM9QDCVJ0QVNxT0vs",1791414106890]