Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m

## Unreleased

- fix(sync-project): **the "Baseline-only skills cited" warning no longer fires on the toolkit's own wiring block, and no longer sizes a section that does not exist.** The check grepped all of `CLAUDE.md` for `skills/learned-mdl-preflight.md` / `skills/query-the-model.md`, and `wire-agents.sh`'s `mxtk:wiring` block cites the first, so every sync flagged the toolkit's own text; with no "mxcli-project-toolkit Integration" heading it then printed a whole-file word count as "heading to EOF". The wiring block is now stripped before the grep, and the warning is raised only when the heading exists. `tests/wave2/test-sync-dup-heading-exit.sh` T4 flips (no heading: no warning) and gains T7-T9. — joshuamoesa (#382)
- learn(workflow, rest): **the v0.20-era workflow notes are marked superseded for mxcli v0.26.0:** `WAIT FOR NOTIFICATION` takes a name, `NOTIFY WORKFLOW` needs `TARGET Module.Workflow.Element` (CE0166 / MDL-WF16 without), mxcli writes the end-of-boundary-path marker itself so a boundary terminator is no longer a hand-add (the parallel-split terminator is a separate node and unchanged), and published REST `Authentication: (basic)` works (BUG-152 item 1: 401 / 401 / 200 proven, URL includes the resource segment). Sources: a five-app lab field run (Mendix 11.15, mxcli v0.26.0) and mxcli's public `write-workflows` skill and docs. `wf-add-path-terminators.py` already takes an `.mpr` since #294 (the reported crash was the older script). — TK-019 of a five-app lab report
- learn(workflow): **a "compute, then branch" pattern in `workflow-structure-rules.md`: a workflow decision reads a Boolean or enumeration on the context and cannot call a microflow, so the rule is computed by an earlier call microflow into a context attribute (TK-023).** The same paragraph names the three limits a field run hit (called microflow returns Boolean, enumeration or nothing; decision expressions on the context only; single-outcome user task holds no activities, MDL-WF02 / CE1876). The call-microflow return rule and the lone-outcome rule were already in the skill (§5, `learned-workflow-patterns.md` §6); the report's claim that an `exposed as workflow action` microflow cannot return a value was not adopted, because mxcli's own docs show one with `returns String`. — five-app lab report, TK-023
- learn(bug-ledger): **published REST answers 404, not 403, for a user without the allowed role** (TK-046, Mendix runtime behaviour; write 404 into the contract) — a five-app lab project
Expand Down
20 changes: 14 additions & 6 deletions bin/sync-project.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1058,17 +1058,25 @@ if [ -f "$PROJECT_DIR/CLAUDE.local.md" ]; then
# can also trip it; the message below is phrased as "check whether" for that reason, not as
# a flat assertion. Same rule as the ledger-row warn above: CLAUDE.md is bootstrap-project.md's
# (an LLM merge), not this script's, so sync never edits it — only names the fix.
if [ -f "$PROJECT_DIR/CLAUDE.md" ] && grep -qE 'skills/(learned-mdl-preflight|query-the-model)\.md' "$PROJECT_DIR/CLAUDE.md"; then
# The toolkit's own wiring block (mxtk:wiring:start..end, written by wire-agents.sh) cites
# skills/learned-mdl-preflight.md in its item-3 sentence, so it is stripped before the grep:
# otherwise the toolkit flags its own text as the adopter's duplicate (#382). And the check
# only speaks when the "mxcli-project-toolkit Integration" heading exists: with no heading
# there is no section to name or size, and a whole-file word count described as "heading to
# EOF" pointed the adopter at text that is not theirs to edit.
_dup_from_line=""
if [ -f "$PROJECT_DIR/CLAUDE.md" ]; then
_dup_body="$(awk '/mxtk:wiring:start/{skip=1} !skip{print} /mxtk:wiring:end/{skip=0}' "$PROJECT_DIR/CLAUDE.md")"
# `|| true`: no heading is the COMMON case (every CLAUDE.md mxcli init v0.25 writes cites
# the skills without it). Unguarded, grep's exit 1 fails the pipeline under pipefail and
# errexit ended the whole sync here, silently, before the bin/ and tests/e2e refresh —
# every sync from 9a0350b (2026-09-18) to this fix. Regression: tests/wave2/test-sync-dup-heading-exit.sh.
_dup_from_line="$(grep -n 'mxcli-project-toolkit Integration' "$PROJECT_DIR/CLAUDE.md" | head -1 | cut -d: -f1 || true)"
if [ -n "$_dup_from_line" ]; then
_dup_words="$(tail -n "+$_dup_from_line" "$PROJECT_DIR/CLAUDE.md" | wc -w | tr -d ' ')"
else
_dup_words="$(wc -w < "$PROJECT_DIR/CLAUDE.md" | tr -d ' ')"
if grep -qE -- 'skills/(learned-mdl-preflight|query-the-model)\.md' <<<"$_dup_body"; then
_dup_from_line="$(printf '%s\n' "$_dup_body" | grep -n 'mxcli-project-toolkit Integration' | head -1 | cut -d: -f1 || true)"
fi
fi
if [ -n "$_dup_from_line" ]; then
_dup_words="$(printf '%s\n' "$_dup_body" | tail -n "+$_dup_from_line" | wc -w | tr -d ' ')"
warn "CLAUDE.md cites Baseline-only skills also covered by CLAUDE.local.md — check whether" \
"its \"mxcli-project-toolkit Integration\" section (~$_dup_words word(s), heading to" \
"EOF, not all of it necessarily routing) is a duplicated Baseline routing block." \
Expand Down
26 changes: 23 additions & 3 deletions tests/wave2/test-sync-dup-heading-exit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ printf '%s\n' "$OUT" | grep -q 'Would install: bin/exec.sh' \
printf '%s\n' "$OUT" | grep -qE 'artifact\(s\) would be updated|All copied artifacts up to date' \
&& ok "T3 no heading: sync reaches its summary line" \
|| bad "T3 no heading: sync reaches its summary line"
printf '%s\n' "$OUT" | grep -q 'cites Baseline-only skills' \
&& ok "T4 no heading: the duplicate-routing warning is still raised" \
|| bad "T4 no heading: the duplicate-routing warning is still raised"
if printf '%s\n' "$OUT" | grep -q 'cites Baseline-only skills'; then
bad "T4 no heading: no duplicate-routing warning (nothing to name or size, #382)"
else
ok "T4 no heading: no duplicate-routing warning (nothing to name or size, #382)"
fi

# --- heading present: the case the check was written for keeps working ------------------
P2="$(mkproj withheading)"
Expand All @@ -60,6 +62,24 @@ printf '%s\n' "$OUT2" | grep -qE 'section \(~[0-9]+ word' \
&& ok "T6 heading: warning sizes the section" \
|| bad "T6 heading: warning sizes the section"

# --- #382: a citation inside the toolkit's own wiring block is not the adopter's duplicate ---
P3="$(mkproj wiringonly)"
printf '\n<!-- mxtk:wiring:start -->\nsee skills/learned-mdl-preflight.md STOP table\n<!-- mxtk:wiring:end -->\n' >> "$P3/CLAUDE.md"
OUT3="$("$SYNC" "$P3" --dry-run 2>&1)"; RC3=$?
[ "$RC3" -eq 0 ] && ok "T7 wiring block only: sync exits 0" || bad "T7 wiring block only: sync exits 0 (got $RC3)"
if printf '%s\n' "$OUT3" | grep -q 'cites Baseline-only skills'; then
bad "T8 wiring block only: no duplicate-routing warning"
else
ok "T8 wiring block only: no duplicate-routing warning"
fi
# the same text OUTSIDE the block, under the heading, still warns
P4="$(mkproj wiringplusheading)"
printf '\n<!-- mxtk:wiring:start -->\nsee skills/learned-mdl-preflight.md\n<!-- mxtk:wiring:end -->\n\n## mxcli-project-toolkit Integration\n\nRead skills/query-the-model.md.\n' >> "$P4/CLAUDE.md"
OUT4="$("$SYNC" "$P4" --dry-run 2>&1)"
printf '%s\n' "$OUT4" | grep -qE 'section \(~[0-9]+ word' \
&& ok "T9 block + heading: warning still raised, sized from the heading" \
|| bad "T9 block + heading: warning still raised, sized from the heading"

echo ""
echo "test-sync-dup-heading-exit: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]
Loading