diff --git a/.gitignore b/.gitignore index 64334423fa..50235974ec 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ failedSyncs/ .claude/scheduled_tasks.lock .claude/agent-memory-local/ screenshots/ + +# local markdown issue tracker (agent skills) +.scratch/ diff --git a/AGENTS.md b/AGENTS.md index 8a11c5a6a0..56db4e3309 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -93,6 +93,20 @@ Before implementing any change that will touch many files or is in a πŸ”΄ **Crit If you are struggling, explain the difficulty to the user instead of cheating. **Integrity is non-negotiable.** +## Agent skills + +### Issue tracker + +Issues and specs live locally as markdown files under `.scratch/` (git-ignored). See `docs/agents/issue-tracker.md`. + +### Triage labels + +Default five-role vocabulary, recorded as `Status:` lines in each issue file. See `docs/agents/triage-labels.md`. + +### Domain docs + +Multi-context: root `CONTEXT-MAP.md` points at per-context `CONTEXT.md` files. See `docs/agents/domain.md`. + ## Cursor Cloud specific instructions System deps (.NET 10 SDK, Taskfile/`task`) are baked into the VM snapshot; the startup update script only refreshes pnpm + FwLiteWeb NuGet deps. The generated TS types under `frontend/viewer/src/lib/dotnet-types/generated-types/` are committed, so the viewer runs without a backend build. diff --git a/docs/agents/domain.md b/docs/agents/domain.md new file mode 100644 index 0000000000..1dee4b426c --- /dev/null +++ b/docs/agents/domain.md @@ -0,0 +1,38 @@ +# Domain Docs + +How the engineering skills should consume this repo's domain documentation when exploring the codebase. + +This repo uses the **multi-context** layout: a root `CONTEXT-MAP.md` points at one `CONTEXT.md` per context (e.g. `backend/FwLite/CONTEXT.md`). + +## Before exploring, read these + +- **`CONTEXT-MAP.md`** at the repo root β€” it points at one `CONTEXT.md` per context. Read each one relevant to the topic. +- **`docs/adr/`** β€” read ADRs that touch the area you're about to work in. Also check `/docs/adr/` for context-scoped decisions. + +If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. + +## File structure + +Multi-context repo (presence of `CONTEXT-MAP.md` at the root): + +``` +/ +β”œβ”€β”€ CONTEXT-MAP.md +β”œβ”€β”€ docs/adr/ ← system-wide decisions +└── backend/ + └── FwLite/ + β”œβ”€β”€ CONTEXT.md + └── docs/adr/ ← context-specific decisions +``` + +## Use the glossary's vocabulary + +When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in the relevant `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. + +If the concept you need isn't in the glossary yet, that's a signal β€” either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`). + +## Flag ADR conflicts + +If your output contradicts an existing ADR, surface it explicitly rather than silently overriding: + +> _Contradicts ADR-0007 (event-sourced orders) β€” but worth reopening because…_ diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md new file mode 100644 index 0000000000..c99ffc6622 --- /dev/null +++ b/docs/agents/issue-tracker.md @@ -0,0 +1,32 @@ +# Issue tracker: Local Markdown + +Issues and specs (you may know a spec as a PRD) for this repo live as markdown files in `.scratch/`. + +> **Note:** `.scratch/` is git-ignored β€” issues are local to your working copy and are not shared through the repo. Don't expect them on other clones or in CI. + +## Conventions + +- One feature per directory: `.scratch//` +- The spec is `.scratch//spec.md` +- Implementation issues are one file per ticket at `.scratch//issues/-.md`, numbered from `01` β€” never a single combined tickets file +- Triage state is recorded as a `Status:` line near the top of each issue file (see `triage-labels.md` for the role strings) +- Comments and conversation history append to the bottom of the file under a `## Comments` heading + +## When a skill says "publish to the issue tracker" + +Create a new file under `.scratch//` (creating the directory if needed). + +## When a skill says "fetch the relevant ticket" + +Read the file at the referenced path. The user will normally pass the path or the issue number directly. + +## Wayfinding operations + +Used by `/wayfinder`. The **map** is a file with one **child** file per ticket. + +- **Map**: `.scratch//map.md` β€” the Notes / Decisions-so-far / Fog body. +- **Child ticket**: `.scratch//issues/NN-.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`. +- **Blocking**: a `Blocked by: NN, NN` line near the top. A ticket is unblocked when every file it lists is `resolved`. +- **Frontier**: scan `.scratch//issues/` for files that are open, unblocked, and unclaimed; first by number wins. +- **Claim**: set `Status: claimed` and save before any work. +- **Resolve**: append the answer under an `## Answer` heading, set `Status: resolved`, then append a context pointer (gist + link) to the map's Decisions-so-far in `map.md`. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md new file mode 100644 index 0000000000..c5f833da1f --- /dev/null +++ b/docs/agents/triage-labels.md @@ -0,0 +1,17 @@ +# Triage Labels + +The skills speak in terms of five canonical triage roles. This file maps those roles to the actual strings used in this repo's issue tracker. + +Because issues live as local markdown (see `issue-tracker.md`), a "label" is just the value of the `Status:` line near the top of an issue file β€” there is no external label system to reconcile with. + +| Label in mattpocock/skills | Status string in our tracker | Meaning | +| -------------------------- | ---------------------------- | ---------------------------------------- | +| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue | +| `needs-info` | `needs-info` | Waiting on reporter for more information | +| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent | +| `ready-for-human` | `ready-for-human` | Requires human implementation | +| `wontfix` | `wontfix` | Will not be actioned | + +When a skill mentions a role (e.g. "apply the AFK-ready triage label"), write the corresponding string on the issue file's `Status:` line. + +Edit the right-hand column to match whatever vocabulary you actually use. diff --git a/docs/pr-self-merge-rubric.md b/docs/pr-self-merge-rubric.md new file mode 100644 index 0000000000..7c69e800f7 --- /dev/null +++ b/docs/pr-self-merge-rubric.md @@ -0,0 +1,144 @@ +# PR Self-Merge Rubric (languageforge-lexbox) + +> **Interactive version:** an interactive, tick-through copy of this rubric is +> published as an artifact: +> +> (viewable once shared from the artifact's share menu). + +Decide whether **your own** PR can be merged **without a second human review**. +Internal authors only (not outside contributors). Default-closed: **if anything +is uncertain, get a human.** You are not saving time by merging something that +needed review β€” you are moving the cost downstream and making it bigger. + +--- + +## 0. Preconditions β€” both true, or stop here + +- [ ] **CI is green.** +- [ ] **An AI review has run** (Devin / CodeRabbit / your own agent) and **you + read its output** and addressed anything real. + +These are assumed by everything below. This rubric only decides whether a +*second human* is still required on top of them. + +--- + +## The rule + +> **A PR is self-mergeable if β€” and only if β€” *every* changed file is GREEN.** + +Judge each changed file by its **(path, change-type)** pair. Generated files +don't count as their own files β€” they inherit the classification of the source +edit that produced them (see reference). + +A changed file is **GREEN** when either: + +1. **Its change-type is universal-green** β€” *regardless of path*: docs / + comment-only, formatting-or-whitespace-only, a **new** test (not a test + edit), or i18n / new UI string additions. No further gates. +2. **Its path is not πŸ”΄** *and* its change-type is **conditional-green** + (everything else) *and* it clears the gates in Β§2 that apply to it. + +If a file is neither β†’ **not self-mergeable, get a human.** A **mixed PR** is +judged file-by-file: one non-green file sinks it β€” split the PR or request +review. + +--- + +## 1. πŸ”΄ Always-human β€” the hard stops + +If the PR changes any of these, **get a human** β€” *unless every such change is a +universal-green type* (docs/comment, formatting, new test, i18n), which is +allowed anywhere. + +- `backend/FwLite/FwLiteProjectSync/**` β€” CRDT↔FwData sync orchestration +- `backend/FwLite/LcmCrdt/**` β€” CRDT implementation +- `backend/FwLite/FwDataMiniLcmBridge/**` β€” FwData↔MiniLcm conversion +- `backend/FwLite/MiniLcm/**` model / `IMiniLcmApi` files β€” model-field fanout +- `backend/FwHeadless/**` Β· `backend/FixFwData/**` Β· `backend/LexCore/Sync/**` Β· + `backend/SyncReverseProxy/**` Β· `hgweb/**` +- `**/Migrations/**` β€” EF migrations +- Harmony package version bumps / MSBuild reference changes +- **Auth / JWT / secrets anywhere** (incl. `*/Auth/`, connection strings) +- **Breaking GraphQL schema changes** β€” removes/renames a field/type/enum-value, + tightens nullability, adds a required arg, or changes an auth attribute on an + existing resolver +- `deployment/**` β€” k8s / Kustomize / PVCs / secrets + +*Why data loss / security / deployed-contract risk β€” see the repo's πŸ”΄ CRITICAL +AGENTS.md flags and the sentinel review agents.* + +--- + +## 2. Gates β€” apply to every *conditional-green* file + +- **Size (always).** ≀ **150 net changed lines** of *reviewable, non-green* code + β€” excluding generated files, universal-green files, lockfiles, and snapshots β€” + **AND** it's *one coherent change you can hold in your head* (not 40 lines + smeared across 15 unrelated files). +- **Test (only if the change alters behavior** β€” new behavior / bug fix / + feature**).** New behavior β†’ a new test; bug fix β†’ a **regression test**. *If + it can't reasonably be tested, get a human.* Non-behavior changes (refactor, + config, dependency bump, test edit) need no new test β€” green CI covers them. + Run the cheap targeted tests locally (per AGENTS.md tiers); rely on CI for + stack-dependent suites. +- *(Verification is folded into the attestation below.)* + +--- + +## 3. Final attestation β€” you are the reviewer of record + +Applies to **every** PR. Vouch for this diff to **the same standard you'd hold a +teammate's PR to** (the repo's "Integrity is non-negotiable" ethos). Honest +**YES** to all four, or get a human: + +- [ ] **Read** β€” I read every non-generated changed line, not skimmed. +- [ ] **Explain** β€” I can explain why each change exists, *without re-reading* β€” + as if I wrote it. +- [ ] **Blast radius & ran it** β€” I checked what this could break (callers / + consumers of any changed contract), and where it has a runtime surface a + test can't fully capture, I exercised it and saw the intended behavior. +- [ ] **No mystery code** β€” there is nothing here I don't fully understand + ("the agent probably knows what it's doing" is a NO). + +--- + +## Tie-breaker + +**Any "I'm not sure" on any line above β†’ get a human.** That is the correct, +low-cost outcome, not a failure. + +--- + +## Reference + +### Change-type reach + +*Reach* = how far a change-type green-lights across paths. **Universal** overrides +even a πŸ”΄ path. **Conditional** is green only outside πŸ”΄, and is subject to the Β§2 +gates. + +| Change-type | Reach | Test needed? / Notes | +|---|---|---| +| Docs / comment-only | 🟒 Universal | No runtime effect | +| Formatting / whitespace | 🟒 Universal | Auto-format, import reorder | +| **New** test (addition, not edit) | 🟒 Universal | Adds coverage, can't weaken a guard | +| i18n / new UI string additions | 🟒 Universal | Low-risk content | +| Test *modification* | 🟑 Conditional | No test; a weakened assertion in a πŸ”΄ test β†’ πŸ”΄ = human | +| Dependency bump | 🟑 Conditional | No test; Harmony bump is πŸ”΄ by path | +| Config change | 🟑 Conditional | No test; secret/auth/connection-string config is πŸ”΄ by path | +| Pure refactor (no behavior change) | 🟑 Conditional | No test (no behavior change); leans on the Β§3 attestation | +| New behavior / bug fix / feature | 🟑 Conditional | **Needs a test** (Β§2); additive GraphQL lives here | + +### Other + +- **Generated files** (`frontend/viewer/src/lib/dotnet-types/generated-types/**`, + `.po` catalogs) are *transparent*: classify the PR by the source edit; they're + excluded from the size count. +- **Tool-ability.** The path lists are globs and the size rule is a computable + line count on purpose β€” a future helper tool can implement this rubric + verbatim. +- **On the two tiers.** An earlier draft split conditional-green into + "zone-limited" and "gated." They had identical *reach* (green only outside πŸ”΄, + same size + attestation) and differed only by the test requirement β€” so + they're merged, and "behavior change β†’ test" is just a rule in Β§2.