home.social

Search

4 results for “heurism”

  1. HIMMEL UNTER BERLIN VOL. 3

    THE GIFT
    VON KON

    Der Künstler hat für diesen Raum Schlitten aus den Jahren 1940 bis 1943 gesammelt. Angeblich wurden diese von Hitler im 2. Weltkrieg deutschen Kindern geschenkt, deren Väter gefallen waren. Dafür gibt es aber keine Belege, dass das stimmt.

    KON bezieht sich in der Installation auf das Phänomen „contagion heuristic“ oder das „Gesetz der Ansteckung“ - beschrieben von dem Psychologen Paul Rozin in den 1980er Jahren. „Er fragte Testpersonen, ob sie gegen Bezahlung einen Pullover tragen würden. Kurz bevor sie ihn anziehen sollten, wurde ihnen gesagt, er habe einst Adolf Hitler gehört. Das Ergebnis: Die meisten sagten nein. (…) Gemeint ist der Glaube, dass sich der „Wesenskern“ einer Person über Berührung auf Objekte überträgt. Ein Effekt, der sich weder durch Waschen noch durch Zeit noch durch Vernunft neutralisieren lässt.

    #HimmelUnterBerlin #Berlin #Installation #Ausstellung

  2. In other interesting news, #Instagram has been very aggressively marking *tons* of images as “AI”. Even posts that I know aren’t #AI-generated are sometimes marked “AI content”. Some accounts are marked as “AI-generated profile” accounts—I’m not sure what the criteria are, but I think it’s a label that Instagram *makes* you add to your account if you have too many images of (what it thinks are) AI-generated faces in your posts. If you don’t add the label, they will deemphasize your account in your followers’ feeds.

    The AI labels are irritating some folks I know who post hand-made or clipart-based flyer art. And there is no way to get rid of the label. Funny enough, I can post the *exact* same image and it does *not* get labelled as AI, so it’s not just some image-scoring model; there’s got to be some other heuristic at play.

  3. You review a 30-line template diff. Production sends 40,000 tokens assembled at request time from six sources, four of which changed this week and none of which appear in the pull request. The diff you approved is not the change you shipped.

    This is the part of LLMOps that keeps biting teams after they have evals, tracing, and a gateway in place. The template is versioned in git. The context is assembled by code paths nobody treats as release artifacts.

    The prompt is a build output


    List what actually goes into a request for a typical RAG-plus-tools system:

    • The system template (in git, reviewed).
    • Top-k retrieved chunks from an index that gets rebuilt on its own schedule.
    • Tool JSON schemas, whose descriptions are prompt text written by whoever last touched the tool.
    • A conversation summary produced by another model call.
    • A user profile or tenant config blob.
    • Few-shot examples chosen at runtime by a selector.

    Each is a dependency with its own version and its own deploy cadence. The retrieved chunks change when someone reindexes. The tool schema changes when a backend engineer renames a parameter and rewrites the description. Neither triggers a review of the prompt.

    So when quality drops on Tuesday and no code shipped, there is no diff to look at. That is the failure this whole post is about.

    Fingerprint everything the model sees


    Compute a content hash over the inputs that can change model behaviour, and log it with every trace:

    • model id and version
    • template version
    • retrieval snapshot id (the index build, not the query)
    • the fully rendered prompt
    • decoding parameters that matter

    Store fingerprints always. Store full rendered prompts sampled or redacted, depending on your data rules — full-text retention is a compliance decision, not an observability one. The fingerprint is small, cheap, and answers "what changed" during an incident in one query.

    The trade-off: a fingerprint that includes a timestamp, a request id, or a per-user greeting has near-zero collision rate and zero diagnostic value. Hash the parts that affect generation, not the metadata around it. I have watched a team spend a day on "why is our prompt hash changing every request" when the answer was a locale string.

    A small assembler with provenance and eviction


    You do not need a framework for this. You need three properties: every section carries a trust level, every section carries an eviction priority, and over-budget on a pinned section is a hard error rather than a silent trim.

    from dataclasses import dataclass, field
    from hashlib import sha256
    import re

    @dataclass
    class Section:
    name: str
    text: str
    trusted: bool # False for retrieval, tool output, user uploads
    priority: int # higher survives truncation
    pinned: bool = False # never evict; over budget means fail loudly

    INSTRUCTION_LIKE = re.compile(
    r"(ignore (all )?(previous|prior) instructions|you are now|system prompt)",
    re.IGNORECASE,
    )

    def screen(text: str) -> str:
    # Cheap heuristic, not a guarantee. Log hits and route to a stricter path.
    return INSTRUCTION_LIKE.sub("[filtered]", text)

    def count_tokens(s: str) -> int:
    # Swap in tiktoken/the provider counter. One counter per model family.
    return len(s) // 4

    @dataclass
    class Assembled:
    prompt: str
    fingerprint: str
    dropped: list[str] = field(default_factory=list)

    def assemble(sections, budget, model_id, template_version, snapshot_id):
    ordered = sorted(sections, key=lambda s: (s.pinned, s.priority), reverse=True)
    kept, dropped, used = [], [], 0
    for s in ordered:
    body = f"<{s.name} trust={'high' if s.trusted else 'low'}>\n"
    body += (s.text if s.trusted else screen(s.text)) + f"\n</{s.name}>"
    cost = count_tokens(body)
    if used + cost > budget:
    if s.pinned:
    raise ValueError(f"pinned section {s.name} exceeds budget")
    dropped.append(s.name)
    continue
    kept.append((s, body))
    used += cost
    # Render in original order so layout is stable across requests.
    pos = {id(s): i for i, s in enumerate(sections)}
    kept.sort(key=lambda pair: pos[id(pair[0])])
    prompt = "\n\n".join(body for _, body in kept)
    h = sha256()
    for part in (model_id, template_version, snapshot_id, prompt):
    h.update(part.encode())
    return Assembled(prompt, h.hexdigest()[:16], dropped)

    # Usage: build once per request, log the fingerprint beside the trace id.
    ctx = assemble(
    sections=[
    Section("question", "why was my claim denied?", trusted=True, priority=10, pinned=True),
    Section("policy_chunk", retrieved_text, trusted=False, priority=5),
    Section("profile", tenant_blob, trusted=True, priority=1),
    ],
    budget=12_000,
    model_id="claude-sonnet-4",
    template_version="support-v14",
    snapshot_id=index_build_id,
    )

    Two details in there are load-bearing. Sections render in original insertion order rather than priority order, because reordering the same content changes model behaviour and makes your eval deltas unattributable. And pinned turns budget pressure into an exception instead of a degraded#ai #llm #devops #python #software #coding #development #engineering #inclusive #community
    Context Assembly Is a Build Step: Versioning the Prompt You Actually Send

  4. The first week after launch is not about ranking. It is about confirming three things: crawlers can reach the site, they are actually fetching it, and the contact path works end to end. Everything else can wait until there is data.

    Day 0, before you tell anyone: four things that block indexing silently


    1. A coming-soon or maintenance mode that is still switched on.
    2. A noindex left over from staging. There are two places: a meta tag in the head, and an X-Robots-Tag response header. Check both. Open the page source and search for noindex, then request the page headers with curl -I. The header is the one people forget.
    3. HTTP auth or a site-wide password still enabled.
    4. The same page reachable on more than one hostname (with and without www, or both protocols) with no redirect between them. Pick one, 301 the other.

    One more, before launch rather than after: put the measurement tag on the site. Analytics installed on day 3 means day 1 and 2 have no data at all.

    Test all of this from a phone on mobile data, not from the office wifi, and not while logged in as an administrator. Logged-in views hide caching and coming-soon behaviour.

    Day 1: verification and submission


    • Add a domain property, verified by a DNS TXT record. It covers every subdomain and both protocols in one property, which matters when you are not yet sure whether the canonical host is www or not.
    • Add a URL-prefix property as well if you want per-protocol reporting. It is a second view of the same data, verified separately.
    • Submit the sitemap once.

    Before submitting, open the sitemap in a browser. It has to load, return 200, be valid XML, and contain only canonical URLs that themselves return 200. No redirects, no 404s, no noindexed pages inside it. A sitemap full of redirects teaches the crawler to distrust the whole file.

    Then URL inspection on a handful of pages, not hundreds: home page, one category or service page, one product page, the contact page. "Request indexing" is a queue entry, not a switch. There is a daily quota and no way to buy more.

    Bing: import from Search Console or verify directly, then submit the sitemap there too. Ten minutes, and it feeds the results that are not Google.

    What not to do in week one: resubmitting the sitemap every morning, requesting indexing for every URL, or deleting and recreating the property because nothing shows on day 2.

    Day 2-4: crawl your own site before the crawlers do


    Check that every key URL returns the status you expect. One line per URL, status code first:

    while read -r u; do
    printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' -L "$u")" "$u"
    done < urls.txt

    urls.txt is one URL per line in a plain text file: home, top landing pages, contact, the sitemap, robots.txt.

    Then check, on each page:

    • the canonical tag points at that page itself, not at the home page and not at the other hostname
    • internal links use the canonical hostname; one mixed link is enough to create a duplicate
    • the main text is in the HTML source, not injected by JavaScript. View source, not the rendered DOM.

    Fix these now. Crawlers come back, but they come back on their own schedule, not yours.

    Day 3-7: read the access log


    This is the step people skip, and it is the place that shows what actually happened rather than what you submitted.

    Where the file is. On a managed host, the control panel, usually under access logs or raw logs, rotated daily. On your own server, /var/log/nginx/access.log or /var/log/apache2/access.log. Behind a CDN, the origin log shows the CDN's IP addresses, so you need the CDN's own log or an origin header that carries the real client IP.

    Download a couple of days and work on the copy.

    # Who is hitting the site at all
    awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

    # How many requests claim to be a crawler
    grep -Eic 'googlebot|bingbot' access.log

    # Which paths the crawler actually fetched, busiest first
    grep -Ei 'googlebot' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

    # What we served it
    grep -Ei 'googlebot' access.log | awk '{print $9}' | sort | uniq -c | sort -rn

    The field numbers ($1, $7, $9) assume the combined log format: client IP, identity, user, timestamp, request, status, bytes, referrer, user agent. Check the first line of the file and the server config before trusting them.

    A user agent proves nothing. Anyone can send the word Googlebot. Verify the IP by reverse lookup, then forward-resolve the name it returns and confirm it comes back to the same IP:

    host 66.249.66.1
    # the returned name should sit under googlebot.com or google.com
    host <the-name-it-returned>

    If either lookup fails, or the forward lookup does not return the original IP, that hit was somebody else. Usually a scraper or a monitoring service.

    What real crawling looks like: more than one hit, spread over several days; requests for HTML pages rather than only images and CSS; 200 responses; and a spread of URLs that includes internal pages, not just the home page.

    What it does not look like: a single hit on the home page, a run of hits on the login path, or hits only on assets. Those are fetchers and scanners, not indexing.

    The self-inflicted block. If you switched on a firewall bot rule, a rate limit, or a security feature that blocks suspicious traffic during launch week, check it before concluding anything about the index. The log will show 403s or 429s served to a crawler. That is your own rule, not a search engine decision.

    Inquiries: prove the path works end to end


    Submit the form yourself on launch day, from a network that is not yours, using a mailbox you control. Confirm four separate things:

    1. the thank-you message appears
    2. the notification email arrives
    3. the entry is stored somewhere you can query
    4. the sender address passes SPF, DKIM and DMARC for your domain

    The email is the fragile part. It can fail while the form still looks fine to the visitor. Check the spam folder, then check the host's mail log for the message ID. If the mail path turns out to be unreliable, at least store every submission so nothing is lost.

    Server-side proof that a submission reached you, even when the email did not:

    grep 'POST ' access.log | awk '{print $7, $9}' | sort | uniq -c | sort -rn | head

    A 200 on the form handler means the data arrived somewhere. A 500 means the handler is failing and the visitor saw an error or a blank page. A 429 means your own rate limit ate a real inquiry.

    Separating noise from a real inquiry. Noise usually looks like this: the same IP hitting the handler several times in a few minutes, fields that are empty or obviously generated, a message body that is only a link, a referrer from a directory site. A real one usually has a company name you can look up, a reply-to address that matches the domain in the message, and a specific question about a specific thing.

    That is a set of heuristics, not a rule. Read the message.

    The week-one sheet


    One place, filled in daily. Five minutes a day.

    WhatWhereNormal in week onePages known / indexedSearch Console pages reporta small number, growing slowlyCrawl requestsaccess log, filtered by verified crawler IPsa handful per day, spread across URLs4xx / 5xx on canonical URLsaccess logclose to zeroForm POSTsaccess logequals the number of inquiries you receivedInquiriesinbox or a shared sheetany number, including zeroTop referrersanalyticsmostly direct and your own links early on


    The form POST count and the inquiry count should match. If they do not, you have a delivery problem, not a traffic problem.

    What not to conclude in week one


    • Zero indexed pages on day 3 is not a penalty.
    • Zero inquiries from fifteen visitors is not a conversion problem. It is a traffic problem, and it is too early to see either.
    • Do not rewrite the site on five days of data.
    • Do not resubmit anything twice. Once is the instruction; the second time is noise in your own process.

    The whole first week is a verification exercise: is the door open, is anyone walking through it, and does the contact path actually deliver. Everything after that is content, which runs on a much slower clock.#seo #startup #webdev #software #coding #development #engineering #inclusive #community
    Launch week: what to submit, what the logs should show, and how to tell a real inquiry from noise

Share on Mastodon

Enter the server where you have an account.