Skip to content

fix(bindings): repair no longer clobbers wardline-owned launch flags in .mcp.json - #110

Merged
tachyon-beep merged 1 commit into
release/1.5.0from
fix/binding-repair-preserves-wardline-flags
Aug 7, 2026
Merged

fix(bindings): repair no longer clobbers wardline-owned launch flags in .mcp.json#110
tachyon-beep merged 1 commit into
release/1.5.0from
fix/binding-repair-preserves-wardline-flags

Conversation

@tachyon-beep

Copy link
Copy Markdown
Collaborator

Summary

Owner-reported: "loomweave removes the trust pack when it repairs, it shouldn't do that." On elspeth, the three-way binding repair rewrote the tracked .mcp.json wardline entry from ["mcp","--root",".","--trust-pack","scripts.wardline_pack","--allow-custom-packs"] to ["mcp","--root",".","--loomweave-url","http://127.0.0.1:10251"] — silently un-trusting the project's trust-grammar pack and baking the deterministic port into a git-tracked file.

Root cause: desired_wardline_args composed the entry from scratch (only --filigree-url was ceded/carried), and wardline_mcp_ok was exact args-array equality, so any wardline-owned flag made the entry permanently "stale".

Fix

Same functionally-equivalent-is-healthy discipline as #109:

  • Existing sane entries (args invoke mcp) are carried forward verbatim — command, --root, trust flags, ceded --filigree-url. The single owned mutation: refresh the --loomweave-url value when the flag is present and stale.
  • An entry omitting --loomweave-url is current — wardline's resolver (flag > env > published .weft/loomweave/ephemeral.port) discovers Loomweave at runtime — so no flag-injection churn on tracked files.
  • Fresh registrations unchanged: full seeded entry incl. deterministic-port URL (ADR-044), no synthesized --filigree-url.

Closes clarion-c379a8c9ee.

Testing

  • New: repair_preserves_wardline_owned_flags_and_flagless_url_is_current (elspeth regression, byte-for-byte no-op incl. custom command), repair_refreshes_only_the_owned_loomweave_url_value (order + flags survive, only the value changes, check agrees with write).
  • All three existing cede tests and the doctor/install integration tests pass unchanged.
  • Full CI floor green locally (fmt, clippy, build, nextest 2315, doc, deny, ruff/format/mypy/pytest 317).

🤖 Generated with Claude Code

…in .mcp.json

The three-way binding repair rebuilt the wardline entry from scratch,
keeping only the ceded --filigree-url. Every other wardline-owned launch
flag (--trust-pack, --allow-custom-packs, --read-only, ...) was silently
dropped, and the health check was exact args-array equality, so any
hand-authored entry classified MissingOrStale forever and got rewritten on
every install/doctor --fix — on elspeth this stripped the project's
trust-grammar pack grant from a git-tracked .mcp.json and baked in the
deterministic-port --loomweave-url.

Now an existing sane entry (args invoke `mcp`) is carried forward verbatim
— command included — with exactly one owned mutation: the --loomweave-url
VALUE is refreshed when the flag is present with a stale value. An entry
omitting the flag entirely is current (wardline's resolver falls through to
the published .weft/loomweave/ephemeral.port rung). Fresh registrations
still seed the full entry including the deterministic-port URL (ADR-044
unchanged).

Closes clarion-c379a8c9ee.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 7, 2026 22:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts Loomweave’s Wardline .mcp.json “repair” behavior to avoid rewriting (and thereby clobbering) Wardline/operator-owned launch flags, while still keeping Loomweave’s owned --loomweave-url value up to date when present.

Changes:

  • Updates the “is current” check for the Wardline MCP entry to treat missing --loomweave-url as acceptable and only validate Loomweave’s owned URL value when the flag exists.
  • Makes install_wardline_mcp preserve existing sane args verbatim and refresh only the --loomweave-url value when stale (no whole-entry rewrite).
  • Adds regression tests to ensure repair preserves Wardline-owned flags and only refreshes the owned URL value.
Suppressed comments (1)

crates/loomweave-cli/src/integration_bindings.rs:273

  • The surgical-repair path in install_wardline_mcp considers an entry "sane" if it only has an args array starting with "mcp". That means partially malformed entries (e.g., type/command missing) can fall into the early-return/no-op paths (especially when --loomweave-url is omitted) and never get repaired to a runnable wardline registration. Tighten the "sane" predicate to require the expected structural fields before attempting an in-place edit; otherwise fall back to seeding a fresh entry.
    if let Some(args) = servers
        .get_mut("wardline")
        .and_then(|entry| entry.get_mut("args"))
        .and_then(Value::as_array_mut)
        .filter(|args| args.first().and_then(Value::as_str) == Some("mcp"))

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +175 to +187
// Loomweave owns exactly one field of this entry: the --loomweave-url
// VALUE. Everything else — the command, --root, wardline-owned launch
// flags like --trust-pack/--allow-custom-packs, the ceded --filigree-url —
// is wardline's (or the operator's) and never judged here. An entry that
// omits --loomweave-url entirely is also current: wardline's resolver
// falls through to the published .weft/loomweave/ephemeral.port rung.
let Some(args) = entry.get("args").and_then(Value::as_array) else {
return Ok(false);
};
if args.first().and_then(Value::as_str) != Some("mcp") {
return Ok(false);
}
Ok(loomweave_url_arg(args).is_none_or(|url| url == desired.loomweave_url))
@tachyon-beep
tachyon-beep merged commit e8f5e91 into release/1.5.0 Aug 7, 2026
6 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa53bcace2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +181 to +187
let Some(args) = entry.get("args").and_then(Value::as_array) else {
return Ok(false);
};
if args.first().and_then(Value::as_str) != Some("mcp") {
return Ok(false);
}
Ok(loomweave_url_arg(args).is_none_or(|url| url == desired.loomweave_url))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require a launchable Wardline entry before declaring success

With an existing .mcp.json where mcpServers.wardline.args begins with mcp but the entry lacks a string command (for example a partial/manual edit containing only {"args":["mcp"]}), this new predicate returns Present, and install_wardline_mcp uses the same loose shape to no-op instead of seeding the full entry. MCP clients cannot launch the stdio server without the command field, so doctor --fix can give a false all-clear while leaving an unusable binding; preserving custom commands still needs to distinguish a missing/non-string command as malformed or stale.

Useful? React with 👍 / 👎.

Comment on lines +285 to +286
if flag + 1 < args.len() {
args[flag + 1] = url;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Insert the URL when the next token is another flag

When an existing entry has --loomweave-url without a value before another option, e.g. [..., "--loomweave-url", "--filigree-url", "http://..."], this branch overwrites --filigree-url with the Loomweave URL instead of inserting a missing value after the Loomweave flag. That silently drops Wardline's ceded emit flag and leaves its URL as a positional arg; the health check then accepts the corrupted argv, so one repair can break the wardline-owned flag preservation this change is meant to protect.

Useful? React with 👍 / 👎.

@tachyon-beep
tachyon-beep deleted the fix/binding-repair-preserves-wardline-flags branch August 7, 2026 23:16
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.

2 participants