Skip to content

Commit a8fbbe3

Browse files
committed
Review fixes for #526: held status, badge, sign-off phase, signed-off counts
- F1: a clean, LOOK n/n module whose State is blocked or pending a person is "held" (st-person), never Verified and not counted as signed off, as #501 never promoted it. - F2: the Phase state badge is rolled up from build rows only (disp_rollup); a HARNESS-only phase reads "sign-off only". build-plan.json is unchanged (byte-identical apart from generatedAt). - F3: a phase with no build rows says "Sign-off phase: no build rows", no bar. - F4: Stage 5 owed text, Build progress line and KPI add ", k of n modules signed off". - F5: stale with no build since -> "a script was marked done- after it". - F6: the lede counts sign-off modules, not rows. - Drop the now-unused harness_verify(); "(not counted)" in the fallback table. Fixture: H9, H10, N5, N6 added, N1/N2/N4 updated; both layouts. master 2/30, previous head af9876c 18/30, this head 30/30. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
1 parent af9876c commit a8fbbe3

4 files changed

Lines changed: 94 additions & 52 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m
1919

2020
## Unreleased
2121

22-
- fix(progress-report, build-plan-status): **HARNESS rows are no longer counted as built rows, and a module's `verify-module.sh` row shows once, as that module's sign-off status on its phase card, instead of as a row.** A HARNESS step is a module's sign-off, not a build, so it is out of every "x of y built" count: the phase cards, the plan rollup and the Stage 5 card in `progress-report.html`, and the lede of `build-plan-status.sh --html` ("N build rows", plus a "Not counted: N HARNESS rows" note). The verify row's evidence is read exactly as #501 reads it (`harness_verify`, now split into `verify_evidence` + `module_status` in `progress-report.py`; nothing new measured, no extra script run, no mxcli or mxbuild call) and shown as one line per module: `Verified ✓ <date> (LOOK n/n)`, `Verify owed - LOOK + CONFIRM`, `Verify stale (N builds since)`, `Verify not run`, `built? no verify summary`, or `Verify not clean <date> (<why>)` for a summary with a FAULT, FINDING or SKIPPED row; a State cell that disagrees is flagged under it, and the rollup says how many modules are verified. A module with no verify row shows no status. Other HARNESS rows (a coherence pass, a harness run) stay in the row list, marked "(not counted)". `build-plan.md`, `build-plan.json` and the text output are unchanged, so agents still see every HARNESS step. **Behaviour change to check in your project:** the progress report's built counts drop the HARNESS rows (a plan of 10 rows with 2 HARNESS reads "x of 8"), and the verify rows leave the row tables. Fixture: `test-progress-harness-verify.sh` (H1-H8, N1-N4, both layouts). — MendixMau (decision 2026-10-21)
22+
- fix(progress-report, build-plan-status): **HARNESS rows are no longer counted as built rows, and a module's `verify-module.sh` row shows once, as that module's sign-off status on its phase card, instead of as a row.** A HARNESS step is a module's sign-off, not a build, so it is out of every "x of y built" count: the phase cards, the plan rollup and the Stage 5 card in `progress-report.html`, and the lede of `build-plan-status.sh --html` ("N build rows", plus a "Not counted: N HARNESS rows" note). The verify row's evidence is read exactly as #501 reads it (`harness_verify`'s rule, now `verify_evidence` + `module_status` in `progress-report.py`; nothing new measured, no extra script run, no mxcli or mxbuild call) and shown as one line per module: `Verified ✓ <date> (LOOK n/n)`, `Verify owed - LOOK + CONFIRM`, `Verify stale (N builds since)` (or `(a script was marked done- after it)`), `Verify not run`, `built? no verify summary`, `Verify not clean <date> (<why>)` for a summary with a FAULT, FINDING or SKIPPED row, or `Verify clean <date>, LOOK n/n - held: State says <State>` when State is blocked or pending a person (held is not signed off, as #501 never promoted it); a State cell that disagrees is flagged under it, the rollup says how many modules are verified, and the Stage 5 card, KPI and owed text add ", k of n modules signed off". The Phase state badge is read from the build rows only (a phase of HARNESS rows alone says "sign-off only" and its card "Sign-off phase: no build rows"). A module with no verify row shows no status. Other HARNESS rows (a coherence pass, a harness run) stay in the row list, marked "(not counted)". `build-plan.md`, `build-plan.json` and the text output are unchanged, so agents still see every HARNESS step. **Behaviour change to check in your project:** the progress report's built counts drop the HARNESS rows (a plan of 10 rows with 2 HARNESS reads "x of 8"), and the verify rows leave the row tables. Fixture: `test-progress-harness-verify.sh` (H1-H10, N1-N6, both layouts). — MendixMau (decision 2026-10-21)
2323
- fix(exec): **a script restated from a stale DESCRIBE now WARNs instead of silently reverting an earlier exec** (#261). A script drafted from a DESCRIBE taken before an earlier script of the batch ran put four old messages back, with check, mxbuild and lint green. New `project-bin/describe-baseline.sh stamp` writes `-- baseline: <Doc> sha256=<hash>` (plus `-- baseline-mxcli: <version>`) from a DESCRIBE at draft time; `exec.sh` runs `verify` only for a script that carries the header, so other scripts cost one grep and no mxcli call. It reports DRIFT with the first lines of the diff, STALEHEADER, and RESTAMP after an mxcli upgrade (DESCRIBE text may change, so that is not called drift). A re-run by the script's own last recorded write (the #269 ledger) and a fresh model are not drift. Nothing is refused and the exit codes do not change. Preflight STOP 21 gains one clause (`-- supersedes:`, `stamp`, exec.sh only warns) and its trigger names `create or modify` (+24 words). Not-found DESCRIBE and `--version` output are captured from mxcli v0.26.0. Lands after the #269 PR; with it, supersedes draft #311. **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: stale draft: …` lines, and the BUILD-LOG detail cell `WARN stale baseline: <docs>`; `MXTK_RESTATE_GUARD=off` skips the check. — AlvinnYeo (#261)
2424
- fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: <docs>`. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269)
2525
- fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A script counts as run when it has a ledger row, a `done-` name, or an applied `docs/BUILD-LOG.md` row, so a fresh clone or cloud session (empty ledger) still warns on a replay over committed newer work; a script nobody ran yet (draft-ahead) stays quiet. The ledger cannot see Studio Pro edits or a `git pull`/`checkout` of the `.mpr`. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: <docs>`. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269)

