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: 6 additions & 2 deletions docs/PROJECT-MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

Stateless WebSocket router between mobile clients and pyry binaries. Internet-exposed; adversarial input is the default assumption. Authoritative wire spec lives in `pyrycode/pyrycode/docs/protocol-mobile.md`.

> **READ-ONLY FOR AGENTS (as of 2026-05-11).** All five pipeline agents have explicit "Never Update docs/PROJECT-MEMORY.md" rules. Per-ticket content (implementation, patterns, lessons) goes in [`docs/knowledge/codebase/<ticket>.md`](knowledge/codebase/). Humans maintain this file directly.

## What's built

> **Convention (2026-05-10 onwards):** Per-ticket implementation summaries live in [`docs/knowledge/codebase/<ticket-number>.md`](knowledge/codebase/), one file per ticket. The table below is pre-2026-05-10 history — frozen, kept for context. See [`docs/knowledge/codebase/README.md`](knowledge/codebase/README.md) for the convention rationale.
> **FROZEN.** Pre-2026-05-10 history. Per-ticket implementation summaries live in [`docs/knowledge/codebase/<ticket-number>.md`](knowledge/codebase/). The table below is kept for context — do not append.

| Area | Status | Where |
|---|---|---|
Expand All @@ -25,7 +27,9 @@ Stateless WebSocket router between mobile clients and pyry binaries. Internet-ex
| `conn_id` generation scheme | Not started | — |
| Threat model doc — operational surface (deploy, supply chain, DoS, log hygiene, cert handling, TLS, error leakage) | Done (#11) | `docs/threat-model.md` |

## Patterns established
## Patterns established (frozen 2026-05-11)

> **FROZEN.** Pre-2026-05-11 patterns. New per-ticket patterns live in `docs/knowledge/codebase/<N>.md`. Do not append here.

- **Sentinel errors, branched via `errors.Is`** for validation failures at protocol boundaries. New routing-layer code follows the `Err...` naming and wraps with `fmt.Errorf("…: %w", err, sentinel)` when adding context.
- **Opacity by type.** Inner-frame payloads are carried as `json.RawMessage`. The relay never deserialises payloads; the type makes that hard to violate accidentally.
Expand Down
13 changes: 9 additions & 4 deletions docs/knowledge/codebase/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
# Per-Ticket Codebase Notes

One file per ticket: `<ticket-number>.md`. Each file describes what was built for that ticket — the bullets that historically went into `docs/PROJECT-MEMORY.md`'s "What's Built" section.
One file per ticket: `<ticket-number>.md`. Each file describes what was built for that ticket — **implementation summary, patterns established, AND lessons learned** all live in this per-ticket file.

## Convention

- **Filename**: `<ticket-number>.md` (e.g. `5.md`, `21.md`). Numeric only — no prefix, no description in the filename.
- **One file per ticket.** Never edit a sibling ticket's file.
- **Never modify `docs/PROJECT-MEMORY.md`'s "What's Built" section.** It holds frozen pre-2026-05-10 history; new work lives here.
- **Never modify `docs/PROJECT-MEMORY.md`.** All sections in that file are frozen as of 2026-05-11. New work lives here.
- **Never append to `docs/lessons.md`.** Frozen 2026-05-11. New lessons surface as a "Lessons learned" section inside the relevant `<ticket>.md`.
- **Directory listing IS the index.** `ls docs/knowledge/codebase/` sorted is reverse-chronological-ish (issue numbers monotonic). No separate index file to maintain.

## Why

Parallel docs agents writing to the same line in `PROJECT-MEMORY.md`'s "What's Built" caused recurring merge conflicts in the canonical pyrycode pipeline (2026-05-09 Phase 3 batch — 3 stuck PRs; 2026-05-10 — 2 more stuck PRs). Per-ticket files eliminate the hot line entirely — two concurrent docs runs never touch the same file.
Shared-append docs (whether `PROJECT-MEMORY.md`'s sections or `lessons.md`) cause recurring merge conflicts via three failure modes:

Pyrycode-relay's pipeline is younger but inherits the same convention for consistency, so the docs agent prompt is portable and the failure mode never surfaces here.
- **Concurrent docs** — two cycles' documentation agents both append at the same anchor → add/add conflict. Fixed by `serial: true` in v1 dispatcher `2d6b4ee`.
- **Stale-branch + marched-forward main** — feature/B appends based on B's snapshot, while feature/A merges with its own appended section first. When B tries to merge, B has no record of A's entry → conflict. `serial: true` doesn't fix this; only rebase does.
- **Cross-phase bleeding** — developer writes to PROJECT-MEMORY.md in feat commits (not just documentation), bypassing the doc-phase serial protection entirely.

Incidents this convention prevents: 2026-05-09 pyrycode Phase 3 batch (3 PRs stuck), 2026-05-10 pyrycode (#260/PR #266, #255/PR #259), 2026-05-11 v2 pipeline (4 stranded PRs on `docs/PROJECT-MEMORY.md`). Per-ticket files eliminate the hot line entirely — two cycles never touch the same file, stale-branch conflicts impossible by construction.

See `pyrycode/agent-dispatcher#1` for the rollout history.

Expand Down
8 changes: 6 additions & 2 deletions docs/lessons.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Lessons
# Lessons (frozen)

Gotchas worth carrying forward. Each entry: what bit us (or nearly did), and what we do about it.
**Frozen 2026-05-11.** This file is historical reference only. New lessons go into the relevant ticket's `docs/knowledge/codebase/<N>.md` under a "Lessons learned" section.

The pre-2026-05-11 entries below were collected before the per-ticket file convention. They remain unchanged so existing cross-references still resolve. Future tickets do not append here — the per-ticket file convention eliminates the shared-append conflict surface (same fix shape as `PROJECT-MEMORY.md`'s sections, frozen the same day).

---

## `time.Timer.Stop()` returns false if the func has already started — a mutex alone won't save you

Expand Down