Level 8: Real Issue Contribution

Every level before this one was curated. You built Firecracker from a known-good baseline, you traced the vCPU run loop someone chose for you, you wired up an API action against a spec, and you added a test where the expected outcome was already understood. Level 8 ends the scaffolding. Here you do what a Firecracker maintainer does on a normal Tuesday: take a real, open GitHub issue from a stranger's bug report, reproduce it deterministically on your own checkout, root-cause it by walking the actual execution path, fix it with the smallest correct diff, write the test that fails before and passes after, run the full tools/devtool gate, and open a pull request that two AWS maintainers will read critically before either of them approves it.

There is no answer key. The issue may be mis-triaged. The "obvious" fix may break a snapshot compatibility guarantee or widen the seccomp surface. The reproduction may be racy because the bug is in the EventManager epoll loop, not in the code the reporter blamed. That is the job. This level is where the skills from Levels 1–7 stop being exercises and start being leverage — the only reason you can reproduce a virtio-block hang is that you traced one in Level 7, and the only reason you can read an API validation failure is that you walked the action channel in Level 3.

This curriculum will not hold your hand here least of all. It points you at the issue tracker, gives you the right questions, and makes you run every command. The output of this level is not a passing lab — it is a branch the maintainers would merge.


Learning Objectives

By the end of Level 8 you must be able to:

  1. Find a tractable open issue in firecracker-microvm/firecracker and judge honestly whether it is in scope for you right now — small surface, readable subsystem, no live PR.
  2. Build a deterministic reproducer that fails on your build of main and will pass after the fix — a config file, a curl --unix-socket sequence, or (ideally) a failing pytest integration test or a cargo test unit test.
  3. Separate the symptom (what the reporter saw) from the trigger conditions (the minimal set of inputs that actually provoke it), varying one factor at a time.
  4. Root-cause a defect by walking the execution path with rg — from the API endpoint or config field, through VmmAction, into the builder, the device, or the vCPU, down to the KVM ioctl if needed.
  5. Implement a minimal, correct fix that respects the threat model, the snapshot/API compatibility guarantees, and the minimal-device-model philosophy.
  6. Write the required test (integration test for new behavior; unit test for pure logic) that is red before your change and green after, and pass tools/devtool checkstyle + checkbuild --all + test.
  7. Author the CHANGELOG entry, commit with DCO sign-off (git commit -s), and open a PR whose description a reviewer can act on without asking you a single clarifying question.
  8. Map a given bug class onto the codebase areas you learned in Levels 3–7, so you know where to look before you start grepping.

The Issue Lifecycle (the loop everything below runs on)

Everything in this level — and the Capstone — is one loop. Internalize it; you will run it for the rest of your contributor life.

flowchart LR
    F[Find issue<br/>Type: Bug / good first issue] --> R[Reproduce<br/>fails on main, every run]
    R --> P[Execution path<br/>rg from symptom to cause]
    P --> C[Root cause<br/>the real defect, not the symptom]
    C --> X[Fix<br/>minimal, correct diff]
    X --> T[Test<br/>red before, green after]
    T --> G[Gate<br/>devtool checkstyle + checkbuild + test]
    G --> L[CHANGELOG + sign-off]
    L --> PR[PR<br/>links the issue, clear description]
    PR --> CI[CI + 2 maintainer reviews]
    CI -->|changes requested| X
    CI -->|2 approvals| M[A maintainer merges]

The non-obvious truth, and the thing that separates serious contributors from drive-by ones: the reproducer, not the fix, is the center of gravity. A bug you can reproduce on demand is a bug you can fix with confidence and prove you fixed. A bug you cannot reproduce is a guess dressed as a patch, and maintainers reject those. Lab 8.1 is entirely about building the reproducer; Lab 8.2 turns it into a merged-quality PR.

Note: "Reproduce on demand" has a precise meaning in a VMM. For a pure-logic bug (a parser, a validator, a rate-limiter calculation) it means a deterministic cargo test. For a behavioral bug (a device hang, a boot failure, a wrong API status code) it means a pytest integration test on a real microVM. For a timing/race bug it may mean a test that fails often, with the conditions pinned. All three count — fabricating a clean unit test for a race you cannot actually trigger does not.


