patchwork-os 1.2.0-beta.2.canary.625 → 1.2.0-beta.2.canary.627

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.
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Information boundary — declared labels and the boundary decision (ADR-0021,
3
+ * Phases 1 and 2).
4
+ *
5
+ * The invariant this exists to hold:
6
+ *
7
+ * > No model-bound context leaves Patchwork without passing the
8
+ * > information-boundary decision point.
9
+ *
10
+ * Two properties are deliberate and load-bearing.
11
+ *
12
+ * **Declared, never detected.** A step says what it carries; a destination says
13
+ * what it may receive. Nothing is inferred. ADR-0021 rules detection out on the
14
+ * grounds that a detector which IS the boundary fails silently on everything it
15
+ * does not recognise, and its recall is unknowable. A detector may later suggest
16
+ * a classification; policy still decides.
17
+ *
18
+ * **Pure.** The decision is a function of (declared policy, destination policy)
19
+ * and nothing else — no clock, no filesystem, no model. That is what makes it
20
+ * testable without a model in the loop, and what stops the boundary being
21
+ * enforced by the thing it constrains.
22
+ */
23
+ /**
24
+ * Sensitivity ladder, ordered. The order is the whole comparison: a destination
25
+ * cleared for `internal` is cleared for `public`, never the reverse.
26
+ */
27
+ export declare const CLASSIFICATIONS: readonly ["public", "internal", "personal", "confidential", "restricted"];
28
+ export type Classification = (typeof CLASSIFICATIONS)[number];
29
+ /**
30
+ * Default for a step that declares nothing.
31
+ *
32
+ * `internal` rather than `restricted`, deliberately. Every existing recipe
33
+ * declares nothing, so a strict default would refuse the entire installed base
34
+ * on upgrade to solve a problem those installs do not have — and a boundary
35
+ * that breaks everything on day one gets switched off, which protects nobody.
36
+ * Same fail-soft reasoning as the identity roster's implicit owner.
37
+ */
38
+ export declare const DEFAULT_CLASSIFICATION: Classification;
39
+ export declare function classificationRank(c: Classification): number;
40
+ /** What a step declares it is carrying. */
41
+ export interface DataPolicy {
42
+ classification: Classification;
43
+ /** Free-form tags (e.g. "financial"). Used for redaction, not for ranking. */
44
+ categories?: string[];
45
+ }
46
+ /** What a destination declares it may receive. */
47
+ export interface Destination {
48
+ id: string;
49
+ /** `local` never leaves the machine; `remote` crosses a network boundary. */
50
+ type: "local" | "remote";
51
+ /** Classifications this destination is cleared for. */
52
+ classifications: Classification[];
53
+ /**
54
+ * Categories this destination must never receive even when it is cleared for
55
+ * the classification. Redaction removes them; if they cannot be removed the
56
+ * decision escalates rather than silently sending them.
57
+ */
58
+ forbiddenCategories?: string[];
59
+ /**
60
+ * Whether a human may authorise an otherwise-refused send. Absent means no:
61
+ * the refusal stands, which keeps DENY meaningful as "no approval unlocks
62
+ * this" exactly as the autonomy gate's `forbid` does.
63
+ */
64
+ approvable?: boolean;
65
+ }
66
+ /**
67
+ * The five outcomes.
68
+ *
69
+ * `LOCAL_ONLY` is distinct from `DENY` on purpose: it means the data may be
70
+ * processed, just not here. It is a routing instruction, and the caller is
71
+ * expected to retry against a local destination rather than fail the step.
72
+ */
73
+ export type BoundaryDecision = "ALLOW" | "ALLOW_REDACTED" | "LOCAL_ONLY" | "REQUIRE_APPROVAL" | "DENY";
74
+ export interface BoundaryOutcome {
75
+ decision: BoundaryDecision;
76
+ /** One sentence, safe to show a human. Never contains the payload. */
77
+ reason: string;
78
+ /** Categories that must be removed before dispatch (ALLOW_REDACTED only). */
79
+ redactCategories?: string[];
80
+ }
81
+ /**
82
+ * Decide whether `policy` may be sent to `destination`.
83
+ *
84
+ * The rule table, in evaluation order:
85
+ *
86
+ * 1. destination not cleared for the classification
87
+ * → LOCAL_ONLY if a local destination could take it, else
88
+ * REQUIRE_APPROVAL if the destination is approvable, else DENY
89
+ * 2. cleared, but carries a forbidden category
90
+ * → ALLOW_REDACTED (the category is removable)
91
+ * 3. otherwise → ALLOW
92
+ *
93
+ * Rule 1 runs FIRST and is not reachable past. A destination cannot become
94
+ * cleared by redacting a category, because the classification is a property of
95
+ * the step as a whole — dropping a tag does not declassify what remains.
96
+ */
97
+ export declare function decideBoundary(policy: DataPolicy, destination: Destination, opts?: {
98
+ localDestinationAccepts?: boolean;
99
+ }): BoundaryOutcome;
100
+ /**
101
+ * Parse a step's declared `data_policy`, falling back to the default.
102
+ *
103
+ * An UNRECOGNISED classification is not silently defaulted — it returns null so
104
+ * the caller can fail closed. Defaulting a typo to `internal` would let
105
+ * `classification: confidentail` sail through as ordinary internal data, which
106
+ * is precisely the failure a declared-labels scheme cannot afford: the operator
107
+ * believes they labelled it and the system believes they did not.
108
+ */
109
+ export declare function parseDataPolicy(raw: unknown): DataPolicy | null;
110
+ export declare function narrowest(a: BoundaryOutcome, b: BoundaryOutcome): BoundaryOutcome;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Information boundary — declared labels and the boundary decision (ADR-0021,
3
+ * Phases 1 and 2).
4
+ *
5
+ * The invariant this exists to hold:
6
+ *
7
+ * > No model-bound context leaves Patchwork without passing the
8
+ * > information-boundary decision point.
9
+ *
10
+ * Two properties are deliberate and load-bearing.
11
+ *
12
+ * **Declared, never detected.** A step says what it carries; a destination says
13
+ * what it may receive. Nothing is inferred. ADR-0021 rules detection out on the
14
+ * grounds that a detector which IS the boundary fails silently on everything it
15
+ * does not recognise, and its recall is unknowable. A detector may later suggest
16
+ * a classification; policy still decides.
17
+ *
18
+ * **Pure.** The decision is a function of (declared policy, destination policy)
19
+ * and nothing else — no clock, no filesystem, no model. That is what makes it
20
+ * testable without a model in the loop, and what stops the boundary being
21
+ * enforced by the thing it constrains.
22
+ */
23
+ /**
24
+ * Sensitivity ladder, ordered. The order is the whole comparison: a destination
25
+ * cleared for `internal` is cleared for `public`, never the reverse.
26
+ */
27
+ export const CLASSIFICATIONS = [
28
+ "public",
29
+ "internal",
30
+ "personal",
31
+ "confidential",
32
+ "restricted",
33
+ ];
34
+ /**
35
+ * Default for a step that declares nothing.
36
+ *
37
+ * `internal` rather than `restricted`, deliberately. Every existing recipe
38
+ * declares nothing, so a strict default would refuse the entire installed base
39
+ * on upgrade to solve a problem those installs do not have — and a boundary
40
+ * that breaks everything on day one gets switched off, which protects nobody.
41
+ * Same fail-soft reasoning as the identity roster's implicit owner.
42
+ */
43
+ export const DEFAULT_CLASSIFICATION = "internal";
44
+ export function classificationRank(c) {
45
+ return CLASSIFICATIONS.indexOf(c);
46
+ }
47
+ /**
48
+ * Decide whether `policy` may be sent to `destination`.
49
+ *
50
+ * The rule table, in evaluation order:
51
+ *
52
+ * 1. destination not cleared for the classification
53
+ * → LOCAL_ONLY if a local destination could take it, else
54
+ * REQUIRE_APPROVAL if the destination is approvable, else DENY
55
+ * 2. cleared, but carries a forbidden category
56
+ * → ALLOW_REDACTED (the category is removable)
57
+ * 3. otherwise → ALLOW
58
+ *
59
+ * Rule 1 runs FIRST and is not reachable past. A destination cannot become
60
+ * cleared by redacting a category, because the classification is a property of
61
+ * the step as a whole — dropping a tag does not declassify what remains.
62
+ */
63
+ export function decideBoundary(policy, destination, opts = {}) {
64
+ const cleared = destination.classifications.includes(policy.classification);
65
+ if (!cleared) {
66
+ if (destination.type === "remote" && opts.localDestinationAccepts) {
67
+ return {
68
+ decision: "LOCAL_ONLY",
69
+ reason: `"${policy.classification}" may not leave the machine; a local destination accepts it`,
70
+ };
71
+ }
72
+ if (destination.approvable) {
73
+ return {
74
+ decision: "REQUIRE_APPROVAL",
75
+ reason: `"${destination.id}" is not cleared for "${policy.classification}"; a human may authorise this send`,
76
+ };
77
+ }
78
+ return {
79
+ decision: "DENY",
80
+ reason: `"${destination.id}" is not cleared for "${policy.classification}" and no approval can unlock it`,
81
+ };
82
+ }
83
+ const forbidden = destination.forbiddenCategories ?? [];
84
+ const carried = policy.categories ?? [];
85
+ const hits = carried.filter((c) => forbidden.includes(c));
86
+ if (hits.length > 0) {
87
+ return {
88
+ decision: "ALLOW_REDACTED",
89
+ reason: `"${destination.id}" is cleared for "${policy.classification}" but must not receive: ${hits.join(", ")}`,
90
+ redactCategories: hits,
91
+ };
92
+ }
93
+ return {
94
+ decision: "ALLOW",
95
+ reason: `"${destination.id}" is cleared for "${policy.classification}"`,
96
+ };
97
+ }
98
+ /**
99
+ * Parse a step's declared `data_policy`, falling back to the default.
100
+ *
101
+ * An UNRECOGNISED classification is not silently defaulted — it returns null so
102
+ * the caller can fail closed. Defaulting a typo to `internal` would let
103
+ * `classification: confidentail` sail through as ordinary internal data, which
104
+ * is precisely the failure a declared-labels scheme cannot afford: the operator
105
+ * believes they labelled it and the system believes they did not.
106
+ */
107
+ export function parseDataPolicy(raw) {
108
+ if (raw === undefined || raw === null) {
109
+ return { classification: DEFAULT_CLASSIFICATION };
110
+ }
111
+ if (typeof raw !== "object")
112
+ return null;
113
+ const obj = raw;
114
+ const c = obj.classification;
115
+ let classification;
116
+ if (c === undefined) {
117
+ classification = DEFAULT_CLASSIFICATION;
118
+ }
119
+ else if (typeof c === "string" &&
120
+ CLASSIFICATIONS.includes(c)) {
121
+ classification = c;
122
+ }
123
+ else {
124
+ return null;
125
+ }
126
+ const categories = Array.isArray(obj.categories)
127
+ ? obj.categories.filter((x) => typeof x === "string")
128
+ : undefined;
129
+ return categories ? { classification, categories } : { classification };
130
+ }
131
+ /**
132
+ * NEVER-WIDEN composition, mirroring the autonomy gate's rule.
133
+ *
134
+ * A later stage may restrict further; it may never restore what an earlier one
135
+ * removed. Applied by taking the MORE restrictive of two decisions, so ordering
136
+ * the stages wrongly cannot loosen the result.
137
+ */
138
+ const RESTRICTIVENESS = {
139
+ ALLOW: 0,
140
+ ALLOW_REDACTED: 1,
141
+ LOCAL_ONLY: 2,
142
+ REQUIRE_APPROVAL: 3,
143
+ DENY: 4,
144
+ };
145
+ export function narrowest(a, b) {
146
+ return RESTRICTIVENESS[b.decision] > RESTRICTIVENESS[a.decision] ? b : a;
147
+ }
148
+ //# sourceMappingURL=dataPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataPolicy.js","sourceRoot":"","sources":["../../src/privacy/dataPolicy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Destination registry (ADR-0021).
3
+ *
4
+ * The decision in `dataPolicy.ts` is pure and complete, and until this module
5
+ * existed it was also unreachable: `executeAgent` only evaluates the boundary
6
+ * when a destination is supplied, and nothing supplied one. The engine was
7
+ * built and inert.
8
+ *
9
+ * A destination is *where a prompt is about to go*. Patchwork resolves that
10
+ * from the driver, because that is what actually determines whether bytes
11
+ * cross a network boundary:
12
+ *
13
+ * local — a model on this machine (`local`, `ollama`, an OpenAI-compatible
14
+ * endpoint pointed at localhost)
15
+ * remote — anything that sends the prompt to a third party
16
+ *
17
+ * ## Configuration is opt-in, and absence means inert
18
+ *
19
+ * With no `privacy.destinations` block, `resolveDestination` returns null and
20
+ * `executeAgent` skips the boundary entirely — byte-identical to before. That
21
+ * is the same fail-soft posture as the default classification, and for the same
22
+ * reason: a boundary that refuses work on every install that has not configured
23
+ * it would be switched off before it ever protected anyone.
24
+ *
25
+ * The asymmetry is deliberate and worth stating. Configuring a destination is
26
+ * how an operator OPTS IN to enforcement. Once opted in, the decision is
27
+ * fail-CLOSED — an unknown driver resolves to the strictest registered remote
28
+ * profile rather than to "no destination", because "we do not recognise where
29
+ * this is going" must never read as "it is fine to send".
30
+ */
31
+ import { type Classification, type Destination } from "./dataPolicy.js";
32
+ export interface DestinationConfig {
33
+ type?: string;
34
+ classifications?: unknown;
35
+ forbiddenCategories?: unknown;
36
+ approvable?: unknown;
37
+ /** Driver names this destination covers. */
38
+ drivers?: unknown;
39
+ }
40
+ export interface PrivacyConfig {
41
+ destinations?: Record<string, DestinationConfig>;
42
+ }
43
+ export interface ParsedRegistry {
44
+ destinations: Destination[];
45
+ /** Destination id → driver names it covers. */
46
+ driversFor: Map<string, string[]>;
47
+ /**
48
+ * Entries that could not be parsed, with a reason. REPORTED rather than
49
+ * dropped: a destination that silently vanishes from the registry downgrades
50
+ * enforcement to "no destination", which is exactly the direction this must
51
+ * never fail in.
52
+ */
53
+ invalid: Array<{
54
+ id: string;
55
+ reason: string;
56
+ }>;
57
+ }
58
+ export declare function parseRegistry(cfg: PrivacyConfig | undefined): ParsedRegistry;
59
+ export interface ResolvedDestination {
60
+ destination: Destination;
61
+ /** True when some registered LOCAL destination is cleared for `forClass`. */
62
+ localDestinationAccepts: boolean;
63
+ }
64
+ /**
65
+ * Resolve the destination for a dispatch.
66
+ *
67
+ * Returns null ONLY when nothing is registered — the inert case. Once anything
68
+ * is registered, this always yields a destination, because falling back to null
69
+ * on an unrecognised driver would silently disable the boundary for exactly the
70
+ * dispatches nobody anticipated.
71
+ */
72
+ export declare function resolveDestination(registry: ParsedRegistry, driver: string | undefined, forClass: Classification): ResolvedDestination | null;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Destination registry (ADR-0021).
3
+ *
4
+ * The decision in `dataPolicy.ts` is pure and complete, and until this module
5
+ * existed it was also unreachable: `executeAgent` only evaluates the boundary
6
+ * when a destination is supplied, and nothing supplied one. The engine was
7
+ * built and inert.
8
+ *
9
+ * A destination is *where a prompt is about to go*. Patchwork resolves that
10
+ * from the driver, because that is what actually determines whether bytes
11
+ * cross a network boundary:
12
+ *
13
+ * local — a model on this machine (`local`, `ollama`, an OpenAI-compatible
14
+ * endpoint pointed at localhost)
15
+ * remote — anything that sends the prompt to a third party
16
+ *
17
+ * ## Configuration is opt-in, and absence means inert
18
+ *
19
+ * With no `privacy.destinations` block, `resolveDestination` returns null and
20
+ * `executeAgent` skips the boundary entirely — byte-identical to before. That
21
+ * is the same fail-soft posture as the default classification, and for the same
22
+ * reason: a boundary that refuses work on every install that has not configured
23
+ * it would be switched off before it ever protected anyone.
24
+ *
25
+ * The asymmetry is deliberate and worth stating. Configuring a destination is
26
+ * how an operator OPTS IN to enforcement. Once opted in, the decision is
27
+ * fail-CLOSED — an unknown driver resolves to the strictest registered remote
28
+ * profile rather than to "no destination", because "we do not recognise where
29
+ * this is going" must never read as "it is fine to send".
30
+ */
31
+ import { CLASSIFICATIONS, } from "./dataPolicy.js";
32
+ /** Drivers that keep the prompt on this machine. */
33
+ const LOCAL_DRIVERS = new Set(["local", "ollama", "lmstudio", "llamacpp"]);
34
+ function parseClassifications(raw) {
35
+ if (!Array.isArray(raw))
36
+ return null;
37
+ const out = [];
38
+ for (const v of raw) {
39
+ if (typeof v !== "string")
40
+ return null;
41
+ if (!CLASSIFICATIONS.includes(v))
42
+ return null;
43
+ out.push(v);
44
+ }
45
+ return out;
46
+ }
47
+ export function parseRegistry(cfg) {
48
+ const destinations = [];
49
+ const driversFor = new Map();
50
+ const invalid = [];
51
+ for (const [id, raw] of Object.entries(cfg?.destinations ?? {})) {
52
+ if (!raw || typeof raw !== "object") {
53
+ invalid.push({ id, reason: "not an object" });
54
+ continue;
55
+ }
56
+ const type = raw.type === "local" ? "local" : raw.type === "remote" ? "remote" : null;
57
+ if (!type) {
58
+ invalid.push({ id, reason: `type must be "local" or "remote"` });
59
+ continue;
60
+ }
61
+ const classifications = parseClassifications(raw.classifications);
62
+ if (!classifications) {
63
+ invalid.push({
64
+ id,
65
+ reason: "classifications must be an array of known classifications",
66
+ });
67
+ continue;
68
+ }
69
+ const dest = { id, type, classifications };
70
+ if (Array.isArray(raw.forbiddenCategories)) {
71
+ dest.forbiddenCategories = raw.forbiddenCategories.filter((c) => typeof c === "string");
72
+ }
73
+ if (raw.approvable === true)
74
+ dest.approvable = true;
75
+ destinations.push(dest);
76
+ driversFor.set(id, Array.isArray(raw.drivers)
77
+ ? raw.drivers.filter((d) => typeof d === "string")
78
+ : []);
79
+ }
80
+ return { destinations, driversFor, invalid };
81
+ }
82
+ /** The strictest remote destination — fewest classifications wins. */
83
+ function strictestRemote(destinations) {
84
+ const remotes = destinations.filter((d) => d.type === "remote");
85
+ if (remotes.length === 0)
86
+ return null;
87
+ return remotes.reduce((a, b) => b.classifications.length < a.classifications.length ? b : a);
88
+ }
89
+ /**
90
+ * Resolve the destination for a dispatch.
91
+ *
92
+ * Returns null ONLY when nothing is registered — the inert case. Once anything
93
+ * is registered, this always yields a destination, because falling back to null
94
+ * on an unrecognised driver would silently disable the boundary for exactly the
95
+ * dispatches nobody anticipated.
96
+ */
97
+ export function resolveDestination(registry, driver, forClass) {
98
+ if (registry.destinations.length === 0)
99
+ return null;
100
+ const d = (driver ?? "").toLowerCase();
101
+ const localAccepts = registry.destinations.some((dest) => dest.type === "local" && dest.classifications.includes(forClass));
102
+ // Explicit driver mapping wins.
103
+ for (const dest of registry.destinations) {
104
+ if ((registry.driversFor.get(dest.id) ?? []).includes(d)) {
105
+ return { destination: dest, localDestinationAccepts: localAccepts };
106
+ }
107
+ }
108
+ // Otherwise infer by driver family.
109
+ if (LOCAL_DRIVERS.has(d)) {
110
+ const local = registry.destinations.find((x) => x.type === "local");
111
+ if (local) {
112
+ return { destination: local, localDestinationAccepts: localAccepts };
113
+ }
114
+ }
115
+ // Unknown or remote driver → strictest remote. Fail closed: "we do not
116
+ // recognise where this is going" must never read as "it is fine to send".
117
+ const remote = strictestRemote(registry.destinations);
118
+ if (remote) {
119
+ return { destination: remote, localDestinationAccepts: localAccepts };
120
+ }
121
+ // Only local destinations are registered but the driver is not local. The
122
+ // strictest available answer is the local profile, which will refuse
123
+ // anything it is not cleared for.
124
+ const first = registry.destinations[0];
125
+ return { destination: first, localDestinationAccepts: localAccepts };
126
+ }
127
+ //# sourceMappingURL=destinationRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destinationRegistry.js","sourceRoot":"","sources":["../../src/privacy/destinationRegistry.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@
7
7
  * CHANGELOG: chained users with model:local in ~/.patchwork/config now route to
