diff --git a/.claude/skills/resolving-issues/SKILL.md b/.claude/skills/resolving-issues/SKILL.md index a6d16629..035fdd70 100644 --- a/.claude/skills/resolving-issues/SKILL.md +++ b/.claude/skills/resolving-issues/SKILL.md @@ -47,7 +47,18 @@ Why this shape: 3. Skip big features + major refactors. Out of scope. 4. No in-scope issues? Noop. Skip the rest. No master branch created, no PR opened. 5. Create fresh master branch (see ## Master Branch Setup). -6. Per issue, sequential, max 10 per run: +6. **Coordinator-direct already-fixed sweep (run BEFORE any implementer dispatch).** For each picked issue, before dispatching, scan recent merged commits + closing PRs against the issue's scope: + - `git log --oneline ..origin/main -- ` to find candidate fix commits + - `mcp__github__search_pull_requests` w/ issue keywords for closure-by-PR cases + - cross-check against recent general-audit master tickets ("verified fixed by ..." entries) + + If the issue is resolved by a landed change, do the close pass directly — no implementer dispatch: + - caveman comment on the issue citing the upstream commit / PR + the fix location + - close `completed` (audit intent now holds) or `not_planned` (audit premise moot) + - record under `## Already-Fixed` for master PR body + + Closing GH issues = metadata work, not code work; allowed under "coordinator never codes." Implementers only dispatch for *unresolved* issues. This pass typically clears audit lessons (already folded into skills), structural-deps follow-ups (still structural), and audit findings closed by intervening fixes — saves dispatch overhead on no-op work. +7. Per remaining issue, sequential, max 10 per run: - **Pre-dispatch sync:** before spawning each implementer, in the coordinator's checkout: ```bash git fetch origin @@ -56,11 +67,11 @@ Why this shape: Prior implementers' commits must be the implementer's base; stale local state poisons the next dispatch. - Spawn fresh implementer agent (see ## Implementer Agent below). - Implementer commits directly to master branch and pushes. No worktree, no sub-PR. - - Track `Fixes #N` for final PR body assembly. **Already-fixed-upstream** issues go under `## Already-Fixed`, not `Fixes`. + - Track `Fixes #N` for final PR body assembly. - Next issue. -7. Implementer finds related rot? File follow-up issue. -8. Apply Lessons Learned skill edits to `.claude/skills/resolving-issues/SKILL.md`, commit on master branch, push. (Coordinator does this directly — see ### Coordinator never codes.) -9. Open the master PR — **ready (not draft)** — base `main`, head master branch. Body: `Fixes #N` list + `## Already-Fixed` + `## Parked` + `## Skill Evolution` + `## Lessons Learned`. Master PR runs full CI; human merges when satisfied. If anything's unfinished, leave the branch un-PR'd instead of opening a draft. +8. Implementer finds related rot? File follow-up issue. +9. Apply Lessons Learned skill edits to `.claude/skills/resolving-issues/SKILL.md`, commit on master branch, push. (Coordinator does this directly — see ### Coordinator never codes.) +10. Open the master PR — **ready (not draft)** — base `main`, head master branch. Body: `Fixes #N` list + `## Already-Fixed` + `## Parked` + `## Skill Evolution` + `## Lessons Learned`. Master PR runs full CI; human merges when satisfied. If anything's unfinished, leave the branch un-PR'd instead of opening a draft. ## Implementer Agent diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22b3c2fd..45893c93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,6 +110,7 @@ jobs: - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: targets: wasm32-unknown-unknown + components: clippy - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | @@ -119,6 +120,8 @@ jobs: key: wasm-${{ hashFiles('**/Cargo.lock') }} restore-keys: wasm- - run: cargo check --target wasm32-unknown-unknown --workspace --exclude willow-relay --exclude willow-worker --exclude willow-replay --exclude willow-storage --exclude willow-agent + - name: Clippy (wasm32, willow-web) + run: cargo clippy --target wasm32-unknown-unknown -p willow-web --all-targets -- -D warnings browser: name: Browser tests (wasm-pack + Firefox) diff --git a/crates/web/src/components/message_row/day_separator.rs b/crates/web/src/components/message_row/day_separator.rs index 2c0dcb80..2547680f 100644 --- a/crates/web/src/components/message_row/day_separator.rs +++ b/crates/web/src/components/message_row/day_separator.rs @@ -111,8 +111,9 @@ pub fn day_bucket(ts_ms: u64) -> DayBucket { use wasm_bindgen::JsValue; // Out-of-range timestamps make `js_sys::Date` accessors return NaN; - // the `as i32` / `as u32` casts then collapse to 0, which would index - // into `WEEKDAYS`/`MONTHS` and produce a bogus "sunday · 0 january" + // the `as i32` cast (and the implicit `u32` return on `get_month` / + // `get_date`) then collapse to 0, which would index into + // `WEEKDAYS`/`MONTHS` and produce a bogus "sunday · 0 january" // label. Bail to a stable fallback variant instead. if ts_ms > MAX_VALID_TS_MS as u64 { return DayBucket::Older { @@ -127,11 +128,11 @@ pub fn day_bucket(ts_ms: u64) -> DayBucket { let now = js_sys::Date::new_0(); let ts_y = ts.get_full_year() as i32; - let ts_m = ts.get_month() as u32; + let ts_m = ts.get_month(); let ts_d = ts.get_date(); let now_y = now.get_full_year() as i32; - let now_m = now.get_month() as u32; + let now_m = now.get_month(); let now_d = now.get_date(); if (ts_y, ts_m, ts_d) == (now_y, now_m, now_d) { @@ -152,7 +153,7 @@ pub fn day_bucket(ts_ms: u64) -> DayBucket { 0, ); let y_y = yesterday.get_full_year() as i32; - let y_m = yesterday.get_month() as u32; + let y_m = yesterday.get_month(); let y_d = yesterday.get_date(); if (ts_y, ts_m, ts_d) == (y_y, y_m, y_d) { return DayBucket::Yesterday;