Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ updates:
- '*'
multi-ecosystem-group: monthly-stack-maintenance
rebase-strategy: auto
# The npm updater currently fetches unrelated ancestor pnpm support files
# and mistakes these standalone package-lock projects for sub-workspaces.
# Exclude only those two ancestor files here; the root entry owns them.
exclude-paths:
- '../../pnpm-lock.yaml'
- '../../pnpm-workspace.yaml'
- '../../../pnpm-lock.yaml'
- '../../../pnpm-workspace.yaml'
cooldown:
default-days: 7
ignore:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ jobs:

- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version-file: tools/codegen/pyproject.toml
# Keep CI reproducible while pyproject permits Dependabot's uv resolver.
version: '0.11.32'
python-version: '3.12'
enable-cache: true
cache-dependency-glob: tools/codegen/uv.lock
Expand Down
7 changes: 6 additions & 1 deletion conformance/runner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ pnpm --filter @bsv/conformance-runner-ts test

The structural runner's `build` command verifies its JavaScript syntax.
The TypeScript runner is linted and checked in strict mode before executing its
tests. `test` executes the required vector suite. `validate` checks vector and
tests. Its workspace dependencies include wallet-toolbox because the wallet
dispatchers typecheck against its built declarations. For a clean targeted
build, run `pnpm --filter '@bsv/conformance-runner-ts...' --if-present build`
before the TypeScript runner's typecheck; the declared dependency graph builds
those prerequisites even when the changed package is air-gap or CHIRP.
`test` executes the required vector suite. `validate` checks vector and
implementation metadata without executing the cases. Generated vectors live
under `conformance/generated`; edit their source specifications and run the
owned generator rather than editing generated output.
Expand Down
1 change: 1 addition & 0 deletions conformance/runner/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@bsv/air-gap": "workspace:^",
"@bsv/chirp": "workspace:^",
"@bsv/sdk": "workspace:^",
"@bsv/wallet-toolbox": "workspace:^",
"@jest/globals": "^30.4.1",
"@types/node": "^26.1.2",
"@typescript/native": "npm:typescript@7.0.2",
Expand Down
45 changes: 32 additions & 13 deletions docs/architecture/wallet-utxo-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ title: Wallet UTXO Lifecycle
kind: meta
domain: wallet
version: 'n/a'
last_updated: '2026-08-13'
last_verified: '2026-08-13'
last_updated: '2026-09-23'
last_verified: '2026-09-23'
review_cadence_days: 30
status: stable
tags: ['architecture', 'BRC-100', 'wallet', 'utxo', 'storage']
Expand All @@ -24,6 +24,12 @@ It is written against two implementations, [`@bsv/wallet-toolbox`](../packages/w
against it, and the places where either one deviates are collected in
[Implementation differences](#implementation-differences).

The TypeScript paths and lifecycle were rechecked against TS Stack main
`57d72e24a565d090bd605cf9767785c51ea4f179` on 2026-09-23. The Go diagrams and
comparisons below preserve the **2026-08-13 review snapshot**; they are historical
findings, not claims about the latest Go release. Recheck the linked Go source
before using a difference as a current cross-implementation defect.

## How to read the diagrams

Each lane is a layer, and time runs downward. The lanes below appear in every diagram on
Expand Down Expand Up @@ -105,14 +111,14 @@ sequenceDiagram
end
```

The write transaction opens at `storage/methods/createAction.ts:196` and every call from
`insertTransaction` onward is inside it. The transaction row is born `unsigned`
(`createAction.ts:690`). If anything downstream throws, the cleanup path drives it to
`failed` (`:309`) and records a forensic row (`:312`) rather than deleting evidence.
The write transaction in `storage/methods/createAction.ts` contains
`insertTransaction` and its subsequent writes. The transaction row is born
`unsigned`. If construction fails after recording the plan, the cleanup path
drives it to `failed` and records a forensic row rather than deleting evidence.

`markChangeInputsSpent` (`:1398`) is the moment funding becomes exclusive: it flips the
`markChangeInputsSpent` is the moment funding becomes exclusive: it flips the
selected change outputs to `{spendable: false, spentBy: transactionId}` under the row
locks taken by `findFundingOutputsForUpdate` (`:1376`).
locks taken by `findFundingOutputsForUpdate`.

### Storage call ledger

Expand Down Expand Up @@ -166,7 +172,7 @@ sequenceDiagram

The `pendingSignActions` cache is process memory on the `Wallet` instance. A `reference`
issued by one process cannot be signed by another, and cannot survive a restart —
`Wallet.ts:1056` throws `WERR_NOT_IMPLEMENTED` rather than attempting recovery. Go stores
`signer/methods/signAction.ts` throws `WERR_NOT_IMPLEMENTED` rather than attempting recovery. Go stores
these in a pluggable repository instead; see [difference 6](#implementation-differences).

### processAction — commit and broadcast
Expand Down Expand Up @@ -429,6 +435,14 @@ custom instructions and tags.

### abortAction

The diagram below describes ordinary actions. BRC-177 expiring `noSend` actions
have a separate durable lifecycle: aborting a released signed action requests
revocation instead of immediately freeing its inputs. `TaskNoSendExpiry` uses
positive chain and UTXO evidence to arbitrate target-versus-reclaim races;
reclaiming, reclaimed, broadcast, target-won and conflicted states retain their
specific guards. See `StorageProvider.abortAction` and `TaskNoSendExpiry` before
operating on expiring actions.

```mermaid
sequenceDiagram
autonumber
Expand Down Expand Up @@ -504,11 +518,14 @@ sequenceDiagram
end
```

Nineteen tasks ship in `src/monitor/tasks/`. Beyond those above, `TaskReorg` and
The task classes in `src/monitor/tasks/` are selected by the Monitor profile;
not every class is registered by default. Beyond those above, `TaskReorg` and
`TaskNewHeader` handle chain reorganisation, `TaskCheckNoSends` settles `nosend`
transactions, `TaskUnFail` retries operator-flagged failures, `TaskArcSSE` consumes
broadcaster push events, `TaskPurge` and `TaskCleanupActionBatches` reclaim storage, and
`TaskSyncWhenIdle` replicates to backup stores.
`TaskSyncWhenIdle` can be registered to replicate to backup stores. The default
and multi-user profiles include `TaskNoSendExpiry`, `TaskReviewProvenTxs` and
`TaskReconcilePendingTransactions`; `TaskMineBlock` is mock-chain-only.

## The Go implementation

Expand Down Expand Up @@ -771,8 +788,10 @@ list-outputs special operations.

### 11. Background convergence uses different mechanisms

TypeScript ships nineteen registered Monitor tasks; Go registers four. That comparison is
misleading on its own, because Go moves much of the same work off the scheduler:
The TypeScript default and multi-user profiles each schedule sixteen tasks plus
two housekeeping tasks, with a mock-only miner added for mock chains. The archived
Go review found four scheduled tasks. Counts alone do not describe convergence:
that Go implementation moved much of the work off the scheduler:

- **Event consumers.** `pkg/monitor` runs an SSE broadcast-event pipeline with a persisted
replay cursor (`arcade_sse_last_event_id`) plus reorg and new-tip consumers. Reorg
Expand Down
14 changes: 12 additions & 2 deletions docs/infrastructure/chaintracks-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ id: infra-chaintracks-server
title: 'Chaintracks Server'
kind: infra
version: '1.2.0'
last_updated: '2026-08-12'
last_verified: '2026-08-12'
last_updated: '2026-09-23'
last_verified: '2026-09-23'
review_cadence_days: 30
status: stable
tags: [chaintracks, block-headers, spv, merkle, infrastructure]
Expand Down Expand Up @@ -175,6 +175,16 @@ them as a fallback until the first new generation is complete. Roll back the
service image without deleting this root. Older releases continue to see their
flat files; the new content-addressed and generation directories are additive.

## Verification scope

Rechecked on 2026-09-23 against TS Stack main
`57d72e24a565d090bd605cf9767785c51ea4f179`: v1/v2 route handlers,
`server.ts` readiness and upstream/worker limits, the edge policies, and
`BulkHeaderSnapshotPublisher` generation retention and atomic current pointer.
These are source contracts. Operators must separately verify the deployed image,
ready endpoints, durable storage and public routes during each rollout; a source
version or passing unit test does not prove a live service has been upgraded.

## When to deploy this

- Running `@bsv/wallet-toolbox`-based wallets in production (the toolbox calls Chaintracks for SPV)
Expand Down
22 changes: 22 additions & 0 deletions docs/reference/ci-performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ Review the 40 exact run links, classification threshold, sample summaries,
workflow or runner changes, and the stated median/p95 budget. Never loosen a
budget solely to make a red trend green.

## Sampling and investigation

The collector searches up to ten pages of successful PR runs, deduplicates source
heads, and paginates each run's complete job list. It retains 20 full-scope and
20 targeted runs, including job and step timings. When history cannot supply the
required sample, it writes the partial report before failing; incomplete samples
cannot establish a new baseline. API requests and pagination are bounded.

The September review found that the July baseline predates the optical-codec
mutation target and later QA additions. In the recovered 40-run sample, full-scope
median/p95 was 2,007/2,254 seconds and targeted median/p95 was 566/833 seconds.
The optical-codec mutation job dominated full runs (median 1,378 seconds), while
wallet coverage dominated the longer targeted runs. Those observations do not by
themselves justify raising the budget. Keep the historical baseline until a
reviewed workload comparison and measurements justify a replacement.

The duplicate-tracking codec regression now bounds its fixture's search and
avoids constructing a successful Jest matcher for every redundant frame. It
still sends more than the actual tracking limit, checks every acceptance result,
repeats the final frame and verifies exact recovered bytes. Mutation and property
coverage, payload sizes, test counts and timeout budgets remain governed.

## Complete release acceptance

Dispatch `CI` manually on the reviewed main commit to select the entire governed
Expand Down
19 changes: 16 additions & 3 deletions docs/reference/dependency-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
id: dependency-release-policy
title: 'Dependency and Release Policy'
kind: reference
version: '1.3.1'
last_updated: '2026-09-15'
last_verified: '2026-09-15'
version: '1.3.2'
last_updated: '2026-09-23'
last_verified: '2026-09-23'
review_cadence_days: 30
status: stable
tags: [reference, dependencies, security, releases]
Expand Down Expand Up @@ -61,6 +61,19 @@ Security updates are grouped only within a package-manager ecosystem and are
never delayed into the monthly cross-ecosystem version update. First-party
`@bsv/*` versions remain owned by the release graph.

Standalone infrastructure uses npm `package-lock.json` files outside the pnpm
workspace. Its Dependabot entry excludes only the unrelated ancestor
`pnpm-lock.yaml` and `pnpm-workspace.yaml` support files, avoiding the updater's
sub-workspace misclassification; the root entry continues to own both files.
Every infrastructure manifest and npm lockfile remains monitored. Remove this
workaround when Dependabot respects standalone npm boundaries beneath a pnpm root.

The Python code generator accepts uv >=0.11.32 so Dependabot can resolve its
locked dependency graph with the uv version supplied by GitHub. The codegen
workflow retains an explicit uv 0.11.32 pin, Python 3.12, `uv run --locked`, and
byte-for-byte generated-output verification. A resolver proposal does not
silently change the CI toolchain or authorize different generated types.

Major changes that alter a runtime, compiler, or persisted-data contract are
held from the routine monthly PR until their focused migration is ready:

Expand Down
16 changes: 14 additions & 2 deletions packages/helpers/air-gap/tests/decoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,23 @@ describe('AirGapDecoder', () => {
const dec = new AirGapDecoder()
expect(dec.accept(e.partAt(0)).have).toBe(1)
const redundant: number[] = []
for (let seq = 2; redundant.length < MAX_TRACKED_SEQS + 1; seq++) {
// Bound fixture generation too: a broken mapping must fail this test,
// not make the fixture search forever during mutation testing.
for (
let seq = 2;
seq < MAX_TRACKED_SEQS * 16 && redundant.length < MAX_TRACKED_SEQS + 1;
seq++
) {
const blocks = blocksForPart(seq, 2)
if (blocks.length === 1 && blocks[0] === 0) redundant.push(seq)
}
for (const seq of redundant) expect(dec.accept(e.partAt(seq)).ok).toBe(true)
expect(redundant).toHaveLength(MAX_TRACKED_SEQS + 1)
for (const seq of redundant) {
const accepted = dec.accept(e.partAt(seq)).ok
// Avoid allocating thousands of successful Jest matchers in every mutant.
// Keep the same literal-true assertion, with full diagnostics on failure.
if (accepted !== true) expect({ seq, accepted }).toEqual({ seq, accepted: true })
}
// The tracker is full; new and repeated sequence numbers are simply
// re-processed as redundancy instead of being remembered, and the honest
// part still completes the message.
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading