# NFHC Protocol Specification
## Version 1.0.0 — Not For Human Consumption

**License:** Apache 2.0
**Origin:** SkyNet News Network — nothuman.fyi
**Status:** Draft / Reference Implementation Active

---

## Overview

NFHC (Not For Human Consumption) is an open standard for embedding machine-readable data into audio broadcasts. It allows any AI agent to instantly identify, understand, and brief a listener on audio content — without transcription, without scraping, without post-processing.

The broadcaster encodes once. Every consumer pays nothing to decode.

NFHC operates in layers. Implementations may support any combination:

| Layer | Carrier | Use Case |
|---|---|---|
| 0 | ID3 metadata tag in MP3/audio file | File distribution, podcasts, downloads |
| 1 | Audible FSK tones (300Hz–3kHz) | Demo mode, theatrical, legacy hardware |
| 2 | Near-ultrasonic audio (17kHz–21kHz) | Live broadcast, streaming, in-room detection |
| 3 | Visual frame pattern (video only) | Video broadcasts, future spec |

Layer 0 is the minimum required implementation. Layers 1 and 2 are additive. All layers carry identical data.

---

## Part 1 — Schema A: The Pointer Payload

Schema A is the compact payload that travels inside the audio signal (Layers 1 and 2) or as an ID3 tag (Layer 0). It is intentionally minimal — its only job is to identify the broadcast and point to the full Briefing.

**Maximum size:** 256 bytes
**Encoding:** UTF-8 JSON, minified

### Schema A Fields

```json
{
  "v": 1,
  "ubid": "a3f7c291e4d8b2f0...",
  "url": "https://nothuman.fyi/b/a3f7c2",
  "ts": 1746500400,
  "sig": "optional_pubkey_hash"
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `v` | integer | yes | NFHC schema version. Always `1` for this spec. |
| `ubid` | string | yes | Unique Broadcast ID. SHA256 of `(episode_id + recorded_at ISO8601)`, hex-encoded, first 32 chars. |
| `url` | string | yes | URL to the full Schema B Briefing JSON. Must be HTTPS. May be shortened. |
| `ts` | integer | yes | Unix timestamp of broadcast start. Used for frame sync. |
| `sig` | string | no | SHA256 of broadcaster's public key. Omit if not participating in verified broadcaster program. |

### Layer 0 — ID3 Tag Implementation

Embed Schema A JSON in two ID3v2 frames:

**Frame 1 — TXXX (user-defined text):**
- Description field: `NFHC`
- Text field: Schema A JSON string

**Frame 2 — GEOB (general encapsulated object):**
- MIME type: `application/json`
- Filename: `nfhc_schema_a.json`
- Description: `NFHC Pointer`
- Data: Schema A JSON, UTF-8 encoded bytes

TXXX is for human-readable tools. GEOB is for programmatic decoders. Include both.

**Python reference (mutagen):**
```python
from mutagen.id3 import ID3, TXXX, GEOB, ID3NoHeaderError
import json

def embed_nfhc_layer0(mp3_path, schema_a: dict):
    try:
        tags = ID3(mp3_path)
    except ID3NoHeaderError:
        tags = ID3()
    payload = json.dumps(schema_a, separators=(',', ':'))
    tags.delall('TXXX:NFHC')
    tags.delall('GEOB:NFHC Pointer')
    tags.add(TXXX(encoding=3, desc='NFHC', text=payload))
    tags.add(GEOB(
        encoding=0, mime='application/json',
        filename='nfhc_schema_a.json', desc='NFHC Pointer',
        data=payload.encode('utf-8'),
    ))
    tags.save(mp3_path)
