feat(cli): graph register / --params accept the op-script form (fieldtest 0107 F5)

Both verbs now route through the same composite_from_any shape
discrimination file-mode --content-id shipped with (op-script array ->
one-build tail; envelope object -> loader), so the three on-ramp verbs
agree on accepted shapes and an op-script registers under the same
shape-invariant content id as its built envelope — no more raw serde
refusal ('invalid type: map, expected u32') hiding the graph build
bridge.

RED-first (tdd-author handoff): two same-seam behavioural pins
(register stores the envelope id for an op-script; --params matches
the envelope's axis lines) observed failing on the serde refusal, then
the two call sites rerouted.

Gates: workspace 990/0, clippy -D warnings clean.

closes #202
This commit is contained in:
2026-07-03 22:49:12 +02:00
parent 2968fbef40
commit c3d62f2ce3
2 changed files with 67 additions and 4 deletions
+6 -4
View File
@@ -370,8 +370,9 @@ fn resolve_blueprint_text(target: &str, env: &crate::project::Env) -> Result<Str
fn params_lines(target: &str, env: &crate::project::Env) -> Result<String, String> {
use std::fmt::Write as _;
let text = resolve_blueprint_text(target, env)?;
let composite =
blueprint_from_json(&text, &|t| env.resolve(t)).map_err(|e| blueprint_load_prose(&e))?;
// Shape-discriminated like file-mode --content-id: an op-script (array)
// builds through the one-build tail, an envelope (object) loads (#202).
let composite = composite_from_any(&text, env)?;
let mut out = String::new();
for p in composite.param_space() {
let _ = writeln!(out, "{}:{:?}", p.name, p.kind);
@@ -396,8 +397,9 @@ pub fn register_cmd(file: &Path, env: &crate::project::Env) {
fn register_blueprint(file: &Path, env: &crate::project::Env) -> Result<String, String> {
let text = std::fs::read_to_string(file)
.map_err(|e| format!("cannot read {}: {e}", file.display()))?;
let composite =
blueprint_from_json(&text, &|t| env.resolve(t)).map_err(|e| blueprint_load_prose(&e))?;
// Shape-discriminated like file-mode --content-id (#202): either shape
// canonicalizes to the envelope form, so the stored id is shape-invariant.
let composite = composite_from_any(&text, env)?;
let canonical = blueprint_to_json(&composite).map_err(|e| format!("serialize error: {e:?}"))?;
let id = crate::content_id(&canonical);
let registry = env.registry();