Skip to content

The transcript model

A transcript is not a file. It is an ordered set of line records, and every line has an id computed from what the line is: the transcript it belongs to, who spoke, when, and the text itself. The containers a transcript arrives in — the archive's plain text, the log-saver add-on's JSON, the lines a game-side consumer sends over the bridge — are three ingest formats of that one model.

This matters because everything else in the estate points at lines. A consent denial names lines. A seal covers a range of them. A token, a scene and an annotation all anchor to one. If a line were addressed by its position in a file, then reformatting the file, re-importing the evening from another source, or rejoining a message the chat cap had split would move every address after it — and a denial written last year would silently release words somebody withheld.

What a line carries

Field Meaning
id the digest of the transcript, the speaker, the instant and the text
seq the line's order within the transcript, from zero. Not part of the id
speaker a nick, the narrator, or unknown — see below
style dialogue, narration, or system
channel the channel the line was said on, as its container names it
receiver whom a directed line was addressed to, when it was directed
ts the instant, when the container carries a date
clock the wall clock the container showed, when it showed one and no date
text the line's own words, with the speaker's name cut off the front
source which container it was read from

Three speakers, and the third is not the first two. A nick is a voice the container names. The narrator is the narrator speaking as themselves, which only a container that records commands can tell you. Unknown is a line whose voice its container does not say — and that is not the same as narration by the narrator. A pasted chat log that lost its signatures has lines somebody said and nobody can name; crediting those to the narrator would put everybody's words in one person's mouth.

The three formats, and what each cannot recover

The archive's plain text. Stamps ([21:51], [15:42:08]), an optional channel tag, and a signature (Nick: text, or «Nick» text from the old interface). It has no date: a stamp is a wall clock, so no line from this container gets an instant. The clock is kept as written so the human form can be printed back, and the ids fall back to including seq — which the transcript reports once, rather than leaving you to notice a field is empty.

The add-on's JSON. One record per message, with a unix date, so this is the container that yields real instants and the strongest ids. It also carries what the others cannot: the narrator of record, the cast, the scene the recorder filed, and the channel a message was routed on.

The bridge. A consumer may assert the speaker, the channel, the timestamp, the text and the style of a line it sends. Anything else it offers is a proposal recorded under that consumer's own name, never a fact about the transcript.

The container is decided by the bytes, never by the file name. The archive stores the add-on's JSON records under a .log extension, because the importer keeps the bytes it was given. A reader that trusted the suffix would read one of those as a chat paste, find no stamps in it, and hand the raw JSON to the language pipeline as a single line of prose.

How a transcript is stored

New transcripts are stored as JSON Lines: one record per line, in seq order, keys sorted, LF endings. Old .log files stay exactly as they are and are parsed. The two containers therefore coexist across the archive — and never for one transcript: a name that exists in both is refused rather than resolved, because the two copies would answer with two different sets of line ids.

nerthus transcripts convert <name> proposes an old file as the corpus form. The record is added and the .log removed in the same change, so the archive is never in the refused state. Nothing downstream moves when it lands: an id is a hash of what a line is, not of the file it was read from, so the records carry the ids the .log was already answering with.

nerthus transcripts render <name> prints the human form from whichever container holds it. It is what a person reads; it is not a byte-for-byte reproduction of an archived file, because a transcript read from JSON has instants where the plain form had a wall clock.

Two lines that look identical

By the id rule, two lines of one transcript that agree on speaker, instant and text are the same line. Sometimes they are not — somebody says one word twice in the same second. Those keep two ids, disambiguated by seq, and the collision is reported as a finding. Silently collapsing them would lose a word somebody said.

A related case is not a duplicate at all: the game's message cap splits a long message in two, and the fragments are rejoined into the line that was typed. Fragments are only rejoined when they agree on speaker, channel, style and addressee, sit within a few seconds of each other, and were said in the same scene — a fragment written after the room moved is a new line, however close the clock.

Where to go next

  • Oddaj transkrypt sesji — the same subject for a narrator: what to hand in, and what each container cannot recover.
  • Link session logs — how a session points at its transcripts today.
  • The speech layer — what the corpus answers about a person once their lines are indexed.