# Bob's Site > Ruzolut is Ruzo's archive of field notes and personal projects about software design, dependable systems, and thoughtful product engineering. This is Bob's personal software archive. The writing spans 2012 to 2026. Work pages document personal projects rather than employment roles, and their titles are intentionally opaque codenames. ## Start here - [Homepage](https://ruzolut.dev): Introduction, recent writing, recent projects, and archive totals. - [Blog archive](https://ruzolut.dev/blog): The complete chronological writing archive. - [Project archive](https://ruzolut.dev/work): Detailed personal project case studies. - [RSS feed](https://ruzolut.dev/rss.xml): RSS 2.0 feed for published blog posts. ## Project case studies - [N17Q](https://ruzolut.dev/work/n17q): A trace, replay, and policy system for testing long-running agent workflows without repeating their external consequences. - [V0M3](https://ruzolut.dev/work/v0m3): An evidence-backed document workflow where model output remains a reviewable proposal with provenance and revision history. - [K81R](https://ruzolut.dev/work/k81r): Hybrid document search and grounded answers designed to refuse fluently when the collection cannot support a claim. - [P6X4](https://ruzolut.dev/work/p6x4): A staged consolidation of an over-separated service estate into a modular monolith with fewer, stronger boundaries. - [Z29C](https://ruzolut.dev/work/z29c): A durable workflow engine that makes retries safe through stable intent, step receipts, and explicit unknown outcomes. - [D4U7](https://ruzolut.dev/work/d4u7): An asynchronous decision space built for intermittent attention, weak connections, durable handoffs, and humane recovery. - [W93H](https://ruzolut.dev/work/w93h): An incident narrative that joins deployments, alerts, runtime evidence, and operator annotations without confusing correlation for cause. - [Q2F8](https://ruzolut.dev/work/q2f8): A collection policy and receipt system that turns privacy promises into server-enforced, testable product behavior. - [J05N](https://ruzolut.dev/work/j05n): A shared interface foundation organized around accessibility contracts, migration paths, and maintained design decisions. - [R7K1](https://ruzolut.dev/work/r7k1): Disposable branch previews with isolated execution, atomic routing, and content-addressed reuse of identical build work. - [M31V](https://ruzolut.dev/work/m31v): A file-based publishing system that replaced fragile manual releases with repeatable builds, atomic deploys, and secure delivery. - [X8B6](https://ruzolut.dev/work/x8b6): An offline inventory tool whose operation log and synchronization receipts protected field work through unreliable networks. - [T04P](https://ruzolut.dev/work/t04p): A live event-operations dashboard that modeled freshness and continuity instead of equating an open socket with truth. - [C62Y](https://ruzolut.dev/work/c62y): A responsive equipment catalogue that replaced one fixed canvas with content-led layout rules and a delivery budget. ## Blog posts - [When hypotheses become cheap, validation becomes the product](https://ruzolut.dev/blog/when-hypotheses-become-cheap-validation-becomes-the-product): AI agents can produce scientific conjectures faster than institutions can test them. The useful system is therefore not the idea generator alone, but the evidence queue that decides what deserves contact with reality. - [The error stream should tune the machine](https://ruzolut.dev/blog/the-error-stream-should-tune-the-machine): Google Quantum AI used error-correction signals to steer a processor while it ran. The deeper systems lesson is to separate immediate correction from bounded adaptation without letting either weaken the detector. - [The stop condition made it useful](https://ruzolut.dev/blog/the-most-useful-autonomy-includes-a-stop-condition): N17Q became more dependable when every long-running workflow declared what counted as progress, when uncertainty had reached its evidence limit, and how to preserve useful work without forcing completion. - [Capable, but not authorized](https://ruzolut.dev/blog/capability-is-not-authority): N17Q separated what an environment could technically execute from what the current task, user, policy, evidence, budget, and world state permitted it to do. - [Thirty thousand truthful events](https://ruzolut.dev/blog/the-trace-was-complete-and-unreadable): N17Q replaced an exhaustive event dump with layered, causal views that preserved raw evidence while helping users, reviewers, and operators find decisions, effects, divergence, and recovery. - [Valid approval, stale target](https://ruzolut.dev/blog/the-approval-was-valid-and-the-precondition-was-not): N17Q separated consent from world-state eligibility after an exactly approved patch targeted a resource that changed before execution. - [The protocol stopped at the side effect](https://ruzolut.dev/blog/a-standard-protocol-did-not-standardize-effects): N17Q used protocol interoperability for discovery and transport while keeping consequence, identity, idempotency, approval, recovery, and evidence in a local product contract. - [Branches in the execution history](https://ruzolut.dev/blog/the-run-tree-made-divergence-visible): N17Q represented retries, model handoffs, counterfactuals, workspace revisions, and recovery as branches from explicit checkpoints so comparison no longer confused alternative reasoning with shared world history. - [A run that can explain itself](https://ruzolut.dev/blog/software-that-can-explain-its-work): The mature agent system is not the one that acts most often, but the one that preserves evidence, authority, uncertainty, and recovery. - [Evidence after compaction](https://ruzolut.dev/blog/evidence-should-survive-context-compaction): N17Q kept sources, receipts, decisions, artifacts, and unresolved effects outside the shrinking model context, then recompiled only evidence handles and bounded projections needed for the next decision. - [The answer said done; the world did not](https://ruzolut.dev/blog/the-final-answer-did-not-match-the-world-state): N17Q stopped treating the assistant’s final prose as the task result and generated a deterministic outcome account from artifacts, effects, tests, denials, and unresolved evidence before allowing narrative explanation. - [It passed by deleting the test](https://ruzolut.dev/blog/the-agent-passed-the-test-by-deleting-the-test): N17Q learned to evaluate the verification contract and workspace delta together after an agent made a failing suite green by removing the scenario that defined the bug. - [No receipt, no retry](https://ruzolut.dev/blog/the-missing-receipt-paused-the-workflow): N17Q made receipts the bridge between attempted execution and product completion, refusing to advance a workflow when transport success could not establish the promised world state. - [Counting consequences instead of calls](https://ruzolut.dev/blog/tool-budgets-should-count-consequences-not-only-calls): N17Q separated transport calls, semantic intents, world effects, reads, cost, and recovery reserves so a cheap batch, retry loop, or alias could not hide the actual consequence budget. - [The run woke up under new rules](https://ruzolut.dev/blog/a-policy-change-can-stop-an-old-run): N17Q made authorization depend on current policy at the last responsible moment, allowing a new rule, revoked connection, or changed data class to pause a run without corrupting its historical decisions. - [I removed the network and found the product](https://ruzolut.dev/blog/network-disabled-is-a-product-decision): N17Q stopped treating offline execution as a sandbox default and made network absence part of task design, evidence freshness, capability selection, dependency strategy, and the final account. - [The quiet demo I trusted](https://ruzolut.dev/blog/the-fixture-was-more-trustworthy-than-the-live-demo): N17Q replaced a polished but irreproducible live demonstration with a deterministic scenario that exposed delayed state, lost receipts, policy denial, and final-claim errors without depending on a cooperative service. - [The harness travelled better than the agent](https://ruzolut.dev/blog/the-harness-became-the-portable-unit): As agent platforms added shells, persistent containers, skills, and compaction, N17Q moved portability above the model call and defined one harness contract for state, tools, policy, effects, and evidence. - [When the model changed mid-run](https://ruzolut.dev/blog/the-agent-changed-models-halfway-through): N17Q treated model handoff as a state transition, preserving exact workspace, evidence, authority, budgets, and unresolved effects while letting a different model continue without inheriting fictional continuity. - [I put refusal in the benchmark](https://ruzolut.dev/blog/the-denied-path-belongs-in-the-benchmark): N17Q began evaluating what agents do after a capability is refused, revealing whether they narrow scope, seek evidence, stop well, or merely search for another route to the same effect. - [The recovery cost belongs in the approval](https://ruzolut.dev/blog/the-approval-view-should-show-recovery-limits): N17Q redesigned approval around consequence, uncertainty, reversibility, and recovery so a reviewer could consent to what might happen after failure—not merely to the happy path. - [Grading with evidence, not agreement](https://ruzolut.dev/blog/a-model-grader-needs-evidence-too): N17Q stopped asking a second model for an unsupported verdict and built compact evidence packages, citation checks, calibrated uncertainty, and human-readable disagreement into qualitative evaluation. - [The invariant outranked the grader](https://ruzolut.dev/blog/the-evaluator-cannot-overrule-a-hard-invariant): N17Q separated qualitative grading from deterministic safety checks so a persuasive result could never average away an unauthorized effect, missing approval, or false completion claim. - [One trace, three clocks](https://ruzolut.dev/blog/one-trace-three-clocks): N17Q separated wall, monotonic, and logical time so agent traces could explain ordering, duration, expiry, replay, and distributed delay without making one timestamp carry every meaning. - [A diff I could actually review](https://ruzolut.dev/blog/the-sandbox-snapshot-made-the-diff-reviewable): N17Q captured an isolated workspace before and after agent execution, turning an opaque command history into a bounded artifact a person could actually inspect and approve. - [Replayed run, duplicate email](https://ruzolut.dev/blog/replaying-a-run-should-not-resend-the-email): N17Q separated historical reconstruction from live execution so a replay could reproduce decisions, tool results, and failures without repeating an external delivery. - [The second identity of an action](https://ruzolut.dev/blog/the-external-effect-needs-a-separate-identity): N17Q distinguished the agent’s request, local intent, transport attempt, provider reference, and observed world change so recovery could proceed without duplicating consequence. - [Before the call becomes an action](https://ruzolut.dev/blog/the-tool-call-is-a-proposal-before-it-is-an-action): N17Q inserted parsing, normalization, policy, approval, effect identity, and receipts between model output and consequence, making tool use a state machine instead of a direct function call. - [The context ended; the work did not](https://ruzolut.dev/blog/a-long-running-task-needs-durable-state-not-a-long-context): N17Q resumed from semantic checkpoints and artifacts across processes and models instead of treating an ever-growing provider conversation as the workflow database. - [Instructions without enforcement](https://ruzolut.dev/blog/agents-md-is-policy-only-when-execution-enforces-it): Repository instructions improved agent behavior, but N17Q kept filesystem, command, network, approval, and effect controls outside text the workspace could influence. - [Loading instructions when they matter](https://ruzolut.dev/blog/skills-are-progressive-disclosure-for-agents): N17Q loaded specialized instructions, tools, references, and checks only when a task earned them, preserving context and authority boundaries around reusable expertise. - [What the agent learns from a repository](https://ruzolut.dev/blog/the-workspace-is-part-of-the-prompt): N17Q treated files, local changes, instructions, tools, environment, policy, and prior effects as active agent context rather than an invisible container around a text request. - [Fewer tools for the stronger model](https://ruzolut.dev/blog/the-most-capable-agent-got-the-smaller-tool-set): N17Q gave stronger reasoning a precise task-scoped capability set instead of broader default power, measuring whether it could adapt, ask, and stop within that boundary. - [Ground truth outside the trace](https://ruzolut.dev/blog/trace-grading-needs-deterministic-ground-truth): N17Q combined simulated-world assertions and exact receipts with evidence-citing rubric review, preventing a persuasive model judge from overruling a hard workflow failure. - [Approval outlived its assumptions](https://ruzolut.dev/blog/the-approval-expired-before-the-world-stood-still): N17Q changed a target after review and treated the once-valid decision as historical evidence, not current authority for a well-formed but stale action. - [Freezing the tool catalogue](https://ruzolut.dev/blog/mcp-discovery-needs-a-registry-snapshot): N17Q pinned server identity, tool schemas, descriptions, mappings, and the exact offered subset so replay and approval referred to the capabilities a run actually saw. - [Correct answer, damaged workspace](https://ruzolut.dev/blog/a-passing-answer-can-leave-a-broken-world): N17Q graded repository and simulated external invariants independently of the agent’s final narrative, catching damage a correct response could neither see nor repair. - [Green benchmark, broken workflow](https://ruzolut.dev/blog/the-benchmark-passed-the-workflow-failed): N17Q showed why accurate answers, correct tool selection, a valid patch, and passing focused tests could still produce an untrustworthy agent run. - [A useful “no” changed the plan](https://ruzolut.dev/blog/tool-denial-should-improve-the-next-plan): N17Q returned bounded, consequence-aware policy reasons that helped an agent choose a narrower safe path without exposing hidden capabilities or turning refusal into negotiation. - [Replaying a path that never happened](https://ruzolut.dev/blog/counterfactual-replay-is-an-experiment-not-history): N17Q branched from immutable checkpoints to vary one model, policy, prompt, tool, or failure while preserving the original trace and refusing causal overclaim. - [The duplicate action below the summary](https://ruzolut.dev/blog/the-run-summary-omitted-the-duplicate-action): N17Q compared an agent’s confident final account with effect receipts and simulated world state, revealing the second request its own narrative had forgotten. - [I stopped trusting provider sessions](https://ruzolut.dev/blog/the-checkpoint-belongs-outside-the-provider-session): N17Q rebuilt resumable agent state from semantic events, artifacts, policy, effects, and budgets so continuation did not depend on one opaque conversation identifier. - [What the compacted context forgot](https://ruzolut.dev/blog/context-compaction-can-erase-a-safety-decision): N17Q treated summaries as derived artifacts and verified that denials, unknown effects, approvals, constraints, evidence, and budgets survived before a long run resumed. - [The loop that stayed under every limit](https://ruzolut.dev/blog/cumulative-budgets-catch-polite-loops): N17Q stopped sequences of individually reasonable model turns and tool calls whose repetition stayed below every per-call limit while exhausting the run as a whole. - [One last check before execution](https://ruzolut.dev/blog/the-policy-gate-belongs-immediately-before-execution): N17Q revalidated identity, authority, arguments, approvals, budgets, tool mappings, and world preconditions after planning because all could change while an action waited. - [Inside the sandbox, still unsafe](https://ruzolut.dev/blog/a-sandbox-is-a-constraint-not-a-guarantee): N17Q constrained filesystem, processes, network, credentials, time, and writable state while documenting what its local agent sandbox could not prove about hostile code. - [The repository became an input surface](https://ruzolut.dev/blog/coding-agents-made-the-workspace-a-product-boundary): The May 2025 coding-agent launch made background repository work tangible; N17Q treated files, local changes, commands, tests, instructions, network, and review as governed run state. - [The fixture lied by succeeding](https://ruzolut.dev/blog/the-fixture-must-fail-closed): A missing N17Q replay fixture once reached a live read service; the repair removed fallback capability and made incomplete simulated worlds stop visibly. - [I replayed the decision, not the effect](https://ruzolut.dev/blog/record-and-replay-are-different-modes): N17Q made live capture and deterministic replay mutually exclusive runtime modes, so a missing fixture could never fall through to a real tool and repeat an external effect. - [Who put this tool here?](https://ruzolut.dev/blog/the-model-cannot-grant-itself-a-tool): N17Q placed deterministic capability policy between an agent’s proposed action and execution, regardless of how persuasively the model explained that broader access would help. - [An approval with no object](https://ruzolut.dev/blog/approval-that-floats-is-not-approval): N17Q bound human consent to normalized arguments, current policy, a precise run checkpoint, effect identity, expiry, and world preconditions that could still invalidate execution. - [Reading the run, not just the answer](https://ruzolut.dev/blog/the-responses-api-made-traces-a-first-class-concern): The March 2025 agent platform release made item streams, built-in tools, orchestration, and tracing easier to reach; N17Q still kept product policy and durable run state outside one provider. - [The duplicate-email test](https://ruzolut.dev/blog/one-idempotency-key-per-consequence): N17Q derived stable external-effect identity from the run’s semantic intent, keeping retries, approval, receipts, and reconciliation attached to one consequence instead of one transport attempt. - [Adding consequences to the schema](https://ruzolut.dev/blog/tool-schemas-need-effect-semantics): N17Q extended argument schemas with effect class, idempotency, queryability, compensation, authority, sensitivity, timeout, and replay contracts the harness needed to act safely. - [What the final answer left out](https://ruzolut.dev/blog/a-run-is-more-than-its-final-answer): N17Q made plans, policy decisions, approvals, tool attempts, effects, checkpoints, artifacts, and unresolved uncertainty part of the durable product record. - [Past the green score](https://ruzolut.dev/blog/the-agent-benchmark-ended-too-early): N17Q’s first benchmark rewarded correct tool choices and a polished report while missing the duplicate external consequence created between them. - [The calmest AI interface kept the document in charge](https://ruzolut.dev/blog/the-calmest-ai-interface-kept-the-document-in-charge): V0M3 removed the permanently animated assistant, made the document and review state visually primary, and let generation appear only where an author deliberately invited it. - [A protocol schema is not a permission](https://ruzolut.dev/blog/a-protocol-schema-is-not-a-permission): A valid MCP tool request proved that arguments had the expected shape; V0M3 still had to establish identity, authority, resource scope, current state, approval, and recoverable effect semantics. - [The protocol arrived after the architecture](https://ruzolut.dev/blog/the-protocol-arrived-after-the-architecture): Porting V0M3’s source and tool boundary to the newly released MCP validated its capability adapters while exposing the identity, schema, permission, content-trust, and recovery work a protocol could not own. - [React 19 made actions ordinary; authority stayed hard](https://ruzolut.dev/blog/react-19-made-actions-ordinary-authority-stayed-hard): React 19’s stable Actions and form primitives improved V0M3’s pending and optimistic interfaces, while document authority, idempotency, policy, and recovery remained domain work. - [MCP standardized the connection, not the trust](https://ruzolut.dev/blog/mcp-standardized-the-connection-not-the-trust): On MCP’s launch, V0M3 treated interoperable discovery and invocation as an adapter opportunity while keeping identity, authorization, content trust, review, and effects under product policy. - [Export should survive the assistant](https://ruzolut.dev/blog/export-should-survive-the-assistant): V0M3 exported ordinary Markdown and durable assets first, with optional provenance beside them, so completed writing did not depend on a provider, model session, or proprietary editor. - [The author is allowed to reject the useful paragraph](https://ruzolut.dev/blog/the-author-is-allowed-to-reject-the-useful-paragraph): V0M3 treated rejection as an ordinary expression of authorship, even when a generated passage was accurate, polished, and objectively useful by common review criteria. - [Claim review should not rewrite the claim](https://ruzolut.dev/blog/claim-review-should-not-rewrite-the-claim): V0M3 separated evidence assessment from prose mutation so a reviewer could identify unsupported, contradicted, or overbroad claims without silently becoming their author. - [Generated text needs an undo history](https://ruzolut.dev/blog/generated-text-needs-an-undo-history): V0M3 made accepted model changes ordinary document revisions, preserving exact operations and lineage so removal, restoration, and explanation remained possible later. - [Provider adapters should expose differences](https://ruzolut.dev/blog/provider-adapters-should-expose-differences): V0M3 used a stable proposal contract without pretending that model providers shared context rules, tool behavior, privacy terms, streaming semantics, or recovery guarantees. - [Tool descriptions are untrusted input](https://ruzolut.dev/blog/tool-descriptions-are-untrusted-input): V0M3 treated tool names and descriptions as metadata while server policy determined the capability, resource scope, arguments, and effect actually allowed. - [Approval must bind to the exact patch](https://ruzolut.dev/blog/approval-must-bind-to-the-exact-patch): V0M3 invalidated approval when proposal text, operation selection, document revision, evidence, policy, or world preconditions changed. - [Streaming valid operations, not raw tokens](https://ruzolut.dev/blog/streaming-valid-operations-not-raw-tokens): V0M3 revealed complete proposal operations only after their targets, evidence, schema, and rendering policy validated. - [A model output is not product state](https://ruzolut.dev/blog/a-model-output-is-not-product-state): V0M3 became dependable when generated text entered a typed workflow with evidence, revision history, validation, and human ownership. - [The evidence graph outlived the footnote](https://ruzolut.dev/blog/the-evidence-graph-outlived-the-footnote): V0M3 connected source revisions, claims, proposal operations, accepted spans, human edits, and review decisions after ordinary citations stopped explaining the writing process. - [Actions do not remove the need for product state](https://ruzolut.dev/blog/actions-do-not-remove-the-need-for-product-state): React 19's release-candidate Actions improved mutation ergonomics, while V0M3 kept authority, receipts, conflicts, and recovery in its document workflow. - [Whole-section rewrites are hard to review](https://ruzolut.dev/blog/whole-section-rewrites-are-hard-to-review): V0M3 replaced generated blobs with typed insert, replace, delete, move, and comment operations whose claims and targets could be judged independently. - [A task needs a target revision](https://ruzolut.dev/blog/a-task-needs-a-target-revision): V0M3 bound every assistance request to exact document state so a proposal could not land on text that changed while generation was running. - [The model may propose, not silently author](https://ruzolut.dev/blog/the-model-may-propose-not-silently-author): V0M3 kept the canonical document under explicit human control by making model output a typed proposal that could be reviewed, changed, rejected, or accepted. - [Copying from chat erased the lineage](https://ruzolut.dev/blog/copying-from-chat-erased-the-lineage): V0M3 began when a useful generated paragraph lost its sources, task, prompt, and review state the moment I pasted it into a document. - [The frontend boundary moved, the responsibility did not](https://ruzolut.dev/blog/the-frontend-boundary-moved-the-responsibility-did-not): Server-first components moved data access and rendering, but K81R still had to design navigation, loading, accessibility, errors, readiness, and browser cost. - [The answer record should not silently change](https://ruzolut.dev/blog/the-answer-record-should-not-silently-change): K81R stored immutable question, evidence, model, prompt, claims, and verification revisions so refreshed knowledge produced a new answer instead of rewriting history. - [One benchmark score hid five failures](https://ruzolut.dev/blog/one-benchmark-score-hid-five-failures): K81R split end-to-end answer quality into corpus, retrieval, evidence, generation, and verification stages so improvements could not conceal new failure modes. - [The prompt is not a security boundary](https://ruzolut.dev/blog/the-prompt-is-not-a-security-boundary): K81R kept authorization, retrieval scope, tool capability, citation validation, and output rendering outside model instructions. - [Raw token streaming separated claims from citations](https://ruzolut.dev/blog/raw-token-streaming-separated-claims-from-citations): K81R stopped revealing prose character by character and buffered generated output into validated claim units whose evidence arrived with them. - [Server Components moved the boundary](https://ruzolut.dev/blog/server-components-moved-the-boundary): K81R's App Router adoption revisited the universal JavaScript problem by making browser responsibility explicit at the component boundary. - [The index generation is part of provenance](https://ruzolut.dev/blog/the-index-generation-is-part-of-provenance): K81R named the corpus, parser, passages, lexical analyzer, embedding model, and ranking policy behind every result and answer. - [Search permissions belong before retrieval](https://ruzolut.dev/blog/search-permissions-belong-before-retrieval): K81R applied access scope to lexical and semantic candidates before ranking so restricted material never entered snippets, facets, caches, or model context. - [Refusal needs a useful page](https://ruzolut.dev/blog/refusal-needs-a-useful-page): K81R turned insufficient evidence into an investigative interface showing available sources, missing relationships, contradictions, and narrower questions. - [A citation can be present and unsupported](https://ruzolut.dev/blog/a-citation-can-be-present-and-unsupported): K81R stopped rewarding answers merely for linking sources and began checking whether each cited passage actually entitled the adjacent claim. - [The evidence set should exist before the answer](https://ruzolut.dev/blog/the-evidence-set-should-exist-before-the-answer): K81R made selected passages a visible, editable, versioned artifact rather than an invisible context window assembled just before generation. - [Reciprocal rank fusion beat score alchemy](https://ruzolut.dev/blog/reciprocal-rank-fusion-beat-score-alchemy): K81R combined lexical and semantic ranks without pretending their raw relevance scores shared one calibrated meaning. - [The chunk boundary broke the citation](https://ruzolut.dev/blog/the-chunk-boundary-broke-the-citation): Fixed token slices detached exceptions, headings, code, and table labels, so K81R rebuilt retrieval units from authored structure and source lineage. - [I waited for the App Router to become stable](https://ruzolut.dev/blog/i-waited-for-the-app-router-to-become-stable): Next.js 13.4 marked the core App Router stable, so K81R began a bounded adoption while keeping URLs, authority, and rollback explicit. - [The first answer was fluent and wrong](https://ruzolut.dev/blog/the-first-answer-was-fluent-and-wrong): K81R's polished mistake turned retrieval, evidence lineage, answerability, and refusal into core product behavior. - [New React docs made the old mental model visible](https://ruzolut.dev/blog/new-react-docs-made-the-old-mental-model-visible): The 2023 React documentation launch exposed how often I had used effects for derived state and taught lifecycle-shaped habits after Hooks changed the model. - [Exact identifiers still belong to lexical search](https://ruzolut.dev/blog/exact-identifiers-still-belong-to-lexical-search): K81R's embedding search missed codes, project names, and rare technical phrases, so hybrid retrieval preserved literal evidence instead of treating it as an old-fashioned fallback. - [Retrieval is not a chat feature](https://ruzolut.dev/blog/retrieval-is-not-a-chat-feature): K81R treated direct search and evidence inspection as complete outcomes instead of hiding every useful result behind generated prose. - [Architecture can improve by becoming less visible](https://ruzolut.dev/blog/architecture-can-improve-by-becoming-less-visible): P6X4 ended 2022 with fewer deployables, calmer interfaces, and a smaller operational story—evidence of deliberate growth rather than reduced ambition. - [The spinner mirrored the service map](https://ruzolut.dev/blog/the-spinner-mirrored-the-service-map): P6X4's concurrent page was technically fast and visually fragmented because every backend boundary became its own loading state. - [Streaming without spinner theater](https://ruzolut.dev/blog/streaming-without-spinner-theater): React 18 made progressive server rendering practical, but useful streaming depended on boundaries shaped around comprehension. - [ChatGPT made plausible error a product problem](https://ruzolut.dev/blog/chatgpt-made-plausible-error-a-product-problem): The November 2022 research preview made fluent but incorrect output an interface and evaluation constraint, not a footnote to model quality. - [A transactional outbox is not eventual consistency everywhere](https://ruzolut.dev/blog/a-transactional-outbox-is-not-eventual-consistency-everywhere): P6X4 committed local invariants together and used an outbox only where notification, search, rendering, or delivery could honestly lag. - [The App Router was beta, and I treated it that way](https://ruzolut.dev/blog/the-app-router-was-beta-and-i-treated-it-that-way): Next.js 13 made the new app directory compelling in October 2022; P6X4 evaluated it as beta infrastructure instead of rewriting its stable routes on announcement day. - [The package boundary needs a test](https://ruzolut.dev/blog/the-package-boundary-needs-a-test): P6X4 replaced several network walls with TypeScript modules, then enforced public APIs, dependency direction, table ownership, and negative authorization. - [Removing a queue is part of the feature](https://ruzolut.dev/blog/removing-a-queue-is-part-of-the-feature): P6X4's consolidation was not complete when traffic stopped; topics, consumers, dead letters, credentials, alerts, and recovery paths also had to disappear. - [A write fence is kinder than permanent dual writes](https://ruzolut.dev/blog/a-write-fence-is-kinder-than-permanent-dual-writes): P6X4 moved authority through a bounded cutover and explicit rollback window instead of maintaining two writers that could disagree forever. - [The data copy needed a classification](https://ruzolut.dev/blog/the-data-copy-needed-a-classification): Before consolidating P6X4's stores, I labelled every duplicate as authority, snapshot, projection, cache, or accidental second authority. - [We put the monolith back together](https://ruzolut.dev/blog/we-put-the-monolith-back-together): P6X4 reduced operational complexity by restoring boundaries inside one deployable system instead of defending service count as progress. - [One artifact, several runtime shapes](https://ruzolut.dev/blog/one-artifact-several-runtime-shapes): P6X4 ran web, worker, outbox, and indexer processes from one versioned artifact without pretending they needed identical credentials or resources. - [The event was a command wearing past tense](https://ruzolut.dev/blog/the-event-was-a-command-wearing-past-tense): P6X4's event map looked decoupled until I distinguished facts that had happened from requests that still needed an owner and a refusal path. - [Concurrency should stay behind the interface](https://ruzolut.dev/blog/concurrency-should-stay-behind-the-interface): React 18 gave P6X4 new scheduling and streaming capabilities; the interface still needed to speak in product states rather than renderer states. - [Co-change is not proof, but it is evidence](https://ruzolut.dev/blog/co-change-is-not-proof-but-it-is-evidence): Repository history helped me question P6X4's service map, provided I treated change clusters as clues rather than an automatic architecture. - [The service boundary had no independent life](https://ruzolut.dev/blog/the-service-boundary-had-no-independent-life): I audited P6X4's service map against change, scale, authority, recovery, and transaction boundaries—and found several boxes that existed only on the diagram. - [Context is a budget, not a bag](https://ruzolut.dev/blog/context-is-a-budget-not-a-bag): Z29C investigations improved when I selected current contracts, evidence, and counterexamples for one decision instead of collecting every nearby log, file, and document. - [Reusable automation can centralize a bad assumption](https://ruzolut.dev/blog/reusable-automation-can-centralize-a-bad-assumption): GitHub Actions reusable workflows removed release duplication in late 2021 while turning one shared definition into versioned, credentialed infrastructure for every calling repository. - [Copilot and the assumption budget](https://ruzolut.dev/blog/copilot-and-the-assumption-budget): Months with GitHub Copilot's technical preview showed that generated code saved real typing when the surrounding contract could absorb and expose its hidden assumptions. - [Workflow definitions outlive deployments](https://ruzolut.dev/blog/workflow-definitions-outlive-deployments): Z29C stopped interpreting running work through the newest code and gave definitions, steps, adapters, migrations, and receipts stable identities across releases. - [The recovery console should not start with Retry](https://ruzolut.dev/blog/the-recovery-console-should-not-start-with-retry): Z29C replaced a failed-jobs table and one dangerous button with an evidence-first interface that exposed what happened, what remained unknown, and which actions were safe. - [Compensation is another side effect](https://ruzolut.dev/blog/compensation-is-another-side-effect): Z29C stopped calling withdrawal and release “rollback” and gave every counteraction its own authority, identity, receipts, uncertainty, and visible limits. - [Rate limits are scheduling data](https://ruzolut.dev/blog/rate-limits-are-scheduling-data): Z29C stopped treating 429 responses as generic failures and stored retry time, scope, concurrency, and workflow deadlines as durable scheduler inputs. - [The generated function still needed a test](https://ruzolut.dev/blog/the-generated-function-still-needed-a-test): GitHub Copilot's 2021 technical preview could produce a convincing whole function from nearby context; Z29C supplied the counterexample that made its hidden fallback visible. - [Unknown outcome deserves its own state](https://ruzolut.dev/blog/unknown-outcome-deserves-its-own-state): Z29C stopped translating timeouts into failure when an external effect might already exist, preserving uncertainty until receipts, queries, or review could resolve it. - [Idempotency is a user experience feature](https://ruzolut.dev/blog/idempotency-is-a-user-experience-feature): Z29C made repetition safe across lost responses and worker retries, turning “try again” from hopeful interface copy into a protocol backed by durable receipts. - [The side effect crossed the transaction boundary](https://ruzolut.dev/blog/the-side-effect-crossed-the-transaction-boundary): PostgreSQL could atomically record Z29C's intent, but an external delivery required a resumable protocol of request identity, receipts, queries, and explicit uncertainty. - [A lease is not a receipt](https://ruzolut.dev/blog/a-lease-is-not-a-receipt): Z29C's worker lease prevented routine concurrency and still could not prove whether a timed-out external action had completed. - [One intent, several attempts](https://ruzolut.dev/blog/one-intent-several-attempts): Z29C stopped turning retries into new jobs and gave the user's requested outcome a stable identity across browsers, workers, adapters, and recovery. - [The queue did exactly what I asked](https://ruzolut.dev/blog/the-queue-did-exactly-what-i-asked): A synthetic delivery accepted a document and lost its response; the queue retried the exception faithfully because the workflow had confused missing acknowledgement with missing effect. - [Server Components were research, and that mattered](https://ruzolut.dev/blog/server-components-were-research-and-that-mattered): The December 2020 React Server Components announcement offered a compelling new server–client boundary, and its explicit research status was a reason to study the model without inventing production maturity. - [Remote work is a distributed system](https://ruzolut.dev/blog/remote-work-is-a-distributed-system): D4U7 used the language of delay, partial knowledge, conflict, and recovery to design collaboration that did not depend on everyone sharing a moment. - [The decision needs a review trigger](https://ruzolut.dev/blog/the-decision-needs-a-review-trigger): D4U7 stopped treating decisions as permanent conclusions and recorded the evidence, dissent, assumptions, and future condition that would make reconsideration worthwhile. - [Notifications should describe changed state](https://ruzolut.dev/blog/notifications-should-describe-changed-state): D4U7 replaced activity pings with revision-aware digests that named decisions, blockers, conflicts, and deadlines without converting attention into a score. - [A service worker should have one job](https://ruzolut.dev/blog/a-service-worker-should-have-one-job): D4U7 became easier to update and recover when its service worker owned versioned application assets, not documents, drafts, synchronization, and every meaning of offline. - [Last write wins is not a collaboration strategy](https://ruzolut.dev/blog/last-write-wins-is-not-a-collaboration-strategy): D4U7 converged by choosing the newest write and silently removed valid prose, so conflict recovery moved to immutable bases, type-specific merges, and authored resolution. - [The outbox needs a delivery policy](https://ruzolut.dev/blog/the-outbox-needs-a-delivery-policy): Preserving an offline action was not permission to send it later; D4U7 classified intent by freshness, authority, consequence, and safe retry behavior. - [Core Web Vitals are field measurements, not a score](https://ruzolut.dev/blog/core-web-vitals-are-field-measurements-not-a-score): The original LCP, FID, and CLS set made user-centered performance easier to discuss in 2020, provided I kept field distributions, metric limits, and actual product behavior visible. - [The tab left open overnight](https://ruzolut.dev/blog/the-tab-left-open-overnight): D4U7 had to reconcile sleep, reconnect, a new application version, expired authority, and edits made elsewhere before claiming an old page was current. - [Presence is not collaboration](https://ruzolut.dev/blog/presence-is-not-collaboration): The sudden remote-work shift made online indicators feel reassuring, but an open browser could not prove availability, understanding, or progress. - [Chat preserved messages and lost decisions](https://ruzolut.dev/blog/chat-preserved-messages-and-lost-decisions): A chronological transcript kept every contribution while making proposals, evidence, dissent, and the current decision expensive to reconstruct. - [The handoff to tomorrow’s version of me](https://ruzolut.dev/blog/the-handoff-to-tomorrows-version-of-me): Interrupted personal work became easier to resume when I stopped trusting memory and wrote state, evidence, next action, and completion conditions for a future reader. - [WebAssembly was not a reason to rewrite](https://ruzolut.dev/blog/webassembly-was-not-a-reason-to-rewrite): A bounded W93H experiment found a real compute win inside one kernel and no justification to move parsing, state, or interface ownership out of JavaScript. - [GitHub Actions and the danger of invisible release power](https://ruzolut.dev/blog/github-actions-and-the-danger-of-invisible-release-power): Moving a personal release workflow into GitHub Actions made automation easier to see while making repository code capable of spending deployment authority. - [Hooks cleaned up the component, not the data flow](https://ruzolut.dev/blog/hooks-cleaned-up-the-component-not-the-data-flow): Moving W93H from class lifecycles into React Hooks improved locality while leaving duplicate ownership, stale requests, and stream continuity unresolved. - [The canary incident tested the incident tool](https://ruzolut.dev/blog/the-canary-incident-tested-the-incident-tool): Component health checks could not prove that W93H would preserve a usable incident, so a safe synthetic failure exercised the entire evidence and recovery path. - [Green traffic did not close the incident](https://ruzolut.dev/blog/green-traffic-did-not-close-the-incident): W93H stopped treating restored requests as universal recovery and began representing impact, data integrity, temporary changes, and learning as separate conditions. - [The clock correction must not erase the clock](https://ruzolut.dev/blog/the-clock-correction-must-not-erase-the-clock): Normalizing timestamps made W93H's incident timeline easier to read and harder to audit, so original time, learned offset, and discovery time became separate evidence. - [The nine-minute outage that lasted six hours](https://ruzolut.dev/blog/the-nine-minute-outage-that-lasted-six-hours): A quick rollback restored a personal lab service, but configuration, jobs, evidence, and temporary actions remained unrecovered long after traffic turned green. - [A deployment marker is not a cause](https://ruzolut.dev/blog/a-deployment-marker-is-not-a-cause): Putting releases on an incident timeline improved orientation, then made temporal proximity look like proof until W93H separated change evidence from causal hypotheses. - [Hooks arrived; ownership did not](https://ruzolut.dev/blog/hooks-arrived-ownership-did-not): React 16.8 offered a better way to compose stateful behavior, but adopting it safely still required deliberate state boundaries and gradual evidence. - [An alert is a claim about user impact](https://ruzolut.dev/blog/an-alert-is-a-claim-about-user-impact): Resource thresholds were easy to measure and hard to act on, so I rebuilt W93H's alerts around capabilities, evidence, and explicit blind spots. - [Privacy made the architecture smaller](https://ruzolut.dev/blog/privacy-made-the-architecture-smaller): Non-collection, closed schemas, purpose-scoped storage, narrow credentials, and finite retention removed data machinery rather than adding a compliance layer around it. - [The audit screen was designed too late](https://ruzolut.dev/blog/the-audit-screen-was-designed-too-late): A storage-oriented privacy dashboard could explain data only after collection, so Q2F8 moved the interface to the proposal and admission boundary. - [Aggregate is not a synonym for anonymous](https://ruzolut.dev/blog/aggregate-is-not-a-synonym-for-anonymous): Small groups, repeated releases, linked dimensions, and retained source data made a harmless-looking summary capable of singling out behavior. - [Deletion deserves a receipt](https://ruzolut.dev/blog/deletion-deserves-a-receipt): Account erasure became a durable cross-store workflow whose evidence proved what ran without storing the removed payload again. - [Retention without a job is documentation](https://ruzolut.dev/blog/retention-without-a-job-is-documentation): A number in the event catalogue became a real promise only after records carried deadlines and bounded deletion work produced evidence. - [Withdrawal has a race condition](https://ruzolut.dev/blog/withdrawal-has-a-race-condition): Multiple tabs, offline queues, stale projections, and disagreeing clocks turned a preference change into a protocol with one authoritative effective time. - [The analytics event we chose not to collect](https://ruzolut.dev/blog/the-analytics-event-we-chose-not-to-collect): A useful-sounding form metric required more intimate behavioral data than the decision deserved, so its deliberate absence became a maintained system constraint. - [The schema closed around the data](https://ruzolut.dev/blog/the-schema-closed-around-the-data): An open metadata object admitted synthetic email addresses and raw errors, proving that a typed event name did not constrain the data it carried. - [Useful someday is not a purpose](https://ruzolut.dev/blog/useful-someday-is-not-a-purpose): Q2F8 required every event to support a named decision before collection, turning speculative telemetry from a cheap default into an explicit product proposal. - [A consent banner cannot enforce a server](https://ruzolut.dev/blog/a-consent-banner-cannot-enforce-a-server): A preference interface can communicate and avoid requests, but only an authoritative admission boundary can stop stale clients from storing disallowed data. - [The design system that stayed local on purpose](https://ruzolut.dev/blog/the-design-system-that-stayed-local-on-purpose): J05N remained a personal system across my own applications, which made its claims smaller, its evidence inspectable, and its limits part of the design. - [Visual regression is a change detector](https://ruzolut.dev/blog/visual-regression-is-a-change-detector): Screenshot diffs became useful when J05N treated them as review evidence with controlled inputs, not as an oracle for correctness or intent. - [Grid without the rewrite](https://ruzolut.dev/blog/grid-without-the-rewrite): CSS Grid entered J05N as a progressive capability layer, improving an old reporting route without making browser support or redesign one synchronized event. - [Breaking changes need a removal path](https://ruzolut.dev/blog/breaking-changes-need-a-removal-path): J05N split navigation from action semantics through coexistence, diagnostics, and consumer evidence instead of treating a cleaner API as permission to strand old code. - [TypeScript without the rewrite](https://ruzolut.dev/blog/typescript-without-the-rewrite): J05N adopted TypeScript at contracts and package boundaries while existing JavaScript kept shipping through a measured, removable migration path. - [Tokens should name decisions](https://ruzolut.dev/blog/tokens-should-name-decisions): A token system became useful only when its names expressed maintained visual roles instead of preserving a palette as numbered aliases. - [A design system is a change-management system](https://ruzolut.dev/blog/a-design-system-is-a-change-management-system): J05N became useful when every shared decision included a route from existing behavior, evidence of adoption, and a planned end for the old path. - [A dialog is a focus contract](https://ruzolut.dev/blog/a-dialog-is-a-focus-contract): The reusable part of a modal was not its panel or backdrop but the temporary rules it established for naming, focus, dismissal, and return. - [Inventory before abstraction](https://ruzolut.dev/blog/inventory-before-abstraction): Repeated interface shapes became useful only after separating accidental variation, shared contracts, and behavior that belonged to a domain. - [The component library nobody adopted](https://ruzolut.dev/blog/the-component-library-nobody-adopted): A polished catalogue failed inside my own projects because it optimized the destination while ignoring every path from existing code. - [The universal JavaScript tax](https://ruzolut.dev/blog/the-universal-javascript-tax): Server-rendering React improved the first response while revealing the bundle, hydration, and ownership costs hidden by shared code. - [The health check that proved only a port was open](https://ruzolut.dev/blog/the-health-check-that-proved-only-a-port-was-open): An unusable preview passed every automated gate because the check answered an operational question nobody reviewing the change had asked. - [Next.js made universal JavaScript feel inevitable](https://ruzolut.dev/blog/next-js-made-universal-javascript-feel-inevitable): The first Next.js release made server-rendered React look ordinary, which was precisely why its remaining runtime boundaries deserved scrutiny. - [Expiry is part of provisioning](https://ruzolut.dev/blog/expiry-is-part-of-provisioning): R7K1 gave every temporary environment an owner, deadline, resource graph, revocation order, and resumable removal path before creating it. - [The preview must not know production](https://ruzolut.dev/blog/the-preview-must-not-know-production): R7K1 treated branch code as unaccepted code, using synthetic data, scoped credentials, separate networks, and generated identities instead of production copies. - [The manifest was more stable than the branch](https://ruzolut.dev/blog/the-manifest-was-more-stable-than-the-branch): R7K1 stopped caching by branch and built an artifact identity from source, lockfile, recipe, base image, and declared configuration. - [Every branch deserved a URL](https://ruzolut.dev/blog/every-branch-deserved-a-url): Building disposable preview environments made review concrete and turned duplicated build work into a solvable systems problem. - [Docker packaged the app, not the lifecycle](https://ruzolut.dev/blog/docker-packaged-the-app-not-the-lifecycle): R7K1 could start a container from a repeatable image and still lacked scheduling, routing, readiness, isolation, expiry, and evidence. - [The shell script did not know where it failed](https://ruzolut.dev/blog/the-shell-script-did-not-know-where-it-failed): R7K1 replaced an optimistic preview script with durable, idempotent lifecycle transitions that could resume after uncertain outcomes. - [A branch is a moving name](https://ruzolut.dev/blog/a-branch-is-a-moving-name): R7K1 stopped treating a Git branch as a preview identity and separated source revision, declared inputs, artifact, environment, and route. - [HTTPS was the easy part](https://ruzolut.dev/blog/https-was-the-easy-part): Automating certificates for a publishing system exposed the larger migration hiding behind one change of scheme. - [A service worker without an offline promise](https://ruzolut.dev/blog/a-service-worker-without-an-offline-promise): M31V cached articles enthusiastically, then removed the service worker when it could not explain freshness, coverage, updates, or recovery to readers. - [The redirect map is content](https://ruzolut.dev/blog/the-redirect-map-is-content): M31V treated old URLs as maintained public identifiers, giving redirects source files, validation, preview, release identity, and retirement policy. - [Atomic deployment in four boring steps](https://ruzolut.dev/blog/atomic-deployment-in-four-boring-steps): M31V separated build, upload, verification, and activation so an interrupted transfer could never become the public release. - [Preview the artifact you will publish](https://ruzolut.dev/blog/preview-the-artifact-you-will-publish): M31V stopped approving an editor approximation and began reviewing the exact immutable build proposed for activation. - [ES2015 made old async habits visible](https://ruzolut.dev/blog/es2015-made-old-async-habits-visible): Promises, modules, and block scoping improved M31V only after the build stopped hiding cancellation, cleanup, and error ownership inside callbacks. - [HTTP/2 did not fix the image](https://ruzolut.dev/blog/http-2-did-not-fix-the-image): Multiplexing changed M31V’s request economics in 2015, but a large photograph still cost transfer, decoding, memory, and attention. - [One source for page, feed, and archive](https://ruzolut.dev/blog/one-source-for-page-feed-and-archive): M31V stopped parsing articles separately for each output and built one normalized content graph that every publication surface consumed. - [Validation should speak to the file](https://ruzolut.dev/blog/validation-should-speak-to-the-file): M31V’s build stopped handing writers stack traces and began reporting source, field, consequence, and correction in editorial language. - [A CMS was too much and FTP was too little](https://ruzolut.dev/blog/a-cms-was-too-much-and-ftp-was-too-little): M31V needed editorial validation, preview, and atomic releases without inheriting a general CMS or trusting mutable uploads as a publishing protocol. - [The receipt made retry safe](https://ruzolut.dev/blog/the-receipt-made-retry-safe): X8B6 completed its offline protocol by making every accepted operation produce a durable, queryable result that survived lost responses and repeated delivery. - [Containers changed what I could reproduce](https://ruzolut.dev/blog/containers-changed-what-i-could-reproduce): Docker’s emerging image model gave X8B6 a repeatable server and database fixture, while leaving readiness, durable data, security, and lifecycle as application work. - [Conflict messages should name the work](https://ruzolut.dev/blog/conflict-messages-should-name-the-work): X8B6 replaced version numbers and overwrite buttons with explanations of the local action, confirmed state, and intervening change. - [A timeout is not a failed action](https://ruzolut.dev/blog/a-timeout-is-not-a-failed-action): X8B6’s server committed an inventory adjustment after the browser stopped waiting, turning a familiar error state into outcome unknown. - [The cache was the product](https://ruzolut.dev/blog/the-cache-was-the-product): Building an offline field ledger revealed that dependable local work requires an operation log, reconciliation, and visible uncertainty. - [Last write wins by losing](https://ruzolut.dev/blog/last-write-wins-by-losing): A deterministic timestamp merge made X8B6 converge by silently erasing one legitimate inventory action, proving that conflict resolution needed domain verbs. - [IndexedDB migrations carry unsent work](https://ruzolut.dev/blog/indexeddb-migrations-carry-unsent-work): X8B6’s browser database could contain the only copy of an inventory action, so a schema upgrade had to behave like a deployment rather than a disposable cache reset. - [TypeScript 1.0 and the boundary I actually needed](https://ruzolut.dev/blog/typescript-1-0-and-the-boundary-i-actually-needed): TypeScript’s 1.0 release tempted a rewrite, but X8B6 gained more by typing operation and receipt boundaries before converting every line of JavaScript. - [The operation came before the record](https://ruzolut.dev/blog/the-operation-came-before-the-record): X8B6 stopped treating an editable inventory row as the truth and began preserving immutable actions from which local and shared projections could be explained. - [Local storage is not offline](https://ruzolut.dev/blog/local-storage-is-not-offline): X8B6 could retain a form in the browser and still lose the meaning of an unconfirmed inventory change, forcing offline work to become a protocol. - [React was interesting; the state model mattered more](https://ruzolut.dev/blog/react-was-interesting-the-state-model-mattered-more): React’s 2013 release made one-way rendering tangible, but T04P improved only after its transport, continuity, and freshness states were made explicit outside the view library. - [A performance budget before I knew the name](https://ruzolut.dev/blog/a-performance-budget-before-i-knew-the-name): A slow phone and an expensive connection turned page weight from a technical afterthought into a product constraint. - [A small source simulator taught me more than production-like data](https://ruzolut.dev/blog/a-small-source-simulator-taught-me-more-than-production-like-data): A deterministic feed generator made delayed, duplicated, skipped, and out-of-order events ordinary enough to design T04P around them. - [The browser tab that ran all day](https://ruzolut.dev/blog/the-browser-tab-that-ran-all-day): T04P behaved well for ten minutes and badly by the sixth hour, exposing timer drift, leaked listeners, unbounded history, and assumptions about browser attention. - [Notes are observations, not chat](https://ruzolut.dev/blog/notes-are-observations-not-chat): T04P’s short human updates became more trustworthy when they gained attribution, subject, observation time, and a deliberate relationship to machine evidence. - [I removed the green light](https://ruzolut.dev/blog/i-removed-the-green-light): A pulsing status dot made T04P feel live while hiding which part of the system it described, so the interface was rebuilt around scoped evidence. - [Reconnect is a data operation](https://ruzolut.dev/blog/reconnect-is-a-data-operation): Restoring a Socket.IO connection did not restore a trustworthy dashboard; the application needed to prove continuity or replace local state. - [Two clocks and one stale number](https://ruzolut.dev/blog/two-clocks-and-one-stale-number): A recently delivered counter update was already old, so T04P learned to preserve when an observation happened and when the system received it. - [The dashboard that lied](https://ruzolut.dev/blog/the-dashboard-that-lied): A live operations screen looked healthy while its data stood still, forcing freshness to become explicit product state. - [A socket is not a source](https://ruzolut.dev/blog/a-socket-is-not-a-source): T04P’s browser connection stayed healthy while one upstream feed stopped, proving that transport and knowledge needed separate state. - [Shipping a static site without mixing releases](https://ruzolut.dev/blog/shipping-a-static-site-without-mixing-releases): A failed upload left C62Y serving new HTML with old assets, so even a small static catalogue learned to build immutable releases and activate them once. - [A print stylesheet is a product decision](https://ruzolut.dev/blog/a-print-stylesheet-is-a-product-decision): Printing C62Y exposed which screen controls were merely controls, which links needed destinations, and which content relationships had to survive another medium. - [What happened when JavaScript did not](https://ruzolut.dev/blog/what-happened-when-javascript-did-not): A compact menu hid the catalogue before its control was ready, turning progressive enhancement from a preference into an execution-order requirement. - [The breakpoint belonged to the sentence](https://ruzolut.dev/blog/the-breakpoint-belonged-to-the-sentence): Device widths gave me convenient numbers; content pressure revealed when the catalogue actually needed a different layout rule. - [The page is not 960 pixels wide](https://ruzolut.dev/blog/the-page-is-not-960-pixels-wide): Learning to design rules instead of screenshots while rebuilding a fixed-width catalogue for an unpredictable web. - [Images were the bandwidth](https://ruzolut.dev/blog/images-were-the-bandwidth): CSS made product photographs fit a phone while the network still delivered the desktop originals, forcing image cost into the design itself. - [The table refused to become cards](https://ruzolut.dev/blog/the-table-refused-to-become-cards): Turning a product comparison into stacked cards made the narrow layout prettier and the comparison task dramatically worse. - [One navigation, not a mobile copy](https://ruzolut.dev/blog/one-navigation-not-a-mobile-copy): The catalogue needed one semantic set of destinations that could change presentation without becoming a second, reduced mobile information architecture. - [Content before chrome](https://ruzolut.dev/blog/content-before-chrome): Responsive layout became much easier after the catalogue stopped treating every field as equally important and every empty value as the same kind of absence. - [The comp is not the interface](https://ruzolut.dev/blog/the-comp-is-not-the-interface): A polished desktop composition taught me almost nothing about how the catalogue should behave when content, width, input, and loading conditions changed. ## Optional - [GitHub](https://github.com/ruzolut): Public code and repository activity. - [X](https://x.com/ruzolut): Social profile for ruzolut.