Skip to content
Open
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
9 changes: 5 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P
| 0 Foundations | 19 | 16 | 1 | 2 | 0 | 0 | 0 | 84% |
| 1 M0 Validate | 17 | 1 | 6 | 10 | 0 | 0 | 0 | 6% |
| 2 Contract + registry | 41 | 24 | 3 | 14 | 0 | 0 | 0 | 59% |
| 3 SDK + indexer | 24 | 18 | 3 | 3 | 0 | 0 | 0 | 75% |
| 3 SDK + indexer | 24 | 20 | 1 | 3 | 0 | 0 | 0 | 83% |
| 4 App | 27 | 15 | 7 | 5 | 0 | 0 | 0 | 56% |
| 5 Testnet pilot | 7 | 0 | 0 | 7 | 0 | 0 | 0 | 0% |
| 6 Pre-mainnet features | 10 | 0 | 0 | 10 | 0 | 0 | 0 | 0% |
Expand All @@ -139,7 +139,7 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P
| 9 Conditional ramp | 9 | 0 | 0 | 0 | 0 | 9 | 0 | n/a |
| 10 Wave + community | 10 | 5 | 1 | 4 | 0 | 0 | 0 | 50% |
| 11 Deferred parking lot | 16 | 0 | 0 | 0 | 0 | 16 | 0 | n/a |
| **All** | **214** | **79** | **21** | **89** | **0** | **25** | **0** | **42%** |
| **All** | **214** | **81** | **19** | **89** | **0** | **25** | **0** | **43%** |

---

