<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Siandro Sena</title>
    <description>The latest articles on DEV Community by Siandro Sena (@siandro_sena_a284a12507b6).</description>
    <link>https://dev.to/siandro_sena_a284a12507b6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4099206%2F627d3ebc-a398-44ad-a023-99989f81c732.jpg</url>
      <title>DEV Community: Siandro Sena</title>
      <link>https://dev.to/siandro_sena_a284a12507b6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siandro_sena_a284a12507b6"/>
    <language>en</language>
    <item>
      <title>Which fleet vehicle should I check first? Modeling a maintenance priority score</title>
      <dc:creator>Siandro Sena</dc:creator>
      <pubDate>Mon, 31 Aug 2026 02:42:36 +0000</pubDate>
      <link>https://dev.to/siandro_sena_a284a12507b6/which-fleet-vehicle-should-i-check-first-modeling-a-maintenance-priority-score-i0g</link>
      <guid>https://dev.to/siandro_sena_a284a12507b6/which-fleet-vehicle-should-i-check-first-modeling-a-maintenance-priority-score-i0g</guid>
      <description>&lt;p&gt;At a passenger river-transport operation with a garage in Barcarena, in the Brazilian Amazon, every vehicle in the fleet generates maintenance data all the time: tire tread depth, tire pressure, alignment, oil and filters, lubrication. That's a good thing — it means there's enough data to decide with information instead of gut feeling. The problem is that &lt;strong&gt;raw data isn't a decision&lt;/strong&gt;. Someone still has to open 20 spreadsheet tabs, compare category by category, and decide off the top of their head which vehicle is most urgent. In practice, that turns into one of two things: an experienced mechanic deciding by instinct (which works fine until they take vacation or change jobs), or a list nobody looks at until a tire blows out on the road.&lt;/p&gt;

&lt;p&gt;This article is about how I modeled that problem — it's not a code tutorial, it's about the engineering decisions behind two small, tested pieces: a wheel wear classifier, and a fleet priority engine. In my day-to-day work I solve this kind of problem with &lt;strong&gt;low-code&lt;/strong&gt; — n8n, Google Apps Script, Google Sheets formulas — because that's what delivers value fastest to whoever actually has to use it. For this article and the public repository, I rewrote the same logic in plain Python: it's easier to read, test, and adapt for anyone not using my specific stack. The code is published, generalized and anonymized, at &lt;a href="https://github.com/siandrosena/fleet-maintenance-priority-engine" rel="noopener noreferrer"&gt;github.com/siandrosena/fleet-maintenance-priority-engine&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first problem: the mechanic decides by instinct, and that doesn't scale
&lt;/h2&gt;

