@anselmdk/feature-spec-md 0.5.0 → 0.6.1

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 (76) hide show
  1. package/README.md +59 -78
  2. package/SPEC_FORMAT.md +38 -78
  3. package/dist/cli.js +194 -86
  4. package/dist/cli.js.map +1 -1
  5. package/dist/featureSpecs.d.ts +1 -1
  6. package/dist/featureSpecs.d.ts.map +1 -1
  7. package/dist/featureSpecs.js +57 -10
  8. package/dist/featureSpecs.js.map +1 -1
  9. package/dist/githubActionDiffReport.d.ts +61 -0
  10. package/dist/githubActionDiffReport.d.ts.map +1 -1
  11. package/dist/githubActionDiffReport.js +410 -120
  12. package/dist/githubActionDiffReport.js.map +1 -1
  13. package/dist/githubActionReport.d.ts.map +1 -1
  14. package/dist/githubActionReport.js +27 -22
  15. package/dist/githubActionReport.js.map +1 -1
  16. package/dist/index.d.ts +8 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +4 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/mockReports.d.ts +36 -0
  21. package/dist/mockReports.d.ts.map +1 -0
  22. package/dist/mockReports.js +280 -0
  23. package/dist/mockReports.js.map +1 -0
  24. package/dist/mocks/current/app/supportDesk.d.ts +12 -0
  25. package/dist/mocks/current/app/supportDesk.d.ts.map +1 -0
  26. package/dist/mocks/current/app/supportDesk.js +19 -0
  27. package/dist/mocks/current/app/supportDesk.js.map +1 -0
  28. package/dist/mocks/current/tests/supportDesk.spec.d.ts +3 -0
  29. package/dist/mocks/current/tests/supportDesk.spec.d.ts.map +1 -0
  30. package/dist/mocks/current/tests/supportDesk.spec.js +15 -0
  31. package/dist/mocks/current/tests/supportDesk.spec.js.map +1 -0
  32. package/dist/mocks/previous/app/supportDesk.d.ts +10 -0
  33. package/dist/mocks/previous/app/supportDesk.d.ts.map +1 -0
  34. package/dist/mocks/previous/app/supportDesk.js +9 -0
  35. package/dist/mocks/previous/app/supportDesk.js.map +1 -0
  36. package/dist/mocks/previous/tests/supportDesk.spec.d.ts +3 -0
  37. package/dist/mocks/previous/tests/supportDesk.spec.d.ts.map +1 -0
  38. package/dist/mocks/previous/tests/supportDesk.spec.js +15 -0
  39. package/dist/mocks/previous/tests/supportDesk.spec.js.map +1 -0
  40. package/dist/reportArtifacts.d.ts +7 -0
  41. package/dist/reportArtifacts.d.ts.map +1 -0
  42. package/dist/reportArtifacts.js +26 -0
  43. package/dist/reportArtifacts.js.map +1 -0
  44. package/dist/reportHtml.d.ts +9 -0
  45. package/dist/reportHtml.d.ts.map +1 -0
  46. package/dist/reportHtml.js +36 -0
  47. package/dist/reportHtml.js.map +1 -0
  48. package/dist/reportMetadata.d.ts +9 -0
  49. package/dist/reportMetadata.d.ts.map +1 -0
  50. package/dist/reportMetadata.js +28 -0
  51. package/dist/reportMetadata.js.map +1 -0
  52. package/dist/screenshots.d.ts +3 -1
  53. package/dist/screenshots.d.ts.map +1 -1
  54. package/dist/screenshots.js +23 -0
  55. package/dist/screenshots.js.map +1 -1
  56. package/dist/types.d.ts +11 -1
  57. package/dist/types.d.ts.map +1 -1
  58. package/docs/evidence-policy.md +63 -0
  59. package/docs/report-development.md +102 -0
  60. package/docs/spec-driven-flow.md +67 -8
  61. package/package.json +3 -1
  62. package/src/mocks/current/app/supportDesk.ts +27 -0
  63. package/src/mocks/current/screenshots/SUPPORT-INBOX-S001-line-27-current.svg +10 -0
  64. package/src/mocks/current/screenshots/SUPPORT-REPLY-S001-line-27-current.svg +10 -0
  65. package/src/mocks/current/screenshots/screenshots.json +18 -0
  66. package/src/mocks/current/specs/support-desk.model.md +29 -0
  67. package/src/mocks/current/specs/ticket-inbox.feature.md +27 -0
  68. package/src/mocks/current/specs/ticket-reply.feature.md +33 -0
  69. package/src/mocks/current/tests/supportDesk.spec.ts +17 -0
  70. package/src/mocks/previous/app/supportDesk.ts +17 -0
  71. package/src/mocks/previous/screenshots/SUPPORT-INBOX-S001-line-27-previous.svg +10 -0
  72. package/src/mocks/previous/screenshots/screenshots.json +11 -0
  73. package/src/mocks/previous/specs/support-desk.model.md +29 -0
  74. package/src/mocks/previous/specs/ticket-inbox.feature.md +26 -0
  75. package/src/mocks/previous/specs/ticket-reply.feature.md +26 -0
  76. package/src/mocks/previous/tests/supportDesk.spec.ts +17 -0
