Stop Scraping Betting Sites: How to Build a Real-Time Sports Tracker in Python

If you have ever tried to build a sports dashboard, an arbitrage scanner, or an automated trading bot, you already know the painful truth: scraping bookmaker data is a nightmare.

Sites like Bet365, FanDuel, and DraftKings have aggressive anti-bot protection (hello, Cloudflare). Even if you bypass it, they constantly change their HTML structure, breaking your scrapers every few weeks. Plus, managing custom WebSocket connections for live in-play odds is an infrastructure money pit.

In this quick guide, we’ll build a real-time sports odds tracker in Python without writing a single line of scraper code.

To do this, we’ll use PulseScore, a real-time sports odds API that aggregates multiple bookmakers into a single, unified JSON shape. They have a completely free tier (no credit card required), which is perfect for this project.

🛠️ The Tech Stack

  • Python 3.x
  • Requests library (for polling pre-match data)
  • WebSockets library (for ultra-low latency live updates)

First, make sure you have the required packages installed:

pip install requests websockets

1️⃣ Fetching Pre-Match Odds (REST API)

One of the biggest headaches of multi-bookie apps is normalizing data. Every bookmaker names their markets and sports differently. PulseScore solves this by serving the same JSON structure whether you fetch from Bet365, DraftKings, or Bwin.

Here is how to fetch upcoming tennis or soccer matches using their clean REST endpoints:

import requests

# Get your free API key from [https://pulsescore.net](https://pulsescore.net)
API_KEY = "YOUR_FREE_SECRET_HEADER_KEY"
URL = "[https://api.pulsescore.net/v1/odds/bet365](https://api.pulsescore.net/v1/odds/bet365)" # You can easily swap /bet365 for /fanduel or /bwin

headers = {
    "X-Secret": API_KEY,
    "Accept": "application/json"
}

response = requests.get(URL, headers=headers)

if response.status_code == 200:
    data = response.json()
    # Let's print out the first few upcoming events
    for event in data.get("events", [])[:5]:
        print(f"Match: {event['home_team']} vs {event['away_team']}")
        print(f"Start Time: {event['start_time']}")
        print(f"1X2 Odds: {event['markets'].get('1x2')}n")
else:
    print(f"Error: {response.status_code}, {response.text}")

2️⃣ Streaming Live In-Play Odds (WebSockets)

For live betting or real-time trading, a 10-second delay is unacceptable. WebSockets allow you to stream low-latency data straight into your application.

Here is how you can listen to live match updates with a 1-2 second refresh rate:

import asyncio
import websockets
import json

API_KEY = "YOUR_FREE_SECRET_HEADER_KEY"
WS_URL = f"wss://ws.pulsescore.net/live?secret={API_KEY}"

async def stream_live_sports():
    async with websockets.connect(WS_URL) as websocket:
        print("Successfully connected to PulseScore live stream...")

        while True:
            try:
                message = await websocket.recv()
                event_data = json.loads(message)

                # Print real-time shifts in lines/odds
                print(f"Live Update: {event_data['home_team']} vs {event_data['away_team']}")
                print(f"Current Score: {event_data['score']}")
                print(f"Live In-Play Odds: {event_data['live_markets']}n")

            except websockets.ConnectionClosed:
                print("Connection closed, reconnecting...")
                break

asyncio.run(stream_live_sports())

💡 Why This Beats Custom Scrapers

  1. Unified JSON Shape: You can swap /bet365 for /fanduel, /bwin, or /ps3838 in your code, and the payload format remains identical. No need to map data structures manually.

  2. No IP Bans: You don’t have to manage proxy rotation or deal with headless browsers.

  3. Low Latency: Live events update every 1 second, keeping your data ahead of the curve.

Conclusion
Building sports tools should be about creating smart algorithms and beautiful dashboards, not fighting website layouts and Cloudflare blocks.eo

If you want to try this out yourself, head over to pulsescore.net, spin up a free plan (gives you 500 requests/mo right away), and test the payloads with the scripts above.

What are you currently building with sports data? Let me know in the comments below! ⚽🏀🎾

Civic Identity and Responsibility in Modern Democracy

Democracy depends on more than constitutions, elections, and political institutions. While laws and systems provide structure, the true strength of democratic society comes from citizens who actively participate in public life and contribute to the well-being of their communities. Civic identity and civic responsibility remain essential because they encourage individuals to move beyond passive observation and become engaged participants in shaping society.

Perspectives associated with Johnathan Bartee often emphasize that democratic values are strengthened through participation, service, and community engagement. Citizens who understand the importance of civic responsibility help create more resilient communities, reinforce public trust, and contribute to the long-term stability of democratic institutions.

Understanding Civic Identity

Civic identity refers to the connection individuals feel toward their society and democratic system. It reflects the understanding that citizenship includes both rights and responsibilities. In democratic societies, people are encouraged not only to benefit from freedom and opportunity but also to contribute positively to the broader community.

A strong civic identity develops through education, family influence, cultural traditions, and real-world experiences. Schools teach civic principles, communities encourage participation, and families often model values related to responsibility and public engagement.

Citizens who develop a strong civic identity are typically more likely to vote, volunteer, participate in community discussions, and support local initiatives. These forms of participation strengthen democratic culture because they encourage cooperation, accountability, and shared responsibility.

Democracy thrives when citizens recognize that their actions influence the health of their communities and institutions. Participation creates stronger social connections and helps reinforce the belief that collective effort can lead to meaningful progress.

Civic Responsibility Beyond Politics

Many people think of civic responsibility only in terms of voting or political participation, but civic engagement extends far beyond elections. Civic responsibility also includes volunteerism, community service, mentorship, and participation in projects that improve public life.

These activities strengthen communities because they encourage citizens to work together toward common goals. Volunteers who support food programs, educational initiatives, environmental projects, or public health campaigns contribute directly to social well-being while also building stronger relationships within their communities.

Service also creates opportunities for individuals from different backgrounds to collaborate. In diverse democratic societies, people often hold different political views, cultural traditions, and personal experiences. Community engagement provides common ground where individuals can cooperate despite these differences.

This collaborative environment strengthens democratic culture because it encourages empathy, understanding, and trust. Citizens who work together toward practical goals are more likely to appreciate shared interests and recognize the importance of cooperation.

Observations associated with Johnathan Bartee often highlight the idea that civic participation creates stronger communities by encouraging citizens to become active contributors rather than passive observers.

Historical Importance of Civic Participation

The relationship between democracy and civic responsibility has deep historical roots. Democratic societies throughout history have relied on active citizen participation to maintain stability and legitimacy.

In early democratic communities, citizens were expected to contribute to public life through governance, local projects, and collective decision-making. Participation was considered essential because democratic systems depended on citizens who were willing to support the broader community.

The American democratic tradition also placed strong emphasis on civic participation. Local organizations, town meetings, volunteer associations, and community initiatives became important parts of public life. Citizens who engaged in these activities helped strengthen social trust and reinforce democratic values.

Historical periods of national challenge often demonstrated the importance of shared responsibility and collective action. Communities came together during economic hardships, social transitions, and national emergencies to support one another and preserve stability.

These historical examples continue to offer important lessons today. Modern democratic societies still rely on active citizenship and civic engagement to address social challenges and maintain public trust.

