Example

Turn an hour of speech into units that walk back to timestamps

Pin a timestamped transcript by hash, cut it into units from exact spans, and see a proposal that names a line that does not exist refused with its reason.

An hour of speech is not an addressable thing. The chapter’s move is to make it one: a timestamped transcript becomes a hash-pinned source, and a unit is one or more exact spans of it. A proposer — a model, in practice — may suggest which lines form a unit, what role it has and what it depends on. It cannot supply the text: that is always the text at the spans.

Run it

git clone https://github.com/ernanhughes/project-language.git
cd project-language
git checkout 329660f679a5a87831f91fe1430c20ac9360dda8
npm ci
npm run example:talk

No host, no interface and no model are involved. The proposer is a scripted function and the transcript is one invented talk of 17 lines.

Expected outcome

The units are cut from the transcript, and one of them joins minute 4 with minute 53:

...
17 lines, 1286 characters, sha256 1ecff193254759fc…
  u-intro       other     [0:00-0:21]
  u-history     other     [3:15]
  u-scope       claim     [4:02] + [53:20]
  u-sync-sense  qualifier [4:30]
  u-quorum      other     [5:10]
  u-round       other     [6:00]           needs u-quorum
  u-proof       evidence  [12:40]
  u-benchmark   claim     [41:50-42:10]    needs u-scope
  u-clock-sync  evidence  [47:30]          needs u-scope

A proposal that names a line that does not exist is refused, and so is a unit that depends on it:

...
refused proposals:
  x-invented-line  UNKNOWN_LINE: no such line: 99
  x-needs-it       DEPENDENCY_NOT_ACCEPTED: x-invented-line

The unit’s text is the text at its spans, never what the proposer said:

...
A unit's text is the text at its spans, never what the proposer says. u-scope joins minute 4 and minute 53:
  "For the purposes of this talk, a fault means a crash and nothing worse. Good question. This result assumes bounded delays between machines. The title does not say that."

The text is derived, never supplied

decompose is where a proposal becomes a unit. The text is sliced from the source; a proposal naming a missing line, no line, a duplicate id, or a dependency that is not itself an accepted unit is refused with its reason.

export function decompose(parsed: ParsedTranscript, propose: Proposer): Decomposition {
  const proposals = propose(parsed.lines);
  const byLine = new Map(parsed.lines.map(l => [l.n, l]));
  const units: Unit[] = []; const refused: Decomposition["refused"] = [];
  const seen = new Set<string>();
  for (const p of proposals) {
    if (seen.has(p.id)) { refused.push({ id: p.id, code: "DUPLICATE_ID", detail: p.id }); continue; }
    seen.add(p.id);
    const ns = [...new Set(p.lines)].sort((a, b) => a - b);
    if (ns.length === 0) { refused.push({ id: p.id, code: "NO_LINES", detail: "a unit needs at least one line" }); continue; }
    const missing = ns.filter(n => !byLine.has(n));
    if (missing.length) { refused.push({ id: p.id, code: "UNKNOWN_LINE", detail: `no such line: ${missing.join(",")}` }); continue; }

And the unit’s own validation refuses a unit whose text is not the text at its spans — a property that holds for any unit, not only the fixture:

export function validateUnits(units: readonly Unit[], source: SourceVersion): UnitProblem[] {
  const out: UnitProblem[] = [];
  const ids = new Set<string>();
  if (sha256(source.text) !== source.sha256) out.push({ unit: "*", code: "SOURCE_HASH_MISMATCH", detail: source.id });
  for (const u of units) {
    if (ids.has(u.id)) out.push({ unit: u.id, code: "DUPLICATE_ID", detail: u.id });
    ids.add(u.id);
    if (u.source_id !== source.id || u.source_version !== source.version) out.push({ unit: u.id, code: "WRONG_SOURCE", detail: `${u.source_id}@${u.source_version}` });
    if (u.spans.length === 0) out.push({ unit: u.id, code: "NO_SPAN", detail: "a unit needs at least one span" });
    for (const s of u.spans) {
      if (!Number.isInteger(s.start) || !Number.isInteger(s.end) || s.start < 0 || s.end > source.text.length || s.start >= s.end)
        out.push({ unit: u.id, code: "BAD_SPAN", detail: JSON.stringify(s) });
    }
    if (!out.some(p => p.unit === u.id && p.code === "BAD_SPAN") && u.spans.length && sliceOf(source, u) !== u.text)
      out.push({ unit: u.id, code: "TEXT_NOT_SPAN", detail: "unit text is not the text at its spans" });
  }

Mechanism and limitations

Documented: the input format ([m:ss] caption text), the rule that the proposer cannot supply content, and the “judging pieces one at a time” failure are stated in the header comment of core/radar/src/attention/transcript.ts.

Observed: the run above. The transcript parsed to 17 lines and 1,286 characters with a pinned hash; a unit joined two spans 49 minutes apart; two proposals were refused with their reasons; and the joined unit’s text is the source text at those spans.

Not shown. Nothing here finds units: the proposals are scripted. There is no video, no audio and no slides — the input is a text transcript, and nothing is persisted. The local-window scorer in the same file is a deliberately naive baseline used for a constructed contrast; it is not a claim about any system that exists. Timestamps are checked for plausibility, not verified against a recording.

Canonical source and the transcript module .

Understand this example

Copy this prompt into your AI tool. No code runs here.

Apply this example

Copy this prompt into your AI tool. No code runs here.