The Landing Pipeline

Project10 min · Scope → Isolate → Supervise → Land · Updated 2026-09-11

You end this lesson with: fleet/landing-pipeline.md — one issue taken to a merged change with the evidence each gate produced.

Chapters

  1. Brief
    01
  2. Steps
    02
  3. Acceptance
    03
  4. Rubric
    04
  5. Key Takeaways
    05
  6. What You Have Now
    06

Project 04. The Landing Pipeline

Support has filed the same complaint fourteen times this month: a customer edits their shipping address twice within a minute (typical mobile pattern — tap save, notice a typo, tap save again), gets two identical confirmation emails, and about a third of the time the address that sticks is the first one they typed, not the corrected one. Nobody has a repro, and it has sat in the backlog long enough that support triage finally wrote it up properly. You will take this one issue through every stage this module built: a task spec an agent can execute, an isolated run, a headless gate verdict, an evidence bundle, a trust-tiered review record, and a merge through the queue. You hand over fleet/landing-pipeline.md — one issue taken to a merged change with the evidence each gate produced.

Brief

The issue, as support triage wrote it:

BUG-482 — Duplicate "address updated" email on rapid re-edit, occasional revert to first value. Reported 14 times in 30 days. A customer who edits their shipping address twice inside 60 seconds gets two identical confirmation emails, and roughly a third of those double-edits show the saved address matching the first edit instead of the second, with no error shown to the customer. No reports of data loss beyond the address field. Priority P2. Owner: support triage. No repro attached; the timing suggests two nearly-simultaneous requests, not a single bad input.

Illustrative composite. BUG-482, its 14 reports and the pipeline artifacts below are composite for teaching; your own submission uses a real issue from your own backlog, run through the same six stages.

Constraints carried from the earlier lessons in this module. From the task-sizing rule: the fix must be scoped to one agent-sized task, not a redesign of the address-update flow. From the containment tier and permission policy: the agent may read and write application code and tests; it may not touch production data or send real email. From the review-policy lesson: a bug fix touching a shared handler with no prior incident record starts in the fast-review tier, not auto-merge. From the gate lesson: "tests pass" is not evidence on its own — the gate must produce a machine-readable verdict, not a narrative.

Steps

  1. Write the task spec. One file, one goal, the files the agent may touch, the interfaces it must not invent, the done test, and a ceiling. A filled example:

    markdown
    # Task: BUG-482 duplicate email / occasional revert on rapid re-edit
    
    Goal: a second address-update request within 60 seconds of the first,
    for the same customer, must not send a second confirmation email and
    must not let an in-flight first request overwrite a completed second
    request.
    
    Files this task may touch: `address/update-handler.ts`,
    `address/update-handler.test.ts`. No other file.
    
    Must not invent: a new email-template system, a new queue, a new
    database table. Use the existing `emailQueue` and the existing
    `addresses` row's own `updated_at` column.
    
    Done test: two requests fired concurrently (`Promise.all`) against the
    same customer within 60 seconds produce exactly one queued email and
    leave the address at whichever value was submitted last by wall-clock
    time, deterministically, across 50 repeated runs.
    
    Ceiling: one context window, one sitting. If the fix needs to touch a
    third file, stop and report why instead of expanding scope.
    
  2. Dispatch into an isolated run. The agent claims the task (a compare-and-swap on the task row, so a retried dispatch never double-claims it), gets its own worktree, its own port range and its own scratch database per the isolation lessons, and works inside that boundary only. The run record that comes out of this step is short: branch name, worktree path, container or process id, start and end timestamps.

  3. Run the headless gate. The gate is not "the agent says it ran the tests." It is a separate, unattended process that runs the done test from the task spec against the agent's diff and emits a verdict file the agent cannot edit:

    json
    {
      "task": "BUG-482",
      "branch": "fix/bug-482-address-race",
      "commit": "a91f2c3",
      "checks": [
        { "name": "existing-suite", "result": "pass", "durationMs": 4210 },
        { "name": "concurrent-double-edit (50 runs)", "result": "pass", "durationMs": 3860 },
        { "name": "lint", "result": "pass", "durationMs": 900 }
      ],
      "verdict": "pass",
      "exitCode": 0
    }
    
  4. Assemble the evidence bundle. The bundle is the diff, the gate's verdict file, and the done test's own output, bundled together. It is explicitly not the agent's own prose summary of what it did; a bundle whose only content is a paragraph claiming success fails review before a human ever reads the diff. A minimal bundle manifest:

    markdown
    ## Evidence bundle — BUG-482
    
    - Diff: fix/bug-482-address-race @ a91f2c3 (call for `updateAddress` now
      does a CAS on `addresses.version`, second concurrent write loses the
      race cleanly instead of racing the email send)
    - Gate verdict: pass (see gate/BUG-482-a91f2c3.json)
    - Concurrent-double-edit test: 50/50 runs, exactly one email queued,
      final address matches the later wall-clock write every run
    - What was NOT changed: no schema migration, no new queue, no change
      to any other handler
    
  5. Route through trust-tiered review. Classify the change: a bug fix, one file plus its test, no schema change, no auth or payment code touched, so it lands in the fast-review tier from the review-policy lesson, not auto-merge (it touches a shared handler) and not full review (it carries none of the risk markers that require it). A filled review record:

    markdown
    ## Review record — BUG-482
    
    Tier: fast review. Reviewer: [name]. Time spent: 6 minutes.
    Read: the CAS diff, the concurrent test, the verdict file. Did not
    re-run the suite locally; trusted the gate's verdict for that.
    Decision: approve. Note: the CAS approach generalises to the other
    two handlers with the same race shape; filed as a follow-up task,
    not expanded into this one.
    
  6. Merge through the queue. BUG-482's branch touches one file no other open branch touches this week, so its conflict-budget slot is unclaimed and it merges as soon as it reaches the front of the queue: rebase onto current main, gate re-runs against the rebased result, fast-forward. The merge log entry:

    json
    { "branch": "fix/bug-482-address-race", "mergedAt": "2026-09-14T10:02Z", "gateRerun": "pass", "mergeCommit": "e5d0a1b" }
    

