feat: fmt --check, batch mutation, migrate, slice-tag export, SVG render policy - #4
Merged
Merged
Conversation
…der policy Batch C of the ADOPTION-HARDENING backlog (authoring ergonomics): - T3a fmt: `maapp fmt [--check]` canonicality verb (gofmt -l style); wired into the init CI gate + routing-patch maintenance loop as a hard canonical-form gate. - T3b batch mutation: update-node/remove-node accept multiple slugs OR `--where key=value` (kind/refs.*/attrs.*); one atomic all-or-nothing write. Single-slug behavior unchanged. - T5 migrate: `maapp migrate [--to <minor>]` mechanical additive schema upgrade (1.3 -> 1.4 = version bump), through the shared no-regression canonical commit. (The companion validate behind-arm hint is deferred pending a corpus decision.) - T6 slice-tag export: `export --slice-tag <tag>` emits the refs.slice==tag sub-graph + interconnecting edges; same contract as --slice. - T8 SVG render policy: storyboard/spine `--out *.svg` now exits 2 pointing at `render html` (no bounded server-side SVG emitter exists) instead of silently writing ASCII into a .svg file; docs clarified. All verbs keep byte-stable --json, 0/1/2 exit codes, and native/wasm cfg gates. cargo test (full), clippy -D warnings, fmt --check, release + wasm32 builds all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F5Fg4YtoTiccEhcLECTKH1
…rpus to 1.4 Completes T5 per the owner's Option-1 decision (a public tool whose own examples warn "you're behind" is the theme-1 cold-start noise this backlog exists to kill; adopters copy the examples, so examples must model current best practice). - validate: the previously-silent behind-arm now emits W_VERSION_BEHIND (advisory, exit 0) pointing at `maapp migrate` when a graph's minor trails the engine. Tests: tests/validate.rs behind_minor_version_warns_with_migrate_hint + current_minor_version_emits_no_version_advisory. - migrate: changed to a MINIMAL in-place version bump that preserves the document's existing order (a version upgrade must never wholesale-reorder an authored file; `fmt` is the canonicalizer). Still guarded by the no-regression rule. - corpus: upgraded the 6 shipped examples 1.3 -> 1.4 by RUNNING `maapp migrate` on each (dogfood proof; clean 1-line bumps). Left the 5 compact internal lifecycle fixtures at 1.3 (not adopter-facing; their tests assert errors/diffs, not clean). Regenerated the 7 version-embedding render snapshots; bumped 2 inline clean- assertion docs to 1.4 (kept STRICT — genuinely clean, no W_ tolerance). Full suite 398 green; clippy -D warnings, fmt --check, release + wasm32 builds clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F5Fg4YtoTiccEhcLECTKH1
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…amples Review LOW: `migrate` bumped top-level `version` but left a redundant `meta.version` field behind, diverging the two. - ENGINE: migrate now bumps `meta.version` in the SAME minimal in-place write when the field is PRESENT (order-preserving), and never injects one when absent. Tests: migrate_bumps_redundant_meta_version_in_the_same_write + migrate_does_not_inject_meta_version_when_absent (red-first). - CORPUS: the 6 examples I migrated earlier had meta.version stuck at 1.3 while top-level was 1.4 (migrate is a no-op now that top-level is at target, so it can't reconcile them) — fixed their meta.version 1.3 -> 1.4 directly (1 line each) so both fields agree, matching the onboarding-variant/settings-account convention. All 8 examples now read version == meta.version == 1.4. Full suite 400 green; clippy -D warnings, fmt --check clean; deny-sweep 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F5Fg4YtoTiccEhcLECTKH1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Batch C — authoring ergonomics (ADOPTION-HARDENING)
Five features from the adoption-hardening backlog, all TDD, all keeping the house rules
(byte-stable
--json, 0/1/2 exit codes, native/wasm cfg gates, per-verb tests).T3a —
fmtcanonicality verbmaapp fmt <graph>rewrites to canonical form atomically;maapp fmt <graph> --checkexits 1naming the offending file path (
gofmt -lstyle) when non-canonical, writing nothing.initCI-gate template (a hardfmt --checkstep) and the CLAUDE.md/AGENTS.mdrouting-patch maintenance loop.
tests/fmt.rs(5 tests: check pass/fail + writes-nothing, rewrite→fixed-point,equals mutation canonical form, missing-file exit 2);
tests/init.rs::ci_gate_and_routing_patch_wire_fmt_check.T3b — batch
update-node/remove-node--where key=valueselector (matcheskind,refs.<k>,attrs.<k>), applying the change to every selected node in ONE atomic all-or-nothing write.--wherematch fails the whole batch before any write (exit 2, fileuntouched); without
--cascade,remove-noderefuses on the first still-edged node.are thin wrappers over the batch fns).
query/render) so slugs, an optional trailing file, and flagscan appear in any order; the file token is disambiguated from slugs (
.jsonsuffix or no:).tests/mutate.rs(+8 batch tests: multi-slug set, atomic unknown-slug,--where kind,--where refs.slice, empty match, slug/--whereconflict, batch cascade, first-offender refusal).T5 —
migrateverb +W_VERSION_BEHINDadvisorymaapp migrate <graph> [--to <minor>]mechanically upgrades a behind-schema graph to theengine's latest known minor (or
--to). The 1.3→1.4 delta is additive (meta.flows,Trigger.attrs.cause, attrEnumRegistry are all optional), so the upgrade is a minimal in-place
version bump that preserves the document's existing order — a version upgrade must never
wholesale-reorder an authored file (run
fmtfor that) — guarded by the mutation verbs'no-regression rule.
no-parseable-version (exit 2, file untouched). Evidence:
tests/migrate.rs(8 tests).validatebehind-arm hint: the previously-silent behind-arm now emitsW_VERSION_BEHIND(advisory, exit 0) pointing at
maapp migratewhen a graph's minor is behind the engine.Evidence:
tests/validate.rs::behind_minor_version_warns_with_migrate_hint+current_minor_version_emits_no_version_advisory.maapp migrate(the verb's end-to-end proof;a stale reference corpus that self-warns is the exact theme-1 cold-start noise this backlog kills).
The 6 shipped examples were upgraded by running the new binary on each:
tests/fixtures/lifecycle/*.jsonwere deliberately LEFT at 1.3 (they are stored ina compact format
migratewould reformat into noise, they are not adopter-facing, and their testsassert errors / semantic diffs, not clean-with-zero-warnings —
export.rseven asserts the sliceis 1.3). Regenerated the 7 render snapshots that embed the schema version (
v1.3→v1.4); bumped2 inline clean-assertion test docs to 1.4 (kept STRICT — genuinely clean, no
W_tolerance).T6 — slice-tag export
maapp export --slice-tag <tag>emits a complete, valid sub-graph of every node carryingrefs.slice == <tag>plus interconnecting edges — same contract as--slice,meta.slice_ofstamped
slice-tag:<tag>. Mutually exclusive with--slice; a tag matching nothing is exit 2.tests/export.rs(+5 tests).T8 — SVG render policy (chose the docs-correct path, not an emitter)
storyboard/spine: there is NO reusable server-side SVG code(the
render htmltemplate's SVG is client-side JS over the embedded graph JSON), so building afrom-scratch layout→SVG pipeline for both views far exceeds the bounded budget. Chose the policy:
render storyboard|spine --out *.svgnow exits 2 pointing atrender html, instead of silentlywriting ASCII into a
.svgfile.--outto a non-.svgfile still writes the ASCII text.rendercommand help to state storyboard/spine are ASCII and onlyrender htmlemits SVG.tests/render.rs(+4 tests).Verification
cargo test --locked(full suite): 398 passed, 0 failed.cargo clippy --all-targets --locked -- -D warnings: clean.cargo fmt --check: clean.cargo build --release --lockedandcargo build --target wasm32-unknown-unknown --locked: green.🤖 Generated with Claude Code