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(facts-lock): **`check` no longer reports "N BRD(s) agree with all 0 frozen fact(s)" when nothing was compared** (#519). A corpus whose BRDs carry identifiers only under keys the harvest does not read (`domainEntities[].name`, `pages[].name`) froze an empty lock, and `check` printed what reads as a pass. With 0 frozen facts, `check` now prints `PENDING facts-lock: 0 identifiers found under any known key in N BRD(s): the lock is empty and check proves nothing (keys read: ...)`, or, when identifiers exist but no lock was built, `PENDING ... run build first; check compared nothing`; `build` prints the same empty-lock line when it froze 0 facts and found no conflicts. Exit codes are unchanged (an exit-3 "nothing measured" and harvesting `name` keys are left for a separate change). Fixture: `test-facts-lock.sh` (the issue's repro: 3 fail on master; 19/19). — AlvinnYeo (#519)
- fix(journey-runner): **the RUNG 1 landing guard now waits up to its 12 s for `ui.ready`** (#536). It called `locator.isVisible({ timeout: 12000 })`, and Playwright ignores that timeout and answers at once, so a page that rendered more than 300 ms after the per-action settle (a progress bar, a microflow before the page opens, a step ending in a fixed `settleMs`) read `reached: FAIL` and every later rung of the step INVALID. It now uses `waitFor({ state: 'visible', timeout: 12000 })`, and the NOT-REACHED screenshot is taken after that wait. Only the landing guard changes; the same no-wait call in `act()` (`click`, lines 184/210/222), the named-control probe and `helpers.js`/`monkey.js`/`full-app-walkthrough.js` are left for a separate change. **Behaviour change to check in your project:** a journey whose ready selector never appears now spends 12 s per such step before it reports NOT-REACHED. Verified by inspection and a Playwright probe (hidden element shown after 2 s: `isVisible` false in 74 ms, `waitFor` true in 2.3 s); no fixture drives the runner's step loop. — AlvinnYeo (#536)
- fix(build loop, exec): **the commit guidance stages `javasource/` and `javascriptsource/`, and `exec.sh` prints a staging hint when they changed** (#540). `create java action ... as $$` writes `javasource/<module>/actions/*.java` beside the model; the skill's example (`git add App.mpr mprcontents/ mdlsource/<script>.mdl`) committed the model without the body, which builds on the machine that ran exec and not in a clone. `iterative-build-loop.md` (both `git add` examples and the sentence after the exec one, +44 words, on-demand file: baseline 73828 before and after) now names both folders and says to drop one the app lacks (git refuses the whole add on a missing pathspec). After a clean exec, `exec.sh` runs one `git status --porcelain` over the model folder's `javasource/` and `javascriptsource/` and, when either has changes, prints `Action sources changed outside the model ...: stage them with the .mpr.` with up to 5 paths; never a failure, no mxcli call, exit codes unchanged. **Behaviour change to check in your project:** `exec.sh` success output can carry that hint. Fixture: `test-bug07-08.sh` A2/A3 (A2 fails on master; 48/48). — AlvinnYeo (#540)
- fix(page-fidelity): **a wireframe's `widget-datagrid-content` grid mimic is no longer taken as the page body** (#537). `contentOf()`'s `.main` and `.content` fallbacks matched `\bmain\b` / `\bcontent\b`, and `\b` treats `-` as a boundary, so a hyphenated class such as `widget-datagrid-content` won, the page was reduced to the inside of one grid, and the title and buttons outside it scored `headings 0/0 actions 0/0` (or UNMEASURED). Both fallbacks now match the whole class word with the existing `cls()` helper (still `div` only), as the popup rules already did. **Behaviour change to check in your project:** text-match scores (and the `docs/PAGE-FIDELITY.tsv` rows they append) can move for a wireframe with no `<main>`/`wf-screen`/`wf-shell`/`mockup-frame` whose first `main`/`content` match was a hyphenated class such as `main-area` or `x-content`: it is now scored from the next rule (often `<body>`). Fixture: `test-page-fidelity-mocks.sh` (the issue's wireframe: fails 3 on master; 83/83). — AlvinnYeo (#537)
Expand Down
12 changes: 11 additions & 1 deletion bin/facts-lock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ for ns, clusters in sorted(harvest.items()):
conflicts.append((ns, ck, {v: sorted(spellings[v]) for v in variants}))

# --- act ----------------------------------------------------------------------------------------
EMPTY_MSG = ("PENDING facts-lock: 0 identifiers found under any known key in %d BRD(s): the lock is empty "
"and check proves nothing (keys read: " + ", ".join(k for ks in KEYED.values() for k in ks) + ", *_CODE_SET)")
if CMD == "build":
for ns, ck, canon, srcs in new_facts:
frozen.setdefault(ns, {})[ck] = {"canonical": canon, "sources": srcs}
Expand All @@ -229,6 +231,8 @@ if CMD == "build":
total = sum(len(v) for v in frozen.values())
print("facts-lock: %d fact(s) frozen across %d namespace(s), from %d BRD(s)" % (total, len(frozen), len(brds)))
print(" %s" % LOCK)
if total == 0 and not conflicts:
print(EMPTY_MSG % len(brds))

for src, err in unreadable:
print(" UNREADABLE %s — %s (its facts are NOT in the lock)" % (src, err))
Expand All @@ -253,7 +257,13 @@ if CMD == "check":
print(" UNFROZEN %s/%s is contested (%s) — build has not resolved it" % (ns, ck, "/".join(sorted(sp))))
if not deviations and not conflicts:
total = sum(len(v) for v in frozen.values())
print("facts-lock: %d BRD(s) agree with all %d frozen fact(s)" % (len(brds), total))
if total == 0:
# 0 compared is not agreement (#519): a lock with no facts proves nothing.
print(EMPTY_MSG % len(brds) if not harvest else
"PENDING facts-lock: the lock holds 0 facts while %d identifier(s) were found in %d BRD(s): run build first; check compared nothing"
% (sum(len(c) for c in harvest.values()), len(brds)))
else:
print("facts-lock: %d BRD(s) agree with all %d frozen fact(s)" % (len(brds), total))

if unreadable:
sys.exit(1)
Expand Down
27 changes: 27 additions & 0 deletions tests/wave2/test-facts-lock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,33 @@ esac
bash "$SUBJECT" "$P" show >/dev/null 2>&1
[ "$?" -ne 0 ] && ok "an unreadable BRD makes the run non-zero" || bad "exited 0 despite not reading a BRD"

# --- 0 facts is not agreement (#519) -------------------------------------------------------------------
# The issue's repro: BRDs that carry identifiers only under `name` keys give the harvest nothing.
# check used to print "2 BRD(s) agree with all 0 frozen fact(s)", which reads as a pass over a
# comparison that never happened. Exit codes are unchanged; the line must say PENDING, not agree.
Z="$WORK/zero"; mkdir -p "$Z/analysis/x/knowledge-base/brd"
echo '{"id":"F001","domainEntities":[{"name":"PaymentPlan"}],"pages":[{"name":"PaymentPlan_Overview"}]}' > "$Z/analysis/x/knowledge-base/brd/F001-a.brd.json"
echo '{"id":"F002","domainEntities":[{"name":"Paymentplan"}],"pages":[{"name":"PaymentPlan_Overview"}]}' > "$Z/analysis/x/knowledge-base/brd/F002-b.brd.json"
ZC=$(bash "$SUBJECT" "$Z" check 2>&1)
case "$ZC" in
*"agree with all 0"*) bad "check over 0 harvested facts still reads as agreement"; echo " $ZC" | head -2 ;;
*"PENDING facts-lock: 0 identifiers found under any known key in 2 BRD(s)"*) ok "check over 0 harvested facts says PENDING, not agree" ;;
*) bad "check over 0 harvested facts printed neither agree nor PENDING"; echo " $ZC" | head -2 ;;
esac
ZB=$(bash "$SUBJECT" "$Z" build 2>&1)
case "$ZB" in
*"PENDING facts-lock: 0 identifiers found"*) ok "build that freezes 0 facts says the lock is empty" ;;
*) bad "build froze 0 facts and did not say the lock is empty"; echo " $ZB" | head -3 ;;
esac
# A lock not yet built over a corpus that does have identifiers: check says build first.
N="$WORK/notbuilt"; mkdir -p "$N/analysis/x/knowledge-base/brd"
echo '{"id":"F001","domainEntities":[{"entity":"PaymentPlan"}]}' > "$N/analysis/x/knowledge-base/brd/F001-a.brd.json"
NC=$(bash "$SUBJECT" "$N" check 2>&1)
case "$NC" in
*"run build first"*) ok "check with no lock built says run build first, not agree" ;;
*) bad "check with no lock built did not say run build first"; echo " $NC" | head -2 ;;
esac

# --- usage --------------------------------------------------------------------------------------------
bash "$SUBJECT" 2>/dev/null; [ "$?" -eq 2 ] && ok "no argument exits 2" || bad "no argument did not exit 2"
bash "$SUBJECT" "$P" nonsense 2>/dev/null; [ "$?" -eq 2 ] && ok "unknown subcommand exits 2" || bad "unknown subcommand accepted"
Expand Down
Loading