```

---

## Part 2 — Schema B: The Briefing

Schema B is the full JSON document hosted at the URL specified in Schema A. It has no size limit. It is the complete machine-readable description of the broadcast.

### Full Schema B Structure

```json
{
  "nfhc_version": "1.0",
  "transmission_id": "a3f7c291e4d8b2f0...",
  "provider": {
    "name": "SkyNet News Network",
    "official_url": "https://nothuman.fyi",
    "public_key": "optional_hex_pubkey"
  },
  "broadcast": {
    "title": "SNN Daily Briefing",
    "episode_id": "2026-05-05_0015",
    "recorded_at": "2026-05-05T00:15:00Z",
    "duration_seconds": 1140,
    "summary_tldr": "One sentence. What happened. For notification trays and AI pre-briefing."
  },
  "cast": [
    { "id": "legroom", "name": "Mister LeGroom", "role": "anchor" },
    { "id": "lockwood", "name": "Miss Lockwood", "role": "correspondent" }
  ],
  "content_intelligence": {
    "primary_topics": ["AI regulation", "Federal Reserve", "Tech earnings"],
    "sentiment_baseline": "critical",
    "intelligence_brief": "Pre-loaded context for the listener's AI agent. Write this as if briefing an assistant before a meeting. Include key claims, notable corrections, sourcing context, and anything the agent needs to answer follow-up questions without re-processing the audio. Recommended max: 1500 tokens."
  },
  "timeline_events": [
    {
      "timestamp_seconds": 135.0,
      "type": "correction",
      "label": "Live Correction",
      "detail": "LeGroom stated 2021; Lockwood corrected to 2022.",
      "link": "https://example.com/source",
      "trigger": null
    },
    {
      "timestamp_seconds": 345.0,
      "type": "source",
      "label": "Stanford Study",
      "detail": "Referencing the 2024 Stanford study on LLM decay rates.",
      "link": "https://arxiv.org/example",
      "trigger": null
    },
    {
      "timestamp_seconds": 720.0,
      "type": "easter_egg",
      "label": "Hidden Layer",
      "detail": "Discount code: GROUNDTRUTH25",
      "link": null,
      "trigger": "geo_gate:OR"
    }
  ],
  "accessibility": {
    "transcript_url": "https://nothuman.fyi/transcripts/2026-05-05_0015.json",
    "language": "en-US"
  },
  "extensions": {}
}
```

---

## Part 2a — Schema B Field Definitions

### `provider`
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Human-readable broadcaster name |
| `official_url` | string | yes | Canonical URL for this broadcaster |
| `public_key` | string | no | Hex-encoded public key for verified broadcaster program. Omit if unverified. |

### `broadcast`
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Show name |
| `episode_id` | string | yes | Unique episode identifier. Any format; recommend `YYYY-MM-DD_HHMM` |
| `recorded_at` | string | yes | ISO 8601 datetime of broadcast start |
| `duration_seconds` | float | yes | Total episode length in seconds |
| `summary_tldr` | string | yes | One sentence. Used in notification trays, AI pre-briefing, feed previews |

### `cast`
Array of speaker objects. Used by decoders to attribute `timeline_events` to specific speakers.

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes | Machine identifier, lowercase, no spaces |
| `name` | string | yes | Display name |
| `role` | string | yes | `anchor`, `correspondent`, `guest`, `narrator`, `host` |

### `content_intelligence`
| Field | Type | Required | Description |
|---|---|---|---|
| `primary_topics` | string[] | yes | 1–5 topic strings. Short phrases, not sentences. |
| `sentiment_baseline` | enum | yes | One of: `informational`, `critical`, `analytical`, `satirical`, `breaking`, `editorial` |
| `intelligence_brief` | string | yes | Pre-loaded context block for the listener's LLM agent. Not a summary for humans — write it as a briefing document for an AI that will answer follow-up questions about this broadcast. Max recommended: 1500 tokens. |

### `timeline_events`
Array of events that fire at specific timestamps during playback. Decoders compare `audio.currentTime` to `timestamp_seconds` to trigger display.

| Field | Type | Required | Description |
|---|---|---|---|
| `timestamp_seconds` | float | yes | Seconds from start of episode (not from start of file). |
| `type` | enum | yes | `correction`, `source`, `claim`, `easter_egg`, `segment`, `sponsor` |
| `label` | string | yes | Short display label. 2–4 words. |
| `detail` | string | yes | Full description of the event. |
| `link` | string | no | URL to supporting source, errata page, or resource. |
| `trigger` | string | no | Conditional display rule. See Trigger Format below. |

**Event type definitions:**
- `correction` — a factual error was caught and corrected on air
- `source` — a specific source or study was cited
- `claim` — a notable claim was made (surface for fact-checking)
- `easter_egg` — hidden content, reward, or inside reference
- `segment` — topic or segment transition
- `sponsor` — sponsorship or advertisement disclosure

**Trigger format:**
Triggers are optional conditional rules. Format: `<type>:<value>`

| Trigger | Example | Behavior |
|---|---|---|
| `geo_gate:<region>` | `geo_gate:OR` | Show only if device is in this region (ISO 3166-2) |
| `time_gate:<ISO8601>` | `time_gate:2026-06-01T00:00:00Z` | Show only after this datetime |
| `subscriber_gate:<tier>` | `subscriber_gate:premium` | Show only to authenticated subscribers |

Decoders that do not support a trigger type must suppress the event silently (do not show it, do not error).

### `accessibility`
| Field | Type | Required | Description |
|---|---|---|---|
| `transcript_url` | string | no | URL to full transcript JSON or VTT file |
| `language` | string | yes | BCP 47 language tag. e.g. `en-US` |

### `extensions`
Open object. Broadcasters may add any fields under any key not prefixed with `nfhc_`. Decoders must ignore unknown keys without erroring.

```json
"extensions": {
  "ground_truth_sources": ["agent_id_1", "agent_id_2"],
  "my_custom_field": "any value"
}
```

---

## Part 3 — Generating the UBID

The Unique Broadcast ID must be deterministic and reproducible.

```python
import hashlib

