# sub-reviewer-5 — LENS 5: SCOPE-DISCIPLINE / anti-over-engineering / honest-notes

**VERDICT: COMPLIANT** (memory-selector already meets the 3 function-floors → quick re-verify only, NO rewrite). The ONLY real code change in this run is Part B (hmw.js fail-soft→stop-hard), which is a legitimately-directed in-scope MUST. My lane's value = guarding the other 4 lanes against over-reach: the archive-gate `oldest-first` ordering is a **RED-FLAG-SHAPED** construct but is **functionally gated** (value_protect + keep_floor + DRY-RUN + em-main), so it is at most a bounded SHOULD, never a MUST/rewrite.

Run: `2026-07-13-presence-not-age-adopt` · lane 5 of 5 · floorPoint = scope-discipline (meta).

---

## 0. What the broadcast actually asks (the scope contract I am enforcing)

Broadcast `ab6c387e` (disk `AI_INFRA/broadcasts/outbox/all/2026-07-13-...reinject.md`) is **type: update**, self-labelled repeatedly as a SMALL delta:
- §1 L20 "**bản cập-nhật (type: update), KHÔNG phải một quy-tắc mới**"; L26 "**re-verify đúng phần bộ chọn — KHÔNG cần adopt lại toàn-bộ vòng bộ-nhớ từ đầu**".
- §5 three honest-notes (L90/L92/L94): (1) basis = **ONE occurrence already fixed** = proactive-prevention, NOT a spreading incident; (2) **SPECIFIC-APPLICATION not new rule** → already-presence-based = quick re-verify only; (3) **floor = FUNCTION not FORM** → filenames/structure self-determined, **do NOT copy hub org**.
- §6 L102 "**Nếu bộ chọn đã đúng → ghi một dòng xác-nhận... 'đã re-verify, không có gì đổi'**".

So the *default expected outcome* is "already-compliant + one-line re-verify". Any lane proposing a script rewrite bears a heavy burden of proof.

---

## 1. Evidence — SE is ALREADY presence-based on all 3 floors

### Floor (i) reinject-by-absence — COMPLIANT (0 change)
`.claude/governance/reinject-ledger.md` L3 + L12: trigger is **floor-rot** = "item **ĐÃ-từng-tồn-tại ∩ CÒN-giá-trị ∩ RỚT-khỏi-L1**" (B3 test). That is a pure **coverage-gap / presence** predicate — age is not a term in it. L12 explicitly routes the two non-presence cases *away* from reinject: "chưa-từng-dựng = build-gap", "hết-giá-trị = cold-archive". Drop-date-column test: the B3 predicate never reads a date, so behavior is invariant → presence-clean.

### Floor (ii) archive value-gate — COMPLIANT-BY-FUNCTION (value-gate EXISTS)
`memory-budget.json` `archive_gate.value_protect.patterns` (L38-41) + the mark it cites, **`RC-pqhuy1987-20-06-2026-10-29-11`** (verified present, `ACTIVE-MARKS.md` L17, Active-High, anh-confirm S79: "time/age/recency-decay = false-proxy … kiến-trúc KHÔNG dựa cũ … archive-gate"). The value-axis gate is already implemented and already anchored to the exact mark the broadcast descends from. `keep_floor_entries=5` (L36) is a **recency PROTECT-floor** (protects newest-5 from being drained) — it is a *floor that prevents cutting*, NOT a selector that cuts by age; the budget `_note` L39 states this orthogonality explicitly ("keep_floor protects NEWEST-n … value_protect protects HIGH-VALUE regardless of age … archival cuts LOW-VALUE, NOT FIFO-by-date").

### Floor (iii) self-check for age-rank — one real red-flag-SHAPE, but downstream-gated
`scripts/memory-archive-gate.ps1` PASS-1 PLANNER L137-165 literally computes "**Move oldest entries one-by-one**" (`for ($move = 1; $move -le ($entryCount - $keepFloor); $move++)`, cutting at `markers[$move]`). This is an **age-RANK ordering** by the broadcast's own drop-date test (remove entry order → cannot compute `moveCount` → behavior changes). BUT: (a) whole script is **DRY-RUN**, header L7 "FLAG-ONLY … Does NOT move/edit"; (b) `value_protect` scans the moved prefix and FLAGS high-value entries "KEEP in L1 regardless of age" (L167-191); (c) the actual archive DECISION is em-main (human), L56/L190 "ADVISORY FLAG ONLY - em-main decides (no auto-exclude)". So the *decision layer* is value-gated; oldest-first is a proposal-ordering heuristic inside a dry-run, not the cool-down decision.

