Summary
There is no machine-generated, single-source error-code reference for the six Soroban contracts. The only error documentation in the repo is docs/standards/error-handling.md, and it is stale in three concrete ways: it marks the CreditLine, Merchant-Registry, and Liquidity-Pool sections "(Planned)" (docs/standards/error-handling.md:28,43,53) though all three ship today; it documents only 5 of the reputation contract's 11 real variants (:19-25 against contracts/reputation-contract/src/errors.rs:8-18); and it lists variants that exist nowhere in code — InvalidMerchant, UnauthorizedRepayment, LowReputationScore (:32,37,41) and the "Merchant" naming that was dropped when merchant-registry-contract was renamed to vendor-registry-contract (context/progress-tracker.md:112-116). The canonical catalog the roadmap expects — "error-code catalog scaffolded" (docs/PRD.md:331) — is absent: docs/ERROR_CODES.md does not exist (verified). Hand-maintained tables drift the moment any enum changes; only generation from the enums themselves keeps the catalog truthful.
Why these together: both workstreams are faces of one property — the published error reference is a build product of contracts/*/src/errors.rs, so it can never disagree with the code, and the drifting hand-written table that pretends to be that reference is retired in the same change. A generator with the old doc still in place leaves two contradictory sources; deleting the old doc without a generator leaves none.
Labels
area: contracts type: documentation priority: medium
Workstream 1 — Generate docs/ERROR_CODES.md from the six error enums
Objective
Produce one committed reference file whose every row is derived from the #[contracterror] enums, with a CI check that fails when the committed file and the generated file diverge.
Problem
Every contract's error enum carries no machine-readable metadata and no doc comments — contracts/creditline-contract/src/errors.rs:7-41 (33 variants), contracts/liquidity-pool-contract/src/errors.rs:6-26 (19), contracts/parameters-contract/src/errors.rs:6-26 (19), contracts/reputation-contract/src/errors.rs:7-19 (11), contracts/vouching-contract/src/errors.rs:6-20 (13), contracts/vendor-registry-contract/src/errors.rs:6-20 (13) — so there is no source a generator could read, and nothing forces the reference to update when a variant is added. The only existing table (docs/standards/error-handling.md) was edited by hand and has already drifted (:28,32,37,41,43,53).
Scope
scripts/generate-error-codes.sh (new — walks the enums, emits the catalog)
docs/ERROR_CODES.md (new — generated, committed, do-not-edit header)
Makefile (edit — error-codes target that runs the generator)
.github/workflows/contracts-ci.yml (edit — drift-check step)
Implementation
- Add
scripts/generate-error-codes.sh that, for each contract dir under contracts/*-contract, parses src/errors.rs, extracts the enum name, each Variant = <n> and its trailing /// doc comment (if any), and writes a table section per contract: | Code | Variant | Recoverable | When | Fix |.
- Emit a fixed header line
<!-- generated by scripts/generate-error-codes.sh — do not edit by hand --> and an ERROR_CODES_OUT env override, default docs/ERROR_CODES.md.
- Add
make error-codes invoking the script; the script exits non-zero if any contract's errors.rs is missing or contains an unparseable variant line (so a new variant can never be silently skipped).
- Add a
contracts-ci.yml step error-codes-drift: run the generator into a temp path and diff against the committed docs/ERROR_CODES.md; fail the job when they differ, printing the diff.
- Seed the "Recoverable / When / Fix" columns from doc comments where present and
TBD where a variant is undocumented, so the file is truthful about gaps until the per-contract error-model work lands.
Acceptance Criteria
Testing
- Unit: a fixture
errors.rs with 3 variants → parser returns exactly 3 (code, name, doc) tuples; a malformed line → non-zero exit.
- Integration: run the full generator over the real workspace; assert row counts per contract match the enum counts above; assert the
docs/ERROR_CODES.md in the tree is up to date.
Workstream 2 — Retire the stale docs/standards/error-handling.md table
Objective
Remove the hand-written, drifted error table and replace the standards page with a pointer to the generated reference plus the retained patterns guidance.
Problem
docs/standards/error-handling.md duplicates error data it cannot keep in sync: "CreditLine Contract (Planned)" (:28), "Merchant Registry (Planned)" (:43), "Liquidity Pool (Planned)" (:53) are all shipped contracts; its tables name phantom variants (InvalidMerchant :32, UnauthorizedRepayment :37, LowReputationScore :41) and phantom "Merchant" codes (:48-51); its reputation table stops at 5 variants (:19-25). It is also linked from the standards index (docs/standards/README.md:7), so the stale table is what readers reach today. The retained content — the #[contracterror] pattern, panic_with_error! usage, and safe-arithmetic guidance (:65-105) — is useful and should stay.
Scope
docs/standards/error-handling.md (edit — delete the four drifted tables; keep patterns + link the generated reference)
docs/standards/README.md (edit — relabel the link as "Error Handling (patterns) → see docs/ERROR_CODES.md")
Implementation
- Delete the "Reputation Contract", "CreditLine Contract (Planned)", "Merchant Registry (Planned)", and "Liquidity Pool (Planned)" tables from
error-handling.md.
- Add a top pointer: "Canonical error codes:
docs/ERROR_CODES.md (generated). This page covers patterns only."
- Retarget the standards index link so no reader lands on a phantom table.
Acceptance Criteria
Testing
- Unit: n/a (docs).
- Integration:
make error-codes drift check still green after the edit; link-check that every docs/standards/README.md link resolves.
Shared acceptance criteria (whole epic)
Security & compatibility considerations
- The generator reads only
errors.rs; it must never execute contract code or touch target/.
- The drift gate must fail closed: an unparseable enum or a missing contract dir exits non-zero rather than emitting an empty section.
- No public API, ABI code value, or Rust symbol changes — this is documentation and tooling only.
References
contracts/creditline-contract/src/errors.rs:7-41 — 33-variant CreditLineError (the largest source section).
contracts/liquidity-pool-contract/src/errors.rs:6-26 — 19-variant LiquidityPoolError.
contracts/parameters-contract/src/errors.rs:6-26 — 19-variant ParametersError.
contracts/reputation-contract/src/errors.rs:7-19 — 11-variant ReputationError.
contracts/vouching-contract/src/errors.rs:6-20 — 13-variant VouchingError.
contracts/vendor-registry-contract/src/errors.rs:6-20 — 13-variant bare Error.
docs/standards/error-handling.md:28,32,37,41,43,48-53 — the drifted tables to retire.
docs/standards/README.md:7 — link to the stale page.
docs/PRD.md:331 — roadmap expectation "error-code catalog scaffolded".
context/progress-tracker.md:112-116 — merchant-registry → vendor-registry rename (why "Merchant" codes are phantom).
Makefile — target host for error-codes.
.github/workflows/contracts-ci.yml — CI host for the drift check.
- Fed by the per-contract error-model documentation work (creditline, liquidity-pool, parameters, reputation, vouching, vendor-registry) which supplies the Recoverable/When/Fix columns; the namespacing work that assigns non-colliding code ranges lands in the same catalog.
If you're solving this with AI
In scope: scripts/generate-error-codes.sh, docs/ERROR_CODES.md, Makefile, .github/workflows/contracts-ci.yml, docs/standards/error-handling.md, docs/standards/README.md — only.
Out of scope: any change to contracts/*/src/*.rs; other repos; new dependencies beyond POSIX shell + awk/sed (already available); renaming contracts or variants; reformatting untouched docs.
Must: follow the repo PR template exactly; keep CI green for real (build + clippy + fmt + tests); add the generator's unit fixtures and the CI drift check; a regression fixture that FAILS when a variant is added to the committed file without regenerating; reference this issue (Closes #<n>); no secrets.
Contribution requirements: Follow the repo PR template exactly — https://github.com/StepFi-app/StepFi-Contracts/blob/main/.github/pull_request_template.md. Reference this issue in your PR. CI must pass green (build + fmt + clippy + tests). No secrets; no out-of-scope changes.
Summary
There is no machine-generated, single-source error-code reference for the six Soroban contracts. The only error documentation in the repo is
docs/standards/error-handling.md, and it is stale in three concrete ways: it marks the CreditLine, Merchant-Registry, and Liquidity-Pool sections "(Planned)" (docs/standards/error-handling.md:28,43,53) though all three ship today; it documents only 5 of the reputation contract's 11 real variants (:19-25againstcontracts/reputation-contract/src/errors.rs:8-18); and it lists variants that exist nowhere in code —InvalidMerchant,UnauthorizedRepayment,LowReputationScore(:32,37,41) and the "Merchant" naming that was dropped whenmerchant-registry-contractwas renamed tovendor-registry-contract(context/progress-tracker.md:112-116). The canonical catalog the roadmap expects — "error-code catalog scaffolded" (docs/PRD.md:331) — is absent:docs/ERROR_CODES.mddoes not exist (verified). Hand-maintained tables drift the moment any enum changes; only generation from the enums themselves keeps the catalog truthful.Why these together: both workstreams are faces of one property — the published error reference is a build product of
contracts/*/src/errors.rs, so it can never disagree with the code, and the drifting hand-written table that pretends to be that reference is retired in the same change. A generator with the old doc still in place leaves two contradictory sources; deleting the old doc without a generator leaves none.Labels
area: contractstype: documentationpriority: mediumWorkstream 1 — Generate
docs/ERROR_CODES.mdfrom the six error enumsObjective
Produce one committed reference file whose every row is derived from the
#[contracterror]enums, with a CI check that fails when the committed file and the generated file diverge.Problem
Every contract's error enum carries no machine-readable metadata and no doc comments —
contracts/creditline-contract/src/errors.rs:7-41(33 variants),contracts/liquidity-pool-contract/src/errors.rs:6-26(19),contracts/parameters-contract/src/errors.rs:6-26(19),contracts/reputation-contract/src/errors.rs:7-19(11),contracts/vouching-contract/src/errors.rs:6-20(13),contracts/vendor-registry-contract/src/errors.rs:6-20(13) — so there is no source a generator could read, and nothing forces the reference to update when a variant is added. The only existing table (docs/standards/error-handling.md) was edited by hand and has already drifted (:28,32,37,41,43,53).Scope
scripts/generate-error-codes.sh(new — walks the enums, emits the catalog)docs/ERROR_CODES.md(new — generated, committed, do-not-edit header)Makefile(edit —error-codestarget that runs the generator).github/workflows/contracts-ci.yml(edit — drift-check step)Implementation
scripts/generate-error-codes.shthat, for each contract dir undercontracts/*-contract, parsessrc/errors.rs, extracts the enum name, eachVariant = <n>and its trailing///doc comment (if any), and writes a table section per contract:| Code | Variant | Recoverable | When | Fix |.<!-- generated by scripts/generate-error-codes.sh — do not edit by hand -->and anERROR_CODES_OUTenv override, defaultdocs/ERROR_CODES.md.make error-codesinvoking the script; the script exits non-zero if any contract'serrors.rsis missing or contains an unparseable variant line (so a new variant can never be silently skipped).contracts-ci.ymlsteperror-codes-drift: run the generator into a temp path anddiffagainst the committeddocs/ERROR_CODES.md; fail the job when they differ, printing the diff.TBDwhere a variant is undocumented, so the file is truthful about gaps until the per-contract error-model work lands.Acceptance Criteria
make error-codesregeneratesdocs/ERROR_CODES.mdwith exactly 33 creditline + 19 liquidity-pool + 19 parameters + 11 reputation + 13 vouching + 13 vendor-registry rows.NewError = 99to a copy oferrors.rs→ generator emits a 34th row and the CI drift check fails against the stale committed file.Testing
errors.rswith 3 variants → parser returns exactly 3 (code, name, doc) tuples; a malformed line → non-zero exit.docs/ERROR_CODES.mdin the tree is up to date.Workstream 2 — Retire the stale
docs/standards/error-handling.mdtableObjective
Remove the hand-written, drifted error table and replace the standards page with a pointer to the generated reference plus the retained patterns guidance.
Problem
docs/standards/error-handling.mdduplicates error data it cannot keep in sync: "CreditLine Contract (Planned)" (:28), "Merchant Registry (Planned)" (:43), "Liquidity Pool (Planned)" (:53) are all shipped contracts; its tables name phantom variants (InvalidMerchant:32,UnauthorizedRepayment:37,LowReputationScore:41) and phantom "Merchant" codes (:48-51); its reputation table stops at 5 variants (:19-25). It is also linked from the standards index (docs/standards/README.md:7), so the stale table is what readers reach today. The retained content — the#[contracterror]pattern,panic_with_error!usage, and safe-arithmetic guidance (:65-105) — is useful and should stay.Scope
docs/standards/error-handling.md(edit — delete the four drifted tables; keep patterns + link the generated reference)docs/standards/README.md(edit — relabel the link as "Error Handling (patterns) → seedocs/ERROR_CODES.md")Implementation
error-handling.md.docs/ERROR_CODES.md(generated). This page covers patterns only."Acceptance Criteria
grep -n "Planned\|Merchant\|InvalidMerchant\|LowReputationScore" docs/standards/error-handling.mdreturns nothing.docs/standards/error-handling.mdlinks todocs/ERROR_CODES.md, which exists.:65-105content) are preserved.Testing
make error-codesdrift check still green after the edit; link-check that everydocs/standards/README.mdlink resolves.Shared acceptance criteria (whole epic)
cargo fmt --all --check,cargo clippy --workspace --all-targets --locked -- -D warnings, andcargo build --locked --target wasm32-unknown-unknown --releaseall exit 0; test count does not drop.docs/ERROR_CODES.mdexists, is generated, and the CI drift check passes.errors.rsfiles are read-only inputs.scripts/,docs/,Makefile,.github/workflows/contracts-ci.yml.Security & compatibility considerations
errors.rs; it must never execute contract code or touchtarget/.References
contracts/creditline-contract/src/errors.rs:7-41— 33-variantCreditLineError(the largest source section).contracts/liquidity-pool-contract/src/errors.rs:6-26— 19-variantLiquidityPoolError.contracts/parameters-contract/src/errors.rs:6-26— 19-variantParametersError.contracts/reputation-contract/src/errors.rs:7-19— 11-variantReputationError.contracts/vouching-contract/src/errors.rs:6-20— 13-variantVouchingError.contracts/vendor-registry-contract/src/errors.rs:6-20— 13-variant bareError.docs/standards/error-handling.md:28,32,37,41,43,48-53— the drifted tables to retire.docs/standards/README.md:7— link to the stale page.docs/PRD.md:331— roadmap expectation "error-code catalog scaffolded".context/progress-tracker.md:112-116— merchant-registry → vendor-registry rename (why "Merchant" codes are phantom).Makefile— target host forerror-codes..github/workflows/contracts-ci.yml— CI host for the drift check.If you're solving this with AI
In scope:
scripts/generate-error-codes.sh,docs/ERROR_CODES.md,Makefile,.github/workflows/contracts-ci.yml,docs/standards/error-handling.md,docs/standards/README.md— only.Out of scope: any change to
contracts/*/src/*.rs; other repos; new dependencies beyond POSIX shell +awk/sed(already available); renaming contracts or variants; reformatting untouched docs.Must: follow the repo PR template exactly; keep CI green for real (build + clippy + fmt + tests); add the generator's unit fixtures and the CI drift check; a regression fixture that FAILS when a variant is added to the committed file without regenerating; reference this issue (
Closes #<n>); no secrets.Contribution requirements: Follow the repo PR template exactly — https://github.com/StepFi-app/StepFi-Contracts/blob/main/.github/pull_request_template.md. Reference this issue in your PR. CI must pass green (build + fmt + clippy + tests). No secrets; no out-of-scope changes.