@@ -4,9 +4,9 @@
4
4
 
5
5
  ```txt
6
6
  AI drafts specs
7
- -> humans review intent
7
+ -> humans review intent and evidence policy
8
8
  -> AI writes tests from stable IDs
9
- -> tooling checks coverage
9
+ -> tooling checks coverage and declared evidence
10
10
  -> implementation follows failing tests
11
11
  -> reports show what is implemented
12
12
  ```
@@ -54,7 +54,9 @@ Useful instruction:
54
54
  ```txt
55
55
  Create feature-spec-md documents for this change. Keep the documents small.
56
56
  Use stable uppercase IDs. Put durable behavior in rules. Put testable examples
57
- in scenarios. Do not include test mappings inside the specs.
57
+ in scenarios. For each feature or scenario, declare whether the expected test
58
+ is unit, integration, playwright, manual, or skip. Require screenshots only for
59
+ UI flows where visual evidence should be part of the review.
58
60
  ```
59
61
 
60
62
  Run:
@@ -74,9 +76,34 @@ Check that:
74
76
  - model terms are clear enough for test authors
75
77
  - feature rules are durable product truths
76
78
  - scenarios are concrete enough to become executable tests
79
+ - each scenario has the right test policy
80
+ - screenshots are required only for UI/browser behavior where visual evidence is valuable
77
81
  - stack choices are specific enough to guide implementation
78
82
  - design direction covers the visible behavior users will judge
79
83
 
84
+ Example feature-level policy for UI behavior:
85
+
86
+ ```md
87
+ ---
88
+ id: ACCOUNT-ACCESS
89
+ title: Account access
90
+ test: playwright
91
+ screenshots: required
92
+ ---
93
+ ```
94
+
95
+ Example scenario-level override for unit-only behavior:
96
+
97
+ ```md
98
+ ### ACCOUNT-ACCESS-S002: Link expiry is calculated
99
+ Test: unit
100
+ Screenshots: skip
101
+
102
+ Given a sign-in link was created 31 minutes ago
103
+ When expiry is calculated
104
+ Then the link is expired
105
+ ```
106
+
80
107
  Then run:
81
108
 
82
109
  ```bash
@@ -87,14 +114,17 @@ This keeps the spec set valid while allowing missing tests.
87
114
 
88
115
  ## 3. Ask AI To Write Tests From The Specs
89
116
 
90
- Give the AI the relevant spec files and tell it to write executable tests that preserve spec IDs in the test source.
117
+ Give the AI the relevant spec files and tell it to write executable tests that preserve spec IDs in the test source and match the declared test policy.
91
118
 
92
119
  Useful instruction:
93
120
 
94
121
  ```txt
95
122
  Write tests from these feature-spec-md specs. Each scenario test must include
96
123
  the scenario ID in the test title. Add comments or annotations for covered
