[CLAUDE] Docs: adopt Harness-10 — tracked run-trace folder convention + checklist 9-10 (3-workflow invest/imple/review)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m36s

Migrate .claude/workflows/wave-*/ (gitignored) -> runs/<run-id>/ git-TRACKED (run.md+sub-md/+harvest/) + _ledger.md 2-beat + 3-layer anti-miss + containment model shift (B6 'any tracked-change=violation' -> 'tracked-change outside run-folder+code-disjoint=violation'). hmw.js wave->run-trace (accept args.run + alias). Review (R2+R3) caught C5 L1 over-claim -> fixed (em-main convention, engine no-fs). 3 run-id: wf_9c2cd2cd-2e7 / wf_e4e46725-231 / wf_636bc95b-939. 0 production code, state unchanged (Mig 53/88 tables/306 test/68 gotcha).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-18 09:15:51 +07:00
parent f3ad1a2ae0
commit 8c47bd0f0c
28 changed files with 467 additions and 69 deletions

View File

@ -70,6 +70,12 @@ Bearer từ `POST api.solutions.com.vn/api/auth/login` → status matrix expecte
## 📅 Recent activity (FIFO — older → archive/git)
- **2026-06-18 (S71 Harness-10 ref-sweep — wave-*/agent-teams/harvest migration map, on-disk):** ⭐ **2 RULE-MECHANISM (cơ-chế, sửa CẨN THẬN ≠ text-swap):** (1) **`.gitignore:93-94`** `.claude/workflows/wave-*/` + `.claude/agent-teams/` AFTER `!.claude/**:83` (last-match-wins) — Harness-10 LẬT containment: runs/ TRACKED nên KHÔNG gitignore (đã có `runs/_ledger.md:4` "tracked-change NGOÀI run-folder = vi-phạm" thay B6 "mọi tracked = vi-phạm"). agent-teams = n-a Windows in-process → giữ-hay-bỏ tùy. (2) **`hmw.js`** wave-mechanism: meta.description:9 (2-MODE) · args:19 `wave:{name,dir}` · SCHEMA subMdPath:52 · WAVE-MODE block:87-91 (`const wave = A.wave&&A.wave.dir`) · log:94 · subMd path:102 · writeGuard TOOL-AWARE 2-nhánh:106-120 (wave→sub-MD-isolated / default→return-delta) · prompt subMdPath:131. → run-trace = đổi `wave``run`, dir `wave-<tên>``runs/<run-id>`, +harvest/ path. **TEXT-ONLY (đổi chữ, KHÔNG cơ-chế):** `.claude/workflows/README.md` TOÀN BỘ (48 dòng, đầu-đề + table 2-MODE + structure + B1-B6 + agent-team §) · `session-end.md:32,49,51` (§L.b(d)(f) GATE + B5 wave-gom) · `session-start.md:71` (H2 báo wave-folder tồn-đọng) · `agents/README.md:111` (decision-tree wave-gom B5) + :22-28,52 harvest-curator.md (B5 scan path `wave-<tên>/sub-*.md` + agent-team) · `harvest-curator/MEMORY.md:20` (wave-folder gitignored). **DOC/HISTORY (immutable evidence — KHÔNG sửa):** `broadcasts/**` (handshake:17 + inbox/README:15 "khác wave-folder gitignored") · `docs/governance/adap-reports/2026-06-07-Agent-harness-2.md` (toàn bộ B1-B6 spec) · `docs/changelog/sessions/*` · `error-ledger.md:86` (wave-folder-leak=0 evidence). **ĐÃ SCAFFOLD Harness-10 (S71 đang chạy):** `runs/_ledger.md` (2-beat OPEN/CLOSE) + `runs/2026-06-18-h10-invest/run.md` + `harvest/`. ⚠️ **Note .gitignore:92 comment** `git check-ignore -v .claude/workflows/wave-x/wave.md` = verify-cmd cũ, đổi theo. Tag `[s71, harness-10-refsweep, wave-to-runtrace-migration, gitignore-mechanism, hmw-wave-mechanism]`.
- **2026-06-18 (S71 Harness-10 STAGE-C harvest-flow recon — per-turn + 3-layer wire points, on-disk):** ⭐ **CURRENT harvest = SINGLE-POINT @session-end (B5), KHÔNG per-turn.** Driver = `harvest-curator` H2 (`agents/harvest-curator.md:22` "sau workflow-dài/cuối-session quét `wave-<tên>/sub-*.md`→gom→APPEND agent-memory/<role>"). Wired ONLY `session-end.md §L.b(f):51` (5-trục GATE + wave-folder gom B5). `session-start.md:71` = REPORT-only (báo wave tồn-đọng, KHÔNG gom). ZERO per-turn hook — `hmw.js` JS-sandbox no-fs (`hmw.js:5`), harvest deferred-to-close. **C4 per-turn-primary wire (3 chỗ):** (a) `hmw.js:122-134` prompt-builder — sub return findings; (b) NEW em-main step: ghi `runs/<id>/harvest/` SAU MỖI fan-out turn (KHÔNG đợi close); (c) `session-end.md §L.b(f):51` đổi "gom @end" → "VERIFY per-turn harvest đủ". **C5 3-layer anti-miss wire:** L1 in-run-reminder = `hmw.js` prompt + `run.md` checklist (run trước chưa-harvest → flag); L2 post-exec-rescan = `session-start.md:71` (mở rộng orphan-scan `runs/*/` tìm ledger-OPEN-no-harvest, hiện chỉ báo wave); L3 close-gate = `session-end.md §L.b(f):51` (GATE đã có, repoint wave→runs). **EVIDENCE tracked:** `git check-ignore runs/.../run.md`→matched `!.claude/**` (.gitignore:83 negation)=NOT-ignored ✓ vs `wave-*/` still gitignored (:93). Run-folder ĐÃ scaffold S71: `runs/2026-06-18-h10-invest/`{run.md·sub-md/.gitkeep·harvest/.gitkeep}+`runs/_ledger.md` (2-beat OPEN/CLOSE `:3`, orphan=OPEN-no-CLOSE). **G-015 shift:** Harness-2 "mọi tracked=vi-phạm" (wave gitignored→diff mù) → Harness-10 "tracked NGOÀI run-folder+code-disjoint=vi-phạm" (`_ledger.md:4`) → containment MẠNH hơn (run-folder in git-diff thấy sub-MD writes). Tag `[s71, h10-harvest-flow, per-turn-C4, 3-layer-C5, single-point-end-current]`.
- **2026-06-18 (S71 Harness-10 task-A — hmw.js EXACT edit-list wave→run-trace, on-disk):** ⭐ Refines sibling ref-sweep with precise diffs. **3 LOGIC edits:** (1) `:90` `const wave=(A.wave&&A.wave.dir)?A.wave:null``run=(A.run&&A.run.dir)?A.run:null`; (2) `:102` subMd `\`${wave.dir}/sub-${role||'task'}-${i}.md\`` → `\`${run.dir}/sub-md/sub-${role||'task'}-${i}.md\`` (⚠️ +`/sub-md/` SUBDIR — matches scaffolded `runs/<id>/sub-md/`, today FLAT); (3) `:106-120` writeGuard 2-branch keep TOOL-AWARE, reword. **CONTAINMENT-FLIP 2 strings:** `:112` "wave-folder gitignored nên KHÔNG hiện trong diff = sạch" → "run-folder TRACKED; tracked-change NGOÀI run-folder(+code-disjoint)=vi-phạm" (model = `runs/_ledger.md:4`); `:114` "file NGOÀI repo/wave-folder"→run-folder. **TEXT reword:** `:5,9(+drop stale two-tier H4.5→H8),19(args wave→run),52,55,88-91,94,108,113,131`. **VERDICT: pure mechanical** — fan-out/SCHEMA/resolveModel/parallel/checkpoint-gate ALL unchanged; only rename + path-subdir + 2 string-flips. **Read-only sub flow same** (`:111` subMdPath→em-main-scribe @P3, no Write tool). **C2/C4 stay em-main** (hmw.js no-fs `:1-5`). Tag `[s71, h10-task-a, hmw-exact-difflist, subdir-sub-md, mechanical-rename]`.
- **2026-06-17 (PE-workflow recon for FDC feature-plan — urgent flag + value-threshold routing, on-disk):** ⭐ **PE VALUE: NO stored "giá trị gói thầu" column.** Best-fit = winner-quote-total `SUM(Quote.ThanhTien WHERE supplier==SelectedSupplierId)` — COMPUTED (submit-guard `PurchaseEvaluationWorkflowService.cs:188-190` + `CurrentProposalTotal` in `PeBudgetSummaryDto`). Other amounts: `PE.BudgetPeriodAmount`(:40 drafter NS kỳ này)/`ExpectedRemainingAmount`(:41)/`PeWorkItemBudget.FullAmount`=(Initial??0)+(Adjustment??0) (`PeWorkItemBudget.cs:29-30`) — all budgets, not deal-value. **ROLES PRO/CCM/CEO = domain shorthand NOT constants** (`AppRoles.cs` has Procurement/CostControl/Director; PRO=Procurement CCM=CostControl CEO=Director). **V2 routing IGNORES roles** — approvers = specific `ApproverUserId` (`ApprovalWorkflow.cs:80`), OR-of-N = N Level rows same `Order` (GroupBy :687). "Phòng CCM" = seed Step NAME + non-strict DeptId hint only (`:67`). **CEO = positional (last level/last step), NOT conditional.** **ROUTING 100% LINEAR** (level→step, `DaDuyet` when `nextIdx>=steps.Count`). ZERO value/threshold/conditional config anywhere (grep 0 on AW/Step/Level/PEType). ⭐ **HOOK B (value-threshold) = `ApproveV2Async` advance block lines 816-845** (`:817` levelOrder++ / `:828-837` terminal DaDuyet / `:838-845` next step). Precedent: `skipToFinal :773-814` already "jump pointer to last step+level" — reuse mechanic conditioned on value. **HOOK A (urgent):** add `IsUrgent bit`/`PePriority` enum (mirror `ItTicketPriority{Low,Medium,High,Urgent}` `Office/Enums.cs:48-54`) AddColumn no-new-table; notify `INotificationService.NotifyAsync(userId,type,title,desc?,href?,refId?)` (`INotificationService.cs:10`)+SignalR interceptor; LogTransition notifies DRAFTER-only on terminal (`:960-980`), NO approver-notify yet. Badge DTOs: `PurchaseEvaluationListItemDto`(`PurchaseEvaluationDtos.cs:6`)+`DetailBundleDto`(:201). Type A/B (`PurchaseEvaluationType.cs:6-10`) constrains pinnable ApplicableType only — ZERO type-conditional routing. ⚠️ "Từ chối" REMOVED S60 hard-guard `:80-85` (throws even Admin; only Duyệt/Trả lại). ⚠️ drafter-in-chain bypass `:543` auto-approves drafter's own step-1 levels on submit (interacts w/ value-finalize). Tag `[pe-workflow-recon, value-threshold-hook, urgent-flag, fdc-feature-plan]`.
- **2026-06-17 (S69 recon — Office-module inventory + Hồ sơ-NS CSS-contract, on-disk):** ⭐ **PART A Office:** 21 `Off_*` keys (`MenuKeys.cs:99-121`): root `Off` + DanhBa(card-grid), `Off_PhongHop`{View=cal/Manage=room-CRUD-admin/Book}, `Off_DeXuat`{List/Create/Inbox=Proposal-V2}, `Off_DonTu`{Leave/Ot/Travel}, `Off_DatXe`, `Off_ItTicket`, `Off_ChamCong`(re-parent→Personal S57), `Off_AttendanceReport`(admin). 10 office pages `{fe-admin,fe-user}/src/pages/office/` ALL SHA256-MIRROR except **MyAttendancePage DIFFERS** + AttendanceReportPage ADMIN-ONLY. Routes `App.tsx` user:70-80/admin:88-100; staticMap `Layout.tsx:87-103` (workflow-apps :kind `/workflow-apps/{leave,ot,travel,vehicle}`); menuKeys.ts:45-63. **HIDE-FLAG** `RevokeTemporarilyHiddenModulesAsync` (`DbInitializer.cs:2157-2190` called :2040 LAST) wipes CRUD on `MenuKey.StartsWith("Off")||"Hrm"||==Personal` non-Admin, idempotent. **Golive flip:** remove :2040 call (+ re-add prefix InReviewScope grant). Office already S55-shell polished NOT bare. **PART B Hồ sơ-NS CSS:** layout=3-col flex (`EmployeesListPage.tsx` SHA256-identical x2, 1597 LOC): cây-tổ-chức TRÁI(:178) + NV-list MID(:244) + detail PHẢI = avatar-header `app-gradient-brand`(:643)+`text-white!`(:653)+initials chip bg-white/15 → 5-TAB(:507 Tổng quan/Thân nhân/Trình độ/Kinh nghiệm/Hợp đồng) → `Card`(:1526 left-rail+icon-chip) w/ `Field`(:1572 label uppercase accent-tint + value `font-medium text-brand-800`, empty=`text-slate-300 —`). `ACCENT` map :497-503 Record<5,{chipBg/chipFg/head/rail/labelText}> accent∈{brand,teal,violet,amberx,greenx}, palettes stops 50/100/500/600/700 only no-800→headings -700 (brand -800 OK). Tokens `index.css`: brand-600=#1f7dc1 brand-800=#175685 @theme:5-55, font Be-Vietnam-Pro:53; classes `.app-gradient-brand`(:105 120deg b600→700→800),`.card-accent`(:112),`.icon-chip`(:128 --chip-bg/--chip-fg),`.stat-value`(:140),`.label-eyebrow`(:89). ⚠️ **GOTCHA #66 = `index.css:79-83` `h1,h2,h3,h4{color:#0b1220;font-weight:700}` OUTSIDE @layer** → TW-v4 unlayered wins → heading-tag inside gradient MUST `text-white!`. ⚠️ **CROSS-APP DRIFT:** fe-user=S68 (h1-4 #0b1220/700, label-eyebrow brand-600, 175L); **fe-admin STILL OLD** (h1-4 #0f172a/600, label-eyebrow #64748b slate, 167L) — fe-admin NOT synced S66-68 heading bump → mirror Office to fe-admin needs index.css sync. Tag `[s69, office-inventory, hoso-css-contract, gotcha66, fe-admin-css-drift]`.

