# Tasks: validation-critical-bugfix ## 1. Critical bug fixes - [x] 1.1 `BaseSchema.parse` and `BaseSchema.safeParse` MUST loud-fail with `VALIDATION.ASYNC_REFINEMENT_REQUIRES_PARSEASYNC` when any refinement is async (no more silent skip). - [x] 1.2 Register the new code in `VALIDATION_CODES` and the `ValidationCode` string-union type. - [x] 1.3 `coerceString` returns `null` for non-coercible `symbol` inputs. ## 2. Ghost-API wiring - [x] 2.1 Add `BaseSchema.withHooks(hooks)` returning an immutable clone with merged hooks. Carry `_hooks` through `_clone()`. - [x] 2.2 Invoke `beforeValidate` / `afterValidate` / `onError` from `parse` (sync, return value discarded) and `parseAsync` (awaited) at every terminal branch. `safeParse` re-implemented as a try-catch shim so hooks + OTel fire on the safe path too. - [x] 2.3 Wire `recordParseSuccess` / `recordParseFailure` and duration histogram via `performance.now()` at every terminal branch of `parse` and `parseAsync`, tagged with `schema.type = this.constructor.name`. ## 3. Type surface - [x] 3.1 Add `declare protected readonly _phantomInput: TInput` on `BaseSchema` so `InferInput` resolves to the schema's input type instead of degrading to `unknown`. ## 4. Tests - [x] 4.1 Replace `schema.test.ts::"sync parse skips async refinements without error"` with two scenarios: sync `parse` throws `ASYNC_REFINEMENT_REQUIRES_PARSEASYNC` and `safeParse` returns a failure with the same code. - [x] 4.2 Add `coerce.test.ts::"returns null for symbol input"`. - [x] 4.3 Existing `schema.spec-conformance.test.ts` (VL-01, VL-02, VL-10, VL-11) now passes against the wired implementation. ## 5. Spec annotations - [x] 5.1 Add `**Verified by:**` line under every VL-NN requirement in `openspec/specs/validation/spec.md`. - [x] 5.2 Add new requirement VL-13 (async-refinement loud-fail). ## 6. Verify - [x] 6.1 `bunx turbo lint typecheck test --filter=@suaveplan/validation` green. - [x] 6.2 `bunx turbo test:coverage --filter=@suaveplan/validation` 100/100/100/100. - [x] 6.3 `bun scripts/openspec-conformance.ts @suaveplan/validation` exits 0. ## 7. Fold + archive - [x] 7.1 Fold delta into `openspec/specs/validation/spec.md`. - [x] 7.2 Move `openspec/changes/validation-critical-bugfix/` to `openspec/archive/2026-04-27-validation-critical-bugfix/`. - [x] 7.3 Move the now-superseded `openspec/changes/validation-spec-conformance/` to `openspec/archive/2026-04-27-validation-spec-conformance/` (its scope is fully subsumed by this change).