projectkeeper 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +283 -2
- package/README.zh-CN.md +285 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/bin/pk.mjs +6 -0
- package/bin/postinstall.mjs +5 -0
- package/bin/strip-types.mjs +28 -0
- package/package.json +68 -4
- package/patches/README.md +111 -0
- package/patches/pi-ai-0.85.0.ts +122 -0
- package/patches/pi-ai-0.87.1.ts +122 -0
- package/scripts/apply-pi-streaming-patch.ts +86 -0
- package/skills/clerk/coverage/SKILL.md +35 -0
- package/skills/clerk/cross-check/SKILL.md +118 -0
- package/skills/clerk/deepen-dispatch/SKILL.md +69 -0
- package/skills/clerk/lane-follow-up/SKILL.md +94 -0
- package/skills/clerk/lane-plan/SKILL.md +107 -0
- package/skills/clerk/lane-slot/SKILL.md +113 -0
- package/skills/clerk/lane-topic/SKILL.md +116 -0
- package/skills/clerk/orientation/SKILL.md +160 -0
- package/skills/clerk/reconcile/SKILL.md +77 -0
- package/skills/clerk/skeleton-dispatch/SKILL.md +43 -0
- package/skills/clerk/spot-check/SKILL.md +52 -0
- package/skills/clerk/synthesis/SKILL.md +65 -0
- package/skills/table-follow-up/SKILL.md +42 -0
- package/src/cli.ts +319 -0
- package/src/codemap/README.md +13 -0
- package/src/codemap/engines.ts +102 -0
- package/src/codemap/facts.ts +504 -0
- package/src/context/agent-entry.ts +232 -0
- package/src/context/ask.ts +97 -0
- package/src/context/assemble.ts +1058 -0
- package/src/context/code-source.ts +103 -0
- package/src/context/k-briefs.ts +114 -0
- package/src/context/lineage.ts +100 -0
- package/src/context/object-brief.ts +300 -0
- package/src/context/owner-words.ts +191 -0
- package/src/context/pack-fixture.ts +342 -0
- package/src/context/project-rules.ts +160 -0
- package/src/intake/intake.ts +392 -0
- package/src/intake/material-rules.ts +166 -0
- package/src/intake/removal.ts +316 -0
- package/src/intake/skipped.ts +72 -0
- package/src/keeper/adjustment.ts +565 -0
- package/src/keeper/bounds/boundary.ts +509 -0
- package/src/keeper/bounds/command.ts +1665 -0
- package/src/keeper/bounds/paths.ts +164 -0
- package/src/keeper/bounds/reads.ts +718 -0
- package/src/keeper/bounds/shell-write-guard.ts +521 -0
- package/src/keeper/capabilities.ts +136 -0
- package/src/keeper/clerk-steps.ts +151 -0
- package/src/keeper/clerk-tools.ts +1424 -0
- package/src/keeper/conversation.ts +253 -0
- package/src/keeper/evidence.ts +662 -0
- package/src/keeper/fake-provider.ts +132 -0
- package/src/keeper/held.ts +15 -0
- package/src/keeper/history-tools.ts +163 -0
- package/src/keeper/jobs/answering.ts +53 -0
- package/src/keeper/key-check.ts +105 -0
- package/src/keeper/ledger-tools.ts +295 -0
- package/src/keeper/link-check.ts +185 -0
- package/src/keeper/merge.ts +260 -0
- package/src/keeper/note-origin.ts +56 -0
- package/src/keeper/numbers-check.ts +102 -0
- package/src/keeper/open-in-pi.ts +57 -0
- package/src/keeper/organize/absence.ts +266 -0
- package/src/keeper/organize/carried-on.ts +214 -0
- package/src/keeper/organize/clerk-coverage.ts +293 -0
- package/src/keeper/organize/clerk-prompts.ts +132 -0
- package/src/keeper/organize/clerk.ts +1395 -0
- package/src/keeper/organize/coverage-gate.ts +19 -0
- package/src/keeper/organize/coverage-tools.ts +765 -0
- package/src/keeper/organize/entries.ts +153 -0
- package/src/keeper/organize/entry-gate.ts +289 -0
- package/src/keeper/organize/fill-tools.ts +718 -0
- package/src/keeper/organize/follow-up.ts +280 -0
- package/src/keeper/organize/generation-check.ts +504 -0
- package/src/keeper/organize/graph.ts +230 -0
- package/src/keeper/organize/lane-tools.ts +289 -0
- package/src/keeper/organize/looked-tools.ts +54 -0
- package/src/keeper/organize/materials.ts +243 -0
- package/src/keeper/organize/owner-lines.ts +493 -0
- package/src/keeper/organize/place-tools.ts +216 -0
- package/src/keeper/organize/placement-inference.ts +1045 -0
- package/src/keeper/organize/placement-time.ts +320 -0
- package/src/keeper/organize/placing.ts +821 -0
- package/src/keeper/organize/positioning.ts +33 -0
- package/src/keeper/organize/readiness.ts +47 -0
- package/src/keeper/organize/reading.ts +401 -0
- package/src/keeper/organize/round-blocks.ts +65 -0
- package/src/keeper/organize/round-news.ts +164 -0
- package/src/keeper/organize/round-open.ts +586 -0
- package/src/keeper/organize/schedule-state.ts +39 -0
- package/src/keeper/organize/schedule.ts +137 -0
- package/src/keeper/organize/service.ts +409 -0
- package/src/keeper/organize/skills.ts +116 -0
- package/src/keeper/organize/slots.ts +85 -0
- package/src/keeper/organize/stage-gate.ts +175 -0
- package/src/keeper/organize/stage-tools.ts +471 -0
- package/src/keeper/organize/standing-notes.ts +141 -0
- package/src/keeper/organize/table-follow-up.ts +330 -0
- package/src/keeper/organize/takeover-clerk.ts +832 -0
- package/src/keeper/organize/takeover-state.ts +103 -0
- package/src/keeper/organize/takeover.ts +216 -0
- package/src/keeper/organize/update-pending.ts +535 -0
- package/src/keeper/organize/workbench-placement.ts +92 -0
- package/src/keeper/own-keys.ts +114 -0
- package/src/keeper/owner-text.ts +165 -0
- package/src/keeper/project-folder.ts +334 -0
- package/src/keeper/prompts.ts +101 -0
- package/src/keeper/references.ts +177 -0
- package/src/keeper/relook/compose.ts +120 -0
- package/src/keeper/relook/prompts.ts +36 -0
- package/src/keeper/roles.ts +259 -0
- package/src/keeper/round-tools.ts +227 -0
- package/src/keeper/route.ts +148 -0
- package/src/keeper/rules.ts +97 -0
- package/src/keeper/runtime.ts +1858 -0
- package/src/keeper/scope-tools.ts +194 -0
- package/src/keeper/sendback-text.ts +83 -0
- package/src/keeper/step-timing.ts +207 -0
- package/src/keeper/testing/clerk-script.ts +212 -0
- package/src/keeper/testing/streaming-arguments.ts +57 -0
- package/src/keeper/tools.ts +2340 -0
- package/src/keeper/utterance-tools.ts +64 -0
- package/src/keeper/verbatim.ts +397 -0
- package/src/ledger/adapters.ts +186 -0
- package/src/ledger/arrangements.ts +257 -0
- package/src/ledger/blame.ts +58 -0
- package/src/ledger/code-engine-child.ts +69 -0
- package/src/ledger/code-engine.ts +548 -0
- package/src/ledger/code.ts +607 -0
- package/src/ledger/docs.ts +294 -0
- package/src/ledger/git-read.ts +321 -0
- package/src/ledger/index.ts +1850 -0
- package/src/ledger/item-range.ts +16 -0
- package/src/ledger/lines.ts +328 -0
- package/src/ledger/numbering.ts +269 -0
- package/src/ledger/ranges.ts +74 -0
- package/src/ledger/rebuild-worker.ts +15 -0
- package/src/ledger/rebuild.ts +387 -0
- package/src/ledger/repo-scan.ts +181 -0
- package/src/ledger/schema.ts +450 -0
- package/src/ledger/sessions.ts +134 -0
- package/src/ledger/text-scan.ts +466 -0
- package/src/ledger/time.ts +185 -0
- package/src/ledger/ts-symbols.ts +180 -0
- package/src/ledger/views.ts +377 -0
- package/src/mcp/server.ts +127 -0
- package/src/mcp/tools.ts +187 -0
- package/src/model/ids.ts +23 -0
- package/src/model/k-types.ts +912 -0
- package/src/model/time.ts +85 -0
- package/src/model/types.ts +1382 -0
- package/src/model/views-k.ts +707 -0
- package/src/model/vocab.ts +269 -0
- package/src/process/analysis.ts +79 -0
- package/src/process/breakpoint-candidates.ts +383 -0
- package/src/process/breakpoints.ts +746 -0
- package/src/process/claim-check.ts +295 -0
- package/src/process/delivery-links.ts +52 -0
- package/src/process/facts.ts +487 -0
- package/src/process/generations.ts +138 -0
- package/src/process/index.ts +243 -0
- package/src/process/integration.ts +128 -0
- package/src/process/placement.ts +107 -0
- package/src/process/plan.ts +276 -0
- package/src/process/sendbacks.ts +244 -0
- package/src/process/text.ts +185 -0
- package/src/process/units.ts +543 -0
- package/src/process/unnumbered.ts +431 -0
- package/src/process/work.ts +884 -0
- package/src/scope/candidates.ts +86 -0
- package/src/scope/decisions.ts +229 -0
- package/src/scope/discover.ts +741 -0
- package/src/scope/ignore.ts +126 -0
- package/src/scope/ignored-place.ts +93 -0
- package/src/scope/skip.ts +161 -0
- package/src/scope/toolchain.ts +180 -0
- package/src/scope/worktree.ts +187 -0
- package/src/server/api.ts +549 -0
- package/src/server/app.ts +595 -0
- package/src/server/drafts-api.ts +170 -0
- package/src/server/folders-api.ts +243 -0
- package/src/server/graph-view.ts +639 -0
- package/src/server/http.ts +224 -0
- package/src/server/k-agent-api.ts +56 -0
- package/src/server/k-rounds-d99.ts +91 -0
- package/src/server/k-views.ts +405 -0
- package/src/server/keeper-page.ts +446 -0
- package/src/server/keys-api.ts +239 -0
- package/src/server/project-folder-api.ts +104 -0
- package/src/server/vendor.ts +14 -0
- package/src/server/workbench-content.ts +561 -0
- package/src/sources/anchor.ts +129 -0
- package/src/sources/files.ts +267 -0
- package/src/sources/gitobs.ts +41 -0
- package/src/sources/history.ts +231 -0
- package/src/sources/scan-worker.ts +10 -0
- package/src/sources/sessions/locate.ts +292 -0
- package/src/sources/sessions/read.ts +346 -0
- package/src/sources/sessions/scope.ts +42 -0
- package/src/sources/sessions/utterances.ts +223 -0
- package/src/sources/watch.ts +215 -0
- package/src/store/json-file.ts +50 -0
- package/src/store/paths.ts +39 -0
- package/src/store/project-store.ts +295 -0
- package/src/store/versions.ts +172 -0
- package/src/store/workspace.ts +216 -0
- package/src/table/check.ts +333 -0
- package/src/table/follow-up-tools.ts +30 -0
- package/src/table/follow-up.ts +344 -0
- package/src/table/import.ts +610 -0
- package/src/table/project-home.ts +61 -0
- package/src/table/sessions.ts +168 -0
- package/src/table/takeover.ts +483 -0
- package/src/util/git-check.ts +29 -0
- package/src/util/git.ts +411 -0
- package/src/util/own-ts.ts +15 -0
- package/src/util/paths.ts +225 -0
- package/template/FILLING-IN.md +148 -0
- package/template/examples/papertrail.json +747 -0
- package/template/projectkeeper.schema.json +1001 -0
- package/ui/app.js +1135 -0
- package/ui/failures.js +82 -0
- package/ui/flyout.js +120 -0
- package/ui/folder-chooser.js +264 -0
- package/ui/glossary.js +156 -0
- package/ui/graph-fit.js +157 -0
- package/ui/graph-material.js +61 -0
- package/ui/graph-palette.js +109 -0
- package/ui/graph-tools.js +62 -0
- package/ui/graph.js +1712 -0
- package/ui/index.html +31 -0
- package/ui/k/code-view.js +230 -0
- package/ui/k/draft-view.js +93 -0
- package/ui/k/k-views.css +224 -0
- package/ui/k/round-tree.js +450 -0
- package/ui/k/scope-k.js +159 -0
- package/ui/k-data.js +118 -0
- package/ui/k-fold.js +106 -0
- package/ui/k-process.css +302 -0
- package/ui/k-process.js +934 -0
- package/ui/keeper-activity.js +175 -0
- package/ui/keeper-view.js +801 -0
- package/ui/keeper.css +101 -0
- package/ui/key-order.js +62 -0
- package/ui/list-fold.js +67 -0
- package/ui/markdown.d.ts +21 -0
- package/ui/markdown.js +472 -0
- package/ui/placement.d.ts +92 -0
- package/ui/placement.js +445 -0
- package/ui/popover-place.d.ts +16 -0
- package/ui/popover-place.js +89 -0
- package/ui/popover.js +198 -0
- package/ui/project-folder.js +37 -0
- package/ui/shell-state.js +40 -0
- package/ui/strip-rows.js +171 -0
- package/ui/styles.css +492 -0
- package/ui/theme-pick.js +36 -0
- package/ui/theme.js +74 -0
- package/ui/themes/LICENSE.md +13 -0
- package/ui/themes/README.md +44 -0
- package/ui/themes/TOKENS.md +291 -0
- package/ui/themes/a1/board.css +1557 -0
- package/ui/themes/a1/pk.css +392 -0
- package/ui/themes/b1/board.css +1163 -0
- package/ui/themes/b1/pk.css +218 -0
- package/ui/themes/d2/board.css +518 -0
- package/ui/themes/d2/pk.css +243 -0
- package/ui/themes/guard.css +73 -0
- package/ui/themes/i1/board.css +776 -0
- package/ui/themes/i1/pk.css +223 -0
- package/ui/themes/manifest.json +13 -0
- package/ui/views.js +2796 -0
|
@@ -0,0 +1,1382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project assets (Spec §1 "共同对象", §8.5). Everything here belongs to ProjectKeeper, lives
|
|
3
|
+
* outside the project directory, and can be read without a running Keeper.
|
|
4
|
+
*
|
|
5
|
+
* All views, the conversation and every delivery read these same records; nothing assembles
|
|
6
|
+
* a second understanding at delivery time.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
Acceptance, Assessment, Availability, Basis, CarryOut, ChangeEffect, ChangeMaterial, ContextPurpose, CoverageLabel,
|
|
11
|
+
Delivery, Identity, ItemClose, JobKind, JobStatus, MarkClose, MarkKind, MaterialRule, NodeCategory, NoteAsk, NoteOrigin,
|
|
12
|
+
NoteStatus, NotJudgedReason, OrganizingLevel, OwnerResponse, Progress, Propagation, ReferenceCategory,
|
|
13
|
+
RelationType, RuleGroup, ScopeCategory, ScopeRelation, SessionHost, StatementType, TakeoverDepth, UnderstandingState,
|
|
14
|
+
UsedAs, Validity, WorkKind, WorkSegmentKind, ProcessExpectation,
|
|
15
|
+
} from './vocab.ts';
|
|
16
|
+
import type { AbsenceLooked, RoundNews, RoundStepKind, SixThing, StepTiming, LaneKind, SlotKind } from './k-types.ts';
|
|
17
|
+
|
|
18
|
+
// ───────────────────────── §1.2 sources and anchors ─────────────────────────
|
|
19
|
+
|
|
20
|
+
export interface FileAnchor {
|
|
21
|
+
readonly kind: 'file';
|
|
22
|
+
readonly path: string; // absolute
|
|
23
|
+
readonly headingPath: readonly string[];
|
|
24
|
+
readonly lineStart: number;
|
|
25
|
+
readonly lineEnd: number;
|
|
26
|
+
readonly tableRow?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface SessionAnchor {
|
|
29
|
+
readonly kind: 'session';
|
|
30
|
+
readonly host: SessionHost;
|
|
31
|
+
readonly sessionId: string;
|
|
32
|
+
readonly file: string; // native log file
|
|
33
|
+
readonly cwd: string | null;
|
|
34
|
+
/** Message position inside the native log; the range covers one segment. */
|
|
35
|
+
readonly messageStart: number;
|
|
36
|
+
readonly messageEnd: number;
|
|
37
|
+
readonly at: string | null; // ISO time of the first message in the range
|
|
38
|
+
}
|
|
39
|
+
export interface CommitAnchor {
|
|
40
|
+
readonly kind: 'commit';
|
|
41
|
+
readonly repo: string;
|
|
42
|
+
readonly commit: string;
|
|
43
|
+
/** When the commit was made, as git records it (author date, ISO 8601 with its offset). Absent on commit sources
|
|
44
|
+
* written before intake recorded it. */
|
|
45
|
+
readonly at?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface CommandAnchor {
|
|
48
|
+
readonly kind: 'command';
|
|
49
|
+
readonly command: string;
|
|
50
|
+
readonly cwd: string;
|
|
51
|
+
readonly ranAt: string;
|
|
52
|
+
}
|
|
53
|
+
export interface StatusAnchor {
|
|
54
|
+
readonly kind: 'status';
|
|
55
|
+
readonly description: string; // e.g. "git status of D:\x at 2026-…"
|
|
56
|
+
readonly at: string;
|
|
57
|
+
}
|
|
58
|
+
/** A file as it was at a commit, read from version history: always `History only` (§1.2, D61). */
|
|
59
|
+
export interface RevisionAnchor {
|
|
60
|
+
readonly kind: 'revision';
|
|
61
|
+
readonly repo: string; // the repository whose history holds it (a worktree's is its main repository)
|
|
62
|
+
readonly commit: string; // full hash
|
|
63
|
+
readonly path: string; // relative to the repository root, forward slashes
|
|
64
|
+
}
|
|
65
|
+
export type SourceAnchor = FileAnchor | SessionAnchor | CommitAnchor | CommandAnchor | StatusAnchor | RevisionAnchor;
|
|
66
|
+
|
|
67
|
+
export interface Source {
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly projectId: string;
|
|
70
|
+
readonly title: string;
|
|
71
|
+
readonly anchor: SourceAnchor;
|
|
72
|
+
/** Material's own numbering found at the anchor (DEC-020, TASK-7.2, #18 …). */
|
|
73
|
+
readonly ids: readonly string[];
|
|
74
|
+
readonly version: { readonly fingerprint: string; readonly readAt: string; readonly commit: string | null };
|
|
75
|
+
/** Exact text at the anchor as it was when read. Credential values are redacted (§3.1). */
|
|
76
|
+
readonly excerpt: string;
|
|
77
|
+
readonly usedAs: UsedAs | null; // null → `Not yet judged`
|
|
78
|
+
readonly usedAsBy: 'keeper' | 'owner' | null;
|
|
79
|
+
/** The project rule this `Used as` follows (§1.15: `Reference only`, `Recovery only` → `History only`); absent or
|
|
80
|
+
* null when the Keeper judged it without one. */
|
|
81
|
+
readonly usedAsByRuleId?: string | null;
|
|
82
|
+
/** The scope item whose classification set this `Used as` (§1.1: the documents third-party material brings are
|
|
83
|
+
* `Reference only`); absent or null otherwise. It goes when the classification does. */
|
|
84
|
+
readonly usedAsByScopeItemId?: string | null;
|
|
85
|
+
readonly availability: Availability | null;
|
|
86
|
+
readonly movedTo: string | null;
|
|
87
|
+
/** Scope item this source belongs to (main project, a copy, a worktree …). */
|
|
88
|
+
readonly scopeItemId: string;
|
|
89
|
+
readonly hasCredential: boolean;
|
|
90
|
+
readonly bytes: number;
|
|
91
|
+
/**
|
|
92
|
+
* A message ProjectKeeper stores itself — one message of the Keeper conversation (§1.2, §6.8): who wrote it, the owner
|
|
93
|
+
* or an execution agent asking, and where their words begin in the excerpt, after the heading it is shown under. When
|
|
94
|
+
* it was said is the anchor's `at`. Written when the message is stored, so the heading's wording never decides whose
|
|
95
|
+
* words these are. Absent on material read from elsewhere, and on conversation messages stored before it was recorded,
|
|
96
|
+
* which are read from their heading.
|
|
97
|
+
*/
|
|
98
|
+
readonly said?: { readonly by: 'owner' | 'agent'; readonly wordsFrom: number };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ───────────────────────── §1.9 attribution ─────────────────────────
|
|
102
|
+
|
|
103
|
+
export interface Author {
|
|
104
|
+
readonly kind: 'owner' | 'role' | 'agent' | 'unknown';
|
|
105
|
+
readonly name: string | null; // role name, agent name, or null
|
|
106
|
+
readonly window: string | null;
|
|
107
|
+
readonly host: string | null; // claude / codex / pi …
|
|
108
|
+
readonly model: string | null;
|
|
109
|
+
}
|
|
110
|
+
export interface Attribution {
|
|
111
|
+
readonly author: Author;
|
|
112
|
+
readonly holder: { readonly role: string; readonly window: string | null } | null;
|
|
113
|
+
readonly identity: Identity;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ───────────────────────── §1.4 layered work facts ─────────────────────────
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Who made a claim and when (§2.4, D63): which report, role or agent, on which day. An agent's report is a summary of
|
|
120
|
+
* what it says it did, so it is recorded as its claim, never as a fact.
|
|
121
|
+
*/
|
|
122
|
+
export interface ClaimedBy {
|
|
123
|
+
readonly who: string; // the report, role or agent that makes the claim
|
|
124
|
+
readonly at: string; // when it was claimed, at the precision the material gives (a date stays a date, §1.8)
|
|
125
|
+
/** The project's `Untrusted` rule that covers this source, when one does (§1.15); the claim stays `Claimed`. */
|
|
126
|
+
readonly untrustedRuleId: string | null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* What reading the code found about one claim (§2.4, D63): which claim, in which order it was checked, whether the code
|
|
130
|
+
* agrees, and where it was read. It sits on the `Observed` statement of what the code shows, next to the claim, so how
|
|
131
|
+
* many claims were checked, in which order and how many did not hold can be counted from the assets.
|
|
132
|
+
*/
|
|
133
|
+
export interface CodeCheck {
|
|
134
|
+
readonly of: string; // the id of the `Claimed` statement it checks, in the same fact record
|
|
135
|
+
readonly tier: string; // the order it was checked in: the owner's words and red lines, a Done or verified status, the rest
|
|
136
|
+
readonly result: string; // Consistent | Inconsistent | Partly consistent
|
|
137
|
+
readonly anchor: { readonly repo: string | null; readonly commit: string | null; readonly file: string; readonly lines: string };
|
|
138
|
+
}
|
|
139
|
+
export interface Statement {
|
|
140
|
+
readonly id: string;
|
|
141
|
+
readonly type: StatementType;
|
|
142
|
+
readonly text: string;
|
|
143
|
+
readonly sourceIds: readonly string[];
|
|
144
|
+
/** Every `Claimed` statement written since v2.8 carries it; older ones do not. */
|
|
145
|
+
readonly claimedBy?: ClaimedBy;
|
|
146
|
+
/** On an `Observed` statement of what the code shows: the claim it checks and what the check found (§2.4). */
|
|
147
|
+
readonly check?: CodeCheck;
|
|
148
|
+
}
|
|
149
|
+
export interface RecordedDecision {
|
|
150
|
+
readonly text: string;
|
|
151
|
+
readonly by: Attribution;
|
|
152
|
+
readonly sourceIds: readonly string[];
|
|
153
|
+
/** Set when the decision is recorded in the project's own decision record. */
|
|
154
|
+
readonly documented: boolean;
|
|
155
|
+
}
|
|
156
|
+
export interface RecordedChange {
|
|
157
|
+
readonly text: string;
|
|
158
|
+
readonly sourceIds: readonly string[];
|
|
159
|
+
readonly changeRecordId: string | null;
|
|
160
|
+
}
|
|
161
|
+
/** What one cognitive job actually received (§3.3 "每次整理只拿这项工作需要的输入"). */
|
|
162
|
+
export interface JobInputs {
|
|
163
|
+
readonly jobId: string;
|
|
164
|
+
readonly sourceIds: readonly string[];
|
|
165
|
+
readonly factRecordIds: readonly string[];
|
|
166
|
+
readonly threadIds: readonly string[];
|
|
167
|
+
readonly areaIds: readonly string[];
|
|
168
|
+
readonly referenceIds: readonly string[];
|
|
169
|
+
readonly noteIds: readonly string[];
|
|
170
|
+
readonly location: string; // project positioning text given to the job
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface FactRecord {
|
|
174
|
+
readonly id: string;
|
|
175
|
+
readonly projectId: string;
|
|
176
|
+
readonly title: string;
|
|
177
|
+
/** The single material or session segment this record was formed from. */
|
|
178
|
+
readonly aboutSourceIds: readonly string[];
|
|
179
|
+
readonly statements: readonly Statement[];
|
|
180
|
+
readonly decisions: readonly RecordedDecision[];
|
|
181
|
+
readonly changes: readonly RecordedChange[];
|
|
182
|
+
readonly openQuestions: readonly string[];
|
|
183
|
+
/** Execution and QC facts kept with the record (§1.4). */
|
|
184
|
+
readonly executionFacts: readonly Statement[];
|
|
185
|
+
readonly language: string;
|
|
186
|
+
readonly inputs: JobInputs;
|
|
187
|
+
readonly asOf: string;
|
|
188
|
+
readonly updatedAt: string;
|
|
189
|
+
readonly pendingSourceIds: readonly string[]; // new material not yet merged (§1.4)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface ServesClaim {
|
|
193
|
+
readonly referenceId: string;
|
|
194
|
+
readonly claim: string;
|
|
195
|
+
readonly basis: Basis;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* How a change the next round will take in reaches an entry (§1.11 `Update pending`), by the links the clerk method's
|
|
200
|
+
* assets hold (keeper/organize/update-pending.ts): the change names the entry's number; the entry cites a part of the
|
|
201
|
+
* material that changed; the change is in code a work item changed (its code territory); a step, breakpoint or send-back
|
|
202
|
+
* of the work's process rests on the material; a change recorded earlier from the same material reached it; for an area,
|
|
203
|
+
* a work item that contributes to it waits.
|
|
204
|
+
*/
|
|
205
|
+
export type PendingLink = 'Number' | 'Cited source' | 'Code territory' | 'Process' | 'Recorded change' | 'Contributing work';
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* One change an entry waits for (§1.11 `Update pending`; §7.1, §7.6: the mark names the changes it waits for): the entry of
|
|
209
|
+
* the coverage's pending list it is (the same ref and label), the parts of it that reach the entry — source ids, to read
|
|
210
|
+
* now — and how it reaches it. Written by the program from the pending list, never by a model, and gone once a round has
|
|
211
|
+
* taken the change in.
|
|
212
|
+
*/
|
|
213
|
+
export interface PendingWait {
|
|
214
|
+
readonly ref: string;
|
|
215
|
+
readonly kind: PendingMaterial['kind'];
|
|
216
|
+
readonly label: string;
|
|
217
|
+
readonly since: string;
|
|
218
|
+
readonly sourceIds: readonly string[];
|
|
219
|
+
readonly reasons: readonly { readonly link: PendingLink; readonly detail: string }[];
|
|
220
|
+
}
|
|
221
|
+
export interface WorkThread {
|
|
222
|
+
readonly id: string;
|
|
223
|
+
readonly projectId: string;
|
|
224
|
+
readonly title: string;
|
|
225
|
+
readonly ids: readonly string[]; // contract / task ids the project uses
|
|
226
|
+
readonly doing: string;
|
|
227
|
+
readonly changed: string;
|
|
228
|
+
readonly results: string;
|
|
229
|
+
readonly unresolved: string;
|
|
230
|
+
readonly doneMeans?: string; // the completion conditions the material states (§7.3 `Done means`); owner review belongs in acceptanceMeans
|
|
231
|
+
readonly acceptanceMeans?: string; // what the material says only the owner can judge (D41); never lowers progress
|
|
232
|
+
readonly acceptance?: Acceptance; // §2.2 owner acceptance, separate from progress and from any check
|
|
233
|
+
readonly executionFacts: readonly Statement[];
|
|
234
|
+
readonly qcFacts: readonly Statement[];
|
|
235
|
+
readonly factRecordIds: readonly string[];
|
|
236
|
+
readonly serves: readonly ServesClaim[];
|
|
237
|
+
readonly dependsOn: readonly { readonly threadId: string; readonly claim: string; readonly basis: Basis }[];
|
|
238
|
+
readonly progress: Progress;
|
|
239
|
+
readonly validity: Validity;
|
|
240
|
+
readonly replacedBy: string | null;
|
|
241
|
+
readonly attribution: Attribution;
|
|
242
|
+
readonly inputs: JobInputs;
|
|
243
|
+
readonly asOf: string;
|
|
244
|
+
readonly updatedAt: string;
|
|
245
|
+
/** `Update pending` (§1.11): the sources of the changes it waits for; empty when it waits for none. */
|
|
246
|
+
readonly pendingSourceIds: readonly string[];
|
|
247
|
+
/** The changes it waits for, each with how it reaches this work item; absent when it waits for none. */
|
|
248
|
+
readonly waitsFor?: readonly PendingWait[];
|
|
249
|
+
/** The project rule this work item's validity follows (§1.15, e.g. an `Obsolete` rule), when one does. */
|
|
250
|
+
readonly validityByRuleId?: string | null;
|
|
251
|
+
/** The project rule its progress is read by — the authoritative index or field (§1.15 `Authoritative`, §2.2). */
|
|
252
|
+
readonly progressByRuleId?: string | null;
|
|
253
|
+
/** The status its document writes for it, kept as written (D99; CKC-23 AC-21): not its progress, which is judged. */
|
|
254
|
+
readonly writtenStatus?: WrittenStatus | null;
|
|
255
|
+
/** Why its progress stands as it does when the material seems to say otherwise (CJ): a contract still Planned although tickets implementing it are Done. */
|
|
256
|
+
readonly progressWhy?: string | null;
|
|
257
|
+
/**
|
|
258
|
+
* CN (E152; Spec §1.4 落位): the work serves its whole plan — all of the plan's modules — and no single one (a milestone
|
|
259
|
+
* QC across every contract, a reading of the whole graph): why, in the Keeper's words. It then stands in its plan's
|
|
260
|
+
* cross-cutting cell with this reason and is not counted as work in no module. It needs a plan, and counts only while
|
|
261
|
+
* the work item serves no Area.
|
|
262
|
+
*/
|
|
263
|
+
readonly wholePlanWhy?: string | null;
|
|
264
|
+
/**
|
|
265
|
+
* CQ (D104; Spec §1.4 落位): the records lead nowhere for this work — no plan or dispatch table lists it, no prompt
|
|
266
|
+
* metadata, no contract, no decision it carries out or cites leads to a plan, no arrangement current or archived names
|
|
267
|
+
* it — and why, naming the records read. A record the program can refuse: it is refused where the records do lead to a
|
|
268
|
+
* plan (placement-inference.ts), and accepted when the chain is empty or the project has no plan layer. With it the
|
|
269
|
+
* work item is written as "no plan — why" and is not counted as work in no plan.
|
|
270
|
+
*/
|
|
271
|
+
readonly noPlanWhy?: string | null;
|
|
272
|
+
/** CQ (D104): the same for the module — the records name no Area for this work, and why. */
|
|
273
|
+
readonly noAreaWhy?: string | null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* A status a document writes in a table row (D99 "工作台是一道填空题"), copied by the fill-in tools: "ready" stays "ready";
|
|
278
|
+
* progress is the judgement's (§2.2) and is set from a written status only through the model's own mapping.
|
|
279
|
+
*/
|
|
280
|
+
export interface WrittenStatus {
|
|
281
|
+
readonly text: string;
|
|
282
|
+
/** The file source that holds the row, and the row's line. */
|
|
283
|
+
readonly sourceId: string;
|
|
284
|
+
readonly line: number;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface AreaUnderstanding {
|
|
288
|
+
readonly id: string;
|
|
289
|
+
readonly projectId: string;
|
|
290
|
+
readonly referenceId: string; // the `Area` reference item
|
|
291
|
+
readonly effectNow: string;
|
|
292
|
+
readonly gaps: string;
|
|
293
|
+
readonly contributions: readonly { readonly threadId: string; readonly claim: string; readonly basis: Basis }[];
|
|
294
|
+
readonly inputs: JobInputs;
|
|
295
|
+
readonly asOf: string;
|
|
296
|
+
readonly updatedAt: string;
|
|
297
|
+
/** `Update pending` (§1.11): the sources of the changes it waits for — its area's own, and its work items'. */
|
|
298
|
+
readonly pendingSourceIds: readonly string[];
|
|
299
|
+
/** The changes it waits for, each with how it reaches this area; absent when it waits for none. */
|
|
300
|
+
readonly waitsFor?: readonly PendingWait[];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ───────────────────────── §1.3 product reference ─────────────────────────
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* One part of a decision that a later decision superseded (§5.5: 被取代的部分标 `Replaced`,指向新决定,其余不变).
|
|
307
|
+
* A decision only part of which was superseded stays `Current`, because the rest is still in force and objects
|
|
308
|
+
* still have to follow it; what the later decision took over is recorded here and on the `replaces` relation's
|
|
309
|
+
* claim. `validity: 'Replaced'` with `replacedBy` is the other case: the whole decision went.
|
|
310
|
+
*/
|
|
311
|
+
export interface SupersededPart {
|
|
312
|
+
readonly part: string; // which part of this decision the later one took over
|
|
313
|
+
readonly byId: string; // the decision that superseded it
|
|
314
|
+
readonly basis: Basis; // Explicit when the new decision says so, Inferred when it only gives different content (§5.5)
|
|
315
|
+
readonly at: string;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Whether a decision that asks for something to be done was carried out (§2.2, v2.8). The work that carries it out is
|
|
320
|
+
* linked by `carries out`; `Partly carried out` says what is left. A decision carried out stays `Current`.
|
|
321
|
+
*/
|
|
322
|
+
export interface DecisionCarryOut {
|
|
323
|
+
readonly status: CarryOut;
|
|
324
|
+
readonly remaining: string | null; // what is still left; set for `Partly carried out`
|
|
325
|
+
readonly workIds: readonly string[]; // the work items that carry it out
|
|
326
|
+
readonly evidenceSourceIds: readonly string[]; // what shows it (code, commits, reports)
|
|
327
|
+
readonly at: string;
|
|
328
|
+
readonly jobId: string | null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface ReferenceItem {
|
|
332
|
+
readonly id: string;
|
|
333
|
+
readonly projectId: string;
|
|
334
|
+
readonly category: ReferenceCategory;
|
|
335
|
+
readonly name: string; // the project's own name/number
|
|
336
|
+
readonly ids: readonly string[];
|
|
337
|
+
readonly text: string;
|
|
338
|
+
/** Owner's own words when the item records an owner statement. */
|
|
339
|
+
readonly quote: string | null;
|
|
340
|
+
/**
|
|
341
|
+
* DA (Spec §3.11: 「owner 说“可以”时,要看它答的是什么」): for an Owner's words quote too short to stand alone, the message
|
|
342
|
+
* it answers, copied from where it was said. Absent on a quote that stands alone.
|
|
343
|
+
*/
|
|
344
|
+
readonly answers?: string | null;
|
|
345
|
+
readonly basis: Basis;
|
|
346
|
+
readonly validity: Validity;
|
|
347
|
+
readonly progress: Progress | null;
|
|
348
|
+
readonly attribution: Attribution;
|
|
349
|
+
readonly sourceIds: readonly string[];
|
|
350
|
+
readonly refines: readonly string[]; // upstream reference ids
|
|
351
|
+
readonly replacedBy: string | null;
|
|
352
|
+
/** Parts of this decision a later decision superseded while the rest stays in force (§5.5). Absent on items
|
|
353
|
+
* nothing has superseded, and on items written before the replacement check recorded parts. */
|
|
354
|
+
readonly supersededParts?: readonly SupersededPart[];
|
|
355
|
+
/** Whether a decision that asks for something was carried out (§2.2); absent until it is recorded. */
|
|
356
|
+
readonly carryOut?: DecisionCarryOut | null;
|
|
357
|
+
/** The project rule this item's validity follows (§1.15, e.g. an `Obsolete` rule), when one does. */
|
|
358
|
+
readonly validityByRuleId?: string | null;
|
|
359
|
+
readonly inputs: JobInputs | null;
|
|
360
|
+
readonly asOf: string;
|
|
361
|
+
readonly updatedAt: string;
|
|
362
|
+
/** `Update pending` (§1.11): the sources of the changes it waits for; absent or empty when it waits for none. */
|
|
363
|
+
readonly pendingSourceIds?: readonly string[];
|
|
364
|
+
/** The changes it waits for, each with how it reaches this item; absent when it waits for none. */
|
|
365
|
+
readonly waitsFor?: readonly PendingWait[];
|
|
366
|
+
/** The status its document writes for it, kept as written (D99; CKC-23 AC-21); absent when none is written. */
|
|
367
|
+
readonly writtenStatus?: WrittenStatus | null;
|
|
368
|
+
/**
|
|
369
|
+
* An Area only (D101; Spec §1.4): a cross-cutting foundation the project's own documents treat as a peer of its modules
|
|
370
|
+
* (a row of the module or scope table, a requirement-group heading, a Spec chapter tagged with it, a value of a
|
|
371
|
+
* contract's Module column). It is a column of its own under the project's name, placed after every module.
|
|
372
|
+
*/
|
|
373
|
+
readonly foundation?: boolean;
|
|
374
|
+
/**
|
|
375
|
+
* A decision, boundary, requirement or design placed on the whole product (CM; Spec §1.4 落位): why it concerns the whole
|
|
376
|
+
* product rather than an area or a plan, as written by the Keeper. The cross-cutting ring shows it; without it, an item on
|
|
377
|
+
* the product alone counts as not placed.
|
|
378
|
+
*/
|
|
379
|
+
readonly wholeProductWhy?: string | null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ───────────────────────── §1.5 / §1.6 graph ─────────────────────────
|
|
383
|
+
|
|
384
|
+
export type NodeRefKind = 'reference' | 'thread' | 'fact' | 'source' | 'change' | 'session' | 'result';
|
|
385
|
+
|
|
386
|
+
export interface GraphNode {
|
|
387
|
+
readonly id: string;
|
|
388
|
+
readonly projectId: string;
|
|
389
|
+
readonly category: NodeCategory;
|
|
390
|
+
readonly label: string;
|
|
391
|
+
readonly refKind: NodeRefKind;
|
|
392
|
+
readonly refId: string;
|
|
393
|
+
readonly validity: Validity;
|
|
394
|
+
readonly progress: Progress | null;
|
|
395
|
+
readonly acceptance?: Acceptance; // work items only; '' when the project has no acceptance step
|
|
396
|
+
readonly basis: Basis;
|
|
397
|
+
readonly attribution: Attribution | null;
|
|
398
|
+
readonly sourceIds: readonly string[];
|
|
399
|
+
readonly areaId: string | null; // owning area reference id when placed
|
|
400
|
+
readonly parentWorkId: string | null; // sessions/runs/reviews fold under their work
|
|
401
|
+
readonly replacedBy: string | null;
|
|
402
|
+
/** When the node first appeared ('' when it predates this record); stars on the graph mark new nodes (owner 2026-09-17). */
|
|
403
|
+
readonly createdAt?: string;
|
|
404
|
+
readonly updatedAt: string;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface Evidence {
|
|
408
|
+
readonly sourceIds: readonly string[];
|
|
409
|
+
readonly factRecordIds: readonly string[];
|
|
410
|
+
readonly factsSoFar: string; // e.g. "implemented, not yet verified"
|
|
411
|
+
}
|
|
412
|
+
export interface GraphRelation {
|
|
413
|
+
readonly id: string;
|
|
414
|
+
readonly projectId: string;
|
|
415
|
+
readonly type: RelationType;
|
|
416
|
+
readonly from: string;
|
|
417
|
+
readonly to: string;
|
|
418
|
+
readonly claim: string;
|
|
419
|
+
readonly basis: Basis;
|
|
420
|
+
readonly evidence: Evidence;
|
|
421
|
+
readonly assessment: Assessment;
|
|
422
|
+
readonly assessedAt: string | null;
|
|
423
|
+
readonly assessedInJobId: string | null;
|
|
424
|
+
readonly updatedAt: string;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ───────────────────────── §1.7 notes ─────────────────────────
|
|
428
|
+
|
|
429
|
+
export interface NoteFact {
|
|
430
|
+
readonly text: string;
|
|
431
|
+
readonly sourceIds: readonly string[];
|
|
432
|
+
readonly inferred: boolean;
|
|
433
|
+
/** The note that puts a round's inferred rules to the owner (§1.15, §3.9): the rule this fact is about — a link, so its sentence carries no id (D105). */
|
|
434
|
+
readonly ruleId?: string;
|
|
435
|
+
}
|
|
436
|
+
/** One choice a `For your decision` note puts to the owner (§4.2, D105): what is chosen, and what follows from choosing it. */
|
|
437
|
+
export interface NoteOption {
|
|
438
|
+
readonly option: string;
|
|
439
|
+
readonly then: string;
|
|
440
|
+
}
|
|
441
|
+
export interface NoteBody {
|
|
442
|
+
/**
|
|
443
|
+
* A `For your decision` note's options, one per choice, at least two (§4.2, D105; CKC-08 AC-26): they come after the
|
|
444
|
+
* first sentence (the preview: the question) and the background. Absent on other notes, and on notes written before D105.
|
|
445
|
+
*/
|
|
446
|
+
readonly options?: readonly NoteOption[];
|
|
447
|
+
readonly currentView: string | null;
|
|
448
|
+
readonly whyItMatters: string | null;
|
|
449
|
+
readonly facts: readonly NoteFact[];
|
|
450
|
+
readonly otherExplanations: string | null;
|
|
451
|
+
readonly keepAdjust: string | null;
|
|
452
|
+
readonly whatWouldSettleIt: string | null;
|
|
453
|
+
}
|
|
454
|
+
export interface NoteVersion {
|
|
455
|
+
readonly version: number;
|
|
456
|
+
readonly at: string;
|
|
457
|
+
readonly title: string;
|
|
458
|
+
readonly preview: string;
|
|
459
|
+
readonly body: NoteBody;
|
|
460
|
+
readonly ask: NoteAsk;
|
|
461
|
+
readonly judgementRecordId: string; // `Based on`
|
|
462
|
+
readonly reason: string; // why this version exists
|
|
463
|
+
}
|
|
464
|
+
export interface NoteMount {
|
|
465
|
+
readonly kind: 'project' | 'node' | 'relation' | 'path';
|
|
466
|
+
readonly ids: readonly string[];
|
|
467
|
+
}
|
|
468
|
+
export interface DiscussionEntry {
|
|
469
|
+
readonly role: 'owner' | 'keeper';
|
|
470
|
+
readonly text: string;
|
|
471
|
+
readonly at: string;
|
|
472
|
+
readonly sourceId: string | null;
|
|
473
|
+
}
|
|
474
|
+
export interface FollowUp {
|
|
475
|
+
readonly kind: 'investigation' | 'adjustment' | 'relook' | 'request';
|
|
476
|
+
readonly jobId: string | null;
|
|
477
|
+
readonly at: string;
|
|
478
|
+
readonly summary: string;
|
|
479
|
+
}
|
|
480
|
+
export interface NoteCameFrom {
|
|
481
|
+
/** One of the four; null when the work that wrote it is none of them (e.g. organizing a material). */
|
|
482
|
+
readonly kind: NoteOrigin | null;
|
|
483
|
+
/** The writing job's own kind, kept so the four can be refined later without re-deriving. */
|
|
484
|
+
readonly jobKind: string | null;
|
|
485
|
+
readonly jobId: string | null;
|
|
486
|
+
/** For a change follow-up: the change or changes the note is about. */
|
|
487
|
+
readonly changeIds: readonly string[];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export interface Note {
|
|
491
|
+
readonly id: string;
|
|
492
|
+
readonly projectId: string;
|
|
493
|
+
readonly mount: NoteMount;
|
|
494
|
+
readonly status: NoteStatus;
|
|
495
|
+
readonly ownerResponse: OwnerResponse | null;
|
|
496
|
+
readonly versions: readonly NoteVersion[]; // last = current
|
|
497
|
+
readonly discussion: readonly DiscussionEntry[];
|
|
498
|
+
readonly followUps: readonly FollowUp[];
|
|
499
|
+
readonly author: { readonly agent: string; readonly model: string | null };
|
|
500
|
+
readonly resolvedReason: string | null;
|
|
501
|
+
readonly withdrawnReason: string | null;
|
|
502
|
+
readonly delegatedTo: { readonly holder: string; readonly requestId: string; readonly handledAt: string | null } | null;
|
|
503
|
+
/** How the note came about (Spec §4.1); absent on notes written before it was recorded, until they are backfilled. */
|
|
504
|
+
readonly cameFrom?: NoteCameFrom | null;
|
|
505
|
+
/** Which of the six things the owner judges this note is about (§2.13), e.g. `Dropped along the way?` (3), `Ratify?` (4). */
|
|
506
|
+
readonly sixThing?: SixThing | null;
|
|
507
|
+
/**
|
|
508
|
+
* CN (E152; Spec §2.12): what an absence claim in this note rests on — where it was looked for and up to when. A note
|
|
509
|
+
* that says something has no follow-up, was let pass or was taken up by nobody carries it (keeper/organize/absence.ts).
|
|
510
|
+
*/
|
|
511
|
+
readonly looked?: AbsenceLooked | null;
|
|
512
|
+
readonly language: string;
|
|
513
|
+
readonly updatedAt: string;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ───────────────────────── §1.8 change records ─────────────────────────
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* The piece of work one change record covers (§1.8, D56): one session or one execution, together with the files it
|
|
520
|
+
* changed and the commits it made. A piece of work never spans two Follow up rounds — a session still running when
|
|
521
|
+
* a round starts is organized only up to its last pause, and the rest becomes another piece of work next round.
|
|
522
|
+
*/
|
|
523
|
+
export interface WorkSegment {
|
|
524
|
+
readonly kind: WorkSegmentKind;
|
|
525
|
+
readonly label: string; // which session or execution, or how the time range was cut
|
|
526
|
+
readonly sessionId: string | null;
|
|
527
|
+
readonly startedAt: string;
|
|
528
|
+
readonly endedAt: string; // the last pause when the work had not finished
|
|
529
|
+
/** True when the work was still going at `endedAt`: what came after belongs to the next round's record. */
|
|
530
|
+
readonly openEnded: boolean;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* One net change inside a piece of work (§1.8). A piece of work that fixed 7 problems has 7 items; each carries its
|
|
535
|
+
* own category, effect, before and after, basis, and the objects it directly changed.
|
|
536
|
+
*/
|
|
537
|
+
export interface ChangeItem {
|
|
538
|
+
readonly id: string;
|
|
539
|
+
readonly at: string;
|
|
540
|
+
readonly atSource: 'material' | 'observed';
|
|
541
|
+
readonly material: ChangeMaterial;
|
|
542
|
+
readonly effect: ChangeEffect;
|
|
543
|
+
readonly title: string;
|
|
544
|
+
readonly summary: string;
|
|
545
|
+
readonly before: string | null;
|
|
546
|
+
readonly after: string | null;
|
|
547
|
+
readonly sourceIds: readonly string[]; // basis: which file, commit or session segment of this work
|
|
548
|
+
readonly by: Attribution;
|
|
549
|
+
/** Why this change was made, in the material's own terms — the owner asked for it, a trial showed the old shape
|
|
550
|
+
* failed, a contract required it. `Changes since last session` says what changed *and why* (D59 design 2), and
|
|
551
|
+
* only the material this work came from knows the why; a later reader cannot recover it. Empty when the material
|
|
552
|
+
* gives no reason: that is a fact about the material, not a gap to fill in. */
|
|
553
|
+
readonly why: string | null;
|
|
554
|
+
/** The objects this item directly changed — its subject. Downstream is found from here (§5.5); the subject
|
|
555
|
+
* itself is not downstream of its own item. */
|
|
556
|
+
readonly affects: readonly string[];
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** §2.10 an object listed in the change's detail but never judged, with the reason it is not. */
|
|
560
|
+
export interface NotJudgedEntry {
|
|
561
|
+
readonly nodeId: string;
|
|
562
|
+
readonly reason: NotJudgedReason;
|
|
563
|
+
readonly at: string;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* One item of one record, as an object's judgement refers to it. `itemId` is empty for a record written before
|
|
568
|
+
* items existed, which counts as one item covering the whole record.
|
|
569
|
+
*/
|
|
570
|
+
export interface ItemRef {
|
|
571
|
+
readonly changeId: string;
|
|
572
|
+
readonly itemId: string;
|
|
573
|
+
}
|
|
574
|
+
export interface LackedItem extends ItemRef {
|
|
575
|
+
readonly what: string; // what the object still has to follow
|
|
576
|
+
}
|
|
577
|
+
/** Who said an item need not be handled, and where they said it (§2.10: only the owner or the object's holder can,
|
|
578
|
+
* and it is read from the owner's response or from later material). */
|
|
579
|
+
export interface ItemCloseAuthority {
|
|
580
|
+
readonly who: 'owner' | 'holder';
|
|
581
|
+
readonly role: string | null; // the holder's role; null when the owner said it
|
|
582
|
+
readonly sourceId: string; // the material that carries what they said
|
|
583
|
+
}
|
|
584
|
+
/** An item that has ended: the object followed it, a later change superseded it, or nobody has to handle it.
|
|
585
|
+
* The last two carry what makes them checkable; both fields are absent on entries written before that was
|
|
586
|
+
* recorded, which is why they are optional here and required by the tool that writes new ones. */
|
|
587
|
+
export interface ClosedItem extends ItemRef {
|
|
588
|
+
readonly close: ItemClose;
|
|
589
|
+
readonly reason: string;
|
|
590
|
+
/** `Superseded by a later change`: the change record whose later content took this item's place. */
|
|
591
|
+
readonly supersededByChangeId?: string;
|
|
592
|
+
/** `No action needed`: who said so, and the material that shows it. */
|
|
593
|
+
readonly saidBy?: ItemCloseAuthority;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
export interface PropagationEntry {
|
|
597
|
+
readonly nodeId: string;
|
|
598
|
+
readonly state: Propagation;
|
|
599
|
+
readonly sourceOrReason: string;
|
|
600
|
+
readonly updatedAt: string;
|
|
601
|
+
/** The round whose one judgement of this object produced the entry, and which items of this record it covered. */
|
|
602
|
+
readonly roundId?: string;
|
|
603
|
+
readonly itemIds?: readonly string[];
|
|
604
|
+
}
|
|
605
|
+
export interface ChangeRecord {
|
|
606
|
+
readonly id: string;
|
|
607
|
+
readonly projectId: string;
|
|
608
|
+
readonly at: string;
|
|
609
|
+
readonly atSource: 'material' | 'observed';
|
|
610
|
+
readonly material: ChangeMaterial;
|
|
611
|
+
readonly effect: ChangeEffect;
|
|
612
|
+
readonly title: string;
|
|
613
|
+
readonly summary: string;
|
|
614
|
+
readonly before: string | null;
|
|
615
|
+
readonly after: string | null;
|
|
616
|
+
readonly sourceIds: readonly string[];
|
|
617
|
+
readonly by: Attribution;
|
|
618
|
+
readonly affects: readonly string[]; // node ids: the union of the items' subjects
|
|
619
|
+
readonly propagation: readonly PropagationEntry[];
|
|
620
|
+
readonly segment: { readonly name: string; readonly sourceId: string } | null;
|
|
621
|
+
readonly createdInJobId: string | null;
|
|
622
|
+
readonly updatedAt: string;
|
|
623
|
+
/** The piece of work this record covers (D56); absent on records written before it was recorded. */
|
|
624
|
+
readonly work?: WorkSegment | null;
|
|
625
|
+
/** This piece of work's net changes. Absent on a record written before items existed: the record's own
|
|
626
|
+
* material, effect, before and after are then read as its single item. */
|
|
627
|
+
readonly items?: readonly ChangeItem[];
|
|
628
|
+
/** Objects the record reached that are never judged (§2.10): listed here, not in `propagation`. */
|
|
629
|
+
readonly notJudged?: readonly NotJudgedEntry[];
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* One object's judgement for one round (§2.10, §5.5; D56). Every item that reached the object this round, plus the
|
|
634
|
+
* items on it with no conclusion yet, are judged together and get one state — not one state per change and object.
|
|
635
|
+
* On the 2026-09-18 assets the pairwise form gave 233 objects 5,237 judgements, and the real findings were buried.
|
|
636
|
+
*/
|
|
637
|
+
export interface ObjectJudgement {
|
|
638
|
+
readonly id: string; // `${roundId}:${nodeId}`
|
|
639
|
+
readonly projectId: string;
|
|
640
|
+
readonly nodeId: string;
|
|
641
|
+
readonly roundId: string;
|
|
642
|
+
readonly state: Propagation;
|
|
643
|
+
readonly sourceOrReason: string;
|
|
644
|
+
/** Which records and which of their items this state covers. */
|
|
645
|
+
readonly covers: readonly ItemRef[];
|
|
646
|
+
readonly followed: readonly ItemRef[];
|
|
647
|
+
/** What the object still lacks; each stays until it is followed, superseded, or declared not to need handling. */
|
|
648
|
+
readonly lacks: readonly LackedItem[];
|
|
649
|
+
readonly closed: readonly ClosedItem[];
|
|
650
|
+
/** The object's own `updatedAt` when it was judged: the judgement re-opens as soon as the object changes. */
|
|
651
|
+
readonly objectUpdatedAt: string;
|
|
652
|
+
readonly jobId: string | null;
|
|
653
|
+
readonly at: string;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* One round of Follow up (§3.8, §5.5): one main job, one result. Every count in the result is taken from the assets
|
|
658
|
+
* by the program (D43); the model writes only the sentences.
|
|
659
|
+
*/
|
|
660
|
+
export interface RoundCounts {
|
|
661
|
+
readonly objectsJudged: number;
|
|
662
|
+
readonly byState: Readonly<Record<string, number>>;
|
|
663
|
+
readonly behind: number;
|
|
664
|
+
readonly itemsLacked: number;
|
|
665
|
+
readonly notJudged: number;
|
|
666
|
+
readonly requests: number;
|
|
667
|
+
readonly notes: number;
|
|
668
|
+
readonly decisionsReplaced: number;
|
|
669
|
+
readonly decisionsSuspected: number;
|
|
670
|
+
/**
|
|
671
|
+
* What the round made new, counted from its news (§3.8; CKC-07 AC-27, CKC-24 AC-15): breakpoints newly lit, send-backs
|
|
672
|
+
* new and moved, what newly became one of the six things, semantic patches confirmed, notes written or updated.
|
|
673
|
+
* Absent on a result closed before rounds counted them.
|
|
674
|
+
*/
|
|
675
|
+
readonly news?: { readonly breakpoints: number; readonly sendbacksNew: number; readonly sendbacksMoved: number; readonly sixThings: number; readonly patches: number; readonly notes: number };
|
|
676
|
+
}
|
|
677
|
+
export interface RoundResult {
|
|
678
|
+
readonly at: string;
|
|
679
|
+
readonly summary: string; // the round's own account, written by the main job
|
|
680
|
+
readonly counts: RoundCounts; // counted by the program, never by the model
|
|
681
|
+
readonly behind: readonly { readonly nodeId: string; readonly holder: string | null; readonly lacks: number }[];
|
|
682
|
+
readonly byHolder: readonly { readonly holder: string; readonly requestId: string; readonly nodeIds: readonly string[] }[];
|
|
683
|
+
readonly noteIds: readonly string[];
|
|
684
|
+
readonly unassigned: readonly string[]; // objects behind with no holder the Keeper could identify
|
|
685
|
+
/** What the round made new, each with its position, or that it found nothing new (§3.8, D79). Absent on older results. */
|
|
686
|
+
readonly news?: RoundNews | null;
|
|
687
|
+
}
|
|
688
|
+
export interface FollowUpRound {
|
|
689
|
+
readonly id: string;
|
|
690
|
+
readonly projectId: string;
|
|
691
|
+
readonly number: number;
|
|
692
|
+
readonly startedAt: string;
|
|
693
|
+
readonly endedAt: string | null;
|
|
694
|
+
readonly mainJobId: string | null;
|
|
695
|
+
readonly result: RoundResult | null;
|
|
696
|
+
/** When the owner opened this round's result. `Notes (attention)` carries one item per round and it leaves once
|
|
697
|
+
* they have looked (D56 item 3). */
|
|
698
|
+
readonly seenAt?: string | null;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// ───────────────────────── §1.11 marks and coverage ─────────────────────────
|
|
702
|
+
|
|
703
|
+
export interface EntryMark {
|
|
704
|
+
readonly id: string;
|
|
705
|
+
readonly projectId: string;
|
|
706
|
+
readonly kind: MarkKind;
|
|
707
|
+
readonly targetId: string; // node, reference, thread or source id
|
|
708
|
+
readonly clueSourceIds: readonly string[];
|
|
709
|
+
readonly clue: string;
|
|
710
|
+
readonly since: string;
|
|
711
|
+
readonly noteId: string | null;
|
|
712
|
+
readonly closed: { readonly result: MarkClose; readonly at: string; readonly reason: string } | null;
|
|
713
|
+
/** `Decided without owner`: who set the rule in the owner's place and when (§1.9, §2.6). */
|
|
714
|
+
readonly decidedBy?: { readonly who: string; readonly at: string } | null;
|
|
715
|
+
/** Which of the six things the owner judges this mark is material for (§2.13), when it is one; for `Filter`. */
|
|
716
|
+
readonly sixThing?: SixThing | null;
|
|
717
|
+
/** CN: what was read before it was judged dropped along the way or let pass (keeper/organize/absence.ts). */
|
|
718
|
+
readonly looked?: AbsenceLooked | null;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
export interface PendingMaterial {
|
|
722
|
+
readonly kind: 'file' | 'session' | 'commit' | 'worktree' | 'task' | 'qc' | 'other';
|
|
723
|
+
readonly ref: string; // path, session file, commit …
|
|
724
|
+
readonly label: string;
|
|
725
|
+
readonly since: string;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* A file over the size intake reads of one file (§1.11 `Skipped: too large`, D105): its text is not read; the ledger
|
|
729
|
+
* still records its path, size and versions. Not a failure and not pending.
|
|
730
|
+
*/
|
|
731
|
+
export interface SkippedMaterial {
|
|
732
|
+
readonly ref: string;
|
|
733
|
+
/** Its size when it was skipped; null for an entry an older home recorded as a failure, whose file is gone since. */
|
|
734
|
+
readonly bytes: number | null;
|
|
735
|
+
/** The most intake reads of one file, in bytes. */
|
|
736
|
+
readonly limit: number;
|
|
737
|
+
readonly at: string;
|
|
738
|
+
}
|
|
739
|
+
export interface CoverageScope {
|
|
740
|
+
readonly id: string; // 'project' or area/thread id
|
|
741
|
+
readonly kind: 'project' | 'area' | 'thread';
|
|
742
|
+
readonly label: string;
|
|
743
|
+
readonly coverage: CoverageLabel;
|
|
744
|
+
readonly asOf: string | null;
|
|
745
|
+
readonly commit: string | null;
|
|
746
|
+
readonly pending: readonly PendingMaterial[];
|
|
747
|
+
readonly organizing: readonly PendingMaterial[];
|
|
748
|
+
/** What went wrong while organizing and stayed undone after the retries (§3.10). A file too large to read is not here (D105). */
|
|
749
|
+
readonly failed: readonly { readonly ref: string; readonly reason: string; readonly at: string }[];
|
|
750
|
+
/** `Skipped: too large` (§1.11, §6.7): listed in Project scope, not counted in the top bar. Absent in a home written before D105. */
|
|
751
|
+
readonly skipped?: readonly SkippedMaterial[];
|
|
752
|
+
readonly lastRelookAt: string | null;
|
|
753
|
+
}
|
|
754
|
+
/** §1.11 materials of one organizing level, counted by material kind. */
|
|
755
|
+
export interface LevelCount {
|
|
756
|
+
readonly level: OrganizingLevel;
|
|
757
|
+
readonly byKind: Readonly<Record<string, number>>;
|
|
758
|
+
readonly materials: number;
|
|
759
|
+
readonly chars: number;
|
|
760
|
+
}
|
|
761
|
+
/** §3.7 one takeover depth option with this project's actual figures (CKC-13 AC-19). */
|
|
762
|
+
export interface DepthOption {
|
|
763
|
+
readonly depth: TakeoverDepth;
|
|
764
|
+
readonly levels: readonly LevelCount[];
|
|
765
|
+
readonly toOrganize: number; // materials the Keeper would read, in full or for conclusions
|
|
766
|
+
readonly chars: number;
|
|
767
|
+
readonly minutes: number; // at the current parallel setting
|
|
768
|
+
readonly cost: number | null;
|
|
769
|
+
readonly lanes: number;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* §3.7 the owner's-words step of the first round, as evidence (D37): when the Keeper started reading the owner's own
|
|
773
|
+
* messages and when it wrote the last of the `Owner's words` items, how many messages and characters it read of how
|
|
774
|
+
* many there are, and how many items it wrote. Counted from the job's steps and trace, never by the model.
|
|
775
|
+
*/
|
|
776
|
+
export interface OwnerWordsStep {
|
|
777
|
+
readonly startedAt: string;
|
|
778
|
+
readonly endedAt: string;
|
|
779
|
+
readonly minutes: number;
|
|
780
|
+
readonly calls: number;
|
|
781
|
+
readonly utterances: number;
|
|
782
|
+
readonly chars: number;
|
|
783
|
+
readonly total: number;
|
|
784
|
+
readonly totalChars: number;
|
|
785
|
+
readonly items: number;
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* §3.7 by the clerk method: what a Full deepening reads path by path — counted from the ledger, by material category —
|
|
789
|
+
* what Focused covers, the stated basis of the estimates, and the deepening's progress path by path once it runs.
|
|
790
|
+
*/
|
|
791
|
+
export interface DeepeningPlan {
|
|
792
|
+
/**
|
|
793
|
+
* Each path with what it reads by category, counted by the question list (§3.7: 按问题清单算); `basis` says how a path
|
|
794
|
+
* was counted — what its brief names, or the ledger's totals for its kind of question.
|
|
795
|
+
*/
|
|
796
|
+
readonly paths: readonly { readonly path: string; readonly reads: readonly { readonly category: string; readonly count: number }[]; readonly basis?: string }[];
|
|
797
|
+
readonly focused: readonly { readonly category: string; readonly count: number }[];
|
|
798
|
+
readonly basis: string;
|
|
799
|
+
/**
|
|
800
|
+
* Each step of the deepening under way or done: its status, its time, and — once it has read — what it read against its
|
|
801
|
+
* path's plan. A path read by reading assignments is one row with `reading`, however many assignments it took.
|
|
802
|
+
*/
|
|
803
|
+
readonly progress: readonly { readonly path: string; readonly status: string; readonly minutes: number | null; readonly reads?: DeepeningReads; readonly reading?: PathReading }[];
|
|
804
|
+
/** The deepening as it ran, beside the estimate (CKC-13 AC-8): what the whole round read against the plan, its time and cost. */
|
|
805
|
+
readonly actual?: DeepeningActual | null;
|
|
806
|
+
/** How a deepening read by assignments is counted and how its assignments are sized, in words; absent before one ran. */
|
|
807
|
+
readonly readingBasis?: string | null;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* One path of a Full deepening read by reading assignments (Spec §3.3, §3.7; the owner's approval of 2026-09-28): what it
|
|
811
|
+
* planned, what was read of it, what the round recorded as read in part or not read — each with why — what is still open,
|
|
812
|
+
* and its assignments. Counted by the program from the assignments' recorded reads (`JobStep.reads`); never by a model.
|
|
813
|
+
*/
|
|
814
|
+
export interface PathReading {
|
|
815
|
+
readonly planned: number;
|
|
816
|
+
/** Read whole. */
|
|
817
|
+
readonly whole: number;
|
|
818
|
+
/** Read in part, recorded with why. */
|
|
819
|
+
readonly part: number;
|
|
820
|
+
/** Recorded as not read, with why. */
|
|
821
|
+
readonly notRead: number;
|
|
822
|
+
/** Not accounted for yet: an assignment (a first one or a follow-up) still has it. */
|
|
823
|
+
readonly open: number;
|
|
824
|
+
readonly assignments: {
|
|
825
|
+
readonly total: number; readonly done: number; readonly running: number; readonly queued: number; readonly failed: number;
|
|
826
|
+
/** Of `total`, the follow-ups: assignments that took up what earlier ones left unread. */
|
|
827
|
+
readonly followUps: number;
|
|
828
|
+
};
|
|
829
|
+
/** Each planned material recorded as read in part or not read, with why and who said it. */
|
|
830
|
+
readonly accounted: readonly { readonly key: string; readonly label: string; readonly outcome: 'part' | 'none'; readonly why: string; readonly by: 'assignment' | 'program' }[];
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* What a deepening step read against what its path planned (§3.7; CKC-13 AC-8), in the plan's units: a document version,
|
|
834
|
+
* a code file, a commit — and a session, for a path counted by the ledger's totals. Counted from what the step's jobs read
|
|
835
|
+
* (`JobStep.reads`), never written by a model.
|
|
836
|
+
*/
|
|
837
|
+
export interface DeepeningReads {
|
|
838
|
+
/** What the path planned to read closely (as `paths` counts it); null for a step no path plans (cross-check, synthesis, spot-check). */
|
|
839
|
+
readonly planned: number | null;
|
|
840
|
+
/** Of what was planned: read whole, read only in part; and `left`, planned and not read at all (null with no plan). */
|
|
841
|
+
readonly whole: number;
|
|
842
|
+
readonly part: number;
|
|
843
|
+
readonly left: number | null;
|
|
844
|
+
/** What was read that the plan does not name — for a step with no plan, everything it read. */
|
|
845
|
+
readonly beyond: { readonly whole: number; readonly part: number };
|
|
846
|
+
/** The same by category (document versions, code files, commits, sessions); a category with nothing planned or read is left out. */
|
|
847
|
+
readonly byCategory: readonly ({ readonly category: string } & Omit<DeepeningReads, 'byCategory'>)[];
|
|
848
|
+
}
|
|
849
|
+
/** The deepening round as it ran: what it read against the plan (every step of it together), its time and its cost. */
|
|
850
|
+
export interface DeepeningActual extends DeepeningReads {
|
|
851
|
+
readonly depth: TakeoverDepth;
|
|
852
|
+
readonly roundId: string;
|
|
853
|
+
readonly status: string;
|
|
854
|
+
readonly minutes: number | null;
|
|
855
|
+
readonly cost: number | null;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* The materials a job read only in part (CKC-13 AC-8), counted beside the levels: §1.11 has no level for a part read, so
|
|
859
|
+
* such a material stays at the level it has otherwise — mostly `Indexed` — and `byLevel` says which.
|
|
860
|
+
*/
|
|
861
|
+
export interface PartReads {
|
|
862
|
+
readonly materials: number;
|
|
863
|
+
readonly byKind: Readonly<Record<string, number>>;
|
|
864
|
+
readonly chars: number;
|
|
865
|
+
readonly byLevel: Readonly<Record<string, number>>;
|
|
866
|
+
}
|
|
867
|
+
/** §3.7 takeover progress: depth, stage, the first usable slice as evidence (D37), levels, remaining work, the three options. */
|
|
868
|
+
export interface TakeoverStatus {
|
|
869
|
+
readonly depth: TakeoverDepth | 'Depth not chosen';
|
|
870
|
+
/** `Not started`: the owner has not pressed `Start` (D105). The depth is chosen before the start, so no stage asks for it. */
|
|
871
|
+
readonly stage: 'Not started' | 'First usable' | 'Deepening' | 'Daily';
|
|
872
|
+
readonly firstUsable: { readonly startedAt: string; readonly completedAt: string | null; readonly minutes: number | null; readonly byKind: Readonly<Record<string, number>>; readonly chars?: number; readonly share?: number | null; readonly ownerWords?: OwnerWordsStep | null };
|
|
873
|
+
readonly levels: readonly LevelCount[]; // every material of the project, by level
|
|
874
|
+
/** Beside the levels: the materials a job read only in part (they stay at their level). Absent on coverage written before it was counted. */
|
|
875
|
+
readonly readInPart?: PartReads;
|
|
876
|
+
readonly sampled: readonly { readonly rule: string; readonly samples: readonly string[]; readonly members: number }[];
|
|
877
|
+
readonly remaining: { readonly materials: number; readonly minutes: number; readonly cost: number | null } | null; // under the chosen depth
|
|
878
|
+
readonly options: readonly DepthOption[];
|
|
879
|
+
/**
|
|
880
|
+
* `perMaterial`: the time and cost of reading one planned material, measured from this project's own jobs — a finished
|
|
881
|
+
* deepening's reading assignments, else the first usable round's steps — and what they were measured from.
|
|
882
|
+
*/
|
|
883
|
+
readonly rates: { readonly basis: string; readonly msPerChar: number; readonly costPerChar: number | null; readonly perMaterial?: { readonly minutes: number; readonly cost: number | null; readonly from: string } | null };
|
|
884
|
+
/**
|
|
885
|
+
* The history-tier materials (older than the takeover and outside the first usable slice) whose level is `Indexed`,
|
|
886
|
+
* `Sampled` or `Not organized` — counted from the levels, whatever the depth (CKC-13 AC-10: what is left is listed).
|
|
887
|
+
*/
|
|
888
|
+
readonly historyNotOrganized: number;
|
|
889
|
+
readonly noteId: string | null;
|
|
890
|
+
/** By the clerk method: the deepening's paths, what they read, and their progress (§3.7). */
|
|
891
|
+
readonly deepening?: DeepeningPlan | null;
|
|
892
|
+
}
|
|
893
|
+
export interface Coverage {
|
|
894
|
+
readonly projectId: string;
|
|
895
|
+
readonly state: UnderstandingState;
|
|
896
|
+
readonly scopes: readonly CoverageScope[];
|
|
897
|
+
readonly missingSourceKinds: readonly { readonly kind: string; readonly reason: string }[];
|
|
898
|
+
readonly processedByKind: Readonly<Record<string, number>>;
|
|
899
|
+
readonly pendingByKind: Readonly<Record<string, number>>;
|
|
900
|
+
readonly takeover?: TakeoverStatus | null;
|
|
901
|
+
/**
|
|
902
|
+
* The last Follow up round that closed, for the top bar (§6.2): when it ended and whether it found anything new — "the
|
|
903
|
+
* last round found nothing new" is said here and nowhere else when it did not (CKC-07 AC-27, CKC-24 AC-15).
|
|
904
|
+
*/
|
|
905
|
+
readonly lastFollowUp?: { readonly recordId: string; readonly round: number; readonly endedAt: string; readonly nothingNew: boolean; readonly statement: string } | null;
|
|
906
|
+
readonly updatedAt: string;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// ───────────────────────── §1.13 Keeper work and judgement records ─────────────────────────
|
|
910
|
+
|
|
911
|
+
export interface Usage {
|
|
912
|
+
readonly input: number;
|
|
913
|
+
readonly output: number;
|
|
914
|
+
readonly cacheRead: number;
|
|
915
|
+
readonly cacheWrite: number;
|
|
916
|
+
readonly cost: number | null; // null when the runtime reports none
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* What one step read (Spec §1.11 `Read in full`; CKC-13 AC-8), worked out from the call and its result as the step ended
|
|
920
|
+
* (keeper/bounds/reads.ts): a file — whole, or some of its lines — a version of a document from the history, or a commit.
|
|
921
|
+
* Searching (grep and the like), listing and counting are not reading and are not here. A step recorded before this was
|
|
922
|
+
* kept has none; the coverage then counts its `target` as before.
|
|
923
|
+
*/
|
|
924
|
+
export interface StepRead {
|
|
925
|
+
/** The file, absolute. Absent: a commit was read (`rev`). */
|
|
926
|
+
readonly path?: string;
|
|
927
|
+
/** With `path`: the commit whose version of the file was read (the history, not the current file). Alone: the commit read. */
|
|
928
|
+
readonly rev?: string;
|
|
929
|
+
/** The lines shown, 1-based and inclusive. Neither given: the whole file; `to` not given: to its end. */
|
|
930
|
+
readonly from?: number;
|
|
931
|
+
readonly to?: number;
|
|
932
|
+
/** How many lines the file had when read, given with a range: whether the ranges read together cover it. */
|
|
933
|
+
readonly lines?: number;
|
|
934
|
+
/** Only a part whose lines are not known was shown: the last lines, what a pattern picked, a diff, output cut short. */
|
|
935
|
+
readonly part?: boolean;
|
|
936
|
+
/**
|
|
937
|
+
* A session read through the ledger (`pk_ledger_sessions` with a session): its ledger id. `from`, `to` and `lines` are
|
|
938
|
+
* then message positions (1-based: the ledger's message index plus one) and the session's message count.
|
|
939
|
+
*/
|
|
940
|
+
readonly session?: string;
|
|
941
|
+
}
|
|
942
|
+
export interface JobStep {
|
|
943
|
+
readonly at: string;
|
|
944
|
+
readonly tool: string;
|
|
945
|
+
readonly target: string;
|
|
946
|
+
readonly summary: string;
|
|
947
|
+
readonly isError: boolean;
|
|
948
|
+
/** What the step read (`StepRead`); absent on steps recorded before it was kept, and on steps that read nothing. */
|
|
949
|
+
readonly reads?: readonly StepRead[];
|
|
950
|
+
}
|
|
951
|
+
export interface KeeperJob {
|
|
952
|
+
readonly id: string;
|
|
953
|
+
readonly projectId: string;
|
|
954
|
+
readonly kind: JobKind;
|
|
955
|
+
readonly initiator: 'auto' | 'owner';
|
|
956
|
+
readonly scope: { readonly kind: string; readonly ids: readonly string[]; readonly label: string };
|
|
957
|
+
readonly status: JobStatus;
|
|
958
|
+
readonly queuedAt: string;
|
|
959
|
+
readonly startedAt: string | null;
|
|
960
|
+
readonly endedAt: string | null;
|
|
961
|
+
readonly savedResults: readonly { readonly collection: string; readonly id: string; readonly label: string }[];
|
|
962
|
+
readonly usage: Usage;
|
|
963
|
+
readonly agent: string; // 'pi'
|
|
964
|
+
readonly model: { readonly provider: string; readonly id: string; readonly thinking: string | null } | null;
|
|
965
|
+
readonly sessionFile: string | null;
|
|
966
|
+
readonly sessionId: string | null;
|
|
967
|
+
readonly steps: readonly JobStep[];
|
|
968
|
+
readonly error: string | null;
|
|
969
|
+
readonly requestBasis: { readonly kind: 'delegation' | 'authorization'; readonly ref: string; readonly label: string } | null;
|
|
970
|
+
readonly parentJobId: string | null;
|
|
971
|
+
readonly resultText: string | null;
|
|
972
|
+
readonly priority: number; // §3.2 order: 0 owner, 1 in-progress work, 2 re-look, 3 backlog
|
|
973
|
+
readonly task: unknown; // job-kind specific parameters, replayed on Continue/Retry
|
|
974
|
+
/** How many reads or shell commands the read boundary refused during this job (CKC-03 AC-23); each is also a step. */
|
|
975
|
+
readonly boundaryDenials?: number;
|
|
976
|
+
/**
|
|
977
|
+
* The step of a clerk-method round this job is (Spec §3.3): which round, which step, and for a deep sweep its name — and,
|
|
978
|
+
* when the sweep is read by reading assignments (§3.7), which assignment of the round's reading record this job is.
|
|
979
|
+
*/
|
|
980
|
+
readonly step?: { readonly roundId: string; readonly kind: RoundStepKind; readonly path: string | null; readonly assignment?: string | null;
|
|
981
|
+
/** D99: a lane's kind and the slots it writes; `path` is then the lane's name. */
|
|
982
|
+
readonly lane?: { readonly kind: LaneKind; readonly slots: readonly SlotKind[] } | null } | null;
|
|
983
|
+
/** Where this job's time went (§3.10, D81), filled in when it ends. */
|
|
984
|
+
readonly timing?: StepTiming | null;
|
|
985
|
+
/**
|
|
986
|
+
* The job's next run goes on in its own pi session (`sessionFile`) instead of starting over (Spec §3.10, D99): set when
|
|
987
|
+
* a run is interrupted — the model provider refused it (a rate limit, an exhausted quota) or ProjectKeeper restarted
|
|
988
|
+
* while it ran — and cleared when a run starts. `since` is when the interrupted run stopped.
|
|
989
|
+
* D99: `pause` — the owner paused organizing and the running tree was stopped to go on when it resumes (E148 D-i);
|
|
990
|
+
* `again` — the program runs the job again in its own session (a round's main job that ended before its handover, or
|
|
991
|
+
* its synthesis job that ended before the round's Result; D103).
|
|
992
|
+
* `note`: what the continued session is told besides, e.g. the stage the main agent stopped at.
|
|
993
|
+
*/
|
|
994
|
+
readonly resume?: { readonly why: 'provider' | 'restart' | 'pause' | 'again'; readonly since: string; readonly note?: string | null } | null;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
export interface JudgementRecord {
|
|
998
|
+
readonly id: string;
|
|
999
|
+
readonly projectId: string;
|
|
1000
|
+
readonly jobId: string;
|
|
1001
|
+
readonly at: string;
|
|
1002
|
+
readonly scope: { readonly kind: string; readonly ids: readonly string[]; readonly label: string };
|
|
1003
|
+
readonly inputs: {
|
|
1004
|
+
readonly referenceIds: readonly string[];
|
|
1005
|
+
readonly threadIds: readonly string[];
|
|
1006
|
+
readonly areaIds: readonly string[];
|
|
1007
|
+
readonly relationIds: readonly string[];
|
|
1008
|
+
readonly keyEvidenceSourceIds: readonly string[];
|
|
1009
|
+
readonly conflictingSourceIds: readonly string[];
|
|
1010
|
+
readonly previousNoteIds: readonly string[];
|
|
1011
|
+
readonly investigations: readonly { readonly jobId: string; readonly conclusion: string; readonly sourceIds: readonly string[] }[];
|
|
1012
|
+
/**
|
|
1013
|
+
* D103: the round documents a round's synthesis was given — the lanes' reports, the adoption record and the main
|
|
1014
|
+
* agent's handover (CKC-23 AC-8: `Based on` lists what it received). Absent on records written before, and on a
|
|
1015
|
+
* re-look outside a round.
|
|
1016
|
+
*/
|
|
1017
|
+
readonly roundDocIds?: readonly string[];
|
|
1018
|
+
};
|
|
1019
|
+
/** What was deliberately not given (e.g. "implementation session history as a whole"). */
|
|
1020
|
+
readonly excluded: readonly string[];
|
|
1021
|
+
readonly outcome: {
|
|
1022
|
+
readonly noteIds: readonly string[];
|
|
1023
|
+
readonly assessments: readonly { readonly relationId: string; readonly assessment: Assessment }[];
|
|
1024
|
+
readonly reconsideredOnly: boolean;
|
|
1025
|
+
/**
|
|
1026
|
+
* D103 (CKC-08 AC-25): the notes standing from earlier rounds this synthesis looked at again and found still to hold,
|
|
1027
|
+
* each with what it read that shows it. No new version of the note is written for it (keeper/organize/standing-notes.ts).
|
|
1028
|
+
*/
|
|
1029
|
+
readonly stillHolds?: readonly { readonly noteId: string; readonly read: readonly string[]; readonly at: string }[];
|
|
1030
|
+
};
|
|
1031
|
+
/** Thread id → `progress/validity` at judgement time; a later difference is a substantial change (§3.4). */
|
|
1032
|
+
readonly snapshot?: Readonly<Record<string, string>>;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// ───────────────────────── §1.15 the project's rules ─────────────────────────
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* One rule the project set for itself (§1.15, D62, D64): about its material (`Material rules`, with a category) or
|
|
1039
|
+
* about how it works (`How work is organized`, `Working rules`). The Keeper finds, digs out, records and follows them;
|
|
1040
|
+
* it does not set them. Rules are not areas, work items or graph nodes (R-50).
|
|
1041
|
+
*/
|
|
1042
|
+
export interface ProjectRule {
|
|
1043
|
+
readonly id: string;
|
|
1044
|
+
readonly projectId: string;
|
|
1045
|
+
readonly group: RuleGroup;
|
|
1046
|
+
readonly category: MaterialRule | null; // Material rules only
|
|
1047
|
+
readonly summary: string; // the Keeper's one sentence
|
|
1048
|
+
readonly excerpt: string | null; // the project's own words; always there when the basis is Explicit
|
|
1049
|
+
readonly sourceIds: readonly string[]; // where it is written; for an inferred rule, the records it was inferred from
|
|
1050
|
+
readonly appliesTo: readonly string[]; // directories, branches, files, fields, roles or work
|
|
1051
|
+
readonly basis: Basis;
|
|
1052
|
+
readonly validity: Validity; // a changed rule: the new one Current, the old one Replaced pointing to it
|
|
1053
|
+
readonly replacedBy: string | null;
|
|
1054
|
+
/** The owner-summarized way of working this rule belongs to (for example a role system), when it does. */
|
|
1055
|
+
readonly ownerSystem: string | null;
|
|
1056
|
+
/** Where the project's actual practice differs from it, each side with its sources; neither side is rewritten. */
|
|
1057
|
+
readonly differsInPractice: readonly { readonly text: string; readonly sourceIds: readonly string[] }[];
|
|
1058
|
+
/** §2.12: the steps this rule says the project expects of its work (`How work is organized`), read by the breakpoints. */
|
|
1059
|
+
readonly expects?: readonly ProcessExpectation[];
|
|
1060
|
+
/** The owner confirmed it: their words and the message they said them in (§3.9). */
|
|
1061
|
+
readonly ownerConfirmation: { readonly sourceId: string; readonly quote: string; readonly at: string } | null;
|
|
1062
|
+
readonly jobId: string | null;
|
|
1063
|
+
readonly asOf: string;
|
|
1064
|
+
readonly updatedAt: string;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* The plan and focus of the organizing that follows the framing round (§3.7, D62): what the rules settle directly,
|
|
1069
|
+
* what is read closely, where the focus is and in what order. The owner sees it in Project scope and corrects it in
|
|
1070
|
+
* conversation; each correction is kept with their words and with what the plan said before.
|
|
1071
|
+
*/
|
|
1072
|
+
export interface OrganizingPlanContent {
|
|
1073
|
+
readonly byRule: readonly { readonly what: string; readonly targets: readonly string[]; readonly ruleId: string; readonly treatment: string }[];
|
|
1074
|
+
readonly readClosely: readonly { readonly what: string; readonly targets: readonly string[]; readonly why: string }[];
|
|
1075
|
+
readonly focus: readonly { readonly what: string; readonly why: string; readonly sourceIds: readonly string[] }[];
|
|
1076
|
+
readonly order: readonly string[];
|
|
1077
|
+
}
|
|
1078
|
+
export interface OrganizingPlanCorrection {
|
|
1079
|
+
readonly at: string;
|
|
1080
|
+
readonly sourceId: string; // the owner's message
|
|
1081
|
+
readonly quote: string; // the owner's words
|
|
1082
|
+
readonly changed: string; // what the correction changed, in the Keeper's words
|
|
1083
|
+
readonly previous: OrganizingPlanContent; // what the plan said before it
|
|
1084
|
+
}
|
|
1085
|
+
export interface OrganizingPlan extends OrganizingPlanContent {
|
|
1086
|
+
readonly id: string;
|
|
1087
|
+
readonly projectId: string;
|
|
1088
|
+
readonly corrections: readonly OrganizingPlanCorrection[];
|
|
1089
|
+
readonly jobId: string | null;
|
|
1090
|
+
readonly asOf: string;
|
|
1091
|
+
readonly updatedAt: string;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// ───────────────────────── §1.4 merged duplicates ─────────────────────────
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* A work item merged into the one kept (§1.4; CKC-06 AC-28; E64, E65). The merged one leaves the work items, its
|
|
1098
|
+
* sources, facts and relations move over, and its id resolves to the one kept. Not `Replaced`: that is the history of
|
|
1099
|
+
* something superseded, and a merge is the same unit of work written twice.
|
|
1100
|
+
*/
|
|
1101
|
+
export interface MergeRecord {
|
|
1102
|
+
readonly id: string;
|
|
1103
|
+
readonly projectId: string;
|
|
1104
|
+
readonly kind: 'thread';
|
|
1105
|
+
readonly mergedId: string;
|
|
1106
|
+
readonly keptId: string;
|
|
1107
|
+
readonly reason: string; // why they are one unit of work
|
|
1108
|
+
readonly sourceIds: readonly string[]; // what shows it
|
|
1109
|
+
readonly merged: WorkThread; // the merged work item as it was
|
|
1110
|
+
readonly at: string;
|
|
1111
|
+
readonly jobId: string | null;
|
|
1112
|
+
readonly roundId: string | null;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// ───────────────────────── §1.14 delegation and standing authorization ─────────────────────────
|
|
1116
|
+
|
|
1117
|
+
export interface Authorization {
|
|
1118
|
+
readonly id: string;
|
|
1119
|
+
readonly projectId: string;
|
|
1120
|
+
readonly scope: string;
|
|
1121
|
+
readonly sourceId: string;
|
|
1122
|
+
readonly quote: string;
|
|
1123
|
+
readonly at: string;
|
|
1124
|
+
readonly revokedAt: string | null;
|
|
1125
|
+
readonly projectFolder?: { path: string; commits: boolean; lastWrite: { at: string; commit: string | null } | null } | null;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// ───────────────────────── §5.4 modification requests to role holders ─────────────────────────
|
|
1129
|
+
|
|
1130
|
+
export interface ModificationRequest {
|
|
1131
|
+
readonly id: string;
|
|
1132
|
+
readonly projectId: string;
|
|
1133
|
+
readonly holder: string; // role name
|
|
1134
|
+
readonly what: string;
|
|
1135
|
+
readonly why: string;
|
|
1136
|
+
readonly basisSourceIds: readonly string[];
|
|
1137
|
+
readonly impact: readonly string[]; // node ids
|
|
1138
|
+
readonly noteId: string | null;
|
|
1139
|
+
readonly at: string;
|
|
1140
|
+
readonly handled: { readonly at: string; readonly evidenceSourceIds: readonly string[] } | null;
|
|
1141
|
+
/** The Follow up round this request belongs to (§5.4, D56): one holder gets one request per round, however many
|
|
1142
|
+
* objects of theirs are behind. Absent on requests written outside a round. */
|
|
1143
|
+
readonly roundId?: string | null;
|
|
1144
|
+
/** The items this request asks the holder to follow, one line per object. */
|
|
1145
|
+
readonly lines?: readonly { readonly nodeId: string; readonly what: string; readonly changeIds: readonly string[] }[];
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// ───────────────────────── §1.12 context packages ─────────────────────────
|
|
1149
|
+
|
|
1150
|
+
export interface ContextRequest {
|
|
1151
|
+
readonly scope: { readonly kind: 'project' | 'area' | 'work' | 'path' | 'question'; readonly ids: readonly string[] };
|
|
1152
|
+
readonly purpose: ContextPurpose;
|
|
1153
|
+
readonly kind: WorkKind;
|
|
1154
|
+
readonly recipient: string; // `Incoming agent` or a recognised role
|
|
1155
|
+
readonly lastSessionAt: string | null;
|
|
1156
|
+
readonly taskVersion?: string | null; // the version the agent's task description cites (§7.3 `Version check`)
|
|
1157
|
+
}
|
|
1158
|
+
export interface ContextPackage {
|
|
1159
|
+
readonly id: string;
|
|
1160
|
+
readonly projectId: string;
|
|
1161
|
+
readonly request: ContextRequest;
|
|
1162
|
+
readonly asOf: string;
|
|
1163
|
+
readonly commit: string | null;
|
|
1164
|
+
readonly keeperStatus: string;
|
|
1165
|
+
readonly markdown: string;
|
|
1166
|
+
readonly citedSourceIds: readonly string[];
|
|
1167
|
+
readonly generatedAt: string;
|
|
1168
|
+
readonly deliveries: readonly { readonly sessionRef: string; readonly state: Delivery; readonly at: string }[];
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// ───────────────────────── §1.1 project and scope ─────────────────────────
|
|
1172
|
+
|
|
1173
|
+
export interface ScopeItem {
|
|
1174
|
+
readonly id: string;
|
|
1175
|
+
readonly path: string;
|
|
1176
|
+
readonly category: ScopeCategory;
|
|
1177
|
+
readonly relation: ScopeRelation;
|
|
1178
|
+
readonly reason: string;
|
|
1179
|
+
readonly reasonSourceIds: readonly string[];
|
|
1180
|
+
readonly sessionHost: SessionHost | null;
|
|
1181
|
+
readonly readOnly: boolean;
|
|
1182
|
+
readonly copyOf: string | null;
|
|
1183
|
+
readonly worktreeOf: string | null;
|
|
1184
|
+
readonly versionControl: 'git' | 'none' | 'unknown';
|
|
1185
|
+
readonly missing: { readonly reason: string } | null;
|
|
1186
|
+
readonly addedBy: 'keeper' | 'owner';
|
|
1187
|
+
/** §1.1 (E60): a worktree measured against the trunk from git's records — merged or not, what was skipped, what was taken. */
|
|
1188
|
+
readonly worktree?: WorktreeSummary | null;
|
|
1189
|
+
/** §1.1: the project's ignore rule that leaves this out, and what it holds. */
|
|
1190
|
+
readonly ignoredBy?: IgnoreRuleRef | null;
|
|
1191
|
+
/** §1.1: third-party material or generated output — offered by the program, judged by the Keeper, corrected by the owner. */
|
|
1192
|
+
readonly classification?: ScopeClassification | null;
|
|
1193
|
+
/** §1.15 (CKC-04 AC-1, AC-14): the project's material rules that cover this location, with their words and sources. */
|
|
1194
|
+
readonly coveredBy?: readonly ScopeRuleCover[] | null;
|
|
1195
|
+
/** §1.1: a `Session source` item's working directory — the one whose sessions it reads; intake files each session
|
|
1196
|
+
* under the item of its own directory by comparing this path. Absent on other items, and on session items recorded
|
|
1197
|
+
* before it was. */
|
|
1198
|
+
readonly sessionCwd?: string;
|
|
1199
|
+
/** Base directory holding `.claude/projects` and `.codex/sessions` for this session source. A copy may use a frozen store instead of the host home. */
|
|
1200
|
+
readonly sessionStoreRoot?: string;
|
|
1201
|
+
}
|
|
1202
|
+
/** One file a worktree contributes (§1.1, E60): an uncommitted change, or content its branch has and the trunk does not. */
|
|
1203
|
+
export interface WorktreeTaken {
|
|
1204
|
+
readonly path: string; // relative to the worktree, forward slashes
|
|
1205
|
+
readonly kind: 'Uncommitted change' | 'Changed on branch';
|
|
1206
|
+
readonly deleted?: boolean; // the change removes the file: nothing to read, still part of the work
|
|
1207
|
+
}
|
|
1208
|
+
export interface WorktreeSummary {
|
|
1209
|
+
readonly trunk: { readonly ref: string; readonly commit: string } | null;
|
|
1210
|
+
readonly branch: string | null;
|
|
1211
|
+
readonly head: string | null;
|
|
1212
|
+
readonly merged: boolean | null; // every commit of its branch is in the trunk; null when git could not tell
|
|
1213
|
+
readonly uniqueCommits: number; // commits the trunk does not have
|
|
1214
|
+
readonly files: number; // files in the worktree: tracked ones, and untracked ones not ignored
|
|
1215
|
+
readonly sameAsTrunk: number; // skipped: the same as the trunk
|
|
1216
|
+
readonly olderVersions: number; // skipped: different only because the trunk moved on; the version history keeps them
|
|
1217
|
+
readonly taken: readonly WorktreeTaken[]; // taken: uncommitted changes and what the trunk does not have
|
|
1218
|
+
readonly error: string | null;
|
|
1219
|
+
}
|
|
1220
|
+
export interface IgnoreRuleRef {
|
|
1221
|
+
readonly file: string; // the ignore file as git names it: `.gitignore`, `docs/.gitignore`, `.git/info/exclude` …
|
|
1222
|
+
readonly line: number;
|
|
1223
|
+
readonly pattern: string;
|
|
1224
|
+
readonly files: number; // files it leaves out here
|
|
1225
|
+
readonly documents: number; // of them, documents: text a person wrote (notes, plans …)
|
|
1226
|
+
readonly documentNames: readonly string[]; // the first few, for the owner
|
|
1227
|
+
/** Files ignored one by one rather than as a whole directory: which, relative to the project root. */
|
|
1228
|
+
readonly paths?: readonly string[];
|
|
1229
|
+
}
|
|
1230
|
+
export interface ScopeClassification {
|
|
1231
|
+
readonly by: 'program' | 'keeper' | 'owner';
|
|
1232
|
+
readonly basis: Basis;
|
|
1233
|
+
readonly kind: string | null; // build output, cache, installed dependencies, vendored code, upstream repository, license, linked in …
|
|
1234
|
+
readonly evidence: readonly string[]; // what shows it when no source does: a directory name, a marker file, a remote, a link target
|
|
1235
|
+
readonly sourceIds: readonly string[];
|
|
1236
|
+
readonly ruleId: string | null;
|
|
1237
|
+
readonly jobId: string | null;
|
|
1238
|
+
readonly at: string | null;
|
|
1239
|
+
}
|
|
1240
|
+
export interface ScopeRuleCover {
|
|
1241
|
+
readonly ruleId: string;
|
|
1242
|
+
readonly category: MaterialRule | null;
|
|
1243
|
+
readonly summary: string;
|
|
1244
|
+
readonly excerpt: string | null;
|
|
1245
|
+
readonly sourceIds: readonly string[];
|
|
1246
|
+
readonly basis: Basis;
|
|
1247
|
+
readonly target: string; // the rule's own words for the location (its appliesTo entry)
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* §1.1 the Keeper's classification of a location, or the owner's correction of it (CKC-04 AC-13, AC-17). The latest per
|
|
1251
|
+
* path stands; the owner's word stands over the Keeper's. A question the Keeper could not settle goes to the owner as a
|
|
1252
|
+
* scope question (§3.9).
|
|
1253
|
+
*/
|
|
1254
|
+
export interface ScopeJudgement {
|
|
1255
|
+
readonly id: string;
|
|
1256
|
+
readonly projectId: string;
|
|
1257
|
+
readonly path: string; // absolute
|
|
1258
|
+
readonly relation: ScopeRelation;
|
|
1259
|
+
readonly reason: string;
|
|
1260
|
+
readonly sourceIds: readonly string[];
|
|
1261
|
+
readonly evidence: readonly string[];
|
|
1262
|
+
readonly basis: Basis;
|
|
1263
|
+
readonly ruleId: string | null;
|
|
1264
|
+
readonly by: 'keeper' | 'owner';
|
|
1265
|
+
readonly ownerQuote: string | null;
|
|
1266
|
+
readonly question: { readonly id: string; readonly question: string; readonly whyItMatters: string; readonly clues: readonly string[]; readonly options: readonly string[] } | null;
|
|
1267
|
+
readonly previous: { readonly relation: ScopeRelation; readonly reason: string; readonly by: 'keeper' | 'owner'; readonly at: string } | null;
|
|
1268
|
+
readonly jobId: string | null;
|
|
1269
|
+
readonly at: string;
|
|
1270
|
+
}
|
|
1271
|
+
export interface ScopeQuestion {
|
|
1272
|
+
readonly id: string;
|
|
1273
|
+
readonly question: string;
|
|
1274
|
+
readonly whyItMatters: string;
|
|
1275
|
+
readonly clues: readonly string[];
|
|
1276
|
+
readonly options: readonly string[];
|
|
1277
|
+
readonly answer: { readonly text: string; readonly at: string; readonly sourceId: string | null } | null;
|
|
1278
|
+
}
|
|
1279
|
+
/** §6.7 a toolchain location the project's config points at, with the config item it came from as its reason. */
|
|
1280
|
+
export interface ToolchainLocation {
|
|
1281
|
+
readonly path: string;
|
|
1282
|
+
readonly reason: string;
|
|
1283
|
+
readonly configPath: string;
|
|
1284
|
+
/** false: listed for the owner but not a read root, because it is too broad (§3.1); absent in older records. */
|
|
1285
|
+
readonly used?: boolean;
|
|
1286
|
+
/** Why it is not used, e.g. "not used: too broad (the whole home directory)". */
|
|
1287
|
+
readonly notUsedReason?: string | null;
|
|
1288
|
+
}
|
|
1289
|
+
export interface Project {
|
|
1290
|
+
readonly id: string;
|
|
1291
|
+
readonly name: string;
|
|
1292
|
+
readonly locations: readonly string[]; // what the owner gave
|
|
1293
|
+
readonly scope: readonly ScopeItem[];
|
|
1294
|
+
readonly scopeQuestions: readonly ScopeQuestion[];
|
|
1295
|
+
readonly keeperFiles: readonly { readonly path: string; readonly kind: string }[];
|
|
1296
|
+
/** §6.7 toolchain locations the project's own config points at (an SDK, a compiler); the Keeper may read them (§3.1). */
|
|
1297
|
+
readonly toolchain?: readonly ToolchainLocation[];
|
|
1298
|
+
readonly roles: readonly string[]; // recognised roles (empty when no role system)
|
|
1299
|
+
readonly language: string;
|
|
1300
|
+
readonly organizingPaused: boolean;
|
|
1301
|
+
/**
|
|
1302
|
+
* §3.7 the takeover depth the owner chose on the `Takeover` page before pressing `Start` (D105): the depth the takeover
|
|
1303
|
+
* runs to. Null or absent on a project that has not been started. The depth that actually ran is read from the rounds
|
|
1304
|
+
* (takeover-state.ts), never from this field alone.
|
|
1305
|
+
*/
|
|
1306
|
+
readonly takeoverDepth?: TakeoverDepth | null;
|
|
1307
|
+
readonly takeoverDepthChosenAt?: string | null;
|
|
1308
|
+
/** §3.7 (D105): when the owner pressed `Start`. Absent on a project not started; a home from before D105 has rounds instead. */
|
|
1309
|
+
readonly takeoverStartedAt?: string | null;
|
|
1310
|
+
/**
|
|
1311
|
+
* D107: the project was taken over by an agent filling the ProjectKeeper table, and `pk import` took the table in —
|
|
1312
|
+
* when it was filled, by whom, and the file. With it the takeover is done without a Keeper round (takeover-state.ts).
|
|
1313
|
+
*/
|
|
1314
|
+
readonly takenOverByTable?: { readonly at: string; readonly by: string; readonly file: string } | null;
|
|
1315
|
+
/**
|
|
1316
|
+
* The rhythm from before D105 (`Daily`: a day after the last round ended; `Continuous`). Read only to map an existing
|
|
1317
|
+
* home to `schedule` (schedule.ts `scheduleOf`); nothing writes it any more.
|
|
1318
|
+
*/
|
|
1319
|
+
readonly organizeRhythm?: 'Daily' | 'Continuous';
|
|
1320
|
+
/** §3.8 (D105): the schedule of daily organizing the owner saved on the `Daily` page. Absent until saved: the default applies. */
|
|
1321
|
+
readonly schedule?: OrganizeSchedule | null;
|
|
1322
|
+
/** §3.8: the last scheduled time that was dealt with — a round started for it, or it was passed over, with why. */
|
|
1323
|
+
readonly scheduleHandled?: ScheduleHandled | null;
|
|
1324
|
+
/** §3.7 清空: what the project had spent before it was last cleared; the total stays in `Usage`, named as from before. */
|
|
1325
|
+
readonly usageBeforeClear?: { readonly usage: Usage; readonly clearedAt: string; readonly times: number } | null;
|
|
1326
|
+
/**
|
|
1327
|
+
* §6.10 (D105; CKC-03 AC-29, AC-35): the key and models this project runs on, chosen in `Keeper` → `Model provider`.
|
|
1328
|
+
* Absent until the owner saves one: the machine's settings apply (keeper/route.ts `routeOf`). It names keys by the
|
|
1329
|
+
* provider id they run under, never a key's value.
|
|
1330
|
+
*/
|
|
1331
|
+
readonly route?: ProjectRoute | null;
|
|
1332
|
+
readonly lastRoundAt?: string | null; // when the last round of daily upkeep ran out of work (rounds queue in waves, so it is stamped at the end)
|
|
1333
|
+
readonly followUpAt?: string | null; // the owner asked for a round now (the dock's Follow up)
|
|
1334
|
+
readonly createdAt: string; // when the takeover started: material older than this is history unless the first picture needs it
|
|
1335
|
+
readonly lastOpenedAt: string | null;
|
|
1336
|
+
readonly lastScopedAt: string | null;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/** A model on a key: the provider id the key runs under, the model, how hard it thinks. */
|
|
1340
|
+
export interface RouteModel { readonly provider: string; readonly id: string; readonly thinking: string | null }
|
|
1341
|
+
/** One step's own model and thinking (§6.10); `provider` names whose model it is. */
|
|
1342
|
+
export interface StepRoute { readonly provider?: string; readonly model?: string; readonly thinking?: string }
|
|
1343
|
+
/** A project's route (§6.10; keeper/route.ts): its main model, each step's own setting, the backup order of keys. */
|
|
1344
|
+
export interface ProjectRoute {
|
|
1345
|
+
readonly model: RouteModel;
|
|
1346
|
+
readonly backups: readonly RouteModel[];
|
|
1347
|
+
readonly steps: Readonly<Partial<Record<string, StepRoute>>>;
|
|
1348
|
+
readonly savedAt: string;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/** §3.8 how often a round of daily organizing starts by itself, and at what local time (D105). */
|
|
1352
|
+
export type ScheduleFrequency = 'Off' | 'Every day' | 'On selected days' | 'Every N days' | 'Continuous';
|
|
1353
|
+
export interface OrganizeSchedule {
|
|
1354
|
+
readonly frequency: ScheduleFrequency;
|
|
1355
|
+
/** Local time of day, `HH:MM`; unused by `Off` and `Continuous`. */
|
|
1356
|
+
readonly time: string;
|
|
1357
|
+
/** `On selected days`: days of the week, 0 = Sunday … 6 = Saturday. */
|
|
1358
|
+
readonly days?: readonly number[];
|
|
1359
|
+
/** `Every N days`: N, counted from `anchor`. */
|
|
1360
|
+
readonly everyDays?: number;
|
|
1361
|
+
/** `Every N days`: the local date (`YYYY-MM-DD`) the count starts from. */
|
|
1362
|
+
readonly anchor?: string;
|
|
1363
|
+
/** When the owner saved it; null on the default and on a schedule mapped from the old rhythm. */
|
|
1364
|
+
readonly savedAt: string | null;
|
|
1365
|
+
}
|
|
1366
|
+
export interface ScheduleHandled {
|
|
1367
|
+
/** The scheduled time dealt with (ISO). */
|
|
1368
|
+
readonly slot: string;
|
|
1369
|
+
readonly at: string;
|
|
1370
|
+
readonly outcome: 'round' | 'nothing changed' | 'a round was running';
|
|
1371
|
+
readonly roundId?: string | null;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
export interface TraceEntry {
|
|
1375
|
+
readonly at: string;
|
|
1376
|
+
readonly jobId: string | null;
|
|
1377
|
+
readonly collection: string;
|
|
1378
|
+
readonly id: string;
|
|
1379
|
+
readonly op: 'put' | 'remove';
|
|
1380
|
+
readonly basisSourceIds: readonly string[];
|
|
1381
|
+
readonly summary: string;
|
|
1382
|
+
}
|