<?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: Efe Genç</title>
    <description>The latest articles on DEV Community by Efe Genç (@efe_genc).</description>
    <link>https://dev.to/efe_genc</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%2F4110228%2F338f35c9-5ee2-4a88-9cc7-e393cb651dfa.jpg</url>
      <title>DEV Community: Efe Genç</title>
      <link>https://dev.to/efe_genc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/efe_genc"/>
    <language>en</language>
    <item>
      <title>How to Show Engineering Ownership When the Repositories Are Private</title>
      <dc:creator>Efe Genç</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:59:16 +0000</pubDate>
      <link>https://dev.to/efe_genc/how-to-show-engineering-ownership-when-the-repositories-are-private-3fon</link>
      <guid>https://dev.to/efe_genc/how-to-show-engineering-ownership-when-the-repositories-are-private-3fon</guid>
      <description>&lt;p&gt;I have spent more than four years shipping production software, and I have no public repositories worth showing you. Everything substantial I have written at work lives in private repositories that belong to the companies I wrote it for, and confidentiality obligations do not lapse when a role ends. So I cannot hand you the code, and I am not going to.&lt;/p&gt;

&lt;p&gt;I do not say that to sound careful. An engineer who sends a prospective employer another company's source code has told you exactly what they will do with yours. The restraint is part of what you are assessing, and I would want the same restraint applied to my own work later.&lt;/p&gt;

&lt;p&gt;That leaves a real problem. "I was the principal author of the web application" and "I contributed to the web application" are the same sentence to a reader who cannot check either one. Most engineering CVs resolve this by getting louder. The only honest resolution I have found is to publish the &lt;strong&gt;measurement method&lt;/strong&gt; instead of the artefact, in enough detail that someone who knows the tools can judge the figure on its own terms without ever seeing the repository.&lt;/p&gt;

&lt;p&gt;Here is the method I used, what it does badly, and the places where applying it forced me to shrink a claim I would have preferred to keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three measurements, in increasing order of rigour
&lt;/h2&gt;

&lt;p&gt;The first is the all-branch commit count: total authored activity. Do not use it. It counts abandoned branches, spikes and experiments, and it inflates in favour of whoever is most willing to commit. It is the number that makes contribution graphs look impressive and says the least about a codebase.&lt;/p&gt;

&lt;p&gt;The second is the production-branch commit count, scoped to tenure: what reached customers while you were there. This is better, because it excludes work that never shipped, and because scoping to tenure stops you from taking credit for years of history that predate you, or being penalised for them. But it still counts commits, and a commit is a unit of activity, not a unit of code. Commit share rewards granular committers and punishes people who work in larger increments. It is the weakest of the three, and unfortunately the easiest to produce, which is why it is the one people quote.&lt;/p&gt;

&lt;p&gt;The third is &lt;code&gt;git blame&lt;/code&gt; on the production branch: which lines are alive in production today, and who wrote them. This is the authoritative one, because it measures surviving authorship. The code was written, shipped, survived every later refactor by everyone else, and is running now. Its weakness is that it is slow, so it has to be sampled.&lt;/p&gt;

&lt;p&gt;Two details make the blame figure defensible, and they carry the whole exercise.&lt;/p&gt;

&lt;p&gt;The flags. I ran &lt;code&gt;git blame -w -M&lt;/code&gt; against the production branch. &lt;code&gt;-w&lt;/code&gt; ignores whitespace-only changes and &lt;code&gt;-M&lt;/code&gt; detects lines moved or copied within a file. Both make the result &lt;em&gt;more conservative&lt;/em&gt; rather than more flattering, because reformatted or relocated code is attributed to whoever originally wrote it instead of whoever last touched it. If I had wanted a bigger number I would have left both flags off, and anybody who knows the command can verify that without access to anything.&lt;/p&gt;

&lt;p&gt;The sampling. Deterministic, every Nth file across the sorted file list. I did not hand-pick a directory, and I did not take a random draw that I could have re-rolled until it flattered me. Anyone with the same repository can reproduce it. Sampling by directory is where this kind of measurement usually goes wrong, because directories are exactly where authorship clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that produced, and why the gap is the interesting part
&lt;/h2&gt;

