Lookout Context#
Lookout is @kontourai/lookout, a source registry and drift-check runner built
on Forage snapshots. Given a registry of sources and a snapshot store, it
answers whether a source drifted, can deterministically compare caller-produced
proposal observations, and emits that comparison as neutral, typed drift in its
own vocabulary. It composes Forage for fetch and snapshots, Traverse for
schema/proposal types, and depends on
nothing in the trust layer — its events are already
Hachure-evidence-shaped (Hachure is the
open, product-neutral trust-record spec Surface's TrustBundle implements), but
lifting them into a Hachure TrustBundle (via @kontourai/surface's
TrustBundleBuilder) is a consumer/product responsibility, not Lookout's.
Extraction implementations, Surface projection, authority policy, notification,
and scheduling remain external. Public operational entrypoints return typed
results rather than throwing.
Term Glossary#
- Source (
LookoutSource): a caller-owned description of one monitored target — itsid,kind(web-page|api-record|structured-file), an absolute HTTP(S)url, and acadenceHint. Web/API sources also carry a TraverseTargetFieldSchema[]plus inertrenderPolicy; structured files instead declareformat(yaml|json|csv). Lookout retains their raw bytes but does not parse or normalize them. - Registry (
LookoutRegistry): the loaded, validated set of sources from a versioned{ version: 1, sources: [...] }JSON document (default<cwd>/lookout.sources.json). Provides exact-id lookup (get) and a stable file-orderlist; it never merges, discovers, or fetches. Validation reports every deterministic issue at once and never reads the network. - Render Policy (
renderPolicy):never|on-shell-warning|always, validated registry data that is inert at L1 — it is never translated into a Forage fetch/render policy. Render wiring remains deferred. - Check: one drift observation for a source. Its exact order is: read the
prior snapshot →
fetchSourcewithrevalidate: trueagainst the same store → validate the dependency result → classify → persist the fresh snapshot before reporting success → emit provenance. Lookout owns the prior-vs-freshbodyHashcomparison; Forage computes a fresh hash and only reads the store. - Snapshot Reference (
snapshotRef/priorSnapshotRef/currentSnapshotRef): a portable logical ref from Forage'sbuildSnapshotSourceRef, never a filesystem path.unchanged-304carries one ref; fresh comparisons carry both prior and current refs. - Check Result (
CheckResult): the discriminated result of a check — exactly one of four kinds, each carryingsourceId, registeredsourceUrl,checkedAt, and Forage fetch warnings:unchanged-304: a validator-backed conditional request returned304; the prior snapshot was re-served with zero body transfer and is not re-persisted. Trustworthy only with Forage's validator-scoped revalidation.unchanged-hash: a full body was fetched, but its sha256bodyHashequals the prior snapshot's — no drift, established by L1's own comparison. A byte-identical repeat of the prior capture is not persisted again; both refs then name the stored capture.changed: the fresh body was persisted and differs from the prior (changeBasis: "hash"), or it is the first successful observation (changeBasis: "initial"with a null prior ref).error: an operational failure, contained so the runner never rejects —origin: "forage"preserving a ForageFetchErrordiscriminant, ororigin: "lookout"with a typed kind (prior-read|persistence|history-full|dependency-contract|unexpected).
- Snapshot Store (
createLookoutSnapshotStore): a thin wrapper over Forage's filesystem snapshot store, rooted by default at<cwd>/.kontourai/lookout/snapshotswith an injectable root and an optionalmaxHistoryFilespassed to Forage. Lookout adds no custom filenames or storage format. Optional check-runner retention (keepLastplus a caller-suppliedcitedset) prunes through Forage'spruneafter each stored capture and never removes the latest, the result's prior, or a cited snapshot.resolveLookoutSnapshotresolves and authenticates one exact durable reference offline through this store boundary. - Provider Resolver (
ProviderResolver): a Datumresolvecapability threaded into the runner for L2. L1 accepts it but never invokes it — resolving would materialize secrets for no purpose this slice. - Proposal Observation Store (
ObservationStore): Lookout-owned, digest-addressed proposal continuity under<cwd>/.kontourai/lookout/observations. It validates same-source snapshot and check anchors, atomically advances one per-source pointer, and retains the two newest valid committed observations. Missing means first run; corruption is a typed error and never an empty baseline. - Drift emission (
DriftEmitter): compares a genuine stored prior with a current caller-produced proposal observation and emits one neutralDriftFact/ProposalDiffEventset per comparison —events,facts, and apriorObservationId(nullon the first-ever observation). When the current proposal set is markedincomplete(its extraction did not read all of its text), nothing the prior had is reported as removed: those proposals and entities areunobserved, and the fact carries theincompletemarker. An incomplete run whose loss might not recur never replaces an existing baseline (committedObservation: null); one whose every loss recurs (a cap), or a first observation, is stored with its marker, and what a later run adds against it isnewlyObserved, not added, unless the emitter's optionalpriorTextpreparation rebuilds and verifies the prior's full prepared text and none of the entity's exact excerpts occur in it (Prior Text Anchoring); the fact'spriorTextsays whether that text wasverifiedor why it wasunavailable. An occurrence paired with a field occurrence the incomplete prior did read is never newly observed: if it moved or changed, the provenance change or field-changed event describes it and the occurrence is added. Newly observed proposals are reviewable asproposal-newly-observedsemantic review work. Registry kind supplies factorigin; resolution is alwaysobservation. First observation produces abaseline-establishedfact, no events, and a nullpriorObservationId. - Observe-extract-diff composition (
createObserveExtractDiff): an additive, injected acquisition/extraction/recording composition. It recordsunchanged-304andunchanged-hashobservations without calling extraction when the capture matches the recorder's last extracted snapshot (same URL and body hash); therefore no preparation or provider work occurs for unchanged sources. An unchanged capture that was never extracted is extracted instead. A changed source retains its registered identity, prior/current snapshot refs, Traverse prepared-artifact identity, proposal-set observation, compact attempt record, and recorder-provided observation identities. Traverse's typed partial completion, provider failures, and mixed partial/failure runs remain distinct outcomes. Durable failure details are reduced to neutral classifications without provider names, messages, native diagnostics, or free-form extraction warnings; a first observation has a null prior identity and no fabricated comparison. - Semantic review work (
buildSemanticReviewWork): a pure projection of one genuine prior/current proposal transition into structurally Survey-compatibleReviewItemresources. Added, removed, moved, and value-changed and provenance-changed proposals are distinct; newly introduced declared-field coverage gaps and exact-provenance gaps are explicit. One field change is one item: a value change that also moved is a single value-changed item with both locators. Provenance equality is the resolved occurrence, not how the resolver was steered to it (occurrence.selection,hintUsed). An excerpt only narrowed by whole paragraphs around an equal value at the same offsets is anexcerptBoundaryChangesfact carrying the dropped text, not work; any widening or shift is still one moved item. Every item binds both observation identities and preserves each available side's source snapshot, locator, excerpt, extractor, and observation time. An absent side remains a reviewable source-version candidate anchored to that observation's snapshot. Stable proposal sets emit no work, and deterministic transition/item identities make replay idempotent. Lookout imports no review package at runtime and chooses no resolution, escalation, or authority policy. - Consumer projection: lifting emitted drift events into a Hachure
TrustBundle(via@kontourai/surface'sTrustBundleBuilder) is a consumer/product responsibility. Lookout imports nothing from the trust layer and chooses no review, supersession, precedence, or carry-forward policy.
Boundary#
Lookout owns the registry, drift classification, deterministic proposal diff, proposal-observation continuity, neutral drift emission, semantic review-work shaping, injected observe-extract branching, and JSONL commands. Forage owns fetching, snapshot storage, and durable reference integrity; Traverse owns extraction. Trust-bundle authoring, Surface projection, notification, crawling, review/authority policy, and scheduling remain external.