@codyswann/lisa 4.84.7 → 4.84.8
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/all/copy-overwrite/scripts/lib/completion-authorization.mjs +282 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-adapters.mjs +213 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-conformance.mjs +115 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-content.mjs +408 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-errors.mjs +16 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-github.mjs +233 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-markdown.mjs +70 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-projection.mjs +169 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-publisher.mjs +238 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-reader.mjs +175 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-shape.mjs +374 -0
- package/all/copy-overwrite/scripts/lib/completion-proof-source.mjs +174 -0
- package/all/copy-overwrite/scripts/lib/history-secret-scanner.mjs +20 -5
- package/all/copy-overwrite/scripts/lib/npm-update-helper-inventory.mjs +15 -0
- package/all/copy-overwrite/scripts/lib/usage-effectiveness.d.mts +27 -0
- package/all/copy-overwrite/scripts/lib/usage-effectiveness.mjs +156 -0
- package/all/copy-overwrite/scripts/lib/usage-ledger-integrity.d.mts +8 -0
- package/all/copy-overwrite/scripts/lib/usage-ledger-integrity.mjs +141 -0
- package/all/copy-overwrite/scripts/lib/usage-ledger.d.mts +89 -0
- package/all/copy-overwrite/scripts/lib/usage-ledger.mjs +206 -0
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +3 -1
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +255 -39
- package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +141 -3
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +186 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +101 -12
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +3 -1
- package/dist/utils/effectiveness.d.ts +4 -41
- package/dist/utils/effectiveness.d.ts.map +1 -1
- package/dist/utils/effectiveness.js +2 -126
- package/dist/utils/effectiveness.js.map +1 -1
- package/dist/utils/usage-accounting.d.ts +5 -100
- package/dist/utils/usage-accounting.d.ts.map +1 -1
- package/dist/utils/usage-accounting.js +4 -287
- package/dist/utils/usage-accounting.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa/hooks/parity-safety-net.sh +3 -1
- package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa/rules/reference/completion-authorization.md +10 -0
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +3 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa-agy/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa-agy/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +3 -1
- package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa-copilot/rules/reference/completion-authorization.md +10 -0
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa-copilot/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa-copilot/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +3 -1
- package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
- package/plugins/lisa-cursor/rules/completion-authorization-reference.mdc +15 -0
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa-cursor/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa-cursor/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/hooks/parity-safety-net.sh +3 -1
- package/plugins/lisa-devin/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa-devin/rules/reference/completion-authorization.md +10 -0
- package/plugins/lisa-devin/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/lisa-devin/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/lisa-devin/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/parity-safety-net.sh +3 -1
- package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
- package/plugins/src/base/rules/reference/completion-authorization.md +10 -0
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +15 -1
- package/plugins/src/base/skills/lisa-tracker-evidence/SKILL.md +7 -1
- package/plugins/src/base/skills/lisa-tracker-evidence/references/completion-authorization.md +193 -0
- package/scripts/two-channel-couplings.json +2 -2
- package/typescript/copy-overwrite/.prettierignore +15 -0
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +32 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
// This file is managed by Lisa and IS replaced on each `lisa` run.
|
|
2
|
+
// Do not edit directly — durable changes belong upstream in Lisa.
|
|
3
|
+
|
|
4
|
+
/** Strict shared data contract for accepted-for-completion records. */
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import {
|
|
7
|
+
markdownSection,
|
|
8
|
+
topLevelLines,
|
|
9
|
+
} from "./completion-proof-markdown.mjs";
|
|
10
|
+
import {
|
|
11
|
+
canonicalCompletionBlock,
|
|
12
|
+
usageSpecRemainder,
|
|
13
|
+
} from "./completion-proof-projection.mjs";
|
|
14
|
+
import {
|
|
15
|
+
CompletionProofError,
|
|
16
|
+
requireProof,
|
|
17
|
+
} from "./completion-proof-errors.mjs";
|
|
18
|
+
|
|
19
|
+
const CLI_OUTPUT = "cli-output";
|
|
20
|
+
const TEST_RUN_LOG = "test-run-log";
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
CompletionProofError,
|
|
24
|
+
requireProof,
|
|
25
|
+
} from "./completion-proof-errors.mjs";
|
|
26
|
+
|
|
27
|
+
export const PROOF_MARKER = "[lisa-completion-authorization]";
|
|
28
|
+
export const PROOF_KIND = "lisa-completion-authorization";
|
|
29
|
+
export const MAX_RECORD_BYTES = 2 * 1024 * 1024;
|
|
30
|
+
// Native subjects and slurped listings have an independent byte ceiling. The
|
|
31
|
+
// separate page/row ceilings do not promise that arbitrarily large rows fit.
|
|
32
|
+
export const MAX_NATIVE_JSON_BYTES = 16 * 1024 * 1024;
|
|
33
|
+
export const MAX_ATTACHMENT_BYTES = 64 * 1024 * 1024;
|
|
34
|
+
export const MAX_TOTAL_BYTES = 256 * 1024 * 1024;
|
|
35
|
+
export const KINDS = [
|
|
36
|
+
"screenshot",
|
|
37
|
+
"recording",
|
|
38
|
+
"http-transcript",
|
|
39
|
+
CLI_OUTPUT,
|
|
40
|
+
"log-snippet",
|
|
41
|
+
"db-query-output",
|
|
42
|
+
"perf-trace",
|
|
43
|
+
TEST_RUN_LOG,
|
|
44
|
+
"deploy-log",
|
|
45
|
+
"state-dump",
|
|
46
|
+
];
|
|
47
|
+
export const BOUNDARIES = {
|
|
48
|
+
"code-unit": [TEST_RUN_LOG],
|
|
49
|
+
browser: ["screenshot", "recording"],
|
|
50
|
+
"http-api": ["http-transcript"],
|
|
51
|
+
cli: [CLI_OUTPUT],
|
|
52
|
+
data: ["db-query-output", "state-dump"],
|
|
53
|
+
"deploy-health": ["deploy-log"],
|
|
54
|
+
performance: ["perf-trace"],
|
|
55
|
+
"standards-compat": [CLI_OUTPUT, TEST_RUN_LOG],
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** Hash actual bytes, never a caller's claimed digest. */
|
|
59
|
+
export function sha256(bytes) {
|
|
60
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Unambiguous typed fields used by the producer and reader. */
|
|
64
|
+
export const isObject = value =>
|
|
65
|
+
value !== null && typeof value === "object" && !Array.isArray(value);
|
|
66
|
+
export const isText = value =>
|
|
67
|
+
typeof value === "string" && value.trim().length > 0;
|
|
68
|
+
export const isDigest = value =>
|
|
69
|
+
typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
70
|
+
export const isOid = value =>
|
|
71
|
+
typeof value === "string" && /^[a-f0-9]{40}$/.test(value);
|
|
72
|
+
export const isId = value => Number.isSafeInteger(value) && value > 0;
|
|
73
|
+
export const isTime = value =>
|
|
74
|
+
typeof value === "string" &&
|
|
75
|
+
/(?:Z|\+00:00)$/.test(value) &&
|
|
76
|
+
Number.isFinite(Date.parse(value));
|
|
77
|
+
|
|
78
|
+
/** Remove only exact canonical machine-owned sections, retaining unknown prose. */
|
|
79
|
+
export function primarySpecProjection(body) {
|
|
80
|
+
requireProof(
|
|
81
|
+
typeof body === "string",
|
|
82
|
+
"The primary work-item description is unreadable."
|
|
83
|
+
);
|
|
84
|
+
const headings = topLevelLines(body).filter(row => row.heading);
|
|
85
|
+
const usage = headings.filter(row => row.text === "## Lisa Usage");
|
|
86
|
+
requireProof(
|
|
87
|
+
usage.length <= 1,
|
|
88
|
+
"Duplicate canonical usage sections make the primary specification ambiguous."
|
|
89
|
+
);
|
|
90
|
+
let result = body;
|
|
91
|
+
if (usage.length) {
|
|
92
|
+
const start = usage[0].start;
|
|
93
|
+
const end = headings.find(row => row.start > start)?.start ?? body.length;
|
|
94
|
+
result =
|
|
95
|
+
body.slice(0, start) +
|
|
96
|
+
usageSpecRemainder(body.slice(start, end)) +
|
|
97
|
+
body.slice(end);
|
|
98
|
+
}
|
|
99
|
+
for (const name of ["authorization", "postcondition"]) {
|
|
100
|
+
const start = `<!-- lisa:completion-${name}:start -->`;
|
|
101
|
+
const end = `<!-- lisa:completion-${name}:end -->`;
|
|
102
|
+
const rows = topLevelLines(result);
|
|
103
|
+
const starts = rows.filter(row => row.text === start);
|
|
104
|
+
const ends = rows.filter(row => row.text === end);
|
|
105
|
+
if (!starts.length && !ends.length) continue;
|
|
106
|
+
requireProof(
|
|
107
|
+
starts.length === 1 &&
|
|
108
|
+
ends.length === 1 &&
|
|
109
|
+
ends[0].start > starts[0].start,
|
|
110
|
+
`The canonical completion ${name} block has ambiguous boundaries.`
|
|
111
|
+
);
|
|
112
|
+
if (
|
|
113
|
+
!canonicalCompletionBlock(
|
|
114
|
+
name,
|
|
115
|
+
result.slice(starts[0].end, ends[0].start).trim()
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
continue;
|
|
119
|
+
result = result.slice(0, starts[0].start) + result.slice(ends[0].end);
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Read the maximal code-fence run without letting its suffix repartition it. */
|
|
125
|
+
function claimingFence(line) {
|
|
126
|
+
let start = 0;
|
|
127
|
+
while (start < 3 && line[start] === " ") start += 1;
|
|
128
|
+
const character = line[start];
|
|
129
|
+
if (character !== "`" && character !== "~") return null;
|
|
130
|
+
let end = start;
|
|
131
|
+
while (line[end] === character) end += 1;
|
|
132
|
+
if (end - start < 3) return null;
|
|
133
|
+
const suffix = line.slice(end);
|
|
134
|
+
if (/[\r\n\u2028\u2029]/.test(suffix)) return null;
|
|
135
|
+
return { character, length: end - start, suffix };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Remove comment contents while preserving text on both sides of their ends. */
|
|
139
|
+
function withoutClaimingComments(line, state) {
|
|
140
|
+
let visible = "";
|
|
141
|
+
let offset = 0;
|
|
142
|
+
while (offset < line.length) {
|
|
143
|
+
const boundary = line.indexOf(state.comment ? "-->" : "<!--", offset);
|
|
144
|
+
if (boundary < 0) {
|
|
145
|
+
if (!state.comment) visible += line.slice(offset);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
if (!state.comment) visible += line.slice(offset, boundary);
|
|
149
|
+
offset = boundary + (state.comment ? 3 : 4);
|
|
150
|
+
state.comment = !state.comment;
|
|
151
|
+
}
|
|
152
|
+
return visible;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Fence and comment contents cannot change the other construct's state. */
|
|
156
|
+
function claimingLine(line, state) {
|
|
157
|
+
const marker = claimingFence(line);
|
|
158
|
+
if (state.fence) {
|
|
159
|
+
if (
|
|
160
|
+
marker &&
|
|
161
|
+
marker.character === state.fence.character &&
|
|
162
|
+
marker.length >= state.fence.length &&
|
|
163
|
+
!marker.suffix.trim()
|
|
164
|
+
)
|
|
165
|
+
state.fence = null;
|
|
166
|
+
return "";
|
|
167
|
+
}
|
|
168
|
+
if (!state.comment) {
|
|
169
|
+
if (/^ {4}|^\t/.test(line)) return "";
|
|
170
|
+
if (marker && !(marker.character === "`" && marker.suffix.includes("`"))) {
|
|
171
|
+
state.fence = marker;
|
|
172
|
+
return "";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return withoutClaimingComments(line, state);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Claim discovery keeps closing-line suffixes; full-spec projection is separate. */
|
|
179
|
+
function claimingText(body) {
|
|
180
|
+
const state = { comment: false, fence: null };
|
|
181
|
+
return body
|
|
182
|
+
.split("\n")
|
|
183
|
+
.map(raw =>
|
|
184
|
+
claimingLine(raw.endsWith("\r") ? raw.slice(0, -1) : raw, state)
|
|
185
|
+
)
|
|
186
|
+
.join("\n");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Exact visible claiming markers; examples and other-item refs do not claim. */
|
|
190
|
+
export function localMarkers(body) {
|
|
191
|
+
const text = claimingText(body);
|
|
192
|
+
const matches = [
|
|
193
|
+
...text.matchAll(/\[EVIDENCE:\s*([a-z-]+):\s*([a-z][a-z0-9-]*)\s*\]/g),
|
|
194
|
+
];
|
|
195
|
+
const legacy = [...text.matchAll(/\[SCREENSHOT:\s*([a-z][a-z0-9-]*)\s*\]/g)];
|
|
196
|
+
requireProof(
|
|
197
|
+
matches.length === (text.match(/\[EVIDENCE:/g) ?? []).length,
|
|
198
|
+
"A local evidence declaration is malformed; repair its type and name."
|
|
199
|
+
);
|
|
200
|
+
const markers = [
|
|
201
|
+
...matches.map(row => ({ kind: row[1], name: row[2] })),
|
|
202
|
+
...legacy.map(row => ({ kind: "screenshot", name: row[1] })),
|
|
203
|
+
];
|
|
204
|
+
requireProof(
|
|
205
|
+
markers.every(row => KINDS.includes(row.kind)),
|
|
206
|
+
"A local evidence declaration has an unsupported type."
|
|
207
|
+
);
|
|
208
|
+
requireProof(
|
|
209
|
+
new Set(markers.map(row => row.name)).size === markers.length,
|
|
210
|
+
"Local evidence declarations must have unique names."
|
|
211
|
+
);
|
|
212
|
+
return markers;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Read an exact markdown section without discarding unknown source sections. */
|
|
216
|
+
export function section(body, heading) {
|
|
217
|
+
return markdownSection(body, heading);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Preserve the first whitespace-delimited environment suffix in linear work. */
|
|
221
|
+
function environmentValue(declaration) {
|
|
222
|
+
let whitespaceStart = -1;
|
|
223
|
+
for (let index = 0; index < declaration.length; index += 1) {
|
|
224
|
+
const character = declaration[index];
|
|
225
|
+
if (/\s/.test(character)) {
|
|
226
|
+
if (whitespaceStart < 0) whitespaceStart = index;
|
|
227
|
+
} else {
|
|
228
|
+
if (
|
|
229
|
+
whitespaceStart >= 0 &&
|
|
230
|
+
(character === "-" || character === "—") &&
|
|
231
|
+
/\s/.test(declaration[index + 1] ?? "")
|
|
232
|
+
)
|
|
233
|
+
return declaration.slice(0, whitespaceStart).trim();
|
|
234
|
+
whitespaceStart = -1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return declaration.trim();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Exemptions are explicit declarations, never an absent environment. */
|
|
241
|
+
export function declaredScope(body, environment) {
|
|
242
|
+
const declaration = section(body, "Target Backend Environment");
|
|
243
|
+
const exemption =
|
|
244
|
+
/^None\s*[—-]\s*no runtime behavior change:\s*(doc-only|config-only|type-only)\s*$/i.exec(
|
|
245
|
+
declaration
|
|
246
|
+
);
|
|
247
|
+
if (exemption) return { runtime: false, reason: exemption[1].toLowerCase() };
|
|
248
|
+
const value = environmentValue(
|
|
249
|
+
declaration.replace(/^(Assumption|Inferred|Confirmed):\s*/i, "")
|
|
250
|
+
);
|
|
251
|
+
requireProof(
|
|
252
|
+
value === environment,
|
|
253
|
+
`The primary item does not declare target environment ${environment}; run canonical verification for its actual target.`,
|
|
254
|
+
"pending-proof"
|
|
255
|
+
);
|
|
256
|
+
return { runtime: true, reason: null };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Positive shape validation before any network-selected record is interpreted. */
|
|
260
|
+
export function validateRecordShape(record) {
|
|
261
|
+
requireProof(
|
|
262
|
+
isObject(record) &&
|
|
263
|
+
record.schema_version === 1 &&
|
|
264
|
+
record.kind === PROOF_KIND,
|
|
265
|
+
"The completion record schema is unsupported or malformed."
|
|
266
|
+
);
|
|
267
|
+
requireProof(
|
|
268
|
+
isText(record.record_id) &&
|
|
269
|
+
isId(record.revision) &&
|
|
270
|
+
["accepted-for-completion", "pending", "revoked"].includes(
|
|
271
|
+
record.state
|
|
272
|
+
) &&
|
|
273
|
+
isTime(record.captured_at) &&
|
|
274
|
+
(record.supersedes === null || isDigest(record.supersedes)),
|
|
275
|
+
"The completion record identity, revision, state or capture time is malformed."
|
|
276
|
+
);
|
|
277
|
+
requireProof(
|
|
278
|
+
isObject(record.subject) &&
|
|
279
|
+
["github", "linear"].includes(record.subject.provider) &&
|
|
280
|
+
isText(record.subject.ref) &&
|
|
281
|
+
isText(String(record.subject.native_id ?? "")) &&
|
|
282
|
+
isText(record.subject.scope),
|
|
283
|
+
"The completion record must identify the exact native work item and provider scope."
|
|
284
|
+
);
|
|
285
|
+
requireProof(
|
|
286
|
+
isObject(record.repository) &&
|
|
287
|
+
isId(record.repository.id) &&
|
|
288
|
+
/^[^/\s]+\/[^/\s]+$/.test(record.repository.name ?? ""),
|
|
289
|
+
"The implementation repository identity is malformed."
|
|
290
|
+
);
|
|
291
|
+
requireProof(
|
|
292
|
+
isObject(record.producer) && isId(record.producer.github_actor_id),
|
|
293
|
+
"The completion record has no stable publisher identity."
|
|
294
|
+
);
|
|
295
|
+
requireProof(
|
|
296
|
+
isText(record.environment) &&
|
|
297
|
+
isText(record.branch) &&
|
|
298
|
+
isDigest(record.spec_sha256),
|
|
299
|
+
"The completion record environment, branch or full-spec digest is malformed."
|
|
300
|
+
);
|
|
301
|
+
if (record.state !== "accepted-for-completion") return record;
|
|
302
|
+
const source = record.source;
|
|
303
|
+
requireProof(
|
|
304
|
+
isObject(source) &&
|
|
305
|
+
isId(source.pull_request) &&
|
|
306
|
+
isOid(source.tested_head) &&
|
|
307
|
+
isOid(source.pr_head) &&
|
|
308
|
+
isOid(source.merge_sha) &&
|
|
309
|
+
isOid(source.production_snapshot_sha) &&
|
|
310
|
+
isOid(source.delivered_sha) &&
|
|
311
|
+
Array.isArray(source.declaring_commits) &&
|
|
312
|
+
source.declaring_commits.length > 0 &&
|
|
313
|
+
source.declaring_commits.every(isOid),
|
|
314
|
+
"The accepted record lacks exact primary PR, source, merge and delivered identities."
|
|
315
|
+
);
|
|
316
|
+
requireProof(
|
|
317
|
+
Array.isArray(record.manifest) &&
|
|
318
|
+
Array.isArray(record.verdicts) &&
|
|
319
|
+
record.verdicts.length > 0 &&
|
|
320
|
+
Array.isArray(record.evidence) &&
|
|
321
|
+
Array.isArray(record.requirements) &&
|
|
322
|
+
record.requirements.length > 0,
|
|
323
|
+
"The accepted record lacks an enumerable proof manifest, verdicts or requirement map."
|
|
324
|
+
);
|
|
325
|
+
requireProof(
|
|
326
|
+
[
|
|
327
|
+
record.manifest,
|
|
328
|
+
record.verdicts,
|
|
329
|
+
record.evidence,
|
|
330
|
+
record.requirements,
|
|
331
|
+
].every(rows => rows.every(isObject)),
|
|
332
|
+
"The accepted proof contains malformed attachment or requirement rows."
|
|
333
|
+
);
|
|
334
|
+
const names = [
|
|
335
|
+
"remote",
|
|
336
|
+
"conformance",
|
|
337
|
+
"typed_manifest",
|
|
338
|
+
"delivery",
|
|
339
|
+
"usage",
|
|
340
|
+
"linkage",
|
|
341
|
+
"acceptance",
|
|
342
|
+
];
|
|
343
|
+
requireProof(
|
|
344
|
+
isObject(record.obligations) &&
|
|
345
|
+
Object.keys(record.obligations).sort().join() === names.sort().join(),
|
|
346
|
+
"The accepted record must explicitly account for every completion obligation."
|
|
347
|
+
);
|
|
348
|
+
return record;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Native locator content is discovery, never acceptance or a free-form URL. */
|
|
352
|
+
export function parseLocator(body) {
|
|
353
|
+
if (typeof body !== "string" || !body.startsWith(`${PROOF_MARKER}\n`))
|
|
354
|
+
return null;
|
|
355
|
+
try {
|
|
356
|
+
const value = JSON.parse(body.slice(PROOF_MARKER.length).trim());
|
|
357
|
+
requireProof(
|
|
358
|
+
value.schema_version === 1 &&
|
|
359
|
+
isId(value.asset_id) &&
|
|
360
|
+
isDigest(value.sha256) &&
|
|
361
|
+
isId(value.revision) &&
|
|
362
|
+
isText(value.record_id) &&
|
|
363
|
+
isText(value.repository),
|
|
364
|
+
"The completion locator is malformed."
|
|
365
|
+
);
|
|
366
|
+
return value;
|
|
367
|
+
} catch (error) {
|
|
368
|
+
if (error instanceof CompletionProofError) throw error;
|
|
369
|
+
throw new CompletionProofError(
|
|
370
|
+
"invalid-proof",
|
|
371
|
+
"The completion locator is not readable structured JSON."
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// This file is managed by Lisa and IS replaced on each `lisa` run.
|
|
2
|
+
// Do not edit directly — durable changes belong upstream in Lisa.
|
|
3
|
+
|
|
4
|
+
/** Native source/delivery reconciliation, independent of checkout credentials. */
|
|
5
|
+
import { requireProof, isOid } from "./completion-proof-shape.mjs";
|
|
6
|
+
|
|
7
|
+
const PENDING_PROOF = "pending-proof";
|
|
8
|
+
|
|
9
|
+
/** Full native compare pagination; absence/truncation is never clean ancestry. */
|
|
10
|
+
export function compareSource(transport, base, head) {
|
|
11
|
+
requireProof(
|
|
12
|
+
isOid(base) && isOid(head),
|
|
13
|
+
"The source comparison has an invalid commit identity."
|
|
14
|
+
);
|
|
15
|
+
const pages = transport.json(
|
|
16
|
+
`${transport.root}/compare/${base}...${head}?per_page=100`,
|
|
17
|
+
true
|
|
18
|
+
);
|
|
19
|
+
requireProof(
|
|
20
|
+
pages.length > 0 && pages.every(page => Array.isArray(page.commits)),
|
|
21
|
+
"Native source comparison pages are incomplete."
|
|
22
|
+
);
|
|
23
|
+
const first = pages[0];
|
|
24
|
+
const commits = pages.flatMap(page => page.commits);
|
|
25
|
+
requireProof(
|
|
26
|
+
["ahead", "identical"].includes(first.status) &&
|
|
27
|
+
first.merge_base_commit?.sha === base &&
|
|
28
|
+
Number.isSafeInteger(first.total_commits) &&
|
|
29
|
+
commits.length === first.total_commits &&
|
|
30
|
+
new Set(commits.map(row => row.sha)).size === commits.length,
|
|
31
|
+
"The accepted source is not a completely observed ancestor of the delivered branch."
|
|
32
|
+
);
|
|
33
|
+
return commits;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The primary PR and its declaring commits outrank related timeline links. */
|
|
37
|
+
export function validateSource(record, context, transport) {
|
|
38
|
+
const source = record.source;
|
|
39
|
+
const pr = transport.json(`${transport.root}/pulls/${source.pull_request}`);
|
|
40
|
+
requireProof(
|
|
41
|
+
pr.number === source.pull_request &&
|
|
42
|
+
pr.merged === true &&
|
|
43
|
+
pr.base?.ref === context.branch &&
|
|
44
|
+
pr.merge_commit_sha === source.merge_sha &&
|
|
45
|
+
pr.head?.sha === source.pr_head &&
|
|
46
|
+
context.declares(pr.body ?? "", context.ref),
|
|
47
|
+
"The accepted primary pull request does not declare this work item or match its merged production source."
|
|
48
|
+
);
|
|
49
|
+
if (context.suppliedPrUrl)
|
|
50
|
+
requireProof(
|
|
51
|
+
context.suppliedPrUrl === pr.html_url,
|
|
52
|
+
"The supplied pull request is not the accepted record's primary pull request; related work cannot choose authorization."
|
|
53
|
+
);
|
|
54
|
+
const merge = transport.json(`${transport.root}/commits/${source.merge_sha}`);
|
|
55
|
+
requireProof(
|
|
56
|
+
merge.parents?.some(row => row.sha === source.pr_head),
|
|
57
|
+
"The actual merge did not include the recorded primary PR head."
|
|
58
|
+
);
|
|
59
|
+
if (source.tested_head !== source.pr_head) {
|
|
60
|
+
const tested = transport.json(
|
|
61
|
+
`${transport.root}/commits/${source.tested_head}`
|
|
62
|
+
);
|
|
63
|
+
requireProof(
|
|
64
|
+
tested.parents?.some(row => row.sha === source.pr_head),
|
|
65
|
+
"The tested execution head has no native reconciliation to the primary PR head."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
for (const sha of source.declaring_commits) {
|
|
69
|
+
const commit = transport.json(`${transport.root}/commits/${sha}`);
|
|
70
|
+
requireProof(
|
|
71
|
+
commit.sha === sha &&
|
|
72
|
+
context.declares(commit.commit?.message ?? "", context.ref),
|
|
73
|
+
"A primary source commit does not declare this exact work item."
|
|
74
|
+
);
|
|
75
|
+
compareSource(transport, sha, source.merge_sha);
|
|
76
|
+
}
|
|
77
|
+
compareSource(transport, source.merge_sha, source.delivered_sha);
|
|
78
|
+
const afterDelivery = compareSource(
|
|
79
|
+
transport,
|
|
80
|
+
source.delivered_sha,
|
|
81
|
+
source.production_snapshot_sha
|
|
82
|
+
);
|
|
83
|
+
requireProof(
|
|
84
|
+
!afterDelivery.some(row =>
|
|
85
|
+
context.declares(row.commit?.message ?? "", context.ref)
|
|
86
|
+
),
|
|
87
|
+
"Newer source for this work item precedes the accepted snapshot but has no delivered verification proof.",
|
|
88
|
+
PENDING_PROOF
|
|
89
|
+
);
|
|
90
|
+
return pr;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Later unrelated work is allowed; newer work for this item needs new proof. */
|
|
94
|
+
export function validateFrontier(record, context, transport) {
|
|
95
|
+
const tip = transport.json(
|
|
96
|
+
`${transport.root}/branches/${encodeURIComponent(context.branch)}`
|
|
97
|
+
).commit?.sha;
|
|
98
|
+
const later = compareSource(
|
|
99
|
+
transport,
|
|
100
|
+
record.source.production_snapshot_sha,
|
|
101
|
+
tip
|
|
102
|
+
);
|
|
103
|
+
requireProof(
|
|
104
|
+
!later.some(row =>
|
|
105
|
+
context.declares(row.commit?.message ?? "", context.ref)
|
|
106
|
+
),
|
|
107
|
+
"Newer source for this work item is awaiting fresh remote verification and evidence.",
|
|
108
|
+
PENDING_PROOF
|
|
109
|
+
);
|
|
110
|
+
return tip;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Actual declared delivery mechanism, never a convenient auxiliary green run. */
|
|
114
|
+
export function validateDelivery(record, context, transport) {
|
|
115
|
+
const delivery = record.obligations.delivery;
|
|
116
|
+
if (!delivery.required) return;
|
|
117
|
+
const configured = context.policy.delivery?.[context.environment];
|
|
118
|
+
requireProof(
|
|
119
|
+
configured &&
|
|
120
|
+
["github-actions", "artifact", "external-deployment"].includes(
|
|
121
|
+
configured.mechanism
|
|
122
|
+
),
|
|
123
|
+
"The actual delivery mechanism is not declared in verification.completion.delivery; configure it and run canonical Verify/evidence.",
|
|
124
|
+
PENDING_PROOF
|
|
125
|
+
);
|
|
126
|
+
requireProof(
|
|
127
|
+
delivery.mechanism === configured.mechanism,
|
|
128
|
+
"The accepted delivery mechanism differs from project configuration."
|
|
129
|
+
);
|
|
130
|
+
if (configured.mechanism !== "github-actions") {
|
|
131
|
+
requireProof(
|
|
132
|
+
Array.isArray(delivery.evidence_refs) &&
|
|
133
|
+
delivery.evidence_refs.length > 0 &&
|
|
134
|
+
delivery.verified_empirically === true,
|
|
135
|
+
"The declared artifact/external delivery has no empirically verified reaching record."
|
|
136
|
+
);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
requireProof(
|
|
140
|
+
Array.isArray(delivery.runs) &&
|
|
141
|
+
delivery.runs.length > 0 &&
|
|
142
|
+
typeof configured.workflow_path === "string" &&
|
|
143
|
+
Array.isArray(configured.events),
|
|
144
|
+
"The configured post-merge delivery workflow and run are missing."
|
|
145
|
+
);
|
|
146
|
+
for (const expected of delivery.runs) {
|
|
147
|
+
const run = transport.json(
|
|
148
|
+
`${transport.root}/actions/runs/${expected.run_id}`
|
|
149
|
+
);
|
|
150
|
+
requireProof(
|
|
151
|
+
run.repository?.id === record.repository.id &&
|
|
152
|
+
run.workflow_id === expected.workflow_id &&
|
|
153
|
+
run.path === configured.workflow_path &&
|
|
154
|
+
run.path === expected.workflow_path &&
|
|
155
|
+
configured.events.includes(run.event) &&
|
|
156
|
+
run.event === expected.event &&
|
|
157
|
+
run.head_branch === context.branch &&
|
|
158
|
+
run.head_sha === expected.head_sha &&
|
|
159
|
+
run.run_attempt === expected.attempt,
|
|
160
|
+
"The delivery run is not the configured post-merge workflow for this source and environment."
|
|
161
|
+
);
|
|
162
|
+
requireProof(
|
|
163
|
+
run.status === "completed",
|
|
164
|
+
"The required delivery workflow is still pending; finish canonical Verify/evidence.",
|
|
165
|
+
PENDING_PROOF
|
|
166
|
+
);
|
|
167
|
+
requireProof(
|
|
168
|
+
run.conclusion === "success",
|
|
169
|
+
"The required whole delivery workflow did not succeed."
|
|
170
|
+
);
|
|
171
|
+
compareSource(transport, record.source.merge_sha, run.head_sha);
|
|
172
|
+
compareSource(transport, run.head_sha, record.source.delivered_sha);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -156,15 +156,30 @@ const pin = () => {
|
|
|
156
156
|
export const provisionScanner = async destination => {
|
|
157
157
|
const selected = pin();
|
|
158
158
|
const archiveName = `gitleaks_${VERSION}_${process.platform}_${process.arch}.tar.gz`;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
let response;
|
|
160
|
+
try {
|
|
161
|
+
response = await fetch(
|
|
162
|
+
`https://github.com/gitleaks/gitleaks/releases/download/v${VERSION}/${archiveName}`,
|
|
163
|
+
{ signal: AbortSignal.timeout(120000) }
|
|
164
|
+
);
|
|
165
|
+
} catch {
|
|
166
|
+
throw new HistorySecretError(
|
|
167
|
+
"Pinned scanner download setup failed. Restore access to the official release and retry provisioning."
|
|
168
|
+
);
|
|
169
|
+
}
|
|
163
170
|
if (!response.ok)
|
|
164
171
|
throw new HistorySecretError(
|
|
165
172
|
"Pinned scanner download failed. Restore access to the official release and retry provisioning."
|
|
166
173
|
);
|
|
167
|
-
|
|
174
|
+
let body;
|
|
175
|
+
try {
|
|
176
|
+
body = await response.arrayBuffer();
|
|
177
|
+
} catch {
|
|
178
|
+
throw new HistorySecretError(
|
|
179
|
+
"Pinned scanner archive transfer failed. Restore access to the official release and retry provisioning."
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const bytes = Buffer.from(body);
|
|
168
183
|
if (digest(bytes) !== selected.archive)
|
|
169
184
|
throw new HistorySecretError(
|
|
170
185
|
"Scanner archive checksum mismatch. Discard the download and restore the official pinned release."
|
|
@@ -13,6 +13,21 @@ const COMMON = [
|
|
|
13
13
|
"lisa-test-node.mjs",
|
|
14
14
|
"lib/invoked-as-script.mjs",
|
|
15
15
|
"lib/bounded-spawn.mjs",
|
|
16
|
+
"lib/completion-authorization.mjs",
|
|
17
|
+
"lib/completion-proof-adapters.mjs",
|
|
18
|
+
"lib/completion-proof-conformance.mjs",
|
|
19
|
+
"lib/completion-proof-content.mjs",
|
|
20
|
+
"lib/completion-proof-errors.mjs",
|
|
21
|
+
"lib/completion-proof-github.mjs",
|
|
22
|
+
"lib/completion-proof-markdown.mjs",
|
|
23
|
+
"lib/completion-proof-projection.mjs",
|
|
24
|
+
"lib/completion-proof-publisher.mjs",
|
|
25
|
+
"lib/completion-proof-reader.mjs",
|
|
26
|
+
"lib/completion-proof-shape.mjs",
|
|
27
|
+
"lib/completion-proof-source.mjs",
|
|
28
|
+
"lib/usage-effectiveness.mjs",
|
|
29
|
+
"lib/usage-ledger-integrity.mjs",
|
|
30
|
+
"lib/usage-ledger.mjs",
|
|
16
31
|
"lib/process-tree-runner.mjs",
|
|
17
32
|
"lib/windows-process-job.mjs",
|
|
18
33
|
"lib/windows-process-job.ps1",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// This file is managed by Lisa and IS replaced on each `lisa` run.
|
|
2
|
+
// Do not edit directly — durable changes belong upstream in Lisa.
|
|
3
|
+
|
|
4
|
+
/** Four independent clocks and their provenance for one usage row. */
|
|
5
|
+
export interface EffectivenessObservation {
|
|
6
|
+
readonly schema: 1;
|
|
7
|
+
readonly lisaVersion: string | null;
|
|
8
|
+
readonly workerConfigRevision: string | null;
|
|
9
|
+
readonly workerWallMs: number | null;
|
|
10
|
+
readonly feedbackMs: readonly number[] | null;
|
|
11
|
+
readonly workerSource: string | null;
|
|
12
|
+
readonly attention:
|
|
13
|
+
| readonly { readonly id: string; readonly source: string }[]
|
|
14
|
+
| null;
|
|
15
|
+
readonly readyAt: string | null;
|
|
16
|
+
readonly acceptedAt: string | null;
|
|
17
|
+
readonly lifecycleSources: readonly string[] | null;
|
|
18
|
+
readonly reworkSources: readonly string[] | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function isEvidenceString(value: unknown): value is string;
|
|
21
|
+
export declare function isEvidenceTime(value: unknown): value is string;
|
|
22
|
+
export declare function parseEffectiveness(
|
|
23
|
+
value: unknown
|
|
24
|
+
): EffectivenessObservation;
|
|
25
|
+
export declare function parseEffectivenessTokens(
|
|
26
|
+
section: string
|
|
27
|
+
): ReadonlyMap<string, EffectivenessObservation>;
|