4.3 KiB
4.3 KiB
OpenSpec Change: templates-spec-conformance
- Change ID: templates-spec-conformance
- Package:
@suaveplan/templates - Status: PROPOSED
- Date: 2026-04-26
Summary
Bring @suaveplan/templates into spec conformance with
openspec/specs/templates/spec.md. Closes the parsing gap (the previous
spec used ### <Section> plus REQ-TPL-NNN bullets so the conformance
parser saw zero requirements), wires the missing OpenTelemetry instruments
the spec mandated but the engine never emitted, and adds boundary
validation of TemplateEngineOptions / ParseOptions so the exported Zod
schemas are actually called by the engine.
Current state
@suaveplan/templates ships an enterprise-grade plugin engine
(TemplateEngine<TContext>, four preset families, ten plugins, a
structured error hierarchy backed by defineCodes("TEMPLATE", …),
fast-check property tests, and a mitata bench suite). The spec gaps
are mechanical / observability:
- The folded spec used non-parseable section headings (
### Package identity,### Dependencies, …) sobun scripts/openspec-conformance.ts @suaveplan/templatesreported "0 requirements parsed". - The constructor advertised
TemplateEngineOptionsSchemabut never invoked it; same forParseOptionsSchema. Both schemas were exported yet had zero non-test call sites. - The OTel contract (
template.render.total,template.render.duration_ms,template.plugin.calls.total) was specced but the engine had no@opentelemetry/apiimport at all. tasks.mdof2026-04-19-enterprise-templates/carried the bulk-archive marker (> Archived YYYY-MM-DD: all tasks …) banned by AGENTS.md section 12.- Several behaviours were exercised only indirectly: ParseState clone
independence, reverse-index splice ordering inside
applyPlugin,throwOnError=false→onErrorforwarding,Clock/Rnginjection on dynamic plugins, and preset super-set relationships.
What changes
- Add
@opentelemetry/apias a runtime dependency (catalog:observability). - Add
src/otel/templates-otel.tsexportingrecordRender,recordPluginCall,startRenderTimer, and_resetInstruments. Wire it fromTemplateEngine.parse/parseAsync(render counter + duration histogram) and fromapplyPlugin/applyPluginAsync(plugin counter, attributeoutcome∈{"success","skip","error"}). TemplateEngineconstructor now callsTemplateEngineOptionsSchema.safeParse(options)and throwsTemplateError(TEMPLATE.PARSE_ERROR)on failure.parse/parseAsynccallParseOptionsSchema.safeParse(options)when options are passed.- Mark
PluginPrioritySchemaas// schema: boundary-only(consumer facing only; the engine accepts any numeric priority). - Rewrite
openspec/specs/templates/spec.mdfrom### Package identity+REQ-TPL-NNNbullets to fourteen### TPL-NN — namerequirement headings, each with a**Verified by:**line that names the specific test case. - Add seven
*.spec-conformance.test.tsfiles pinning the implicit scenarios:src/__tests__/package-shape.spec-conformance.test.ts— TPL-01 / TPL-02.src/__tests__/types.spec-conformance.test.ts— TPL-04.src/engine/ParseState.spec-conformance.test.ts— TPL-05.src/engine/TemplateEngine.spec-conformance.test.ts— TPL-06 / TPL-07 / TPL-09.src/engine/apply-plugin.spec-conformance.test.ts— TPL-08.src/errors/template-error.spec-conformance.test.ts— TPL-03.src/otel/templates-otel.spec-conformance.test.ts— TPL-13.src/plugins/plugins.spec-conformance.test.ts— TPL-10.src/presets/presets.spec-conformance.test.ts— TPL-11.
- Replace the
retroactively tickedline inarchive/2026-04-19-enterprise-templates/tasks.mdwith prose pointing at this change folder.
Impact
- Public API gains
recordRender,recordPluginCall,startRenderTimer,_resetInstruments,RenderOutcome,PluginOutcomere-exports. No removed exports. TemplateEngineconstructor now validates options at the boundary — invalid configs throwTemplateError(TEMPLATE.PARSE_ERROR)instead of silently coercing.- Nine new test files (~600 lines combined).
- One new module + sibling
.md(src/otel/). @opentelemetry/apiadded as runtime dep; ships no-op when noMeterProvideris registered.