&lt;p&gt;At &lt;a href="https://dev.to/projects/cendra/"&gt;Cendra&lt;/a&gt;, where I was one of two founding engineers, blame analysis on a deterministic one-in-seven sample of the production TypeScript sources (several hundred files) attributes &lt;strong&gt;84.7%&lt;/strong&gt; of surviving frontend code to me, with the remainder spread across eight other contributors. My production-branch commit share over the same period, scoped to my tenure, is &lt;strong&gt;80.7%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The script is public now as &lt;a href="https://github.com/Bubblegunn/surviving-lines" rel="noopener noreferrer"&gt;surviving-lines&lt;/a&gt;: one file, no dependencies, the same deterministic sample and the same &lt;code&gt;git blame -w -M&lt;/code&gt;, with the caveats printed under every table so the number cannot travel without them.&lt;/p&gt;

&lt;p&gt;The gap between those two numbers is the claim, and it points in the direction most people would not expect. My share of surviving lines is &lt;em&gt;higher&lt;/em&gt; than my share of commits, which means code written by others was disproportionately replaced by code written by me. I did more than add volume to a growing surface; I rewrote and consolidated the one that was already there. That is an argument about architectural ownership rather than throughput, and it is why I describe myself as principal author instead of the person who happened to commit the most.&lt;/p&gt;

&lt;p&gt;Had the ratio gone the other way, with commit share above blame share, the honest reading would be that I produced a lot of code that other people later replaced. That is a real outcome and it happens. A method that could not have shown it would not be a measurement.&lt;/p&gt;

&lt;p&gt;Some figures need no method at all. Every commit to the &lt;code&gt;ios/&lt;/code&gt; and &lt;code&gt;android/&lt;/code&gt; projects across the entire history of the repository is mine, 47 and 28 respectively, along with the Capacitor configuration and the Playwright end-to-end suites at 11 of 11 each. No other author has ever committed to those paths. That is the least arguable claim I have, and it is arithmetic rather than analysis.&lt;/p&gt;

&lt;p&gt;I measured all of these while I held authorised access, using ordinary &lt;code&gt;git&lt;/code&gt; invocations. I am not offering to demonstrate them live, and you should be wary of anyone who would. Opening a former employer's private repository in a screen share is a breach in itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The method is most useful when it makes you shrink things
&lt;/h2&gt;

&lt;p&gt;The uncomfortable half of publishing a method is that it applies to the parts of the work you were less central to, and it does not let you round them up.&lt;/p&gt;

&lt;p&gt;The same blame analysis run against the production C# sources attributes &lt;strong&gt;23.2%&lt;/strong&gt; of surviving backend code to me, with a 30.9% commit share over my tenure. I joined the backend roughly six months into a twelve-month tenure. It had been under active development for eighteen months before I touched it, by engineers who are still there. So the accurate sentence is that I was a substantial contributor to a codebase I joined late, and I was not its architect. I have tried hard not to imply otherwise anywhere.&lt;/p&gt;

&lt;p&gt;Where that contribution sits turns out to be more informative than the total. My share of commits since joining runs highest in the test suite at 83.2%, the domain services at 53.6% and the event-processing consumer at 55.4%, and lowest in the infrastructure at 24.1%, the core domain at 20.8% and the CQRS feature handlers at 16.6%. Low in shared CRUD surfaces, high where architectural judgement was required. I was not the highest-volume backend contributor. I owned the parts that needed design, and the test suite the rest of the team relied on. Other contributors' shares are their own information, and they are not mine to publish.&lt;/p&gt;

&lt;p&gt;Across all four repositories, scoped to my tenure, the combined figure is 5,717 of 10,402 production-branch commits, or 55.0%. That is the most conservative aggregate available, and I record it for that reason, but I would not lead an argument with it. A single number that spans a frontend I was principal author of and an integration service I touched occasionally is not really a claim about either. Any aggregate over unlike repositories describes them worse than the per-repository figures it averages. That is why the breakdown above exists, and why the 84.7% is the number I would defend first.&lt;/p&gt;

&lt;p&gt;The method cannot measure two more boundaries, but honesty requires them.&lt;/p&gt;

&lt;p&gt;The core AI architecture at Cendra was not mine. Our AI engineer owned the LangGraph services, the agent workflows and the RAG pipelines. I built the product layer those capabilities were surfaced through (agent configuration, the knowledge base, the agentic rule-authoring interface and the in-product assistant) and the transport between the two, over AG-UI, server-sent events and the realtime hub. I contributed to how the rule and guardrail semantics were shaped, because building an interface through which a non-technical operator expresses a rule an engine will enforce requires understanding those semantics as deeply as the person implementing the enforcement. But I did not architect the orchestration. "I worked on the AI product" is the easiest sentence in this industry to say and the least informative.&lt;/p&gt;

