> Rule-based brand-semantics audit. Detects (a) tokens used in forbidden contexts per their `$extensions.harness.brand.forbidden_contexts` metadata (BRAND-T001) and (b) UI copy containing phrases listed in `DESIGN.md ## Brand Rules → voice.forbidden_phrases` (BRAND-V001). The 4th composed verifier in `harness check-design`, alongside audit-component-anatomy, design-craft critique, and detect-design-drift.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Intense-Visions/harness-engineering --skill audit-brand-compliance --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Audit Brand Compliance?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/intense-visions-audit-brand-compliance-3dbceb92)More formats (shields.io, HTML) on the badges page.
# Audit Brand Compliance
> Rule-based brand-semantics audit. Detects (a) tokens used in forbidden contexts per their `$extensions.harness.brand.forbidden_contexts` metadata (BRAND-T001) and (b) UI copy containing phrases listed in `DESIGN.md ## Brand Rules → voice.forbidden_phrases` (BRAND-V001). The 4th composed verifier in `harness check-design`, alongside audit-component-anatomy, design-craft critique, and detect-design-drift.
## When to Use
- After authoring or editing `DESIGN.md ## Brand Rules` — verify the new constraints are enforceable on the existing codebase
- After adding `$extensions.harness.brand` metadata to a token — discover existing call sites in forbidden contexts
- As part of `harness validate` (fast-mode hook, gated by `design.audit.brandCompliance.enabled`)
- As the 4th composed verifier in `harness check-design` (the unified design check)
- Before a PR with UI copy or token-usage changes lands
- NOT for tone-by-context rules (deferred to v1.x — requires component-state inference)
- NOT for reading-level or sentence-length rules (deferred to v1.x — ship with tone-context)
- NOT for asset-usage rules (deferred to v1.x — requires image-tag scanning)
- NOT for semantic-token-alias enforcement (overlaps with detect-design-drift T001 — design after both have shipped)
- NOT for brand-rule authoring (use `harness-design` skill to draft DESIGN.md sections)
## Capability Roles
<!-- Capability seam: this skill participates in a real extension point whose three roles are named and concrete. A seam with only one role filled is accidental single-implementation lock-in. See harness-skill-authoring Phase 1C. -->
- **Defines (Service Definition):** the shared `Verifier<F, Cat, Meta>` interface (`packages/cli/src/shared/verifier.ts`); this was the 4th verifier whose addition triggered extraction of the interface.
- **Provides (Provider):** **this skill** — emits `AuditBrandOutput = Verifier<BrandFinding>` (`packages/cli/src/brand/index.ts`).
- **Consumes (Consumer):** `harness-design-pipeline` / `harness check-design`, which compose it generically via `VerifierRegistry`.
## Process
### Phase 1: LOAD — Parse the two input sources
1. **Read project configuration.** Check `harness.config.json` for:
- `design.strictness` — `strict` / `standard` / `permissive` (default `standard`)
- `design.audit.brandCompliance.enabled` — gate (default `true`)
- `design.audit.brandCompliance.rules.{tokenMisuse,voice}` — per-rule toggles
2. **Load `design-system/DESIGN.md` `## Brand Rules`.** The parser extracts:
- `voice.forbiddenPhrases: string[]` — used by BRAND-V001 in v1
- `voice.constant`, `voice.readingLevel`, `voice.maxSentenceWords` — parsed but unused in v1 (forward-compat)
- `toneByContext`, `assets`, `semanticTokenAliases` — parsed but unused (v1.x)
- Returns `null` when DESIGN.md absent or `## Brand Rules` section missing → BRAND-V001 silently skips.
3. **Load `design-system/tokens.json` `$extensions.harness.brand`.** Walks the DTCG token tree capturing per-token `role`, `approved_contexts`, `forbidden_contexts`. Returns `null` when no token carries the extension → BRAND-T\* silently skips.
### Phase 2: SCAN — Apply the two rule families
1. **BRAND-T001 — token misuse (regex-based).** For each token whose `forbidden_contexts` is non-empty:
- Find every reference to the token's dotted path in source (recognizes three forms):
- `tokens.X.Y.Z` (JS accessor)
- `var(--X-Y-Z)` (CSS var, kebab-cased)
- `'X.Y.Z'` / `"X.Y.Z"` (string literal)
- Inspect surrounding context (same line + nearest non-blank previous and next line) for the v1 context-vocabulary keywords: `cta`, `selection`, `focus`, `data-visualization`, `decorative`, `background`, `text`, `border`, `error`, `success`, `warning`.
- If a forbidden context matches: emit BRAND-T001.
2. **BRAND-V001 — forbidden phrases (TS Compiler API).** For each `.tsx`/`.jsx` file:
- Walk the JSX tree.
- For each `JsxText` node: case-insensitive substring scan for any forbiddenPhrase.
- For each `JsxAttribute` whose initializer is a string literal: same scan.
- Deduplicate per `(file, line, phrase)`.
### Phase 3: REPORT — Aggregate and surface
1. **Severity from `design.strictness`** (uses `severityFor`):
- `strict` — all findings `error`
- `standard` — BRAND-T001 `error` (declared violation), BRAND-V001 `warn` (copy nuance)
- `permissive` — all findings `info`
2. **Aggregate `bySeverity` and `byCode`** into the standard Verifier shape: `{ findings, summary, catalog, meta }`.
3. **Persist findings to the graph (when composed by check-design).** check-design routes brand findings through `DesignConstraintAdapter.recordFindings()` alongside anatomy / craft / drift. v1 uses the shared `VIOLATES_design` edge; v1.x may add a brand-specific edge.
## Harness Integration
- **`harness validate`** — Fast-mode hook gated by `design.audit.brandCompliance.enabled`. Degrades gracefully on failure (single warning; other checks continue).
- **`harness check-design`** — Composes brand as the 4th verifier alongside audit-anatomy, design-craft critique, and detect-design-drift. This is the canonical invocation path.
- **`mcp__harness__audit_brand`** — MCP tool. Input: `{ path, mode, files?, designStrictness?, rules? }`. Output: `{ findings, summary, catalog, meta }`. Consumed by check-design and the (future) design-pipeline orchestrator.
- **`DesignConstraintAdapter.recordFindings()`** — Generic graph persistence entry point. Brand findings reuse the adapter (no graph schema changes in v1).
- **`harness-design` skill** — Authors `DESIGN.md ## Brand Rules`. audit-brand-compliance is the matching enforcer.
- **`Verifier<F>` interface** — Extracted in this PR at the 4th-verifier threshold. Lives at `packages/cli/src/shared/verifier.ts`. Adding a 5th verifier requires only a type-alias declaration of conformance.
## Success Criteria
See `docs/changes/design-pipeline/audit-brand-compliance/proposal.md` for the full 34 success criteria. Highlights:
- DESIGN.md parser returns `null` when section absent (silent-skip pattern)
- Token-extensions walker returns `null` when no token carries `$extensions.harness.brand`
- BRAND-T001 fires on `tokens.X`, `var(--x)`, and `'X'` reference forms
- BRAND-T001 honors approved_contexts (no finding when context is allowed)
- BRAND-V001 fires on JSX text + string-typed JSX attributes (case-insensitive)
- BRAND-V001 deduplicates per `(file, line, phrase)`
- Verifier interface extraction: anatomy / drift / brand all declare structural conformance
- `harness check-design` test extended for 4-verifier composition (zero regressions)
- MCP tool count bumps 72 → 73
## Rationalizations to Reject
These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.
| Rationalization | Why It Is Wrong |
| ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "This copy says 'world-class' which sounds off-brand, so I'll flag it even though it isn't in `forbidden_phrases`." | BRAND-V001 fires ONLY on phrases declared in `DESIGN.md ## Brand Rules → voice.forbidden_phrases`. Inventing violations beyond the declared list is editorializing, not auditing. If the phrase should be banned, that is a DESIGN.md authoring change (via `harness-design`), not an audit finding. |
| "This token is clearly used decoratively, so I'll flag it even though `decorative` isn't in its `forbidden_contexts`." | BRAND-T001 fires only when a matched context keyword is in that token's declared `forbidden_contexts`, and honors `approved_contexts`. The policy lives in the token metadata — do not substitute your own judgment for the declared contract. |
| "This `.ts` file has a forbidden phrase in a string, so I'll flag it." | BRAND-V001 scans only `.jsx`/`.tsx` — user-visible JSX text and string-typed JSX attributes. `.ts`/`.js` and `.md` copy are a different audience and explicitly out of scope. |
| "`## Brand Rules` is missing from DESIGN.md, but I can infer the brand voice, so I'll audit anyway." | The DESIGN.md parser returns `null` when the section is absent, and BRAND-V001 silently skips. Likewise BRAND-T\* skips when no token carries `$extensions.harness.brand`. No findings without parsed inputs — a null resolver is not a verifier failure. |
| "This copy looks like an error state, so I'll infer the tone-by-context and flag a mismatch." | Tone-by-context inference is deferred to v1.x. v1 matches only the explicit context-vocabulary keywords against adjacent source text. Do not simulate component-state inference the audit does not yet perform. |
## Examples
### Example: Token used in forbidden context
**Input:**
`design-system/tokens.json`:
```json
{
"color": {
"brand": {
"500": {
"$type": "color",
"$value": "#3b82f6",
"$extensions": {
"harness": {
"brand": {
"role": "primary",
"approved_contexts": ["cta", "selection", "focus"],
"forbidden_contexts": ["data-visualization", "decorative"]
}
}
}
}
}
}
}
```
`src/Chart.tsx`:
```tsx
// data-visualization color palette
const palette = [tokens.color.brand.500, ...];
```
**Output:**
```
BRAND-T001 [error] src/Chart.tsx:2 — Token "color.brand.500" is used in forbidden context "data-visualization"
Fix: Token "color.brand.500" is not approved for the "data-visualization" context.
Use an approved token (allowed contexts: cta, selection, focus), or update
tokens.json $extensions.harness.brand if the policy is wrong.
```
### Example: Forbidden phrase in UI copy
**Input:**
`DESIGN.md`:
```markdown
## Brand Rules
### Voice
forbidden_phrases:
- "click here"
- "best-in-class"
```
`src/Cta.tsx`:
```tsx
export const Cta = () => <a href="/x">Click here</a>;
```
**Output:**
```
BRAND-V001 [warn] src/Cta.tsx:1 — UI copy contains forbidden phrase "click here" — declared at DESIGN.md ## Brand Rules → Voice → forbidden_phrases
Fix: Rewrite to avoid "click here". If the phrase is unavoidable for this context,
remove it from voice.forbidden_phrases (or scope the audit) — but the default
policy is that brand voice trumps convenience.
```
## Gates
- **No findings without parsed inputs.** DESIGN.md absent → BRAND-V001 skips silently. tokens.json `$extensions.harness.brand` absent on every token → BRAND-T001 skips silently. Either resolver returning null is NOT a verifier failure.
- **No `.ts`/`.js` file scans for BRAND-V001.** Only `.jsx`/`.tsx` (user-visible JSX). Doc copy in `.md` is a different audience.
- **No tone-by-context inference.** v1 only matches the explicit context-vocabulary keywords against surrounding source text. v1.x adds component-state inference.
- **No autofix.** audit-only. The matching `align-brand-compliance` fix-side skill is deferred until detect signals demand.
- **No graph schema changes.** v1 reuses `VIOLATES_design` via `recordFindings()`. v1.x may add `VIOLATES_brand` edge for queryability.
- **Strictness from config, not assumed.** Read `design.strictness` from `harness.config.json`; default `standard` if absent.
## Escalation
- **When BRAND-T001 false-positives on a far-context reference:** the v1 context inference is intentionally narrow (same line + adjacent non-blank). For a token used in a "background" context where the keyword appears 10 lines away, v1 misses it. v1.x adds richer context inference; for now, either widen the surrounding comment or accept the miss.
- **When BRAND-V001 false-positives on a substring (e.g., "as is" in "as issued"):** v1 uses substring match. Add word-boundary regex in v1.x. For now, rephrase the copy or remove the phrase from voice.forbidden_phrases.
- **When a project ships tokens with a different `$extensions` shape:** v1 reads only `harness.brand`. Document the actual shape your project uses and add it to the schema sketch in ADR 0028 — DTCG `$extensions` namespaces are vendor-prefixed and additions are forward-compatible.
- **When `harness validate` runtime exceeds 3 seconds:** Set `design.audit.brandCompliance.fastMode.maxFiles` to cap the scope. The MCP tool ignores the cap (`fast`/`full` equivalent in v1).
- **When the graph persistence fails:** Skip graph integration for that run; findings still appear in the report. The graph is a consumer, not a gate.
- **When you want tone-by-context rules today:** Manual audit until v1.x ships. Component-state inference (empty/error/success/loading) requires JSX-context analysis that's a separate brainstorm.
## Status
**v1 — in implementation.** See:
- Spec: `docs/changes/design-pipeline/audit-brand-compliance/proposal.md`
- ADR (input schema source): `docs/knowledge/decisions/0028-brand-guidelines-source-of-truth.md`
- Roadmap entry: part of the `design-pipeline` initiative in `docs/roadmap.md`
- Sibling rule-based audits: `audit-component-anatomy`, `detect-design-drift`
- Cross-cutting: extracts `Verifier<F>` interface at `packages/cli/src/shared/verifier.ts` (deferred until 4th data point — this is it)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!