Joel Stevick

Chapter 11 · section 3 of 7

The register, measured

A right figure in a wrong voice is still a miss. The deployed pipeline’s register was planned on 10 October 2026 and the eval’s register verdict came with it, so every shown answer has been scored against it since: at most two sentences, three for a question of the what happens if shape, and no law’s name or number in the prose, because the app shows those underneath. The next day the author’s note that an answer was “way too detailed and verbose. This is for teenagers” tightened it. That answer was two sentences, inside the count, and its first ran 36 words; the rewrite of the road-law rule in Chapter 2 came from the note, and so did a cap of 28 words on a sentence.

Listing: ask/register.ts

// Whether a shown answer reads the way a sixteen-year-old wants one: a
// couple of sentences, boiled down, with no law's number in them. The eval
// scores every case by it beside the facts, and a miss is a miss.

/** A question of the consequence shape -- what happens, what if, will I, do I have to, how much -- may take three sentences; every other question takes two. */
export function consequenceShaped(question: string): boolean {
  return /\b(what happens|what if|will i|do i have to|how much)\b/i.test(question);
}

// A sentence ends at a full stop, a question mark or an exclamation mark
// followed by a space and a capital, or at the end of the text: "5 a.m. and"
// and "0.08" are not two sentences, and nor is an initialism before a name.
function sentencesOf(text: string): string[] {
  return text
    .trim()
    .split(/(?<!\b(?:\p{Lu}\.){2,})(?<=[.!?])["”’)]?\s+(?=["“¿¡(]?[\p{Lu}\d$])/u)
    .filter((sentence) => /\p{L}/u.test(sentence));
}

export function sentencesIn(text: string): number {
  return sentencesOf(text).length;
}

/** The longest a sentence may run, in words. The prompt asks for under about 20; 28 is where a sentence is a miss. */
export const MAX_SENTENCE_WORDS = 28;

export function longestSentenceWords(text: string): number {
  return Math.max(
    0,
    ...sentencesOf(text).map((sentence) => sentence.split(/\s+/).filter((word) => /[\p{L}\d]/u.test(word)).length),
  );
}

/** A law's name or number written into the sentences, which the app already shows under them: "§ 16-112", "p.30", "page 30", "section 21-1003". */
export function namesALaw(text: string): boolean {
  return (
    /§|\bp\.\s?\d|\bpages?\b|\b(sub)?sections?\s+\(?\d|\bsubsection\b/i.test(text) ||
    /(?<![$\d.,])\b\d{2,}[A-Z]{0,2}[.:-]\d+(?![\d.]*\s*(?:[ap]\.?m\b|dollars?|days?|feet|miles?|mph|hours?|years?|months?|percent|points?))/i.test(text)
  );
}

/** What is wrong with a shown answer's register, or nothing. An answer that was not shown has no register to judge. */
export function registerMisses(found: { question: string; shown: string }): string[] {
  if (found.shown.trim() === "") return [];
  const out: string[] = [];
  const most = consequenceShaped(found.question) ? 3 : 2;
  const count = sentencesIn(found.shown);
  if (count > most) out.push(`register: ${count} sentences, at most ${most}`);
  const longest = longestSentenceWords(found.shown);
  if (longest > MAX_SENTENCE_WORDS) out.push(`register: a sentence of ${longest} words, at most ${MAX_SENTENCE_WORDS}`);
  if (namesALaw(found.shown)) out.push("register: names a law or page in the sentences");
  return out;
}

The sentence splitter is the part with the history. A naive split on full stops counted “a helmet that meets U.S. Department of Transportation standards” as three sentences, and five right answers in six for North Dakota’s helmet question missed the register. The second regular expression in namesALaw has to tell a section number, 16-112, from a figure that looks like one, 0.08, $12.50, 11:00 p.m., and every alternative in its tail is a case that was once misread. The twenty-eight is a limit set above the rule it checks, so that a right answer of 22 words is not refused by a counter stricter than the prompt.