Evaluation report · Content pipeline
A single createContentLoader now reads three collections and emits one normalized card shape. The contract is deliberately strict: directory indexes, templates and drafts are excluded, verdicts are enum-checked, and every URL is unique. A malformed entry should disappear with a null, not render a broken card.
Every card rendered by
<CardGrid>comes from one loader, and every frontmatter record that reaches the client satisfies the same schema.
| Field | Rule | Failure mode |
|---|---|---|
url | Non-empty, unique, no trailing slash | Duplicate keys, index pages as cards |
kind | Derived from path: work / case / eval | Wrong badge and wrong index filter |
lang | Derived from /zh/ prefix | English cards leaking into Chinese pages |
title | Non-empty string | Blank card heading |
tldr | Optional string | Missing summary |
capabilities | Optional string list | Tag list collapse |
metrics | Optional { label, value } list | Metric row renders undefined |
verdict | pass / conditional / fail | False authority badge |
date | Optional ISO YYYY-MM-DD | Invalid <time> value |
draft | true excludes the entry | Unfinished content published |
work, case, eval × en, zh)./ (index pages) and the template slug.verdict is one of the three allowed values or null.label and value.| Check | Result |
|---|---|
| Collections loaded | 3 |
| Schema errors | 0 |
| Duplicate URLs | 0 |
| Index / template leaks | 0 |
| Verdict values outside enum | 0 |
| Broken card links | 0 |
Pass. The loader is the only producer of card data, and both indexes render from it without page-specific mapping code.
Residual risk: the loader normalizes frontmatter but does not validate prose. A card can be truthful in shape and still make an unsupported claim. That is why every report also carries a body with reproduction steps.