AGENTS.md@examples ยท diff
git:20261007.d88f6ab to git:20261008.df1f80c
11 added, 6 removed. Audit A to A.
# examples
## Context
Real Grit applications, generated by the CLI and committed. They are the only
check in this repository that the framework produces something that works,
rather than something that compiles: a scaffold test asserts a template contains
a string, and an example proves an app builds, type-checks and runs.
Two kinds live here.
- - **`library` and `commerce`** are applications, **gated by CI**. `library` is a
- generated project; `commerce` is a shop with a hand-written cart on top, plus a
- `TUTORIAL.md` that reproduces it from scratch. Seven framework faults were
- found by building `commerce`, which is the entire argument for having it.
+ - **`library`, `commerce` and `saas`** are applications, **gated by CI**.
+ `library` is a generated project; `commerce` is a shop with a hand-written cart
+ on top, plus a `TUTORIAL.md` that reproduces it from scratch; `saas` is a
+ subscription product whose customer portal and operator console share one users
+ table, and whose tests prove a customer cannot read another customer's rows.
+ Seven framework faults were found by building `commerce` and one more by
+ building `saas`, which is the entire argument for having them.
- **`job-portal-*`** are one project per architecture, so a change to a shape can
be diffed rather than described.
## Source of truth
- - **What CI builds**: `.github/workflows/ci.yml`. `examples/library/apps/api` and
- `examples/commerce` have their own steps.
+ - **What CI builds**: `.github/workflows/ci.yml`. `examples/library/apps/api`,
+ `examples/commerce` and `examples/saas` have their own steps. `saas` has a
+ second step running its isolation tests alone, so a failure names the breach
+ rather than being one line in a wall of output.
- **`commerce/TUTORIAL.md`**: generated by `scripts/tutorial-build.py` from the
checked-in app. **Never hand-edit its code blocks**; edit the app, re-run the
script.
- **Which architecture each `job-portal-*` is**: its own `grit.json`.
## Boundary rules
1. **These are generated output, not source.** Do not hand-fix an example to make
CI pass. If an example is wrong, the **template** is wrong: fix
`internal/scaffold` or `internal/generate`, regenerate, and commit the result.
A hand-patched example hides the bug it was there to find.
2. **The hand-written part of `commerce` is the exception**, and only the cart
and the pages the tutorial describes. Everything else in it is regenerated.
3. **Regenerate with a rebuilt binary.** An example regenerated by a stale
`grit.exe` commits the previous release's output and reports it as current.
4. **Compare by bytes.** Same project name, both binaries, read as bytes.
Different names and decoded text each give a false answer about what changed.
5. **Stage new files explicitly.** A regeneration that adds a file in a tracked
directory is exactly the case where the new file gets left out of the commit
and breaks CI. Verify with `git diff --cached --stat`.
6. **Do not add an example casually.** Each one is a build in CI and a diff to
maintain forever. Eight is already a lot.
## Validation workflow
A change that touches an example has to pass what CI runs, locally, first:
```bash
cd examples/library/apps/api && go build ./... && go test ./...
cd examples/commerce/apps/api && go build ./...
cd examples/commerce && pnpm install && pnpm typecheck
```
And if you regenerated:
1. Diff the regenerated tree against the committed one and **read** the diff. An
unexplained change is a template change you did not intend.
2. Stand the app up and open it. `commerce` has a cart; put something in it.
3. Re-run `python scripts/tutorial-build.py` if `commerce` changed, and check
the tutorial still describes the app that is there.