8
8
  * localFn (Ollama/LM Studio) instead of Anthropic API — opt-in behaviour change.
9
9
  */
10
+ import { type Destination } from "../privacy/dataPolicy.js";
11
+ import { type PrivacyConfig } from "../privacy/destinationRegistry.js";
10
12
  /**
11
13
  * Token usage reported by an adapter. Both fields are integers; absent
12
14
  * `usage` on the parent `AgentResult` means the driver didn't surface
@@ -42,6 +44,23 @@ export interface AgentResult {
42
44
  };
43
45
  }
44
46
  export interface AgentExecutorDeps {
47
+ /**
48
+ * Receipt sink for information-boundary decisions (ADR-0021 Phase 3).
49
+ * Optional: an unwired sink means no receipt, never a refusal — the
50
+ * boundary must not depend on its own audit trail being configured.
51
+ */
52
+ /**
53
+ * Supplies `privacy.destinations` from operator config. Absent means the
54
+ * boundary stays inert unless a caller passes an explicit destination —
55
+ * the opt-in posture ADR-0021 requires.
56
+ */
57
+ loadPrivacyConfigFn?: () => PrivacyConfig | undefined;
58
+ recordBoundaryDecisionFn?: (r: {
59
+ decision: string;
60
+ reason: string;
61
+ destinationId?: string;
62
+ redactCategories?: string[];
63
+ }) => void;
45
64
  anthropicFn: (prompt: string, model: string) => Promise<AgentResult>;