‎project-bin/build-plan-status.sh‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ def classify(state): # the parser's rollup reading, per row (keep in step with
590590
591591
CLS = {"built": "st-built", "not built": "st-todo", "pending a person": "st-person",
592592
"partial": "st-progress", "blocked": "st-todo", "skipped": "st-todo",
593-
"in progress": "st-progress", "unknown": "st-unknown", None: "st-unknown"}
593+
"in progress": "st-progress", "unknown": "st-unknown", "sign-off only": "st-person", None: "st-unknown"}
594594
595595
phases = d.get("phases", [])
596596
all_steps = [s for p in phases for s in p["steps"]]
@@ -599,6 +599,19 @@ is_harness = lambda s: (s.get("kind") or "").strip().upper() == "HARNESS"
599599
is_signoff = lambda s: is_harness(s) and bool(VERIFY_STEP.search(s.get("step") or ""))
600600
build_steps = [s for s in all_steps if not is_harness(s)]
601601
n_signoff = sum(1 for s in all_steps if is_signoff(s)); n_harness = len(all_steps) - len(build_steps)
602+
signoff_mods = {VERIFY_STEP.search(s["step"] or "").group(1) for s in all_steps if is_signoff(s)} # modules, as the card's "k of n modules"
603+
604+
def disp_rollup(steps): # the badge: parse_plan's rollup over the build rows only (build-plan.json keeps its own)
605+
rows = [s for s in steps if not is_harness(s)]
606+
if not rows: return "sign-off only" if steps else "unknown"
607+
kinds = [classify(s["state"]) for s in rows]
608+
if None in kinds: return "unknown"
609+
kinds = [k for k in kinds if k != "skipped"]
610+
if not kinds: return "unknown"
611+
if all(k == "built" for k in kinds): return "built"
612+
if all(k in ("not built", "blocked") for k in kinds): return "not built"
613+
if all(k in ("built", "pending a person") for k in kinds): return "pending a person"
614+
return "in progress"
602615
for s in build_steps:
603616
tally[classify(s["state"])] += 1
604617
named_total = named_done = drift_rows = 0
@@ -648,7 +661,7 @@ print("<p class=lede>From <code>architecture/build-plan.md</code>: %s, %s: "
648661
(", %d not needed" % tally["skipped"]) if tally["skipped"] else "",
649662
(", <b class=st-unknown>%d with a State cell this page cannot read</b>" % tally[None]) if tally[None] else "")
650663
+ ("<p class=note>Not counted: %s (%s). A module's sign-off shows as its verify status on the phase card, not as a row.</p>" % (
651-
plural(n_harness, "HARNESS row"), ", ".join(x for x in ((plural(n_signoff, "module sign-off") if n_signoff else ""), (plural(n_harness - n_signoff, "harness pass") if n_harness - n_signoff else "")) if x)) if n_harness else ""))
664+
plural(n_harness, "HARNESS row"), ", ".join(x for x in ((("sign-offs of " + plural(len(signoff_mods), "module")) if n_signoff else ""), (plural(n_harness - n_signoff, "harness pass") if n_harness - n_signoff else "")) if x)) if n_harness else ""))
652665
if named_total:
653666
print("<p class=note>Scripts named in the plan: %d, of which %d are renamed <code>done-</code> under <code>mdlsource/</code>.%s</p>" % (
654667
named_total, named_done,
@@ -658,7 +671,7 @@ if named_total:
658671
det = []
659672
for p, out in zip(phases, rows_html):
660673
h = ['<!--phase:%s-->' % e(p["id"]),
661-
'<p class=note>Phase state: <span class="badge %s">%s</span></p>' % (CLS.get(p["state"], "st-unknown"), e(p["state"]))]
674+
'<p class=note>Phase state: <span class="badge %s">%s</span></p>' % (CLS.get(disp_rollup(p["steps"]), "st-unknown"), e(disp_rollup(p["steps"])))]
662675
if p.get("note"):
663676
h.append("<p class=note>%s</p>" % e(p["note"]))
664677
if p["steps"]:

0 commit comments

Comments
 (0)