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
21 changes: 16 additions & 5 deletions .claude/skills/resolving-issues/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <last-audit-ref>..origin/main -- <relevant paths>` 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 <master-branch>
Expand All @@ -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

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand All @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions crates/web/src/components/message_row/day_separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -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;
Expand Down