patchwork-os 0.2.0-beta.13.canary.263 → 0.2.0-beta.13.canary.265
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/approvalQueue.d.ts +1 -1
- package/dist/approvalQueue.js.map +1 -1
- package/dist/riskSignals.js +42 -1
- package/dist/riskSignals.js.map +1 -1
- package/dist/workers/actionClass.d.ts +31 -0
- package/dist/workers/actionClass.js +137 -0
- package/dist/workers/actionClass.js.map +1 -0
- package/dist/workers/graduation.d.ts +52 -0
- package/dist/workers/graduation.js +86 -0
- package/dist/workers/graduation.js.map +1 -0
- package/dist/workers/shadowGate.d.ts +30 -0
- package/dist/workers/shadowGate.js +32 -0
- package/dist/workers/shadowGate.js.map +1 -0
- package/dist/workers/shadowRun.d.ts +38 -0
- package/dist/workers/shadowRun.js +44 -0
- package/dist/workers/shadowRun.js.map +1 -0
- package/dist/workers/trustLevel.d.ts +77 -0
- package/dist/workers/trustLevel.js +91 -0
- package/dist/workers/trustLevel.js.map +1 -0
- package/dist/workers/worker.d.ts +41 -0
- package/dist/workers/worker.js +77 -0
- package/dist/workers/worker.js.map +1 -0
- package/dist/workers/workerLevelStore.d.ts +33 -0
- package/dist/workers/workerLevelStore.js +87 -0
- package/dist/workers/workerLevelStore.js.map +1 -0
- package/package.json +1 -1
- package/templates/recipes/dependency-bump.yaml +33 -0
- package/templates/recipes/release-notes.yaml +30 -0
- package/templates/recipes/triage-failing-tests.yaml +38 -0
- package/templates/workers/dependency-upkeep.worker.yaml +18 -0
- package/templates/workers/release-notes.worker.yaml +17 -0
- package/templates/workers/test-guardian.worker.yaml +18 -0
package/dist/approvalQueue.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type { RiskTier } from "./riskTier.js";
|
|
|
11
11
|
* - TTL prevents zombie entries if the dashboard never responds
|
|
12
12
|
*/
|
|
13
13
|
export interface RiskSignal {
|
|
14
|
-
kind: "destructive_flag" | "domain_reputation" | "path_escape" | "chaining";
|
|
14
|
+
kind: "destructive_flag" | "domain_reputation" | "path_escape" | "chaining" | "destructive_command" | "data_exfiltration";
|
|
15
15
|
label: string;
|
|
16
16
|
severity: "low" | "medium" | "high";
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approvalQueue.js","sourceRoot":"","sources":["../src/approvalQueue.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,eAAe,GAChB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"approvalQueue.js","sourceRoot":"","sources":["../src/approvalQueue.ts"],"names":[],"mappings":"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"}
|
package/dist/riskSignals.js
CHANGED
|
@@ -25,9 +25,19 @@ export function computeRiskSignals(toolName, params, workspace) {
|
|
|
25
25
|
const signals = [];
|
|
26
26
|
// Destructive flags — shell commands
|
|
27
27
|
if (COMMAND_TOOLS.has(toolName)) {
|
|
28
|
-
const
|
|
28
|
+
const cmdBase = (typeof params.command === "string" && params.command) ||
|
|
29
29
|
(typeof params.text === "string" && params.text) ||
|
|
30
30
|
"";
|
|
31
|
+
// runCommand delivers the subcommand + flags in params.args (its `command`
|
|
32
|
+
// is the bare basename, e.g. "git"); runInTerminal / sendTerminalCommand
|
|
33
|
+
// carry the whole shell string and have no `args`. Join them so every
|
|
34
|
+
// pattern below sees the FULL command for all four tools — otherwise a
|
|
35
|
+
// `git reset --hard` issued as runCommand{command:"git",args:[…]} reduces
|
|
36
|
+
// to "git" and silently matches nothing. (P1-3 / P1-7)
|
|
37
|
+
const argsArr = Array.isArray(params.args)
|
|
38
|
+
? params.args.filter((a) => typeof a === "string")
|
|
39
|
+
: [];
|
|
40
|
+
const cmd = argsArr.length > 0 ? `${cmdBase} ${argsArr.join(" ")}` : cmdBase;
|
|
31
41
|
if (/\brm\b.*-[a-z]*r[a-z]*f|\brm\b.*-[a-z]*f[a-z]*r/i.test(cmd)) {
|
|
32
42
|
signals.push({
|
|
33
43
|
kind: "destructive_flag",
|
|
@@ -84,6 +94,37 @@ export function computeRiskSignals(toolName, params, workspace) {
|
|
|
84
94
|
severity: "low",
|
|
85
95
|
});
|
|
86
96
|
}
|
|
97
|
+
// Destructive git / system commands — mirrors the SubprocessDriver deny-list
|
|
98
|
+
// (claudeDriver.ts / subprocessSettings.ts). The driver HARD-denies these on
|
|
99
|
+
// its ungated subprocess path; the bridge's gated path escalates them to
|
|
100
|
+
// human approval instead. `--force-with-lease` is intentionally NOT flagged
|
|
101
|
+
// (it is the safe force-push the bridge itself uses). `rm -rf` / `sudo` are
|
|
102
|
+
// already covered above. (audit P1-3)
|
|
103
|
+
if (/\bgit\b.*\breset\b.*--hard\b/i.test(cmd) ||
|
|
104
|
+
/\bgit\b.*\bclean\b.*(-[a-z]*f|--force|-d)/i.test(cmd) ||
|
|
105
|
+
/\bgit\b.*\bpush\b.*(--force(?!-with-lease)|(?:^|\s)-f)\b/i.test(cmd) ||
|
|
106
|
+
/\beval\b/i.test(cmd) ||
|
|
107
|
+
/\bchmod\b.*\b777\b/i.test(cmd) ||
|
|
108
|
+
/\bkill\b.*\s-9\b/i.test(cmd) ||
|
|
109
|
+
/\bpkill\b/i.test(cmd)) {
|
|
110
|
+
signals.push({
|
|
111
|
+
kind: "destructive_command",
|
|
112
|
+
label: "destructive git/system command",
|
|
113
|
+
severity: "high",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Data exfiltration — a network-egress upload flag co-occurring with a
|
|
117
|
+
// credential-path reference. Near-zero legitimate use at an agent approval
|
|
118
|
+
// gate, so escalate to approval. (audit P1-7)
|
|
119
|
+
const exfilEgress = /\bcurl\b.*(-T\b|--upload-file\b|--data(?:-binary)?\s+@|(?:^|\s)-d\s+@)|\bwget\b.*--post-file=/i;
|
|
120
|
+
const credPath = /\.ssh\b|\.aws\b|\bid_rsa\b|\bid_ed25519\b|\.env\b|\bcredentials\b|\.npmrc\b|\.netrc\b/i;
|
|
121
|
+
if (exfilEgress.test(cmd) && credPath.test(cmd)) {
|
|
122
|
+
signals.push({
|
|
123
|
+
kind: "data_exfiltration",
|
|
124
|
+
label: "network upload of credential file",
|
|
125
|
+
severity: "high",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
87
128
|
}
|
|
88
129
|
// Domain reputation — WebFetch / sendHttpRequest
|
|
89
130
|
if (toolName === "WebFetch" || toolName === "sendHttpRequest") {
|
package/dist/riskSignals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"riskSignals.js","sourceRoot":"","sources":["../src/riskSignals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AAE5D;;;;GAIG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,MAAM;IACN,YAAY;IACZ,eAAe;IACf,qBAAqB;CACtB,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,MAA+B,EAC/B,SAAiB;IAEjB,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,qCAAqC;IACrC,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,MAAM,
|
|
1
|
+
{"version":3,"file":"riskSignals.js","sourceRoot":"","sources":["../src/riskSignals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type RiskTier } from "../riskTier.js";
|
|
2
|
+
/**
|
|
3
|
+
* Worker trust is scoped per (worker × action-class), never globally. An
|
|
4
|
+
* action-class is the unit that accumulates evidence. It is intentionally
|
|
5
|
+
* COARSE enough to graduate (a worker touches only a handful) yet keyed on
|
|
6
|
+
* blast-tier so that a rarer, higher-blast action in the same domain is a
|
|
7
|
+
* DISTINCT, less-trusted class — competence on routine `git status` can never
|
|
8
|
+
* transfer to `git push --force`. (worker-ramp-v0)
|
|
9
|
+
*/
|
|
10
|
+
export type Reversibility = "reversible" | "compensable" | "irreversible";
|
|
11
|
+
export interface ActionClass {
|
|
12
|
+
/** Stable identity: `${domain}:${reversibility}:${blastTier}`. */
|
|
13
|
+
key: string;
|
|
14
|
+
domain: string;
|
|
15
|
+
reversibility: Reversibility;
|
|
16
|
+
blastTier: RiskTier;
|
|
17
|
+
/**
|
|
18
|
+
* Brand/reputational exposure — a DISTINCT gating dimension from safety blast
|
|
19
|
+
* radius (cf. Arts & Media: low safety risk, high reputational risk). An
|
|
20
|
+
* externally-visible action (outbound message, public PR/push, issue) whose
|
|
21
|
+
* failure damages reputation rather than (or as well as) systems. Folds into
|
|
22
|
+
* the failure weight so reputational mistakes demote trust harder.
|
|
23
|
+
*/
|
|
24
|
+
brandExposed: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function classifyActionClass(toolName: string, _params?: Record<string, unknown>): ActionClass;
|
|
27
|
+
export declare function outcomeWeight(actionClass: ActionClass, good: boolean): number;
|
|
28
|
+
/** Which ramp rungs are reachable for a class. Irreversible classes skip the
|
|
29
|
+
* safety-net rungs L2/L3 (no compensating action exists), so they must clear a
|
|
30
|
+
* higher bar to reach L4. */
|
|
31
|
+
export declare function reachableLevels(actionClass: ActionClass): number[];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { classifyTool } from "../riskTier.js";
|
|
2
|
+
/**
|
|
3
|
+
* Tool → capability domain. Coarse on purpose. Unknown tools fall to "other"
|
|
4
|
+
* (treated as irreversible — conservative: an unrecognised side effect is
|
|
5
|
+
* assumed unrecoverable until proven otherwise).
|
|
6
|
+
*/
|
|
7
|
+
const DOMAIN_BY_TOOL = {
|
|
8
|
+
// version control — read
|
|
9
|
+
getGitStatus: "vcs-read",
|
|
10
|
+
getGitDiff: "vcs-read",
|
|
11
|
+
getGitLog: "vcs-read",
|
|
12
|
+
gitBlame: "vcs-read",
|
|
13
|
+
gitListBranches: "vcs-read",
|
|
14
|
+
// version control — local mutations (reversible: reset/reflog/restore)
|
|
15
|
+
gitAdd: "vcs-local",
|
|
16
|
+
gitCommit: "vcs-local",
|
|
17
|
+
gitCheckout: "vcs-local",
|
|
18
|
+
gitStash: "vcs-local",
|
|
19
|
+
// version control — remote / shared history
|
|
20
|
+
gitPush: "vcs-remote",
|
|
21
|
+
githubCreatePR: "vcs-remote",
|
|
22
|
+
githubMergePR: "vcs-remote",
|
|
23
|
+
// filesystem
|
|
24
|
+
editText: "fs-write",
|
|
25
|
+
searchAndReplace: "fs-write",
|
|
26
|
+
createFile: "fs-write",
|
|
27
|
+
formatDocument: "fs-write",
|
|
28
|
+
getBufferContent: "fs-read",
|
|
29
|
+
findFiles: "fs-read",
|
|
30
|
+
// shell
|
|
31
|
+
runCommand: "shell",
|
|
32
|
+
runInTerminal: "shell",
|
|
33
|
+
sendTerminalCommand: "shell",
|
|
34
|
+
// outbound messaging
|
|
35
|
+
slackPostMessage: "messaging",
|
|
36
|
+
// generic network
|
|
37
|
+
sendHttpRequest: "http",
|
|
38
|
+
WebFetch: "http",
|
|
39
|
+
// issue trackers
|
|
40
|
+
githubCreateIssue: "issue",
|
|
41
|
+
createLinearIssue: "issue",
|
|
42
|
+
addLinearComment: "issue",
|
|
43
|
+
updateLinearIssue: "issue",
|
|
44
|
+
// CI / tests
|
|
45
|
+
runTests: "ci",
|
|
46
|
+
githubActions: "ci",
|
|
47
|
+
// dependency intel (read-only)
|
|
48
|
+
auditDependencies: "deps-read",
|
|
49
|
+
getSecurityAdvisories: "deps-read",
|
|
50
|
+
// recipe-tool ids — RecipeRunLog records THESE (not the MCP names), so the
|
|
51
|
+
// shadow dial attributes recipe-run steps by them. git.*/github.list_* are
|
|
52
|
+
// reads; file.* writes; slack/http are outbound. (worker-ramp-v0 dogfood)
|
|
53
|
+
"git.log_since": "vcs-read",
|
|
54
|
+
"git.stale_branches": "vcs-read",
|
|
55
|
+
"github.list_commits": "vcs-read",
|
|
56
|
+
"github.list_prs": "vcs-read",
|
|
57
|
+
"github.list_issues": "vcs-read",
|
|
58
|
+
"file.read": "fs-read",
|
|
59
|
+
"file.write": "fs-write",
|
|
60
|
+
"file.append": "fs-write",
|
|
61
|
+
"slack.post_message": "messaging",
|
|
62
|
+
"http.post": "http",
|
|
63
|
+
"linear.list_issues": "issue",
|
|
64
|
+
"sentry.get_issue": "issue",
|
|
65
|
+
"diagnostics.get": "fs-read",
|
|
66
|
+
};
|
|
67
|
+
/** Domain → reversibility. The middle ramp rungs (L2/L3) only exist for a class
|
|
68
|
+
* whose reversibility is not "irreversible", so this is load-bearing. */
|
|
69
|
+
const REVERSIBILITY_BY_DOMAIN = {
|
|
70
|
+
"vcs-read": "reversible",
|
|
71
|
+
"vcs-local": "reversible", // reset / reflog / restore
|
|
72
|
+
"vcs-remote": "compensable", // force-push back / close PR — lossy, possible
|
|
73
|
+
"fs-write": "reversible", // transactions + WriteEffectLedger
|
|
74
|
+
"fs-read": "reversible",
|
|
75
|
+
shell: "irreversible", // arbitrary side effects — assume unrecoverable
|
|
76
|
+
messaging: "irreversible", // a sent message can't be unsent reliably
|
|
77
|
+
http: "irreversible", // a POST may not be undoable
|
|
78
|
+
issue: "compensable", // close / delete the created issue
|
|
79
|
+
ci: "reversible", // re-runnable, no durable side effect
|
|
80
|
+
"deps-read": "reversible",
|
|
81
|
+
other: "irreversible",
|
|
82
|
+
};
|
|
83
|
+
/** Domains whose actions are externally visible — failure is reputational. */
|
|
84
|
+
const BRAND_EXPOSED_DOMAINS = new Set([
|
|
85
|
+
"messaging",
|
|
86
|
+
"vcs-remote",
|
|
87
|
+
"issue",
|
|
88
|
+
"http",
|
|
89
|
+
]);
|
|
90
|
+
export function classifyActionClass(toolName, _params) {
|
|
91
|
+
const domain = DOMAIN_BY_TOOL[toolName] ?? "other";
|
|
92
|
+
const reversibility = REVERSIBILITY_BY_DOMAIN[domain] ?? "irreversible";
|
|
93
|
+
const blastTier = classifyTool(toolName);
|
|
94
|
+
return {
|
|
95
|
+
key: `${domain}:${reversibility}:${blastTier}`,
|
|
96
|
+
domain,
|
|
97
|
+
reversibility,
|
|
98
|
+
blastTier,
|
|
99
|
+
brandExposed: BRAND_EXPOSED_DOMAINS.has(domain),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const BLAST_MULTIPLIER = {
|
|
103
|
+
low: 2,
|
|
104
|
+
medium: 5,
|
|
105
|
+
high: 12,
|
|
106
|
+
};
|
|
107
|
+
const REVERSIBILITY_MULTIPLIER = {
|
|
108
|
+
reversible: 1,
|
|
109
|
+
compensable: 1.5,
|
|
110
|
+
irreversible: 3,
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Evidence weight for one outcome. A routine success is low-information
|
|
114
|
+
* (weight 1 → the posterior climbs slowly). A failure is weighted by
|
|
115
|
+
* blast-tier × reversibility, so a high-blast irreversible failure is high
|
|
116
|
+
* information and craters the posterior (instant demote). This is the entire
|
|
117
|
+
* anti-trust-transfer-grinding defence: count alone never graduates a risky
|
|
118
|
+
* class, and one catastrophic outcome dominates a thousand trivial ones.
|
|
119
|
+
*/
|
|
120
|
+
const BRAND_MULTIPLIER = 1.5;
|
|
121
|
+
export function outcomeWeight(actionClass, good) {
|
|
122
|
+
if (good)
|
|
123
|
+
return 1;
|
|
124
|
+
const brand = actionClass.brandExposed ? BRAND_MULTIPLIER : 1;
|
|
125
|
+
return (BLAST_MULTIPLIER[actionClass.blastTier] *
|
|
126
|
+
REVERSIBILITY_MULTIPLIER[actionClass.reversibility] *
|
|
127
|
+
brand);
|
|
128
|
+
}
|
|
129
|
+
/** Which ramp rungs are reachable for a class. Irreversible classes skip the
|
|
130
|
+
* safety-net rungs L2/L3 (no compensating action exists), so they must clear a
|
|
131
|
+
* higher bar to reach L4. */
|
|
132
|
+
export function reachableLevels(actionClass) {
|
|
133
|
+
return actionClass.reversibility === "irreversible"
|
|
134
|
+
? [0, 1, 4]
|
|
135
|
+
: [0, 1, 2, 3, 4];
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=actionClass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionClass.js","sourceRoot":"","sources":["../../src/workers/actionClass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Posterior, type TrustLevel } from "./trustLevel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Folds outcomes into a (worker × action-class) trust state and decides
|
|
4
|
+
* promotions/demotions with the asymmetry + hysteresis the ramp requires:
|
|
5
|
+
* - DEMOTE is instant and can jump multiple rungs (one catastrophic outcome
|
|
6
|
+
* craters the posterior; we honor it immediately, even mid-dwell);
|
|
7
|
+
* - PROMOTE is gated by dwell-time (real elapsed time since the last level
|
|
8
|
+
* change) AND a post-demote cooldown, and climbs only to the NEXT reachable
|
|
9
|
+
* rung — so reaching L4 needs both sustained evidence and sustained time.
|
|
10
|
+
* Every level change emits an event — the promotion/demotion log is the
|
|
11
|
+
* compliance/audit artifact.
|
|
12
|
+
*/
|
|
13
|
+
export interface Outcome {
|
|
14
|
+
toolName: string;
|
|
15
|
+
good: boolean;
|
|
16
|
+
/** epoch ms (passed in — the runtime has no Date.now() in pure code). */
|
|
17
|
+
at: number;
|
|
18
|
+
params?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface ClassTrustState {
|
|
21
|
+
classKey: string;
|
|
22
|
+
posterior: Posterior;
|
|
23
|
+
prior: Posterior;
|
|
24
|
+
level: TrustLevel;
|
|
25
|
+
/** epoch ms of the last level change (drives dwell). */
|
|
26
|
+
lastChangeAt: number;
|
|
27
|
+
/** epoch ms before which promotions are blocked (post-demote cooldown). */
|
|
28
|
+
demoteUntil: number;
|
|
29
|
+
observations: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GraduationConfig {
|
|
32
|
+
dwellMs: number;
|
|
33
|
+
demoteCooldownMs: number;
|
|
34
|
+
k?: number;
|
|
35
|
+
minEvidenceForGraduation?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare const DEFAULT_GRADUATION_CONFIG: GraduationConfig;
|
|
38
|
+
export interface GraduationEvent {
|
|
39
|
+
type: "promote" | "demote";
|
|
40
|
+
classKey: string;
|
|
41
|
+
from: TrustLevel;
|
|
42
|
+
to: TrustLevel;
|
|
43
|
+
at: number;
|
|
44
|
+
lcb: number;
|
|
45
|
+
evidence: number;
|
|
46
|
+
reason: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function initialState(classKey: string, prior: Posterior, at?: number): ClassTrustState;
|
|
49
|
+
export declare function graduate(state: ClassTrustState, outcome: Outcome, cfg?: GraduationConfig): {
|
|
50
|
+
state: ClassTrustState;
|
|
51
|
+
event?: GraduationEvent;
|
|
52
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { classifyActionClass, outcomeWeight, reachableLevels, } from "./actionClass.js";
|
|
2
|
+
import { applyOutcome, levelFromPosterior, } from "./trustLevel.js";
|
|
3
|
+
export const DEFAULT_GRADUATION_CONFIG = {
|
|
4
|
+
dwellMs: 6 * 60 * 60 * 1000, // 6h between climbs
|
|
5
|
+
demoteCooldownMs: 24 * 60 * 60 * 1000, // 24h freeze after a fall
|
|
6
|
+
minEvidenceForGraduation: 10,
|
|
7
|
+
};
|
|
8
|
+
export function initialState(classKey, prior, at = 0) {
|
|
9
|
+
return {
|
|
10
|
+
classKey,
|
|
11
|
+
posterior: prior,
|
|
12
|
+
prior,
|
|
13
|
+
level: 0,
|
|
14
|
+
lastChangeAt: at,
|
|
15
|
+
demoteUntil: 0,
|
|
16
|
+
observations: 0,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function graduate(state, outcome, cfg = DEFAULT_GRADUATION_CONFIG) {
|
|
20
|
+
const ac = classifyActionClass(outcome.toolName, outcome.params);
|
|
21
|
+
const weight = outcomeWeight(ac, outcome.good);
|
|
22
|
+
const posterior = applyOutcome(state.posterior, outcome.good, weight);
|
|
23
|
+
const observations = state.observations + 1;
|
|
24
|
+
const result = levelFromPosterior(posterior, state.prior, {
|
|
25
|
+
k: cfg.k,
|
|
26
|
+
minEvidenceForGraduation: cfg.minEvidenceForGraduation,
|
|
27
|
+
reachable: reachableLevels(ac),
|
|
28
|
+
});
|
|
29
|
+
const candidate = result.level;
|
|
30
|
+
const base = {
|
|
31
|
+
...state,
|
|
32
|
+
posterior,
|
|
33
|
+
observations,
|
|
34
|
+
};
|
|
35
|
+
// DEMOTE — instant, may skip rungs.
|
|
36
|
+
if (candidate < state.level) {
|
|
37
|
+
const next = {
|
|
38
|
+
...base,
|
|
39
|
+
level: candidate,
|
|
40
|
+
lastChangeAt: outcome.at,
|
|
41
|
+
demoteUntil: outcome.at + cfg.demoteCooldownMs,
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
state: next,
|
|
45
|
+
event: {
|
|
46
|
+
type: "demote",
|
|
47
|
+
classKey: state.classKey,
|
|
48
|
+
from: state.level,
|
|
49
|
+
to: candidate,
|
|
50
|
+
at: outcome.at,
|
|
51
|
+
lcb: result.lcb,
|
|
52
|
+
evidence: result.evidence,
|
|
53
|
+
reason: `blast-weighted failure (weight=${weight})`,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// PROMOTE — gated by dwell + cooldown, one reachable rung at a time.
|
|
58
|
+
if (candidate > state.level) {
|
|
59
|
+
const dwellOk = outcome.at >= state.lastChangeAt + cfg.dwellMs;
|
|
60
|
+
const cooldownOk = outcome.at >= state.demoteUntil;
|
|
61
|
+
if (dwellOk && cooldownOk) {
|
|
62
|
+
const nextRung = reachableLevels(ac)
|
|
63
|
+
.filter((r) => r > state.level && r <= candidate)
|
|
64
|
+
.sort((a, b) => a - b)[0];
|
|
65
|
+
if (nextRung !== undefined) {
|
|
66
|
+
const to = nextRung;
|
|
67
|
+
return {
|
|
68
|
+
state: { ...base, level: to, lastChangeAt: outcome.at },
|
|
69
|
+
event: {
|
|
70
|
+
type: "promote",
|
|
71
|
+
classKey: state.classKey,
|
|
72
|
+
from: state.level,
|
|
73
|
+
to,
|
|
74
|
+
at: outcome.at,
|
|
75
|
+
lcb: result.lcb,
|
|
76
|
+
evidence: result.evidence,
|
|
77
|
+
reason: `sustained evidence (lcb=${result.lcb.toFixed(3)})`,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// No level change — posterior still updates.
|
|
84
|
+
return { state: base };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=graduation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graduation.js","sourceRoot":"","sources":["../../src/workers/graduation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TrustLevel } from "./trustLevel.js";
|
|
2
|
+
import { type WorkerManifest } from "./worker.js";
|
|
3
|
+
import type { WorkerLevelStore } from "./workerLevelStore.js";
|
|
4
|
+
/**
|
|
5
|
+
* What the ramp WOULD decide for a worker's action — a PURE recommendation.
|
|
6
|
+
*
|
|
7
|
+
* v0 is shadow-only: this is NOT wired into the live approval gate
|
|
8
|
+
* (`evaluateInProcessGate`). Flipping the gate to obey the ramp is a deliberate,
|
|
9
|
+
* flag-gated phase-2 step, taken only after shadow data shows the ramp's
|
|
10
|
+
* decisions track reality. Until then this exists to log "ramp would bypass /
|
|
11
|
+
* gate did queue" and to drive the dial.
|
|
12
|
+
*
|
|
13
|
+
* Only the two execution modes that already exist are actionable in v0:
|
|
14
|
+
* L4 → bypass (autonomous), everything below → queue (approve-each).
|
|
15
|
+
* The full earned level (0–4) is reported for the dial. The effective level is
|
|
16
|
+
* `min(earned, autonomyCeiling)`, floored to 0 for actions outside the worker's
|
|
17
|
+
* domain — a worker has no standing trust on things it doesn't own.
|
|
18
|
+
*/
|
|
19
|
+
export interface ShadowDecision {
|
|
20
|
+
decision: "queue" | "bypass";
|
|
21
|
+
classKey: string;
|
|
22
|
+
owned: boolean;
|
|
23
|
+
/** Trust the worker has actually earned on this class (drives the dial). */
|
|
24
|
+
earnedLevel: TrustLevel;
|
|
25
|
+
autonomyCeiling: TrustLevel;
|
|
26
|
+
/** What the gate would operate at: min(earned, ceiling), 0 if not owned. */
|
|
27
|
+
effectiveLevel: TrustLevel;
|
|
28
|
+
reason: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function recommend(worker: WorkerManifest, toolName: string, params: Record<string, unknown> | undefined, store: WorkerLevelStore): ShadowDecision;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { classifyActionClass } from "./actionClass.js";
|
|
2
|
+
import { ownsAction } from "./worker.js";
|
|
3
|
+
const AUTONOMOUS_LEVEL = 4;
|
|
4
|
+
export function recommend(worker, toolName, params, store) {
|
|
5
|
+
const ac = classifyActionClass(toolName, params);
|
|
6
|
+
const owned = ownsAction(worker, ac);
|
|
7
|
+
const earnedLevel = (store.getState(worker.id, ac.key)?.level ??
|
|
8
|
+
0);
|
|
9
|
+
let effectiveLevel = owned ? earnedLevel : 0;
|
|
10
|
+
if (effectiveLevel > worker.autonomyCeiling)
|
|
11
|
+
effectiveLevel = worker.autonomyCeiling;
|
|
12
|
+
const decision = effectiveLevel >= AUTONOMOUS_LEVEL ? "bypass" : "queue";
|
|
13
|
+
let reason;
|
|
14
|
+
if (!owned)
|
|
15
|
+
reason = "outside-worker-domain";
|
|
16
|
+
else if (worker.autonomyCeiling < earnedLevel)
|
|
17
|
+
reason = `capped-by-autonomy-ceiling (L${worker.autonomyCeiling}, earned L${earnedLevel})`;
|
|
18
|
+
else if (decision === "bypass")
|
|
19
|
+
reason = "autonomous (earned L4)";
|
|
20
|
+
else
|
|
21
|
+
reason = `below-autonomy (effective L${effectiveLevel})`;
|
|
22
|
+
return {
|
|
23
|
+
decision,
|
|
24
|
+
classKey: ac.key,
|
|
25
|
+
owned,
|
|
26
|
+
earnedLevel,
|
|
27
|
+
autonomyCeiling: worker.autonomyCeiling,
|
|
28
|
+
effectiveLevel,
|
|
29
|
+
reason,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=shadowGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadowGate.js","sourceRoot":"","sources":["../../src/workers/shadowGate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AA+B9D,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,MAAM,UAAU,SAAS,CACvB,MAAsB,EACtB,QAAgB,EAChB,MAA2C,EAC3C,KAAuB;IAEvB,MAAM,EAAE,GAAG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK;QAC3D,CAAC,CAAe,CAAC;IAEnB,IAAI,cAAc,GAAe,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,IAAI,cAAc,GAAG,MAAM,CAAC,eAAe;QACzC,cAAc,GAAG,MAAM,CAAC,eAAe,CAAC;IAE1C,MAAM,QAAQ,GAAG,cAAc,IAAI,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAEzE,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC,KAAK;QAAE,MAAM,GAAG,uBAAuB,CAAC;SACxC,IAAI,MAAM,CAAC,eAAe,GAAG,WAAW;QAC3C,MAAM,GAAG,gCAAgC,MAAM,CAAC,eAAe,aAAa,WAAW,GAAG,CAAC;SACxF,IAAI,QAAQ,KAAK,QAAQ;QAAE,MAAM,GAAG,wBAAwB,CAAC;;QAC7D,MAAM,GAAG,8BAA8B,cAAc,GAAG,CAAC;IAE9D,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,EAAE,CAAC,GAAG;QAChB,KAAK;QACL,WAAW;QACX,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,cAAc;QACd,MAAM;KACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type GraduationConfig, type Outcome } from "./graduation.js";
|
|
2
|
+
import { type WorkerManifest } from "./worker.js";
|
|
3
|
+
import { type AuditEvent, type BoardRow, WorkerLevelStore } from "./workerLevelStore.js";
|
|
4
|
+
/**
|
|
5
|
+
* Replay an outcome sequence for a worker and capture the per-step dial
|
|
6
|
+
* trajectory. This is the cheapest test of the evidence-latency risk: it shows,
|
|
7
|
+
* deterministically, how many real observations (and how much wall-clock) a
|
|
8
|
+
* worker needs to climb each class — and how one catastrophic outcome demotes
|
|
9
|
+
* it in a single step. No model calls, no live gate — pure replay.
|
|
10
|
+
*/
|
|
11
|
+
export interface TrajectoryStep {
|
|
12
|
+
index: number;
|
|
13
|
+
at: number;
|
|
14
|
+
toolName: string;
|
|
15
|
+
good: boolean;
|
|
16
|
+
classKey: string;
|
|
17
|
+
level: number;
|
|
18
|
+
changed: "promote" | "demote" | null;
|
|
19
|
+
}
|
|
20
|
+
export interface ShadowRunResult {
|
|
21
|
+
workerId: string;
|
|
22
|
+
trajectory: TrajectoryStep[];
|
|
23
|
+
board: BoardRow[];
|
|
24
|
+
events: AuditEvent[];
|
|
25
|
+
store: WorkerLevelStore;
|
|
26
|
+
}
|
|
27
|
+
export declare function shadowRun(worker: WorkerManifest, outcomes: Outcome[], opts?: {
|
|
28
|
+
cfg?: GraduationConfig;
|
|
29
|
+
store?: WorkerLevelStore;
|
|
30
|
+
}): ShadowRunResult;
|
|
31
|
+
/** First trajectory step where `classKey` reached at least `level`. */
|
|
32
|
+
export declare function firstReached(result: ShadowRunResult, classKey: string, level: number): TrajectoryStep | undefined;
|
|
33
|
+
/** Build a steady cadence of same-tool outcomes spaced `intervalMs` apart. */
|
|
34
|
+
export declare function cadence(toolName: string, count: number, opts?: {
|
|
35
|
+
startAt?: number;
|
|
36
|
+
intervalMs?: number;
|
|
37
|
+
good?: boolean;
|
|
38
|
+
}): Outcome[];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DEFAULT_GRADUATION_CONFIG, } from "./graduation.js";
|
|
2
|
+
import { priorFor } from "./worker.js";
|
|
3
|
+
import { WorkerLevelStore, } from "./workerLevelStore.js";
|
|
4
|
+
export function shadowRun(worker, outcomes, opts = {}) {
|
|
5
|
+
const store = opts.store ?? new WorkerLevelStore();
|
|
6
|
+
const cfg = opts.cfg ?? DEFAULT_GRADUATION_CONFIG;
|
|
7
|
+
const prior = priorFor(worker);
|
|
8
|
+
const trajectory = [];
|
|
9
|
+
outcomes.forEach((o, index) => {
|
|
10
|
+
const r = store.apply(worker.id, o, { prior, cfg });
|
|
11
|
+
trajectory.push({
|
|
12
|
+
index,
|
|
13
|
+
at: o.at,
|
|
14
|
+
toolName: o.toolName,
|
|
15
|
+
good: o.good,
|
|
16
|
+
classKey: r.classKey,
|
|
17
|
+
level: r.state.level,
|
|
18
|
+
changed: r.event?.type ?? null,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
workerId: worker.id,
|
|
23
|
+
trajectory,
|
|
24
|
+
board: store.board(worker.id),
|
|
25
|
+
events: store.events(worker.id),
|
|
26
|
+
store,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** First trajectory step where `classKey` reached at least `level`. */
|
|
30
|
+
export function firstReached(result, classKey, level) {
|
|
31
|
+
return result.trajectory.find((s) => s.classKey === classKey && s.level >= level);
|
|
32
|
+
}
|
|
33
|
+
/** Build a steady cadence of same-tool outcomes spaced `intervalMs` apart. */
|
|
34
|
+
export function cadence(toolName, count, opts = {}) {
|
|
35
|
+
const start = opts.startAt ?? 0;
|
|
36
|
+
const interval = opts.intervalMs ?? 6 * 60 * 60 * 1000; // 6h
|
|
37
|
+
const good = opts.good ?? true;
|
|
38
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
39
|
+
toolName,
|
|
40
|
+
good,
|
|
41
|
+
at: start + i * interval,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=shadowRun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadowRun.js","sourceRoot":"","sources":["../../src/workers/shadowRun.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,GAG1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAuB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAGL,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AA4B/B,MAAM,UAAU,SAAS,CACvB,MAAsB,EACtB,QAAmB,EACnB,OAA6D,EAAE;IAE/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,gBAAgB,EAAE,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,yBAAyB,CAAC;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,UAAU,CAAC,IAAI,CAAC;YACd,KAAK;YACL,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK;YACpB,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI;SAC/B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,UAAU;QACV,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,KAAK;KACN,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAC1B,MAAuB,EACvB,QAAgB,EAChB,KAAa;IAEb,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CACnD,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,OAAO,CACrB,QAAgB,EAChB,KAAa,EACb,OAAkE,EAAE;IAEpE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;IAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,QAAQ;QACR,IAAI;QACJ,EAAE,EAAE,KAAK,GAAG,CAAC,GAAG,QAAQ;KACzB,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bayesian trust model for a single (worker × action-class) pair.
|
|
3
|
+
*
|
|
4
|
+
* Reliability `p` (the probability that an action of this class is "good") is a
|
|
5
|
+
* Beta(α, β) posterior. The discrete autonomy rung L0–L4 is a threshold
|
|
6
|
+
* crossing of the posterior's LOWER confidence bound, not its mean. Using the
|
|
7
|
+
* lower bound is what makes the ramp behave correctly:
|
|
8
|
+
* - cold-start floors automatically: a fresh/wide posterior has a low bound
|
|
9
|
+
* even if its mean is optimistic, so a worker (or a marketplace prior) can't
|
|
10
|
+
* start trusted — uncertainty must collapse on local evidence first;
|
|
11
|
+
* - climbing is slow: the bound only rises as the mean rises AND variance
|
|
12
|
+
* shrinks, i.e. with sustained evidence;
|
|
13
|
+
* - demotion is instant: one high-weight failure spikes β, the mean drops and
|
|
14
|
+
* the bound craters in a single step.
|
|
15
|
+
*
|
|
16
|
+
* Asymmetry ("slow up, instant down") is therefore information, not a tuned
|
|
17
|
+
* rule — it falls out of weighting failures by blast radius (see actionClass).
|
|
18
|
+
*/
|
|
19
|
+
export interface Posterior {
|
|
20
|
+
readonly alpha: number;
|
|
21
|
+
readonly beta: number;
|
|
22
|
+
}
|
|
23
|
+
/** Uniform prior — maximally uncertain, no shipped competence. */
|
|
24
|
+
export declare const DEFAULT_PRIOR: Posterior;
|
|
25
|
+
/**
|
|
26
|
+
* Build a prior from a competence claim: a mean reliability + a strength
|
|
27
|
+
* (pseudo-count). Low strength = wide uncertainty = the bound stays low until
|
|
28
|
+
* local evidence accumulates. This is how a marketplace worker ships
|
|
29
|
+
* competence (a mean) without shipping trust (the bound only tightens on the
|
|
30
|
+
* operator's own data). Strength is capped low on purpose.
|
|
31
|
+
*/
|
|
32
|
+
export declare function priorFromCompetence(mean: number, strength: number): Posterior;
|
|
33
|
+
export declare function posteriorMean(p: Posterior): number;
|
|
34
|
+
export declare function posteriorStddev(p: Posterior): number;
|
|
35
|
+
/** Lower confidence bound: mean − k·σ, clamped to [0, 1]. The level reads off
|
|
36
|
+
* THIS, not the mean. */
|
|
37
|
+
export declare function lowerConfidenceBound(p: Posterior, k?: number): number;
|
|
38
|
+
/** Apply one outcome. A good outcome adds to α, a bad one to β, scaled by the
|
|
39
|
+
* blast-weighted evidence weight from actionClass.outcomeWeight. */
|
|
40
|
+
export declare function applyOutcome(p: Posterior, good: boolean, weight: number): Posterior;
|
|
41
|
+
/** Total evidence accumulated relative to the prior (pseudo-observations). */
|
|
42
|
+
export declare function evidenceCount(p: Posterior, prior: Posterior): number;
|
|
43
|
+
export type TrustLevel = 0 | 1 | 2 | 3 | 4;
|
|
44
|
+
/** LCB → rung. Tunable; conservative by default. */
|
|
45
|
+
export declare const DEFAULT_THRESHOLDS: ReadonlyArray<{
|
|
46
|
+
min: number;
|
|
47
|
+
level: TrustLevel;
|
|
48
|
+
}>;
|
|
49
|
+
export interface LevelOpts {
|
|
50
|
+
k?: number;
|
|
51
|
+
/** Min evidence before a class may exceed L1 (novel-class floor). */
|
|
52
|
+
minEvidenceForGraduation?: number;
|
|
53
|
+
/** Rungs reachable for this class (irreversible classes omit L2/L3). */
|
|
54
|
+
reachable?: number[];
|
|
55
|
+
thresholds?: ReadonlyArray<{
|
|
56
|
+
min: number;
|
|
57
|
+
level: TrustLevel;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export interface LevelResult {
|
|
61
|
+
level: TrustLevel;
|
|
62
|
+
/** Level before the novel-floor + reachability clamps (for diagnostics). */
|
|
63
|
+
rawLevel: TrustLevel;
|
|
64
|
+
lcb: number;
|
|
65
|
+
mean: number;
|
|
66
|
+
evidence: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Map a posterior to a discrete rung, applying:
|
|
70
|
+
* 1. LCB → raw level via thresholds.
|
|
71
|
+
* 2. Novel-class floor: below the evidence minimum, cap at L1 regardless of how
|
|
72
|
+
* good the (necessarily wide) posterior looks — no class graduates on faith.
|
|
73
|
+
* 3. Reachability clamp: drop to the highest reachable rung ≤ the computed one,
|
|
74
|
+
* so an irreversible class climbing through "would-be L2/L3" stays at L1
|
|
75
|
+
* until it actually clears the L4 bar.
|
|
76
|
+
*/
|
|
77
|
+
export declare function levelFromPosterior(p: Posterior, prior: Posterior, opts?: LevelOpts): LevelResult;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bayesian trust model for a single (worker × action-class) pair.
|
|
3
|
+
*
|
|
4
|
+
* Reliability `p` (the probability that an action of this class is "good") is a
|
|
5
|
+
* Beta(α, β) posterior. The discrete autonomy rung L0–L4 is a threshold
|
|
6
|
+
* crossing of the posterior's LOWER confidence bound, not its mean. Using the
|
|
7
|
+
* lower bound is what makes the ramp behave correctly:
|
|
8
|
+
* - cold-start floors automatically: a fresh/wide posterior has a low bound
|
|
9
|
+
* even if its mean is optimistic, so a worker (or a marketplace prior) can't
|
|
10
|
+
* start trusted — uncertainty must collapse on local evidence first;
|
|
11
|
+
* - climbing is slow: the bound only rises as the mean rises AND variance
|
|
12
|
+
* shrinks, i.e. with sustained evidence;
|
|
13
|
+
* - demotion is instant: one high-weight failure spikes β, the mean drops and
|
|
14
|
+
* the bound craters in a single step.
|
|
15
|
+
*
|
|
16
|
+
* Asymmetry ("slow up, instant down") is therefore information, not a tuned
|
|
17
|
+
* rule — it falls out of weighting failures by blast radius (see actionClass).
|
|
18
|
+
*/
|
|
19
|
+
/** Uniform prior — maximally uncertain, no shipped competence. */
|
|
20
|
+
export const DEFAULT_PRIOR = { alpha: 1, beta: 1 };
|
|
21
|
+
/**
|
|
22
|
+
* Build a prior from a competence claim: a mean reliability + a strength
|
|
23
|
+
* (pseudo-count). Low strength = wide uncertainty = the bound stays low until
|
|
24
|
+
* local evidence accumulates. This is how a marketplace worker ships
|
|
25
|
+
* competence (a mean) without shipping trust (the bound only tightens on the
|
|
26
|
+
* operator's own data). Strength is capped low on purpose.
|
|
27
|
+
*/
|
|
28
|
+
export function priorFromCompetence(mean, strength) {
|
|
29
|
+
const m = Math.min(0.99, Math.max(0.01, mean));
|
|
30
|
+
const s = Math.min(8, Math.max(0.5, strength));
|
|
31
|
+
return { alpha: m * s, beta: (1 - m) * s };
|
|
32
|
+
}
|
|
33
|
+
export function posteriorMean(p) {
|
|
34
|
+
return p.alpha / (p.alpha + p.beta);
|
|
35
|
+
}
|
|
36
|
+
export function posteriorStddev(p) {
|
|
37
|
+
const n = p.alpha + p.beta;
|
|
38
|
+
return Math.sqrt((p.alpha * p.beta) / (n * n * (n + 1)));
|
|
39
|
+
}
|
|
40
|
+
/** Lower confidence bound: mean − k·σ, clamped to [0, 1]. The level reads off
|
|
41
|
+
* THIS, not the mean. */
|
|
42
|
+
export function lowerConfidenceBound(p, k = 1.5) {
|
|
43
|
+
return Math.max(0, Math.min(1, posteriorMean(p) - k * posteriorStddev(p)));
|
|
44
|
+
}
|
|
45
|
+
/** Apply one outcome. A good outcome adds to α, a bad one to β, scaled by the
|
|
46
|
+
* blast-weighted evidence weight from actionClass.outcomeWeight. */
|
|
47
|
+
export function applyOutcome(p, good, weight) {
|
|
48
|
+
return good
|
|
49
|
+
? { alpha: p.alpha + weight, beta: p.beta }
|
|
50
|
+
: { alpha: p.alpha, beta: p.beta + weight };
|
|
51
|
+
}
|
|
52
|
+
/** Total evidence accumulated relative to the prior (pseudo-observations). */
|
|
53
|
+
export function evidenceCount(p, prior) {
|
|
54
|
+
return p.alpha + p.beta - (prior.alpha + prior.beta);
|
|
55
|
+
}
|
|
56
|
+
/** LCB → rung. Tunable; conservative by default. */
|
|
57
|
+
export const DEFAULT_THRESHOLDS = [
|
|
58
|
+
{ min: 0.95, level: 4 },
|
|
59
|
+
{ min: 0.85, level: 3 },
|
|
60
|
+
{ min: 0.7, level: 2 },
|
|
61
|
+
{ min: 0.5, level: 1 },
|
|
62
|
+
{ min: 0, level: 0 },
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* Map a posterior to a discrete rung, applying:
|
|
66
|
+
* 1. LCB → raw level via thresholds.
|
|
67
|
+
* 2. Novel-class floor: below the evidence minimum, cap at L1 regardless of how
|
|
68
|
+
* good the (necessarily wide) posterior looks — no class graduates on faith.
|
|
69
|
+
* 3. Reachability clamp: drop to the highest reachable rung ≤ the computed one,
|
|
70
|
+
* so an irreversible class climbing through "would-be L2/L3" stays at L1
|
|
71
|
+
* until it actually clears the L4 bar.
|
|
72
|
+
*/
|
|
73
|
+
export function levelFromPosterior(p, prior, opts = {}) {
|
|
74
|
+
const k = opts.k ?? 1.5;
|
|
75
|
+
const minEvidence = opts.minEvidenceForGraduation ?? 10;
|
|
76
|
+
const reachable = opts.reachable ?? [0, 1, 2, 3, 4];
|
|
77
|
+
const thresholds = opts.thresholds ?? DEFAULT_THRESHOLDS;
|
|
78
|
+
const lcb = lowerConfidenceBound(p, k);
|
|
79
|
+
const mean = posteriorMean(p);
|
|
80
|
+
const evidence = evidenceCount(p, prior);
|
|
81
|
+
const rawLevel = thresholds.find((t) => lcb >= t.min)?.level ?? 0;
|
|
82
|
+
let level = rawLevel;
|
|
83
|
+
// Novel-class floor.
|
|
84
|
+
if (evidence < minEvidence && level > 1)
|
|
85
|
+
level = 1;
|
|
86
|
+
// Reachability clamp (highest reachable rung ≤ level).
|
|
87
|
+
const allowed = reachable.filter((r) => r <= level);
|
|
88
|
+
level = (allowed.length ? Math.max(...allowed) : 0);
|
|
89
|
+
return { level, rawLevel, lcb, mean, evidence };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=trustLevel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trustLevel.js","sourceRoot":"","sources":["../../src/workers/trustLevel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ActionClass } from "./actionClass.js";
|
|
2
|
+
import { type Posterior, type TrustLevel } from "./trustLevel.js";
|
|
3
|
+
export interface WorkerCompetence {
|
|
4
|
+
/** Claimed reliability mean (0–1) — a competence claim, not trust. */
|
|
5
|
+
mean: number;
|
|
6
|
+
/** Prior strength (pseudo-count); capped low so local evidence dominates. */
|
|
7
|
+
strength: number;
|
|
8
|
+
}
|
|
9
|
+
export interface WorkerManifest {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
responsibilities: string[];
|
|
13
|
+
/** Recipe name that forms this worker's body (its triggers + steps). */
|
|
14
|
+
recipe?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Action-classes this worker is responsible for. Each pattern matches a
|
|
17
|
+
* class by its domain, or by an exact/prefix class-key match
|
|
18
|
+
* (`vcs-local` matches `vcs-local:*`; `fs-write:reversible:medium` is exact).
|
|
19
|
+
*/
|
|
20
|
+
owns: string[];
|
|
21
|
+
/**
|
|
22
|
+
* Policy/regulatory cap on the max ramp level this worker may EVER reach,
|
|
23
|
+
* independent of earned track record — the schema encoding of the
|
|
24
|
+
* autonomy-tolerance axis (e.g. a Legal-sector worker is pinned at L2). The
|
|
25
|
+
* dial still shows *earned* level; the gate operates at min(earned, ceiling).
|
|
26
|
+
*/
|
|
27
|
+
autonomyCeiling: TrustLevel;
|
|
28
|
+
/** Optional shipped competence → the per-class prior. */
|
|
29
|
+
competence?: WorkerCompetence;
|
|
30
|
+
/** Free-form sector tag (drives default ceilings / reporting). */
|
|
31
|
+
sector?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class WorkerParseError extends Error {
|
|
34
|
+
constructor(message: string);
|
|
35
|
+
}
|
|
36
|
+
export declare function parseWorker(raw: unknown): WorkerManifest;
|
|
37
|
+
/** The per-class trust prior for a worker (its shipped competence, or uniform). */
|
|
38
|
+
export declare function priorFor(worker: WorkerManifest): Posterior;
|
|
39
|
+
/** Whether a worker is responsible for a given action-class. A pattern matches
|
|
40
|
+
* the class domain, an exact key, or a key prefix. Empty `owns` ⇒ owns nothing. */
|
|
41
|
+
export declare function ownsAction(worker: WorkerManifest, ac: ActionClass): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { DEFAULT_PRIOR, priorFromCompetence, } from "./trustLevel.js";
|
|
2
|
+
/**
|
|
3
|
+
* A worker manifest. Deliberately NOT a fork of the recipe schema — the recipe
|
|
4
|
+
* is the worker's *body* (triggers + steps); this manifest adds identity, the
|
|
5
|
+
* action-classes it owns, a trust prior, and the policy autonomy ceiling. It
|
|
6
|
+
* references a recipe by name rather than redefining execution. (worker-ramp-v0)
|
|
7
|
+
*/
|
|
8
|
+
const WORKER_ID_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
9
|
+
export class WorkerParseError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "WorkerParseError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function reqString(o, key) {
|
|
16
|
+
const v = o[key];
|
|
17
|
+
if (typeof v !== "string" || !v)
|
|
18
|
+
throw new WorkerParseError(`worker.${key} must be a non-empty string`);
|
|
19
|
+
return v;
|
|
20
|
+
}
|
|
21
|
+
export function parseWorker(raw) {
|
|
22
|
+
if (typeof raw !== "object" || raw === null)
|
|
23
|
+
throw new WorkerParseError("worker must be an object");
|
|
24
|
+
const r = raw;
|
|
25
|
+
const id = reqString(r, "id");
|
|
26
|
+
if (!WORKER_ID_RE.test(id))
|
|
27
|
+
throw new WorkerParseError(`worker.id must be kebab-case (got ${JSON.stringify(id)})`);
|
|
28
|
+
const name = reqString(r, "name");
|
|
29
|
+
const owns = Array.isArray(r.owns)
|
|
30
|
+
? r.owns.filter((x) => typeof x === "string")
|
|
31
|
+
: [];
|
|
32
|
+
const responsibilities = Array.isArray(r.responsibilities)
|
|
33
|
+
? r.responsibilities.filter((x) => typeof x === "string")
|
|
34
|
+
: [];
|
|
35
|
+
// autonomyCeiling: 0–4, default 4 (uncapped).
|
|
36
|
+
let autonomyCeiling = 4;
|
|
37
|
+
if (r.autonomyCeiling !== undefined) {
|
|
38
|
+
const c = r.autonomyCeiling;
|
|
39
|
+
if (typeof c !== "number" || !Number.isInteger(c) || c < 0 || c > 4)
|
|
40
|
+
throw new WorkerParseError("worker.autonomyCeiling must be an integer 0–4");
|
|
41
|
+
autonomyCeiling = c;
|
|
42
|
+
}
|
|
43
|
+
let competence;
|
|
44
|
+
if (r.competence !== undefined) {
|
|
45
|
+
const c = r.competence;
|
|
46
|
+
if (typeof c !== "object" ||
|
|
47
|
+
c === null ||
|
|
48
|
+
typeof c.mean !== "number" ||
|
|
49
|
+
typeof c.strength !== "number")
|
|
50
|
+
throw new WorkerParseError("worker.competence must be { mean: number, strength: number }");
|
|
51
|
+
if (c.mean < 0 || c.mean > 1)
|
|
52
|
+
throw new WorkerParseError("worker.competence.mean must be in [0,1]");
|
|
53
|
+
competence = { mean: c.mean, strength: c.strength };
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
id,
|
|
57
|
+
name,
|
|
58
|
+
responsibilities,
|
|
59
|
+
recipe: typeof r.recipe === "string" ? r.recipe : undefined,
|
|
60
|
+
owns,
|
|
61
|
+
autonomyCeiling,
|
|
62
|
+
competence,
|
|
63
|
+
sector: typeof r.sector === "string" ? r.sector : undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** The per-class trust prior for a worker (its shipped competence, or uniform). */
|
|
67
|
+
export function priorFor(worker) {
|
|
68
|
+
return worker.competence
|
|
69
|
+
? priorFromCompetence(worker.competence.mean, worker.competence.strength)
|
|
70
|
+
: DEFAULT_PRIOR;
|
|
71
|
+
}
|
|
72
|
+
/** Whether a worker is responsible for a given action-class. A pattern matches
|
|
73
|
+
* the class domain, an exact key, or a key prefix. Empty `owns` ⇒ owns nothing. */
|
|
74
|
+
export function ownsAction(worker, ac) {
|
|
75
|
+
return worker.owns.some((p) => p === ac.domain || p === ac.key || ac.key.startsWith(`${p}:`));
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/workers/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ClassTrustState, type GraduationConfig, type GraduationEvent, type Outcome } from "./graduation.js";
|
|
2
|
+
import { type Posterior } from "./trustLevel.js";
|
|
3
|
+
export type AuditEvent = GraduationEvent & {
|
|
4
|
+
workerId: string;
|
|
5
|
+
};
|
|
6
|
+
export interface AppliedOutcome {
|
|
7
|
+
classKey: string;
|
|
8
|
+
state: ClassTrustState;
|
|
9
|
+
event?: AuditEvent;
|
|
10
|
+
}
|
|
11
|
+
export interface BoardRow {
|
|
12
|
+
classKey: string;
|
|
13
|
+
level: number;
|
|
14
|
+
observations: number;
|
|
15
|
+
mean: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class WorkerLevelStore {
|
|
18
|
+
private states;
|
|
19
|
+
private log;
|
|
20
|
+
/** Fold one outcome for a worker; derives the action-class from the tool. */
|
|
21
|
+
apply(workerId: string, outcome: Outcome, opts?: {
|
|
22
|
+
prior?: Posterior;
|
|
23
|
+
cfg?: GraduationConfig;
|
|
24
|
+
}): AppliedOutcome;
|
|
25
|
+
getState(workerId: string, classKey: string): ClassTrustState | undefined;
|
|
26
|
+
/** Dial snapshot for one worker: every action-class it has touched, sorted. */
|
|
27
|
+
board(workerId: string): BoardRow[];
|
|
28
|
+
/** The audit log (optionally filtered to one worker). */
|
|
29
|
+
events(workerId?: string): AuditEvent[];
|
|
30
|
+
/** Serialize states + events to JSONL (one record per line). */
|
|
31
|
+
toJSONL(): string;
|
|
32
|
+
static fromJSONL(text: string): WorkerLevelStore;
|
|
33
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { classifyActionClass } from "./actionClass.js";
|
|
2
|
+
import { DEFAULT_GRADUATION_CONFIG, graduate, initialState, } from "./graduation.js";
|
|
3
|
+
import { DEFAULT_PRIOR, posteriorMean } from "./trustLevel.js";
|
|
4
|
+
/**
|
|
5
|
+
* Holds the per-(worker × action-class) trust state and the promotion/demotion
|
|
6
|
+
* event log. The state map is the dial; the event log is the compliance/audit
|
|
7
|
+
* artifact ("prove this worker never acted beyond its authority"). In-memory
|
|
8
|
+
* with a JSONL round-trip; wiring it to a live append-only JSONL file with the
|
|
9
|
+
* tail-on-read concurrency pattern (ADR-0007, as the existing trace stores do)
|
|
10
|
+
* is the productionization step — kept out of v0 to stay pure + testable.
|
|
11
|
+
*/
|
|
12
|
+
function compositeKey(workerId, classKey) {
|
|
13
|
+
return `${workerId}::${classKey}`;
|
|
14
|
+
}
|
|
15
|
+
export class WorkerLevelStore {
|
|
16
|
+
states = new Map();
|
|
17
|
+
log = [];
|
|
18
|
+
/** Fold one outcome for a worker; derives the action-class from the tool. */
|
|
19
|
+
apply(workerId, outcome, opts = {}) {
|
|
20
|
+
const ac = classifyActionClass(outcome.toolName, outcome.params);
|
|
21
|
+
const k = compositeKey(workerId, ac.key);
|
|
22
|
+
const prior = opts.prior ?? DEFAULT_PRIOR;
|
|
23
|
+
const current = this.states.get(k) ?? initialState(ac.key, prior, outcome.at);
|
|
24
|
+
const { state, event } = graduate(current, outcome, opts.cfg ?? DEFAULT_GRADUATION_CONFIG);
|
|
25
|
+
this.states.set(k, state);
|
|
26
|
+
const audit = event ? { ...event, workerId } : undefined;
|
|
27
|
+
if (audit)
|
|
28
|
+
this.log.push(audit);
|
|
29
|
+
return { classKey: ac.key, state, event: audit };
|
|
30
|
+
}
|
|
31
|
+
getState(workerId, classKey) {
|
|
32
|
+
return this.states.get(compositeKey(workerId, classKey));
|
|
33
|
+
}
|
|
34
|
+
/** Dial snapshot for one worker: every action-class it has touched, sorted. */
|
|
35
|
+
board(workerId) {
|
|
36
|
+
const prefix = `${workerId}::`;
|
|
37
|
+
const rows = [];
|
|
38
|
+
for (const [k, s] of this.states) {
|
|
39
|
+
if (!k.startsWith(prefix))
|
|
40
|
+
continue;
|
|
41
|
+
rows.push({
|
|
42
|
+
classKey: s.classKey,
|
|
43
|
+
level: s.level,
|
|
44
|
+
observations: s.observations,
|
|
45
|
+
mean: posteriorMean(s.posterior),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return rows.sort((a, b) => a.classKey.localeCompare(b.classKey));
|
|
49
|
+
}
|
|
50
|
+
/** The audit log (optionally filtered to one worker). */
|
|
51
|
+
events(workerId) {
|
|
52
|
+
return workerId
|
|
53
|
+
? this.log.filter((e) => e.workerId === workerId)
|
|
54
|
+
: this.log;
|
|
55
|
+
}
|
|
56
|
+
/** Serialize states + events to JSONL (one record per line). */
|
|
57
|
+
toJSONL() {
|
|
58
|
+
const lines = [];
|
|
59
|
+
for (const [k, s] of this.states) {
|
|
60
|
+
const workerId = k.slice(0, k.indexOf("::"));
|
|
61
|
+
lines.push(JSON.stringify({ rec: "state", workerId, state: s }));
|
|
62
|
+
}
|
|
63
|
+
for (const e of this.log)
|
|
64
|
+
lines.push(JSON.stringify({ rec: "event", ...e }));
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
67
|
+
static fromJSONL(text) {
|
|
68
|
+
const store = new WorkerLevelStore();
|
|
69
|
+
for (const line of text.split("\n")) {
|
|
70
|
+
const t = line.trim();
|
|
71
|
+
if (!t)
|
|
72
|
+
continue;
|
|
73
|
+
const obj = JSON.parse(t);
|
|
74
|
+
if (obj.rec === "state") {
|
|
75
|
+
const workerId = obj.workerId;
|
|
76
|
+
const state = obj.state;
|
|
77
|
+
store.states.set(compositeKey(workerId, state.classKey), state);
|
|
78
|
+
}
|
|
79
|
+
else if (obj.rec === "event") {
|
|
80
|
+
const { rec: _rec, ...event } = obj;
|
|
81
|
+
store.log.push(event);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return store;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=workerLevelStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerLevelStore.js","sourceRoot":"","sources":["../../src/workers/workerLevelStore.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "0.2.0-beta.13.canary.
|
|
3
|
+
"version": "0.2.0-beta.13.canary.265",
|
|
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",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://patchwork.dev/schemas/recipe.v1.json
|
|
2
|
+
# Body for the Dependency Upkeep Worker
|
|
3
|
+
# (templates/workers/dependency-upkeep.worker.yaml). Weekly cron — reviews the
|
|
4
|
+
# open dependency-update PRs rather than opening them (autonomyCeiling L3: a
|
|
5
|
+
# human still merges).
|
|
6
|
+
apiVersion: patchwork.sh/v1
|
|
7
|
+
name: dependency-bump
|
|
8
|
+
description: Weekly — list open dependency-update PRs and summarize which look safe to merge.
|
|
9
|
+
trigger:
|
|
10
|
+
type: cron
|
|
11
|
+
at: "0 9 * * MON"
|
|
12
|
+
steps:
|
|
13
|
+
- tool: github.list_prs
|
|
14
|
+
max: 30
|
|
15
|
+
into: prs
|
|
16
|
+
- agent:
|
|
17
|
+
prompt: |
|
|
18
|
+
Open pull requests:
|
|
19
|
+
{{prs}}
|
|
20
|
+
|
|
21
|
+
Identify the dependency-update PRs (dependabot / renovate / "bump …"
|
|
22
|
+
titles). For each, note the package, the version jump (patch / minor /
|
|
23
|
+
major), and a recommendation: SAFE to merge (patch/minor with green CI)
|
|
24
|
+
or NEEDS REVIEW (major, or a security-sensitive dependency). Output a
|
|
25
|
+
short markdown table; if there are none, say "No dependency PRs open."
|
|
26
|
+
driver: claude-code
|
|
27
|
+
into: review
|
|
28
|
+
- tool: file.write
|
|
29
|
+
path: ~/.patchwork/inbox/dependency-review-{{date}}.md
|
|
30
|
+
content: |
|
|
31
|
+
# Dependency PR review — {{date}}
|
|
32
|
+
|
|
33
|
+
{{review}}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://patchwork.dev/schemas/recipe.v1.json
|
|
2
|
+
# Body for the Release Worker (templates/workers/release-notes.worker.yaml).
|
|
3
|
+
# Self-waking on every commit (git_hook → onGitCommit, wired in #1016/#1018).
|
|
4
|
+
apiVersion: patchwork.sh/v1
|
|
5
|
+
name: release-notes
|
|
6
|
+
description: After a commit lands, draft a changelog entry from the new commits into the inbox.
|
|
7
|
+
trigger:
|
|
8
|
+
type: git_hook
|
|
9
|
+
event: post-commit
|
|
10
|
+
steps:
|
|
11
|
+
- tool: git.log_since
|
|
12
|
+
since: 24h
|
|
13
|
+
into: commits
|
|
14
|
+
- agent:
|
|
15
|
+
prompt: |
|
|
16
|
+
New commits landed in the last 24h:
|
|
17
|
+
{{commits}}
|
|
18
|
+
|
|
19
|
+
Write a concise changelog entry as a markdown bullet list — one line per
|
|
20
|
+
user-facing change, grouped under feat / fix / chore. Omit pure noise
|
|
21
|
+
(merge commits, formatting-only). If nothing is user-facing, say so.
|
|
22
|
+
# subprocess `claude -p` under your existing subscription (no API key)
|
|
23
|
+
driver: claude-code
|
|
24
|
+
into: notes
|
|
25
|
+
- tool: file.write
|
|
26
|
+
path: ~/.patchwork/inbox/release-notes-{{date}}.md
|
|
27
|
+
content: |
|
|
28
|
+
# Release notes draft — {{date}}
|
|
29
|
+
|
|
30
|
+
{{notes}}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://patchwork.dev/schemas/recipe.v1.json
|
|
2
|
+
# Body for the Test Guardian Worker
|
|
3
|
+
# (templates/workers/test-guardian.worker.yaml). Self-waking on a FAILING test
|
|
4
|
+
# run (on_test_run.filter: failure). Correlates the failure with recent commits
|
|
5
|
+
# and writes a triage note — richer than the plain watch-failing-tests recipe.
|
|
6
|
+
apiVersion: patchwork.sh/v1
|
|
7
|
+
name: triage-failing-tests
|
|
8
|
+
description: On a failing test run, correlate the failure with recent commits and write a triage note.
|
|
9
|
+
trigger:
|
|
10
|
+
type: on_test_run
|
|
11
|
+
filter: failure
|
|
12
|
+
steps:
|
|
13
|
+
- tool: git.log_since
|
|
14
|
+
since: 12h
|
|
15
|
+
into: recent
|
|
16
|
+
- agent:
|
|
17
|
+
prompt: |
|
|
18
|
+
Tests just failed. Runner: {{runner}}. Failed {{failed}} / {{total}}.
|
|
19
|
+
|
|
20
|
+
Failures:
|
|
21
|
+
{{failures}}
|
|
22
|
+
|
|
23
|
+
Recent commits (last 12h) that may be responsible:
|
|
24
|
+
{{recent}}
|
|
25
|
+
|
|
26
|
+
Write a triage note (≤5 sentences): (1) which test(s) failed, (2) the
|
|
27
|
+
single most likely cause, (3) the suspect commit if any, (4) the first
|
|
28
|
+
command to run to confirm.
|
|
29
|
+
driver: claude-code
|
|
30
|
+
into: triage
|
|
31
|
+
- tool: file.write
|
|
32
|
+
path: ~/.patchwork/inbox/test-triage-{{date}}-{{time}}.md
|
|
33
|
+
content: |
|
|
34
|
+
# Test triage — {{date}} {{time}}
|
|
35
|
+
|
|
36
|
+
Runner {{runner}} · failed {{failed}}/{{total}}
|
|
37
|
+
|
|
38
|
+
{{triage}}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Dependency-upkeep worker — top-right beachhead. The classic low-blast,
|
|
2
|
+
# continuous, verifiable job to land first (the wedge): watch for outdated /
|
|
3
|
+
# vulnerable deps and open a bump PR. A human still merges → ceiling held at L3.
|
|
4
|
+
id: dependency-upkeep-worker
|
|
5
|
+
name: Dependency Upkeep Worker
|
|
6
|
+
sector: engineering
|
|
7
|
+
recipe: dependency-bump
|
|
8
|
+
responsibilities:
|
|
9
|
+
- Audit dependencies for outdated / vulnerable packages
|
|
10
|
+
- Open a bump PR with the changelog and advisory links
|
|
11
|
+
owns:
|
|
12
|
+
- deps-read # auditDependencies / getSecurityAdvisories — read-only
|
|
13
|
+
- vcs-local # gitCommit / gitCheckout on a branch — reversible
|
|
14
|
+
- vcs-remote # githubCreatePR — compensable + brand-exposed
|
|
15
|
+
autonomyCeiling: 3 # opening PRs autonomously is fine; merging stays human (policy)
|
|
16
|
+
competence:
|
|
17
|
+
mean: 0.8
|
|
18
|
+
strength: 4
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Release worker — top-right beachhead (high task-impact × high autonomy-tolerance).
|
|
2
|
+
# Body: a chained recipe triggered on merge-to-main that drafts release notes.
|
|
3
|
+
# Reversible, verifiable, internal → fast ramp evidence.
|
|
4
|
+
id: release-notes-worker
|
|
5
|
+
name: Release Worker
|
|
6
|
+
sector: engineering
|
|
7
|
+
recipe: release-notes # the recipe that forms this worker's body
|
|
8
|
+
responsibilities:
|
|
9
|
+
- Watch merges to main and draft release notes / changelog entries
|
|
10
|
+
- Summarize the diff and link the PRs in the range
|
|
11
|
+
owns:
|
|
12
|
+
- vcs-read # getGitStatus / getGitDiff / getGitLog — reversible, low blast
|
|
13
|
+
- fs-write # editText / createFile (the changelog) — reversible
|
|
14
|
+
autonomyCeiling: 4 # internal + reversible: may earn full autonomy
|
|
15
|
+
competence: # shipped competence (a prior), NOT trust — trust earns locally
|
|
16
|
+
mean: 0.85
|
|
17
|
+
strength: 4
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Test-guardian worker — top-right beachhead. Fires on a test-run failure
|
|
2
|
+
# (on_test_run trigger), investigates the failure, and files an issue. Reversible
|
|
3
|
+
# investigation + compensable issue creation → may earn full autonomy on triage.
|
|
4
|
+
id: test-guardian-worker
|
|
5
|
+
name: Test Guardian Worker
|
|
6
|
+
sector: engineering
|
|
7
|
+
recipe: triage-failing-tests
|
|
8
|
+
responsibilities:
|
|
9
|
+
- On a failing test run, investigate the stack trace and identify the cause
|
|
10
|
+
- File / update an issue with the failure summary and the suspect commit
|
|
11
|
+
owns:
|
|
12
|
+
- ci # runTests (re-runnable) — reversible
|
|
13
|
+
- vcs-read # getGitDiff / gitBlame to find the suspect commit
|
|
14
|
+
- issue # githubCreateIssue / addLinearComment — compensable + brand-exposed
|
|
15
|
+
autonomyCeiling: 4
|
|
16
|
+
competence:
|
|
17
|
+
mean: 0.8
|
|
18
|
+
strength: 4
|