diff --git a/CHANGELOG.md b/CHANGELOG.md index 51ab053..8ba727d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- new(existing-app-change): **map the app first, ask what to do with the findings, and let a project park until the change is named.** Stage 0 in this mode now opens with the app analysis (`app-facts.sh` + `app-report.sh`, `skills/app-analysis.md`), run without asking since it is read-only and takes about a minute, followed by the question the user owns: fix / log / accept per top finding. Kickoff no longer opens with "which slice?"; the slice and its blast radius (read from the map's tangles and edges, not recomputed) come at Stage 0b, when the change arrives. `artifact-manifest.tsv` owes the map in this mode (`app-report`, Stage 0); gate-check reports a mapped project with no change as Stage 0 `PENDING` instead of a permanent FAIL, and its Stage 1 hint names Path D instead of an extractor. `existing-app-assurance.md` Track A starts from the same report, so an audit that turns into a change does not redo it. Fixture: `test-bug03-gates.sh` T12. Field run: a live client workflow app — 28 modules, one tangle of 7 of 9 own modules, 213 loop microflows, mapped in 76 s; gate-check read it PENDING/parked with 0 needing attention — Maurits Visser - docs(pipeline-walks): **`docs/pipeline-walks.html` — a process diagram per entry mode, with the scripts run at every step.** Shared spine, migration, requirements-driven (incl. the docs-ready fast path), greenfield, change-an-existing-app (opening with the app-mapping step: `SHOW STRUCTURE`, `graph-report`, `lint`, `report`, security matrix, `marketplace diff`), à-la-carte tracks A/A2/B, and the Stage 5 BUILD→GATE→PROVE→LOOK→CONFIRM loop, each as a mermaid flowchart plus a stage/what/scripts table. Linked from the README entry-modes paragraph — Maurits Visser - fix(bin/doctor.sh): **doctor told every Podman user "docker is not installed"** — the section advertised Podman in its advice text ("Rancher Desktop or Podman … are common substitutes") while all four probes ran `docker` only: `docker info`, the `command -v docker` gate, the not-installed warning, and a start hint that said `open -a Docker`. So a machine fully able to run the container lane on Podman, but without the docker shim, was reported broken — and on a team that cannot licence Docker Desktop that reads as "go install software you are not allowed to have" (a colleague's machine-ready status carried "Docker not installed" as a known issue; they may have had Podman all along). Detection is now docker-then-podman (`MXTK_CONTAINER_RUNTIME` forces one), the runtime is **named** in the report (`podman responding — …`), the start hint knows `podman machine start` / `podman.socket`, and the not-installed warning names Podman as the licence-free option instead of implying Docker Desktop is required. Same bounded background/poll/kill probe for both, same 0/1/2 exit contract; `mxcli docker check` invocation deliberately untouched (different repo). **Not field-run** — no container runtime in the authoring container; needs one run on a Mac with Podman and no `docker` on PATH. Driver: the Mendix migration team's Docker Desktop licensing constraint — Maurits Visser - learn(skills/doctor-triage.md): **"doctor.sh says red — what now?" is now on disk instead of in a Slack thread.** Three failures that render identically get separated: my environment is wrong / the toolkit's own self-check is wrong / this line does not apply in my lane. Check the machine before naming a fix — a wrong-arch binary, a missing one and a broken self-check all read the same, which is how *"install Studio Pro 10.24.18"* became the first confident answer to a Linux-ELF mxbuild on a Mac, and how a false `fail (unreadable error file)` (the self-test bug fixed in `c0ea53c`) sent people to audit their own machines. Also: the three toolchain lanes (bundled `mx` — macOS ships one only from Mendix 11 — the Linux-only CDN toolchain, and the container lane, runtime-agnostic although doctor still probes only `docker`), a derivation for which FAILs block rather than a list that rots, the N+M-lines-dispositioned bound, and the VM/arch caveat. From the macOS onboarding thread of 2026-09-22 — Yvann, and the four people in it diff --git a/bin/gate-check.sh b/bin/gate-check.sh index 609d5ac..a902c93 100755 --- a/bin/gate-check.sh +++ b/bin/gate-check.sh @@ -824,6 +824,12 @@ check_stage_0() { }' "$f") if [ -z "$signer" ]; then echo "FAIL|no non-empty 'Confirmed by:' line inside the '## Sign-off' section of $f — anything the user actually said is enough (\"confirmed in chat\", \"agreed, move on\"); it only has to not be the shipped placeholder" + elif printf '%s' "$signer" | grep -q '\[' && [ "$ENTRY_MODE" = "existing-app-change" ] \ + && [ -s "$PROJECT_DIR/analysis/app-report.json" ]; then + # Mapped and waiting for a change is a normal state in this mode (existing-app-change.md + # §"Map the app first"): there is no slice to sign off yet, so this is not-started, not wrong. + # Without it a parked project read "needs attention" forever (existing-app field run, 2026-09-22). + echo "PENDING|app mapped (analysis/app-report.html), waiting on the change — triage.md is signed off at Stage 0b, once the user names the slice and its blast radius is written ($f, ## Sign-off)" elif printf '%s' "$signer" | grep -q '\['; then echo "FAIL|'Confirmed by:' still holds the shipped placeholder: \"$signer\" — replace it with whatever the user actually said (\"confirmed in chat 2026-08-20\" is fine; a full name is not required) ($f, ## Sign-off)" else @@ -837,6 +843,13 @@ check_stage_1() { # extractor it was never going to run (2026-08-20). "No knowledge-base directory" is true in # every mode; what to DO about it is not, and the KB for a document corpus is built by a # skill, not a pipeline. Name both routes rather than assuming the migration one. + if [ "$ENTRY_MODE" = "existing-app-change" ]; then + # Neither route above exists in this mode: there is no source to extract, only the live + # model, and Stage 1 cannot be scoped until the user has named the change (existing-app + # field run, 2026-09-22 — the generic hint pointed at an extractor the mode never runs). + echo "PENDING|no knowledge-base directory yet — existing app: this stage reads the live model (Path D, skills/existing-app-change.md), scoped to the change and its blast radius. Waiting on the change is a normal state: map the app first (analysis/app-report.html, skills/app-analysis.md), then scope when the user names the change" + return + fi echo "PENDING|no knowledge-base directory yet — migration: run the extraction pipeline; requirements-driven: build the KB from the document corpus per skills/kb-generation.md (Path B). Either way it lands at analysis//knowledge-base/" return fi diff --git a/bin/lib/artifact-manifest.tsv b/bin/lib/artifact-manifest.tsv index ec138e5..a0a64c1 100644 --- a/bin/lib/artifact-manifest.tsv +++ b/bin/lib/artifact-manifest.tsv @@ -43,7 +43,9 @@ # migration,requirements,greenfield,existing-app-change # (conversion-runbook.md §"Entry Modes", its table; existing-app-change runs # P–6 per slice, so it owes every row but coverage-ledger — that mode's ledger -# is `mxcli brain plan`, existing-app-change.md §"Coverage in this mode"). +# is `mxcli brain plan`, existing-app-change.md §"Coverage in this mode") — plus +# app-report, the one row only it owes: the map of the live app that Stage 0's +# blast radius is read from (existing-app-change.md §"Map the app first"). # À-la-carte projects # run no stages and are excused wholesale by artifact-check.sh, same test as # obligation-check.sh. @@ -70,6 +72,7 @@ artifact stage paths producer consumers modes absence intake P intake.md bin/init-project.sh scaffold + the Stage-P kickoff interview (conversion-runbook.md §2 Stage P) bin/gate-check.sh:596 (check_stage_P), bin/gate-check.sh:497 (entry-mode fallback read) migration,requirements,greenfield,existing-app-change gate register P PROJECT.md bin/init-project.sh (empty register); every checkpoint writes into it (CLAUDE.md §One decision register) bin/gate-check.sh:285 (register resolution feeding every ✋ gate), bin/lib/obligation-check.sh:151 (waivers/adoption read from it) migration,requirements,greenfield,existing-app-change gate triage 0 triage.md bin/init-project.sh scaffold, filled per skills/source-triage.md; N/A rows recorded, never deleted (conversion-runbook.md:130) bin/gate-check.sh:684 (check_stage_0 sign-off test) migration,requirements,greenfield,existing-app-change gate +app-report 0 analysis/app-report.json|analysis/app-report.html project-bin/app-facts.sh (read-only: full catalog build + mxcli graph-report + loop sweep) then bin/app-report.sh — skills/app-analysis.md Procedure steps 1 and 5 skills/existing-app-change.md §"Map the app first" (the findings interview reads analysis/app-report.json) and §"Blast radius" (reads analysis/app-facts/dependencies.json tangles and edges) existing-app-change report extraction-report 1 analysis/*/knowledge-base/extraction-report.html|analysis/knowledge-base/extraction-report.html|knowledge-base/extraction-report.html bin/extraction-report.sh — one renderer for every entry mode bin/gate-check.sh:725 (check_stage_1) migration,requirements,existing-app-change gate source-ledger 1 analysis/source-ledger.html bin/source-ledger.sh report — every inventoried source file and what consumed it (Stage 1 owes a disposition per row; gate-check blocks 1–2 on the check) bin/gate-check.sh (LEDGER block — the check; the html is the human-facing table of the same rows) migration,requirements,existing-app-change report brds 2 analysis/*/knowledge-base/brd/*.brd.json|analysis/knowledge-base/brd/*.brd.json|knowledge-base/brd/*.brd.json pipeline generators (migration), skills/kb-generation.md (documents), skills/brd-generation.md (by hand) — the reader must not care which bin/lib/discover-brds.sh:43 (the one path authority), bin/gate-check.sh:773 (check_stage_2), bin/brd-report.sh, bin/open-questions.sh migration,requirements,existing-app-change gate diff --git a/docs/pipeline-walks.html b/docs/pipeline-walks.html index 604c2a3..7e390a8 100644 --- a/docs/pipeline-walks.html +++ b/docs/pipeline-walks.html @@ -244,17 +244,17 @@