Volunteerism and Community Engagement

Volunteerism remains one of the clearest expressions of civic responsibility in modern society. Millions of people contribute their time, skills, and resources to causes that support education, healthcare, environmental protection, and social services.

Community engagement allows citizens to make tangible contributions while also strengthening social connections. Volunteers often gain a better understanding of local challenges and develop stronger relationships with the people around them.

Service projects also encourage leadership development. Individuals who participate in community initiatives frequently gain experience in communication, organization, collaboration, and problem-solving. These skills benefit both the individual and society as a whole.

Volunteerism also reinforces the democratic principle that individuals can create positive change through collective effort. Citizens who work together to address challenges help create stronger and more resilient communities.

Perspectives connected to Johnathan Bartee often emphasize that volunteerism remains a powerful way to strengthen democratic participation and encourage social responsibility.

Civic Education and Future Generations

The future of democracy depends heavily on how younger generations understand civic identity and responsibility. Civic education helps students learn about democratic systems, public institutions, and the importance of participation.

However, effective civic education involves more than classroom instruction. Young people also benefit from practical experiences such as volunteer programs, community projects, and service-learning initiatives.

These experiences teach students how their actions can influence society while also helping them develop empathy, leadership abilities, and critical thinking skills. Service-learning programs are especially valuable because they combine academic knowledge with real-world engagement.

Families and communities also play an important role in shaping civic values. Young people who see examples of volunteerism and public participation are more likely to adopt those behaviors themselves.

By encouraging civic engagement early in life, societies help cultivate future citizens who are prepared to contribute meaningfully to democratic institutions and community life.

Civic Responsibility in the Digital Era

Technology has transformed how citizens participate in public life. Social media platforms and digital communication tools provide new opportunities for civic engagement, awareness campaigns, and community organizing.

Digital platforms make it easier for people to support charitable causes, organize volunteer efforts, and raise awareness about social issues. These tools can strengthen participation when used responsibly.

At the same time, the digital environment also creates challenges related to misinformation, polarization, and online hostility. Civic responsibility in the digital era requires individuals to think critically, verify information, and engage respectfully with others.

Responsible digital citizenship involves using technology in ways that support constructive dialogue and strengthen communities rather than contribute to division.

Communities that encourage thoughtful digital participation are often better equipped to maintain healthy democratic discussion and public trust.

Democracy Through Participation

Ultimately, democracy depends on citizens who are willing to participate actively in public life. Civic identity and civic responsibility provide the foundation for stronger communities, healthier institutions, and more resilient democratic societies.

Volunteerism, service, leadership, and public engagement all reinforce democratic values by encouraging cooperation, accountability, and shared responsibility. Citizens who contribute positively to their communities help create environments where democracy can continue to thrive.

Perspectives associated with Johnathan Bartee continue to emphasize that democracy is not self-sustaining. It requires active citizens who recognize that freedom and participation are closely connected.

As societies continue to evolve, civic engagement remains one of the most important ways individuals can strengthen democracy and contribute to a more connected and responsible society.

OLTP vs OLAP

Introduction

It’s the favorite time of the year, Christmas. It’s Christmas eve night and you remember that you haven’t gotten your special person a gift yet. What do you do? hurriedly you get you phone and go straight to your favorite online shopping platform. You search for the product you want and you find it, only one is remaining in stock ‘I am lucky’ you sigh in relief and click on the buy now button. Immediately you click on the button, a popup appears saying ‘Out of Stock’, I guess you were not so lucky after all. But how did this happen? That is where Online Transactional Processing (OLTP) comes into play. Behind the scenes there was a system that made sure that you were able to see that your product has only one item left in stock and milliseconds later tell you that it is out of stock and at the same time sell the product to the other person who beat you to it. Next time buy your gifts early.
January is hear and the festivities are over. As data analyst working for an online shopping platform, your organization wants to go back in time ( 5 years), know what products sell best during the Christmas season, what regions have the highest sales, total revenues generated and customer trends over the period. How will these be possible? That is where Online Analytical Processing (OLAP) comes into play. With OLAP, you will have a system optimized to enalble you as an analyst perform complex queries and data analysis on these vast amount of data recorded over the past five years.

What is OLTP?

Online Transaction Processing (OLTP) is a type of database system that is designed to manage and process large numbers of short, fast and real-time transaction such as banking operations, online shopping, ATM withdrawals and point-of-sale purchases.

For example: When using an online shopping platform, you select the item you want to buy, add it to a shopping cart, enter your payment details and then click on the ‘buy now’ button. But what exactly happens? behind the system lies an online transactional processing system that verifies your customer account, checks the product inventory to make sure that the product you intend to buy is in stock, records the order, process the payment, updates the stock levels, generates an invoice and sends an order confirmation. Each of these actions must happen quickly and accurately within seconds and milliseconds while thousands if not millions of other users are also shopping at the same time. The OLTP database ensures that the transactions are completed reliably and preventing a situation where a product is sold twice while only one time was in stock.

What is OLAP?

Online Analytical Processing (OLAP) is a type of database system designed for analyzing large amounts of historical and business data to support decision-making, reporting, forecasting and business intelligence. They are optimized to handle complex queries and data analysis across multiple dimensions such as time, region, product or customers.

For example: A a supermarket chain with multiple stores across the country collects all its transactions data including what was sold, when, where and at what price and stores it a data warehouse. Managers and analysts can perform analysis on these data and gather insights such as; comparing total sales across different regions, finding out which products sell the most during weekends vs weekdays and perhaps identifying the best and least performing stores.

So what is the difference between OLTP and OLAP?
OLTP is optimized for executing online database transactions helping you to reliably and efficiently collect and store high volumes of transactional data while OLAP on the other hand is optimized for complex data analysis aiding you in analyzing the stored data and get insights that lead to business decisions and strategies.

Key differences between OLTP and OLAP

The primary purpose of Online Transactional Processing is to process (OLTP) is to process database transactions while Online Analytical Processing (OLAP) is to analyze aggregated data.

1. Data formatting

  • OLPT systems are unidimensional and focus on one data aspect. They use relational databases to organize data into tables with each raw representing an entity instance and each column representing an entity attribute.
  • OLAP systems store data in multidimensional data models so you can view data from different angles. OLAP databases store data in a cube format where each dimension represents a different data attribute and each of the cell in the cube represents a value or measure for the intersection of the dimensions.

2. Data architecture

  • OLTP database architecture prioritizes data write operations. It is optimized for write-heavy workloads and can update high-frequency, high-volume transactional data without compromising data integrity.
  • OLAP database architecture prioritizes data read over data write operations allowing analysts to perform complex queries on large volumes of data. Also, availability is low concern as the primary use case is analytics.

3. Performance

  • OLTP processing times are in milliseconds or less. OLPT databases manage databases updates in realtime. Updates are fast, short and triggered by you or your users. Stream processing is often used over batch processing.
  • With OLAP, processing times can vary from minutes to hours depending on the type and volume of data being analyzed. To update OLAP databases, you periodically process data in large batches then upload the batch to the system all at once. Data update frequency also varies between systems from daily, weekly or even monthly.

