pi-aia-asf 0.9.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,11 +7,118 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.0] - 2026-10-12
11
+
12
+ ### Added
13
+
14
+ - (describe changes for 0.11.0)
15
+
16
+
17
+ ### Added
18
+
19
+ - **Browser verification now follows what a change TOUCHES, and happens in the
20
+ build (06b Rule 9, strengthened in place)**. The rule already existed, but
21
+ every formulation keyed on *"if the deliverable has a UI"* — which an agent
22
+ editing one helper in an existing app reads as not engaged, and "I only
23
+ changed a helper" is exactly the change that reaches a rendered surface
24
+ unnoticed. The trigger is now **can this change reach a rendered surface**,
25
+ with an explicit touched list: pages, routes, components, forms, templates;
26
+ markup, styling, copy, formatting, truncation, empty and error states;
27
+ client-side state, routing and the fetching a view depends on; **an API,
28
+ serializer or query that a UI consumes** (a server-side diff is not exempt
29
+ for living in `src/server/`); auth/permission paths that gate what a user
30
+ sees; user-triggered uploads and downloads.
31
+ - **Moved from final verification into the Phase 6 loop.** "Must be verified"
32
+ was Phase 7 language, which makes the gate the first time anyone has looked —
33
+ by then the cause is buried in the whole change. The touched interface is now
34
+ opened in the browser **before committing that change**, while the context is
35
+ warm and the defect is one edit wide (test-first step 5).
36
+ - **Same safety inversion as Rule 19**: uncertain whether the change reaches a
37
+ surface? Then it is touched. "It's only a backend change" is not an argument;
38
+ naming the render path it cannot affect is. Uncertainty costs a browser run,
39
+ never a skipped one.
40
+ - **Closes a hole Rule 19 opened**: nothing previously stopped a subset run
41
+ from excluding the browser/E2E suite for the surface just changed. For a
42
+ touched surface that suite is now **never excludable** — selection may drop
43
+ unrelated suites, never the one that looks at what you just changed.
44
+ - **Evidence, not assertion.** A run is reported with the page/URL opened, the
45
+ action taken and what was asserted — or `n/a: no rendered surface touched,
46
+ because <reason>`. Bare "browser tested" is named as an assertion rather than
47
+ evidence, and an unavailable `pi-aia-browser` must be said out loud instead of
48
+ reading as a passed check. Backed by the Rule 10 checkbox, the `/asf verify`
49
+ checklist item, four new anti-patterns, and `test/test-browser-touched.mjs`
50
+ (42 assertions, 6 negative controls). Rule 9 keeps its number, its five steps
51
+ and its silent-async paragraph — strengthened, not duplicated.
52
+
53
+ ## [0.10.0] - 2026-10-07
54
+
55
+ ### Added
56
+
57
+ - **06b Rule 19 — test selection for the inner loop (P25)**. Rule 10's
58
+ "full test suite green (not a subset)" is a **gate**, and it stays exactly
59
+ where it is: the run before a commit is always the full suite. What Rule 19
60
+ relaxes is only the **intermediate red-green-refactor runs inside a single
61
+ change** — the runs on code you are still editing. The rule is the user's
62
+ own: **run a partial, impact-area subset only when certain that is
63
+ warranted; if not certain, or the blast radius *might* be larger, always run
64
+ full. Default is full** — so the burden of proof sits on the subset, and the
65
+ cheap direction to be wrong in is also the safe one.
66
+ - **"Certain" is evidence, not a feeling.** A subset run must be preceded by a
67
+ stated **impact statement** — changed files, tests selected, and *why nothing
68
+ else can be reached*. Restating the file list does not qualify; no statement
69
+ means not certain, which means full. On top of that, a **mechanical
70
+ disqualifier list** removes judgment wherever "might be bigger" is the
71
+ honest answer: shared/global state, dependencies and lockfile, build/test/CI
72
+ config or the harness itself, schema/migrations/shared fixtures, public
73
+ contracts and shared types, cross-module refactor/rename/move/delete — and
74
+ **any changed file with no entry in the test-impact map**, so a project that
75
+ has not built a map always runs full. The relaxation only ever applies where
76
+ the mapping is known, never where it is guessed.
77
+ - **Deliberately not built**: the drafted coin toss and `iteration % N`
78
+ counter are gone. An LLM cannot roll a dice — asked to flip one it picks the
79
+ answer that skips the slow run — and an undefined iteration boundary means
80
+ the trigger silently never fires. A subset streak also cannot survive a
81
+ commit, because every commit is full-gated. Below a measured ~90s full-suite
82
+ runtime the assessment is skipped entirely and the suite is just run.
83
+ - **Wired in**: `06b-testing-qa.md` Rule 10's checkbox now says in place that
84
+ the gate never moves; `06-implementation.md` test-first steps 3 and 4 name
85
+ the loop/gate split; `SKILL.md` gains two anti-patterns (a subset run with no
86
+ impact statement, and a subset run passed off as the Rule 10 checkbox) and
87
+ the index count moves to 19 rules. Covered by
88
+ `test/test-test-selection.mjs` (26 assertions), which includes a regression
89
+ guard that **fails if the coin-toss or iteration-counter design ever returns**.
90
+
10
91
  ## [0.9.2] - 2026-10-04