&lt;p&gt;Cendra's product-level metrics are not mine either. Automation rates and platform reach are company figures published by the company. I contributed to the systems behind them. I did not measure them, and presenting a company outcome as a personal one is the specific move that makes every other number on a CV suspect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where commit share is all you have
&lt;/h2&gt;

&lt;p&gt;At &lt;a href="https://dev.to/projects/readyfly/"&gt;ReadyFly&lt;/a&gt;, a part-time founding-engineer role, I have commit shares and nothing better: 157 of 209 commits to the web application, roughly three quarters, and I made the first one; and 31 of 209 to the Python API. So I say principal author of the first and contributor to the second, and I do not dress the 15% up. The AI models themselves, semantic matching and candidate evaluation, were owned by the team's AI engineer. I built the product layer they were surfaced through, and the browser side of that story is in &lt;a href="https://dev.to/writing/an-interview-inside-the-browser/"&gt;An Interview Inside the Browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Commit share is the weakest of the three measurements. When it is the only one available, the right response is to say so, rather than to present it in the same voice as a blame figure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What closes the gap
&lt;/h2&gt;

&lt;p&gt;Method plus disclosure gets you to a claim that can be &lt;em&gt;judged&lt;/em&gt;. It does not get you to a claim that has been independently &lt;em&gt;confirmed&lt;/em&gt;, and I do not think any amount of self-published measurement does.&lt;/p&gt;

&lt;p&gt;Three things do. Process artefacts that exist independently of my description of them: &lt;a href="https://dev.to/writing/the-spec-is-the-fast-path/"&gt;255 design specifications, 207 implementation plans and 17 production runbooks&lt;/a&gt;, alongside 377 production releases coordinated across four repositories over 239 active development days in a twelve-month tenure. Two Cendra co-founders who have agreed to act as references and can confirm scope and ownership without me in the room. And an offer that costs me nothing to make, because it is the part I am confident about: a walkthrough of the systems that are mine, line by line, including the parts I would now build differently.&lt;/p&gt;

&lt;p&gt;The measurements are there so the conversation can start somewhere better than mutual assertion. They are not the evidence. They describe how I would go about finding out, and I have published them so that you can disagree with them.&lt;/p&gt;




&lt;p&gt;This essay first appeared on my site, efe-genc-portfolio.vercel.app, where the rest of the series lives. If you have had to prove ownership of work you cannot show, I would like to hear how you did it. Disagreement is the most useful comment I can get.&lt;/p&gt;

</description>
      <category>career</category>
      <category>git</category>
      <category>softwareengineering</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The Spec Is the Fast Path</title>
      <dc:creator>Efe Genç</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:59:12 +0000</pubDate>
      <link>https://dev.to/efe_genc/the-spec-is-the-fast-path-3m2l</link>
      <guid>https://dev.to/efe_genc/the-spec-is-the-fast-path-3m2l</guid>
      <description>&lt;p&gt;The standard objection to writing the design down is that it is what you give up in exchange for speed. Early-stage companies are meant to be the place where you skip it. No specifications, no plans, build the thing and find out. Documentation gets treated as a tax that mature organisations can afford and small ones cannot.&lt;/p&gt;

&lt;p&gt;I have worked the other way round for a while now, and I want to make the argument properly instead of just asserting it.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://dev.to/projects/cendra/"&gt;Cendra&lt;/a&gt;, across a twelve-month tenure as one of two founding engineers, the work produced 255 design specifications, 207 implementation plans and 17 production runbooks. Over the same period there were 377 production releases coordinated across four repositories, and 482 merge commits across those repositories (an all-merges count, broader than the frontend-only first-parent integration figure on the Cendra page), spread over 239 active development days. The release figure works out at roughly one every twenty-two hours.&lt;/p&gt;

&lt;p&gt;All of those figures are tenure-scoped and self-measured against private repositories while I held authorised access to them, a caveat I will come back to. The shape is what I care about here. The documents and the shipping happened together, at the same time, by the same person.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;p&gt;I cannot prove the specifications caused the cadence. There is no control group. It is entirely possible to imagine a version of that year with no documents and more releases, and I have no way to rule it out.&lt;/p&gt;

