Performance Tip: Use
Ctrl+Fto jump to sections using anchor links (e.g.,#building-and-running)
make unit-tests - Run unit testsmake unit-tests-race - Unit tests with race detectormake integration-tests-fabtoken-fabric-t1 - Fabtoken integration testsmake integration-tests-dlog-fabric-t1 TEST_FILTER="T1" - ZK integration tests with T1 filtermake fmt - Format code using gofmtmake lint - Check code stylemake lint-auto-fix - Auto-fix linting issues (recommended pre-commit)make install-tools - Install development dependenciesmake checks - Run all pre-CI checks (license, fmt, vet, etc.)make download-fabric - Download Fabric binariesmake docker-images - Prepare Docker imagesmake testing-docker-images - Prepare test Docker imagesmake clean - Remove build artifactsmake clean-all-containers - Remove Docker containersmake tidy - Synchronize Go dependenciesgo generate ./... - Generate mocksmake install-tools
make download-fabric
export FAB_BINS=$PWD/../fabric/bin
make docker-images
make testing-docker-images
# Code quality
make lint-auto-fix
make checks
# Testing
make unit-tests # Standard
make unit-tests-race # With race detection
make integration-tests-fabtoken-fabric-t1 # Integration tests
# Performance profiling
go test -cpuprofile=cpu.out ./...
go test -memprofile=mem.out ./...
# Focused testing
make integration-tests-dlog-fabric TEST_FILTER="T1"
FAB_BINS is set correctly and points to valid Fabric binariesmake testing-docker-imagesmake lint-auto-fixchmod +x on Fabric binaries in $FAB_BINSmake clean-all-containersmake tidymake install-tools (ensures counterfeiter is installed)token/drivertoken/services*_test.go)assert for values, require for error handling)integration/ directoryTEST_FILTER environment variable with Ginkgo labels for focused testingTEST_FILTER="T1" runs only tests with T1 labelFuzzXxx test (Go native fuzzing) wherever meaningful — any exported
function that parses untrusted/attacker-controlled bytes (deserializers,
wire-format decoders, signature/identity/token parsers) should get one,
proactively when the entry point is added or touched, not only after a bug
is found there.f.Add(...): valid input, empty input, truncated/
malformed input, and any known historical edge cases (e.g. a payload that
previously triggered a panic).go test <pkg> -run='^$' -fuzz='^FuzzXxx$' -fuzztime=20s
with no panics, plus a plain go test <pkg> run to confirm the seed corpus
passes as ordinary test cases.FuzzXxx target into .github/workflows/nightly-fuzz.yml:
add a {name, pkg, func} entry to the fuzz job’s strategy.matrix.include
list. A fuzz test that isn’t in that matrix never actually runs under
extended -fuzztime in CI — it only gets exercised by its seed corpus in
the regular unit-test run.counterfeiter (go generate ./...)disabled.Provider for metrics to avoid nil panicsnoop.NewTracerProvider() for tracingtoken/services/ttx for example)fmt.Errorf (or fmt at all) to build or wrap errors. Always use github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors instead (errors.New, errors.Errorf, errors.Wrap, errors.Wrapf, errors.WithMessage, errors.WithMessagef, errors.Join, etc.). This applies to source code, tests, and code samples in docs/.git commit -s)Full guidance: docs/development/general.md. Summary:
gh label list for the
current set), Milestone (gh api repos/LFDT-Panurus/panurus/milestones --jq '.[].title'),
and Project (always "Panurus"). One gh pr create/gh issue create call can set
all of these via --assignee, --label, --milestone, --project.gh has no CLI flag for it; set it via gh api graphql with
updateIssueIssueType (node IDs from gh api orgs/LFDT-Panurus/issue-types).Fixes #N / Closes #N in the PR body — not just a
mention — so GitHub connects them and the project board updates automatically.git push and before gh pr create.Before implementing any task:
plan.md in project root with:
[ ] Pending checkboxes[x] Done + brief change notes## Notes & Decisions✅ COMPLETE when finishedBefore marking a task complete, update or create the relevant documentation under docs/:
docs/ page (or create one if it does not exist).docs/ pages must follow the existing style (Markdown, same heading hierarchy as neighbouring files).docs/<subsystem>/<topic>.md and add a link from the nearest index or README.Reusable, agent-agnostic step-by-step procedures live under docs/development/ and are
readable by any agent that reads this file — not just Claude Code. When Claude Code also
needs a /slash-command trigger for one, add a symlink at
.claude/skills/<name>/SKILL.md pointing back at the doc, so there is one source of truth.
fabric-smart-client to latest main: docs/development/update-fsc.md
(Claude Code: /update-fsc). Bumps the FSC dependency across every Go module, resolves
API/lint breakage until make checks and make lint-auto-fix are clean, then stops and
waits for the user’s go-ahead before pushing a branch or opening the PR — the “never push
or open a PR without explicit go-ahead” rule above still applies to this runbook./debug-integration-tests). Log locations, Docker/network inspection, and
Ginkgo focus/skip techniques for diagnosing failing integration tests.See Debugging Integration Tests (Claude Code: /debug-integration-tests).