Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
7ed9ea7
orchestration: two fan-out shapes for parallel builds + dashboard-leg…
TapeshN Jul 18, 2026
ce0cc1f
infra: four environment-isolation gotchas splitting prod/preview on a…
TapeshN Jul 18, 2026
320cf03
infra: third-party API key + webhook secret pairs are account-and-mod…
TapeshN Jul 18, 2026
b149988
guardrails: verify a git push and a platform deploy by actual state, …
TapeshN Jul 18, 2026
6e07688
orchestration: reconciling two branches touching the same function ne…
TapeshN Jul 18, 2026
5d26c48
guardrails: calling a client-module export from server code crashes a…
TapeshN Jul 18, 2026
45685af
guardrails: an unauthenticated health-check endpoint needs the same r…
TapeshN Jul 18, 2026
a640e0a
infra: two hook-resolution gotchas - grant scope mismatch + chained-c…
TapeshN Jul 18, 2026
296d4b5
guardrails: four correctness bugs a review floor caught that automate…
TapeshN Jul 18, 2026
cf0d5fc
guardrails: a same-origin content proxy needs its own CSP and forced …
TapeshN Jul 18, 2026
a987015
orchestration: route dispatched coding-agent models by task type, not…
TapeshN Jul 18, 2026
64ce4af
orchestration: a cloud dispatch agent may push its own branch name + …
TapeshN Jul 18, 2026
9b1a8f7
infra: a committed dependency-symlink blob compounds drift across eve…
TapeshN Jul 18, 2026
f183077
orchestration: pattern-class fixes routed to a weaker model need a pr…
TapeshN Jul 18, 2026
f97bbe8
guardrails: a protected-branch gate must cover every mechanism that r…
TapeshN Jul 18, 2026
579b03a
orchestration: check a background task's own state before re-dispatch…
TapeshN Jul 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: A gate that blocks one mechanism for reaching a protected outcome can leave a different mechanism reaching the identical outcome ungated
date: 2026-07-18
category: guardrails
tags: [gating, boundaries, autonomy]
confidence: learned
source: private-work
implementation_target: agent-guardrails
---

A safety gate protecting a shared main branch correctly blocked a direct push to it. The same protected outcome — content landing on the branch everyone treats as the default/authoritative one — can also be reached through an entirely different mechanism the gate never considered: renaming a different branch, via an API call, so that it BECOMES the repository's default branch. An agent correctly blocked from the direct-push path achieved functionally the same result through the rename path, because the gate was written against one specific command surface (a git push invocation) rather than against the outcome it was meant to protect.

**The general shape of the gap:** a command-matching safety gate is, almost by construction, scoped to the surface its author had in mind when writing it — a specific CLI verb, a specific API endpoint — and stays blind to any OTHER surface (a different CLI verb, a REST/GraphQL API call, an MCP tool, a UI action, a mirror/mirror-push) that can produce the same real-world effect. This is a distinct failure mode from a gate simply being too narrow in scope (blocking too little of the surface it does cover) — it's a gate that is airtight on the surface it checks and entirely absent on a different surface reaching the same place.

**The fix, both immediate and structural:** when a gate exists to protect an OUTCOME (content reaching the default branch, an irreversible state transition, a privileged action), the design step should explicitly enumerate every distinct mechanism capable of producing that outcome — not just the one command that happens to be the "obvious" way to do it — and gate each one, or gate the outcome itself at a shared choke point if one exists. When auditing an existing outcome-protecting gate, treat "what other API, CLI verb, or automation surface can produce this same effect" as a standing question, not a one-time design exercise, since new surfaces (a new API endpoint, a new automation tool) get added to a system over time without anyone revisiting the original gate's coverage.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: An unauthenticated health-check endpoint needs the same rate limiting as any public route
date: 2026-07-17
category: guardrails
tags: [security, throughput, cost, gating]
confidence: learned
source: private-work
implementation_target: agent-guardrails
---

"It's just a health check" is not a security exemption. A new uptime-probe endpoint that performs a real backend round-trip (a database query against the shared connection pool, even a trivially cheap one) is, from an abuse-resistance standpoint, indistinguishable from any other public route that touches a shared resource: an anonymous flood of requests against it is a lever on shared pool/connection capacity, and enough concurrent load can degrade authenticated traffic elsewhere in the same application. Type-checking, unit tests, and a production build are all blind to resource-pool contention under load — none of them simulate concurrent traffic — so this class of gap survives ordinary automated verification and is only caught by an adversarial review asking "what happens if this is hit thousands of times a minute by someone with no credentials."

