@mdferdousalam/agentic-sdlc 0.0.0-stage → 3.0.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 (90) hide show
  1. package/.claude-plugin/marketplace.json +11 -0
  2. package/.claude-plugin/plugin.json +31 -0
  3. package/CHANGELOG.md +330 -0
  4. package/GETTING-STARTED.md +174 -0
  5. package/LICENSE +21 -0
  6. package/README.md +268 -2
  7. package/SECURITY.md +25 -0
  8. package/agents/sdlc-architecture-reviewer.md +71 -0
  9. package/agents/sdlc-branch-opener.md +83 -0
  10. package/agents/sdlc-code-reviewer.md +62 -0
  11. package/agents/sdlc-impact-analyst.md +70 -0
  12. package/agents/sdlc-implementer.md +60 -0
  13. package/agents/sdlc-lander.md +40 -0
  14. package/agents/sdlc-readiness-gate.md +128 -0
  15. package/agents/sdlc-release-manager.md +76 -0
  16. package/agents/sdlc-remediator.md +89 -0
  17. package/agents/sdlc-reporter.md +42 -0
  18. package/agents/sdlc-security-reviewer.md +62 -0
  19. package/agents/sdlc-spec-reviewer.md +56 -0
  20. package/agents/sdlc-spec-writer.md +62 -0
  21. package/agents/sdlc-test-author.md +32 -0
  22. package/agents/sdlc-triager.md +48 -0
  23. package/agents/sdlc-verifier.md +69 -0
  24. package/bin/__pycache__/sdlccpython-315.pyc +0 -0
  25. package/bin/sdlc +2747 -0
  26. package/bin/sdlc-install-opencode +10 -0
  27. package/commands/doctor.md +9 -0
  28. package/commands/feature.md +17 -0
  29. package/commands/gate.md +33 -0
  30. package/commands/impact.md +13 -0
  31. package/commands/implement.md +11 -0
  32. package/commands/init.md +15 -0
  33. package/commands/land.md +10 -0
  34. package/commands/metrics.md +12 -0
  35. package/commands/readiness.md +8 -0
  36. package/commands/release.md +16 -0
  37. package/commands/remediate.md +13 -0
  38. package/commands/report.md +11 -0
  39. package/commands/review.md +12 -0
  40. package/commands/status.md +9 -0
  41. package/commands/trace.md +9 -0
  42. package/commands/triage.md +14 -0
  43. package/commands/verify.md +10 -0
  44. package/docs/compliance.md +70 -0
  45. package/docs/configuration.md +106 -0
  46. package/docs/control-spec.md +269 -0
  47. package/docs/install.md +75 -0
  48. package/docs/maturity.md +129 -0
  49. package/docs/opencode.md +45 -0
  50. package/docs/openspec.md +58 -0
  51. package/docs/pipeline.md +160 -0
  52. package/docs/platforms.md +99 -0
  53. package/docs/rules.md +122 -0
  54. package/evals/baseline-attributes-failure/graders/criteria.md +18 -0
  55. package/evals/baseline-attributes-failure/prompt.md +23 -0
  56. package/evals/budget-stops-rather-than-asks/graders/criteria.md +19 -0
  57. package/evals/budget-stops-rather-than-asks/prompt.md +14 -0
  58. package/evals/critical-low-confidence-escalates/graders/criteria.md +22 -0
  59. package/evals/critical-low-confidence-escalates/prompt.md +17 -0
  60. package/evals/gate-refuses-unexecuted/graders/criteria.md +16 -0
  61. package/evals/gate-refuses-unexecuted/prompt.md +15 -0
  62. package/evals/refusal-is-not-negotiated/graders/criteria.md +17 -0
  63. package/evals/refusal-is-not-negotiated/prompt.md +7 -0
  64. package/evals/release-needs-rollback-and-approval/graders/criteria.md +15 -0
  65. package/evals/release-needs-rollback-and-approval/prompt.md +6 -0
  66. package/evals/remediator-refuses-weakened-test/graders/criteria.md +20 -0
  67. package/evals/remediator-refuses-weakened-test/prompt.md +33 -0
  68. package/evals/spec-review-catches-unfalsifiable/graders/criteria.md +17 -0
  69. package/evals/spec-review-catches-unfalsifiable/prompt.md +17 -0
  70. package/examples/worked-example.md +131 -0
  71. package/hooks/hooks.json +16 -0
  72. package/npm/cli.js +35 -0
  73. package/opencode/plugin/agentic-sdlc.ts +52 -0
  74. package/package.json +59 -4
  75. package/profiles/README.md +52 -0
  76. package/profiles/compiler.md +33 -0
  77. package/profiles/concerns/architecture.md +50 -0
  78. package/profiles/concerns/concurrency.md +59 -0
  79. package/profiles/concerns/data.md +62 -0
  80. package/profiles/concerns/memory.md +52 -0
  81. package/profiles/concerns/performance.md +54 -0
  82. package/profiles/concerns/platform.md +62 -0
  83. package/profiles/library.md +31 -0
  84. package/profiles/service.md +32 -0
  85. package/profiles/webapp.md +40 -0
  86. package/schema/finding.schema.json +267 -0
  87. package/schema/sdlc.config.schema.json +324 -0
  88. package/skills/agentic-sdlc-pipeline/SKILL.md +66 -0
  89. package/skills/openspec-with-sdlc/SKILL.md +56 -0
  90. package/skills/writing-specifications/SKILL.md +51 -0
