You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #333 / #334. PR #334 hoisted the scenario-template wiring into materializer/src/templateRegistry.ts as a single source of truth, but the registry still carries a hand-maintained outputDir per template name. That field encodes a materializer aesthetic (the short names edges/, entities/, runtime-entities/, state-transitions/) that has no ontology basis — the ABox in configs/<config>/ontology/scenario-templates.json only knows about name, appliesTo.kind, and steps[].
The remaining materializer-side knowledge should go too. The materializer should be a generic transformer: given an ABox row, derive everything mechanically.
Proposal: Option A — mirror the planner's layout
The planner already writes scenarios to generated/<config>/scenarios/templates/<TemplateName>/. The materializer mirrors it exactly:
The output dir is template.name verbatim. No translation table anywhere; the relationship between scenario JSON and rendered spec is visible from the directory structure alone.
Considered and rejected:
Derive from appliesTo.kind alone — fails. Two RuntimeEntity templates (UpdatedFieldVisibleOnReadBack, StateTransitionVisibleAfterAction) would collide.
Keep short names via a compound key (e.g. appliesTo.kind + terminal Observe.expect) — works but re-encodes the materializer's aesthetic split inside a derivation function. Same problem, different shape.
materializer/src/index.ts reads the scenario-templates ABox via the existing loader and iterates abox.templates. For each row, the materializer reads scenarios/templates/<row.name>/ → emits to playwright/templates/<row.name>/.
materializer/src/coverage.ts takes the ABox (or the iterated names) instead of templates: TemplateBinding[].
Renderer dispatch stays as a single function for now (emitTemplateSuites for all four). If a second renderer appears later, key it on an explicit ABox renderer field — that's a separate, intentional design step.
Rotate tests/codegen/template-registry.test.ts (or delete it) so the symmetry guard asserts "every ABox row maps to a unique on-disk directory" using row.name alone.
One-time cost (mechanical renames)
Path constants and doc references that mention the old short names need updating:
These are path renames only — no test logic changes, no scenario count changes, no L3 assertions reshape.
Acceptance criteria
TEMPLATE_REGISTRY is deleted.
The materializer reads the scenario-templates ABox and derives its output layout from template.name alone, with no template-name string literals in materializer code.
L3 invariants in configs/camunda-oca/regression-invariants.test.ts pass with the renamed paths (same count: +26 lifecycle suites, –73 suppressed).
Symmetry guard test asserts every ABox template name maps to a unique on-disk directory.
Full pre-push gate green; pipeline regenerates byte-identically to the new layout.
Branch hygiene
After #334 merges. Fresh branch off main (e.g. refactor/generic-materializer-335).
Context
Follow-up to #333 / #334. PR #334 hoisted the scenario-template wiring into
materializer/src/templateRegistry.tsas a single source of truth, but the registry still carries a hand-maintainedoutputDirper template name. That field encodes a materializer aesthetic (the short namesedges/,entities/,runtime-entities/,state-transitions/) that has no ontology basis — the ABox inconfigs/<config>/ontology/scenario-templates.jsononly knows aboutname,appliesTo.kind, andsteps[].The remaining materializer-side knowledge should go too. The materializer should be a generic transformer: given an ABox row, derive everything mechanically.
Proposal: Option A — mirror the planner's layout
The planner already writes scenarios to
generated/<config>/scenarios/templates/<TemplateName>/. The materializer mirrors it exactly:The output dir is
template.nameverbatim. No translation table anywhere; the relationship between scenario JSON and rendered spec is visible from the directory structure alone.Considered and rejected:
appliesTo.kindalone — fails. Two RuntimeEntity templates (UpdatedFieldVisibleOnReadBack,StateTransitionVisibleAfterAction) would collide.appliesTo.kind+ terminalObserve.expect) — works but re-encodes the materializer's aesthetic split inside a derivation function. Same problem, different shape.Implementation sketch
materializer/src/templateRegistry.ts.materializer/src/index.tsreads the scenario-templates ABox via the existing loader and iteratesabox.templates. For each row, the materializer readsscenarios/templates/<row.name>/→ emits toplaywright/templates/<row.name>/.materializer/src/coverage.tstakes the ABox (or the iterated names) instead oftemplates: TemplateBinding[].emitTemplateSuitesfor all four). If a second renderer appears later, key it on an explicit ABoxrendererfield — that's a separate, intentional design step.tests/codegen/template-registry.test.ts(or delete it) so the symmetry guard asserts "every ABox row maps to a unique on-disk directory" usingrow.namealone.One-time cost (mechanical renames)
Path constants and doc references that mention the old short names need updating:
README.mdL363 —playwright/edges/→playwright/templates/EdgeLifecycle/configs/camunda-oca/regression-invariants.test.ts— ~6 sites (L2330, L7883, L7899, L8110, L8708, L8729, L8750) with path constants likeEDGES_SUITE_DIRand string literals'state-transitions', etc.materializer/src/playwright/templateEmitter.ts— JSDoc referencepath-analyser/src/types.ts— JSDoc referenceThese are path renames only — no test logic changes, no scenario count changes, no L3 assertions reshape.
Acceptance criteria
TEMPLATE_REGISTRYis deleted.template.namealone, with no template-name string literals in materializer code.configs/camunda-oca/regression-invariants.test.tspass with the renamed paths (same count: +26 lifecycle suites, –73 suppressed).Branch hygiene
After #334 merges. Fresh branch off
main(e.g.refactor/generic-materializer-335).