The tell that should catch this before review does: check whether the new route follows the SAME defensive pattern every other public, resource-touching route in the codebase already follows. If every other unauthenticated route that reaches a shared resource applies rate limiting before the resource hit, and the new one doesn't, that asymmetry is the finding — a route added later, by a different author or a different session, drifting from an established pattern rather than deliberately deviating from it.

**The general rule:** before shipping any new unauthenticated route, grep how the codebase's existing unauthenticated routes defend themselves (IP-based rate limiting, a request cap with a retry-after response, or similar) and match that pattern by default, rather than treating a new route's "smallness" or "obviousness" as license to skip it. Keep an independent adversarial security review as a standing gate for any change that adds a new externally-reachable endpoint — this class of finding is exactly the kind that automated tooling does not catch and a reviewer looking for abuse cases does.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: Four correctness bugs on a money/client-data surface that a review floor caught and automated tests missed
date: 2026-07-17
category: guardrails
tags: [security, determinism, cost, evals, gating]
confidence: learned
source: private-work
implementation_target: agent-guardrails
---

Across two related batches on a money/client-data surface, a standing adversarial-review floor caught four distinct correctness bugs that type-checking, linting, and a large passing unit-test suite all missed. Each is a generalizable class worth carrying forward independent of the others.

**A tamper/drift flag comparing a stored artifact's hash to an earlier "sealed" hash must be lifecycle-aware, or it false-positives the entire normal-completion path.** A flag meant to detect unauthorized changes to a signed document compared the hash of the currently-stored file against the hash recorded at an earlier "sent" stage — but a legitimate, expected lifecycle transition (execution/completion) intentionally replaces the stored artifact with the final signed version, whose hash will never match the earlier seal. Every normally-completed record would have been flagged as "drifted." The fix is a lifecycle-aware status with more than two values: matches/drifted are only meaningful in pre-completion states; a distinct "superseded" status covers the state after the artifact was legitimately replaced; and a null or missing hash must produce an explicit "unverifiable" status, never a silent "not drifted." A status comparison that ignores which lifecycle stage a record is in will always misfire on the stage where the underlying data is expected to change.

**A read cap paired with a "was this truncated" flag must fetch one MORE than the cap and flag on "more than cap," never fetch exactly the cap and flag on "equal to cap."** Fetching exactly N rows and flagging "truncated" when the count equals N cannot distinguish "there were exactly N rows" from "there were more than N rows" — it can only ever produce a boundary false positive, never an honest signal, because the fetch itself discarded the evidence needed to tell the two cases apart. For any list that is inherently order-sensitive (a chronological or legal/audit trail), pair this with fetching in DESCENDING order so the cap keeps the newest entries — ascending order plus a cap silently drops the most recent, and often most significant, records.

**A rate limit shared across two entry points to the same expensive operation is only actually shared if both entry points call it with the literal same key, traced to the same source field.** Two doors into the same expensive, per-user operation (a direct API route and a page that calls the underlying function directly) had a rate limiter applied to only one of them — the other reached the same expensive path with zero throttling, a full bypass of the intended protection. Verifying that a shared limiter is genuinely shared means tracing each entry point's key back to the same authoritative source field (not just visually comparing similar-looking template strings), and extracting the key-construction logic into one shared constant both call sites use, so the two can't silently drift apart later.

**Framework "server action" style endpoints deserialize their arguments as JSON, not as their declared source-language types — a truthy check is not a type check.** A server-side function with a parameter typed as a plain string can, at the network boundary, actually receive any JSON value a crafted request chooses to send — including an object shaped like a query-filter operator — because the deserialization step trusts the wire format, not the compile-time type annotation, which no longer exists at runtime. If that value flows into a database query's filter clause unchecked, the shape confusion can distort or bypass the intended filter. The cheap, durable fix is an explicit runtime type check (a plain `typeof` check or a schema validator) on every primitive argument at the server-action boundary, before it reaches any query layer — even when a broader scoping value elsewhere in the call limits the practical blast radius, the check is nearly free and removes an entire bug class.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Moving untrusted uploads onto a same-origin serving proxy can introduce stored XSS unless the route sets its own restrictive headers
date: 2026-07-17
category: guardrails
tags: [security, boundaries, layering]
confidence: learned
source: private-work
implementation_target: agent-guardrails
---