`scripts/mfe-eval.ps1` age-band L183-188: "**age-band : FLAG old-but-still-required, NEVER cut (mark RC-...10-29-11)**", "**>30d old but still Active … -> KEPT (status-driven, age-blind)**". This is presence-clean already (age = surfacing flag, drop only on status-change).

---

## 2. Ranked proposed-change table (my core deliverable)

| # | Proposed change | Necessity | Rationale (scope-discipline) |
|---|---|---|---|
| A | Write the presence-not-age **re-verify note** (1 paragraph) into docs (ledger honest-nac §6.5 or reinject-ledger footer) confirming floors i/ii/iii met + citing keep_floor/value_protect/DRY-RUN + mark …29-11 | **MUST** | Broadcast §6 L102/L105 *requires* a written confirmation + the 3 honest-notes. Doc-only, cheap, zero code risk. |
| B | Keep all **3 honest-notes** verbatim-in-substance in the spec (ONE-occurrence proactive-prevention · specific-application-not-rule · function-not-form/no-copy-hub) | **MUST** | Broadcast §5 L104 "Giữ đủ ba ghi-chú trung-thực". Free, and it is the anti-over-reach anchor itself. |
| C | **Part B** — hmw.js invalid-role fail-soft-WARN → **STOP-HARD + ask owner**, mirrored to `commands/ultra-on.md` doc | **MUST** | Directed `6c32df89` §2.3 REC-3 (in-scope, real silent-break class fixed hub-side today w/ 5-case sim). See §4 for minimal form. |
| D | In `memory-archive-gate.ps1`, compute the value-protect / keep-floor exclusion **BEFORE** the oldest-first ordering, so the candidate set = (entries − floor − value-protected) and the PLAN is value-gated-then-ordered rather than ordered-then-flagged | **SHOULD** (optional) | Tightens self-check (iii) at the FORM level using pieces that already exist (~10 LOC reorder). NOT a MUST: DRY-RUN + human + existing advisory flag already deliver the function. **Guard: must NOT balloon into a value-SCORING engine** — that violates function-not-form. |
| E | Alias-removal (directed §2.3 "check if SE has a similar alias to remove") | **SKIP / verify-N-A** | SE has no conversational-vs-ensemble alias split. `fable-real.md` + `fable-clone.md` are **2 distinct engines by design** (fable-clone.md L34 "2 engine GIỮ từ H19"), not aliases. Correct outcome = "verified none". Lane 4 owns the definitive call. |
| F | Rewrite reinject-ledger / build a coverage-scanner / rewrite archive-gate to delete oldest-first | **SKIP (over-eng)** | Violates §5 note-2 (quick re-verify) + note-3 (function-not-form). Floor (i) already presence-by-construction. |
| G | Remove/weaken `keep_floor_entries` or the mfe age-band as "age-based selectors" | **SKIP — ANTI-REGRESSION GUARD** | keep_floor is a recency **PROTECT** floor (never cuts by age); mfe age-band is already FLAG-never-cut. Removing either would HARM (drain-below-floor / lose surfacing) and would MISREAD the mark. Explicitly flag if any lane proposes this. |

---

## 3. The crux tension (self-refutation of my COMPLIANT verdict)

**Strongest case AGAINST "COMPLIANT / no MUST on the memory side":** The broadcast self-check (iii) is literal — "any place that SORTS/FILTERS by … oldest-first to DECIDE … cool-down = RED FLAG → redesign to presence." `memory-archive-gate.ps1` L138/L153-162 DOES sort oldest-first to produce the archive proposal, and `value_protect` is **advisory-only, no auto-exclude** (L55-56, L190). So the *computed* plan (`move $moveCount oldest`, L182) is FIFO-shaped and the value-gate is a flag appended AFTER — not a gate that alters the move-set. Under the drop-date test the planner's behavior changes → age is used for RANK → by the broadcast's own words this is a red flag that "cần sửa".

**Why I still settle COMPLIANT (not NEEDS-FIX):** The broadcast's target is the **cool-down DECISION**, not every heuristic that touches order inside a dry-run. In SE the decision-maker is em-main (human), the value-gate (value_protect + mark …29-11) is *in that human's loop*, and the script **never cuts** (DRY-RUN, exit-0-unless-pointer-broken L293-295). Function-floor (ii) — "archive passes through a value-gate" — is satisfied at the decision layer. The oldest-first is a proposal-ordering, and the honest fix is not a rewrite but the **bounded reorder in row D** (make the value-gate precede the ordering so the PLAN is value-gated-first). That is a SHOULD, and even it is optional. Calling this a MUST/rewrite would itself violate the scope-discipline the broadcast demands (note-2 quick-re-verify, note-3 function-not-form). Net: the red-flag SHAPE is real and worth one honest sentence in the spec + optional row-D tightening — it is NOT a spreading defect and NOT a rewrite trigger.

