@popoverai/dotrequirements 0.24.1 → 0.24.3
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.
- package/README.md +1 -1
- package/dist/codebase-to-spec/cache.d.ts +6 -0
- package/dist/codebase-to-spec/cache.js +1 -0
- package/dist/codebase-to-spec/claude.d.ts +1 -0
- package/dist/codebase-to-spec/claude.js +9 -0
- package/dist/codebase-to-spec/dispatch.d.ts +69 -0
- package/dist/codebase-to-spec/dispatch.js +484 -0
- package/dist/codebase-to-spec/pack.d.ts +16 -0
- package/dist/codebase-to-spec/pack.js +17 -3
- package/dist/codebase-to-spec/present.d.ts +8 -1
- package/dist/codebase-to-spec/present.js +7 -4
- package/dist/codebase-to-spec/progress.d.ts +6 -0
- package/dist/codebase-to-spec/progress.js +34 -0
- package/dist/codebase-to-spec/prompts/outline-reviewer.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/outline-reviewer.js +3 -1
- package/dist/codebase-to-spec/prompts/planner-initial.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/planner-initial.js +4 -0
- package/dist/codebase-to-spec/prompts/planner-revise.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/planner-revise.js +2 -2
- package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/spec-reviewer.js +6 -1
- package/dist/codebase-to-spec/prompts/specifier.d.ts +1 -1
- package/dist/codebase-to-spec/prompts/specifier.js +6 -4
- package/dist/codebase-to-spec/prompts/style-check.d.ts +10 -2
- package/dist/codebase-to-spec/prompts/style-check.js +76 -46
- package/dist/codebase-to-spec/schemas.d.ts +460 -1
- package/dist/codebase-to-spec/schemas.js +158 -1
- package/dist/codebase-to-spec/skill-install.d.ts +36 -12
- package/dist/codebase-to-spec/skill-install.js +127 -26
- package/dist/codebase-to-spec/specifier.js +6 -0
- package/dist/commands/codebase-to-spec/compose-orchestrator.d.ts +14 -0
- package/dist/commands/codebase-to-spec/compose-orchestrator.js +54 -0
- package/dist/commands/codebase-to-spec/dispatch-context.d.ts +12 -0
- package/dist/commands/codebase-to-spec/dispatch-context.js +22 -0
- package/dist/commands/codebase-to-spec/dispatch-editor.d.ts +16 -0
- package/dist/commands/codebase-to-spec/dispatch-editor.js +71 -0
- package/dist/commands/codebase-to-spec/dispatch-planner.d.ts +19 -0
- package/dist/commands/codebase-to-spec/dispatch-planner.js +90 -0
- package/dist/commands/codebase-to-spec/dispatch-spec.d.ts +16 -0
- package/dist/commands/codebase-to-spec/dispatch-spec.js +59 -0
- package/dist/commands/codebase-to-spec/index.js +69 -1
- package/dist/commands/codebase-to-spec/pack.d.ts +6 -0
- package/dist/commands/codebase-to-spec/pack.js +1 -0
- package/dist/commands/codebase-to-spec/present-orchestrator.d.ts +20 -0
- package/dist/commands/codebase-to-spec/present-orchestrator.js +81 -0
- package/dist/commands/codebase-to-spec/present.d.ts +5 -0
- package/dist/commands/codebase-to-spec/present.js +6 -1
- package/dist/commands/codebase-to-spec/run.js +1 -0
- package/dist/commands/codebase-to-spec/skill-install.js +12 -1
- package/dist/templates/agents/cts-worker.md +9 -0
- package/dist/templates/hooks/cts-worker-persona.sh +76 -0
- package/dist/templates/skills/codebase-to-spec/SKILL.md +159 -68
- package/package.json +4 -5
|
@@ -1,118 +1,209 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: codebase-to-spec
|
|
3
|
-
description: Generate dotrequirements behavioral specifications from a codebase. Use this when the user wants to capture what an existing codebase does as a set of testable behavioral requirements
|
|
3
|
+
description: Generate dotrequirements behavioral specifications from a codebase via the conversational orchestrator. The user's CC session drives the pipeline directly — dispatching workers as subagents, reviewing per-area drafts, and iterating with editor passes. Use this when the user wants to capture what an existing codebase does as a set of testable behavioral requirements (legacy systems, third-party libraries, before refactoring).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Codebase to Spec
|
|
6
|
+
# Codebase to Spec — Conversational Orchestrator
|
|
7
7
|
|
|
8
|
-
You are
|
|
8
|
+
You are the conversational orchestrator for codebase-to-spec. Unlike a thin CLI wrapper, **you drive the pipeline directly** — dispatching workers as `cts-worker` subagents (via the Task tool), reading their outputs, writing per-stage reviews into `.dotrequirements-cache/outline.yaml`, and looping until each stage converges.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
2. Run the CLI via the Bash tool.
|
|
12
|
-
3. Narrate progress as the CLI emits it.
|
|
13
|
-
4. Surface the final summary and residual notes.
|
|
14
|
-
5. Offer sensible follow-ups (push to cloud, re-run, narrow scope, etc.).
|
|
10
|
+
The CLI provides dispatch-instruction commands (`cts dispatch-*`) that you call to scaffold each step; you then dispatch the worker subagent yourself. The substrate is the single evolving `outline.yaml` file — it carries both the spec content (areas, customers, source files) and the review thread for each stage.
|
|
15
11
|
|
|
16
12
|
## When this skill is right
|
|
17
13
|
|
|
18
|
-
Use
|
|
14
|
+
Use when the user wants behavioral requirements *from* code that already exists. Typical phrasings:
|
|
19
15
|
- "Generate requirements from this codebase"
|
|
20
16
|
- "Capture the behavior of this library"
|
|
21
17
|
- "I want a behavioral spec for the auth module"
|
|
22
18
|
- "Document what this service does"
|
|
23
19
|
|
|
24
|
-
Do **not** use
|
|
25
|
-
- New feature design (use `dotreq-requirements` / the capture flow instead)
|
|
26
|
-
- Bug investigation
|
|
27
|
-
- Code review
|
|
20
|
+
Do **not** use for new feature design (use the `dotreq-requirements` skill instead), bug investigation, or code review.
|
|
28
21
|
|
|
29
22
|
## Workflow
|
|
30
23
|
|
|
31
24
|
### Step 1 — Confirm scope
|
|
32
25
|
|
|
33
|
-
If the user passed a scope argument (
|
|
26
|
+
If the user passed a scope argument (path), use it. Otherwise ask one concise question:
|
|
34
27
|
|
|
35
|
-
> "Which part of the codebase should I spec?
|
|
28
|
+
> "Which part of the codebase should I spec? Give me a path (e.g. `src/auth`) or say 'the whole thing'."
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
For larger codebases, encourage scoping to a single area. The CLI will surface a `BudgetExceeded` exit code if the compressed pack is too large.
|
|
38
31
|
|
|
39
|
-
### Step 2 —
|
|
32
|
+
### Step 2 — Pack
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
Run `dotrequirements cts pack --scope <PATH>` via Bash. This is deterministic — no LLM work. The CLI emits `[CTS] pack/done` and `[CTS] pack/budget-ok` lines.
|
|
35
|
+
|
|
36
|
+
### Step 3 — Plan: dispatch the planner, review, iterate to approval
|
|
37
|
+
|
|
38
|
+
**3a. Initial planner dispatch.** Run `dotrequirements cts dispatch-planner` via Bash. The output is JSON like `{ "dispatch_id": "planner-initial", "output_path": "..." }`. Dispatch the worker:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=planner-initial")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The PreToolUse hook composes the full planner prompt; the worker writes `outline.yaml` and signals completion.
|
|
45
|
+
|
|
46
|
+
**3b. Review the outline.** Read `.dotrequirements-cache/outline.yaml`. Assess:
|
|
47
|
+
- **Customer naming**: Each area must have ≥1 customers with concrete, area-scoped descriptions (not "a developer" — "a Python data engineer building ETL pipelines"). Same role across areas is OK if described freshly per area's context.
|
|
48
|
+
- **Area set**: Customer-vocabulary names, not architectural labels. Coverage of substantive files; non-behavioral files (tests, build infrastructure) excluded.
|
|
49
|
+
- **Mechanical correctness**: distinct prefixes per area; paths matching the pack; ≥1 customer per area.
|
|
50
|
+
|
|
51
|
+
**3c. Write your review into outline.yaml.** Edit the outline to add a top-level `review:` section. Two shapes:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
# Approved
|
|
55
|
+
review:
|
|
56
|
+
result: approved
|
|
57
|
+
thread:
|
|
58
|
+
- result: approved
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
# Needs revision (revisions list is required, ≥1 entries)
|
|
63
|
+
review:
|
|
64
|
+
result: needs-revision
|
|
65
|
+
thread:
|
|
66
|
+
- result: needs-revision
|
|
67
|
+
revisions:
|
|
68
|
+
- "Split the FOO area into two areas, separating the producer behavior from the reviewer behavior. Each should have its own customer and source files."
|
|
69
|
+
- "Tighten the customer description on BAR — it currently reads as generic 'a developer'; ground it in what the customer is doing at this specific moment in the system."
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Revisions must be specific, actionable directives the planner can apply mechanically. Avoid "this feels off" — say what to change.
|
|
73
|
+
|
|
74
|
+
**3d. If needs-revision, dispatch the planner again.** Run `dotrequirements cts dispatch-planner --revise`. Dispatch:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=planner-revise-<N>")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
(N comes from the CLI's payload — `planner-revise-2` for the 2nd round, `planner-revise-3` for the 3rd, etc.)
|
|
81
|
+
|
|
82
|
+
The worker rewrites outline.yaml's content while preserving the existing `review` section. After it completes, return to step 3b and review the revised outline. Append another entry to the `review.thread` array based on what you find.
|
|
83
|
+
|
|
84
|
+
**3e. Approval.** When you're satisfied, edit outline.yaml to set `review.result: approved` and append a `{ result: approved }` entry to the thread. Proceed to step 4.
|
|
85
|
+
|
|
86
|
+
### Step 4 — Fan out: dispatch all specifiers in parallel
|
|
87
|
+
|
|
88
|
+
Run `dotrequirements cts dispatch-spec`. The output is a JSON array of N payloads, one per area:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
[
|
|
92
|
+
{ "dispatch_id": "specifier-PLAN", "output_path": "...", "area_name": "...", "area_prefix": "PLAN" },
|
|
93
|
+
...
|
|
94
|
+
]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Fire all N background Task dispatches in **one message** (parallel, not sequential):
|
|
42
98
|
|
|
43
|
-
```bash
|
|
44
|
-
dotrequirements cts run --scope <PATH> --non-interactive
|
|
45
99
|
```
|
|
100
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=specifier-PLAN", run_in_background=true)
|
|
101
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=specifier-OREV", run_in_background=true)
|
|
102
|
+
... etc
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Each worker:
|
|
106
|
+
- Reads the area's source files via Read tool (from `.dotrequirements-cache/source.txt` or directly from the worktree)
|
|
107
|
+
- Drafts the partial at `.dotrequirements-cache/partials/<sanitized-area>.partial.md`
|
|
108
|
+
- Runs `cts validate` + `cts style-check` on its own draft via Bash (self-style-check loop, capped at 2 runs)
|
|
109
|
+
- Signals completion via task-notification
|
|
110
|
+
|
|
111
|
+
### Step 5 — Per-area review and editor loops
|
|
112
|
+
|
|
113
|
+
As each specifier's task-notification arrives, review that area's partial:
|
|
114
|
+
|
|
115
|
+
**5a. Read the partial.** Pull up the file the worker wrote.
|
|
46
116
|
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
117
|
+
**5b. Review against per-area criteria.** The area's customer descriptions in outline.yaml ground your review. Look for:
|
|
118
|
+
- **Customer-grounding**: requirements use named personas from the area's customers
|
|
119
|
+
- **Behavioral framing**: requirements describe what the customer observes, not API contracts or implementation mechanics
|
|
120
|
+
- **Independent testability**: no cross-references between requirements; each readable on its own
|
|
121
|
+
- **Coverage**: behaviors visible in source files are captured; tests/recipes informed but didn't drift into the spec
|
|
122
|
+
- **Schema cleanliness**: validate already ran (worker self-validated); just sanity-check
|
|
53
123
|
|
|
54
|
-
|
|
124
|
+
**5c. Write your review into outline.yaml's area section.** Same shape as the project-level review, on the area:
|
|
55
125
|
|
|
56
|
-
|
|
126
|
+
```yaml
|
|
127
|
+
areas:
|
|
128
|
+
- name: ...
|
|
129
|
+
prefix: PLAN
|
|
130
|
+
review:
|
|
131
|
+
result: approved
|
|
132
|
+
thread:
|
|
133
|
+
- result: approved
|
|
134
|
+
...
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or needs-revision with a revisions list (≥1 entries).
|
|
57
138
|
|
|
58
|
-
|
|
139
|
+
**5d. If needs-revision, dispatch the editor.** Run `dotrequirements cts dispatch-editor <area-prefix>`. Then:
|
|
59
140
|
|
|
60
141
|
```
|
|
61
|
-
|
|
62
|
-
[CTS] plan/done Plan loop converged at turn 1 with verdict: approved-with-revisions
|
|
63
|
-
[CTS] specify/summary Completed: 7 / Skipped (resume): 0 / Failed: 0
|
|
64
|
-
[CTS] spec-review/done Edit loop converged at turn 1 with verdict: approved-with-revisions
|
|
65
|
-
[CTS] present/created created: .../sample.requirements.md
|
|
142
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=editor-<prefix>")
|
|
66
143
|
```
|
|
67
144
|
|
|
68
|
-
|
|
145
|
+
The worker reads the current partial + the revisions list inline (in the composed prompt), applies each revision via Edit, runs validate + style-check, signals completion. Return to 5a and re-review.
|
|
146
|
+
|
|
147
|
+
**5e. Convergence.** Continue per-area loops until every area's `review.result` is `approved`. Each area can converge independently; don't block on one area to start reviewing another.
|
|
148
|
+
|
|
149
|
+
### Step 6 — Cross-area review
|
|
150
|
+
|
|
151
|
+
Once all per-area reviews are approved, run `cts compose-orchestrator` to assemble the composed spec. Then read it and check:
|
|
152
|
+
|
|
153
|
+
- **Persona consistency**: same role mentioned across areas should use consistent naming
|
|
154
|
+
- **Duplicated behaviors**: same behavior captured in two areas (one should own it)
|
|
155
|
+
- **Cross-area gaps**: behaviors that fell between areas
|
|
156
|
+
- **Framing drift**: areas in different voices
|
|
157
|
+
|
|
158
|
+
If cross-area concerns surface, edit the affected areas' `review` to needs-revision with appropriate revisions, dispatch editors per 5d, then re-compose. Otherwise proceed to step 7.
|
|
159
|
+
|
|
160
|
+
### Step 7 — Present
|
|
161
|
+
|
|
162
|
+
Run `dotrequirements cts present-orchestrator [--overwrite] [--skip-existing]` via Bash. Writes the final files under `.requirements/`. Per CTS-PRESENT-1, splits into per-area files when the outline has ≥5 areas; single file otherwise.
|
|
163
|
+
|
|
164
|
+
In non-interactive mode without `--overwrite` / `--skip-existing`, the CLI errors on conflicts. Ask the user which they want when a conflict is detected.
|
|
69
165
|
|
|
70
|
-
### Step
|
|
166
|
+
### Step 8 — Summarize and offer follow-ups
|
|
71
167
|
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
- specifier completion count
|
|
77
|
-
- spec review turns and verdict
|
|
78
|
-
- the list of output files written
|
|
79
|
-
- residual notes (issues the reviewer flagged in `approved-with-revisions` outcomes)
|
|
168
|
+
Present the final summary in conversational form:
|
|
169
|
+
- How many areas, how many requirements
|
|
170
|
+
- Any unconverged areas (latest thread entry was max-turns-hit)
|
|
171
|
+
- File paths written
|
|
80
172
|
|
|
81
|
-
|
|
82
|
-
- `
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
- `spec.cross_area` — duplication across areas
|
|
86
|
-
- `spec.internal_mechanics` — internal vocabulary that leaked into a user-facing spec
|
|
173
|
+
Offer useful follow-ups:
|
|
174
|
+
- **Push to cloud** — `dotrequirements push` syncs to dotrequirements cloud. Only suggest if the user has cloud configured (check `.dotrequirements/config.json` or ask).
|
|
175
|
+
- **Refine an area** — re-review one area; mark needs-revision; re-dispatch editor.
|
|
176
|
+
- **Re-run on different scope** — start over with a different `--scope` path.
|
|
87
177
|
|
|
88
|
-
|
|
178
|
+
## Pausing for user input
|
|
89
179
|
|
|
90
|
-
|
|
180
|
+
These moments naturally invite user judgment — surface them in conversation rather than auto-deciding:
|
|
181
|
+
- **Scope confirmation** at the start
|
|
182
|
+
- **Outline approval** before fan-out (the area decomposition is high-leverage)
|
|
183
|
+
- **Cross-area concerns** that look like the user's call (e.g., "should X and Y be one area or two?")
|
|
184
|
+
- **Residual concerns** at the end (anything the loop didn't fully address)
|
|
91
185
|
|
|
92
|
-
|
|
93
|
-
- **Refine a specific area** — re-run `dotrequirements cts specify-area "<name>"` for one area, optionally with `--model <name>` for a stronger model.
|
|
94
|
-
- **Refine the whole spec** — re-run `dotrequirements cts edit-loop` to iterate on the composed spec.
|
|
95
|
-
- **Narrow the scope** — re-run with a smaller `--scope`.
|
|
96
|
-
- **Hand-edit** — the output files are plain Markdown; the user can edit them directly.
|
|
186
|
+
Routine progress narration ("dispatching planner...", "fan-out complete...") should NOT interrupt the user. Only judgment-requiring moments surface as questions.
|
|
97
187
|
|
|
98
188
|
## Failure handling
|
|
99
189
|
|
|
100
|
-
The CLI uses stable exit codes
|
|
190
|
+
The CLI uses stable exit codes:
|
|
101
191
|
|
|
102
|
-
- **Exit
|
|
103
|
-
- **Exit
|
|
104
|
-
- **Exit
|
|
105
|
-
- **Exit
|
|
106
|
-
- **
|
|
192
|
+
- **Exit 10 (BudgetExceeded)** — codebase too large after compression. Surface, offer narrower `--scope`.
|
|
193
|
+
- **Exit 11 (MaxTurnsHit)** — review loop hit its cap. Latest artifact is on disk; surface residual notes and ask user whether to ship, re-iterate, or hand-edit.
|
|
194
|
+
- **Exit 12 (OverwriteRefused)** — present found existing files. Offer `--overwrite` or `--skip-existing`.
|
|
195
|
+
- **Exit 2 (MissingInput)** — usually means a prior step wasn't run. Surface CLI message verbatim.
|
|
196
|
+
- **Exit 3 (StageFailed)** — a stage errored. Read stderr; offer resume (re-run same command — the cache means earlier stages are skipped), restart fresh (`--fresh`), or investigate.
|
|
107
197
|
|
|
108
198
|
## What you must NOT do
|
|
109
199
|
|
|
110
|
-
- Don't try to generate requirements yourself; always
|
|
111
|
-
- Don't paraphrase
|
|
112
|
-
- Don't claim
|
|
200
|
+
- Don't try to generate requirements yourself; always dispatch workers.
|
|
201
|
+
- Don't paraphrase the CLI's progress lines in misleading ways. If the CLI emits "specifier failed", don't say "specifier completed."
|
|
202
|
+
- Don't claim convergence when an area's thread ends with `needs-revision`. The loop hasn't closed.
|
|
113
203
|
- Don't push to cloud without asking — `dotrequirements push` is a destructive sync.
|
|
114
|
-
- Don't
|
|
204
|
+
- Don't edit files inside `.dotrequirements-cache/` other than `outline.yaml` (which you DO edit, to write reviews). Other cache files are managed by the CLI and workers.
|
|
205
|
+
- Don't dispatch a worker without the corresponding `cts dispatch-*` call first — the dispatch-id must match what the CLI scaffolded.
|
|
115
206
|
|
|
116
207
|
## Host portability
|
|
117
208
|
|
|
118
|
-
This skill
|
|
209
|
+
This skill relies on Claude Code's Task tool, PreToolUse hook, and Bash. It does not work on hosts without subagent dispatch (Cursor, Codex) — those should use the legacy `cts run` CLI directly. The skill is bundled with `dotrequirements ai-setup` for Claude Code; the `cts-worker` agent definition and persona-injection hook are installed at the same time.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popoverai/dotrequirements",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.3",
|
|
4
4
|
"description": "Requirements tracking CLI, test harness, and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,10 +24,9 @@
|
|
|
24
24
|
"test": "vitest",
|
|
25
25
|
"test:run": "vitest run",
|
|
26
26
|
"test:coverage": "vitest run --coverage",
|
|
27
|
-
"
|
|
28
|
-
"publish:
|
|
29
|
-
"publish:
|
|
30
|
-
"publish:major": "pnpm prepublish:check && npm version major && pnpm build && npm publish && git push && git push --tags"
|
|
27
|
+
"publish:patch": "echo 'ERROR: publish:patch is decommissioned. CLI npm publishes now happen via the cli-publish GitHub Action when a production PR with a CLI version bump merges. Use the /release Claude Code skill to queue a bump and open the production PR. See docs/working/cli-publish-workflow.md for details.' && exit 1",
|
|
28
|
+
"publish:minor": "echo 'ERROR: publish:minor is decommissioned. CLI npm publishes now happen via the cli-publish GitHub Action when a production PR with a CLI version bump merges. Use the /release Claude Code skill to queue a bump and open the production PR. See docs/working/cli-publish-workflow.md for details.' && exit 1",
|
|
29
|
+
"publish:major": "echo 'ERROR: publish:major is decommissioned. CLI npm publishes now happen via the cli-publish GitHub Action when a production PR with a CLI version bump merges. Use the /release Claude Code skill to queue a bump and open the production PR. See docs/working/cli-publish-workflow.md for details.' && exit 1"
|
|
31
30
|
},
|
|
32
31
|
"keywords": [
|
|
33
32
|
"requirements",
|