diff --git a/README.md b/README.md index dc7a0272be..0c73c35e6e 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,55 @@

- GitHub stars - License - CI - PRs Welcome + CI + Diff coverage enforced per pull request + Mutation gate: no unjustified survivors + Fork of QuackbackIO/quackback + License

+> **The two blue badges state a rule, not a measurement.** There is no +> repository-wide coverage or mutation percentage here, deliberately: the gates +> grade **what a change touches**, not the total, because a total is a number +> nobody has to defend and it improves when you measure less. `diff-coverage` +> and `mutation` are jobs in the workflow the CI badge reports, and per PR is +> where they bite: on `main` the comparison base is `main`, so the diff is empty +> and there is nothing for them to grade. What the two rules actually require is +> in [CLAUDE.md](CLAUDE.md). + +## This is a fork + +Upstream is [QuackbackIO/quackback](https://github.com/QuackbackIO/quackback); +everything below this section is upstream's own description of the product and +is left as it stands, so a sync stays a sync. This section is the fork-local +part. + +Exkulpa runs this codebase as a network service for its own products. Under +AGPL-3.0 §13 that carries obligations towards the people using that instance — +what they are, what is already satisfied, and what is still open is recorded in +[LEGAL.md](LEGAL.md). Read it before building anything proprietary in here. + +Four things differ from upstream and will bite whoever ignores them: + +- **Everything written into the repo is English** — code, comments, commits, + docs. The conversation around it is German; the file is not. A patch has to be + able to go upstream without a translation pass. +- **The contract comes before the tests, and the tests before the code.** For + anything with branches, money, dates, permissions or parsing, the guarantees + are written as a numbered list in plain domain language and confirmed _before_ + a property is written. A property read off the implementation cannot fail. +- **Two CI gates grade the diff, not the repo** — see the badges above. +- **Never deploy a moving tag.** A push to `main` publishes + `ghcr.io/therealbithive/quackback:main`, which is fine to try things with and + wrong to run: a pod rescheduled overnight silently picks up a different build, + and afterwards nobody can say which source was running. Every merge gets a + `vX.Y.Z-exkulpa.N` tag instead. + +The working rules are in [CLAUDE.md](CLAUDE.md), and the concrete gotchas that +have already cost someone an afternoon are collected in +[SELF-IMPROVE.md](SELF-IMPROVE.md). Both are fork-local and absent upstream, so +neither ever conflicts on a sync. +

Quackback feedback portal

@@ -73,7 +116,7 @@ Slack, Linear, Jira, GitHub, GitLab, Asana, ClickUp, Monday, Trello, Notion, Sho ### Docker ```bash -git clone https://github.com/QuackbackIO/quackback.git +git clone https://github.com/theRealBithive/quackback.git cd quackback cp .env.example .env # Edit with your configuration docker build -t quackback -f apps/web/Dockerfile . @@ -97,7 +140,7 @@ See the [Contributing Guide](CONTRIBUTING.md) to get started. Prerequisites: [Bun](https://bun.sh/) v1.4.0+ and [Docker](https://docker.com/) ```bash -git clone https://github.com/QuackbackIO/quackback.git +git clone https://github.com/theRealBithive/quackback.git cd quackback bun run setup # Install deps, start Docker, run migrations bun run db:seed # Optional: seed demo data diff --git a/SELF-IMPROVE.md b/SELF-IMPROVE.md index 5201b665bf..15ee49cb14 100644 --- a/SELF-IMPROVE.md +++ b/SELF-IMPROVE.md @@ -310,6 +310,40 @@ database up in one command. # Resolved +## 1x — Declaring a file in the mutation manifest is a claim, and it can cost an afternoon to find out it is false + +Adding an entry to `scripts/mutation-manifest.json` asserts that the named +suites, on their own, pin that file's behaviour. The word "asserts" is doing +real work: on a file that was already in the repository, the claim is usually +**not** true, and there is no cheap way to find out except running the gate. + +Measured while touching two GitLab files with one field each. +`gitlab/server/inbound.ts` came back with 21 survivors — all but one in guards +nobody had ever pinned (an issue hook naming no issue, a note whose text is not +text, an absent author, both 401 bodies). Closing them was worth doing and took +about a dozen small tests, because the file is pure parsing. Then +`gitlab/server/hook.ts` came back with **60**: 15 survivors and 45 never +executed, across outbound error handling the change had not touched. That one +was backed out — the entry would have been a false claim, and the gate's +designed answer for an unpinned file is to name it as ungraded. + +So: the size of the claim has nothing to do with the size of the diff. Before +declaring a pre-existing file, run the gate with the entry added and read the +number before committing to it. A pure module is usually a dozen tests away +from honest; a module that does I/O in its branches is a work item of its own. + +Two smaller traps found on the way: + +- `NoCoverage` mutants mean the entry names too few suites, not that the code is + untested. `inbound.ts` had 18 of them purely because `verifySignature` lives + in that file and is tested from `signature-matrix.test.ts` two directories + away. The fix is a second entry in `suites`, not more tests. +- Editing the manifest with a blind string replace puts the new record in + `equivalents` as well as `graded`, because the same `"file":` line matches in + both arrays. The gate refuses to run at all and says an equivalence record + needs a `why` — which reads like a missing reason rather than a record that + should not exist. Edit that file as JSON, not as text. + ## 1x — A Stryker run leaves two things behind that nothing else guards Both surfaced within an hour of the mutation gate going green, and neither is