97
- rule IDs and model item IDs. Do not invent IDs that are not in the specs.
124
+ rule IDs and model item IDs. Use Playwright and the screenshot evidence helper
125
+ for scenarios declared as test: playwright with screenshots: required. Use unit
126
+ or integration tests for scenarios declared that way. Do not invent IDs that are
127
+ not in the specs.
98
128
  ```
99
129
 
100
130
  Example:
@@ -137,7 +167,7 @@ Run:
137
167
  npx feature-spec-md report --out test-results/feature-spec-report/index.html
138
168
  ```
139
169
 
140
- The report is useful as a PR artifact because it shows specs, coverage state, validation issues, and optional screenshot evidence.
170
+ The report is useful as a PR artifact because it shows specs, coverage state, validation issues, declared evidence policy, and optional screenshot evidence.
141
171
 
142
172
  If your tests produce screenshot manifests, include them:
143
173
 
@@ -147,6 +177,17 @@ npx feature-spec-md report \
147
177
  --out test-results/feature-spec-report/index.html
148
178
  ```
149
179
 
180
+ When missing declared screenshot evidence should block the build, enforce evidence policy:
181
+
182
+ ```bash
183
+ npx feature-spec-md report \
184
+ --screenshots "test-results/spec-report/screenshots-*.json" \
185
+ --enforce-evidence \
186
+ --out test-results/feature-spec-report/index.html
187
+ ```
188
+
189
+ The gate only fails for scenarios whose resolved screenshot policy is `required`.
190
+
150
191
  Screenshot manifest shape:
151
192
 
152
193
  ```json
@@ -162,14 +203,32 @@ Screenshot manifest shape:
162
203
  }
163
204
  ```
164
205
 
165
- ## 6. Keep The Loop Honest
206
+ ## 6. Publish The Report From CI
207
+
208
+ A typical CI sequence is:
209
+
210
+ ```bash
211
+ npm run build
212
+ npx feature-spec-md check --require-rule-coverage --require-model-coverage
213
+ npx feature-spec-md coverage --fail-on-missing
214
+ npm test
215
+ npx feature-spec-md report \
216
+ --screenshots "test-results/spec-report/screenshots-*.json" \
217
+ --enforce-evidence \
218
+ --out test-results/spec-report/index.html
219
+ npx feature-spec-md github-report --publish ftp --report-dir test-results/spec-report
220
+ ```
221
+
222
+ Use `--enforce-evidence` when the project wants missing required screenshots to fail the build. Leave it out when the report should show screenshot state without blocking.
223
+
224
+ ## 7. Keep The Loop Honest
166
225
 
167
226
  When behavior changes, update specs first, then regenerate or update tests from the changed specs.
168
227
 
169
228
  The expected loop is:
170
229
 
171
230
  ```txt
