Contributing
The gate
Section titled “The gate”pnpm verify # backend: typecheck + lint + tests + buildpnpm web:verify # admin panelpnpm docs:verify # this documentation siteRun the gate for every area you touched. A red gate is never “fixed later”.
Workflow
Section titled “Workflow”-
Branch from the development branch, named for the change:
feat/add-webhook-notifier,fix/duplicate-alerts. -
Make the change small. One behaviour per branch. A refactor and a behaviour change in the same commit cannot be reviewed or reverted cleanly.
-
Write the test first when changing a decision rule. It is the layer where a mistake reaches users directly.
-
Run the gate.
-
Run the accuracy harness (
pnpm eval) if you touched the evaluator prompt or any decision rule, and state the before/after in the description. -
Update the documentation in the same change. A new configuration value, a new route or a new source type that is not documented is unfinished.
-
Open a pull request describing why, not just what. The diff shows what.
Commit messages
Section titled “Commit messages”Conventional commits, imperative mood:
feat(collectors): add a webhook-backed collectorfix(delivery): persist undelivered alerts so they are retrieddocs: document the retry guaranteetest(mongo): cover run-state round-trippingThe body should say what was wrong and why this is the fix — a year from now that is the only record of the reasoning.
Rules a change must respect
Section titled “Rules a change must respect”| Rule | Why |
|---|---|
Dependencies point inward — domain/ and application/ never import adapters/ or entrypoints/ |
The core stays portable and testable |
| Domain code is pure — no I/O, no clock, no randomness | Deterministic decisions |
| Secrets only through the config module | One audited entry point |
| Validate at every boundary with the shared schemas | Malformed data stops at the edge |
| Every adapter ships with a test using an injected transport | The suite stays offline |
| Persisted fields are handled in both repositories | The in-memory one is not production |
| New optional fields default to the old behaviour | Upgrades do not surprise anyone |
Dependencies
Section titled “Dependencies”Adding one is a decision, not a convenience. Before you do: can the standard library do it; does an existing dependency already cover it; and what is the cost of maintaining it for years? The project deliberately runs a small dependency set, and several places use platform primitives instead of a library on purpose.
Documentation changes
Section titled “Documentation changes”This site lives in the repository alongside the code:
pnpm docs:dev # write with live reloadpnpm docs:verify # types, build, links, and the content-safety scanReference pages declare the source files they document in their frontmatter. If you rename a module, update the pages that name it — the build checks those paths exist and fails if they do not.