---
name: parallel-mock-implementation
description: Pattern for parallelizing emule mock authorship via the Workflow tool. Spawn one sub-agent per file in isolation; the orchestrator handles centralized finalization (wiring, build, test, promote). Invoked from `/implement-mock` (Strategy A batching) and `/compute-llk-bringup` (shim sweeps).
---
# Parallel mock implementation
This is a **building block**, not a standalone bring-up workflow.
Invoke it as part of `/implement-mock` or `/compute-llk-bringup` when
the work-list is large enough to amortize the dispatch overhead.
## When to use
- ≥4 similar files to author (e.g. a batch of SFPU shims, a sweep of
missing NOC overloads, a fanout of fabric primitives).
- Each output is **independent** — one file per worker, no shared
edits, no read dependencies between workers.
Don't use it for:
- Single-file work — call the worker prompt directly inline.
- Cross-cutting wiring that touches a shared file (e.g. one
`sfpu_split_includes.h`, one `.claude/references/structure.yaml`). The orchestrator
handles those centrally after workers return.
## Worker prompt skeleton
Each worker writes exactly one file. Customize the constraints for
your scope; the structure below stays the same.
```
You are implementing an emule mock for tt-emule. Write exactly ONE file.
TARGET FILE:
UPSTREAM REFERENCE (read-only):
ADDITIONAL REFERENCE (read-only, optional):
REFERENCE EMULE FILES (read for boilerplate):
REQUIRED SIGNATURES (mirror upstream — if upstream differs, follow upstream):
SEMANTICS:
HARD CONSTRAINTS:
- Do NOT modify any file other than the TARGET FILE.
- Do NOT touch shared wiring files (the orchestrator handles those).
- Do NOT run pytest, build, or commit.
- Read at most 3 files: upstream, optional second reference, one
existing mock as boilerplate.
- (Add scope-specific exclusions — e.g. for compute shims:
"Do NOT read tt_metal/llrt/, tt_metal/impl/dispatch/,
tt_metal/soc_descriptors/".)
OUTPUT: write the file, return status=DONE with file=
and lines=.
If signature is ambiguous or upstream missing, return status=STUCK with
a one-sentence reason.
Do NOT invent signatures.
```
## Result schema
```js
const RESULT_SCHEMA = {
type: 'object',
properties: {
status: { type: 'string', enum: ['DONE', 'STUCK'] },
file: { type: 'string' },
lines: { type: 'integer' },
reason: { type: 'string' },
},
required: ['status', 'file'],
additionalProperties: false,
}
```
## Orchestration
```js
phase('Write mocks')
const results = await parallel(ITEMS.map(it => () =>
agent(makePrompt(it), {
label: `mock:${it.name}`,
phase: 'Write mocks',
schema: RESULT_SCHEMA,
}).then(r => ({ item: it.name, ...(r || {status: 'NULL'}) }))
))
const done = results.filter(r => r.status === 'DONE')
const stuck = results.filter(r => r.status !== 'DONE')
log(`${done.length}/${ITEMS.length} DONE; ${stuck.length} STUCK`)
return { done, stuck }
```
## Orchestrator finalization
After the workers return, the orchestrator (you) handles centrally:
1. Visual diff each new file.
2. Wire any shared aggregator/registration file (e.g. for compute LLK
shims: `SFPU_OP_*_INCLUDE` branches in `sfpu_split_includes.h`).
3. Update `.claude/references/structure.yaml` with one line per new file (per `CLAUDE.md`
project rule).
4. Build.
5. Run targeted tests for each new mock — this loop can itself
parallelize via one pytest call per item.
6. Promote 100%-pass entries into the regression script (e.g.
`scripts/run_ttnn_pytests.sh` for compute LLK shims).
7. For partial passes, decide per-item: pytest `-k` filter, or defer
with a written note.
## Anti-patterns
1. **Don't have parallel workers touch shared files.** Each worker
owns a unique target path; the orchestrator centralizes wiring
after the batch returns. Without this, you get racing writes that
silently lose changes.
2. **Don't skip the `STUCK` branch.** When a worker hits ambiguity it
must report STUCK with a reason; the orchestrator decides how to
resolve (e.g. surface to the user, drop the item, hand-write it).
Workers that "guess" produce subtle bugs that surface much later.
3. **Don't bypass the schema.** Free-text worker output is unparseable
at scale. Even a STUCK item needs structured `{status: STUCK,
file: , reason: }`.
4. **Concurrency cap is automatic.** The Workflow runtime limits
concurrent `agent()` calls (typically ≤16); excess queue up. Don't
manually batch in chunks unless you have a reason — `parallel()`
over the full work-list is fine.