From cc24c78e17dcc95fdb241ca5f86cb6ed053d7655 Mon Sep 17 00:00:00 2001 From: abrcrmb Date: Thu, 8 Oct 2026 20:22:56 +0100 Subject: [PATCH] docs(contributing): adopt the org Wave issue template Replaces ISSUE_TEMPLATE/wave-task.md with the single Kinlock issue format (including the mandatory context review that binds contributors to PRD.md, ARCHITECTURE.md and the AGENTS.md constraints before they write code), and adds the seven roadmap rows the seeded Wave backlog maps to, byte-identically across all five ROADMAP.md copies. W-05 is an org row and stays TODO here. --- .github/ISSUE_TEMPLATE/wave-task.md | 118 ++++++++++++++++++++++++++-- ROADMAP.md | 18 +++-- 2 files changed, 125 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/wave-task.md b/.github/ISSUE_TEMPLATE/wave-task.md index 12416fb..d51ab02 100644 --- a/.github/ISSUE_TEMPLATE/wave-task.md +++ b/.github/ISSUE_TEMPLATE/wave-task.md @@ -1,15 +1,121 @@ --- name: Wave task -about: A scoped task for Drips Wave contributors +about: A scoped, self-contained task for an external or bounty-program contributor labels: wave --- -**Roadmap row**: + -**Task** +**Seeded:** YYYY-MM-DD -**Done when** +## Task -**Files in scope** (no security-sensitive paths) +One to three sentences: what to build or fix, and what the world looks like when it is done. -**How to verify** (commands to run) +## Context + +Where this sits today, with `path:line` evidence for each claim. Name the `docs/ARCHITECTURE.md` +sections the task touches, because the mandatory review below points at them. + +- + +## Before you start: mandatory context review + +Kinlock moves other people's money, so the docs are **binding constraints, not background reading**. +They record decisions this task must not silently reopen. Read them in this order and tick each box: + +- [ ] `docs/ARCHITECTURE_ESSENTIALS.md` — start here, it is short (`AGENTS.md` §1) +- [ ] `docs/ARCHITECTURE.md` — only the sections named in **Context** above +- [ ] `docs/PRD.md` — if this task touches user-facing behaviour or scope +- [ ] `AGENTS.md` §3 (hard rules), §4 (deferred list), §8 for this repo, §12 (roadmap rule) +- [ ] `ROADMAP.md` — the row(s) listed under **Related roadmap rows**, including their **Depends on** + +In your first PR comment, name the hard-rule numbers or doc sections that constrain this task. That +line is how we know the review happened. + +Then: +- If code and docs disagree, or two docs disagree: **stop and say so on this issue.** Do not pick one + silently, and do not "fix" either side without approval (`AGENTS.md` §1). +- If the task looks like it needs anything from the deferred list (§4), a change to a hard rule (§3), + or a **new dependency** (§2): raise it here first. Those need a human; deciding them is not your job. +- If a row you are told to finish is `BLOCKED` or depends on a row that is not `DONE`, say so here + instead of starting. + +## Why we need this + +Two to four bullets. Say which commitment this serves: a hard rule (§3), a gate, a pilot need, or a +row's **Done when**. If the honest answer is "nicer", the issue is not ready to be filed. + +- + +## Scope + +**In scope** +- + +**Do not touch** (security-sensitive or generated; changing these needs a human first — `AGENTS.md` §2, `docs/project_structure.md` §8) +- + +## Suggested implementation + +Numbered steps, with the read-first documents in step 1. Say explicitly that an alternative approach +is welcome and should be posted on the issue before building. + +1. + +## Done means + +Binary and checkable, one line each. Anything a reviewer cannot verify by looking is not a criterion. + +- [ ] + +## Tests + +What to add, what not to weaken, and which existing cases must stay untouched. State the rule: no +skipped tests, no relaxed assertions, no deleting a fixture to make a case fit. + +## Documentation + +Which doc or ADR changes with this task, or "None" — and if the behaviour changes, "None" is wrong. + +## Verify before you open the PR + +Every command, in the order that works, so a contributor on a clean machine is not guessing. + +``` +``` + +Run every command and paste the real output in the PR. We do not accept "should pass" — +`AGENTS.md` §6: *"You actually ran the commands."* + +## Opening the pull request + +- Branch `feat/…`, `fix/…`, `docs/…`, `test/…` or `chore/…`; Conventional Commit subject. +- Update `ROADMAP.md` in the same PR (`AGENTS.md` §12): row status, a Changelog entry, `Last updated`. + CI fails a PR without it. Only rows owned by this repo. +- Follow `.github/PULL_REQUEST_TEMPLATE.md` (`AGENTS.md` §7); in "Hard rules / invariants touched", + give numbers, not prose. +- One logical change. Do not reformat or touch files outside **Scope**. +- Do not add the `security-sensitive` label — that is the maintainer's flag for contract-logic PRs. +- Never commit to `main`; open a PR. Never force-push. + +## Tier and effort + +`tier/trivial` | `tier/medium` | `tier/high` · roughly \. Definitions and the Wave +point mapping: `docs/wave-issue-format.md` in `Kinlock-Org/.github`. + +## Related roadmap rows + +`ID` — row description (status). New rows created for a batch of issues are listed with the PR that +added them. + +## Questions + +Answer time for this repo, and the claim protocol ("I'll take this"), plus the instruction to post a +draft PR when stuck rather than going quiet. diff --git a/ROADMAP.md b/ROADMAP.md index c7ed39f..c401c6d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,7 +4,7 @@ | | | |---|---| -| **Last updated** | 2026-10-08 (all copies reconciled with `scripts/roadmap-merge`; readiness 41%) | +| **Last updated** | 2026-10-08 (Wave issue template adopted; rows M1-38..M1-41, M2-20, M2-21, M3-27 added; W-05 left TODO — org row, resolved by .github#26) | | **Docs baseline** | v0.3, worldwide scope (`PRD.md`, `ARCHITECTURE.md`, `ARCHITECTURE_ESSENTIALS.md`, `AGENTS.md`, `CLAUDE.md`, `project_structure.md`) | | **Current phase** | Phase 0 (Foundations) → starting Phase 1 (M0 Validate) | | **Readiness** | See [§3](#3-progress-snapshot) | @@ -129,9 +129,9 @@ 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 | 37 | 24 | 3 | 10 | 0 | 0 | 0 | 65% | -| 3 SDK + indexer | 19 | 14 | 3 | 2 | 0 | 0 | 0 | 74% | -| 4 App | 26 | 15 | 7 | 4 | 0 | 0 | 0 | 58% | +| 2 Contract + registry | 41 | 24 | 3 | 14 | 0 | 0 | 0 | 59% | +| 3 SDK + indexer | 21 | 14 | 3 | 4 | 0 | 0 | 0 | 67% | +| 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% | | 7 Hardening | 26 | 0 | 0 | 26 | 0 | 0 | 0 | 0% | @@ -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 | 4 | 1 | 5 | 0 | 0 | 0 | 40% | | 11 Deferred parking lot | 16 | 0 | 0 | 0 | 0 | 16 | 0 | n/a | -| **All** | **204** | **74** | **21** | **84** | **0** | **25** | **0** | **41%** | +| **All** | **211** | **74** | **21** | **91** | **0** | **25** | **0** | **40%** | --- @@ -241,6 +241,10 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P | M1-35 | Spec decisions from the vault review: tranches with `unlock_at == expires_at` can never be released; suspend/re-activate toggling restarts the sender's refund grace | contracts | P1 | TODO | — | ADR accepted; code and tests follow it | | M1-36 | Failed token transfers surface the token's error code, which collides with Kinlock codes (SAC code 10 decodes as `PayeeAlreadyExists`); decide on a dedicated error or document it for the SDK | contracts | P1 | TODO | — | Decision recorded; SDK handles it | | M1-37 | Script the local-network setup (identities, local USDC, contract, attester, token, one payee) so anyone can run the SDK smoke test locally | contracts | P1 | DONE | M2-02 | One command on a fresh local network prints the env block; the SDK smoke test passes with it | +| M1-38 | Property harness asserts invariants 5, 6 and 8 directly in `check_invariants`, not only through the operation gates | contracts | P1 | TODO | M1-14 | Each has a named assertion; a deliberately weakened gate is caught; `src/` untouched | +| M1-39 | Contract surface reference: `docs/ERRORS.md` (every `#[contracterror]` code) and `docs/EVENTS.md` (all seven events with fields and `schema_version`) | contracts | P1 | TODO | M1-02 | Both pages exist in canonical docs; counts match `errors.rs` and `events.rs`; `sync-docs.sh --check` passes | +| M1-40 | Registry validator boundary-fixture corpus: 0-, 2- and 3-decimal `local_currency`, non-Latin and right-to-left `display_name`, `slug` at its length limit, rejected `payout_address` forms | registry | P1 | TODO | M1-24, M1-27 | Each rule has a fixture that exercises it; rejections asserted by message; at least three countries represented | +| M1-41 | `validate` reports every rule failure in one run instead of stopping at the first | registry | P2 | TODO | M1-40 | A record with three violations lists all three with file, rule id and fix hint; deterministic output; existing cases unedited | ### 6.2 `kinlock-registry` @@ -281,6 +285,8 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P | M2-17 | SDK docs and API reference; publish testnet package versions | sdk | P0 | DONE | M2-07 | Published; docs match exports | | M2-18 | Indexer container, testnet deployment, managed Postgres, daily backups | sdk | P0 | IN PROGRESS | M2-14 | Running on testnet; restore tested once | | M2-19 | Indexer and list API: store and filter payees by `country` and `local_currency` (display and filter only) | sdk | P0 | DONE | M2-13, M1-29 | `/payees?country=` works; no country logic elsewhere | +| M2-20 | Public HTTP reference for the list API (`services/indexer/docs/API.md`) with a route-parity test | sdk | P1 | TODO | M2-12 | All five routes documented with units and chain-vs-indexer labelling; renaming a route without editing the doc fails a test | +| M2-21 | Amount precision boundary pinned at the `i128` and `NUMERIC(39,0)` limits; any SDK-side guard approved on the issue first | sdk | P1 | TODO | M2-07 | Boundary cases tested and as-is behaviour recorded; no money path uses `number` | --- @@ -317,6 +323,7 @@ Readiness % = `DONE ÷ (all rows − DEFERRED − DROPPED)`. Conditional rows (P | M3-24 | CI guard: fail on hard-coded country, currency, anchor, or locale literals outside registry data, tests, and fixtures | all | P1 | DONE | M3-01, M2-01 | Guard runs in app and sdk CI; passing and failing examples tested | | M3-25 | Favicon/app icon, persistent site header (nav, docs and GitHub links), mobile hamburger menu, reduced-motion-safe entrance motion | app | P2 | DONE | M3-01, M3-04 | Favicon set in every browser; nav usable one-handed on a narrow viewport; `prefers-reduced-motion` honored | | M3-26 | Interim chain-verified payee source for `/send` and `/request`, since no indexer is deployed (`M2-18`) | app | P1 | DONE | M3-05, M3-06 | `/send` and `/request` list real, on-chain `Active` payees and complete their flow up to wallet connect; **retired 2026-10-08**, superseded now that `M2-18`'s indexer is live (code removed, pages point at the real indexer again) | +| M3-27 | Route-level `loading.tsx`, `error.tsx` and `not-found.tsx` for the user-facing routes | app | P1 | TODO | M3-01 | Every in-scope route has a designed pending/error/404 state; no stack trace or file path reaches the UI; `/claim/*` untouched | --- @@ -528,6 +535,7 @@ Newest first. One entry per PR. Required for every contribution (see §2). | Date | PR / ref | Repo | Rows touched | Summary | |---|---|---|---|---| +| 2026-10-08 | `docs/wave-issue-format` (org side: `.github` #26) | app | Added `M3-27` (this repo); `M1-38`, `M1-39`, `M1-40`, `M1-41`, `M2-20`, `M2-21` mirrored for copy parity; `W-05` left `TODO` (org row) | Adopted the single org issue format and seeded the app half of the Wave backlog: #37 → `M3-27`, #38 and #39 → `M3-17`, #40 → `M3-15`, #41 → `M3-18`, #42 → `M3-12`. Seven rows byte-identical across all five `ROADMAP.md` copies. | | 2026-10-08 | `chore/roadmap-reconcile` | org | canonical: 43 statuses corrected, rows M1-37 / M3-25 / M3-26 added; each repo copy: 36-52 statuses corrected, rows W-09 / W-10 added | First run of `scripts/roadmap-merge` (F-15) since the copies diverged at c488967 (2026-10-06). Three-way merge against that revision as ancestor: rows owned by a repo taken from that repo's copy, `org` / `all` rows from whichever copy changed them relative to the ancestor. One conflict adjudicated by hand: **F-11** - the canonical copy's reword and `DONE` (bea228e, ADR-0026) supersedes every repo copy's stale `IN PROGRESS`. **DEC-03** differed only in its ADR link prefix (`adr/` under `docs/`, `docs/adr/` at a repo root); `roadmap-merge` now normalizes that on read, so a path difference is never reported as a conflict. Root cause: each copy only ever advanced its own repo's rows, so every copy was stale for every other repo's rows too - 92 divergent statuses across the seven copies. Also corrects PR #25's changelog row, which was dated 2026-10-09 although the merge ran 2026-10-08 UTC. Progress table regenerated with `scripts/roadmap-progress`: **74 of 204 rows DONE, 41% readiness** | | 2026-10-08 | `feat/m3-24-country-agnostic-guard` | app | DONE: M3-24 | `M3-24` is a cross-cutting row ("all"); this PR plus a matching one in `kinlock-sdk` (PR #32 there) together complete it, so both mark it `DONE`. Added `lib/country-agnostic.test.ts`: fails if `nigeria`, `naira`, `ngn`, or `lagos` (case-insensitive, whole-word) appears anywhere under `app/`, `components/`, `lib/`, or `messages/`, excluding `*.test.ts`/`*.test.tsx`. Grounded in `AGENTS.md`'s own quick-reference wording ("Don't assume Nigeria or naira in code, tests, fixtures, or copy"), not a general country/currency-word ban, since this app's fixtures and UI deliberately exercise several real markets side by side (`messages/en.json` is included, since "copy" is explicitly in scope per that same rule). `docs/PRD.md`/`docs/ARCHITECTURE.md` are out of scope, since they legitimately narrate the pre-v0.3 "abroad to Nigeria" history. Runs via the existing `pnpm test` step already in CI, mirroring `lib/i18n/inline-strings.test.ts`'s existing pattern for a different check: no CI workflow changes needed. Verified the guard can actually fail: temporarily added a real violation to `lib/constants.ts`, confirmed it was caught with the exact term and file named, reverted (`git diff` empty), confirmed a clean pass. `pnpm lint`, `pnpm typecheck`, `pnpm test` (166/166), `pnpm build` all green | | 2026-10-08 | `feat/m3-14-fragment-leak-test` | app | DONE: M3-14 | The security headers, strict CSP, and no-third-party-scripts work was already built (`proxy.ts`, `lib/security/csp.ts`); the row's actual "Done when" (an automated test confirming the claim-link fragment never appears in any network request) didn't exist, and `lib/security/csp.test.ts` only unit-tests the CSP string builder, not real runtime behavior. Added `e2e/claim-fragment-privacy.spec.ts`: loads `/claim/11` (a real, already-existing testnet lock) with a real-shaped fragment, captures every outbound request for the page's lifetime (URL, body, headers), and fails if the reference or salt appears anywhere. Configured `playwright.config.ts` with a `webServer` (`pnpm build && pnpm start`, since `/claim/*`'s CSP differs between dev and production) and a `baseURL`, neither of which existed before. Verified the test can actually fail, not just trivially pass: temporarily injected a real leak into `useClaim.ts` (a stray `fetch` echoing the reference and salt), confirmed the test caught it with a clear diagnostic, then reverted (`git diff` confirms byte-identical to before) and confirmed a clean pass on the real code. Also caught and fixed two test-design bugs along the way: an invalid (non-`generateSalt()`-shaped) test salt silently made `parseClaimLink` throw before any of the code under test ran, and `waitForLoadState("networkidle")` never resolves on this page (it polls), so switched to a fixed wait. Verified: `pnpm lint`, `pnpm typecheck`, `pnpm test` (108/108), `pnpm build`, and the E2E test itself, run manually multiple times. **Not done here**: wiring this into CI. `.github/workflows/e2e.yml` is marked `DRAFT (ask-first: CI)` and currently just echoes a placeholder; actually running `pnpm e2e` there needs a human to approve editing the workflow file, per `AGENTS.md`'s CI/CD ask-first rule. No new secrets needed (all required env vars are the existing public `NEXT_PUBLIC_*` testnet config) |