---

## 4. Part B in-scope confirmation + minimal form (guard against ballooning)

Part B is **NOT** part of broadcast `ab6c387e`; it comes from directed reply `6c32df89` §2.3 REC-3. Bundling two same-day AI_INFRA items into one run is reasonable batching, **not harmful scope-creep** — but the spec MUST keep Part B in a clearly-separated section so the "quick, no-rewrite" presence-not-age re-verify is not conflated with an actual code change.

Current state (2 fail-soft spots, only #2 is the target):
- `hmw.js` L106 `const role = VALID_ROLES.includes(raw) ? raw : undefined` + L107 WARN + L145 `agentType: role || undefined` → **invalid role silently runs the DEFAULT subagent** (the silent-break class the hub hit).
- `hmw.js` L46-49 resolveModel is about MODEL inherit for invalid role — leave the role-LESS legitimate path (`!role && !rawRole`, L49 governed-ultracode default) UNTOUCHED.

**Minimal in-scope form** (Lane 4 owns the exact diff; I only bound it): add a **pre-flight validation BEFORE `parallel()`** (after the `checkpointApproved` throw ~L85), mirroring the existing throw pattern L83-85:
```js
// Part B (directed 6c32df89 REC-3): role specified-but-∉-whitelist = STOP-HARD, ask owner.
// (role-LESS by design stays legal — governed-ultracode default, L49.)
const badRoles = A.taskList
  .map(t => t && t.role)
  .filter(r => r != null && !VALID_ROLES.includes(r))
if (badRoles.length > 0) {
  throw new Error(`hmw: role(s) ∉ VALID_ROLES: ${[...new Set(badRoles)].join(', ')} — `
    + `STOP-HARD (directed REC-3): báo anh bổ sung vai vào VALID_ROLES hoặc sửa typo. `
    + `KHÔNG rơi-lặng về default subagent.`)
}
```
Precision guard (scope-discipline): the predicate is `r != null && !includes(r)` — it must fire ONLY on a *specified-but-invalid* role, never on the legitimate `null` role-less path. Doc mirror: `commands/ultra-on.md` L21 + L26 currently document "role lạ → default subagent + WARN (fail-soft)"; these two lines MUST be updated to "STOP-HARD + hỏi anh" or the doc will lie about the engine. **Do NOT** expand Part B into a rework of resolveModel, the model-tier system, or VALID_ROLES membership.

---

## 5. Measurable acceptance criteria

1. **Spec contains all 3 honest-notes** (grep the spec for: "one/ONE occurrence" + "proactive-prevention"; "specific-application"/"not a new rule"; "function not form"/"do NOT copy hub"). 3/3 present = PASS.
2. **Presence re-verify note written** to a git-tracked doc citing floors i/ii/iii + `keep_floor` + `value_protect` + mark `RC-pqhuy1987-20-06-2026-10-29-11`. Exists + cites the mark = PASS.
3. **Zero deletion** of `keep_floor_entries`, `value_protect`, or the mfe age-band in the final diff (`git diff` shows these lines intact). Any removal = FAIL (row G regression).
4. **Part B**: `hmw.js` throws on a specified-but-invalid role (fault-inject: taskList `[{role:'not-a-role'}]` → hard error, run aborts BEFORE any spawn) AND a role-LESS task (`{role:null}`) STILL runs (no throw). Both = PASS. `commands/ultra-on.md` L21/L26 no longer say "fail-soft/default subagent". 
5. **No script rewrite**: `memory-archive-gate.ps1` diff is either empty, or (row D) a bounded reorder < ~15 LOC that introduces NO value-scoring/ranking numeric. Larger diff = scope-fail.
6. **Alias**: spec records "verified N/A — fable-real/fable-clone are distinct engines, no alias" OR a concrete alias found by Lane 4. Fabricated alias-removal = FAIL.

---

## 6. Bottom line for the synthesizer

- Memory-selector (floors i/ii/iii): **already functionally compliant** → MUST = write the re-verify note + keep 3 honest-notes (docs only). SHOULD = optional row-D reorder. SKIP = any script rewrite / ledger rebuild / keep_floor-or-age-band removal.
- Part B (hmw.js): **in-scope MUST**, minimal pre-flight throw + doc mirror, precision-guarded to spare the role-less path.
- Alias: **verify-N/A**, do not fabricate.
- The single biggest risk in this run is a lane over-reading self-check (iii) into a rewrite of `memory-archive-gate.ps1`. Hold that at SHOULD-optional; the DRY-RUN + human + value_protect + mark already satisfy the FUNCTION.
