Capstone Project
The Capstone is the bridge from "I have read the OpenSearch codebase" to "I have
shipped a non-trivial fix that an OpenSearch maintainer merged into main."
Everything in Levels 1–9 was preparation. This is the work.
You will pick one real, open issue from
github.com/opensearch-project/OpenSearch/issues,
reproduce it against a current build, trace the failure through the codebase,
identify the root cause, write a minimum-diff fix with deterministic tests, get
it through ./gradlew precommit and the gradle-check CI, open a Pull Request,
sign your commits off under the DCO (git commit -s — OpenSearch has no
CLA), respond to review rounds, land the change, and write it up so the next
person can learn from your investigation.
OpenSearch contribution is GitHub-native. There is no JIRA, no patch file
emailed to a list, no Apache ID. You fork, branch, push, open a PR, sign off,
add a CHANGELOG.md entry, and iterate in the PR conversation until a
maintainer merges and the backport bot cherry-picks to the release branches.
Keep that model in your head — every step below assumes it.
This chapter is the table of contents. The ten step-chapters that follow are the work itself.
Prerequisites
Do not start the Capstone until you can answer "yes" to every one of these:
- Levels 1–9 complete. You can read
RestSearchAction,TransportSearchAction,IndexShard,InternalEngine, the coordination layer (Coordinator,MasterService/ cluster-manager service,ClusterApplierService), and at least one allocation decider, without a guide open. If those names are not familiar, go back to Level 4 and the deep dives. - You can build from source.
./gradlew assemblesucceeds on your machine, and./gradlew :server:test --tests "org.opensearch.cluster.ClusterStateTests"finishes green. Some flakes are normal — see the flaky-test discussion. - You have run a cluster from source.
./gradlew runbrings up a single node with REST onlocalhost:9200, and you have hit it withcurl. - You have run an
InternalTestClustertest../gradlew :server:internalClusterTest --tests "*ClusterHealthIT"(or any*IT) goes green, so you know the multi-node in-JVM harness works on your box. - You have a GitHub account with DCO configured. You can
git commit -sand theSigned-off-by:line carries your real name and the email tied to your GitHub account. (The DCO check on the PR matches the sign-off email to a commit author — get this right once, locally, before you ever push.) - You have read the contribution hygiene files in the repo:
CONTRIBUTING.md,DEVELOPER_GUIDE.md, andTESTING.md.
If any of these is "no," stop. Go back. The Capstone is unforgiving of partial preparation — you will spend three weeks confused instead of three weeks shipping.
Note: OpenSearch renamed the master node role and many APIs to cluster manager for inclusive language (the old
masterterms survive as deprecated aliases). Throughout the Capstone, write cluster manager (formerly master) the first time you reference it in any artifact, then use "cluster manager." Reviewers notice.
The 10-Step Flow
flowchart TD
A[Step 1: Issue Selection] --> B[Step 2: Reproduction]
B --> C[Step 3: Execution Path Analysis]
C --> D[Step 4: Root Cause Identification]
D --> E[Step 5: Implementation]
E --> F[Step 6: Testing]
F --> G[Step 7: Validation]
G --> H[Step 8: Pull Request Preparation]
H --> I[Step 9: GitHub Documentation]
I --> J[Step 10: Engineering Write-Up]
G -.precommit fail.-> E
F -.test fail.-> E
D -.hypothesis wrong.-> C
H -.review round.-> E
I -.gradle-check red.-> F
The dotted arrows are the loops you will actually run. Nobody gets root cause
right on the first hypothesis. Nobody passes precommit on the first push.
Nobody clears review in one round. Plan for two or three iterations through
Steps 4–9 before the merge button turns green.
Deliverables
By the time you mark the Capstone done, every one of these artifacts exists:
| # | Artifact | Lives in |
|---|---|---|
| 1 | Failing reproducer test (a JUnit test that fails on main without your fix and passes with it) | server/src/test/... or server/src/internalClusterTest/... |
| 2 | Root-cause document (200–500 words, with file-path citations) | capstone-work/root-cause.md in your fork |
| 3 | Minimum-diff fix branch | A branch on your fork of opensearch-project/OpenSearch |
| 4 | Unit tests (OpenSearchTestCase; AbstractWireSerializingTestCase if serialization changed) | The relevant src/test/java |
| 5 | Integration tests (OpenSearchIntegTestCase / InternalTestCluster) if end-to-end behavior changed | server/src/internalClusterTest/java/... |
| 6 | Validation report (./gradlew precommit, spotlessJavaCheck, affected-module tests) | capstone-work/validation.md |
| 7 | GitHub Pull Request against opensearch-project/OpenSearch:main, DCO-signed | https://github.com/opensearch-project/OpenSearch/pulls |
| 8 | CHANGELOG.md entry under ## [Unreleased ...] (Added / Changed / Fixed) | CHANGELOG.md in your branch |
| 9 | Issue updated and linked (Fixes #NNNN), labels and backport label as appropriate | https://github.com/opensearch-project/OpenSearch/issues/NNNN |
| 10 | Engineering write-up (500–1000 words: problem, investigation, design, alternatives, lessons) | Personal blog, the forum, or the PR itself |
Every one. No exceptions. The write-up is not optional — it is how the community (and your future self) learns from your investigation. See Step 10.
Use a - [ ] checklist to track them:
-
Failing reproducer test committed and confirmed red on
main -
capstone-work/root-cause.mdwritten - Minimum-diff fix on a feature branch
- Unit tests cover every trigger condition
- Integration / REST-YAML tests if behavior is end-to-end
-
capstone-work/validation.mdwith a greenprecommit -
DCO-signed PR opened against
main -
CHANGELOG.mdentry added -
Issue linked with
Fixes #NNNN, labels set - Write-up published
100-Point Rubric Summary
The full rubric lives in evaluation-rubric.md. Headline:
| Area | Weight |
|---|---|
| Problem articulation (symptom vs. root cause, trigger conditions) | 20 |
| Execution-path mastery (file-path citations, accurate diagram) | 20 |
| Implementation quality (minimum diff, conventions, BWC, no scope creep) | 20 |
| Testing (unit + integration, deterministic, trigger coverage) | 15 |
| Review responsiveness (addresses comments, iteration cadence) | 10 |
| Documentation (issue/PR hygiene, CHANGELOG, write-up) | 10 |
| Community interaction (forum/Slack/PR etiquette, handoff hygiene) | 5 |
Tier thresholds:
- 80+ — credible OpenSearch contributor. You can sustain a steady PR flow.
- 90+ — maintainer-ready. You are doing work a
MAINTAINERS.mdreviewer would do without hand-holding. - 95+ — TSC-track. You are leading work others want to follow, across repos.
You will self-grade in Step 10. Be honest. Inflated self-grades are visible from orbit the moment a maintainer reads your PR.
Timeline
The Capstone is a 4–6 week effort if you have one focused evening per weekday plus weekend mornings. Less than that and you risk losing context between sessions — which is far more expensive than people expect for cluster-state and coordination code.
| Week | Steps | Hours |
|---|---|---|
| 1 | 1–2: Pick an issue, build a deterministic reproducer | 10–15 |
| 2 | 3–4: Trace the execution path, identify root cause | 12–18 |
| 3 | 5–6: Implement the fix, write unit + integration tests | 12–18 |
| 4 | 7–8: Validate locally, open the DCO-signed PR | 8–12 |
| 5 | 8–9: Review iteration — two or three rounds is normal | 6–10 |
| 6 | 10: Write-up, issue cleanup, retrospective | 4–6 |
If you blow past six weeks, that is a signal — not a failure. Either the issue
is larger than it looked (pause and renegotiate scope in the issue thread), or
you are stuck on a specific step (ask on the
forum or in
#community on Slack). See
Communication Channels.
Success Indicators
You will know it is working when:
- A maintainer comments "LGTM" / approves the PR, and
gradle-checkis green. - Your fix appears in
git log origin/mainwith yourSigned-off-by:line, and the backport bot opens a follow-up PR onto2.x. - The issue you claimed flips to closed via
Fixes #NNNN, with your name on the merge. - Your write-up gets traffic — forum replies, a question from another contributor, a maintainer pointing the next person at it.
- The next time you pick an issue, you reach root cause in days, not weeks.
You will know it is failing when:
- You are still editing files in Step 5 with no failing test in hand from Step 2.
- Your PR description says "I think this might fix it."
- You have not run
./gradlew precommitin over a week. - You are arguing in PR comments instead of changing code or asking questions.
- CI (
gradle-check) has been red for days and you are pushing "fix CI" commits blind instead of reproducing the failure locally.
If you spot a failure signal, do not push through. Stop, reread the relevant step chapter, and reset.
How to Use This Chapter
Read all ten step-chapters once, end-to-end, before you start Step 1. You need the shape of the whole journey in your head — Step 4 (root cause) makes choices that Step 6 (testing) depends on; Step 8 (PR) assumes you have artifacts from Steps 2 and 7; Step 9 assumes your tests cleared CI. Skim now, deep-read each as you arrive at it.
Then go to Step 1: Issue Selection. Pick the issue. The clock starts when you comment "I'd like to work on this" on the GitHub issue.
Validation / Self-check
Before starting Step 1, confirm:
- You can produce, from memory, the source path of
RestSearchAction,TransportSearchAction,IndexShard,InternalEngine, andCoordinator. ./gradlew assemblecompletes against your local clone../gradlew runbrings up a node and you have curledlocalhost:9200/_cluster/health../gradlew :server:internalClusterTest --tests "*ClusterHealthIT"passes.git commit -sproduces a correctSigned-off-by:line with your GitHub email.- You have a
capstone-work/directory in your fork ready forroot-cause.mdandvalidation.md. - You have skimmed every step-chapter once.
- You have set aside 4–6 calendar weeks with a realistic time budget.
- You have read
CONTRIBUTING.md,DEVELOPER_GUIDE.md, andTESTING.md.