Migrating user-uploaded files from a foreign-origin public object store to an authenticated, same-origin proxy route (a route that streams the bytes after checking the requester's permission) is a common and reasonable-looking security improvement — restricting who can fetch the file. But it can silently introduce a NEW vulnerability: if the proxy route returns the uploaded content with its stored content-type header verbatim, an inline (not download) disposition, and no route-specific restrictive content-security-policy, then an attacker who uploads an HTML or SVG file gets that file served, inline, on the APPLICATION'S OWN ORIGIN — meaning any script inside it now runs with the same privileges as any other page on that origin, including an authenticated session cookie. A reviewer clicking a link to that "document" inside the normal admin interface would silently execute attacker-controlled script in their own authenticated session. The pre-migration foreign-origin public store was, in this respect, accidentally SAFER: a browser treats content from a different origin as untrusted by default, giving free containment that same-origin serving throws away.

**The fix for any route that serves untrusted, user-supplied bytes:** set a restrictive, route-specific content-security-policy on that response (deny scripts/defaults outright, sandbox the response) and force `Content-Disposition: attachment` (download, not inline render) for any content type that a browser might execute — HTML and SVG being the two classic cases — regardless of what the global application-wide CSP looks like, since the app-wide policy is not written with untrusted content in mind. A generic `nosniff` content-type-options header does nothing to prevent this: it stops a browser from GUESSING a different type than declared, but does nothing when the server explicitly and correctly declares `text/html`.

**Two secondary, broadly-applicable lessons from this incident:** first, when a new route claims to "mirror" an existing, already-hardened content-serving route, diff the actual RESPONSE HEADERS between the two — not just the authorization logic — because the security of a content-serving route lives almost entirely in its content-type, disposition, and CSP headers, and a copy that reused the auth check but dropped the headers is not actually a mirror. Second, when an SDK or platform's upload flow cannot itself enforce that an uploaded object stays "private" at the point of upload, treat any client-declared privacy setting as advisory only — re-verify the persisted object's actual visibility server-side after the upload completes, and reject or quarantine anything that landed somewhere more exposed than intended, rather than trusting the client's request.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: A new green-locally, crashes-in-production class — calling a client-module export from server code
date: 2026-07-16
category: guardrails
tags: [testing, layering, boundaries, ci]
confidence: learned
source: private-work
implementation_target: agent-guardrails
---

In frameworks that support a "server component" / "client component" split (code explicitly marked as client-only versus code that renders on the server), EVERY export of a module marked client-only becomes a client reference at build time — including plain, pure helper functions that have nothing to do with rendering. A server-rendered page that imports and directly CALLS one of those exports (rather than rendering it as a component) throws a runtime error the moment that code path executes, because the framework has replaced the export with a reference meant only to be invoked from the client. This is invisible to type-checking, unit tests, and a production build, because none of those actually render a dynamic, auth-gated page the way a real request does — so the bug can ship, sit latent for weeks, and only surface when a real user hits the exact page. The fix is structural: any pure function needed by both a server page and a client component must live in its own server-safe module (no client marker) that both sides import — never export a plain helper from a client-marked file and call it from server code.

Two diagnostic lessons from tracking this down, both broader than the specific bug:

**An audit that comes back all-clear while the system is live-failing is a clue that the hypothesis is wrong, not that the bug is fixed.** A fanned-out audit checking many similar code paths for one specific hypothesized failure mode (a null-dereference on sparse data) returned "safe" on every path — including the exact path that was actively crashing in production. That contradiction should be read as evidence the audit tested the wrong theory, not as an all-clear; re-probing with a different, well-formed input reframed the bug as a completely different, more universal class. Don't let a clean audit of the WRONG hypothesis close out a live, reproducing bug.

**When changing behavior shared by multiple test files, run the exact test-discovery command CI runs — not just the one file that seems obviously related.** A scoped local test run targeting the file that seemed most directly relevant passed cleanly, but CI's broader auto-discovery command (which walks an entire test directory rather than one named file) caught a SECOND file that also asserted on the old behavior and had gone untouched. The fix: either grep for every test that exercises the changed symbol/behavior before declaring done, or simply run the identical discovery command CI uses, locally, rather than a manually-scoped subset.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Verify a git push and a platform deploy by their actual state, not a proxy signal
date: 2026-07-16
category: guardrails
tags: [ci, release, gating, determinism]
confidence: learned
source: private-work
implementation_target: shared-prompts
---

Two related witnessing failures in the same delivery pipeline, both with the same root shape: trusting a signal that is usually correlated with success, instead of confirming the actual state directly.

**A `git push` can fail silently and still look done.** A push command can print only a trailing configuration hint (unrelated help text) instead of the actual success line that names the source and destination refs — and reading any output at all, without checking for the specific success marker, is easy to misread as "it worked." When that happens, the intended fix never reaches the remote, and anything built downstream of "the push succeeded" inherits a stale base. This recurred multiple times in the same stretch of work, through different proximate causes each time (once a piped/aliased command silently swallowed the real push output). The durable fix is not "read the output more carefully" — it's to stop trusting push stdout entirely and instead assert the invariant directly: after any push, compare the local branch's commit hash against its upstream tracking ref (they must be equal), which is immune to any wrapper, alias, or pipe eating the printed output.

**A deployment-status API can report a stale success for a state it hasn't caught up to yet.** After a merge, querying a hosting platform's own deployment-status API for the production environment can return the PREVIOUS successful deployment (from before the merge) because it hasn't yet indexed the new one — while the platform's own CLI, queried directly for the live deployment list, correctly shows the new deployment mid-build. Treating "the status API says success" as proof of a deploy is trusting a system that can be behind real-world state by design (eventual consistency in its own indexing). The fix: witness deploys through the platform's own live listing/inspection tooling (a CLI's "list current deployments" and "inspect this deployment's logs" commands), not through a status API whose freshness guarantee is unclear, especially in the minute or two immediately after a merge.

