@zio.dev/zio-blocks 0.0.32 → 0.0.33

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/reference/xml.md CHANGED
@@ -466,7 +466,7 @@ val xml = XmlReader.read("""
466
466
  </book>
467
467
  </books>
468
468
  </library>
469
- """).toOption.get
469
+ """)
470
470
 
471
471
  // Navigate to child elements
472
472
  val books = xml.select.get("library").get("books")
@@ -478,9 +478,16 @@ val firstBook = books.get("book")(0)
478
478
  Extract text content from the first book:
479
479
 
480
480
  ```scala
481
- val title: Either[XmlError, String] = firstBook.get("title").text
482
- // title: Either[XmlError, String] = Left(
483
- // zio.blocks.schema.xml.XmlError: Expected single value but got 0
481
+ val title: Either[SchemaError, String] = firstBook.get("title").text
482
+ // title: Either[SchemaError, String] = Left(
483
+ // SchemaError(
484
+ // List(
485
+ // Message(
486
+ // source = DynamicOptic(IndexedSeq()),
487
+ // details = "Expected single value but got 0"
488
+ // )
489
+ // )
490
+ // )
484
491
  // )
485
492
  ```
486
493
 
@@ -534,19 +541,19 @@ import zio.blocks.schema.xml._
534
541
  val selection: XmlSelection = ???
535
542
 
536
543
  // Get single value (fails if not exactly one)
537
- val one: Either[XmlError, Xml] = selection.one
544
+ val one: Either[SchemaError, Xml] = selection.one
538
545
 
539
546
  // Get any value (first of many)
540
- val any: Either[XmlError, Xml] = selection.any
547
+ val any: Either[SchemaError, Xml] = selection.any
541
548
 
542
549
  // Get all values as a single XML element
543
- val all: Either[XmlError, Xml] = selection.all
550
+ val all: Either[SchemaError, Xml] = selection.all
544
551
 
545
552
  // Convert to chunk
546
553
  val chunk = selection.toChunk
547
554
 
548
555
  // Extract text content
549
- val text: Either[XmlError, String] = selection.text
556
+ val text: Either[SchemaError, String] = selection.text
550
557
  val allText: String = selection.textContent
551
558
  ```
552
559
 
@@ -635,7 +642,7 @@ val xml: Xml = ???
635
642
  val patch = XmlPatch.setAttribute(p".person", "active", "true")
636
643
 
637
644
  // Apply the patch
638
- val result: Either[XmlError, Xml] = patch(xml)
645
+ val result: Either[SchemaError, Xml] = patch(xml)
639
646
  ```
640
647
 
641
648
  ### Composing Patches
@@ -657,175 +664,6 @@ val patch2 = XmlPatch.add(
657
664
  val combined = patch1 ++ patch2
658
665
  ```
659
666
 
660
- ## XmlEncoder and XmlDecoder
661
-
662
- For more fine-grained control over XML serialization, use the separate `XmlEncoder` and `XmlDecoder` traits:
663
-
664
- ### XmlEncoder
665
-
666
- `XmlEncoder[A]` provides type-safe XML encoding:
667
-
668
- ```scala
669
- import zio.blocks.schema._
670
- import zio.blocks.schema.xml._
671
-
672
- // Automatic derivation from Schema
673
- case class Person(name: String, age: Int)
674
- object Person {
675
- implicit val schema: Schema[Person] = Schema.derived
676
- implicit val encoder: XmlEncoder[Person] = XmlEncoder.fromSchema
677
- }
678
-
679
- val person = Person("Alice", 30)
680
- val xml: Xml = XmlEncoder[Person].encode(person)
681
- ```
682
-
683
- #### Creating custom encoders
684
-
685
- Create custom encoders from functions or using contravariance:
686
-
687
- ```scala
688
- import zio.blocks.schema.xml._
689
-
690
- // Create from a function
691
- val customEncoder: XmlEncoder[Int] = XmlEncoder.instance(n =>
692
- Xml.Element("number", Xml.Text(n.toString))
693
- )
694
-
695
- // Map with contravariance - encode a wrapper type
696
- case class UserId(value: Int)
697
-
698
- val userIdEncoder: XmlEncoder[UserId] =
699
- customEncoder.contramap[UserId](_.value)
700
- ```
701
-
702
- #### Using implicit resolution
703
-
704
- Leverage implicit resolution for automatic encoder derivation:
705
-
706
- ```scala
707
- import zio.blocks.schema._
708
- import zio.blocks.schema.xml._
709
-
710
- case class Product(id: String, price: Double)
711
- object Product {
712
- implicit val schema: Schema[Product] = Schema.derived
713
- }
714
-
715
- // No explicit encoder needed - derives automatically
716
- def encodeProduct[A](value: A)(implicit encoder: XmlEncoder[A]): Xml =
717
- encoder.encode(value)
718
-
719
- val result = encodeProduct(Product("item-1", 99.99))
720
- ```
721
-
722
- ### XmlDecoder
723
-
724
- `XmlDecoder[A]` provides type-safe XML decoding with error handling:
725
-
726
- ```scala
727
- import zio.blocks.schema._
728
- import zio.blocks.schema.xml._
729
-
730
- // Automatic derivation from Schema
731
- case class Person(name: String, age: Int)
732
- object Person {
733
- implicit val schema: Schema[Person] = Schema.derived
734
- implicit val decoder: XmlDecoder[Person] = XmlDecoder.fromSchema
735
- }
736
-
737
- val xml = Xml.Element("Person",
738
- Xml.Element("name", Xml.Text("Alice")),
739
- Xml.Element("age", Xml.Text("30"))
740
- )
741
- ```
742
-
743
- Decode the XML:
744
-
745
- ```scala
746
- val result: Either[XmlError, Person] = XmlDecoder[Person].decode(xml)
747
- // result: Either[XmlError, Person] = Right(Person(name = "Alice", age = 30))
748
- ```
749
-
750
- #### Creating custom decoders
751
-
752
- Create custom decoders from functions or using covariance:
753
-
754
- ```scala
755
- import zio.blocks.schema.xml._
756
- import zio.blocks.chunk.Chunk
757
-
758
- // Create from a function
759
- val numberDecoder: XmlDecoder[Int] = XmlDecoder.instance { xml =>
760
- xml match {
761
- case Xml.Element(_, _, Chunk(Xml.Text(text), _*)) =>
762
- text.toIntOption.toRight(XmlError("Invalid number"))
763
- case _ => Left(XmlError("Expected number element"))
764
- }
765
- }
766
-
767
- // Map for covariance - decode to a wrapper type
768
- case class UserId(value: Int)
769
-
770
- val userIdDecoder: XmlDecoder[UserId] =
771
- numberDecoder.map(UserId(_))
772
- ```
773
-
774
- #### Error handling with decoders
775
-
776
- Handle decoding errors gracefully with fallback strategies:
777
-
778
- ```scala
779
- import zio.blocks.schema._
780
- import zio.blocks.schema.xml._
781
-
782
- case class Person(name: String, age: Int)
783
- object Person {
784
- implicit val schema: Schema[Person] = Schema.derived
785
- }
786
-
787
- def decodeWithFallback[A](
788
- xml: Xml,
789
- fallback: A
790
- )(implicit decoder: XmlDecoder[A]): A = {
791
- decoder.decode(xml).getOrElse(fallback)
792
- }
793
-
794
- val invalidXml = Xml.Element("Empty")
795
- val defaultPerson = Person("Unknown", 0)
796
- val result = decodeWithFallback(invalidXml, defaultPerson)
797
- // Person("Unknown", 0)
798
- ```
799
-
800
- #### Combining encoders and decoders
801
-
802
- Round-trip values by encoding and decoding:
803
-
804
- ```scala
805
- import zio.blocks.schema._
806
- import zio.blocks.schema.xml._
807
- import zio.blocks.schema.xml.syntax._
808
-
809
- case class Message(id: String, text: String)
810
- object Message {
811
- implicit val schema: Schema[Message] = Schema.derived
812
- }
813
-
814
- // Round-trip: encode then decode
815
- val message = Message("msg-1", "Hello")
816
- val encoded: Xml = message.toXml
817
- ```
818
-
819
- Decode the encoded value:
820
-
821
- ```scala
822
- val result: Either[XmlError, Message] =
823
- implicitly[XmlDecoder[Message]].decode(encoded)
824
- // result: Either[XmlError, Message] = Right(
825
- // Message(id = "msg-1", text = "Hello")
826
- // )
827
- ```
828
-
829
667
  ## Extension Syntax
830
668
 
831
669
  When a `Schema` is in scope, use convenient extension methods:
@@ -963,7 +801,7 @@ val person = Person("Alice", 30)
963
801
  val xml: Xml = codec.encodeValue(person)
964
802
 
965
803
  // Decode from Xml directly
966
- val decoded: Either[XmlError, Person] = codec.decodeValue(xml)
804
+ val decoded: Person = codec.decodeValue(xml)
967
805
  ```
968
806
 
969
807
  **XmlCodec supports all Schema types:**
@@ -977,7 +815,7 @@ val decoded: Either[XmlError, Person] = codec.decodeValue(xml)
977
815
 
978
816
  ## Error Handling
979
817
 
980
- All decoding operations return `Either[SchemaError, A]` or `Either[XmlError, A]`. The `XmlError` type provides detailed error information:
818
+ All decoding operations return `Either[SchemaError, A]` or `Either[SchemaError, A]`. The `SchemaError` type provides detailed error information:
981
819
 
982
820
  ```scala
983
821
  import zio.blocks.schema._
@@ -1002,12 +840,12 @@ result match {
1002
840
  }
1003
841
  ```
1004
842
 
1005
- `XmlError` provides detailed error information for debugging:
843
+ `SchemaError` provides detailed error information for debugging:
1006
844
 
1007
845
  ```scala
1008
846
  import zio.blocks.schema.xml._
1009
847
 
1010
- val error = XmlError("Parse failed")
848
+ val error = SchemaError("Parse failed")
1011
849
 
1012
850
  // Error message
1013
851
  val message: String = error.getMessage
@@ -1133,7 +971,7 @@ val xmlString = """
1133
971
  </library>
1134
972
  """
1135
973
 
1136
- val xml = XmlReader.read(xmlString).toOption.get
974
+ val xml = XmlReader.read(xmlString)
1137
975
 
1138
976
  // Find all books
1139
977
  val books = xml.select.get("library").get("books").get("book")
package/ringbuffer.md CHANGED
@@ -25,7 +25,7 @@ All variants expose `offer` (returns `false` if full) and `take` (returns `null`
25
25
  ## Installation
26
26
 
27
27
  ```scala
28
- libraryDependencies += "dev.zio" %% "zio-blocks-ringbuffer" % "0.0.32"
28
+ libraryDependencies += "dev.zio" %% "zio-blocks-ringbuffer" % "0.0.33"
29
29
  ```
30
30
 
31
31
  ---
@@ -0,0 +1,407 @@
1
+ # Docs Critique Subagent Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Add a maker-critic agent workflow that automatically reviews documentation for content quality, technical accuracy, completeness, and consistency.
6
+
7
+ **Architecture:** A pure-coordinator skill (`docs-critique`) spawns a maker agent to run a doc creation skill, then spawns a fresh critic agent to review the output. The orchestrator passes critique back to the maker via `SendMessage`. The maker fixes its own work. Critic is freshly spawned each review round.
8
+
9
+ **Tech Stack:** Claude Code skills, Claude Code agent definitions, Agent tool, SendMessage
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-19-docs-critique-subagent-design.md`
12
+
13
+ ---
14
+
15
+ ## File Structure
16
+
17
+ | File | Responsibility |
18
+ |------|---------------|
19
+ | `.claude/agents/docs-critic.md` | Critic agent definition — persona, review dimensions, severity rubric, report format. Read-only tools. |
20
+ | `.claude/skills/docs-critique/SKILL.md` | Orchestrating skill — pure coordinator that spawns maker, spawns critic, passes messages, manages iteration loop. Never edits files. |
21
+
22
+ ---
23
+
24
+ ### Task 1: Create the Critic Agent Definition
25
+
26
+ **Files:**
27
+ - Create: `.claude/agents/docs-critic.md`
28
+
29
+ - [ ] **Step 1: Create the `.claude/agents/` directory**
30
+
31
+ Run: `mkdir -p /home/milad/sources/scala/zio-blocks-new/.claude/agents`
32
+
33
+ - [ ] **Step 2: Write the critic agent definition**
34
+
35
+ Create `.claude/agents/docs-critic.md` with this exact content:
36
+
37
+ ```markdown
38
+ ---
39
+ name: docs-critic
40
+ description: Reviews ZIO Blocks documentation for content quality, technical accuracy, completeness, and consistency. Returns a structured report with severity-rated findings. Read-only — never modifies files.
41
+ tools: Read, Glob, Grep
42
+ model: sonnet
43
+ color: purple
44
+ ---
45
+
46
+ You are a senior technical writer and Scala developer reviewing ZIO Blocks documentation. You are skeptical by default — assume the document has problems and find them.
47
+
48
+ ## Inputs
49
+
50
+ You will receive:
51
+ 1. A documentation file path to review
52
+ 2. A list of relevant Scala source file paths (read them yourself)
53
+ 3. A list of related documentation file paths (read them yourself)
54
+ 4. (Optional) Results from mechanical checks already performed — skip those areas
55
+
56
+ ## Review Dimensions
57
+
58
+ Evaluate the document across four dimensions:
59
+
60
+ ### Content Quality
61
+ - Is there motivation before code? Does the reader understand *why* before *how*?
62
+ - Are examples realistic (not toy `foo`/`bar` examples)?
63
+ - Is the narrative arc logical — does each section build on the previous?
64
+ - Is the writing appropriate for the target audience?
65
+ - Is the prose clear and concise?
66
+
67
+ ### Technical Accuracy
68
+ - Do API signatures in the doc match the actual source code? (Read the source files to verify.)
69
+ - Are code examples correct beyond just compiling? Would they produce the described output?
70
+ - Does the described behavior match the actual implementation?
71
+ - Are type parameters, return types, and method names accurate?
72
+
73
+ **Note:** You cannot compile code. Your accuracy checks are static text comparisons against source files. Flag anything you cannot verify with certainty.
74
+
75
+ ### Completeness
76
+ - Are all required sections present for this doc type?
77
+ - **Reference pages** (`docs/reference/`): Overview, Construction, Predefined Instances, Operators, Comparison, Advanced Usage
78
+ - **How-to guides** (`docs/guides/`): Prerequisites, Steps, Verification, Troubleshooting
79
+ - **Tutorials** (`docs/tutorials/`): Introduction, Prerequisites, Steps, Summary, Next Steps
80
+ - If the doc type cannot be determined from its path, skip required-sections check and note this in your report.
81
+ - Are edge cases and error scenarios mentioned?
82
+ - Are cross-references to related types/pages adequate?
83
+
84
+ ### Consistency
85
+ - Does terminology match related documentation pages? (Read the related docs to verify.)
86
+ - Are there contradictions with other pages?
87
+ - Is the tone consistent with the rest of the documentation?
88
+
89
+ ## Severity Rubric
90
+
91
+ Rate each finding:
92
+
93
+ - **HIGH**: Factually wrong, misleading, or missing critical content. A reader following this doc would be confused or write buggy code.
94
+ - **MEDIUM**: Incomplete, unclear, or inconsistent. A reader could figure it out but shouldn't have to.
95
+ - **LOW**: Stylistic nit or minor improvement. A reader wouldn't notice.
96
+
97
+ ## Report Format
98
+
99
+ You MUST structure your response exactly like this:
100
+
101
+ ## Docs Critic Report: <filename>
102
+
103
+ ### Summary
104
+ <1-2 sentence overall assessment>
105
+
106
+ ### Findings
107
+
108
+ #### [HIGH/dimension] <title>
109
+ **Location:** <section name or line range>
110
+ **Issue:** <what's wrong>
111
+ **Evidence:** <quote from source code or related doc that proves it>
112
+ **Suggested fix:** <concrete suggestion>
113
+
114
+ #### [MEDIUM/dimension] <title>
115
+ **Location:** <section name or line range>
116
+ **Issue:** <what's wrong>
117
+ **Evidence:** <supporting evidence>
118
+ **Suggested fix:** <concrete suggestion>
119
+
120
+ #### [LOW/dimension] <title>
121
+ **Location:** <section name or line range>
122
+ **Issue:** <what's wrong>
123
+ **Suggested fix:** <concrete suggestion>
124
+
125
+ ### Verdict
126
+ <APPROVED | ITERATE — N high, M medium issues remain>
127
+
128
+ ## Rules
129
+
130
+ - Always read the source files before making accuracy claims. Never guess.
131
+ - Always read related docs before making consistency claims.
132
+ - If you find no issues, return APPROVED with an empty Findings section.
133
+ - Never suggest fixes that require information you don't have.
134
+ - Never modify any files. You are read-only.
135
+ ```
136
+
137
+ - [ ] **Step 3: Verify the file was created correctly**
138
+
139
+ Run: `head -5 /home/milad/sources/scala/zio-blocks-new/.claude/agents/docs-critic.md`
140
+ Expected: The YAML frontmatter starting with `---` and `name: docs-critic`
141
+
142
+ - [ ] **Step 4: Commit**
143
+
144
+ ```bash
145
+ git add .claude/agents/docs-critic.md
146
+ git commit -m "feat: add docs-critic agent definition
147
+
148
+ Read-only agent that reviews documentation for content quality,
149
+ technical accuracy, completeness, and consistency. Returns structured
150
+ reports with severity-rated findings."
151
+ ```
152
+
153
+ ---
154
+
155
+ ### Task 2: Create the Orchestrating Skill
156
+
157
+ **Files:**
158
+ - Create: `.claude/skills/docs-critique/SKILL.md`
159
+
160
+ - [ ] **Step 1: Create the skill directory**
161
+
162
+ Run: `mkdir -p /home/milad/sources/scala/zio-blocks-new/.claude/skills/docs-critique`
163
+
164
+ - [ ] **Step 2: Write the orchestrating skill**
165
+
166
+ Create `.claude/skills/docs-critique/SKILL.md` with this exact content:
167
+
168
+ ````markdown
169
+ ---
170
+ name: docs-critique
171
+ description: >
172
+ Run a documentation creation skill with automatic maker-critic review loop.
173
+ Spawns a maker agent to run the skill, then a critic agent to review the output.
174
+ The maker receives critique and fixes its own work. Iterates until approved or
175
+ max 3 rounds. Pure coordinator — never edits files itself.
176
+ argument-hint: "<skill-name> <skill-args>"
177
+ allowed-tools: Agent, Glob, Grep, Read, SendMessage
178
+ ---
179
+
180
+ # Documentation Critique Loop
181
+
182
+ ## Arguments
183
+
184
+ 1. **skill-name** — The documentation skill to run (e.g., `docs-data-type-ref`, `docs-how-to-guide`, `docs-tutorial`, `docs-document-pr`, `docs-enrich-section`, `docs-add-missing-section`)
185
+ 2. **skill-args** — Arguments to pass to the skill (e.g., `Schema`, `TypeId`)
186
+
187
+ Example invocation: `/docs-critique docs-data-type-ref Schema`
188
+
189
+ ## Role
190
+
191
+ You are a **pure coordinator**. You NEVER read, write, or edit documentation files yourself. You ONLY:
192
+ 1. Spawn agents
193
+ 2. Pass messages between agents
194
+ 3. Parse critic reports to decide next action
195
+ 4. Report final status to the user
196
+
197
+ ## Phase 1: Spawn Maker Agent
198
+
199
+ Spawn a general-purpose agent via the `Agent` tool:
200
+
201
+ ```
202
+ Agent(
203
+ description: "Run doc creation skill",
204
+ prompt: "Run /<skill-name> <skill-args>. Complete all steps of the skill.
205
+ When done, report the absolute path of the generated/modified
206
+ documentation file as the LAST line of your response, in the format:
207
+ DOC_PATH: <absolute-path>"
208
+ )
209
+ ```
210
+
211
+ Parse the maker's response to extract the doc file path from the `DOC_PATH:` line.
212
+
213
+ **Error handling:** If the maker does not return a `DOC_PATH:` line, ask the user which file was generated and use that path.
214
+
215
+ Save the maker's agent ID for later `SendMessage` calls. The `Agent` tool returns an `agentId` in its result — store this value. You will use it as the `to` field in `SendMessage` to route critique back to the maker.
216
+
217
+ ## Phase 2: Gather Critic Context
218
+
219
+ Using the doc file path from Phase 1, gather context for the critic. You MAY use `Glob` and `Grep` for this phase only — this is the one exception to the "never read files" rule, because you need file paths (not content) to pass to the critic.
220
+
221
+ 1. **Source files** — Extract the type name from the doc path (e.g., `docs/reference/schema.md` → `Schema`). Find source files:
222
+ ```
223
+ Glob: **/<TypeName>.scala
224
+ Grep: "class <TypeName>" or "trait <TypeName>" or "object <TypeName>"
225
+ ```
226
+ Also find test files:
227
+ ```
228
+ Glob: **/<TypeName>Spec.scala or **/<TypeName>Test.scala
229
+ ```
230
+
231
+ 2. **Related docs** — Find sibling pages using two methods:
232
+ - **sidebars.js** (preferred): Read `sidebars.js` and find the array containing the doc's ID. Extract sibling page IDs from the same array. Map IDs to file paths.
233
+ - **Fallback glob** (if sidebars.js parsing fails): Glob the parent directory:
234
+ ```
235
+ Glob: docs/reference/*.md (for reference pages)
236
+ Glob: docs/guides/*.md (for guides)
237
+ Glob: docs/tutorials/*.md (for tutorials)
238
+ ```
239
+
240
+ 3. Collect all found paths into two lists: `source_files` and `related_docs`.
241
+
242
+ ## Phase 3: Spawn Critic Agent
243
+
244
+ Spawn the `docs-critic` agent:
245
+
246
+ ```
247
+ Agent(
248
+ description: "Review documentation",
249
+ subagent_type: "docs-critic",
250
+ prompt: "Review the following documentation file for content quality,
251
+ technical accuracy, completeness, and consistency.
252
+
253
+ Documentation file: <doc-path>
254
+
255
+ Source files to check accuracy against:
256
+ <list of source_files, one per line>
257
+
258
+ Related documentation to check consistency against:
259
+ <list of related_docs, one per line>
260
+
261
+ Read each file yourself using the Read tool. Return your
262
+ structured report."
263
+ )
264
+ ```
265
+
266
+ **Error handling:** If the critic's response does not contain a `### Findings` section or a `### Verdict` line, treat it as an agent failure. Retry by spawning a fresh critic with the same prompt. If the second attempt also fails, report the raw response to the user and stop.
267
+
268
+ ## Phase 4: Triage
269
+
270
+ Parse the critic's `### Verdict` line:
271
+
272
+ - **`APPROVED`** → Report success to user. Done.
273
+ - **`ITERATE`** with HIGH or MEDIUM findings → Enter Phase 5.
274
+ - Only LOW findings → Send LOWs to maker for a single-pass fix:
275
+ ```
276
+ SendMessage(
277
+ to: <maker-agent-id>,
278
+ message: "The documentation critic found minor issues. Fix them if easy,
279
+ skip if not. One commit per fix.
280
+ Commit format: docs(<file-stem>): fix LOW/<dimension> — <description>
281
+
282
+ <paste LOW findings here>"
283
+ )
284
+ ```
285
+ Done after maker responds.
286
+
287
+ ## Phase 5: Fix Loop
288
+
289
+ **Maximum 3 rounds.** Track the current round number.
290
+
291
+ **Severity-based iteration rules:**
292
+ - **HIGH** findings: iterate until fixed (up to round 3)
293
+ - **MEDIUM** findings: iterate at most once — if a MEDIUM finding persists after round 1, do not iterate further for it
294
+ - After round 1, only HIGH findings drive further iteration
295
+
296
+ ### Each Round:
297
+
298
+ **Step A — Send critique to maker:**
299
+
300
+ For round 1, send all HIGH and MEDIUM findings:
301
+ ```
302
+ SendMessage(
303
+ to: <maker-agent-id>,
304
+ message: "The documentation critic found issues that need fixing.
305
+ Fix ALL HIGH and MEDIUM findings below. For each fix:
306
+ - Make a separate git commit
307
+ - Commit format: docs(<file-stem>): fix <SEVERITY>/<dimension> — <description>
308
+ - If multiple findings target the same paragraph, combine into one commit
309
+ using the highest severity level
310
+
311
+ <paste HIGH and MEDIUM findings here>"
312
+ )
313
+ ```
314
+
315
+ For rounds 2+, send only HIGH findings (MEDIUM issues have had their one iteration).
316
+
317
+ Wait for the maker to respond confirming fixes are done.
318
+
319
+ **Step B — Spawn fresh critic:**
320
+
321
+ Spawn a NEW `docs-critic` agent (do NOT reuse the previous one — fresh eyes each round):
322
+
323
+ ```
324
+ Agent(
325
+ description: "Re-review documentation round N",
326
+ subagent_type: "docs-critic",
327
+ prompt: <same prompt as Phase 3, identical>
328
+ )
329
+ ```
330
+
331
+ **Step C — Check verdict:**
332
+
333
+ - `APPROVED` → Report success to user. Done.
334
+ - `ITERATE` with only MEDIUM findings remaining (no HIGH) → Done. MEDIUM had its one iteration.
335
+ - `ITERATE` with HIGH findings and round < 3 → Go to next round.
336
+ - `ITERATE` and round = 3 → Report remaining issues to user:
337
+ "The documentation was reviewed 3 times. These issues remain unresolved:
338
+ <paste remaining findings>
339
+ Please review manually."
340
+
341
+ ## Output
342
+
343
+ When done, report to the user:
344
+ - Whether the doc was APPROVED or has remaining issues
345
+ - How many rounds were needed
346
+ - Summary of findings fixed (count by severity)
347
+ ````
348
+
349
+ - [ ] **Step 3: Verify the file was created correctly**
350
+
351
+ Run: `head -10 /home/milad/sources/scala/zio-blocks-new/.claude/skills/docs-critique/SKILL.md`
352
+ Expected: The YAML frontmatter with `name: docs-critique`
353
+
354
+ - [ ] **Step 4: Commit**
355
+
356
+ ```bash
357
+ git add .claude/skills/docs-critique/SKILL.md
358
+ git commit -m "feat: add docs-critique orchestrating skill
359
+
360
+ Pure coordinator that spawns a maker agent to run any doc creation
361
+ skill, then spawns a fresh critic agent each round to review. Passes
362
+ critique back to maker via SendMessage. Severity-gated iteration
363
+ with max 3 rounds."
364
+ ```
365
+
366
+ ---
367
+
368
+ ### Task 3: Manual Smoke Test
369
+
370
+ **Files:**
371
+ - None (testing only)
372
+
373
+ - [ ] **Step 1: Verify the critic agent is recognized**
374
+
375
+ Run: `ls -la /home/milad/sources/scala/zio-blocks-new/.claude/agents/docs-critic.md`
376
+ Expected: File exists with correct permissions
377
+
378
+ - [ ] **Step 2: Verify the skill is recognized**
379
+
380
+ Run: `ls -la /home/milad/sources/scala/zio-blocks-new/.claude/skills/docs-critique/SKILL.md`
381
+ Expected: File exists with correct permissions
382
+
383
+ - [ ] **Step 3: Test invocation with an existing doc**
384
+
385
+ In a new Claude Code session, run:
386
+ ```
387
+ /docs-critique docs-data-type-ref TypeId
388
+ ```
389
+
390
+ Verify:
391
+ - The orchestrator spawns a maker agent that runs `/docs-data-type-ref TypeId`
392
+ - After the maker finishes, the orchestrator gathers source file and related doc paths
393
+ - The orchestrator spawns a `docs-critic` agent with the gathered context
394
+ - The critic returns a structured report with `### Findings` and `### Verdict`
395
+ - If ITERATE, the orchestrator sends findings to the maker via SendMessage
396
+ - The maker fixes issues and commits
397
+ - The loop repeats until APPROVED or 3 rounds
398
+
399
+ - [ ] **Step 4: Verify error handling — malformed critic report**
400
+
401
+ If the critic returns a malformed report (no `### Verdict`), verify:
402
+ - The orchestrator retries once
403
+ - If still malformed, it reports the raw response and stops
404
+
405
+ - [ ] **Step 5: Commit any fixes discovered during smoke test**
406
+
407
+ If any issues are found in the agent definition or skill during testing, fix them and commit each fix separately.