How to get a change merged into did-btcr2-js.
Use a single-segment prefix that describes the kind of work, followed by a short kebab-case description:
| Prefix | Use for |
|---|---|
feat/ |
New features (new public APIs, new beacon types, new packages) |
fix/ |
Bug fixes |
chore/ |
Tooling, build system, dependency updates, lint config |
docs/ |
Documentation-only changes |
refactor/ |
Internal refactoring with no behavioral change |
test/ |
Test-only changes (adding coverage, fixing test infrastructure) |
release/ |
Release preparation (version bumps, changelog) |
Examples: feat/cas-beacon-publish, fix/resolver-discovery-loop, chore/lib-tsconfig-node-types, docs/typedoc-unified-site.
main:
git checkout main
git pull origin main
git checkout -b feat/your-feature
pnpm install
pnpm build:ts
pnpm build:tests && pnpm test
pnpm lint
If any of these fail on a fresh main checkout, that’s a main-level bug: open an issue rather than starting feature work on top of broken state.
Commit messages use the imperative mood (“Add”, “Fix”, “Refactor”: not “Added”, “Fixed”, “Refactoring”). Subject lines are short (<= 72 chars). Body explains why, not what: the diff already shows what.
Example:
fix: cap resolver beacon discovery rounds at 10
Without an upper bound, a malicious or buggy DID document could cause
the resolver to loop indefinitely re-discovering newly-added beacon
services. Cap at 10 rounds, which is well above any realistic update
chain depth, and throw a ResolveError on overflow.
Each commit should be a single coherent change. Don’t bundle a refactor with a feature. Don’t bundle multiple unrelated bug fixes. If you find yourself writing “and” in a commit message, the commit probably wants to be split.
pnpm build:ts # incremental TypeScript build
pnpm build:tests && pnpm test # full test suite
pnpm lint # zero-warning lint
The lint step is enforced as --max-warnings 0. CI will fail if any warning slips through. Fix as you go: pnpm lint:fix handles most autofixable issues.
If your change modifies anything exported from a package’s src/index.ts, you’re modifying its public API. That has versioning consequences:
Pre-1.0 packages (currently keypair, cryptosuite, bitcoin, kms, smt, method, api, cli) treat MINOR as breaking under strict semver. The common package is post-1.0 and follows full semver.
You don’t bump versions yourself in your PR: that happens at release time. But your PR description should call out the bump category so the reviewer can sanity-check.
Squash WIP commits if your branch has noisy intermediate commits. The history that lands on main should be reviewable.
main (don’t merge main into your branch: that creates a merge commit that pollutes the history):
git fetch origin
git rebase origin/main
git push origin feat/your-feature
gh:
gh pr create --base main --head feat/your-feature \
--title "feat: short description" \
--body "$(cat <<'EOF'
## Summary
<1-3 bullets explaining what changed and why>
## Test plan
- [ ] Steps you took to verify the change
- [ ] Edge cases you considered
- [ ] Anything you didn't test and why
## Version impact
- <package>: PATCH | MINOR | MAJOR: <reason>
EOF
)"
A reviewer will look for:
Address review comments with new commits on your branch (don’t force-push during review unless asked: it makes incremental review harder). After approval, the merge commit will preserve the commit history if you want it preserved, or squash if you prefer a single commit on main.
For substantial multi-commit PRs (typically 3+ commits), the project convention is to squash to a single commit on main with a structured message that lists package versions and per-package changes. See the rebase template in feedback-rebase-template.md (maintainer-only memory file).
For small PRs (1-2 commits), preserve the individual commits with a merge commit.
gh pr merge --merge: preserves all commits, adds a merge commit. Use for multi-commit PRs where each commit is meaningful.gh pr merge --squash: collapses to a single commit. Use for trivial fixes or when commits are noisy.gh pr merge --rebase: rebases each commit individually onto main (no merge commit). Use sparingly: it rewrites your branch’s commit hashes.git checkout main
git pull origin main
git branch -d feat/your-feature
gh didn’t already):
git push origin --delete feat/your-feature