peer-ai-standards 1.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/core/ai-features.d.ts +65 -0
  4. package/dist/core/ai-features.js +113 -0
  5. package/dist/core/api-design.d.ts +41 -0
  6. package/dist/core/api-design.js +91 -0
  7. package/dist/core/architecture.d.ts +41 -0
  8. package/dist/core/architecture.js +93 -0
  9. package/dist/core/backend.d.ts +21 -0
  10. package/dist/core/backend.js +25 -0
  11. package/dist/core/code-quality.d.ts +91 -0
  12. package/dist/core/code-quality.js +179 -0
  13. package/dist/core/data.d.ts +45 -0
  14. package/dist/core/data.js +59 -0
  15. package/dist/core/delivery.d.ts +153 -0
  16. package/dist/core/delivery.js +149 -0
  17. package/dist/core/design-accessibility.d.ts +124 -0
  18. package/dist/core/design-accessibility.js +199 -0
  19. package/dist/core/frontend.d.ts +77 -0
  20. package/dist/core/frontend.js +109 -0
  21. package/dist/core/mobile.d.ts +46 -0
  22. package/dist/core/mobile.js +83 -0
  23. package/dist/core/money.d.ts +81 -0
  24. package/dist/core/money.js +135 -0
  25. package/dist/core/operations.d.ts +108 -0
  26. package/dist/core/operations.js +177 -0
  27. package/dist/core/performance.d.ts +53 -0
  28. package/dist/core/performance.js +85 -0
  29. package/dist/core/privacy-compliance.d.ts +68 -0
  30. package/dist/core/privacy-compliance.js +77 -0
  31. package/dist/core/reliability.d.ts +67 -0
  32. package/dist/core/reliability.js +105 -0
  33. package/dist/core/requirements.d.ts +41 -0
  34. package/dist/core/requirements.js +58 -0
  35. package/dist/core/safety-critical.d.ts +41 -0
  36. package/dist/core/safety-critical.js +71 -0
  37. package/dist/core/security.d.ts +281 -0
  38. package/dist/core/security.js +427 -0
  39. package/dist/core/system-design.d.ts +31 -0
  40. package/dist/core/system-design.js +69 -0
  41. package/dist/core/testing.d.ts +51 -0
  42. package/dist/core/testing.js +124 -0
  43. package/dist/domains.d.ts +6 -0
  44. package/dist/domains.js +53 -0
  45. package/dist/index.d.ts +30 -0
  46. package/dist/index.js +118 -0
  47. package/dist/profile.d.ts +262 -0
  48. package/dist/profile.js +269 -0
  49. package/dist/profiles/express.d.ts +2 -0
  50. package/dist/profiles/express.js +93 -0
  51. package/dist/profiles/fastapi.d.ts +2 -0
  52. package/dist/profiles/fastapi.js +104 -0
  53. package/dist/profiles/fastify.d.ts +2 -0
  54. package/dist/profiles/fastify.js +56 -0
  55. package/dist/profiles/github-actions.d.ts +2 -0
  56. package/dist/profiles/github-actions.js +151 -0
  57. package/dist/profiles/nestjs.d.ts +2 -0
  58. package/dist/profiles/nestjs.js +77 -0
  59. package/dist/profiles/next.d.ts +2 -0
  60. package/dist/profiles/next.js +73 -0
  61. package/dist/profiles/node.d.ts +2 -0
  62. package/dist/profiles/node.js +79 -0
  63. package/dist/profiles/python.d.ts +2 -0
  64. package/dist/profiles/python.js +232 -0
  65. package/dist/profiles/react-native.d.ts +2 -0
  66. package/dist/profiles/react-native.js +133 -0
  67. package/dist/profiles/react.d.ts +2 -0
  68. package/dist/profiles/react.js +180 -0
  69. package/dist/profiles/typescript.d.ts +2 -0
  70. package/dist/profiles/typescript.js +214 -0
  71. package/dist/rule.d.ts +72 -0
  72. package/dist/rule.js +39 -0
  73. package/package.json +39 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qudus Lawal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # peer-ai-standards
