Companion spec
Portfolio Specification
Structure of portfolio/portfolio.md: the file that records a brand’s product ranges, the naming and claim rules that govern them, and the Category Entry Points each range serves.
| Spec version | 0.1 |
| Status | Draft |
| Parent spec | brandbook-spec.md §4 (secondary files, type: portfolio) |
Theoretical basis: Jenni Romaniuk and Byron Sharp. A portfolio exists to cover Category Entry Points — a range that serves no CEP is a warning sign, and a CEP no range serves is unclaimed territory. The file makes that coverage inspectable: it is a CEP-coverage matrix, not a product catalogue.
Two boundaries keep it one:
- The PIM boundary. SKUs, prices, ingredients, and technical specifications MUST NOT appear in a portfolio file. The file governs how products are named, claimed, and mentally positioned — not what they contain or cost. That data belongs in a PIM or ERP system, exactly as narrative essays belong in
context/. Rationale: catalogue data changes at operational speed and would bury the brand rules under churn. - The sub-brand boundary. If a range needs its own Distinctive Brand Assets, voice, or anchor rules beyond naming and claims, it is not a range — it is a sub-brand. Give it a child package (parent spec §7) instead of a portfolio entry. Rationale: a portfolio entry has no governance surface of its own; forcing a brand into one hides rules from validation.
1. File layout#
The file MUST carry standard secondary-file frontmatter with type: portfolio. Its body is a sequence of range records. Each record is a ## heading (the range’s human name) followed by exactly one fenced ```yaml block and optional free prose.
- P-01. Range records MUST be fenced YAML blocks, one per range. Rationale: tooling extracts records by scanning fences, with no Markdown AST needed, mirroring the DBA inventory (D-01).
2. Range record fields#
id: range-original # REQUIRED. Unique in file. Pattern: range-[a-z0-9-]+
name: "Acme Original Forge" # REQUIRED. Canonical written form of the range name
names: # OPTIONAL. Localised forms, language code → name
de: "Acme Original Forge Extra Scharf"
status: core # REQUIRED. core | seasonal | test | phase-out
rule: >- # REQUIRED. One naming/usage rule, imperative, one sentence.
Always write the full range name on first mention; never abbreviate.
ceps: [CEP-01, CEP-02] # REQUIRED. CEP ids (C-03) this range serves
claims: # OPTIONAL. What may and may not be said about the range
allowed:
- "Aged in the smoke forge"
forbidden:
- "Boosts metabolism (health claim, AR-03)"
dbas: [dba-bottle-smithy] # OPTIONAL. DBA ids of pack/design assets from the inventory
scope: [US, GB] # OPTIONAL. Markets; default = all root markets
notes: "" # OPTIONAL. One line; longer prose goes below the block
Field rules:
- P-02.
idMUST match^range-[a-z0-9-]+$, be unique within the file, and MUST NOT be reused after retirement. Rationale: like anchor rules and DBAs, ranges are referenced by ID in approvals and prompts; recycled IDs corrupt history. - P-03.
name,status, andruleare REQUIRED.statusMUST be one ofcore | seasonal | test | phase-out;ruleis one imperative sentence a generator or approver can act on;namesMAY carry localised forms keyed by language tag. Rationale: a range without a naming rule invites the abbreviations and puns that erode a name’s memory structure. - P-04.
cepsis REQUIRED and lists the CEP ids (C-03) the range serves. An empty list is valid but validators SHOULD warn on it, on referenced ids that do not exist in the package’s CEP file, and on CEP ids that no range serves. Rationale: Romaniuk/Sharp — the portfolio’s job is CEP coverage; both an unanchored range and an unclaimed CEP are honest gaps worth surfacing, not conformance failures. - P-05.
claims.allowedandclaims.forbiddenare OPTIONAL lists of statements that may or may not be made about the range; forbidden entries SHOULD cite the anchor rule that bans them where one exists. Rationale: claims are where product copy most often breaks brand and legal rules; a citable list makes rejections auditable. - P-06. Records with
scopeapply only in the listed markets, each of which MUST be one of the rootmarkets(mirrors parent spec §6.5). Rationale: ranges, like assets, do not always travel. - P-07.
dbasreferences SHOULD exist in the package’s DBA inventory; validators warn on unknown ids. Rationale: a pack asset named only in the portfolio is invisible to asset governance.
3. Ordering#
Ranges SHOULD be ordered by importance; the top entries mirror the optional Portfolio section of BRANDBOOK.md. phase-out ranges SHOULD be kept at the end of the file rather than deleted. Rationale: the phase-out record prevents an agency rediscovering and re-promoting a range the brand is retiring.
- P-08. A portfolio file records ranges of the package’s own brand. Child packages (parent spec §7) declare their own portfolio; portfolios are never inherited wholesale (H-05). Rationale: coverage checks are per brand; an inherited portfolio would make them meaningless.