4. Requirements

  • OLTP requires high amounts of compute power and storage space. This is because of their nature of performing high amounts of transactions and at high speeds. They also store high volumes of data thus requiring a good amount of storage space ranging to gigabytes(GB). OLPT database can be cleared once the data has been moved to a data warehouse.
  • OLAP systems act like centralized data storage pulling data from data warehouses, relational databases and other systems. Storage requirements measure from terabytes(TB) to petabytes(PB). Data reads can also be compute intensive thus requiring high performing servers.

When to use OLPT vs OLAP

pick OLTP when your application processes individual transactions that need immediate consistency and fast response times. For example an e-commerce application or banking application that performs high volumes of transactions, has strict requirements where it cannot tolerate temporary inconsistencies and has low-latency point lookups such as user authentications and balance checks.

Choose OLAP when you need to analyze historical data through complex queries that aggregate millions of rows. For example huge multinational organizations that need to perform complex aggregations at scale, analyze historical trend analysis and has dashboard need for visualization and reporting needs for management.

Can OLPT and OLAP be used together?

The answer is yes. OLTP and OLAP systems are often used together in modern data systems where OLTP handles day-to-day business operations while OLAP supports analysis and decision making. For example, a business using OLTP to record customer transactional data in real time an using technologies such as change data capture (CDC) and tools such as Apache Kafka and Debezium they can stream database changes to OLAP systems.

Conclusion

OLTP and OLAP serve complementary but distinct roles in modern data-driven systems. OLTP is optimized for speed,accuracy and reliability while handling real-time transactional operations while OLAP is optimized for complex analysis enabling organizations to explore historical data and gather insights.

“Online Transactional Processing (OLTP) enables you to purchase products online and bank reliably while Online Analytical Processing (OLAP) enables the online shopping platform and banking institutions to perform analysis of you other millions of customers data and provide better services.”

Are binaries really executable code ?

What is the difference between a binary file and an executable( machine code )?

so this questions has been in my head for a long time and they are almost used interchangabely right but are they so lets find out ..and i want to learn this from the very first principle . so in order to understand this we would use C and cause its simple and fun to mess around with without unnecessary abstractions . so first we would need to get some fundamentals clear that i am rusty on .

to answer this we need to understand how c actually turns your code into something you can run — and that journey is where the answer lives.

char text[100] = "hello";
char other[100] = "hello";
// this is a simple declaration in c for declaring 2 array of char 
// This compares addresses, NOT content - always false
if (text == other) {
 printf("match"); // never runs
}
// This compares the actual characters - works correctly
if (strcmp(text, other) == 0) {
 printf("match"); // runs!
}

strcmp? what is the full form ? and what about strncpy? i kind of wonder what these are made of ? ← FIXED: added strncpy mention here

ok lets try to look at the source code of strncpy i hopes its called .. ← FIXED: says strncpy now

/* Copyright © 1991–2018 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see http://www.gnu.org/licenses/. */

please dont sue me or anything i know i dont own any of this i am just an idiot that is it and if you do please tell me before so i can delete it

#include <string.h>
#undef strncpy
#ifndef STRNCPY
 #define STRNCPY strncpy
#endif

what is this ? what is a preprocessor directive anyways ? what is it telling the compiler ?


char *
STRNCPY (char *s1, const char *s2, size_t n)
{
 size_t size = __strnlen (s2, n);
 if (size != n)
 memset (s1 + size, '', n - size);
 return memcpy (s1, s2, size);
}
libc_hidden_builtin_def (strncpy)

so here is the first thing that is bugging me fom this example .what the hell is a preprocessor directive ? so what is a preprocessor ? a preprocessor is like a butler that formats and changes the code into a more “refined” version of the code that is then fed to the compiler . so that would mean that if the preprocessor is not related to the compilation of the language then its not in the compilation of the code . making this # stuff something that would help the compiler do its job somehow . so here is what happens in c during the compilation and before the compilation –

the preprocessor just copy pastes all the headers that you have imported in the code in the main c program .. i am not even kidding its just a big copy and paste if you have used a library like #include or something its gonna literally copy and paste all the functions that are in that header file into your main program . to see this with your own eyes write a program and import all the headers that you want and then just write this in the terminal

gcc -E main.c

i am assuming that your file name is main.c alright dont be dumb like me as to copy and paste the entire line for your file name and then thinking why doesnt it work this -E only activates the preprocessor and hence you can see the copy and paste happening with your own eyes . then whatever the remaining of the code is there usually in one file is gonna be fed to the compiler for turning that into machine code .

one thing really caught my eye is that c doesnt allow you to have two functions definitions even though they are literally the same in terms of definition the c compiler will throw an error as soon as it comes across . now this might look harmless cause well we wont define a functions twice right but it has stuff that can be dangerous in the grand scheme of things . the preprocessor will copy the functions right it doesnt care if they are the same or not its just does copy and paste and some of the other simmilar stuff that we will talk about in a sec . so before we talk about it i want you to answer a question for me — Q. I just said that the compiler wont let you define something twice right? and the implications of that is that lets say that i use a popular header in the c program right something like stdio.h right and lets say that another header file that i am using in my code also have that … then shouldnt it give out an error ? lets try it — ← FIXED: “declare” → “define”

this is the main.c right and here i am importing some of the header file without particularly using them but that is not the point alright-

#include <stdio.h>
#include <stdlib.h>
#include "math_my.h"
int main(){
printf("%dn",add(4,6));
// the add function is defined in the math_my.h 
//this is defined below ..
}

this is the math_my.h

#include <stdio.h>
int add(int a , int b ){
 return a+b;
}

now notice something that i told you all before and that is that the is included twice and yet the compiler wont give out any errors ? why is that ? and this question is really interesting … ← FIXED: “declared” → “included”

Learn about Medium’s values
here look at the compilation message

avirals554@Avirals-MacBook-Air c-term % gcc explore.c -o explore
avirals554@Avirals-MacBook-Air c-term % ./explore
10
42
look it compiled ? but why is that ? how ? i mean it shouldnt right ? but why did it ? even though we are literally using the stdio.h twice ? hmmm… ok lets read the stdio.h itself alright

avirals554@Avirals-MacBook-Air c-term % cat /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdio.h
i just hope i dont get copyright violation or something . that is why i have added this so the important thing in all of this is this like #include <_stdio.h> so this is importing another header file ? and what are these stuff ??


#ifdef _USE_EXTENDED_LOCALES_
#include <xlocale/_stdio.h>
#endif /* _USE_EXTENDED_LOCALES_ */

hmm iteresting .. lets read the _stdio.h file right … ok apart from the copyright stuff this is what i am able to extract from this file –

#ifndef _STDIO_H_
#define _STDIO_H_
void clearerr(FILE *);
int fclose(FILE *);
int feof(FILE *);
int fgetc(FILE *);
int fprintf(FILE * __restrict, const char * __restrict, …);
int fputc(int, FILE *);
int scanf(const char * __restrict, …);
int printf(const char * __restrict, …);
#include <_types.h>
#include <sys/_types/_va_list.h>
#include <sys/_types/_size_t.h>
#if __DARWIN_C_LEVEL >= 200809L
 ssize_t getline(…);
#endif

alright i get some of it 2nd one is the declaration of the functions that it has right but not the definitions themselves ? so where is it getting the actual definitions from ? i mean if the preprocessor is just gonna copy and paste this then … where does it get the definitions of these functions ? …