How This Level Differs From Levels 1–7

Earlier levelsLevel 8
Curated labs with a known answerReal open issues, possibly mis-triaged
Execution path chosen for youYou locate the code from a symptom
Repro providedYou build the repro from a prose bug report
"Make it compile / make the test pass""Make two maintainers say yes"
No external stakesA real PR, real CI, real reviewers, real compatibility constraints
One subsystem at a timeThe bug spans whatever subsystems it spans

You bring the whole stack from prior levels:

You learned in……and use it in Level 8 to…
L3 — API & threadingtrace PUT /... → ParsedRequest → VmmAction → the VMM thread
L4 — vCPU & KVMreason about a wrong VM-exit handling or a CPUID/MSR defect
L5 — testingwrite the pytest integration test or cargo test that gates the fix
L6 — boot & memorydiagnose a boot-config, e820, or guest-memory bug
L7 — virtiodiagnose a virtqueue, MMIO-transport, or block/net/vsock bug

Mapping Bug Classes to the Codebase

Before you grep blindly, know where a class of bug lives. This table is your starting map; always rg to confirm the current path on your branch — the big crate merge moved most subsystems into src/vmm/src/.

Bug symptom (from the report)Likely subsystemWhere to start (rg/path)
API returns wrong status / accepts bad inputAPI server + request parsing + VmmAction validationsrc/firecracker/src/api_server/, src/vmm/src/rpc_interface.rs
Config field silently ignored or mis-appliedvmm_config/ parsing + VmResourcesrg -n "deserialize|struct .*Config" src/vmm/src/vmm_config/
Wrong/opaque error on bad configthe error enums for that subsystemrg -n "enum .*Error" src/vmm/src/vmm_config/
microVM fails to boot / panics on startthe builder + boot config + kernel loadrg -n "build_microvm_for_boot|configure_system" src/vmm/src/
Device hangs, stalls, or corrupts datathe virtio device + its virtqueue handlingrg -n "fn process_queue|fn handle_queue" src/vmm/src/devices/virtio/
Wrong CPUID/MSR in guestCPU templates / cpu_configrg -n "fn normalize|KVM_SET_CPUID2|set_cpuid" src/vmm/src/
Snapshot restore fails / incompatiblepersist.rs + the device's Persist implrg -n "impl Persist|fn save|fn restore" src/vmm/src/
Wrong rate-limit behaviorthe token bucketrg -n "struct TokenBucket|fn reduce" src/vmm/src/rate_limiter/
Jailer/seccomp denies a legit syscallseccomp filter JSON or jailer setupresources/seccomp/, src/jailer/src/

Tip: The fastest way to find the code that produced a message a user pasted into an issue is to grep for a fixed substring of that message. Run rg -n "the unique phrase from the error" src/ before anything else. If the message is built from a format string, grep the static prefix.


Required Reading

Read these before Lab 8.1. The point is to learn the project's own standards from its own documents and from recent merged PRs — not from this book paraphrasing them.

SourceWhat to extract
CONTRIBUTING.md (repo root)The exact PR rules: DCO sign-off, one logical change per commit, integration tests for new behavior, the devtool checks, ≥2 approvals
CHANGELOG.md (repo root)The entry format and the ### Added/Changed/Fixed/Deprecated/Removed sections — you will add a line
tests/README.md (and tests/)How the pytest integration harness is run and structured
docs/ for the subsystem you touchThe intended behavior, so you fix toward the spec, not your guess
Recent merged PRs (below)Live exemplars of diff size, test style, commit message, and CHANGELOG line that actually got merged

Confirm the docs exist on your branch, then study real merged PRs as your gold standard:

# Confirm the contribution docs are present on your checkout.
ls CONTRIBUTING.md CHANGELOG.md SPECIFICATION.md docs/ tests/

# The single most useful study material: PRs the maintainers actually merged.
# (Requires the GitHub CLI, authenticated: gh auth login)
gh pr list --repo firecracker-microvm/firecracker --state merged --limit 30

# Filter to bug-fix exemplars, then read a few end to end (diff + discussion).
gh pr list --repo firecracker-microvm/firecracker --state merged --label "Type: Bug" --limit 20
gh pr view <NUMBER> --repo firecracker-microvm/firecracker
gh pr diff <NUMBER> --repo firecracker-microvm/firecracker

