import { type ProposalBasis } from "./proposals.js"; import { type BaselineMetadata } from "./baseline.js"; import type { Artifact, Board, Comment, ExecutionEvidence, Id, Job, Question, Region, Track } from "./model.js"; import type { HandoverPlacement } from "./handover.js"; /** * The board is an append-only log of operations. A snapshot is fold(ops). * Agents propose; people commit. In v0.1 every op applies immediately but * carries provenance, so the queue can be added later without changing the log. */ export interface HandoverSnapshot { jobs: (Job | { id: string; absent: true; })[]; artifacts: (Artifact | { id: string; absent: true; })[]; } export type Op = { t: "setVocabulary"; vocabulary: import("./vocabulary.js").DomainVocabulary; } | { t: "acceptAlternative"; alternative: Board; baseline: Board; expectedBasis: string; } | { t: "baseline"; baseline: BaselineMetadata; snapshot: Board; } | { t: "handover"; jobId: string; toTrack: string; placement?: HandoverPlacement; basis: string; before: HandoverSnapshot; after: HandoverSnapshot; } | { t: "restoreHandover"; of: string; snapshot: HandoverSnapshot; inverse: HandoverSnapshot; } | { t: "board"; id: Id; title: string; goal?: string; origin?: string; } | { t: "setGoal"; goal: string; } | { t: "track"; track: Track; } | { t: "artifact"; artifact: Artifact; } | { t: "job"; job: Job; } | { t: "addExecutionEvidence"; id: Id; evidence: ExecutionEvidence; } | { t: "retractExecutionEvidence"; id: Id; key: string; reason: string; } | { t: "updateJob"; id: Id; patch: Partial; } | { t: "removeJob"; id: Id; replacedBy?: Id; } | { t: "confirmField"; id: Id; field: string; by?: string; } | { t: "split"; id: Id; tasks: { id: Id; name: string; track?: Id; }[]; } | { t: "collect"; id: Id; name: string; track: Id; into: Id[]; } | { t: "uncollect"; id: Id; } | { t: "reorder"; id: Id; before?: Id; after?: Id; } | { t: "removeTrack"; id: Id; } | { t: "ask"; question: Question; } | { t: "answer"; id: Id; answer: string; by: "agent" | "human"; who?: string; } | { t: "confirm"; id: Id; by?: string; } | { t: "comment"; comment: Comment; } | { t: "removeComment"; id: Id; } | { t: "setVolume"; perWeek: number; } | { t: "setIntent"; intent: Board["intent"]; } | { t: "base"; board: Id; } | { t: "accept"; seq: number; by?: string; } | { t: "reject"; seq: number; by?: string; why?: string; } | { t: "setContext"; context: NonNullable; } /** what the interview has settled, so a conversation that starts again does not start over */ | { t: "settle"; class: import("./ledger.js").LedgerClass; settled: boolean; by: "human" | "staves"; quote?: string; basis?: string; } | { t: "region"; region: Region; } | { t: "regionMembers"; id: Id; add?: Id[]; remove?: Id[]; } | { t: "removeRegion"; id: Id; } | { t: "issue"; id: Id; status: NonNullable; by?: string; } /** undo: restore an entity to the state it had before the entry `of` */ | { t: "revert"; of: string; entity: "job" | "track" | "region" | "artifact" | "question" | "comment"; id: Id; prior: unknown | null; relatedJobs?: Job[]; expectedJobs?: Job[]; }; /** Schema version written on every new entry. Migrations bring older entries up at fold time. */ export declare const SCHEMA = 2; /** What a suggestion is, in the words it came from. A proposal records an op; this records why anyone * should believe it — the person's own words, and how sure the interviewer was. It travels with the * proposal so a collaborator, or a coding agent reading the board, sees the same card the author saw. */ export interface Suggestion { name: string; quote?: string; detail?: string; /** "said" their words outright, "implied" an assumption to review, "asked" an open question */ confidence?: "said" | "implied" | "asked"; /** the card kind the interview used: who, job, task, outcome, exit … */ type?: string; warning?: string; } export interface Entry { seq: number; /** globally unique, time-ordered; the identity of the entry across machines (seq is only local order) */ id?: string; /** schema version the entry was written with */ v?: number; at: string; by: string; op: Op; /** a proposal: not part of the board until a person accepts it */ pending?: boolean; /** Applied state captured when a new proposal was authored; absent on legacy logs. */ proposalBasis?: ProposalBasis; /** the card this proposal came from, when a suggestion made it */ suggestion?: Suggestion; /** ids of entities this op assumed existed; on merge, an op whose basis is gone becomes a proposal */ basis?: Id[]; /** set on merge: this op was demoted to a proposal because its basis had changed elsewhere */ demoted?: boolean; } /** Bring an entry written by an older version up to the current schema. Idempotent. */ export declare function migrate(e: Entry): Entry; /** Rule 2 at the write boundary: a job that cannot say where it came from is refused, not stored. * Stored, every later read fails — lint reads provenance.source on each board load — so one bad op * makes the board unreadable. The vocabulary itself is not policed here: production writes sources * ("interview", "import") that ProvenanceSource does not declare. */ export declare function validateOpShape(op: Op): void; /** The ids a structural op assumes exist. */ export declare function basisOf(op: Op): Id[]; /** Proposals: pending entries that have not been accepted or rejected. */ export declare function pending(entries: Entry[]): Entry[]; export declare function fold(entries: Entry[], baseEntries?: Entry[] | Board): Board; /** Serialise one entry per line. */ export declare function encode(entries: Entry[]): string; export declare function decode(text: string): Entry[]; /** Which entity an op touches, for undo. */ export declare function targetOf(op: Op): { entity: "job" | "track" | "region" | "artifact" | "question" | "comment"; id: string; } | null; /** The reference identity is stable even when an observation's summary later changes. */ export declare function sameExecutionEvidence(a: ExecutionEvidence, b: ExecutionEvidence): boolean;