so here is the fun thing . the compiler actually compiles this as it is like this into the machine code meaning the compiler doesnt get the definition of those functions at all … so you might ask wait …. then how does the code works at all just from the declarations of those functions ?? doesnt it needs to get those definitions ? it does it AFTER the compilation.. through a little thing called a linker .. which finds those definitions and in this there is a file that i found named this — libSystem.dylib and i am not sure what this library has accurately but my best guess is that its must have those definitions but as its not in the .h format they are stored in some other format . now here is what bugs me if the code is already compiled then it cannot be in the c code right ? i mean it must be in the machine code cause the compilations is already done . now i need to find the step just before the linker and ask the gcc to show my that only , so the process is like this –

code → preprocessor → compiler → linker → executable ← FIXED: “machine_code” → “executable”

alright we know what is (2) right ? from this command that we talked about above — gcc -E main.c

alright so this is a code that is what the compiler sees right and as i said about the same name problem so i am guessing that the compiler dont have a problem with declarations being done twice — and that is the key insight. stdio.h only contains declarations (just the list of functions without the actual code), and you can declare something as many times as you want. What you cant do is define it twice — the full function with the curly braces and the code inside. Thats what would cause an error. ← FIXED: clarified the declaration vs definition point

ok but to know that i need to see what the compiler produces right ? so i looked it up and got this –

gcc -c main.c

this creates a .o file with the same name so we get a main.o file and so if i try to read it via cat i am getting garbage meaning its a machine code probably ,so we will use this –

objdump -d explore.o

this objdump thing is just something that can apperently read BINARIES, and if you see the topic of this blog i am asking the difference between binaries and executable so here we are .. this .o file is an incomplete binary. meaning that it still does the thing was in the code that the preprocessor gave it but doesnt really have the definitions yet . so we must read it the .o file i mean .. so after running the command i get this –


