From e411cbf3c3d9d8fd7e84b4e50d3b516a4947279f Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 7 Jun 2026 13:39:32 +0200 Subject: [PATCH 1/3] Make CLAUDE.md import AGENTS.md as single source of truth AGENTS.md becomes the canonical instructions file; CLAUDE.md is now a one-line @AGENTS.md import so the two never drift. Also folds the runs table audit-trail paragraph (previously only in CLAUDE.md) into AGENTS.md so no content is lost in the consolidation. --- AGENTS.md | 38 ++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 39 +-------------------------------------- 2 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7e6b22e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,38 @@ +# Core principle: never lose track of content + +Squirrel indexes **content** (BLAKE3 hashes), not paths. A hash that has ever been observed must remain retrievable from the index. Paths are observations of content; content is the entity. + +The v4 schema enforces this: the `files` PK is `(volume_id, path, blake3)`, status is one of `present`/`missing`/`superseded`, and per `(volume_id, path)` at most one row is non-superseded. When content at a path changes, `Upsert` flips the prior row to `superseded` and inserts a new row — `blake3` is never rewritten in place. Any new feature (sync, pruning, dedup, GC) must preserve this rule: don't delete or overwrite historical rows without an explicit, opt-in retention policy. + +The same applies to the `runs` table: squirrel never auto-prunes runs — the run history is an audit trail, and any retention is explicit and operator-driven only. + +# Code quality reminders + +Don't: +- Export test helpers when tests are in the same package +- Write functions over ~50 lines — decompose by phase +- Put multiple cobra subcommands in one file +- Leave unused fields or flags in public types +- Write to `os.Stderr`/`os.Stdout` from library packages — surface via return values +- Concatenate user input into DSNs or URLs +- Route ambiguous inputs by syntax alone — check authoritative state first +- Index low-cardinality columns; prefer partial indexes +- Skip `go mod tidy` after adding a dependency +- Preserve names or visibility blindly when moving code — re-evaluate + +# Pull request conventions + +When opening a PR that completes one or more issues, include a closing keyword per issue in the PR body (`Closes #19`, or `Closes #19, Closes #20` for several). GitHub auto-closes the linked issues on merge. Use `Closes` only when the PR completes the issue in full — for partial work, reference the issue without the closing keyword. + +Always preserve individual PR commits on merge — never squash. The per-commit history is the audit trail (review fixes, CI fix-ups, refactor steps) and collapsing it loses information that may matter later. + +# Default workflow for issue implementations + +When asked to implement an issue (e.g. "implement #19"), unless instructed otherwise, do all of the following: + +1. Implement on a feature branch, following the principles above. +2. Open a PR with `Closes #N` in the body. +3. After pushing, self-review for code quality: dead code, oversize functions, accidental scope creep, anything that violates AGENTS.md. Push fixes for what you find. +4. After opening the PR, start watching its activity feed automatically — don't ask first — so CI results, automated reviews (e.g. Copilot), and other events arrive as they happen. Cap the watch at 10 minutes total: if CI and review threads aren't settled by then, unsubscribe, tell the user you stopped watching, and wait for direction. On CI failure within the window, diagnose and push a fix. On review comments, address legitimate findings by pushing fixes; reply briefly to dismiss anything that's incorrect or out of scope. +5. Once CI is green and any automated review threads are resolved, surface readiness to the user. +6. Stop and wait for explicit approval before merging — never self-merge. diff --git a/CLAUDE.md b/CLAUDE.md index e1c1a33..43c994c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,38 +1 @@ -# Core principle: never lose track of content - -Squirrel indexes **content** (BLAKE3 hashes), not paths. A hash that has ever been observed must remain retrievable from the index. Paths are observations of content; content is the entity. - -The v4 schema enforces this: the `files` PK is `(volume_id, path, blake3)`, status is one of `present`/`missing`/`superseded`, and per `(volume_id, path)` at most one row is non-superseded. When content at a path changes, `Upsert` flips the prior row to `superseded` and inserts a new row — `blake3` is never rewritten in place. Any new feature (sync, pruning, dedup, GC) must preserve this rule: don't delete or overwrite historical rows without an explicit, opt-in retention policy. - -The same applies to the `runs` table: squirrel never auto-prunes runs — the run history is an audit trail, and any retention is explicit and operator-driven only. - -# Code quality reminders - -Don't: -- Export test helpers when tests are in the same package -- Write functions over ~50 lines — decompose by phase -- Put multiple cobra subcommands in one file -- Leave unused fields or flags in public types -- Write to `os.Stderr`/`os.Stdout` from library packages — surface via return values -- Concatenate user input into DSNs or URLs -- Route ambiguous inputs by syntax alone — check authoritative state first -- Index low-cardinality columns; prefer partial indexes -- Skip `go mod tidy` after adding a dependency -- Preserve names or visibility blindly when moving code — re-evaluate - -# Pull request conventions - -When opening a PR that completes one or more issues, include a closing keyword per issue in the PR body (`Closes #19`, or `Closes #19, Closes #20` for several). GitHub auto-closes the linked issues on merge. Use `Closes` only when the PR completes the issue in full — for partial work, reference the issue without the closing keyword. - -Always preserve individual PR commits on merge — never squash. The per-commit history is the audit trail (review fixes, CI fix-ups, refactor steps) and collapsing it loses information that may matter later. - -# Default workflow for issue implementations - -When asked to implement an issue (e.g. "implement #19"), unless instructed otherwise, do all of the following: - -1. Implement on a feature branch, following the principles above. -2. Open a PR with `Closes #N` in the body. -3. After pushing, self-review for code quality: dead code, oversize functions, accidental scope creep, anything that violates CLAUDE.md. Push fixes for what you find. -4. After opening the PR, start watching its activity feed automatically — don't ask first — so CI results, automated reviews (e.g. Copilot), and other events arrive as they happen. Cap the watch at 10 minutes total: if CI and review threads aren't settled by then, unsubscribe, tell the user you stopped watching, and wait for direction. On CI failure within the window, diagnose and push a fix. On review comments, address legitimate findings by pushing fixes; reply briefly to dismiss anything that's incorrect or out of scope. -5. Once CI is green and any automated review threads are resolved, surface readiness to the user. -6. Stop and wait for explicit approval before merging — never self-merge. +@AGENTS.md From 2eac48a845b7375c411ec99ec6248d41d212bb08 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 7 Jun 2026 13:47:34 +0200 Subject: [PATCH 2/3] Trim AGENTS.md: drop duplication and stale schema specifics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace the rotted schema description (it claimed v4 + files PK (volume_id, path, blake3); v7→v8 rebuilt files to (folder_id, name, blake3) and current SchemaVersion is 13) with the invariant plus a pointer to where it's actually enforced: the files_blake3_immutable trigger and uniq_files_live_per_path index in store/migrations.go. - Keep the never-squash rule as a one-liner so the repo file stands alone for agents that don't see a personal global config. - Fold the PR Closes convention and merge rule into one section; drop the redundant restatement in the workflow. - Add the CI-equivalent local verify command. Net ~40% smaller with no loss of load-bearing guidance. --- AGENTS.md | 56 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7e6b22e..8e54703 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,38 +1,46 @@ # Core principle: never lose track of content -Squirrel indexes **content** (BLAKE3 hashes), not paths. A hash that has ever been observed must remain retrievable from the index. Paths are observations of content; content is the entity. +Squirrel indexes **content** (BLAKE3 hashes), not paths. A hash ever observed +must stay retrievable. Paths are observations of content; content is the entity. -The v4 schema enforces this: the `files` PK is `(volume_id, path, blake3)`, status is one of `present`/`missing`/`superseded`, and per `(volume_id, path)` at most one row is non-superseded. When content at a path changes, `Upsert` flips the prior row to `superseded` and inserts a new row — `blake3` is never rewritten in place. Any new feature (sync, pruning, dedup, GC) must preserve this rule: don't delete or overwrite historical rows without an explicit, opt-in retention policy. +So `Upsert` never rewrites a row's `blake3` in place: when content at a path +changes it marks the prior row `superseded` and inserts a new one, keeping at +most one live (non-`superseded`) row per path. The same no-loss rule governs the +`runs` table and its history. The schema enforces it — the +`files_blake3_immutable` trigger and the `uniq_files_live_per_path` partial +unique index (`store/migrations.go`) — so any new feature (sync, prune, dedup, +GC) must preserve it: no deleting or overwriting history without an explicit, +opt-in retention policy. -The same applies to the `runs` table: squirrel never auto-prunes runs — the run history is an audit trail, and any retention is explicit and operator-driven only. - -# Code quality reminders +# Code quality Don't: -- Export test helpers when tests are in the same package +- Export test helpers when tests are in-package - Write functions over ~50 lines — decompose by phase - Put multiple cobra subcommands in one file -- Leave unused fields or flags in public types -- Write to `os.Stderr`/`os.Stdout` from library packages — surface via return values +- Leave unused fields/flags on public types +- Write to stdout/stderr from library packages — return values instead - Concatenate user input into DSNs or URLs -- Route ambiguous inputs by syntax alone — check authoritative state first -- Index low-cardinality columns; prefer partial indexes -- Skip `go mod tidy` after adding a dependency -- Preserve names or visibility blindly when moving code — re-evaluate - -# Pull request conventions +- Route ambiguous input by syntax alone — check authoritative state first +- Index low-cardinality columns — prefer partial indexes +- Forget `go mod tidy` after adding a dependency +- Keep names/visibility when moving code — re-evaluate -When opening a PR that completes one or more issues, include a closing keyword per issue in the PR body (`Closes #19`, or `Closes #19, Closes #20` for several). GitHub auto-closes the linked issues on merge. Use `Closes` only when the PR completes the issue in full — for partial work, reference the issue without the closing keyword. +Before pushing, verify like CI: `go vet ./...`, `go test ./...`, `golangci-lint run`. -Always preserve individual PR commits on merge — never squash. The per-commit history is the audit trail (review fixes, CI fix-ups, refactor steps) and collapsing it loses information that may matter later. +# Pull requests -# Default workflow for issue implementations +- `Closes #N` (one per issue) in the PR body — only when the PR fully closes + that issue; otherwise reference it without the keyword. +- Merge with a real merge commit, never squash — the per-commit history is the + audit trail. -When asked to implement an issue (e.g. "implement #19"), unless instructed otherwise, do all of the following: +# Issue workflow ("implement #N") -1. Implement on a feature branch, following the principles above. -2. Open a PR with `Closes #N` in the body. -3. After pushing, self-review for code quality: dead code, oversize functions, accidental scope creep, anything that violates AGENTS.md. Push fixes for what you find. -4. After opening the PR, start watching its activity feed automatically — don't ask first — so CI results, automated reviews (e.g. Copilot), and other events arrive as they happen. Cap the watch at 10 minutes total: if CI and review threads aren't settled by then, unsubscribe, tell the user you stopped watching, and wait for direction. On CI failure within the window, diagnose and push a fix. On review comments, address legitimate findings by pushing fixes; reply briefly to dismiss anything that's incorrect or out of scope. -5. Once CI is green and any automated review threads are resolved, surface readiness to the user. -6. Stop and wait for explicit approval before merging — never self-merge. +Unless told otherwise: +1. Work on a feature branch; open a PR (see Pull requests). +2. Self-review the diff against this file: dead code, oversize functions, scope creep. +3. Watch the PR feed automatically (don't ask) for up to 10 min: fix CI failures, + address legitimate review comments, briefly dismiss the rest. If it isn't + settled by 10 min, unsubscribe, say so, and wait. +4. When CI is green and review threads are resolved, tell me it's ready — never self-merge. From 249059c854cc40c87245513873d901fb7130c736 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 7 Jun 2026 13:55:16 +0200 Subject: [PATCH 3/3] AGENTS.md: address Copilot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Separate the files schema invariant (enforced by the files_blake3_immutable trigger + uniq_files_live_per_path index) from the runs retention rule (policy, not schema — runs is overwrite-in-place via FinishRun). The prior wording implied the trigger/index governed both tables. - Drop the 'verify like CI' framing: CI also runs go build (and a wailsdesktop build), which the local check intentionally omits. --- AGENTS.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8e54703..e378c0d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,12 +5,16 @@ must stay retrievable. Paths are observations of content; content is the entity. So `Upsert` never rewrites a row's `blake3` in place: when content at a path changes it marks the prior row `superseded` and inserts a new one, keeping at -most one live (non-`superseded`) row per path. The same no-loss rule governs the -`runs` table and its history. The schema enforces it — the -`files_blake3_immutable` trigger and the `uniq_files_live_per_path` partial -unique index (`store/migrations.go`) — so any new feature (sync, prune, dedup, -GC) must preserve it: no deleting or overwriting history without an explicit, -opt-in retention policy. +most one live (non-`superseded`) row per path. The schema enforces this on +`files` — the `files_blake3_immutable` trigger and the `uniq_files_live_per_path` +partial unique index (`store/migrations.go`). + +The `runs` table follows the same no-loss spirit by policy, not schema: squirrel +never auto-prunes runs — they're an audit trail, and any retention is explicit +and operator-driven. + +Any new feature (sync, prune, dedup, GC) must preserve both: no deleting or +overwriting history without an explicit, opt-in retention policy. # Code quality @@ -26,7 +30,7 @@ Don't: - Forget `go mod tidy` after adding a dependency - Keep names/visibility when moving code — re-evaluate -Before pushing, verify like CI: `go vet ./...`, `go test ./...`, `golangci-lint run`. +Before pushing: `go vet ./...`, `go test ./...`, `golangci-lint run`. # Pull requests