Expand Down Expand Up @@ -275,11 +275,11 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P
| M2-07 | SDK tests, including a check that nothing derived from the fragment is logged | sdk | P0 | DONE | M2-03 | Test fails if fragment data reaches logger |
| M2-08 | Indexer scaffold: Zod config, RPC client with multi-provider failover | sdk | P0 | DONE | M2-01 | Failover tested |
| M2-09 | Indexer ingest: poller, persisted cursor, gap detection | sdk | P0 | DONE | M2-08 | Gaps stop ingestion and alert; never skipped silently |
| M2-10 | Indexer handlers per event type and `schema_version` | sdk | P0 | IN PROGRESS | M2-09, M1-02 | Mixed-version fixtures handled |
| M2-10 | Indexer handlers per event type and `schema_version` | sdk | P0 | DONE | M2-09, M1-02 | Mixed-version fixtures handled |
| M2-11 | DB schema and forward-only Drizzle migrations | sdk | P0 | DONE | M2-01 | `chain_events`, `indexer_cursor`, `locks`, `tranches`, `payees` created |
| M2-12 | List API: `/locks`, `/locks/:id`, `/payees`, `/health` with lag | sdk | P0 | DONE | M2-10, M2-11 | OpenAPI or typed docs; lag exposed |
| M2-13 | Join payee display data from the registry repo | sdk | P0 | DONE | M1-25 | Payees show name, city, attester |
| M2-14 | Indexer tests: fixture replay, idempotency, cursor recovery, mixed versions | sdk | P0 | IN PROGRESS | M2-10 | Replay twice yields identical DB |
| M2-14 | Indexer tests: fixture replay, idempotency, cursor recovery, mixed versions | sdk | P0 | DONE | M2-10 | Replay twice yields identical DB |
| M2-15 | Lag alerting and health metric | sdk | P1 | TODO | M2-12 | Alert fires in a simulated lag test |
| M2-16 | Implement tier-3 verification and backfill per `M0-09` decision | sdk | P1 | TODO | M0-09, M2-06 | Old receipts verify; backfill fills a deliberate gap |
| M2-17 | SDK docs and API reference; publish testnet package versions | sdk | P0 | DONE | M2-07 | Published; docs match exports |
Expand Down Expand Up @@ -547,6 +547,7 @@ Newest first. One entry per PR. Required for every contribution (see §2).
| 2026-10-26 | `ci/pin-action-shas` | sdk | M2-25 IN PROGRESS | Scorecard remediation Tier 1: pinned `actions/checkout@v4`, `pnpm/action-setup@v4`, `actions/setup-node@v4`, `actions/setup-python@v5` to commit SHAs across `ci.yml`, `publish.yml`, `docs-in-sync.yml`, `roadmap-check.yml`, `malware-scan.yml` (resolved via `gh api .../git/refs/tags/{tag}`, not guessed); added `.github/dependabot.yml` (`npm` + `github-actions`); enabled CodeQL default setup for `actions`+`javascript-typescript` via the Code Scanning API (admin access already present on the active account, no new credential needed). This repo's own Scorecard job (`M2-23`, PR #45) hasn't merged yet, so there's no baseline score to compare against -- done proactively based on the pattern already confirmed in `kinlock-contracts`/`kinlock-app`/`kinlock-registry`. **Update 2026-10-26:** this branch predates `M2-24`'s `zod` DoS fix (PR #46), so its `dependency-audit` check was failing on the same already-diagnosed `GHSA-mrhx-c7xc-m3w5`; applied the same `zod` 4.6.5→4.6.6 bump here too. Verified: `pnpm audit --audit-level=high` clean of the advisory; lint/typecheck/test (173/173)/build all green. Left `IN PROGRESS` pending a real post-merge Scorecard run. |
| 2026-10-23 | `ci/malware-scan` (#44) | sdk | M2-22 DONE | Follow-up: the first CI run caught the unscoped Semgrep call also scanning `.github/workflows/*.yml`, flagging unpinned action tags and a real shell-injection pattern in the existing `roadmap-check.yml` — out of this job's scope, flagged rather than fixed silently (same finding as `kinlock-contracts`/`kinlock-app`/`kinlock-registry`; their workflow files are independent copies of the same pattern). Rescoped the scan to `packages/sdk/src services/indexer/src`; all checks (`build`, `docs-in-sync`, `dependency-audit`, `roadmap-check`, `indexer-image`, `source-scan`) now pass on PR #44. `M2-22` confirmed `DONE`. |
| 2026-10-23 | `ci/malware-scan` | sdk | M2-22 IN PROGRESS | Added `.github/workflows/malware-scan.yml`: `pnpm audit --audit-level=high` (npm advisory DB) plus a Semgrep source scan (`--config auto --error`) on every PR. Verified locally: `pnpm audit --audit-level=high` exits 0 (2 pre-existing low/moderate advisories below the `high` gate — `esbuild` via `drizzle-kit` dev dependency, `fastify` header-validation bypass — neither is this PR's scope, flagged separately); Semgrep (clean venv, v1.136.0) finds 0 findings across `packages/sdk/src` and `services/indexer/src`. Left `IN PROGRESS` pending the first real PR run confirming the job executes green in GitHub Actions. |
| 2026-10-17 | `test/mixed-schema-version-indexer` (#34) | sdk | DONE: M2-10, M2-14 | Mixed schema_version fixtures and stop-on-unknown test coverage: added forward-compatible v2 handler stubs (lockCreatedV2, releasedV2), synthesized mixed-versions fixture (15 events covering interleaved v1/v2 schema events on the same Lock 3 with tranches), verified stop-on-unknown (schema_version 0, 99) and missing schema_version batch rollback, proved idempotent replay across varying page sizes. 171/171 tests green. |
| 2026-10-17 | `test/amount-precision-boundary` (#36) | sdk | DONE: M2-21 | Pin amount precision boundary at `i128` and `NUMERIC(39,0)` limits: characterise as-is behaviour of `toBaseUnits`/`fromBaseUnits` at `2^127-1`, `2^127`, 39-digit (`NUMERIC(39,0)` max), 40-digit, and `i128::MAX/10^7` boundaries without rounding; verify write path stops on `NUMERIC(39,0)` overflow in Postgres; no `number` type on money paths. 173 tests passing. |
| 2026-10-08 | `chore/roadmap-copy-back` (#39) | sdk | no row changes | Copy-back run: `ROADMAP.md` replaced with the merged canonical (`.github` main as of #31) in repo-root link form, and §3 recomputed with `scripts/roadmap-progress`. This is the step `roadmap-merge`'s header requires after every merge and that was skipped between 2026-10-06 and 2026-10-08, which is how the seven copies reached 92 divergent statuses. Verified in this checkout: the file equals canonical byte for byte apart from this entry and the ADR link prefix, `W-05` reads `DONE`, the seven Wave rows are present, duplicate row-ID scan is 0. No row, status, priority, dependency or **Done when** was authored in this repo. |
| 2026-10-08 | `fix/roadmap-merge-link-anchor` | org | no row changes | Found while preparing the copy-back. `roadmap-merge`'s read normalization rewrote the docs-rooted ADR link form into the root-relative one on every copy so the two depths compare equal — correct for links, wrong for prose: the union entry above quotes both forms, so reading that line collapsed its own quote and emitted a Changelog entry contradicting itself, in a copy that no longer matched canonical line for line. Fixed by anchoring the replace on the numeric ADR filename that always follows the slash, so only real links are rewritten, and by re-wording the union entry to name the two forms as `docs/adr/` and `adr/` rather than spelling them as link text: **an entry that describes this rewrite must not itself be a string the rewrite can act on.** Verified: the anchored read leaves a quoted form byte-identical where the blanket replace corrupted it; a full `roadmap-merge` over all five copies against `b12d290` exits 0 with **0 lines** differing from canonical, which also confirms the union is complete; the one real link (`ADR-0026`) still normalizes both ways. No row, status, priority, dependency or **Done when** in this diff. |
Expand Down
8 changes: 4 additions & 4 deletions services/indexer/src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
* Must accept every schema_version the contract has ever emitted; anything else stops ingestion.
*/
import { declinedV1 } from "./declined.js";
import { lockCreatedV1 } from "./lock-created.js";
import { lockCreatedV1, lockCreatedV2 } from "./lock-created.js";
import { payeeRegisteredV1 } from "./payee-registered.js";
import { payeeStatusChangedV1 } from "./payee-status-changed.js";
import { payoutUpdatedV1 } from "./payout-updated.js";
import { refundedV1 } from "./refunded.js";
import { releasedV1 } from "./released.js";
import { releasedV1, releasedV2 } from "./released.js";
import {
type DecodedEvent,
type EventHandler,
Expand All @@ -20,8 +20,8 @@ const HANDLERS: Record<EventType, Record<number, EventHandler>> = {
PayeeRegistered: { 1: payeeRegisteredV1 },
PayeeStatusChanged: { 1: payeeStatusChangedV1 },
PayoutUpdated: { 1: payoutUpdatedV1 },
LockCreated: { 1: lockCreatedV1 },
Released: { 1: releasedV1 },
LockCreated: { 1: lockCreatedV1, 2: lockCreatedV2 },
Released: { 1: releasedV1, 2: releasedV2 },
Refunded: { 1: refundedV1 },
Declined: { 1: declinedV1 },
};
Expand Down
5 changes: 5 additions & 0 deletions services/indexer/src/handlers/lock-created.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ export const lockCreatedV1: EventHandler = async (db, event, ctx) => {
})),
);
};

/** Forward-compatible hypothetical v2 shape for M2-10/M2-14 coverage. */
export const lockCreatedV2: EventHandler = async (db, event, ctx) => {
return lockCreatedV1(db, event, ctx);
};
5 changes: 5 additions & 0 deletions services/indexer/src/handlers/released.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ export const releasedV1: EventHandler = async (db, event) => {
.set({ released, state: released === lock.total ? "Completed" : "Open" })
.where(eq(locks.id, id));
};

/** Forward-compatible hypothetical v2 shape for M2-10/M2-14 coverage. */
export const releasedV2: EventHandler = async (db, event, ctx) => {
return releasedV1(db, event, ctx);
};
Loading
Loading