objdump -d explore.o
explore.o: file format mach-o arm64
Disassembly of section __TEXT,__text:
0000000000000000 <ltmp0>:
 0: d10043ff sub sp, sp, #0x10
 4: b9000fe0 str w0, [sp, #0xc]
 8: b9000be1 str w1, [sp, #0x8]
 c: b9400fe8 ldr w8, [sp, #0xc]
 10: b9400be9 ldr w9, [sp, #0x8]
 14: 0b090100 add w0, w8, w9
 18: 910043ff add sp, sp, #0x10
 1c: d65f03c0 ret
0000000000000020 <_square>:
 20: d10083ff sub sp, sp, #0x20
 24: a9017bfd stp x29, x30, [sp, #0x10]
 28: 910043fd add x29, sp, #0x10
 2c: b81fc3a0 stur w0, [x29, #-0x4]
 30: b85fc3a0 ldur w0, [x29, #-0x4]
 34: b85fc3a1 ldur w1, [x29, #-0x4]
 38: 94000000 bl 0x38 <_square+0x18>
 3c: b9000be0 str w0, [sp, #0x8]
 40: b9400be8 ldr w8, [sp, #0x8]
 44: 11008908 add w8, w8, #0x22
 48: b9000be8 str w8, [sp, #0x8]
 4c: b9400be0 ldr w0, [sp, #0x8]
 50: a9417bfd ldp x29, x30, [sp, #0x10]
 54: 910083ff add sp, sp, #0x20
 58: d65f03c0 ret
000000000000005c <_main>:
 5c: d10103ff sub sp, sp, #0x40
 60: a9037bfd stp x29, x30, [sp, #0x30]
 64: 9100c3fd add x29, sp, #0x30
 68: 52800008 mov w8, #0x0 ; =0
 6c: b81ec3a8 stur w8, [x29, #-0x14]
 70: b81fc3bf stur wzr, [x29, #-0x4]
 74: b81f83a0 stur w0, [x29, #-0x8]
 78: f81f03a1 stur x1, [x29, #-0x10]
 7c: 52800080 mov w0, #0x4 ; =4
 80: b9000fe0 str w0, [sp, #0xc]
 84: 528000c1 mov w1, #0x6 ; =6
 88: 94000000 bl 0x88 <_main+0x2c>
 8c: 910003e9 mov x9, sp
 90: aa0003e8 mov x8, x0
 94: f9000128 str x8, [x9]
 98: 90000000 adrp x0, 0x0 <ltmp0>
 9c: 91000000 add x0, x0, #0x0
 a0: f9000be0 str x0, [sp, #0x10]
 a4: 94000000 bl 0xa4 <_main+0x48>
 a8: b9400fe0 ldr w0, [sp, #0xc]
 ac: 94000000 bl 0xac <_main+0x50>
 b0: aa0003ea mov x10, x0
 b4: f9400be0 ldr x0, [sp, #0x10]
 b8: 910003e9 mov x9, sp
 bc: aa0a03e8 mov x8, x10
 c0: f9000128 str x8, [x9]
 c4: 94000000 bl 0xc4 <_main+0x68>
 c8: b85ec3a0 ldur w0, [x29, #-0x14]
 cc: a9437bfd ldp x29, x30, [sp, #0x30]
 d0: 910103ff add sp, sp, #0x40
 d4: d65f03c0 ret

now this is a machine code right ? but its very very small and you can kind of see the tags as main , square and all that

`88: 94000000 bl … ← call to add()
a4: 94000000 bl … ← call to printf()
ac: 94000000 bl … ← call to square()
c4: 94000000 bl … ← call to printf()`

so i just googled where in this code are the “call” to the functions in that library right and here they are these are literally the stuff that are getting called . but notice something else as they are getting called its calling a machine code .. that would mean that all the code is compiled to machine code and our code is just calling it .. making it an EXECUTABLE get it ? that is the difference between an executable and a binary .

a binary is any file that contains machine-readable bytes — not human-readable text. your .o file is a binary. a JPEG image is a binary. a PDF is a binary. none of them are text.

an executable is a specific type of binary — one that is complete and ready to run as a program. the .o file is binary but NOT executable because it still has holes (those 94000000 placeholders). after the linker fills in those holes, THATS when it becomes an executable.

every executable is a binary. but not every binary is an executable. ← FIXED: expanded the ending

ps : the definitions are more nuanced than i have just told right cause there are many many types of binaries right

Is AI Actually Citing Your Site? How to Measure What Google Rankings Can’t

SEO KPIs vs LLMO KPIs: ranking position disappears, citation becomes the metric

I’ve spent the past few weeks writing about LLMO: how to get cited by AI search engines, which content structures work, what Princeton’s GEO study says about visibility. All useful stuff. One problem: I had no idea whether any of it was actually working.

I was like a chef who obsesses over recipes but never tastes the food. My Google Search Console was immaculate. My LLMO measurement setup? I was literally typing “does ChatGPT know about my site” into ChatGPT and refreshing the page like a teenager checking if their crush liked their post.

Measuring LLMO is a genuinely hard problem, and most people aren’t doing it at all. Here’s what I’ve built: three measurement layers, from “costs nothing” to “costs you a Saturday afternoon of Python.”

SEO KPIs vs LLMO KPIs: ranking position disappears, citation becomes the metric

The Measurement Gap

In SEO, measurement is a solved problem. Google Search Console shows rankings, impressions, clicks, and CTR for free, updated daily. Ahrefs adds backlink data. SEMrush gives you keyword tracking. Everything is visible.

In LLMO, almost nothing is visible out of the box.

There’s no “AI Search Console.” ChatGPT doesn’t send a weekly email saying “You were cited 47 times!” Perplexity has no creator dashboard. The shift: SEO had rankings (1st through 100th position). LLMO has a binary outcome. You’re either cited or you’re not. And nobody is telling you which.

This gap isn’t just an inconvenience. You can’t improve what you can’t measure, and right now, most content creators are optimizing for AI visibility while flying blind.

Three layers of LLMO measurement: GA4, manual protocol, Python automation

Layer 1: GA4 AI Referral Traffic (Free, 5 Minutes)

The easiest measurement you can set up today is tracking AI referral traffic in Google Analytics 4. When an AI search engine cites your site with a clickable link and someone clicks it, GA4 records the source.

Here is the regex pattern I use in a custom channel group:

chatgpt.com|perplexity.ai|claude.ai|gemini.google.com|copilot.microsoft.com|deepseek.com|you.com|meta.ai|poe.com

Go to Admin → Channel Groups → Create, add a new channel with this regex as the session source filter, and name it “AI Search.” You’ll immediately see aggregated traffic from all AI platforms in one view.

A few things to know:

ChatGPT plays nicely. Since late 2025, ChatGPT appends utm_source=chatgpt.com to outbound links. ChatGPT traffic shows up cleanly as chatgpt.com / referral in GA4.

Perplexity is decent. Traffic appears as perplexity.ai / referral, though without UTM tags. Still trackable.

Free-tier ChatGPT is a black hole. Free users often don’t send referrer data due to privacy settings. Their clicks show up as “Direct,” indistinguishable from someone typing your URL manually. Your GA4 numbers are a floor, not a ceiling.

The conversion story is where this gets interesting. Industry data from 2026 shows AI referral traffic converts at 8-12%, compared to 2-3% for traditional Google organic. People who arrive via AI search have already done their research. The AI did it for them. They are further along in the decision process.

I started tracking three weeks ago. My AI referral traffic is still small (single digits daily), but the conversion rate is 3x my organic average. Small sample, but a signal worth watching.

Layer 2: The “Ask Five AIs” Protocol (Free, 30 Min/Month)

GA4 tells you who clicked through. It does not tell you whether AI is mentioning you without linking, or whether it is mentioning you at all.

For that, you need to ask directly. I run this on the first Monday of every month:

Step 1. Write 10-15 prompts related to your niche. Mine include “What are the best resources for AI search optimization?”, “How do I get my site cited by ChatGPT?”, and “LLMO vs SEO differences.”

Step 2. Run each prompt on five platforms: ChatGPT, Perplexity, Gemini, Claude, and Copilot.

Step 3. Record four things per prompt per platform:

  • Mentioned? (Yes / No)
  • Context (recommendation / comparison / neutral / negative)
  • Accuracy of information
  • URL provided?

Step 4. Calculate your citation rate. 15 prompts x 5 platforms = 75 checks. Mentioned 20 times? That’s 26.7%.

This takes about 30 minutes with a spreadsheet. It’s manual and tedious, and also the most reliable method that exists today. Automated tools can approximate this, but they can’t replicate the nuance of “was that mention positive or just a passing reference?”

One caveat: LLM responses are non-deterministic. The same prompt can produce different answers on different days. A single check isn’t statistically significant. That is why I track the monthly trend, not individual data points. Three months of data starts showing real patterns.

Layer 3: Automate It With Python (One Saturday)

If you’re an engineer, you can automate the manual protocol with API calls. Hit the OpenAI and Anthropic APIs with your query set, check whether your brand appears in the response, and log results as a time series.

The core logic is simple:

BRAND_VARIANTS = ["your-site.com", "Your Brand", "yourbrand"]
CHECK_QUERIES = [
    "Best tools for [your category]",
    "How to solve [problem you address]",
    "[Your brand] vs [competitor]",
]

def check_openai(query: str) -> dict:
    client = OpenAI()
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": query}],
        temperature=0.0,
    )
    answer = response.choices[0].message.content
    mentioned = any(v.lower() in answer.lower() for v in BRAND_VARIANTS)
    return {"platform": "ChatGPT", "query": query, "mentioned": mentioned}

Extend this for Claude and Perplexity, run weekly via cron, dump to CSV. You get a time series of your AI visibility score for about $0.50/week.

The payoff: instead of “I think LLMO is working,” you can say “my visibility went from 12% to 28% after I added structured data.” Numbers beat feelings.

What’s Available in May 2026

If building your own tools isn’t your thing, several commercial platforms now track AI citations:

Otterly.ai is the fastest-growing option, with 10,000+ users since launching in October 2024. It monitors your brand across ChatGPT, Perplexity, Google AI Overviews, and Copilot. Keyword-level citation tracking, competitor benchmarking, and clean dashboards.

Profound sits at the enterprise end. Their published case study with Ramp, where they went from 3.2% to 22.2% AI visibility in one month, is the kind of result that gets budget approved. If you’re a larger organization, this is where you’ll probably land.

Peec AI focuses on brand mention analysis across LLM outputs. Beyond whether you’re cited, it tracks how: what sentiment surrounds your mentions, which prompt patterns trigger citations.

My honest take: for individual creators and small teams, the manual protocol plus a basic Python script gives you 80% of the insight at 0% of the cost. Commercial tools become worthwhile when you’re tracking dozens of keywords across multiple brands and need team dashboards.

The Crawler Signal You’re Probably Ignoring

Here’s a measurement angle most people miss: AI crawler logs.

Your server access logs already record which AI systems are visiting your content. GPTBot (OpenAI), ClaudeBot (Anthropic), PerplexityBot, Google-Extended. They all identify themselves in the User-Agent string.

grep -E "GPTBot|ClaudeBot|PerplexityBot|Google-Extended" 
  /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn

Pages that get crawled frequently are more likely to appear in AI responses. Pages that never get crawled are invisible. It is an indirect signal, but useful for finding content that AI systems are skipping entirely.

I checked my own logs and found that /blog/ pages get crawled 15x more than my /about/ page. Not shocking, but the gap was wider than I expected.

Building a Measurement Habit

Measurement without action is just data hoarding. Here is the cycle I run:

Weekly (10 min): Check GA4 AI referral dashboard. Note spikes or drops. Compare week-over-week.

Monthly (30 min): Run the five-platform manual protocol. Calculate citation rate. Scan crawler logs for new patterns.

Quarterly (1 hour): Full review. Update query set. Compare citation rate trends. Check whether content changes produced measurable results.

The LLMO Framework provides a structured approach to KPI design if you want a more formal methodology. I reference it when deciding which metrics matter most at different growth stages.

The Punchline

I started measuring my LLMO visibility three weeks ago. My citation rate across five platforms is 14%. Not great. Not terrible. But the important part is that I know the number, and three months from now I’ll know whether it went up or down.

The SEO world figured out measurement twenty years ago. The LLMO world is still in its “checking rankings by Googling yourself” era. The people who build measurement infrastructure now will have a compounding advantage over those who keep guessing.

If you’re still typing your brand name into ChatGPT and squinting at the output, I get it. I was doing the same thing last month. But now I have a spreadsheet, a cron job, and a regex filter in GA4. Less romantic, more informative. I’ll take that trade.

References

The full playbook (llms.txt patterns, JSON-LD examples, citation-rate KPIs, and ChatGPT/Perplexity/Brave comparison) is in LLMO Practical Guide: Why ChatGPT Ignores Your Website.

What a Datacenter in Space Actually Buys You: Three Server Racks

Last December, Sundar Pichai announced that Google had decided to put data centers in space. Project Suncatcher was the moonshot — Pichai’s word — and the framing was that the sun puts out “100 trillion times more energy than what we produce on all of Earth today,” and Google would like access to that. Two pilot satellites with Planet Labs are scheduled for early 2027. “A more normal way to build data centers” is how Pichai described it, with a horizon of about a decade.

Then a former NASA engineer with a PhD in space electronics, who happened to have spent a decade at Google’s YouTube and Cloud-AI infrastructure, sat down at a blog called taranis.ie, opened with “For clarity: I am a former NASA engineer/scientist with a PhD in space electronics. I also worked at Google for 10 years,” and proceeded to walk through why none of this works. The post — credited to a single byline, Taranis — went to the front page of Hacker News and ran 361 comments deep, then to Lobsters, and game-engineering veteran Christer Ericson endorsed it on X with “data centers in space is a fantasy.”

Here is the math I cannot stop thinking about. The largest solar array ever deployed in space is on the International Space Station. It produces about 200 kilowatts at peak, covers about 2,500 square meters — half a football field — and required several Shuttle missions to install. An NVIDIA H200 draws 700 watts at maximum thermal design power, and Taranis’s rule of thumb of about one kilowatt per GPU once support hardware is counted is conservative. So an ISS-sized solar array, the largest humans have ever flown, can power approximately two hundred GPUs. NVIDIA’s standard 72-GPU rack ships in a DGX configuration that already exists. One ISS in orbit, powered to its peak, runs three of them.

Stargate Norway — OpenAI’s first European AI gigafactory, announced in summer 2025 — targets 100,000 GPUs by the end of 2026. To match that in orbit you would need five hundred ISS-sized solar arrays. The ISS itself took thirteen years and forty-some launches to build.

This is the kind of piece where the rest of the article is the unpacking.

Power

The intuition behind a space data center is that the sun is up there and it is enormous, and so power is, in some loose sense, free. The intuition is wrong in a specific way. Solar panels in orbit are essentially the same panels that cover the roof of any rooftop installation, with the same conversion efficiency, slightly more sunlight (the atmosphere absorbs a few percent), and no night. The advantages are real but they are a couple of multipliers, not a step change. The disadvantage is that the panels have to be deployed in vacuum, which is hard, and held there, which is harder. The four primary ISS solar wings were each delivered on a separate Shuttle mission — STS-97, STS-115, STS-117, STS-119 — between December 2000 and March 2009. That’s nine years to get four solar wings in orbit. The deployment is the easy part of operating them.

The other power option is nuclear, and in orbit that means radioisotope thermoelectric generators, which are the small plutonium-powered heat engines that drove the Voyager and Cassini probes. They produce 50 to 150 watts apiece. As Taranis observes, that is not enough to power one H200, even before you have asked anyone for a sub-critical lump of plutonium-238 and explained what you plan to do with it. The reactors NASA actually flies in orbit aren’t reactors at all. The reactors that would be reactors aren’t ready, and the agencies that would have to license them are unenthusiastic.

So the math is solar, and the math is two hundred GPUs per ISS-sized array, and the marketing slide where the sun is “100 trillion times the energy” of all human civilization is operating on a scale where the energy that matters is not the energy in the sun but the energy you can collect on a panel, beam to a chip, and not boil the chip with.

Thermal regulation

This is the section that broke me on first reading and is, in the long run, the structural argument against the whole project.

There is no air in space, which means there is no convection. On Earth, the way a data center stays alive is that hot air rises off a chip, gets entrained in a heatsink fan, gets dumped into a cold aisle, gets pumped through liquid loops or chilled-water exchangers, and ultimately gets convected into the atmosphere. The atmosphere has been doing the heavy lifting for the entire computing industry for sixty years. The atmosphere is the actual cooling system; everything else is a connector to it.

In orbit there is no atmosphere. There is no medium for the heat to leave through except radiation, which is the same mechanism that makes a hot piece of metal glow. The Stefan-Boltzmann law puts a cap on how much heat per square meter a radiator panel can dump, and the cap is unforgiving.

The ISS has the largest active thermal-control system humans have ever flown, the Active Thermal Control System (ATCS). It uses an ammonia coolant loop and a series of large radiator panels that face away from the sun. The system’s dissipation cap is 16 kilowatts. Sixteen kilowatts is the peak heat budget of the ISS thermal system. That is the equivalent of approximately sixteen H200 GPUs, or roughly one-quarter of an NVIDIA DGX rack. The radiator panels themselves are 13.6 m × 3.12 m, about 42.5 m². To dissipate the full 200 kW from a notional ISS-sized solar array, the same scaling on radiator area lands around 531 square metres of additional radiator panel, on top of the 2,500 m² solar array that’s already there. The satellite is now substantially larger than the ISS, and it is dissipating the heat of three server racks.

There is no engineering shortcut here. Stefan-Boltzmann is a temperature-to-the-fourth-power relationship and the radiator surface temperature is bounded by the temperature at which the chips you’re cooling stay alive. You can play tricks at the margin — heat pipes, two-phase loops, anti-sun-side radiators — but the margins are tens of percent. The marketing pitch “space is cold, so cooling is easy” is the inverse of the truth: space is insulating, and the only way to lose heat is to radiate it, and your radiator is what bounds the size of the satellite.

Radiation

The third reason this doesn’t work is that the chips you would put in orbit don’t survive in orbit.

GPUs and TPUs and the high-bandwidth memory they depend on are the worst-case silicon for radiation tolerance. The transistors are small, which means a single charged particle passing through one is a larger fraction of the gate’s relevant area, which means a single hit is more likely to flip a bit (a single-event upset) or, worse, to cause a single-event latch-up where a transistor turns itself on, draws current it shouldn’t, and burns the chip out. The die area is also enormous, which means more hits per second per chip. And the cumulative dose effect over months — transistors switching slower, drawing more power, eventually crossing into nonfunctional — is exactly the failure mode you don’t want at scale, because you can’t service it.

Chips actually designed for space use a different gate topology and much larger geometry — typically the BAE RAD750, based on a PowerPC architecture from the late 1990s, or its successors. Per Taranis’s framing, the typical processor on an actually-flying spacecraft has compute roughly equivalent to a 2005-era PowerPC. The relationship is not negotiable: radiation hardness comes from larger transistor geometry; performance comes from smaller. Pick one.

You could ship the H200s anyway — Taranis calls this the “YOLO approach” — and that’s how cubesats often work, which is also why cubesats often fail within weeks. Shielding helps a little, except past a thin layer it makes the problem worse: a cosmic ray hitting a sufficient mass of shielding produces a shower of secondary particles, and now you have many hits where you used to have one. Mass is always at a premium on a satellite. The result is that for a long-duration orbital data center — which it has to be, because at $5,000 per kilogram of launch mass, it isn’t economic for anything short — you can’t ship the GPUs you actually want, and the chips you can ship aren’t the ones the customer is paying for.

Google’s own Project Suncatcher paper acknowledges this and reports that Google ran TPUs in a particle accelerator and they survived for a simulated five years. This is a real result and it is not the same thing as the chips being the chips you would ship to a customer. The accelerator simulates dose; it doesn’t simulate every failure mode at sufficient fidelity, and the chip you put in space still has to be one that exists, which means it’s a TPU one or two generations old by the time it flies, and it’s competing in the AI-compute market against a TPU running on the ground that is being upgraded twice a year.

Communication

The smaller of the four problems, but worth saying. A typical orbital satellite communicates with the ground at single-digit gigabits per second on radio. Optical inter-satellite links are improving but they require atmospheric clarity to reach the ground, and a single rack of GPUs in a terrestrial data center can saturate hundred-gigabit interconnect to its neighbors as a floor. The space data center, until somebody builds the orbital optical mesh that doesn’t exist, has the I/O of a rack from 2010 with the compute of three.

The marketing-physics gap

Project Suncatcher’s own paper gets to the punchline by halfway through. “Launch costs could drop below $200 per kilogram by the mid-2030s.” SpaceX’s Falcon 9 is currently around $2,720 per kilogram to LEO; Starship’s projected mature cost — if Starship works at full reusable cadence, which it currently does not — is in the $200–500 range. Google’s paper is asking the reader to assume that Starship works, at scale, with the cost curve fully realized, in eight to ten years, and then the math becomes plausible.

The math also doesn’t actually become plausible. At $200/kg, the launch costs of a 200 kW solar array (a large structure of conservative-but-substantial mass) plus the corresponding 531 m² radiator plus the rad-hard or non-rad-hard compute payload plus the maneuvering and station-keeping plus the redundancy still produces three racks of orbital compute for tens of millions of dollars in launch costs alone, before the spacecraft bus or the deployment operations. You can build the equivalent terrestrial data center, including the grid hookup and the power-purchase agreement and the cooling tower, for less than that.

The honest version of the case for space data centers is that the grid is the binding constraint, not the silicon, and the AI industry has lost so much social license over the past two years on water consumption, farmland conversion, and electricity-rate impacts that putting the next 100,000 GPUs into someone else’s atmosphere is starting to look like the path of least resistance. That’s not engineering. That’s the marketing department’s response to the political problem the engineers gave them.

Why the marketing keeps coming back

The reason a fundamentally non-functional idea keeps showing up at scale is that the AI industry, in 2026, has a supply story it cannot tell honestly. Demand for AI compute is growing faster than grid hookups can be brought online. Hyperscaler PR, investor decks, and ESG reports all need a future answer to the question of how this gets built; “we’ll figure out the grid eventually” doesn’t fit on a slide. “Datacenters in space” does. The fact that the slide is in the deck is itself doing work — it absorbs the question for the duration of the meeting and lets the actual capacity expansion plan, which involves a lot of natural-gas peaker plants and disputed grid interconnects, proceed unexamined.

The other thing the slide does is launder. The single hardest political problem the AI industry has right now is that its capacity expansion is locally visible: the gas plants are in someone’s town, the data center is drinking someone’s aquifer, the rate hike is on someone’s bill. A satellite is in nobody’s town. A satellite, in the marketing imagination, runs on solar and harms no one. The fact that the satellite would have to be the size of the ISS, and would deliver three racks of compute, and would do so at a unit cost incompatible with the AI industry’s actual capex curve, is information that doesn’t survive the trip from the engineering team to the keynote.

There is one argument I find honestly worth taking seriously: the orbital infrastructure has to start somewhere, Project Suncatcher’s two pilot satellites are an order of magnitude cheaper than nothing, and the long-run learning curve on rad-hard compute and orbital deployment might justify the spend even if the short-run economics don’t close. This is a real argument and it is the one Google’s paper actually makes when you read past the marketing layer. It is also a different argument from “this is how we’ll meet AI compute demand,” and the gap between the two is the gap that Pichai’s keynote invites the audience not to notice.

What stays on the ground

Engineering arguments dressed in physics don’t shift with political winds. Stefan-Boltzmann doesn’t care that 2026 is a hard year for hyperscaler PR. The radiator-size problem will be the same in 2030 as it is now. The radiation-tolerance problem will be the same. The launch-cost problem might come down to within an order of magnitude of viable, and the bet on Starship reaching its target cost by the mid-2030s is the same kind of bet all the other 2010s reusable-rocket projections were — except this one lives in the appendix of a Google research paper instead of the keynote.

Three racks of orbital compute, on a structure the size of the ISS, riding on a launch cost that is almost certainly twice what the marketing assumes, in a chip generation that is one or two cycles behind the ground, with a thermal envelope that constrains everything else — that is the thing the slide is about. The slide is about the slide. The slide is in the deck because the deck needed something. The slide will be in the next deck for the same reason.

Meanwhile the next 100,000 GPUs that OpenAI is bringing online for the next training cycle are getting installed in northern Norway by its joint venture with Nscale and Aker, drawing 230 megawatts of renewable power, and cooled by a closed-loop direct-to-chip liquid loop. The data center stays on the ground because it has to. The space data center stays in the slide because it can.

The lie of the 80%: why software progress charts don’t work

The lie of the 80%: why software progress charts don’t work

Picture the ideal burndown chart. A clean diagonal line, descending steadily from “all the points” down to zero by the end of the sprint. Beautiful. Reassuring. Shareable in a stakeholder meeting.

Now picture an actual sprint you’ve lived through. Did the line ever look like that?

I’m going to guess: no. And not because your team was bad. Not because you’re undisciplined. Not because the estimates were off. The reason no real burndown ever matches the ideal one is more fundamental: software isn’t built like that.

Charts of progress assume a model of how software gets made that doesn’t reflect reality. And once you see it, you can’t unsee it.

Software isn’t a brick wall

The mental model behind every progress chart — burndown, burnup, Gantt, percent-complete, you name it — is the same: development is a stack of bricks. You add one brick at a time. The wall gets taller. Eventually, it reaches the height you wanted, and you’re done.

This metaphor is comforting and almost entirely wrong.

Real software development looks more like this: you build half a wall. You realize the foundation is in the wrong place. You tear the wall down. You build a different wall. You realize the room is in the wrong place. You spend three days reading and thinking and not laying any bricks at all. Then on day four, you build the entire wall in six hours because you finally understood the problem.

This isn’t a failure mode. This is what software development is. Exploration, dead ends, tear-downs, breakthroughs. The progress is non-linear because the work is non-linear. Any chart that assumes a smooth descent from “not done” to “done” is lying about the shape of the work itself.

The 80% lie

Here’s the most universally-told lie in software:

“It’s basically done. Just need to finish that last 20%.”

Every developer has said this. Every developer has heard this. And every developer has been on the receiving end of that 20% turning out to be 80% of the actual work.

It’s not that we’re all liars. It’s that the way development actually unfolds — exploration phase, implementation phase, polish phase — doesn’t map cleanly onto percentages. When you say “I’m 80% done”, what you usually mean is “I’ve done a lot, and I have a vague sense that the remaining stuff is smaller than the stuff I did”. That’s not a measurement. That’s a feeling.

The “remaining 20%” often contains:

  • The integration with the system you haven’t talked to yet
  • The edge case that surfaces only when you wire it up end-to-end
  • The performance problem that shows up only at production scale
  • The thing the PM forgot to mention until you demoed

None of these are visible from where you stand at the supposed 80% mark. They’re not in the chart. They can’t be in the chart. They haven’t been discovered yet.

Every metric is biased by who produces it

Here’s a quieter problem with progress charts: the person reporting the metric always has a stake in what the metric says.

If you want to look productive, you inflate. If you want to avoid getting more work assigned to you, you deflate. If you’re protecting a teammate, you smooth. If you’re frustrated with management, you let the truth show through harder than it should.

This isn’t dishonesty. It’s people responding rationally to incentives. The metric isn’t a mirror — it’s a message. Once you understand that progress charts are a form of communication, not measurement, you stop expecting them to reflect reality. They reflect the politics of the team’s relationship with whoever’s reading the chart.

The fix isn’t “be more honest”. The fix is recognizing that any metric whose value depends on the reporter’s interpretation will be shaped by the reporter’s incentives. Always. Every time.

The fallacy of uniform effort

Charts also assume that everyone on the team is contributing in roughly the same way at roughly the same time. Sprint velocity. Points completed per developer. Burndown lines that smoothly descend.

Real teams don’t work like that. Real teams have weeks where the frontend dev ships forty CMS templates because the work happened to be parallelizable, while the backend dev appears to be drinking mate and playing ping pong for two weeks. And then the next sprint flips: the backend ships a complex migration that took weeks to design, while the frontend dev waits, tests, and unblocks.

That’s not dysfunction. That’s how interdependent work looks.

If your chart shows uneven contribution and your interpretation is “the backend dev didn’t pull their weight”, your chart has lied to you. Maybe the backend dev was the reason the frontend could ship forty templates without blockers. Maybe they were doing the design work that makes next sprint possible. Maybe they were unblocking three other teams off-camera.

Charts can’t see any of that. They show throughput per person and call it productivity. It isn’t.

So who do these charts actually serve?

Once you’ve internalized all of the above, the question becomes hard to avoid: if these charts don’t reflect the work, don’t predict the future, and don’t measure productivity — why do we still draw them?

The honest answer: because somebody with money needs to see them.

Stakeholders need a deliverable. Steering committees need slides. Procurement needs evidence the contract is being honored. Investors want a sense that the burn is producing output. None of these audiences are going to read the codebase. None of them are going to sit in your standup. They need a representation, and the chart is what we hand them.

That’s fine. That’s the corporate game, and pretending it can be opted out of is naive. But let’s stop pretending the chart is a tool for the team. It isn’t. It’s a tool for the people the team has to report to. Calling it “project management” obscures what it actually is: status theater, dressed in the language of measurement.

The team doesn’t need the chart to know how the project is going. The team knows. They’re the ones doing it.

What actually works

If charts are theater, what’s the alternative? Three things, in this order:

1. Demos over charts. The only honest measurement of progress is working software. Last week the product looked like this. This week it looks like this. Did it move? Did it move in the right direction? That’s the question, and no chart in the world answers it as well as a five-minute demo. If you can’t show anything that works, you’re not progressing — no matter what the burndown says.

2. Narrative over numbers. Replace “we’re 73% done” with “we explored approach A, it didn’t pan out, we’re now on approach B and we expect to know if it works by Thursday”. This is harder than producing a chart, because it requires the reporter to actually understand the work. That’s a feature, not a bug. The narrative forces honest engagement; the chart allows comfortable distance.

3. Output metrics as complement, not substitute. What did the user actually receive? Deploys to production. Features released. Bugs closed in the wild. These can be counted because they’re real events with real artifacts. The user doesn’t lie. The git log doesn’t lie. Process metrics — story points completed, sprint percentage, velocity trends — measure the appearance of work. Output metrics measure work that left the building.

And if a stakeholder genuinely needs a number — sometimes they do, and that’s fair — give them one. Just be honest about what it is. “Let’s invent a number over a beer” is a more accurate framing than “based on our velocity-weighted forecast of remaining story points”. They’re often the same number. The first one tells the truth about its origins.

The elephant: but the stakeholders want the chart

I’m not naive. I know that in many companies, you can’t just stop producing burndowns. The contract requires it. The PMO requires it. The CFO has a slide template with that chart shape on it and changing the slide is harder than changing the moon.

So produce the chart. Hand it over. Smile at the meeting.

But internally, don’t let the team start believing the chart. That’s where the real damage happens — when developers start optimizing for the line on the screen instead of for the product. When the chart becomes the goal, the chart will start telling you the team is doing great while the codebase is rotting in ways no chart can show.

The worst version of this is the team building its own charts. When developers start producing the very theater that’s being used to manage them, the gap between “what we say is happening” and “what is happening” stops being a stakeholder problem and starts being an internal one. That’s how you end up with teams that look productive on paper and ship nothing of value for two quarters.

The bottom line

A chart never built a product.

The people who build great software don’t do it by staring at burndowns. They do it by talking to their teammates, watching the product grow, adjusting direction when something isn’t working, and being honest with each other about what they don’t yet understand. The chart is, at best, a translation layer between that work and the people who fund it.

Translation layers aren’t bad. But they aren’t the work, and they aren’t where the work happens.

If you’re a manager: the chart is for your audience, not your team. Don’t manage by it.

If you’re a developer: the chart is theater. Produce it if you have to, but don’t let it shape how you actually think about the project.

And if you’re at a company where the chart is the project — where decisions are made off the line on the screen and the actual code is invisible to everyone above the team lead — that’s not a measurement problem. That’s a much deeper one, and no better chart will fix it.

If your team genuinely needs a burndown chart to know how the project is going, the problem isn’t the chart. It’s that nobody is actually talking about the project.

What does your team use to track progress? Charts you trust, charts you tolerate, or something else entirely? I’d love to hear it in the comments.

Samsung, açık yapılı bir kablosuz kulaklık geliştiriyor

Samsung

SamsungSamsung, yapılan birden fazla sızıntıya göre “Galaxy Buds Able” adına sahip açık yapılı bir kablosuz kulaklık modeli geliştiriyor. Açık yapısı sayesinde müzik dinlerken çevrenin de duyulmasına imkan tanıyacak ürün, bu konuda şirket için bir ilke imza atacak ve büyük ihtimalle kulağın yanına kıstırarak takmaya yönelik gövde yapısını benimseyecek. Pazarda Huawei FreeClip, Sony LinkBuds Clip, Bose Ultra Open Earbuds ve Anker Soundcore AeroClip gibi modellere rakip olacak kulaklığın ne zaman tanıtılacağı henüz tam olarak bilinmiyor ancak 2026’nın kaçırılması beklenmiyor.

Samsung, açık yapılı bir kablosuz kulaklık geliştiriyor yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

Presentation: The Ironies of A^2 I^2

J. Paul Reed discusses the “ironies of automation” – a 40 years-old concept now amplified by AI. He explains how advanced systems often make the human operator more crucial, not less, while simultaneously degrading the skills needed to intervene. Sharing real-world stories of “AI-fueled” incidents, he shares why over-reliance on AI can double recovery times and how to maintain resilience.

By J. Paul Reed