2
+
3
+ Peer AI's engineering standards: the rules every project follows, in any language.
4
+
5
+ - **Readable pages:** [`docs/`](https://github.com/AbuMahir980/peer-ai/blob/main/packages/standards/docs/README.md), one page per domain, and one per stack profile in [`docs/profiles/`](https://github.com/AbuMahir980/peer-ai/blob/main/packages/standards/docs/README.md#stack-profiles).
6
+ - **The rules themselves:** `src/core/`, written as typed data, so Peer AI's review can cite them and `standards_for_file` can hand the right ones to an AI tool.
7
+ - **Stack profiles:** `src/profiles/`, how to follow the core rules in one stack, and the tool that enforces each automatic rule.
8
+ - **The design:** [RFC 0003](https://github.com/AbuMahir980/peer-ai/blob/main/rfcs/0003-how-a-standard-is-written.md) for the rules, and [RFC 0006](https://github.com/AbuMahir980/peer-ai/blob/main/rfcs/0006-stack-profiles-and-their-enforcers.md) for the profiles.
9
+
10
+ ## What every rule has
11
+
12
+ | Part | What it says |
13
+ |------|--------------|
14
+ | ID | Stable and never reused, such as `MONEY-01` |
15
+ | Rule | The rule, in plain words |
16
+ | Why | What goes wrong without it |
17
+ | Ask | The question a reviewer answers |
18
+ | Applies from | Prototype, MVP or production |
19
+ | Checked by | A tool, AI review, or a person |
20
+ | Severity | How serious breaking it usually is |
21
+ | Applies when | The traits a product needs for the rule to apply, such as `money` |
22
+ | Source | The outside standard it comes from, such as OWASP, where there is one |
23
+
24
+ ## Choosing the rules that apply
25
+
26
+ ```ts
27
+ import { rulesFor } from "peer-ai-standards";
28
+
29
+ rulesFor({ stage: "mvp", traits: ["money"], domains: ["money", "code-quality"] });
30
+ ```
31
+
32
+ ## Adding or changing a rule
33
+
34
+ 1. Add or edit it in `src/core/`. A rule with a missing part, an id that doesn't match its domain, or an id used twice fails the build.
35
+ 2. Regenerate the pages: `pnpm --filter peer-ai-standards generate`. A test fails if you forget.
36
+ 3. Changing what an existing rule requires needs an RFC.
37
+
38
+ ## Stack profiles
39
+
40
+ A profile rule has every part a core rule has, and four more:
41
+
42
+ | Part | What it says |
43
+ |------|--------------|
44
+ | Carries | The core rule it carries out, such as `CODE-14` |
45
+ | Architectures | The architecture labels it applies to, such as `layered`; none means every architecture |
46
+ | Default | A number or choice the project may change in `standards.overrides`, which `{value}` in its text stands for |
47
+ | Enforcer | For an automatic rule, the tool and setting that checks it, such as ESLint's `max-depth` |
48
+
49
+ A project lists its profiles in `standards.profiles`. A profile applies to a part whose stack has one of its tags, and brings the profiles it builds on:
50
+
51
+ ```ts
52
+ import { profileRulesFor } from "peer-ai-standards";
53
+
54
+ profileRulesFor({ listed: ["typescript"], stack: ["typescript", "react"], stage: "mvp" });
55
+ ```
56
+
57
+ ## Adding a profile or a profile rule
58
+
59
+ 1. Add the profile to `src/profiles/`, and list it in `src/index.ts`. A rule that carries no core rule, an id without the profile's prefix, or an automatic rule without its enforcer and examples fails the build.
60
+ 2. Give each automatic rule an example that must fail and one that must pass. The tests run the real tool on both: the compiler here, ESLint in `peer-ai-eslint-config`, and Ruff in `peer-ai`, through `@astral-sh/ruff-wasm-nodejs`. The GitHub Actions profile's examples are proven in CI instead: `scripts/pipeline-proof.ts` installs the tools its pipeline uses and runs them on each example.
61
+ 3. Regenerate the pages: `pnpm --filter peer-ai-standards generate`.
62
+ 4. A new profile doesn't need an RFC; changing what a rule requires does.
@@ -0,0 +1,65 @@
1
+ export declare const aiFeatures: ({
2
+ id: string;
3
+ domain: "ai-features";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "ai-review";
10
+ severity: "high";
11
+ when: "ai-features"[];
12
+ sources: {
13
+ name: string;
14
+ ref: string;
15
+ url: string;
16
+ }[];
17
+ } | {
18
+ id: string;
19
+ domain: "ai-features";
20
+ title: string;
21
+ rule: string;
22
+ why: string;
23
+ ask: string;
24
+ stage: "mvp";
25
+ check: "ai-review";
26
+ severity: "high";
27
+ when: "ai-features"[];
28
+ sources: {
29
+ name: string;
30
+ ref: string;
31
+ url: string;
32
+ }[];
33
+ } | {
34
+ id: string;
35
+ domain: "ai-features";
36
+ title: string;
37
+ rule: string;
38
+ why: string;
39
+ ask: string;
40
+ stage: "prototype";
41
+ check: "ai-review";
42
+ severity: "medium";
43
+ when: "ai-features"[];
44
+ sources: {
45
+ name: string;
46
+ ref: string;
47
+ url: string;
48
+ }[];
49
+ } | {
50
+ id: string;
51
+ domain: "ai-features";
52
+ title: string;
53
+ rule: string;
54
+ why: string;
55
+ ask: string;
56
+ stage: "mvp";
57
+ check: "ai-review";
58
+ severity: "medium";
59
+ when: "ai-features"[];
60
+ sources: {
61
+ name: string;
62
+ ref: string;
63
+ url: string;
64
+ }[];
65
+ })[];
@@ -0,0 +1,113 @@
1
+ // For products with the ai-features trait: features that use AI models. Rules cite the entry of
2
+ // the OWASP Top 10 for Large Language Model Applications (2025) they come from, checked against
3
+ // OWASP's own repository.
4
+ const LLM = "OWASP Top 10 for LLM Applications 2025";
5
+ const entry = (file) => `https://github.com/OWASP/www-project-top-10-for-large-language-model-applications/blob/main/2_0_vulns/${file}.md`;
6
+ export const aiFeatures = [
7
+ {
8
+ id: "AI-01",
9
+ domain: "ai-features",
10
+ title: "An AI's output is untrusted input",
11
+ rule: "Output from an AI model is checked and escaped like any outside input before it's shown, stored, or passed to code, a database, a shell or another service.",
12
+ why: "What a model says can be steered by what it was given, so its output can carry an attack as easily as a user's input can.",
13
+ ask: "Is every AI output in this change checked and escaped before it's used?",
14
+ stage: "prototype",
15
+ check: "ai-review",
16
+ severity: "high",
17
+ when: ["ai-features"],
18
+ sources: [{ name: LLM, ref: "LLM05, Improper Output Handling", url: entry("LLM05_ImproperOutputHandling") }],
19
+ },
20
+ {
21
+ id: "AI-02",
22
+ domain: "ai-features",
23
+ title: "An AI's guess is never shown as fact",
24
+ rule: "An AI's answer is shown as a suggestion, never as fact. Anything about safety, health, money or the law also tells the person to check with someone qualified.",
25
+ why: "Models state wrong answers as confidently as right ones, and a wrong answer about whether a plant is safe for a pet can hurt someone.",
26
+ ask: "Does this change show any AI answer as fact, or give safety advice without telling the person to check?",
27
+ stage: "prototype",
28
+ check: "ai-review",
29
+ severity: "high",
30
+ when: ["ai-features"],
31
+ sources: [{ name: LLM, ref: "LLM09, Misinformation", url: entry("LLM09_Misinformation") }],
32
+ },
33
+ {
34
+ id: "AI-03",
35
+ domain: "ai-features",
36
+ title: "People know what's sent to an AI service, and nothing sensitive goes without need",
37
+ rule: "People are told what's sent to an AI service before it's sent. Personal or sensitive data is sent only when the feature needs it, and removed when it doesn't.",
38
+ why: "Data sent to a model provider can be logged, kept or used for training, and people didn't agree to that just by using a feature.",
39
+ ask: "Does this change send an AI service anything people haven't been told about, or don't need to send?",
40
+ stage: "mvp",
41
+ check: "ai-review",
42
+ severity: "high",
43
+ when: ["ai-features"],
44
+ sources: [
45
+ { name: LLM, ref: "LLM02, Sensitive Information Disclosure", url: entry("LLM02_SensitiveInformationDisclosure") },
46
+ ],
47
+ },
48
+ {
49
+ id: "AI-04",
50
+ domain: "ai-features",
51
+ title: "Content can't change what the model is allowed to do",
52
+ rule: "Instructions to the model and the content it works on are kept apart, and the model's permissions are enforced outside it, so text in a document, email or web page can't change what it's allowed to do.",
53
+ why: "A line hidden in a web page can tell a model to ignore its instructions, and the model can't reliably tell instructions from content.",
54
+ ask: "Could content the model reads in this change make it do something it shouldn't?",
55
+ stage: "mvp",
56
+ check: "ai-review",
57
+ severity: "high",
58
+ when: ["ai-features"],
59
+ sources: [{ name: LLM, ref: "LLM01, Prompt Injection", url: entry("LLM01_PromptInjection") }],
60
+ },
61
+ {
62
+ id: "AI-05",
63
+ domain: "ai-features",
64
+ title: "An AI does only what it needs to, and a person confirms what matters",
65
+ rule: "An AI can call only the tools and data its task needs, with the least permission they allow, and anything that moves money, changes data or acts on someone's account needs a person's confirmation.",
66
+ why: "A model given broad powers will eventually use them wrongly, whether by mistake or because someone tricked it.",
67
+ ask: "Does the AI in this change have more access than its task needs, or act on anything important without confirmation?",
68
+ stage: "mvp",
69
+ check: "ai-review",
70
+ severity: "high",
71
+ when: ["ai-features"],
72
+ sources: [{ name: LLM, ref: "LLM06, Excessive Agency", url: entry("LLM06_ExcessiveAgency") }],
73
+ },
74
+ {
75
+ id: "AI-06",
76
+ domain: "ai-features",
77
+ title: "Instructions to the model hold no secrets",
78
+ rule: "The instructions given to a model hold no secrets, credentials or rules that only work if nobody sees them.",
79
+ why: "People can get a model to repeat its instructions, so anything in them should be safe to read.",
80
+ ask: "Do the model's instructions in this change hold anything that would matter if someone read them?",
81
+ stage: "prototype",
82
+ check: "ai-review",
83
+ severity: "medium",
84
+ when: ["ai-features"],
85
+ sources: [{ name: LLM, ref: "LLM07, System Prompt Leakage", url: entry("LLM07_SystemPromptLeakage") }],
86
+ },
87
+ {
88
+ id: "AI-07",
89
+ domain: "ai-features",
90
+ title: "AI calls have limits",
91
+ rule: "Every call to an AI service has a timeout and a size limit, and each person has a spending or usage limit.",
92
+ why: "AI calls are slow and paid per use, so one runaway loop or one abusive user can take the feature down or run up a large bill.",
93
+ ask: "Does every AI call in this change have a timeout, a size limit and a per-person limit?",
94
+ stage: "mvp",
95
+ check: "ai-review",
96
+ severity: "medium",
97
+ when: ["ai-features"],
98
+ sources: [{ name: LLM, ref: "LLM10, Unbounded Consumption", url: entry("LLM10_UnboundedConsumption") }],
99
+ },
100
+ {
101
+ id: "AI-08",
102
+ domain: "ai-features",
103
+ title: "An AI feature is tested on fixed examples, attacks included",
104
+ rule: "An AI feature has a set of example inputs with the behaviour expected for each, including attacks such as prompt injection and attempts to make it leak data or go beyond its permissions. They're run before every change to its instructions or its model.",
105
+ why: "A small change to a prompt or a model version can quietly break answers that used to be right, and a model that resisted an attack last month may not after an update.",
106
+ ask: "Were the AI feature's examples, attacks included, run for this change to its instructions or model?",
107
+ stage: "mvp",
108
+ check: "ai-review",
109
+ severity: "medium",
110
+ when: ["ai-features"],
111
+ sources: [{ name: LLM, ref: "LLM01, Prompt Injection", url: entry("LLM01_PromptInjection") }],
112
+ },
113
+ ];
@@ -0,0 +1,41 @@
1
+ export declare const apiDesign: ({
2
+ id: string;
3
+ domain: "api-design";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "mvp";
9
+ check: "ai-review";
10
+ severity: "medium";
11
+ } | {
12
+ id: string;
13
+ domain: "api-design";
14
+ title: string;
15
+ rule: string;
16
+ why: string;
17
+ ask: string;
18
+ stage: "mvp";
19
+ check: "ai-review";
20
+ severity: "high";
21
+ } | {
22
+ id: string;
23
+ domain: "api-design";
24
+ title: string;
25
+ rule: string;
26
+ why: string;
27
+ ask: string;
28
+ stage: "mvp";
29
+ check: "auto";
30
+ severity: "medium";
31
+ } | {
32
+ id: string;
33
+ domain: "api-design";
34
+ title: string;
35
+ rule: string;
36
+ why: string;
37
+ ask: string;
38
+ stage: "mvp";
39
+ check: "ai-review";
40
+ severity: "low";
41
+ })[];
@@ -0,0 +1,91 @@
1
+ // How services and clients agree on what they send each other.
2
+ export const apiDesign = [
3
+ {
4
+ id: "API-01",
5
+ domain: "api-design",
6
+ title: "Requests and responses are typed schemas",
7
+ rule: "Every request and response body is a typed schema, not a loose map or dictionary. The schema is the contract.",
8
+ why: "A loose response becomes a loose client type, in every app that uses the API, at once.",
9
+ ask: "Is every request and response body in this change a typed schema?",
10
+ stage: "mvp",
11
+ check: "ai-review",
12
+ severity: "medium",
13
+ },
14
+ {
15
+ id: "API-02",
16
+ domain: "api-design",
17
+ title: "The contract has one source of truth",
18
+ rule: "The API's contract has one source of truth, whether it's generated from the code's schemas or written by hand, and every client works from it.",
19
+ why: "Two descriptions of one API disagree, and the client finds out in production.",
20
+ ask: "Does this change keep the API contract's one source of truth up to date?",
21
+ stage: "mvp",
22
+ check: "ai-review",
23
+ severity: "high",
24
+ },
25
+ {
26
+ id: "API-03",
27
+ domain: "api-design",
28
+ title: "Client types come from the contract",
29
+ rule: "Client code gets its API types from the contract, never by writing them by hand, and CI fails if they fall behind it.",
30
+ why: "Hand-written types are a copy of the contract that silently goes out of date.",
31
+ ask: "Does this change write any API type by hand instead of generating it from the contract?",
32
+ stage: "mvp",
33
+ check: "auto",
34
+ severity: "medium",
35
+ },
36
+ {
37
+ id: "API-04",
38
+ domain: "api-design",
39
+ title: "Errors have one shape",
40
+ rule: "Every error response from the API has the same shape.",
41
+ why: "A client that has to handle four error formats will handle three of them.",
42
+ ask: "Does every error in this change use the API's one error shape?",
43
+ stage: "mvp",
44
+ check: "ai-review",
45
+ severity: "medium",
46
+ },
47
+ {
48
+ id: "API-05",
49
+ domain: "api-design",
50
+ title: "Lists have one shape",
51
+ rule: "Every list response has the same shape, everywhere in the API. The profile gives a default.",
52
+ why: "A client can't write one list component against four conventions.",
53
+ ask: "Does every list in this change use the API's one list shape?",
54
+ stage: "mvp",
55
+ check: "ai-review",
56
+ severity: "low",
57
+ },
58
+ {
59
+ id: "API-06",
60
+ domain: "api-design",
61
+ title: "Changing a field breaks clients: add, migrate, then remove",
62
+ rule: "Adding a field is safe. Removing, renaming or retyping one breaks clients, so it's done in steps: add the new one, move every client across, then remove the old one.",
63
+ why: "Clients aren't updated at the same moment as the server, and some, like installed phone apps, are never updated at all.",
64
+ ask: "Does this change remove, rename or retype a field that clients may still use?",
65
+ stage: "mvp",
66
+ check: "ai-review",
67
+ severity: "high",
68
+ },
69
+ {
70
+ id: "API-07",
71
+ domain: "api-design",
72
+ title: "Every list is paged",
73
+ rule: "Every endpoint that returns a list returns it a page at a time. None returns everything.",
74
+ why: "An endpoint that returns everything passes every test on sample data, then falls over on real data.",
75
+ ask: "Does every list endpoint in this change return pages?",
76
+ stage: "mvp",
77
+ check: "auto",
78
+ severity: "medium",
79
+ },
80
+ {
81
+ id: "API-08",
82
+ domain: "api-design",
83
+ title: "Page sizes come from one place",
84
+ rule: "The default and largest page sizes come from one shared place, not each endpoint's own numbers.",
85
+ why: '"What\'s the largest page a client can ask for?" should have one answer, especially under load.',
86
+ ask: "Does this change set a page size anywhere other than the shared place?",
87
+ stage: "mvp",
88
+ check: "ai-review",
89
+ severity: "low",
90
+ },
91
+ ];
@@ -0,0 +1,41 @@
1
+ export declare const architecture: ({
2
+ id: string;
3
+ domain: "architecture";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "ai-review";
10
+ severity: "medium";
11
+ } | {
12
+ id: string;
13
+ domain: "architecture";
14
+ title: string;
15
+ rule: string;
16
+ why: string;
17
+ ask: string;
18
+ stage: "mvp";
19
+ check: "ai-review";
20
+ severity: "medium";
21
+ } | {
22
+ id: string;
23
+ domain: "architecture";
24
+ title: string;
25
+ rule: string;
26
+ why: string;
27
+ ask: string;
28
+ stage: "mvp";
29
+ check: "auto";
30
+ severity: "medium";
31
+ } | {
32
+ id: string;
33
+ domain: "architecture";
34
+ title: string;
35
+ rule: string;
36
+ why: string;
37
+ ask: string;
38
+ stage: "mvp";
39
+ check: "ai-review";
40
+ severity: "high";
41
+ })[];
@@ -0,0 +1,93 @@
1
+ // How a system is divided, and which way its parts depend on each other. These hold for any
2
+ // architecture: a modular monolith, microservices, a mobile app or a library. A folder layout
3
+ // is a stack profile's default, never a core rule.
4
+ export const architecture = [
5
+ {
6
+ id: "ARC-01",
7
+ domain: "architecture",
8
+ title: "Code is judged against the project's own architecture",
9
+ rule: "Code is judged against the architecture the project has declared (its tracks, each track's architecture and its decision records), never against a structure from somewhere else.",
10
+ why: "A review that expects a layout the project never chose buries the real problems under false ones.",
11
+ ask: "Does this review check the code against the architecture the project declared?",
12
+ stage: "prototype",
13
+ check: "ai-review",
14
+ severity: "medium",
15
+ },
16
+ {
17
+ id: "ARC-02",
18
+ domain: "architecture",
19
+ title: "One module owns each area",
20
+ rule: "Each area of the business is owned by one module. Another area that needs its logic calls it; it never copies it.",
21
+ why: "Two implementations of one business rule will disagree, and nobody will know which is right.",
22
+ ask: "Does this change put its logic in the module that owns that area?",
23
+ stage: "mvp",
24
+ check: "ai-review",
25
+ severity: "medium",
26
+ },
27
+ {
28
+ id: "ARC-03",
29
+ domain: "architecture",
30
+ title: "Modules don't reach into each other's internals",
31
+ rule: "A module has a deliberate public surface, and nothing uses its internals. Something several modules need is moved somewhere shared and named honestly.",
32
+ why: "Marking something internal tells the next person they may change it freely. Using it from elsewhere breaks that promise, and the break shows up later as someone else's bug.",
33
+ ask: "Does anything in this change use another module's internals?",
34
+ stage: "mvp",
35
+ check: "ai-review",
36
+ severity: "medium",
37
+ },
38
+ {
39
+ id: "ARC-04",
40
+ domain: "architecture",
41
+ title: "Business rules are plain code",
42
+ rule: "Business rules, calculations and validation live in plain code, with no database, network, framework or user interface in it, so they can be tested with plain values.",
43
+ why: "Rules tangled with a framework can only be tested slowly and partly. Plain rules can be tested exhaustively, which is where the hardest rules need it most.",
44
+ ask: "Could the business logic in this change be tested without a database, a network or a user interface?",
45
+ stage: "mvp",
46
+ check: "ai-review",
47
+ severity: "medium",
48
+ },
49
+ {
50
+ id: "ARC-05",
51
+ domain: "architecture",
52
+ title: "Business logic doesn't know how it's called",
53
+ rule: "Business logic never deals in HTTP: no status codes, no request objects, no HTTP errors. It raises or returns its own errors, and the layer that received the request translates them.",
54
+ why: "Logic that knows about HTTP can't be reused by a background job, a script or a different interface.",
55
+ ask: "Does any business logic in this change refer to HTTP?",
56
+ stage: "mvp",
57
+ check: "ai-review",
58
+ severity: "medium",
59
+ },
60
+ {
61
+ id: "ARC-06",
62
+ domain: "architecture",
63
+ title: "Dependencies point inward",
64
+ rule: "Code depends toward the business rules, never away from them, and features don't depend on each other.",
65
+ why: "Without a direction, every part ends up coupled to every other, and nothing can change on its own.",
66
+ ask: "Does any dependency in this change point outward, or from one feature to another?",
67
+ stage: "mvp",
68
+ check: "auto",
69
+ severity: "medium",
70
+ },
71
+ {
72
+ id: "ARC-07",
73
+ domain: "architecture",
74
+ title: "Data is reached through an interface",
75
+ rule: "Screens and business logic reach data through an interface, never a storage engine or the network directly.",
76
+ why: "Then changing where data lives, from local storage to an API or from one API to another, touches one place.",
77
+ ask: "Does anything outside the data layer talk to storage or the network directly?",
78
+ stage: "mvp",
79
+ check: "auto",
80
+ severity: "medium",
81
+ },
82
+ {
83
+ id: "ARC-08",
84
+ domain: "architecture",
85
+ title: "There is one managed way to reach the database",
86
+ rule: "The database is reached one managed way, so transactions and connection pooling can't be bypassed.",
87
+ why: "Code that opens its own connection escapes the transaction it should be part of, and exhausts the connection pool under load.",
88
+ ask: "Does anything in this change open its own database connection?",
89
+ stage: "mvp",
90
+ check: "ai-review",
91
+ severity: "high",
92
+ },
93
+ ];
@@ -0,0 +1,21 @@
1
+ export declare const backend: ({
2
+ id: string;
3
+ domain: "backend";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "ai-review";
10
+ severity: "high";
11
+ } | {
12
+ id: string;
13
+ domain: "backend";
14
+ title: string;
15
+ rule: string;
16
+ why: string;
17
+ ask: string;
18
+ stage: "mvp";
19
+ check: "ai-review";
20
+ severity: "medium";
21
+ })[];
@@ -0,0 +1,25 @@
1
+ // How servers take requests and report what happened, whatever the language or framework.
2
+ export const backend = [
3
+ {
4
+ id: "BE-01",
5
+ domain: "backend",
6
+ title: "A failed operation is reported as failed",
7
+ rule: "An operation that didn't happen is never reported as done: a payment that didn't go through is never shown as sent.",
8
+ why: "A false success is worse than an error. The person relies on it, and the problem surfaces much later, somewhere else.",
9
+ ask: "Could anything in this change report success for an operation that failed?",
10
+ stage: "prototype",
11
+ check: "ai-review",
12
+ severity: "high",
13
+ },
14
+ {
15
+ id: "BE-02",
16
+ domain: "backend",
17
+ title: "Request bodies have a size limit",
18
+ rule: "The server limits how large a request body can be, with a limit that fits what each endpoint really needs.",
19
+ why: "Without a limit, one oversized request can use up a server's memory and take it down for everyone.",
20
+ ask: "Does every endpoint in this change have a sensible limit on the size of what it accepts?",
21
+ stage: "mvp",
22
+ check: "ai-review",
23
+ severity: "medium",
24
+ },
25
+ ];
@@ -0,0 +1,91 @@
1
+ export declare const codeQuality: ({
2
+ id: string;
3
+ domain: "code-quality";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "ai-review";
10
+ severity: "low";
11
+ } | {
12
+ id: string;
13
+ domain: "code-quality";
14
+ title: string;
15
+ rule: string;
16
+ why: string;
17
+ ask: string;
18
+ stage: "mvp";
19
+ check: "ai-review";
20
+ severity: "low";
21
+ } | {
22
+ id: string;
23
+ domain: "code-quality";
24
+ title: string;
25
+ rule: string;
26
+ why: string;
27
+ ask: string;
28
+ stage: "prototype";
29
+ check: "ai-review";
30
+ severity: "high";
31
+ } | {
32
+ id: string;
33
+ domain: "code-quality";
34
+ title: string;
35
+ rule: string;
36
+ why: string;
37
+ ask: string;
38
+ stage: "mvp";
39
+ check: "ai-review";
40
+ severity: "medium";
41
+ } | {
42
+ id: string;
43
+ domain: "code-quality";
44
+ title: string;
45
+ rule: string;
46
+ why: string;
47
+ ask: string;
48
+ stage: "mvp";
49
+ check: "auto";
50
+ severity: "low";
51
+ } | {
52
+ id: string;
53
+ domain: "code-quality";
54
+ title: string;
55
+ rule: string;
56
+ why: string;
57
+ ask: string;
58
+ stage: "prototype";
59
+ check: "auto";
60
+ severity: "high";
61
+ } | {
62
+ id: string;
63
+ domain: "code-quality";
64
+ title: string;
65
+ rule: string;
66
+ why: string;
67
+ ask: string;
68
+ stage: "mvp";
69
+ check: "auto";
70
+ severity: "medium";
71
+ } | {
72
+ id: string;
73
+ domain: "code-quality";
74
+ title: string;
75
+ rule: string;
76
+ why: string;
77
+ ask: string;
78
+ stage: "prototype";
79
+ check: "auto";
80
+ severity: "medium";
81
+ } | {
82
+ id: string;
83
+ domain: "code-quality";
84
+ title: string;
85
+ rule: string;
86
+ why: string;
87
+ ask: string;
88
+ stage: "prototype";
89
+ check: "ai-review";
90
+ severity: "medium";
91
+ })[];