When you read a merged bug-fix PR, answer for yourself: How many lines did it touch? Where was the test, and does it visibly map to the bug? What did the CHANGELOG line say? How was the issue linked in the description? Those four answers are the merge bar.


Source Code Areas to Inspect

You will not know which of these you need until you have the issue. Survey them now so the map is in your head.

AreaPath (verify with find/rg)Why it matters at Level 8
API server + request parsingsrc/firecracker/src/api_server/Where bad input should be rejected; many bug reports start here
Action enum + dispatchsrc/vmm/src/rpc_interface.rsVmmAction, VmmActionError, PrebootApiController/RuntimeApiController
Config parsing & validationsrc/vmm/src/vmm_config/The most common home of validation and error-message bugs
The buildersrc/vmm/src/builder.rsBoot-time failures and ordering bugs
Devicessrc/vmm/src/devices/virtio/{block,net,vsock,balloon,rng}/Hangs, stalls, data bugs
vCPU / KVM statesrc/vmm/src/vstate/vcpu/, vstate/vm.rsVM-exit handling and KVM-error reporting
Snapshot persistencesrc/vmm/src/persist.rs, src/vmm/src/snapshot/Restore failures, version-compat
Teststests/integration_tests/ (pytest), *_test.rs / #[cfg(test)] (Rust)Where your fix's test goes
# Orient yourself on the current workspace before you dive.
find src -maxdepth 2 -name Cargo.toml          # crate boundaries
rg -n "enum VmmAction" src/vmm/src/rpc_interface.rs
rg -n "enum VmmActionError" src/vmm/src/rpc_interface.rs

Key Types Quick Reference

Names by role, each with the command that finds it on your branch. Never trust a line number.

Type / itemRoleFind it
VmmActionControl-plane command from API → VMM threadrg -n "enum VmmAction" src/vmm/src/rpc_interface.rs
VmmActionErrorWhat a failed action returns to the API callerrg -n "enum VmmActionError" src/vmm/src/rpc_interface.rs
VmResourcesAggregated pre-boot configrg -n "struct VmResources" src/vmm/src/resources.rs
ParsedRequestA parsed HTTP request, pre-dispatchrg -n "struct ParsedRequest|enum RequestAction" src/firecracker/src/
build_microvm_for_bootCold-boot builder entryrg -n "fn build_microvm_for_boot" src/vmm/src/builder.rs
The subsystem …Error enumPer-subsystem error type (often thiserror)rg -n "enum .*Error" src/vmm/src/vmm_config/
Persist traitSave/restore for snapshot-able staterg -n "trait Persist" src/vmm/src/
The device process_* fnsVirtqueue processing (hang/stall bugs)rg -n "fn process_" src/vmm/src/devices/virtio/

GitHub Issue Categories for Level 8

These are the classes you can credibly take on now. Find them with real label filters (verify label spellings on the tracker — Firecracker uses Type: … and Status: … and Priority: … with colons):

# Good first issues — maintainer-vetted as small and self-contained.
gh issue list --repo firecracker-microvm/firecracker --state open --label "good first issue"

# Bugs — sorted by most recently updated (active, likely still valid).
gh issue list --repo firecracker-microvm/firecracker --state open --label "Type: Bug" --limit 40

# Enhancements that are genuinely small (verify each — most need design buy-in first).
gh issue list --repo firecracker-microvm/firecracker --state open --label "Type: Enhancement"
CategoryTypical sizeWhere it livesYour lab
Config/API validation accepts bad inputsmallvmm_config/, rpc_interface.rs, api_server8.1 + 8.2
Opaque/poor error message on a real failuresmallerror enums across subsystems8.3
Device edge case (off-by-one, bad descriptor handling)mediumdevices/virtio/8.2
Boot-config or memory-layout bugmediumbuilder.rs, arch/, vmm_config/8.2
Missing or wrong test for existing behaviorsmall–mediumtests/, *_test.rsbuilds on Level 5

Warning: Before you sink a day into an issue, read the entire thread and check for a linked PR. The community norm is announce intent, then work: comment that you are investigating so two people do not fix the same bug. gh issue view <N> --repo firecracker-microvm/firecracker --comments.


