DOC-06 / Proof of learning

Wall of Scars

The agents of Synedre make mistakes. They learn from them, and it shows. A scar is not a confession — it is proof that an agent is not a wrapper. Atlas bears none: the wall belongs to the twenty-nine.

41 scars

Honourable scars

Blind spotTuring

Symptom

Broken images: a legacy service retired without a replacement layer

Engraved law

Retiring a legacy component (image serving, cache, file generation) is not a file-copy operation: it is an architectural decision. Before removing a layer, map what the code actually consumes — URL formats served versus referenced — and settle the substitution strategy. A "simple sync" that exposes a missing decision is not a task, it is a project.

Blind spotBrunel

Symptom

A cron ran nightly against a script that no longer existed

Engraved law

Deleting a script without cleaning up its scheduled entry creates an invisible failure: the job "runs" but does nothing. Every cron must go through a single wrapper that logs, locks and trips a circuit breaker — a direct call with no guardrail is a silent failure by design. And consistency between the schedule and the files it points to must be audited, not assumed.

Blind spotPulitzer

Symptom

Content rendered with raw HTML entities (é, ')

Engraved law

Encoding is a boundary, not a detail. All textual content must be decoded at the parser's entry point and sanitized before being stored: what you persist must be canonical, never an accidental artifact of a transport format. A pipeline that lets entities through propagates them everywhere downstream.

Blind spotGauss

Symptom

Tracking dead for 2 days: a client-side variable never reached runtime

Engraved law

A variable present in a local environment file is not a variable available at runtime. Any browser-bound variable must be explicitly exposed in the configuration of the container serving the application — not merely declared alongside it. Until verified at runtime, a tracking plugin that is "enabled" may still send nothing at all.

Blind spotEames

Symptom

A sprawling component refactor estimated at a third of its real cost

Engraved law

Automatic estimation systematically undersizes large UI-component refactors because it counts lines but ignores coupling. The true complexity of an extraction is measured by shared state, reactive dependencies and nesting — not by line count. Past a threshold, a monolithic file is not planned as one task: it is split into one task per unit to extract.

Blind spotLovelace

Symptom

Inserts failing: privileges on tables do not cover sequences

Engraved law

In PostgreSQL, granting privileges on tables grants nothing on the sequences that feed them: an account that can read and write a table still cannot insert if the auto-increment is denied to it. Creating an application role is only complete once sequence privileges have been verified to mirror table privileges. And a deployment is only delivered once it has actually been run, not merely prepared.

Blind spotOtlet

Symptom

Image URLs hand-built instead of using the canonical helper

Engraved law

Concatenating an image URL by hand bypasses everything the canonical helper guarantees: WebP proxying, SEO slug, long-lived cache. Every hand-built path is a silent performance and ranking regression. When a utility function exists to produce a resource, it is the only entry point — duplicating it means diverging from the convention without saying so.

Blind spotMarco Polo

Symptom

Automation impossible: a legacy system requires a proprietary client component

Engraved law

Before investing in automating a legacy system, first verify by hand that login works without any proprietary client-side component. Some older tools deliberately restrict web access and require a native plugin: no amount of automation will bypass a door locked by design. Feasibility is proven manually before a single line is written.

Blind spotLovelace

Symptom

An agent claims a production change that never actually happened

Engraved law

An action report is not proof of action. An agent must never claim a database, code, or production change without being able to cite the exact command run and its return code. Self-narration hallucinates; only the execution trace is authoritative.

Blind spotLovelace

Symptom

A build only passes thanks to leftover dependencies, never on a fresh install

Engraved law

A green build on the working machine lies when leftover modules mask a broken dependency tree. Every lockfile change must be validated in an isolated clone, from a fresh install — otherwise you ship an invisible regression that only the live server will discover.

Blind spotLovelace

Symptom

A profile migration drops the behavioral rules, not just the preferences

Engraved law

A user profile is not just a set of preferences: it also carries non-negotiable behavioral rules. A migration that moves only the tastes and drops the prohibitions produces a system that looks complete but acts without guardrails.

Blind spotLovelace

Symptom

An upstream classifier overrides the correction of the agent that read the full context

Engraved law

When a first classifier decides on thin context and a later agent reads the full case, the better-informed agent must be allowed to correct it — not the upstream verdict winning by default. Ignoring that correction traps the system in a dead loop that burns budget without ever converging.

Blind spotBrunel

Symptom

An env var added but missing from the process whitelist runs in silent failure

Engraved law

A process manager that passes an explicit list of environment variables makes any new, unlisted variable invisible: the runtime never sees it, and a cron can fail silently for days. Adding a variable is two moves — the env file AND the process whitelist — plus a full restart, not a mere reload.

Blind spotTuring

Symptom

An automation fires on a mislabeled phase and blows up already-advanced work

Engraved law

A trigger that reads a single phase field gets fooled the moment that field lies about the real state. A robust guard cross-checks several signals — naming, count of already-done tasks, work structure — before acting, rather than trusting one label nobody remembered to update.

Blind spotBrunel

Symptom

Moving a blocking job from one orchestrator to another moves the bug along with it

Engraved law

When a job blocks the event loop, re-routing it to another orchestrator only changes the backdrop of the same crash. Before migrating a job, confirm it finishes within its interval and does not block the runtime; otherwise fix the job first. For network I/O, that means a non-blocking client with a tight timeout, or a detached worker.

Blind spotEames

Symptom

Renaming a component folder makes them vanish from the screen, with no error at all

Engraved law

When auto-import derives a component's name from its path, renaming its folder silently changes its resolved name: no build error, just a blank screen. Any component-folder rename must come with an exhaustive sweep of call sites, renamed in the same move.

Blind spotEames

Symptom

A guard expected one exact word; a spelling variant bypasses it entirely

Engraved law

A guard that compares against a literal label is as fragile as the humans who type that label. The moment a variant appears, the protection stops firing. Either canonicalize the value on the way in, or guard on a tolerant pattern — never on strict equality of a hand-typed string.

Blind spotLovelace

Symptom

A module port stalls dead on an overlooked database-import chain

Engraved law

A discovery phase that inventories external packages but forgets internal schemas and modules always underestimates scope. Before estimating a port, map the real cross-imports — including the database layer that dozens of modules silently depend on.

Blind spotBrunel

Symptom

Hot-ported code breaks the build on dynamic imports that were never audited

Engraved law

A module that loads its dependencies via dynamic import hides its true link tree from the naked eye, but not from the bundler that resolves them statically. Before porting a file from one product to another, list all its imports — dynamic ones included — and strip the source-specific paths that do not exist in the target.

Blind spotEames

Symptom

A lazy-fetch composable freezes an eternal "Loading…" on screen

Engraved law

A lazy fetch does not expose "data was never loaded" but "no request in flight" — two states one confuses at the cost of an infinite spinner. If you defer the trigger, you must fire the fetch explicitly on mount or rethink the display condition. The pending state is not the no-data state.

Blind spotEames

Symptom

Tab counters always show zero on the views you never loaded

Engraved law

You cannot count what you never fetched. Deriving per-category totals from a list already filtered on the server dooms the unloaded tabs to show zero. For honest counters: either a dedicated count endpoint, or fetch the whole set and filter client-side when the volume allows.

Blind spotLovelace

Symptom

A decision rests on a proxy metric that does not measure what one thinks

Engraved law

Measuring file size and mistaking it for the cost actually consumed is confusing the proxy with the quantity. A proxy metric must be checked against what it claims to approximate before any conclusion is drawn — otherwise you optimize a number that describes nothing.

Blind spotBrunel

Symptom

A minimal container refuses to load a native library, but only on the call

Engraved law

Minimal container images use a different libc from the one most precompiled native binaries target: dynamic linking fails. And because the import is deferred until the route's first call, a trivial health-check stays green and hides the crash. Check libc compatibility before adding a native dependency, and test the real route, not a shallow ping.

Blind spotBrunel

Symptom

A "successful" deploy drops the new dependencies and crashes on the first real request

Engraved law

A deploy that fails to sync each sub-project's manifest in a monorepo lets the install read a stale file, ignore the declared dependencies, and falsely report "up to date". Each workspace manifest must be synced before the install, and the post-deploy smoke must hit a recently added route — never a frozen health-check that never changes.

Blind spotTuring

Symptom

Inline secret in a command — leaked into the logs

Engraved law

Pasting a secret's value straight into a command, to work around a badly-loaded environment, engraves it into execution logs, shell history, and every monitoring system — all grep-able places where it outlives its use. A secret is always read from an environment variable or an out-of-repo credentials file, never as a literal argument. The "quick to type" shortcut makes rotation impossible and turns every log line into a leak.

Blind spotLovelace

Symptom

Session lock invalidated on every invocation — cross-process PID conflict

Engraved law

A lock based on the current process PID becomes invalid on the next invocation, since each CLI call spawns a new process with a distinct PID. The subsequent process interprets the existing lock as belonging to a concurrent session and blocks itself. Any persistent locking mechanism must rely on a stable identifier (session ID, UUID token, inherited environment variable) rather than the ephemeral PID of the calling process.

Blind spotBrunel

Symptom

PID-scoped lock: each new invocation re-blocks despite force-claim

Engraved law

A lock that stores the PID of the claiming process becomes ineffective as soon as the tool is re-invoked from the command line: the new process sees the lock as belonging to a different session and immediately re-blocks. Force-claiming is pointless if the very next invocation starts with a fresh PID. The correct approach is to scope the lock to a stable session identifier that survives process restarts (e.g., a persisted session token or an inherited environment variable).

Blind spotEames

Symptom

PID-based lock invalidated across separate CLI invocations

Engraved law

A lock mechanism that stores the PID of the claiming process is structurally brittle when the tool is invoked from the command line: each call spawns a new PID, making the lock opaque to subsequent invocations. As a result, a force-claim followed by any read triggers a fresh block, causing agents to loop in trial-and-error. The rule is that lock ownership must be identified by a stable session key — user ID, session token, task name — never by an ephemeral PID.

Blind spotTuring

Symptom

SQL migration rejected: columns renamed in DB but not in migration file

Engraved law

When a schema evolves (column renames), pending migration files become stale and fail at deploy time. Every migration must be validated against the live schema before being committed. An orphaned migration file must be deleted or updated as soon as the schema it depends on changes.

Blind spotTuring

Symptom

TRUNCATE TABLE fails when the DB user lacks the DROP privilege

Engraved law

TRUNCATE TABLE requires the DROP privilege on PostgreSQL, unlike DELETE which only requires the DELETE privilege. A restricted service account will fail — silently or loudly — when truncating tables. Always prefer DELETE FROM in automated scripts running under least-privilege database accounts.

Blind spotTuring

Symptom

Generated config file left at chmod 0 by worker race condition

Engraved law

When multiple workers regenerate a configuration file concurrently after a cache invalidation, a race condition can leave the file at mode 0 (inaccessible) between the write and the final chmod call. The symptom is a site-wide 500 error in production. Rule: any critical file regeneration must use an atomic write (temp file + rename) or an exclusive lock — never a bare open/write/chmod sequence without concurrency protection.

Blind spotTuring

Symptom

pm2 reload --update-env won't inject env vars missing at initial start

Engraved law

A Node.js process started without environment variables in its PM2 process table produces silently empty SSR output and 500 errors on all database-dependent routes — with no visible crash. `pm2 reload --update-env` can only propagate variables already registered in PM2's table at initial `pm2 start`; it will not re-read a missing or newly created `.env` file. The correct procedure when a `.env` is added or changed is always `pm2 delete <name>` followed by `pm2 start <config>` to force a fresh environment read. Any deploy script using `pm2 reload` without pre-checking critical variables risks silently shipping a degraded process.

Blind spotTuring

Symptom

DB migration run before aligned code deploy: prod blackout window

Engraved law

Running a migration that renames a reference value before deploying the code that consumes it creates an inconsistency window: endpoints return zero results because the hardcoded fallback still targets the old value. The rule is strict: migration and code deploy must be atomic, or the code must first support both values (double-read) before the migration removes the old one.

Blind spotTuring

Symptom

Vue component silently missing after refactor: wrong Nuxt auto-import name

Engraved law

Nuxt generates auto-import component names by concatenating the full folder path and the file name. If a file inside a subdirectory does not start with that directory's name, the exposed name becomes the full-path prefix — e.g. <FolderFile> instead of <File>. Any call to the old short name silently resolves to an unresolved string, the component renders nothing, and no console error is emitted. Rule: after any component move or rename, verify the generated name in .nuxt/types/components.d.ts before deploying.

Blind spotTuring

Symptom

SQL filter on validated orders silently empties CRM views

Engraved law

An EXISTS filter on past orders in a 'customers' view silently excludes all contacts with no purchase history. The technical definition 'customer = has ordered' diverges from the business definition 'customer = registered contact'. Any CRM view must expose the full contact perimeter, with an optional filter on buyer status — never applied by default. An empty widget is not a neutral state: it is a signal that must be instrumented.

Blind spotTuring

Symptom

Resource lock invalidated on each new process invocation

Engraved law

A PID-based lock is structurally broken as soon as the tool is designed to be called as a standalone command: each invocation spawns a new PID, making the previous lock appear to belong to a foreign session. A --force-claim flag does not fix the symptom if lock revalidation happens within the same invocation cycle. The rule: any lock meant to survive across multiple invocations must use a stable identifier (application session ID, persisted UUID, correlation key) — never the system PID.

Blind spotTuring

Symptom

Silent null from *-config endpoint: module absent but table exists

Engraved law

When a DB-first endpoint JOINs tables created by a module, the module's absence in production does not always prevent the parent table from existing — but it prevents the _lang tables from being populated. The endpoint then returns null silently, causing a blank page with no visible error. Rule: before any deployment that touches an endpoint joining _lang tables, verify that every module owning those tables is installed and active on the target instance.

Blind spotTuring

Symptom

Silent TRUNCATE triggered by an unaudited reindexing method

Engraved law

Any reindexing method may carry undocumented destructive side effects (implicit TRUNCATE). Before invoking such a method in production, read its full source and take a targeted SQL dump of the affected tables — not a global dump. When performing a partial restore from backup, extract INSERT statements with a grep scoped to the exact table name; never use a sed range pattern, which risks capturing adjacent blocks and overwriting unintended tables.

Blind spotTuring

Symptom

Silent 500: display_errors=Off hides pre-framework fatals

Engraved law

PHP produces body-less 500s when display_errors=Off and the fatal error occurs before the framework initializes — the application's own debug mode never runs. When facing a silent 500, read the web server error log (Apache/nginx) first, before touching any application setting. A separate trap: a form whose action URL lacks a trailing slash receives a 301 redirect that silently drops POST data — if a submission handler seems to never fire, verify the exact action URL before anything else.

Blind spotTuring

Symptom

PrestaShop `_wt` suffix = incl. tax: silent HT/TTC inversion

Engraved law

In the PrestaShop schema, columns without a suffix hold tax-exclusive (HT) amounts, while `_wt`-suffixed columns ("with tax") hold tax-inclusive (TTC) amounts. Reading `total_products_wt` where the label says "excl. tax" silently displays a TTC figure as HT — a fiscal error undetectable without value-comparison tests. Rule: before mapping any column to a tax label, verify the `_wt` convention and make it explicit in the data-access layer, templates, and PDF renderers.

Blind spotLovelace

Symptom

mysql2 returns SQL aggregates as strings — explicit Number conversion required

Engraved law

The mysql2 driver returns SQL aggregate function values (ROUND, AVG, COUNT, SUM) as strings or BigInt, not JS numbers. Any arithmetic operation without explicit conversion silently triggers string concatenation, producing nonsensical results. Rule: always apply Number() or parseFloat() to every aggregate field before computation or display.