172
- spec change -> validation -> AI test update -> coverage -> implementation -> report
231
+ spec change -> validation -> AI test update -> coverage -> implementation -> evidence report
173
232
  ```
174
233
 
175
234
  That keeps the AI-generated work anchored to a small, reviewable contract instead of a loose conversation history.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anselmdk/feature-spec-md",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Markdown specs for AI-assisted, testable spec driven development across model, feature, stack, and design documents.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "files": [
28
28
  "dist",
29
+ "src/mocks",
29
30
  "README.md",
30
31
  "SPEC_FORMAT.md",
31
32
  "docs",
@@ -43,6 +44,7 @@
43
44
  "spec": "tsx src/cli.ts check",
44
45
  "spec:init": "tsx src/cli.ts init",
45
46
  "spec:report": "tsx src/cli.ts report",
47
+ "report:mock": "tsx src/mockReports.ts",
46
48
  "format": "prettier --write .",
47
49
  "check:example": "tsx src/cli.ts check --specs examples/**/*.feature.md --require-scenario-coverage=false",
48
50
  "report:example": "tsx src/cli.ts report --specs examples/**/*.feature.md --tests tests/**/*.test.ts --out test-results/feature-spec-report/index.html",
@@ -0,0 +1,27 @@
1
+ export type Ticket = {
2
+ id: string;
3
+ title: string;
4
+ status: "open" | "closed";
5
+ priority: "low" | "normal" | "high";
6
+ createdAt: string;
7
+ };
8
+
9
+ export function visibleTickets(tickets: Ticket[]) {
10
+ return tickets
11
+ .filter((ticket) => ticket.status === "open")
12
+ .sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt));
13
+ }
14
+
15
+ export function priorityBadge(ticket: Ticket) {
16
+ if (ticket.priority === "high") return "High priority";
17
+ if (ticket.priority === "low") return "Low priority";
18
+ return "Normal priority";
19
+ }
20
+
21
+ export function draftReply(existingDraft: string, nextText: string) {
22
+ return nextText.trim() ? nextText : existingDraft;
23
+ }
24
+
25
+ export function applySavedReply(template: string) {
26
+ return template.trim();
27
+ }
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540" role="img" aria-label="Inbox with priority badges">
2
+ <rect width="960" height="540" fill="#f6f8fa"/>
3
+ <rect x="72" y="64" width="816" height="412" rx="24" fill="white" stroke="#d0d7de"/>
4
+ <rect x="112" y="112" width="736" height="72" rx="14" fill="#ddf4ff" stroke="#54aeff"/>
5
+ <text x="144" y="158" font-family="system-ui, sans-serif" font-size="28" font-weight="700" fill="#1f2328">Inbox with priority badges</text>
6
+ <rect x="112" y="224" width="520" height="44" rx="10" fill="#f6f8fa"/>
7
+ <rect x="112" y="292" width="660" height="44" rx="10" fill="#f6f8fa"/>
8
+ <rect x="112" y="360" width="420" height="44" rx="10" fill="#f6f8fa"/>
9
+ <circle cx="812" cy="384" r="34" fill="#ddf4ff" stroke="#54aeff"/>
10
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540" role="img" aria-label="Reply composer with suggested answer">
2
+ <rect width="960" height="540" fill="#f6f8fa"/>
3
+ <rect x="72" y="64" width="816" height="412" rx="24" fill="white" stroke="#d0d7de"/>
4
+ <rect x="112" y="112" width="736" height="72" rx="14" fill="#ddf4ff" stroke="#54aeff"/>
5
+ <text x="144" y="158" font-family="system-ui, sans-serif" font-size="28" font-weight="700" fill="#1f2328">Reply composer with suggested answer</text>
6
+ <rect x="112" y="224" width="680" height="44" rx="10" fill="#f6f8fa"/>
7
+ <rect x="112" y="292" width="620" height="44" rx="10" fill="#f6f8fa"/>
8
+ <rect x="112" y="360" width="300" height="44" rx="10" fill="#ddf4ff" stroke="#54aeff"/>
9
+ <circle cx="812" cy="384" r="34" fill="#ddf4ff" stroke="#54aeff"/>
10
+ </svg>
@@ -0,0 +1,18 @@
1
+ {
2
+ "screenshots": [
3
+ {
4
+ "specPath": "src/mocks/current/specs/ticket-inbox.feature.md",
5
+ "line": 27,
6
+ "path": "screenshots/SUPPORT-INBOX-S001-line-27-current.svg",
7
+ "title": "Inbox with priority badges",
8
+ "testPath": "src/mocks/current/tests/supportDesk.spec.ts"
9
+ },
10
+ {
11
+ "specPath": "src/mocks/current/specs/ticket-reply.feature.md",
12
+ "line": 27,
13
+ "path": "screenshots/SUPPORT-REPLY-S001-line-27-current.svg",
14
+ "title": "Reply composer with suggested answer",
15
+ "testPath": "src/mocks/current/tests/supportDesk.spec.ts"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: SUPPORT
3
+ title: Support desk
4
+ status: active
5
+ ---
6
+
7
+ # Support desk
8
+
9
+ ## Purpose
10
+
11
+ Define the shared vocabulary for a small customer support workflow.
12
+
13
+ ## Model
14
+
15
+ ### SUPPORT-M001: Ticket
16
+
17
+ A customer request that needs a response from an agent.
18
+
19
+ ### SUPPORT-M002: Agent
20
+
21
+ A team member who reviews tickets and sends replies.
22
+
23
+ ### SUPPORT-M003: Priority
24
+
25
+ A visible urgency label used to sort the queue.
26
+
27
+ ## Rules
28
+
29
+ - SUPPORT-M-R001: Tickets MUST keep a stable public reference.
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: SUPPORT-INBOX
3
+ title: Ticket inbox
4
+ status: active
5
+ model: SUPPORT
6
+ test: playwright
7
+ screenshots: optional
8
+ ---
9
+
10
+ # Ticket inbox
11
+
12
+ ## Purpose
13
+
14
+ Let agents find the next ticket to work on without losing context.
15
+
16
+ ## Rules
17
+
18
+ - SUPPORT-INBOX-R001: The inbox MUST show open tickets first.
19
+ - SUPPORT-INBOX-R002: The inbox SHOULD highlight high priority tickets.
20
+
21
+ ## Scenarios
22
+
23
+ ### SUPPORT-INBOX-S001: Agent reviews the queue
24
+
25
+ Given an agent has open tickets
26
+ When they open the inbox
27
+ Then open tickets are listed by age with priority badges
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: SUPPORT-REPLY
3
+ title: Ticket replies
4
+ status: active
5
+ model: SUPPORT
6
+ test: playwright
7
+ screenshots: optional
8
+ ---
9
+
10
+ # Ticket replies
11
+
12
+ ## Purpose
13
+
14
+ Help agents answer a customer without leaving the ticket.
15
+
16
+ ## Rules
17
+
18
+ - SUPPORT-REPLY-R001: The reply composer MUST preserve unsent text.
19
+ - SUPPORT-REPLY-R002: Saved replies SHOULD be reusable across tickets.
20
+
21
+ ## Scenarios
22
+
23
+ ### SUPPORT-REPLY-S001: Agent drafts a reply
24
+
25
+ Given an agent has selected a ticket
26
+ When they write a reply
27
+ Then the draft remains visible
28
+
29
+ ### SUPPORT-REPLY-S002: Agent sends a saved reply
30
+
31
+ Given an agent has selected a ticket
32
+ When they choose a saved reply
33
+ Then the composer is filled with reusable text
@@ -0,0 +1,17 @@
1
+ import { draftReply, priorityBadge, visibleTickets } from "../app/supportDesk.js";
2
+
3
+ const tickets = [
4
+ { id: "T-2", title: "Newer", status: "open" as const, priority: "high" as const, createdAt: "2026-01-02T10:00:00Z" },
5
+ { id: "T-1", title: "Older", status: "open" as const, priority: "normal" as const, createdAt: "2026-01-01T10:00:00Z" },
6
+ ];
7
+
8
+ export function verifiesTicketInboxMock() {
9
+ // Covers SUPPORT-M001, SUPPORT-M002, SUPPORT-M003 and SUPPORT-M-R001.
10
+ // Covers SUPPORT-INBOX-R001, SUPPORT-INBOX-R002 and SUPPORT-INBOX-S001.
11
+ return visibleTickets(tickets).map((ticket) => priorityBadge(ticket));
12
+ }
13
+
14
+ export function verifiesReplyDraftMock() {
15
+ // Covers SUPPORT-REPLY-R001 and SUPPORT-REPLY-S001.
16
+ return draftReply("Existing draft", "Updated draft");
17
+ }
@@ -0,0 +1,17 @@
1
+ export type Ticket = {
2
+ id: string;
3
+ title: string;
4
+ status: "open" | "closed";
5
+ priority: "low" | "normal" | "high";
6
+ createdAt: string;
7
+ };
8
+
9
+ export function visibleTickets(tickets: Ticket[]) {
10
+ return tickets
11
+ .filter((ticket) => ticket.status === "open")
12
+ .sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt));
13
+ }
14
+
15
+ export function draftReply(existingDraft: string, nextText: string) {
16
+ return nextText.trim() ? nextText : existingDraft;
17
+ }
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540" role="img" aria-label="Inbox before priority badges">
2
+ <rect width="960" height="540" fill="#f6f8fa"/>
3
+ <rect x="72" y="64" width="816" height="412" rx="24" fill="white" stroke="#d0d7de"/>
4
+ <rect x="112" y="112" width="736" height="72" rx="14" fill="#fff8c5" stroke="#d4a72c"/>
5
+ <text x="144" y="158" font-family="system-ui, sans-serif" font-size="28" font-weight="700" fill="#1f2328">Inbox before priority badges</text>
6
+ <rect x="112" y="224" width="520" height="44" rx="10" fill="#f6f8fa"/>
7
+ <rect x="112" y="292" width="660" height="44" rx="10" fill="#f6f8fa"/>
8
+ <rect x="112" y="360" width="420" height="44" rx="10" fill="#f6f8fa"/>
9
+ <circle cx="812" cy="384" r="34" fill="#fff8c5" stroke="#d4a72c"/>
10
+ </svg>
@@ -0,0 +1,11 @@
1
+ {
2
+ "screenshots": [
3
+ {
4
+ "specPath": "src/mocks/previous/specs/ticket-inbox.feature.md",
5
+ "line": 27,
6
+ "path": "screenshots/SUPPORT-INBOX-S001-line-27-previous.svg",
7
+ "title": "Inbox before priority badges",
8
+ "testPath": "src/mocks/previous/tests/supportDesk.spec.ts"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: SUPPORT
3
+ title: Support desk
4
+ status: active
5
+ ---
6
+
7
+ # Support desk
8
+
9
+ ## Purpose
10
+
11
+ Define the shared vocabulary for a small customer support workflow.
12
+
13
+ ## Model
14
+
15
+ ### SUPPORT-M001: Ticket
16
+
17
+ A customer request that needs a response from an agent.
18
+
19
+ ### SUPPORT-M002: Agent
20
+
21
+ A team member who reviews tickets and sends replies.
22
+
23
+ ### SUPPORT-M003: Priority
24
+
25
+ An internal urgency label.
26
+
27
+ ## Rules
28
+
29
+ - SUPPORT-M-R001: Tickets MUST keep a stable public reference.
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: SUPPORT-INBOX
3
+ title: Ticket inbox
4
+ status: active
5
+ model: SUPPORT
6
+ test: playwright
7
+ screenshots: optional
8
+ ---
9
+
10
+ # Ticket inbox
11
+
12
+ ## Purpose
13
+
14
+ Let agents find the next ticket to work on without losing context.
15
+
16
+ ## Rules
17
+
18
+ - SUPPORT-INBOX-R001: The inbox MUST show open tickets first.
19
+
20
+ ## Scenarios
21
+
22
+ ### SUPPORT-INBOX-S001: Agent reviews the queue
23
+
24
+ Given an agent has open tickets
25
+ When they open the inbox
26
+ Then open tickets are listed by age
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: SUPPORT-REPLY
3
+ title: Ticket replies
4
+ status: draft
5
+ model: SUPPORT
6
+ test: playwright
7
+ screenshots: optional
8
+ ---
9
+
10
+ # Ticket replies
11
+
12
+ ## Purpose
13
+
14
+ Help agents answer a customer without leaving the ticket.
15
+
16
+ ## Rules
17
+
18
+ - SUPPORT-REPLY-R001: The reply composer MUST preserve unsent text.
19
+
20
+ ## Scenarios
21
+
22
+ ### SUPPORT-REPLY-S001: Agent drafts a reply
23
+
24
+ Given an agent has selected a ticket
25
+ When they write a reply
26
+ Then the draft remains visible
@@ -0,0 +1,17 @@
1
+ import { draftReply, visibleTickets } from "../app/supportDesk.js";
2
+
3
+ const tickets = [
4
+ { id: "T-2", title: "Newer", status: "open" as const, priority: "high" as const, createdAt: "2026-01-02T10:00:00Z" },
5
+ { id: "T-1", title: "Older", status: "open" as const, priority: "normal" as const, createdAt: "2026-01-01T10:00:00Z" },
6
+ ];
7
+
8
+ export function verifiesTicketInboxMock() {
9
+ // Covers SUPPORT-M001, SUPPORT-M002, SUPPORT-M003 and SUPPORT-M-R001.
10
+ // Covers SUPPORT-INBOX-R001 and SUPPORT-INBOX-S001.
11
+ return visibleTickets(tickets);
12
+ }
13
+
14
+ export function verifiesReplyDraftMock() {
15
+ // Covers SUPPORT-REPLY-R001 and SUPPORT-REPLY-S001.
16
+ return draftReply("Existing draft", "Updated draft");
17
+ }