feat(gatorwalk-factory): the factory definition lives in the factory model, with its schema (swamp-club #2884) #408

Merged
seth merged 1 commit from cue/2884-gatorwalk-factory-factory into main 2026-10-01 14:19:46 +00:00
Owner

Closes swamp-club #2884.

A factory's definition now lives in the factory model itself, with the definition schema as the factory type's schema, so swamp validates it like any model. This replaces #2803's factories/<factory>.yaml file, following Adam's review: "I don't understand why the definition is not itself a model."

What changed

  • Factory globalArguments are { definition, tracker, scenarios }.
    • definition is the definition schema, nested under that key. Nesting avoids a collision between the definition's tracker: { kind } and the factory's tracker: <instance>, and it keeps swamp's shallow partial() checking the whole definition.
    • definition is optional, because swamp model create checks the full schema and the factory is created with only its tracker.
    • definition and scenarios are marked foreignTemplate, so swamp's template scan leaves gatorwalk's {{name}} placeholders alone. That includes a placeholder named like a swamp namespace, such as {{run}}.
  • Saved scenarios are inline, in the factory's scenarios list, instead of scenarios/<factory>/*.yaml (decided in triage). swamp checks their shape, and they reach a remote worker. The factory: key is gone, and two scenarios can't share a name.
  • One read path. validate, design_page, new_key, start, reset repin=true and the trackers' claim all read the raw model definition through loadFactory, in both the local and the remote (_globalArguments) shape. start still pins a copy with its digest.
  • Removed: init, factories/ files, scenarios/ files, definition_file.ts, starters.ts, gen_starters.
  • Skill:
    • The agent creates the factory with --global-arg tracker=<instance>, then writes an example's definition: and scenarios: blocks under globalArguments:, right after tracker: and before methods:. It never replaces an existing definition.
    • Each example is now one file holding those two blocks. I checked the converted data is identical to the old files.
  • Docs: README and DESIGN are updated. That covers where the definition lives, what swamp model validate reports versus gatorwalk's validate, the foreign-template marker, why ${{ stays rejected, the studio, and saved scenarios, plus a decision-log entry.

swamp model validate vs gatorwalk validate

Checked on real swamp:

  • swamp model validate <factory> reports a schema error in the definition or a scenario, with its path, for example targets unknown stage 'missing' at "definition.stages.1.transitions.0.to". Every factory method stops on the same error first (Global arguments validation failed: ...).
    • It does not report a missing definition, because the key is optional.
    • It skips a key that holds a ${{ }} expression.
  • gatorwalk's validate checks the raw definition again, which also refuses ${{. Then it checks the tracker binding, runs the graph analysis and the saved scenarios, and says where to write a missing definition.

Swamp-native ${{ }} (vault or env references) stays rejected. Allowing it later would mean reading those specific fields from the evaluated arguments, and accepting that swamp then skips the schema check for the whole definition.

For #2808 (Simulate mode)

The studio now reads one file per factory: its model definition, models/@swamp/gatorwalk-factory/factory/<factory>.yaml, at the path swamp's definition repository gives (getPath).

  • GET /api/factories/<factory> returns that file's text.
  • The definition is at globalArguments.definition. loadDefinition in studio/src/model.ts handles the prefix, and paths inside the page stay definition-relative (stages.2).
  • Saved scenarios are at globalArguments.scenarios. Loaded.scenarios lists them with their source text.
  • There are no scenario routes and no scenarios event: one definition event reloads both.

Testing

  • Unit tests: 711 pass.
    • examples_test checks every example against the factory type's full schema, its graph and its scenarios.
    • factory_test covers partial() staying shallow, the foreign-template marker, and the scenario errors.
    • work_item_test covers a start from the remote shape.
    • The studio server, watcher and page tests cover the model-file source.
  • Integration tests on real swamp: 42 pass.
    • A factory created with only its tracker, then written in, validated, rendered and started, with no factories/ or scenarios/ path anywhere.
    • swamp model validate reports a definition error with its path.
    • A {{run}} placeholder and CEL gates survive save-and-run.
    • A ${{ }} expression in a prompt is refused and pins nothing.
    • The skill's authoring commands run as written. A new # agent: write <example> into <factory> step in the command runner stands in for the agent's file edit.
  • Acceptance run by hand in an isolated scratch repo, following the authoring reference: tracker → factory with only its tracker → starter written in → swamp model validate PASSED → validate (2 saved scenarios passed) → new_key → start → status at plan.

The dogfood factory is not migrated; it gets reset after this lands.

🤖 Generated with Claude Code

Closes swamp-club #2884. A factory's definition now lives in the factory model itself, with the definition schema as the factory type's schema, so swamp validates it like any model. This replaces #2803's `factories/<factory>.yaml` file, following Adam's review: "I don't understand why the definition is not itself a model." ## What changed - **Factory `globalArguments` are `{ definition, tracker, scenarios }`.** - `definition` is the definition schema, nested under that key. Nesting avoids a collision between the definition's `tracker: { kind }` and the factory's `tracker: <instance>`, and it keeps swamp's shallow `partial()` checking the whole definition. - `definition` is optional, because `swamp model create` checks the full schema and the factory is created with only its tracker. - `definition` and `scenarios` are marked `foreignTemplate`, so swamp's template scan leaves gatorwalk's `{{name}}` placeholders alone. That includes a placeholder named like a swamp namespace, such as `{{run}}`. - **Saved scenarios are inline**, in the factory's `scenarios` list, instead of `scenarios/<factory>/*.yaml` (decided in triage). swamp checks their shape, and they reach a remote worker. The `factory:` key is gone, and two scenarios can't share a name. - **One read path.** `validate`, `design_page`, `new_key`, `start`, `reset repin=true` and the trackers' `claim` all read the raw model definition through `loadFactory`, in both the local and the remote (`_globalArguments`) shape. `start` still pins a copy with its digest. - **Removed:** `init`, `factories/` files, `scenarios/` files, `definition_file.ts`, `starters.ts`, `gen_starters`. - **Skill:** - The agent creates the factory with `--global-arg tracker=<instance>`, then writes an example's `definition:` and `scenarios:` blocks under `globalArguments:`, right after `tracker:` and before `methods:`. It never replaces an existing definition. - Each example is now one file holding those two blocks. I checked the converted data is identical to the old files. - **Docs:** README and DESIGN are updated. That covers where the definition lives, what `swamp model validate` reports versus gatorwalk's `validate`, the foreign-template marker, why `${{` stays rejected, the studio, and saved scenarios, plus a decision-log entry. ## swamp model validate vs gatorwalk validate Checked on real swamp: - **`swamp model validate <factory>`** reports a schema error in the definition or a scenario, with its path, for example `targets unknown stage 'missing' at "definition.stages.1.transitions.0.to"`. Every factory method stops on the same error first (`Global arguments validation failed: ...`). - It does not report a missing definition, because the key is optional. - It skips a key that holds a `${{ }}` expression. - **gatorwalk's `validate`** checks the raw definition again, which also refuses `${{`. Then it checks the tracker binding, runs the graph analysis and the saved scenarios, and says where to write a missing definition. **Swamp-native `${{ }}`** (vault or env references) stays rejected. Allowing it later would mean reading those specific fields from the evaluated arguments, and accepting that swamp then skips the schema check for the whole definition. ## For #2808 (Simulate mode) The studio now reads **one file per factory: its model definition**, `models/@swamp/gatorwalk-factory/factory/<factory>.yaml`, at the path swamp's definition repository gives (`getPath`). - `GET /api/factories/<factory>` returns that file's text. - The definition is at `globalArguments.definition`. `loadDefinition` in `studio/src/model.ts` handles the prefix, and paths inside the page stay definition-relative (`stages.2`). - Saved scenarios are at `globalArguments.scenarios`. `Loaded.scenarios` lists them with their source text. - There are **no scenario routes and no `scenarios` event**: one `definition` event reloads both. ## Testing - **Unit tests:** 711 pass. - `examples_test` checks every example against the factory type's full schema, its graph and its scenarios. - `factory_test` covers `partial()` staying shallow, the foreign-template marker, and the scenario errors. - `work_item_test` covers a start from the remote shape. - The studio server, watcher and page tests cover the model-file source. - **Integration tests on real swamp:** 42 pass. - A factory created with only its tracker, then written in, validated, rendered and started, with no `factories/` or `scenarios/` path anywhere. - `swamp model validate` reports a definition error with its path. - A `{{run}}` placeholder and CEL gates survive save-and-run. - A `${{ }}` expression in a prompt is refused and pins nothing. - The skill's authoring commands run as written. A new `# agent: write <example> into <factory>` step in the command runner stands in for the agent's file edit. - **Acceptance run by hand** in an isolated scratch repo, following the authoring reference: tracker → factory with only its tracker → starter written in → `swamp model validate` PASSED → `validate` (2 saved scenarios passed) → `new_key` → `start` → `status` at `plan`. The dogfood factory is not migrated; it gets reset after this lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(gatorwalk-factory): the factory definition lives in the factory model, with its schema (swamp-club #2884)
All checks were successful
CI / Review Integrity (pull_request) Successful in 54s
CI / Validate Attestation (pull_request) Successful in 1m2s
d15681b64f
A factory's globalArguments are { definition, tracker, scenarios }: the
definition inline and checked by swamp against the factory type's schema,
beside its tracker and its saved scenarios. factories/ and scenarios/ files,
init, the embedded starters and definition_file.ts are removed. Every reader
(validate, design_page, new_key, start, reset repin, claim) reads the raw
model definition, in either the local or the remote-worker shape. The studio
reads each factory's model definition file, with Copy reference naming
globalArguments.definition paths. The skill's examples are definition and
scenarios blocks the agent writes into a factory.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seth merged commit f572fd1074 into main 2026-10-01 14:19:46 +00:00
seth deleted branch cue/2884-gatorwalk-factory-factory 2026-10-01 14:19:47 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
swamp-club/swamp-extensions!408
No description provided.