bmad-plus 0.14.0 → 0.16.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 (60) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +34 -15
  3. package/SECURITY.md +71 -0
  4. package/THIRD-PARTY-LICENSES.md +349 -0
  5. package/osint-agent-package/README.md +1 -1
  6. package/package.json +9 -3
  7. package/readme-international/README.de.md +14 -8
  8. package/readme-international/README.es.md +15 -9
  9. package/readme-international/README.fr.md +14 -8
  10. package/src/bmad-plus/agents/agent-architect-dev/SKILL.md +11 -13
  11. package/src/bmad-plus/agents/agent-orchestrator/SKILL.md +147 -8
  12. package/src/bmad-plus/agents/agent-quality/SKILL.md +41 -11
  13. package/src/bmad-plus/data/role-triggers.yaml +19 -0
  14. package/src/bmad-plus/module-help.csv +1 -0
  15. package/src/bmad-plus/module.yaml +1 -0
  16. package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/create-story.md +3 -1
  17. package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story-checklist.md +2 -0
  18. package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story.md +5 -1
  19. package/src/bmad-plus/packs/pack-memory/README.md +29 -4
  20. package/src/bmad-plus/packs/pack-memory/memory-orchestrator.md +21 -1
  21. package/src/bmad-plus/packs/pack-memory/shared/karpathy-guardrails.md +3 -3
  22. package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +27 -3
  23. package/src/bmad-plus/packs/pack-memory/zecher-agent.md +18 -2
  24. package/src/bmad-plus/skills/bmad-plus-autopilot/SKILL.md +47 -10
  25. package/src/bmad-plus/skills/bmad-plus-parallel/SKILL.md +17 -3
  26. package/src/bmad-plus/skills/bmad-plus-sync/SKILL.md +76 -67
  27. package/src/bmad-plus/skills/bmad-plus-uat/SKILL.md +144 -0
  28. package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-results.schema.json +60 -0
  29. package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-spec.schema.json +121 -0
  30. package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-triage.schema.json +60 -0
  31. package/src/bmad-plus/skills/bmad-plus-uat/template/page.html +552 -0
  32. package/src/bmad-plus/skills/bmad-plus-uat/template/strings.json +362 -0
  33. package/tools/build/check-install-contract.js +202 -4
  34. package/tools/build/generate.js +16 -0
  35. package/tools/build/generated-adapters/.codex/AGENTS.md +1 -1
  36. package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +1 -1
  37. package/tools/build/generated-adapters/.opencode/AGENTS.md +1 -1
  38. package/tools/build/generated-adapters/AGENTS.md +1 -1
  39. package/tools/build/generated-adapters/CLAUDE.md +1 -1
  40. package/tools/build/generated-adapters/CONVENTIONS.md +1 -1
  41. package/tools/build/generated-adapters/GEMINI.md +1 -1
  42. package/tools/cli/bmad-plus-cli.js +15 -12
  43. package/tools/cli/commands/doctor.js +1 -0
  44. package/tools/cli/commands/install.js +21 -2
  45. package/tools/cli/commands/memory-journal-cmd.js +119 -19
  46. package/tools/cli/commands/nexus.js +111 -0
  47. package/tools/cli/commands/uat.js +389 -0
  48. package/tools/cli/lib/README-memory-journal.md +19 -8
  49. package/tools/cli/lib/installation-health.js +6 -0
  50. package/tools/cli/lib/memory-journal.js +0 -0
  51. package/tools/cli/lib/memory-outcomes.js +293 -0
  52. package/tools/cli/lib/memory-store.js +139 -0
  53. package/tools/cli/lib/nexus-process.js +377 -0
  54. package/tools/cli/lib/nexus.js +1532 -0
  55. package/tools/cli/lib/pack-copy.js +39 -11
  56. package/tools/cli/lib/packs.js +17 -3
  57. package/tools/cli/lib/uat.js +869 -0
  58. package/tools/maintain/upstream-candidate.js +456 -0
  59. package/tools/release/publication-content.js +3 -1
  60. package/tools/release/supply-chain.js +282 -0
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: bmad-plus-uat
3
+ description: Turn a delivery into a human acceptance recipe (recette) — a self-contained page a non-technical tester plays step by step, whose ticks become a JSON run the agent reads, triages and gates on. Use when a version goes to a test environment, when someone asks "what should I check", or when a run's results appear.
4
+ ---
5
+
6
+ # Human acceptance recipe (recette)
7
+
8
+ ## Overview
9
+
10
+ Automated tests prove that the pieces behave. A recipe proves that **a person saw the chain
11
+ work on screen**: writer → reader → screen → gesture. This skill turns a delivery into a
12
+ protocol anyone can run, and turns the tester's ticks into evidence the agent reads without
13
+ an intermediary.
14
+
15
+ Three gestures: **write the spec**, **build and deliver the page**, **read the run and triage it**.
16
+ Everything else is the `bmad-plus uat` command (alias `bmad-plus recette`), which is deterministic
17
+ and identical for every host and model.
18
+
19
+ ```
20
+ delivery ─► spec JSON ─► build page ─► deploy to test env ─► a person plays it ─► run JSON
21
+ ▲ │
22
+ └─── fix, or amended spec ◄─── triage: product / recipe / data / undecided ◄────────┘
23
+ ```
24
+
25
+ ## When to activate
26
+
27
+ - A version is ready for DEMO / PREPROD, before production — **always**.
28
+ - A visible feature was implemented and someone must confirm it on screen.
29
+ - Someone asks for "the recette", "the UAT", "what should I check".
30
+ - A results file appears, or the user says "read the run".
31
+
32
+ Read `recette.mode` from `_bmad/config.yaml`: `advisory` (default — build and offer the page,
33
+ never block), `gate` (the delivery waits for a passing gate), `off` (no recipe; say so in the
34
+ delivery report). A delivery with no human-observable change states that fact rather than
35
+ skipping in silence.
36
+
37
+ ## 1. Write the spec — `_bmad-output/uat/specs/<product>-<version>.json`
38
+
39
+ Schema: `bmad-plus/uat-spec/2` (`ref/uat-spec.schema.json`). Sources: the story's acceptance
40
+ criteria, the changelog, and **the screen itself** — read the component, do not recall it.
41
+
42
+ 1. **A real sequence.** Steps follow one human pass: preparation → nominal case → control →
43
+ gesture → end. Numbered because it is an order, not decoration.
44
+ 2. **Where / Do / Expect** for every step. One click per `do` line. **One verifiable fact per
45
+ expectation** — two facts are two lines, because the tester may see one and not the other.
46
+ 3. **On-screen labels word for word**, inside `<span class="ecran">…</span>`, copied from the
47
+ code. `uat lint --src <dir>` fails on a label that exists in no source file; run it before
48
+ anyone opens the page.
49
+ 4. **Name the witness and prove its state.** Every `witnesses[]` entry carries the read-only
50
+ query that establishes it. A recipe placed on a witness that is not in the assumed state is
51
+ unplayable, and the measurement must be re-run before publishing, not remembered.
52
+ 5. **A positive control per changed behaviour**: the case that must stay as it was.
53
+ 6. **`writes: true` on every step that persists something**, with `verify` — the read-only check
54
+ (query, endpoint, command) you will run afterwards. When the step *attempts* something the
55
+ product must refuse, keep `writes: true` and use `warning` to say what happens if the refusal
56
+ does not come, and that the tester should stop and answer *not seen*.
57
+ 7. **Numbers in `intro`**: what the measurement showed before the delivery, production included.
58
+ "0" is a number and gets said.
59
+ 8. Never an expectation no writer produces: if the data does not exist, the expectation is false
60
+ before the tester starts. Never an expectation that quotes the defect it replaces — write what
61
+ the screen shows now.
62
+ 9. `closing.text`: what did not change, what still waits for a decision, the gesture you left out.
63
+ 10. Keep a page under the configured budget (15 steps / 30 minutes by default). Beyond it, split
64
+ into ordered pages and declare the order with `after` — a step meant "for later" inside
65
+ another page gets played at once.
66
+
67
+ ## 2. Build and deliver
68
+
69
+ ```bash
70
+ bmad-plus uat lint <id> --src src # labels, markup, budget, witnesses
71
+ bmad-plus uat build <id> # → _bmad-output/uat/pages/uat-<id>.html
72
+ ```
73
+
74
+ The page is self-contained and carries the spec's SHA-256, so a run always says which revision
75
+ it answered. It opens in the recipe's language, otherwise the project's `communication_language`,
76
+ otherwise English, and the tester can switch to any of the installed languages on the page itself.
77
+
78
+ Deliver in the way the host allows, and say so plainly:
79
+
80
+ | Host | Delivery | Where the answers go |
81
+ |---|---|---|
82
+ | Claude Code / claude.ai | publish the page as an artifact with `capabilities: {db: {}, downloads: true}` | saved on every tick in the artifact database; read it with `ArtifactData list` on collection `recettes`, then `bmad-plus uat import` so the evidence lands in the repository |
83
+ | Any host, tester on this machine | `bmad-plus uat serve <id>` (loopback only) | written straight into `_bmad-output/uat/results/<id>/` at every tick |
84
+ | Any host, tester elsewhere | send `pages/uat-<id>.html` | the tester saves or copies the JSON; `bmad-plus uat import <id> --input <file>` |
85
+
86
+ Then tell the tester four things: the link or file, how long it takes, **which steps write for
87
+ real**, and the play order when several recipes share an environment (`bmad-plus uat order`).
88
+
89
+ ## 3. Read, triage, gate
90
+
91
+ ```bash
92
+ bmad-plus uat read <id> # every failure with its text and the tester's note
93
+ bmad-plus uat gate <id> [--emit-check] # 0 pass · 1 fail · 2 awaiting · 3 stale
94
+ ```
95
+
96
+ Classify **every** failed or blocked expectation in `_bmad-output/uat/triage/<id>.json` before
97
+ anything becomes a fix. A "not seen" is not automatically a bug — on the eight runs that shaped
98
+ this skill, eleven of seventeen were defects of the recipe itself.
99
+
100
+ | Class | Sign | What follows |
101
+ |---|---|---|
102
+ | `product` | the screen differs from what the code was meant to render | fix task on the story, and a replay step in the next version's recipe |
103
+ | `recipe` | the screen shows the intended result, the expectation described it wrongly | amend the spec, rebuild (new fingerprint), replay the affected steps, and say no product change was needed |
104
+ | `data` | the witness is no longer in the assumed state | re-run the witness query, reset or rename it, replay |
105
+ | `undecided` | no note, or not attributable | ask the tester what they saw — never guess. The gate stays red |
106
+
107
+ **A tick on a writing step is not a write.** Run each `verify` read-only and record the result in
108
+ `writeChecks`. This is not ceremony: a step ticked nine times out of nine once turned out to have
109
+ written nothing, and three correct steps were nearly rewritten on that false premise.
110
+
111
+ Then write the verdict where the project records deliveries — changelog or delivery report —
112
+ with the figures, the tester's name, and what stays open. The evidence is labelled
113
+ **human-observed**: the gate establishes that the run is complete, current and triaged, never
114
+ that the tester looked at the right place.
115
+
116
+ ## Gating a delivery with Nexus
117
+
118
+ ```bash
119
+ bmad-plus uat gate <id> --emit-check # writes checks/gate-<id>.cjs, self-contained
120
+ ```
121
+
122
+ Create a task whose scope is the results and triage folders, whose resources include the spec and
123
+ that verifier, and whose check runs it. `start` it with a host backend for the tester, record
124
+ `blocked` while the person plays, then `completed`, then `verify` and `accept`. A failing gate
125
+ keeps acceptance out of reach; the fix task carries the run and the triage entry as resources.
126
+
127
+ ## What this skill does not do
128
+
129
+ - It does not replace automated tests or adversarial review. It is the human proof no test gives.
130
+ - It does not invent expectations: what the spec announces comes from the code and the
131
+ measurement, never from the plan alone.
132
+ - It does not play the recipe. An agent that "plays" it in a headless browser has written a test,
133
+ not a recipe.
134
+
135
+ ## Pitfalls already paid for
136
+
137
+ - A witness chosen without checking its state ("4 reds" were 2).
138
+ - A label with accents in the spec when the screen has none — the tester searches for the exact word.
139
+ - "the tiles" when two components render different tiles: name the card that carries the fact **and**
140
+ the neighbouring card that looks like it.
141
+ - "go back to the folder" without saying how (browser back ≠ another tab plus refresh).
142
+ - One step reading two screens: totals were hunted on a page that only shows subtotals. One step, one screen.
143
+ - Two recipes on one environment destroying each other's witnesses through indirect writes — a save
144
+ that triggers a recomputation. Declare witnesses, run `uat order`, and re-measure after each pass.
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "bmad-plus/uat-results/2",
4
+ "title": "Human acceptance recipe — one run",
5
+ "description": "What the page writes: one document per run, never modified afterwards. A second pass is a second document. States use the evidence vocabulary of the framework: passed, failed, blocked (unavailable to the tester), skipped (optional step), null (unanswered).",
6
+ "type": "object",
7
+ "required": ["schema", "specId", "runId", "tester", "startedAt", "steps", "summary"],
8
+ "properties": {
9
+ "schema": { "const": "bmad-plus/uat-results/2" },
10
+ "specId": { "type": "string" },
11
+ "specSha256": {
12
+ "type": "string",
13
+ "pattern": "^[0-9a-f]{64}$",
14
+ "description": "Fingerprint of the spec the page was built from. Says WHICH revision the tester answered: if the spec was amended since, the run is stale and the affected steps are replayed."
15
+ },
16
+ "runId": { "type": "string", "pattern": "^[0-9a-z][0-9a-z-]{0,63}$", "description": "<YYYYMMDD>-<tester>-<4 chars>." },
17
+ "tester": { "type": "string" },
18
+ "observedVersion": { "type": "string", "description": "Version the tester actually saw on screen." },
19
+ "startedAt": { "type": "string", "format": "date-time" },
20
+ "updatedAt": { "type": "string", "format": "date-time" },
21
+ "finishedAt": { "type": ["string", "null"], "format": "date-time" },
22
+ "overallNote": { "type": "string" },
23
+ "summary": {
24
+ "type": "object",
25
+ "required": ["passed", "failed", "blocked", "skipped", "unanswered"],
26
+ "properties": {
27
+ "passed": { "type": "integer" },
28
+ "failed": { "type": "integer" },
29
+ "blocked": { "type": "integer" },
30
+ "skipped": { "type": "integer" },
31
+ "unanswered": { "type": "integer" }
32
+ }
33
+ },
34
+ "steps": {
35
+ "type": "object",
36
+ "description": "Key = step id from the spec.",
37
+ "additionalProperties": {
38
+ "type": "object",
39
+ "required": ["expect"],
40
+ "properties": {
41
+ "title": { "type": "string" },
42
+ "state": { "enum": ["passed", "failed", "blocked", "skipped", null] },
43
+ "note": { "type": "string", "description": "Free remark for the whole step." },
44
+ "expect": {
45
+ "type": "object",
46
+ "description": "Key = expectation letter.",
47
+ "additionalProperties": {
48
+ "type": "object",
49
+ "properties": {
50
+ "text": { "type": "string", "description": "Snapshot of the expectation as the tester read it." },
51
+ "state": { "enum": ["passed", "failed", "blocked", "skipped", null] },
52
+ "note": { "type": "string", "description": "What the tester saw instead, word for word — the most useful material there is." }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "bmad-plus/uat-spec/2",
4
+ "title": "Human acceptance recipe (recette) — specification",
5
+ "description": "What an agent writes to describe a human acceptance run step by step. `bmad-plus uat build` turns it into a self-contained HTML page. Validation is performed by tools/cli/lib/uat.js; this file documents the contract.",
6
+ "type": "object",
7
+ "required": ["schema", "id", "product", "versions", "title", "environment", "steps"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": { "type": "string" },
11
+ "schema": { "const": "bmad-plus/uat-spec/2" },
12
+ "id": {
13
+ "type": "string",
14
+ "pattern": "^[a-z0-9][a-z0-9.-]{2,80}$",
15
+ "description": "Stable identifier, lowercase: <product>-<versions>. Used as file name and storage key."
16
+ },
17
+ "product": { "type": "string", "minLength": 1 },
18
+ "versions": { "type": "array", "minItems": 1, "items": { "type": "string" } },
19
+ "date": { "type": "string", "description": "ISO date the recipe was written." },
20
+ "language": { "enum": ["en", "fr"], "description": "Page strings. Defaults to English." },
21
+ "title": { "type": "string", "minLength": 1, "description": "What this delivery changes, in one sentence." },
22
+ "subtitle": { "type": "string" },
23
+ "environment": {
24
+ "type": "object",
25
+ "required": ["name"],
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "name": { "type": "string", "description": "DEMO, STAGING, PREPROD…" },
29
+ "url": { "type": "string", "format": "uri" }
30
+ }
31
+ },
32
+ "estimate": { "type": "string", "description": "e.g. \"25 min\". Over the configured budget, lint asks for a split." },
33
+ "intro": { "type": "array", "items": { "type": "string" }, "description": "Allowlisted inline markup: what the measurement showed, with its numbers." },
34
+ "warnings": { "type": "array", "items": { "type": "string" }, "description": "Shown in orange: real writes, play order, prerequisites." },
35
+ "notes": { "type": "array", "items": { "type": "string" } },
36
+ "witnesses": {
37
+ "type": "array",
38
+ "description": "Named test records. `proof` is the read-only query that establishes the state; `reads`/`writes` list the steps. Two recipes sharing a witness get an order.",
39
+ "items": {
40
+ "type": "object",
41
+ "required": ["id", "proof"],
42
+ "additionalProperties": false,
43
+ "properties": {
44
+ "id": { "type": "string" },
45
+ "proof": { "type": "string", "minLength": 1 },
46
+ "reads": { "type": "array", "items": { "type": "string" } },
47
+ "writes": { "type": "array", "items": { "type": "string" } }
48
+ }
49
+ }
50
+ },
51
+ "after": { "type": "array", "items": { "type": "string" }, "description": "Recipe ids that must be played before this one." },
52
+ "steps": {
53
+ "type": "array",
54
+ "minItems": 1,
55
+ "items": {
56
+ "type": "object",
57
+ "required": ["id", "title", "where", "do", "expect"],
58
+ "additionalProperties": false,
59
+ "properties": {
60
+ "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,60}$" },
61
+ "title": { "type": "string", "minLength": 1 },
62
+ "duration": { "type": "string" },
63
+ "writes": { "type": "boolean", "description": "True when the step persists something. Requires `verify`." },
64
+ "warning": { "type": "string", "description": "Replaces the default orange sentence; use it when the product must REFUSE the attempted action." },
65
+ "optional": { "type": "boolean", "description": "The tester may skip it; a skipped expectation never blocks the gate." },
66
+ "stories": {
67
+ "type": "array",
68
+ "description": "Traceability to the delivery's acceptance criteria.",
69
+ "items": {
70
+ "type": "object",
71
+ "additionalProperties": false,
72
+ "properties": {
73
+ "ref": { "type": "string" },
74
+ "criteria": { "type": "array", "items": { "type": "string" } }
75
+ }
76
+ }
77
+ },
78
+ "verify": {
79
+ "type": "object",
80
+ "required": ["kind", "text"],
81
+ "additionalProperties": false,
82
+ "description": "The read-only confirmation run AFTER the tester: a tick on a writing step is not a write.",
83
+ "properties": {
84
+ "kind": { "enum": ["sql", "http", "command", "manual"] },
85
+ "text": { "type": "string", "minLength": 1 }
86
+ }
87
+ },
88
+ "where": { "type": "array", "minItems": 1, "items": { "type": "string" } },
89
+ "do": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "One click per line." },
90
+ "expect": {
91
+ "type": "array",
92
+ "minItems": 1,
93
+ "items": {
94
+ "type": "object",
95
+ "required": ["id", "text"],
96
+ "additionalProperties": false,
97
+ "properties": {
98
+ "id": { "type": "string", "pattern": "^[a-z]$" },
99
+ "text": {
100
+ "type": "string",
101
+ "minLength": 1,
102
+ "description": "ONE verifiable observation, on-screen labels quoted word for word inside <span class=\"ecran\">…</span>. Lint refuses a label that exists in no source file."
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "closing": {
111
+ "type": "object",
112
+ "additionalProperties": false,
113
+ "properties": { "text": { "type": "array", "items": { "type": "string" } } }
114
+ },
115
+ "authorNotes": {
116
+ "type": "array",
117
+ "items": { "type": "string" },
118
+ "description": "The author's doubts (unverified witness, label to confirm). Ignored by the page, read by the reviewer."
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "bmad-plus/uat-triage/1",
4
+ "title": "Human acceptance recipe — triage of one or more runs",
5
+ "description": "Written by the agent after reading a run. Every failed or blocked expectation is classified and decided before it becomes a fix, and every passed writing step gets its read-only confirmation. The gate reads this file; an unclassified failure keeps it red.",
6
+ "type": "object",
7
+ "required": ["schema", "specId", "runs"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schema": { "const": "bmad-plus/uat-triage/1" },
11
+ "specId": { "type": "string" },
12
+ "runs": {
13
+ "type": "array",
14
+ "items": {
15
+ "type": "object",
16
+ "required": ["runId"],
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "runId": { "type": "string" },
20
+ "specSha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
21
+ "failures": {
22
+ "type": "array",
23
+ "items": {
24
+ "type": "object",
25
+ "required": ["step", "expect", "class", "decision"],
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "step": { "type": "string" },
29
+ "expect": { "type": "string", "pattern": "^[a-z]$" },
30
+ "class": {
31
+ "enum": ["product", "recipe", "data", "undecided"],
32
+ "description": "product: the screen differs from what the code was meant to render. recipe: the screen is right, the expectation described it wrongly. data: the witness is no longer in the assumed state. undecided: no note — ask the tester, never guess (keeps the gate red)."
33
+ },
34
+ "evidence": { "type": "string", "description": "What establishes the class: code path, query result, screenshot reference." },
35
+ "decision": { "enum": ["fix", "amend-spec", "remeasure", "accept-risk", "ask-tester"] },
36
+ "decidedBy": { "type": "string", "description": "Required for accept-risk: who took the risk." },
37
+ "fixRef": { "type": "string", "description": "Story, task or commit that carries the fix." },
38
+ "replayIn": { "type": "string", "description": "Recipe id where this step is played again." }
39
+ }
40
+ }
41
+ },
42
+ "writeChecks": {
43
+ "type": "array",
44
+ "description": "One entry per step with writes: true that the tester passed. A tick is an observation; this is the proof.",
45
+ "items": {
46
+ "type": "object",
47
+ "required": ["step", "verified"],
48
+ "additionalProperties": false,
49
+ "properties": {
50
+ "step": { "type": "string" },
51
+ "verified": { "type": "boolean" },
52
+ "evidence": { "type": "string", "description": "Read-only result: row timestamp, event, response." }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }