@cleocode/skills 2026.5.83 → 2026.5.86
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/package.json +1 -1
- package/skills/_shared/__tests__/lifecycle-protocol-reconcile.test.ts +112 -0
- package/skills/_shared/__tests__/loom-adr-links.test.ts +163 -0
- package/skills/_shared/__tests__/loom-stage-coverage.test.ts +167 -0
- package/skills/ct-adr-recorder/SKILL.md +92 -0
- package/skills/ct-adr-recorder/__tests__/skill-adr-recorder.test.ts +65 -0
- package/skills/ct-consensus-voter/SKILL.md +14 -0
- package/skills/ct-contribution/SKILL.md +80 -0
- package/skills/ct-docs-lookup/SKILL.md +116 -1
- package/skills/ct-docs-lookup/references/ctx7-workflow.md +198 -0
- package/skills/ct-docs-lookup/references/library-id-resolution.md +217 -0
- package/skills/ct-docs-lookup/references/version-specific-docs.md +220 -0
- package/skills/ct-docs-review/SKILL.md +133 -1
- package/skills/ct-docs-review/__tests__/skill-docs-review.test.ts +53 -0
- package/skills/ct-docs-review/references/inline-comment-patterns.md +268 -0
- package/skills/ct-docs-review/references/pr-review-mode.md +270 -0
- package/skills/ct-docs-review/references/style-violations.md +341 -0
- package/skills/ct-docs-write/SKILL.md +157 -1
- package/skills/ct-docs-write/__tests__/skill-docs-write.test.ts +55 -0
- package/skills/ct-docs-write/references/audience-targeting.md +305 -0
- package/skills/ct-docs-write/references/cleo-style-guide.md +234 -0
- package/skills/ct-docs-write/references/markdown-patterns.md +329 -0
- package/skills/ct-documentor/SKILL.md +11 -0
- package/skills/ct-documentor/references/anti-patterns.md +216 -0
- package/skills/ct-documentor/references/chain-orchestration.md +194 -0
- package/skills/ct-documentor/references/doc-types-and-templates.md +301 -0
- package/skills/ct-documentor/references/style-coordination.md +195 -0
- package/skills/ct-epic-architect/SKILL.md +15 -0
- package/skills/ct-ivt-looper/SKILL.md +32 -0
- package/skills/ct-release-orchestrator/SKILL.md +16 -0
- package/skills/ct-research-agent/SKILL.md +24 -0
- package/skills/ct-research-agent/references/anti-patterns.md +154 -0
- package/skills/ct-research-agent/references/citation-and-evidence.md +140 -0
- package/skills/ct-research-agent/references/source-strategy.md +116 -0
- package/skills/ct-research-agent/references/triggers-and-routing.md +93 -0
- package/skills/ct-skill-validator/SKILL.md +19 -0
- package/skills/ct-skill-validator/scripts/check_depth.py +306 -0
- package/skills/ct-spec-writer/SKILL.md +86 -1
- package/skills/ct-spec-writer/__tests__/skill-spec-writer.test.ts +60 -0
- package/skills/ct-spec-writer/references/anti-patterns.md +176 -0
- package/skills/ct-spec-writer/references/rfc2119-language.md +138 -0
- package/skills/ct-spec-writer/references/spec-templates.md +233 -0
- package/skills/ct-spec-writer/references/traceability-matrix.md +145 -0
- package/skills/ct-task-executor/SKILL.md +25 -0
- package/skills/ct-task-executor/references/acceptance-criteria-mapping.md +163 -0
- package/skills/ct-task-executor/references/anti-patterns.md +201 -0
- package/skills/ct-task-executor/references/common-failures.md +193 -0
- package/skills/ct-task-executor/references/evidence-and-gates.md +179 -0
- package/skills/ct-task-executor/references/implementation-patterns.md +160 -0
- package/skills/ct-validator/SKILL.md +44 -0
- package/skills/ct-validator/references/anti-patterns.md +194 -0
- package/skills/ct-validator/references/compliance-reports.md +199 -0
- package/skills/ct-validator/references/schema-checking.md +191 -0
- package/skills/ct-validator/references/validation-modes.md +185 -0
- package/skills/manifest.json +82 -16
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Anti-Patterns
|
|
2
|
+
|
|
3
|
+
Common failure modes when running validation tasks. These degrade the
|
|
4
|
+
report's usefulness, break downstream consumers, or mask defects. Avoid
|
|
5
|
+
them by following the detection cue and the remediation.
|
|
6
|
+
|
|
7
|
+
## 1. The Short-Circuit Validator
|
|
8
|
+
|
|
9
|
+
**Symptom.** Validator stops on the first failure and reports only that
|
|
10
|
+
one. The report claims "FAIL" but lists only one issue when there are
|
|
11
|
+
several.
|
|
12
|
+
|
|
13
|
+
**Detection cue.** Issue count is exactly 1 but the underlying tool
|
|
14
|
+
(biome, tsc, jsonschema) has multi-issue output.
|
|
15
|
+
|
|
16
|
+
**Root cause.** Engine was run without `--all-errors` (AJV),
|
|
17
|
+
`--exhaustive`, or equivalent. Or a try/catch wrapped the validation
|
|
18
|
+
and bailed on first throw.
|
|
19
|
+
|
|
20
|
+
**Fix.** Always pass the all-errors flag. For Zod, use `safeParse` and
|
|
21
|
+
collect every issue from `result.error.issues`. For TypeScript, use
|
|
22
|
+
`tsc -b --pretty false` and capture every line.
|
|
23
|
+
|
|
24
|
+
## 2. The Soft Pass
|
|
25
|
+
|
|
26
|
+
**Symptom.** Report status is `PASS` but the target has known
|
|
27
|
+
unaddressed warnings.
|
|
28
|
+
|
|
29
|
+
**Detection cue.** Findings table contains entries; status is PASS.
|
|
30
|
+
|
|
31
|
+
**Root cause.** Status calculus violation — PASS requires zero
|
|
32
|
+
critical AND ≤2 warnings (per `compliance-reports.md`). Warnings
|
|
33
|
+
above threshold demote to PARTIAL.
|
|
34
|
+
|
|
35
|
+
**Fix.** Apply the status calculus mechanically. PASS only when the
|
|
36
|
+
table is empty (or warnings ≤2). When in doubt, demote.
|
|
37
|
+
|
|
38
|
+
## 3. The Unreproducible Report
|
|
39
|
+
|
|
40
|
+
**Symptom.** Six weeks later, someone tries to re-validate the same
|
|
41
|
+
target. The report's claims cannot be verified.
|
|
42
|
+
|
|
43
|
+
**Detection cue.** Report has no `## Trace` section or the Trace lists
|
|
44
|
+
no reproducer command.
|
|
45
|
+
|
|
46
|
+
**Root cause.** Reporter forgot to record the command sequence and
|
|
47
|
+
tool versions used.
|
|
48
|
+
|
|
49
|
+
**Fix.** Always include the reproducer. The Trace section is mandatory
|
|
50
|
+
per the canonical scaffold.
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
## Trace
|
|
54
|
+
|
|
55
|
+
- Target: packages/cleo/src/release.ts (at 5608f75cd)
|
|
56
|
+
- Tooling: biome@2.4.11, tsc@5.6.0, pnpm@9.x
|
|
57
|
+
- Reproducer:
|
|
58
|
+
pnpm biome check packages/cleo/src/release.ts && \
|
|
59
|
+
pnpm exec tsc -b packages/cleo --pretty false
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 4. The Mode Confusion
|
|
63
|
+
|
|
64
|
+
**Symptom.** A Document-mode report applies Code-mode rules, or
|
|
65
|
+
vice-versa.
|
|
66
|
+
|
|
67
|
+
**Detection cue.** Findings about TypeScript strictness in a spec
|
|
68
|
+
review; findings about RFC 2119 in a code lint.
|
|
69
|
+
|
|
70
|
+
**Root cause.** Mode was not made explicit at the start; the validator
|
|
71
|
+
defaulted to its strongest familiarity.
|
|
72
|
+
|
|
73
|
+
**Fix.** Declare mode in the report header. The spawn prompt or task
|
|
74
|
+
body MUST set it; if absent, ask the orchestrator to clarify before
|
|
75
|
+
proceeding.
|
|
76
|
+
|
|
77
|
+
## 5. The Missing Severity
|
|
78
|
+
|
|
79
|
+
**Symptom.** Findings listed but consumer cannot prioritize.
|
|
80
|
+
|
|
81
|
+
**Detection cue.** Findings without `Critical | Warning | Suggestion`
|
|
82
|
+
classification.
|
|
83
|
+
|
|
84
|
+
**Root cause.** Reporter treated all findings as equal.
|
|
85
|
+
|
|
86
|
+
**Fix.** Every finding MUST carry severity. When unclear, apply the
|
|
87
|
+
"blocks ship?" test: yes → Critical; no → Warning; "nice to have" →
|
|
88
|
+
Suggestion.
|
|
89
|
+
|
|
90
|
+
## 6. The Vague Remediation
|
|
91
|
+
|
|
92
|
+
**Symptom.** Issue says "fix this". Reader does not know how.
|
|
93
|
+
|
|
94
|
+
**Detection cue.** `Fix:` line is missing or contains only "see above"
|
|
95
|
+
/ "obvious from context" / "fix the issue".
|
|
96
|
+
|
|
97
|
+
**Root cause.** Reporter ran out of energy by the time they got to
|
|
98
|
+
the fix column.
|
|
99
|
+
|
|
100
|
+
**Fix.** Every finding has a concrete fix step. If the fix requires
|
|
101
|
+
discussion (architectural change), state that — but specifically:
|
|
102
|
+
"file a task to redesign the credential rotation flow; reference
|
|
103
|
+
ADR-XX-NEW once it lands".
|
|
104
|
+
|
|
105
|
+
## 7. The Phantom Test
|
|
106
|
+
|
|
107
|
+
**Symptom.** Protocol mode report claims REQ-NNN is verified by
|
|
108
|
+
`test/foo.test.ts::case-name`. The test does not exist.
|
|
109
|
+
|
|
110
|
+
**Detection cue.** Reproducer command fails with "no such test".
|
|
111
|
+
|
|
112
|
+
**Root cause.** Reporter copied the spec's traceability matrix without
|
|
113
|
+
re-checking that the named tests still exist (or ever existed).
|
|
114
|
+
|
|
115
|
+
**Fix.** Re-run each verification command from the traceability
|
|
116
|
+
matrix during validation. Flag REQs whose verification fails to
|
|
117
|
+
resolve as Critical findings — the spec drifted from the implementation.
|
|
118
|
+
|
|
119
|
+
## 8. The Single-File Tunnel
|
|
120
|
+
|
|
121
|
+
**Symptom.** Code-mode validation runs only on the file that was
|
|
122
|
+
explicitly named. Misses related files that share the violation.
|
|
123
|
+
|
|
124
|
+
**Detection cue.** Report has findings in `release.ts` only; the
|
|
125
|
+
same issue exists in 5 sibling files that were not checked.
|
|
126
|
+
|
|
127
|
+
**Root cause.** Reporter took the task literally instead of the
|
|
128
|
+
useful scope.
|
|
129
|
+
|
|
130
|
+
**Fix.** Apply the validation to all related files when feasible —
|
|
131
|
+
"the diff" usually means "all files touched by the task branch", not
|
|
132
|
+
"only the one file the orchestrator mentioned".
|
|
133
|
+
|
|
134
|
+
## 9. The Stale Schema
|
|
135
|
+
|
|
136
|
+
**Symptom.** Schema-mode validation passes but downstream consumers
|
|
137
|
+
still reject the data.
|
|
138
|
+
|
|
139
|
+
**Detection cue.** Schema version pinned in the report does not match
|
|
140
|
+
the producer's contract.
|
|
141
|
+
|
|
142
|
+
**Root cause.** Schema was updated upstream; validator used a cached
|
|
143
|
+
or pinned older version.
|
|
144
|
+
|
|
145
|
+
**Fix.** Always resolve the schema fresh from the contract source
|
|
146
|
+
(`@cleocode/contracts`). Pin the consumer/producer relationship in
|
|
147
|
+
the schema's `$id` and `version` fields and check both.
|
|
148
|
+
|
|
149
|
+
## 10. The Disposable Sidecar
|
|
150
|
+
|
|
151
|
+
**Symptom.** JSON sidecar emitted, but it has different findings than
|
|
152
|
+
the markdown report.
|
|
153
|
+
|
|
154
|
+
**Detection cue.** `diff <(md-extract-findings report.md)
|
|
155
|
+
<(jq '.findings' report.json)` shows mismatched data.
|
|
156
|
+
|
|
157
|
+
**Root cause.** Reporter wrote the markdown manually and the JSON
|
|
158
|
+
separately; they drifted.
|
|
159
|
+
|
|
160
|
+
**Fix.** Generate one from the other. Write the structured data first
|
|
161
|
+
(JSON), then render the markdown from it. A `--render-md` flag on the
|
|
162
|
+
report generator enforces this.
|
|
163
|
+
|
|
164
|
+
## 11. The Unsourced Rule
|
|
165
|
+
|
|
166
|
+
**Symptom.** A finding cites a rule that does not exist in any visible
|
|
167
|
+
standard.
|
|
168
|
+
|
|
169
|
+
**Detection cue.** Rule reference is prose ("naming should be
|
|
170
|
+
consistent") rather than a stable identifier ("AGENTS.md §Package
|
|
171
|
+
Boundary").
|
|
172
|
+
|
|
173
|
+
**Root cause.** Reporter applied a personal preference and labeled
|
|
174
|
+
it as a rule.
|
|
175
|
+
|
|
176
|
+
**Fix.** Every rule citation MUST link to a stable source:
|
|
177
|
+
`AGENTS.md §X`, `ADR-NNN`, `biome.json#rules.style.Y`. If the
|
|
178
|
+
preference is real but unwritten, the report SHOULD propose adding
|
|
179
|
+
it to the standard (file a task) rather than enforcing it silently.
|
|
180
|
+
|
|
181
|
+
## 12. The Pre-Empty Report
|
|
182
|
+
|
|
183
|
+
**Symptom.** Validator runs against an empty or absent target, reports
|
|
184
|
+
`PASS`.
|
|
185
|
+
|
|
186
|
+
**Detection cue.** Target file is empty or does not exist; report says
|
|
187
|
+
"100% compliance".
|
|
188
|
+
|
|
189
|
+
**Root cause.** Engine returned zero violations because there was
|
|
190
|
+
nothing to violate.
|
|
191
|
+
|
|
192
|
+
**Fix.** Always sanity-check the target exists and has content before
|
|
193
|
+
running validation. Empty/missing target is itself a Critical finding —
|
|
194
|
+
not a clean pass.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Compliance Reports
|
|
2
|
+
|
|
3
|
+
The shape, severity calculus, and downstream consumption of the
|
|
4
|
+
validation report. The report is the validator's product — its format
|
|
5
|
+
is rigid because `ct-ivt-looper`, `ct-release-orchestrator`, and HITL
|
|
6
|
+
gates all parse it.
|
|
7
|
+
|
|
8
|
+
## Canonical Report Scaffold
|
|
9
|
+
|
|
10
|
+
Every report MUST use this structure. Sections are mandatory; their
|
|
11
|
+
content varies by mode.
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
# Validation Report: {{VALIDATION_TARGET}}
|
|
15
|
+
|
|
16
|
+
**Mode**: schema | code | document | protocol
|
|
17
|
+
**Date**: {{DATE}}
|
|
18
|
+
**Validator**: ct-validator v2.0.0
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
- **Status**: PASS | PARTIAL | FAIL
|
|
25
|
+
- **Compliance**: {X}%
|
|
26
|
+
- **Critical Issues**: {N}
|
|
27
|
+
- **Warnings**: {N}
|
|
28
|
+
- **Suggestions**: {N}
|
|
29
|
+
|
|
30
|
+
## Checklist Results
|
|
31
|
+
|
|
32
|
+
| Check | Status | Details |
|
|
33
|
+
|-------|--------|---------|
|
|
34
|
+
| {CHECK_1} | PASS/FAIL | {Details} |
|
|
35
|
+
| {CHECK_2} | PASS/FAIL | {Details} |
|
|
36
|
+
|
|
37
|
+
## Issues Found
|
|
38
|
+
|
|
39
|
+
### Critical
|
|
40
|
+
{List or "None"}
|
|
41
|
+
|
|
42
|
+
### Warnings
|
|
43
|
+
{List or "None"}
|
|
44
|
+
|
|
45
|
+
### Suggestions
|
|
46
|
+
{List or "None"}
|
|
47
|
+
|
|
48
|
+
## Remediation
|
|
49
|
+
|
|
50
|
+
{Required fixes if FAIL/PARTIAL, or "No remediation required" if PASS}
|
|
51
|
+
|
|
52
|
+
## Trace
|
|
53
|
+
|
|
54
|
+
- Target: {file/spec/diff path}
|
|
55
|
+
- Tooling: {versions of tools run}
|
|
56
|
+
- Reproducer: {one command that re-runs this report}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The Trace section is essential — without a reproducer, the report
|
|
60
|
+
cannot be re-run later to confirm a remediation worked.
|
|
61
|
+
|
|
62
|
+
## Status Calculus
|
|
63
|
+
|
|
64
|
+
| Mode | PASS | PARTIAL | FAIL |
|
|
65
|
+
|------|------|---------|------|
|
|
66
|
+
| Schema | 0 violations | (n/a) | ≥1 violation |
|
|
67
|
+
| Code | 0 critical, ≤2 warnings | 0 critical, 3+ warnings | ≥1 critical |
|
|
68
|
+
| Document | All required sections present, 0 broken links | 1-2 missing sections | 3+ missing sections OR broken refs |
|
|
69
|
+
| Protocol | 100% REQ compliance | 70-99% compliance | <70% compliance |
|
|
70
|
+
|
|
71
|
+
The status is not a vote — it is a computed function of the findings.
|
|
72
|
+
Two validators running on the same target MUST produce the same
|
|
73
|
+
status.
|
|
74
|
+
|
|
75
|
+
PARTIAL is reserved for cases where the target is shippable WITH
|
|
76
|
+
recorded remediation; FAIL means the target cannot ship as-is.
|
|
77
|
+
|
|
78
|
+
## Severity Definitions
|
|
79
|
+
|
|
80
|
+
| Severity | Meaning | Examples |
|
|
81
|
+
|----------|---------|----------|
|
|
82
|
+
| Critical | Blocks ship; data corruption, security, AGENTS.md rejection | `any` type, missing required field, broken link in spec |
|
|
83
|
+
| Warning | Should fix soon; degrades quality but does not block | Long body, unused import, missing optional section |
|
|
84
|
+
| Suggestion | Improvement opportunity; no obligation | Extract helper, rename for clarity |
|
|
85
|
+
|
|
86
|
+
Each finding MUST carry a severity. Findings without severity are
|
|
87
|
+
unactionable — the consumer cannot prioritize.
|
|
88
|
+
|
|
89
|
+
## Per-Finding Format
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
### Critical
|
|
93
|
+
|
|
94
|
+
**C-001**: `packages/cleo/src/dispatch.ts:42` uses `any` type.
|
|
95
|
+
- Rule: AGENTS.md Type Safety §1 — "NEVER use `any` type"
|
|
96
|
+
- Fix: Import the relevant type from `@cleocode/contracts` or
|
|
97
|
+
define a narrower union.
|
|
98
|
+
- Verification: `pnpm biome check packages/cleo/src/dispatch.ts`
|
|
99
|
+
|
|
100
|
+
**C-002**: `packages/cleo/src/release.ts:107` catches `err: unknown`.
|
|
101
|
+
- Rule: AGENTS.md Type Safety §5 — "NEVER use `catch (err: unknown)`"
|
|
102
|
+
- Fix: Throw and catch by class from `@cleocode/contracts/errors`.
|
|
103
|
+
- Verification: Replace with `catch (err)` and pattern-match by
|
|
104
|
+
`instanceof`.
|
|
105
|
+
|
|
106
|
+
### Warnings
|
|
107
|
+
|
|
108
|
+
**W-001**: `packages/cleo/src/dispatch.ts` is 487 lines (warn at 400).
|
|
109
|
+
- Rule: ct-skill-validator audit_body §body-length
|
|
110
|
+
- Fix: Extract sub-handlers into sibling files.
|
|
111
|
+
- Verification: re-run audit_body.py.
|
|
112
|
+
|
|
113
|
+
### Suggestions
|
|
114
|
+
|
|
115
|
+
**S-001**: `packages/cleo/src/dispatch.ts:120` has a TODO with no task ID.
|
|
116
|
+
- Rule: Internal — TODOs should reference task IDs.
|
|
117
|
+
- Fix: File a task, attach the ID: `// TODO(T9999): ...`.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Each finding gets a stable ID (`C-NNN`, `W-NNN`, `S-NNN`) so subsequent
|
|
121
|
+
reports can reference whether the same issue persists.
|
|
122
|
+
|
|
123
|
+
## Compliance Percentage
|
|
124
|
+
|
|
125
|
+
For modes that report a percentage:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
compliance = (passed_checks / total_checks) × 100
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Round to one decimal. For Protocol mode (REQ compliance), checks are
|
|
132
|
+
the REQs in the spec's traceability matrix. For Schema mode, "checks"
|
|
133
|
+
is the count of constraints evaluated.
|
|
134
|
+
|
|
135
|
+
When the denominator is zero (e.g., a spec with no REQs), the
|
|
136
|
+
percentage is undefined — emit `N/A` and report a Critical finding for
|
|
137
|
+
the empty spec.
|
|
138
|
+
|
|
139
|
+
## Integration with ct-ivt-looper
|
|
140
|
+
|
|
141
|
+
The IVT loop reads the validator's `status` and `compliance` fields
|
|
142
|
+
to decide whether to continue iterating. The contract:
|
|
143
|
+
|
|
144
|
+
- `status: PASS` → IVT loop converges; release-orchestrator may proceed.
|
|
145
|
+
- `status: PARTIAL` → IVT loop loops once more with the remediation as
|
|
146
|
+
input; if still PARTIAL on iteration 3, escalates to HITL.
|
|
147
|
+
- `status: FAIL` → IVT loop blocks; release-orchestrator MUST not
|
|
148
|
+
proceed; HITL escalation immediate.
|
|
149
|
+
|
|
150
|
+
This contract is the reason status calculus is rigid — fuzzy statuses
|
|
151
|
+
break the loop's termination conditions.
|
|
152
|
+
|
|
153
|
+
## Integration with Release
|
|
154
|
+
|
|
155
|
+
`ct-release-orchestrator` reads the most recent validation report
|
|
156
|
+
for the epic before allowing ship. The release pipeline (ADR-065)
|
|
157
|
+
contains a gate that asserts `status: PASS` on the implementation
|
|
158
|
+
against the spec. PARTIAL reports trigger a recorded remediation
|
|
159
|
+
plan; FAIL reports block.
|
|
160
|
+
|
|
161
|
+
## Machine-Readable Sidecar
|
|
162
|
+
|
|
163
|
+
Always emit a JSON sidecar next to the markdown report:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"target": "packages/cleo/src/release.ts",
|
|
168
|
+
"mode": "code",
|
|
169
|
+
"status": "FAIL",
|
|
170
|
+
"compliance": 88.5,
|
|
171
|
+
"findings": {
|
|
172
|
+
"critical": [
|
|
173
|
+
{"id": "C-001", "file": "...", "line": 42, "rule": "...", "fix": "..."},
|
|
174
|
+
{"id": "C-002", "file": "...", "line": 107, "rule": "...", "fix": "..."}
|
|
175
|
+
],
|
|
176
|
+
"warnings": [...],
|
|
177
|
+
"suggestions": [...]
|
|
178
|
+
},
|
|
179
|
+
"trace": {
|
|
180
|
+
"tooling": ["biome@2.4.11", "tsc@5.6.0"],
|
|
181
|
+
"reproducer": "pnpm biome check . && pnpm exec tsc -b",
|
|
182
|
+
"timestamp": "2026-05-19T19:35:00Z"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The orchestrator parses this when programmatic decisions are needed;
|
|
188
|
+
the human report (.md) is for review.
|
|
189
|
+
|
|
190
|
+
## Anti-Patterns
|
|
191
|
+
|
|
192
|
+
| Anti-pattern | Why it fails |
|
|
193
|
+
|--------------|--------------|
|
|
194
|
+
| Vague finding ("file looks weird") | Cannot remediate |
|
|
195
|
+
| Missing severity | Consumer cannot prioritize |
|
|
196
|
+
| No reproducer in trace | Cannot re-validate after fix |
|
|
197
|
+
| PARTIAL with no remediation plan | Status calculus violation |
|
|
198
|
+
| Findings without rule reference | Disputable, not actionable |
|
|
199
|
+
| Markdown only, no JSON sidecar | Breaks orchestrator integration |
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Schema Checking
|
|
2
|
+
|
|
3
|
+
Deeper guidance for Schema Validation mode (Mode 1 from
|
|
4
|
+
`validation-modes.md`). Schema checking is the most mechanical of the
|
|
5
|
+
four modes — but only if the inputs are correctly configured. This
|
|
6
|
+
reference covers the configuration pitfalls and tool-selection rules.
|
|
7
|
+
|
|
8
|
+
## Pick the Right Engine
|
|
9
|
+
|
|
10
|
+
| Engine | Strength | When to use |
|
|
11
|
+
|--------|----------|-------------|
|
|
12
|
+
| AJV (`ajv-cli`) | Fast; draft-07 / 2019-09 / 2020-12 | Generic JSON Schema validation |
|
|
13
|
+
| Zod | Type-safe; integrates with TypeScript | Project-internal data validation |
|
|
14
|
+
| drizzle-orm/zod | Schema → Zod auto-generation | Drizzle ORM consumers |
|
|
15
|
+
| jsonschema (Python) | Cross-language; same draft support | Python-side validation |
|
|
16
|
+
| `cargo schema` / serde | Type-safe; Rust-side | Rust crates |
|
|
17
|
+
|
|
18
|
+
The CLEO repo's primary engine is Zod (via `@cleocode/contracts`) — most
|
|
19
|
+
internal schemas are exported as Zod schemas with optional drizzle
|
|
20
|
+
codegen. Use Zod's `safeParse` to get structured errors.
|
|
21
|
+
|
|
22
|
+
For external contracts (LAFS envelope spec, JSON-RPC requests from
|
|
23
|
+
non-CLEO clients), use AJV or jsonschema for cross-language portability.
|
|
24
|
+
|
|
25
|
+
## Draft Selection
|
|
26
|
+
|
|
27
|
+
Always state the draft explicitly. Draft-07 and draft-2020-12 have
|
|
28
|
+
incompatible semantics around `$ref`, `if/then/else`, and tuple arrays.
|
|
29
|
+
|
|
30
|
+
| Draft | Best for | Caveats |
|
|
31
|
+
|-------|----------|---------|
|
|
32
|
+
| draft-04 | Legacy | `id` not `$id`; many engines deprecated this |
|
|
33
|
+
| draft-07 | Industry standard | Most engines support fully |
|
|
34
|
+
| draft-2019-09 | New work, conservative | `$defs` replaces `definitions` |
|
|
35
|
+
| draft-2020-12 | New work, full | Some engines lag |
|
|
36
|
+
|
|
37
|
+
CLEO contracts target draft-07 unless the schema needs 2020-12-only
|
|
38
|
+
features (typically `prefixItems` for tuple arrays). Add the explicit
|
|
39
|
+
`"$schema"` field on every published schema:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
44
|
+
"title": "TaskEnvelope",
|
|
45
|
+
"type": "object",
|
|
46
|
+
"required": ["success", "meta"],
|
|
47
|
+
...
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The Standard Validation Loop
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 1. Choose engine; choose draft
|
|
55
|
+
ENGINE=ajv
|
|
56
|
+
DRAFT=draft-07
|
|
57
|
+
|
|
58
|
+
# 2. Resolve schema file (must include $schema or pass --spec)
|
|
59
|
+
SCHEMA=packages/contracts/schemas/envelope.json
|
|
60
|
+
|
|
61
|
+
# 3. Iterate over data files
|
|
62
|
+
for DATA in path/to/*.json; do
|
|
63
|
+
echo "=== $DATA ==="
|
|
64
|
+
npx ajv validate -s "$SCHEMA" -d "$DATA" --spec=$DRAFT --all-errors
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
# 4. Aggregate by file in the report
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The `--all-errors` flag (AJV) or `--exhaustive` (Zod's `safeParse` does
|
|
71
|
+
this by default) is essential — the spec ground rule is "report every
|
|
72
|
+
violation", not "stop at the first one".
|
|
73
|
+
|
|
74
|
+
## Pitfalls
|
|
75
|
+
|
|
76
|
+
### 1. $ref Resolution Failure
|
|
77
|
+
|
|
78
|
+
**Symptom.** Validator complains "could not resolve $ref" or "unknown
|
|
79
|
+
keyword $ref".
|
|
80
|
+
|
|
81
|
+
**Cause.** Schema references another file by relative path; the engine
|
|
82
|
+
does not know the base directory.
|
|
83
|
+
|
|
84
|
+
**Fix.** Pass `--ref` (AJV) pointing at the referenced files, or inline
|
|
85
|
+
the references with `$defs`. For multi-file schemas, use AJV's
|
|
86
|
+
`addSchema()` API or a bundler step that flattens before validation.
|
|
87
|
+
|
|
88
|
+
### 2. Implicit Type Coercion
|
|
89
|
+
|
|
90
|
+
**Symptom.** A string `"123"` validates against `{"type": "number"}`.
|
|
91
|
+
|
|
92
|
+
**Cause.** Engine has coercion enabled (`coerceTypes: true` in AJV).
|
|
93
|
+
|
|
94
|
+
**Fix.** Disable coercion for strict validation:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
new Ajv({ coerceTypes: false, strict: true, allErrors: true })
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
CLEO contracts are strict by default — incoming data must already be
|
|
101
|
+
typed correctly.
|
|
102
|
+
|
|
103
|
+
### 3. Missing required not flagged
|
|
104
|
+
|
|
105
|
+
**Symptom.** A required field is missing; schema says it's required;
|
|
106
|
+
validator passes.
|
|
107
|
+
|
|
108
|
+
**Cause.** The schema's `required` is at the wrong level (nested vs
|
|
109
|
+
top), or the validator is in non-strict mode.
|
|
110
|
+
|
|
111
|
+
**Fix.** Re-check the schema structure. `required` must be a peer of
|
|
112
|
+
`properties` at the same nesting level.
|
|
113
|
+
|
|
114
|
+
### 4. Additional Properties Silently Allowed
|
|
115
|
+
|
|
116
|
+
**Symptom.** Data has extra fields not in the schema; validator passes.
|
|
117
|
+
|
|
118
|
+
**Cause.** Schema does not specify `additionalProperties: false`.
|
|
119
|
+
|
|
120
|
+
**Fix.** CLEO contracts default to `additionalProperties: false` — extra
|
|
121
|
+
fields indicate either drift in the producer or a malicious payload.
|
|
122
|
+
Override only with an inline justification.
|
|
123
|
+
|
|
124
|
+
## Reporting Schema Violations
|
|
125
|
+
|
|
126
|
+
Each violation goes in the report as:
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
### Violations
|
|
130
|
+
|
|
131
|
+
| Path | Keyword | Actual | Expected | File |
|
|
132
|
+
|------|---------|--------|----------|------|
|
|
133
|
+
| `/data/items/3/id` | required | (absent) | string | manifest-instance.json |
|
|
134
|
+
| `/data/version` | type | "1.2.3" (string) | number | manifest-instance.json |
|
|
135
|
+
| `/meta/timestamp` | format | "today" | date-time | manifest-instance.json |
|
|
136
|
+
| `/error.code` | enum | "E_WUT" | one of [E_NOT_FOUND, E_VALIDATION, ...] | response.json |
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The Path column uses JSON Pointer (RFC 6901). The Keyword column names
|
|
140
|
+
the schema constraint violated. Actual + Expected gives the diff
|
|
141
|
+
needed to fix.
|
|
142
|
+
|
|
143
|
+
## Bulk Schema Validation
|
|
144
|
+
|
|
145
|
+
When validating many instances (e.g., every manifest file in
|
|
146
|
+
`.cleo/agent-outputs/`), produce a summary table first, then drill
|
|
147
|
+
into failures.
|
|
148
|
+
|
|
149
|
+
```markdown
|
|
150
|
+
## Summary
|
|
151
|
+
|
|
152
|
+
- **Files validated**: 47
|
|
153
|
+
- **Pass**: 42
|
|
154
|
+
- **Fail**: 5
|
|
155
|
+
- **Compliance**: 89.4%
|
|
156
|
+
|
|
157
|
+
## Failed Files
|
|
158
|
+
|
|
159
|
+
| File | Violations |
|
|
160
|
+
|------|-----------|
|
|
161
|
+
| `.cleo/agent-outputs/2026-05-19_old.md` | 3 |
|
|
162
|
+
| `.cleo/agent-outputs/2026-05-19_draft.md` | 1 |
|
|
163
|
+
| ... | ... |
|
|
164
|
+
|
|
165
|
+
## Detail (per-file)
|
|
166
|
+
|
|
167
|
+
### `.cleo/agent-outputs/2026-05-19_old.md`
|
|
168
|
+
|
|
169
|
+
| Path | Keyword | Actual | Expected |
|
|
170
|
+
|------|---------|--------|----------|
|
|
171
|
+
| ... | ... | ... | ... |
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Bulk reports SHOULD be machine-readable. Emit a sibling JSON report
|
|
175
|
+
under the same name when the consumer is automation.
|
|
176
|
+
|
|
177
|
+
## Self-Test the Schema
|
|
178
|
+
|
|
179
|
+
Before trusting any schema for validation, verify it accepts known-good
|
|
180
|
+
instances and rejects known-bad instances. Maintain a `fixtures/`
|
|
181
|
+
directory next to the schema:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
packages/contracts/schemas/envelope.json
|
|
185
|
+
packages/contracts/schemas/fixtures/envelope-valid.json
|
|
186
|
+
packages/contracts/schemas/fixtures/envelope-missing-success.json
|
|
187
|
+
packages/contracts/schemas/fixtures/envelope-wrong-type.json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
A test that exercises all three confirms the schema does what it
|
|
191
|
+
claims. Without fixtures, schema drift goes undetected.
|