Initial Commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# 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`, …) so `bun scripts/openspec-conformance.ts
|
||||
@suaveplan/templates` reported "0 requirements parsed".
|
||||
- The constructor advertised `TemplateEngineOptionsSchema` but never
|
||||
invoked it; same for `ParseOptionsSchema`. 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/api` import at all.
|
||||
- `tasks.md` of `2026-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` → `onError` forwarding, `Clock` / `Rng` injection
|
||||
on dynamic plugins, and preset super-set relationships.
|
||||
|
||||
## What changes
|
||||
|
||||
1. Add `@opentelemetry/api` as a runtime dependency
|
||||
(`catalog:observability`).
|
||||
2. Add `src/otel/templates-otel.ts` exporting `recordRender`,
|
||||
`recordPluginCall`, `startRenderTimer`, and `_resetInstruments`. Wire
|
||||
it from `TemplateEngine.parse` / `parseAsync` (render counter +
|
||||
duration histogram) and from `applyPlugin` / `applyPluginAsync`
|
||||
(plugin counter, attribute `outcome` ∈ `{"success","skip","error"}`).
|
||||
3. `TemplateEngine` constructor now calls
|
||||
`TemplateEngineOptionsSchema.safeParse(options)` and throws
|
||||
`TemplateError(TEMPLATE.PARSE_ERROR)` on failure. `parse` / `parseAsync`
|
||||
call `ParseOptionsSchema.safeParse(options)` when options are passed.
|
||||
4. Mark `PluginPrioritySchema` as `// schema: boundary-only` (consumer
|
||||
facing only; the engine accepts any numeric priority).
|
||||
5. Rewrite `openspec/specs/templates/spec.md` from
|
||||
`### Package identity` + `REQ-TPL-NNN` bullets to fourteen
|
||||
`### TPL-NN — name` requirement headings, each with a
|
||||
`**Verified by:**` line that names the specific test case.
|
||||
6. Add seven `*.spec-conformance.test.ts` files 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.
|
||||
7. Replace the `retroactively ticked` line in
|
||||
`archive/2026-04-19-enterprise-templates/tasks.md` with prose pointing
|
||||
at this change folder.
|
||||
|
||||
## Impact
|
||||
|
||||
- Public API gains `recordRender`, `recordPluginCall`,
|
||||
`startRenderTimer`, `_resetInstruments`, `RenderOutcome`,
|
||||
`PluginOutcome` re-exports. No removed exports.
|
||||
- `TemplateEngine` constructor now validates options at the boundary —
|
||||
invalid configs throw `TemplateError(TEMPLATE.PARSE_ERROR)` instead of
|
||||
silently coercing.
|
||||
- Nine new test files (~600 lines combined).
|
||||
- One new module + sibling `.md` (`src/otel/`).
|
||||
- `@opentelemetry/api` added as runtime dep; ships no-op when no
|
||||
`MeterProvider` is registered.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Capability Spec Delta: templates (spec-conformance)
|
||||
|
||||
**Package**: `@suaveplan/templates`
|
||||
**Status**: PROPOSED
|
||||
|
||||
This delta records the verification mapping that the conformance script
|
||||
(`bun scripts/openspec-conformance.ts @suaveplan/templates`) ingests and
|
||||
captures the inline drift fixes (OTel instruments, boundary validation
|
||||
of `TemplateEngineOptions` / `ParseOptions`).
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
(See `openspec/specs/templates/spec.md` for the full requirement bodies;
|
||||
this delta only records the verification mapping.)
|
||||
|
||||
| Requirement | Verified by |
|
||||
|---|---|
|
||||
| TPL-01 — Package shape and dependencies | `tests/dep-graph.test.ts` AND `src/__tests__/package-shape.spec-conformance.test.ts` |
|
||||
| TPL-02 — Subpath exports | `src/__tests__/package-shape.spec-conformance.test.ts` |
|
||||
| TPL-03 — Error hierarchy and code registry | `src/errors/template-error.test.ts` AND `src/errors/template-error.spec-conformance.test.ts` |
|
||||
| TPL-04 — Public types and SKIP_PLUGIN sentinel | `src/__tests__/types.spec-conformance.test.ts` |
|
||||
| TPL-05 — ParseState API | `src/engine/ParseState.test.ts` AND `src/engine/ParseState.spec-conformance.test.ts` |
|
||||
| TPL-06 — Boundary validation of constructor options | `src/engine/TemplateEngine.spec-conformance.test.ts::"rejects invalid options at the boundary (TPL-06)"` |
|
||||
| TPL-07 — Plugin registration and ordering | `src/engine/TemplateEngine.test.ts` AND `src/engine/TemplateEngine.spec-conformance.test.ts` |
|
||||
| TPL-08 — Sync render, async render, and recursive depth guard | `src/engine/TemplateEngine.test.ts` AND `src/engine/apply-plugin.spec-conformance.test.ts` |
|
||||
| TPL-09 — Error-suppression mode | `src/engine/TemplateEngine.spec-conformance.test.ts::"throwOnError=false swallows errors and returns original template (TPL-09)"` |
|
||||
| TPL-10 — Variable, transform, dynamic, and control-flow plugins | `src/plugins/plugins.spec-conformance.test.ts` AND the existing `src/plugins/**/*.test.ts` suite |
|
||||
| TPL-11 — Preset bundles | `src/presets/presets.spec-conformance.test.ts` |
|
||||
| TPL-12 — Utilities | `src/utils/escape.test.ts` AND `src/utils/format.test.ts` AND `src/utils/nested-value.test.ts` |
|
||||
| TPL-13 — OpenTelemetry instrumentation | `src/otel/templates-otel.spec-conformance.test.ts` |
|
||||
| TPL-14 — Quality gates | `vitest.config.ts` Istanbul thresholds + `bunx turbo test:coverage --filter=@suaveplan/templates` gate |
|
||||
|
||||
## Newly added tests in this change
|
||||
|
||||
- `src/__tests__/package-shape.spec-conformance.test.ts` — pins
|
||||
`sideEffects: false`, runtime-dep set, and the subpath export map.
|
||||
- `src/__tests__/types.spec-conformance.test.ts` — pins the
|
||||
`PluginPriority` numeric enum, the `SKIP_PLUGIN` symbol, and the
|
||||
generic-threading of `TemplateEngine<TContext>` / `Plugin<TContext>`.
|
||||
- `src/engine/ParseState.spec-conformance.test.ts` — pins
|
||||
`createParseState` defaults, deep-clone independence, counter / depth
|
||||
helpers.
|
||||
- `src/engine/TemplateEngine.spec-conformance.test.ts` — pins
|
||||
constructor-side schema validation, priority-descending ordering,
|
||||
defensive `getPlugins` snapshot, and `throwOnError=false` suppression.
|
||||
- `src/engine/apply-plugin.spec-conformance.test.ts` — pins
|
||||
reverse-index splicing and `SKIP_PLUGIN` semantics.
|
||||
- `src/errors/template-error.spec-conformance.test.ts` — pins
|
||||
`SuaveplanError` parentage, `pluginName`/`match`/`depth`/`maxDepth`
|
||||
fields, and the `TEMPLATE.*` namespace.
|
||||
- `src/otel/templates-otel.spec-conformance.test.ts` — pins the
|
||||
no-op-without-provider behaviour, the `metrics.getMeter` namespace,
|
||||
and that `parse` / `parseAsync` drive the helpers on success / skip /
|
||||
error paths.
|
||||
- `src/plugins/plugins.spec-conformance.test.ts` — pins the priority
|
||||
bands and the `Clock` / `Rng` injection contracts on
|
||||
`createDateTimePlugin` / `createUuidPlugin`.
|
||||
- `src/presets/presets.spec-conformance.test.ts` — pins the
|
||||
`minimal ⊂ standard ⊂ full ⊂ fullWithLoops` super-set relationships
|
||||
and that each call returns fresh plugin instances.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Tasks: templates-spec-conformance
|
||||
|
||||
## 1. Inline drift fixes
|
||||
|
||||
- [x] 1.1 Add `@opentelemetry/api` runtime dep (`catalog:observability`) to `packages/primitives/templates/package.json`.
|
||||
- [x] 1.2 Create `src/otel/templates-otel.ts` with `recordRender`, `recordPluginCall`, `startRenderTimer`, `_resetInstruments` + sibling `.md`.
|
||||
- [x] 1.3 Wire `recordRender` (success / error) and `recordPluginCall` (success / skip / error) into `TemplateEngine` and `applyPlugin` / `applyPluginAsync`.
|
||||
- [x] 1.4 Validate `TemplateEngineOptions` via `TemplateEngineOptionsSchema.safeParse` in the constructor, throwing `TemplateError(TEMPLATE.PARSE_ERROR)` on failure.
|
||||
- [x] 1.5 Validate `ParseOptions` via `ParseOptionsSchema.safeParse` in `parse` / `parseAsync` when callers pass options.
|
||||
- [x] 1.6 Mark `PluginPrioritySchema` as `// schema: boundary-only`.
|
||||
- [x] 1.7 Add `src/otel/templates-otel.ts` to the `tests/no-disallowed.test.ts` `APPROVED` set so the OTel timing helper can use `Date.now`.
|
||||
|
||||
## 2. Spec rewrite (folded)
|
||||
|
||||
- [x] 2.1 Rewrite `openspec/specs/templates/spec.md` to fourteen `### TPL-NN — name` requirement blocks.
|
||||
- [x] 2.2 Add `**Verified by:**` lines under each requirement naming the test files / cases that pin it.
|
||||
|
||||
## 3. Conformance tests
|
||||
|
||||
- [x] 3.1 `src/__tests__/package-shape.spec-conformance.test.ts` — TPL-01 / TPL-02.
|
||||
- [x] 3.2 `src/__tests__/types.spec-conformance.test.ts` — TPL-04 (PluginPriority enum, SKIP_PLUGIN symbol, generic threading).
|
||||
- [x] 3.3 `src/engine/ParseState.spec-conformance.test.ts` — TPL-05.
|
||||
- [x] 3.4 `src/engine/TemplateEngine.spec-conformance.test.ts` — TPL-06 / TPL-07 / TPL-09.
|
||||
- [x] 3.5 `src/engine/apply-plugin.spec-conformance.test.ts` — TPL-08.
|
||||
- [x] 3.6 `src/errors/template-error.spec-conformance.test.ts` — TPL-03.
|
||||
- [x] 3.7 `src/otel/templates-otel.spec-conformance.test.ts` — TPL-13.
|
||||
- [x] 3.8 `src/plugins/plugins.spec-conformance.test.ts` — TPL-10.
|
||||
- [x] 3.9 `src/presets/presets.spec-conformance.test.ts` — TPL-11.
|
||||
|
||||
## 4. Archive hygiene
|
||||
|
||||
- [x] 4.1 Replace the bulk-archive marker line in `openspec/archive/2026-04-19-enterprise-templates/tasks.md` with a pointer to this change folder.
|
||||
|
||||
## 5. Verification
|
||||
|
||||
- [x] 5.1 `bun scripts/openspec-conformance.ts @suaveplan/templates` — green (no errors; warnings for boundary-only schemas tolerated).
|
||||
- [x] 5.2 `bunx turbo lint typecheck test --filter=@suaveplan/templates` — green.
|
||||
- [x] 5.3 `bunx turbo test:coverage --filter=@suaveplan/templates` — 100/100/100/100.
|
||||
Reference in New Issue
Block a user