patchwork-os 1.2.0-beta.2.canary.633 → 1.2.0-beta.2.canary.635
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/dist/butler/errandOutcomeGrader.d.ts +92 -0
- package/dist/butler/errandOutcomeGrader.js +79 -0
- package/dist/butler/errandOutcomeGrader.js.map +1 -0
- package/dist/butler/outcomeShadowLog.d.ts +88 -0
- package/dist/butler/outcomeShadowLog.js +113 -0
- package/dist/butler/outcomeShadowLog.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Butler errand outcome grader — "did the operator keep it?"
|
|
3
|
+
*
|
|
4
|
+
* A Butler errand's artifact is usually a task in a tracker, not a GitHub
|
|
5
|
+
* issue, so `classifyIssueDisposition` (outcomeStore.ts) does not apply. This
|
|
6
|
+
* is its sibling for artifacts whose only honest signal is what the operator
|
|
7
|
+
* subsequently did with the thing.
|
|
8
|
+
*
|
|
9
|
+
* ## The model
|
|
10
|
+
*
|
|
11
|
+
* completed → confirmed the operator acted on it. Real positive.
|
|
12
|
+
* deleted → junk the operator threw it away. Real negative.
|
|
13
|
+
* open + stale → junk left untouched past the staleness horizon.
|
|
14
|
+
* open + recent → WITHHELD no signal yet. Not evidence in EITHER
|
|
15
|
+
* direction.
|
|
16
|
+
*
|
|
17
|
+
* ## Why "open + recent" must withhold rather than pass
|
|
18
|
+
*
|
|
19
|
+
* This is the single load-bearing rule, and it is the one a reasonable person
|
|
20
|
+
* gets wrong. An errand that nobody has deleted looks like a success and is
|
|
21
|
+
* not one: the operator may simply not have looked. Folding it as good is
|
|
22
|
+
* trust-by-neglect, the exact defect closed three times already in this
|
|
23
|
+
* subsystem (#1064, #1318/#1319, #1320, #1322) — each time by making absence
|
|
24
|
+
* of a negative stop counting as a positive.
|
|
25
|
+
*
|
|
26
|
+
* So the grader has no "default to good" branch at all. Every path that is not
|
|
27
|
+
* a POSITIVE ACT by the operator returns `unknown`, which the fold withholds.
|
|
28
|
+
*
|
|
29
|
+
* ## Why stale → junk rather than unknown
|
|
30
|
+
*
|
|
31
|
+
* Asymmetric on purpose. `unknown` is the right answer while the operator
|
|
32
|
+
* might still act; it is the wrong answer once enough time has passed that
|
|
33
|
+
* not-acting IS the answer. Leaving it `unknown` forever would let a worker
|
|
34
|
+
* that files things nobody ever touches sit permanently un-judged instead of
|
|
35
|
+
* accumulating the negative it has earned. The horizon is explicit and long
|
|
36
|
+
* (default 14 days) precisely because it converts silence into a negative.
|
|
37
|
+
*
|
|
38
|
+
* ## No model in the loop
|
|
39
|
+
*
|
|
40
|
+
* Pure function of observed state and two timestamps. A prior LLM judge in
|
|
41
|
+
* this repo flipped verdicts between runs on identical inputs, which makes the
|
|
42
|
+
* trust ledger unreproducible — and a trust ledger you cannot replay is not
|
|
43
|
+
* evidence, it is an opinion with a timestamp.
|
|
44
|
+
*/
|
|
45
|
+
import type { OutcomeDisposition } from "../workers/outcomeStore.js";
|
|
46
|
+
/** Default staleness horizon: 14 days. */
|
|
47
|
+
export declare const DEFAULT_STALE_AFTER_MS: number;
|
|
48
|
+
/**
|
|
49
|
+
* What we observed about the errand's artifact.
|
|
50
|
+
*
|
|
51
|
+
* Every field is optional because observation is best-effort — a connector may
|
|
52
|
+
* not report deletion at all. Absent fields must never be read as a positive:
|
|
53
|
+
* see `gradeErrandOutcome`'s ordering.
|
|
54
|
+
*/
|
|
55
|
+
export interface ObservedErrandArtifact {
|
|
56
|
+
/** The operator marked it done. A positive act. */
|
|
57
|
+
completed?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* The artifact is gone. A positive act in the other direction.
|
|
60
|
+
*
|
|
61
|
+
* Distinct from "we could not find it": a lookup failure must be reported as
|
|
62
|
+
* `undefined`, never as `deleted: true`. A transient API error that reads as
|
|
63
|
+
* deletion would manufacture a negative against a worker that did nothing
|
|
64
|
+
* wrong.
|
|
65
|
+
*/
|
|
66
|
+
deleted?: boolean;
|
|
67
|
+
/** When the errand created the artifact. */
|
|
68
|
+
createdAt?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface GradeOptions {
|
|
71
|
+
/** Clock. Injected so grading is reproducible in replay. */
|
|
72
|
+
now: number;
|
|
73
|
+
/** How long "open" stays `unknown` before becoming `junk`. */
|
|
74
|
+
staleAfterMs?: number;
|
|
75
|
+
}
|
|
76
|
+
export interface GradedOutcome {
|
|
77
|
+
disposition: OutcomeDisposition;
|
|
78
|
+
/**
|
|
79
|
+
* Why, in a form a human can check against the row. Stored alongside the
|
|
80
|
+
* disposition — a verdict whose reasoning is not recorded cannot be audited,
|
|
81
|
+
* only believed.
|
|
82
|
+
*/
|
|
83
|
+
reason: "completed" | "deleted" | "stale-unactioned" | "open-recent" | "not-observed";
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Grade one observed artifact.
|
|
87
|
+
*
|
|
88
|
+
* Ordering is deliberate: the two POSITIVE ACTS are tested first, then
|
|
89
|
+
* staleness, and everything remaining falls to `unknown`. There is no branch
|
|
90
|
+
* that reaches `confirmed` without `completed === true`.
|
|
91
|
+
*/
|
|
92
|
+
export declare function gradeErrandOutcome(observed: ObservedErrandArtifact, opts: GradeOptions): GradedOutcome;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Butler errand outcome grader — "did the operator keep it?"
|
|
3
|
+
*
|
|
4
|
+
* A Butler errand's artifact is usually a task in a tracker, not a GitHub
|
|
5
|
+
* issue, so `classifyIssueDisposition` (outcomeStore.ts) does not apply. This
|
|
6
|
+
* is its sibling for artifacts whose only honest signal is what the operator
|
|
7
|
+
* subsequently did with the thing.
|
|
8
|
+
*
|
|
9
|
+
* ## The model
|
|
10
|
+
*
|
|
11
|
+
* completed → confirmed the operator acted on it. Real positive.
|
|
12
|
+
* deleted → junk the operator threw it away. Real negative.
|
|
13
|
+
* open + stale → junk left untouched past the staleness horizon.
|
|
14
|
+
* open + recent → WITHHELD no signal yet. Not evidence in EITHER
|
|
15
|
+
* direction.
|
|
16
|
+
*
|
|
17
|
+
* ## Why "open + recent" must withhold rather than pass
|
|
18
|
+
*
|
|
19
|
+
* This is the single load-bearing rule, and it is the one a reasonable person
|
|
20
|
+
* gets wrong. An errand that nobody has deleted looks like a success and is
|
|
21
|
+
* not one: the operator may simply not have looked. Folding it as good is
|
|
22
|
+
* trust-by-neglect, the exact defect closed three times already in this
|
|
23
|
+
* subsystem (#1064, #1318/#1319, #1320, #1322) — each time by making absence
|
|
24
|
+
* of a negative stop counting as a positive.
|
|
25
|
+
*
|
|
26
|
+
* So the grader has no "default to good" branch at all. Every path that is not
|
|
27
|
+
* a POSITIVE ACT by the operator returns `unknown`, which the fold withholds.
|
|
28
|
+
*
|
|
29
|
+
* ## Why stale → junk rather than unknown
|
|
30
|
+
*
|
|
31
|
+
* Asymmetric on purpose. `unknown` is the right answer while the operator
|
|
32
|
+
* might still act; it is the wrong answer once enough time has passed that
|
|
33
|
+
* not-acting IS the answer. Leaving it `unknown` forever would let a worker
|
|
34
|
+
* that files things nobody ever touches sit permanently un-judged instead of
|
|
35
|
+
* accumulating the negative it has earned. The horizon is explicit and long
|
|
36
|
+
* (default 14 days) precisely because it converts silence into a negative.
|
|
37
|
+
*
|
|
38
|
+
* ## No model in the loop
|
|
39
|
+
*
|
|
40
|
+
* Pure function of observed state and two timestamps. A prior LLM judge in
|
|
41
|
+
* this repo flipped verdicts between runs on identical inputs, which makes the
|
|
42
|
+
* trust ledger unreproducible — and a trust ledger you cannot replay is not
|
|
43
|
+
* evidence, it is an opinion with a timestamp.
|
|
44
|
+
*/
|
|
45
|
+
/** Default staleness horizon: 14 days. */
|
|
46
|
+
export const DEFAULT_STALE_AFTER_MS = 14 * 24 * 60 * 60 * 1000;
|
|
47
|
+
/**
|
|
48
|
+
* Grade one observed artifact.
|
|
49
|
+
*
|
|
50
|
+
* Ordering is deliberate: the two POSITIVE ACTS are tested first, then
|
|
51
|
+
* staleness, and everything remaining falls to `unknown`. There is no branch
|
|
52
|
+
* that reaches `confirmed` without `completed === true`.
|
|
53
|
+
*/
|
|
54
|
+
export function gradeErrandOutcome(observed, opts) {
|
|
55
|
+
// Deleted is checked BEFORE completed. A tracker can report both when an
|
|
56
|
+
// operator completes and then clears a task, and "they threw it away" is the
|
|
57
|
+
// more conservative reading of a contradictory pair — it lowers trust rather
|
|
58
|
+
// than raising it on ambiguous evidence.
|
|
59
|
+
if (observed.deleted === true) {
|
|
60
|
+
return { disposition: "junk", reason: "deleted" };
|
|
61
|
+
}
|
|
62
|
+
if (observed.completed === true) {
|
|
63
|
+
return { disposition: "confirmed", reason: "completed" };
|
|
64
|
+
}
|
|
65
|
+
// Not completed, not deleted. Everything from here is an ABSENCE, and no
|
|
66
|
+
// absence may produce `confirmed`.
|
|
67
|
+
if (observed.createdAt === undefined) {
|
|
68
|
+
// We cannot even tell how long it has been open, so we cannot tell whether
|
|
69
|
+
// silence has become meaningful. Withhold.
|
|
70
|
+
return { disposition: "unknown", reason: "not-observed" };
|
|
71
|
+
}
|
|
72
|
+
const staleAfter = opts.staleAfterMs ?? DEFAULT_STALE_AFTER_MS;
|
|
73
|
+
const age = opts.now - observed.createdAt;
|
|
74
|
+
if (age >= staleAfter) {
|
|
75
|
+
return { disposition: "junk", reason: "stale-unactioned" };
|
|
76
|
+
}
|
|
77
|
+
return { disposition: "unknown", reason: "open-recent" };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=errandOutcomeGrader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errandOutcomeGrader.js","sourceRoot":"","sources":["../../src/butler/errandOutcomeGrader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AA+C/D;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgC,EAChC,IAAkB;IAElB,yEAAyE;IACzE,6EAA6E;IAC7E,6EAA6E;IAC7E,yCAAyC;IACzC,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;IACD,IAAI,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAChC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC3D,CAAC;IAED,yEAAyE;IACzE,mCAAmC;IACnC,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACrC,2EAA2E;QAC3E,2CAA2C;QAC3C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,IAAI,sBAAsB,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC;IAC1C,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;QACtB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shadow ledger for graded Butler errand outcomes.
|
|
3
|
+
*
|
|
4
|
+
* A SEPARATE file from `outcome-log.jsonl`, and that separation is the entire
|
|
5
|
+
* safety property of this phase. The trust fold reads `outcome-log.jsonl`; it
|
|
6
|
+
* does not read this file and must not be taught to. Rows here are a
|
|
7
|
+
* measurement of what the grader WOULD have said, recorded so the labelling
|
|
8
|
+
* can be checked against reality before anything moves a worker's dial.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors how the autonomy gate itself was landed — `workers shadow` and
|
|
11
|
+
* `workers backtest` measured divergence for a whole campaign before the gate
|
|
12
|
+
* was allowed to decide anything — and how #1319 was flipped, against a
|
|
13
|
+
* measured delta rather than an argument. The pattern exists because the
|
|
14
|
+
* alternative has failed here repeatedly: a labelling change that looks
|
|
15
|
+
* obviously correct turns out to move real workers in ways nobody predicted,
|
|
16
|
+
* and by then it is already in the ledger the gate rests on.
|
|
17
|
+
*
|
|
18
|
+
* ## What "shadow" costs
|
|
19
|
+
*
|
|
20
|
+
* Nothing observable. No gate decision consults it, no dial reads it, and
|
|
21
|
+
* deleting the file loses only the measurement. That is the point: until
|
|
22
|
+
* someone has read these rows against the real errands they describe, the
|
|
23
|
+
* grader has not earned the right to be evidence.
|
|
24
|
+
*
|
|
25
|
+
* ## Promotion
|
|
26
|
+
*
|
|
27
|
+
* Promoting it means writing graded rows into `outcome-log.jsonl` through
|
|
28
|
+
* `OutcomeStore.upsert` — deliberately NOT implemented here. That step needs
|
|
29
|
+
* the join key to be right (`ref` = `"<tool>:<id>"`, see `actionRef.ts`) and a
|
|
30
|
+
* measured before/after on the real log, exactly as #1319 required.
|
|
31
|
+
*/
|
|
32
|
+
import type { OutcomeDisposition } from "../workers/outcomeStore.js";
|
|
33
|
+
import type { GradedOutcome } from "./errandOutcomeGrader.js";
|
|
34
|
+
/**
|
|
35
|
+
* Filename. Deliberately NOT `outcome-log.jsonl` and deliberately not in a
|
|
36
|
+
* subdirectory of it — a reader that globs the outcome log must not pick this
|
|
37
|
+
* up by accident.
|
|
38
|
+
*/
|
|
39
|
+
export declare const SHADOW_LOG_BASENAME = "butler_outcome_shadow.jsonl";
|
|
40
|
+
export declare function shadowLogPath(override?: string): string;
|
|
41
|
+
export interface ShadowOutcomeRow {
|
|
42
|
+
/**
|
|
43
|
+
* The action this grades, in `canonicalActionRef` form (`"<tool>:<id>"`).
|
|
44
|
+
* Stored so a promoted row can join to the same action the fold would —
|
|
45
|
+
* recording a grade under a key the fold cannot resolve would produce a
|
|
46
|
+
* measurement of nothing.
|
|
47
|
+
*/
|
|
48
|
+
ref: string;
|
|
49
|
+
disposition: OutcomeDisposition;
|
|
50
|
+
reason: GradedOutcome["reason"];
|
|
51
|
+
/** When the grade was computed. */
|
|
52
|
+
gradedAt: number;
|
|
53
|
+
/** The recipe that filed the action, for attribution during review. */
|
|
54
|
+
recipe?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Whether the fold WOULD have counted this as evidence. Derived once at
|
|
57
|
+
* write time so a reviewer reading the file does not have to re-derive the
|
|
58
|
+
* withholding rule and risk deriving it differently.
|
|
59
|
+
*/
|
|
60
|
+
wouldCountAsEvidence: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** `unknown` is withheld by the fold; the other two are evidence. */
|
|
63
|
+
export declare function wouldCountAsEvidence(d: OutcomeDisposition): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Append one graded row. Append-only and best-effort: this is a measurement,
|
|
66
|
+
* and a measurement must never be able to fail an errand it is observing.
|
|
67
|
+
*/
|
|
68
|
+
export declare function appendShadowOutcome(row: Omit<ShadowOutcomeRow, "wouldCountAsEvidence">, opts?: {
|
|
69
|
+
dir?: string;
|
|
70
|
+
}): void;
|
|
71
|
+
export interface ShadowSummary {
|
|
72
|
+
total: number;
|
|
73
|
+
confirmed: number;
|
|
74
|
+
junk: number;
|
|
75
|
+
unknown: number;
|
|
76
|
+
/** Rows that would have become evidence had the grader been live. */
|
|
77
|
+
wouldCount: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Summarise the shadow ledger — the number this phase exists to produce.
|
|
81
|
+
*
|
|
82
|
+
* Malformed lines are SKIPPED but counted in nothing; a half-written row from
|
|
83
|
+
* an interrupted append is not evidence of anything and must not inflate a
|
|
84
|
+
* count someone is about to make a decision on.
|
|
85
|
+
*/
|
|
86
|
+
export declare function summariseShadowLog(opts?: {
|
|
87
|
+
dir?: string;
|
|
88
|
+
}): ShadowSummary;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shadow ledger for graded Butler errand outcomes.
|
|
3
|
+
*
|
|
4
|
+
* A SEPARATE file from `outcome-log.jsonl`, and that separation is the entire
|
|
5
|
+
* safety property of this phase. The trust fold reads `outcome-log.jsonl`; it
|
|
6
|
+
* does not read this file and must not be taught to. Rows here are a
|
|
7
|
+
* measurement of what the grader WOULD have said, recorded so the labelling
|
|
8
|
+
* can be checked against reality before anything moves a worker's dial.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors how the autonomy gate itself was landed — `workers shadow` and
|
|
11
|
+
* `workers backtest` measured divergence for a whole campaign before the gate
|
|
12
|
+
* was allowed to decide anything — and how #1319 was flipped, against a
|
|
13
|
+
* measured delta rather than an argument. The pattern exists because the
|
|
14
|
+
* alternative has failed here repeatedly: a labelling change that looks
|
|
15
|
+
* obviously correct turns out to move real workers in ways nobody predicted,
|
|
16
|
+
* and by then it is already in the ledger the gate rests on.
|
|
17
|
+
*
|
|
18
|
+
* ## What "shadow" costs
|
|
19
|
+
*
|
|
20
|
+
* Nothing observable. No gate decision consults it, no dial reads it, and
|
|
21
|
+
* deleting the file loses only the measurement. That is the point: until
|
|
22
|
+
* someone has read these rows against the real errands they describe, the
|
|
23
|
+
* grader has not earned the right to be evidence.
|
|
24
|
+
*
|
|
25
|
+
* ## Promotion
|
|
26
|
+
*
|
|
27
|
+
* Promoting it means writing graded rows into `outcome-log.jsonl` through
|
|
28
|
+
* `OutcomeStore.upsert` — deliberately NOT implemented here. That step needs
|
|
29
|
+
* the join key to be right (`ref` = `"<tool>:<id>"`, see `actionRef.ts`) and a
|
|
30
|
+
* measured before/after on the real log, exactly as #1319 required.
|
|
31
|
+
*/
|
|
32
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
33
|
+
import path from "node:path";
|
|
34
|
+
import { patchworkHome } from "../patchworkHome.js";
|
|
35
|
+
/**
|
|
36
|
+
* Filename. Deliberately NOT `outcome-log.jsonl` and deliberately not in a
|
|
37
|
+
* subdirectory of it — a reader that globs the outcome log must not pick this
|
|
38
|
+
* up by accident.
|
|
39
|
+
*/
|
|
40
|
+
export const SHADOW_LOG_BASENAME = "butler_outcome_shadow.jsonl";
|
|
41
|
+
export function shadowLogPath(override) {
|
|
42
|
+
return path.join(override ?? patchworkHome(), SHADOW_LOG_BASENAME);
|
|
43
|
+
}
|
|
44
|
+
/** `unknown` is withheld by the fold; the other two are evidence. */
|
|
45
|
+
export function wouldCountAsEvidence(d) {
|
|
46
|
+
return d !== "unknown";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Append one graded row. Append-only and best-effort: this is a measurement,
|
|
50
|
+
* and a measurement must never be able to fail an errand it is observing.
|
|
51
|
+
*/
|
|
52
|
+
export function appendShadowOutcome(row, opts = {}) {
|
|
53
|
+
const full = {
|
|
54
|
+
...row,
|
|
55
|
+
wouldCountAsEvidence: wouldCountAsEvidence(row.disposition),
|
|
56
|
+
};
|
|
57
|
+
try {
|
|
58
|
+
appendFileSync(shadowLogPath(opts.dir), `${JSON.stringify(full)}\n`);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Swallowed on purpose. See above: an unwritable shadow ledger must not
|
|
62
|
+
// turn into an errand failure.
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Summarise the shadow ledger — the number this phase exists to produce.
|
|
67
|
+
*
|
|
68
|
+
* Malformed lines are SKIPPED but counted in nothing; a half-written row from
|
|
69
|
+
* an interrupted append is not evidence of anything and must not inflate a
|
|
70
|
+
* count someone is about to make a decision on.
|
|
71
|
+
*/
|
|
72
|
+
export function summariseShadowLog(opts = {}) {
|
|
73
|
+
const empty = {
|
|
74
|
+
total: 0,
|
|
75
|
+
confirmed: 0,
|
|
76
|
+
junk: 0,
|
|
77
|
+
unknown: 0,
|
|
78
|
+
wouldCount: 0,
|
|
79
|
+
};
|
|
80
|
+
const p = shadowLogPath(opts.dir);
|
|
81
|
+
if (!existsSync(p))
|
|
82
|
+
return empty;
|
|
83
|
+
let text;
|
|
84
|
+
try {
|
|
85
|
+
text = readFileSync(p, "utf-8");
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return empty;
|
|
89
|
+
}
|
|
90
|
+
const out = { ...empty };
|
|
91
|
+
for (const line of text.split("\n")) {
|
|
92
|
+
if (!line.trim())
|
|
93
|
+
continue;
|
|
94
|
+
let row;
|
|
95
|
+
try {
|
|
96
|
+
row = JSON.parse(line);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (row.disposition !== "confirmed" &&
|
|
102
|
+
row.disposition !== "junk" &&
|
|
103
|
+
row.disposition !== "unknown") {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
out.total++;
|
|
107
|
+
out[row.disposition]++;
|
|
108
|
+
if (row.wouldCountAsEvidence)
|
|
109
|
+
out.wouldCount++;
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=outcomeShadowLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcomeShadowLog.js","sourceRoot":"","sources":["../../src/butler/outcomeShadowLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;AAEjE,MAAM,UAAU,aAAa,CAAC,QAAiB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,aAAa,EAAE,EAAE,mBAAmB,CAAC,CAAC;AACrE,CAAC;AAwBD,qEAAqE;AACrE,MAAM,UAAU,oBAAoB,CAAC,CAAqB;IACxD,OAAO,CAAC,KAAK,SAAS,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAmD,EACnD,OAAyB,EAAE;IAE3B,MAAM,IAAI,GAAqB;QAC7B,GAAG,GAAG;QACN,oBAAoB,EAAE,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC;KAC5D,CAAC;IACF,IAAI,CAAC;QACH,cAAc,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,+BAA+B;IACjC,CAAC;AACH,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAyB,EAAE;IAC5D,MAAM,KAAK,GAAkB;QAC3B,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,CAAC;KACd,CAAC;IACF,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,GAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqB,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IACE,GAAG,CAAC,WAAW,KAAK,WAAW;YAC/B,GAAG,CAAC,WAAW,KAAK,MAAM;YAC1B,GAAG,CAAC,WAAW,KAAK,SAAS,EAC7B,CAAC;YACD,SAAS;QACX,CAAC;QACD,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,oBAAoB;YAAE,GAAG,CAAC,UAAU,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "1.2.0-beta.2.canary.
|
|
3
|
+
"version": "1.2.0-beta.2.canary.635",
|
|
4
4
|
"description": "Your personal AI runtime, local-first. Patchwork OS gives any AI model a consistent set of tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all on your machine, all under your policy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|