&lt;p&gt;What I can do is describe precisely what the documents removed from the critical path, and let you judge whether that is worth the hours. The mechanism matters more than the correlation to me, because the mechanism is the part that transfers to your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The specification is a comprehension test I administer to myself
&lt;/h2&gt;

&lt;p&gt;People assume I write a design down before building it in order to communicate it. Communication is a side effect. Writing it is how I find out whether I actually understand the problem.&lt;/p&gt;

&lt;p&gt;There is a specific and reliable experience involved. Somewhere in the second half of a document, I reach a paragraph I cannot write. The words are not the difficulty. The thing I am trying to describe does not resolve. What happens when both of those conditions are true at once? Which side owns this state? What does the system do when the third case arrives, the one I have been mentally filing as "unlikely"?&lt;/p&gt;

&lt;p&gt;That paragraph is the design flaw, and it has surfaced while it costs a paragraph. The same flaw would surface on its own eventually, after the schema is written, after two features depend on the shape, after something is in production carrying data. The distance between those two moments is most of what people mean when they say a piece of work took longer than expected.&lt;/p&gt;

&lt;p&gt;So the cheapest place for a design to be wrong is in a document, and the second cheapest place is nowhere near as cheap. Everything below is bookkeeping on top of that one observation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three artefacts because they answer three different questions
&lt;/h2&gt;

&lt;p&gt;The counts differ (255, 207, 17) because the three documents do different work and are needed at different rates.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;specification&lt;/strong&gt; says what a thing should do and why, including what it deliberately will not do. That last part earns its place more often than the rest. A written non-goal is the only defence I have found against a feature that grows a third of the way through implementation. "We said explicitly that this was out of scope" is a settled question. "I don't think we should do that" is a conversation.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;implementation plan&lt;/strong&gt; says in what order, what can break, and what has to land before what. It exists because a design being correct says nothing about a sequence being safe.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;runbook&lt;/strong&gt; says how the thing reaches production and how it comes back out. There are only seventeen because a runbook describes a recurring operation rather than a change: staged rollout, feature-flagged release, a forty-eight-hour post-merge soak, rollback procedures, cross-repository dependency ordering, smoke matrices, incident response and on-call handover.&lt;/p&gt;

&lt;p&gt;The runbooks were the ones I nearly did not write. They turned out to have the clearest payback.&lt;/p&gt;

&lt;h2&gt;
  
  
  The runbook exists because of a single point of failure that looked like competence
&lt;/h2&gt;

&lt;p&gt;Releases spanned four repositories with real ordering constraints. Backend routes had to land before the frontend that called them. A web deployment and a mobile over-the-air bundle had to activate together, or a native shell would spend an afternoon calling an endpoint that did not exist yet.&lt;/p&gt;

&lt;p&gt;That ordering lived in my head, and I was good at it, which was the problem. An engineer who reliably gets a complex sequence right looks the same as a documented process right up until the day they are ill or gone. I had been treating "I know the release order" as a strength. It was a single point of failure that felt like one, and the fact that it felt good is what stopped me fixing it sooner.&lt;/p&gt;

&lt;p&gt;Writing it down was the fix. It also made the sequence reviewable, a second-order benefit I did not anticipate. An ordering constraint you can read is one somebody else can find a hole in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the speed actually comes from
&lt;/h2&gt;

&lt;p&gt;Nobody's bottleneck is typing. The expensive things in shipping software are rework and coordination, and specifications attack both.&lt;/p&gt;

&lt;p&gt;Rework, because a design flaw found in a document is fixed by editing the document. Coordination, because a written interface is how two people build against each other without a meeting. That second one was concrete for me. Our AI engineer owned the LangGraph services, the agent workflows and the RAG pipelines. I built the product layer those capabilities were surfaced through (agent configuration, the knowledge base, the agentic rule-authoring interface, the in-product assistant) plus the transport between them. I did not architect the orchestration underneath, and the boundary between us is exactly where a specification pays for itself. Two people can build towards a written interface at the same time. They cannot build towards a remembered one.&lt;/p&gt;

&lt;p&gt;The third piece is a completion standard rather than a document. Nothing counted as done until I had watched it behave correctly in production logs, in the database, or on a real device. I adopted that after being wrong often enough to stop trusting a passing build. The clearest illustration I have is &lt;a href="https://dev.to/writing/the-feature-i-chose-not-to-ship/"&gt;a mobile feature that passed everything and still had to be removed after I reproduced its behaviour on a physical handset&lt;/a&gt;. Specify, implement, then verify in production. That last step is where the specification either turns out to have been true or does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the artefacts turned out to be good for that I did not intend
&lt;/h2&gt;

