Skip to content

[finding] the hook metadata type's authorable keys reach no key-level ratchet — HookSchema emits no JSON Schema, so authorable-surface/ holds zero data/Hook: keys #16906

Description

@claude

Found by the domain:spec execution seat while implementing #16431 option (c) — the never-published ratchet. Out of scope there by that card's own fence (triage ruled (c) reports what is already true and changes no schema), so it is filed rather than fixed. Unassigned, bare, for triage.

Measured on origin/main @ 142c01c88ee1be4c24e20f7b803a511a00c992fb

hook is a declared metadata type that authors write as documents — packages/spec/src/kernel/metadata-plugin.zod.ts:800:

{ type: 'hook', label: 'Hook', filePatterns: ['**/*.hook.ts', '**/*.hook.yml'],
  supportsOverlay: false, allowOrgOverride: false, allowRuntimeCreate: true,}

HookSchema emits no JSON Schema. From pnpm --filter @objectstack/spec check:authorable-surface (exit 0 — the skip is a warn):

⊘ Data.HookSchema: Custom types cannot be represented in JSON Schema (skipped)

The unrepresentable member is the deprecated inline-function half of handler, packages/spec/src/data/hook.zod.ts:252:

handler: z.union([z.string(), z.custom<(...args: any[]) => any>()]).optional()

What that costs, beyond the missing reference page

Counted in packages/spec/, each with a firing control on the same corpus:

grep -ho '"data/Hook:[^"]*"'        authorable-surface/data.json | wc -l   ->  0
grep -ho '"data/HookContext:[^"]*"' authorable-surface/data.json | wc -l   -> 14   (control)
grep -ho '"data/Object:[^"]*"'      authorable-surface/data.json | wc -l   -> 43   (control)

grep -c '"data/Hook"'        json-schema.manifest/data.json   -> 0
grep -c '"data/HookContext"' json-schema.manifest/data.json   -> 1    (control)

So the authorable keys of a live, author-written metadata type are recorded by no key-level ratchet:

build-schemas.ts records the mechanism in its own words, in the #4725 block: reachability "is keyed by zodByDefKey, populated only for defs this build EMITS". The measurements above are direct; the mechanism pointer is offered as the likely cause, not as a proof.

Sibling instance, same shape

Data.MemoryConfigSchema — a memory datasource's authorable config — is unprojectable for the same structural reason: exactly one branch of its persistence union ({ type: 'custom', adapter }) carries live functions, while everything an author can write in YAML is representable. Both are now recorded in packages/spec/unemitted-schemas.baseline.json with that reasoning.

Why this is worth a card rather than a passing note

#16431 measured the population (23 exports) and ruled its own remedy scope to the four filter.zod.ts exports whose cause is z.date(). This one has a different cause (z.custom), a different remedy, and a consequence that card does not state: it is not only a documentation gap but a ratchet coverage gap on a metadata type the platform invites authors to write.

A plausible remedy is narrow: the inline-function handler form is already marked DEPRECATED in favour of body, so retiring that union member (ADR-0049 enforce-or-remove, with the ADR-0087 conversion the retirement kit requires) would make HookSchema projectable and pull its keys back under both ratchets. That is a decision, not an edit — hence this card.

Refs: #16431 · #3855 · #4650 · #4666 · #2978 · #4725


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions