Skip to content

feat: add model validate command with validate-all support#5

Merged
adamhjk merged 1 commit intomainfrom
model-validate
Jan 28, 2026
Merged

feat: add model validate command with validate-all support#5
adamhjk merged 1 commit intomainfrom
model-validate

Conversation

@adamhjk
Copy link
Copy Markdown
Contributor

@adamhjk adamhjk commented Jan 28, 2026

Summary

  • Add model validate command to validate model inputs and resources against their Zod schemas
  • Support single-model validation: model validate <model_id_or_name>
  • Support batch validation: model validate (no args) validates all models in repository
  • Add findAllGlobal() method to YamlInputRepository for centralized batch operations
  • Add ValidationService with parallel validation execution
  • Interactive and JSON output modes with appropriate exit codes

Test plan

  • Unit tests for ValidationService and output components
  • Integration tests for single-model and batch validation
  • deno task test passes (192 tests)
  • deno check main.ts passes
  • deno lint passes
  • deno fmt passes
  • Manual testing with model validate --repo-dir /tmp/test

🤖 Generated with Claude Code

Add `model validate` command to validate model inputs and resources against
their Zod schemas. The command supports both single-model and batch validation:

- `model validate <model_id_or_name>` - validates a single model by ID or name
- `model validate` (no args) - validates all models in the repository

Features:
- ValidationService with parallel validation of input/resource schemas
- Interactive output with checkmarks/X marks and colored results
- JSON output mode for CI/automation use cases
- Exit code 1 when any validation fails
- Multi-model summary showing pass/fail counts

Repository changes:
- Add findAllGlobal() method to YamlInputRepository for batch operations
- Add ValidationResult value object and DefaultModelValidationService

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@adamhjk adamhjk merged commit 1ac1185 into main Jan 28, 2026
2 of 3 checks passed
@adamhjk adamhjk deleted the model-validate branch January 28, 2026 20:59
ianarsenault pushed a commit to ianarsenault/swamp that referenced this pull request Apr 21, 2026
…-club#141) (systeminit#1205)

## Summary

- Fixes [swamp-club#141](https://swamp.club/lab/issues/141): extension
authors whose `_test.ts` imports the model source hit `TS7006` (implicit
`any` on execute parameters) under strict mode.
- Ships a type-only `ModelDefinition<TGlobalArgs>` in
`@systeminit/swamp-testing` that authors opt into via `satisfies
ModelDefinition<typeof Schema>` (or the `defineModel` function-form
alternative). The literal stays identical — only a trailing satisfies
and a type-only import are added.
- `context.globalArgs` narrows to the schema-inferred shape (verified by
probing an undeclared field → TS2339). This is a real type-safety
upgrade, not a TS7006 silencer.
- Default authoring experience is **unchanged** — unannotated execute
params remain the Quick Start. Existing extensions do not need to
migrate. The `: any` workaround keeps working for anyone already using
it.

## What's included

- `packages/testing/model_definition_types.ts` — new type-only file with
`ModelDefinition`, `MethodDefinition`, `CheckDefinition`,
`ResourceOutputSpec`, `FileOutputSpec`, `VersionUpgrade`, `CheckResult`,
and the `defineModel` helper.
- `packages/testing/types.ts` — `MethodContext<TGlobalArgs =
Record<string, unknown>>` (additive, backward compatible).
- `packages/testing/mod.ts` — new "Model authoring" export block.
- `packages/testing/model_definition_types_test.ts` — type-level
regression test asserting both `satisfies` and `defineModel` paths
narrow `globalArgs` under strict+noImplicitAny.
- `src/domain/models/testing_package_compat_test.ts` — extended to guard
drift between testing and canonical `ModelDefinition` /
`MethodDefinition`.
- `.claude/skills/swamp-extension-model/references/typing.md` — new
reference with before/after, "when not to use," and cross-links to the
compat test and issue systeminit#141.
- `.claude/skills/swamp-extension-model/SKILL.md` — Key Rule systeminit#5 points
at typing.md.
- `.claude/skills/swamp-extension-model/references/testing.md` —
cross-link banner at the top.
- `packages/testing/README.md` — new "Model authoring escape hatch"
subsection.
- `packages/testing/deno.json` — bumped 0.2.0 → 0.3.0.

## Author-facing usage

```typescript
import { z } from "npm:zod@4";
import type { ModelDefinition } from "jsr:@systeminit/swamp-testing";

const GlobalArgsSchema = z.object({ region: z.string() });

export const model = {
  type: "@myorg/my-model",
  version: "2026.04.21.1",
  globalArguments: GlobalArgsSchema,
  methods: {
    run: {
      description: "Run the model",
      arguments: z.object({ bucket: z.string() }),
      execute: async (_args, context) => {
        // context.globalArgs narrows to { region: string }
        return { dataHandles: [] };
      },
    },
  },
} satisfies ModelDefinition<typeof GlobalArgsSchema>;
```

## Why not a per-method args-narrowing helper

The plan's initial `defineModel` sketch intended per-method `args`
inference via mapped-intersection generics. Both the F-bounded recursive
constraint and the `Omit`-based override pattern failed contextual
typing during inference — per-method args narrowing for inline literals
requires a builder-style API (as used by tRPC / zod's own `.input()`
chain), which is out of scope here. Authors narrow `args` per method
with `MySchema.parse(args)` at runtime (the canonical Zod way).
`typing.md` documents this.

## Test plan

- [x] `deno check main.ts packages/testing/mod.ts` passes
- [x] `deno run test` — all 4505 existing tests pass; new 4 type-level +
smoke tests pass
- [x] `deno lint` clean
- [x] `deno fmt` applied
- [x] `deno run review-skills` — all skills pass the 90% threshold
- [x] Scratch-repo verification: reproduces TS7006 on the pre-fix shape;
compiles cleanly with `satisfies ModelDefinition<typeof Schema>` and
`defineModel({ ... })`; narrowing probe confirms
`context.globalArgs.region` is typed and
`context.globalArgs.undeclaredField` errors as expected.
- [x] Drift-guard verification: injecting `description: number` into
testing-side `MethodDefinition` immediately failed
`testing_package_compat_test.ts` as designed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant