What the Quỹ Hoa Mặt Trời voice actually sounds like, and why it sounds that way — the trustee instructions, the field-team corpus (N=50), and the brand rules they crystallised into.
Trustee brand feeling · 2026-05-27
Warm · Human · Uplifting · High-quality
Not pity-based. Dignity, never pity. The voice of a real community organisation telling true stories, not running a campaign.
Read aloud at a school event, the people in the post should recognise themselves.
Positioning anchor · the mission spine
Education-focused charity in Vietnam
Not just scholarships. The Foundation works through an 8-petal holistic-development model: financial support + skills + confidence + social-emotional growth + real-world exposure.
Every caption ties back to a petal. A piece that reads as generic "helping poor kids" has missed the position.
Cùng em tiến bướcNâng bước tương laiTrao gửi yêu thương
The 8-petal model — the position trustees ask every post to reflect
Source: Knowledge/Brand/program-model.md · official deck filed 2026-05-21.
Each petal is also a ready Stream-B content theme.
Hỗ trợ học tập — học bổng, dụng cụ, khích lệ tinh thần học tập.
Thuyết trình & tranh luận — sinh hoạt kỹ năng hàng tháng.
Cảm xúc & ứng xử — SE assessments, ứng xử tích cực.
Suy ngẫm & sáng tạo — viết, vẽ, cuộc thi sáng tác.
Sức khỏe thể chất — hội thao thường niên, nhảy dây, đồng đội.
Thế giới quan — tham quan trải nghiệm hằng năm.
Định hướng nghề nghiệp — tham quan doanh nghiệp, gặp chuyên gia.
Lan tỏa yêu thương — các em đi phụng sự cộng đồng.
Why this matters for voice: the outcome-for-the-child beat in every Stream-A caption maps to one of these 8 petals. Not naming a petal in the post itself — naming the kind of outcome (a skill, a confidence moment, an exposure, an SE growth) that the petal predicts.
The four-beat story shape (Stream A · event posts · 80–140 words VN)
Trustees, 2026-05-27: "strong hook, clear outcome/meaning, donor-friendly close, not generic."
Codified in .claude/rules/brand-voice.md § Story shape and Knowledge/Brand/system-prompt.md.
1
Strong hook
One line. A person, a place, or a number that becomes a scene.
Never: date stamp, process noun (Buổi sinh hoạt…), salutation formula (Quỹ xin gửi…).
2
Why it matters
One short sentence connecting the moment to the programme's purpose.
3
Outcome for the child
Required. Verb-led. In the child's own agency — skill, confidence, exposure, SE growth, a next step.
Not "the volunteers were moved." The outcome is for the child.
4
Donor-friendly close
An achievable action — follow, share, attend, volunteer — or a light reader question. Specific to the moment.
No donation ask until the Foundation supplies approved CTA wording.
Sentence-level signatures (from N=50 in Kho bai.xlsx → Kho content)
These rhetorical moves appear in both first-drafts and trustee-edited finals. They are the voice — not AI tells.
Two clusters: A · reportorial · Stream AB · contemplative · Stream B (QA's voice).
S1 · the "không chỉ X, mà Y" reframe
The single most common move. Hook, body, or pivot.
"Kiên trì — không phải là không biết mệt. Kiên trì là khi đã mệt, vẫn chọn 'cố thêm một chút nữa'."— corpus #2
"Mỗi giải thưởng không chỉ là một tấm bằng, mà là một câu chuyện về ý chí và niềm tin."— corpus #7 (32 em – 32 giải)
S2 · the cascading parallel trio
Three (or four) short lines, same opener, different completion. The defining beat of Cluster B.
"Có em mang về một ước mơ mới. / Có em mang về một câu hỏi lớn về tương lai. / Có em chỉ mang về một suy nghĩ rất đơn giản…"— corpus #30
S3 · the "có những X…" observation
A soft entry into a generalisation. Almost always followed by S1 or S2.
"Có những đứa trẻ lớn lên sớm hơn tuổi."— corpus #34
"Có những thay đổi không đến từ những điều quá lớn lao."— corpus #39
S4 · the "đủ" cluster
"Đủ" as a standalone adverbial, repeated to define what a moment needs.
"đủ kiên nhẫn / đủ an toàn / đủ lâu / đủ thời gian / đủ những người sẵn sàng đồng hành"— corpus #23, #31, #36
S5 · the closing reader question
~40 of 50 entries. The strongest single structural signature of the whole corpus.
"💛 Theo bạn, trẻ nên được khen vì thành tích, hay vì quá trình cố gắng?"— corpus #22
"💛 Nếu là bạn, bạn sẽ nói gì với một đứa trẻ đang nghĩ rằng mình không đủ giỏi?"— corpus #24
Lexicon fingerprint
Recurring vocabulary across drafts and edits.
Verbs: đồng hành · lan tỏa · gieo · nuôi dưỡng · chắp cánh · thắp · ươm · vững bước · trỗi dậy · tin rằng.
Nouns: hành trình · ước mơ · niềm tin · kiên trì · khoảnh khắc · ánh mắt · nụ cười · hạt mầm · nội lực · mái nhà · mỗi em.
Audience markers: các em (children) · em (one child) · con (parent voice) · chúng tôi (Foundation) · bạn (reader).
The hard rules — what the voice is not
1 · No pity / poverty-porn
No "tội nghiệp", no helpless framing, no donor/volunteer as hero. People are agents in their own story.
Non-overridable. Gate 4 + gate 8.
2 · No em-dash / en-dash
No — and no – in prose. Use comma, semicolon, parentheses, or split.
The single most reliable AI tell in published copy. brand-voice-editor rewrites every em-dash on the Stream-A pass.
3 · No bureaucratic opening
No date stamp, no process noun, no "Quỹ xin gửi lời chúc mừng…".
Strongest trustee edit pattern in the corpus (rows 12, 16, 46).
4 · No fabricated quote or number
Quotes verbatim and attributed. Numbers traceable to a Foundation record (logged in STATUS.md → claim_sources[]).
Gate 6 (claim-checker) fires only when a post asserts a number or a CTA.
5 · No donation CTA (yet)
Until the Foundation supplies approved CTA + banking wording, captions don't carry an ask.
"Donor-friendly close" means the shape: follow, share, attend, volunteer.
6 · Restraint on emoji
🌻 as paragraph anchor · 💛 at the closing question · ✨ for an insight beat. Never mid-word, never triple-stacked.
Editor call 2026-05-27 — no strict number, but not more emoji than blank lines.
Where the rules come from — a trustee edit, side-by-side
Corpus row 12 · "32 học sinh – 32 giải": the canonical example of E1 (strip the bureaucratic opening) and E5 (convert dry congratulations into momentum poetry).
✏️ Bài gốc — first draft, field-team
Quỹ Hoa Mặt Trời xin gửi lời chúc mừng nồng nhiệt tới Trường THPT Lương Thế Vinh — ngôi trường đã có 32 học sinh đạt giải học sinh giỏi cấp tỉnh năm học 2025–2026.
Mỗi giải thưởng là một câu chuyện về sự cố gắng, kiên trì và niềm tin của thầy cô, gia đình và các em…
Failures: bureaucratic salutation lede · long single-paragraph body · em-dash · no scene.
🌻 Bản biên tập — trustee final
32 học sinh. 32 giải thưởng học sinh giỏi cấp tỉnh.
Một con số khiến ai nghe cũng phải dừng lại.
Nhưng phía sau con số ấy không chỉ là thành tích, mà là hàng trăm giờ học, là những lần không bỏ cuộc, là sự đồng hành bền bỉ của thầy cô. ✨
How this signal lands in the system: the diff above (and 5 other pairs in the corpus) is captured in
Knowledge/Brand/voice-signatures.md as Signal 1 (bureaucratic openings get rewritten) and
Signal 2 (literary flourish pruned, names + numbers kept). Trustee instructions from the deck review feed
trustee-feedback-log.md. Both files are read by every producer agent at draft time.
2
How a story is written, reviewed, and audited
From "bullets + pictures" → caption draft → seven automated QC gates → a manual safeguarding sign-off → Editor approval. The same four-beat story shape and hard rules apply at every stage.
2.1 · How a Stream-A caption is developed
Rule (Editor, 2026-05-28): bullets + pictures, not pictures alone. The Coordinator supplies a factual spine via the brief form;
Claude composes around it. The model never guesses load-bearing facts from photos.
Input · what Claude sees
brief.yaml — bullets from the Coordinator form (activity, school, date, programme, outcome, named people, quotes, sensitive flags).
copy/facebook.md — 80–140 words VN, blank line between paragraphs.
copy/web.md — same beats, longer body.
DRAFT — INTERNAL marker at top; stripped only at pack time.
EN block only when milestone: true.
2.2 · A worked example — Stream-A draft from a real brief
Fictional but representative — based on corpus row 16 (Đại An · "Câu hỏi phụ có thưởng").
brief.yaml (Coordinator input)
activity_type: Sinh hoạt kỹ năng hàng thángschool: THCS Đại Anevent_date: 2026-04-18program: Cùng em tiến bướcevent_summary: |Buổi sinh hoạt chủ đề "Kiên trì — không bỏ
cuộc". Các em xem video, thảo luận, viết
câu trả lời lên 22 bảng nhỏ. Có 14 câu
được chấm điểm cao, 5 câu được giải
thưởng nhỏ. Cô Hiệu trưởng dự cùng.named_people: |Thầy Nguyễn Minh Đức — Hiệu trưởngquotes: |"Bắt đầu thì dễ, đi đến tận cùng mới khó."
— câu khẩu hiệu buổi sinh hoạtoutcome_for_child: |Các em mạnh dạn nói ra suy nghĩ của mình
trước cả lớp; nhiều em ngày thường rụt rè
đã chủ động viết câu trả lời lên bảng.petal_anchor: 2 — Thuyết trình và tranh luậnsensitive_flags: []coordinator_name: Quỳnh Anh
copy/facebook.md (Claude draft)
> DRAFT — INTERNAL. Chưa duyệt; không phân phối.
🌻 "BẮT ĐẦU THÌ DỄ, ĐI ĐẾN TẬN CÙNG MỚI KHÓ." 🌻
Một dòng chữ trên bảng. 22 chiếc bảng nhỏ. 14 câu trả lời được chấm điểm cao, 5 câu được giải.
Buổi sinh hoạt kỹ năng tháng này của lớp Cùng em tiến bước tại THCS Đại An không xoay quanh điểm số. Nó xoay quanh việc dám viết ra một suy nghĩ của riêng mình.
✨ Có những em ngày thường rất ít nói, hôm nay lại là người chủ động cầm phấn đầu tiên. Có em viết một câu ngắn, rồi nán lại rất lâu để gạch dưới một chữ. Khi Thầy Hiệu trưởng Nguyễn Minh Đức dừng đọc, cả lớp lặng đi một nhịp, rồi vỗ tay.
Quỹ tin rằng kiên trì không phải là không biết mệt; kiên trì là khi đã mệt, vẫn chọn cố thêm một chút nữa, trước mặt cả lớp.
💛 Còn bạn, bạn nhớ nhất một câu trả lời nào của tuổi học trò?
5brand-voice-editorTerminology / mission consistency — programme names exact (Cùng em tiến bước, etc.); 8-petal positioning visible.WARNING
6claim-checkerClaims — only fires if the post asserts a number or a donation CTA. Number must trace to a Foundation record.CONDITIONAL
7brand-voice-editorPlatform-policy fit — per-channel format, 4–5 photos, 9:16 reframe is human, no IG output while deferred.BLOCKING
8safeguarding-signoffNamed manual safeguarding sign-off — dignity + appropriateness for sensitive subjects. Records SAFEGUARDING: cleared by <name> at <ISO> in STATUS.md.MANUAL · NEVER OVERRIDDEN
Gate 8 is the firewall. Never automated, never overridden by a non-safeguarding role, never collapsed into the Approver role.
The only programmatic backstop is the route-regression rule: a bundle that reaches awaiting-approval
with empty gate_findings[] is flagged as a regression.
2.4 · The audit trail — what STATUS.md captures
Every transition is appended to Sandbox/posts/<slug>/STATUS.md and mirrored into index/registry.sqlite (WAL, nightly file-copy backup) as the system of record for asset → rendition → caption → post lineage.
---event_slug: 2026-04-18__dai-an-cau-hoi-phustream: Astate: awaiting-approvalassignee: editorlast_updated: 2026-04-21T09:14:00+07:00gate_findings:
- gate: 3-brand-voicestatus: passednote: "hook is quote-as-scene; 121 words; 0 em-dash"
- gate: 4-dignitystatus: passednote: "outcome beat present, child agency clear"
- gate: 6-claimsstatus: no-opnote: "no impact number asserted"dignity_flags: []claim_sources: []override_log: []SAFEGUARDING: cleared by Hằng at 2026-04-21T09:11:00+07:00
---# Reviewer notes
- 5 photos shortlisted, 4 in renditions/fb (Editor decision on 9:16 reframe pending).
- Coordinator confirmed Thầy Đức's name is OK to print (named_people list).
- Suggested schedule: 2026-04-22 19:00 +07 (Tuesday evening, weekly cadence slot).
What this enables: every bad post that ships, every override, every gate-3 correction is one line in
_system/runs/qc-log-<YYYY-MM>.jsonl. Monthly, the top 2 recurring corrections become a template or
field-card change — that is the quality ratchet. The quality-auditor agent reports the
trailing-30-day mix (80/20 value:ask), cadence, accessibility coverage, dignity, safeguarding KPI, and journey-anonymity in
/system-review. It does not gate publication; it audits after.
3
The full workflow — from the brief form to the published log
Ten stages. Three roles never collapsed (Coordinator · Approver · Safeguarding). Phase A: nothing leaves the workspace without /approve.
Stage 3 · The Coordinator brief form — the spine of every post
Google Form on the Foundation's domain. Phone-friendly, <5 min to fill. Responses land in a Sheet under
08_Phieu-thong-tin-bai-dang/ on the Shared Drive; tools/intake_brief.py
writes a brief.yaml into the matching event folder. No required fields at the form;
downstream spine validation (activity, school, date, outcome) lives in intake_brief.py.
🌻 Phiếu thông tin bài đăng — Quỹ Hoa Mặt Trời
① Stream A — Thông tin sự kiện
Sinh hoạt kỹ năng · Cuộc thi viết · Thể thao · Tham quan trải nghiệm · Tham quan doanh nghiệp · SE assessment · Lan tỏa yêu thương · Thăm gia đình…
THCS Tam Thanh · THCS Đại An · THCS Tân Khánh · THCS Vĩnh Hào · THPT Lương Thế Vinh · THPT Nguyễn Bính · …
2026-04-18
Cùng em tiến bước · Nâng bước tương lai · Trao gửi yêu thương
Buổi sinh hoạt thứ 4 của lớp Cùng em tiến bước. Các em được học chủ đề Kiên trì, thảo luận theo nhóm, tự thiết kế poster. Có cô Hiệu trưởng dự cùng…
② Stream A — Người và lời nói
Cô Bùi Thị Nga — Hiệu trưởng THCS Tam Thanh Em Phạm Thanh Quyền — lớp 8A
"Em không cần giỏi hơn ai cả. Em chỉ cần đừng bỏ cuộc với chính mình." — cô Hương, GV chủ nhiệm
③ Stream A — Điều gì là điểm sáng? outcome beat · trustee requirement
Các em đã dám đứng trước lớp thuyết trình lần đầu tiên. Một em ngày thường rất rụt rè đã chủ động kể về ước mơ của mình.
1 Hỗ trợ học tập · 2 Thuyết trình & tranh luận · 3 Cảm xúc & ứng xử · 4 Suy ngẫm & sáng tạo · 5 Sức khỏe · 6 Thế giới quan · 7 Nghề nghiệp · 8 Lan tỏa
④ Stream B — Bài chia sẻ / nhận thức (bỏ qua nếu là bài sự kiện)
Kết nối cộng đồng · Tư duy giáo dục · Hậu trường, testimonial · Dữ liệu tổng quan · Dữ liệu sau hoạt động · Dữ liệu theo hành trình · Triết lý Quỹ HMT…
Trẻ nhút nhát không phải vì thiếu khả năng, mà vì chưa từng được tin rằng mình xứng đáng được thử.
⑤ Link tới ảnh
https://drive.google.com/drive/folders/…
⑥ Lưu ý đặc biệt safeguarding
☐ Hoàn cảnh khó khăn của một em cụ thể · ☐ Mất mát / biến cố trong gia đình · ☐ Sức khỏe · ☐ Chưa có sự đồng ý dùng ảnh · ☐ Trường yêu cầu kiểm tra trước · ☐ Khác…
Bất cứ điều gì khác — câu chuyện hậu trường, lý do tổ chức, mong muốn đặc biệt của trường, hoặc "không cần nhắc đến X".
Quỳnh Anh · Hằng · c An…
3.3 · The 10-stage SOP — owner, action, definition of done
Source: RUNBOOK.md. Three roles never collapsed: Coordinator ≠ Approver ≠ Safeguarding Sign-off.
#
Stage
Owner
Tool / skill
Definition of done
1
Field capture
Photographer
—
Only the agreed shot-list; dignity respected; nothing posted by the photographer.
2
Drive upload
Photographer
01_Tai-lieu-thuc-dia/<YYYY-MM-DD>__<slug>/
Folder shape correct; uploaded within 48h.
3
Brief form
Coordinator
Google Form → Sheet 08_Phieu-thong-tin-bai-dang/
Spine fields filled: activity · school · date · outcome.
awaiting-approval→rejected→_rejected/ · reason logged for autoimprove
The publish.yaml pin:channel-publisher is never cron-triggered in Phase A.
publish_pack.py only runs if state: approved and gate-1 is clean.
It strips the DRAFT marker, emits the renditions plus a single human-readable post sheet per channel under
Sandbox/_review-prints/<slug>/, and flips state to packed.
A human still does the Facebook post.
3.6 · After publication — logs, ratchet, monthly recap
Per-bundle audit
STATUS.md · state machine + gate findings + overrides
autoimprove · proposes challenger prompts from QC log + rejections
auto-optimize · eval ratchet — promotes on ≥60% win, never protected agents
/recap · monthly bilingual impact recap → website
The Phase-A absolutes (non-overridable): no hook, cron, agent or skill publishes without an explicit
/approve. The safeguarding sign-off is never automated and never overridden by a non-safeguarding
role. /setup-schedules refuses to register any channel-publisher job while
current_phase: A. The firewall holds: no data leaves this workspace.
4
The photo-editing standard — what published chrome actually looks like
Corpus-calibrated from the 13 trustee-approved finals in Trang tính3. Stream-A photos ship with a single composite chrome unit — yellow gradient wash + bottom-left logo + bottom-right tagline. Stream-B uses a different template family entirely.
4.1 · Two categories of editing — corrective vs presentational
Codified in .claude/rules/image-polish.md. The polish-vs-fabrication line is the load-bearing rule; the chrome layer is the second editing pass that happens after polish.
① Category 1 — pixel polish (AI corrective)
Engine: Gemini Nano Banana Pro (model gemini-3-pro-image-preview). Opt-in, paid cloud. The image still shows the same moment.
Allowed: exposure, white balance, contrast, denoise, sharpen, mild upscale, clutter removal, background blur, privacy blur on bystander faces.
Forbidden: face beautification, fabricated scene elements, changing what a subject is doing or holding, compositing two moments, "restoring" detail the camera didn't capture.
Every polished file writes a recipe sidecar: model id, full verbatim prompt, before/after SHA-256, system-prompt hash. Gate 8 reviews any bundle with ai_polished: true.
② Category 2 — brand chrome (overlay)
Engine: Pillow + project fonts, free, deterministic, regenerable from a recipe. No AI in this step.
Allowed: logo + watermark, gradient wash, tagline lockup, picture frame, programme bug, end-card / outro graphic.
Discipline: brand palette only · ≥4.5:1 contrast · logo never over a face · one composite unit, no double-stacking on top of it.
No ai_polished flag; the chrome layer is presentation, not pixel synthesis. Records all parameters + tagline string in the rendition recipe so the look is regenerable.
4.2 · Stream-A photo chrome composite — the corpus standard
Calibrated from all 13 Stream-A finals in Trang tính3. The four elements below are one indivisible unit, applied to the hero photo of every event piece.
Anatomy of the composite
photo subject (face-aware crop)
hoa mặt trời QUỸ TỪ THIỆN
Không chỉ trao học bổng — chúng tôi trao cơ hội trưởng thành.
5:4 landscape
Canvas · 5:4 landscape, ~1440 px on the long edge.
Wash · yellow #FED138 → α 0, ~14° diagonal sweep, height 42% of canvas, peak α 0.65 at bottom-left.
Logo · bottom-left, 8.5% canvas width, 3.5% inset. No white chip — the wash provides contrast.
Tagline · bottom-right, Playfair Display SemiBold ~2.8% of canvas height, white with navy shadow, right-aligned, line-height 1.55.
Corpus reference · default stock tagline
Hương Sơn, Trang tính3 row 2. The default "Không chỉ trao học bổng — chúng tôi trao cơ hội trưởng thành." tagline appears on 9 of 13 trustee-approved finals.
4.3 · Two more references — per-event override + Stream-B card
Per-event tagline override · Đại An "Bữa cơm"
Same composite, different tagline. When the brief supplies a short 2-line tagline (here: "Bữa cơm nhỏ / Tình thần lớn."), it replaces the stock string for that event series.
row-07/image3.png · brief.yaml field tagline: supplies the override
Stream-B quote card · different template family
Stream-B contemplative posts ship as a typographic card, not a chromed photo. Cream background, navy Playfair Display, teal ellipse outline, top-centre logo, no tagline. Square 1:1.
row-13/image15.png · Stream-A composite never applied to Stream-B
4.4 · The pipeline reproduces the standard — raw → chrome composite
tools/media_retouch.py with the corpus-calibrated CHROME_DEFAULTS (2026-05-28). Raw photo on the left, the same photo through the pipeline on the right. No prompts, no AI, no fabrication — just smart-crop + gradient wash + logo + tagline.
📷 Raw source
2024-05-19 HMT × Hope School Bana visit. EXIF/GPS already stripped at gate 2.
🌻 After media_retouch.py
Wins: 5:4 smart-crop · gradient wash anchored bottom-left · logo lockup at 3.5% inset · default tagline right-aligned in Playfair Display SemiBold · recipe sidecar records every parameter for regenerability.
4.5 · The four-step editing sequence inside Stage 5 (/curate)
What page 3 collapses into one box ("Stage 5 · Curation · media_triage.py · media_retouch.py") actually runs four ordered sub-steps. The first is mandatory and non-overridable; the third is opt-in paid.
① Sanitise
media_sanitise.py
EXIF + GPS strip on every original. exiftool wrapper; hard-fails if exiftool is missing (gate 2 cannot be silently downgraded).
Non-overridable · free · deterministic.
② Triage
media_triage.py
Cull 7–30 raw → 4–5 keepers. Pillow HighFreqSharpness baseline + optional pyiqa-BRISQUE + imagededup PHash clustering + MediaPipe face boost.
Free · 4–5 photos preferred · 7 max (platform-policy).
③ Polish paid, opt-in
photo_polish.py
Gemini Nano Banana Pro corrective polish. Hard-coded system prompt forbids fabrication. Records full prompt + before/after hash + system-prompt hash in the recipe.
Skipped when GEMINI_API_KEY is absent · gate 8 reviews.
④ Retouch + chrome
media_retouch.py
Face-aware smart-crop → per-channel renditions → chrome composite. Wash + logo + tagline as one unit. Recipe sidecar per rendition.
Free · deterministic · regenerable.
4.6 · What the recipe sidecar records — every rendition is regenerable
Every output writes a *.recipe.json next to it. The recipe is the regenerability contract: original photo + recipe → byte-identical rendition. AI-polished outputs additionally carry a YAML polish recipe so the AI step is auditable.
Pillow chrome rendition recipe
tool: "media_retouch"source: "source/img-01.jpg"spec:
channel: fbpurpose: feed-5x4aspect: [5, 4]longest_edge: 1440format: JPEGfocus: [0.52, 0.41]# mediapipe face centrechrome:
wash_color: [254, 209, 56]wash_alpha: 0.65wash_height_pct: 0.42wash_angle_deg: 14.0logo_width_pct: 0.085tagline_size_pct: 0.028tagline: "Không chỉ trao học bổng — chúng tôi trao cơ hội trưởng thành."watermark: null# legacy path off when chrome is on
Polished output is preserved alongside the recipe; unlike the Pillow chrome recipe it is not bit-for-bit regenerable (generative model).
Where the standard is documented:
spec → .claude/rules/image-polish.md § Stream-A photo chrome composite (corpus-calibrated 2026-05-28) ·
canonical targets → Knowledge/Brand/assets/social-templates/stream-a-chrome-target.png + stream-a-chrome-target-per-event-tagline.png + stream-b-quote-card-target.png ·
tagline strings → Knowledge/Brand/brand-assets.md § Stream-A photo chrome ·
implementation → tools/media_retouch.pyCHROME_DEFAULTS + apply_chrome_composite() ·
field findings → _system/notes/kho-content-2026-05-27-observations.md §5.
Pre-pilot blockers:
(1) GEMINI_API_KEY is not yet in .env — Category-1 polish runs only via --polish-fake until the Foundation mints a key.
(2) The logo redesign flagged in brand-assets.md 2026-05-27 is still pending; current renditions use hmt-logo-on-dark.png as supplied.
(3) End-to-end Crawl-pilot on one real event hasn't run yet — the chrome composite was validated on a 2024 Đà Nẵng raw photo + synthetic selftest, not on a 2026 Vụ Bản event.