UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

114 lines (113 loc) • 5.83 kB
/** * time/forms — every spelling of a time the answer may write, split by * WHO produced it (time design § 9.5, step T7). * * Pattern: a pure function over recorded values — the person's text, or one * window the record holds — never over the answer. The evidence gate * asks it (`evidence/evidenceIndex.ts` · `exemptFromRun`, * `stages/timeLineage.ts` · `timeLineageOf`) and never keeps a time table of * its own. * Role: L0 leaf (the time layer). Imports `windows.ts`, `rows.ts`, * `resolve.ts`, `textForms.ts` (the text rule, split out so the * evidence gate's synchronous corpus never loads the resolver), * `instant.ts` and `zone.ts` only. Loaded under `.time()` only, * through `import()` (`stages/timeLineage.ts`). * Emits: N/A. * * ## The two lists * * - **`said`** — spellings of the parts the PERSON said, at the grain they * said them: "8 AM" said at grain hour is also `8:00` and `08:00` — the * same instant at that grain, equality and not a new fact. They count as * the person's words (the gate exempts them). * - **`derived`** — everything the LIBRARY produced from a reading: an * implied year, the zone's abbreviation in effect (`PDT` for a said `PST`), * offsets, UTC and epoch spellings, the end-of-grain `08:41`, a look-back's * duration, the window's length ("6:25 to 6:45" is `20-minute` as said and * `21-minute` as read to the end of its grain — arithmetic over the ends, * never a part anyone wrote), every part of a `model` reading, every part * of a PROPOSAL — a `rule` reading the time ask offers that the person has * not answered yet (`06:25:00` for "6:25"; its implied year) — and the * turn's CLOCK, at the grain it is served (G16: "This turn's time: …" on * every request under `.time()`): the minute of `now` in the person's zone * (UTC under an unknown zone) — `7:08`, `07:08`, `7:08am`, the date, the * year, the zone and its offset. Never a time the clock does not produce * (`7:09`, or the clock's seconds). And a source's HELD span the served * time line names in the person's zone (take 3): each end's wall spellings * there and in UTC. The gate files an answer * value found only here with the lineage `derived-from-reading`: it can * support "not sure", never "known", and it is never called invented. * * A time value no recorded reading produced is in neither list and still * fails the gate. Library text is never evidence: without `derived`, a model * echoing the served time line back would read as the person's words. */ import { type TimeForms } from './textForms.js'; import { type TurnWindow } from './windows.js'; import { type TimeCandidate } from './resolve.js'; import { type ClockRow } from './rows.js'; import { type ZoneName } from './zone.js'; export type { TimeForms }; /** One window the record holds, as the spellings read it. */ export interface FormsWindow extends Pick<TurnWindow, 'source' | 'range' | 'zone' | 'lookback'> { /** * The reading this window IS, when the person confirmed a `rule` reading * of their words — which parts they WROTE, and how the range was read. * Absent: a window they typed in the ask, a UI control, a `model` reading. */ readonly reading?: Pick<TimeCandidate, 'said' | 'notes' | 'grain'>; /** On an `answered` window: the person picked the offered reading, or wrote their own. */ readonly answer?: TurnWindow['answer']; } /** The turn's clock as the record keeps it (`rows.ts` · `ClockRow`) — what the served time line names. */ export type FormsClock = Pick<ClockRow, 'now' | 'zone'>; /** * A source's held span as the served time line names it (`coverage/timeLimits.ts` * · `heldLine`): the instants the tool declared, and the person's zone the * line renders them in. */ export interface FormsHeld { readonly from: string; readonly to: string; readonly zone: ZoneName; } /** What {@link timeFormsOf} spells: words the person or the app wrote, one recorded window, the turn's clock, or a source's held span. */ export type TimeFormsSource = { readonly text: string; } | { readonly window: FormsWindow; } | { readonly clock: FormsClock; } | { readonly held: FormsHeld; }; /** * The spellings of one source's times, split by lineage (§ 9.5). * * A `text` — the person's message, their typed answer, the app's prompt — * has only `said` spellings, and each is a SPELLING, never an * interpretation: an ISO date → its year, month and day; a 12-hour reading * (`8 Am`) → its 24-hour, padded and glued forms; a 24-hour reading * (`20:00`) → the same set. Slash dates are never read (their order is a * locale) and durations never (a quantity is not a time of day). * * A `window` — the turn's recorded window — splits by who produced each * part: the person's said parts at grain, or everything of a window they * typed or set in a UI, are `said`; the rest is `derived`. A `model` * reading's window (`derived-from-reading`) has no `said` spelling at all. * * @example * ```ts * timeFormsOf({ text: 'what connected 8 Am to 8:40 AM PST' }).said; * // ['8:00', '08:00', '8:00am', '8:40', '08:40', '8:40am'] * timeFormsOf({ text: '2026-10-09' }).said; // ['2026', '10', '9'] * timeFormsOf({ text: 'took 2h' }); // { said: [], derived: [] } * ``` */ export declare function timeFormsOf(source: TimeFormsSource): TimeForms; /** * Every recorded window of the LATEST turn on the ledger (its `clock` row's * turn), with the reading each one is — what the gate spells. Empty when no * clock was filed (an agent without `.time()`). */ export declare function turnFormsWindowsOf(ledger: readonly unknown[] | undefined): readonly FormsWindow[];