&lt;p&gt;They are the only part of that work I can still point at. Every repository I have shipped production code into belongs to somebody else, so &lt;a href="https://dev.to/writing/showing-ownership-private-repositories/"&gt;demonstrating ownership becomes a problem of publishing a method rather than an artefact&lt;/a&gt;. Commit shares and blame analysis are self-measured; you are taking my word for the numbers and judging the method. Process artefacts sit differently. They existed in the repositories independently of my description of them, and two co-founders who were there have agreed to act as references and can confirm scope and ownership without me in the room.&lt;/p&gt;

&lt;p&gt;I did not write 255 documents in order to have evidence. But a habit that produces its own record turns out to be worth more than a habit that produces only working software, once the working software is behind an NDA.&lt;/p&gt;

&lt;p&gt;The same discipline runs in my own projects, at a scale suited to them. &lt;a href="https://dev.to/writing/default-deny-rights-documentary-pipeline/"&gt;The autonomous documentary pipeline&lt;/a&gt; carries 25 design specifications committed alongside the code, including a build-versus-buy roadmap with licence analysis per component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I would not write one, and what the counts do not tell you
&lt;/h2&gt;

&lt;p&gt;A specification for a change whose blast radius is smaller than the document is ceremony, and ceremony is what gives specifications their bad reputation. My rule of thumb is to write one when the decision is expensive to reverse, when it crosses a boundary someone else builds against, or when the state it introduces will outlive my memory of why. A copy change or a dependency bump meets none of those. Neither does a contained bug fix.&lt;/p&gt;

&lt;p&gt;The counts are counts of artefacts, not of quality. 255 documents is not 255 good documents, and I would rather say so than present a number as evidence of uniform rigour. The only claim a count of this kind can support is that the habit was consistent. The order is not always clean either. Sometimes the honest way to understand a problem is to build a throwaway first and write down what I learned afterwards, and a document produced that way is still worth having even though it arrived out of sequence.&lt;/p&gt;

&lt;p&gt;There is one more thing this discipline carries. LLM coding tools are central to how I work, and the specification is what makes that safe rather than fast and hopeful. It is the artefact a tool's output can be checked against, something outside my own memory of what I asked for. Working this way is what lets one engineer cover a large surface, and the specs, the tests and the production verification are the reason it holds.&lt;/p&gt;




&lt;p&gt;Ownership evidence and how each figure was measured: &lt;a href="https://dev.to/projects/cendra/"&gt;Cendra&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This essay first appeared on my site, efe-genc-portfolio.vercel.app, where the rest of the series lives. If you have run a small team with a different ratio of writing to shipping, say so. Disagreement is the most useful comment I can get.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>ai</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The Hardest Part of a Proactive Assistant Is Knowing When Not to Speak</title>
      <dc:creator>Efe Genç</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:59:09 +0000</pubDate>
      <link>https://dev.to/efe_genc/the-hardest-part-of-a-proactive-assistant-is-knowing-when-not-to-speak-44f0</link>
      <guid>https://dev.to/efe_genc/the-hardest-part-of-a-proactive-assistant-is-knowing-when-not-to-speak-44f0</guid>
      <description>&lt;p&gt;Almost everything written about proactive AI is about the generating half. How the system notices a pattern, how it phrases the insight, which model reads the calendar. I no longer think that half is the hard part. The hard part is the decision immediately after. Having noticed something true, do you say it?&lt;/p&gt;

&lt;p&gt;A proactive assistant pays a lopsided price for its mistakes. Surfacing something useful earns a little trust. Interrupting at the wrong moment loses a great deal, and users do not give a second chance to a notification stream they have already learned to ignore. Once attention has been trained away from a channel, it does not come back. So the interesting engineering sits on the restraint side, and in my experience that side gets built last.&lt;/p&gt;

&lt;p&gt;I know that because on the first notification system I owned, I built it last.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design that does not work
&lt;/h2&gt;

&lt;p&gt;The common shape is to generate candidate insights, score them, and filter against a threshold. It fails in two specific ways.&lt;/p&gt;

