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
@@ -0,0 +1,68 @@
1
+ export declare const privacyCompliance: ({
2
+ id: string;
3
+ domain: "privacy-compliance";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "auto";
10
+ severity: "high";
11
+ sources: {
12
+ name: string;
13
+ ref: string;
14
+ url: string;
15
+ }[];
16
+ } | {
17
+ id: string;
18
+ domain: "privacy-compliance";
19
+ title: string;
20
+ rule: string;
21
+ why: string;
22
+ ask: string;
23
+ stage: "prototype";
24
+ check: "ai-review";
25
+ severity: "high";
26
+ sources?: never;
27
+ } | {
28
+ id: string;
29
+ domain: "privacy-compliance";
30
+ title: string;
31
+ rule: string;
32
+ why: string;
33
+ ask: string;
34
+ stage: "mvp";
35
+ check: "ai-review";
36
+ severity: "high";
37
+ sources?: never;
38
+ } | {
39
+ id: string;
40
+ domain: "privacy-compliance";
41
+ title: string;
42
+ rule: string;
43
+ why: string;
44
+ ask: string;
45
+ stage: "mvp";
46
+ check: "ai-review";
47
+ severity: "high";
48
+ sources: {
49
+ name: string;
50
+ ref: string;
51
+ url: string;
52
+ }[];
53
+ } | {
54
+ id: string;
55
+ domain: "privacy-compliance";
56
+ title: string;
57
+ rule: string;
58
+ why: string;
59
+ ask: string;
60
+ stage: "production";
61
+ check: "ai-review";
62
+ severity: "medium";
63
+ sources: {
64
+ name: string;
65
+ ref: string;
66
+ url: string;
67
+ }[];
68
+ })[];
@@ -0,0 +1,77 @@
1
+ // Personal data, and handling it the way the law and the people it belongs to expect. The laws
2
+ // themselves, such as the NDPA or the GDPR, are rule packs a project chooses in its config.
3
+ const ASVS = "OWASP ASVS 5.0";
4
+ const V14 = "https://github.com/OWASP/ASVS/blob/master/5.0/en/0x23-V14-Data-Protection.md";
5
+ const V16 = "https://github.com/OWASP/ASVS/blob/master/5.0/en/0x25-V16-Security-Logging-and-Error-Handling.md";
6
+ export const privacyCompliance = [
7
+ {
8
+ id: "PRIV-01",
9
+ domain: "privacy-compliance",
10
+ title: "Logs never hold secrets, tokens or personal data",
11
+ rule: "Passwords, tokens, keys, payment details and personal data are never written to logs. A redaction filter in the logging layer removes them, and it can't be bypassed.",
12
+ why: "Logs are copied, shipped and kept far more widely than the data they came from, and a password in a log is a password everyone with log access has.",
13
+ ask: "Could anything in this change write a secret or personal data to a log?",
14
+ stage: "prototype",
15
+ check: "auto",
16
+ severity: "high",
17
+ sources: [{ name: ASVS, ref: "16.2.5, level 2", url: V16 }],
18
+ },
19
+ {
20
+ id: "PRIV-02",
21
+ domain: "privacy-compliance",
22
+ title: "No real personal data in the repository",
23
+ rule: "Fixtures, seed data, screenshots, tests and examples use invented data. No real person's data goes into the repository.",
24
+ why: "Everything in a repository is copied to every machine that clones it, forever.",
25
+ ask: "Does this change add any real person's data to the repository?",
26
+ stage: "prototype",
27
+ check: "ai-review",
28
+ severity: "high",
29
+ },
30
+ {
31
+ id: "PRIV-03",
32
+ domain: "privacy-compliance",
33
+ title: "Only what's needed is collected",
34
+ rule: "A feature collects only the personal data it needs, at the precision it needs, and only while it needs it: a rough area rather than an exact location, and location only while searching rather than all the time.",
35
+ why: "Data you don't collect can't leak, can't be misused and doesn't need protecting. Collecting only what's needed is also what data protection laws require.",
36
+ ask: "Does this change collect more personal data, or more precise data, than it needs?",
37
+ stage: "mvp",
38
+ check: "ai-review",
39
+ severity: "high",
40
+ },
41
+ {
42
+ id: "PRIV-04",
43
+ domain: "privacy-compliance",
44
+ title: "Personal data goes only where people have been told",
45
+ rule: "Personal data is sent only to the services people have been told about, with their consent where the law requires it. Analytics and telemetry are off until the person opts in.",
46
+ why: "Sending data to a third party people didn't know about breaks their trust, and in most countries it breaks the law too.",
47
+ ask: "Does this change send personal data anywhere people haven't been told about?",
48
+ stage: "mvp",
49
+ check: "ai-review",
50
+ severity: "high",
51
+ sources: [{ name: ASVS, ref: "14.2.3, level 2", url: V14 }],
52
+ },
53
+ {
54
+ id: "PRIV-05",
55
+ domain: "privacy-compliance",
56
+ title: "Hidden details are removed from files before they leave",
57
+ rule: "Before a photo or file is shared or sent to another service, details the person may not know it carries, such as where a photo was taken, are removed, unless the person chose to keep them.",
58
+ why: "A photo's location can reveal where someone lives, and most people have no idea it's there.",
59
+ ask: "Does this change send or share files with hidden details, such as location, still in them?",
60
+ stage: "mvp",
61
+ check: "ai-review",
62
+ severity: "high",
63
+ sources: [{ name: ASVS, ref: "14.2.8, level 3", url: V14 }],
64
+ },
65
+ {
66
+ id: "PRIV-06",
67
+ domain: "privacy-compliance",
68
+ title: "Personal data is kept only as long as it's needed",
69
+ rule: "Each kind of personal data has a set time it's kept, such as location from a live stream, and a scheduled job deletes it when that time is up.",
70
+ why: 'Data kept forever is data that can leak forever, and "we\'ll delete it later" never happens without a job that does it.',
71
+ ask: "Does the personal data in this change have a set time it's kept, and a job that deletes it?",
72
+ stage: "production",
73
+ check: "ai-review",
74
+ severity: "medium",
75
+ sources: [{ name: ASVS, ref: "14.2.7, level 3", url: V14 }],
76
+ },
77
+ ];
@@ -0,0 +1,67 @@
1
+ export declare const reliability: ({
2
+ id: string;
3
+ domain: "reliability";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "mvp";
9
+ check: "ai-review";
10
+ severity: "medium";
11
+ when?: never;
12
+ } | {
13
+ id: string;
14
+ domain: "reliability";
15
+ title: string;
16
+ rule: string;
17
+ why: string;
18
+ ask: string;
19
+ stage: "production";
20
+ check: "ai-review";
21
+ severity: "medium";
22
+ when?: never;
23
+ } | {
24
+ id: string;
25
+ domain: "reliability";
26
+ title: string;
27
+ rule: string;
28
+ why: string;
29
+ ask: string;
30
+ stage: "mvp";
31
+ check: "ai-review";
32
+ severity: "high";
33
+ when?: never;
34
+ } | {
35
+ id: string;
36
+ domain: "reliability";
37
+ title: string;
38
+ rule: string;
39
+ why: string;
40
+ ask: string;
41
+ stage: "production";
42
+ check: "auto";
43
+ severity: "high";
44
+ when?: never;
45
+ } | {
46
+ id: string;
47
+ domain: "reliability";
48
+ title: string;
49
+ rule: string;
50
+ why: string;
51
+ ask: string;
52
+ stage: "production";
53
+ check: "ai-review";
54
+ severity: "medium";
55
+ when: "real-time"[];
56
+ } | {
57
+ id: string;
58
+ domain: "reliability";
59
+ title: string;
60
+ rule: string;
61
+ why: string;
62
+ ask: string;
63
+ stage: "mvp";
64
+ check: "ai-review";
65
+ severity: "high";
66
+ when: "offline"[];
67
+ })[];
@@ -0,0 +1,105 @@
1
+ // Staying up, and failing safely when something underneath fails.
2
+ export const reliability = [
3
+ {
4
+ id: "REL-01",
5
+ domain: "reliability",
6
+ title: "Every call to another service has a timeout and handles failure",
7
+ rule: "Every call to another service or API has a timeout, and a failed or slow response is handled: retried when that's safe, reported when it isn't.",
8
+ why: "A call with no timeout waits forever, and one slow provider then ties up every request that depends on it.",
9
+ ask: "Does every call to another service in this change have a timeout and handle failure?",
10
+ stage: "mvp",
11
+ check: "ai-review",
12
+ severity: "medium",
13
+ },
14
+ {
15
+ id: "REL-02",
16
+ domain: "reliability",
17
+ title: "If the cache is down, requests are slower, not failed",
18
+ rule: "When a cache is unavailable, requests fall back to working without it. They get slower; they don't fail.",
19
+ why: "A cache is there to speed things up. If losing it takes the service down, it has become a single point of failure.",
20
+ ask: "Does everything in this change keep working if the cache is down?",
21
+ stage: "production",
22
+ check: "ai-review",
23
+ severity: "medium",
24
+ },
25
+ {
26
+ id: "REL-03",
27
+ domain: "reliability",
28
+ title: "Rate limiting never switches off",
29
+ rule: "If the rate limiter's shared store is down, it falls back to a limit on each server and raises an alert. For sign-in, password reset, two-factor and one-time codes, the fallback is at least as strict as normal. Limiting is never simply switched off.",
30
+ why: "Refusing every request would turn a cache outage into a total outage, and allowing unlimited sign-in attempts would open a window for guessing passwords.",
31
+ ask: "If the rate limiter's store fails, does this change still limit requests, as strictly for sign-in?",
32
+ stage: "production",
33
+ check: "ai-review",
34
+ severity: "medium",
35
+ },
36
+ {
37
+ id: "REL-04",
38
+ domain: "reliability",
39
+ title: "Configuration fails closed",
40
+ rule: "An unrecognised environment name is treated as production, and one function decides which environment is running.",
41
+ why: "A typo in an environment name must never switch production's safeguards off.",
42
+ ask: "Does this change decide the environment anywhere other than the one function, or treat an unknown one as safe?",
43
+ stage: "mvp",
44
+ check: "ai-review",
45
+ severity: "high",
46
+ },
47
+ {
48
+ id: "REL-05",
49
+ domain: "reliability",
50
+ title: "Demo shortcuts can't run in production",
51
+ rule: "Demo passwords, seed shortcuts and sandbox providers are refused when the app starts in production.",
52
+ why: "A convenience left switched on in production is a back door.",
53
+ ask: "Could any demo or test shortcut in this change run in production?",
54
+ stage: "production",
55
+ check: "auto",
56
+ severity: "high",
57
+ },
58
+ {
59
+ id: "REL-06",
60
+ domain: "reliability",
61
+ title: "Every process runs the same safety checks at start-up",
62
+ rule: "Every process that can move money or change data, including background workers and scripts, runs the same production safety checks when it starts as the main server.",
63
+ why: "The worker nobody thought about is the one that runs with the unsafe setting.",
64
+ ask: "Does every process in this change run the same start-up safety checks as the server?",
65
+ stage: "production",
66
+ check: "ai-review",
67
+ severity: "medium",
68
+ },
69
+ {
70
+ id: "REL-07",
71
+ domain: "reliability",
72
+ title: "A dropped live connection loses nothing that mattered",
73
+ rule: "Anything that matters is saved, not held only in a live connection, so a dropped connection loses nothing.",
74
+ why: "Live connections drop all the time on mobile networks. State that only existed in the stream is gone.",
75
+ ask: "Would a dropped connection lose anything that matters in this change?",
76
+ stage: "production",
77
+ check: "ai-review",
78
+ severity: "medium",
79
+ when: ["real-time"],
80
+ },
81
+ {
82
+ id: "REL-08",
83
+ domain: "reliability",
84
+ title: "When the device holds the only copy, it's protected",
85
+ rule: "When a person's device holds the only copy of their data, the app asks the platform to keep it rather than clear it when space runs short, and offers a way to back it up.",
86
+ why: "Browsers and phones clear stored data under pressure, and for an offline-first app that can mean everything the person ever entered.",
87
+ ask: "Is data that exists only on the device protected from being cleared, with a way to back it up?",
88
+ stage: "mvp",
89
+ check: "ai-review",
90
+ severity: "high",
91
+ when: ["offline"],
92
+ },
93
+ {
94
+ id: "REL-09",
95
+ domain: "reliability",
96
+ title: "An app that caches itself still updates",
97
+ rule: "An app that caches its own code to work offline checks for new versions and applies them, so every person gets updates.",
98
+ why: "An app that always serves its cached copy never gets fixes, including the fix for the bug that's hurting people.",
99
+ ask: "Will people running a cached copy of this app get the next version?",
100
+ stage: "mvp",
101
+ check: "ai-review",
102
+ severity: "high",
103
+ when: ["offline"],
104
+ },
105
+ ];
@@ -0,0 +1,41 @@
1
+ export declare const requirements: ({
2
+ id: string;
3
+ domain: "requirements";
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: "requirements";
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: "requirements";
24
+ title: string;
25
+ rule: string;
26
+ why: string;
27
+ ask: string;
28
+ stage: "mvp";
29
+ check: "ai-review";
30
+ severity: "low";
31
+ } | {
32
+ id: string;
33
+ domain: "requirements";
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,58 @@
1
+ // What the product must do, for whom, and how anyone will know it works.
2
+ export const requirements = [
3
+ {
4
+ id: "REQ-01",
5
+ domain: "requirements",
6
+ title: "A requirement names who it's for and the problem",
7
+ rule: "A requirement says who it's for and the problem it solves, not only the solution someone has in mind.",
8
+ why: "A solution with no stated problem can't be questioned or improved, and often solves the wrong thing well.",
9
+ ask: "Does this requirement say who it's for and what problem it solves?",
10
+ stage: "prototype",
11
+ check: "ai-review",
12
+ severity: "low",
13
+ },
14
+ {
15
+ id: "REQ-02",
16
+ domain: "requirements",
17
+ title: "Every feature has acceptance criteria before it's built",
18
+ rule: "Before a feature is built, it has acceptance criteria: what done looks like, written so it can be tested.",
19
+ why: 'Without them, "done" means whatever the builder thought, and disagreements surface after the work is finished.',
20
+ ask: "Does this feature have testable acceptance criteria?",
21
+ stage: "mvp",
22
+ check: "ai-review",
23
+ severity: "medium",
24
+ },
25
+ {
26
+ id: "REQ-03",
27
+ domain: "requirements",
28
+ title: "The needs behind the features are written down",
29
+ rule: "The needs that shape everything are written down: who uses the product and what they need to access it, how many people and how much data, where it operates and which laws apply, and how available it must be.",
30
+ why: "These needs decide the architecture, and discovering them late means rebuilding it.",
31
+ ask: "Are the product's users, scale, laws and availability needs written down?",
32
+ stage: "mvp",
33
+ check: "ai-review",
34
+ severity: "medium",
35
+ },
36
+ {
37
+ id: "REQ-04",
38
+ domain: "requirements",
39
+ title: "Ideas outside the agreed scope go to the backlog",
40
+ rule: "An idea outside the agreed scope of a piece of work goes to the backlog, not into the change.",
41
+ why: "Scope that grows inside a change makes it late, hard to review and risky to ship.",
42
+ ask: "Does this change include anything outside its agreed scope?",
43
+ stage: "mvp",
44
+ check: "ai-review",
45
+ severity: "low",
46
+ },
47
+ {
48
+ id: "REQ-05",
49
+ domain: "requirements",
50
+ title: "A feature ships only when every acceptance criterion holds",
51
+ rule: "A feature ships only when every one of its acceptance criteria holds. A criterion that doesn't is fixed first, or changed or dropped by whoever agreed it, never shipped broken or quietly skipped.",
52
+ why: "The acceptance criteria are what was agreed. A feature that fails one does something nobody agreed to, and the people relying on it find out first.",
53
+ ask: "Does every acceptance criterion of this feature hold in the code?",
54
+ stage: "mvp",
55
+ check: "ai-review",
56
+ severity: "high",
57
+ },
58
+ ];
@@ -0,0 +1,41 @@
1
+ export declare const safetyCritical: ({
2
+ id: string;
3
+ domain: "safety-critical";
4
+ title: string;
5
+ rule: string;
6
+ why: string;
7
+ ask: string;
8
+ stage: "prototype";
9
+ check: "auto";
10
+ severity: "critical";
11
+ } | {
12
+ id: string;
13
+ domain: "safety-critical";
14
+ title: string;
15
+ rule: string;
16
+ why: string;
17
+ ask: string;
18
+ stage: "prototype";
19
+ check: "ai-review";
20
+ severity: "high";
21
+ } | {
22
+ id: string;
23
+ domain: "safety-critical";
24
+ title: string;
25
+ rule: string;
26
+ why: string;
27
+ ask: string;
28
+ stage: "mvp";
29
+ check: "ai-review";
30
+ severity: "high";
31
+ } | {
32
+ id: string;
33
+ domain: "safety-critical";
34
+ title: string;
35
+ rule: string;
36
+ why: string;
37
+ ask: string;
38
+ stage: "mvp";
39
+ check: "auto";
40
+ severity: "high";
41
+ })[];
@@ -0,0 +1,71 @@
1
+ // For products with the safety-critical trait: data where a wrong value could hurt someone, such
2
+ // as allergens, medical dosage, legal deadlines, or eligibility that affects a person's rights.
3
+ // The project's add-on names what counts.
4
+ export const safetyCritical = [
5
+ {
6
+ id: "SAFE-01",
7
+ domain: "safety-critical",
8
+ title: "Safety checks block; they never just warn",
9
+ rule: "A check on safety-critical data blocks the action. Nobody can get past it: not a user, not an administrator, not a direct call to the API.",
10
+ why: "A warning people can click past isn't a safety check. They will click past it.",
11
+ ask: "Can anyone get past this safety check?",
12
+ stage: "prototype",
13
+ check: "auto",
14
+ severity: "critical",
15
+ },
16
+ {
17
+ id: "SAFE-02",
18
+ domain: "safety-critical",
19
+ title: "States that differ stay distinct",
20
+ rule: 'Distinct states stay distinct. "Present", "may be present" and "absent" are three states, never a yes-or-no.',
21
+ why: 'The person relying on the answer is the one at risk, and "may contain" squeezed into "no" can hurt them.',
22
+ ask: "Does any safety-critical value in this change lose a state it should have?",
23
+ stage: "prototype",
24
+ check: "auto",
25
+ severity: "critical",
26
+ },
27
+ {
28
+ id: "SAFE-03",
29
+ domain: "safety-critical",
30
+ title: "Safety-critical data is structured, never free text",
31
+ rule: "Safety-critical data is stored as structured fields the system can reason about, never as free text.",
32
+ why: "A system can't check, filter or warn about something written in a sentence.",
33
+ ask: "Is any safety-critical information in this change held as free text?",
34
+ stage: "prototype",
35
+ check: "ai-review",
36
+ severity: "high",
37
+ },
38
+ {
39
+ id: "SAFE-04",
40
+ domain: "safety-critical",
41
+ title: "Editing sends it through the check again",
42
+ rule: "Editing a record that already passed a safety check sends it through the check again.",
43
+ why: "Otherwise one edit after approval quietly undoes the check.",
44
+ ask: "Does editing an approved record in this change repeat the safety check?",
45
+ stage: "mvp",
46
+ check: "ai-review",
47
+ severity: "high",
48
+ },
49
+ {
50
+ id: "SAFE-05",
51
+ domain: "safety-critical",
52
+ title: "It's shown where the decision is made",
53
+ rule: "Safety-critical information is shown where the person makes the decision, never behind a tab, a toggle, a disclosure or a scroll.",
54
+ why: "Information a person has to go looking for is information they won't see at the moment it matters.",
55
+ ask: "Is safety-critical information visible, without any extra step, where the decision is made?",
56
+ stage: "prototype",
57
+ check: "ai-review",
58
+ severity: "high",
59
+ },
60
+ {
61
+ id: "SAFE-06",
62
+ domain: "safety-critical",
63
+ title: "Every change to it is tested",
64
+ rule: "Any change that touches safety-critical data comes with a test that proves it's still stored, checked and shown correctly.",
65
+ why: "A refactor that drops a warning looks harmless in review. Only a test catches it every time.",
66
+ ask: "Does this change to safety-critical data come with a test that proves it still works end to end?",
67
+ stage: "mvp",
68
+ check: "auto",
69
+ severity: "high",
70
+ },
71
+ ];