Skip to content

feat(doctor, sync-project): mxcli fix property-sets in the upgrade path, report first; model-stamp.sh known-fix note - #314

Closed
MendixMau wants to merge 9 commits into
masterfrom
feat/adopt-mxcli-026-fixes
Closed

MendixMau wants to merge 9 commits into
masterfrom
feat/adopt-mxcli-026-fixes

Conversation

@MendixMau

@MendixMau MendixMau commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Depends on #315 (the baseline word trim), which is merged into this branch. The new learned-detection-gaps.md row needs room in the baseline budget, so merge #315 first.

#295: adopt mxcli v0.25/v0.26 commands (partial)

Problem. mxcli up to v0.25 wrote units that are missing part of the property set Studio Pro writes. mx check, the build and the runtime all pass. Studio Pro's merge/diff then throws ("Objects with ID … do not have the same properties") once Studio Pro has saved such a document. No toolkit gate saw it.

Fix: report first; repair only through the gate.

bin/doctor.sh --property-sets <project> runs mxcli fix property-sets -p <mpr> --dry-run, which is read-only. Exit codes:

Exit Meaning
0 clean
1 units need repair (NEEDS/FAILED rows)
2 not run: no model, no mxcli, or a timeout
3 this mxcli is older than v0.26.0 and has no fix property-sets
4 could not check: an error, unclassifiable output, a crashed fix --help probe, or no readable Mendix version. A repair would not help, so none is suggested.

There is never a green result by absence.

  • Receipt. Only settled results are recorded in .claude/.property-sets-receipt: clean, needs, failed, and unsupported. Unsupported is recorded only when mxcli fix --help itself ran. The receipt is machine-local and gitignored, and adding it to .gitignore is announced. Errors and timeouts are never recorded.
  • --if-stale. Skips the run only when the receipt holds a clean or unsupported result for the installed mxcli. A needs result or a one-off error is checked again.
  • Time bound. The dry-run is bounded by MXTK_PROPSETS_TIMEOUT: 300 s by default in doctor, and 120 s by default under sync. It uses timeout when a working one is on PATH, and a polling watchdog otherwise.
  • Repair. bin/doctor.sh --fix-property-sets <project> runs the repair only through bin/exec.sh --patch, which gives it a snapshot, the mxbuild gate, and restore on failure. doctor.sh is its own patch script. It refuses when the project's exec.sh has no --patch, and it re-checks after the repair.
  • doctor (full run) includes the check.
  • doctor --quick only compares the receipt with the installed mxcli. It warns while the check is owed or the last result was not clean. If the support probe crashed, it says "could not probe" rather than saying the mxcli predates the command. exec.sh runs --quick whenever the mxcli version changes.
  • sync-project.sh (section 4d) first prints checking property sets (read-only, up to 120s)…, then runs the check with --if-stale. It never repairs. How it handles each exit:
    • Exit 1 gets a sync warning that names --fix-property-sets.
    • Exit 3 gets an info line saying to upgrade mxcli.
    • Exit 4 gets a neutral line, could not check property sets: <reason>. There is no warning and no repair advice.
    • Exit 2 shows doctor's NOT RUN note.
    • With --dry-run, sync only says it would run the check.
  • Docs.

Evidence. Checked against mxcli source at v0.26.0 (cmd/mxcli/cmd_fix_property_sets.go) and the release binaries:

  • The dry-run exits 1 both when units need repair and on errors such as "project not found" (captured). So the rows decide the result, never the exit code alone.
  • On v0.24.0 and v0.25.0, mxcli fix property-sets --help exits 0 and prints the parent fix help (captured). For that reason, support is detected from the mxcli fix --help listing.

Golden input. Captured from the official v0.24.0, v0.25.0 and v0.26.0 linux-amd64 binaries. None of them was run against a model.

  • --version
  • fix --help, cut at "Global Flags:"
  • fix property-sets --help on v0.25
  • a dry-run against a missing project

The clean, NEEDS and FAILED reports are not captured, because they need a real model. The test stub prints them from mxcli's source format strings, and the fixture header says so.

Still pending in #295:

#236 remainder

Review

Three rounds of independent review, all applied on this branch:

  1. First review: MERGE-AFTER-SMALL-FIX.
  2. Lead correction. An intro edit to learned-detection-gaps.md, made only to fit the budget, was reverted, because a feature PR does not squeeze other text (process(merging): independent review before every merge #316). The room comes from chore(context): free baseline word budget without dropping rules #315, which is merged in. With it, LC_ALL=C bin/render-routing.sh --check reports the baseline at 76292 words against a budget of 80000.
  3. Confirmation review: MERGE-AFTER-SMALL-FIX.
    • Sync announces the check and its bound, using its own 120 s default.
    • A check that could not run gets exit 4, which sync reports with a neutral line and no repair advice.
    • --quick says "could not probe" when the probe crashed.
    • The fixture stub's slow state now execs sleep, so no child process is left behind.

Checks run

  • tests/wave2/test-property-sets.sh: 61 passed, 0 failed. The first-round version also fails on master's doctor.sh and sync-project.sh (23 passed, 35 failed).

  • Existing fixtures for the changed files, all passing:

    Fixture Result
    test-model-stamp 35/35
    test-bug12-sync 61/61
    test-sync-dup-heading-exit 6/6
    test-sync-past-stock 22/22
    test-dryrun-writes-nothing 6/6
    test-doctor-docker-probe 18/18
    test-doctor-gate-selftest 28/28
    test-ritual-slim 17/17
    test-slim-claude-md 16/16

    After the last round, only the doctor/sync-dup-heading/dryrun fixtures were re-run.

  • Repo checks, all clean: check-no-client-data, check-pr-discipline, check-scripts (109/109), check-portability, check-no-private-citations.

  • LC_ALL=C bin/render-routing.sh --check: in sync; baseline 76292 words, budget 80000.

Field run

Still owed. Nothing was run against a real model. Still to do:

  • Run --property-sets on a project written with v0.24, to capture the real report rows and the timing on a large model.
  • Run --fix-property-sets through a real exec.sh gate.

Windows/Git Bash has not been run either.

Risks

  • On a very large model, the dry-run can hit its time bound (120 s under sync, 300 s in doctor). It then reports NOT RUN and is not recorded. Raise the bound with MXTK_PROPSETS_TIMEOUT.
  • A FAILED unit makes exec.sh roll back the whole repair. This is deliberately conservative, and it is documented.

Refs #295
Closes #236

🤖 Generated with Claude Code

https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw

…rade path, report first; name a pre-fix model-stamp.sh

#295. mxcli up to v0.25 wrote units without Studio Pro's full property
set. mx check, the build and the runtime stay green, and Studio Pro's
merge/diff throws once it has saved such a document. No gate saw it.

- bin/doctor.sh --property-sets <dir>: read-only `mxcli fix property-sets
  --dry-run`, result plus mxcli version in .claude/.property-sets-receipt
  (gitignored). Exit 0 clean / 1 needs or unclassified / 2 not run /
  3 mxcli < v0.26.0. --if-stale skips when already run for this mxcli.
- bin/doctor.sh --fix-property-sets <dir>: the repair, only through
  bin/exec.sh --patch (snapshot, mxbuild gate, restore); refused on an
  exec.sh without --patch. doctor.sh is its own patch script.
- doctor --quick (run by exec.sh when the mxcli version changes) warns
  while the check is owed; a full doctor runs it.
- sync-project.sh runs the check with --if-stale (never the repair).
- Support is read from `mxcli fix --help`: `fix property-sets --help`
  exits 0 on v0.24/v0.25 too (cobra prints the parent's help).
- learned-detection-gaps.md row; platform-link.md "Before a Team Server
  merge" (fix property-sets, fix hashes, git note).

#236 remainder: known_fix_note gains the model-stamp.sh arm keyed on
GIT_WORK_TREE (patch 0004); test-model-stamp.sh T9 adds the unstaged
worktree `commit -a` and `commit -- app` cases.

Golden input: `--version`, `fix --help`, `fix property-sets --help` and
a not-found dry-run, captured from the official v0.24.0/v0.25.0/v0.26.0
linux-amd64 release binaries (never run against a model). The clean /
NEEDS / FAILED reports follow mxcli v0.26.0's source format strings.
tests/wave2/test-property-sets.sh: 43 passed here, 26 fail on master's
doctor.sh/sync-project.sh. Field run on a real model still owed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
The always-on baseline tier counted by bin/render-routing.sh --check was
at 79,735 of its 80,000-word cap. This frees 3,772 words (now 75,964)
by moving narrative and setup-only text out of baseline files, keeping
every rule, STOP, denominator and gate cell in place, each rule still
paired with a one-line failure example plus a pointer to the full text.

- conversion-runbook.md, source-triage.md, interview-protocol.md: long
  incident narratives -> one line + pointer; originals verbatim in new
  on-demand process/baseline-incident-history.md (R1-R20, AR1, ST1-ST4,
  IP1-IP3). Runbook's duplicate open-questions status table now defers
  to interview-protocol.md section 4.
- agent-roles.md: the six template shapes (setup-only) moved to
  agents/README.md, which installers never copy (explicit MXTK_AGENTS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…low", ST1 id

Independent review of #315: obligations.tsv still pointed at agent-roles.md for
step 8a, which moved to agents/README.md; agent-roles.md said the example bodies
are "below"; the history header cited a non-existent section id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Measured with LC_ALL=C on the branch after master (#313) was merged in:
79,997 -> 76,259 (-3,738); the old line used pre-#313 figures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Merge: origin/master (b9cf37c, #313). learned-detection-gaps.md
conflict resolved by keeping master's two new rows plus this branch's
row.

Review fixes (independent review of #314):
1. Never cache an unsettled result. ps_write_receipt records only clean /
   needs / failed / unsupported, and unsupported only when `mxcli fix
   --help` itself ran. A failed probe is an error now, not "unsupported".
   --if-stale short-circuits only on a recorded clean or unsupported, so
   a one-off error (locked model, not found, no version) re-checks on the
   next sync instead of repeating until mxcli changes.
2. The dry-run is bounded: MXTK_PROPSETS_TIMEOUT (default 300s), through
   a working `timeout`, else a polling watchdog. A timeout is NOT RUN
   (exit 2) and not recorded.
3. Appending the receipt to the project's .gitignore is announced.
4. In sync, an mxcli < v0.26 (exit 3) shows as an info line, not WARN.
5. Baseline budget: the learned-detection-gaps.md row is now trigger +
   rule + one failure line, and the intro is tightened. The mechanics live
   in platform-link.md (on-demand). render-routing --check went from
   80178 words (over budget) to 79999. Master alone measures 79997.

tests/wave2/test-property-sets.sh: 58 passed (23/58 pass on master's
scripts). New cases: errors not recorded, --if-stale re-checks after an
error and on needs, a failed help probe, short-circuit on unsupported,
timeouts via both the timeout binary and the watchdog, the .gitignore
note, and sync's info line for an old mxcli.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
A feature PR does not squeeze other text to make room (the rule in #316).
Room comes from the baseline trim in #315, merged next. This branch's own
row stays trimmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…6-fixes

Room in the baseline budget for this branch's detection-gaps row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…it code; sync announces its bound

Confirmation review of #314:
1. Sync captures doctor's output, so it now prints "checking property
   sets (read-only, up to Ns)…" first. Sync uses its own shorter default:
   MXTK_PROPSETS_TIMEOUT=${MXTK_PROPSETS_TIMEOUT:-120}.
2. A check that could not run is exit 4 now, not exit 1. That covers an
   error, unclassified output, a crashed `fix --help` probe or no Mendix
   version. Exit 1 is only NEEDS/FAILED rows. On exit 4, sync prints a
   neutral "could not check property sets: <reason>" line, with no
   warning and no --fix-property-sets advice, because the repair would
   fail the same way.
3. When the probe crashed, --quick says "could not probe", not that the
   mxcli "predates" the command.
4. The fixture stub's slow state now execs sleep, so a timeout kills the
   process itself and leaves no child behind.

test-property-sets.sh: 61 passed. New cases: exit 4 for errors, --quick
on a crashed probe, sync's bound announcement, and sync's neutral line
on exit 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
MendixMau pushed a commit that referenced this pull request Oct 13, 2026
…their own exit code; sync announces its bound

Review: independent joint review (agent a1e0b45) of head d7804c5 — MERGE.
Nit (follow-up): sync-project.sh 4d grep -v under pipefail needs || true
if doctor ever prints nothing. Fixture: property-sets (bin/doctor.sh) 61/0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
MendixMau added a commit that referenced this pull request Oct 14, 2026
)

Every constituent PR was reviewed by a fresh agent that did not write it (CLAUDE.md "Merging a PR"); only MERGE verdicts joined. CI green on each constituent head and on this head (40814fc); full suites run on the branch.

Review lines (per merged PR):
- #315 context trim — MERGE; 360/385 removed lines found verbatim in their new homes, rest read by hand; baseline 79,997 -> 76,259.
- #316 independent-review + word-budget rules — MERGE-AFTER-FIX (3 rounds), fixes applied as specified.
- #318 page-fidelity displayed text — MERGE after fix round + confirmation.
- #317 interaction-model skill (#291 part 1) — MERGE after fix round + confirmation; no client names leaked.
- #321 PROOF-OF-LOOK per section; final-look not due before derived Stage 6 — MERGE after fix round + confirmation.
- #307 graph-sweep guard; per-BRD conformance ledgers — MERGE after two fix rounds + confirmation.
- #325 extraction-quality section; token-burn fixes — MERGE after fix round + confirmation.
- #310 e2e OQL by alias, negative-span liveness, APP-DOWN, #302 credential regression fix — MERGE after fix round + 3 confirmations.
- #323 inbox promotions — MERGE after fix round + confirmation.
- #308 lint gate BLIND on reverted stock rules — MERGE (FIRST-SEEN reverted) after two fix rounds + confirmation.
- #328 pipefail + grep -q flake — MERGE; 0/30 flakes vs 15/100 on master. Follow-up: run-all resolves bin/lib/ subjects (reviewed, MERGE).
- #319 test-stack-up command-line ownership proof — MERGE after fix round + 2 confirmations.
- #327 change-intake core + on-demand detail; CRLF-safe change log — MERGE after fix round + confirmation.
- #320 follow-ups to #290/#292; Dispatching split out — MERGE after fix round + confirmation.
- #326 status delivery rounds (existing-app mode) — MERGE after fix round + confirmation.
- #312 lint batch 4: SEC014, toolkit CONV009 — MERGE after review + 2 fix rounds + confirmation; field run on mxcli 0.26.
- #324 exec.sh change classes, shared stale-lock takeover, SEC014 note echo — MERGE (joint review); follow-up owed for a takeover race after a mid-takeover crash.
- #322 MxTest after-startup guard, mxcli-run pid check — MERGE (joint review).
- #314 doctor property-set exit code; sync announces its bound — MERGE (joint review).
- #330 review follow-ups (exit 4/5 docs, pipefail, NUL strip) — MERGE-AFTER-FIX, fixes applied; takeover re-check dropped.

Field runs are still owed for most instruments in this batch (stated in each PR).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
@MendixMau

Copy link
Copy Markdown
Owner Author

Landed on master as part of the integration squash #329 (commit 31e90ae), after independent review — its Review: line is in that commit message. Closing as superseded.


Generated by Claude Code

@MendixMau MendixMau closed this Oct 14, 2026
@MendixMau
MendixMau deleted the feat/adopt-mxcli-026-fixes branch October 15, 2026 10:45
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.

[bug] sync-project dies silently (rc 1) before its bin/ drift section, so a pre-fix model-stamp.sh is never reported

2 participants