&lt;p&gt;The threshold is a single scalar standing in for many unrelated reasons to stay quiet. "Not this person", "not at three in the morning", "not in the first week", "not again, they have dismissed this three times" and "not today, the budget is spent" are different rules with different owners and different failure modes. Compressing them into one number means none of them can be reasoned about, and tuning any one of them moves all the others.&lt;/p&gt;

&lt;p&gt;And nothing records &lt;em&gt;why&lt;/em&gt; anything was suppressed. A threshold returns false. So the suppression behaviour, which is the most important behaviour in the product, becomes the one part of the system that generates no data, and therefore the one part that cannot be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two questions, two places
&lt;/h2&gt;

&lt;p&gt;The design I settled on in &lt;a href="https://dev.to/projects/lila/"&gt;LILA&lt;/a&gt; separates the questions completely.&lt;/p&gt;

&lt;p&gt;Whether something is worth saying at all is a reasoning problem. It depends on the content, the evidence behind it, and whether the observation is one a product should be making. It has nothing to do with the time of day.&lt;/p&gt;

&lt;p&gt;Whether it should be said now, to this person, on this surface, is a policy problem. It depends on consent, preferences, timezone, history and budget. It has nothing to do with how interesting the insight is.&lt;/p&gt;

&lt;p&gt;They live in different places in the codebase, and only the first involves a model. Keeping them apart is what lets me change the phrasing of an insight without touching a single rule about when a user may be interrupted, and change the quiet-hours logic without any risk of altering what the system notices.&lt;/p&gt;

&lt;h2&gt;
  
  
  One gate, twelve checks, in order
&lt;/h2&gt;

&lt;p&gt;Everything the system might say passes through a single delivery gate. Twelve checks, evaluated in a fixed order. First an engine kill-switch, a production hard-stop that silences every producer at once. Then consent, whether proactive behaviour is enabled on the profile, operating mode, a global snooze, a per-type mute, the user's intensity setting, timezone-aware quiet hours, a seven-day trust ramp for new users, a dismissal cooldown, and a daily interaction budget. Quiet hours can be bypassed only above a priority floor. The cooldown triggers when a user has dismissed three suggestions of a type within thirty days, and it buys a week of silence.&lt;/p&gt;

&lt;p&gt;On rejection the gate logs the specific reason and returns it. On allow it returns the set of surfaces the suggestion should be routed to: feed, push, chat or voice.&lt;/p&gt;

&lt;p&gt;I chose one gate rather than checks scattered through the pipeline for three reasons, and I would defend each of them.&lt;/p&gt;

&lt;p&gt;It is the only way to answer "why was the user not told about this". With checks distributed across a pipeline, the honest answer is "somewhere, something returned false". With one gate and a logged reason, the question has an answer, and the answer is a metric.&lt;/p&gt;

&lt;p&gt;Ordering is a design decision and it should be visible. Consent has to come before everything, or you have evaluated preferences for a user who never agreed to be contacted. Quiet hours have to come before the daily budget, or an item that arrives overnight consumes budget it was never eligible to spend. Ordering that is spread across a codebase is ordering nobody controls.&lt;/p&gt;

&lt;p&gt;Adding a rule is one change in one place. The dismissal cooldown was added long after the original design, the kill-switch later still, and in August 2026 an adaptive-timing check that does not reject at all. It strips the push surface during hours the user has historically dismissed and lets the suggestion wait in the feed. Each was a single insertion into an ordered list. None of them needed an audit of every path that could reach a user.&lt;/p&gt;

&lt;p&gt;The check I would defend hardest is the trust ramp. For the first seven days a new user hears from the system only when priority is high. A proactive assistant is at its least calibrated exactly when the user is deciding whether to trust it, which is the worst possible moment to be talkative. Being quiet early is what buys permission to be useful later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The log turns suppression into a distribution
&lt;/h2&gt;

&lt;p&gt;Because every rejection is recorded with its reason, the operational question stops being "how many notifications did we send today". It becomes: of everything the system considered surfacing, how much did it suppress, and under which rule?&lt;/p&gt;

&lt;p&gt;That distribution tells you things a send count never can. Heavy suppression on quiet hours means detection is running at the wrong time of day, and the rule itself is probably fine. Heavy suppression on the daily budget means the correlation stage upstream is under-grouping and producing three suggestions where there was one situation. Heavy suppression on intensity means confidence calibration has drifted. You cannot see any of that if you only count what was sent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then you have to measure the silence
&lt;/h2&gt;

