diff --git a/AGENTS.md b/AGENTS.md index bbfdb9e..86a3145 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,45 +1,176 @@ # Agent instructions -Instructions for AI coding agents (Claude Code and others) working in this repo. -Human contributors: see `README.md`. +For AI coding agents. Human contributors: see `README.md`. -## Before starting work - -Sync with `origin/main` before branching and again before opening a PR. Branch -from a stale base and CI's `npm-build` "Check build changes" job, DCO check, or -plain merge conflicts will fail for reasons unrelated to your change — and a -refactor may have moved the code you're about to edit somewhere else entirely. +## Branch from fresh `main` ```bash -git fetch origin -git checkout -b origin/main +git fetch origin && git checkout -b origin/main ``` -If you've been working for a while, `git fetch origin && git log --oneline -HEAD..origin/main` before pushing — rebase if `main` has moved. +CI builds your branch merged with current `main`, so a stale base can fail the +`npm-build` "Check build changes" job even after a recompile, and a refactor +may have moved the code you're about to edit. You'll re-check `main` before +opening the PR too — see below. -## Commit atomically +## Commit discipline One concern per commit: a functional change, a cleanup, and a docs update are -three commits, not one. Do not bundle an unrelated fix into a feature commit -because it happened to be nearby. A reviewer (human or bot) diffing a single -concern can actually verify it; a "fix + refactor + docs" commit can't be -reviewed, only trusted. +three commits. A reviewer can verify a single-concern diff; a mixed one can +only be trusted. + +CI checks every commit: conventional-format headline (`fix:`, `feat:`, +`docs:`, ...) and DCO sign-off — `git commit -s`. + +A new unit lands with its `.spec.ts` sibling in the same commit — +`src/utils/` and `src/components/` pair each unit with one; follow that. + +Changing what an existing function returns or accepts isn't done until every +`.spec.ts` that mocks or asserts on it reflects the new shape — `grep` the +function name across `src/**/*.spec.ts` before considering the commit +finished. `npm run test:unit` (see the checklist below) will catch the ones +you miss, but only if you run it before opening the PR, not after. + +Fixing a bug in existing logic — same signature, different behavior — still +needs a regression test pinning the corrected behavior, in the same commit +as the fix. Without one, nothing stops the bug from coming back next time +this code is touched, and the fix reads as untested even in a file that +already has specs. + +A red test means one of three things: the code is wrong, the behavior it +pins changed on purpose, or the test itself is wrong — asserting on a mock +instead of real behavior, or flaky. Only the last two justify touching the +test, and both require the commit message to say which it is and why, not +just that the failure went away. Deciding a test is wrong is itself a +contestable call (see below) — if you're not certain, ask rather than +deleting the evidence. + +Skipping (`.skip`, `.todo`), deleting a case, or dulling a matcher +(`toEqual` → `toBeTruthy`, dropping an assertion) to turn a failure green +without that justification makes the test stop proving anything; it's the +bug staying in, with the evidence removed. + +Confident AI output still needs splitting: a flawless-looking helper and a real +bug can come from the same commit. + +## Commit source only + +Build locally to test, then hand the tree back clean: + +```bash +npm run build +git restore --staged js css +``` + +`js/` and `css/` are build output; the `nextcloud-command` bot compiles and +commits them to your branch after a maintainer comments `/compile` on the PR — +say in the description that it's still needed. `.githooks/pre-commit` is a +backstop, not a plan. + +## Reuse before you write + +Preference order: an existing `@nextcloud/vue` component, an existing design +token, an existing pattern in `src/`. + +Each keeps you on the design system the library already maintains; hand-rolled +equivalents drift from it and duplicate maintenance. + +Tokens: `var(--color-...)`, `var(--border-radius)`, +`var(--default-clickable-area)`, `var(--default-grid-baseline)`. Treat +`node_modules/@nextcloud/vue/dist/assets/*.css` as a partial list — many tokens +are defined server-side, so search there and assume more exist. Where no token +matches, use the literal value. + +An undefined `var()` doesn't fall back to an earlier declaration in the same +rule — the property resets to its inherited or initial value, so a hardcoded +line above the token is not a safety net. + +## Separate concerns by default + +Give each responsibility its own unit. If you can name what a block of markup or +logic *does* — validates a filename, formats a timestamp, renders a share row — +that name is the component or function it should become, at one call site or +five. Prefer small units with explicit inputs (props, arguments) over logic +inline in a large `