Where silicon meets syntax.

Explainers on how AI inference really works, from the transistor to the token. Plus chip design, tooling, and the lessons I pick up building with agents.

Move across the lattice. Click to send a pulse.

// lessons

Lessons, logged daily

One thing I learned, most days. Point at a day in the field, or slide through them, newest first.

261 lessons in 16 weeks

1 / 398
  1. Deployment

    Evaluate the installed path, including its managed policy.

    A test harness that injects its own tools may bypass the installation users actually run—or fail before it starts. Read the host policy and make the test exercise the supported entry point.

  2. Evaluation

    Write eval questions without borrowing the source wording.

    A search test is easier when its questions repeat the documents it searches. Ask in the reader’s words and score the facts a useful answer must contain.

  3. Reviews

    Severity and blocking are different decisions.

    A finding can be serious without belonging to this change. Decide both how harmful it is and whether it makes the change’s promise false, then give it a clear next action.

  4. Writing

    Writing like me means keeping my structure, not copying my slips.

    My casual messages show how I explain a problem. They also contain grammar I do not want carried into a finished post.

  5. Debugging

    A fix brief sets the width of the fix.

    Brief a worker on one failing value and it may repair only that value. Brief it on the broken rule and its input dimensions so the next sibling failure is part of the same job.

  6. Quality gates

    Pin who owns the check, not just its passing threshold.

    A passing number is weak evidence when the person producing the result can replace the script that measures it. The measuring rule needs an owner as well as a threshold.

  7. Data integrity

    A snapshot id must cover its immutable metadata.

    If two records share an id but differ in fields the store promises never to change, an ordinary second write becomes a collision. Decide what the identity owns before hashing it.

  8. Telemetry

    A streaming usage field may be a snapshot, not a total.

    Adding every usage field in a transcript can produce a neat total from incomplete counters. Cross-check one complete session before using that total to price a change.

  9. Writing

    Delegated work can be mine without pretending I typed every command.

    My October 24 ruling allows I found or I built for work an agent did on my assignment, while the source names the run that did it.

  10. Testing

    A fake binary on PATH can lose to an inherited environment variable.

    The tests installed a fake aws command, but the launcher had already selected a real binary through AWS_CLI_BIN.

  11. Tooling

    A command should tell the operator what to do next.

    Every make command became a small guide: explain the fix when it fails, or show the follow-on commands when it succeeds.

  12. Bash

    exec inside a pipeline can leave the parent script running.

    The personal statusline appeared, but the default appeared too. The handover test only checked that the personal output existed.

  13. Testing

    A green test can depend on a file Git never tracked.

    A clean worktree exposed a bug that the main checkout had been hiding with an untracked symlink.

  14. Testing

    A fake host cannot prove an update leaves a busy real host alone.

    The suite had tested the refusal against fakes. A supervised host pilot checked the behaviour where the update would actually run.

  15. frontend

    Measure text in a real browser with the real font.

    Character counts guess. The rendered width decides whether a column wraps or overflows.

  16. docs

    A file header is a barcode.

    A few key-value fields at the top let a person or an agent identify a file before reading the rest.

  17. eda

    Peak memory follows design size, not input file size.

    Predicting from the size of the input files made forecasts worse. The tool's own log of design size was the signal.

  18. process

    Reversible questions shouldn't wait for me.

    My work stalled while I slept. Now a reversible call is made and logged as what, why and cost if wrong; only irreversible ones wait.

  19. art

    Done means someone looked.

    Code that draws can be valid and still ugly. A figure is finished when the audit passes and a person has seen the render.

  20. slurm

    A job that ends exactly at the time limit wasn't finished.

    Runs stopping at the partition ceiling were hung, not done. Raising the limit to unlimited only let them hang longer.

  21. agents

    A skill's description says when, not how.

    The description decides when it fires. Put the steps in the body; steps in the description only blur the trigger.

  22. security

    List what an agent inherits, not just what it may do.

    Passphraseless SSH keys, plaintext git credentials, cloud profiles and tokens left in settings files all come along with the user's session.

  23. css

    Tailwind is styling, not a component library.

    Components come from Radix, shadcn or your own set. Borrow their structure and behaviour, but colour, type and spacing should still come from your tokens.

  24. ci

    If setup is good, CI should just call it.

    Then every CI run tests the real bootstrap on a fresh machine, and the setup steps can't quietly rot.

  25. process

    Blame the process, not the person.

    People only record mistakes if the record can't be used against them. A captured mistake should make the team ask why, not who.

  26. process

    Capture the mistake when it happens.

    A lessons-learnt review at the end is short and tidied by hindsight. Record the fix or the slip while the detail is still there.

  27. frontend

    Check the bundle hash before believing the browser.

    The old design on screen was a cached bundle. Compare the served file to the build before debugging the code.

  28. process

    Rulings in a chat are not a backlog.

    Decisions made in conversation get lost or overruled by older drafts. Write each one where the work queue lives.

  29. design

    Make the design defend itself.

    Take every feature it must carry and ask the hard questions: ten times the input, a second user, a failure nobody notices. Gaps found now cost an edit.

  30. design

    Requirements and architecture shape each other.

    A design choice shows a requirement is vague or too costly; a requirement shows a missing block. Write them together, in short loops.

  31. systems

    Retries can cause the outage they're meant to survive.

    A timed-out request is retried while the first attempt is still running downstream. Under load, that doubles traffic exactly when it hurts.

  32. design

    Ask why until you hit a decision.

    A feature is robust when repeated whys end at a recorded decision or policy. If they don't, you've found a decision nobody made.

  33. linux

    Judge a process by its private memory.

    Listings count shared buffers once per process, so a database looks enormous. Private memory shows what each process really holds.

  34. security

    Let the firewall own the network boundary.

    An allowed-domains list inside a sandbox drifts and is hard to audit. The proxy already sees every connection.

  35. linux

    On a RAM-backed /tmp, scratch files are memory.

    Files in tmpfs count against RAM and can dwarf a process's own footprint. Clean up scratch after every slice.

  36. planning

    Decide slowly, then move fast.

    Before you build is the cheap window. Lay everything out while being wrong still costs an edit; once a project ramps up, every mistake costs more and the team ends up firefighting.

  37. ledgers

    A hash chain proves a record wasn't changed. Not that it was true.

    One writer checking itself is the opposite of what makes a blockchain trustworthy. The writer needs independent checkers, and a mirror it can't rewrite.

  38. reporting

    Silence is the absence of reporting, not of problems.

    A block with no regression results isn't passing. No evidence means unknown, never green.

  39. code

    Every branch ends with an exit code and a sign.

    Think of code as a tree of roads. Every dead end should close with a clear status and a message saying why.

  40. agents

    Every instruction should answer a failure you saw.

    Rules written for imagined problems pile up and get ignored. Write the rule after the mistake, and say which one.

  41. linux

    Missing glyphs look like missing words.

    Blank gaps in the terminal were font coverage, not locale. fc-list :charset=<hex> shows which fonts have the character.

  42. security

    Model output in a spreadsheet can run as a formula.

    Cells starting with = + - or @ execute in Excel. Prefix them with an apostrophe, on the export path only.

  43. linux

    O_NOFOLLOW only guards the last path component.

    A symlink earlier in the path is still followed. Safe walks open each directory relative to its parent's descriptor, then fstat the final file.

  44. llm

    A neutral API doesn't mean neutral limits.

    One chat API fronts many vendors, yet one model family rejected max tokens below 16 while others accepted 1. Test every model.

  45. build

    A build cache skips work. It doesn't speed up one long step.

    EDA regressions spend their time in single long tool runs, and caching only helps once every input is declared.

  46. typography

    Find the code point before blaming the font.

    Name the exact glyph (say U+23FA), check which installed fonts cover it, then add a fallback font in your user font folder. No root needed.

  47. build

    One shared defines header defeats incremental builds.

    When every file includes a hub header, touching it invalidates everything. Skip-based tools like Bazel or Snakemake save little until such hub files are split.

  48. riscv

    ISA compliance is won in the edge cases.

    The common path rarely breaks. Compliance is judged on corner cases, so enumerate them explicitly during analysis instead of hoping tests stumble on them.

  49. testing

    Offline tests prove the question. Live data proves the answer.

    A mocked page test shows the UI asks the server the right thing. Only live data shows the server answers it correctly.

  50. security

    Env-var filtering is a seatbelt, not a sandbox.

    Stripping variables cuts accidents. It doesn't stop a process that goes looking for another one's environment.

  51. llm

    A one-line agent call isn't a small call.

    Most of its cost is the agent writing its own long system prompt to cache. Tiny requests carry a fixed overhead.

  52. process

    Record proof that goes stale, not status people type.

    A ticket says 'done' until someone edits it. Evidence tied to a hash goes stale by itself when an input changes.

  53. python

    A surviving mutant can be a stale .pyc.

    After an in-place edit within the same second, Python reused the cached bytecode. Run mutation checks with python -B.

  54. git

    '.venv/' doesn't ignore a symlink.

    A trailing slash in .gitignore matches only directories, so a symlink named .venv slips into 'git add -A'. Write '.venv'.

  55. building

    Buy the commodity. Build the differentiator.

    A missing 10% is rarely a reason to rebuild the other 90%. Wrap it, extend it, or write a plugin.

  56. testing

    Chain tests on events, not delays.

    In a simulator, time is exact. On a busy machine, a sleep before the next step is a flaky test that only passes on a quiet day.

  57. evals

    Random inputs need a golden model.

    Constrained random works in verification because a reference model knows the right answer. For LLM output, that means an eval set with known answers, or a judge.

  58. interfaces

    Ports freeze at tape-out. Software interfaces don't.

    So version them, and let both sides cope with the old shape for a while.

  59. eda

    Closing the viewer doesn't stop the job.

    A GUI tool in a detached session keeps its licence until a cut-off or time limit, long after the user walked away.

  60. frontend

    Hand-typed API types are a silent contract.

    Rename a backend field and the frontend still compiles. Generate types from one schema so a mismatch goes red.

  61. rtl

    Parse RTL with a real front end, not regex.

    Text search loses hierarchy and connectivity. A proper SystemVerilog parser that builds a syntax tree gives you the design's actual structure to reason about.

  62. linux

    X has no timeouts.

    One stalled hop in a forwarded display chain can freeze a whole shared desktop. Remove the forwarding; moving users doesn't help.

  63. design

    Judge a style from more than one page.

    One screenshot gave the wrong read on my own site's style. Sample widely before calling a pattern a pattern.

  64. design

    Strictness is for the builders, not the customer.

    Strict ledgers and gates are taste for systems people rely on. The customer should feel the reliability, not carry the rules.

  65. art

    SVG is the wrong tool for painterly looks.

    Watercolour or oil textures need raster generation. Vectors suit line and low-poly diagrams, and they diff and review like code.

  66. frontend

    Test the response shape with the route.

    A route that returns 200 with the wrong shape passes a status check. Checking the shape is the same test, extended.

  67. aws

    A wrong tag key gives you $0 forever.

    Budget tag filters need the user: prefix. Get it wrong and there's no error, just a budget that never moves. Prove it with real spend.

  68. git

    A force-push doesn't erase old commits from the host.

    They stay reachable by ID until the host garbage-collects. Rotate the leaked secret; rewriting history is cleanup, not the fix.

  69. frontend

    An alarm that's always lit gets ignored.

    Highlights are alarms. Keep them under a rate ceiling, or a permanently lit row trains people to look away.

  70. security

    Anything on the command line is public.

    Every user on the host can read argv. Pipe secrets and sensitive names in through stdin.

  71. css

    One CSS system per project.

    Plain CSS on custom-property tokens, and no utility framework beside it. Two systems drift, and nothing tells a new page which one to use.

  72. protocols

    APB slaves can stretch a transfer with PREADY.

    A slow peripheral holds PREADY low to stall the access phase, so logic that assumes every APB transfer takes two cycles breaks.

  73. docs

    Hand docs go stale. Generated docs go wrong.

    Nothing checks the prose of a hand doc, so it drifts. Generated docs are fluent, cited and sometimes false. Both need a drift test.

  74. aws

    Bedrock has no dollar cap.

    Only token rate limits, and budgets lag by hours. The only hard stop is a gateway in front, and only for traffic that goes through it.

  75. networking

    TIME_WAIT sockets can fool peer matching.

    Matching a local connection to a user by address alone can pick a stale closed socket. Match the full four-tuple and the ESTABLISHED state.

  76. ai

    An LLM is a probability machine.

    Output quality follows input quality, so the real work is the grounding and orchestration around the model.

  77. python

    urllib has no default timeout.

    A probe can hang forever unless you set one. Also catch HTTPError, which urllib raises for any non-2xx response.

  78. linux

    A shared home carries more than files.

    With linger on and an NFS home, every batch job started my user services on the compute node too.

  79. tls

    AWS CLI v2 ignores the system trust store.

    It ships its own CA bundle, so a proxy root added to the OS does nothing. Set ca_bundle or AWS_CA_BUNDLE.

  80. rag

    Better input means better curated, not more.

    Adding a reranker made retrieval worse, and navigation chunks caused refusals. Grounding is curation.

  81. frontend

    When a layout choice is unclear, ask what the page is for.

    Restate the decision in terms of what the reader came to do. The answer usually picks the option.

  82. frontend

    A dashboard page leads with its answer.

    One sentence first, then figures, then tables. Make readers dig and they will quote the wrong number.

  83. frontend

    Check every width in a real browser.

    Phone-width overflow only showed up in live viewport checks. Unit tests don't render anything.

  84. reviews

    Cap the review loop.

    Each round finds small issues in the last round's fixes. Without a severity cap, a two-line fix grows into thousands of lines.

  85. security

    Scan history for secrets, not just the tree.

    Before the first push, check every commit. A secret deleted last week is still in the repo.

  86. eda

    Some tools hold every licence until they exit.

    A step that combines several stages keeps each earlier stage's licence to the end. Splitting the step frees them sooner.

  87. eda

    A licence server can be up while its daemons are down.

    An lmgrd up/down check stays green while the vendor daemons that actually serve the features have failed. Check health at daemon level.

  88. data

    Fix attribution at the source.

    Scraping logs to guess which job used what is fragile. Have the flow record the job id and its parent when it runs.

  89. postgres

    A green SQLite suite says nothing about Postgres.

    Types, upserts and time zones differ. A test on the real engine found migrations that couldn't rebuild the live database.

  90. teams

    When prototypes take hours, alignment is the bottleneck.

    Building stopped being the slow part. Agreeing on direction is, so talk it through together and early.

  91. rag

    An agent that writes to its own knowledge base can poison it.

    Route its writes through an inbox and a review gate, with provenance tags, before they become things it answers from.

  92. eda

    EDA tools stamp dates and hostnames.

    Two identical runs give different files because of the header. Hash a copy with the header stripped.

  93. eda

    Licence capacity is set by the scarcest feature.

    Tools that need several licence features at once saturate together, and the rarest one caps everyone.

  94. thoughts

    The future engineer orchestrates.

    AI is the hands: fast, tireless, good at patterns. The human is the slower brain that holds the taste and makes the call.

  95. data

    A peak can't tell five minutes from twenty hours.

    Peak-only history makes a short spike look like constant saturation. Time spent at full use is what should drive a capacity decision.

  96. rtl

    Decoupled units must still retire in order.

    When a vector unit runs apart from the scalar core, dispatch, hazard checks and retirement must keep architectural state in program order, or software sees results out of order.

  97. slurm

    srun inside a batch script is a step, not a job.

    Only sbatch makes a child job. Count steps as jobs, or miss their peaks, and the accounting skews.

  98. design

    The design shouldn't care which library you picked.

    If the architecture can be described without naming components, swapping one is cheap. I swap them often.

  99. postgres

    Autovacuum never analyzes partitioned parents.

    The parent's statistics stay empty until an explicit ANALYZE, which can hide planner and counting bugs for weeks.

  100. data

    Claim before you send.

    Mark the items in the ledger first, then build the message from exactly those, so a retry can't send twice.

  101. data

    A join that returns the wrong match is worse than none.

    An empty result makes you look. A plausible wrong match looks like it works and quietly poisons everything downstream.

  102. linux

    Closing any descriptor drops a POSIX lock.

    fcntl locks belong to the process, so opening and closing the same file anywhere else in your code quietly releases the lock.

  103. python

    One blocking call stalls every async route.

    A subprocess or sync DB call inside `async def` freezes the event loop, health checks included. Push it to a thread.

  104. python

    Python truthiness eats zero.

    'exit_code or "not recorded"' turned a clean exit into missing data. Test for None, not for falsy.

  105. frontend

    If the UI doesn't show it, it wasn't computed.

    Metrics the database worked out and the page threw away were wasted effort. A lot of value was already there, unshown.

  106. thoughts

    Understanding beats acceptance.

    I don't need every detail, but I need the mental model before I trust a system. A true black box is a liability.

  107. linux

    A oneshot unit takes its background children with it.

    When the service's main process exits, systemd cleans up the unit's processes, so work launched with & silently never finishes.

  108. slurm

    One field can mean different things in different states.

    A scheduler's reason code explains why a pending job waits, but on a running job it means something else. Summing it as wait time is wrong.

  109. postgres

    SET statement_timeout sticks to a pooled connection.

    The next request on that connection inherits it. Use SET LOCAL inside a transaction instead.

  110. eda

    The scheduler can't see licences checked out mid-run.

    A job gets its node, then waits on a licence the scheduler never knew about, holding memory and cores the whole time.

  111. learning

    Jump in, then work backwards.

    With something new I start from a working example and take it apart until I understand each piece.

  112. aws

    Serverless doesn't mean zero idle cost.

    OpenSearch Serverless bills capacity for as long as the collection exists. Compare standing hourly floors before per-query prices.

  113. linux

    Don't keep data where the cleaner sweeps.

    systemd-tmpfiles ages out files under /tmp and /var/tmp. A database kept there was deleted, starting with the tables nobody read, so it looked harmless at first.

  114. tls

    'Invalid token' can be a TLS error.

    gh auth status reports any failure as a bad token. Check for a certificate error before you log in again.

  115. rag

    Old versions can outrank the current doc.

    With several versions in one index, the top hits were drafts 0.5, 0.4 and 0.2 instead of 1.1. Clean out old versions before loading.

  116. debugging

    You can rule something out without knowing the cause.

    I couldn't prove why a host wedged, but I could prove my service wasn't the reason. Label what you measured apart from what you inferred.

  117. python

    Path.exists() can raise.

    On a path you're not allowed to read, it re-raises the permission error. One unreadable file killed whole poll cycles.

  118. frontend

    Secrets go in the URL fragment, not the query.

    The #fragment never leaves the browser in requests or server logs. The query string ends up in both.

  119. frontend

    Accept what you print.

    The UI showed durations like 1.5h and the filter rejected decimals. Whatever the app displays, its inputs should take back.

  120. slurm

    MaxRSS misses spikes and double-counts shared pages.

    It is sampled every 30 seconds, so short peaks vanish, and multi-process jobs can read up to 2x high. The cgroup high-water mark is the true peak.

  121. security

    SELECT ... INTO is a write.

    A blocklist that trusts anything starting with SELECT lets writes through. Use a read-only transaction and a statement timeout instead.

  122. frontend

    astro preview ignores your Vite config.

    It builds Vite with configFile:false, so proxy and allowedHosts settings silently drop. Use the Astro server block, or astro dev.

  123. frontend

    Number(null) is 0.

    A missing value rendered as 0.0%. Keep null and zero apart all the way to the pixel.

  124. python

    FastAPI ignores parameters you didn't declare.

    An unknown query parameter is dropped and the call still returns 200, so one table quietly ignored a filter its sibling honoured.

  125. typography

    Meet a brand point size with optical size, not scaling.

    A spec like 'Inter 18pt' is honoured through the font's optical-size axis and leading, not by literally blowing the text up.

  126. postgres

    A materialised view can carry an index. A plain view can't.

    The plain view recomputed everything on every read. Its materialised twin cached the work and turned max() into an index seek: 12 s down to 21 ms.

  127. postgres

    GREATEST ignores NULL in Postgres.

    GREATEST(NULL - x, 0) returns 0, so a missing value reported a confident zero waste. Handle NULL before you compare.

  128. sql

    Always end ORDER BY with a unique key.

    Sorting on a column with few distinct values let the same rows land on two pages. A unique tiebreaker makes paging stable.

  129. postgres

    A backup that exits 0 can be empty.

    Check a dump by listing what's inside it, not by its exit code.

  130. frontend

    TypeScript types don't cross the network.

    A client compiled cleanly while calling four endpoints the API never defined. Only a test against the server's real routes catches that.

  131. css

    Tokens, never hex.

    Every colour, gap and radius comes from a token. One place to change the theme, and no one-off values creeping in.

  132. aws

    Match on tags, not lists of ARNs.

    Listing each model in an IAM policy hits the size limit at around fifty. Matching a tier tag scales to any number.

  133. design

    An accent is a spotlight, not a paint.

    One loud colour, one focal point per view. Use it everywhere and nothing stands out.

  134. eda

    Sign-off tools peak where you can't restart.

    Timing and physical checks hit peak memory in phases that can't be checkpointed, so an OOM means starting over. Size from a comparable run.

  135. ops

    Up is not the same as working.

    A collector passed every liveness check while no new data arrived. Check that fresh rows landed, not just that the process answered.

  136. frontend

    Never trade information for looks.

    Wide tables get merged cells and an 'all columns' view, not hidden data. A pretty table that drops a column is a wrong table.

  137. design

    Safe to change depends on who reads it, not who owns it.

    Owning a file doesn't make editing it safe. Count its consumers; a file with many readers needs care whoever owns it.

  138. security

    A good policy on one host protects nobody.

    The design was never the weak part. The strong policy simply never reached the machines people actually worked on, so distribution is the control.

  139. data

    Use UTC everywhere, and label it.

    Host-local summer time put the same wait on two different dates in one report. Labelled UTC keeps day buckets stable.

  140. typography

    Rank with weight and space, not size.

    Small, dense type reads calmer. Weight, case and spacing do the ranking without shouting.

  141. eda

    In distributed STA, the master reserves big and uses little.

    The coordinator mostly hands scenarios to worker jobs, so its memory request skews right-sizing. Its own launch log, not job shape, shows which workers it spawned.

  142. git

    Rename first, edit second.

    A pure `git mv` commit keeps `git log --follow` working. Mixing content edits into the move can break rename detection.

  143. typography

    Monospace for machines, a reading face for prose.

    Mono for labels, ids and code. A proportional face for long text. Pick type by role, not by mood.

  144. security

    A convenient private install is a governance gap.

    Same fact, seen twice: whatever lets one user run ahead of the fleet also runs outside the fleet's policy.

  145. docs

    A version number in prose has no owner.

    It goes stale the day the pin moves and nothing fails. Point to the file that owns the version instead.

  146. agents

    Back off in the tool, not in the model.

    Show an LLM a raw 429 and it invents its own retry plan and narrates it. Rate limits are a platform job.

  147. systemd

    In systemd, a failed condition counts as success.

    A false ConditionPathExists skips the unit and reports success, and Before= only sets order. A fail-closed guard needs Requires=.

  148. shell

    grep -q under pipefail can fail on a match.

    grep exits as soon as it matches, the writer gets SIGPIPE, and pipefail reports the whole pipe as failed.

  149. git

    Squash merge undoes a reformat commit.

    A mechanical reformat kept as its own commit protects git blame. Squash it into the feature and blame points at the formatter again.

  150. shell

    $(tty || echo none) can give you both.

    tty prints 'not a tty' to stdout and still exits non-zero, so you get two strings. It only shows up in non-interactive runs.

  151. config

    Check behaviour on the version you actually run.

    An older pinned binary silently ignored the newer form of a setting. The docs describe the latest; your fleet runs something else.

  152. design

    Code goes in a terminal window.

    On my pages, prose gets paper and ink, and code gets a terminal frame. The frame tells you what kind of text you're reading.

  153. data

    A read path that repairs is a write path.

    A reader can't tell a live writer from a dead one, so only the writer should recover a crashed store.

  154. agents

    Isolation beats a shared soup of state.

    Multi-agent works when each agent gets a bounded context and a clean handoff. Without that discipline, one agent does better.

  155. security

    Skills on shared storage are an injection path.

    Anyone who can write to that folder can write instructions your agent will follow. Lock the folder or don't load from it.

  156. postgres

    EXPLAIN ANALYZE really runs the statement.

    It executes the query to time it, so wrap writes in a transaction and roll back. Add BUFFERS to see page counts, not just time.

  157. agents

    Rules held by checks survive. Prose rules drift.

    Across audits, requirements backed by a check stayed true and prose-only governance didn't. Move rules into checks.

  158. teams

    Small teams with guardrails win.

    AI multiplies a small team once linters, rule decks and checklists are in place. Without them it multiplies chaos.

  159. linux

    A bind mount pins the old file.

    Sessions that mounted a file keep seeing that version even after it is replaced on disk. Restart them after an update.

  160. ops

    Govern the config, not the install.

    You don't have to win the argument about how people install a tool if a managed policy file applies to every copy on the host.

  161. thoughts

    Python for now. Rust is underrated.

    The AI ecosystem pulls everything to Python today. For systems-level infrastructure, where speed starts to matter, Rust is worth a serious look.

  162. process

    Enforce the standard one level up.

    If the job wrapper adds the metadata every job needs, nobody below has to remember it, and the data comes out clean.

  163. data

    Split the schema before you have data.

    A storage layout is cheapest to change while nothing is committed and no corpus exists. After that, every split is a migration.

  164. linux

    A control that can't work is worse than none.

    BlockIOWeight on RHEL 8 needs the CFQ scheduler, which was removed, so it reads as protection while enforcing nothing. Reading the value back proves acceptance, not effect.

  165. data

    Bracket your ORs.

    A AND B OR C means (A AND B) OR C in most query languages. That silently dropped a date filter. Brackets make the intent explicit.

  166. networking

    Check the search domain before calling a host missing.

    A short name can fail while the full name resolves. A reverse lookup is a cheap way to confirm.

  167. agents

    Close the loop like a control system.

    Agents should check their own output and correct against the error, the way a controller corrects against a sensor. Open-loop agents drift.

  168. docs

    A new owner should inherit a system, not a story.

    A handover full of 'then we tried' is history. The next maintainer needs the current design and how to run it.

  169. shell

    A pipeline ending in tail always exits 0.

    Pipe a failing check into tail and the gate goes green. Use set -o pipefail, or don't pipe the gate.

  170. tooling

    Use ProxyJump, not nested remotes.

    Remote editors open one remote per window. To reach a host behind a jump box, put ProxyJump in your SSH config.

  171. docs

    A fact stated twice will disagree.

    The doc bugs I traced came from one fact living in two places and ageing at different speeds. Give each fact one home and link to it.

  172. networking

    SSH doesn't care about your CA bundle.

    SSH trusts host keys, not X.509 certificates, so git over SSH keeps working when HTTPS tools fail under TLS interception.

  173. docs

    Write the doc for a junior or an outsider.

    The five Ws, the exact commands, the steps in order. The reader who needs a doc most has the least context.

  174. linux

    Your shell expands the glob before sudo runs.

    `sudo cat /root-only/*.log` fails because your own user can't list that directory. Wrap the command in `sudo sh -c`.

  175. ops

    Baked images turn age into version drift.

    A machine built from an old image runs old pins forever. In a baked-image world, how old a host is decides which version it runs.

  176. evals

    A score can be perfect while the output is wrong.

    Word recall was 1.0 while list nesting and emphasis were broken. A word count can't see structure; structure needs its own check.

  177. data

    Never report a mean for skewed durations.

    Resolution times have long tails, so the mean misleads. Give n, coverage and method alongside any figure you report.

  178. ops

    Running the deployment finds what reading it won't.

    A health check read the local user file while real accounts lived in the directory service, so it audited almost nobody. Only the live run showed it.

  179. yaml

    Quote your YAML.

    Bare no, yes, on and off become booleans, and an unquoted id: 42 becomes an int. Identity keys need a type, not a guess.

  180. teams

    Conventions must work for humans and LLMs alike.

    With few programmers, the next reader of your code is often an agent. Written standards make its reading guaranteed rather than lucky.

  181. python

    Read text with utf-8-sig.

    A byte-order mark survives a plain utf-8 read and breaks the parser on line one. One codec name saves a confusing SyntaxError.

  182. linux

    install -d resets modes on existing directories.

    It applies mode and owner even when the directory already exists, so a deploy step quietly loosened a 0700 directory to 0755.

  183. data

    A mapping should be a join, never a hand-kept list.

    Two lists kept by hand drift apart. Derive one from the other and the question goes away.

  184. llm

    Long context is paid again every turn.

    The whole context is re-sent on each turn, which raises cost and degrades answers. Default to a modest window and opt in to the huge one.

  185. data

    Never guess to fill a gap.

    Backfill with NULL or UNKNOWN, so missing stays distinct from zero and later readers can tell the two apart.

  186. art

    Show the lines.

    I like drawings where you can see the strokes: line art, low-poly, diagrams that look drawn by hand. A diagram that looks drawn reads as a diagram.

  187. docs

    A heading's closing hashes vanish.

    In CommonMark `# Drain procedure #` renders as 'Drain procedure', so a trailing # in a title is silently lost.

  188. design

    Light themes should be paper, not white.

    Pure white on a screen glares. A cream background with dark ink reads like a page.

  189. design

    Derive graph edges. Never draw them.

    A graph view is a projection of a store. Hand-drawn edges go stale; edges aggregated from the data can't.

  190. agents

    Build tools around the user's question, not the API's pages.

    Paging through raw records burns tokens and context. A tool that answers 'how many, grouped by what' directly is cheaper and harder to misuse.

  191. tooling

    A formatter outside the gate is decoration.

    The format target existed, but nothing ran it in verify or CI. A tool that isn't wired into a gate isn't enforcing anything.

  192. data

    Too many categories is as bad as too many synonyms.

    Split a vocabulary too finely and tags scatter; leave it open and synonyms pile up. Both break grouping, so keep the list closed and short.

  193. agents

    Caveats only work if the model reads them.

    'Sample too small' flags do nothing if the agent stops at the headline number. Sometimes you have to force a second step.

  194. tls

    Most TLS errors behind a corporate proxy are one missing root.

    An inspecting proxy re-signs traffic. Install its root once and point each tool's bundle at it, and git, pip and containers all recover.

  195. tls

    A green smoke test can use a different trust store.

    The smoke test passed with the OS certificates while the real path used its own bundle and failed behind the proxy. Test the path you ship.

  196. process

    A waiver is a decision. Record it like one.

    Tool-specific waiver files scattered around hide who accepted which risk and why. A real waiver has an owner, a reason and a date.

  197. eda

    Broken DFT flows are ownership problems, not tool problems.

    Engineers copy the last project's scan scripts and edit them, so nobody owns the flow and a fix has nowhere to live.

  198. build

    Everything the tool reads belongs in the cache key.

    Headers pulled in through an include directory were left out of the key, so a stale result was served as current.

  199. networking

    Ping and TCP can succeed on a starved host.

    The kernel answers ICMP and completes TCP handshakes even when userspace is wedged. Only SSH or VNC banner timing showed the host was stuck.

  200. inference

    GPU memory utilisation is a target, not a cap.

    The same vLLM setting gave different KV cache sizes on different starts. Pin the cache in bytes when you need a fixed footprint.

  201. security

    Hand people a group, not sudo.

    A service account runs the process. A purpose-made group may start, stop and edit its config, and nothing else. People join and leave the group.

  202. integrity

    Read-only is a promise about a path. A hash is a fact about bytes.

    Permissions say who may write. Only a content hash tells you whether anything actually changed.

  203. linux

    An idle service in swap isn't a leak.

    A long-lived model server with nothing to do gets its weights paged out. It looks like a leak and is usually just the kernel tidying.

  204. frontend

    CORS lives in the browser, so curl proves nothing.

    curl and server-to-server calls ignore CORS. And an error response without CORS headers shows up in the console as a CORS failure.

  205. shell

    Initialise what your cleanup trap uses.

    Under set -u, a trap that reads an unset variable fails itself, and the cleanup never runs.

  206. design

    A design is ready when it has a feedback loop.

    If the output can't be checked and fed back to the input, you can't tell whether it works. That loop is my test for 'ready to build'.

  207. rag

    A reranker only reorders what retrieval found.

    It scores query and candidate together, but if the right chunk wasn't in the first-stage top-N, no amount of reranking brings it back.

  208. aws

    An assumed-role profile doesn't inherit ca_bundle.

    The source profile worked behind the proxy and the role profile failed TLS. Each profile needs the setting.

  209. accessibility

    Colour alone can't carry state.

    A red dot means nothing to a colour-blind reader or on a grey printout. Add a shape, a pattern or a word.

  210. agents

    When an agent fails something simple, check its context.

    A plain SQL aggregation shouldn't fail. When it does, the cause is usually missing schema or bad orchestration, not the model.

  211. testing

    A stub that lies finds different bugs than one that fails.

    Exit non-zero catches ignored errors. Exit zero while doing nothing catches code that treats an exit status as proof of state.

  212. linux

    inotify doesn't see another machine's writes.

    On NFS, a file changed from another client fires no event. Watching across hosts needs a poller.

  213. tooling

    A tool nobody updates is worse than none.

    People trust stale data. Put the truth next to the work so updating it is a side effect, not a chore people skip.

  214. testing

    Tests can be complicit in the bug.

    If the test was written from the same wrong reading of the spec, it passes with the code. Check what a test assumes, not just that it's green.

  215. sqlite

    SQLite's WAL mode is unsafe on NFS.

    WAL coordinates writers through shared memory on one host, which a network filesystem can't provide. On NFS, pin the rollback journal mode.

  216. inference

    Without a reasoning parser, thinking leaks into answers.

    Some models close their thinking with </think> but never open it. The server needs the matching parser to split the thought from the reply.

  217. testing

    A skip that looks deliberate hides forever.

    A test that quietly skips on a missing dependency can stay unrun for the life of the project. Make skips loud, or count them as failures.

  218. make

    '|| exit 0' only exits its own line.

    Each recipe line in a Makefile runs in its own shell, so an early exit on one line doesn't stop the next.

  219. build

    For Python, build means import.

    Compiling won't catch a module importing a name another change removed. The gate has to import every module.

  220. protocols

    Never make VALID wait for READY.

    If the sender waits for ready and the receiver waits for valid, both stall forever. The source must raise valid on its own and hold it steady.

  221. rag

    The key RAG test is a question it can't answer.

    Ask something outside the corpus. The system must say 'not found' rather than invent, because the grounding layer is where quality is won.

  222. ops

    On a shared host, look for the farm first.

    Size the job and send heavy work to the scheduler. With no farm, run gently. Only on your own machine do you just run it.

  223. design

    Taste stays human.

    AI implements a design well and invents one badly. I set the direction and the templates; the agent fills them in.

  224. agents

    Agents should cite what they worked from.

    Work that can't be traced to a spec or a requirement can't be trusted, however good it looks.

  225. shell

    dirname $0 breaks under a symlink.

    It returns the link's folder, not the script's. Use readlink -f to find where the script really lives.

  226. sql

    INSERT OR REPLACE is a delete in disguise.

    SQLite deletes the clashing row and inserts a new one, so a guard that blocks UPDATE and DELETE can still be bypassed.

  227. docs

    A '- - -' bullet becomes a horizontal rule.

    Content inside a list item can start a new block, so the text '- - -' turns into a thematic break and the bullet deletes itself.

  228. building

    Ship it end to end, or don't ship it.

    A stub 'for later' is a ghost: it looks like a feature and does nothing. Half-built is worse than missing.

  229. sta

    A timing violation is a symptom.

    The cause can be the RTL, the constraints, the library or the layout. Working out which is the real job.

  230. docs

    A model's default prose sits in the middle of everyone's.

    To make it sound like you, give it your own writing samples and rules a reviewer can check, not adjectives like 'sound human'.

  231. git

    core.fileMode=false drops exec bits silently.

    With file modes ignored, a chmod +x never reaches the commit, and the script fails on the next clone.

  232. synthesis

    Toy constraints give toy answers.

    A synthesis run with simple SDC says little about real timing. Results are only as real as the constraints and libraries you feed in.

  233. postgres

    A recreated view loses its grants.

    DROP and CREATE make a new object with default privileges. Re-grant in the same script, and test reads, not just denials.

  234. frontend

    Hover-only help doesn't exist on a phone.

    Tooltips need a pointer. Put the hint in the placeholder or a help line people can reach on any screen.

  235. eda

    Wrap every tool run in a script.

    An interactive synthesis or lint session can't be repeated. A script can, and a script is something an agent can run too.

  236. tooling

    A merge tool can succeed and drop your changes.

    A template update reported success while silently keeping the template's side of conflicted files. Diff the result; don't trust the exit code.

  237. tls

    A normal auth error proves TLS works.

    If an unauthenticated request gets a plain 'access denied' back, the handshake succeeded, so the certificate problem is fixed.

  238. thoughts

    Chip design's exclusivity is artificial.

    The complexity is real. The gatekeeping isn't. More people in means more ideas and faster progress.

  239. agents

    If the handoff isn't enough, the handoff is the bug.

    An agent should finish a task from the handoff alone. Missing context isn't the agent's failure, and it multiplies token cost.

  240. linux

    RLIMIT_AS counts reserved memory, not used memory.

    Node, Java and PyTorch reserve big address ranges up front, so a tight cap kills them before they use anything.

  241. lint

    Lint early, or integrate late.

    Hardware integration is slow, so a mistake found there costs days. Lint and static formal move the check to where it is cheap.

  242. design

    Motion should scale with the page's purpose.

    A showcase page can have theatre. A page someone works in for hours gets one short ease and nothing else. Every page needs a reduced-motion fallback.

  243. design

    Between two equal designs, pick the one easier to draw.

    The design that makes a cleaner block diagram is the one you will still understand in a year.

  244. inference

    /health can be answered by the wrong server.

    An unrelated service holding the port returns OK. Check /v1/models for the expected model name, then send a real completion.

  245. data

    pptx slide order isn't in the file names.

    Reordering slides only changes sldIdLst in presentation.xml; slide1.xml keeps its name. Resolve each r:id, and shuffle fixture order so tests can catch it.

  246. networking

    A redirect on a WebSocket handshake means a proxy answered.

    Upgrades only accept 101. A 303 with a branded HTML page came from an inspecting proxy, not the server.

  247. linux

    Group membership doesn't reach an open shell.

    Add yourself to a group and existing sessions still lack it. Log in again, or use newgrp.

  248. protocols

    Handshake on valid and ready, never on timing.

    On AXI, data moves only when both are high. Assuming the other side is ready 'by now' is a bug waiting for a slower clock.

  249. docs

    Do, understand, what's true now.

    Docs split into runsheets, references and registers, plus frozen decision records for why. Mix them and every one gets worse.

  250. security

    Once a doc is in a shared index, assume it was read.

    You can't know who already searched it. Decide what goes in up front, because removing it later doesn't undo the exposure.

  251. systemverilog

    Simulates fine does not mean synthesises.

    SystemVerilog is two languages: a small synthesisable subset and a big verification one. A construct can pass simulation and fail synthesis.

  252. systemverilog

    Keep state and logic in separate blocks.

    Flops in always_ff, next-state logic in always_comb. Mixing them is how latches and sim-versus-synthesis mismatches sneak in.

  253. networking

    Raw TCP can't pass a domain allowlist.

    Domain filtering works through an HTTP proxy. Licence servers, schedulers and SSH speak raw TCP, so they get blocked.

  254. security

    A limited token beats a path deny.

    Deny rules match text, and child programs like git read their own config. A narrowly scoped token stays narrow whatever reads it.

  255. verification

    Assertions are cheap spies.

    An SVA fires on the cycle a rule breaks, not three blocks later where the bad data finally shows up.

  256. slurm

    You can't grow a running Slurm job's memory.

    The cgroup limit is fixed when the step launches, so even an admin edit after start doesn't change what is enforced. Get the request right before submitting.

  257. ai

    AI is slightly over-hyped, and mostly misused.

    People ask it to do their whole job. It earns its keep as one bounded step inside a larger, mostly deterministic process.

  258. tooling

    A desktop build is the wrong artifact for a headless host.

    Remote editing needs only a small server on the host; the UI stays on your own machine.

  259. llm

    Models write broken JSON. Parse loosely, check strictly.

    Raw line breaks and invalid escapes are common in model output. Tolerant parsing followed by strict validation keeps good answers without trusting bad ones.

  260. postgres

    READ ONLY transactions still allow advisory locks.

    Session-level advisory locks are permitted and outlive the transaction on a pooled connection, so a read-only fence must deny them by name.

  261. python

    Rich will happily colour your dollar signs.

    Its number highlighter split '$0.04' with ANSI codes. Turn highlighting off for text that has to stay intact.

  262. security

    A Unix socket can tell you who is calling.

    SO_PEERCRED gives the peer's uid, stamped by the kernel, so a local service can identify users without a login. Clients should check the server's uid too.

  263. llm

    Instructions loaded early fade by decision time.

    Later context dilutes early instructions. Inject the rule at the point where the decision is made, not only at the start of the prompt.

  264. reviews

    The judge should not be the author.

    For a merge, use reviewers who didn't write the code and ask for zero blockers. Self-review only finds what you already looked for.

  265. verification

    Traceability is arithmetic, not testimony.

    A tracker status is someone's claim. A trace computed from the repo and test markers can be checked, and fails on any requirement no test names.

  266. eda

    EDA tool versions don't sort.

    Strings like V-2023.12 and T-2022.03-SP1 have no total order, so compare them for equality, never with >=.

  267. make

    Never name a Makefile variable AS.

    AS, CC and CXX are GNU Make built-ins and are never empty, so '--as $(AS)' quietly became '--as as'.

  268. linux

    One command-line argument is capped at 128 KiB.

    Linux refuses a single argv element over 131,072 bytes, so a big prompt passed as an argument has a hard ceiling. Use stdin or a file.

  269. agents

    Soft wording gives an agent permission to skip.

    A protocol step loses to the main task unless it is written as a commitment, with a named trigger and stop behaviour.

  270. evals

    The grader must not share code with the thing it grades.

    If the checker and the converter use the same extraction, their mistakes cancel and the score reads perfect.

  271. security

    Knowing who's asking isn't the same as being allowed.

    When an API authenticates the key and not the person, it can't scope by user. The layer in front has to own identity.

  272. security

    The prompt is not the boundary.

    Scope has to be enforced by code the model can't talk its way past, like a hook that re-checks arguments and live ownership and fails closed.

  273. testing

    Unverified is not refuted.

    When a checker dies before finishing, its findings are a third state. Scoring them as false quietly drops real bugs.

  274. config

    A hardcoded value is a question nobody asked.

    It means no one thought about what might change. Put it in config, and let the code and the docs both read it from there.

  275. inference

    torch.compile needs a modern C++ compiler.

    TorchInductor compiles kernels at runtime, and an old gcc 8.5 can't build them. Disabling Dynamo works, but compare eager output against CI before trusting it.

  276. agents

    A rule nobody receives does nothing.

    Distribution matters more than how good the rule is. Put it where the agent already reads, or it doesn't exist.

  277. testing

    Mock the world, then check the mock once.

    Most tests should be fast and mocked. A few unmocked tests on storage, auth and timing prove the mocks aren't lying.

  278. rtl

    Design for the safety standard from the first line.

    Parity and duplicated logic for functional safety shape the whole block. They are hard to bolt on later, so they belong in the first draft.

  279. frontend

    Deploy the server before the client.

    A new client sending requests the old server rejects breaks for everyone during the rollout. Server first, then client.

  280. agents

    Natural language is the front door, not the plumbing.

    Humans talk to agents in prose. Agents should talk to each other in schemas, because prose degrades with every hop.

  281. dft

    Coverage is a number. The holes are the to-do list.

    Pushing ATPG coverage up meant chasing each uncovered fault class one by one. The percentage says how far you are; the holes say what to do next.

  282. inference

    Size images to the model's training geometry.

    Feeding 300 DPI pages to a vision retriever trained on small fixed-size images explodes patch count, time and VRAM. Resize first and batch to bound memory.

  283. docs

    Silicon docs are full of brackets that aren't links.

    Bit ranges like [31:0] look like Markdown link text. A converter that treats every bracket as a link mangles every register table.

  284. linux

    A running daemon keeps using its deleted binary.

    Long-running processes execute the unlinked old file until they restart, so an upgrade isn't live just because the file changed.

  285. design

    Tight coupling is the real sin.

    A wrong choice is fine if the module can be swapped out. Coupling is what turns a wrong choice into a rewrite.

  286. build

    Incremental rebuilds matter most when reruns cost money.

    Skipping unchanged steps saves minutes for a compiler and real money for an LLM step, where every rerun is billed.

  287. python

    Regex alternation takes the first match, not the longest.

    oa|oasis matched '.oa' and truncated the file extension. Put longer options first or add a boundary lookahead.

  288. verification

    Random finds the surprises. Directed tests prove the corners.

    Constrained random stimulus covers what you didn't think of; directed cases pin down the edges you did. A test plan needs both.

  289. frontend

    One shared component can bloat a bundle.

    Sharing a filter control pulled a whole page's code into another chunk, which grew six-fold. Check chunk sizes when you share components.

  290. llm

    Prompt caching is the biggest lever on agent cost.

    Agent sessions resend the same long prompt every turn. Cached reads cost a small fraction of fresh input, so most of the bill falls away.

  291. testing

    Random checks need a seed, a snapshot and an oracle.

    The seed replays any failure, one snapshot keeps a race from looking like a bug, and a simple evaluator that shares no code says what's right.

  292. unicode

    NFKC is for comparing, not storing.

    It folds ligatures, superscripts and full-width forms, which is great for matching extracted text and lossy for content you keep.

  293. agents

    Script 80%. Let the model judge 20%.

    Agents inside a mostly scripted workflow are predictable. The boring version, deterministic steps with AI in the loop, beats the fully autonomous one.

  294. building

    Don't buy a gateway that skips the hard part.

    A gateway that moves requests but not identity leaves the real problem where it was. A thin wrapper you own can do the one thing that matters.

  295. eda

    EDA tools were built for people, not programs.

    Before an agent can help with chip design, the tools need clean CLIs and structured output. Making the flow scriptable is step one, not a nice-to-have.

  296. python

    FastAPI uses the first route that matches.

    A duplicate path silently shadows the later handler. Nothing warns you, so test that each route reaches its own code.

  297. inference

    Restart=always can't see a wedged model.

    systemd only reacts to process exit, so a hung server needs a probe. A model that runs out of GPU memory minutes after start never trips the start limit and restarts forever.

  298. python

    A process-wide signal can land on any thread.

    os.kill targets the whole process, so the kernel may deliver it to any thread that hasn't blocked it. signal.pthread_kill aims at the thread you mean.

  299. career

    Be T-shaped.

    Broad enough to design the whole system, deep enough in one area that people come to you. In a fast-moving field, breadth is underrated.

  300. build

    Hashing makes inputs reproducible, not outputs.

    Content addressing proves you fed the same things in. Outputs repeat only if the tool is deterministic, and LLM steps often aren't.

  301. security

    shred doesn't wipe a network drive.

    The filer may keep copies and snapshots. Revoking the secret is what actually helps.

  302. evals

    The instrument needs its own instrument.

    Whatever a checker doesn't compare can regress in silence. Point a check at the grader too, or its blind spots become yours.

  303. python

    Type hints are port declarations.

    In SystemVerilog the ports say what goes in and out before anything runs. Type hints do the same for a Python function, and a checker can read them.

  304. lint

    Put the coding standard in the lint deck, not in people's heads.

    Teams wrote RTL their own way and paid for it at integration. A shared rule set that runs on every block fixed what review kept missing.

  305. design

    If you can't draw it, you don't understand it.

    A system should fit on a block diagram, and the code should be laid out like the diagram, so a reader knows where to look without grep.

  306. python

    `import a.b` binds a, not b.

    The name added to your namespace is the top package. Any tool that resolves or patches imports has to follow that rule.

  307. build

    Same commit, different report means a hidden input.

    Reruns with no code change still differed, because released IP, flow scripts and tool versions weren't declared. Declare them before trusting a cache.

  308. email

    sendmail exit 0 means queued, not delivered.

    The local mail server accepted it. SPF or DMARC checks at the receiver can still quarantine it silently, with no bounce.

  309. security

    A sandbox stops accidents, not attackers.

    It constrains a well-meaning agent. Stopping a hostile user is the network layer's job, at the firewall or proxy.

  310. security

    A shared service account collapses identity.

    When everyone runs as one account, the log can't say who did what. Per-person identity has to be kept above it.

  311. process

    Imagine it already failed.

    Asking 'what could go wrong' gets polite answers. Declaring that the project failed makes finding reasons the task, and makes doubt safe to say.

  312. rtl

    Stateless logic is the easiest logic to verify.

    In RTL, logic with no state is checked by its truth table. Software that keeps state at the edges and pure functions in the middle gets the same gift.

  313. llm

    A reasoning model with a low token limit returns nothing.

    It spends the budget thinking and has no answer left. The empty content looks like success; the reasoning sits in a separate field.

  314. llm

    Let code aggregate. Let the model judge.

    LLMs summarise well and count badly. Do the heavy aggregation in code and hand the model only the part that needs judgment.

  315. design

    A design simulator isn't an end-to-end test.

    Load-testing a diagram shows what saturates first. It never runs your code, so it can't find a wrong answer.

  316. eda

    In EDA, the gap is orchestration, not tools.

    People forget updates and skip steps. Tools should be deterministic recipe runners, with AI only judging, converting or fixing around them.

  317. testing

    Instrument the harness before blaming the tool.

    A 'my change does nothing' result was the test harness cloning the wrong tree. Harness faults look exactly like tool limits.

  318. testing

    Use asymmetric fixtures, or swapped fields pass.

    If test values collapse to equal numbers, a bug that swaps two fields is invisible. Use distinct values like 33.3 and 50.0.

  319. testing

    A gate you've never seen fail is unproven.

    Several gates passed over real damage before anyone checked they could go red. Inject the fault, watch it fail, and record what you injected.

  320. gpu

    No answer from nvidia-smi means unknown, not free.

    A hung driver or a missing tool says nothing about the card. Treating silence as free lets you start work on a busy GPU.

  321. slurm

    The man page said order didn't matter. It did.

    An experiment showed the first listed partition wins when both have room. Test scheduler behaviour; don't just read it.

  322. security

    In a group chat, a bot may only know what everyone may see.

    Its answer is visible to the whole channel, so retrieval must be limited to what every participant is allowed to read.

  323. process

    For a service company, the process is the product.

    The customer keeps the chip; the company keeps only how it was delivered. So capture lessons on the spot, not in a hindsight review.

  324. systemd

    MemoryHigh throttles. MemoryLimit kills.

    On cgroup v2, MemoryHigh slows a service down. The older v1 MemoryLimit is a hard OOM kill. Know which one your host has.

  325. rag

    Embed the body, not the front matter.

    On small documents the metadata header can be most of the tokens, so the vector ends up describing the header, not the content.

  326. design

    Your faintest text token is where contrast fails.

    A muted ink at about 3.3:1 sits below the 4.5:1 that small text needs. Check the dimmest token, not just the body colour.

  327. llm

    Ground in your documents when you can't train on them.

    Most companies can't fine-tune on their own data. Retrieving the right document into context gets most of the benefit.

  328. ops

    Metrics say how much, never who.

    Token metrics show trend by model but carry no caller. Per-person spend needs the invocation log or a per-key gateway.

  329. linux

    NFS with sec=sys only carries 16 groups.

    AUTH_SYS sends at most 16 group IDs per request, so permissions granted through any group beyond those fail silently.

  330. postgres

    CREATE SCHEMA IF NOT EXISTS checks privileges first.

    Postgres checks the CREATE permission before existence, so the 'safe' statement fails for a role without it, even when the schema is already there.

  331. protocols

    AXI bursts must not cross a 4KB boundary.

    The spec forbids it, so an address generator has to split any burst that would run past a 4KB line.

  332. postgres

    Naive timestamps take the session's time zone.

    Postgres read naive datetime parameters in the session time zone, so a summer-time shift moved every window by an hour. Pass time-zone-aware values.

  333. sql

    NULL logic can hide a warning.

    `state='FAILED' AND exit_signal=0` is NULL when the signal is missing, not true, so the warning badge never renders.

  334. testing

    Some checks need no oracle at all.

    A AND B must sit inside A. count(A) plus count(NOT A) must equal the total. Relations like these catch parser bugs cheaply.

  335. inference

    Check that the GPU shares add up.

    Each model's memory fraction looked fine on its own; together they asked for 1.67 cards. Validate invariants across files before anything starts.

  336. integrity

    A content hash is also an address.

    Name a file by the hash of its bytes and the name tells you where it's stored and whether it changed. Git and build caches both work this way.

  337. art

    A drawing should look like someone drew it.

    Thin ink lines, visible characters and one filled accent, never a polished photo-sharp finish. Code-drawn SVG keeps how the picture was made on show.

  338. frontend

    The hard part of a chat UI isn't the screen.

    Drawing a chat window is easy. Owning sign-in and conversation storage is the real work, and the real risk, of a custom front end.

  339. aws

    AssumeRole needs both policies to say yes.

    The caller's identity policy and the role's trust policy must both allow it. Editing a trust template does nothing until deploy updates existing roles.

  340. git

    Git happily stores Foo.md and foo.md.

    Linux sees two files; a case-insensitive checkout sees a collision. Check case-folded uniqueness wherever filenames are generated.

  341. git

    Git only stores the exec bit.

    Group, setgid and other mode intent is lost on clone, so it has to live in a package or install script.

  342. frontend

    A test that scrolls first can't see the fold.

    Scrolling the element into view hides what a real first visit shows. Test at the real screen size, from the top.

  343. aws

    One role per budget, or one cap stops everyone.

    A budget deny attaches to a principal. Two tiers sharing a role means the first to overspend blocks the other.

  344. ops

    Systemd is enough for a handful of GPU boxes.

    Kubernetes pays off at fleet scale. For a few servers, one unit template and one config file per model are simpler to run and to explain.

  345. linux

    Ctrl+Z can leave your terminal in mouse mode.

    Suspend a program that turned mouse tracking on, and the shell receives escape codes every time you click. A terminal reset fixes it.

  346. typography

    Load only the font weights you use.

    Each weight is another file on every page load. Fonts from a CDN also fail on locked-down networks, so self-host when needed.

  347. knowledge

    Many small graphs, joined by stable names.

    One giant graph is hard to navigate and many loose ones drift. Keep one per source and connect them like netlists at their ports.

  348. testing

    Prove the parallel run matches the serial one.

    Run the suite serially, with four and sixteen workers, and shuffled. Hidden order dependence only shows when the order changes.

  349. postgres

    Killing psql doesn't kill the query.

    The server backend keeps running after the client dies. Set statement_timeout on ad-hoc queries instead.

  350. design

    Restraint can be a mode, not a new design.

    A reading page can be the same theme turned down: same palette and fonts, fewer colours, almost no motion.

  351. aws

    Ask for a model family, not a version.

    Callers that use a family alias never need a config edit when a new version ships. The mapping moves in one place.

  352. linux

    A 'read' capability overrides every file mode.

    CAP_DAC_READ_SEARCH skips read and directory-search checks everywhere, so isolation by file modes only holds against processes without it.

  353. process

    Keep the claim and today's state in separate columns.

    Mix what it will do with what it does now and you'll be issuing corrections. Two columns keep the claim honest.

  354. frontend

    Refuse min > max. Don't show an empty page.

    An impossible filter returns no rows, which reads as 'nothing matched'. Reject it on both sides with a message.

  355. security

    Log metadata, not content.

    Prompts are private, and anyone with log access could read them. Metadata alone still attributes usage and cost to each person, cheaply.

  356. security

    Skills are words. Hooks are code.

    An instruction file can't widen permissions; a hook or tool server can run anything. Lock each down by its own risk.

  357. agents

    A good playbook is defined by its edges.

    In scope, out of scope, reject when. A skill without boundaries does a little of everything and nothing reliably.

  358. data

    Alert on waste, not efficiency.

    A tiny job at 10% efficiency wastes nothing worth a ping. Gigabyte-hours wasted is what costs money, so alert on that.

  359. rag

    Check the stored chunk before blaming the model.

    A wrong answer about a PDF table came from corruption at parse time. Swapping the LLM would never have fixed it.

  360. testing

    Climb the test ladder: mock, fake, real-local, real.

    Each rung catches what the one below can't. A green mock says the logic holds; only the top rung says the world agrees.

  361. sta

    A clock target is a budget.

    At 2.6 GHz the period is about 385 ps, shared by PLL jitter, clock-tree skew, variation and setup time. When one share grows, another must shrink.

  362. rtl

    Hazards hide between two blocks that each look right.

    Core and accelerator can each pass their own checks while the handoff between them breaks. List the boundary cases early and synchronise retirement across both units.

  363. rag

    Synthetic test documents lie about real ones.

    Two changes passed synthetic tests and broke on a real datasheet, whose PDF outline was flattened to one level. Keep a real-document soak test.

  364. testing

    Don't assert on message text.

    Hundreds of tests checked error wording, so every copy edit broke them. Assert on a code or a field instead.

  365. linux

    Turn off GPU compositing on forwarded displays.

    Chromium's GPU process can crash under ssh -X, VNC or xvfb and black out the whole X session. Disable hardware acceleration there.

  366. git

    Keep a PR under 500 hand-written lines.

    A reviewer can read 500 lines line by line. Past that, review turns into skimming. Generated files don't count toward it.

  367. networking

    DNS round-robin doesn't balance clients that cache.

    Python clients resolved the name once and stuck to one replica. A real load balancer in front spread the load.

  368. growth

    If I make the same point a third time, stop me.

    Holding a position is a strength until it outlasts the evidence. Repeating without new support is the tell.

  369. ops

    Read the output, not the task status.

    A background run reported success because its wrapper exited cleanly. The file it was meant to write said otherwise.

  370. debugging

    Delta debugging finds a minimal set, not the smallest.

    ddmin guarantees that dropping any one difference stops the failure, not that no smaller set exists. Both ends must reproduce before you start.

  371. inference

    Context length is paid for in KV cache.

    vLLM must fit one full max-length request (length times per-token KV) or it refuses to start. Longer context means fewer requests fit at once.

  372. games

    Games teach you to think one move ahead.

    Plan the move, predict the response, adapt. Thousands of hours of that loop turned out to be debugging practice.

  373. inference

    Pin KV cache in bytes. Let the runtime count tokens.

    A fixed byte budget skips memory profiling and makes the footprint repeatable. How many tokens those bytes hold changes between versions, so re-read it after upgrades.

  374. ops

    A late cap costs money. A wrong cap takes production down.

    Lateness is bounded, visible and recoverable. A misconfigured automatic stop cuts people off with no human in the loop and no explanation.

  375. music

    Music taught me structure.

    Grade 8 piano: themes, variations, tension and resolution. The same shapes show up in how I lay out a system.

  376. gpu

    Finishing first is not happening-before.

    A write that completed earlier is still not visible to a reader unless the two sync through an acquire-release pair. Clock order is not memory order.

  377. llm

    Make every run report its own spend.

    Cost was visible only for runs that logged their tokens. A run that doesn't report spend is spend you find out about later.

  378. process

    Slice vertically, not horizontally.

    'All the error handling everywhere' is too broad to test and easy to miss. 'Error handling and logging for one part' has a clear edge and a clear test.

  379. testing

    Fixtures shouldn't share names with real data.

    A find-and-replace over real names rewrote the fixtures too, and tests failed for no real reason.

  380. evals

    No model as the judge in a gate.

    A deterministic scorer gives the same answer twice. A model judge can flip on a rerun, and a gate that flips isn't a gate.

  381. design

    Accent fills and accent text need separate tokens.

    Bright lime works as a button fill but is unreadable as small text on white, so the text role gets a darker ink in light mode.

  382. testing

    Write the tests from the plan, before the code.

    Tests written after the code tend to describe the code. Written from the plan, they describe the intent and can't be bent to fit.

  383. testing

    A check has three outcomes: yes, no, and couldn't run.

    Callers must tell 'the answer is no' from 'I couldn't ask'. One exit code for both hides a broken check.

  384. security

    A guard that finds nothing to protect should fail.

    'No git here, so nothing to check' let changes through. When a guard can't find its subject, that's an error, not a pass.

  385. eda

    Constraints and netlists belong in a release area.

    A user's own directory is the least reproducible input. Local config tweaks are fine, but SDC, UPF and netlists need a controlled, traceable source.

  386. inference

    Embedding models need KV cache too.

    They generate nothing, but the model still stores keys and values for every input token, so an embedder with too little cache won't start.

  387. design

    A new feature shouldn't touch the spine.

    If adding a feature means changing the core pipeline, the integration point is wrong. Fix the seam first.

  388. config

    Passing options straight through is a privilege.

    A config value forwarded as raw options lets whoever edits the config run anything the tool allows. Name the options you accept.

  389. frontend

    esbuild strips types without checking them.

    A green bundle says nothing about type errors. Run `tsc --noEmit` as its own gate.

  390. gpu

    Race sanitizers sample, so they can miss and misfire.

    Tracking every reader's clock costs too much memory, so only a sample is kept. Races with old reads slip by, and a wrapped clock buffer reports races that never happened.

  391. data

    Tie deadlines to milestones, not dates.

    Date deadlines go overdue on paper whenever a schedule slips, which trains reviewers to clear the flag instead of the debt.

  392. testing

    A pass over zero items is a failure.

    A live eval where every case was 'not run' scored a pass. A check that selected nothing has proven nothing.

  393. learning

    I can't maintain what I don't understand.

    So I rewrite borrowed code until it fits my mental model. That costs time, and sometimes the original was fine.

  394. git

    Tag after the full gate. Push last.

    The release order that works: changelog, commit, tag locally, run the full gate, then push. It was found by running it, not by planning it.

  395. linux

    On NFS, root on the client is nobody on the server.

    root_squash maps root to an anonymous user, so even uid 0 or CAP_DAC_READ_SEARCH can't read other users' private NFS homes. The server decides.

  396. thoughts

    Taste is knowing which option is right before you can say why.

    It comes from having seen enough good and bad work. AI can copy preferences; it doesn't build taste.

  397. rag

    Text embeddings miss diagrams.

    Embed page images too, as patch vectors, so charts, tables and layouts that text extraction loses can still be found.

  398. debugging

    To find why a tool refuses, change one input.

    Grepping its output for clues is guessing. Two runs that differ by a single input show the cause directly.

