# sub-implementer-frontend-1 — S133 STAGE A (FE types + badge frozen)

Role: implementer-frontend. Task: FE `budgetFrozen` field + badge (disjoint BE). 4 files only.

## Refuse self-check → PASS (proceed)
- UX decision? NO — badge placement + style fully specified (pill cạnh header "Tổng hợp ngân sách trình ký", amber/slate rounded-full text-xs).
- Schema design? NO — field `budgetFrozen: boolean` chốt sẵn spec ②.
- BE touch? NO — chỉ FE 4 file.
- First-time pattern? NO — pill badge proven (line 588/591/759 emerald "Đã ký"/"Đã duyệt").
- Ambiguity? < 20% — spec chi tiết + MEMORY-PACK định vị chính xác.

## Recon (evidence file:line)
- Baseline SHA both PeDetailTabs = `931025f240e04404a7d1821dbfd948f56da5eae5` (git hash-object) → khớp spec `931025f2`. 2 file byte-identical.
- `PeBudgetSummary` type: fe-user `types/purchaseEvaluation.ts:314-333` · fe-admin `:312-331`. Kết thúc bằng `currentProposalTotal: number` + `}`. 2 file block NỘI-DUNG identical (chỉ lệch line-number → edit riêng, same old_string OK).
- `bs = ev.budgetSummary` (`PeBudgetSummary|null`) @ PeDetailTabs.tsx:1226-1228. Null-guard `if(!bs) return` @:1298 → `bs` narrowed non-null tại render → `bs.budgetFrozen` typecheck OK.
- Header render @ PeDetailTabs.tsx:1350-1352: `<div className="bg-[#1F7DC1] px-3 py-2 text-[12px] font-bold uppercase tracking-wide text-white">Tổng hợp ngân sách trình ký</div>`. className `bg-[#1F7DC1]...` LẶP @:1931 (winners section) → anchor phải gồm text "Tổng hợp ngân sách trình ký" (unique).
- Pill pattern sync: `:588-594` header `flex items-center justify-between` + badge `inline-flex items-center gap-1 rounded-full bg-emerald-100 px-2 py-0.5 text-[10px] font-medium text-emerald-700`. Dùng amber variant cho frozen (blue header bar → amber pill đọc rõ).

## Plan 4 edit
1. types fe-user + fe-admin: +`budgetFrozen: boolean` cuối type PeBudgetSummary (comment [S133]). Edit RIÊNG 2 file (same old_string).
2. PeDetailTabs fe-user + fe-admin: header div → flex justify-between, wrap title `<span>`, +badge `{bs.budgetFrozen && ...}` amber pill "🔒 Ngân sách chốt tại thời điểm duyệt" (normal-case tracking-normal override header uppercase). Edit GIỐNG HỆT byte 2 file.

## Progress — ALL DONE ✅
- [x] Edit types ×2: `budgetFrozen: boolean` @ fe-user types:333 · fe-admin types:331 (edit riêng, same old_string; comment [S133]).
- [x] Edit PeDetailTabs ×2 (byte-identical): header div → `flex items-center justify-between gap-2`, title wrap `<span>`, +badge `{bs.budgetFrozen && (<span className="inline-flex shrink-0 items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-[10px] font-medium normal-case tracking-normal text-amber-800">🔒 Ngân sách chốt tại thời điểm duyệt</span>)}` @ both :1352. `normal-case tracking-normal` override header `uppercase tracking-wide` để badge text đọc thường. Layout non-frozen giữ nguyên (1 span trong flex = left-align).
- [x] git hash-object 2 PeDetailTabs EQUAL: `5534addb9a7887c00562a99ab1f52ed4ee77c0ca` (cả 2) — mirror giữ (baseline `931025f2` → post `5534addb`).
- [x] grep budgetFrozen = 4 hit: fe-user types:333 + fe-user PeDetailTabs:1352 + fe-admin types:331 + fe-admin PeDetailTabs:1352.
- [x] npm build fe-user EXIT 0 — 1939 modules, 19.84s, `index-DxCKQyJZ.js` 1534.07kB. Warn pre-existing (@import order + >500KB chunk + INEFFECTIVE_DYNAMIC_IMPORT realtime.ts).
- [x] npm build fe-admin EXIT 0 — 1950 modules, 8.75s, `index-DTUy4uPK.js` 1627.72kB. Warn pre-existing (same 3).

## Isolation audit (git status --short)
- Mine (4 target FE): fe-admin/fe-user × {PeDetailTabs.tsx, types/purchaseEvaluation.ts} — M ✓
- Run-folder: sub-implementer-frontend-1.md — ?? ✓
- NO src/Backend touched (grep Backend → none) ✓
- ⚠️ `.claude/governance/.session-counter.json` M = harness/session-tooling artifact, KHÔNG do tôi ghi (mọi Bash tôi chạy read-only: build→dist/ gitignored, hash-object, grep, status). Flag để em main không quy cho STAGE A.

## Note cho STAGE B (BE — implementer-backend)
- FE khai `budgetFrozen: boolean` (non-null) theo DTO chốt spec ②. BE PeBudgetSummaryDto phải append `bool BudgetFrozen = false` → serialize camelCase `budgetFrozen`. Field CHƯA ship BE → runtime `bs.budgetFrozen` undefined = falsy → badge ẩn an-toàn (KHÔNG vỡ UI, KHÔNG runtime error). Khi BE ship: DaDuyet+snapshot → true → badge hiện.