View File

@ -61,6 +61,7 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
## 📅 Recent activity (FIFO — older → archive/git)
- **2026-06-18 (S71 Harness-10 adap run-trace convention — Stage-3 REVIEW lens R1 frozen-evidence+containment, PASS, 0 blocker):** Governance/infra-only (wave-folder→run-trace `.claude/workflows/runs/<run-id>/` TRACKED). 10 modified (8 H10 + investigator MEMORY residual + CLAUDE.md pre-existing) + 1 untracked `runs/`. NO product/test/csproj/package.json/migration → test baseline 306 untouched, deps N/A. **Spec path trap:** spec said `runs/...` but actual `.claude/workflows/runs/...` (verify disk, không tin claim path). **R1 verify ALL PASS:** (1) **Frozen-evidence 0-touch**`git status --porcelain` on broadcasts/** · adap-reports/2026-06-07-harness-2 · error-ledger · sessions/* · STATUS · HANDOFF · `*/archive/*` ALL empty = none touched. (2) **Containment wording đồng-bộ 4 chỗ**`_ledger.md:4``hmw.js:89/113``workflows/README:38``runs/README:78` ALL = "tracked-change NGOÀI run-folder + code-disjoint = vi-phạm" (model thay Harness-2 B6 "mọi tracked = vi-phạm"). (3) **gitignore exit-code-trap**`check-ignore runs/.../run.md && echo IGNORED || echo NOT`=NOT (re-included via `:83 !.claude/**`); `wave-x/wave.md`=IGNORED (legacy `:93` kept); trap-note PRESENT gitignore `:96-98`. No new ignore rule shadows runs/. **residuals verified as-claimed:** investigator MEMORY +6 (3 S71 diary, 29819B≈29.8KB over-cap, race artifact closeout); CLAUDE.md pure test-count 263→306 flush. hmw.js `node --check`=PARSE-OK, `args.run` w/ legacy `args.wave` fallback `:91`, `sub-md/` subdir `:103`. harvest-curator DEDUP axis (sha/substring before APPEND); session-end idempotent VERIFY-not-re-APPEND; session-start orphan-scan. 6× `.gitkeep` present. **1 MINOR (non-block, actionable):** runs/ currently UNTRACKED (`git ls-files` empty, `?? runs/`) = tracked-ELIGIBLE not-yet-committed; docs say "TRACKED" = post-commit steady-state — em main MUST `git add runs/` in SAME commit else run-trace invisible to git-diff audit model depends on. **Learned:** "TRACKED" containment = 2-level — check-ignore NOT-IGNORED (eligible) vs `git ls-files` (committed); model only works after `git add`. **surprise:** internal var `const wave = (A.run&&A.run.dir)?A.run:...` keeps name `wave` but reads `A.run` first — cosmetic-only, downstream identical (not bug). Verdict PASS — safe commit (git-add-runs/ caveat). Tag [s71, harness-10-runtrace, frozen-evidence-clean, containment-wording-4file-sync, gitignore-exit-trap, tracked-eligible-vs-committed].
- **2026-06-17 (S69 GOLIVE Văn phòng số public-all-roles authz — PASS, 0 blocker, gotcha #44-family CLEAN):** 1-file BE-only DbInitializer.cs (+81, new `SeedAllRolesOfficeModulePermissionsAsync` :2261 + call :2055 AFTER S65 HRM grant → AFTER revoke :2042). NOT deployed (static + Dev-DB review, build PASS). Near-exact mirror of S65 HRM method, ONLY delta = `+CanCreate=true` (HRM was read-only). **8 verify ALL PASS:** (1) **Ordering** — grant call sits after `RevokeTemporarilyHiddenModulesAsync` (:2042) + after S65 (:2048) → grant wins revoke. (2) **Allow-list EXACTLY 16 Off keys** — Off/Dashboard/DanhBa/PhongHop(+View+Book)/DeXuat(+List+Create+Inbox)/DonTu(+Leave+Ot+Travel)/DatXe/ItTicket; const names map correct values per MenuKeys.cs:99-120; NO PhongHopManage/AttendanceReport/ChamCong; array contains ZERO Hrm*/Personal/Pe*/Master key → no leak. (3) **Upgrade-only correct** — row exists→only flips CanRead/CanCreate false→true (`if(!row.CanRead)`+`if(!row.CanCreate)`), NEVER touches CanUpdate/CanDelete, never lowers; new row→read+create=true, update/delete=false (Permission.cs defaults false anyway). (4) **3 excluded keys STAY HIDDEN — decisive cascade check:** `Off` is NOT one of the 4 inherit-roots in GetMyMenuTreeQuery (:56-59,:70-73,:80-83 = Contracts/Workflows/PE/PeWorkflows ONLY) → granting Off does NOT cascade to children; each Off child reads its OWN `resolved` flags (:65, falls to false-tuple if no row); PhongHop_Manage(parent=Off_PhongHop:1830)/AttendanceReport(parent=Off:1845) not-in-list→revoke-false→filtered by HasAccess(:96); ChamCong re-parented to Personal(:1850/:1962) under hidden Personal root, not under Off, not granted→hidden. (5) **Admin unharmed** — MenuPermissionHandler:27 Admin bypass; Dev DB: all 18 Off rows belong to Admin already read+create=true → upgrade branch no-op. (6) **No real write-path opened — KEY for golive:** grep Controllers for Off menu keys = 0 matches; Office controllers gate writes by class-level `[Authorize]` (any-auth, self-service create) + per-action `[Authorize(Roles="Admin")]` for true admin writes (MeetingRoomsController Create/Update/Delete=Manage-rooms :26/34/43, Attendances :37/42, LeaveBalances :23/28) — NOT by Off_*.Create policy. So broad CanCreate grant only drives FE menu+button (usePermission/PermissionGuard); API write-auth untouched, admin CRUD stays Admin-only regardless. (7) **No migration** — seed-logic only; all 16 keys in MenuKeys.All:157-161 (seeded). (8) **Idempotent** — 2nd run: rows already true→0 change; SaveChanges gated `if(added>0||upgraded>0)`. **Dev DB baseline** (307 perms,13 roles): 0 non-admin Off rows exist→method takes add-branch for 12 non-admin roles (creates 16 read+create rows each, 3 excluded never added). build Infrastructure 0err/0warn. 0 rogue write (only cicd-monitor/MEMORY.md noise, read-only respected). **Learned:** for a public-grant golive the load-bearing security proof is TWO-fold — (a) cascade-safety = confirm the granted root is NOT an inherit-root (else siblings leak, gotcha #44-family) AND trace excluded keys' ParentKey to a non-granted/hidden parent; (b) write-path-safety = grep that the broadly-granted menu key is NOT used as a controller `[Authorize(Policy=)]` (here Office uses class `[Authorize]`+per-action Roles=Admin, so CanCreate is FE-only — granting it cannot escalate API writes). **surprise:** the "Manage rooms" admin function is double-protected — excluded from allow-list (menu hidden) AND its API is `[Authorize(Roles=Admin)]`; menu-hide alone would've been insufficient but the controller gate makes the broad grant safe even if a key had slipped. Verdict PASS — safe commit+deploy. Tag [s69, office-golive-authz, public-all-roles, inherit-root-no-cascade, off-not-policy-key-fe-only-grant, gotcha44-family-clean, admin-write-double-protected].
- **2026-06-17 (S69 Văn phòng số RE-SKIN static logic-preservation — PASS, 0 blocker):** 10 pages presentation-only re-skin → PURO PageHeader/KpiCard + Hồ sơ-NS idiom (9 fe-user office + 1 fe-admin AttendanceReport). NOT built yet, fe-admin not mirrored (em main next). **Strongest proof = exact API/queryKey diff OLD-vs-NEW byte-identical ALL 8 fe-user pages** (grep `api\.(get|post|put|delete)` + `queryKey:[...]` sorted -u, zero delta): proposals POST /submit + /{kind} · workflow-apps POST /{k}+/submit+PUT /workflow · meeting-bookings POST/DELETE+invalidate · it-tickets PUT /{id}/assign · directory/departments/attendance-report/excel-blob all UNCHANGED. Mutation side-effects (onSuccess/onError/invalidateQueries/setActionDialog/setComment/navigate) 1:1 (line-shift only). ProposalCreate validation `!title.trim()` throw + required + submit-disabled intact. AttendanceReport exportExcel blob (createObjectURL→a.download→click→revoke) intact. **Cat2 orphans CLEAN:** 0 unused import — flagged Users(=UsersIcon alias) + FormEvent/ReactNode (React.* namespace not named-import) + Accent(comment word) all FALSE-alarm verified. **Cat3 shared-comp contract:** PageHeader{eyebrow,title,subtitle,icon,accent,actions} + KpiCard{label,value,icon,accent,active,onClick} props all match real sig; KpiCard onClick wired to REAL filter state (ItTickets `setFilter`/WorkflowAppsList `setStatusFilter`/ProposalsList — driving actual client `.filter()`), InternalDirectory 2 KpiCards INTENTIONALLY inert (no onClick=presentational counts, matches comp design — NOT dummy). **Shared comps + index.css NOT modified** (git status -- ui/ + *.css EMPTY; sha256 identical fe-user==fe-admin per ls). **Cat4 color-trap CLEAN:** grep added lines for `(teal|violet|amberx|greenx)-(200|300|400|800|900)` = ZERO; index.css confirms accents ship only 50/100/500/600/700 (brand has full 50-900 so brand-800 valid); gotcha #66 — 0 gradient/dark-bg headings added (all headers on light surface use accent-ink text-brand-800/{accent}-700 via PageHeader). **Cat1 mock-markers:** 0 //Mock/alert/TODO-wire. **Client-side filter additions** (ItTickets filter/breached, WorkflowAppsList statusFilter useMemo) = presentation views over fetched items, NO new query/endpoint. **2 MINOR (non-block):** (a) ProposalDetail status badge now renders TWICE — PageHeader actions slot + existing status-row (cosmetic dup, both presentation); (b) it-tickets/workflow-apps client-filter is view-only over a `pageSize:100/50` first-page fetch (pre-existing pagination limit, re-skin doesn't worsen). **Learned:** for pure re-skin, the decisive logic-preservation proof is `grep api-call + queryKey sorted -u` OLD-vs-NEW byte-equality across every page — faster + more rigorous than reading each hunk; orphan-import heuristic (body-occ<=1) flags `X as Y` aliases + `React.X` namespace + comment-words as false-positives, always grep the actual usage line before flagging build-break. **surprise:** custom accent palettes (amberx/greenx/teal/violet) deliberately ship NO -800 stop so headings MUST use -700 (brand is the only -800-bearing accent) — a -800 on a non-brand accent = silent no-class Tailwind v4, the re-skin respected this everywhere. Verdict PASS — safe for em main to build+mirror. Tag [s69, office-reskin, presentation-only, api-querykey-byte-equal, color-trap-clean, kpicard-inert-vs-filter, gotcha66-clean].
- **2026-06-16 (S65 PE mục E HoSoLink review — em-main PROXY, PE-Workflow reviewer-stage died-empty):** Review mục-E hyperlink render + HoSoLink BE wiring (`5a0aaa4`). Reviewer-stage trong Workflow `pe-hoso-link-rename-pro` return RỖNG → em main self-gate evidence: Detail DTO `hoSoLink` present + `null` backward-compat phiếu thật (Run #293 GET 200); Create/Update +trailing-optional `HoSoLink=null` KHÔNG vỡ call-site (grep 0 manual ctor — KHÁC CreateDepartmentCommand #291 CS7036 vì positional-required vs trailing-optional); mirror fe-user==fe-admin SHA256 IDENTICAL (PeDetailTabs+PeWorkspaceCreateView); hyperlink `<a target=_blank rel=noopener noreferrer>` no reverse-tabnabbing; rename "Dự trù PRO"→"Ngân sách PRO" CHỈ display (giữ "Ghi chú từ PRO" + field-code). LEARNED: hyperlink free-text = no server-side XSS (render-as-href client-only); absolute-set Update (null=clear) chủ đích. SURPRISE: reviewer-stage chết-rỗng trong fan-out = lý do verify-heavy task vẫn cần em-main self-gate dù có Workflow (verdict `feedback_workflow_fanout_reliability`). Tag `[s65, pe-section-e-review, em-main-proxy-self-gate, hosolink-backward-compat, workflow-fanout]`.
@ -78,6 +79,9 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
---
- **2026-06-18 (Harness-10 adap R2-lens hmw.js ENGINE integrity — CONCERN, confirms sibling L1 over-claim still live, pre-commit):** Lens = hmw.js engine integrity (em-main rename wave→run-trace). **Engine itself CLEAN — all 4 R2 checks PASS:** (1) structure valid — `const wave=(A.run&&A.run.dir)?A.run:((A.wave&&A.wave.dir)?A.wave:null)` :91 nested-ternary paren-balanced 3/3, accepts args.run primary + args.wave alias (additive, old callers OK), var `wave` internal-name kept consistent :91/:92/:95/:103/:107/:132; subMd path :103 `${wave.dir}/sub-md/${role||'task'}-${i}.md` matches spec; template-literals balanced (backtick 54 EVEN all-escaped, brace 56/56, paren 140/140, bracket 14/14). (2) zero operative WAVE-MODE — grep `WAVE-MODE`=0; all 6 wave refs contextualized (legacy-alias :19/:90/:91, "supersedes Harness 2 wave" :87/:109); :113 ISOLATION contains "tracked-change NGOÀI run-folder (runs/<run-id>/)+code-disjoint=vi-phạm" ✓. (3) fan-out logic UNCHANGED — `git diff -U0` hunks = ONLY :91 behavioral (alias-accept); resolveModel/SCHEMA/checkpointApproved-guard/parallel/results.filter untouched. (4) valid JS (balance + structural, NO node --check per top-level-await). **THE CATCH (CONCERN, intersects R2):** runs/README.md:51 documents L1 in-run-reminder as firing in "`hmw.js` prompt-builder" w/ exact text 'run đang OPEN—nhớ scaffold@P1'+'run trước OPEN-beat đã harvest chưa' → grep that in hmw.js = **0**. hmw.js writeGuard :114 emits ONLY C4 return-instruction ("Harvest per-turn primary (C4)..."), NO scaffold/OPEN orchestrator-reminder; :92 is a log() at mode-detect not prompt-injection + still lacks the promised text. **Plan-vs-applied gap proven:** invest-synthesis:17 PLANNED "C5 Layer1: thêm reminder vào prompt-builder"; implement-synthesis NEVER lists applying L1 to hmw.js (only L2 :71 + L3 :51 applied); yet README:51+C7:72 present L1 as live. Doc asserts engine-behavior grep proves absent = over-claim. **Sibling reviewer (same adap, prior run today) already CONCERN on this exact gap — I independently re-confirm UNFIXED.** **Cross-file PASS:** gitignore runs/ TRACKED via `!.claude/**`:83 (check-ignore -v confirms negation) + wave-*/ kept IGNORED; containment wording synced 4 files (_ledger:4↔hmw:89/113↔runs/README:78); frozen evidence (broadcasts/adap-harness-2/error-ledger/STATUS/HANDOFF/archive_INDEX/sessions) ALL empty-diff; 0 mojibake. **Residual (non-block, self-flagged):** investigator-codebase/MEMORY.md +6 (29819B ~just-under-cap) = 4 same-role INVEST agents race (concurrency risk #7 invest-synthesis flagged) → em-main reconcile @closeout; new :113 guard forbids sub agent-memory writes = prevents recurrence. **Learned:** narrow lens (hmw.js JS structure) ≠ excuse to wave a doc-asserts-engine over-claim — when README says a layer "fires in <engine-file>", grep the engine for the CLAIMED text not a sibling instruction; INVEST-plan ≠ IMPLEMENT-applied. **Surprise:** engine rename genuinely flawless (dual-alias/balance/logic-frozen) — ONLY defect is adjacent doc over-stating what the clean engine does; engine-perfect + doc-overclaim coexist in one adap. Smart-Friend held: did NOT downgrade to PASS despite narrow lens + clean engine + sibling already-flagged. Tag [harness10, r2-hmwjs-engine, engine-clean-doc-overclaim, c5-L1-overclaim-reconfirm, plan-vs-applied-gap, dual-alias-additive].
- **2026-06-18 (Harness-10 adap run-trace folder R3-floor review — CONCERN, 1 over-claim, pre-commit):** Reviewed adap thay wave-mode → `runs/<run-id>/` 3-part (run.md+sub-md/+harvest/) git-TRACKED. Floor C1-C8 disk-verified. **C1/C2 PASS** — all 3 runs (invest/implement/review) scaffolded full 3-part (`ls` confirm + .gitkeep placeholders). **C3 PASS correct-nấc (NO over-claim)**`git check-ignore runs/`=NOT-IGNORED (tracked-eligible via `!.claude/**` :83) AND `git ls-files runs/`=EMPTY=NOT-committed-yet; _ledger:4 + runs/README:80 + gitignore:89-99 document "tracked" correctly, NEVER falsely claim "committed". Nấc THẬT = tracked-ELIGIBLE pre-commit (must commit to realize — expected, not defect). **C4 PASS** — invest+implement synthesis present per-turn; review harvest empty=correct (in-progress). **C5 CONCERN (the catch)** — L2 (session-start:71 orphan scan `closed=⏳`+harvest-rỗng) + L3 (session-end:51 idempotent VERIFY-not-re-APPEND) genuinely wired. BUT **L1 OVER-CLAIM**: runs/README:51 documents L1 in-run reminder firing in "hmw.js prompt-builder" w/ exact text 'run đang OPEN—nhớ scaffold@P1'+'run trước...harvest chưa' → `grep -c` that text in hmw.js = **0**. hmw.js writeGuard only emits C4 return-instruction ("Harvest per-turn primary (C4)"), NO scaffold/OPEN reminder. INVEST planned it ("C5 Layer1: thêm reminder vào prompt-builder"), IMPLEMENT synthesis never mentions applying it, yet runs/README:51+C7:72 present L1 as live. Doc-vs-reality gap = over-claim. **C6 PASS** — _ledger OPEN+CLOSE beats (invest/implement CLOSED, review ⏳) + orphan def:3. **C7 PASS** — caveat genuinely honest (engine no-fs · C2 fragile · 3-layer=lưới-không-khóa · G-015 TRACKED≠read-only-enforced); strong. **C8 PASS** — wave→runs migration done (0 wave-*/ remain), wave-*/ kept IGNORED (verified). **Frozen evidence 0-byte-loss CONFIRMED** (broadcasts/·adap-harness-2·error-ledger·STATUS·HANDOFF all empty-diff vs HEAD). hmw.js `node --check`=OK, dual-alias A.run/A.wave intact. Containment wording synced 4 files (_ledger:4↔hmw:113↔workflows/README:38↔runs/README:78). **Learned:** for a multi-layer "anti-miss net" adap, the catch is grepping each layer's CLAIMED trigger-site against the actual engine file — a layer documented as "fires in hmw.js prompt-builder" must have backing text there, not just a sibling instruction; INVEST-plan ≠ IMPLEMENT-applied (cross-check synthesis-plan vs disk). **Surprise:** README's own C1-C7 section-numbering ≠ task's C1-C8 reviewer-axes (two schemes, NOT a defect — README documents convention, task axes evaluate it); don't conflate. Over-claim=CONCERN per task rule (would be PASS if README:51 softened L1 to "C4 return-instruction" matching reality, OR hmw.js actually added the scaffold reminder). Tag [harness10, run-trace-folder, c5-L1-overclaim, tracked-not-committed-correct-nac, frozen-evidence-clean, plan-vs-applied-gap].
## 🔄 Curate trigger
- >~30KB → archive recent → L2 `archive/<period>.md`. Stale >3mo → remove.
- **Last curate: 2026-06-17 S70 (Harness-9, em-main + Stage-B workflow)** (42.5→24.8KB): moved 9 entries S51→S57 (byte-exact) → `archive/2026-06.md`; KEPT foundation + 6 newest (S69×2/S65×2/S60/S57bis) + S49/S43/S35/S33 tail + Smart-Friend-cumulative + archive-pointers. Built `archive/_INDEX.md` (substring sha-keyed) + `.gist.md` (4-field distill-gen:1). Also Stage-C audit actor (`wf_9520d8cd-4fe` — verify 0-byte-loss/pointer/coverage). No re-ground (additive-only). Prev: S40 (28.4→18KB) · S34 q2 · S22 q1.