@orderful/droid 0.54.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +2 -0
- package/CHANGELOG.md +6 -0
- package/dist/tools/test-blueprints/.claude-plugin/plugin.json +22 -0
- package/dist/tools/test-blueprints/TOOL.yaml +22 -0
- package/dist/tools/test-blueprints/commands/test-blueprints.md +27 -0
- package/dist/tools/test-blueprints/skills/test-blueprints/SKILL.md +160 -0
- package/dist/tools/test-blueprints/skills/test-blueprints/references/codebase-paths.md +79 -0
- package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.d.ts +28 -0
- package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.d.ts.map +1 -0
- package/dist/tools/test-blueprints/skills/test-blueprints/scripts/validate.ts +250 -0
- package/package.json +1 -1
- package/src/tools/test-blueprints/.claude-plugin/plugin.json +22 -0
- package/src/tools/test-blueprints/TOOL.yaml +22 -0
- package/src/tools/test-blueprints/commands/test-blueprints.md +27 -0
- package/src/tools/test-blueprints/skills/test-blueprints/SKILL.md +160 -0
- package/src/tools/test-blueprints/skills/test-blueprints/references/codebase-paths.md +79 -0
- package/src/tools/test-blueprints/skills/test-blueprints/scripts/validate.ts +250 -0
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"./src/tools/share/skills/share/SKILL.md",
|
|
34
34
|
"./src/tools/status-update/skills/status-update/SKILL.md",
|
|
35
35
|
"./src/tools/tech-design/skills/tech-design/SKILL.md",
|
|
36
|
+
"./src/tools/test-blueprints/skills/test-blueprints/SKILL.md",
|
|
36
37
|
"./src/tools/webform/skills/webform/SKILL.md",
|
|
37
38
|
"./src/tools/wrapup/skills/wrapup/SKILL.md"
|
|
38
39
|
],
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"./src/tools/share/commands/share.md",
|
|
54
55
|
"./src/tools/status-update/commands/status-update.md",
|
|
55
56
|
"./src/tools/tech-design/commands/tech-design.md",
|
|
57
|
+
"./src/tools/test-blueprints/commands/test-blueprints.md",
|
|
56
58
|
"./src/tools/webform/commands/webform.md",
|
|
57
59
|
"./src/tools/wrapup/commands/wrapup.md"
|
|
58
60
|
],
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @orderful/droid
|
|
2
2
|
|
|
3
|
+
## 0.55.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#330](https://github.com/Orderful/droid/pull/330) [`490323a`](https://github.com/Orderful/droid/commit/490323a23b49a420ebbbc5a02cb021afb1387d29) Thanks [@DenisSa](https://github.com/DenisSa)! - Add test-blueprints tool for writing and verifying EDI test blueprint HBS templates
|
|
8
|
+
|
|
3
9
|
## 0.54.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "droid-test-blueprints",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Write and verify test blueprint HBS templates for EDI transaction types. Automates scenario design, template creation, registration, and Zod schema validation.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Orderful",
|
|
7
|
+
"url": "https://github.com/orderful"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/orderful/droid",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"droid",
|
|
13
|
+
"ai",
|
|
14
|
+
"test-blueprints"
|
|
15
|
+
],
|
|
16
|
+
"skills": [
|
|
17
|
+
"./skills/test-blueprints/SKILL.md"
|
|
18
|
+
],
|
|
19
|
+
"commands": [
|
|
20
|
+
"./commands/test-blueprints.md"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: test-blueprints
|
|
2
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types. Automates scenario design, template creation, registration, and Zod schema validation."
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
status: beta
|
|
5
|
+
audience:
|
|
6
|
+
- engineering
|
|
7
|
+
|
|
8
|
+
includes:
|
|
9
|
+
skills:
|
|
10
|
+
- name: test-blueprints
|
|
11
|
+
required: true
|
|
12
|
+
commands:
|
|
13
|
+
- name: test-blueprints
|
|
14
|
+
is_alias: false
|
|
15
|
+
agents: []
|
|
16
|
+
|
|
17
|
+
dependencies: []
|
|
18
|
+
|
|
19
|
+
prerequisites:
|
|
20
|
+
- "ts-node and tsconfig-paths must be available in the target workspace (used by the validate script)"
|
|
21
|
+
|
|
22
|
+
config_schema: {}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-blueprints
|
|
3
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types."
|
|
4
|
+
argument-hint: "[write {type} | verify {type}]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /test-blueprints
|
|
8
|
+
|
|
9
|
+
**User invoked:** `/test-blueprints $ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
**Your task:** Invoke the **test-blueprints skill** with these arguments.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
- `/test-blueprints write 943`
|
|
16
|
+
- `/test-blueprints verify 943`
|
|
17
|
+
- `/test-blueprints 944`
|
|
18
|
+
|
|
19
|
+
## Quick Reference
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
/test-blueprints write {type} # Full create flow: schema → scenarios → templates → register → validate
|
|
23
|
+
/test-blueprints verify {type} # Validate existing blueprints against Zod schema
|
|
24
|
+
/test-blueprints {type} # Alias for write {type}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
See the **test-blueprints skill** for full behaviour and validation rules.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-blueprints
|
|
3
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types. Use when creating test scenarios for a new transaction type (e.g., 'create blueprints for 943'), verifying existing blueprints against their Zod schema (e.g., 'verify 943 blueprints', 'validate the 855 templates'), or adding test blueprints to the testTransformation module. User prompts like 'create test blueprints for 940', 'generate 944 test templates', 'verify 943 blueprints', 'validate the 855 templates', 'check if 944 blueprints are valid'."
|
|
4
|
+
argument-hint: "[write {type} | verify {type}]"
|
|
5
|
+
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Test Blueprints Skill
|
|
9
|
+
|
|
10
|
+
Write and verify test blueprint HBS templates for EDI transaction types in the Orderful platform. Each blueprint is a JSON file conforming to the transaction type's simplified Zod schema, representing a distinct business scenario.
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
| Command | Action |
|
|
15
|
+
|---------|--------|
|
|
16
|
+
| `/test-blueprints write {type}` | Full workflow: discover schema, design scenarios, create templates, register, validate |
|
|
17
|
+
| `/test-blueprints verify {type}` | Validate existing blueprints against the Zod schema and report results |
|
|
18
|
+
| `/test-blueprints {type}` | Alias for `write {type}` |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Command: verify
|
|
23
|
+
|
|
24
|
+
Validate existing blueprint templates against their Zod schema. Use this to check that all templates for a transaction type are still valid after schema changes, or to spot-check templates at any time.
|
|
25
|
+
|
|
26
|
+
### Steps
|
|
27
|
+
|
|
28
|
+
1. **Locate files.** Read `references/codebase-paths.md` for exact paths.
|
|
29
|
+
- Find the Zod schema for the transaction type
|
|
30
|
+
- Find the blueprint directory (`testBlueprints/{type}s/`)
|
|
31
|
+
- If no blueprints exist for the type, report that and stop
|
|
32
|
+
|
|
33
|
+
2. **Read the Zod schema** to determine the schema export name and import path.
|
|
34
|
+
|
|
35
|
+
3. **Run the validation script:**
|
|
36
|
+
```bash
|
|
37
|
+
droid exec test-blueprints validate \
|
|
38
|
+
--workspace {workspace-root} \
|
|
39
|
+
--schema-import "{import-path}" \
|
|
40
|
+
--schema-name "{SchemaExportName}" \
|
|
41
|
+
--blueprints-dir "{path-to-blueprints-dir}"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The script automatically:
|
|
45
|
+
- Discovers all `.json.hbs` files in the blueprints directory
|
|
46
|
+
- Skips templates containing Handlebars expressions (validated at render time, not statically)
|
|
47
|
+
- Validates remaining templates against the Zod schema via ts-node
|
|
48
|
+
- Returns structured JSON with per-file pass/fail/skip results
|
|
49
|
+
|
|
50
|
+
4. **Report results.** Parse the JSON output and show a summary table:
|
|
51
|
+
- PASS / FAIL / SKIP status per template
|
|
52
|
+
- For failures: the exact field path and error message
|
|
53
|
+
- Suggest fixes for common mistakes (see Common Validation Pitfalls below)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Command: write
|
|
58
|
+
|
|
59
|
+
Full workflow to create test blueprint templates for a transaction type.
|
|
60
|
+
|
|
61
|
+
### Phase 1: Discovery
|
|
62
|
+
|
|
63
|
+
Identify the transaction type and locate the required files. Read `references/codebase-paths.md` for exact paths.
|
|
64
|
+
|
|
65
|
+
1. **Find the Zod schema** for the transaction type. This is the source of truth for the template shape. Read it fully - every field, every enum value, every `metaEnum` definition. Also read `shared.zod.ts` for all imported shared types and their enum values.
|
|
66
|
+
|
|
67
|
+
2. **Find the example JSON** (if one exists) in the simplified schema examples directory. This shows realistic field values.
|
|
68
|
+
|
|
69
|
+
3. **Check TransactionTypeName** to confirm the enum key exists (e.g., `T943`).
|
|
70
|
+
|
|
71
|
+
4. **Check existing blueprints** to see if templates already exist for this type. If they do, ask the user whether to replace or augment.
|
|
72
|
+
|
|
73
|
+
5. **Determine if the template is static or templated.** This is an EDI domain question, not a codebase config lookup — the config may not exist yet for the transaction type.
|
|
74
|
+
|
|
75
|
+
Ask: **"Is this transaction type a direct response that echoes back data from a specific inbound document?"**
|
|
76
|
+
|
|
77
|
+
- **Static** — The transaction originates from the sender's own system data. The sender generates it from their own records (WMS, ERP, inventory system) without referencing a specific inbound EDI document. Templates are pure JSON with no Handlebars expressions.
|
|
78
|
+
- Examples: 846 (inventory report from seller's system), 943 (warehouse ships from WMS data), 944 (warehouse reports what it received), 940 (depositor issues a shipping order)
|
|
79
|
+
- **Templated** — The transaction is a direct response to a specific inbound document and structurally echoes back fields from it (line items, PO numbers, product IDs). Templates use Handlebars expressions to pull from the upstream document's data.
|
|
80
|
+
- Examples: 855 (acknowledges an 850's line items), 856 (ships against an 850), 810 (invoices against an 856)
|
|
81
|
+
|
|
82
|
+
If unsure, check existing templates for similar transaction types in the same document family.
|
|
83
|
+
|
|
84
|
+
### Phase 2: Scenario Design
|
|
85
|
+
|
|
86
|
+
Analyse the Zod schema to identify the key variability dimensions, then design scenarios.
|
|
87
|
+
|
|
88
|
+
**Identify dimensions of variability:**
|
|
89
|
+
- Enum fields (especially top-level ones like reporting codes, purpose codes, status codes) - each distinct value is a potential scenario axis
|
|
90
|
+
- Optional object blocks (parties, dates, notes, references, carrier details) - presence/absence is a scenario axis
|
|
91
|
+
- Array fields (line items, pallets) - single vs. multiple is a scenario axis
|
|
92
|
+
- Nested optional structures (exception details, physical details, lot tracking) - exercising these is important
|
|
93
|
+
|
|
94
|
+
**Select 8-12 scenarios** ranked by business impact. Always include:
|
|
95
|
+
1. **Standard/baseline** - the happy path with typical fields populated
|
|
96
|
+
2. **Comprehensive** - every field populated (mirrors `810_comprehensive` / `846_comprehensive` pattern)
|
|
97
|
+
3. **Minimal** - only required fields, everything optional absent
|
|
98
|
+
|
|
99
|
+
Then select the remaining scenarios based on what the schema uniquely supports. Prioritise:
|
|
100
|
+
- Each distinct enum value for top-level enums (e.g., different reporting codes)
|
|
101
|
+
- Key structural variations (pallets vs. loose items, single vs. multi-line)
|
|
102
|
+
- Industry-specific scenarios (cold chain, lot tracking, ocean shipment, returns)
|
|
103
|
+
- Correction/amendment flows (if the schema has a purpose/action code)
|
|
104
|
+
|
|
105
|
+
**Present the scenario list to the user** with a brief rationale for each before creating files. Wait for approval.
|
|
106
|
+
|
|
107
|
+
### Phase 3: Template Creation
|
|
108
|
+
|
|
109
|
+
Create the blueprint files.
|
|
110
|
+
|
|
111
|
+
1. **Create the directory** at:
|
|
112
|
+
```
|
|
113
|
+
apps/platform-api/src/modules/testTransformation/data/testBlueprints/{type}s/
|
|
114
|
+
```
|
|
115
|
+
where `{type}` is the three-digit transaction number (e.g., `943s`, `944s`).
|
|
116
|
+
|
|
117
|
+
2. **Write each template** as a `.json.hbs` file. Follow these rules:
|
|
118
|
+
- File naming: `{type}_{scenarioName}.json.hbs` (e.g., `943_standard.json.hbs`)
|
|
119
|
+
- If static: pure JSON, no Handlebars expressions
|
|
120
|
+
- If templated: use Handlebars expressions to reference upstream context (e.g., `{{purchaseOrder.*}}`, `{{#each purchaseOrder.lineItems}}`). See existing 855 templates for the PO-response pattern.
|
|
121
|
+
- Use realistic but clearly fictional data (company names, addresses, product descriptions)
|
|
122
|
+
- Use distinct data across templates - don't copy-paste the same parties/products everywhere
|
|
123
|
+
- Every enum value must be a valid value from the Zod schema's `metaEnum` definition - use the simplified name (e.g., `"commonCarrier"`), not the X12 code (e.g., not `"M"`)
|
|
124
|
+
|
|
125
|
+
### Phase 4: Registration
|
|
126
|
+
|
|
127
|
+
Register the blueprints in the repository.
|
|
128
|
+
|
|
129
|
+
1. **Edit `testBlueprint.repository.ts`**:
|
|
130
|
+
- Add imports for each template file (follow the existing naming convention)
|
|
131
|
+
- Add a new entry in `blueprintsByTransactionType` under the appropriate `TransactionTypeName` key
|
|
132
|
+
- Place it in alphabetical/numerical order relative to existing entries
|
|
133
|
+
|
|
134
|
+
### Phase 5: Validation
|
|
135
|
+
|
|
136
|
+
Run the **verify** command for the newly created templates. Fix any errors and re-run until all pass.
|
|
137
|
+
|
|
138
|
+
### Phase 6: Summary
|
|
139
|
+
|
|
140
|
+
Report to the user:
|
|
141
|
+
- How many templates were created
|
|
142
|
+
- A table of template names and the scenario each covers
|
|
143
|
+
- The file edited for registration
|
|
144
|
+
- Validation result (all pass)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Common Validation Pitfalls
|
|
149
|
+
|
|
150
|
+
These are the most frequent errors when writing blueprints. Check `shared.zod.ts` to verify exact enum values.
|
|
151
|
+
|
|
152
|
+
| Mistake | Fix |
|
|
153
|
+
|---------|-----|
|
|
154
|
+
| `"motor"` for transportation method | Use `"commonCarrier"` |
|
|
155
|
+
| `"truck"` for transportation method | Use `"commonCarrier"` or `"privateCarrier"` |
|
|
156
|
+
| `"inches"` for dimension UOM | Use `"inch"` |
|
|
157
|
+
| `"assignedByBuyer"` for identification code type | Use `"receiversId"` or a value from the enum |
|
|
158
|
+
| X12 codes like `"M"`, `"F"`, `"01"` | Use simplified names like `"commonCarrier"`, `"fullDetail"`, `"damaged"` |
|
|
159
|
+
| `"lbs"` or `"kg"` for weight UOM | Use `"pound"` or `"kilogram"` |
|
|
160
|
+
| `"EA"` or `"CS"` for unit of measure | Use `"each"` or `"case"` (lowercase simplified names) |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Codebase Paths Reference
|
|
2
|
+
|
|
3
|
+
All paths are relative to the orderful-workspace root.
|
|
4
|
+
|
|
5
|
+
## Zod Schemas (source of truth for template shape)
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
libs/schemas/src/lib/data/simplifiedSchemas/
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
To find the Zod schema for a transaction type, search the index:
|
|
12
|
+
```bash
|
|
13
|
+
grep -r "TransactionTypeName.T<number>" libs/schemas/src/lib/data/simplifiedSchemas/index.ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then find the schema file and export name from the import.
|
|
17
|
+
|
|
18
|
+
## Example JSON (realistic field values)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
libs/schemas/src/lib/data/simplifiedSchemas/examples/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Pattern: `simplified-<schemaName>.json`
|
|
25
|
+
|
|
26
|
+
## Shared Zod Schemas (enum values, shared types)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
libs/schemas/src/lib/data/simplifiedSchemas/shared.zod.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This file defines all shared types used across transaction schemas:
|
|
33
|
+
- `PartySchema` - party identification with contacts
|
|
34
|
+
- `QuantitySchema` - value + unit of measure
|
|
35
|
+
- `PhysicalDetailsSchema` - pack, weight, dimensions
|
|
36
|
+
- `LineItemIdentifiersSchema` - product IDs (buyer, vendor, GTIN)
|
|
37
|
+
- `ProductAttributeDetailsSchema` - description, color, size, material
|
|
38
|
+
- `RoutingDetailsSchema` - carrier and transportation method
|
|
39
|
+
- `EquipmentDetailsSchema` - trailer, container, seal
|
|
40
|
+
- `FOBDetailsSchema` - freight payment terms
|
|
41
|
+
- `SpecialHandlingDetailsSchema` - handling codes
|
|
42
|
+
- `CarrierWeightDetailsSchema` - shipment weight totals
|
|
43
|
+
- `NoteDetailsSchema` - notes with text array
|
|
44
|
+
- `PalletExchangeSchema` - pallet exchange/return enum
|
|
45
|
+
- `ContactSchema` - contact person details
|
|
46
|
+
|
|
47
|
+
## TransactionTypeName Enum
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
libs/platform-types/src/lib/transactionTypeNames.ts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Check this file for the exact enum key (e.g., `T943`, `T944`).
|
|
54
|
+
|
|
55
|
+
## Blueprint Templates
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
apps/platform-api/src/modules/testTransformation/data/testBlueprints/
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Organised by type: `810s/`, `846s/`, `855s/`, `856s/`, `943s/`, etc.
|
|
62
|
+
|
|
63
|
+
## Blueprint Repository (registration)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
apps/platform-api/src/modules/testTransformation/repositories/testBlueprint.repository.ts
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This file:
|
|
70
|
+
1. Imports all `.json.hbs` template files
|
|
71
|
+
2. Registers them in `blueprintsByTransactionType` under the `TransactionTypeName` key
|
|
72
|
+
3. Optionally registers upstream blueprints in `upstreamBlueprints`
|
|
73
|
+
|
|
74
|
+
## Validation Script Execution
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd <workspace-root> && npx ts-node -r tsconfig-paths/register \
|
|
78
|
+
--project apps/platform-api/tsconfig.json <path-to-script>
|
|
79
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* test-blueprints validate
|
|
4
|
+
*
|
|
5
|
+
* Validate blueprint .json.hbs templates against their Zod schema.
|
|
6
|
+
* Generates a temporary validation script in the workspace and runs it
|
|
7
|
+
* via ts-node so that tsconfig paths resolve correctly.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* droid exec test-blueprints validate \
|
|
11
|
+
* --workspace /path/to/orderful-workspace \
|
|
12
|
+
* --schema-import "simplifiedSchemas/schemaFile" \
|
|
13
|
+
* --schema-name "Simplified943Schema" \
|
|
14
|
+
* --blueprints-dir "apps/platform-api/src/modules/testTransformation/data/testBlueprints/943s"
|
|
15
|
+
*
|
|
16
|
+
* Output (JSON):
|
|
17
|
+
* {
|
|
18
|
+
* "success": true,
|
|
19
|
+
* "results": [
|
|
20
|
+
* { "file": "943_standard.json.hbs", "status": "pass" },
|
|
21
|
+
* { "file": "943_templated.json.hbs", "status": "skip", "reason": "contains Handlebars expressions" },
|
|
22
|
+
* { "file": "943_bad.json.hbs", "status": "fail", "errors": [{ "path": "header.type", "message": "Invalid enum value" }] }
|
|
23
|
+
* ],
|
|
24
|
+
* "summary": { "pass": 8, "fail": 1, "skip": 2, "total": 11 }
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../../../src/tools/test-blueprints/skills/test-blueprints/scripts/validate.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* test-blueprints validate
|
|
4
|
+
*
|
|
5
|
+
* Validate blueprint .json.hbs templates against their Zod schema.
|
|
6
|
+
* Generates a temporary validation script in the workspace and runs it
|
|
7
|
+
* via ts-node so that tsconfig paths resolve correctly.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* droid exec test-blueprints validate \
|
|
11
|
+
* --workspace /path/to/orderful-workspace \
|
|
12
|
+
* --schema-import "simplifiedSchemas/schemaFile" \
|
|
13
|
+
* --schema-name "Simplified943Schema" \
|
|
14
|
+
* --blueprints-dir "apps/platform-api/src/modules/testTransformation/data/testBlueprints/943s"
|
|
15
|
+
*
|
|
16
|
+
* Output (JSON):
|
|
17
|
+
* {
|
|
18
|
+
* "success": true,
|
|
19
|
+
* "results": [
|
|
20
|
+
* { "file": "943_standard.json.hbs", "status": "pass" },
|
|
21
|
+
* { "file": "943_templated.json.hbs", "status": "skip", "reason": "contains Handlebars expressions" },
|
|
22
|
+
* { "file": "943_bad.json.hbs", "status": "fail", "errors": [{ "path": "header.type", "message": "Invalid enum value" }] }
|
|
23
|
+
* ],
|
|
24
|
+
* "summary": { "pass": 8, "fail": 1, "skip": 2, "total": 11 }
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execSync } from 'child_process';
|
|
29
|
+
import { existsSync, writeFileSync, unlinkSync, readdirSync, readFileSync } from 'fs';
|
|
30
|
+
import { join } from 'path';
|
|
31
|
+
import { tmpdir } from 'os';
|
|
32
|
+
|
|
33
|
+
interface ValidationError {
|
|
34
|
+
path: string;
|
|
35
|
+
message: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface FileResult {
|
|
39
|
+
file: string;
|
|
40
|
+
status: 'pass' | 'fail' | 'skip';
|
|
41
|
+
reason?: string;
|
|
42
|
+
errors?: ValidationError[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ValidateResult {
|
|
46
|
+
success: boolean;
|
|
47
|
+
results?: FileResult[];
|
|
48
|
+
summary?: { pass: number; fail: number; skip: number; total: number };
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface ParsedArgs {
|
|
53
|
+
workspace?: string;
|
|
54
|
+
schemaImport?: string;
|
|
55
|
+
schemaName?: string;
|
|
56
|
+
blueprintsDir?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseArgs(args: string[]): ParsedArgs {
|
|
60
|
+
const result: ParsedArgs = {};
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < args.length; i++) {
|
|
63
|
+
const arg = args[i];
|
|
64
|
+
if (arg === '--workspace' && args[i + 1]) {
|
|
65
|
+
result.workspace = args[++i];
|
|
66
|
+
} else if (arg === '--schema-import' && args[i + 1]) {
|
|
67
|
+
result.schemaImport = args[++i];
|
|
68
|
+
} else if (arg === '--schema-name' && args[i + 1]) {
|
|
69
|
+
result.schemaName = args[++i];
|
|
70
|
+
} else if (arg === '--blueprints-dir' && args[i + 1]) {
|
|
71
|
+
result.blueprintsDir = args[++i];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function expandPath(p: string): string {
|
|
79
|
+
if (p.startsWith('~/')) {
|
|
80
|
+
return p.replace('~', process.env.HOME || '');
|
|
81
|
+
}
|
|
82
|
+
if (p.startsWith('$HOME/')) {
|
|
83
|
+
return p.replace('$HOME', process.env.HOME || '');
|
|
84
|
+
}
|
|
85
|
+
return p;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function validate(parsed: ParsedArgs): ValidateResult {
|
|
89
|
+
if (!parsed.workspace) {
|
|
90
|
+
return { success: false, error: 'Missing --workspace' };
|
|
91
|
+
}
|
|
92
|
+
if (!parsed.schemaImport) {
|
|
93
|
+
return { success: false, error: 'Missing --schema-import' };
|
|
94
|
+
}
|
|
95
|
+
if (!parsed.schemaName) {
|
|
96
|
+
return { success: false, error: 'Missing --schema-name' };
|
|
97
|
+
}
|
|
98
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(parsed.schemaName)) {
|
|
99
|
+
return { success: false, error: 'Invalid --schema-name: must be a valid identifier' };
|
|
100
|
+
}
|
|
101
|
+
if (/['"\n\r]/.test(parsed.schemaImport)) {
|
|
102
|
+
return { success: false, error: 'Invalid --schema-import: must not contain quotes or newlines' };
|
|
103
|
+
}
|
|
104
|
+
if (!parsed.blueprintsDir) {
|
|
105
|
+
return { success: false, error: 'Missing --blueprints-dir' };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const workspace = expandPath(parsed.workspace);
|
|
109
|
+
if (!existsSync(workspace)) {
|
|
110
|
+
return { success: false, error: `Workspace not found: ${workspace}` };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const blueprintsDir = parsed.blueprintsDir.startsWith('/')
|
|
114
|
+
? parsed.blueprintsDir
|
|
115
|
+
: join(workspace, parsed.blueprintsDir);
|
|
116
|
+
|
|
117
|
+
if (!existsSync(blueprintsDir)) {
|
|
118
|
+
return { success: false, error: `Blueprints directory not found: ${blueprintsDir}` };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Find .json.hbs files
|
|
122
|
+
const files = readdirSync(blueprintsDir).filter(f => f.endsWith('.json.hbs'));
|
|
123
|
+
if (files.length === 0) {
|
|
124
|
+
return { success: false, error: `No .json.hbs files found in ${blueprintsDir}` };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Pre-check for Handlebars templates (skip these from Zod validation)
|
|
128
|
+
const results: FileResult[] = [];
|
|
129
|
+
const filesToValidate: string[] = [];
|
|
130
|
+
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
const content = readFileSync(join(blueprintsDir, file), 'utf-8');
|
|
133
|
+
if (content.includes('{{')) {
|
|
134
|
+
results.push({ file, status: 'skip', reason: 'contains Handlebars expressions' });
|
|
135
|
+
} else {
|
|
136
|
+
// Check JSON parsability before sending to ts-node
|
|
137
|
+
try {
|
|
138
|
+
JSON.parse(content);
|
|
139
|
+
filesToValidate.push(file);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
const err = e as Error;
|
|
142
|
+
results.push({ file, status: 'fail', errors: [{ path: '(root)', message: `Invalid JSON: ${err.message}` }] });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If all files are skipped or failed JSON parse, return early
|
|
148
|
+
if (filesToValidate.length === 0) {
|
|
149
|
+
const summary = {
|
|
150
|
+
pass: 0,
|
|
151
|
+
fail: results.filter(r => r.status === 'fail').length,
|
|
152
|
+
skip: results.filter(r => r.status === 'skip').length,
|
|
153
|
+
total: results.length,
|
|
154
|
+
};
|
|
155
|
+
return { success: summary.fail === 0, results, summary };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Generate validation script
|
|
159
|
+
const validationScript = `
|
|
160
|
+
import { ${parsed.schemaName} } from '${parsed.schemaImport}';
|
|
161
|
+
import * as fs from 'fs';
|
|
162
|
+
import * as path from 'path';
|
|
163
|
+
|
|
164
|
+
const dir = ${JSON.stringify(blueprintsDir)};
|
|
165
|
+
const filesToValidate: string[] = ${JSON.stringify(filesToValidate)};
|
|
166
|
+
const results: Array<{ file: string; status: string; errors?: Array<{ path: string; message: string }> }> = [];
|
|
167
|
+
|
|
168
|
+
for (const file of filesToValidate) {
|
|
169
|
+
const content = fs.readFileSync(path.join(dir, file), 'utf-8');
|
|
170
|
+
const parsed = JSON.parse(content);
|
|
171
|
+
const result = ${parsed.schemaName}.safeParse(parsed);
|
|
172
|
+
|
|
173
|
+
if (result.success) {
|
|
174
|
+
results.push({ file, status: 'pass' });
|
|
175
|
+
} else {
|
|
176
|
+
results.push({
|
|
177
|
+
file,
|
|
178
|
+
status: 'fail',
|
|
179
|
+
errors: result.error.issues.map((issue: { path: (string | number)[]; message: string }) => ({
|
|
180
|
+
path: issue.path.join('.'),
|
|
181
|
+
message: issue.message,
|
|
182
|
+
})),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log(JSON.stringify(results));
|
|
188
|
+
`.trim();
|
|
189
|
+
|
|
190
|
+
const scriptPath = join(tmpdir(), `_validate-${Date.now()}.ts`);
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
writeFileSync(scriptPath, validationScript, 'utf-8');
|
|
194
|
+
|
|
195
|
+
const output = execSync(
|
|
196
|
+
`npx ts-node -r tsconfig-paths/register --project apps/platform-api/tsconfig.json ${JSON.stringify(scriptPath)}`,
|
|
197
|
+
{
|
|
198
|
+
cwd: workspace,
|
|
199
|
+
encoding: 'utf-8',
|
|
200
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
201
|
+
timeout: 60_000,
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
let zodResults: Array<{ file: string; status: string; errors?: ValidationError[] }>;
|
|
206
|
+
try {
|
|
207
|
+
zodResults = JSON.parse(output.trim());
|
|
208
|
+
} catch {
|
|
209
|
+
return { success: false, error: `Failed to parse validation output: ${output}` };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (const r of zodResults) {
|
|
213
|
+
results.push({
|
|
214
|
+
file: r.file,
|
|
215
|
+
status: r.status as 'pass' | 'fail',
|
|
216
|
+
errors: r.errors,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
} catch (err: unknown) {
|
|
220
|
+
const error = err as { stderr?: string; message?: string };
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
error: `Validation script failed: ${error.stderr || error.message}`,
|
|
224
|
+
};
|
|
225
|
+
} finally {
|
|
226
|
+
try { unlinkSync(scriptPath); } catch { /* ignore cleanup errors */ }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Sort results to match original file order
|
|
230
|
+
results.sort((a, b) => files.indexOf(a.file) - files.indexOf(b.file));
|
|
231
|
+
|
|
232
|
+
const summary = {
|
|
233
|
+
pass: results.filter(r => r.status === 'pass').length,
|
|
234
|
+
fail: results.filter(r => r.status === 'fail').length,
|
|
235
|
+
skip: results.filter(r => r.status === 'skip').length,
|
|
236
|
+
total: results.length,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
return { success: summary.fail === 0, results, summary };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Main
|
|
243
|
+
const args = process.argv.slice(2);
|
|
244
|
+
const parsed = parseArgs(args);
|
|
245
|
+
const result = validate(parsed);
|
|
246
|
+
console.log(JSON.stringify(result, null, 2));
|
|
247
|
+
|
|
248
|
+
if (!result.success) {
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "droid-test-blueprints",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Write and verify test blueprint HBS templates for EDI transaction types. Automates scenario design, template creation, registration, and Zod schema validation.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Orderful",
|
|
7
|
+
"url": "https://github.com/orderful"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/orderful/droid",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"droid",
|
|
13
|
+
"ai",
|
|
14
|
+
"test-blueprints"
|
|
15
|
+
],
|
|
16
|
+
"skills": [
|
|
17
|
+
"./skills/test-blueprints/SKILL.md"
|
|
18
|
+
],
|
|
19
|
+
"commands": [
|
|
20
|
+
"./commands/test-blueprints.md"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: test-blueprints
|
|
2
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types. Automates scenario design, template creation, registration, and Zod schema validation."
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
status: beta
|
|
5
|
+
audience:
|
|
6
|
+
- engineering
|
|
7
|
+
|
|
8
|
+
includes:
|
|
9
|
+
skills:
|
|
10
|
+
- name: test-blueprints
|
|
11
|
+
required: true
|
|
12
|
+
commands:
|
|
13
|
+
- name: test-blueprints
|
|
14
|
+
is_alias: false
|
|
15
|
+
agents: []
|
|
16
|
+
|
|
17
|
+
dependencies: []
|
|
18
|
+
|
|
19
|
+
prerequisites:
|
|
20
|
+
- "ts-node and tsconfig-paths must be available in the target workspace (used by the validate script)"
|
|
21
|
+
|
|
22
|
+
config_schema: {}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-blueprints
|
|
3
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types."
|
|
4
|
+
argument-hint: "[write {type} | verify {type}]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /test-blueprints
|
|
8
|
+
|
|
9
|
+
**User invoked:** `/test-blueprints $ARGUMENTS`
|
|
10
|
+
|
|
11
|
+
**Your task:** Invoke the **test-blueprints skill** with these arguments.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
- `/test-blueprints write 943`
|
|
16
|
+
- `/test-blueprints verify 943`
|
|
17
|
+
- `/test-blueprints 944`
|
|
18
|
+
|
|
19
|
+
## Quick Reference
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
/test-blueprints write {type} # Full create flow: schema → scenarios → templates → register → validate
|
|
23
|
+
/test-blueprints verify {type} # Validate existing blueprints against Zod schema
|
|
24
|
+
/test-blueprints {type} # Alias for write {type}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
See the **test-blueprints skill** for full behaviour and validation rules.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-blueprints
|
|
3
|
+
description: "Write and verify test blueprint HBS templates for EDI transaction types. Use when creating test scenarios for a new transaction type (e.g., 'create blueprints for 943'), verifying existing blueprints against their Zod schema (e.g., 'verify 943 blueprints', 'validate the 855 templates'), or adding test blueprints to the testTransformation module. User prompts like 'create test blueprints for 940', 'generate 944 test templates', 'verify 943 blueprints', 'validate the 855 templates', 'check if 944 blueprints are valid'."
|
|
4
|
+
argument-hint: "[write {type} | verify {type}]"
|
|
5
|
+
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Test Blueprints Skill
|
|
9
|
+
|
|
10
|
+
Write and verify test blueprint HBS templates for EDI transaction types in the Orderful platform. Each blueprint is a JSON file conforming to the transaction type's simplified Zod schema, representing a distinct business scenario.
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
| Command | Action |
|
|
15
|
+
|---------|--------|
|
|
16
|
+
| `/test-blueprints write {type}` | Full workflow: discover schema, design scenarios, create templates, register, validate |
|
|
17
|
+
| `/test-blueprints verify {type}` | Validate existing blueprints against the Zod schema and report results |
|
|
18
|
+
| `/test-blueprints {type}` | Alias for `write {type}` |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Command: verify
|
|
23
|
+
|
|
24
|
+
Validate existing blueprint templates against their Zod schema. Use this to check that all templates for a transaction type are still valid after schema changes, or to spot-check templates at any time.
|
|
25
|
+
|
|
26
|
+
### Steps
|
|
27
|
+
|
|
28
|
+
1. **Locate files.** Read `references/codebase-paths.md` for exact paths.
|
|
29
|
+
- Find the Zod schema for the transaction type
|
|
30
|
+
- Find the blueprint directory (`testBlueprints/{type}s/`)
|
|
31
|
+
- If no blueprints exist for the type, report that and stop
|
|
32
|
+
|
|
33
|
+
2. **Read the Zod schema** to determine the schema export name and import path.
|
|
34
|
+
|
|
35
|
+
3. **Run the validation script:**
|
|
36
|
+
```bash
|
|
37
|
+
droid exec test-blueprints validate \
|
|
38
|
+
--workspace {workspace-root} \
|
|
39
|
+
--schema-import "{import-path}" \
|
|
40
|
+
--schema-name "{SchemaExportName}" \
|
|
41
|
+
--blueprints-dir "{path-to-blueprints-dir}"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The script automatically:
|
|
45
|
+
- Discovers all `.json.hbs` files in the blueprints directory
|
|
46
|
+
- Skips templates containing Handlebars expressions (validated at render time, not statically)
|
|
47
|
+
- Validates remaining templates against the Zod schema via ts-node
|
|
48
|
+
- Returns structured JSON with per-file pass/fail/skip results
|
|
49
|
+
|
|
50
|
+
4. **Report results.** Parse the JSON output and show a summary table:
|
|
51
|
+
- PASS / FAIL / SKIP status per template
|
|
52
|
+
- For failures: the exact field path and error message
|
|
53
|
+
- Suggest fixes for common mistakes (see Common Validation Pitfalls below)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Command: write
|
|
58
|
+
|
|
59
|
+
Full workflow to create test blueprint templates for a transaction type.
|
|
60
|
+
|
|
61
|
+
### Phase 1: Discovery
|
|
62
|
+
|
|
63
|
+
Identify the transaction type and locate the required files. Read `references/codebase-paths.md` for exact paths.
|
|
64
|
+
|
|
65
|
+
1. **Find the Zod schema** for the transaction type. This is the source of truth for the template shape. Read it fully - every field, every enum value, every `metaEnum` definition. Also read `shared.zod.ts` for all imported shared types and their enum values.
|
|
66
|
+
|
|
67
|
+
2. **Find the example JSON** (if one exists) in the simplified schema examples directory. This shows realistic field values.
|
|
68
|
+
|
|
69
|
+
3. **Check TransactionTypeName** to confirm the enum key exists (e.g., `T943`).
|
|
70
|
+
|
|
71
|
+
4. **Check existing blueprints** to see if templates already exist for this type. If they do, ask the user whether to replace or augment.
|
|
72
|
+
|
|
73
|
+
5. **Determine if the template is static or templated.** This is an EDI domain question, not a codebase config lookup — the config may not exist yet for the transaction type.
|
|
74
|
+
|
|
75
|
+
Ask: **"Is this transaction type a direct response that echoes back data from a specific inbound document?"**
|
|
76
|
+
|
|
77
|
+
- **Static** — The transaction originates from the sender's own system data. The sender generates it from their own records (WMS, ERP, inventory system) without referencing a specific inbound EDI document. Templates are pure JSON with no Handlebars expressions.
|
|
78
|
+
- Examples: 846 (inventory report from seller's system), 943 (warehouse ships from WMS data), 944 (warehouse reports what it received), 940 (depositor issues a shipping order)
|
|
79
|
+
- **Templated** — The transaction is a direct response to a specific inbound document and structurally echoes back fields from it (line items, PO numbers, product IDs). Templates use Handlebars expressions to pull from the upstream document's data.
|
|
80
|
+
- Examples: 855 (acknowledges an 850's line items), 856 (ships against an 850), 810 (invoices against an 856)
|
|
81
|
+
|
|
82
|
+
If unsure, check existing templates for similar transaction types in the same document family.
|
|
83
|
+
|
|
84
|
+
### Phase 2: Scenario Design
|
|
85
|
+
|
|
86
|
+
Analyse the Zod schema to identify the key variability dimensions, then design scenarios.
|
|
87
|
+
|
|
88
|
+
**Identify dimensions of variability:**
|
|
89
|
+
- Enum fields (especially top-level ones like reporting codes, purpose codes, status codes) - each distinct value is a potential scenario axis
|
|
90
|
+
- Optional object blocks (parties, dates, notes, references, carrier details) - presence/absence is a scenario axis
|
|
91
|
+
- Array fields (line items, pallets) - single vs. multiple is a scenario axis
|
|
92
|
+
- Nested optional structures (exception details, physical details, lot tracking) - exercising these is important
|
|
93
|
+
|
|
94
|
+
**Select 8-12 scenarios** ranked by business impact. Always include:
|
|
95
|
+
1. **Standard/baseline** - the happy path with typical fields populated
|
|
96
|
+
2. **Comprehensive** - every field populated (mirrors `810_comprehensive` / `846_comprehensive` pattern)
|
|
97
|
+
3. **Minimal** - only required fields, everything optional absent
|
|
98
|
+
|
|
99
|
+
Then select the remaining scenarios based on what the schema uniquely supports. Prioritise:
|
|
100
|
+
- Each distinct enum value for top-level enums (e.g., different reporting codes)
|
|
101
|
+
- Key structural variations (pallets vs. loose items, single vs. multi-line)
|
|
102
|
+
- Industry-specific scenarios (cold chain, lot tracking, ocean shipment, returns)
|
|
103
|
+
- Correction/amendment flows (if the schema has a purpose/action code)
|
|
104
|
+
|
|
105
|
+
**Present the scenario list to the user** with a brief rationale for each before creating files. Wait for approval.
|
|
106
|
+
|
|
107
|
+
### Phase 3: Template Creation
|
|
108
|
+
|
|
109
|
+
Create the blueprint files.
|
|
110
|
+
|
|
111
|
+
1. **Create the directory** at:
|
|
112
|
+
```
|
|
113
|
+
apps/platform-api/src/modules/testTransformation/data/testBlueprints/{type}s/
|
|
114
|
+
```
|
|
115
|
+
where `{type}` is the three-digit transaction number (e.g., `943s`, `944s`).
|
|
116
|
+
|
|
117
|
+
2. **Write each template** as a `.json.hbs` file. Follow these rules:
|
|
118
|
+
- File naming: `{type}_{scenarioName}.json.hbs` (e.g., `943_standard.json.hbs`)
|
|
119
|
+
- If static: pure JSON, no Handlebars expressions
|
|
120
|
+
- If templated: use Handlebars expressions to reference upstream context (e.g., `{{purchaseOrder.*}}`, `{{#each purchaseOrder.lineItems}}`). See existing 855 templates for the PO-response pattern.
|
|
121
|
+
- Use realistic but clearly fictional data (company names, addresses, product descriptions)
|
|
122
|
+
- Use distinct data across templates - don't copy-paste the same parties/products everywhere
|
|
123
|
+
- Every enum value must be a valid value from the Zod schema's `metaEnum` definition - use the simplified name (e.g., `"commonCarrier"`), not the X12 code (e.g., not `"M"`)
|
|
124
|
+
|
|
125
|
+
### Phase 4: Registration
|
|
126
|
+
|
|
127
|
+
Register the blueprints in the repository.
|
|
128
|
+
|
|
129
|
+
1. **Edit `testBlueprint.repository.ts`**:
|
|
130
|
+
- Add imports for each template file (follow the existing naming convention)
|
|
131
|
+
- Add a new entry in `blueprintsByTransactionType` under the appropriate `TransactionTypeName` key
|
|
132
|
+
- Place it in alphabetical/numerical order relative to existing entries
|
|
133
|
+
|
|
134
|
+
### Phase 5: Validation
|
|
135
|
+
|
|
136
|
+
Run the **verify** command for the newly created templates. Fix any errors and re-run until all pass.
|
|
137
|
+
|
|
138
|
+
### Phase 6: Summary
|
|
139
|
+
|
|
140
|
+
Report to the user:
|
|
141
|
+
- How many templates were created
|
|
142
|
+
- A table of template names and the scenario each covers
|
|
143
|
+
- The file edited for registration
|
|
144
|
+
- Validation result (all pass)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Common Validation Pitfalls
|
|
149
|
+
|
|
150
|
+
These are the most frequent errors when writing blueprints. Check `shared.zod.ts` to verify exact enum values.
|
|
151
|
+
|
|
152
|
+
| Mistake | Fix |
|
|
153
|
+
|---------|-----|
|
|
154
|
+
| `"motor"` for transportation method | Use `"commonCarrier"` |
|
|
155
|
+
| `"truck"` for transportation method | Use `"commonCarrier"` or `"privateCarrier"` |
|
|
156
|
+
| `"inches"` for dimension UOM | Use `"inch"` |
|
|
157
|
+
| `"assignedByBuyer"` for identification code type | Use `"receiversId"` or a value from the enum |
|
|
158
|
+
| X12 codes like `"M"`, `"F"`, `"01"` | Use simplified names like `"commonCarrier"`, `"fullDetail"`, `"damaged"` |
|
|
159
|
+
| `"lbs"` or `"kg"` for weight UOM | Use `"pound"` or `"kilogram"` |
|
|
160
|
+
| `"EA"` or `"CS"` for unit of measure | Use `"each"` or `"case"` (lowercase simplified names) |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Codebase Paths Reference
|
|
2
|
+
|
|
3
|
+
All paths are relative to the orderful-workspace root.
|
|
4
|
+
|
|
5
|
+
## Zod Schemas (source of truth for template shape)
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
libs/schemas/src/lib/data/simplifiedSchemas/
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
To find the Zod schema for a transaction type, search the index:
|
|
12
|
+
```bash
|
|
13
|
+
grep -r "TransactionTypeName.T<number>" libs/schemas/src/lib/data/simplifiedSchemas/index.ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then find the schema file and export name from the import.
|
|
17
|
+
|
|
18
|
+
## Example JSON (realistic field values)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
libs/schemas/src/lib/data/simplifiedSchemas/examples/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Pattern: `simplified-<schemaName>.json`
|
|
25
|
+
|
|
26
|
+
## Shared Zod Schemas (enum values, shared types)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
libs/schemas/src/lib/data/simplifiedSchemas/shared.zod.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This file defines all shared types used across transaction schemas:
|
|
33
|
+
- `PartySchema` - party identification with contacts
|
|
34
|
+
- `QuantitySchema` - value + unit of measure
|
|
35
|
+
- `PhysicalDetailsSchema` - pack, weight, dimensions
|
|
36
|
+
- `LineItemIdentifiersSchema` - product IDs (buyer, vendor, GTIN)
|
|
37
|
+
- `ProductAttributeDetailsSchema` - description, color, size, material
|
|
38
|
+
- `RoutingDetailsSchema` - carrier and transportation method
|
|
39
|
+
- `EquipmentDetailsSchema` - trailer, container, seal
|
|
40
|
+
- `FOBDetailsSchema` - freight payment terms
|
|
41
|
+
- `SpecialHandlingDetailsSchema` - handling codes
|
|
42
|
+
- `CarrierWeightDetailsSchema` - shipment weight totals
|
|
43
|
+
- `NoteDetailsSchema` - notes with text array
|
|
44
|
+
- `PalletExchangeSchema` - pallet exchange/return enum
|
|
45
|
+
- `ContactSchema` - contact person details
|
|
46
|
+
|
|
47
|
+
## TransactionTypeName Enum
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
libs/platform-types/src/lib/transactionTypeNames.ts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Check this file for the exact enum key (e.g., `T943`, `T944`).
|
|
54
|
+
|
|
55
|
+
## Blueprint Templates
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
apps/platform-api/src/modules/testTransformation/data/testBlueprints/
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Organised by type: `810s/`, `846s/`, `855s/`, `856s/`, `943s/`, etc.
|
|
62
|
+
|
|
63
|
+
## Blueprint Repository (registration)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
apps/platform-api/src/modules/testTransformation/repositories/testBlueprint.repository.ts
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This file:
|
|
70
|
+
1. Imports all `.json.hbs` template files
|
|
71
|
+
2. Registers them in `blueprintsByTransactionType` under the `TransactionTypeName` key
|
|
72
|
+
3. Optionally registers upstream blueprints in `upstreamBlueprints`
|
|
73
|
+
|
|
74
|
+
## Validation Script Execution
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd <workspace-root> && npx ts-node -r tsconfig-paths/register \
|
|
78
|
+
--project apps/platform-api/tsconfig.json <path-to-script>
|
|
79
|
+
```
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* test-blueprints validate
|
|
4
|
+
*
|
|
5
|
+
* Validate blueprint .json.hbs templates against their Zod schema.
|
|
6
|
+
* Generates a temporary validation script in the workspace and runs it
|
|
7
|
+
* via ts-node so that tsconfig paths resolve correctly.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* droid exec test-blueprints validate \
|
|
11
|
+
* --workspace /path/to/orderful-workspace \
|
|
12
|
+
* --schema-import "simplifiedSchemas/schemaFile" \
|
|
13
|
+
* --schema-name "Simplified943Schema" \
|
|
14
|
+
* --blueprints-dir "apps/platform-api/src/modules/testTransformation/data/testBlueprints/943s"
|
|
15
|
+
*
|
|
16
|
+
* Output (JSON):
|
|
17
|
+
* {
|
|
18
|
+
* "success": true,
|
|
19
|
+
* "results": [
|
|
20
|
+
* { "file": "943_standard.json.hbs", "status": "pass" },
|
|
21
|
+
* { "file": "943_templated.json.hbs", "status": "skip", "reason": "contains Handlebars expressions" },
|
|
22
|
+
* { "file": "943_bad.json.hbs", "status": "fail", "errors": [{ "path": "header.type", "message": "Invalid enum value" }] }
|
|
23
|
+
* ],
|
|
24
|
+
* "summary": { "pass": 8, "fail": 1, "skip": 2, "total": 11 }
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execSync } from 'child_process';
|
|
29
|
+
import { existsSync, writeFileSync, unlinkSync, readdirSync, readFileSync } from 'fs';
|
|
30
|
+
import { join } from 'path';
|
|
31
|
+
import { tmpdir } from 'os';
|
|
32
|
+
|
|
33
|
+
interface ValidationError {
|
|
34
|
+
path: string;
|
|
35
|
+
message: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface FileResult {
|
|
39
|
+
file: string;
|
|
40
|
+
status: 'pass' | 'fail' | 'skip';
|
|
41
|
+
reason?: string;
|
|
42
|
+
errors?: ValidationError[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ValidateResult {
|
|
46
|
+
success: boolean;
|
|
47
|
+
results?: FileResult[];
|
|
48
|
+
summary?: { pass: number; fail: number; skip: number; total: number };
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface ParsedArgs {
|
|
53
|
+
workspace?: string;
|
|
54
|
+
schemaImport?: string;
|
|
55
|
+
schemaName?: string;
|
|
56
|
+
blueprintsDir?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseArgs(args: string[]): ParsedArgs {
|
|
60
|
+
const result: ParsedArgs = {};
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < args.length; i++) {
|
|
63
|
+
const arg = args[i];
|
|
64
|
+
if (arg === '--workspace' && args[i + 1]) {
|
|
65
|
+
result.workspace = args[++i];
|
|
66
|
+
} else if (arg === '--schema-import' && args[i + 1]) {
|
|
67
|
+
result.schemaImport = args[++i];
|
|
68
|
+
} else if (arg === '--schema-name' && args[i + 1]) {
|
|
69
|
+
result.schemaName = args[++i];
|
|
70
|
+
} else if (arg === '--blueprints-dir' && args[i + 1]) {
|
|
71
|
+
result.blueprintsDir = args[++i];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function expandPath(p: string): string {
|
|
79
|
+
if (p.startsWith('~/')) {
|
|
80
|
+
return p.replace('~', process.env.HOME || '');
|
|
81
|
+
}
|
|
82
|
+
if (p.startsWith('$HOME/')) {
|
|
83
|
+
return p.replace('$HOME', process.env.HOME || '');
|
|
84
|
+
}
|
|
85
|
+
return p;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function validate(parsed: ParsedArgs): ValidateResult {
|
|
89
|
+
if (!parsed.workspace) {
|
|
90
|
+
return { success: false, error: 'Missing --workspace' };
|
|
91
|
+
}
|
|
92
|
+
if (!parsed.schemaImport) {
|
|
93
|
+
return { success: false, error: 'Missing --schema-import' };
|
|
94
|
+
}
|
|
95
|
+
if (!parsed.schemaName) {
|
|
96
|
+
return { success: false, error: 'Missing --schema-name' };
|
|
97
|
+
}
|
|
98
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(parsed.schemaName)) {
|
|
99
|
+
return { success: false, error: 'Invalid --schema-name: must be a valid identifier' };
|
|
100
|
+
}
|
|
101
|
+
if (/['"\n\r]/.test(parsed.schemaImport)) {
|
|
102
|
+
return { success: false, error: 'Invalid --schema-import: must not contain quotes or newlines' };
|
|
103
|
+
}
|
|
104
|
+
if (!parsed.blueprintsDir) {
|
|
105
|
+
return { success: false, error: 'Missing --blueprints-dir' };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const workspace = expandPath(parsed.workspace);
|
|
109
|
+
if (!existsSync(workspace)) {
|
|
110
|
+
return { success: false, error: `Workspace not found: ${workspace}` };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const blueprintsDir = parsed.blueprintsDir.startsWith('/')
|
|
114
|
+
? parsed.blueprintsDir
|
|
115
|
+
: join(workspace, parsed.blueprintsDir);
|
|
116
|
+
|
|
117
|
+
if (!existsSync(blueprintsDir)) {
|
|
118
|
+
return { success: false, error: `Blueprints directory not found: ${blueprintsDir}` };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Find .json.hbs files
|
|
122
|
+
const files = readdirSync(blueprintsDir).filter(f => f.endsWith('.json.hbs'));
|
|
123
|
+
if (files.length === 0) {
|
|
124
|
+
return { success: false, error: `No .json.hbs files found in ${blueprintsDir}` };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Pre-check for Handlebars templates (skip these from Zod validation)
|
|
128
|
+
const results: FileResult[] = [];
|
|
129
|
+
const filesToValidate: string[] = [];
|
|
130
|
+
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
const content = readFileSync(join(blueprintsDir, file), 'utf-8');
|
|
133
|
+
if (content.includes('{{')) {
|
|
134
|
+
results.push({ file, status: 'skip', reason: 'contains Handlebars expressions' });
|
|
135
|
+
} else {
|
|
136
|
+
// Check JSON parsability before sending to ts-node
|
|
137
|
+
try {
|
|
138
|
+
JSON.parse(content);
|
|
139
|
+
filesToValidate.push(file);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
const err = e as Error;
|
|
142
|
+
results.push({ file, status: 'fail', errors: [{ path: '(root)', message: `Invalid JSON: ${err.message}` }] });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If all files are skipped or failed JSON parse, return early
|
|
148
|
+
if (filesToValidate.length === 0) {
|
|
149
|
+
const summary = {
|
|
150
|
+
pass: 0,
|
|
151
|
+
fail: results.filter(r => r.status === 'fail').length,
|
|
152
|
+
skip: results.filter(r => r.status === 'skip').length,
|
|
153
|
+
total: results.length,
|
|
154
|
+
};
|
|
155
|
+
return { success: summary.fail === 0, results, summary };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Generate validation script
|
|
159
|
+
const validationScript = `
|
|
160
|
+
import { ${parsed.schemaName} } from '${parsed.schemaImport}';
|
|
161
|
+
import * as fs from 'fs';
|
|
162
|
+
import * as path from 'path';
|
|
163
|
+
|
|
164
|
+
const dir = ${JSON.stringify(blueprintsDir)};
|
|
165
|
+
const filesToValidate: string[] = ${JSON.stringify(filesToValidate)};
|
|
166
|
+
const results: Array<{ file: string; status: string; errors?: Array<{ path: string; message: string }> }> = [];
|
|
167
|
+
|
|
168
|
+
for (const file of filesToValidate) {
|
|
169
|
+
const content = fs.readFileSync(path.join(dir, file), 'utf-8');
|
|
170
|
+
const parsed = JSON.parse(content);
|
|
171
|
+
const result = ${parsed.schemaName}.safeParse(parsed);
|
|
172
|
+
|
|
173
|
+
if (result.success) {
|
|
174
|
+
results.push({ file, status: 'pass' });
|
|
175
|
+
} else {
|
|
176
|
+
results.push({
|
|
177
|
+
file,
|
|
178
|
+
status: 'fail',
|
|
179
|
+
errors: result.error.issues.map((issue: { path: (string | number)[]; message: string }) => ({
|
|
180
|
+
path: issue.path.join('.'),
|
|
181
|
+
message: issue.message,
|
|
182
|
+
})),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log(JSON.stringify(results));
|
|
188
|
+
`.trim();
|
|
189
|
+
|
|
190
|
+
const scriptPath = join(tmpdir(), `_validate-${Date.now()}.ts`);
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
writeFileSync(scriptPath, validationScript, 'utf-8');
|
|
194
|
+
|
|
195
|
+
const output = execSync(
|
|
196
|
+
`npx ts-node -r tsconfig-paths/register --project apps/platform-api/tsconfig.json ${JSON.stringify(scriptPath)}`,
|
|
197
|
+
{
|
|
198
|
+
cwd: workspace,
|
|
199
|
+
encoding: 'utf-8',
|
|
200
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
201
|
+
timeout: 60_000,
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
let zodResults: Array<{ file: string; status: string; errors?: ValidationError[] }>;
|
|
206
|
+
try {
|
|
207
|
+
zodResults = JSON.parse(output.trim());
|
|
208
|
+
} catch {
|
|
209
|
+
return { success: false, error: `Failed to parse validation output: ${output}` };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (const r of zodResults) {
|
|
213
|
+
results.push({
|
|
214
|
+
file: r.file,
|
|
215
|
+
status: r.status as 'pass' | 'fail',
|
|
216
|
+
errors: r.errors,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
} catch (err: unknown) {
|
|
220
|
+
const error = err as { stderr?: string; message?: string };
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
error: `Validation script failed: ${error.stderr || error.message}`,
|
|
224
|
+
};
|
|
225
|
+
} finally {
|
|
226
|
+
try { unlinkSync(scriptPath); } catch { /* ignore cleanup errors */ }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Sort results to match original file order
|
|
230
|
+
results.sort((a, b) => files.indexOf(a.file) - files.indexOf(b.file));
|
|
231
|
+
|
|
232
|
+
const summary = {
|
|
233
|
+
pass: results.filter(r => r.status === 'pass').length,
|
|
234
|
+
fail: results.filter(r => r.status === 'fail').length,
|
|
235
|
+
skip: results.filter(r => r.status === 'skip').length,
|
|
236
|
+
total: results.length,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
return { success: summary.fail === 0, results, summary };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Main
|
|
243
|
+
const args = process.argv.slice(2);
|
|
244
|
+
const parsed = parseArgs(args);
|
|
245
|
+
const result = validate(parsed);
|
|
246
|
+
console.log(JSON.stringify(result, null, 2));
|
|
247
|
+
|
|
248
|
+
if (!result.success) {
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|