Schema designer
Skill JayLBean/supervised-prompt-producer/skills/run/sub-skills/schema-designer
Disciplined, human-in-the-loop supervised prompt learning for Claude Code — turn a labeled baseline into a production-grade prompt you can defend in review, with evidence not vibes. Classification, structured extraction, and prompt decomposition.From the repository description
npx -y skills add JayLBean/supervised-prompt-producer --skill schema-designerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
45.7 KB, as published. Nobody here has run it
schema-designer
A v0.2 sub-skill of spp that produces a production-grade
OUTPUT_SCHEMA for a supervised prompt-learning task and gates
whether downstream phases are allowed to operate against it. The
v0.2 analog of v0.1.0's single LABEL_SPACE field —
OUTPUT_SCHEMA is an arbitrary structured output (one or more
fields, possibly nested), expressed as a JSON Schema (draft
2020-12) document and rendered into plan.md §2 in the user's
chosen YAML or JSON surface format.
This is the fourth sub-skill in spp (peer to metric-design,
baseline-quality, and prompt-architect) and the second
sub-skill that carries verdict-gate authority. The verdict-token
- enforcement-at-gate pattern is inherited from
baseline-qualitySKILL.md §2; the design contract this sub-skill realizes isDESIGN.md§7.1.1's schema layer.
A note on artifact shape before reading further. spp has three:
phases (orchestration, gate enforcement; user-facing entry
points), agents (judgment with structurally distinct
information access; invoked by phases), and sub-skills like
this one (opinionated reference material that informs decisions
and, when verdict-gated, blocks the gate the sub-skill defends).
A user reading this doc should come away knowing how to design
an OUTPUT_SCHEMA themselves; if follow-up consultation is needed,
the designer agent does it (and reads this doc to know which
follow-up to ask).
This sub-skill ships standalone in its first PR — the
schema-designer directory and its fixtures land before any
phase doc, agent doc, or template references it. Integration
into the live /spp-init flow (which gate slot the verdict
gates, how the designer agent invokes the sub-skill, how
plan.md.template carries OUTPUT_SCHEMA) is bucket 4 of the
v0.2 sequence — see "Cross-references" for what changes when.
The sub-skill is functional and citable in design discussions
from this PR forward; it is not yet wired into a runnable phase.
1. Identity and scope
schema-designer performs two related jobs that share one
verdict gate:
- Render an
OUTPUT_SCHEMAfrom the user's task — either built strawman-first by the designer (Path 1) or validated from a complete artifact the user brings (Path 2). - Validate the rendered schema against a two-layer rule set (mechanical + judgment-driven) and return a verdict that gates whether the rest of the methodology is allowed to operate against the schema.
The framing. v0.1.0's LABEL_SPACE field encoded the task's
output shape implicitly — a finite enum of class names. v0.2
generalizes the slot: any task whose ground truth is a
structured object (multi-field classification, hierarchical
labels, freeform extraction with structured ground truth) is
expressible as an OUTPUT_SCHEMA. The risk this sub-skill exists
to defend against is the schema-layer analog of baseline
overfitting: a schema that mechanically validates but does not
actually describe the task — vague field names, non-exhaustive
enums, missing relationships between fields, over-rich shapes
that invite scope drift — produces a methodology that polishes
toward an ill-formed target and never surfaces the mismatch.
schema-designer is the upstream defense for that mode.
In scope:
- Rendering OUTPUT_SCHEMA as JSON Schema (draft 2020-12), serialized as YAML or JSON per the user's choice.
- Path 1 (consultative): strawman-and-refine when the user has prose, partial pydantic, JSON examples, or just a conversation. Anything not a complete machine-readable artifact is Path 1 context.
- Path 2 (validated): validate-then-calibrate when the user brings a complete machine-readable JSON Schema or pydantic model.
- Two-layer validation — mechanical rules that pass/fail on parser output, plus judgment-driven rules that require the sub-skill's verdict.
- Per-field calibration: the v0.2 analog of v0.1.0's class-
definition calibration that
baseline-qualityruns (§3.1drift,§3.3intuition-vs-rule), applied per OUTPUT_SCHEMA field. - The degenerate single-output case: a v0.1.0-equivalent
shape (
{label: <enum of class names>}) is rendered as the same OUTPUT_SCHEMA shape any multi-field task uses, just with one required enum field. No shorthand, noLABEL_SPACElegacy alias inside the schema. - The extraction shape (
TASK_MODE = extraction; v0.10,DESIGN.md§7.1.11): a row's ground truth is a variable-cardinality set of extracted items, expressed as a JSON Schemaarraywhoseitemsare either strings (text-only spans) or objects with atextfield, an optionaltypeenum (entity category), and optionalstart/endcharacter offsets. Offsets are optional by design so that redaction- and phrase-extraction tasks with no reliable spans and offset-grounded NER tasks share one schema family; when present, offsets are scored by the span metrics, when absent, by set/text alignment (metric-designextraction branch). The array carries no fixed cardinality — the count varies per row, which is exactly what distinguishes extraction from a fixed multi-field classification object.
Out of scope (boundaries, not deferred work):
- Schema synthesis from data alone. The sub-skill does not
scan a baseline CSV and infer fields by clustering. The user
defines the task;
schema-designerrenders and validates. Synthesis-from-data crosses into a different methodology whose validation primitives this sub-skill does not have. - LLM-as-judge validation. Mechanical layer rules pass/fail
on a JSON Schema parser; judgment layer rules require human
judgment. The sub-skill does not invoke an LLM judge to
decide whether a schema is "good enough"; that would import
the
metric-design§5 independence-rule failure into the schema layer. - Generation-task output schemas. Free-form text-generation
outputs do not have ground truth in the way classification
and structured extraction do (
DESIGN.md§7.1.3). This sub-skill does not extend to them; v0.x will not. - Conversion-tooling for source-language schemas. Pydantic, TypeScript interfaces, and Zod schemas are paste-as-context during Path 1, not separate-format-converters the sub-skill must plumb. Path 2 takes only JSON Schema or pydantic (the latter via its built-in JSON-Schema export); other formats are converted to one of those by the user before invoking Path 2.
- Touching the baseline or splits. OUTPUT_SCHEMA design
precedes label generation; splits do not exist when
schema-designerruns. The sacred-test-set guarantee (DESIGN.md§10) is not at risk.
The cross-skill rule that governs every choice in this doc is
the plan.md-as-contract rule (DESIGN.md §10): findings
flow back into plan.md, not into a separate document. The full
elaboration is in §5 below.
2. The decision the sub-skill helps make
Is this OUTPUT_SCHEMA a faithful description of the task — mechanically valid, semantically complete, no broader than the task needs — and is it ready for the rest of the methodology to operate against?
The output of consulting schema-designer is three things, all
of which feed into the verdict gate the sub-skill defends:
- A verdict, one of:
ready— the schema passes both mechanical and judgment layers; the gate advances on the user's approval phrase.revise— specific judgment-layer issues exist that should be fixed before the schema is treated as ground truth, but the user can choose to proceed with a documented justification inplan.md§11.not-ready— substantive issues exist (any mechanical failure, or a judgment failure severe enough that the schema does not actually describe the task). The gate does not advance on the user's approval phrase alone; the user must either resolve the issues (and re-invoke) or record an explicit override entry inplan.md§11 containing the literal substringschema-not-ready override. The override propagates intoREPORT.md's acknowledged-risk surface (§6 below).
- A finalized
OUTPUT_SCHEMArendered in the user's chosen surface format (YAML or JSON) inside a fenced code block. Returned regardless of verdict — even anot-readyverdict returns the latest schema state so the user has a concrete artifact to revise from. - A findings document (only when the verdict is
reviseornot-ready): each violated rule named explicitly, with the rule's layer (mechanical vs judgment), the specific failure, and the corrective action. Required so the user can act without re-deriving the findings.
The verdict has gate-enforcement teeth via the integration that
will land in bucket 4 of the v0.2 sequence; the literal-substring
override is the contract that integration will wire into the
runner. Future contributors must not weaken this authority — see
"Versioning" below; weakening is a BREAKING CHANGE:.
3. The protocol
Walk in order. The protocol has three stages: path detection (§3.1), path-specific rendering (§3.2 or §3.3 — exactly one), and the two-layer validation (§3.4 mechanical, §3.5 judgment-driven) that runs after either path completes. Verdict synthesis (§3.6) aggregates the layer outcomes into the single token returned at §6.
3.1 Path detection
Question: does the user's input include a complete, machine-readable JSON Schema or pydantic model that already describes the task's output?
- Yes — exactly one complete artifact, parseable without modification → Path 2 (validated). Skip §3.2; go to §3.3.
- No — prose, partial pydantic, JSON examples, conversation, multiple disagreeing artifacts, or anything requiring interpretation before rendering → Path 1 (consultative). Skip §3.3; go to §3.2.
The framing matters. "Existing schema" in informal use means context the user brings to Path 1 (pydantic models pasted as text into the chat, TypeScript interfaces, Zod schemas, prose descriptions in a doc) — not a structured artifact in Path 2's sense. Only Path 2 takes a structured artifact as input. The implication is that there is no conversion-tooling burden on the sub-skill: users who arrive with TypeScript or Zod paste their artifact into the consultation, the designer extracts intent, and Path 1 renders. Path 2 is reserved for cases where the user already speaks in JSON Schema or pydantic and wants no interpretation between their artifact and the rendered OUTPUT_SCHEMA.
When in doubt, prefer Path 1 — the cost of an unnecessary strawman is a paragraph of consultation; the cost of treating ambiguous input as a finalized artifact is a schema that mechanically validates but does not describe the task.
3.2 Path 1 — consultative (strawman-and-refine)
The strawman-first pattern from the designer agent (§4 of
agents/designer.md), specialized to schema design.
- Read the repo and the user's context. Existing types (pydantic models, TypeScript interfaces, Zod schemas, GraphQL types, prose docs, JSON examples) are paste-as-context inputs. Note any field names or shapes that already exist in the codebase.
- Build a strawman OUTPUT_SCHEMA. Concrete: name the
fields, give each a JSON Schema
type, enumerate enum values explicitly, mark required vs optional explicitly, and include at least one example output that validates. Render in YAML or JSON — pick the surface format that matches the user's existing artifacts (TypeScript and pydantic users tend toward JSON; YAML repos tend toward YAML); the user can swap. - Present the strawman with the rationale. Explain why
each field is shaped the way it is, surfacing the
assumptions the strawman embeds (e.g., "I made
statusa 3-value enum because your CSV had three distinct values; are there others I missed?"). - Refine through correction. The user adds, removes, renames, or reshapes fields. Each refinement re-renders the schema. Stop refining when the user says the schema looks right (or when refinement loops for more than 2–3 cycles without progress — that is a signal the task description is too thin to render reliably. Halt, surface the gap to the user, and re-run §3.1 to confirm whether they can now provide enough context for Path 1 or whether they have a complete artifact for Path 2).
- Hand off to §3.4 with the refined schema.
The defining property of Path 1 is that the sub-skill renders the canonical artifact; the user is not expected to write JSON Schema themselves.
3.3 Path 2 — validated (validate-then-calibrate)
The user already speaks in JSON Schema or pydantic and brings a complete artifact. The sub-skill validates and calibrates; rendering is a serialization step (re-render to the user's chosen surface format if it differs from what they brought).
- Parse the artifact. Pydantic models export to JSON
Schema via
model_json_schema(); the parsed result is the canonical form. JSON Schema artifacts are parsed directly. - Confirm draft compliance. The schema must be valid JSON Schema draft 2020-12. Other drafts (draft-07, draft 2019-09) are converted to 2020-12 if the user accepts the conversion; otherwise the artifact is rejected at §3.4 (mechanical layer) and the user is asked to update.
- Render in the chosen surface format. YAML or JSON. The
serialization round-trips:
yaml.safe_load(yaml_form) == json.loads(json_form). - Calibrate the per-field definitions. Even with a
complete schema, the user articulates each field's intent
in plain English — same calibration discipline as
baseline-qualitySKILL.md §3.1's drift check, applied per field. Mismatches between the schema's structure and the user's articulated intent are findings for §3.5 (judgment layer). - Hand off to §3.4 with the parsed-and-rendered schema.
The defining property of Path 2 is that the schema is the input; the sub-skill's job is to confirm the schema describes the task the user intends.
3.4 Mechanical layer (always run, regardless of path)
The mechanical rules pass or fail on parser output. They do not
require the sub-skill's verdict; they fail or pass deterministically.
A failure at this layer is a not-ready signal — the schema
cannot be validated against until the failure is fixed.
Rules 1–7 are verbatim from DESIGN.md §7.1.1's schema layer;
rule 8 is the v0.10 extraction-mode addition (DESIGN.md §7.1.11):
- Schema parses as valid JSON Schema (draft 2020-12).
- Every field has a JSON Schema
type. - Every enum field's values are explicitly enumerated (no
plain
"type": "string"where an enum is intended). This applies only to fields intended as enums; an extraction schema's free-text item field ({type: string}inside an item array) is not an enum and does not trigger this rule. - Required vs. optional is explicit on every field (no implicit defaults).
- At least one example output validates against the schema (the schema-actually-describes-the-task test).
- No
$refcycles. - No naked
"type": "object"without either"properties"or"additionalProperties": false. TASK_MODE/ schema-shape consistency (v0.10,DESIGN.md§7.1.11). The schema's shape class must match theplan.md§1TASK_MODEthe designer recorded:TASK_MODE = extractionrequires the output (or a field of it) to be a variable-cardinalityarrayof extracted items — an unbounded item collection, not a fixed tuple. An extraction mode whose schema is a bare enum or a fixed object of scalar fields fails this rule.TASK_MODE = classification(the default) requires a fixed output space — an enum, or an object of fields each with its own label space — and must not be a variable-cardinality item array. A classification mode whose schema is an unbounded item array fails this rule. The check readsTASK_MODEonly to pick which shape the schema must have; it adds no other input. Absent or unsetTASK_MODEreads asclassification, so pre-v0.10 schemas are unaffected.
For each rule that fails, the findings document names the rule number, the field or schema location, and the corrective action. The mechanical layer does not aggregate — every violation is reported.
3.5 Judgment-driven layer (always run, regardless of path)
Judgment rules cannot be checked mechanically. The sub-skill asks the questions; the user (with the sub-skill prompting and checking) answers; the sub-skill aggregates the answers into verdict signals.
Verbatim from DESIGN.md §7.1.1's schema layer:
- Enum exhaustiveness. For each enum field, ask: are these
the only values the task generates in production, or are
these the common values and the residual is "Other"? An
enum that is missing the residual is a
revisesignal — either add the residual values explicitly, or add a documentedOthercategory with calibration on what counts as Other (the analog of v0.1.0's discipline against anOtherclass as a dumping ground; ifOtherexists, it needs a definition tighter than "everything else"). - Field-name clarity (cold-read test). A labeler reading
the schema cold — without consulting the per-field
definitions — should be able to label rows without guessing
the field's intent. Field names like
data,info,metadata,extra,detailsare signals: they label a shape, not a meaning.revisesignal. - Borderline-example concreteness. For each field, the
per-field definition includes positive and borderline
examples. The borderlines must be concrete enough to
disambiguate the field's intent — same standard as v0.1.0's
class definitions (
baseline-qualitySKILL.md §3.3). Vague borderlines ("things that might be X") are arevisesignal. - Relationship capture. If the task requires conditional
fields, nested fields, or cross-field constraints (e.g.,
field B is only meaningful when field A is
Yes), the schema must express those relationships —if/then/else,oneOf,dependentRequired, nested objects with their ownproperties. Flattening relationships into a wider tuple of independent fields is arevisesignal. - Schema scope discipline. The schema is no broader than
the task requires. Over-rich schemas (every field the
labeler could annotate, regardless of whether the task
needs it) invite scope drift across iterations. The analog
of v0.1.0's "no Other class as a dumping ground"
discipline, applied to the schema's surface area as a
whole. A schema visibly broader than the task is a
revisesignal; a schema dramatically broader (e.g., 12 fields when the task description supports 4) is anot-readysignal.
Multilingual input (v0.6). When the dataset spans multiple
languages (a per-row language column; DESIGN.md §7.1.7), the
output label space stays canonical — one fixed enum regardless of
the input row's language. The model classifies non-English input into
the same labels; do not localize enum values per language or branch the
schema on language. Per-language label variants are a revise signal:
they fragment the metric space and break the fixed-output-space
assumption the rest of the methodology rests on. Translating the
labeler-facing definitions for annotators is fine; the schema's
enum values are canonical.
For each rule that fails, the findings document names the rule number, the field, the specific failure, and the corrective action. Multiple judgment failures aggregate per §3.6.
3.6 Verdict synthesis
| Signal pattern | Verdict |
|---|---|
| All mechanical rules pass; all judgment rules pass | ready |
All mechanical rules pass; one or more judgment rules trigger revise (no not-ready signal) | revise |
| Any mechanical rule fails | not-ready |
Any judgment rule fires the not-ready signal explicitly (rule 5's "dramatically broader" case) | not-ready |
Mechanical failures dominate. A schema that does not parse, or
has a $ref cycle, or has implicit-default required fields
cannot be partially-okay; the rest of the methodology cannot
operate against an unparseable schema. This is why the layer
split exists — mechanical failures are categorical
disqualifications; judgment failures are graded.
4. Worked examples
Five scenarios, mapped to the five fixtures in fixtures/.
None references a real source-project task (DESIGN.md §7.2);
each is a generic shape the designer might encounter.
Example 1: consultative happy path → ready
Setup. The user is building a product-listing extractor.
They have a CSV of marketplace listings (4,200 rows, columns
include raw title, body, seller_id, and a recently-added
source_marketplace flag). They describe the task as: "I want
to pull title, price, category, and brand out of each
listing into a structured record. category is one of about a
dozen marketplace-defined buckets; brand is sometimes
unknown."
Path detection (§3.1). No machine-readable schema; user provides prose + a CSV they reference. → Path 1.
Path 1 walk (§3.2). The designer reads the CSV, notes the
12 distinct category values, builds a strawman:
$schema: https://json-schema.org/draft/2020-12/schema
type: object
required: [title, price, category, brand_known, brand]
additionalProperties: false
properties:
title:
type: string
description: The listing's product title, normalized.
price:
type: number
minimum: 0
description: The listing's price in the marketplace's local currency.
category:
type: string
enum: [electronics, apparel, home, toys, beauty, sports,
books, automotive, garden, pet, grocery, other]
description: The marketplace's category bucket for the listing.
brand_known:
type: boolean
description: Whether the brand can be extracted from the listing.
brand:
type: [string, "null"]
description: The brand name, or null when brand_known is false.
examples:
- title: "Acme Cordless Drill, 12V"
price: 79.99
category: home
brand_known: true
brand: "Acme"
- title: "Generic Cotton T-Shirt"
price: 14.50
category: apparel
brand_known: false
brand: null
The user accepts after one refinement (the user adds that
category should include health as a 13th value).
§3.4 mechanical: all 8 rules pass. One example validates
against the schema; no $ref cycles; every field has a type;
the enum is enumerated; required is explicit;
additionalProperties: false closes the object. Rule 8: this is
TASK_MODE = classification (a fixed object of fields, not a
variable-cardinality item array — despite the "extractor" framing,
each row yields exactly these four fields), and the schema shape is
a fixed object — consistent.
§3.5 judgment: enum is exhaustive after the health
addition; field names are clear (a labeler reading
brand_known + brand cold understands the conditional
relationship); borderlines are concrete; the conditional
relationship is captured (brand is [string, "null"] paired
with brand_known); scope is tight (4 fields, exactly what the
task description supports).
Verdict: ready.
Outputs: verdict ready, OUTPUT_SCHEMA above, no findings
list (none needed for ready).
Example 2: validated happy path → ready
Setup. The user is a pydantic native and brings a complete model:
from pydantic import BaseModel, Field
from typing import Literal
class TicketTriage(BaseModel):
queue: Literal["billing", "general", "abuse"] = Field(
description="The queue the ticket routes to.")
urgency: Literal["low", "normal", "high"] = Field(
description="The ticket's urgency tier at intake.")
requires_human_review: bool = Field(
description="True when the model is below its confidence "
"threshold for autonomous routing.")
The user requests YAML rendering.
Path detection (§3.1). Complete machine-readable artifact, parses without modification. → Path 2.
Path 2 walk (§3.3). model_json_schema() returns a JSON
Schema document; conversion to draft 2020-12 is mechanical (the
pydantic export already targets a recent draft). Rendered in
YAML for the user.
The sub-skill walks the calibration discipline: for each field,
the user articulates the meaning. queue → "the queue the
ticket routes to." urgency → "the urgency tier we tag for
prioritization within the queue." requires_human_review →
"when the model's autonomous routing falls below confidence,
the ticket goes to a human." Articulations match the schema's
intent.
§3.4 mechanical: all 8 rules pass (rule 8: TASK_MODE = classification, a fixed enum-field object — consistent).
§3.5 judgment: all 5 rules pass — the enums are exhaustive within the production system, names are clear, borderlines are captured in the user's articulation, no relationships are hidden, scope matches the task.
Verdict: ready.
Outputs: verdict ready, the rendered YAML form of the
JSON Schema, no findings list.
Example 3: mechanical violation → not-ready
Setup. A user brings a JSON Schema for a multi-class
moderation task and pastes it into the consultation. The
schema looks plausible but has a mechanical flaw: the
category field is rendered as "type": "string" with no
enum clause, even though the user's task description names
six specific categories the model must choose from.
Path detection (§3.1). Complete machine-readable JSON Schema → Path 2.
Path 2 walk (§3.3). Schema parses as JSON Schema draft
2020-12. Renders cleanly in JSON. Calibration walk: the user
articulates category as "one of {harassment, spam, csam,
violence, self-harm, other-violation}." The articulation
contradicts the schema, which permits any string.
§3.4 mechanical: rule 3 fails — category is rendered as
plain "type": "string" where the user's articulation
indicates an enum is intended. Findings document names rule 3
explicitly:
Rule 3 (enum enumeration) — failed at field
category. The field is rendered as"type": "string"but the user's articulation enumerates six specific values{harassment, spam, csam, violence, self-harm, other-violation}. Render the field as"enum": [...]with those six values (and add a documented residual category if the production data surfaces values outside the six). Until this is fixed, the schema cannot be operated against — a freeform string field cannot be scored against a fixed-enum ground truth.
§3.5 judgment: not run — mechanical layer dominates.
Verdict: not-ready.
Outputs: verdict not-ready, the user-supplied schema
returned as the latest state (so the user has a concrete
artifact to fix), findings list naming rule 3.
The user fixes the schema and re-invokes; the second pass
returns ready. If the user instead wanted to override (rare
and discouraged), they record an explicit entry in plan.md
§11 whose Reason field contains the literal substring
schema-not-ready override and the limitation propagates into
REPORT.md (§6 below).
Example 4: judgment violation → revise
Setup. The user is building an issue-categorization task for a public bug tracker. They bring a schema with three fields:
$schema: https://json-schema.org/draft/2020-12/schema
type: object
required: [type, severity, info]
additionalProperties: false
properties:
type:
type: string
enum: [bug, feature, question]
description: The issue's type.
severity:
type: string
enum: [low, high]
description: The severity of the issue.
info:
type: string
description: Additional context.
Path detection (§3.1). Complete YAML JSON Schema → Path 2.
§3.4 mechanical: all 8 rules pass — the schema is
parseable, fields have types, enums are enumerated, required
is explicit, an example would validate, no $ref cycles, the
object is closed, and rule 8 is consistent (TASK_MODE = classification, a fixed-field object).
§3.5 judgment:
- Rule 1 (enum exhaustiveness):
typeis missing common categories — public bug trackers routinely surfacetask,documentation, anddiscussionissues that don't fit{bug, feature, question}.severitycollapses an inherently 3+ tier scale into a binary. Both firerevise. - Rule 2 (field-name clarity):
infois a shape, not a meaning. A labeler readinginfocold cannot tell whether it should contain reproduction steps, tracebacks, the user's environment, or the bot's triage notes.revise. - Rule 3 (borderline concreteness): no per-field borderlines
are provided in the schema's
descriptionfields; just shape descriptions.revise. - Rule 4 (relationship capture): no relationships expressed, but the task does not require any (no conditional fields). Pass.
- Rule 5 (scope discipline): three fields is not over-rich;
if anything,
infois so vague it might not belong at all. Pass; folded into rule 2's finding.
Verdict: revise.
Findings list:
Rule 1 (enum exhaustiveness) —
type. The enum{bug, feature, question}is missing common values production bug trackers surface (task,documentation,discussion). Either add them, or add a documentedotherwith calibration on what counts asother.Rule 1 (enum exhaustiveness) —
severity. The two-value enum{low, high}collapses an inherently 3+ tier scale. Addmedium(and possiblycritical); document the labeling rule that distinguishes them.Rule 2 (field-name clarity) —
info. The field name is a shape, not a meaning. Either rename to the specific role the field plays (reproduction_steps,triage_notes,environment) or remove the field if no specific role is needed.Rule 3 (borderline concreteness) — all fields. The
descriptionstrings name what each field is, but do not include borderline examples. Add positive and borderline examples per field (the v0.2 analog of v0.1.0's class definitions; same calibration discipline asbaseline-qualitySKILL.md §3.3).
Outputs: verdict revise, the user-supplied schema
returned as latest state, findings above.
The user fixes the schema and re-invokes for ready, or
records a plan.md §11 entry mentioning schema-designer as
the reason for proceeding without fixing — revise does not
require the literal schema-not-ready override substring; only
not-ready does.
Example 5: extraction happy path → ready
Setup. The user is building an entity extractor over support
emails. The task they describe: "pull every product mention and
every organization name out of the email body — there can be zero,
one, or many of each, and I want the exact text plus where it
appears so I can highlight it in the UI." The designer recorded
TASK_MODE = extraction during task-mode identification
(agents/designer.md), because the answer to "one choice from a
fixed list, or an open-ended set found in the text?" was the latter.
Path detection (§3.1). No machine-readable schema; prose plus a description of the desired output. → Path 1.
Path 1 walk (§3.2). The designer confirms the item types
(product, org), that one item is one contiguous mention, and
that the UI needs offsets — so offsets are present here (the
offset-optional schema family carries them when the task has them).
Strawman:
$schema: https://json-schema.org/draft/2020-12/schema
type: object
required: [entities]
additionalProperties: false
properties:
entities:
type: array
description: >
Every product or organization mention found in the email body,
in order of appearance. Empty array when the body has none.
items:
type: object
required: [text, type, start, end]
additionalProperties: false
properties:
text:
type: string
minLength: 1
description: The exact mention substring, verbatim from the body.
type:
type: string
enum: [product, org]
description: The entity category.
start:
type: integer
minimum: 0
description: Character offset of the mention's first character.
end:
type: integer
minimum: 0
description: Character offset one past the mention's last character.
examples:
- entities:
- {text: "Acme Drill", type: product, start: 12, end: 22}
- {text: "Acme Corp", type: org, start: 40, end: 49}
- entities: []
§3.4 mechanical: all 8 rules pass. The schema parses; every
field has a type; the type enum {product, org} is enumerated
(rule 3 applies to this genuine enum, not to the free-text text
field); required is explicit on the item object; both examples
validate (including the empty-array row); no $ref cycles; the
item object is closed. Rule 8: TASK_MODE = extraction and the
output is a variable-cardinality array of item objects — the
shapes are consistent.
§3.5 judgment: the type enum is exhaustive for the task
(product, org — the user confirms no third category); field
names are clear (text, type, start, end cold-read cleanly);
the borderline calibration came from §5.1's extraction reframe
(what counts as one mention; overlapping spans resolved to the
longest match); no cross-field relationships are needed beyond the
item object; scope is tight (four item fields, exactly what the
highlight UI needs).
Verdict: ready.
Outputs: verdict ready, OUTPUT_SCHEMA above, no findings list.
Had the user instead recorded TASK_MODE = extraction but brought a
bare-enum schema, rule 8 would fail and the verdict would be
not-ready until the schema is rendered as an item array (or the
mode corrected).
5. The cross-skill constraint
Findings flow into plan.md, not into a separate artifact.
This is the operational form of the plan.md-as-contract rule
(DESIGN.md §10 glossary), the same constraint that governs
baseline-quality (SKILL.md §5). Two specific destinations:
plan.md§2 carries theOUTPUT_SCHEMAblock and aSCHEMA_DESIGN_NOTEparagraph (the §2 output of this sub-skill, the analog ofbaseline-quality'sBASELINE_QUALITY_NOTEin §6). The note names what the sub-skill reviewed (which path was taken; which mechanical and judgment rules ran), what was found, and what was resolved. The note is required regardless of verdict — even areadyverdict gets a note saying "review performed, schema rendered, no issues surfaced."plan.md§11 (revision log) gains a row whenever schema-designer caused a change to §2 (schema refinement, per-field definition update, surface-format swap), §10 (new open question surfaced — e.g., a residual-category value the user could not enumerate), or any override — bothnot-ready override(literal substring required) andreviseacknowledgement (no specific substring required). The row follows the standardplan.md.template§11 schema (date, plan version, reason, by) and bumpsPLAN_VERSIONbecause the contract has changed.
What the sub-skill does not do:
- It does not write a separate
schema_quality_review.mdoroutput_schema.jsontoplan.md's sibling files. The schema and findings live inplan.md's prose; separating them would create two sources of truth. - It does not silently rewrite a user-provided schema in Path 2. Findings are surfaced; the user decides whether to accept the proposed corrections, accept some and reject others, or override. The verdict reflects the surfaced state, not the sub-skill's preferred fix.
- It does not annotate
data/baseline.csvrows with schema metadata. The CSV is the raw labeled data; schema lives inplan.md.
There is one place where the sub-skill's verdict does have
force outside plan.md: it gates whether the phase the
integration PR (bucket 4) wires it into is allowed to advance.
That force is operational (the runner consults the verdict at
the gate; the literal schema-not-ready override substring is
the override mechanism), not documentary (no separate verdict
file is written).
Forward-looking note on integration. This PR ships the
sub-skill standalone. The references above to plan.md §2
carrying the OUTPUT_SCHEMA block are forward-looking — the
v0.1.0 plan.md.template does not yet have an OUTPUT_SCHEMA
slot. That template change is part of the breaking-change PR
in bucket 5; the gate-slot wiring is part of bucket 4. The
sub-skill is functional as a reference document and as a
fixture-driven validator from this PR forward; the integration
PRs will edit designer.md, plan.md.template, and the
relevant phase doc to invoke it.
6. What the sub-skill outputs
Three things the caller (the designer agent, in bucket 4's
integration) collects after the protocol walk, all of which
feed into the gate enforcement and the plan.md updates.
Verdict
One of:
ready— schema passes both layers; gate advances on user approval phrase alone.revise— judgment-layer issues exist; user can fix and re-invoke, or proceed with a documented justification inplan.md§11 whose Reason mentionsschema-designer. No specific literal substring is required (parallel tobaseline-quality'srevisetreatment).not-ready— mechanical-layer failure or severe judgment- layer failure (rule 5 dramatic over-richness); gate does not advance on user approval phrase alone. Override requires an explicitplan.md§11 entry whose Reason field contains the literal substringschema-not-ready override. The override propagates intoREPORT.md's acknowledged-risk surface (the same shape asbaseline-quality'snot-ready overridepropagation intoREPORT.md§7.2), so flagged-but-shipped schemas surface in the methodology's transparency layer.
The verdict is a single token; downstream tooling (the integration PR's runner, the Phase 4 validation harness) can match it as a literal string. The override substring is matched as a literal substring within the §11 row's Reason column — exact-substring, case-sensitive.
OUTPUT_SCHEMA
A JSON Schema (draft 2020-12) document, rendered as either
YAML or JSON per the user's choice, returned inside a fenced
code block. Returned regardless of verdict — even a
not-ready verdict returns the latest schema state so the
user has a concrete artifact to revise against.
The schema ships into plan.md §2's OUTPUT_SCHEMA block (once
the breaking-change PR lands the v0.2 plan.md.template).
v0.1.0-equivalent single-output classification renders as the
degenerate one-required-enum-field shape — no shorthand, no
LABEL_SPACE legacy alias, same rendering pipeline as any
multi-field task.
Findings list (only for revise and not-ready)
A list of specific rule violations that need user attention. Each item names:
- The layer (mechanical or judgment-driven) and rule number (§3.4 rules 1–8, §3.5 rules 1–5).
- The field or schema location involved (or "schema-level" if the finding is structural rather than per-field).
- The specific failure observed.
- The recommended corrective action.
- Whether the finding contributed to a
reviseornot-readysignal.
The list is specific, not generic. "The schema looks
under-specified" is not a finding; "Rule 1 (enum
exhaustiveness) — type is missing task, documentation,
discussion" is.
Override mechanics summary
| Verdict | Plan.md §11 entry required? | Literal substring required in Reason? | Propagates to REPORT.md? |
|---|---|---|---|
ready | No | — | No |
revise | Yes (proceed-without-fix path) | No (must mention schema-designer) | No |
not-ready | Yes (override path) | Yes — schema-not-ready override | Yes |
The literal substring is matched case-sensitively. Future contributors must not loosen the match — see "Versioning."
Pattern for subsequent sub-skills
schema-designer is the second verdict-gated sub-skill in
spp (after baseline-quality). The verdict-token +
enforcement-at-gate pattern is now established across two
sub-skills with consistent shape:
- Verdict token set:
ready/revise/not-ready— three values, no others. The token is a single word matched literally; no confidence weighting, no fuzzy match, norevise-but-tend-toward-readyhalf-states. - Override substring: verdict-flavored, kebab-case-ish, ends
in
override.baseline-qualityusesnot-ready override(one rule for the entire sub-skill);schema-designerusesschema-not-ready override(qualified by sub-skill name). - Override propagation:
not-readyoverrides flow intoREPORT.md's acknowledged-risk surface (§7.2 inREPORT.md, for now);reviseacknowledgements stay inplan.md§11. - Findings flow into
plan.md, not parallel artifacts.
metric-design and prompt-architect are review-and-record
sub-skills, not verdict-gated. They remain that way; not every
sub-skill is a gatekeeper. The decision to make a sub-skill
verdict-gated belongs at the sub-skill's design pin (in
DESIGN.md for v0.x sub-skills) and is breaking to flip after
ship.
Versioning
Same rule as designer.md, /spp-init, metric-design, and
baseline-quality: changes that alter methodology
guarantees are flagged as BREAKING CHANGE: in commit
messages and trigger a major-version bump per CLAUDE.md §4.
Methodology-affecting (= breaking):
- Loosening any mechanical-layer rule (§3.4 rules 1–8,
including the v0.10 rule 8
TASK_MODE/ schema-shape consistency precondition on G1). These are the categorical disqualifications that justify the layer split. - Loosening any judgment-layer rule (§3.5 rules 1–5),
including weakening the
revise-vs-not-readythresholds in rule 5 (scope discipline). - Weakening verdict-gate enforcement. Informational
verdicts (verdict that does not block the gate), fuzzy
override matching, or accepting any override phrase that
implies override intent without containing the literal
substring
schema-not-ready override. - Adding any verdict beyond
ready/revise/not-ready. Three tokens, nopartial, noprovisional, no confidence-weighted variants. - Loosening the literal-substring requirement on
schema-not-ready override. Case-sensitive, exact substring, matched within the §11 Reason column. - Allowing the sub-skill to write to any artifact other than
its returned output and
plan.md§11. A separateschema_quality_review.md, per-CSV-row metadata, or any file outside the returned-artifact + plan.md cross-skill contract is a methodology break. - Switching the schema language from JSON Schema (draft
2020-12) without an explicit design pass and pin update
in
DESIGN.md. - Allowing LLM-as-judge validation at either layer (§3.4 or §3.5). Mechanical rules run on a parser; judgment rules run on user judgment with the sub-skill prompting.
Behavioral (= non-breaking):
- Better worked-example phrasing.
- New fixtures exercising existing rules and verdicts.
- Clearer error-message wording in findings documents.
- Additional cross-references to other skills/docs.
- Tightening a judgment-rule's threshold with rationale (e.g.,
rule 5 going from "dramatically broader" to "more than 3x the
fields the task description supports") as long as the
three-tier
ready/revise/not-readystructure is preserved. - Stylistic improvements that do not change required content.
- Documenting the canonical-label policy for multilingual input (§3.5, v0.6). It restates the existing fixed-output-space discipline for the multilingual case; it adds no verdict and no new mechanical rule.
When in doubt, treat the change as breaking. The cost of a release-notes paragraph is low; the cost of silently weakening a rule that defends against schema-overfitting is high.
Cross-references
baseline-quality/SKILL.md— the structural sibling. The verdict-token + enforcement-at- gate pattern is inherited from §2; the parallel-artifacts prohibition from §5; per-field calibration from §3.1 (drift) and §3.3 (intuition-vs-rule).metric-design/SKILL.md— the peer review-and-record sub-skill. Useful as contrast: wheremetric-designrecords a chosen metric without gating,schema-designerblocks the gate. The decision tree inmetric-design§3 has no verdict-token output; this sub-skill's §3.6 does.prompt-architect/SKILL.md— peer for the six-section prompt structure. Not verdict-gated; review-and-record.agents/designer.md— the agent that will invoke this sub-skill once bucket 4 wires the gate slot. The designer's §7 mechanical validation rule 3 ("LABEL_SPACEis enumerable") generalizes to "OUTPUT_SCHEMA passes the mechanical layer above" in v0.2; that edit is part of the breaking-change PR (bucket 5).templates/plan.md.template— the destination for the sub-skill's findings. §2 (schema block +SCHEMA_DESIGN_NOTEsubsection, both forthcoming in the breaking-change PR) and §11 (revision log, includingschema-not-ready overrideentries when applicable).DESIGN.md§7.1.1 schema layer — the design contract this sub-skill realizes; verbatim source for the mechanical and judgment rules in §3.4 and §3.5. §4.2 (per-stage information isolation) — the rationale behind §2's monolithic block, why the auditor'splan.md §2allow-listed slice must remain cleanly addressable. §10 glossary (plan.md as contract) — the rule that findings flow intoplan.md, not into separate documents. §7.1.3 — the deliberate non-goals (generation tasks, RAG, agentic) that bound this sub-skill's scope.CLAUDE.md§4 (Semantic Commits — applies to changes to this sub-skill).