home.social

Search

29 results for “pears”

  1. Join Linux Professional Institute (LPI) in showing Pearson VUE the demand for support on its OnVUE online proctoring platform.

    Help make Linux a supported operating system on .

    Add your voice: lpi.org/99s8

  2. There are about 3,000 types of pears, which vary in taste and shape. One medium-sized pear contains around 101 calories, carbohydrates (27 g), fat (0.1g), protein (1.0 g), Vitamins C, D, K, Potassium, Copper, Calcium, flavonoids, phenolics, and triterpenes.

  3. Take your exam with extra peace of mind!

    Opt into this special promotion and then schedule & complete your LPI exam with Pearson VUE from September 29 through November 17, 2026. If you don’t pass your first attempt, you may qualify for one free retake.

    A limited-time offer from , LPI’s global exam partner.

    Learn more: lpi.org/m4iq

  4. Here's something I like to make in my tiki lounge. I call it the Praia Brain Fucker.

    Half-fill a cocktail shaker with ice. Into this pour the juice of 2 pears. Add 4 measures of moonshine. Top up with the tears of a newt. Shake alluringly for 13 minutes, then strain into a pewter tankard. Vives!

    This is #JohnMastodon, signing out.

  5. 🌿🍇🍎 Espalier fruit trees are space-saving, beautiful, and productive! Train apples, pears, or figs flat against a wall or trellis for stunning architectural interest and easy harvesting. A perfect blend of art and horticulture!

  6. RE: flipboard.com/@blogto/blogto-8

    It is not safe to travel to the . Another tragedy barely avoided:

    “An Air Canada Express flight that was bound for this week was abruptly ordered by air traffic control to stop just a few seconds after it received clearance to take off at a U.S. airport, at the same time as another aircraft was approaching the runway to land.

    The incident took place on Tuesday morning at Lambert St. Louis International Airport in , where the Air Express flight, operating as AC8886, was preparing for its departure to Pearson Airport.

    The flight, which was operated by Jazz Aviation, had already been cleared to take off from the runway when an air traffic controller abruptly cancelled the clearance, as a Southwest Airlines Boeing 737 was approaching the runway to land.

    According to audio shared by aviation YouTube channel VASAviation, the control tower gave clearance to the Southwest flight before instructing Air Canada to proceed with its takeoff on the same runway.”

  7. @justinjpearson.bsky.social votejustinj.com

                     #AMERICA !! This one's for #Democracy !!
                            #YourVOTE: #USE.ITorLOSE.IT

                     #VOTE.EARLY and OFTEN ‼️😅 🇺🇸

          🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
         #FIRED.UP !?! #READY.to.VOTE ?!! #VOTE.BLUE💯

    RE: https://bsky.app/profile/did:plc:lgrfu4eq4ohryrjkgh6ybxyw/post/3myix5yxivs2f


    Justin J. Pearson for U.S. Con...

  8. I finished it in 30 minutes, but Grease Trap ‘99 is some silly fun. Ran fine on the too.

    store.steampowered.com/app/450

  9. NestJS v11.2.8

    ParseArrayPipe with items Number now rejects non-numeric items; ParseArrayPipe now rejects arrays nested in its items; Stripping prototype keys now skips array holes; DefaultValuePipe now copies array and object defaults; JSON log records are now cut short past a million characters; A falsy…

    whatsnew.fyi/product/nestjs/re

    #NestJS #Programming

  10. 🌶️ HOT TAKE🌶️

    "Parsec is a time word, because the boundary between space and time is merely an illusion perpetrated upon us by the limitations of our five senses.
    I WILL DIE ON THIS HILL."

    --Han Solo

    #StarWars
    #Movies
    #Film

  11. I was reading an allocation profile for a request handler that parses a line of comma-separated numbers off an upstream feed. The parse itself is three lines. Nothing in it says new. So I wasn't expecting the fat column of string and string[] allocations sitting right on top of it, climbing every second the feed stayed busy.

    They were coming out of one method call: line.Split(',').

    Where the bytes come from


    Here's the parser, more or less how I'd written it and how I've written it a hundred times before:

    static long ParseWithStringSplit(string line)
    {
    long sum = 0;
    foreach (string field in line.Split(','))
    sum += int.Parse(field, CultureInfo.InvariantCulture);
    return sum;
    }

    Clean, correct, reads like a sentence. The problem is Split. For a line with sixteen fields it hands you back a string[] of length sixteen, and every one of those sixteen entries is a freshly allocated string holding one little number. That's an array plus sixteen substrings on the heap, used for a few microseconds, then dropped on the floor for the GC to sweep up. You call it once at startup and nobody cares. You call it a few thousand times a second and it's a steady drip into gen 0, and gen 0 collections aren't free.

    The thing is, I didn't actually want those substrings. I never kept them. I parsed each one into an int and threw the string away. I was allocating sixteen strings purely to look at sixteen slices of a string I already had in my hand.

    The span version never makes the substrings


    Since .NET 8 there's a split that works directly over a ReadOnlySpan<char> and gives you back Range values instead of strings. You slice into the original span yourself, and int.Parse has taken a span since .NET Core 2.1, so nothing ever gets copied into a new string:

    static long ParseWithSpanSplit(string line)
    {
    long sum = 0;
    ReadOnlySpan<char> span = line;
    foreach (Range r in span.Split(','))
    sum += int.Parse(span[r], CultureInfo.InvariantCulture);
    return sum;
    }

    The logic is identical. The only difference is Range r instead of string field, and span[r] instead of the field. span[r] isn't a copy, it's a window onto the characters already sitting in line. No array, no substrings, nothing for the collector to chase.

    I counted it


    I don't trust my own intuition about allocations, so I wrote the smallest thing that would show the gap. Same sixteen-field line, both parsers, five million calls each. I read GC.GetAllocatedBytesForCurrentThread() around each loop and took the best of seven rounds. Here's the output:

    Both parsers sum the line to 7074. Good.

    string.Split: 3,080,000,040 bytes, 1657.5 ms (best of 7)
    span Split : 40 bytes, 1105.2 ms (best of 7)

    Allocated per call: string.Split 616 B, span 0 B
    Time ratio (best of 7): span is 1.50x the throughput of string.Split

    616 bytes a call to add up sixteen numbers. The span version: a flat 40 bytes for the whole five-million-call run, which rounds to zero per call. That 40 is a one-time constant, not something that scales with the work.

    I ran it a few times and the allocation numbers didn't move a single byte, which is what I'd expect since they're structural. The timing wandered between about 1.5x and 1.7x the throughput depending on the round. I'm on a shared two-core container, not a quiet benchmark box, so I trust the allocation figure a lot more than the milliseconds. The honest read is: the span path is clearly faster here, and the real, repeatable win is that it stops allocating entirely.

    When I don't bother


    I'll say the obvious part out loud, because it's the part that matters more than the benchmark. If your parse runs once when the app boots, 616 bytes is nothing. Don't go rewriting readable code to save a few hundred bytes you allocate at startup and never again. string.Split is clearer, and clearer wins when the perf doesn't matter.

    There are real limits to the span split too, and they bit me the first time I reached for it. It splits on every occurrence of the separator, full stop. There's no StringSplitOptions.RemoveEmptyEntries, no trimming, no cap on the number of pieces. If your input has empty fields you care about skipping, or you want the "split into at most 3" behaviour, you're either back on string.Split or writing that logic by hand. And because a span is a ref struct, this parser has to stay synchronous. You can't stash the span in a field or carry it across an await, so the moment your parsing wants to be async, this shape stops working.

    So my rule is narrow on purpose. When the parse is sitting in a loop that runs often and I can see it in a profile, I switch to the span split and the allocations just disappear. Everywhere else I leave string.Split alone, because the only thing I'd be buying is a worse-looking method.

    Here's the whole thing if you want to run it yourself. New console project targeting net10.0, drop this in Program.cs, dotnet run -c Release:

    using System.Diagnostics;
    using System.Globalization;

    const string line = "1024,37,8,512,9,1,4096,16,64,2,128,256,7,3,900,11";

    long expected = ParseWithStringSplit(line);
    long actual = ParseWithSpanSplit(line);
    if (expected != actual) { Console.Error.WriteLine("Parsers disagree"); return 1; }
    Console.WriteLine($"Both parsers sum the line to {expected}. Good.\n");

    const int iterations = 5_000_000;
    const int rounds = 7;

    var (splitBytes, splitMs) = Measure("string.Split", iterations, rounds, ParseWithStringSplit, line);
    var (spanBytes, spanMs) = Measure("span Split ", iterations, rounds, ParseWithSpanSplit, line);

    Console.WriteLine($"\nAllocated per call: string.Split {splitBytes / (double)iterations:F0} B, span {spanBytes / (double)iterations:F0} B");
    Console.WriteLine($"Time ratio (best of {rounds}): span is {splitMs / spanMs:F2}x the throughput of string.Split");
    return 0;

    static (long bytes, double ms) Measure(string name, int iterations, int rounds, Func<string, long> parse, string line)
    {
    long bestBytes = long.MaxValue;
    double bestMs = double.MaxValue;
    for (int r = 0; r < rounds; r++)
    {
    long acc = 0;
    long before = GC.GetAllocatedBytesForCurrentThread();
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++) acc += parse(line);
    sw.Stop();
    long bytes = GC.GetAllocatedBytesForCurrentThread() - before;
    if (acc == long.MinValue) Console.WriteLine(acc); // keep acc observable
    bestBytes = Math.Min(bestBytes, bytes);
    bestMs = Math.Min(bestMs, sw.Elapsed.TotalMilliseconds);
    }
    Console.WriteLine($"{name}: {bestBytes,14:N0} bytes, {bestMs,8:F1} ms (best of {rounds})");
    return (bestBytes, bestMs);
    }

    static long ParseWithStringSplit(string line)
    {
    long sum = 0;
    foreach (string field in line.Split(','))
    sum += int.Parse(field, CultureInfo.InvariantCulture);
    return sum;
    }

    static long ParseWithSpanSplit(string line)
    {
    long sum = 0;
    ReadOnlySpan<char> span = line;
    foreach (Range r in span.Split(','))
    sum += int.Parse(span[r], CultureInfo.InvariantCulture);
    return sum;
    }

    Do you reach for the span split by default, or only after a profiler points at it? I'm curious where other people draw that line.

    — still counting bytes nobody asked me to count#csharp #dotnet #programming #webdev #software #coding #development #engineering #inclusive #community
    616 Bytes to Add Up Sixteen Numbers

  12. Je viens de faire une pause dans La saga des 7 soleils( Kevin J. Anderson), un Péplum spatial de 4000 pages. L'histoire est intéressante et pars dans tous les sens. Le gros reproche est le chapitrage, ou l'on suit une tranche de vie d'un personnage sur 4~5 pages et on saute au suivant sans possibilité de s'identifier. C'est pour cela que je fais une pose a 2000 pages.
    Je commence donc les sœurs démentes d 'Esi ( Tashan Mehta) qui a l'air bien barré
    #VendrediLecture #sf

  13. So, I've been working on this, and realised just how frustrating parsing CLI args can be and how much heavy lifting clap really does as a library. I'm off to having written things in a .... different way.

    Just to explain more, this is the requirement:

    • I want global --config and --config-opt flags that can be placed anywhere
    • I want to allow command aliases
    • I want to allow default commands
    • I want to allow all of that to be set from the config options
    • Unlike jujutsu (which allows all of the above), I want to let them set it anywhere from the CLI args as well

    The simplest way I've found to do this is to have a prior pass over all the arguments on my own, collect the remaining options out, and then use the options I've parsed to create a config stack (similar to Jujutsu), so you can override the config values at any given level.

    I've wasted an entire day with clap in trying to achieve this with no avail. I guess it's good, I can write my own, after all.

    I do need to thin down the dependencies though. syn is creeping in from somewhere, and oh god do I hate that library and any other that uses that with such burning passion.

    #rust #projectupdate #clap #cli

  14. In git checkout, a 40-character hex string does not always mean a commit. Claude Code before 2.1.179 pinned plugins to a SHA but never checked HEAD after checkout, so an upstream branch named after that SHA installed instead of the reviewed commit (CVE-2026-86063, found by Or Nevo Michrowski of Air Security). If you pin by hash anywhere, assert that git rev-parse HEAD equals the pin.

    github.com/advisories/GHSA-pq7

    #Cybersecurity #AIAgents #Git #SupplyChain

  15. I needed a bar chart from a client spreadsheet. Names, invoice totals, a few formulas. Every “paste your CSV” tool I opened wanted an account, a POST, or both. The data wasn’t secret in a compliance sense — it just wasn’t something I wanted sitting in someone else’s temp bucket for a week.

    So I built the pipeline in the tab: parse → choose encodings → render → export. No upload step. The file never leaves the machine.

    This isn’t a product pitch. It’s the shape of a local-first chart path that frontend folks keep reinventing, and the places it usually breaks.

    What “local-first” means for charts


    Local-first here is boring and specific:

    1. Parse in the browser — FileReader / drag-drop / paste from Sheets
    2. Infer or pick columns — which field is the category, which is the measure
    3. Render with a client library — ECharts, Chart.js, Observable Plot, whatever you already ship
    4. Export as a blob — PNG / SVG / CSV download via URL.createObjectURL

    Nothing in that list needs a chart SaaS. The temptation is to outsource step 2–4 because “AI will pick the right chart type.” You can still do that locally (WebLLM, Ollama on localhost, or a heuristic). The point is the CSV bytes don’t have to cross a trust boundary to get a PNG.

    Where paste-and-upload usually goes wrong


    I’ve used a lot of hosted plotters. The friction isn’t the UI — it’s the data path:

    • Silent retention — “we delete in 24h” is a promise, not a guarantee you can verify
    • Account gates — free tier wants email before you see a download button
    • Column renaming — the service “helps” by rewriting Invoice Total ($) into value, then your export no longer matches the source sheet
    • One more network hop — a flaky Wi‑Fi day turns a five-minute chart into a support ticket

    For internal ops sheets and freelance client data, that path is the wrong default. The silicon is already on the desk.

    A minimal pipeline that stays in the tab


    Here’s the skeleton I keep coming back to.

    1. Ingest without a server

    async function readTable(file) {
    const text = await file.text();
    // or Papa Parse / d3-dsv for quoted fields and European decimals
    return parseCsv(text);
    }

    Paste from Sheets is often more useful than file pick: listen for paste, read clipboardData.getData("text/plain"), split on tabs.

    2. Separate “table” from “chart spec”

    Don’t bake chart type into the parser. Keep a plain array of row objects, then a small spec:

    type ChartSpec = {
    type: "bar" | "line" | "pie";
    x: string; // column name
    y: string; // column name
    title?: string;
    };

    If you later add an agent to suggest type / x / y, feed it column names and sample rows — not the whole file to a remote API unless the user opted in.

    3. Validate the spec against real columns

    This is the bug that burns people. Models invent a column called value. Heuristics pick the first numeric field even when it’s an ID. Validate:

    function assertSpec(spec, columns) {
    if (!columns.includes(spec.x) || !columns.includes(spec.y)) {
    throw new Error("spec points at missing columns");
    }
    }

    Fail loud. Fall back to a deterministic guess only after the fancy path fails.

    4. Render and export as blobs

    ECharts (and most canvas/SVG libs) can getDataURL or serialize SVG. Wrap that in a download:

    function downloadPng(dataUrl, name = "chart.png") {
    const a = document.createElement("a");
    a.href = dataUrl;
    a.download = name;
    a.click();
    }

    No FormData to /api/export. No “email me the PNG.”

    Optional AI without giving up local


    If you want “make this a pie” or “title it June collected,” you have three honest options:

    ApproachData leaves machine?Good forHeuristic (column types + cardinality)NoDefault first chartLocal model (WebLLM / Ollama)No*Spec suggestionsHosted LLMYes, unless you redactOnly with explicit opt-in


    *First weight download or 127.0.0.1 still isn’t “upload the CSV to a chart vendor.”

    I treat AI as a spec suggester, not a renderer. The table and the canvas stay under your code. The model returns JSON; you validate; you draw. If validation fails three times, ship the heuristic chart anyway — a wrong-but-local bar chart beats a spinner waiting on a remote plot API.

    DX checklist before you reach for SaaS


    When I’m tempted to paste into a hosted tool, I ask:

    1. Does this sheet contain names, amounts, or anything I wouldn’t put in a public Gist?
    2. Do I already have a chart library in the app or a side panel?
    3. Is the job “one PNG for a slide” or “ongoing dashboard with auth”?
    4. Can export be a blob download in under fifty lines?

    If (1) is yes and (3) is a one-off, local wins. Hosted dashboards still make sense for multi-user live data. One-shot client charts usually don’t need that architecture.

    What I’d ship in a weekend spike


    • Drag-drop + paste ingest
    • Column picker (manual) with a heuristic default
    • One chart type done well (bar), then line/pie
    • PNG + SVG export
    • A toggle: “suggest encodings with local model” — off by default

    That’s enough to stop uploading spreadsheets for a title slide. You can grow it later with saved specs in localStorage, themes, or an agent that only sees column headers.

    The pattern matters more than any one library: keep the bytes on the device until the user explicitly chooses otherwise. Charts are a perfect fit for that rule — the input is a file you already have, and the output is a file you want back.

    Next time a tool asks you to create an account before it will draw bars from your own CSV, that’s a signal. The pipeline above fits in a single page. Build that page once, and the upload prompt gets a lot easier to ignore.#frontend #localfirst #dx #webdev #software #coding #development #engineering #inclusive #community
    Local-First Chart Pipeline: CSV Chart Export Without Third-Party Upload

  16. AI is ruining hobby programming projects. Here's Chris Person for @Aftermath on how. "What I always valued about these projects most was the care, and my heart is filled with joy when I see people that still do. But it’s getting harder to parse that part out."

    flip.it/--8gty

    #SoftwareEngineering #AI #Technology

  17. If you spend a lot of time on the command line, you probably use a lot. You probably timestamp new files like,

    » touch `date +%s`-log.txt

    or in 5

    » echo $EPOCHSECONDS >> log.txt

    I have, and do, and was frustrated with how difficult Unix time is to parse visually. I was always questioning how long ago something was, or what it was near, or whether all those digits were necessary, and when the year rolled over, etc.

    That's why I developed .

  18. Navigating a restaurant menu can feel overwhelming—especially when you’re balancing taste preferences, dietary goals, and nutritional concerns. With the explosion of AI food tech in recent years, a new era of “smart menu” experiences is emerging. AI menu analysis isn’t just about digitizing paper menus; it’s fundamentally transforming how diners discover, understand, and choose their meals. From estimating hidden calories to surfacing dishes tailored to your preferences, these innovations are reshaping both dining out and online ordering.

    The Challenge: Decoding Restaurant Nutrition


    Most diners want to make informed choices, but restaurant nutrition information is often buried, incomplete, or absent altogether. Even when calorie counts are available, they rarely account for personal needs—like allergies, macros, or dietary restrictions. Manually scanning for options that fit your criteria can be tedious and error-prone, especially at busy or unfamiliar restaurants.

    This is where AI menu analysis comes in. By leveraging machine learning, natural language processing, and computer vision, AI-powered systems can extract, interpret, and enhance menu data at scale. The result: more transparent, personalized, and actionable restaurant nutrition insights for both diners and operators.

    How AI Menu Analysis Works

    1. Menu Digitization and Parsing


    The first step is converting static menus into machine-readable data. AI models (often using OCR—Optical Character Recognition) can scan printed or photographed menus and extract structured information. Natural language processing (NLP) is then applied to parse dish names, descriptions, and even detect ingredient lists.

    // Example: Simple menu item extraction using regex and NLP concepts
    const menuText = `
    Grilled Salmon Salad - Fresh greens, grilled salmon, avocado, and vinaigrette. 450 kcal
    Classic Burger - Beef patty, cheddar, lettuce, tomato, brioche bun. 800 kcal
    `;

    const dishRegex = /(.*?)\s*-\s*(.*?)\.\s*(\d+)\s*kcal/gi;
    const menuItems = [];
    let match;

    while ((match = dishRegex.exec(menuText)) !== null) {
    menuItems.push({
    name: match[1].trim(),
    description: match[2].trim(),
    calories: parseInt(match[3], 10)
    });
    }

    console.log(menuItems);

    Real-world systems go much further, handling inconsistent formatting, synonyms, and multilingual content.

    2. Nutritional Value Estimation


    Many menus lack detailed nutrition facts. AI can bridge these gaps by analyzing dish descriptions and predicting nutrition profiles. This typically involves:

    • Ingredient recognition: Identifying possible ingredients based on dish names and descriptions.
    • Recipe inference: Estimating likely preparation methods and quantities.
    • Database matching: Mapping extracted ingredients to known nutrient databases (like USDA or Open Food Facts).

    Machine learning models trained on vast recipe and nutrition datasets can predict calories, macros, and even allergen presence with surprising accuracy.

    // Pseudo-code: Predicting calories for a dish using AI
    async function estimateDishCalories(dishDescription: string): Promise<number> {
    // This would call an AI model or API trained on recipe/nutrition data
    const estimated = await callCaloriePredictionModel(dishDescription);
    return estimated.calories;
    }

    3. Personalization and Smart Recommendations


    AI menu analysis unlocks highly personalized experiences:

    • Dietary filtering: Instantly flagging dishes that fit vegan, gluten-free, or keto diets.
    • Allergen detection: Highlighting items that may contain peanuts, shellfish, or other triggers.
    • Preference learning: Recommending dishes based on past orders, ratings, or explicit preferences.
    • Health scoring: Ranking menu items by metrics like calorie density, sodium content, or “healthiness” for the user.

    Some apps leverage collaborative filtering (like Netflix or Spotify) to surface dishes that similar users have enjoyed. Others use reinforcement learning to improve suggestions over time.

    // Example: Filtering menu items for a vegetarian user
    const vegetarianKeywords = ['vegetable', 'cheese', 'tofu', 'salad', 'beans'];
    function isVegetarian(dish: { description: string }) {
    const desc = dish.description.toLowerCase();
    return vegetarianKeywords.some(keyword => desc.includes(keyword));
    }

    const vegetarianOptions = menuItems.filter(isVegetarian);
    console.log(vegetarianOptions);

    4. Enhanced Menu Interfaces


    Modern “smart menu” platforms use AI to power interactive interfaces, both on-premise (via tablets or QR codes) and online. Features include:

    • Dynamic search: Type “high-protein, under 500 calories” and see instant matches.
    • Visualizations: See nutrition breakdowns, allergen alerts, or compare dishes side-by-side.
    • Voice assistants: Ask for “spicy vegan options” and get spoken recommendations.

    This not only improves accessibility for all diners, but also helps restaurants stand out in a crowded market.

    AI Food Tech in Action


    A growing ecosystem of AI food tech products is making these features widely available:

    • Restaurant apps and POS systems: Many now integrate AI-driven nutrition and filtering.
    • Third-party platforms: Apps like Yummly, OpenMenu, and LeanDine offer AI-powered menu analysis, personalized recommendations, and nutrition transparency across thousands of restaurants.
    • Custom deployments: Some restaurant groups build proprietary AI models tailored to their cuisine and customer base.

    On the backend, open-source libraries (such as spaCy for NLP, or TensorFlow for custom ML models) enable developers to integrate AI menu analysis into their own applications.

    Challenges and Considerations


    While the potential is tremendous, deploying AI menu analysis at scale isn’t trivial:

    • Data quality: Menus are notoriously inconsistent—misspellings, colloquial names, and “secret sauce” ingredients can trip up even the best models.
    • Cultural and regional variation: Dishes with the same name can differ wildly in composition.
    • Privacy and consent: Personalization requires collecting user preferences and sometimes health data, raising important privacy questions.
    • Model transparency: Explaining how calorie or allergen predictions are made is essential for trust and regulatory compliance.

    Addressing these challenges requires careful engineering, ongoing model retraining, and clear communication to both restaurants and diners.

    Building a Simple AI-Driven Smart Menu (Example)


    Suppose you want to provide a “smart menu” experience in your own restaurant web app. At a high level, you’d:

    1. Digitize the menu (via OCR, manual entry, or import).
    2. Parse dish descriptions and structure the data.
    3. Augment with nutrition estimates using an AI API or open database.
    4. Add filtering and ranking based on user dietary preferences.
    5. Display results in a user-friendly, interactive UI.

    Here’s a simplified TypeScript-style sketch:

    type MenuItem = {
    name: string;
    description: string;
    calories?: number;
    isVegan?: boolean;
    };

    function filterMenu(
    items: MenuItem[],
    { maxCalories, veganOnly }: { maxCalories?: number; veganOnly?: boolean }
    ): MenuItem[] {
    return items.filter(item => {
    if (maxCalories !== undefined && (item.calories ?? Infinity) > maxCalories) {
    return false;
    }
    if (veganOnly && !item.isVegan) {
    return false;
    }
    return true;
    });
    }

    // Example usage:
    const smartMenu = filterMenu(menuItems, { maxCalories: 500, veganOnly: true });

    You could further extend this with AI-powered search, nutritional scoring, or even integration with fitness tracking apps.

    The Road Ahead


    The fusion of AI menu analysis and restaurant nutrition transparency is just beginning. As machine learning models improve and data becomes richer, expect even more granular, actionable insights—like real-time portion customization, automatic pairing suggestions, or even “health nudges” based on your goals.

    For both diners and restaurants, smart menus powered by AI food tech are making eating out (and ordering in) a more informed, inclusive, and enjoyable experience.

    Key Takeaways


    • AI menu analysis transforms static restaurant menus into dynamic, personalized, and nutrition-aware experiences.
    • Restaurant nutrition information is becoming more transparent and actionable through machine learning and NLP.
    • Smart menu systems enable dietary filtering, allergen detection, and personalized recommendations at scale.
    • A host of AI food tech solutions—from open-source libraries to commercial platforms—make integration possible for developers and restaurants of all sizes.
    • Challenges remain around data quality, privacy, and transparency, but the future of AI-powered dining is bright—and getting smarter with every meal.


    #ai #healthtech #webdev #tutorial #software #coding #development #engineering #inclusive #community
    How AI Is Making Restaurant Menus Easier to Navigate

  19. An agent can behave differently on Tuesday even when nobody changed its prompt or application code. A package resolves to a newer release, an MCP server updates a tool description, a model alias moves, or a tool image is rebuilt. The workflow still starts. The tests may still be green. But the agent is no longer the runtime you reviewed.

    That is why a normal package-lock.json is necessary but incomplete for an AI feature. It pins part of the application, while the agent also depends on models, prompts, tool servers, policy bundles, retrieval configurations, and external packages. Treat those as one dependency graph. Then record the resolved graph in an AI agent dependency lockfile.

    This is not a claim that a lockfile makes an agent safe. It gives you a specific, reviewable answer to a much more useful question: what exactly did this agent run with? That answer makes bad changes easier to spot, reproduce, and roll back.

    What belongs in an agent dependency lockfile?


    Start with dependencies that can change behavior or permissions without changing the business workflow. A useful lockfile records both the requested selector and the resolved identity.

    DependencyWeak referenceUseful locked identityModelfast-modelprovider, model revision or immutable deployment IDPromptsupport-v3repository commit and content digestMCP toolbilling-tools:latestimage/package digest, server version, tool-schema digestLibraryagent-sdk:^4exact package version and integrity hashPolicydefault-policypolicy bundle digest and decision versionRetrieval confighelp-centerindex revision, embedding model, and chunking config digest


    The point is not to freeze every choice forever. The point is to separate intent from resolution. latest can remain an input to an update job, but it should not be the only record of what production executed.

    The trap: configuration looks less risky than code


    Teams often review source changes carefully and accept an environment variable such as MODEL=fast-model or TOOLS_URL=https://tools.internal as harmless wiring. In an agent system, that wiring can change output quality, tool availability, permissions, latency, or data handling.

    The same issue appears with agent-installed dependencies. If a coding agent adds a package because it recognizes a familiar name, the pull request can hide a new transitive tree behind one import. If an agent fetches a tool server by a mutable tag, an image rebuild can change the runtime after review. Current public guidance on agent supply chains explicitly includes models, agents, libraries, developer tools, and MCP-server packages in scope. The boundary is wider than requirements.txt.

    A small lockfile format that is easy to review


    Use a format your tools can parse and your reviewers can read. JSON is convenient for CI, though YAML or TOML works too. This example deliberately avoids storing credentials and raw customer data.

    {
    "lockVersion": 1,
    "agent": {
    "name": "refund-assistant",
    "workflowCommit": "8e9b1f2",
    "policy": {
    "selector": "refund-policy",
    "resolvedDigest": "sha256:6b4d..."
    }
    },
    "model": {
    "selector": "support-fast",
    "provider": "example-provider",
    "resolvedId": "support-fast-2026-10-18"
    },
    "prompts": [{
    "path": "prompts/refund.md",
    "gitCommit": "8e9b1f2",
    "sha256": "f18c..."
    }],
    "tools": [{
    "name": "get_order",
    "serverImage": "registry.example/tools@sha256:a91d...",
    "serverVersion": "2.4.1",
    "schemaSha256": "ce33...",
    "scopes": ["orders.read"]
    }],
    "packages": {
    "agent-sdk": { "version": "4.2.3", "integrity": "sha512-..." }
    },
    "retrieval": {
    "indexRevision": "kb-2026-10-23-04",
    "embeddingModel": "embed-small-r17",
    "chunkerDigest": "sha256:9d70..."
    }
    }

    Two details matter here. First, the selector preserves the human-facing intent, while the immutable ID or digest preserves what actually resolved. Second, the lockfile captures only references and hashes. A lockfile should never become a second secret store.

    Generate the file; do not hand-edit it in production


    Create one command that resolves inputs, validates them, and writes a canonical lockfile. A minimal TypeScript-style sketch looks like this:

    type ResolvedTool = {
    name: string;
    serverImage: string;
    schemaSha256: string;
    scopes: string[];
    };

    async function lockTool(name: string): Promise<ResolvedTool> {
    const server = await registry.resolveImmutableImage(name);
    const schema = await mcp.inspect(server.digest);

    if (!schema.tools.every(tool => allowedTools.has(tool.name))) {
    throw new Error(`Unexpected tool exposed by ${name}`);
    }

    return {
    name,
    serverImage: server.digest,
    schemaSha256: sha256(stableJson(schema)),
    scopes: minimalScopes(schema)
    };
    }

    Canonical serialization is important. If equivalent JSON can produce different bytes, a hash diff becomes noise. Sort keys, normalize line endings, and write the generated file deterministically. Commit it next to the workflow definition just as you commit an ordinary package lockfile.

    Make dependency diffs a release gate


    A lockfile only helps if a changed resolution gets attention. In CI, generate a candidate lockfile, compare it with the committed version, and classify the diff.

    ChangeDefault handlingWhyPatch-level library updatetest and reviewbehavior may still changeNew MCP tool or expanded scopeblock pending approvalexpands agent capabilityTool-schema digest changedcontract tests + approvalarguments or semantics may driftModel revision changedevaluation suite + staged rolloutbehavior can shift without API errorsPolicy digest changedpolicy-owner approvaldecision boundary changedRetrieval index revisionfreshness and regression checksevidence may have changed


    Avoid a single “lockfile changed” checkbox. A new read-only tool and a tool that can issue refunds are not equivalent. The classifier should turn a mechanical diff into an appropriate review path.

    Here is a shell-shaped CI outline:

    agentctl lock --config agent.yaml --out agent.lock.next.json
    agentctl lock verify --file agent.lock.next.json
    agentctl lock diff agent.lock.json agent.lock.next.json --format json > diff.json
    agentctl lock policy-check diff.json
    agentctl test contracts --lock agent.lock.next.json
    agentctl eval run --suite refund-safety --lock agent.lock.next.json

    The policy-check command should fail closed for prohibited changes, such as a mutable image tag, an unapproved registry, a newly write-capable tool, or a missing integrity digest. It should produce a readable report for permitted changes, not merely a pass/fail bit.

    Keep resolution separate from activation


    Do not let a production process silently resolve new dependencies at startup. Instead, use a two-step path:

    1. Resolve: an update job produces a candidate lockfile from declared selectors.
    2. Validate: CI runs package scans, tool-contract tests, workflow tests, and representative evaluations.
    3. Approve: reviewers accept the classified dependency diff.
    4. Activate: deployment references the immutable lockfile digest.
    5. Observe: logs attach the lockfile ID to each run; a canary receives a limited traffic slice.
    6. Roll back: redeploy the prior known-good lockfile if failure signals cross a threshold.

    This is deliberately less magical than allowing a runtime to “get the newest compatible tool.” Predictable change is the goal. If fast security patches are needed, the same path can be accelerated with an explicit emergency approval and a short retrospective requirement.

    Record the lockfile ID in operational evidence


    Attach agent_lock_digest to traces, decision records, and evaluation results. When a support team asks why an agent started choosing a different tool, you can group failures by the exact dependency set instead of guessing from deploy timestamps.

    That also makes incident work smaller. You can reproduce an affected run in a sandbox using the workflow commit plus lockfile, then compare it with the previous digest. A release manifest tells you the bundle identity; the dependency lock tells you which mutable ecosystem references became concrete artifacts.

    Common failure modes


    Locking a name, not content. tools: 2.4.1 is better than latest, but a package version alone may not identify the exact artifact. Use an integrity value, immutable image digest, or registry-provided content hash where possible.

    Treating tool schemas as documentation. A schema can alter required fields, defaults, descriptions, or side effects while the server name stays the same. Snapshot the inspected schema and run contract tests against it.

    Locking only dependencies. A model alias, prompt file, retrieval index, and policy bundle can each change an agent’s behavior. Include the components that matter to your threat model and debugging path.

    Making updates impossible. A lockfile that nobody refreshes becomes stale theater. Run a scheduled candidate-resolution job, send bounded diffs to owners, and maintain a tested fast lane for security patches.

    Logging secrets by accident. Store a tool’s allowed scope and identity, not an access token, endpoint query string, or customer payload. Scan generated lockfiles before commit.

    A practical adoption plan


    Begin with one agent that has meaningful external effects. Inventory its model, prompt, tool servers, packages, policy, and retrieval configuration. Add immutable IDs for the two or three components most likely to drift. Then make one CI rule visible: any newly write-capable tool requires a human approval.

    After that, add schema snapshots and trace correlation. Only when those pieces work should you expand the lock to every runtime dependency. The artifact should reduce ambiguity for engineers, not create a giant metadata file nobody can review.

    Use the lockfile with, not instead of, an inventory


    A lockfile answers “what did this release resolve?” An inventory answers “what agent components exist across the organization?” Keep both. The inventory is useful for ownership, patch notifications, and discovering an unmaintained tool server; the lockfile is useful for exact runtime reproduction. Mixing the two creates a document that is too broad for a deploy and too stale for security operations.

    Think of the lockfile as a release-level snapshot and the inventory as a portfolio-level map. A tool may appear in the inventory with an owner, risk classification, and approved registry. Each agent lockfile then states the immutable tool artifact, schema digest, and scopes it actually used. This distinction gives a security reviewer a short answer during a release review and gives an operations team a larger answer when a vulnerability advisory arrives.

    When a dependency advisory appears, first query the inventory to identify candidate owners and workloads. Next, query deployment records for lockfile digests that reference the affected artifact. That keeps response work evidence-based: do not restart every agent merely because a similarly named package exists somewhere in a repository.

    What a good review looks like


    Reviewers should be able to answer four questions from the pull request: What changed? Which capability or behavior could change? What tests exercised the new resolution? How do we return to the previous known-good digest? Include those answers in the generated diff summary.

    For example, a tool image update with an unchanged schema may need integration tests and a vulnerability scan. A schema diff adding issue_refund requires a capability-owner approval even if the image has no known CVEs. A new model revision needs representative task evaluation, because its interface can be stable while its decisions move. The lockfile makes these different kinds of changes visible in one place without pretending they carry the same risk.

    FAQ

    Is an AI agent dependency lockfile different from a package lockfile?


    Yes. A package lockfile resolves language dependencies. An agent lockfile extends the same idea to behavior-relevant dependencies such as models, prompts, MCP tools, policies, and retrieval revisions.

    Should every model request use a pinned model version?


    For production workflows where repeatability matters, record the resolved deployment or revision identity when your provider exposes one. If only an alias exists, record the alias, provider metadata available at resolution time, and the evaluation evidence used for the rollout.

    How do I version an MCP server safely?


    Pin its immutable image or package integrity value, capture the inspected tool-schema digest, test its tool contracts, and require approval when the exposed tools or scopes expand.

    Can a lockfile prevent a malicious dependency?


    No. It helps you know and reproduce what was selected. Combine it with trusted registries, integrity verification, vulnerability scanning, least-privilege credentials, code review, and runtime controls.

    How often should we refresh an agent lockfile?


    Generate a candidate on a predictable cadence and when declared dependencies change. Apply updates only after the appropriate checks; urgency can change the approval speed, not the evidence you retain.

    What should happen when a lockfile changes during an incident?


    Compare the new and previous resolved identities, correlate failures with the lockfile digest, deploy the last known-good lockfile if justified, then preserve the diff and test results for follow-up.

    Do small teams need this much process?


    Start small: pin package and tool identities, commit one generated file, and review capability changes. The same habit scales better than reconstructing a changed agent runtime from scattered environment variables later.#ai #programming #security #devops #software #coding #development #engineering #inclusive #community
    AI Agent Dependency Lockfiles: Stop Silent Tool and Package Drift

  20. Grafana's SQL Expressions Reached DuckDB, and DuckDB Reaches the Filesystem


    Grafana renders queries. A feature that lets a panel run expressions over query results sounds like arithmetic. In releases between 11.0.0 and 11.1.6, with a narrower range in the 11.2 line, that feature routed expressions through a bundled DuckDB client binary, and DuckDB is not an arithmetic library. It is an analytical database engine with file reading, file writing and extension loading, all reachable through SQL.

    The shape of the bug


    CVE-2024-9264 covers SQL Expressions in Grafana. When the expressions feature is enabled and a duckdb binary is present on the path the server searches, an authenticated user with the Viewer role can send an expression whose SQL is passed to that binary. The result is arbitrary file read and, depending on permissions the Grafana process holds, file write. The vendor advisory scores the issue 9.9 and NVD follows; some third-party summaries list 9.4. Either way the privilege required is the lowest authenticated role in the product, which is the detail that matters operationally.

    Two preconditions decide whether a given instance is exploitable. The expressions feature has to be enabled, and the binary has to be discoverable. Neither is guaranteed. Both are common enough that the distinction between "installed" and "vulnerable" does not track the version number closely.

    The mechanism is worth following because it explains why input validation was never the fix. The expression is not parsed by Grafana alone. It reaches an external process, and that process implements a full SQL dialect including functions that touch the filesystem. A parser hardened in the Grafana codebase still hands a string to something that speaks SQL for a living.

    What file read buys


    Reading a file as an unprivileged authenticated user is often treated as a low-severity outcome. On a monitoring server it is not. The Grafana process, and everything it can reach, typically includes:

    • the provisioning configuration, which carries datasource connection strings and often API tokens in plaintext;
    • the database file behind the Grafana instance itself, holding users, API keys and dashboard definitions;
    • environment-rendered secret mounts, where a Kubernetes deployment exposes a token that authenticates to the cluster API;
    • cloud instance metadata, when the workload is not hardened against it.

    The step from file read to impact is usually one hop: a token becomes a session, a connection string becomes warehouse access, a service account becomes a pod. Public proof-of-concept code for this issue appeared quickly after disclosure, which means the exploit is not the expensive part of an attack any more.

    The neighbouring fixes


    Grafana's advisory index across late 2025 and 2026 shows how persistent this class of problem is for the product. A remote code execution issue in sqlExpressions scored 9.1. An image renderer accepted input that led to arbitrary code execution, scored 9.9. An Alloy feature read an arbitrary local file and sent its contents as a bearer token, scored 7.7. Separate issues covered privilege assignment in the Enterprise build and a server-side request forgery path through MCP configuration. The product is an integration hub by design, and an integration hub has to make outbound calls and read configuration, which is exactly the capability set that turns small bugs into credential disclosure.

    Verifying an instance


    • Check whether the expressions feature is enabled. In many environments it was turned on for one team and never reviewed.
    • Determine whether a duckdb binary is on the process search path, and whether the Grafana service account can write files anywhere useful.
    • Review viewer-level accounts. Anyone with a read-only seat may have had the ability to read server files.
    • Inspect provisioning and datasource configuration for tokens that would be valuable if read, then rotate anything that was reachable while the instance was unpatched.
    • Check for outbound connections originating from the Grafana pod to unexpected destinations during the exposure window.


    Reducing the blast radius


    Upgrade to a patched release. Then treat the monitoring server as a credential store rather than a dashboard. Move datasource secrets into a secret manager rendered at runtime with short lifetimes, remove file-write capability from the container filesystem, deny metadata access at the network level, and restrict egress from the Grafana namespace to the specific datasources it queries. None of those controls depend on a future CVE being disclosed, which is the point: the next file-read bug in an integration-heavy product will arrive, and the question is only what it finds when it does.

    References


    • NVD record for CVE-2024-9264, Grafana SQL Expressions file read and command execution.
    • Grafana security advisory for CVE-2024-9264, affected 11.0.x through 11.2.x ranges and fixed releases.
    • Grafana security advisories index, entries for sqlExpressions RCE and the Alloy bearerTokenFile file read.


    #grafana #cve20249264 #duckdb #sqlexpressions #software #coding #development #engineering #inclusive #community
    Grafana's SQL Expressions Reached DuckDB, and DuckDB Reaches the Filesystem

  21. Detecting CVE-2026-96655 exploitation in Plex logs


    Patching Plex Media Server to 1.43.3.10861 removes the SSRF described in CVE-2026-96655. It does not tell you whether someone already used it. That question is answerable, but only if you know what the server records.

    The flaw lets an authenticated user supply a path parameter to /video/:/transcode/universal that the server then fetches on their behalf. Detection therefore rests on three observables: who called the endpoint, what target they nominated, and what the server did with the response.

    Observable one: the request itself


    Plex Media Server logs transcoder activity. Requests to the universal transcoder endpoint appear with client identity and session context. In a normal household, calls to that endpoint come from a small set of device identities at predictable hours.

    The signal is not "the endpoint was called". It is "the endpoint was called by an identity that normally only browses", or "the endpoint was called with an unusual parameter shape". Build a baseline from a quiet week, then review deviations. Any review that starts after detecting a compromise has no baseline, which is why this step belongs in routine work.

    Observable two: outbound destinations


    The stronger signal lives outside the application log. A Plex server that suddenly opens connections to loopback administrative ports, to a router management interface, or to a link-local metadata address is doing something a media server has no reason to do.

    If you have flow logs from a firewall, a router, or a cloud VPC, query for traffic originating from the Plex host toward internal management subnets. Plex fetches artwork, subtitles and metadata from the internet; it does not legitimately talk to 169.254.169.254 or to your hypervisor console.

    On a single host without flow telemetry, host-level tooling can fill the gap. Connection auditing or a short-lived packet capture on the media server's interface will show the second hop within minutes of a test request.

    Observable three: response handling anomalies


    A forged request that succeeds returns content the transcoder did not expect. That frequently produces parse errors, unusual media probe failures, or transcode sessions that start and immediately stop. Spikes in transcode failures with no corresponding client complaint are worth a look.

    This is a weak signal on its own, and it should not be treated as evidence. It is a triage prompt, not a conclusion.

    Building the query


    The remediation guidance from CISA sets a federal due date of 3 November 2026 under BOD 26-04, and organisations that follow KEV-driven prioritisation can reuse the same timeline. A useful internal ticket contains a list of hosts running 1.43.2 or earlier, a pointer to the log fields above, and an explicit statement of what "no evidence of exploitation" means in your environment.

    The ZoomEye product query app="Plex Media Server" returns 507,974 matching assets, which is a reminder of how many servers exist outside any inventory you control. The vul.cve="CVE-2026-96655" query returns zero, meaning asset-level attribution for this CVE is not yet indexed. Absence of indexed vulnerable hosts is not absence of vulnerable hosts.

    If you find something


    Preserve the log segment and the connection records before rotating anything. Identify the account that made the request and disable it. Check what the forged requests reached: a response from a router admin page is different from a response from a metadata service that returned credentials. Rotate any credential or token the target could have disclosed. Then patch, because containment without the upgrade leaves the capability in place.

    A detection rule that never fires is not proof of safety. It is a reason to keep the rule running while the patch rolls out.

    References


    • Plex security advisory for Media Server 1.43.2 and earlier
    • CISA Known Exploited Vulnerabilities entry for CVE-2026-96655
    • CISA BOD 26-04 prioritising security updates based on risk
    • NVD record for CVE-2026-96655


    #vulnerability #cve202696655 #plex #ssrf #software #coding #development #engineering #inclusive #community
    Detecting CVE-2026-96655 exploitation in Plex logs

  22. Once you put a large language model behind a company API gateway, someone asks a simple question.

    Who is paying for this?

    The model bill arrives as one number. Finance sees one number. Every team in the company sees one endpoint. Nobody can tell you which team burned forty percent of the budget, which use case is growing, or which experiment someone forgot to shut off six weeks ago. That gap between one bill and one endpoint is where metering lives.

    We built metering into our LLM gateway before we scaled usage, and it changed how teams behaved. Here is what we learned.

    Why LLM metering is not like API metering


    With a normal REST API, metering is easy. One request costs one request. You count requests per subscription key, and you are done.

    LLM calls do not work that way. One request to a chat endpoint can cost five tokens or five thousand. A prompt injection test script someone ran in a loop overnight can spend more than an entire product team's monthly budget in eight hours. If you count requests, you learn nothing. The unit of cost is the token, and the token count lives in the response, not the request.

    That detail shapes everything. Your metering code has to read the response body, extract the usage block, and attribute it before the data is gone.

    {
    "usage": {
    "prompt_tokens": 1240,
    "completion_tokens": 312,
    "total_tokens": 1552
    }
    }

    Azure OpenAI returns this on every response. If you do not capture it at the gateway, you have to reconstruct it later from logs, and that is a losing fight.

    Capture it at the gateway, not in the app


    Every team wanted to do metering in their own application code. We said no. The gateway is the one layer every call passes through, regardless of language, framework, or team. A metering implementation that depends on each team instrumenting their own service is an implementation that covers sixty percent of traffic on a good month.

    We put a policy on the gateway's inbound path to stamp each request with metadata: the subscription the key belongs to, the product, the environment. On the outbound path, another policy parses the response, pulls the token counts, and ships an event to our analytics pipeline. The policy does not touch the request or response bodies in ways the caller can see. It observes and reports.

    <policies>
    <outbound>
    <choose>
    <when condition="@(context.Response.StatusCode == 200)">
    <set-body>@{
    // parse the usage block and forward a metering event
    // key: subscription id, product, environment, model
    // value: prompt_tokens, completion_tokens, latency
    }</set-body>
    </when>
    </choose>
    </outbound>
    </policies>

    This is pseudo-code, not a real policy file, because every gateway has its own syntax. The shape matters more than the syntax: stamp metadata on the way in, extract cost on the way out, send it somewhere durable.

    Attribute everything, including the failures


    The first version of our metering only counted successful calls. That lasted about two weeks. Someone ran a batch job against a deprecated model deployment that returned 400s all day. The calls were cheap individually, but there were hundreds of thousands of them, and the model provider still charged for the input tokens on each failed request.

    Failed requests still consume input tokens. Rate-limited requests still consume them. Requests that hit a content filter still consume them. If you only meter the 200s, your bill and your dashboard will disagree, and finance will believe the bill.

    Our outbound policy records every response code. Failures get their own bucket so teams can see them separately, but they are not excluded from the total. The first time a team saw how much they were spending on 400s, they fixed their client code that afternoon.

    Give teams their own numbers, not the whole company


    A company-wide dashboard that says the LLM bill is fifty thousand dollars a month helps nobody. A dashboard that says your team spent nine thousand, up forty percent from last month, on a specific model, changes behavior overnight.

    We publish per-team views: tokens and estimated cost by team, by model, by day. The estimated cost part matters. Tokens are abstract. Dollars are not. We maintain a small price table per model and multiply. The estimate is not perfect, and we say that on the dashboard. It is close enough to drive decisions.

    The behavioral change was immediate. Teams started batching requests. They cached repeated prompts. One team switched a summarization job from a large model to a smaller one after seeing the per-run cost. None of that happened when the bill was a single line item.

    Budgets need teeth, but start with visibility


    Once teams can see their spend, the next question is limits. We added budget alerts first, hard stops second. The sequence matters.

    Alerts went to the team's channel when they crossed fifty, eighty, and one hundred percent of their monthly budget. Most teams self-corrected at fifty. For the ones that did not, a hard stop at the gateway rate-limits further calls until someone raises the budget.

    We deliberately did not lead with hard stops. An engineer running a time-sensitive demo who hits a hard limit learns that the gateway is the enemy. An engineer who gets a warning at fifty percent learns to watch their budget. The hard stop exists for the runaway loops, not for normal work.

    What we would do differently


    Three things we would change if we started over.

    First, we would meter streaming responses from day one. Token counts arrive at the end of a streamed response, and our first implementation missed them. Streaming became popular faster than we expected.

    Second, we would standardize the metadata stamp earlier. We let teams add custom attributes organically, and we ended up with three different keys for the same project name. Normalizing that retroactively was tedious.

    Third, we would keep the price table in version control with a review step. Model prices change. When they do, old estimates look wrong. We now treat the price table like code: a pull request, a reviewer, a changelog.

    The real lesson


    Metering is not a billing feature. It is a feedback loop. The moment teams could see what their calls cost, they started engineering like the cost mattered. Architecture improved. Waste fell. Nobody needed a policy document telling them to be careful with the expensive model, because the numbers told the story better than any document could.

    If you are standing up an LLM gateway and nobody has asked about cost attribution yet, they will. Build the metering in before the bill becomes a conversation.#ai #azure #devops #apimanagement #software #coding #development #engineering #inclusive #community
    Who Is Paying for This? Token Metering at the LLM Gateway

  23. Reverse Engineer Anything: The Open-Source Tool That Turns Any Binary Into a Readable Spec (And Why Big Tech Won’t Love It)

    Introduction


    Every binary is a black box. Whether it’s a proprietary CLI tool, a firmware blob, or a legacy service, understanding what it does—and how to automate it—usually means hours of manual reverse engineering. For developers building AI agents, this is a bottleneck: agents need structured interfaces (APIs, schemas, command specs) to interact with the world, not opaque executables.

    Enter BinSpec—an open-source tool that statically analyzes binaries and generates a readable specification: CLI flags, environment variables, input/output formats, and even a Python wrapper. It’s not magic; it combines static analysis (via LIEF and Capstone) with heuristics and optional dynamic tracing (via Intel PIN). The result is a machine-readable spec that an AI agent can consume to call the binary safely.

    Big Tech won’t love it because it democratizes interoperability with closed systems. But for developers building autonomous agents, it’s a force multiplier.

    Problem


    AI agents thrive on structured tools. Frameworks like LangChain or AutoGen expect callable functions with clear input/output schemas. But most software in the wild isn’t an API—it’s a binary with --help text at best, and cryptic error codes at worst.

    Consider a typical proprietary tool:

    $ ./acme_tool --help
    Usage: acme_tool [OPTIONS] INPUT
    -o, --output FILE Write result to FILE
    -v, --verbose Increase verbosity
    --mode MODE One of: fast, safe, debug

    A human can parse this. An AI agent cannot reliably infer types, defaults, or side effects. Worse, many binaries lack help text entirely. The agent is left guessing, leading to brittle prompts and unsafe subprocess calls.

    Manual reverse engineering (disassembly, debugging) is time-consuming and requires expertise. We need automation that produces a spec an agent can use without executing arbitrary code blindly.

    Solution


    BinSpec (fictional name for this article; the approach is real) is a Python tool that:

    1. Extracts strings and symbols from the binary using LIEF.
    2. Disassembles entry points and referenced functions with Capstone to identify argument parsing patterns (e.g., getopt, argparse).
    3. Infers a CLI schema from help text, string literals, and control-flow heuristics.
    4. Optionally traces execution with Intel PIN to observe file I/O and syscalls (sandboxed!).
    5. Emits a JSON spec and a Python wrapper with type hints.

    The spec is not guaranteed complete—it’s a best-effort reconstruction. But it’s enough for an agent to generate safe calls with validation.

    Why open source? Because transparency matters. You can audit the heuristics, extend them, and run everything locally. No phone-home, no proprietary cloud.

    Implementation


    Let’s build a minimal version of BinSpec that extracts strings and generates a spec. We’ll use lief for parsing and capstone for disassembly. Install dependencies:

    pip install lief capstone

    Step 1: Extract strings and symbols


    import lief
    import re

    def extract_strings(binary_path, min_length=4):
    binary = lief.parse(binary_path)
    strings = set()
    for section in binary.sections:
    if section.size == 0:
    continue
    data = section.content
    # naive ASCII string extraction
    for match in re.finditer(rb'[\x20-\x7e]{%d,}' % min_length, data):
    strings.add(match.group().decode('ascii', errors='ignore'))
    return strings

    # Example usage
    strings = extract_strings('/bin/ls')
    print(list(strings)[:10])

    This yields help text fragments, error messages, and flag names.

    Step 2: Disassemble to find argument parsing


    We locate calls to getopt or similar by scanning for symbol references. For simplicity, we disassemble the .text section and look for string references.

    from capstone import Cs, CS_ARCH_X86, CS_MODE_64

    def disassemble_text(binary_path):
    binary = lief.parse(binary_path)
    text = binary.get_section('.text')
    if not text:
    return
    [] md = Cs(CS_ARCH_X86, CS_MODE_64)
    instructions =
    [] for insn in md.disasm(text.content, text.virtual_address):
    instructions.append(insn)
    return instructions

    # Find LEA instructions referencing strings (simplified)
    insns = disassemble_text('/bin/ls')
    for insn in insns[:5]:
    print(f"0x{insn.address:x}: {insn.mnemonic} {insn.op_str}")

    Step 3: Generate a spec


    We combine strings and heuristics to produce a JSON spec. This is intentionally conservative.

    import json

    def generate_spec(binary_path):
    strings = extract_strings(binary_path)
    # Heuristic: flags start with '-' and are short
    flags = [s for s in strings if re.fullmatch(r'--?[a-zA-Z][\w-]*', s)]
    spec = {
    "binary": binary_path,
    "flags": sorted(set(flags)),
    "inferred": True,
    "warning": "Spec is heuristic. Validate before use."
    }
    return spec

    spec = generate_spec('/bin/ls')
    print(json.dumps(spec, indent=2))

    Step 4: Safe agent integration


    An AI agent can use this spec to construct commands—but must validate inputs. Here’s a minimal agent loop with explicit termination:

    import subprocess
    import shlex

    def run_tool(binary, args, timeout=5):
    # SECURITY WARNING: Never pass untrusted input to subprocess without validation.
    # This example uses shlex.quote and a whitelist of flags from the spec.
    allowed_flags = set(spec["flags"])
    for arg in args:
    if arg.startswith('-') and arg not in allowed_flags:
    raise ValueError(f"Flag {arg} not in spec")
    cmd = [binary] + [shlex.quote(a) for a in args]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
    return result.stdout

    # Agent loop: try up to 3 times, then abort
    def agent_loop(binary, user_request, max_attempts=3):
    attempts = 0
    while attempts < max_attempts:
    # In a real agent, an LLM would propose args based on spec
    proposed_args = ["-l"] # example
    try:
    output = run_tool(binary, proposed_args)
    return output
    except Exception as e:
    attempts += 1
    raise RuntimeError("Agent failed to produce valid command")

    Security note: Executing arbitrary binaries is dangerous. Always run in a sandbox (e.g., Docker, firejail) and never use shell=True. The spec reduces risk but doesn’t eliminate it.

    Step 5: Dynamic tracing (optional)


    For deeper insight, you can use strace (Linux) to observe syscalls:

    strace -f -e trace=file,network ./acme_tool input.txt 2> trace.log

    Parse trace.log to infer file access patterns. Integrate this into BinSpec as an optional module. Warning: Tracing executes the binary—only do this in an isolated environment.

    Key Takeaways


    • BinSpec-style tools turn opaque binaries into structured specs that AI agents can consume, bridging the gap between legacy software and modern automation.
    • Static analysis (LIEF + Capstone) extracts strings, symbols, and control-flow hints without execution.
    • Heuristics are imperfect—always validate specs and sandbox execution.
    • Security first: Never eval untrusted output or run binaries without isolation. Use shlex.quote, whitelists, and timeouts.
    • Open source matters for auditability and trust; Big Tech prefers lock-in, but developers benefit from transparency.

    The code above is runnable and extensible. Start with /bin/ls, then try it on a proprietary CLI. You’ll get a spec—and a starting point for your agent.

    Disclaimer: BinSpec is a conceptual name; the techniques are real and implemented in tools like LIEF, Capstone, and strace. Always respect software licenses and local laws when reverse engineering.#ai #python #reverseengineering #opensource #software #coding #development #engineering #inclusive #community
    Reverse Engineer Anything: The Open-Source Tool That Turns Any Binary Into a Readable Spec (And Why Big Tech Won’t Love It)

  24. Reklam panelinde "lead" sayısı artarken satış ekibinin "bu lead'lerin hiçbiri alıcı değil" demesi, dijital pazarlamada en sık duyduğum cümlelerden biri. Ben Koray Yalçın; lead yönetimi, CRM mimarisi, dijital pazarlama ve yapay zekâ destekli otomasyonların kesiştiği projelerde çalışıyorum, özellikle gayrimenkul ve B2B tarafında. Bu cümlenin arkasında çoğu zaman teknik bir kopukluk yatar: Reklam platformu formun doldurulduğunu bilir, ama o kişinin üç hafta sonra showroom'a gelip sözleşme imzaladığını bilmez. Algoritma da doğal olarak form doldurmaya en yatkın kitleyi bulmaya devam eder, satın almaya en yatkın kitleyi değil.

    Bu boşluğu kapatmanın yolu, CRM'de oluşan "nitelikli lead", "randevu gerçekleşti" ve "satış kapandı" gibi olayları sunucu tarafından Meta Conversions API'ye (CAPI) geri göndermek. Bu yazı bir pazarlama rehberi değil; bu köprüyü kodla kurarken karşılaştığım tasarım kararlarını anlatıyor: kullanıcı verisinin normalizasyonu ve hash'lenmesi, olay kimliği ile tekilleştirme, zaman penceresi, yeniden deneme stratejisi ve izin kontrolü. Örnekler Python ama mantık her dile taşınabilir.

    Önce olay sözlüğü: Hangi CRM durumu hangi olay?


    Kod yazmadan önce yapılması gereken en önemli iş, CRM'deki aşamaları sınırlı ve anlamlı bir olay listesine eşlemek. Her aşama değişikliğini Meta'ya göndermek gürültü üretir. Benim kullandığım tipik eşleme şöyle:

    CRM olayıGönderilen olay adıNotForm / lead oluştuLeadGenellikle tarayıcı pikseli zaten gönderirTemsilci "nitelikli" işaretlediQualifiedLead (özel olay)Ölçüm kurgusuna göre seçilirRandevu gerçekleştiSchedule veya özel olay"Randevu alındı" değil, "gerçekleşti"Sözleşme imzalandıPurchasevalue ve currency zorunlu düşünülmeli


    Burada kritik nokta şu: Olay, CRM'de geri alınabilir bir alan değişikliğinden değil, kalıcı bir olaydan tetiklenmeli. Temsilci bir fırsatı yanlışlıkla "kazanıldı" yapıp beş dakika sonra geri alırsa, gönderilmiş bir Purchase olayını geri çekmenin pratik bir yolu yoktur. Bu yüzden ben aşama değişikliklerini doğrudan API'ye bağlamak yerine bir conversion_events tablosuna yazıyorum ve gönderimi kısa bir bekleme süresinden sonra yapan ayrı bir işçiye bırakıyorum.

    CREATE TABLE conversion_events (
    id BIGSERIAL PRIMARY KEY,
    event_id TEXT NOT NULL UNIQUE, -- tekilleştirme anahtarı
    event_name TEXT NOT NULL,
    lead_id BIGINT NOT NULL REFERENCES leads(id),
    occurred_at TIMESTAMPTZ NOT NULL, -- olayın gerçek zamanı
    value_minor BIGINT, -- kuruş/cent cinsinden
    currency CHAR(3),
    status TEXT NOT NULL DEFAULT 'pending', -- pending, sent, failed, skipped
    attempts INT NOT NULL DEFAULT 0,
    last_error TEXT,
    send_after TIMESTAMPTZ NOT NULL DEFAULT now() + interval '15 minutes'
    );

    send_after alanı, "yanlışlıkla kazanıldı" senaryosuna karşı küçük bir tampon. İşçi göndermeden önce fırsatın hâlâ aynı aşamada olup olmadığını kontrol eder; değilse kaydı skipped yapar.

    Kullanıcı verisini normalize etmek: Hash'ten önce gelen asıl iş


    CAPI, e-posta ve telefon gibi kişisel verilerin SHA-256 ile hash'lenmiş olarak gönderilmesini bekler. Çoğu ekip hashlib.sha256(email) yazıp işi bitmiş sayar. Sorun şu ki hash, girdideki tek bir boşluğu ya da büyük harfi tamamen farklı bir değere dönüştürür. Meta tarafındaki eşleşme de birebir karşılaştırmayla çalıştığı için normalizasyon hatası, sessizce düşük eşleşme oranı olarak geri döner.

    Benim sahada gördüğüm en yaygın hatalar:

    • E-postada baştaki/sondaki boşluklar ve büyük harfler.
    • Telefonun 0533 ..., +90 533 ..., 90533... gibi farklı biçimlerde saklanması.
    • İsimlerde Türkçe karakterlerin farklı yazımları ve "Dr." gibi önekler.
    • Boş alanların boş string olarak hash'lenmesi (boş string'in de bir SHA-256 değeri vardır ve anlamsız bir eşleşme anahtarı üretir).

    import hashlib
    import re
    import phonenumbers

    def _sha256(value: str) -> str:
    return hashlib.sha256(value.encode("utf-8")).hexdigest()

    def norm_email(raw: str | None) -> str | None:
    if not raw:
    return None
    v = raw.strip().lower()
    return v if "@" in v else None

    def norm_phone(raw: str | None, default_region: str = "TR") -> str | None:
    if not raw:
    return None
    try:
    num = phonenumbers.parse(raw, default_region)
    except phonenumbers.NumberParseException:
    return None
    if not phonenumbers.is_valid_number(num):
    return None
    # Ülke kodu dahil, yalnızca rakamlar, başta + yok
    return phonenumbers.format_number(num, phonenumbers.PhoneNumberFormat.E164).lstrip("+")

    def build_user_data(lead) -> dict:
    ud = {}
    if (e := norm_email(lead.email)):
    ud["em"] = [_sha256(e)]
    if (p := norm_phone(lead.phone, lead.country_code or "TR")):
    ud["ph"] = [_sha256(p)]
    if lead.external_id:
    ud["external_id"] = [_sha256(str(lead.external_id))]
    # Tarayıcıdan yakalandıysa hash'lenmeden gönderilen alanlar
    if lead.fbc:
    ud["fbc"] = lead.fbc
    if lead.fbp:
    ud["fbp"] = lead.fbp
    return ud

    Bir detay daha: Kıbrıs gibi çok uluslu alıcı kitlesi olan pazarlarda default_region sabit "TR" olamaz. İngiltere'den gelen bir lead'in 07... ile başlayan numarası Türkiye varsayımıyla ayrıştırılırsa geçersiz sayılır ya da daha kötüsü yanlış bir numara üretir. Bu yüzden formda ülke seçimini ayrı bir alan olarak tutmak, normalizasyonun doğruluğunu doğrudan etkiliyor.

    fbc, fbp ve external_id: Eşleşmeyi güçlendiren köprüler


    E-posta ve telefon tek başına çoğu zaman yeterli olur, ama iki alan eşleşme kalitesini belirgin biçimde artırır:

    • fbc: Reklam tıklamasıyla gelen fbclid parametresinden türetilen tıklama kimliği. Kullanıcı sitenize reklamla geldiyse _fbc çerezinde bulunur.
    • fbp: Pikselin tarayıcıya yazdığı _fbp çerezi.

    Bu değerler satış anında değil, lead oluştuğu anda yakalanmalı. Üç hafta sonra sözleşme imzalanırken kullanıcı tarayıcısında değil, satış ofisinde oturuyor. Bu nedenle form gönderiminde bu iki çerezi gizli alanlarla alıp lead kaydına yazmak, sonraki tüm offline olayların kalitesini belirliyor. Meta Lead Ads formlarından gelen lead'lerde ise platformun verdiği lead kimliğini saklamak aynı işi görür; CRM entegrasyonu senaryolarında bu kimliğin olayla birlikte gönderilmesi eşleşmeyi doğrudan kurar.

    external_id ise sizin CRM'deki kişi kimliğiniz. Hem piksel hem sunucu tarafında aynı değer (hash'lenmiş olarak) gönderilirse, aynı kişinin farklı olaylarını birbirine bağlamak kolaylaşır.

    event_id ile tekilleştirme: Aynı satışı iki kez saymamak


    CAPI'de iki ayrı tekrar riski vardır:

    1. Piksel ile sunucu çakışması: Lead olayını hem tarayıcı pikseli hem sunucu gönderiyorsa, iki olay aynı event_name ve aynı event_id ile gelmelidir. Meta bu ikiliyi tek olay olarak sayar.
    2. Yeniden deneme çakışması: Ağ zaman aşımı yüzünden isteğin ulaşıp ulaşmadığını bilmiyorsanız ve tekrar gönderirseniz, aynı event_id korunmalıdır.

    event_id rastgele üretilmemeli; olaydan deterministik olarak türetilmeli. Benim tercihim şu:

    def make_event_id(event_name: str, lead_id: int, stage_version: int) -> str:
    return f"{event_name.lower()}:{lead_id}:{stage_version}"

    stage_version, fırsatın o aşamaya kaçıncı kez girdiğini tutan bir sayaç. Böylece bir müşteri gerçekten ikinci bir daire satın alırsa yeni bir Purchase üretilir, ama aynı satış için yapılan iki gönderim aynı kimliği taşır. Veritabanındaki UNIQUE kısıtı da aynı olayın kuyruğa iki kez girmesini engeller.

    Zaman penceresi: event_time "şimdi" değil, olayın gerçek zamanıdır


    Offline satış entegrasyonunda en sık yapılan hata, event_time alanına gönderim anını yazmak. Olayın değeri, ne zaman gerçekleştiğiyle anlam kazanır; sözleşme salı günü imzalandıysa ve işçi çarşamba gönderdiyse, event_time salı olmalıdır.

    İkinci önemli nokta, Meta'nın kabul ettiği geriye dönük pencere. Bu yazıyı yazarken belgeler, olayların gerçekleştikten sonra sınırlı bir süre içinde gönderilmesini istiyor ve bu süre action_source değerine göre farklılaşabiliyor. Sınır zamanla değişebildiği için kodda sabit bir sayı gömmek yerine yapılandırmadan okuyorum ve pencereyi aşmış olayları göndermeyi denemek yerine skipped olarak işaretleyip raporluyorum:

    from datetime import datetime, timezone, timedelta

    MAX_AGE = { # yapılandırmadan gelir; güncel değeri resmi belgeden doğrulayın
    "system_generated": timedelta(days=7),
    "physical_store": timedelta(days=7),
    }

    def is_sendable(evt, action_source: str) -> bool:
    age = datetime.now(timezone.utc) - evt.occurred_at
    return age <= MAX_AGE.get(action_source, timedelta(days=7))

    Bu kontrolün pratik sonucu, satış ekibinin CRM'i zamanında güncellemesinin bir veri kalitesi konusu haline gelmesi. Sözleşmeyi on gün sonra sisteme giren bir ekip, reklam optimizasyonuna o satışı hiç kazandıramaz. Bu yüzden ben bu entegrasyonu kurarken satış ekibi için "sözleşme imzalandığı gün CRM'de kapanır" kuralını da süreç tarafında yazılı hale getiriyorum.

    action_source ve olay gövdesi


    Sunucudan giden olay gövdesinin iskeleti şöyle:

    def build_payload(evt, lead, action_source="system_generated") -> dict:
    data = {
    "event_name": evt.event_name,
    "event_time": int(evt.occurred_at.timestamp()),
    "event_id": evt.event_id,
    "action_source": action_source,
    "user_data": build_user_data(lead),
    }
    if evt.value_minor is not None:
    data["custom_data"] = {
    "value": evt.value_minor / 100,
    "currency": evt.currency,
    }
    return {"data": [data]}

    action_source alanı, olayın nerede gerçekleştiğini anlatır. Web formu için website, CRM'in kendi ürettiği aşama değişiklikleri için system_generated, satış ofisinde imzalanan sözleşme için physical_store gibi değerler kullanılabilir. Doğru değeri seçmek hem raporlamayı hem de uygulanan kuralları etkiler; bu yüzden olay sözlüğünde her olayın action_source değerini de sabitliyorum.

    value tarafında bir uyarı: Konut gibi yüksek tutarlı satışlarda gerçek sözleşme bedelini göndermek bazı ekiplerin istemediği bir şey olabilir. Bu durumda tutarlı bir "değer skalası" (örneğin ürün tipine göre sabit bir puan) kullanmak, optimizasyon sinyalini korurken hassas ticari bilgiyi dışarı çıkarmamanın bir yolu. Hangisi seçilirse seçilsin, tutarlılık önemlidir; ay ortasında yöntemi değiştirmek raporları kırar.

    Gönderim işçisi: Toplu istek, yeniden deneme ve hata sınıflandırma


    İşçinin görevi basit görünür ama hata sınıflandırması önemli:

    import requests, time

    def send_batch(events, leads, pixel_id, token):
    payload = {"data": []}
    for evt in events:
    payload["data"].extend(build_payload(evt, leads[evt.lead_id])["data"])
    url = f"https://graph.facebook.com/{API_VERSION}/{pixel_id}/events"
    resp = requests.post(url, params={"access_token": token}, json=payload, timeout=15)
    if resp.status_code >= 500 or resp.status_code == 429:
    raise RetryableError(resp.text) # üstel bekleme ile tekrar
    if resp.status_code >= 400:
    raise PermanentError(resp.text) # kaydı failed yap, alarm üret
    return resp.json()

    Kurallarım:

    • 5xx ve hız sınırı hataları yeniden denenir; bekleme süresi her denemede artar ve event_id aynı kalır.
    • 4xx hatalar (geçersiz parametre, süresi dolmuş token) yeniden denenmez. Tekrar göndermek sonucu değiştirmez, yalnızca log kirletir. Bunlar bir alarm kanalına düşer.
    • Token kod içinde değil, gizli değişken yönetiminde tutulur ve süresi izlenir. Sistem kullanıcısı token'ı kullanmak, bir çalışanın hesabı kapandığında entegrasyonun sessizce durmasını engeller.
    • Test olay kodu ile canlıya geçmeden önce olayların Events Manager'daki test ekranında doğru göründüğü doğrulanır.


    İzin ve veri minimizasyonu


    Kişisel veriyi üçüncü bir platforma, hash'lenmiş olsa bile, göndermek bir hukuki dayanak gerektirir. Türkiye'de KVKK, Avrupa'dan gelen alıcılar için GDPR bu çerçeveyi çizer. Benim teknik tarafta uyguladığım kurallar:

    • Lead kaydında reklam ölçümüne ilişkin izin durumu ayrı bir alan olarak tutulur ve işçi, izni olmayan kişi için olay göndermez.
    • Yalnızca eşleşme için gerekli alanlar gönderilir; adres, doğum tarihi gibi alanlar "olsa iyi olur" diye eklenmez.
    • İzin geri çekildiğinde, kuyruktaki bekleyen olaylar da iptal edilir.

    Bu bir hukuki görüş değil; ama izin kontrolünü kodun içine bir if olarak gömmek, sonradan "kimin verisi nereye gitti" sorusuna cevap verebilmeyi sağlıyor.

    Ölçüm: Entegrasyon gerçekten çalışıyor mu?


    Kurulumdan sonra baktığım üç gösterge var:

    1. Eşleşme kalitesi: Events Manager'daki olay eşleşme göstergesi. Düşükse ilk şüpheli normalizasyondur.
    2. Gecikme dağılımı: occurred_at ile gönderim zamanı arasındaki fark. Satış ekibinin CRM'i geç güncellemesi burada hemen görünür.
    3. CRM ile panel karşılaştırması: Aylık kapanan satış sayısı ile Meta'nın aldığı Purchase sayısı arasındaki fark. Birebir tutması beklenmez, ama fark aniden açılırsa token, izin veya şema tarafında bir şey bozulmuştur.


    Sıkça Sorulan Sorular


    Piksel zaten kurulu, neden ayrıca CAPI gerekiyor?
    Piksel yalnızca tarayıcıda olan olayları görür. Telefonla kapanan, satış ofisinde imzalanan ya da haftalar sonra gerçekleşen satışlar tarayıcıda olmaz. CAPI, bu olayları CRM'den doğrudan göndermeyi sağlar.

    E-postayı hash'lemeden göndersem Meta kendisi hash'lemez mi?
    Bazı resmi kütüphaneler hash işlemini kendisi yapar, ama kendi kodunuzla gönderiyorsanız normalizasyon ve hash sizin sorumluluğunuzdadır. Kontrolü elde tutmak, hatayı ayıklamayı da kolaylaştırır.

    Aynı satışı yanlışlıkla iki kez gönderirsem ne olur?
    Aynı event_name ve event_id ile gönderildiyse tekilleştirilir. Farklı kimlikle gönderildiyse iki satış sayılır; bu yüzden kimliği deterministik üretmek önemlidir.

    Satış on gün sonra CRM'e girildi, yine de gönderebilir miyim?
    Meta'nın kabul ettiği geriye dönük pencereyi aşmışsa olay reddedilir. Güncel sınırı resmi belgeden kontrol edin ve asıl çözümü süreçte arayın: satış, gerçekleştiği gün CRM'e girilmeli.

    Gerçek sözleşme bedelini göndermek zorunda mıyım?
    Hayır. Tutarlı bir değer skalası da optimizasyon için yeterli sinyal üretebilir. Önemli olan, seçilen yöntemin zaman içinde değişmemesi.

    Bu entegrasyon küçük ekipler için fazla karmaşık değil mi?
    Kuyruk tablosu, normalizasyon fonksiyonu ve bir gönderim işçisi birkaç yüz satır kod demek. Karşılığında reklam algoritması form dolduranları değil, satın alanları öğrenmeye başlar. Lead hacmi düşük ama satış değeri yüksek sektörlerde bu fark özellikle belirgin.

    Koray Yalçın — lead yönetimi, CRM mimarisi, dijital pazarlama ve gayrimenkul teknolojileri (PropTech) üzerine çalışıyorum. CRM'den reklam platformlarına geri bildirim kurarken sizi en çok hangi adım zorladı? Yorumlarda konuşalım.#backend #crm #api #marketing #software #coding #development #engineering #inclusive #community
    CRM'de kapanan satışı Meta Conversions API'ye geri bildirmek: Hash, event_id ve zaman penceresi üzerine geliştirici notları

  25. Reading List – 2026-10-23

    The agent stories show several ways to constrain or inspect access, from keeping credentials out of an agent’s hands to narrowing network calls and previewing tool requests. They leave a harder boundary open: what can the agent do once access is granted? I keep coming back to that gap. Elsewhere, Jev’s schema-valid output makes a separate point: valid structure isn’t evidence of a sound decision.

    1Password wants AI agents to handle logins without ever taking a peek at your passwords

    1Password’s agent model keeps the credential out of the agent’s hands: after you approve a request, 1Password fills it directly into the sign-in form. I love that boundary; it addresses credential exposure without making the agent’s task impossible. But once signed in, the agent can continue working in the account, and the article doesn’t describe controls on those actions. That leaves the key engineering question: how should access be scoped after authentication?

    Nvidia OpenShell

    OpenShell can hot-reload network policy on a running sandbox, down to HTTP methods and paths; its example allows GitHub API GETs while denying POSTs. That gives operators a way to grant an agent narrowly scoped outbound access without restarting it, though the policy has to reflect the API's real needs. I’d pay particular attention to the boundary between these reloadable rules and filesystem and process constraints, which are fixed at creation; the project is still alpha and single-player.

    Median product "lifespan" has fallen from ~4y down to ~1.5y

    The post cites a drop in SaaSHub’s median product lifespan from roughly four years to 1.5, and links it to cheap, vibe-coded launches. It argues that distribution matters more when features are easy to produce; another commenter warns that abandoning products quickly can skip the hard lessons of finding product-market fit. What catches my attention is that faster failure only helps if teams capture those lessons, so each launch needs to produce evidence before the team moves on.

    Grok Bot can now add events, set reminders, and even turn off your lights for you

    Grok can read and send messages, use location, manage calendar events and reminders, handle contacts, and control Home, with a separate Allow button for each app. That lets someone enable reminders without granting message access, a useful boundary when an assistant can both inspect information and take actions. What catches my attention is the unanswered scope of each permission: the article doesn’t say whether sending a message or locking a door requires any further confirmation.

    The Rise and Fall of Jev

    The article’s strongest engineering point is that Jev’s schema-valid output isn’t evidence of a correct decision. It says conventional language models can get the same constraint through a type checker or JSON-schema parser, while Jev does it faster and without reasoning. I like the distinction: there may be something useful under the hype, especially where local execution or speed matters, but those advantages don’t establish quality for your task. I’d evaluate it against real inputs and error costs, not its claim that it can’t hallucinate.

    Feng Shui for Robots: The Fly MCP Server

    Keeping the agent’s sandbox and production target on Linux avoids a runtime rewrite: Sprites retain files across restarts and run services. The Fly MCP server can create a Machine, volume, and secrets, while the agent brings knowledge of what it configured. Fly says there’s no universal promotion flow because each Sprite can contain a different project. I like that honest boundary; the remaining question is whether the agent can account for production requirements beyond its setup.

    Physicists Trap a Single Antimatter Particle For a Month

    Keeping a positron for a month depends on a container with no walls: electric fields confine it vertically, magnetic fields at the sides, in an ultracold vacuum. I can see why that setup sounds remarkable; it makes a particle that risks annihilation during handling available for measurement over time. The team plans to compare its magnetic moment with the electron’s, testing a precise Standard Model prediction. The trap enables that comparison, but the article reports the positron measurement as future work.

    Is this the new cyber normal?

    The hard part here is less whether LLMs change vulnerability research than whether maintainers, vendors, and operators can coordinate before a patch is usable. The PHP disclosure timeline shows how leaks and premature fixes can compress response into hours; AWS also reported seeing probing before those leaks, so better disclosure alone won't close the window. I’m probably in the author’s naive camp: coordinated security work is hard, but treating rapid exploitation as normal leaves no acceptable alternative. Teams need plans that assume exposure without giving up on improving coordination.

    Rivian buys world model startup to accelerate self-driving ambitions

    Proposal: Rivian's bet is to combine Third Dimension's AI-generated 3D worlds with real driving data, so its simulator can cover complex conditions before rare edge cases occur. The company says its customer fleet uploads more than 400,000 driving sequences daily. What catches my attention is whether generated scenes preserve the details needed for reliable validation; as more companies pursue autonomy, this is a world-model approach worth watching.

    Introducing the Gemini API CLI

    For shell-capable agents, gemini-api makes the interface inspectable before a request runs: –help, machine-readable –usage, –schema, and offline –dry-run expose commands and validate calls. Media commands write files to disk and emit only paths, while JSON, toon, and –jq keep results parseable, avoiding throwaway SDK scripts and base64-heavy context. I like that it treats output shape and offline validation as part of the agent interface, not an afterthought. Because the preview's command surface is still changing, I'd test those contracts before building a durable workflow around them.

    #Agents #AI #Developer #Infrastructure
  26. What the data says


    We read 6,205 public posts from builders whose apps broke at or after launch and verified 659 recent cases. Deploy and build problems are the largest group, at 25%. Of the 659, 89 verified cases are this pattern: the release is blocked or never goes live.

    From the builder's side it looks like this. You push, the pipeline ends in success, you refresh, and the old page is still there. Sometimes there is no deployment at all, or the new frontend is live and calls a route or column that does not exist yet. Sometimes half your users get chunk load errors and the other half are fine.

    The common thread is that nothing in the pipeline was checking what production serves.

    Reproduce it


    Two small mistakes, both common on Next.js with Vercel or any similar host.

    The first is a caching rule added for performance that matches everything, pages included:

    // next.config.js
    module.exports = {
    async headers() {
    return [{
    source: "/:path*",
    headers: [{ key: "Cache-Control", value: "public, max-age=31536000, immutable" }],
    }];
    },
    };

    Every response, including the page that references your script bundles, now tells the browser it is fresh for a year. Ship a change, reload, and the browser does not ask your origin again.

    The second is a post-deploy check that cannot fail:

    - run: npx vercel deploy --prod > deployment.txt
    - run: curl -fsS "$(cat deployment.txt)" > /dev/null

    This requests the new deployment's own address. That address answers whether or not your public domain points at it, so the step passes when the alias is stale, when the deployment was held back, or when the page is cached.

    Why it happens


    Success means the build finished and files uploaded. It does not mean production traffic points at that deployment. Pointing production at a deployment is a separate step, and a check against the deployment's own address cannot see it.

    Browsers obey Cache-Control, not your intentions. MDN defines max-age=N as the response remaining fresh until N seconds after it was generated, so a cache can reuse it without contacting your origin. no-cache is not "don't cache": the response may be stored but must be validated with the origin before each reuse. If you mean "don't store", the directive is no-store. And if you send no header at all, MDN notes that a cache is allowed to cache the response heuristically, so state your requirements explicitly.

    Hosts can hold a deployment back. On Netlify, a production deploy becomes the published deploy only if auto publishing is on, and locking a deploy stops auto-publishing. A lock you forgot about, or a rollback you did not undo, means the build is fine and the pointer is wrong.

    Some failures happen before any build log exists. A deployment can fail on a missing precondition, such as an invalid config file or an ignored build step, and then the error is on the deployment, not in a log you can read. A missing repository webhook has the same effect: nothing starts.

    Version skew breaks users with a tab already open. Vercel's documentation describes it as different versions of the application running on client and server. A page loaded before the deploy asks for a script chunk by a name that the new deployment no longer has, and gets a 404.

    Order matters. If the frontend deploys before the migration, it calls a column that is not there yet.

    Catch it before your users do


    The test has to ask the public domain what it is serving, and compare that with the commit you shipped. First, write the commit into every build. Vercel exposes VERCEL_GIT_COMMIT_SHA during builds, and the fallback covers other hosts:

    {
    "scripts": {
    "build": "echo ${VERCEL_GIT_COMMIT_SHA:-$(git rev-parse HEAD)} > public/version.txt && next build"
    }
    }

    Then paste this script into scripts/verify-deploy.mjs. It needs Node 18 or later.

    const [site, want] = process.argv.slice(2);
    const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
    const fail = (m) => { console.error("FAIL:", m); process.exit(1); };

    let got = "";
    for (let i = 0; i < 30; i++) {
    const res = await fetch(`${site}/version.txt`).catch(() => null);
    if (res?.ok) {
    got = (await res.text()).trim();
    if (got === want) {
    if (!/no-store/.test(res.headers.get("cache-control") ?? ""))
    fail("version.txt is cacheable: send Cache-Control: no-store");
    break;
    }
    }
    await sleep(10_000);
    }
    if (got !== want) fail(`serving ${got || "nothing"}, expected ${want}`);

    const page = await fetch(site);
    const cc = page.headers.get("cache-control") ?? "";
    const maxAge = Number(/max-age=(\d+)/.exec(cc)?.[1] ?? 0);
    if (maxAge > 300 && !/no-cache|no-store/.test(cc))
    fail(`page is fresh for ${maxAge}s without revalidation: "${cc}"`);

    const html = await page.text();
    const refs = [...html.matchAll(/(?:src|href)="(\/[^"]+\.(?:js|css))"/g)].map((m) => m[1]);
    for (const ref of refs) {
    const r = await fetch(site + ref);
    if (!r.ok) fail(`${ref} returned ${r.status}`);
    }
    console.log(`ok: ${want}, ${refs.length} assets`);

    Run it as the last step of the pipeline, against your public domain:

    node scripts/verify-deploy.mjs example.com "$(git rev-parse HEAD)"

    It retries for five minutes, then fails with both values. It also fails if the version file is cacheable, if the page is fresh for more than five minutes without revalidation, or if any script or stylesheet the page references returns something other than 200. It only reads the home page, so add the routes that matter to you.

    A test you have never seen fail proves nothing. Run it once against the previous commit, which must fail:

    node scripts/verify-deploy.mjs example.com "$(git rev-parse HEAD~1)"

    For the second class of problem, push an empty commit with git commit --allow-empty -m "probe" and confirm a new deployment appears listing that commit. If nothing appears, open the repository's webhook settings and look at recent deliveries before touching your build.

    The fix


    1. Remove the catch-all cache rule and mark the version file. Pages keep the default or a short lifetime. Only hashed filenames get a year.

    // next.config.js
    module.exports = {
    async headers() {
    return [
    { source: "/version.txt", headers: [{ key: "Cache-Control", value: "no-store" }] },
    ];
    },
    };

    For other hosts, the rule is the same: public, max-age=31536000, immutable on /assets/app.3f9a1c.js, and no-cache on the page that references it, so every load revalidates and picks up the new filenames.

    2. Install from the lockfile. The npm documentation says npm ci requires an existing package-lock.json or npm-shrinkwrap.json, exits with an error instead of updating the lock if it disagrees with package.json, and never writes to either. A build that installs what you tested cannot quietly pull a new major version.

    npm ci

    3. Run migrations as a pipeline step before the app deploys. Make the deploy depend on it, and keep each migration additive so the previous release still works against the new schema. With Prisma that step is npx prisma migrate deploy, run from the pipeline and not from a laptop.

    4. Protect open tabs. Vercel's Skew Protection is available on Pro and Enterprise. With a supported framework it adds the deployment id to framework-managed requests, including static assets, so an open page keeps loading assets from its own deployment. The default maximum age is one day from deployment creation. It does not pin your own fetch() calls from client components; you pass the id yourself for those.

    5. Rehearse a rollback once, while nothing is on fire. Roll back, run the script with the previous commit and see it pass, then roll forward and run it with the new one. On Netlify, lock the deploy so the next Git push does not publish over it.

    vercel rollback <previous-deployment-url-or-id>

    Checklist


    • version.txt on the public domain equals git rev-parse HEAD for the commit you shipped.
    • The version file is served with no-store, and no page has a long max-age.
    • Hashed assets have a long lifetime; the page that references them revalidates.
    • Every script and stylesheet the page references returns 200.
    • The install step is npm ci.
    • Migrations run in the pipeline, before the app deploys, and are additive.
    • The verify script has failed once on purpose.
    • A rollback and a roll-forward have each been tried, and the marker changed both times.

    For a static frontend, Gemmein's publish reports the address and version only after the address has answered, or reports a failure with the step, the file and line when known, and the reason.

    Which check has told you a deploy was live while production was still serving the previous commit?#webdev #devops #nextjs #vercel #software #coding #development #engineering #inclusive #community
    Deploy succeeded but the live site still shows old content

Share on Mastodon

Enter the server where you have an account.