Skip to content

English · Español

03 — Residual risk and off-ramps

🇪🇸 No todo se arregla. Hay riesgos que aceptas conscientemente y huecos que dejas abiertos a propósito. Esta fase los pone por escrito para que la decisión sea explícita, no por descuido.

The shape of residual risk

After 40 phases, the system has three kinds of "loose ends":

  1. Closed. A threat was identified, a mitigation was implemented, a test verifies it. No further action.
  2. Accepted with rationale. A threat is real, but mitigating it costs more than it's worth at this scope. The rationale is written down.
  3. Punted. A threat is real, mitigation is non-trivial, and this project isn't the right place to solve it. The threat becomes an entry in the off-ramp list — a problem for the next project.

The goal of Phase 40 lab 00 is to put every open item in security/THREATS.md into exactly one of these three states. Zero ambiguity.

What "accepted with rationale" looks like

Bad:

Threat T-014: Supply chain compromise via a malicious PyPI package. Status: Accepted.

Good:

Threat T-014: Supply chain compromise via a malicious PyPI package. Status: Accepted with rationale. Rationale: (1) The project runs single-tenant on Borja's local machine and a single ephemeral cloud instance. No multi-tenant attack surface. (2) pip-audit runs in CI and on a weekly cron; lockfile is pinned to specific hashes. (3) uv lockfile enforces hash verification. (4) Adopting Sigstore-signed wheels was considered but adds toolchain complexity that does not bound any real attack vector at our scale. Reassess if: the project gains a public-facing endpoint OR is adopted by multiple learners with write access. Reviewed: 2026-05-23. Next review: 2026-11-23 (6 months).

The rationale must name: - Why the threat doesn't apply now. - The mitigations in force. - The trigger that would force a re-assessment. - A review date.

The trigger is the key

"Accepted" without a trigger means "ignored forever." That's not a decision; it's deferred indifference.

Good triggers: - "Reassess if we add public-facing traffic." - "Reassess if we onboard a second learner with write access." - "Reassess at next phase that touches X." - "Reassess if the model size exceeds Y."

If you can't write a trigger, the right state is not accepted — it's punted or closed.

What "punted" looks like

Some threats are real but require a different project shape to address properly:

  • "Adversarial prompts crafted to extract the system prompt from the agent."
  • "Side-channel timing attacks on the model inference path."
  • "Data poisoning of the training corpus by a malicious contributor."

These are real attacks on real LLM systems. They're out of scope for a single-learner, single-CPU, English-verb tutor.

A punted threat goes into two documents:

  1. security/THREATS.md — marked as [PUNTED: see READING_LIST.md #N].
  2. READING_LIST.md — listed as an off-ramp, with a recommended resource.

This way, the threat isn't lost; it's repositioned as a learning goal for the next project.

Off-ramps: connecting Phase 40 to the next project

An off-ramp is a deliberate exit from lynx-cortex to a next, different problem. They live in READING_LIST.md under a final section called "Off-ramps: what to do next."

Format each off-ramp:

Off-ramp 1: Scale up to a real LLM. What: Move from the 103,680-param Mini-GPT to a 1B-7B parameter LLM, on a GPU. Why now: The plumbing (corpus → tokenizer → train → eval → serve) is built. The bottleneck shifts to GPU economics, distributed training, and dataset curation. First step: Replicate the Llama 2 7B training run on a single A100 using nanotron or gpt-neox. Allocate ~$200 of cloud time. Recommended resource: Karpathy's "Build GPT" video + nanoGPT repo for the small case; HuggingFace's transformers training scripts for the larger case. Estimated time: 4-8 weeks part-time.

Five off-ramps is the right number. Fewer means you didn't think broadly enough; more means you're not picking one.

The honest test

For each accepted or punted threat: ask "would I tell a security reviewer this with a straight face?"

  • If yes, the rationale is good enough.
  • If no, the rationale is hand-waving. Rewrite.

This isn't a security audit. It's a hygiene check on Borja's own honesty. The threat doc is supposed to reflect reality at Phase 40, not to be a wishlist.

When you'd revisit this file

The threat document and off-ramp list are not static. They should be re-read:

  • At the start of the next project (does any off-ramp become "actively pursued"?).
  • At the review date of each "accepted with rationale" threat.
  • If lynx-cortex is ever adopted by another learner (the multi-tenant trigger fires for several threats).

For this phase: write them, link them, commit them, and stop. Future-Borja will re-read.

What this file does NOT cover

  • The specific threats in security/THREATS.md. Lab 00 walks each one.
  • The specific off-ramps for this project. Lab 02 produces the reading list.
  • How to do a security audit at scale. Out of scope; pointers in the reading list.

Next: ../lab/00-hardening-pass.md