&lt;p&gt;Take any tire in the fleet. You measure tread depth at 4 points across the tread: outer edge, outer center, inner center, inner edge. An experienced mechanic looks at those 4 numbers and knows instantly: "this tire is worn because it's misaligned" or "this one's a pressure problem." Those are two different physical problems with two different fixes (align vs. adjust pressure), and the &lt;em&gt;pattern&lt;/em&gt; across the 4 points is what gives it away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wear concentrated on one edge&lt;/strong&gt; (one edge with noticeably lower tread than the other) → the tire is "eating" on one side, a classic sign of a camber/alignment issue → needs alignment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wear concentrated in the center OR on both edges, symmetrically&lt;/strong&gt; → classic sign of wrong pressure (an underinflated tire wears the edges faster; an overinflated tire wears the center faster) → needs a pressure adjustment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both patterns at once, or neither clearly&lt;/strong&gt; → irregular wear, probably a different root cause (bearing, suspension) that this simple diagnosis doesn't cover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part of modeling this in code isn't the math (it's subtraction and comparing averages) — it's deciding &lt;strong&gt;where the tolerance thresholds sit&lt;/strong&gt; and &lt;strong&gt;what to do when both patterns show up at once&lt;/strong&gt;. A tire with a 1mm difference between edges isn't misaligned, that's normal manufacturing/wear variation. I set 3mm as the alignment threshold and 2mm as the pressure threshold — not magic numbers, they're the point where a real mechanic would stop calling it "normal" and start calling it "a problem." And when both thresholds trip at the same time, the right move isn't to arbitrarily pick one — it's to admit the pattern is mixed (&lt;code&gt;DESGASTE_IRREGULAR&lt;/code&gt; / irregular wear) and flag it for manual inspection, instead of giving a falsely confident diagnosis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;diagnose_wheel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;delta_bordas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borda_externa&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borda_interna&lt;/span&gt;
    &lt;span class="n"&gt;delta_centro_bordas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;media_centro&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;media_bordas&lt;/span&gt;

    &lt;span class="n"&gt;desalinhado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta_bordas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;
    &lt;span class="n"&gt;pressao_errada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta_centro_bordas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;desalinhado&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;pressao_errada&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WheelVerdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DESGASTE_IRREGULAR&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;desalinhado&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ALINHAR_ESQUERDA&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta_bordas&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;ALINHAR_DIREITA&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pressao_errada&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CALIBRAR_MAIS&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta_centro_bordas&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;CALIBRAR_MENOS&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven tests cover all 6 possible verdicts, including the mixed case. The point isn't the code's complexity (it's low, on purpose) — it's that the business rule became something testable and reproducible, instead of "ask your experienced mechanic."&lt;/p&gt;

&lt;h2&gt;
  
  
  The second problem: not every maintenance category weighs the same
&lt;/h2&gt;

&lt;p&gt;Solving the per-wheel diagnosis doesn't solve the real, fleet-wide problem: with 20 vehicles, each generating data across 5 different categories (tire pressure, tread, alignment, oil/filters, lubrication), whoever decides "I'm checking this vehicle today" has to compare things that aren't obviously comparable. Is a vehicle with tire pressure 20% off ideal more urgent than one with lubrication 20% overdue? Yes — and the reason isn't arbitrary: wrong tire pressure degrades the tire fast and affects braking/stability within days, while a lubrication delay has weeks of slack before it becomes a real problem.&lt;/p&gt;

&lt;p&gt;That means the score can't be a simple average across categories. I modeled it as a &lt;strong&gt;weighted sum&lt;/strong&gt;, where the weight reflects how fast ignoring that category turns into an expensive problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CATEGORY_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calibragem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# tire pressure
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sulco&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;# tread depth
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alinhamento&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# alignment
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oleo_filtros&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# oil/filters
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lubrificacao&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# lubrication
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Σ&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="err"&gt;×&lt;/span&gt; &lt;span class="n"&gt;severity&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="err"&gt;–&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each category's severity (0.0 to 1.0) can come from whatever criterion makes sense for it — days overdue, deviation from ideal range, whatever fits — the priority engine doesn't need to know where the number came from, only that it's already normalized. That separation (whoever computes severity ≠ whoever ranks by priority) is what lets you swap the criterion for one category without touching the ranking engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  The actual result
&lt;/h3&gt;

&lt;p&gt;Running against a fictional 7-vehicle fleet with deliberately messy data (each vehicle has a different problem):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOP 5 — vehicles needing attention now:

1. VEHICLE-07 — score 15.0 (worst category: tire pressure)
2. VEHICLE-03 — score 6.4 (worst category: tread depth)
3. VEHICLE-01 — score 6.4 (worst category: tire pressure)
4. VEHICLE-05 — score 6.0 (worst category: tire pressure)
5. VEHICLE-02 — score 1.9 (worst category: tread depth)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the real output of the repository's example CLI, not an illustration. A list where "everyone needs something" turned into an ordered list with an explicit reason attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for a real operation
&lt;/h2&gt;

&lt;p&gt;The win isn't "having a nice dashboard" — it's taking a recurring, expensive decision (which vehicle do I check first, every day) out of one person's head and putting it into an explicit, auditable, consistent criterion. That matters for three concrete reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The decision stops being a single point of failure.&lt;/strong&gt; If the mechanic who "knows it by heart" gets sick, goes on vacation, or changes jobs, the operation doesn't lose its ability to prioritize — the criterion lives in the system, not just in someone's head.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The criterion becomes visible and debatable.&lt;/strong&gt; When each category's weight is explicit in the code, you can question and adjust it ("should alignment weigh more than this for our specific operation?") instead of arguing about a decision nobody can explain the reasoning for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer unplanned breakdowns.&lt;/strong&gt; The end goal isn't the score — it's the tire that doesn't blow out on the road because someone looked at it three days before, not three days after.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Trade-offs and limitations (on purpose, not hidden)
&lt;/h2&gt;

&lt;p&gt;No system modeled in a few weeks is complete, and I'd rather say so than have someone find out the hard way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The thresholds (3mm, 2mm) and weights (5,4,3,2,1) are fixed constants&lt;/strong&gt;, calibrated from my domain understanding, not from statistical analysis of a large base of real failures. For a different operation (different vehicle type, climate, road conditions), those numbers likely need adjusting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The wheel diagnosis covers 2 wear axes&lt;/strong&gt; (edge-to-edge and center-vs-edges). A wear pattern that doesn't fit either one (say, caused by a bearing or suspension issue) falls into "irregular" without pointing at a root cause — the system can say "something's wrong," not always "what."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The priority score doesn't factor in cost, part/shop availability, or route criticality.&lt;/strong&gt; It's an inspection-severity score — one piece of a larger decision system, not the final decision by itself. A vehicle can have the highest score and still not be the truly most urgent one if the part to fix it won't arrive until tomorrow regardless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It trusts the input reading as true&lt;/strong&gt; — if the tread/pressure data going in is wrong (measurement error, typo), the system propagates that error with the same confidence as correct data. That's exactly why I treat data extraction (reading a handwritten card via AI, in a different project in the same portfolio) as a separate layer, with its own validation, before anything reaches this one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I rewrote this from scratch in Python instead of publishing the original system
&lt;/h2&gt;

&lt;p&gt;The production version of this system &lt;strong&gt;isn't Python — it's native Google Sheets formulas and Google Apps Script&lt;/strong&gt;, running inside a real client spreadsheet. That's a deliberate choice, not a limitation: when the person operating the system is a mechanic or a fleet manager, not a programmer, putting the logic directly into the tool they already use every day (the spreadsheet) removes an entire layer of friction — no deployment, no server, no "call IT to change it." My job as an engineer here wasn't "write as much code as possible," it was understanding the maintenance process closely enough to know WHICH rule to automate and WHERE it needed to live to actually get used.&lt;/p&gt;

&lt;p&gt;Spreadsheet formulas tied to one client's specific spreadsheet structure aren't something I can publish, though (it's the client's, not mine to distribute), nor are they easy to read for anyone who can't open that exact spreadsheet. For the public repository, I rewrote the same decision logic from scratch in &lt;strong&gt;plain Python&lt;/strong&gt;, tested in isolation, and generalized enough for any fleet operation to understand and adapt — with no company name, plate number, or any identifiable data from the original operation. The Python here is a portfolio translation, not the tool I'd reach for to solve this again from scratch in a real operation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Repository: &lt;a href="https://github.com/siandrosena/fleet-maintenance-priority-engine" rel="noopener noreferrer"&gt;github.com/siandrosena/fleet-maintenance-priority-engine&lt;/a&gt; — Python, 14 tests, MIT license.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Siandro Sena — Production Engineer (background in Materials Engineering), MBA in Artificial Intelligence. Process automation with AI, data, and operational efficiency. &lt;a href="https://www.linkedin.com/in/siandro-sena-847712314" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>operations</category>
    </item>
    <item>
      <title>Qual veículo da frota precisa de manutenção HOJE? Priorização com pesos por criticidade (e por que meu dia a dia é low-code, não Python)</title>
      <dc:creator>Siandro Sena</dc:creator>
      <pubDate>Fri, 28 Aug 2026 17:44:37 +0000</pubDate>
      <link>https://dev.to/siandro_sena_a284a12507b6/qual-veiculo-da-frota-precisa-de-manutencao-hoje-priorizacao-com-pesos-por-criticidade-e-por-que-5293</link>
      <guid>https://dev.to/siandro_sena_a284a12507b6/qual-veiculo-da-frota-precisa-de-manutencao-hoje-priorizacao-com-pesos-por-criticidade-e-por-que-5293</guid>
      <description>&lt;h2&gt;
  
  
  O problema
&lt;/h2&gt;

&lt;p&gt;Numa frota com vários veículos, cada um gera dado de manutenção o tempo todo: sulco de pneu, calibragem, alinhamento, óleo, lubrificação. Sem um sistema, isso vira uma de duas coisas — decisão na intuição de um mecânico experiente (que erra, esquece, ou não está lá no dia daquela decisão), ou uma planilha manual que ninguém olha até o pneu estourar na estrada. Nos dois casos, quem decide "qual veículo eu vejo primeiro hoje" está adivinhando, não sabendo.&lt;/p&gt;

&lt;p&gt;Isso é um problema real que estruturei para uma empresa de transporte rodofluvial de passageiros com garagem em Barcarena-PA (Brasil). Sem nome da empresa, placa ou qualquer dado identificável — o que compartilho aqui é a lógica de decisão, generalizada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um adendo importante: meu dia a dia é low-code, não Python
&lt;/h2&gt;

&lt;p&gt;Antes de entrar no código: a versão que roda em produção &lt;strong&gt;não é Python&lt;/strong&gt;. É uma automação em &lt;strong&gt;Google Sheets + Apps Script&lt;/strong&gt; — leitura de sulco dispara um desenho automático de resumo visual pro mecânico (&lt;code&gt;onEdit&lt;/code&gt;), e o dashboard de priorização da frota inteira é &lt;strong&gt;100% fórmula nativa&lt;/strong&gt; (&lt;code&gt;QUERY&lt;/code&gt;, sem script rodando por trás).&lt;/p&gt;

&lt;p&gt;Isso não é modéstia nem desculpa — é a ferramenta certa pro contexto: numa operação de frota pequena/média, quem mantém isso no dia a dia é quem já usa planilha, não quem sabe rodar &lt;code&gt;pip install&lt;/code&gt;. Baixo custo de manutenção, zero servidor, qualquer um da operação abre e entende.&lt;/p&gt;

&lt;p&gt;O repositório e este artigo reescrevem essa mesma lógica de decisão em &lt;strong&gt;Python puro, testado e isolado&lt;/strong&gt; — como exercício de portfólio, pra mostrar o raciocínio de forma que rode em qualquer lugar e sirva de referência técnica. É tradução, não é como o sistema roda na vida real.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solução
&lt;/h2&gt;

&lt;p&gt;O sistema faz duas coisas, em sequência:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Olha os 4 pontos de sulco de cada roda&lt;/strong&gt; e já diz o que fazer: o pneu está gasto porque está desalinhado, ou porque a calibragem está errada? São ações diferentes (alinhar vs. calibrar), e o padrão de desgaste denuncia qual — isso é física de pneu, não é chute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pneu &lt;strong&gt;desalinhado&lt;/strong&gt; desgasta mais de UM lado → diferença grande entre as duas bordas (externa vs. interna)&lt;/li&gt;
&lt;li&gt;Pneu com &lt;strong&gt;pressão errada&lt;/strong&gt; desgasta o centro OU as bordas de forma simétrica → murcho gasta mais as bordas, cheio demais gasta mais o centro&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Cruza essa leitura com as outras categorias de manutenção de toda a frota&lt;/strong&gt; — calibragem, sulco, alinhamento, óleo/filtros, lubrificação, nem todas pesam igual — e devolve um &lt;strong&gt;ranking&lt;/strong&gt;: comece por aqui.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modelagem: pesos e limiares
&lt;/h3&gt;

&lt;p&gt;A parte que importa não é o código, é a decisão de negócio por trás dele.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limiares do diagnóstico de roda&lt;/strong&gt; (regra fixa, em milímetros de diferença de sulco):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DIFERENCA_ALINHAMENTO_MM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;   &lt;span class="c1"&gt;# diferença entre bordas externa/interna
&lt;/span&gt;&lt;span class="n"&gt;DIFERENCA_CALIBRAGEM_MM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;    &lt;span class="c1"&gt;# diferença entre média do centro e média das bordas
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pesos por categoria&lt;/strong&gt; (referência: material educativo de segurança de pneus tipo NHTSA TireWise sobre o impacto de calibragem/sulco na frenagem e estabilidade — não é arbitrário, mas também não é uma constante universal):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CATEGORY_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calibragem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# degrada rápido, barata de checar, ignorar é caro
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sulco&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alinhamento&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oleo_filtros&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lubrificacao&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# tem mais folga de prazo
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lógica: calibragem errada não é tratada igual a lubrificação atrasada, porque na vida real elas não têm a mesma urgência nem o mesmo custo de ignorar. O score de cada veículo é a soma de &lt;code&gt;peso × severidade&lt;/code&gt; de cada categoria (severidade de 0.0 a 1.0, saturando em 1.0 conforme os dias de atraso passam do prazo máximo daquela categoria).&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo real de saída
&lt;/h3&gt;

&lt;p&gt;Frota de 7 veículos, situação bagunçada — cada um com um problema diferente, ninguém sabe por onde começar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python scripts/priority_report.py &lt;span class="nt"&gt;--input&lt;/span&gt; sample_data/frota_severidade.json &lt;span class="nt"&gt;--top&lt;/span&gt; 5
&lt;span class="go"&gt;
TOP 5 — veículos que precisam de atenção agora:

1. VEICULO-07 — score 15.0 (pior categoria: calibragem)
2. VEICULO-03 — score 6.4 (pior categoria: sulco)
3. VEICULO-01 — score 6.4 (pior categoria: calibragem)
4. VEICULO-05 — score 6.0 (pior categoria: calibragem)
5. VEICULO-02 — score 1.9 (pior categoria: sulco)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma lista de "todo mundo precisa de alguma coisa" virou uma ordem de prioridade com o motivo ao lado — sem ninguém abrir aba por aba da planilha.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso importa
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menos pneu estourando na estrada&lt;/strong&gt; — o problema é sinalizado antes de virar parada não planejada, não depois.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A decisão para de depender de UMA pessoa&lt;/strong&gt; — hoje, "qual veículo eu olho primeiro" muitas vezes só um mecânico experiente sabe responder de cabeça. Isso vira algo que qualquer pessoa da operação consegue rodar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cada categoria pesa o que realmente pesa&lt;/strong&gt; — porque na vida real elas não têm a mesma urgência.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitações honestas
&lt;/h2&gt;

&lt;p&gt;Nenhum sistema de regra fixa é perfeito, e eu prefiro deixar isso explícito em vez de vender como mágica:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;O diagnóstico de roda confia na leitura de sulco como verdadeira&lt;/strong&gt; — não valida se os 4 números fazem sentido físico (valor negativo, fora da faixa de um pneu novo/gasto). Garbage in, garbage out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Os limiares (3mm alinhamento, 2mm calibragem) são constantes fixas&lt;/strong&gt;, não calibradas por modelo/marca de pneu ou por eixo (dianteiro e traseiro desgastam diferente) — funcionam como regra geral, não como valor validado estatisticamente pra cada operação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Só cobre 2 eixos de desgaste&lt;/strong&gt; (borda-a-borda e centro-vs-bordas). Um padrão de desgaste diagonal (problema de rolamento/suspensão, por exemplo) cai em "desgaste irregular" sem indicar a causa real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O score de prioridade não considera custo, disponibilidade de peça/oficina ou criticidade da rota&lt;/strong&gt; — é um score de severidade de inspeção, não uma otimização operacional completa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Categoria com nome digitado errado é ignorada em silêncio&lt;/strong&gt; — um typo na severidade de entrada derruba a pontuação daquele veículo sem nenhum aviso. Isso é um risco real de qualquer sistema baseado em texto livre, incluindo o de planilha.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Em produção:&lt;/strong&gt; Google Sheets + Apps Script (&lt;code&gt;onEdit&lt;/code&gt;, &lt;code&gt;QUERY&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neste repositório (tradução pra portfólio):&lt;/strong&gt; Python (stdlib, sem dependência externa) + pytest, 14 testes cobrindo os 6 vereditos de roda e o motor de score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repositório completo, com código e testes: &lt;a href="https://github.com/siandrosena/fleet-maintenance-priority-engine" rel="noopener noreferrer"&gt;fleet-maintenance-priority-engine&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Sou engenheiro (Produção/Materiais) com MBA em Inteligência Artificial, estruturando automação de processos com IA e dados pra operações reais. Se você lida com frota, manutenção preventiva ou só curte ver regra de negócio de verdade virar código, comenta aí — troco ideia.&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>fleet</category>
      <category>devto</category>
    </item>
  </channel>
</rss>