Greenfield Just an idea, or a running s

Change an existing app A live .mpr you are altering, not rebuilding

-

The knowledge base comes from the model itself (Path D). The first real step is mapping the app for the agent: structure, quality, security, marketplace drift. Stage 0 adds the blast radius of the slice. A regression net goes under the app before anything changes, and every gate from Stage 5 on is also a regression gate.

+

The knowledge base comes from the model itself (Path D). The first real step is mapping the whole app, run without asking, followed by the one question the user owns: what to do with each top finding. The project may park there until a change is named; Stage 0b then adds the blast radius of the slice, read from the map. A regression net goes under the app before anything changes, and every gate from Stage 5 on is also a regression gate.

 flowchart TD
-  P["P Kickoff light
init-project.sh, intake from the model
register: Change an existing app CONFIRMED"] --> M["Map the app for the agent"] - M --> M1["structure
SHOW MODULES / ENTITIES / ASSOCIATIONS
mxcli graph-report"] - M --> M2["quality
mxcli lint + Starlark rules
mxcli report (assess-quality)"] - M --> M3["security and drift
SHOW SECURITY MATRIX
mxcli marketplace diff"] - M1 --> S0 - M2 --> S0 - M3 --> S0 - S0["0 Triage ✋ two questions:
which slice, what is its blast radius"] --> S0a["blast radius into triage.md
associations, microflows (SEARCH),
pages (SHOW PAGES IN), module tangle,
published / consumed services"] + P["P Kickoff light
./mxcli in place, then init-project.sh
open question: what is driving it?
register: Change an existing app CONFIRMED"] --> M["0a Map the app, not asked, just run
bin/app-facts.sh then bin/app-report.sh
(app-analysis.md, about a minute)"] + M --> F["show the report, ask per top finding:
fix in this work / log / accept
answers into PROJECT.md"] + F --> PK{"change named yet?"} + PK -- "not yet" --> PARK["parked: a normal state
Stage 1 PENDING, nothing nags"] + PARK -.->|change arrives| S0 + PK -- "only audits / tests wanted" --> AS["switch to existing-app-assurance
Track A starts from the same report"] + PK -- "yes" --> S0 + S0["0b Triage ✋ which slice,
what is its blast radius"] --> S0a["blast radius into triage.md, read from the map:
dependencies.json tangles and edges,
then associations, SEARCH, SHOW PAGES IN,
published / consumed services"] S0a --> S0b["capability map from SHOW MODULES
extraction rows N/A
CAC-1, sign-off"] S0b --> RN["Regression net under the app
Track B baseline from existing-app-assurance"] RN --> S1["1 Analysis Path D
DESCRIBE ENTITY, SHOW MICROFLOWS IN,
graph-report scoped to slice + blast radius
counts recorded, Path A = N/A, CAC-1b"] @@ -277,8 +277,8 @@

Change an existing app A live .mpr yo
- - + + diff --git a/skills/app-analysis.md b/skills/app-analysis.md index 6fee454..ad213ff 100644 --- a/skills/app-analysis.md +++ b/skills/app-analysis.md @@ -299,12 +299,12 @@ decided otherwise. - `skills/module-dependency-review.md`, `skills/microflow-loop-antipatterns.md` (the judgement) - `skills/existing-app-assurance.md` (the à-la-carte audit this dossier is the map for) -- `skills/existing-app-change.md` (the change slice, whose Stage 0 blast radius covers the same - ground this dossier already measured). **Not yet wired, as of 2026-09-16.** Neither of those two - files mentions the dossier, the facts or this skill, so nothing reads what this produces except - `bin/app-report.sh`. The change slice still recomputes its blast radius by hand. Until that is - joined, a dossier finding reaches a change slice only because a person carried it, and this - section describes an intended relationship, not an implemented one. Do not write a skill - description that claims otherwise. +- `skills/existing-app-change.md` — **wired 2026-09-22.** Its Stage 0a runs this procedure before any + slice is named, asks the user to disposition the top findings, and reads the blast radius for Stage + 0b from `analysis/app-facts/dependencies.json`. In that mode `bin/lib/artifact-manifest.tsv` owes + the report (`app-report`, Stage 0), so a map nobody ran reports PENDING. `existing-app-assurance.md` + Track A starts from the same report. What is still NOT wired: the dossier itself + (`architecture/app-dossier.md`) is not owed by anything, only the rendered report; and nothing + re-runs the facts at Stage 6 to show a change left the tangle and loop counts no worse. - `skills/lint-that-actually-runs.md`, `skills/report-schema.md`, `skills/measured-claims.md` - `skills/skills-over-scripts.md`: the instrument fetches, this file judges; keep it that way diff --git a/skills/existing-app-assurance.md b/skills/existing-app-assurance.md index 05e70d6..7f429d1 100644 --- a/skills/existing-app-assurance.md +++ b/skills/existing-app-assurance.md @@ -32,6 +32,13 @@ Not for building anything new. Two different places to go, depending on what "ne ## Track A — Analyze / audit the model +**Start with the map.** `bin/app-facts.sh` then `/bin/app-report.sh`, per `app-analysis.md`: +inventory, module tangles, loop-risk microflows and dead elements in about a minute, rendered as +`analysis/app-report.html` with a fix-first list. Its Security and Lint sections report **fault** until +you fill them from the rows below into `architecture/app-dossier.md` (§5, §6) and re-render — the +report is the findings list the rows add to, not a separate deliverable. The same map is Stage 0a of +`existing-app-change.md`, so an audit that turns into a change does not redo it. + | Question | Tool | |---|---| | What's in the model? | `SHOW MODULES / ENTITIES / ASSOCIATIONS`, `DESCRIBE ENTITY`, `SEARCH` — see `query-the-model.md` | @@ -41,7 +48,7 @@ Not for building anything new. Two different places to go, depending on what "ne | Overall quality scan | `assess-quality.md` (bundled) | | Have installed marketplace modules been locally edited? What would an upgrade overwrite? | `mxcli marketplace diff -p app.mpr [--to VERSION] [--json]` (≥ v0.18; content-id via the module's AppStoreGuid) — reports per-element local edits and upgrade collisions; an element it cannot describe is reported **unknown, never unchanged**, and `verified:false` in the JSON means "no modifications found" is not a conclusion | -**Deliverable:** a findings report (markdown or HTML — reuse `toolkit-guide.html`'s tokens), each finding with evidence (the query/lint output) and a proposed disposition: fix now / log / accept. Triage the list *with the user* — dispositions are their call. +**Deliverable:** `analysis/app-report.html`, re-rendered after the dossier carries what the rows above found — each finding with evidence (the query/lint output) and a proposed disposition: fix now / log / accept. Show the report, then triage the list *with the user* — dispositions are their call, and asking for them is the step that ends Track A. ## Track A2 — Audit the design system (bounded: an afternoon, not a re-design) diff --git a/skills/existing-app-change.md b/skills/existing-app-change.md index c3ebde1..bce3e7d 100644 --- a/skills/existing-app-change.md +++ b/skills/existing-app-change.md @@ -69,6 +69,41 @@ from git history of a `.mpr`, which is not a readable record. --- +## Map the app first — before anyone names a slice + +**Do not open with "which slice?".** At kickoff most people do not know the change yet, or know it +vaguely ("the approval flow is slow"), and a slice named before anyone has seen the app is a guess. +Intake Q2 (*what is driving it?*) is the open question, and a change, if they have one, arrives in +their own words there or later. Q4 (scope) may legitimately be answered +`Unverified — how to verify: named when the change request arrives (Stage 0b)`. + +**Stage 0a — the map, not asked for, just run.** It is read-only and costs about a minute (field +run, 2026-09-22: 28 modules, 213 loop microflows, 76 s), so asking "shall I analyse the app?" is a +question with one sane answer. Run it right after intake, per `app-analysis.md` Procedure: + +```bash +bin/app-facts.sh # in the project root; exit 2 = facts not trustworthy, fix and rerun +/bin/app-report.sh # analysis/app-report.html + app-report.json +``` + +**Then ask what to do with the findings — that is the question the human owns.** Read +`analysis/app-report.json` (`fix_first`, severity counts), show the report, and put the top findings +to the user, one disposition each: **fix as part of this work / log for later / accept, with a +reason**. Record the answers in `PROJECT.md`. A finding nobody dispositioned is the same silence the +gates exist to prevent. What the field run put on that list: one tangle holding 7 of 9 own modules, +and a transaction started inside a loop in the app's core decision microflow — neither was in anyone's +change request, and both decide how risky any change there is. + +**Then it may park.** A mapped app with no change yet is a normal state, not a failing one — gate-check +reports Stage 1 `PENDING` with "Waiting on the change is a normal state", and nothing nags. If after +the map the user never wants a change, only audits or a regression net, the mode was wrong: switch to +`existing-app-assurance.md`, whose Track A starts from the same report. + +**Stage 0b — when the change arrives:** scope the slice, then compute its blast radius *from the facts +already collected* (below), not from scratch. + +--- + ## Where the knowledge base comes from — Path D `conversion-runbook.md` Stage 1 names three paths: **A** code → AST extractors, **B** documents → LLM @@ -103,7 +138,10 @@ Still record the counts. `SHOW MODULES` returning 6 when the person who asked fo In every other mode, Stage 0 asks *what do we build first*. Here it asks a second question that has no equivalent elsewhere: **what does this change touch that nobody mentioned?** -Work outward from the entities the change affects: +Work outward from the entities the change affects. Start from the map (Stage 0a): a module in +`analysis/app-facts/dependencies.json` → `tangles` puts the whole tangle in the radius, and `edges` +names who depends on the module you change. The queries below confirm and extend that; they do not +repeat it. 1. **Associations** — `SHOW ASSOCIATIONS`, then `DESCRIBE ENTITY` each end. An entity you are changing that is on the far end of an association from a module nobody mentioned is your blast radius. @@ -111,8 +149,9 @@ Work outward from the entities the change affects: A change to a validation rule lands in every flow that writes the entity, not only the one on the screen you were shown. 3. **Pages bound to them** — `SHOW PAGES IN `, and check which are bound to the entity. -4. **Module dependencies** — `mxcli graph-report`. If the module you are changing is in a tangle, the - blast radius is the tangle. +4. **Module dependencies** — already in the map (`dependencies.json`); rerun `bin/app-facts.sh` only + if the model changed since. If the module you are changing is in a tangle, the blast radius is the + tangle. 5. **Published and consumed services** — a changed entity behind a published REST service is a contract change, and the consumer is not in the `.mpr`. @@ -126,8 +165,8 @@ least able to give you — they know what they want, not what it touches. | Stage | Runs? | What changes in this mode | |---|---|---| -| **P — Kickoff** | Yes, light | `bin/init-project.sh` as normal. Many intake questions are already answered by the app existing — answer them from the model, not by asking. Record entry mode `Change an existing app` `CONFIRMED` in `PROJECT.md`. | -| **0 — Triage & Scope ✋** | **Yes, always** | Two questions, not one: which slice, and its blast radius (above). The Coverage Matrix's *extraction* rows are N/A — Path D has no extractor to choose. The Business Capability Map is built from `SHOW MODULES` + the change request. **CAC-1 runs.** | +| **P — Kickoff** | Yes, light | `bin/init-project.sh` as normal — **with `./mxcli` already in the project root**, because init runs `mxcli init` and skips it when the binary is missing. Many intake questions are already answered by the app existing — answer them from the model, not by asking. The scope question is open: the change may not be known yet. Record entry mode `Change an existing app` `CONFIRMED` in `PROJECT.md`. | +| **0 — Triage & Scope ✋** | **Yes, always, in two halves** | **0a:** map the app and disposition its findings with the user (above) — owed as the `app-report` artifact. May park here. **0b**, once the change is named: which slice, and its blast radius (above), read from the map. The Coverage Matrix's *extraction* rows are N/A — Path D has no extractor to choose. The Business Capability Map is built from `SHOW MODULES` + the change request. **CAC-1 runs.** | | **1 — Analysis** | Yes, **Path D** | Query the model into the knowledge base, scoped to the slice **plus** its blast radius. Path A is declared not-applicable with attribution, not "skipped". Path C (SME) matters more here than anywhere: the model tells you what the app does and nobody wrote down why. **CAC-1b runs** — its scope-out diff is the slice-vs-app statement. | | **2 — Requirements** | Yes, **slice only** | One BRD per capability *being changed*, each carrying **as-is** and **to-be**. Do not BRD untouched capabilities; record explicitly that you did not, and why. **CAC-2 and CAC-3 run.** | | **3 — Architecture & Design ✋** | **Conditionally** | Run it in full if the change crosses module boundaries, adds an integration, or alters the domain model. Otherwise it collapses to: which existing module owns this, and does that still hold. **Never invent new module boundaries for an app that already has them** — `modularize-domain.md` is being used to *check* a boundary here, not to draw one. Wireframes only for screens that change; the design system is the app's existing styling, captured, not designed. **CAC-4 runs, scoped to what changes.** | @@ -184,6 +223,7 @@ it is the only entry mode where that is true. - `PROJECT.md` — gate register: entry mode `Change an existing app` `CONFIRMED`, blast radius confirmed, Stage 7 marked N/A with its reason. - `docs/brain/` — `mxcli brain init` run once; the slice under `plan/`, and the as-is facts nobody wrote down captured as decisions anchored to the modules they are about. `brain check` green at every commit. +- `analysis/app-report.html` + `.json` — the map of the whole app (`app-analysis.md`), with every top finding dispositioned in `PROJECT.md`. - `triage.md` — slice + blast radius, signed off. - Knowledge base — Path D, scoped, with counts recorded: modules, and per in-scope module the entity, page and microflow totals `SHOW …` returned, so a reader can see the slice against the app. - BRDs for the changed slice, each with as-is and to-be — and one line saying how many capabilities were *not* BRD'd and why. diff --git a/tests/wave2/test-bug03-gates.sh b/tests/wave2/test-bug03-gates.sh index 79af95c..c8a81f7 100755 --- a/tests/wave2/test-bug03-gates.sh +++ b/tests/wave2/test-bug03-gates.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Fixture for wave-2 #3: the unanchored substring CONTENT gates — Stage 0 (triage sign-off), -# Stage 2 (validation stop condition) and Stage 7 (cutover decision row). +# Stage 2 (validation stop condition) and Stage 7 (cutover decision row); T12 adds the +# existing-app-change parked state (Stage 0) and that mode's Stage 1 hint. # # Stage P is covered by test-stage-p.sh and is deliberately not retested here. # @@ -174,6 +175,38 @@ V="$(verdict "$P" 7)" case "$V" in *WAIVED*) ok "the short token 'existing-app' still waives stage 7" ;; *) bad "existing-app short token no longer waives stage 7: $V" ;; esac + +echo "== T12: existing-app mode — a mapped app waiting on its change is PENDING, not FAIL ==" +# existing-app-change.md §"Map the app first": the map runs before any slice is named, and the +# project may park there. The parked arm is narrow: this mode, the untouched placeholder, AND a +# rendered map. Drop any one and the old FAIL must come back. +mkexisting() { + d="$WORK/$1"; mkdir -p "$d/analysis" + printf 'Toolkit commit: none\n\n| Stage | Decision | Status | Notes |\n|---|---|---|---|\n\nEntry mode: %s\n' "$2" > "$d/PROJECT.md" + printf '# Triage\n\n## Sign-off\n\nConfirmed by: [user] on [date]\n' > "$d/triage.md" + echo "$d" +} +P="$(mkexisting t12-parked 'Change an existing app')"; printf '{}\n' > "$P/analysis/app-report.json" +V="$(verdict "$P" 0)" +case "$V" in *PENDING*'waiting on the change'*) ok "mapped + unsigned triage in this mode reads PENDING, parked" ;; + *) bad "parked existing-app project not PENDING: $V" ;; esac +V="$(verdict "$P" 1)" +case "$V" in *'Path D'*) ok "Stage 1 hint names the live-model path in this mode" ;; + *) bad "Stage 1 hint still points at extractors in existing-app mode: $V" ;; esac + +P="$(mkexisting t12-unmapped 'Change an existing app')" +V="$(verdict "$P" 0)" +case "$V" in *FAIL*) ok "no map yet: the placeholder still FAILs in this mode" ;; + *) bad "unmapped existing-app project escaped the placeholder FAIL: $V" ;; esac + +P="$(mkexisting t12-migration 'Migration')"; printf '{}\n' > "$P/analysis/app-report.json" +V="$(verdict "$P" 0)" +case "$V" in *FAIL*) ok "another mode with a stray app-report.json still FAILs the placeholder" ;; + *) bad "the parked arm leaked into migration mode: $V" ;; esac +V="$(verdict "$P" 1)" +case "$V" in *'Path D'*) bad "migration project got the existing-app Stage 1 hint: $V" ;; + *) ok "other modes keep the extractor / kb-generation hint" ;; esac + printf '\n%s: %d ok, %d FAIL\n' "$(basename "$0")" "$PASS" "$FAIL" rm -rf "$WORK" [ "$FAIL" -eq 0 ]
StepWhat it doesScripts and commands
P lightScaffold. Intake answers come from the model, not from the user's memory. Run the machine check once.bin/doctor.sh
bin/init-project.sh <project>
Map the appGive the agent a picture of the whole app before scoping: module graph and dependency tangle, current quality score, lint findings, security matrix, marketplace modules that drifted from their published version. The findings feed the blast-radius answer and the regression baseline../mxcli -p app.mpr -c "SHOW MODULES"
./mxcli -p app.mpr -c "SHOW STRUCTURE DEPTH 2"
./mxcli graph-report -p app.mpr (graph-analysis.md)
./mxcli lint -p app.mpr
./mxcli report -p app.mpr --format html
./mxcli -p app.mpr -c "SHOW SECURITY MATRIX"
./mxcli marketplace diff <content-id> -p app.mpr (v0.18+)
0 Triage ✋Two questions: which slice, and what is its blast radius. The radius is written into triage.md as its own section, with counts. Capability map from the module list. CAC-1 and sign-off.SHOW ASSOCIATIONS IN <Module> · DESCRIBE ENTITY M.E
SEARCH '<entity>' · SHOW PAGES IN <Module>
SHOW REFERENCES OF M.E · SHOW IMPACT OF M.E
./mxcli graph-report for the tangle
bin/gate-check.sh <project> 0
0a Map the appRun, do not ask: it is read-only and takes about a minute. Inventory, module tangles, loop-risk microflows, dead elements, with a fix-first list. Show the report and ask the user to disposition each top finding (fix in this work / log / accept); answers go to PROJECT.md. The project may then park until a change is named. Owed in this mode as the app-report artifact. Lint, security matrix and marketplace drift fill the report's Security and Lint sections.bin/app-facts.sh (app-analysis.md)
bin/app-report.sh <project>
./mxcli lint -p app.mpr
./mxcli -p app.mpr -c "SHOW SECURITY MATRIX"
./mxcli marketplace diff <content-id> -p app.mpr (v0.18+)
0b Triage ✋Once the change is named: which slice, and what is its blast radius, starting from the map's tangles and edges. The radius is written into triage.md as its own section, with counts. Capability map from the module list. CAC-1 and sign-off.SHOW ASSOCIATIONS IN <Module> · DESCRIBE ENTITY M.E
SEARCH '<entity>' · SHOW PAGES IN <Module>
SHOW REFERENCES OF M.E · SHOW IMPACT OF M.E
analysis/app-facts/dependencies.json for the tangle
bin/gate-check.sh <project> 0
Regression netTrack B from the assurance skill, before any change: harness, action inventory, one journey per action, DB assertions, wiring sweep, LOOK pass, committed baseline.see Track B below
project-bin/coverage-preflight.sh --assess --module <M>
1 Path DQuery the model into the knowledge base, scoped to slice plus blast radius. Record counts. Path A declared N/A with attribution. Path C matters most here: the people who know why the app is the way it is.SHOW ENTITIES IN · DESCRIBE ENTITY · SHOW MICROFLOWS IN
DESCRIBE MICROFLOW · DESCRIBE PAGE
bin/extraction-report.sh <project>
bin/gate-check.sh <project> 1
2 RequirementsOne as-is / to-be BRD per capability being changed. Nothing for the untouched rest.bin/brd-report.sh · bin/open-questions.sh --stage 2