46
65
  /** Handles openai, grok, gemini, gemini-api, codex — passes driver name through. */
47
66
  providerDriverFn: (driver: "openai" | "grok" | "gemini" | "gemini-api" | "codex", prompt: string, model: string | undefined,
@@ -82,6 +101,19 @@ export interface AgentExecutorInput {
82
101
  allowedTools?: string[];
83
102
  /** Deny rules via --disallowed-tools (any mode). */
84
103
  disallowedTools?: string[];
104
+ /**
105
+ * Information-boundary context (ADR-0021). Absent means the step declared no
106
+ * `data_policy` and no destination is registered, which is byte-identical to
107
+ * pre-boundary behaviour — the overwhelmingly common case on upgrade.
108
+ */
109
+ boundary?: {
110
+ /** Raw `data_policy` as declared on the step. Parsed here, not by callers. */
111
+ dataPolicy?: unknown;
112
+ /** Where this prompt is about to go. */
113
+ destination?: Destination;
114
+ /** Whether ANY registered local destination accepts the classification. */
115
+ localDestinationAccepts?: boolean;
116
+ };
85
117
  /**
86
118
  * Worker-autonomy hard requirement. When true, this agent step carries a
87
119
  * worker-mandated tool sandbox (see disallowedToolsForAgentStep) that ONLY the
@@ -7,6 +7,8 @@
7
7
  * CHANGELOG: chained users with model:local in ~/.patchwork/config now route to
8
8
  * localFn (Ollama/LM Studio) instead of Anthropic API — opt-in behaviour change.
9
9
  */
10
+ import { DEFAULT_CLASSIFICATION, decideBoundary, parseDataPolicy, } from "../privacy/dataPolicy.js";
11
+ import { parseRegistry, resolveDestination, } from "../privacy/destinationRegistry.js";
10
12
  import { resolveLocalModel } from "./localSettings.js";
11
13
  /**
12
14
  * Model the anthropic/local agent paths fall back to when a step omits `model`.
@@ -50,6 +52,52 @@ const CODEX_WORKER_SANDBOX_LOCKDOWN = {
50
52
  networkAccess: false,
51
53
  webSearch: false,
52
54
  };
55
+ /**
56
+ * Evaluate the information boundary for one agent step.
57
+ *
58
+ * Returns null when the step declares nothing AND no destination is registered
59
+ * — byte-identical to pre-boundary behaviour, which is the state of every
60
+ * existing install.
61
+ *
62
+ * A MALFORMED `data_policy` fails closed with DENY rather than defaulting. The
63
+ * operator wrote a label; silently reading it as `internal` because of a typo
64
+ * would leave them believing data was protected when it was not.
65
+ */
66
+ function evaluateBoundary(ctx, driver, loadPrivacyConfig) {
67
+ const policy0 = parseDataPolicy(ctx?.dataPolicy);
68
+ // Resolve the destination HERE rather than requiring every call site to pass
69
+ // one. There are four dispatch sites in the flat runner alone; a boundary
70
+ // that depends on each of them remembering is a boundary with four ways to
71
+ // be bypassed, and the fifth call site added later inherits none of them.
72
+ let destination = ctx?.destination;
73
+ let localAccepts = ctx?.localDestinationAccepts;
74
+ if (!destination && loadPrivacyConfig) {
75
+ const registry = parseRegistry(loadPrivacyConfig());
76
+ const forClass = policy0?.classification ?? DEFAULT_CLASSIFICATION;
77
+ const resolved = resolveDestination(registry, driver, forClass);
78
+ if (resolved) {
79
+ destination = resolved.destination;
80
+ localAccepts = resolved.localDestinationAccepts;
81
+ }
82
+ }
83
+ if (!destination)
84
+ return null;
85
+ const ctx2 = { ...ctx, destination, localDestinationAccepts: localAccepts };
86
+ return evaluateAgainst(policy0, ctx2);
87
+ }
88
+ function evaluateAgainst(policy, ctx) {
89
+ if (policy === null) {
90
+ return {
91
+ decision: "DENY",
92
+ reason: "data_policy declares an unrecognised classification — refusing rather than defaulting a typo to `internal`",
93
+ };
94
+ }
95
+ return decideBoundary(policy, ctx.destination, {
96
+ ...(ctx.localDestinationAccepts !== undefined && {
97
+ localDestinationAccepts: ctx.localDestinationAccepts,
98
+ }),
99
+ });
100
+ }
53
101
  export async function executeAgent(input, deps) {
54
102
  const { prompt, driver, model, mcpAccess, sandbox, allowedTools, disallowedTools, providerOptions, enforceSandbox, } = input;
55
103
  // NEVER-WIDEN guard. A worker-mandated sandbox is enforceable only on drivers
@@ -66,6 +114,42 @@ export async function executeAgent(input, deps) {
66
114
  servedBy: { driver: driver ?? "auto" },
67
115
  };
68
116
  }
117
+ // ── INFORMATION BOUNDARY (ADR-0021) ─────────────────────────────────────
118
+ // Evaluated BEFORE dispatch, and here rather than in `costRouter`, which is
119
+ // the tempting seam and the wrong one: costRouter short-circuits with no
120
+ // downshift list and no USD cap, so binding privacy there would cover only
121
+ // budgeted steps while presenting as total enforcement. This function is on
122
+ // the unconditional path for both runners.
123
+ //
124
+ // Precedence is privacy -> capability -> cost, and it is not negotiable by
125
+ // the later stages: a cheaper or more capable model that is not authorised
126
+ // for the data does not become authorised by being cheaper or more capable.
127
+ const boundary = evaluateBoundary(input.boundary, driver, deps.loadPrivacyConfigFn);
128
+ if (boundary && boundary.decision !== "ALLOW") {
129
+ deps.recordBoundaryDecisionFn?.({
130
+ decision: boundary.decision,
131
+ reason: boundary.reason,
132
+ destinationId: input.boundary?.destination?.id,
133
+ ...(boundary.redactCategories && {
134
+ redactCategories: boundary.redactCategories,
135
+ }),
136
+ });
137
+ // ALLOW_REDACTED is not implemented as a transform in this phase, and is
138
+ // therefore REFUSED rather than silently sent unredacted. Failing closed on
139
+ // "we know something must be removed and cannot remove it" is the whole
140
+ // point; the alternative sends the data and logs that it should not have.
141
+ return {
142
+ text: `[agent step failed: information boundary — ${boundary.reason}]`,
143
+ servedBy: { driver: driver ?? "auto" },
144
+ };
145
+ }
146
+ if (boundary) {
147
+ deps.recordBoundaryDecisionFn?.({
148
+ decision: boundary.decision,
149
+ reason: boundary.reason,
150
+ destinationId: input.boundary?.destination?.id,
151
+ });
152
+ }
69
153
  const cliOpts = mcpAccess !== undefined ||
70
154
  sandbox !== undefined ||
71
155
  allowedTools !== undefined ||
@@ -1 +1 @@
1
- {"version":3,"file":"agentExecutor.js","sourceRoot":"","sources":["../../src/recipes/agentExecutor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agentExecutor.js","sourceRoot":"","sources":["../../src/recipes/agentExecutor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchwork-os",
3
- "version": "1.2.0-beta.2.canary.625",
3
+ "version": "1.2.0-beta.2.canary.627",
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",