11
92
 
12
93
  ### Added
13
94
 
14
- - (describe changes for 0.9.2)
95
+ - **`references/06i-completeness.md` — the completeness standard (P24, mandatory)**.
96
+ Newer models increasingly ship work that *looks* finished: a function whose body is
97
+ a placeholder, a screen populated with invented records, a report citing a limit
98
+ nobody checked. Green tests do not catch it — the tests get written against the
99
+ stub, so the fake looks verified. The reference states the core rule (**ship the
100
+ real thing, or say out loud what is not real**), the banned patterns (`TODO` /
101
+ `not implemented` / `coming soon` on a user-reachable path, fake or seed data the
102
+ user reads as their own, invented facts stated as checked, silently deferred scope,
103
+ built-but-never-wired, mocks in production paths, config nothing sets), the
104
+ exceptions that must be **declared, never silent** (the user asked for a scaffold,
105
+ an approved deferral, a fake at a test seam), how to prove it is real (exercise each
106
+ part through the entry point the user will use and name that action in the delivery
107
+ report), and a completeness DoD.
108
+ - **Wired in, not bolted on**: Phase 6 gains a mandatory read block and discipline
109
+ rule 11; Phase 7 gains the completeness DoD check; the anti-pattern list gains six
110
+ entries (stub wearing a name, fake data the user reads as their own, invented facts
111
+ stated as fact, quietly deferred scope, stub presented as complete because its own
112
+ tests pass, unexplained deliberate stub); the reference index marks 06i as always
113
+ read. Proportionality holds — small work reads only the core rule and the DoD.
114
+
115
+ ### Requires
116
+
117
+ - The enforcement side lives in **pi-vigilant 0.6.2**, which scans the files a
118
+ session changed for stub / fabricated-data / fact-hole markers at final
119
+ verification and puts the `file:line` evidence in front of the agent. The rule and
120
+ the check are the same proposal: the agent must finish the work or state the
121
+ discrepancy.
15
122
 
16
123
 
17
124
  ## [0.9.1] - 2026-10-03
