@sema-agent/core 7.49.1 → 7.49.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/core/arg-summary.js +23 -5
- package/dist/core/credential-vocabulary.js +19 -2
- package/dist/core/gate-fold.js +2 -2
- package/dist/core/runner/prepare-gate-stations.js +2 -2
- package/dist/core/runner/prepare-lsp.d.ts +4 -4
- package/dist/core/runner/prepare-lsp.js +2 -2
- package/dist/core/runner/prepare-safety-scan.js +10 -6
- package/dist/core/runner-deps.d.ts +2 -2
- package/dist/core/task-spec.d.ts +2 -2
- package/dist/core/tool-catalog-entries.js +1 -1
- package/dist/core/tool-conformance.js +2 -1
- package/dist/core/tool-roster.d.ts +11 -6
- package/dist/core/tool-roster.js +8 -4
- package/dist/core/write-protect.d.ts +3 -1
- package/dist/core/write-protect.js +4 -5
- package/dist/tools/fs/bash-readonly-classifier.d.ts +2 -2
- package/dist/tools/fs/bash-readonly-classifier.js +5 -3
- package/dist/tools/fs/read-deny-home.d.ts +5 -1
- package/dist/tools/fs/read-deny-home.js +40 -19
- package/dist/tools/fs/shell-read-check.d.ts +1 -1
- package/dist/tools/fs/shell-read-check.js +29 -15
- package/dist/tools/fs/shell-read-environment.d.ts +74 -0
- package/dist/tools/fs/shell-read-environment.js +71 -0
- package/dist/tools/fs/shell-read-establish.d.ts +8 -4
- package/dist/tools/fs/shell-read-establish.js +34 -36
- package/dist/tools/fs/shell-read-identity.d.ts +3 -2
- package/dist/tools/fs/shell-read-identity.js +5 -3
- package/dist/tools/fs/shell-read-judge.d.ts +69 -18
- package/dist/tools/fs/shell-read-judge.js +27 -14
- package/package.json +1 -1
- package/wire-changes/core@7.49.1.json +57 -0
- package/wire-changes/core@7.49.2.json +138 -0
|
@@ -38,8 +38,8 @@ function targetsByCandidate(e) {
|
|
|
38
38
|
function sameTargets(a, b) {
|
|
39
39
|
return a.size === b.size && [...a].every((t) => b.has(t));
|
|
40
40
|
}
|
|
41
|
-
export async function withHomeViews(
|
|
42
|
-
const views = homeViewsOf(
|
|
41
|
+
export async function withHomeViews(door, placed, established, signal) {
|
|
42
|
+
const views = homeViewsOf(door.fs, placed, signal);
|
|
43
43
|
const place = async (p) => {
|
|
44
44
|
const reads = new Map();
|
|
45
45
|
for (const [segment, rs] of p.reads) {
|
|
@@ -56,5 +56,7 @@ export async function withHomeViews(env, placed, established, signal) {
|
|
|
56
56
|
nested.set(n, await place(np));
|
|
57
57
|
return { ...p, reads, nested };
|
|
58
58
|
};
|
|
59
|
-
|
|
59
|
+
const withViews = await place(established);
|
|
60
|
+
door.adopt(views.unread.map((p) => ({ op: "fileIdentity", detail: `"${p}" cannot be identified against the home directories` })));
|
|
61
|
+
return withViews;
|
|
60
62
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* judge is `withinAnyRoot` over the roots the boundary declares — a WRITE target's over the write roots, at the
|
|
12
12
|
* seat it is written, under the write face in force ({@link judgeWrite}).
|
|
13
13
|
* · `foldShellReadFindings` folds a command's findings — every segment, every nested plan — to ONE word by
|
|
14
|
-
* the priority `identity_changed > deny_hit > outside_roots > unestablishable > declined > none`.
|
|
14
|
+
* the priority `identity_changed > deny_hit > unanswered > outside_roots > unestablishable > declined > none`.
|
|
15
15
|
* · `SHELL_READ_DECISION` is the total table (finding × seat → disposition) that is the ONLY source of
|
|
16
16
|
* "refuse / mandated ask / ordinary ask / vouch" for a shell read. A seat is a FACE word, not a tool name
|
|
17
17
|
* and not a permission mode: which shell face the call runs on (the full shell, the read-only shell) or
|
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import type { BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
24
24
|
import type { ReadCandidate, ShellReadPlan, ShellReadSegment } from "./shell-read-plan.js";
|
|
25
|
+
import type { Incomplete, ObservedFilesystem } from "./shell-read-environment.js";
|
|
25
26
|
import type { WriteSeat } from "./shell-read-write-targets.js";
|
|
26
27
|
import { type ContainmentFace } from "./containment-face.js";
|
|
27
28
|
import type { AssertAllKeysHandled } from "../../core/ask-origin.js";
|
|
28
29
|
/** WHAT the judge found about a command — a closed set, registered in `docs/CLOSED-SETS.md`. */
|
|
29
|
-
export declare const SHELL_READ_FINDINGS: readonly ["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "none"];
|
|
30
|
+
export declare const SHELL_READ_FINDINGS: readonly ["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "unanswered", "none"];
|
|
30
31
|
export type ShellReadFinding = (typeof SHELL_READ_FINDINGS)[number];
|
|
31
32
|
/** WHERE a read is judged — the seats the decision table is keyed on, one per FACE: `full_shell` the
|
|
32
33
|
* writable shell (`Bash`, `Monitor`) under every permission mode and every shell-gate floor; `readonly`
|
|
@@ -38,9 +39,10 @@ export type ShellReadSeat = (typeof SHELL_READ_SEATS)[number];
|
|
|
38
39
|
export declare const SHELL_READ_FINDING_RANK: {
|
|
39
40
|
readonly identity_changed: 6;
|
|
40
41
|
readonly deny_hit: 5;
|
|
41
|
-
readonly
|
|
42
|
-
readonly
|
|
43
|
-
readonly
|
|
42
|
+
readonly unanswered: 4;
|
|
43
|
+
readonly outside_roots: 3;
|
|
44
|
+
readonly unestablishable: 2;
|
|
45
|
+
readonly declined: 1;
|
|
44
46
|
readonly none: 0;
|
|
45
47
|
};
|
|
46
48
|
/** Compile-time fence: `never` while every finding has a rank. */
|
|
@@ -50,6 +52,14 @@ export type RankTableCoversEveryFinding = AssertAllKeysHandled<Exclude<ShellRead
|
|
|
50
52
|
* the auto-mode classifier, a stored allow rule) but no answerless engine table may; `vouch` = the station
|
|
51
53
|
* has no question. */
|
|
52
54
|
export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
|
|
55
|
+
/** One cell of the decision table: a disposition, or — where the READ FACE the question was raised under decides it — the two
|
|
56
|
+
* readings, `narrowed` (the `roots` face: the fence the deployment narrowed, and the engine default) and `open`. */
|
|
57
|
+
export type ShellReadCell = ShellReadDisposition | {
|
|
58
|
+
readonly narrowed: ShellReadDisposition;
|
|
59
|
+
readonly open: ShellReadDisposition;
|
|
60
|
+
};
|
|
61
|
+
/** A cell, read for a question raised under a narrowed read face (`true`) or an open one (`false`). */
|
|
62
|
+
export declare function dispositionOfCell(cell: ShellReadCell, narrowedReadFace: boolean): ShellReadDisposition;
|
|
53
63
|
/**
|
|
54
64
|
* THE decision table — total over findings × seats; no cell is n/a. Row by row:
|
|
55
65
|
* · `deny_hit` — refused on every seat, for a spelling the station can establish: a deny row is a floor
|
|
@@ -58,8 +68,14 @@ export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
|
|
|
58
68
|
* · `outside_roots` — asked where a person can be asked (the full shell), refused where none can (the
|
|
59
69
|
* read-only face has no approval channel; a rewrite that leaves the roots after approval was seen by
|
|
60
70
|
* nobody).
|
|
61
|
-
* · `unestablishable` — the
|
|
62
|
-
*
|
|
71
|
+
* · `unestablishable` — the floor could not say where the command reads, so it is not vouched anywhere: asked
|
|
72
|
+
* where a person can be asked (the full shell), refused where none can be asked. The full shell's cell is read by the read face
|
|
73
|
+
* the question was raised under: on a NARROWED (`roots`) face — the engine default — the deployment asked to be asked, so the
|
|
74
|
+
* ask is MANDATED and no automatic lane answers; on the OPEN face (where the station asks only because a deny list has
|
|
75
|
+
* rows), and for a written target alone (a narrowed WRITE face fences what is written; it is no request to be asked about
|
|
76
|
+
* every word the floor cannot place), it is the ORDINARY ask — the reference implementation's plain permission ask (CC
|
|
77
|
+
* 2.1.296 `sR`, cli296.js @13116941, reason `other`), which a whole-tool allow (`$pn` @18717070), bypass (`$pn` @18716980)
|
|
78
|
+
* and the auto-mode classifier release and a prefix allow does not.
|
|
63
79
|
* · `declined` — the one deliberate fail-open of this table: the scan could not read the program bash
|
|
64
80
|
* will run, or the operands arrive on a stream. On the full shell it is an ORDINARY ask — an answerer
|
|
65
81
|
* may settle it, and an out-of-root read hidden inside such a command is then not asked again. The
|
|
@@ -67,6 +83,15 @@ export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
|
|
|
67
83
|
* n/a.
|
|
68
84
|
* · `identity_changed` — a candidate established at approval time resolves elsewhere at spawn time:
|
|
69
85
|
* refused everywhere (it is only ever produced on the `rejudge` seat).
|
|
86
|
+
* · `unanswered` — the judge did not FINISH: it threw or timed out, the lookup it stands on was absent, or — recorded at the
|
|
87
|
+
* one door to the environment ({@link import("./shell-read-environment.js").Incomplete}) — an environment lookup gave no
|
|
88
|
+
* answer (an error that is no conclusive "not there"), the station stopped at its own bound (more directories or names than
|
|
89
|
+
* it enumerates, a link chain past its hop bound), or a home view could not be read. Any one makes the whole command
|
|
90
|
+
* `unanswered`, whatever the other words found. Not a fact about the command but the state of the station, so it is not
|
|
91
|
+
* the `unestablishable` row's question (a text the station cannot place — a word the shell rewrites, a lost working
|
|
92
|
+
* directory, a pattern its matcher does not model). Absence is not
|
|
93
|
+
* "nothing there": the full shell asks it MANDATED on every read face — a standing allow was given on the premise that the
|
|
94
|
+
* judge works, and a broken judge is not cleared by it — and the read-only face refuses.
|
|
70
95
|
* · `none` — vouched: the station has no question (the full shell's shape tier may still ask).
|
|
71
96
|
*/
|
|
72
97
|
export declare const SHELL_READ_DECISION: {
|
|
@@ -81,7 +106,10 @@ export declare const SHELL_READ_DECISION: {
|
|
|
81
106
|
readonly rejudge: "refuse";
|
|
82
107
|
};
|
|
83
108
|
readonly unestablishable: {
|
|
84
|
-
readonly full_shell:
|
|
109
|
+
readonly full_shell: {
|
|
110
|
+
readonly narrowed: "mandated";
|
|
111
|
+
readonly open: "ordinary";
|
|
112
|
+
};
|
|
85
113
|
readonly readonly: "refuse";
|
|
86
114
|
readonly rejudge: "refuse";
|
|
87
115
|
};
|
|
@@ -95,6 +123,11 @@ export declare const SHELL_READ_DECISION: {
|
|
|
95
123
|
readonly readonly: "refuse";
|
|
96
124
|
readonly rejudge: "refuse";
|
|
97
125
|
};
|
|
126
|
+
readonly unanswered: {
|
|
127
|
+
readonly full_shell: "mandated";
|
|
128
|
+
readonly readonly: "refuse";
|
|
129
|
+
readonly rejudge: "refuse";
|
|
130
|
+
};
|
|
98
131
|
readonly none: {
|
|
99
132
|
readonly full_shell: "vouch";
|
|
100
133
|
readonly readonly: "vouch";
|
|
@@ -109,10 +142,15 @@ export type DecisionTableCoversEverySeat = AssertAllKeysHandled<Exclude<ShellRea
|
|
|
109
142
|
/** The disposition of one command-level finding on one seat — the table, read. A seat word outside
|
|
110
143
|
* {@link SHELL_READ_SEATS} (an untyped caller, or one still passing a retired word) is refused loudly: an
|
|
111
144
|
* absent disposition would read as "no verdict", which no caller can act on safely. */
|
|
112
|
-
export declare function decideShellRead(finding: ShellReadFinding, seat: ShellReadSeat): ShellReadDisposition;
|
|
113
|
-
/**
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
export declare function decideShellRead(finding: ShellReadFinding, seat: ShellReadSeat, context?: ShellReadCellContext): ShellReadDisposition;
|
|
146
|
+
/** What the table is read for beyond (finding, seat): the two facts of a judged command a cell can depend on. */
|
|
147
|
+
export interface ShellReadCellContext {
|
|
148
|
+
/** Every containment finding is an output redirection outside the write roots ({@link SHELL_REDIRECT_DECISION}). Absent ⇒ no. */
|
|
149
|
+
readonly redirectsOnly?: boolean;
|
|
150
|
+
/** The question was raised under a NARROWED (`roots`) read face — a read candidate or the text's own structure while the read
|
|
151
|
+
* face runs the roots containment; `false` for the open face and for a written target alone. Absent ⇒ narrowed, the engine default. */
|
|
152
|
+
readonly narrowedReadFace?: boolean;
|
|
153
|
+
}
|
|
116
154
|
/**
|
|
117
155
|
* The boundary a shell read is judged against: the declared roots (canonical), the working directory and
|
|
118
156
|
* home the plan's bases start from, the deny seat (the SAME `denyMatch` closure every read face mounts),
|
|
@@ -143,8 +181,11 @@ export interface ShellReadBoundary extends BashReadonlyRootBoundary {
|
|
|
143
181
|
* the path is a key the station established (judged as a key, never as a spelling). `"protected"`: the table covers it —
|
|
144
182
|
* the target is not placed and the verdict says so ({@link import("./shell-read-check.js").ShellReadVerdict.writeProtected});
|
|
145
183
|
* `"guarded"`: a deployment row covers it — the target is not placed; `undefined`: nothing covers it. Read by the
|
|
146
|
-
* station's write facts only. A judgment that throws fails the station's answer (the caller's fail-closed arm).
|
|
147
|
-
|
|
184
|
+
* station's write facts only. A judgment that throws fails the station's answer (the caller's fail-closed arm). Every lookup
|
|
185
|
+
* it makes goes through `fs` — the command's door — and through no environment of its own: the station's one decision about
|
|
186
|
+
* what a silence means reads the answers the judgment got as well as the ones it did not. */
|
|
187
|
+
readonly writeTargetJudge?: (target: string, opts: {
|
|
188
|
+
readonly fs: ObservedFilesystem;
|
|
148
189
|
readonly signal?: AbortSignal;
|
|
149
190
|
readonly canonical?: true;
|
|
150
191
|
}) => Promise<"protected" | "guarded" | undefined>;
|
|
@@ -177,7 +218,8 @@ export interface EstablishedRead {
|
|
|
177
218
|
/** The candidate's spelling WAS placed and the environment could not resolve where it leads (the whole chain unanswered by
|
|
178
219
|
* a resolver that declares itself authoritative, or a component it could not follow) — the reading's
|
|
179
220
|
* `target_unresolved` fact, as opposed to a text the station cannot read (a rewritten word, an unsettled working
|
|
180
|
-
* directory). Present only on an `unestablishable` read.
|
|
221
|
+
* directory). Present only on an `unestablishable` read. (That the environment gave no answer is the establishment's
|
|
222
|
+
* `incomplete`, which makes the command `unanswered` whether or not a candidate carries this mark.) */
|
|
181
223
|
readonly unresolved?: true;
|
|
182
224
|
/** WHERE the command's program writes this target — present only on a write target the program itself writes, at the
|
|
183
225
|
* seat this read was established at (`landing`: through the path's links; `entry`: the directory entry, a link there
|
|
@@ -189,7 +231,8 @@ export interface EstablishedRead {
|
|
|
189
231
|
};
|
|
190
232
|
}
|
|
191
233
|
/** What the judge found about ONE candidate. `kind` is one of the four candidate-level findings
|
|
192
|
-
* (`declined` is a segment fact, `identity_changed` a re-establishment fact
|
|
234
|
+
* (`declined` is a segment fact, `identity_changed` a re-establishment fact, `unanswered` a fact of the whole establishment —
|
|
235
|
+
* none is a candidate's). */
|
|
193
236
|
export interface ReadFinding {
|
|
194
237
|
readonly read: EstablishedRead;
|
|
195
238
|
readonly kind: Extract<ShellReadFinding, "deny_hit" | "outside_roots" | "unestablishable" | "none">;
|
|
@@ -255,6 +298,8 @@ export interface JudgedPlan {
|
|
|
255
298
|
readonly guards: boolean;
|
|
256
299
|
/** {@link writeFaceGuards} of the same boundary — what a WRITE target's finding folds by. */
|
|
257
300
|
readonly writeGuards: boolean;
|
|
301
|
+
/** What the command could not finish (the station's one door, decided after the write guards asked); on the top plan only. */
|
|
302
|
+
readonly incomplete?: readonly Incomplete[];
|
|
258
303
|
}
|
|
259
304
|
/**
|
|
260
305
|
* Does the station GUARD anything for this boundary — a closed face (roots: containment is what it guards; an absent
|
|
@@ -281,12 +326,18 @@ export interface ShellReadFold {
|
|
|
281
326
|
readonly finding: ShellReadFinding;
|
|
282
327
|
readonly witness?: ReadFinding;
|
|
283
328
|
readonly declined?: ShellReadSegment;
|
|
284
|
-
/**
|
|
329
|
+
/** What the judge did not finish, for an `unanswered` finding: the first thing the establishment recorded ({@link Incomplete.detail}). */
|
|
330
|
+
readonly cause?: string;
|
|
331
|
+
/** Some read of the text could not be established (an `unestablishable`, `unanswered` or `declined` finding anywhere, winning or not). */
|
|
285
332
|
readonly unestablished?: true;
|
|
333
|
+
/** Some `unestablishable` finding anywhere is about the READ face — a read candidate, or the text's own structure (a rewritten
|
|
334
|
+
* word, a re-entered shell text) — rather than a written target alone. The cell of the row reads it with the read face in force
|
|
335
|
+
* ({@link decideShellRead}). */
|
|
336
|
+
readonly unplacedRead?: true;
|
|
286
337
|
}
|
|
287
338
|
/**
|
|
288
339
|
* Fold a judged plan to ONE finding by {@link SHELL_READ_FINDING_RANK}, over every segment and every nested
|
|
289
|
-
* plan. Where the station guards nothing an `unestablishable` or `declined` finding is no finding: there is nothing to
|
|
340
|
+
* plan. Where the station guards nothing an `unestablishable`, `unanswered` or `declined` finding is no finding: there is nothing to
|
|
290
341
|
* confirm it against. Which guard is asked is the face the finding is about — a read candidate's by the read face's
|
|
291
342
|
* ({@link JudgedPlan.guards}), a write target's by the write face's ({@link JudgedPlan.writeGuards}), and a finding about
|
|
292
343
|
* the text's own structure (no candidate stands in for it) by either ({@link anyFaceGuards}). Two structural rules ride the fold:
|
|
@@ -2,39 +2,43 @@ import { hasWin32AliasedComponent, normalizeAbsPathLexically, withinAnyRoot } fr
|
|
|
2
2
|
import { globInWord } from "./bash-readonly-classifier.js";
|
|
3
3
|
import { readOfText } from "./shell-read-word.js";
|
|
4
4
|
import { skipsRootsContainment } from "./containment-face.js";
|
|
5
|
-
export const SHELL_READ_FINDINGS = Object.freeze(["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "none"]);
|
|
5
|
+
export const SHELL_READ_FINDINGS = Object.freeze(["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "unanswered", "none"]);
|
|
6
6
|
export const SHELL_READ_SEATS = Object.freeze(["full_shell", "readonly", "rejudge"]);
|
|
7
7
|
export const SHELL_READ_FINDING_RANK = {
|
|
8
8
|
identity_changed: 6,
|
|
9
9
|
deny_hit: 5,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
unanswered: 4,
|
|
11
|
+
outside_roots: 3,
|
|
12
|
+
unestablishable: 2,
|
|
13
|
+
declined: 1,
|
|
13
14
|
none: 0,
|
|
14
15
|
};
|
|
16
|
+
export function dispositionOfCell(cell, narrowedReadFace) {
|
|
17
|
+
return typeof cell === "string" ? cell : narrowedReadFace ? cell.narrowed : cell.open;
|
|
18
|
+
}
|
|
15
19
|
export const SHELL_READ_DECISION = {
|
|
16
20
|
deny_hit: { full_shell: "refuse", readonly: "refuse", rejudge: "refuse" },
|
|
17
21
|
outside_roots: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
|
|
18
|
-
unestablishable: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
|
|
22
|
+
unestablishable: { full_shell: { narrowed: "mandated", open: "ordinary" }, readonly: "refuse", rejudge: "refuse" },
|
|
19
23
|
declined: { full_shell: "ordinary", readonly: "refuse", rejudge: "refuse" },
|
|
20
24
|
identity_changed: { full_shell: "refuse", readonly: "refuse", rejudge: "refuse" },
|
|
25
|
+
unanswered: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
|
|
21
26
|
none: { full_shell: "vouch", readonly: "vouch", rejudge: "vouch" },
|
|
22
27
|
};
|
|
23
|
-
export function decideShellRead(finding, seat) {
|
|
28
|
+
export function decideShellRead(finding, seat, context = {}) {
|
|
29
|
+
const redirectCell = context.redirectsOnly === true && Object.hasOwn(SHELL_REDIRECT_DECISION, finding) ? SHELL_REDIRECT_DECISION[finding]?.[seat] : undefined;
|
|
30
|
+
if (redirectCell !== undefined)
|
|
31
|
+
return redirectCell;
|
|
24
32
|
const row = Object.hasOwn(SHELL_READ_DECISION, finding) ? SHELL_READ_DECISION[finding] : undefined;
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
33
|
+
const cell = row !== undefined && Object.hasOwn(row, seat) ? row[seat] : undefined;
|
|
34
|
+
if (cell === undefined) {
|
|
27
35
|
throw new Error(`shell read decision: no cell for finding ${JSON.stringify(finding)} on seat ${JSON.stringify(seat)} — the seats are ${SHELL_READ_SEATS.map((w) => JSON.stringify(w)).join(", ")} (a seat names the face the command runs on)`);
|
|
28
36
|
}
|
|
29
|
-
return
|
|
37
|
+
return dispositionOfCell(cell, context.narrowedReadFace !== false);
|
|
30
38
|
}
|
|
31
39
|
const SHELL_REDIRECT_DECISION = {
|
|
32
40
|
outside_roots: { full_shell: "ordinary" },
|
|
33
41
|
};
|
|
34
|
-
export function decideShellReadForRedirects(finding, seat, redirectsOnly) {
|
|
35
|
-
const cell = redirectsOnly && Object.hasOwn(SHELL_REDIRECT_DECISION, finding) ? SHELL_REDIRECT_DECISION[finding]?.[seat] : undefined;
|
|
36
|
-
return cell ?? decideShellRead(finding, seat);
|
|
37
|
-
}
|
|
38
42
|
export function judgeRead(read, boundary) {
|
|
39
43
|
const writeTarget = read.candidate.face === "write";
|
|
40
44
|
const deny = writeTarget ? boundary.writeDenyMatch : boundary.denyMatch;
|
|
@@ -110,12 +114,15 @@ export function anyFaceGuards(boundary) {
|
|
|
110
114
|
export function foldShellReadFindings(judged) {
|
|
111
115
|
let best = { finding: "none" };
|
|
112
116
|
let unestablished = false;
|
|
117
|
+
let unplacedRead = false;
|
|
113
118
|
const raise = (next) => {
|
|
114
119
|
if (next.finding === "unestablishable" || next.finding === "declined") {
|
|
115
120
|
const face = next.witness?.read.candidate.face;
|
|
116
121
|
if (!(next.witness === undefined ? judged.guards || judged.writeGuards : face === "write" ? judged.writeGuards : judged.guards))
|
|
117
122
|
return;
|
|
118
123
|
unestablished = true;
|
|
124
|
+
if (next.finding === "unestablishable" && face !== "write")
|
|
125
|
+
unplacedRead = true;
|
|
119
126
|
}
|
|
120
127
|
const rank = SHELL_READ_FINDING_RANK[next.finding] - SHELL_READ_FINDING_RANK[best.finding];
|
|
121
128
|
if (rank > 0 || (rank === 0 && next.witness?.read.candidate.face === "write" && best.witness?.read.candidate.face !== "write"))
|
|
@@ -148,7 +155,12 @@ export function foldShellReadFindings(judged) {
|
|
|
148
155
|
}
|
|
149
156
|
};
|
|
150
157
|
walk(judged, false);
|
|
151
|
-
|
|
158
|
+
const unfinished = judged.incomplete?.[0];
|
|
159
|
+
if (unfinished !== undefined && (judged.guards || judged.writeGuards) && SHELL_READ_FINDING_RANK.unanswered > SHELL_READ_FINDING_RANK[best.finding]) {
|
|
160
|
+
unestablished = true;
|
|
161
|
+
best = { finding: "unanswered", cause: unfinished.detail, ...(best.finding === "unestablishable" ? { ...(best.witness !== undefined ? { witness: best.witness } : {}), ...(best.declined !== undefined ? { declined: best.declined } : {}) } : {}) };
|
|
162
|
+
}
|
|
163
|
+
return { ...best, ...(unestablished ? { unestablished: true } : {}), ...(unplacedRead ? { unplacedRead: true } : {}) };
|
|
152
164
|
}
|
|
153
165
|
export function judgeEstablishedPlan(plan, established, boundary, nestedOf) {
|
|
154
166
|
return {
|
|
@@ -244,5 +256,6 @@ export function rejudge(judged, boundary) {
|
|
|
244
256
|
})),
|
|
245
257
|
guards: stationGuards(boundary),
|
|
246
258
|
writeGuards: writeFaceGuards(boundary),
|
|
259
|
+
...(judged.incomplete !== undefined ? { incomplete: judged.incomplete } : {}),
|
|
247
260
|
};
|
|
248
261
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "core",
|
|
3
|
+
"version": "7.49.1",
|
|
4
|
+
"from": "a58f6fef9c81bf031cc3dc1a12a8c5bc72d35193",
|
|
5
|
+
"to": "57363d52a115a659d902a81e8aad865ed98e2419",
|
|
6
|
+
"added": [],
|
|
7
|
+
"removed": [],
|
|
8
|
+
"changed": [],
|
|
9
|
+
"narrowed": [],
|
|
10
|
+
"closedSetMembers": [
|
|
11
|
+
{
|
|
12
|
+
"set": "OPTION_MODES",
|
|
13
|
+
"at": [
|
|
14
|
+
"src/tools/fs/program-read-model.ts:38"
|
|
15
|
+
],
|
|
16
|
+
"newSet": false,
|
|
17
|
+
"added": [
|
|
18
|
+
"queries"
|
|
19
|
+
],
|
|
20
|
+
"removed": [],
|
|
21
|
+
"breaking": false,
|
|
22
|
+
"criteriaCovered": false
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"set": "ToolTurnOutcome",
|
|
26
|
+
"at": [
|
|
27
|
+
"src/core/runner/tool-turn-repair-seat.ts:50"
|
|
28
|
+
],
|
|
29
|
+
"newSet": true,
|
|
30
|
+
"added": [
|
|
31
|
+
"reissued",
|
|
32
|
+
"terminal"
|
|
33
|
+
],
|
|
34
|
+
"removed": [],
|
|
35
|
+
"breaking": false,
|
|
36
|
+
"criteriaCovered": false
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"closedSetsUnreadable": [],
|
|
40
|
+
"typeKeys": [],
|
|
41
|
+
"typeKeysUnreadableArms": [],
|
|
42
|
+
"typeKeysFlattenedCount": 223,
|
|
43
|
+
"signatures": [],
|
|
44
|
+
"declarationMoves": [],
|
|
45
|
+
"mintMoves": [],
|
|
46
|
+
"criteriaObserves": [],
|
|
47
|
+
"consumersHint": {
|
|
48
|
+
"cli": [
|
|
49
|
+
"OPTION_MODES"
|
|
50
|
+
],
|
|
51
|
+
"server": [],
|
|
52
|
+
"sdk": [],
|
|
53
|
+
"note": "scanned cli@82bb8c2d server@a51468d9 sdk@006ce24 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
|
|
54
|
+
},
|
|
55
|
+
"breakingCount": 0,
|
|
56
|
+
"breakingItems": []
|
|
57
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "core",
|
|
3
|
+
"version": "7.49.2",
|
|
4
|
+
"from": "57363d52a115a659d902a81e8aad865ed98e2419",
|
|
5
|
+
"to": "50ffffb636bb70863f86ee9a74aee0c0a82891a0",
|
|
6
|
+
"added": [],
|
|
7
|
+
"removed": [],
|
|
8
|
+
"changed": [],
|
|
9
|
+
"narrowed": [],
|
|
10
|
+
"closedSetMembers": [
|
|
11
|
+
{
|
|
12
|
+
"set": "SHELL_READ_FINDINGS",
|
|
13
|
+
"at": [
|
|
14
|
+
"src/tools/fs/shell-read-judge.ts:34"
|
|
15
|
+
],
|
|
16
|
+
"newSet": false,
|
|
17
|
+
"added": [
|
|
18
|
+
"unanswered"
|
|
19
|
+
],
|
|
20
|
+
"removed": [],
|
|
21
|
+
"breaking": false,
|
|
22
|
+
"criteriaCovered": false
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"closedSetsUnreadable": [],
|
|
26
|
+
"typeKeys": [],
|
|
27
|
+
"typeKeysUnreadableArms": [],
|
|
28
|
+
"typeKeysFlattenedCount": 223,
|
|
29
|
+
"signatures": [
|
|
30
|
+
{
|
|
31
|
+
"name": "ShellReadBoundary.writeTargetJudge",
|
|
32
|
+
"at": [
|
|
33
|
+
"src/tools/fs/shell-read-judge.ts:191"
|
|
34
|
+
],
|
|
35
|
+
"from": [
|
|
36
|
+
"(target: string, opts?: { readonly signal?: AbortSignal; readonly canonical?: true; }): Promise<\"protected\" | \"guarded\" | undefined>"
|
|
37
|
+
],
|
|
38
|
+
"to": [
|
|
39
|
+
"(target: string, opts: { readonly fs: ObservedFilesystem; readonly signal?: AbortSignal; readonly canonical?: true; }): Promise<\"protected\" | \"guarded\" | undefined>"
|
|
40
|
+
],
|
|
41
|
+
"changes": [
|
|
42
|
+
{
|
|
43
|
+
"aspect": "param",
|
|
44
|
+
"detail": "param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re…",
|
|
45
|
+
"breaking": true,
|
|
46
|
+
"uncertain": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"aspect": "param",
|
|
50
|
+
"detail": "param 2 `opts` is now required",
|
|
51
|
+
"breaking": true
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"uncertain": "param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re… — the direction of a type change is not read syntactically, so it is reported breaking: check whether existing call sites still type-check before writing the BREAKING line",
|
|
55
|
+
"breaking": true,
|
|
56
|
+
"criteriaCovered": false
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"declarationMoves": [],
|
|
60
|
+
"mintMoves": [],
|
|
61
|
+
"criteriaObserves": [
|
|
62
|
+
{
|
|
63
|
+
"kind": "taskEventField",
|
|
64
|
+
"name": "tool_end.gate",
|
|
65
|
+
"assertions": [
|
|
66
|
+
"G3.a",
|
|
67
|
+
"G4.a"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"kind": "typeMember",
|
|
72
|
+
"name": "AskRequest.askClass",
|
|
73
|
+
"assertions": [
|
|
74
|
+
"G1.b"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"kind": "typeMember",
|
|
79
|
+
"name": "AskRequest.requiresRealApproval",
|
|
80
|
+
"assertions": [
|
|
81
|
+
"G1.a",
|
|
82
|
+
"G2.a",
|
|
83
|
+
"G3.a"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"kind": "typeMember",
|
|
88
|
+
"name": "RedactionFinding.kind",
|
|
89
|
+
"assertions": [
|
|
90
|
+
"G5.a",
|
|
91
|
+
"G5.b"
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"kind": "typeMember",
|
|
96
|
+
"name": "RedactionFinding.span",
|
|
97
|
+
"assertions": [
|
|
98
|
+
"G5.a"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"kind": "typeMember",
|
|
103
|
+
"name": "ShellReadVerdict.face",
|
|
104
|
+
"assertions": [
|
|
105
|
+
"G1.a",
|
|
106
|
+
"G2.a",
|
|
107
|
+
"G3.b"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"kind": "typeMember",
|
|
112
|
+
"name": "ToolCatalogEntry.mountedBy",
|
|
113
|
+
"assertions": [
|
|
114
|
+
"G4.a"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"kind": "typeMember",
|
|
119
|
+
"name": "ToolSpec.pathTarget",
|
|
120
|
+
"assertions": [
|
|
121
|
+
"G4.b"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"consumersHint": {
|
|
126
|
+
"cli": [
|
|
127
|
+
"SHELL_READ_FINDINGS",
|
|
128
|
+
"ShellReadBoundary"
|
|
129
|
+
],
|
|
130
|
+
"server": [],
|
|
131
|
+
"sdk": [],
|
|
132
|
+
"note": "scanned cli@1aef2b83 server@5a38b2ce sdk@46baee2 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it. Ledger files (**/docs/core-consumption/**, **/docs/wire-consumption/**, **/*LEDGER*.json) are not evidence of use — server: 2 name(s) matched ONLY in bookkeeping files and were set aside (SHELL_READ_FINDINGS, ShellReadBoundary)"
|
|
133
|
+
},
|
|
134
|
+
"breakingCount": 1,
|
|
135
|
+
"breakingItems": [
|
|
136
|
+
"signature changed: ShellReadBoundary.writeTargetJudge — param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re…; param 2 `opts` is now required"
|
|
137
|
+
]
|
|
138
|
+
}
|