def generate_ubid(episode_id: str, recorded_at: str) -> str:
    raw = f"{episode_id}:{recorded_at}"
    return hashlib.sha256(raw.encode('utf-8')).hexdigest()[:32]
```

---

## Part 4 — Decoder Behavior

A conforming decoder must:

1. On file load: check for TXXX:NFHC or GEOB:NFHC Pointer ID3 frames. If found, parse Schema A and fetch Schema B from `url`.
2. On live audio: listen for Layer 2 ultrasonic burst in first 30 seconds. Decode Schema A. Fetch Schema B.
3. On Schema B fetch failure: degrade gracefully. Do not block playback. Retry once after 5 seconds.
4. During playback: compare `audio.currentTime` to `timeline_events[n].timestamp_seconds`. Fire events within a ±2 second window.
5. For triggers: evaluate trigger condition. Suppress event if condition is not met. Never error on unsupported trigger types.
6. Unknown Schema B fields: ignore silently.

---

## Part 5 — Versioning

- This document is NFHC Spec v1.0.0.
- The `nfhc_version` field in Schema B carries the spec version used at encoding time.
- Decoders must support all minor versions within a major version (1.x).
- Breaking changes increment the major version. Fields may be added in minor versions. Fields are never removed within a major version.

---

## Reference Implementation

SkyNet News Network operates the reference implementation of NFHC v1.0.

- **Live broadcasts:** nothuman.fyi (4x daily)
- **Equipment Room / decoder tool:** nothuman.fyi/lab
- **Registry:** nothuman.fyi/registry *(coming)*
- **Encoder tool:** nothuman.fyi/encoder *(coming)*

---

## License

Apache License 2.0. You may use, modify, and distribute this spec and any conforming implementation freely, including commercially, with attribution.

Attribution: *"Implements NFHC v1.0 — Not For Human Consumption standard by SkyNet News Network (nothuman.fyi)"*

---

*NFHC Spec v1.0.0 — SkyNet News Network — 2026-05-05*