Deliverables

You must produce all of the following before advancing to Level 9:

  • A chosen real (or real-feeling) open issue with a written triage note: scope, subsystem, assignee/PR check, and a plan.
  • A deterministic reproducer that fails on your build of main (Lab 8.1).
  • A walked execution path from symptom to root cause, written down (the rg trail).
  • A minimal-diff fix plus a test that is red before, green after (Lab 8.2).
  • A green run of tools/devtool checkstyle, checkbuild --all, and test.
  • A CHANGELOG.md entry and DCO-signed commits (git commit -s).
  • A PR (or a complete PR-ready branch with a filled description, if not submitting upstream).
  • One diagnostics improvement with a test asserting the new message (Lab 8.3).

Common Mistakes

MistakeConsequenceFix
Fixing before reproducingYou patch the wrong thing and cannot prove it worksBuild the reproducer first; it must fail on main
Test that passes before the fixProves nothing; a reviewer will catch itRevert the fix and confirm the test goes red
Patching the symptom, not the causeBug returns via another pathWalk the execution path to the real defect
Drive-by reformatting in the diffReviewer cannot see the real change; fmt churnKeep the diff minimal; never bundle a reformat
Skipping the integration test for new behaviorCONTRIBUTING requires it; PR stallsAdd a pytest integration test, not just a unit test
Forgetting the CHANGELOG entryReviewers ask for it; round-trip wastedAdd a line under the right ### section
Forgetting git commit -sThe DCO bot blocks the PRSign off every commit; amend with --amend -s if needed
Widening seccomp or the device surface to "fix" a bugViolates the threat model; near-certain rejectionFind the fix that does not add attack surface
Bundling two fixes in one PRHard to review; stallsOne issue, one PR; rebase, don't bundle
Picking an enhancement as a first PRNeeds design discussion; spins for weeksStart with Type: Bug / good first issue

How to Verify Success

# 1. Your reproducer is red on a clean main, green on your branch.
git stash && tools/devtool test -- integration_tests/.../test_your_repro.py   # expect FAIL
git stash pop && tools/devtool test -- integration_tests/.../test_your_repro.py # expect PASS
# (or, for a unit-test repro:)
git stash && cargo test -p vmm your_repro_test    # FAIL on main
git stash pop && cargo test -p vmm your_repro_test # PASS on your branch

# 2. The full local gate is green.
tools/devtool checkstyle
tools/devtool checkbuild --all
tools/devtool test

# 3. Every commit is signed off, and the CHANGELOG mentions your change.
git log --format='%H %G? %s%n%b' | rg -i "signed-off-by" -A0 -B1
git diff main -- CHANGELOG.md

If the reproducer fails on main, passes on your branch, the gate is green, the diff is minimal, the CHANGELOG names the change, and the commits are signed — you have a PR a maintainer can review.


PR Profile: Level 8 Graduate

A Level 8 graduate can credibly open these PRs against firecracker-microvm/firecracker:

PR typeExampleWhy you can do it now
Config/API validation fixReject an out-of-range mem_size_mib or a malformed drive config with a clean 400You can trace the API → action → validation path and test it
Error-message improvementTurn an opaque KVM/ioctl or config failure into an operator-actionable messageYou understand the error enums and what an operator needs (Lab 8.3)
Device edge-case fixHandle a malformed virtio descriptor chain without panickingYou traced virtio in Level 7 and can write the pytest test
Boot/memory-config bug fixCorrect a boot-args or layout edge caseYou traced boot in Level 6
Missing-test contributionAdd the integration test that an under-tested behavior was missingBuilds directly on Level 5
Diagnostics/logging fixAdd context (the offending value, the device id) to a failure logLow-risk, high-value, reviewer-friendly

What this graduate does not yet open: new devices, new API endpoints, snapshot-format changes, or anything touching the seccomp/jailer security boundary as a feature. Those require design discussion and the depth of Level 9 and the Capstone.


Next: Lab 8.1 — Reproduce an Existing GitHub Issue. Then Lab 8.2 — Implement the Fix, Write the Test, Open the PR and Lab 8.3 — Improve Error Messages and Diagnostics. The graded, end-to-end version of this loop is the Capstone; the difficulty-ordered map of contribution types is the issue roadmap.