Generation + governance pipeline for dspack contracts. Compiles a dspack v0.3 contract into generation context, generates dspack surfaces via schema-constrained LLMs (Ollama local or hosted — interchangeable adapters), lints them deterministically against the contract's governance rules, repairs bounded, emits to protocols (A2UI and json-render via dspack-emit), and produces a versioned audit report.
A2UI defines what can render. dspack defines what is correct.
Status: Milestone 1 complete —
m1 tag,
write-up in docs/m1-report.md. M2 in progress (second
emitter target landed in dspack-emit; eval harness and ds-mcp tools next).
The emitter is consumed from npm as @aestheticfunction/dspack-emit
(renamed from @aestheticfunction/dspack-to-a2ui with the ADR-D2 repo
rename; the old package is deprecated with a pointer).
- Schema answers "can this object exist" — the generation schema encodes vocabulary and shape only, never governance.
- Linter answers "is this object correct" — deterministic typed rules (gate S3), each with a rationale.
- Renderer answers "can this render" — protocol emitters compile the surface; the target's gates (A1–A3 for A2UI) validate the result.
| Gate | Check | Where |
|---|---|---|
| S1 | generic dspack surface schema | here (pre-emission) |
| S2 | contract vocabulary (components, sub-components, props, enum values, slots) | here (pre-emission) |
| S3 | governance rules (typed, deterministic, rationale-bearing) | here (pre-emission) |
| A1–A3 | schema-compile / catalog-shape / instance validation | dspack-emit (per emitted target) |
S1/S2 are checks on any produced surface; constrained decoding may implement S2 during
generation but the gates are always reported independently — the S0 spike found Ollama's mlx
engine silently ignoring format, which is exactly why.
npm run context -- --dspack fixtures/shadcn.v0_4.dspack.json --intent destructive-action
# prints { system, schema, fewshot } — the compiled generation contextlint (S1–S3) and run (full pipeline) land in later M1 PRs.
| Code | Meaning |
|---|---|
| 0 | clean |
| 1 | internal / usage error |
| 2 | governance failure (any S-gate error) |
| 3 | emitter-gate failure (A1–A3 or target equivalent) |
| 4 | unknown rule type (fail-loud; never silently skipped) |
(Distinct from dspack-emit's exit codes, where 3 = strict-coverage failure and 4 =
surface-emission failure.)
npm run eval -- --adapter fake --matrix eval/matrix.fake.json # deterministic; the CI gate
npm run eval -- --adapter live --matrix eval/matrix.json # documented live run; never CI
npm run eval -- --adapter live --matrix eval/matrix.json --out out/eval/<dir> --resume # resume an interrupted run
npm run eval:assert -- --results out/eval/fake/results.json --model <ref> --min-repair-success 0.9Every cell run goes through the same runPipeline as the CLI and demo; the
harness only iterates and aggregates. Model ids live in eval/matrix.json
(config), never in code. Per cell (model × prompt × repair template,
runsPerCell runs): schema-validity, first-attempt-violation, repair-success
(null over zero violations), end-to-end pass rates, and the count of S3-clean
surfaces refused by emitter gates (the ADR-D1 signal; p10–p12 probe it
deliberately). Prompts span repair shapes — substitution, addition, deletion,
restructuring — and every prompt crosses the two ADR-7 repair templates
(standard vs permit-restructuring, a one-instruction-line delta recorded
in each audit report). One run can never kill the matrix: adapter transport failures are typed
(failed-adapter, with a report) and anything that still escapes a run is
contained as an explicit error run — visible in the distribution with a
retained .error.json, excluded from the model-behavior rate denominators
(errorRuns reports the count). --resume skips already-retained reports
and retries error records. Every run's audit report is retained under
out/eval/…/reports/; results.json is the artifact, report.md the
derived view; findings go to docs/findings.md at measured
strength. The hosted-model eval:assert threshold is the only hard eval gate
in M2; local models are report-only.
@aestheticfunction/dspack-gen/core is the zero-network, emitter-free subpath (compiler +
linter) that ds-mcp consumes without breaking
its read-only/no-network security posture. The boundary is enforced by
src/core/core-boundary.test.ts.
npm ci
npm test # vitest: golden context, generation-schema behavior, core boundary
npm run check:sync # contract-copy drift check vs the dspack repo (CI-run; --write re-syncs)fixtures/shadcn.v0_4.dspack.json is a byte copy of the spec repo's
examples/shadcn-ui.dspack.json; CI fails loudly if they diverge
(dspack-gen#7). After --write, regenerate the derived goldens (context
golden, F-fixture expected outputs, eval fake golden) and commit the sync +
regeneration together.
Apache-2.0. Copyright 2026 Aesthetic Function, LLC.