tickmarkr 2.6.1 → 2.6.3
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/README.md +16 -3
- package/dist/adapters/catalog-remote.js +89 -47
- package/dist/adapters/claude-code.js +9 -6
- package/dist/adapters/codex.js +7 -4
- package/dist/adapters/prompt.d.ts +1 -0
- package/dist/adapters/prompt.js +14 -6
- package/dist/adapters/registry.js +3 -3
- package/dist/adapters/types.d.ts +12 -4
- package/dist/adapters/types.js +6 -0
- package/dist/cli/commands/approve.d.ts +11 -4
- package/dist/cli/commands/approve.js +82 -27
- package/dist/cli/commands/compile.js +13 -3
- package/dist/cli/commands/doctor.d.ts +8 -2
- package/dist/cli/commands/doctor.js +11 -3
- package/dist/cli/commands/fleet.js +87 -11
- package/dist/cli/commands/plan.js +13 -8
- package/dist/cli/commands/report.d.ts +2 -1
- package/dist/cli/commands/report.js +74 -8
- package/dist/cli/commands/resume.js +4 -2
- package/dist/cli/commands/status.js +43 -20
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.js +9 -2
- package/dist/compile/native.js +7 -0
- package/dist/config/config.d.ts +35 -2
- package/dist/config/config.js +86 -10
- package/dist/config/fleet-overlay.d.ts +13 -2
- package/dist/config/fleet-overlay.js +60 -0
- package/dist/drivers/herdr.d.ts +12 -0
- package/dist/drivers/herdr.js +51 -0
- package/dist/drivers/orca.d.ts +35 -2
- package/dist/drivers/orca.js +222 -67
- package/dist/drivers/types.d.ts +2 -0
- package/dist/drivers/types.js +2 -2
- package/dist/eval/canary.d.ts +2 -1
- package/dist/eval/canary.js +2 -2
- package/dist/eval/dispatch.js +1 -0
- package/dist/gates/acceptance.d.ts +9 -1
- package/dist/gates/acceptance.js +31 -4
- package/dist/gates/baseline.d.ts +32 -2
- package/dist/gates/baseline.js +111 -24
- package/dist/gates/cache.d.ts +8 -0
- package/dist/gates/cache.js +12 -2
- package/dist/gates/llm.d.ts +11 -4
- package/dist/gates/llm.js +40 -21
- package/dist/gates/review.d.ts +14 -1
- package/dist/gates/review.js +160 -34
- package/dist/gates/run-gates.d.ts +56 -4
- package/dist/gates/run-gates.js +358 -58
- package/dist/gates/test-manifest.d.ts +45 -1
- package/dist/gates/test-manifest.js +78 -12
- package/dist/graph/schema.d.ts +2 -0
- package/dist/graph/schema.js +2 -0
- package/dist/plan/scope.js +2 -2
- package/dist/route/preference.d.ts +20 -2
- package/dist/route/preference.js +48 -13
- package/dist/route/router.d.ts +12 -1
- package/dist/route/router.js +56 -24
- package/dist/run/consult.d.ts +15 -1
- package/dist/run/consult.js +18 -7
- package/dist/run/daemon.d.ts +38 -2
- package/dist/run/daemon.js +895 -192
- package/dist/run/git.d.ts +8 -0
- package/dist/run/git.js +14 -0
- package/dist/run/interactive-seed.d.ts +4 -0
- package/dist/run/interactive-seed.js +35 -9
- package/dist/run/journal.d.ts +152 -3
- package/dist/run/journal.js +551 -50
- package/dist/run/lease.d.ts +13 -0
- package/dist/run/lease.js +45 -0
- package/dist/run/merge.d.ts +3 -1
- package/dist/run/merge.js +3 -2
- package/dist/run/operator-summary.d.ts +3 -0
- package/dist/run/operator-summary.js +3 -1
- package/dist/run/protocol.d.ts +46 -1
- package/dist/run/protocol.js +14 -2
- package/dist/run/receipt-resolver.d.ts +22 -0
- package/dist/run/receipt-resolver.js +40 -1
- package/dist/run/repair-selection.d.ts +11 -1
- package/dist/run/repair-selection.js +17 -9
- package/dist/run/supervision.d.ts +7 -1
- package/dist/run/supervision.js +5 -2
- package/dist/run/wall-budget.d.ts +48 -0
- package/dist/run/wall-budget.js +280 -0
- package/dist/tui/cockpit/board.js +3 -3
- package/dist/tui/cockpit/decision-actions.d.ts +8 -5
- package/dist/tui/cockpit/decision-actions.js +55 -32
- package/dist/tui/cockpit/derive.js +13 -2
- package/dist/tui/cockpit/live-runtime.d.ts +10 -0
- package/dist/tui/cockpit/live-runtime.js +50 -3
- package/dist/tui/cockpit/run-cockpit.d.ts +3 -0
- package/dist/tui/cockpit/run-cockpit.js +27 -2
- package/dist/tui/cockpit/run-view.d.ts +9 -2
- package/dist/tui/cockpit/run-view.js +66 -9
- package/dist/tui/cockpit/setup-cockpit.d.ts +6 -0
- package/dist/tui/cockpit/setup-cockpit.js +10 -3
- package/dist/tui/ink/fleet-app.d.ts +15 -3
- package/dist/tui/ink/fleet-app.js +91 -22
- package/package.json +3 -1
- package/schema/config.schema.json +825 -0
- package/skills/tickmarkr-loop/SKILL.md +15 -3
- package/skills/tickmarkr-overseer/SKILL.md +42 -0
- package/skills/tickmarkr-overseer/scripts/classify-vitest-log.sh +91 -0
- package/skills/tickmarkr-overseer/scripts/context-statusline.sh +81 -0
- package/skills/tickmarkr-overseer/scripts/grade-ci.sh +36 -34
- package/skills/tickmarkr-overseer/scripts/watch-journal.sh +6 -4
package/dist/run/git.d.ts
CHANGED
|
@@ -277,6 +277,14 @@ export type BaseContainment = {
|
|
|
277
277
|
* future `git cherry` ever emitted a `-` line for a merge.
|
|
278
278
|
*/
|
|
279
279
|
export declare function declaredBaseContainment(cwd: string, declaredRef: string, targetRef?: string): Promise<BaseContainment>;
|
|
280
|
+
/**
|
|
281
|
+
* OBS-1107: does `dest` already hold everything `commit` changed? Replays the commit's OWN
|
|
282
|
+
* parent-to-commit change onto `dest` as a three-way merge; a clean merge whose tree IS `dest`'s tree
|
|
283
|
+
* brings nothing the destination lacks — a content-empty commit, or a patch already represented there
|
|
284
|
+
* under another hash. Content, never hash identity. Any git failure (a root commit, a git without
|
|
285
|
+
* `merge-tree --merge-base`) answers false: unproven work stays unaccounted.
|
|
286
|
+
*/
|
|
287
|
+
export declare function changeRepresented(cwd: string, commit: string, dest?: string): Promise<boolean>;
|
|
280
288
|
export declare function removeWorktree(repo: string, dir: string): Promise<void>;
|
|
281
289
|
export declare const REFS_PREFLIGHT_PREFIX = "refs/tickmarkr/preflight";
|
|
282
290
|
export declare const REFS_PROBE_REMEDY = "run from the main repository or a full clone; a sandbox that denies writes under that path cannot host a run";
|
package/dist/run/git.js
CHANGED
|
@@ -863,6 +863,20 @@ export async function declaredBaseContainment(cwd, declaredRef, targetRef = "HEA
|
|
|
863
863
|
}
|
|
864
864
|
return missing.length > 0 ? { result: "drifted", missing } : { result: "contained", via: "patch-id" };
|
|
865
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* OBS-1107: does `dest` already hold everything `commit` changed? Replays the commit's OWN
|
|
868
|
+
* parent-to-commit change onto `dest` as a three-way merge; a clean merge whose tree IS `dest`'s tree
|
|
869
|
+
* brings nothing the destination lacks — a content-empty commit, or a patch already represented there
|
|
870
|
+
* under another hash. Content, never hash identity. Any git failure (a root commit, a git without
|
|
871
|
+
* `merge-tree --merge-base`) answers false: unproven work stays unaccounted.
|
|
872
|
+
*/
|
|
873
|
+
export async function changeRepresented(cwd, commit, dest = "HEAD") {
|
|
874
|
+
const merged = await shGit(`git merge-tree --write-tree --merge-base=${shq(`${commit}^`)} ${shq(dest)} ${shq(commit)}`, cwd);
|
|
875
|
+
if (merged.code !== 0)
|
|
876
|
+
return false;
|
|
877
|
+
const tree = await shGit(`git rev-parse ${shq(`${dest}^{tree}`)}`, cwd);
|
|
878
|
+
return tree.code === 0 && merged.stdout.split("\n")[0].trim() === tree.stdout.trim();
|
|
879
|
+
}
|
|
866
880
|
export async function removeWorktree(repo, dir) {
|
|
867
881
|
await shGit(`git worktree remove --force ${shq(dir)}`, repo); // best-effort; stale dirs are re-added with -B
|
|
868
882
|
await shGit(`rm -rf ${shq(dir)}`, repo);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Assignment, type WorkerAdapter } from "../adapters/types.js";
|
|
2
|
+
import { DeliveryReadinessError } from "../drivers/herdr.js";
|
|
2
3
|
import type { ExecutorDriver, Slot } from "../drivers/types.js";
|
|
3
4
|
export interface InteractiveSeedResult {
|
|
4
5
|
output: string;
|
|
@@ -8,6 +9,9 @@ export interface InteractiveSeedResult {
|
|
|
8
9
|
trustAnswered: boolean;
|
|
9
10
|
}
|
|
10
11
|
type SeedDriver = Pick<ExecutorDriver, "run" | "waitOutput" | "read" | "sendKey">;
|
|
12
|
+
export declare class SeedReadinessError extends DeliveryReadinessError {
|
|
13
|
+
constructor(waitedMs: number, transcript: string, readinessMatch: string);
|
|
14
|
+
}
|
|
11
15
|
export declare function runInteractiveSeed(opts: {
|
|
12
16
|
driver: SeedDriver;
|
|
13
17
|
slot: Slot;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { matchesTrustDialog } from "../adapters/types.js";
|
|
2
|
+
import { DeliveryReadinessError } from "../drivers/herdr.js";
|
|
2
3
|
// The workspace-trust prompt is a STARTUP gate: it renders before the readiness banner and blocks
|
|
3
4
|
// it, so this wait is the only window in which anything can answer it. Observation therefore runs
|
|
4
5
|
// for the WHOLE readiness budget. Review round 7 (material): a 60-second cutoff here was a window
|
|
@@ -9,6 +10,18 @@ import { matchesTrustDialog } from "../adapters/types.js";
|
|
|
9
10
|
// blocked anyway, and it ends at the first of readiness, a modal, or the deadline.
|
|
10
11
|
const TRUST_POLL_MS = 1_000;
|
|
11
12
|
const TRUST_PANE_ROWS = 80;
|
|
13
|
+
// OBS-1205 add.1: a launch whose readiness never appeared never received the brief, so its deadline is
|
|
14
|
+
// the delivery-readiness class (OBS-142: the interface never became interactive), not a launched
|
|
15
|
+
// worker. Thrown as that class, the daemon's existing catch journals `delivery-readiness-failed`,
|
|
16
|
+
// closes the slot and walks the escalation ladder to a failover — with no `worker-launch` row, which is
|
|
17
|
+
// where a funded repair's findings expire, so the repair the seed never delivered stays owed.
|
|
18
|
+
export class SeedReadinessError extends DeliveryReadinessError {
|
|
19
|
+
constructor(waitedMs, transcript, readinessMatch) {
|
|
20
|
+
super(waitedMs, transcript);
|
|
21
|
+
this.name = "SeedReadinessError";
|
|
22
|
+
this.message = `seed readiness pattern not seen after ${waitedMs}ms: ${readinessMatch}`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
12
25
|
// v1.89 T19 / OBS-406: wait for readiness, answering a fingerprint-matched trust modal at most ONCE
|
|
13
26
|
// on the way. The daemon's own trust loop runs only after runInteractiveSeed returns, and this wait
|
|
14
27
|
// is exactly the window the modal blocks in — a declaration consulted only there is unreachable
|
|
@@ -17,23 +30,34 @@ async function awaitReadiness(opts) {
|
|
|
17
30
|
const { driver, slot, readinessMatch, deadline } = opts;
|
|
18
31
|
const dialog = opts.adapter.trustDialog;
|
|
19
32
|
const left = () => Math.max(0, deadline - Date.now());
|
|
33
|
+
// Every wait below is awaited, and the budget can run out inside any of them (OrcaDriver.waitOutput
|
|
34
|
+
// checks its sweep before its clock). Readiness a wait returns after the deadline is expired — it may
|
|
35
|
+
// be what a key pressed at the edge produced — and a launch whose deadline passed has already
|
|
36
|
+
// failed, so neither a key nor a seed follows it. Both branches apply it.
|
|
37
|
+
const expired = () => Date.now() >= deadline;
|
|
38
|
+
const readyInTime = async (ms) => (await driver.waitOutput(slot, readinessMatch, ms)) && !expired();
|
|
20
39
|
// Nothing this launch could answer (no declaration, an honest {kind:"none"}, or a driver with no
|
|
21
|
-
// keystroke surface): the single long wait,
|
|
40
|
+
// keystroke surface): the single long wait, pre-T19 behaviour plus the post-await deadline check.
|
|
22
41
|
if (!dialog || dialog.kind === "none" || !driver.sendKey) {
|
|
23
|
-
return { ready: await
|
|
42
|
+
return { ready: await readyInTime(left()), trustAnswered: false };
|
|
24
43
|
}
|
|
25
44
|
let trustAnswered = false;
|
|
26
|
-
while (!trustAnswered &&
|
|
27
|
-
if (await
|
|
45
|
+
while (!trustAnswered && !expired()) {
|
|
46
|
+
if (await readyInTime(Math.min(TRUST_POLL_MS, left()))) {
|
|
28
47
|
return { ready: true, trustAnswered };
|
|
29
48
|
}
|
|
30
49
|
let paneText;
|
|
31
50
|
try {
|
|
32
|
-
|
|
51
|
+
// OBS-1205: a cursor-drawn modal has text only on the RENDERED frame, so the slot's screen read
|
|
52
|
+
// is preferred when its driver has one. An unreadable or foreign frame is a failed read, never
|
|
53
|
+
// a cue to match the stream instead; drivers without a screen keep polling `read`.
|
|
54
|
+
paneText = await (slot.readScreen ? slot.readScreen() : driver.read(slot, TRUST_PANE_ROWS));
|
|
33
55
|
}
|
|
34
56
|
catch {
|
|
35
57
|
continue; // a failed read is not a matched modal — keep observing, spend nothing
|
|
36
58
|
}
|
|
59
|
+
if (expired())
|
|
60
|
+
break; // the wait or the read outlived the budget: no key after the deadline
|
|
37
61
|
if (!matchesTrustDialog(paneText, dialog))
|
|
38
62
|
continue;
|
|
39
63
|
// Review round 7 (material): the latch is spent BEFORE the awaited send, not after it. A send
|
|
@@ -54,7 +78,8 @@ async function awaitReadiness(opts) {
|
|
|
54
78
|
/* dispatched-then-rejected: never retried here, and never re-tried by the daemon either */
|
|
55
79
|
}
|
|
56
80
|
}
|
|
57
|
-
|
|
81
|
+
// An expired budget gets no closing sweep: a zero-length wait still reads the terminal once.
|
|
82
|
+
return { ready: !expired() && await readyInTime(left()), trustAnswered };
|
|
58
83
|
}
|
|
59
84
|
// v1.69 T6: launch-then-seed handoff for adapters whose real TUI cannot be argv-seeded.
|
|
60
85
|
// Both the launch command and the seed line are delivered through the driver's existing `run`
|
|
@@ -65,6 +90,8 @@ export async function runInteractiveSeed(opts) {
|
|
|
65
90
|
await opts.driver.run(opts.slot, seed.launch(opts.assignment.model));
|
|
66
91
|
// `trustAnswered` rides EVERY return below, including both early ones: the daemon initializes its
|
|
67
92
|
// per-slot latch from it, and an omission there reads as "no key was sent" — the second-Enter defect.
|
|
93
|
+
// The readiness deadline throws instead; `onTrustAnswered` already carried the latch out.
|
|
94
|
+
const launchedAt = Date.now();
|
|
68
95
|
const { ready, trustAnswered } = await awaitReadiness({
|
|
69
96
|
driver: opts.driver,
|
|
70
97
|
slot: opts.slot,
|
|
@@ -74,9 +101,8 @@ export async function runInteractiveSeed(opts) {
|
|
|
74
101
|
...(opts.onTrustAnswered ? { onTrustAnswered: opts.onTrustAnswered } : {}),
|
|
75
102
|
});
|
|
76
103
|
const banner = await opts.driver.read(opts.slot, 1000);
|
|
77
|
-
if (!ready)
|
|
78
|
-
|
|
79
|
-
}
|
|
104
|
+
if (!ready)
|
|
105
|
+
throw new SeedReadinessError(Date.now() - launchedAt, banner, seed.readinessMatch);
|
|
80
106
|
let sessionId;
|
|
81
107
|
if (seed.confirmBanner) {
|
|
82
108
|
const confirm = seed.confirmBanner(banner, opts.assignment.model);
|
package/dist/run/journal.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface ResumeState {
|
|
|
18
18
|
tried: string[];
|
|
19
19
|
lastAssignment?: Assignment;
|
|
20
20
|
upheldFeedback?: string;
|
|
21
|
+
escalated?: Record<string, string>;
|
|
22
|
+
escalatedAdapters?: string[];
|
|
21
23
|
}
|
|
22
24
|
export interface CurrentAttemptGateReplay {
|
|
23
25
|
commit: string;
|
|
@@ -29,12 +31,70 @@ export declare const ATTEMPT_CAP_RELEASE: "attempt-cap";
|
|
|
29
31
|
export declare const GATE_SATISFIED_RELEASE: "gate-satisfied";
|
|
30
32
|
export declare const REVIEW_UPHELD_RELEASE: "review-upheld";
|
|
31
33
|
export declare const RECHECK_RELEASE: "recheck";
|
|
34
|
+
export declare const APPROVAL_REFUSED: "approval-refused";
|
|
35
|
+
/** OBS-1178: the journal row a decision answers — its physical 1-based line plus its timestamp. */
|
|
36
|
+
export interface DecisionBinding {
|
|
37
|
+
line: number;
|
|
38
|
+
ts: string;
|
|
39
|
+
}
|
|
40
|
+
/** The token every surface prints and `approve --park` accepts: `<line>@<ts>`. */
|
|
41
|
+
export declare const bindingToken: (binding: DecisionBinding) => string;
|
|
42
|
+
export declare function parseBindingToken(token: string): DecisionBinding | undefined;
|
|
43
|
+
/** The binding a task-approved row recorded under `park` or `failure`, when well formed. */
|
|
44
|
+
export declare function recordedBinding(value: unknown): DecisionBinding | undefined;
|
|
45
|
+
/** The newest failed gate before a park row — the gate a waive of that park would satisfy. */
|
|
46
|
+
export declare function failedGateBeforePark(events: readonly JournalEvent[], taskId: string, parkIndex: number): GateName | undefined;
|
|
47
|
+
/** The physical journal line of `events[i]` (see SOURCE_LINE). */
|
|
48
|
+
export declare const physicalLine: (events: readonly JournalEvent[], i: number) => number;
|
|
49
|
+
/** A row parsed outside this module (a cockpit capture) names its own physical line to the decision fold. */
|
|
50
|
+
export declare const withPhysicalLine: <T extends JournalEvent>(row: T, line: number) => T;
|
|
51
|
+
/** OBS-1178: an approval neither enacted nor refused yet, and — when it may not be enacted — why. */
|
|
52
|
+
export interface OpenDecision {
|
|
53
|
+
taskId: string;
|
|
54
|
+
line: number;
|
|
55
|
+
stale?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* OBS-1178: THE decision fold. Every reader of task-approved rows — the replay folds, the daemon's
|
|
59
|
+
* startup, sweep and pending-action folds, scope-amendment replay and its audits, status and both
|
|
60
|
+
* cockpits — reads decisions through it, so no two surfaces can disagree on whether one happened.
|
|
61
|
+
*
|
|
62
|
+
* `effective` holds the PHYSICAL lines of the task-approved rows whose effects may apply: a row that
|
|
63
|
+
* was sound when an enactment row consumed it (bound by line and timestamp to the task's newest park,
|
|
64
|
+
* a waive also to that park's failed gate, or a recheck to the newest failure with no park after it;
|
|
65
|
+
* a legacy row carrying no binding only when no park or failure landed between it and that
|
|
66
|
+
* enactment), plus a row still open that is sound NOW. A refused row is never effective, and neither is an open row that no
|
|
67
|
+
* longer binds — a newer park or failure landed, or it names none — whatever unrelated rows landed
|
|
68
|
+
* around it. An enactment row also consumes the task's park and failure: a decision naming either
|
|
69
|
+
* after the task moved on is stale, while the decisions that enactment already consumed stay effective.
|
|
70
|
+
* `open` lists every unenacted, unrefused row with why it may not be enacted, and `refused` the lines
|
|
71
|
+
* an approval-refused row answered.
|
|
72
|
+
*/
|
|
73
|
+
export declare function foldDecisions(events: readonly JournalEvent[]): {
|
|
74
|
+
effective: Set<number>;
|
|
75
|
+
open: OpenDecision[];
|
|
76
|
+
refused: Set<number>;
|
|
77
|
+
};
|
|
78
|
+
/** The physical lines of the task-approved rows whose effects may apply (see foldDecisions). */
|
|
79
|
+
export declare const effectiveDecisions: (events: readonly JournalEvent[]) => Set<number>;
|
|
80
|
+
/**
|
|
81
|
+
* The journal as every decision reader must see it: task-approved rows that are not effective removed,
|
|
82
|
+
* every other row (and its physical line) kept. Order-only folds iterate this instead of skipping rows
|
|
83
|
+
* on their own.
|
|
84
|
+
*/
|
|
85
|
+
export declare function effectiveEvents(events: readonly JournalEvent[]): JournalEvent[];
|
|
86
|
+
/** Per task, the open decisions that may not be enacted now — what the daemon refuses before enactment. */
|
|
87
|
+
export interface StaleApprovals {
|
|
88
|
+
reason: string;
|
|
89
|
+
lines: number[];
|
|
90
|
+
}
|
|
91
|
+
export declare function staleApprovals(events: readonly JournalEvent[]): Map<string, StaleApprovals>;
|
|
32
92
|
export interface PreservedRef {
|
|
33
93
|
ref: string;
|
|
34
94
|
diffCommand: string;
|
|
35
95
|
}
|
|
36
96
|
export declare function preservedRefsByTask(events: JournalEvent[]): Map<string, PreservedRef[]>;
|
|
37
|
-
export declare function reviewRoundsSinceApproval(events: JournalEvent[], taskId: string): number;
|
|
97
|
+
export declare function reviewRoundsSinceApproval(events: JournalEvent[], taskId: string, rounds?: (decided: JournalEvent[]) => JournalEvent[]): number;
|
|
38
98
|
export declare function upheldFeedbackByTask(events: JournalEvent[]): Map<string, string>;
|
|
39
99
|
export interface StructuredFinding {
|
|
40
100
|
class: string;
|
|
@@ -47,6 +107,8 @@ export interface StructuredFinding {
|
|
|
47
107
|
observedFingerprints?: string[];
|
|
48
108
|
/** Prior id validated against the reviewer's reraised list by the review gate. */
|
|
49
109
|
reraisedFrom?: string;
|
|
110
|
+
/** OBS-1195: an anchor's explicitly named parent chain; it retires when that chain is resolved. */
|
|
111
|
+
boundTo?: string;
|
|
50
112
|
/** Resolved definition AND defect identity; bare symbol spelling is never lineage. */
|
|
51
113
|
codeIdentity?: {
|
|
52
114
|
definition: string;
|
|
@@ -125,7 +187,10 @@ export declare function formatPriorFindingEvidence(evidence: PriorFindingEvidenc
|
|
|
125
187
|
/** Normalized identity of a gate failure: the same defect, seen twice, normalizes to the same bytes. */
|
|
126
188
|
export declare function normalizeGateFailure(details: string): string;
|
|
127
189
|
export declare const GATE_FINGERPRINT_CAP = 2;
|
|
190
|
+
/** The invocation a gate row's receipt names — the identity of the execution that observed it. */
|
|
191
|
+
export declare const receiptOrigin: (data: Record<string, unknown>) => string | undefined;
|
|
128
192
|
export declare function identicalGateFailures(events: JournalEvent[], taskId: string, gate: string, normalized: string): number;
|
|
193
|
+
export declare const readableExcerpt: (text: string) => string;
|
|
129
194
|
/** What each funded repair's next battery actually reached. A repair spends its budget only
|
|
130
195
|
* when that battery reaches one of the gates it was funded to fix; an earlier red is evidence that
|
|
131
196
|
* this repair never got its funded turn, not a charge against the repair ladder. */
|
|
@@ -177,6 +242,7 @@ export type PendingApprovalAction = {
|
|
|
177
242
|
* enacts it.
|
|
178
243
|
*/
|
|
179
244
|
export declare function pendingApprovalActions(events: JournalEvent[]): Map<string, PendingApprovalAction>;
|
|
245
|
+
export declare function approvalAction(taskId: string, e: JournalEvent): PendingApprovalAction;
|
|
180
246
|
/**
|
|
181
247
|
* Why the last attempt failed, one row per journaled cause, in the daemon's own `source: details`
|
|
182
248
|
* shape. The daemon builds that brief in a loop-local variable, which dies with the process: a resumed
|
|
@@ -192,10 +258,20 @@ export declare function pendingApprovalActions(events: JournalEvent[]): Map<stri
|
|
|
192
258
|
* failures OR the delivery failure that preceded it. Of the approvals, only a WAIVE clears (the operator
|
|
193
259
|
* retired the findings by fiat — the uphold case re-derives its own brief separately). OBS-1074: a
|
|
194
260
|
* plain approve, a scope grant or a recheck re-funds an attempt that must still see why the last one
|
|
195
|
-
* parked
|
|
196
|
-
*
|
|
261
|
+
* parked — v2.5.7's T11 looped four times on one hygiene oracle because every approval erased exactly
|
|
262
|
+
* the finding the fresh attempt was funded to fix. The operator's stated reasons ride after those rows
|
|
263
|
+
* as `standingRulings` (OBS-1150): no launch and no waive resets them.
|
|
197
264
|
*/
|
|
198
265
|
export declare function journaledFailureBrief(events: JournalEvent[], taskId: string): string[];
|
|
266
|
+
/**
|
|
267
|
+
* OBS-1150: an operator's approval reason is a ruling on the TASK, not on the attempt it released.
|
|
268
|
+
* The failure rows above are spent at the next worker-launch and the review context once bound only
|
|
269
|
+
* the newest reason, so ruling A vanished at the first launch after it and a later ruling B replaced
|
|
270
|
+
* it. Every effective reason therefore stands, oldest first, for the whole run; a repeat is carried
|
|
271
|
+
* once. A gate-satisfied release accepts a gate's verdict rather than ruling on the work, so its
|
|
272
|
+
* reason adds no standing ruling — and, being no ruling, it retires none either.
|
|
273
|
+
*/
|
|
274
|
+
export declare function standingRulings(events: JournalEvent[], taskId: string): string[];
|
|
199
275
|
/** Never infer a cross-path alias from a symbol, sentence, or hash. */
|
|
200
276
|
export declare function reviewFingerprintMatches(candidate: unknown, fingerprint: string): boolean;
|
|
201
277
|
export declare function observedReviewFingerprints(finding: StructuredFinding): string[];
|
|
@@ -238,7 +314,28 @@ export declare function carryReviewFindings(priors: readonly StructuredFinding[]
|
|
|
238
314
|
* after round re-seats ONE fingerprint, and a revised rationale replaces the prior rationale on that
|
|
239
315
|
* row. N rounds of the same concern therefore carry the newest accepted explanation once, not N rows.
|
|
240
316
|
*/
|
|
317
|
+
/** OBS-1151: this task's journaled judgments, newest first — subjects to compare a fresh ruling against,
|
|
318
|
+
* never verdicts to reuse. A row without a well-formed judgment (legacy, park, unparseable) is skipped. */
|
|
319
|
+
export declare function priorJudgments(events: readonly JournalEvent[], taskId: string): Array<{
|
|
320
|
+
commit: string;
|
|
321
|
+
judge?: string;
|
|
322
|
+
criteria: Array<{
|
|
323
|
+
id: string;
|
|
324
|
+
key: string;
|
|
325
|
+
met: boolean;
|
|
326
|
+
paths: string[];
|
|
327
|
+
}>;
|
|
328
|
+
}>;
|
|
241
329
|
export declare function outstandingReviewFindings(events: JournalEvent[], taskId: string): StructuredFinding[];
|
|
330
|
+
/**
|
|
331
|
+
* OBS-1019 add.2: each outstanding material chain with the number of valid review verdicts that
|
|
332
|
+
* re-raised it since the last review pass or review-gate waive. Only a chain's own observed spellings
|
|
333
|
+
* count, so an unrelated finding sharing a path never lengthens it.
|
|
334
|
+
*/
|
|
335
|
+
export declare function reraisedReviewChains(events: JournalEvent[], taskId: string): Array<{
|
|
336
|
+
finding: StructuredFinding;
|
|
337
|
+
reraises: number;
|
|
338
|
+
}>;
|
|
242
339
|
/** The findings a funded repair must carry into the next dispatch, or undefined if none is pending. */
|
|
243
340
|
export declare function pendingRepairFindings(events: JournalEvent[], taskId: string): string | undefined;
|
|
244
341
|
/**
|
|
@@ -256,6 +353,32 @@ export type WorkerResultCause = (typeof WORKER_RESULT_CAUSES)[number];
|
|
|
256
353
|
export declare function isQualityFailureParkKind(kind: ParkKind): boolean;
|
|
257
354
|
export declare function classifyTaskFailure(taskEvents: JournalEvent[]): ParkKind;
|
|
258
355
|
export declare function recordedTaskFailureKind(events: JournalEvent[], taskId: string): ParkKind | undefined;
|
|
356
|
+
export declare const RESUME_HARVEST_SOURCE: "resume";
|
|
357
|
+
export interface InterruptedAttempt {
|
|
358
|
+
attempt: number;
|
|
359
|
+
/** The producing dispatch's own assignment — the author the harvested work is gated under. */
|
|
360
|
+
assignment: Assignment;
|
|
361
|
+
/** Owned evidence still to read: nothing of this attempt's harvest is recorded yet. */
|
|
362
|
+
launch?: {
|
|
363
|
+
nonce: string;
|
|
364
|
+
dispatchScript: string;
|
|
365
|
+
slot: {
|
|
366
|
+
id: string;
|
|
367
|
+
name: string;
|
|
368
|
+
cwd: string;
|
|
369
|
+
};
|
|
370
|
+
};
|
|
371
|
+
/** A worker-result with no harvest row after it: finish that record. `reaped` only when a resume wrote
|
|
372
|
+
* it — a resume records the result after its owned-process cleanup; a live daemon records it BEFORE
|
|
373
|
+
* handling a failed reap, so its result alone never proves cleanup and `launch` must be reaped again. */
|
|
374
|
+
result?: {
|
|
375
|
+
finished: boolean;
|
|
376
|
+
summary: string;
|
|
377
|
+
reaped: boolean;
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
export declare function resumeHarvestAuthor(events: JournalEvent[], taskId: string): Assignment | undefined;
|
|
381
|
+
export declare function interruptedAttempt(events: JournalEvent[], taskId: string): InterruptedAttempt | undefined;
|
|
259
382
|
export declare function runHasEnded(events: JournalEvent[]): boolean;
|
|
260
383
|
/** OBS-53: classify worker-result failures so retries and routing see the true signal, not one lumped bucket. */
|
|
261
384
|
export declare function classifyWorkerResultCause(opts: {
|
|
@@ -392,6 +515,8 @@ export type EngagementCompare = {
|
|
|
392
515
|
export declare function engagementComparable(events: JournalEvent[], loadedHash: string): EngagementCompare;
|
|
393
516
|
export declare function newRunId(now?: Date): string;
|
|
394
517
|
export declare function parseRunId(runId: string): string;
|
|
518
|
+
/** The journal reader rule over bytes in hand: skip blanks, drop a torn line, keep each row's physical line. */
|
|
519
|
+
export declare function parseJournalText(raw: string): JournalEvent[];
|
|
395
520
|
export declare function readAllTelemetry(repoRoot: string, lastK: number, opts?: {
|
|
396
521
|
after?: string;
|
|
397
522
|
}): (TelemetryRow & {
|
|
@@ -402,6 +527,23 @@ export declare const PRIOR_JOURNAL_RUN_WINDOW = 50;
|
|
|
402
527
|
export declare function readPriorRunEvidence(repoRoot: string, tasks: readonly Pick<Task, "id" | "goal" | "files" | "acceptance">[], opts?: {
|
|
403
528
|
suppressRunId?: string;
|
|
404
529
|
}): PriorRunEvidence;
|
|
530
|
+
export declare const REVIEW_NO_VERDICT_RUN_WINDOW = 10;
|
|
531
|
+
export declare const REVIEW_NO_VERDICT_ADVISORY_AT = 2;
|
|
532
|
+
export interface ReviewNoVerdictHistory {
|
|
533
|
+
/** completed runs measured, oldest first */
|
|
534
|
+
runs: string[];
|
|
535
|
+
/** window journals with a row that did not parse — their events are unknown, never zero */
|
|
536
|
+
unreadable: string[];
|
|
537
|
+
/** reviewer channel → review-no-verdict events; every channel seen reviewing is present, 0 included */
|
|
538
|
+
counts: Map<string, number>;
|
|
539
|
+
}
|
|
540
|
+
export declare function readReviewNoVerdictHistory(repoRoot: string, window?: number): ReviewNoVerdictHistory;
|
|
541
|
+
/** One row per measured channel (plus one naming unreadable journals); doctor prints all, Fleet the warn rows. */
|
|
542
|
+
export declare function reviewNoVerdictRows(history: ReviewNoVerdictHistory): {
|
|
543
|
+
channel: string;
|
|
544
|
+
verdict: "pass" | "warn";
|
|
545
|
+
value: string;
|
|
546
|
+
}[];
|
|
405
547
|
export declare function readProfileCursor(repoRoot: string): string | undefined;
|
|
406
548
|
export declare function profileDiscountsPath(repoRoot: string): string;
|
|
407
549
|
export declare function readProfileDiscounts(repoRoot: string): ProfileDiscount[];
|
|
@@ -424,6 +566,13 @@ export declare class Journal {
|
|
|
424
566
|
append(event: string, taskId?: string, data?: Record<string, unknown>): void;
|
|
425
567
|
phaseStart(taskId: string, phase: TaskPhase, data?: Record<string, unknown>): void;
|
|
426
568
|
read(): JournalEvent[];
|
|
569
|
+
/** Parsed rows paired with their physical 1-based journal lines (OBS-1178 bindings name lines). */
|
|
570
|
+
readSourced(): {
|
|
571
|
+
events: JournalEvent[];
|
|
572
|
+
lines: number[];
|
|
573
|
+
};
|
|
574
|
+
/** OBS-1178: the binding of a task's newest park (or `task-failed`) row — what a decision on it names. */
|
|
575
|
+
newestBinding(taskId: string, event?: "task-human" | "task-failed"): DecisionBinding | undefined;
|
|
427
576
|
readTracked(): TrackedJournalRow[];
|
|
428
577
|
replayStatuses(): Map<string, TaskStatus>;
|
|
429
578
|
/**
|