package/index.ts CHANGED
@@ -44,12 +44,12 @@ interface AsfState {
44
44
  /** Definition-of-done checks (references/06b-testing-qa.md, Rule 10). */
45
45
  const QA_CHECKLIST: Array<{ key: string; label: string }> = [
46
46
  { key: "build", label: "Typecheck/build passes" },
47
- { key: "tests", label: "Full test suite green (not a subset)" },
47
+ { key: "tests", label: "Full test suite green (not a subset) — the gate; Rule 19 never relaxes this checkbox" },
48
48
  { key: "regression", label: "Regression test added for every bug fixed this cycle" },
49
49
  { key: "triggers", label: "Triggers AND non-triggers tested for conditional behavior" },
50
50
  { key: "artifact", label: "Shipped artifact inspected (npm pack file list) + clean-room install" },
51
51
  { key: "observable", label: "Observable end state verified as a user would experience it" },
52
- { key: "browser", label: "Web surfaces exercised through a real browser (n/a if none)" },
52
+ { key: "browser", label: "Every interface the change TOUCHES exercised through a real browser during the build (06b Rule 9) — page + action + assertion named; n/a with reason if none" },
53
53
  { key: "specs", label: "Every MUST spec 'met' with concrete evidence" },
54
54
  { key: "trace", label: "Spec-to-code traceability: every met spec has outcome → codePath → test" },
55
55
  { key: "code-health", label: "Code Health Gate passed (or enabled:false / gate.mode:warn with the report shown)" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-aia-asf",
3
- "version": "0.9.2",
3
+ "version": "0.11.0",
4
4
  "description": "Ai Applied Agentic Software Factory — codifies the full software development flow: intake, research, spec capture, adversarial analysis, planning with approval gates, test-first implementation, and release. Requires pi-vigilant, pi-smart-web-search, pi-smart-fetch, and pi-aia-browser.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -229,7 +229,7 @@ Execute the task list milestone by milestone. Discipline rules:
229
229
  2. **Codebase isolation**: work strictly inside the project's own codebase. Do NOT edit files in other repos, global config, or unrelated directories — **unless the user explicitly instructs otherwise**. If a change would touch another codebase, stop and ask.
230
230
  3. **No scope creep**: if something new is discovered that changes specs, capture it, ask the user, and update the plan before implementing.
231
231
  4. **Descriptive commits**: `git commit -m "type: specific description of what and why"` (e.g. `fix: verify specs before rotation`). No vague messages, no placeholders.
232
- 5. **Browser testing — MANDATORY for any web interface**: if the deliverable has a UI/website/web app, test it through `pi-aia-browser` (`browser_init`, `browser_navigate`, `browser_click`, `browser_type`, `browser_screenshot`, `browser_dom`, …) to replicate the user's real experience — not just curl/API checks. Verify: loads, key user journeys, responsive behavior, console errors. **Silent async paths included**: ingest through the real flow and wait for the enrichment to land (06b Rule 9).
232
+ 5. **Browser testing — MANDATORY for every interface the change TOUCHES, in the build (06b Rule 9)**: the trigger is **can this change reach a rendered surface**, not whether the project "has a UI" — a page, route, component, form, markup, styling, copy, formatting, client-side state, or an API that a UI consumes all count. Exercise it through `pi-aia-browser` (`browser_init`, `browser_navigate`, `browser_click`, `browser_type`, `browser_screenshot`, `browser_dom`, …) **before committing that change**, not at final verification — not just curl/API checks. Verify: loads, key user journeys, responsive behavior, console errors. **Uncertain whether it reaches a surface? Then it is touched** — "only a backend change" is not an argument, naming the render path it cannot affect is. **Silent async paths included**: ingest through the real flow and wait for the enrichment to land (06b Rule 9). Report the page opened, the action taken and what was asserted, or `n/a` with a reason; if the browser tool is unavailable, say so rather than letting it read as passed.
233
233
  6. **Bounded waits — ALWAYS (06b Rule 15)**: **every** tool call or command that waits on the system gets an explicit, reasonable **hard timeout** (`timeout N …` or the tool's `timeout` parameter) — never run unbounded. State the expected duration first and size the bound to it with headroom (a 30s suite gets ~120s, not 3000s). This matters most **during testing**, where harnesses, servers, daemons and browsers hang on ports, locks and prompts. **Absolute ceiling: no single wait may exceed 30 min (1800s).** The ceiling is a backstop, never a substitute for the real per-call bound. When it is hit: kill the wait and diagnose what it is blocking on — that is a bug signal, not patience. The ceiling may be **waived only for a single run**, stated explicitly beforehand with a reason and a finite larger bound; the waiver **does not persist** and resets immediately after that run. A 50,000-second hang is a failure to investigate.
234
234
  7. **Let pi-vigilant do its job**: it will auto-continue after premature stops and verify specs at settle. When it asks for `update_spec_status` with evidence, do it.
235
235
  8. **CHANGELOG discipline**: every user-visible change gets a CHANGELOG entry describing exactly what changed (no placeholder text).
@@ -281,6 +281,10 @@ conflicts). Record the review + triage in the delivery report.
281
281
  - ❌ Skipping research for new projects
282
282
  - ❌ Editing other codebases without explicit permission
283
283
  - ❌ Verifying a UI only via API/curl — browser testing is mandatory
284
+ - ❌ Treating browser testing as about "projects that have a UI" — the trigger is whether **this change** can reach a rendered surface (06b Rule 9)
285
+ - ❌ Deferring browser verification of a touched interface to final verification — open it in the build, before committing that change (06b Rule 9)
286
+ - ❌ "It's only a backend change" with no render path named — if uncertain whether it reaches a surface, browser-test it (06b Rule 9)
287
+ - ❌ Reporting "browser tested" without the page, action and assertion — that is an assertion, not evidence; and a missing browser tool must be said out loud, never read as passed (06b Rule 9)
284
288
  - ❌ Vague commits or CHANGELOG placeholders
285
289
  - ❌ Declaring done while specs are still `open`
286
290
  - ❌ Publishing anything beyond the configured release policy — no `.asf-release.json` means the default: always get the user's explicit go-ahead
@@ -324,6 +328,8 @@ conflicts). Record the review + triage in the delivery report.
324
328
  - ❌ Shipping a delivery summary without the report fields: spec status + evidence, test results, skipped checks, not-tested register (06b Rule 17)
325
329
  - ❌ Letting an escaped defect teach nothing — ask which gate should have caught it and close the gap (06b Rule 18)
326
330
  - ❌ Self-modifying the ASF's own rules during a task run — standards change only via the review process (P22)
331
+ - ❌ Running a subset of tests inside the loop without a stated impact statement, or when uncertain whether the blast radius is larger — default is full (06b Rule 19)
332
+ - ❌ Treating a subset run as satisfying the Rule 10 full-suite checkbox — the commit/DoD gate is always a real full run (06b Rule 19)
327
333
 
328
334
  ## Reference index (read on demand — never load all)
329
335
 
@@ -338,7 +344,7 @@ reads at most 06b + 06c; large work reads the ones its phase calls for.
338
344
  | `04-adversarial.md` | adversarial checklist (spec/architecture/security lenses) | Phase 4 (large) |
339
345
  | `05-plan.md` | PLAN.md template + ADRs + quality scenarios + ATAM-lite + views | Phase 5 (large) |
340
346
  | `06-implementation.md` | coding discipline, M4/M5, drift self-correction (P20) | Phase 6 |
341
- | `06b-testing-qa.md` | **mandatory** testing & QA standard (18 rules + DoD) | before writing tests (always) |
347
+ | `06b-testing-qa.md` | **mandatory** testing & QA standard (19 rules + DoD) | before writing tests (always) |
342
348
  | `06c-code-quality.md` | **mandatory** modularity standard (9 rules, deep modules, smells) | before structuring code |
343
349
  | `06d-delegation.md` | intercom & subagents + independent reviewer gate (P19) | before delegating; Phase 7 review (large) |
344
350
  | `06e-code-health.md` | Code Health Gate (+ depth, supply-chain, secrets metrics) | Gate 8 (large) |
@@ -15,8 +15,15 @@
15
15
 
16
16
  1. Write the failing test for the next behavior
17
17
  2. Implement the minimum to pass
18
- 3. Run the suite; refactor; re-run
19
- 4. Only commit green
18
+ 3. Run the suite; refactor; re-run — steps 3's intermediate runs (not the
19
+ commit-gate run) may use a selected subset per **06b Rule 19**, and only
20
+ when certain the subset is warranted; default is full
21
+ 4. Only commit green — the pre-commit run is always the FULL suite (06b
22
+ Rule 10), never a subset, regardless of what ran in step 3
23
+ 5. Browser-verify every interface the change **touches** through
24
+ `pi-aia-browser` **before committing that change** (06b Rule 9) — not at
25
+ final verification. If you cannot argue the change provably cannot reach a
26
+ rendered surface, it counts as touched and gets a browser run.
20
27
 
21
28
  For web interfaces, browser tests via pi-aia-browser are part of the test suite, not an afterthought.
22
29
 
@@ -27,9 +34,13 @@ For web interfaces, browser tests via pi-aia-browser are part of the test suite,
27
34
  - If a legitimate need to touch another codebase arises (shared lib, dependency fix): **stop and ask the user**.
28
35
  - Exception: the user explicitly instructs otherwise — then note the instruction and proceed.
29
36
 
30
- ## Browser testing (MANDATORY for web interfaces)
37
+ ## Browser testing (MANDATORY for every touched interface, in the build)
31
38
 
32
- Any deliverable with a UI/web surface must be verified through the browser to replicate the user's real experience:
39
+ The trigger is **what the change touches**, not whether the project has a UI.
40
+ If the change can reach a rendered surface — page, route, component, form,
41
+ markup, styling, copy, formatting, client-side state, or an API a UI consumes —
42
+ it gets a browser run, **during Phase 6 while building**, before that change is
43
+ committed. Uncertain whether it reaches one? Then it is touched (06b Rule 9).
33
44
 
34
45
  1. `browser_init` — start the browser
35
46
  2. `browser_navigate` to the app URL (local dev server or deployed)
@@ -40,6 +51,11 @@ Any deliverable with a UI/web surface must be verified through the browser to re
40
51
 
41
52
  API-only verification is NOT sufficient for anything a human would see or click.
42
53
 
54
+ Report it as evidence, not assertion: the page/URL opened, the action taken,
55
+ what was asserted — or `n/a: no rendered surface touched, because <reason>`.
56
+ If `pi-aia-browser` is unavailable, say so and name what you did instead; a
57
+ missing tool must never read as a passed check.
58
+
43
59
  ## Commit messages
44
60
 
45
61
  `type: specific description of what and why`
@@ -117,7 +117,7 @@ two-sided. Half a test suite hides half the bugs.
117
117
  - Check terminal states are reachable, and no state can block its own exit.
118
118
  - Test repeat/idempotent invocations and out-of-order calls.
119
119
 
120
- ## Rule 9 — Browser testing is mandatory for any web surface
120
+ ## Rule 9 — Browser-test every interface you TOUCH, during the build
121
121
 
122
122
  API/curl checks do not replicate what a human sees. Via `pi-aia-browser`:
123
123
 
@@ -129,6 +129,44 @@ API/curl checks do not replicate what a human sees. Via `pi-aia-browser`:
129
129
 
130
130
  A 200 response with a blank or broken page is a **failure**.
131
131
 
132
+ **The trigger is what the change TOUCHES, not whether the project "has a UI".**
133
+ A deliverable-level trigger lets a small edit slide: "I only changed a helper"
134
+ is exactly the change that reaches a rendered surface unnoticed. So the
135
+ question is never *does this project have a UI* — it is **can this change reach
136
+ one**. Anything below counts as touched, and must be exercised through the
137
+ browser:
138
+
139
+ - a page, route, component, widget, form, or template
140
+ - anything that changes what is rendered: markup, styling, copy, formatting,
141
+ date/number/currency rendering, truncation, empty and error states
142
+ - client-side state, routing, data fetching the view depends on
143
+ - an API, serializer or query **that a UI consumes** (server-side changes are
144
+ not exempt just because the diff is in `src/server/`)
145
+ - auth/permission paths that gate what a user sees, and uploads/downloads
146
+ a user triggers from a page
147
+
148
+ **When uncertain, browser-test it — same inversion as Rule 19.** If you cannot
149
+ argue that the change provably cannot reach a rendered surface, treat it as
150
+ touched. "It's only a backend change" is not an argument; naming the render
151
+ path it cannot affect is. The cheap direction to be wrong in must be the safe
152
+ one, so uncertainty costs a browser run, never a skipped one.
153
+
154
+ **This happens in the Phase 6 build loop, per change — not at final
155
+ verification.** Open the touched interface in the browser *before committing
156
+ that change*, while the context is warm and the defect is one edit wide.
157
+ Deferring it to Phase 7 means the gate is the first time anyone has looked, by
158
+ which point the cause is buried in the whole change. If the loop run was a
159
+ Rule 19 subset, the browser/E2E suite for a touched surface is **never
160
+ excludable** — selection may drop unrelated suites, never the one that looks at
161
+ what you just changed.
162
+
163
+ **Evidence, not assertion.** A browser run is reported with what was actually
164
+ done: the page/URL opened, the action taken, and what was asserted — or
165
+ explicitly `n/a: no rendered surface touched, because <reason>`. "Browser
166
+ tested" with no page and no action named is not evidence (Rule 11). If
167
+ `pi-aia-browser` is unavailable, **say so** and name what you did instead;
168
+ never let a missing tool read as a passed check.
169
+
132
170
  **Silent async paths are the priority.** Fire-and-forget enrichment (an async
133
171
  budgeted analysis that fills in a card title after render) fails silently — the
134
172
  page renders, nobody notices the enrichment never landed. For any async/silent
@@ -139,12 +177,12 @@ never arrives, the wiring is dead — that is a failed test.
139
177
  ## Rule 10 — Definition of done (all must hold)
140
178
 
141
179
  - [ ] Typecheck/build passes
142
- - [ ] Full test suite green (not a subset)
180
+ - [ ] Full test suite green (not a subset) — **the gate never moves: this checkbox always means a full run, even when Rule 19 permitted subset runs earlier in the loop that led here**
143
181
  - [ ] Regression test added for every bug fixed this cycle
144
182
  - [ ] Triggers **and** non-triggers tested for conditional behavior
145
183
  - [ ] Shipped artifact inspected (`npm pack` file list) and installed clean-room
146
184
  - [ ] Observable end state verified as a user would experience it
147
- - [ ] Web surfaces exercised through a real browser
185
+ - [ ] Web surfaces exercised through a real browser **in the build, for every interface the change touches** (Rule 9) — report names the page/URL opened, the action taken and what was asserted; `n/a` stated with a reason if nothing rendered is touched
148
186
  - [ ] Every MUST spec `met` with concrete evidence (`update_spec_status`)
149
187
  - [ ] **Spec-to-code traceability: every `met` spec carries `trace` (outcome → codePath → testFile + assertion); `/asf verify` mechanically validates it (large work)**
150
188
  - [ ] **Code Health Gate passed (or `enabled: false` / `gate.mode: warn` with the report shown)**
@@ -325,3 +363,57 @@ production incident), the fix is not the end — the **loop** is:
325
363
  > **Real failure:** a package shipped with a broken `files` allowlist; the
