Files
poimen/tasks/T3.2-workflowformat-trait-yaml-and-json.md

96 lines
3.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T3.2 — `WorkflowFormat` trait + YAML and JSON
| Field | Value |
|---|---|
| Phase | P3 — Workflow as data |
| Size | M — 1 to 3 days |
| Status | Not started |
| Flags | — |
| Spec | inlined below |
| Blocks | — |
## Goal
Formats are plugins. Ship YAML and JSON; prove a third format needs no kernel
change.
## Facts (inlined — no spec read needed)
```rust
pub trait WorkflowFormat: Send + Sync {
fn extensions(&self) -> &[&str];
fn parse(&self, src: &[u8]) -> Result<WorkflowDef, ParseError>;
}
```
- A user wanting a DSL, Starlark, or a database row implements the trait.
- **Validation and canonicalization live in the kernel and run on the IR** (T3.1,
T3.3), so a new format inherits every check without reimplementing one. A
format that does its own validation has forked the rules.
- Because the version hash is over the canonical IR, the same workflow in two
formats must produce the same `WorkflowVersion` — that equality is the test
that the boundary is in the right place.
- Defaults ship working; every default is a port. A user who wants built-in
behaviour writes no code; a user who wants their own writes an impl, not a fork.
## Steps
1. Define the trait exactly as above. `parse` returns the IR and nothing else —
no side effects, no registration, no validation.
2. Implement `YamlFormat` and `JsonFormat` over `serde`. Both target the same IR
types from T3.1.
3. Build the format registry keyed by extension. Resolution is by extension, with
a clear error when two formats claim the same one.
4. Make `ParseError` carry position information where the format supplies it —
this is the only error type that legitimately knows about source text.
5. Write the same workflow in YAML and in JSON; assert equal `WorkflowVersion`.
6. In a **separate test crate**, implement a third trivial format (for example
TOML or a line-based DSL) against the public API only. If it needs anything
`pub(crate)`, the trait is short — fix the trait, not the test.
## Acceptance
- The same workflow expressed in both formats produces the same
`WorkflowVersion`.
- A third format added in a test crate needs **no kernel change**.
## Verify
**Harness:** a **separate test crate outside the workspace** depending only on
the published API — that crate's existence is the deliverable, not a convenience.
**Integration test**`tests/it_format_equivalence.rs` plus
`third-format-crate/`:
1. Express one non-trivial workflow (all five `StepKind`s) in YAML and in JSON.
2. Parse both; assert identical `WorkflowVersion`.
3. Assert the parsed IRs are byte-identical after canonicalization.
4. In the external crate, implement a third format (TOML or a line DSL) against
the public API only. Build it. If it needs any `pub(crate)` item, the trait is
short — that is a finding, not a test workaround.
5. Register the third format and run the **same** validation suite (T3.3) against
it; assert it inherits every check with no new code.
6. Extension collision: register two formats claiming `.yaml`; assert a clear
error rather than last-one-wins.
**Command:** `cargo test -p workflow format_equivalence && cargo test --manifest-path third-format-crate/Cargo.toml`
**False pass:**
- The third-format crate living inside the workspace, where it can reach
internals. It then passes while the public API is unusable — which is the
entire thing being tested.
- Step 5 omitted: a format that does its own validation passes steps 14 and has
quietly forked the rules.
## Traps
- Format-specific validation creeping into `parse`. Two formats then disagree
about what is legal.
- Leaking `serde` types into the IR, which makes the third-format test need a
serde dependency it should not have.
---
Background (not required to do this task):
[rust-agentic-sys.md](../../../rust-agentic-sys.md) §1, §4.2 ·
[rust-agentic-task.md](../../../rust-agentic-task.md)