The picture below is the same six steps as one path, with the one rule that fails a submission marked where it would catch it.

diagram
drawing
Evidence has to survive every arrow; a bundle that skips the gate step and jumps straight from diff to review carries no proof at all.

Acceptance

  • fleet/landing-pipeline.md contains the task spec with goal, allowed files, forbidden inventions, done test and ceiling, all specific enough that a different agent could execute it unchanged.
  • The run record names the isolation boundary (worktree, port range, scratch database) the agent actually worked inside, not just "ran locally."
  • The gate verdict is a separate artifact from the agent's diff, with a pass/fail per check and a real exit code, produced by a process the agent's own session did not control.
  • The evidence bundle includes the diff, the verdict file and the done test's own output; a bundle whose only content is the agent's narrative summary is marked fail, not weak.
  • The review record states the trust tier, the time spent, what was and was not independently re-verified, and the decision.
  • The merge log entry shows a rebase and a gate re-run against the rebased result, not a merge commit carrying a stale verdict.

Rubric

CriterionWeakStrong
Task spec is agent-sizedA restatement of the ticket with no file scope or done testGoal, allowed files, forbidden inventions, a done test that runs under real concurrency, and a ceiling
Isolation is named, not assumed"Ran in a branch"Worktree path, port range and scratch database stated, matching the containment tier from module 2
Gate verdict is real evidenceA checkmark with no artifact, or "tests passed" in proseA verdict file with per-check results and an exit code, produced outside the agent's own session
Evidence bundle is completeThe agent's own summary of what it did, nothing elseDiff, verdict, done-test output and an explicit "what was not changed" line
Review matches its tierNo tier named, or a tier assigned without a reasonTier stated with the risk markers that set it, time spent, and what the reviewer did and did not re-check

A submission scores no higher than weak on "evidence bundle is complete" if the only artifact attached is the agent's own account of its work; this is a hard fail on its own, independent of how the other rows score.

Key Takeaways

  • One issue, six artifacts: task spec, run record, gate verdict, evidence bundle, review record, merge log.
  • A gate verdict has to come from outside the agent's own session to count as evidence.
  • The agent's own summary is never sufficient evidence on its own, however accurate it happens to be.
  • Trust tier follows the change's risk markers, not the size of the fix or how confident the diff looks.
  • The merge step re-gates against a rebase; a stale verdict from before the rebase proves nothing.

What You Have Now

fleet/landing-pipeline.md — one issue taken to a merged change with the evidence each gate produced. It is the first complete run through every artifact this module defined: the task-sizing discipline from earlier in the course, the isolation boundary from module 2, the trust tiers and the headless gate from the two lessons just before this project, and the reconciliation order from the lesson this project follows directly. Run a second issue through the same six stages before moving on; the first run tends to reveal which artifact your own team is tempted to skip.


NO-QUIZ

Quiz coming to this lesson

This lesson doesn't have a graded quiz yet — completion is still tracked, just not verified against questions.

Reading is free — your progress isn't being saved

Nothing you did on this page is recorded. Paid students get saved progress and verified completions, recorded quiz answers, the spaced-repetition review queue, labs, and a certificate for each course they finish.

30-day money-back guarantee. One-time payment — lifetime access and updates.