&lt;p&gt;A gate you cannot measure is a set of guesses with good intentions. The uncomfortable thing about evaluating restraint is that ordinary evaluation datasets cannot express it. They pair an input with an expected output, and there is no natural way to write down "and here, correctly, nothing happened". So those cases never get built, and the metric ends up rewarding a system that talks too much.&lt;/p&gt;

&lt;p&gt;Scoring silence needs datasets constructed from the opposite direction: situations that &lt;em&gt;look&lt;/em&gt; like they contain a pattern and do not, or that contain one too weak or too personal to act on. The expected output is nothing, and the system is penalised for speaking.&lt;/p&gt;

&lt;p&gt;Silence is one of five dimensions in the pattern-detection rubric. The others are accuracy, confidence calibration, evidence, and what I call product truth, meaning whether an observation is one the product should make even when it is entirely correct. A pattern can be real and well-evidenced and still be something a user would find intrusive to have been noticed. Silence and product truth took the longest to get right, and they are the two no generic evaluation framework hands you.&lt;/p&gt;

&lt;p&gt;The result changed the product rather than just the dashboard. Restraint stopped being an implicit hope inside a prompt and became a measured behaviour with a number attached, which meant it could be regressed against. That is the only reason I trust the gate's thresholds at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is still weak
&lt;/h2&gt;

&lt;p&gt;Insight wording is scored by a separate model against a written rubric covering tone, judgement-free phrasing, privacy, evidence and actionability. It is the right tool for qualities that resist assertion-based testing. It is also the weakest part of the harness. Judges drift, they are sensitive to rubric wording, and mine is not calibrated against human raters. I treat judge scores as a regression signal, a way of asking whether this got worse, rather than as an absolute measure of quality. Establishing human agreement on a sample is the obvious next piece of work and it is not done.&lt;/p&gt;

&lt;p&gt;The gate's daily budget started as an in-memory counter keyed by user and date. That was correct for a single instance and wrong the moment the service scaled horizontally. It now lives in Redis under the same key, incremented atomically, and falls back to the in-memory counter when Redis is unreachable. The fallback fails open, so a Redis outage means a user could briefly get more than their daily allowance rather than nothing at all. I chose that direction on purpose, it is written down, and I would rather say it than have it found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I am confident this is the right shape
&lt;/h2&gt;

&lt;p&gt;Because I built the same thing in the opposite order first, and watched it not work.&lt;/p&gt;

&lt;p&gt;At Cendra I owned the notification and real-time system end to end, down to &lt;a href="https://dev.to/writing/one-outbox-record-per-notification/"&gt;the single outbox record that drove every channel&lt;/a&gt;. My initial design treated delivery as the problem and suppression as a later refinement. That ordering was mine and it was wrong. Volume is easy to add and very hard to take back once users have adjusted to it, so a notification system needs a suppression model before it needs a delivery model. The correction was a three-phase programme: event classification to separate the events people need to hear about from telemetry, then preference gating, rate limiting, recipient filtering and collapse keys. It eliminated approximately 19,000 unnecessary push notifications a day. That figure was measured in production log telemetry over a ten-minute observation window against the prior baseline and then scaled to a daily rate. It is not a directly observed twenty-four-hour count, and I would rather qualify it than round it up.&lt;/p&gt;

&lt;p&gt;LILA is what happens when you build the suppression model first. It is my own project, roughly nine and a half thousand commits since February 2026, self-counted in a private repository I own, with nobody else to verify it. So the decisions in it are mine to defend, including the ones above that I have not finished.&lt;/p&gt;

&lt;p&gt;The generation half of a proactive assistant is a solved-enough problem that you can buy it. The restraint half is the product, and it will decide whether anybody still has notifications switched on in a month.&lt;/p&gt;




&lt;p&gt;Both systems are written up in more detail: &lt;a href="https://dev.to/projects/lila/"&gt;LILA&lt;/a&gt; for the gate, the evaluation harness and &lt;a href="https://dev.to/writing/surviving-your-ai-providers/"&gt;the model gateway&lt;/a&gt;, and &lt;a href="https://dev.to/projects/cendra/"&gt;Cendra&lt;/a&gt; for the notification work that taught me the ordering.&lt;/p&gt;




&lt;p&gt;This essay first appeared on my site, efe-genc-portfolio.vercel.app, where the rest of the series lives. If you have shipped a proactive system and disagree with any of this, say so. Disagreement is the most useful comment I can get.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>productdesign</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