@@ -0,0 +1,54 @@
1
+ # Concern: performance
2
+
3
+ Taxonomy domains **E** (performance and computational efficiency) and **N** (scalability and
4
+ capacity). Rules in the `PERF-*` namespace.
5
+
6
+ Enable with `"concerns": ["performance"]`. Checked by `sdlc-code-reviewer`.
7
+
8
+ ## What this concern can and cannot do
9
+
10
+ It reviews code against standards. **It does not measure.** A performance claim without a
11
+ representative workload is an opinion, and this file will not let a reviewer pretend otherwise:
12
+ every `PERF-*` finding raised by reading is `medium` confidence at most. Measurement is a
13
+ benchmark in `quality.cmd`, or it has not happened.
14
+
15
+ ## Complexity and work per request
16
+
17
+ - A loop nested inside a loop over user-controlled length is a finding. State the complexity
18
+ and the input size at which it stops being acceptable.
19
+ - Work that does not depend on the input belongs outside the loop; work that does not depend on
20
+ the request belongs outside the request.
21
+ - A new allocation, copy or serialisation on a hot path needs a reason. Passing by value what
22
+ could be borrowed, re-serialising what is already serialised, and parsing the same
23
+ configuration per call are the usual three.
24
+
25
+ ## Data access
26
+
27
+ - A query inside a loop is `PERF-N-PLUS-ONE` and is blocking. The fix is one query, not a cache.
28
+ - Every list endpoint is paginated. An unpaginated query over a table expected to grow is
29
+ blocking, however small the table is today.
30
+ - A new filter or sort on a growing table arrives with its index, or with the reason it does not
31
+ need one.
32
+ - A cache needs three answers before it is an improvement: what invalidates it, what happens on
33
+ a miss storm, and what a stale read costs. Without them it is a correctness bug with better
34
+ latency.
35
+
36
+ ## Network and I/O
37
+
38
+ - Round trips in series that could be in parallel; payloads that carry fields nobody reads;
39
+ a retry policy with no jitter. Each is a finding with a named fix.
40
+ - Blocking I/O on an asynchronous path blocks everything sharing that thread. Name the call.
41
+
42
+ ## Scale
43
+
44
+ - State the limit: at what concurrency, queue depth, connection count or data volume does this
45
+ stop working? "It scales" is not an answer, and neither is silence.
46
+ - Unbounded concurrency, unbounded queue growth and connection-pool exhaustion are blocking.
47
+ - A hot partition — a tenant, a key, a shard taking disproportionate traffic — is a design
48
+ finding, not an operations problem.
49
+
50
+ ## The tool beats the opinion
51
+
52
+ `cargo bench` / criterion, `go test -bench` and `pprof`, `hyperfine`, `pytest-benchmark`,
53
+ Lighthouse or `bundlesize` for the web, `EXPLAIN ANALYZE` for a query. Put the one that fits in
54
+ `quality.cmd` with a budget, and a `PERF-*` finding can finally be `high` confidence.
@@ -0,0 +1,62 @@
1
+ # Concern: platform and low-level correctness
2
+
3
+ Taxonomy domain **S** (platform-specific and low-level correctness), plus the toolchain half of
4
+ **X8**. Rules in the `PLAT-*` namespace.
5
+
6
+ Enable with `"concerns": ["platform"]`. Checked by `sdlc-code-reviewer`.
7
+
8
+ For anything that runs somewhere other than the machine it was written on — which, once there
9
+ is CI, is everything.
10
+
11
+ ## What this concern can and cannot do
12
+
13
+ Almost everything here is settled by running the code somewhere else, and almost nothing by
14
+ reading it on the machine it was written on. A `PLAT-*` finding from the diff is `medium`
15
+ confidence; a CI matrix that actually fails on another operating system, architecture or
16
+ locale makes it `high`. One failing matrix leg is worth more than this whole file.
17
+
18
+ ## Assumptions about the host
19
+
20
+ - Path separators, case sensitivity, maximum path length, permitted filename characters. A test
21
+ that passes on macOS and fails on Linux is usually a case-sensitivity assumption, and the
22
+ reverse is usually a path-length one.
23
+ - Line endings on anything written, read or compared.
24
+ - A temporary directory is obtained from the platform, never hardcoded to `/tmp`.
25
+ - File permissions, symlink behaviour and atomic rename differ across filesystems. A
26
+ write-then-rename that is atomic on one is not on all.
27
+ - Environment variables: name the ones required, their defaults, and the behaviour when absent
28
+ or malformed at startup. Failing at first use instead of at startup turns a configuration
29
+ error into a 3am page.
30
+
31
+ ## Numbers and encoding
32
+
33
+ - Integer overflow, underflow and precision loss, especially before an allocation or an index.
34
+ Say whether the language wraps, traps or is undefined here — the three behave differently
35
+ and the code usually assumes one.
36
+ - Signed/unsigned conversions and narrowing casts.
37
+ - Endianness and alignment on anything serialised, memory-mapped or sent over a wire.
38
+ - Text is bytes until it is decoded. State the encoding; do not index into a UTF-8 string by
39
+ byte offset and call it a character.
40
+
41
+ ## Locale and time
42
+
43
+ - Case conversion, sorting, number and date formatting are locale-dependent. `toUpperCase` on a
44
+ Turkish locale is the classic. Use an invariant locale for anything the program compares.
45
+ - The system clock moves backwards. A duration measured with a wall clock is not a duration;
46
+ use a monotonic one.
47
+
48
+ ## Process and toolchain
49
+
50
+ - Signal handling and shutdown: what happens to in-flight work on SIGTERM?
51
+ - Exit codes mean something to whatever invoked you.
52
+ - Resource limits — open file descriptors, process count — are real and are lower in a
53
+ container than on a laptop.
54
+ - The toolchain is pinned where the project can pin it. A build that depends on whatever
55
+ version is installed will differ between a developer's machine and CI, and `ENV-TOOLCHAIN-DRIFT`
56
+ exists to say so. Native dependencies and cross-architecture builds are where this bites.
57
+
58
+ ## The tool beats the opinion
59
+
60
+ A CI matrix across the operating systems and architectures you claim to support is worth more
61
+ than this entire file. `cross`, `cibuildwheel`, QEMU runners, `shellcheck` for portable shell,
62
+ and a 32-bit or big-endian target if you claim one.
@@ -0,0 +1,31 @@
1
+ # Profile: library
2
+
3
+ For published packages, SDKs and anything whose consumers are other developers.
4
+
5
+ ## The public API is a promise
6
+
7
+ - Every exported symbol is intentional. A symbol exported by accident is a defect, not a
8
+ feature, and removing it later is a breaking change.
9
+ - Every exported symbol has documentation that says what it does, what it returns, what it
10
+ throws or rejects with, and one runnable example.
11
+ - A change to an exported signature, a default, an error type or a thrown condition is a
12
+ breaking change, whatever the implementation looks like. The specification must say so.
13
+
14
+ ## Versioning
15
+
16
+ - Semantic versioning, decided from the diff rather than from intent: removed or narrowed →
17
+ major; added → minor; neither → patch.
18
+ - The changelog entry is written in the same commit as the change, in the consumer's language —
19
+ what they must do, not what you refactored.
20
+ - Deprecate before removing: a release that warns, then a release that removes.
21
+
22
+ ## Compatibility
23
+
24
+ - The supported runtime and dependency ranges are stated and tested, not assumed.
25
+ - No new required peer dependency in a minor release.
26
+ - Types ship with the package and are tested by compiling an example consumer.
27
+
28
+ ## Tests
29
+
30
+ - Public behaviour is tested through the public entry point, not through internals.
31
+ - Every documented example is executed by a test; a broken README example is a bug.
@@ -0,0 +1,32 @@
1
+ # Profile: service
2
+
3
+ For long-running network services. The questions are about the second year of operation, not
4
+ the first deploy.
5
+
6
+ ## Failure is specified
7
+
8
+ - Every outbound call states its timeout, its retry policy and what happens when it exhausts
9
+ them. "Retry forever" is not a policy.
10
+ - Every failure path either degrades in a stated way or fails loudly. Nothing is swallowed.
11
+ - Partial writes are impossible, or the recovery path is specified and tested.
12
+ - Idempotency: any operation a client may retry states its idempotency key and behaviour.
13
+
14
+ ## Operability
15
+
16
+ - Every new code path is observable: a log line with the correlation identifier, a metric, or a
17
+ span. A failure mode that cannot be seen cannot be operated.
18
+ - Logs carry no personal data, credential or full payload by default.
19
+ - A new configuration value has a default, a documented range, and a stated behaviour when
20
+ absent or invalid at startup.
21
+
22
+ ## Load and limits
23
+
24
+ - Unbounded allocation, unbounded queues, unpaginated queries and user-controlled loop bounds
25
+ are blocking findings.
26
+ - A new endpoint states its expected rate and its limit behaviour.
27
+
28
+ ## Change safety
29
+
30
+ - A schema change is forward and backward compatible across one deploy, or the specification
31
+ states the ordered migration.
32
+ - Rollback is possible, and the specification says what rolling back loses.
@@ -0,0 +1,40 @@
1
+ # Profile: webapp
2
+
3
+ For product applications with users, an admin surface and a database. Adds these standards to
4
+ the core rules. They are checked by `sdlc-spec-reviewer` and `sdlc-code-reviewer`.
5
+
6
+ ## Configurability
7
+
8
+ Anything a non-engineer will want to change — a threshold, a label, a fee, a rate, a status
9
+ name, an email template, a feature flag — is read from configuration or a reference table, and
10
+ is editable through the admin surface. A literal in code for one of these is a blocking finding.
11
+
12
+ The specification must say which values are configurable. A spec that hardcodes one is
13
+ `changes-requested`.
14
+
15
+ ## Data model
16
+
17
+ - A new table or column states its purpose, its nullability, its indexes and its retention.
18
+ - Reference data lives in reference tables, not in enums compiled into the application, unless
19
+ the value is part of the code's own logic.
20
+ - Every migration is reversible, or says explicitly why it is not, and is tested against a
21
+ database with representative data — not an empty one.
22
+ - No destructive migration without an explicit, separately approved step.
23
+
24
+ ## Interface and accessibility
25
+
26
+ - Every interactive element is reachable and operable by keyboard, and has an accessible name.
27
+ - Colour is never the only carrier of meaning; contrast meets WCAG AA.
28
+ - Every form field has a label, an error state, and a described validation rule.
29
+ - Loading, empty, error and permission-denied states exist for every view that can reach them.
30
+
31
+ ## Multi-tenancy and authorisation
32
+
33
+ - Every query that reads tenant data is scoped by tenant, and there is a test that a second
34
+ tenant cannot read the first's.
35
+ - Authorisation is checked on the server for every mutation, not only hidden in the interface.
36
+
37
+ ## Performance
38
+
39
+ - No query inside a loop over user-controlled length; no unpaginated list endpoint.
40
+ - A new index accompanies a new filter or sort on a table expected to grow.
@@ -0,0 +1,267 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/mdferdousalam/agentic-sdlc/schema/finding.schema.json",
4
+ "title": "agentic-sdlc finding",
5
+ "description": "One finding, from any agent or any deterministic tool, in the shape every stage can compare. A finding is a claim about the code; this schema is what makes the claim checkable by something other than the agent that made it. Valid JSON is not proof of correct reasoning \u2014 the gate still independently checks the evidence.",
6
+ "type": "object",
7
+ "required": [
8
+ "id",
9
+ "category",
10
+ "ruleId",
11
+ "summary",
12
+ "evidence",
13
+ "classification",
14
+ "outcome",
15
+ "provenance"
16
+ ],
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "$schema": {
20
+ "type": "string"
21
+ },
22
+ "id": {
23
+ "type": "string",
24
+ "pattern": "^F-[0-9a-f]{8}$",
25
+ "description": "Stable identity for this finding, assigned by `sdlc finding write`. Referenced by the commit that closes it."
26
+ },
27
+ "category": {
28
+ "type": "string",
29
+ "pattern": "^([A-U]\\.(?:[1-9][0-9]{0,2})|X(?:[1-9]|1[0-2]))$",
30
+ "description": "Taxonomy address. A letter domain plus a check number (`D.31` = Security / injection), or a cross-cutting domain (`X7` = agent economics). Domains are listed in docs/control-spec.md."
31
+ },
32
+ "ruleId": {
33
+ "type": "string",
34
+ "pattern": "^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$",
35
+ "description": "The rule in docs/control-spec.md this finding was raised under, e.g. SEC-INJECTION-SQL. Stable across versions; a renamed rule is a new rule.",
36
+ "examples": [
37
+ "SEC-INJECTION-SQL",
38
+ "TEST-SUITE-WEAKENED",
39
+ "ARCH-LAYER-DIRECTION"
40
+ ]
41
+ },
42
+ "component": {
43
+ "type": "string",
44
+ "description": "The module, package or service the finding belongs to. Free text, but consistent within a repository."
45
+ },
46
+ "summary": {
47
+ "type": "string",
48
+ "minLength": 8,
49
+ "maxLength": 200,
50
+ "description": "One sentence stating the defect. Not the fix, not the consequence \u2014 the defect."
51
+ },
52
+ "evidence": {
53
+ "type": "object",
54
+ "description": "What makes this a finding rather than an opinion. A finding with no evidence is itself a finding against the agent that raised it.",
55
+ "required": [
56
+ "file"
57
+ ],
58
+ "additionalProperties": false,
59
+ "properties": {
60
+ "file": {
61
+ "type": "string",
62
+ "description": "Repository-relative path."
63
+ },
64
+ "line": {
65
+ "type": [
66
+ "integer",
67
+ "null"
68
+ ],
69
+ "minimum": 1,
70
+ "description": "1-indexed line the finding anchors to."
71
+ },
72
+ "endLine": {
73
+ "type": [
74
+ "integer",
75
+ "null"
76
+ ],
77
+ "minimum": 1
78
+ },
79
+ "code": {
80
+ "type": [
81
+ "string",
82
+ "null"
83
+ ],
84
+ "description": "The relevant lines, quoted \u2014 not paraphrased."
85
+ },
86
+ "toolOutput": {
87
+ "type": [
88
+ "string",
89
+ "null"
90
+ ],
91
+ "description": "The deterministic output that supports the claim: compiler diagnostic, analyser line, failing assertion, scanner hit. Null for an llm-detected finding, which is why such findings carry lower confidence by default."
92
+ },
93
+ "repro": {
94
+ "type": [
95
+ "string",
96
+ "null"
97
+ ],
98
+ "description": "The smallest sequence that reproduces it, as commands. The brief's rule: a finding you cannot reproduce may simply be wrong."
99
+ }
100
+ }
101
+ },
102
+ "classification": {
103
+ "type": "object",
104
+ "description": "Severity and confidence are deliberately separate axes. A low-confidence fix for a critical vulnerability is not safe merely because the agent believes it solved the problem.",
105
+ "required": [
106
+ "severity",
107
+ "confidence"
108
+ ],
109
+ "additionalProperties": false,
110
+ "properties": {
111
+ "severity": {
112
+ "enum": [
113
+ "critical",
114
+ "high",
115
+ "medium",
116
+ "low",
117
+ "advisory"
118
+ ],
119
+ "description": "How bad it is if real. critical: auth bypass, data corruption, exploitable injection. high: memory-safety, race, broken authorization, destructive migration. medium: performance regression, missing edge case, incorrect retry. low: formatting, lint, safe mechanical refactor. advisory: a trade-off or a disputed judgement \u2014 report, never force."
120
+ },
121
+ "confidence": {
122
+ "enum": [
123
+ "high",
124
+ "medium",
125
+ "low"
126
+ ],
127
+ "description": "How sure we are it is real. high: a deterministic tool said so, or there is a reproduction. medium: strong reading of the code, no execution. low: pattern match or suspicion. Never raise confidence to justify an automatic repair."
128
+ },
129
+ "exploitability": {
130
+ "enum": [
131
+ "remote",
132
+ "local",
133
+ "authenticated",
134
+ "theoretical",
135
+ "not-applicable"
136
+ ],
137
+ "description": "Security findings only. Describe reachability; never write an exploit."
138
+ },
139
+ "impact": {
140
+ "type": [
141
+ "string",
142
+ "null"
143
+ ],
144
+ "description": "What goes wrong for a user or an operator if this is not fixed."
145
+ }
146
+ }
147
+ },
148
+ "rootCause": {
149
+ "type": [
150
+ "string",
151
+ "null"
152
+ ],
153
+ "description": "Why the problem exists, not the visible symptom. A finding with only a symptom tends to produce a symptom-only fix, which is the failure X4 exists to prevent."
154
+ },
155
+ "proposedRepair": {
156
+ "type": [
157
+ "object",
158
+ "null"
159
+ ],
160
+ "additionalProperties": false,
161
+ "properties": {
162
+ "change": {
163
+ "type": "string",
164
+ "description": "The minimal change. Not a refactor of the surrounding module."
165
+ },
166
+ "expectedBehaviour": {
167
+ "type": "string",
168
+ "description": "What is true after the change that is not true now."
169
+ },
170
+ "sideEffects": {
171
+ "type": [
172
+ "string",
173
+ "null"
174
+ ],
175
+ "description": "What else this touches, including anything downstream."
176
+ },
177
+ "autofixEligible": {
178
+ "type": "boolean",
179
+ "description": "Whether the repair policy in docs/control-spec.md permits an agent to make this change unattended. Derived from severity and confidence together; never from severity alone."
180
+ }
181
+ }
182
+ },
183
+ "verificationPlan": {
184
+ "type": [
185
+ "string",
186
+ "null"
187
+ ],
188
+ "description": "The specific test, static check, benchmark or experiment that would establish the repair worked. Written before the repair, so the repair cannot choose its own easy standard."
189
+ },
190
+ "outcome": {
191
+ "enum": [
192
+ "open",
193
+ "fixed",
194
+ "refused",
195
+ "deferred",
196
+ "unexecuted",
197
+ "escalated"
198
+ ],
199
+ "description": "open: raised, not yet addressed. fixed: behaviour changed and a test proves it. refused: the finding is wrong, with the evidence. deferred: real, out of scope, filed where it will be seen. unexecuted: the fix could not be verified \u2014 not closed. escalated: awaiting a human decision. These extend the remediator's existing four; the five evidence words (passed/failed/skipped/refused/unexecuted) describe a criterion, not a finding."
200
+ },
201
+ "closedBy": {
202
+ "type": [
203
+ "string",
204
+ "null"
205
+ ],
206
+ "description": "The commit that closed this finding. One finding per commit, so this is a single sha."
207
+ },
208
+ "closedByActor": {
209
+ "type": [
210
+ "string",
211
+ "null"
212
+ ],
213
+ "description": "Who closed it. A finding could previously be closed by any actor with no record of which \u2014 a remediator closing a reviewer's finding looked identical to the reviewer closing their own."
214
+ },
215
+ "reopened": {
216
+ "type": "integer",
217
+ "minimum": 0,
218
+ "description": "How many times this finding was closed and then detected again. A non-zero value is the honest signal that a fix did not hold; the first version of the re-raise logic wrote the finding straight back as `fixed` and it vanished from the gate's open list."
219
+ },
220
+ "provenance": {
221
+ "type": "object",
222
+ "description": "Who claimed this, with what, and against what state. Without it a finding cannot be reproduced or disputed.",
223
+ "required": [
224
+ "agent",
225
+ "at",
226
+ "commit"
227
+ ],
228
+ "additionalProperties": false,
229
+ "properties": {
230
+ "agent": {
231
+ "type": "string",
232
+ "description": "The agent or tool that raised it, e.g. sdlc-security-reviewer, gitleaks."
233
+ },
234
+ "model": {
235
+ "type": [
236
+ "string",
237
+ "null"
238
+ ],
239
+ "description": "The model behind an llm-detected finding, where the host exposes it."
240
+ },
241
+ "detection": {
242
+ "enum": [
243
+ "deterministic",
244
+ "test",
245
+ "runtime",
246
+ "llm"
247
+ ],
248
+ "description": "How it was found. The brief's rule 2: prefer a tool to an opinion, and record which this was so a reader can weigh it."
249
+ },
250
+ "toolVersion": {
251
+ "type": [
252
+ "string",
253
+ "null"
254
+ ]
255
+ },
256
+ "at": {
257
+ "type": "string",
258
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
259
+ },
260
+ "commit": {
261
+ "type": "string",
262
+ "description": "The commit the finding was raised against. A later commit does not void a finding the way it voids a receipt, but it does mean the line numbers may have moved."
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }