Skip to content

WIP: Mac-local divergence — 2 unique commits + uncommitted state, needs rebase cleanup - #2

Closed
MendixMau wants to merge 11 commits into
masterfrom
wip/local-divergence-20260901
Closed

WIP: Mac-local divergence — 2 unique commits + uncommitted state, needs rebase cleanup#2
MendixMau wants to merge 11 commits into
masterfrom
wip/local-divergence-20260901

Conversation

@MendixMau

Copy link
Copy Markdown
Owner

For the cleanup session — do not merge as-is

Local master on the Mac diverged from origin/master: 10 ahead / 91 behind (merge-base 78c5a1a, 21 Aug). This branch parks everything so nothing is lost.

What's actually unique

git cherry says 8 of the 10 local commits are already upstream (patch-equivalent). Only these two need to survive:

  • 372e2ac — Correct the false Studio Pro dependency in the cloud/mobile prompts
  • 8b5a8bb — Correct the DECISION prohibition and add the workflow-object corruption class

The WIP commit (7cd08ca) on top

Uncommitted working-tree state, committed as-is. 8 files were also changed on origin/master and need manual resolution:
CLAUDE.md, bin/sync-project.sh, bug-logs/mxcli-bugs.md, project-bin/verify-module.sh, project-tests/e2e/design-audit.js, skills/existing-app-assurance.md, skills/learned-mdl-preflight.md, skills/learned-workflow-patterns.md

New files riding along: skills/existing-app-change.md, docs/progress/RESUME.md, docs/progress/checkpoints.md, checkpoint skill edits.

Also gitignores .claude/ — the leak guard flagged a park note carrying a client name; session state stays machine-local.

Suggested cleanup

  1. Rebase this branch onto origin/master — the 8 duplicate commits drop out.
  2. Resolve the 8 overlapping files (mostly append-style: bug-logs, learned-* skills).
  3. Squash/reword the WIP commit into something publishable, then merge.
  4. Local Mac master still points at the old 10-ahead state — reset it to origin/master after this lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SdRumsEs38iGa2QLxbHyvJ

MendixMau and others added 11 commits August 21, 2026 17:30
…dit skill

coherence-cadence.sh derived "proven modules" from architecture/modules/*/
subdirectories per module-brief.md's canonical layout, but a project using
flat <Module>-brief.md files (a spec drift) made the glob match zero
directories, silently reporting 0 proven modules forever regardless of how
many verify-module.sh passes had actually run. Now reads
.claude/loop/verify/<Module>/summary.tsv directly, which is the project's
own record of what ran and doesn't depend on a second directory matching a
convention it may not follow.

Also adds skills/full-harness-audit.md: a consolidated map of the whole
testing harness (layer stack, the three easily-confused review passes, the
five journey rungs, the cadence/obligations layer, and what fires
automatically through the build-plan/module-brief/ledger timeline) plus a
reusable trigger prompt for a genuine full click-through audit. Routed via
ROUTING.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… entries

Rounds out the three-passes table with the whole-app LOOK variant
(full-ui-loop) and names the two UI-focused checks that live inside/
alongside LOOK: design-audit.js (mechanical, runs automatically every
module) and learned-skill-ux-audit.md (heavier, standalone, on-demand
design-system gap analysis). All three were real, already-built parts
of the harness that the first pass at this skill left off the map.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…on class

learned-workflow-patterns.md Warning 1 read as an absolute "never emit a
DECISION activity" while the same file's §13 already scoped that corruption
to a v0.16.0 binary defect — an internal contradiction that sends people to
Studio Pro to hand-build gateways mxcli v0.18.0 writes correctly. Warning 1
is now a binary-version gate, matching §13's shape.

New sections, from 2026-08-20/21 build experience on v0.18.0:

- §14 referencing a not-yet-created microflow from a workflow body corrupts
  the stored workflow object; the corruption survives creating the microflow
  afterwards and resurfaces later as CE0495 on untouched sibling activities.
  Same class as BUG-92. Includes the checker gap, the snapshot-bisect
  procedure, and an untested recovery path.
- §15 DECISION vs CALL MICROFLOW — decided by what the expression must reach,
  not by how simple the logic looks (bracket-predicate traversal is CE0117).
- §16 OUTCOMES is optional; the both-branches-empty dead-branch smell and the
  two legitimate fixes.
- §17 fewer moving parts as a corruption-risk criterion, not style.
- §18 confirm PARALLEL SPLIT isn't already there before flagging a fan-out.
- §19 no BOUNDARY EVENT TIMER without documented SLA evidence.
- §20 `= empty` on an association: valid in an IF, invalid in a RETRIEVE
  WHERE (XPath has no such comparison).

Also adds preflight STOP #20 for the create-before-reference ordering rule,
and updates the three routing descriptors.

Promoted from personal-toolkit skills/workflow-patterns.md; client project
names anonymized per the convention already used in this file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
commands/mobile-dev-loop-prompt.md asserted that the build gate requires
Studio Pro and that a headless container therefore cannot run it. That is
wrong, and it was stopping cloud sessions at a boundary that does not exist:
the gate is mxbuild, a plain binary that project-bin/exec.sh invokes directly,
and exec.sh's only Studio Pro coupling is a lock check (refuse to write while
SP holds the .mpr) which is a no-op where no SP exists.

Both prompts also predate mxcli run --local / --hub / --test-endpoint, which
the toolkit did not mention anywhere. A container can now stand the app up
itself and publish it at a public URL, so the hand-rolled ngrok/cloudflared
tunnel is no longer the only route in.

- mobile-dev-loop-prompt.md: dated correction note; DO-NOT list reframed as
  out-of-scope-for-this-prompt rather than impossible-here.
- mobile-auto-test-prompt.md: stand-it-up-here is now the preferred option.
- testing-shape.md: mxcli run --local flag table, runtime.log note.
- e2e-harness-base.md: BASE_URL no longer assumes localhost:8080.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…import range trap

Re-measured on mxcli v0.18.0 / Mendix 11.13.0 with a runtime mxcli test:
- entity names need not match JSON element names (proven with zero matches)
- JSON structure root 0..1 instantiates fine since v0.17 (BUG-LOCAL-14 fixed)
- NEW: import from mapping with no range keyword writes ForceSingleOccurrence=1
  and returns EMPTY silently; write 'all'. Repro scripts in fixtures/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found during a Windows training round where gate-check took 5-15 minutes per
run and participants switched it off.

CORRECTNESS — the mxbuild gate never ran on Windows at all.
_common.sh looked for Studio Pro only at /Applications/*.app and exec.sh got
JAVA_HOME only from /usr/libexec/java_home, both macOS-only. Under Git Bash both
resolved empty, so exec.sh's guard `[ -x "$MXBUILD" ] && [ -x "$JAVA_EXE" ]` was
false and the whole gate block was skipped. It reported `skipped` rather than a
false `pass` — it was built "three states, not two" for this reason — but a skip
without a stated cause is a skip nobody acts on, so every MDL exec on a Windows
machine went unverified. That is the BSON-corruption class that
iterative-build-loop.md:243 names mxbuild as the only reliable detector for.

  - mxtk_platform() + Windows branches in find_sp_app/find_mxbuild
    (C:\Program Files\Mendix\<version>\modeler\mxbuild.exe, version-sorted)
  - find_java/find_java_exe, preferring Studio Pro's own bundled JRE
  - exec.sh now says WHY the gate will be skipped, naming the missing binary

PERFORMANCE — gate-check forked ~1,130-5,790 processes per run.
_ob_waiver() ran per (obligation x unit) and re-parsed the ENTIRE register on
each call, forking `tr` AND `sed` per line: O(register x obligations x units).
Free at ~4ms/fork on macOS; on Git Bash, where MSYS emulates fork() and a spawn
measured 152ms on a training laptop, it was minutes.

  - register parsed ONCE per path into a memoized cache, one awk pass
  - _ob_lc(): fork-free lowercase via a global (bash 3.2 has no ${var,,})
  - also fixes a portability bug the rewrite subsumes: `sed 's/^[ \t]*//'` read
    \t as a real tab under GNU sed but as literal backslash-or-t under BSD sed,
    so macOS silently stripped a leading 't' from keys

    VB-USI-main     5,790 -> 226 forks  (Windows ~880s -> ~34s)
    fieldrun-keyist 1,127 -> 186 forks  (Windows ~171s -> ~28s)
    scaling is now ~flat per module instead of ~+800 forks each

ESCAPE HATCHES — MXTK_SKIP_GATES=1 (exit 0, loud on stderr, never reads as a
pass) and MXTK_NO_FETCH=1. The protocol-freshness `git fetch` also ran on every
invocation with no timeout over an HTTPS remote; it is now capped by git's own
low-speed abort with GIT_TERMINAL_PROMPT=0. No `timeout` wrapper: macOS ships
neither timeout nor gtimeout.

Verified: gate-check output byte-identical across 4 projects x 11 stages
(controlled for advise()'s one-shot state). test-bug02-register.sh 8 ok,
test-bug03-gates.sh 9 ok. test-source-sufficiency-gate.sh has 2 failures that
reproduce identically with these changes stashed — pre-existing, not from here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three changes from a customer training round's post-mortem (2026-08-25), each
traced to an artifact rather than a hunch.

exec.sh gains guard 5: no module brief, no write. The brief was enforced only
by check_build_ready() -- a command nobody is obliged to run -- so a project
that never declared itself build-ready was never asked for one. That project
executed 25 scripts against a module whose architecture/modules/<M>/ held only
definition.md. Satisfied by either the separate file or a "## Module brief --
<M>" heading in the plan, because single-module projects should merge the two
rather than keep documents that overlap ~70%. Fires on writes INTO a module,
including "create or modify module role" (roles are the brief's access table);
not on bare CREATE MODULE, which is scaffolding an empty shell -- and which
keeps tests/wave2/test-bug07-08.sh's fixture working.

brd-to-build-plan.md Step 5 gains a row schema with four kinds -- BUILD, PROVE,
RUN, HARNESS -- one number sequence, and a Skills column where "none" is valid
but blank is not. That plan had 35 build rows and zero verification rows, and
not because anyone dropped them: every column of the schema in use described a
build, so there was nowhere to write "prove the mapping returns 202". The brief
becomes row 0 of its module's phase, which is what gives the guard above a
state to read.

module-brief.md's "Build skills to read first" asked only about Workflow and
Agent decisions, so integration fell through: skill-routing.tsv had
rest-integration-first-time-right.md in build/integration and nothing ever
named it. All 15 "import from mapping" calls shipped without the range keyword
(silent EMPTY, clean at check/--references/mxbuild/runtime) and all 4 wrapper
associations pointed child->parent. It now covers every build group and is a
roll-up of the rows' Skills column, not a second authoring pass.

iterative-build-loop.md:136 said the brief is enforced manually. It isn't now.

Tested: 12/12 case matrix (comment-stripped phantom modules, both brief forms,
wrong-module heading, FORCE_EXEC, platform skip, multi-module, bare CREATE
MODULE) plus a 28-script replay of that round's real day 1 -- first refusal at
script 1 of 28. No wave2 fixture was run; test-bug07-08.sh was verified by
inspection, which is how the CREATE MODULE regression was caught before it
shipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
known_fix_note had one entry. A project scaffolded before 2026-08-25 has an
exec.sh that differs from the toolkit's, so sync correctly classifies it as
locally modified and reports drift rather than overwriting -- it cannot tell
"the user hardened this" from "the toolkit moved on", and blind-overwriting
would destroy real work in six projects on this machine.

The consequence is that the drift line was the ONLY thing standing between a
Windows project and an exec.sh whose mxbuild gate never runs, and it said only
how many lines differed. Now it names both misses: the Windows mxbuild gate
(macOS-only path resolution meant every exec on Git Bash went unverified) and
the module-brief guard. A reader can decide whether --upgrade-bin is worth it
without diffing 29k of shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The brief was enforced by a hard block in exec.sh guard 5, which blocked
a-la-carte use: a project with no architecture/ at all was refused a write
by a pipeline artifact it never opted into.

Guard 5 now warns and continues, has no FORCE_EXEC path, and is silent
entirely in projects with no architecture/build-plan.md. The ordering
guarantee moves to the document that actually steers a build: every phase
opens with a numbered BRIEF row (a fifth row kind), phrased check-then-
create -- does the brief exist and cover this phase's rows, create if
absent, extend if thin. One brief per module, grown across its phases
rather than rewritten, so a short phase adds a short increment.

A rule in a skill file is followed by whoever loaded the skill; a numbered
row with a State cell is followed by whoever works the plan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The freshness notice was written for someone who already knew what a
"protocol commit" was: two abbreviated SHAs, the word "ack", and skill
file paths. Run in front of TAMs in an enablement session, it reads as
something being broken, and the only reachable answer was a shell command.

Output is now plain-language by default with commit ids, paths and
diffstat behind --verbose. The TTY refusal is replaced, not removed: an
ack still asserts a human was told, but "a human" is no longer equated
with "a human at a terminal". --ack-protocol --verbose without a TTY is a
read-only preview that records nothing and instructs the agent to
summarise and ask; --ack-protocol --approved-in-chat records the answer.
The log line carries which route was used. There is still no env-var
auto-yes.

test-bug06-freshness.sh helpers pass --verbose so every existing technical
assertion holds verbatim, plus a new control for the plain default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dirty tracked files plus new skill/docs, committed as-is so nothing is lost
while another session rebases the branch divergence (local master is
10 ahead / 91 behind origin/master; git cherry says 8 of the 10 are already
upstream — only 372e2ac and 8b5a8bb are unique).

8 of these files were also changed on origin/master and need manual
resolution: CLAUDE.md, bin/sync-project.sh, bug-logs/mxcli-bugs.md,
project-bin/verify-module.sh, project-tests/e2e/design-audit.js,
skills/existing-app-assurance.md, skills/learned-mdl-preflight.md,
skills/learned-workflow-patterns.md

Also gitignores .claude/ session state: the leak guard correctly flagged a
park note carrying a client name — machine-local files, never publishable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdRumsEs38iGa2QLxbHyvJ
MendixMau added a commit that referenced this pull request Sep 8, 2026
…-prompt correction, workflow §21, JUMP TO STOP row, BUG-140 (#20)

The pieces of wip/local-divergence-20260901 (draft PR #2) that master
lacked: the cloud/mobile prompt commands no longer claim the build gate
needs Studio Pro; skills/existing-app-change.md (changing a live app with
no BRDs, Path D knowledge base, blast-radius stages) with routing row;
learned-workflow-patterns §21 reconciled — DECISION recorded as disputed
against BUG-76's same-day reproduction, not cleared; mdl-preflight STOP
row 24 (JUMP TO target validation); BUG-140 plus addenda under
BUG-109/110/118; stale project-profile.md references fixed.

Merged by the toolkit queue: ported in an isolated worktree, five gates
green. Open item: bisect the DECISION shape on a v0.20.0 binary.
Follow-up: close draft PR #2 and delete its branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
@MendixMau MendixMau closed this Sep 8, 2026
@MendixMau

Copy link
Copy Markdown
Owner Author

Closed by the merge queue: everything on this branch that master lacked was salvaged in #20 (cherry-pick of 372e2ac plus the hand-ported existing-app-change.md skill, workflow §21 reconciled against BUG-76, mdl-preflight STOP row 24, BUG-140 and addenda, project-profile.md reference fixes). 8 of the 11 commits were already on master; docs/progress/* and the .gitignore change were deliberately not ported. The branch wip/local-divergence-20260901 can be deleted.


Generated by Claude Code

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.

1 participant