326
364
  > fix landed but the *gap* ("no test inspects the packaged artifact") was not
327
365
  > closed until Rule 1 was added. The loop is what prevents the next one.
366
+
367
+ ## Rule 19 — Test selection for the inner loop (P25; the DoD gate never moves)
368
+
369
+ Rule 10's full-suite checkbox is a **gate**, not a loop constraint. The gate
370
+ never relaxes. What this rule relaxes is the **intermediate** runs inside one
371
+ change's own red-green-refactor cycle (06-implementation "Test-first" steps
372
+ 1-3) — the runs that happen *before* the commit-gate run, on code you are
373
+ still editing.
374
+
375
+ **The rule, in the user's own words: run a partial (impact-area) subset only
376
+ when certain that this is warranted; if not certain, or if the blast radius
377
+ might be greater than the impact area, always run full. Default is full.**
378
+
379
+ - **Burden of proof is on the subset, not on the full run.** Silence,
380
+ uncertainty, or "probably fine" all mean full. A subset run requires an
381
+ affirmative, checkable case.
382
+ - **A subset run requires a stated impact statement** in the transcript,
383
+ before the run: the changed files, the tests selected because of them, and
384
+ *why nothing else can be reached*. A file list alone is not an impact
385
+ statement — restating the diff is not an argument for why the blast radius
386
+ stops there. No statement, or a statement that does not argue the
387
+ boundary → **not certain → full.**
388
+ - **Certainty is impossible by definition (no judgment call — always full)**
389
+ when the changed footprint includes any of:
390
+ - shared/global state, a singleton, a cache, env/config, a feature flag
391
+ - `package.json`, the lockfile, or any dependency
392
+ - build, test, lint, or CI config, or the test harness itself
393
+ - a DB schema, a migration, or a shared fixture
394
+ - a public API/contract, CLI args, or a wire/shared type
395
+ - a cross-module refactor, a rename, a file move, or a deletion
396
+ - **any changed file with no entry in the project's test-impact map** — a
397
+ project that has not built a map always runs full; the relaxation only
398
+ ever applies where the mapping is known, never where it is guessed.
399
+ - **The ~90s-and-under guard**: if the full suite's own measured runtime is
400
+ small enough that an assessment costs more than just running it, skip the
401
+ assessment and run full — state the measured number once rather than
402
+ re-litigating it every iteration.
403
+ - **Reporting stays honest (Rule 11/17) no matter which path was taken.** A
404
+ subset run is reported as a subset run — "ran N/M suites (impact-area: X);
405
+ full suite not run this iteration" — never as "suite green". The Rule 10
406
+ checkbox is only ever satisfied by an actual full run, shown in this cycle,
407
+ regardless of how many subset runs preceded it.
408
+ - **Never an escape from a failing test.** Selection decides *which* suites
409
+ run; it never decides whether a failing test counts. A failing test is
410
+ fixed or deleted (Rule 16), never excluded from the run that would have
411
+ caught it.
412
+ - **If a defect escapes that a full run would have caught**, that is Rule 18:
413
+ the fix must say so, and the certainty bar for that class of change tightens
414
+ (added to the "certainty is impossible" list above if it recurs).
415
+
416
+ This does not change Rule 10, Rule 11, or the commit-gate workflow: a project
417
+ that commits after every green run already runs full before every commit, so
418
+ Rule 19 only ever saves the intermediate runs inside a single change — it
419
+ never reduces what runs before anything is committed.