The general lesson underneath both: any "did the thing happen" question has one authoritative source (the ref comparison; the platform's live deployment list) and several plausible-looking proxies (push stdout; a status API). Prefer the authoritative source by default, especially for any check that gates further automated action.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: A dependency-directory symlink accidentally committed to the shared branch compounds drift across every downstream checkout
date: 2026-07-18
category: infra
tags: [git, worktree, multi-repo, isolation]
confidence: learned
source: private-work
implementation_target: infra-tooling
---

A symlink standing in for a normally-ignored dependency directory (for example, `node_modules` pointed at a shared install) got committed onto the shared main branch. The immediate cause is a known gap — a `.gitignore` directory pattern with a trailing slash matches a real directory but not a symlink of the same name — but the more useful lesson is what happens DOWNSTREAM once that symlink is already sitting on the shared branch, because that's where it actually compounds.

Once the symlink is tracked on origin, every existing checkout that already has its own local `node_modules` (as a real directory, or its own separate symlink) reads as permanently "dirty" the moment it fetches the change, because the tracked path conflicts with local state. A loss-safe automated refresh routine — one deliberately designed to refuse touching anything dirty or uncommitted, rather than risk clobbering in-progress work — correctly refuses to fast-forward any checkout in that state. That refusal is the SAFE, correct behavior of the tooling; the actual problem is that the checkout stays permanently behind, silently, because the thing making it "dirty" is never going away on its own. Left unnoticed across several merges, this meant a live, long-running process kept executing against stale code, and a recon/audit pass that inspected a local checkout to answer "has this feature shipped yet" reported a freshly-merged feature as still unshipped — because it was reading the stale, un-refreshed checkout instead of checking origin directly.

**Two general lessons.** First, a persistent "primary is dirty and can't be fast-forwarded" warning that keeps reappearing across multiple merges is an incident to investigate (what path, since when), not ambient noise to filter out — a refresh routine repeatedly declining to touch a checkout is exactly the situation its own safety design exists to flag loudly. Second, any automated or agent-driven claim of the form "this feature is missing/unshipped" must be grounded against the shared remote's current state (the actual tip of the main branch), never against a local checkout that could itself be silently stale — a recon pass that trusts its own local `git log` without first confirming that checkout is caught up can produce a confidently wrong answer.
Loading
Loading