case-data-material-planner
One-stop material engine between case authoring and case execution.
- Build an optional business-context graph from requirements
- Parse entities and actions from each case
- Construct data and bind commands through adapters
- Emit
case-executable.md
How the work is divided
scripts/pipeline.ts owns orchestration. You supply judgment at three points
only — parse-case, knowledge-build, and select-tool — and the script does
construction, binding, linting, and writeback. This split exists because those
three stages need reading comprehension while the rest must be reproducible: a
case re-run tomorrow has to yield the same manifest, which is impossible if a
model re-derives each step. So when the runner exits asking for one of the three,
launch that Agent, merge its patch, and --resume; do not take over a stage the
script already implements (invoke_entity.ts, bind_action.ts,
slot_render.ts), and with 2+ cases go through the dispatcher so each case gets
its own pipeline.ts process.
Hard constraints
These are the ones that silently corrupt output rather than failing loudly,
which is why they are worth stating:
- Do not invent business IDs, amounts, or config values. A plausible-looking
ID makes a case that fails at execution time with no trace of where the value
came from. When unsure, record
failReason and let the gate surface it.
- Parse before constructing. Data needs come from the case's preconditions
and steps; skipping parse means constructing something the case never asked
for.
- Keep
case-executable.md business-only. No node / python / bash
invoke lines, no skillRoot, cwd, host, or mock-server ports — those live in
manifest.json (invokeCmd / filledCmd). The case document is read by
people and replayed in other environments, where local paths and ports are
wrong or meaningless.
- Persist every non-envelope business field, not just the primary ID. A
downstream step usually needs the attributes that came back with it, and
re-fetching them is not always possible.
- Respect the gates. C3 stays blocking when lint-gate is abnormal, and the
lint-gate loop runs at most 3 rounds before it must hand the decision to the
user — an unbounded loop burns the run without converging.
- During knowledge-build, describe the business, not a shopping list. The
graph answers "what does this domain look like"; deciding what data to prepare
is the parse stage's job and doing it early biases the parse.
Entry routes
After receiving the request, classify the input:
Path A: requirement / design doc (+ cases)
- Read
planner.md and run scripts/pipeline.ts
- Exit 12 → knowledge-build Agent, merge,
--resume
- Then parse (exit 11) or continue if cases were already parsed
Path B: cases only (no requirement doc)
- Read
planner.md and run scripts/pipeline.ts --case-id … --source …
- Reuse
./testdata/case-materials/business-context.json via --context when it exists
- Otherwise knowledge-build is skipped by the runner
- Handle exit 11 (parse-case) then
--resume. Construction, binding, and
writeback stay inside pipeline.ts — do not take those stages over.
Path C: batch (2+ cases)
When the user supplies 2 or more cases:
- Read
case-dispatcher.md and follow it
- One
pipeline.ts process per case (parallel). Shared knowledge-build once
- The user talks to the dispatcher, not a per-case Planner Agent
Rule:
- case count ≥ 2 → Path C
- case count == 1 → Path A or B
Input sources (highest first)
| Priority |
Source |
How |
Notes |
| 0 |
Caller-supplied sources[] |
Passed in the Task / delegate prompt |
Each item is {caseId, sourceType, sourcePath}; skip interactive collection |
| 1 |
Document URL |
doc_source.get(<ref>) |
Requirement / design / knowledge-base page |
| 2 |
planId |
workspace_context.get_plan(<id>) + api_catalog.search_plan_changes(<id>) |
Plan detail and change APIs |
| 3 |
Local file path |
Read the file |
|
| 4 |
Pasted text |
Use as-is |
|
Priority 0 is an optional fast path. sourceType values:
remote-case | local-file | planId | paste.
They map to the four legal caseSource.type values.
Callers that omit sources[] still use priorities 1–4 interactively.
Material gate (case source)
The prerequisite material is the case pack, not executor fields.
- No case source → ask for a file, paste,
planId, or document URL. Do not invent case text. Do not start parse or construct.
- Path A without cases → finish knowledge-build, then wait for cases. Do not jump to invoke.
- Path B → at least one case is mandatory.
knowledge-build may be skipped; parse may not.
- Batch (2+) → every listed case needs a resolvable source. Do not silently drop a case.
- After the user supplies cases,
--resume pipeline.ts. Do not skip parse, invoke, or writeback.
- Executor / tool params inside pipelines follow the original fill rules (defaults for optional fields; do not invent core IDs). C3 / lint-gate stay blocking.
Constraints
- Execution logic lives in
scripts/pipeline.ts; planner.md is the host protocol
- LLM Agents allowed:
parse-case, knowledge-build, select-tool only
- Do not skip C3; the happy path has zero human gates
- Lint-gate loop is at most 3 rounds
- Entities and actions are equal tracks; an empty track short-circuits
targetLocation is the only bind to the original case text
- Action params:
paramsFromEntities / paramsFromGenerators / paramsFromPriorActions
- Tool verify uses
tool_registry.query_input_list (see references/param-source-spec.md)
businessContext = null is a valid degraded mode
- Entities follow
constructionStrategy: tool-build → invoke_entity.ts,
config → generate_config_commands.ts, static-value → filled at parse,
runtime → deferred to execution
- New scenes: drop a slot under pack
slots/ or workspace.slot_roots.
select_tool.ts binds from slot.yaml (or inferred executors). Do not edit the selector
Path roots
Two roots, and mixing them up is the most common failure here:
| Variable |
Points at |
Owns |
SUBSKILL_DIR |
directory of this file ($SKILL_DIR/references/case-data-material-planner/) |
scripts/, agents/, templates/, references/ — every relative path in this sub-skill |
SKILL_DIR |
the parent skill root that contains the top-level SKILL.md |
scripts/adapters/, scripts/search_data_build.ts, slots/ |
There is no adapters/ folder under SUBSKILL_DIR/scripts/. Adapter calls go to
$SKILL_DIR/scripts/adapters/cli.ts.
File layout
SKILL.md entry routing (this file)
planner.md host protocol for pipeline.ts
case-dispatcher.md multi-case: one pipeline.ts per case
agents/ LLM specs (parse / knowledge-build / select-tool)
knowledge-build.md
parse-case.md
select-tool.md
writeback.md slot_render render rules, applied by the script
scripts/ pipeline.ts + construct/writeback scripts
templates/ manifest / cache / context templates
references/ thresholds and contracts
Outputs
./testdata/case-materials/business-context.json
./testdata/case-materials/tool-binding-cache.json
./testdata/case-materials/{case-id}/manifest.json
./testdata/case-materials/{case-id}/case-executable.md
Dependencies
No private CLIs. All I/O goes through the parent skill's adapters
($SKILL_DIR/scripts/adapters/cli.ts):
| Need |
Adapter |
| Discover / install domain skills |
skill_marketplace |
| Query / execute / publish tools |
tool_registry |
| Discover HTTP APIs |
api_catalog |
| Proven methods |
experience_store |
| Documents |
doc_source |
| Test-plan context |
workspace_context |
| Case writeback |
case_writeback |
| Config and SQL |
config_store, data_store |
Collaboration
This sub-skill is hosted by testdata-generation. select_tool.ts reuses
scripts/parallel_search.ts, which calls the same adapters. Enterprise tools
are added through those adapters or a new slot under slots/ /
workspace.slot_roots — invoke_entity.ts only dispatches on toolType.
1---2name: case-data-material-planner3description: Prepares executable case preconditions and case-executable.md from a requirement or written cases. Internal case-material engine; enter through testdata-generation so SKILL_DIR and adapters resolve.4license: Apache-2.05---67# case-data-material-planner89One-stop material engine between case authoring and case execution.1011- Build an optional business-context graph from requirements12- Parse entities and actions from each case13- Construct data and bind commands through adapters14- Emit `case-executable.md`1516## How the work is divided1718`scripts/pipeline.ts` owns orchestration. You supply judgment at three points19only — `parse-case`, `knowledge-build`, and `select-tool` — and the script does20construction, binding, linting, and writeback. This split exists because those21three stages need reading comprehension while the rest must be reproducible: a22case re-run tomorrow has to yield the same manifest, which is impossible if a23model re-derives each step. So when the runner exits asking for one of the three,24launch that Agent, merge its patch, and `--resume`; do not take over a stage the25script already implements (`invoke_entity.ts`, `bind_action.ts`,26`slot_render.ts`), and with 2+ cases go through the dispatcher so each case gets27its own `pipeline.ts` process.2829## Hard constraints3031These are the ones that silently corrupt output rather than failing loudly,32which is why they are worth stating:3334- **Do not invent business IDs, amounts, or config values.** A plausible-looking35 ID makes a case that fails at execution time with no trace of where the value36 came from. When unsure, record `failReason` and let the gate surface it.37- **Parse before constructing.** Data needs come from the case's preconditions38 and steps; skipping parse means constructing something the case never asked39 for.40- **Keep `case-executable.md` business-only.** No `node` / `python` / `bash`41 invoke lines, no `skillRoot`, cwd, host, or mock-server ports — those live in42 `manifest.json` (`invokeCmd` / `filledCmd`). The case document is read by43 people and replayed in other environments, where local paths and ports are44 wrong or meaningless.45- **Persist every non-envelope business field**, not just the primary ID. A46 downstream step usually needs the attributes that came back with it, and47 re-fetching them is not always possible.48- **Respect the gates.** C3 stays blocking when lint-gate is abnormal, and the49 lint-gate loop runs at most 3 rounds before it must hand the decision to the50 user — an unbounded loop burns the run without converging.51- **During knowledge-build, describe the business, not a shopping list.** The52 graph answers "what does this domain look like"; deciding what data to prepare53 is the parse stage's job and doing it early biases the parse.5455---5657## Entry routes5859After receiving the request, classify the input:6061### Path A: requirement / design doc (+ cases)62631. Read `planner.md` and run `scripts/pipeline.ts`642. Exit 12 → knowledge-build Agent, merge, `--resume`653. Then parse (exit 11) or continue if cases were already parsed6667### Path B: cases only (no requirement doc)68691. Read `planner.md` and run `scripts/pipeline.ts --case-id … --source …`702. Reuse `./testdata/case-materials/business-context.json` via `--context` when it exists713. Otherwise knowledge-build is skipped by the runner724. Handle exit 11 (parse-case) then `--resume`. Construction, binding, and73 writeback stay inside `pipeline.ts` — do not take those stages over.7475### Path C: batch (2+ cases)7677When the user supplies **2 or more cases**:78791. Read `case-dispatcher.md` and follow it802. One `pipeline.ts` process per case (parallel). Shared knowledge-build once813. The user talks to the dispatcher, not a per-case Planner Agent8283**Rule:**8485- case count ≥ 2 → Path C86- case count == 1 → Path A or B8788### Input sources (highest first)8990| Priority | Source | How | Notes |91|---|---|---|---|92| 0 | Caller-supplied `sources[]` | Passed in the Task / delegate prompt | Each item is `{caseId, sourceType, sourcePath}`; skip interactive collection |93| 1 | Document URL | `doc_source.get(<ref>)` | Requirement / design / knowledge-base page |94| 2 | `planId` | `workspace_context.get_plan(<id>)` + `api_catalog.search_plan_changes(<id>)` | Plan detail and change APIs |95| 3 | Local file path | Read the file | |96| 4 | Pasted text | Use as-is | |9798Priority 0 is an optional fast path. `sourceType` values:99`remote-case | local-file | planId | paste`.100They map to the four legal `caseSource.type` values.101Callers that omit `sources[]` still use priorities 1–4 interactively.102103## Material gate (case source)104105The prerequisite material is **the case pack**, not executor fields.106107- **No case source** → ask for a file, paste, `planId`, or document URL. Do not invent case text. Do not start parse or construct.108- **Path A without cases** → finish knowledge-build, then **wait** for cases. Do not jump to invoke.109- **Path B** → at least one case is mandatory. `knowledge-build` may be skipped; parse may not.110- **Batch (2+)** → every listed case needs a resolvable source. Do not silently drop a case.111- After the user supplies cases, `--resume` `pipeline.ts`. Do not skip parse, invoke, or writeback.112- Executor / tool params inside pipelines follow the original fill rules (defaults for optional fields; do not invent core IDs). C3 / lint-gate stay blocking.113114---115116## Constraints117118- Execution logic lives in `scripts/pipeline.ts`; `planner.md` is the host protocol119- LLM Agents allowed: `parse-case`, `knowledge-build`, `select-tool` only120- Do not skip C3; the happy path has zero human gates121- Lint-gate loop is at most 3 rounds122- Entities and actions are equal tracks; an empty track short-circuits123- `targetLocation` is the only bind to the original case text124- Action params: `paramsFromEntities` / `paramsFromGenerators` / `paramsFromPriorActions`125- Tool verify uses `tool_registry.query_input_list` (see `references/param-source-spec.md`)126- `businessContext = null` is a valid degraded mode127- Entities follow `constructionStrategy`: `tool-build` → `invoke_entity.ts`,128 `config` → `generate_config_commands.ts`, `static-value` → filled at parse,129 `runtime` → deferred to execution130- New scenes: drop a slot under pack `slots/` or `workspace.slot_roots`.131 `select_tool.ts` binds from `slot.yaml` (or inferred executors). Do not edit the selector132133## Path roots134135Two roots, and mixing them up is the most common failure here:136137| Variable | Points at | Owns |138|---|---|---|139| `SUBSKILL_DIR` | directory of this file (`$SKILL_DIR/references/case-data-material-planner/`) | `scripts/`, `agents/`, `templates/`, `references/` — every relative path in this sub-skill |140| `SKILL_DIR` | the parent skill root that contains the top-level `SKILL.md` | `scripts/adapters/`, `scripts/search_data_build.ts`, `slots/` |141142There is no `adapters/` folder under `SUBSKILL_DIR/scripts/`. Adapter calls go to143`$SKILL_DIR/scripts/adapters/cli.ts`.144145## File layout146147```148SKILL.md entry routing (this file)149planner.md host protocol for pipeline.ts150case-dispatcher.md multi-case: one pipeline.ts per case151agents/ LLM specs (parse / knowledge-build / select-tool)152 knowledge-build.md153 parse-case.md154 select-tool.md155 writeback.md slot_render render rules, applied by the script156scripts/ pipeline.ts + construct/writeback scripts157templates/ manifest / cache / context templates158references/ thresholds and contracts159```160161## Outputs162163- `./testdata/case-materials/business-context.json`164- `./testdata/case-materials/tool-binding-cache.json`165- `./testdata/case-materials/{case-id}/manifest.json`166- `./testdata/case-materials/{case-id}/case-executable.md`167168## Dependencies169170No private CLIs. All I/O goes through the parent skill's adapters171(`$SKILL_DIR/scripts/adapters/cli.ts`):172173| Need | Adapter |174|---|---|175| Discover / install domain skills | `skill_marketplace` |176| Query / execute / publish tools | `tool_registry` |177| Discover HTTP APIs | `api_catalog` |178| Proven methods | `experience_store` |179| Documents | `doc_source` |180| Test-plan context | `workspace_context` |181| Case writeback | `case_writeback` |182| Config and SQL | `config_store`, `data_store` |183184## Collaboration185186This sub-skill is hosted by `testdata-generation`. `select_tool.ts` reuses187`scripts/parallel_search.ts`, which calls the same adapters. Enterprise tools188are added through those adapters or a new slot under `slots/` /189`workspace.slot_roots` — `invoke_entity.ts` only dispatches on `toolType`.