Each tile is a day. A lesson stands it up as a column, taller for more; today is outlined and the lesson you are reading is lit.

See all lessons →

Nov 1, 2026: Evaluate the installed path, including its managed policy.

// posts

All posts

Newest first. Every cover is a live drawing: point at it and it answers.

tutorial24 Oct 202630 minAgents you can repeatThe agents I trust aren't the clever ones. They're the ones whose every decision a script could make has been taken away from them.Read post →
tutorial18 Oct 20268 minA clock target is a budget"Run at 2.6 GHz" sounds like one number, but it's a budget of about 385 picoseconds that four different teams have to share.Read post →
thoughts18 Oct 20266 minBuild the bump, not the signMost of the rules I wrote for my agents either never reached them or quietly stopped being true, until I started writing the check instead.Read post →
thoughts18 Oct 20266 minWhat chip design taught me about software, and where it liesThe habits I brought from chip design mostly help, and the few that lie look exactly like the ones that don't.Read post →
thoughts18 Oct 20266 minDecide slowly, then move fastBefore you build is the cheapest window a project will ever have, and it's the one we rush.Read post →
project18 Oct 20266 minA second brain built from my chatsI couldn't remember half of what I'd built, so I had my AI chats write it down, and the hard part was keeping the record honest.Read post →
thoughts18 Oct 20266 minTeaching an AI to write like meI gave an AI a careful list of rules for how I write, and every draft followed them and still didn't sound like me.Read post →
software18 Oct 20265 minUnknown is not zeroA missing value that turns into a zero looks like an answer, and that is exactly why it gets trusted.Read post →
software18 Oct 20266 minWhat a hash can and can't proveA hash proves the bytes haven't changed, which is a lot, and it's very easy to let it vouch for much more than that.Read post →
tutorial18 Oct 20268 minWhere the GPU memory goesOn a shared GPU, the memory for every request is set aside before the first one arrives, and most serving surprises come from not knowing where it went.Read post →
project17 Oct 20269 minHow I draw the figures on this siteEvery drawing here is a small file run by one clock and checked by an audit that photographs it. Some of those files are templates: a seed, seeded noise and a grammar, and a different picture for every number.Read post →
tutorial14 Jun 202618 minInference, end to endA visual walkthrough of LLM inference from prompt to token — prefill vs decode, the KV-cache, precision, speculative decoding, the memory hierarchy, and how the big labs serve at scale.Read post →
silicon12 Jun 202616 minHow Inference Chips Are BuiltFrom transistors and dataflow to wafer-scale engines — a visual tour of how the silicon behind AI inference is designed, and why startups think they can unseat the GPU.Read post →
silicon28 Apr 202612 minRTL to GDS: A Complete WalkthroughFrom Verilog to tapeout — the full ASIC design flow broken down into digestible steps. Covering synthesis, P&R, timing closure, and the dark arts of DRC.Read post →
software15 Apr 20268 minBuilding a Cyberpunk Portfolio with AstroHow I turned terminal aesthetics and chip schematics into a personal site. Starfields, FSM diagrams, and unhealthy amounts of CSS.Read post →
silicon30 Mar 202615 minNeural Networks on FPGAs: A Practical GuideDeploying quantized models on Xilinx Zynq. Covers HLS, resource budgeting, and why your first attempt will always be too slow.Read post →
tutorial18 Mar 20266 minMy Vim Setup for ASIC DesignCustom keybinds, SystemVerilog LSP, waveform previews, and why I refuse to use an IDE.Read post →
silicon5 Mar 202610 minThe Art of Timing ClosureWhen your critical path laughs at your clock constraint. Strategies, hacks, and copium for meeting timing.Read post →
tutorial20 Feb 20269 minBuilding an Interactive Terminal in ReactState machines, command parsing, and typing animations. How the work experience section actually works under the hood.Read post →
thoughts8 Feb 20267 minSilicon vs Software EngineeringTwo worlds, same debugging despair. A comparison of methodologies, timelines, and the meaning of "shipping."Read post →
tutorial25 Jan 202611 minProcedural Starfield with Canvas APITwinkling stars, shooting stars, parallax layers — building an ambient background that doesn't murder your GPU.Read post →
thoughts10 Jan 20265 minWhat I Actually Do at Aion SiliconA non-NDA-violating look at life as a Senior ASIC Design Engineer. Spoiler: lots of waveform staring.Read post →
project20 Dec 202514 minDesigning a Toy RISC-V CoreA weekend project that took three months. 5-stage pipeline, hazard detection, and the satisfaction of running your own ISA.Read post →
tutorial5 Dec 20258 minAutomating EDA Flows with PythonTCL is pain. Here's how I replaced 2000 lines of TCL with 200 lines of Python and a lot of subprocess calls.Read post →
thoughts18 Nov 20254 min// devlog: ranking every coffee near the officeAn empirical study. N=23. Methodology: caffeine addiction. Results: inconclusive but delicious.Read post →
// trackers

Weekly trackers

An agent reads the release notes every week and writes up what moved, so I don’t keep twenty tabs open.

New posts, no spam.

Follow the feed in any reader, or email me and I’ll tell you when something new goes up.