@entrorove/skill 0.1.70 → 0.1.73
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 +15 -0
- package/IDE-EXECUTION.md +4 -0
- package/SKILL.md +3 -2
- package/local-budget-reads.mjs +7 -2
- package/local-budget.mjs +3 -2
- package/local-probe.mjs +16 -7
- package/local-scope-build-data.mjs +73 -0
- package/local-scope-build-facts.mjs +33 -0
- package/local-scope-build-io.mjs +57 -0
- package/local-scope-build-read.mjs +22 -0
- package/local-scope-build-readset.mjs +49 -0
- package/local-scope-files.mjs +20 -7
- package/local-scope-repository.mjs +47 -37
- package/local-scope-signature.mjs +6 -4
- package/local-scope-state.mjs +7 -5
- package/local-scope-uni-build.mjs +69 -119
- package/local-scope-uni-conditional.mjs +8 -6
- package/local-scope-uni-directives.mjs +5 -5
- package/local-scope-uni-expressions.mjs +10 -5
- package/local-scope-workspaces.mjs +3 -3
- package/manifest.json +1 -1
- package/package.json +12 -2
- package/release-source-groups.mjs +46 -0
- package/release-state.json +40 -30
- package/release.mjs +6 -40
- package/releases.json +18 -0
- package/remote-client.mjs +1 -1
- package/remote-transport.mjs +14 -0
- package/scope-amendment-client.mjs +31 -19
- package/scope-amendment-reference.mjs +22 -4
- package/scope-amendment-state.mjs +1 -1
- package/scope-context-client.mjs +17 -8
- package/scope-context-journal.mjs +5 -4
- package/scope-context-observer.mjs +3 -2
- package/scope-context-remote.mjs +5 -5
- package/scope-context-state.mjs +4 -1
- package/scope-context-wire.mjs +9 -1
- package/scope-evidence-local.mjs +52 -0
- package/scope-evidence-remote.mjs +78 -0
- package/scope-evidence-wire.mjs +120 -0
- package/scope-runner-client.mjs +65 -35
- package/scope-runner-journal.mjs +32 -0
|
@@ -12,14 +12,19 @@ export function uniConditionalError(filename, offset, reason, source = '') {
|
|
|
12
12
|
return Object.assign(new Error(`${filename}:${line}:${column}: ${reason}`), {
|
|
13
13
|
code: 'ENTROROVE_IMPORT_UNSUPPORTED', path: filename, line, column, loc: { start: { offset } } });
|
|
14
14
|
}
|
|
15
|
+
export function uniConditionalLimitError(filename, offset, reason, source = '') {
|
|
16
|
+
return Object.assign(uniConditionalError(filename, offset, reason, source), { code: 'ENTROROVE_SCOPE_LIMIT' });
|
|
17
|
+
}
|
|
18
|
+
const limit = (fail, reason) => Object.assign(fail(reason), { code: 'ENTROROVE_SCOPE_LIMIT' });
|
|
15
19
|
export function uniCondition(expression, fail) {
|
|
16
|
-
if (expression.length > 512) throw fail
|
|
20
|
+
if (expression.length > 512) throw limit(fail, 'Conditional expression exceeds its 512-character bound');
|
|
17
21
|
const tokens = expression.match(/uniVersion|[A-Za-z_][A-Za-z0-9_-]*|\d+(?:\.\d+)?|\|\||&&|>=|<=|===|!==|==|!=|[!()<>]|\S/g) ?? [];
|
|
18
|
-
if (!tokens.length
|
|
22
|
+
if (!tokens.length) throw fail('Conditional expression requires a supported expression');
|
|
23
|
+
if (tokens.length > 128) throw limit(fail, 'Conditional expression exceeds its 128-token bound');
|
|
19
24
|
let cursor = 0, depth = 0;
|
|
20
25
|
const versions = [], macros = new Set();
|
|
21
26
|
const atom = () => {
|
|
22
|
-
if (++depth > 24) throw fail
|
|
27
|
+
if (++depth > 24) throw limit(fail, 'Conditional expression exceeds its nesting bound');
|
|
23
28
|
let result; const token = tokens[cursor++];
|
|
24
29
|
if (token === '!') result = { kind: 'not', value: atom() };
|
|
25
30
|
else if (token === '(') { result = disjunction(); if (tokens[cursor++] !== ')') throw fail('Conditional parentheses are not balanced'); }
|
|
@@ -62,7 +67,7 @@ export function evaluateUniCondition(node, context) {
|
|
|
62
67
|
}
|
|
63
68
|
function versionSamples(conditions, fail) {
|
|
64
69
|
const values = [...new Set(conditions.flatMap(condition => condition.versions))].sort((a, b) => a - b);
|
|
65
|
-
if (values.length > 8) throw fail
|
|
70
|
+
if (values.length > 8) throw limit(fail, 'Conditional versions exceed their eight-boundary inspection limit');
|
|
66
71
|
const samples = new Set([0, ...values]);
|
|
67
72
|
for (let index = 0; index < values.length; index++) {
|
|
68
73
|
const previous = values[index - 1] ?? 0;
|
|
@@ -94,7 +99,7 @@ export function uniConditionContexts(conditions, fail) {
|
|
|
94
99
|
const key = conditions.map(condition => evaluateUniCondition(condition.tree, context) ? '1' : '0').join('');
|
|
95
100
|
if (!seen.has(key)) {
|
|
96
101
|
seen.add(key); output.push({ ...context, key });
|
|
97
|
-
if (output.length > 64) throw fail
|
|
102
|
+
if (output.length > 64) throw limit(fail, 'Conditional compilation exceeds its 64-variant inspection bound');
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
return output;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { promises as fs } from 'node:fs';
|
|
3
|
-
import { scopeFail, scopePath,
|
|
3
|
+
import { scopeFail, scopePath, scopeBuildSourceRead, scopeTarget } from './local-scope-files.mjs';
|
|
4
4
|
import { observeScopeDirectory } from './local-scope-read-set.mjs';
|
|
5
5
|
|
|
6
6
|
async function manifest(root, relative, input) {
|
|
7
7
|
try {
|
|
8
|
-
const read = await
|
|
8
|
+
const read = await scopeBuildSourceRead(root, relative, input);
|
|
9
9
|
return { value: JSON.parse(read.content.toString('utf8')), path: relative, sha256: read.sha256 };
|
|
10
10
|
} catch (error) {
|
|
11
11
|
if (error.code === 'ENOENT') return null;
|
|
@@ -20,7 +20,7 @@ async function patterns(root, input) {
|
|
|
20
20
|
if (!Array.isArray(result)) result = result.packages;
|
|
21
21
|
if (!Array.isArray(result) || result.some(pattern => typeof pattern !== 'string')) scopeFail('ENTROROVE_PACKAGE_INVALID', 'workspace patterns must be a literal string array');
|
|
22
22
|
try {
|
|
23
|
-
const read = await
|
|
23
|
+
const read = await scopeBuildSourceRead(root, 'pnpm-workspace.yaml', input); const yaml = read.content.toString('utf8'); let active = false;
|
|
24
24
|
metadata.push({ path: 'pnpm-workspace.yaml', sha256: read.sha256 });
|
|
25
25
|
for (const line of yaml.split('\n')) {
|
|
26
26
|
if (/^packages:\s*$/.test(line)) { active = true; continue; }
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entrorove/skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.73",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"entrorove": "cli.mjs"
|
|
@@ -319,7 +319,17 @@
|
|
|
319
319
|
"local-scope-uni-directives.mjs",
|
|
320
320
|
"local-scope-uni-conditional.mjs",
|
|
321
321
|
"local-scope-uni-build.mjs",
|
|
322
|
-
"local-scope-read-set.mjs"
|
|
322
|
+
"local-scope-read-set.mjs",
|
|
323
|
+
"release-source-groups.mjs",
|
|
324
|
+
"local-scope-build-read.mjs",
|
|
325
|
+
"local-scope-build-io.mjs",
|
|
326
|
+
"local-scope-build-facts.mjs",
|
|
327
|
+
"local-scope-build-data.mjs",
|
|
328
|
+
"local-scope-build-readset.mjs",
|
|
329
|
+
"scope-evidence-wire.mjs",
|
|
330
|
+
"scope-evidence-local.mjs",
|
|
331
|
+
"scope-evidence-remote.mjs",
|
|
332
|
+
"scope-runner-journal.mjs"
|
|
323
333
|
],
|
|
324
334
|
"scripts": {
|
|
325
335
|
"test": "node test/run.mjs",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const swarmSourceFiles = Object.freeze([
|
|
2
|
+
'local-swarm-authority.mjs',
|
|
3
|
+
'local-swarm-baseline.mjs',
|
|
4
|
+
'local-swarm-completion.mjs',
|
|
5
|
+
'local-swarm-contracts.mjs',
|
|
6
|
+
'local-swarm-mutation.mjs',
|
|
7
|
+
'local-swarm-priority.mjs',
|
|
8
|
+
'local-swarm-state.mjs',
|
|
9
|
+
'local-swarm-storage.mjs',
|
|
10
|
+
'local-swarm.mjs',
|
|
11
|
+
])
|
|
12
|
+
export const coordination17SourceFiles = Object.freeze([
|
|
13
|
+
'local-autocoord17-authority.mjs',
|
|
14
|
+
'local-autocoord17-controller.mjs',
|
|
15
|
+
'local-autocoord17-peers.mjs',
|
|
16
|
+
'local-autocoord17-store.mjs',
|
|
17
|
+
'local-autocoord17-tasks.mjs',
|
|
18
|
+
'local-autocoord17-waits.mjs',
|
|
19
|
+
'local-validator-isolation17.mjs',
|
|
20
|
+
'local-calctool-composition17.mjs',
|
|
21
|
+
])
|
|
22
|
+
export const preservedMutationSourceFiles = Object.freeze([
|
|
23
|
+
'local-preserved-mutation-protection.mjs', 'local-preserved-mutation-signer.mjs',
|
|
24
|
+
'local-preserved-mutation-state.mjs', 'local-preserved-mutation-wire.mjs',
|
|
25
|
+
'local-delegated-modify-analysis.mjs', 'mutation-client.mjs', 'cloud-mutation-authority.mjs',
|
|
26
|
+
])
|
|
27
|
+
export const memberContinuationSourceFiles = Object.freeze([
|
|
28
|
+
'connected-cli.mjs',
|
|
29
|
+
'local-approved-process.mjs',
|
|
30
|
+
'local-approved-supervisor.mjs',
|
|
31
|
+
'local-mutation-consumption.mjs',
|
|
32
|
+
'workflow-local-acceptance.mjs',
|
|
33
|
+
'workflow-observation-client.mjs',
|
|
34
|
+
'workflow-observation-connection.mjs',
|
|
35
|
+
'workflow-observation-remote.mjs',
|
|
36
|
+
'workflow-observation-runner.mjs',
|
|
37
|
+
'workflow-observation-state.mjs',
|
|
38
|
+
'workflow-observation-wire.mjs',
|
|
39
|
+
])
|
|
40
|
+
export const scopeEvidenceSourceFiles = Object.freeze([
|
|
41
|
+
'scope-evidence-wire.mjs', 'scope-evidence-local.mjs', 'scope-evidence-remote.mjs', 'scope-runner-journal.mjs',
|
|
42
|
+
])
|
|
43
|
+
export const scopeEvidenceReleaseNote = {
|
|
44
|
+
zh: '将完整范围证据与签名控制分离:四类原 S 证明经有界独立通道上传,紧凑权威绑定不可变摘要与字节数;未知上传仅恢复原 GET,保留原路径、上下文、审批、独立 M 写入和全部旧失败记录。',
|
|
45
|
+
en: 'Separate full scope evidence from signed controls: upload four kinds of original S proof through a bounded data channel and bind immutable hashes and byte counts in compact authorities. Recover uncertain uploads with the original GET only, preserving complete paths, contexts, approvals, separate M writes and prior failures.',
|
|
46
|
+
}
|
package/release-state.json
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.73",
|
|
4
|
+
"digest": "06693e8422b76b4037a70c0be657104b918234d74fa4c5dd1e29a394d5c83e0e",
|
|
5
5
|
"files": {
|
|
6
|
-
"
|
|
7
|
-
"scope-
|
|
6
|
+
"release-source-groups.mjs": "876b8c8bcf459d3b469bf4f2021d4206de5b199add545597a5c8f6dea7385b38",
|
|
7
|
+
"local-scope-build-read.mjs": "361d4b461cfa2c77b4ec22bc59a0a1c78fed2cfb0ea2e05a8da5c2551ecd88ac",
|
|
8
|
+
"local-scope-build-io.mjs": "8af69722738fa094780f9a2dfcddaf12993fc3b936a75c56c4b0d4f90cb20fd1",
|
|
9
|
+
"local-scope-build-facts.mjs": "8b0bd19347d06d1cb66d8cd2d6784103af9d00ea691d7f4acea523d994b874fb",
|
|
10
|
+
"local-scope-build-data.mjs": "b6e272ca4385629326b4517a53408c561272f5f1a01e5b701f17eaa4c5e64b2e",
|
|
11
|
+
"local-scope-build-readset.mjs": "fd1cb1470c54b3902a4612056281746e947cf96d1f5c03a09ea0becbcd79cc45",
|
|
12
|
+
"scope-evidence-wire.mjs": "d283bbfd002b034e1deb539633b4970b430a97065388288ab3398e2bc0285633",
|
|
13
|
+
"scope-evidence-local.mjs": "25b22ba2cc5a17978d2422e290ee015299f05d639b4b4b9551001afefab55c0d",
|
|
14
|
+
"scope-evidence-remote.mjs": "27077bb8238f3d11e6e18453e2ea8a6e096a104bbee5ee43a82b8c099d253c1e",
|
|
15
|
+
"scope-runner-journal.mjs": "cddb2f20a2812e8bcc3268d8ebdd486c22d0c7f5740e958d0b35cd2cc8819f92",
|
|
16
|
+
"scope-context-client.mjs": "115d82022f71396bab137e9af06421a6d0aa9671838f0df64e6aa83d9d7fb039",
|
|
17
|
+
"scope-context-observer.mjs": "25a84339512c1e80711aca53baed20da556fa2ae5d84e83fa95d58dcdca7cf7d",
|
|
8
18
|
"scope-context-observation.mjs": "d92f2fca3c923caa6f0c5c9cc60b4f12bdae212071da64da6692e3e99b251969",
|
|
9
|
-
"scope-context-remote.mjs": "
|
|
10
|
-
"scope-context-state.mjs": "
|
|
11
|
-
"scope-context-wire.mjs": "
|
|
12
|
-
"scope-context-journal.mjs": "
|
|
19
|
+
"scope-context-remote.mjs": "cbcef3fb0b9e1cf11b68f877c227ac9b0c617432221dc6e661bce9bc4667b87a",
|
|
20
|
+
"scope-context-state.mjs": "dc47da57e411ef11677560a767f2e6d50f8a2fae17706b44715d8cd115ffcf8e",
|
|
21
|
+
"scope-context-wire.mjs": "1aa8c86223e54927a209de59d3514393b4c905ee2fc520d49819aec0f1e97162",
|
|
22
|
+
"scope-context-journal.mjs": "0d9aa1315204d3600f62075fe9a4b0b958b21a04c3a50a743eb5dce1eb16e18a",
|
|
13
23
|
"scope-context-release.mjs": "3b6f5d3bf7abe25e1a1edd0521053f4c1b1e3487b7f37d5f7c6080d32bc0c044",
|
|
14
24
|
"cloud-locale.mjs": "0627ac75b98b439563b61ab217aacb55a099c1d0c8ed3b118776d2007c52dd70",
|
|
15
25
|
"cloud-locale.d.mts": "aff4bced9bbac140f73fd0de24681287349389be5750d89d96abe0f8a2167664",
|
|
@@ -76,7 +86,7 @@
|
|
|
76
86
|
"runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
|
|
77
87
|
"snapshot-retention.mjs": "ca46aeb36b1a5a24fe7e967031a71b9a3d33f40cb715d344402cbe0dc9c425cb",
|
|
78
88
|
"snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
|
|
79
|
-
"IDE-EXECUTION.md": "
|
|
89
|
+
"IDE-EXECUTION.md": "3da7cbfafc1a4e7d4059c6fe8e69d14dacd2c72e300fe8e056581faea7f23aeb",
|
|
80
90
|
"REUSE-DISCIPLINE.md": "a2452911c2b50c4762b4a1374f1958059eb03efd59f63e1b50e1650c52b0dc98",
|
|
81
91
|
"install-identity.mjs": "41b8c8d8b3e265d2057a07bf7dc98066c34d6b05c65bf7159ca9609c01ee4646",
|
|
82
92
|
"package-archive.mjs": "e06db8d709db8710bead254ee950b78928088be01c58dcea383beaa5eb574e59",
|
|
@@ -152,13 +162,13 @@
|
|
|
152
162
|
"install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
|
|
153
163
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
154
164
|
"version.mjs": "85284d4cd5e3314b449e6ae124243f96397bcc274817b5983a79cfdd903d46fd",
|
|
155
|
-
"SKILL.md": "
|
|
165
|
+
"SKILL.md": "1c1509924526711c92df7fd0600e4165353cc602663d83b225e083676501bba3",
|
|
156
166
|
"CAPABILITY-MAP.md": "517809bb20750e5de89b2dab5705c902a27fa68cf4f3f392a5d8cf2f19818888",
|
|
157
167
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
158
168
|
"DELIVERY-BOUNDARIES.md": "cb23ce71b2197085c8441ba7c5b6c05fb21f2a954bf66b4d60cfef8b15895b8b",
|
|
159
|
-
"package.json": "
|
|
169
|
+
"package.json": "9a3bb032185a679b7b0146cc6bd1b46ed44e59d16cbab236c5e90fd4f167ad7c",
|
|
160
170
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
161
|
-
"release.mjs": "
|
|
171
|
+
"release.mjs": "c3a5af873db43872e5a6bdc16eb3d859e8d69f6b21bd1c3b754f4a2b6c305360",
|
|
162
172
|
"local-cli.mjs": "058ac9a4653bc12e0d031b72034ebfe6a72b91b9b23353b9fee04881c7d2e098",
|
|
163
173
|
"local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
|
|
164
174
|
"local-execution.mjs": "721ed7d29bbe4ce6d088909cd84ffc440978c3c9eb0946c49a4281ee685fe3aa",
|
|
@@ -181,28 +191,28 @@
|
|
|
181
191
|
"local-chain-results.mjs": "0455f72cad574cfef87c2c6c0928d6432bba7e5dbaff521a2b62a9575299ca10",
|
|
182
192
|
"local-approved-plan.mjs": "c2c88ab4085ff35a1811fe43e9a28699cfc9387eda54bfeafae3e7dd9e8cdb19",
|
|
183
193
|
"local-budget-renewal.mjs": "6b436358066fe33b2f6d871fc90d8e7c551edd6255efd73c0d255d0fd35d5ef8",
|
|
184
|
-
"local-probe.mjs": "
|
|
194
|
+
"local-probe.mjs": "398f5dd4973503ccad280e0224e4f567c9763d21555a0816afdd83c75987d33a",
|
|
185
195
|
"local-budget-grants.mjs": "c5f6542f5d2c3bfe07f3ca5b5bc849bf05d886b06014f720322d530510775d3d",
|
|
186
196
|
"local-budget-handoff.mjs": "85a8f006dad9c0153843c7b7748ee7fcd756fdba159c97c3905d7fe0c4f604af",
|
|
187
197
|
"local-budget-handoff-contracts.mjs": "bb53ebf135ec7ecfbecee858cfb354f03fee9cfb3940fa5d967d45008bf9aac5",
|
|
188
198
|
"local-budget-lock.mjs": "ab0722630e1792843a94a6d01e79422cd578fe9e4d423b59d63e636770381236",
|
|
189
199
|
"local-budget-handoff-completion.mjs": "f8bc45df7c18a064d0b5aac7338131deb709da5193bfe9a1d20300585ea9acb6",
|
|
190
|
-
"local-budget-reads.mjs": "
|
|
200
|
+
"local-budget-reads.mjs": "91eab0bf12a057709a6d5685c5602debe5299a58fbd6624f6e0d0f3876dc918b",
|
|
191
201
|
"local-budget-source-bindings.mjs": "cfe97b257fd2da0dd45f95f5e45be20baa6445d11ac6d03538a0105b4985b8ff",
|
|
192
202
|
"local-budget-store.mjs": "2ae36c977ecd32d81f88e2eaa697ce8c228cb4405ecc5c4169cdda104c8ce138",
|
|
193
203
|
"local-budget-transition.mjs": "3894f05d4b5d4d6e16e3f201ff8902e6311cf6434010262934e0d1251aa8b9f0",
|
|
194
|
-
"local-budget.mjs": "
|
|
204
|
+
"local-budget.mjs": "378348e583d6889a731679e1427e645f56f6cb7c547d48d300e00b9e10050516",
|
|
195
205
|
"local-flow-lifecycle.mjs": "47534e16599002e5e7cf7d3e95195f4d7a364d2b651ec339d8c6c017d71c1b05",
|
|
196
206
|
"local-stage-boundary.mjs": "84c3bb5beab29306274c5ca8a78f19a83ed664ae1b93a8372bb493158b304fe3",
|
|
197
207
|
"local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
|
|
198
208
|
"local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
|
|
199
|
-
"local-scope-files.mjs": "
|
|
200
|
-
"local-scope-repository.mjs": "
|
|
209
|
+
"local-scope-files.mjs": "b8c98b8ca8bb4953f3d2d9ae1fa71b2a54286032c9dd660d3061b584e77778cb",
|
|
210
|
+
"local-scope-repository.mjs": "fe5187824744233b9fce59d7b964a3f24349a3fe31415181654a1b3a70e8de9c",
|
|
201
211
|
"local-scope-read-set.mjs": "a5137d2e7ecffe669143fb51f0f3fba7526a881b512269858ea1e3504d9a50b2",
|
|
202
|
-
"local-scope-uni-expressions.mjs": "
|
|
203
|
-
"local-scope-uni-directives.mjs": "
|
|
204
|
-
"local-scope-uni-conditional.mjs": "
|
|
205
|
-
"local-scope-uni-build.mjs": "
|
|
212
|
+
"local-scope-uni-expressions.mjs": "626247c87a4fd5f6162e548aa907d3f983d5a77d341e640b6f42a539f0c84405",
|
|
213
|
+
"local-scope-uni-directives.mjs": "e546be317962e30a3547aea376db9a7b8d7641055daf9e3dce4a9ef55cd872af",
|
|
214
|
+
"local-scope-uni-conditional.mjs": "f143a142af069279fcac0a01206744ce323c8dfc4496c2f6cc1f0b229c4e5f5e",
|
|
215
|
+
"local-scope-uni-build.mjs": "1dafd4802859b4c53504395f6186b003ee2657fc16f373ca2637e438e4d1b9e5",
|
|
206
216
|
"local-scope-create-require.mjs": "6b6a209bfcad8fe1398e99c5c8cc3af189c120b9c38e244a73dd1a99c3d91295",
|
|
207
217
|
"local-scope-require-resolution.mjs": "b24596462c8776cbefa6f0a74749d665aa928d1643c68d44798eb93e2dd5ad42",
|
|
208
218
|
"local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
|
|
@@ -228,23 +238,23 @@
|
|
|
228
238
|
"local-budget-git-system-attributes.mjs": "367a4e5a88490c4d4c3717bc893a271970fe70d7705f0c1c72d6f76a442d5d21",
|
|
229
239
|
"runtime/git-native-linux-v1.mjs": "cf5cb91426a105e62c0f07a8a230dec592dba46f85a3f708b4c4e8cfcd1126c6",
|
|
230
240
|
"runtime/git-native-darwin-v1.mjs": "f88aab72dc86f94eb1115784872957cb8ed0f74205ae70e1ecd1939e7790e310",
|
|
231
|
-
"local-scope-signature.mjs": "
|
|
241
|
+
"local-scope-signature.mjs": "3804b84d5ddca5c1ac991b31151d84cddc508517eff7500351ba1bcffdf3c672",
|
|
232
242
|
"local-scope-config-imports.mjs": "a399407227bbdd14468633bb6d25586df7c6a30a1ef0d1a80ab7c7b499d3fadf",
|
|
233
243
|
"local-scope-config-extends.mjs": "3ab4150b846b247e9e0851221123f220c5574699af651830e751f026ab33659e",
|
|
234
244
|
"local-scope-snapshot.mjs": "c0f851470b98863a1d187825ed61ee6072d1c057b178fdc85ae29af02a3b250f",
|
|
235
|
-
"local-scope-state.mjs": "
|
|
236
|
-
"local-scope-workspaces.mjs": "
|
|
245
|
+
"local-scope-state.mjs": "7a6d275d6267a4d0bb55582e1bcc7654c502ecba9221b84b2149a98f0ee7518f",
|
|
246
|
+
"local-scope-workspaces.mjs": "8a75ce7b6639b5682370b5738c5c2a90408e3130729608e008f03053cd50351f",
|
|
237
247
|
"local-task-routing.mjs": "6e2e506b2fb0e2e8d8c5147d7df32849b57a4e94a23634f01a355d45735858e4",
|
|
238
|
-
"remote-client.mjs": "
|
|
248
|
+
"remote-client.mjs": "6cf62706f8ac5f69368d951cd697f912040b2e58ac480dfb151bddb18b09b20d",
|
|
239
249
|
"cloud-task-client.mjs": "f9085c5e6af6f179282670d2e872b85bfabac2657d3d232b1246dc23f5a6ccdd",
|
|
240
|
-
"scope-runner-client.mjs": "
|
|
241
|
-
"scope-amendment-client.mjs": "
|
|
242
|
-
"scope-amendment-state.mjs": "
|
|
250
|
+
"scope-runner-client.mjs": "cc4fe202d5f777a0ec4c46f9b41a18aaf024c0d2e769a0b26bc6505f2f69f460",
|
|
251
|
+
"scope-amendment-client.mjs": "022ec88ecf12a98dd6e9e7915158fc9111cdadfda12cf714804948c8027a57d3",
|
|
252
|
+
"scope-amendment-state.mjs": "9f88cc7029f62eed3b1a0cc1c03b6a98c5713b467a2112278692de90c973b2be",
|
|
243
253
|
"scope-amendment-wire.mjs": "3c4823e23bbdf330616bb675f07f9fcad7423266bd50b92e1134d226060e9b83",
|
|
244
254
|
"scope-amendment-remote.mjs": "15a0b3126248f3101a52e3d7742f9a816dd3d8e58f21bac33e99e810e86cc4fd",
|
|
245
255
|
"scope-amendment-observer.mjs": "de796f2aca2f3bc7f33ae3323b07d98096c0f16b1ffde70e3055610d70d18020",
|
|
246
256
|
"scope-amendment-mutation.mjs": "fa24191df290efad29d41eca3d1a081981fefde02b7dc4a11c75c6118a69106e",
|
|
247
|
-
"scope-amendment-reference.mjs": "
|
|
257
|
+
"scope-amendment-reference.mjs": "dc1768131beb7db224dd2ff8522dbf6361f73e01f466c9334cdfa24118720078",
|
|
248
258
|
"native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
|
|
249
259
|
"native-notification.mjs": "8859a26c6f13d222711f763acf49ed8546b3306cf71f990643ac31a5ccaf1ba1",
|
|
250
260
|
"local-peer-status.mjs": "a971bcc69d60bb32b875ca5bb4297d948631d5d2821b812c279613ea059a8b4f",
|
|
@@ -255,7 +265,7 @@
|
|
|
255
265
|
"task-entry-client.mjs": "940fb068afe28a2a34fe96e285e149afdd9ba79649c0c65cde37ec4ed71ae39d",
|
|
256
266
|
"task-identity.mjs": "e0e6cf1f48bfa5ee3c5cb86a3c21adfce6d66b4220f4a164ca099263c7a09fb4",
|
|
257
267
|
"task-identity.d.mts": "55472e1ffc81b9d5e5c5bd56c0bf1d18ecde03ee5170a58a15ce9caf222d8761",
|
|
258
|
-
"remote-transport.mjs": "
|
|
268
|
+
"remote-transport.mjs": "e9ecb3b9cd4d3bcc7abe1f7097069a07a15319ca0d5641fee752d094eb039194",
|
|
259
269
|
"local-credential.mjs": "2a302a7f67b5ea8dc73453fc96ab33db349b59ca11fa9456e48ca1d9669d877c",
|
|
260
270
|
"local-invocations.mjs": "f6ac4c41c1a5ec34de358c4cca210ca8e403b3a913150a43bb55ec9be55d9998",
|
|
261
271
|
"local-task-handoff-fence.mjs": "5532a359ee29b885f7ce0cf7178f76dba0fc9245bdd92ef460982275baf0d557",
|
package/release.mjs
CHANGED
|
@@ -9,47 +9,10 @@ import { fileURLToPath } from 'node:url'
|
|
|
9
9
|
import { chainReleaseLabels } from './local-chain-release-labels.mjs'
|
|
10
10
|
|
|
11
11
|
const directory = path.dirname(fileURLToPath(import.meta.url))
|
|
12
|
-
|
|
13
|
-
'local-swarm-authority.mjs',
|
|
14
|
-
'local-swarm-baseline.mjs',
|
|
15
|
-
'local-swarm-completion.mjs',
|
|
16
|
-
'local-swarm-contracts.mjs',
|
|
17
|
-
'local-swarm-mutation.mjs',
|
|
18
|
-
'local-swarm-priority.mjs',
|
|
19
|
-
'local-swarm-state.mjs',
|
|
20
|
-
'local-swarm-storage.mjs',
|
|
21
|
-
'local-swarm.mjs',
|
|
22
|
-
])
|
|
23
|
-
const coordination17SourceFiles = Object.freeze([
|
|
24
|
-
'local-autocoord17-authority.mjs',
|
|
25
|
-
'local-autocoord17-controller.mjs',
|
|
26
|
-
'local-autocoord17-peers.mjs',
|
|
27
|
-
'local-autocoord17-store.mjs',
|
|
28
|
-
'local-autocoord17-tasks.mjs',
|
|
29
|
-
'local-autocoord17-waits.mjs',
|
|
30
|
-
'local-validator-isolation17.mjs',
|
|
31
|
-
'local-calctool-composition17.mjs',
|
|
32
|
-
])
|
|
33
|
-
const preservedMutationSourceFiles = Object.freeze([
|
|
34
|
-
'local-preserved-mutation-protection.mjs', 'local-preserved-mutation-signer.mjs',
|
|
35
|
-
'local-preserved-mutation-state.mjs', 'local-preserved-mutation-wire.mjs',
|
|
36
|
-
'local-delegated-modify-analysis.mjs', 'mutation-client.mjs', 'cloud-mutation-authority.mjs',
|
|
37
|
-
])
|
|
38
|
-
const memberContinuationSourceFiles = Object.freeze([
|
|
39
|
-
'connected-cli.mjs',
|
|
40
|
-
'local-approved-process.mjs',
|
|
41
|
-
'local-approved-supervisor.mjs',
|
|
42
|
-
'local-mutation-consumption.mjs',
|
|
43
|
-
'workflow-local-acceptance.mjs',
|
|
44
|
-
'workflow-observation-client.mjs',
|
|
45
|
-
'workflow-observation-connection.mjs',
|
|
46
|
-
'workflow-observation-remote.mjs',
|
|
47
|
-
'workflow-observation-runner.mjs',
|
|
48
|
-
'workflow-observation-state.mjs',
|
|
49
|
-
'workflow-observation-wire.mjs',
|
|
50
|
-
])
|
|
12
|
+
import { swarmSourceFiles, coordination17SourceFiles, preservedMutationSourceFiles, memberContinuationSourceFiles, scopeEvidenceSourceFiles, scopeEvidenceReleaseNote } from './release-source-groups.mjs'
|
|
51
13
|
const sourceFiles = [
|
|
52
|
-
|
|
14
|
+
'release-source-groups.mjs', 'local-scope-build-read.mjs', 'local-scope-build-io.mjs', 'local-scope-build-facts.mjs', 'local-scope-build-data.mjs', 'local-scope-build-readset.mjs',
|
|
15
|
+
...scopeEvidenceSourceFiles, ...SCOPE_CONTEXT_SOURCE_FILES, 'cloud-locale.mjs', 'cloud-locale.d.mts', 'cloud-task-images.mjs', 'model-images.mjs', 'model-images.d.mts', 'cli-input.mjs',
|
|
53
16
|
'scope-amendment-retirement.mjs', 'scope-amendment-consumption.mjs', 'mutation-connection-state.mjs', 'mutation-challenge-refresh.mjs',
|
|
54
17
|
'local-scope-font.mjs', 'local-scope-zip.mjs', 'member-producer-repair-authority.mjs',
|
|
55
18
|
'local-mutation-completion-evidence.mjs', 'local-mutation-environment-observation.mjs', 'local-mutation-finder-observation.mjs', 'local-finder-store.mjs', 'local-finder-plist.mjs',
|
|
@@ -310,6 +273,7 @@ function releaseNote(changed) {
|
|
|
310
273
|
if (suppliedZh && suppliedEn) return {
|
|
311
274
|
zh: suppliedZh.replaceAll(/\s+/g, ' '), en: suppliedEn.replaceAll(/\s+/g, ' '),
|
|
312
275
|
}
|
|
276
|
+
if (changed.some(file => scopeEvidenceSourceFiles.includes(file))) return scopeEvidenceReleaseNote
|
|
313
277
|
if (changed.some(file => SCOPE_CONTEXT_SOURCE_FILES.includes(file))) return scopeContextReleaseNote
|
|
314
278
|
if (changed.some(file => file.startsWith('scope-amendment-'))) return {
|
|
315
279
|
zh: '新增同一任务的精确范围补正:原账号审核文件哈希与写入/只读角色,原S签名真实事实并重评原合同;计划、写入和结算绑定不可变范围修订,改后刷新保留原M消费证据与失败历史。',
|
|
@@ -342,6 +306,8 @@ const archguardReleaseLabels = {
|
|
|
342
306
|
}
|
|
343
307
|
function releaseLabels() {
|
|
344
308
|
return withFinalGate16ReleaseLabels({ ...designGateReleaseLabels, ...reuseDisciplineReleaseLabels, ...calctoolReleaseLabels, ...mutationReleaseLabels, ...swarmReleaseLabels, ...coordination17ReleaseLabels, ...nativeReadReleaseLabels, ...feedbackReleaseLabels, ...invocationReleaseLabels, ...chainReleaseLabels, ...taskEntryReleaseLabels, ...archguardReleaseLabels,
|
|
309
|
+
...Object.fromEntries(['local-scope-build-read.mjs', 'local-scope-build-io.mjs', 'local-scope-build-facts.mjs', 'local-scope-build-data.mjs', 'local-scope-build-readset.mjs', 'local-scope-uni-build.mjs', 'local-scope-uni-expressions.mjs', 'local-scope-uni-directives.mjs', 'local-scope-uni-conditional.mjs'].map(name => [name, { zh: '源码事实与未知构建行为分离', en: 'raw source facts and opaque build observation' }])),
|
|
310
|
+
'release-source-groups.mjs': { zh: '自动版本源文件清单', en: 'automatic version source inventory' },
|
|
345
311
|
...Object.fromEntries(['cloud-task-images.mjs', 'model-images.mjs', 'model-images.d.mts', 'cli-input.mjs'].map(name => [name, { zh: '受限图片输入通道', en: 'bounded image input channel' }])),
|
|
346
312
|
...Object.fromEntries(['scope-amendment-retirement.mjs', 'scope-amendment-consumption.mjs', 'mutation-connection-state.mjs', 'mutation-challenge-refresh.mjs', 'member-producer-repair-authority.mjs'].map(name => [name, { zh: '原授权恢复与请求生命周期', en: 'original-authority recovery and request lifecycle' }])),
|
|
347
313
|
...Object.fromEntries(['local-scope-font.mjs', 'local-scope-zip.mjs'].map(name => [name, { zh: '字体与 ZIP 完整结构核验', en: 'font and ZIP structural verification' }])),
|
package/releases.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.73",
|
|
4
|
+
"date": "2026-10-20",
|
|
5
|
+
"zh": "修复通用范围连接在长时间扫描后的签名期限绑定:原 S 证明到期时间不晚于原云端挑战,保留原随机数、完整范围、独立验签和失败历史;已过期挑战仍明确拒绝。",
|
|
6
|
+
"en": "Bind ordinary scope signatures to their original cloud deadline after long scans. The original S proof expires no later than its challenge, preserving the nonce, complete scope, independent signatures and failure history; expired challenges still reject explicitly."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.72",
|
|
10
|
+
"date": "2026-10-20",
|
|
11
|
+
"zh": "将完整范围证据与签名控制分离:四类原 S 证明经有界独立通道上传,紧凑权威绑定不可变摘要与字节数;未知上传仅恢复原 GET,保留原路径、上下文、审批、独立 M 写入和全部旧失败记录。",
|
|
12
|
+
"en": "Separate full scope evidence from signed controls: upload four kinds of original S proof through a bounded data channel and bind immutable hashes and byte counts in compact authorities. Recover uncertain uploads with the original GET only, preserving complete paths, contexts, approvals, separate M writes and prior failures."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.1.71",
|
|
16
|
+
"date": "2026-10-20",
|
|
17
|
+
"zh": "通用分离源码依赖事实与未知构建行为:动态配置、宏及加载器保留真实哈希与只读来源,不执行项目代码,不把构建未知标为完整。原审批与独立 S/M 签名仅允许已知源码的非结构修改;隐私文件、路径、资源预算、未知目标及配置漂移继续明确拒绝,实际构建与测试仍需原流程验收。",
|
|
18
|
+
"en": "Separate raw source dependency facts from opaque build behavior across projects. Preserve actual hashes and read-only origins for dynamic configuration, macros and loaders without executing project code or claiming compiled completeness. Original approvals and separate S/M signatures permit only known-source nonstructural modifications; private files, unsafe paths, resource budgets, unknown targets and configuration drift remain explicit refusals. Actual builds and tests still require original-flow acceptance."
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"version": "0.1.70",
|
|
4
22
|
"date": "2026-10-20",
|
package/remote-client.mjs
CHANGED
|
@@ -39,7 +39,7 @@ export function buildInvocation(operation, input) {
|
|
|
39
39
|
'message-status', 'message-delivery-start', 'message-delivery-report', 'message-resolve', 'message-complete',
|
|
40
40
|
'handoff-prepare', 'handoff-release', 'handoff-claim', 'handoff-status', 'handoff-resume', 'handoff-execution-authority', 'mutation-snapshot-challenge', 'mutation-pass-issue', 'mutation-pass-settle',
|
|
41
41
|
'member-observation-admit', 'member-observation-report', 'member-observation-status',
|
|
42
|
-
'scope-runner-prepare', 'scope-runner-register', 'scope-runner-challenge', 'scope-runner-attest',
|
|
42
|
+
'scope-runner-prepare', 'scope-runner-register', 'scope-runner-challenge', 'scope-runner-attest', 'scope-evidence-prepare',
|
|
43
43
|
'scope-runner-context-review', 'scope-runner-context-status', 'scope-runner-context-challenge', 'scope-runner-context-apply',
|
|
44
44
|
'start', 'continue'].includes(operation)) throw new Error('Invalid entrorove operation');
|
|
45
45
|
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Input must be a JSON object');
|
package/remote-transport.mjs
CHANGED
|
@@ -108,6 +108,20 @@ export async function requestTransport(origin, pathname, options = {}) {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// Evidence is a separate bounded data channel. A persisted upload reservation
|
|
112
|
+
// is attempted once; every uncertain outcome must use its original GET.
|
|
113
|
+
export async function putScopeEvidence(origin, uploadId, body, headers = {}) {
|
|
114
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/.test(uploadId ?? '') || !Buffer.isBuffer(body)
|
|
115
|
+
|| body.length < 1 || body.length > 16_000_000) throw new Error('Invalid Entrorove scope evidence upload');
|
|
116
|
+
const url = new URL(`/api/skill/evidence/${uploadId}`, trustedOrigin(origin));
|
|
117
|
+
const response = await attempt(url, { method: 'PUT', body, timeoutMs: 30_000,
|
|
118
|
+
headers: { ...headers, 'content-type': 'application/json; charset=utf-8', 'content-length': body.length, 'accept-encoding': 'gzip' } });
|
|
119
|
+
if (response.status >= 300 && response.status < 400) {
|
|
120
|
+
throw Object.assign(new Error('Entrorove API redirects are refused'), { code: 'ENTROROVE_REDIRECT', established: true });
|
|
121
|
+
}
|
|
122
|
+
return { ...response, attempts: 1 };
|
|
123
|
+
}
|
|
124
|
+
|
|
111
125
|
export function parseTransportResponse(response, label = 'Entrorove') {
|
|
112
126
|
try { return JSON.parse(response.body); }
|
|
113
127
|
catch { throw Object.assign(new Error(`Invalid ${label} response`), { code: 'ENTROROVE_RESPONSE_INVALID' }); }
|
|
@@ -9,6 +9,7 @@ import { scopeAmendmentLocation, readScopeAmendmentState, saveScopeAmendmentStat
|
|
|
9
9
|
import { amendmentRemote, scopeAmendmentStatus } from './scope-amendment-remote.mjs';
|
|
10
10
|
import { observeScopeAmendment } from './scope-amendment-observer.mjs';
|
|
11
11
|
import { retainScopeAmendmentReference } from './scope-amendment-reference.mjs';
|
|
12
|
+
import { saveLocalScopeEvidence, ensureScopeEvidence, validateAppliedEvidence } from './scope-evidence-remote.mjs';
|
|
12
13
|
|
|
13
14
|
const schemaVersion = 'entrorove.scope-amendment-connection/1.0';
|
|
14
15
|
function validateProposal(status, input) {
|
|
@@ -17,8 +18,9 @@ function validateProposal(status, input) {
|
|
|
17
18
|
|| !['pending', 'approved', 'declined'].includes(proposal.approval)) amendmentFail('Current account has no matching original scope proposal');
|
|
18
19
|
return proposal;
|
|
19
20
|
}
|
|
20
|
-
function validateApplied(output, state, location) {
|
|
21
|
-
const effective = output.effectiveAuthority,
|
|
21
|
+
async function validateApplied(output, state, location) {
|
|
22
|
+
const effective = output.effectiveAuthority, version = effective?.record?.schemaVersion === 'entrorove.scope-revision-authority/2.0' ? '2.0' : '1.0';
|
|
23
|
+
const record = scopeRevisionAuthority(effective?.record, `entrorove.scope-revision-authority/${version}`);
|
|
22
24
|
const challenge = scopeAmendmentChallenge(state.challenged.challenge, location, { allowExpired: true }), refresh = challenge.purpose === 'scope-revision-refresh';
|
|
23
25
|
if (output.status !== 'succeeded' || output.grantsExecutionAuthority !== false || output.claimsCompletion !== false
|
|
24
26
|
|| output.scopeRevisionDigest !== sha256(canonical(record)) || effective.revisionDigest !== output.scopeRevisionDigest
|
|
@@ -30,21 +32,26 @@ function validateApplied(output, state, location) {
|
|
|
30
32
|
|| canonical(record.files.map(file => ({ ...file, sha256: null }))) !== canonical(challenge.files.map(file => ({ ...file, sha256: null })))) {
|
|
31
33
|
amendmentFail('Applied scope amendment lost its signed original authority or exact roles');
|
|
32
34
|
}
|
|
33
|
-
const
|
|
35
|
+
const factVersion = effective?.fact?.schemaVersion === 'entrorove.scope-revision-facts/2.0' ? '2.0' : '1.0';
|
|
36
|
+
const fact = refresh ? scopeRevisionAuthority(effective.fact, `entrorove.scope-revision-facts/${factVersion}`) : record;
|
|
37
|
+
const compact = fact.schemaVersion.endsWith('/2.0');
|
|
38
|
+
const attestation = compact ? await validateAppliedEvidence(fact, state, location, challenge,
|
|
39
|
+
refresh ? 'scope-refresh' : 'scope-revision') : state.attestation;
|
|
34
40
|
if (refresh && (fact.scopeRevisionDigest !== output.scopeRevisionDigest || fact.factRevision !== challenge.expectedFactRevision
|
|
35
41
|
|| ['flowId', 'ownerId', 'taskDigest', 'chainDigest'].some(field => fact[field] !== challenge[field]))
|
|
36
|
-
|| canonical(fact.candidateAttestation) !== canonical(
|
|
37
|
-
|| fact.scope?.attestationDigest !== sha256(canonical(
|
|
42
|
+
|| !compact && canonical(fact.candidateAttestation) !== canonical(attestation)
|
|
43
|
+
|| fact.scope?.attestationDigest !== sha256(canonical(attestation.scopeAttestation))
|
|
44
|
+
|| compact && effective.candidateAttestationDigest !== sha256(canonical(attestation))
|
|
38
45
|
|| effective.factRevision !== (refresh ? fact.factRevision : 0) || output.factRevision !== effective.factRevision) {
|
|
39
46
|
amendmentFail('Applied scope proof differs from this exact actual signed candidate');
|
|
40
47
|
}
|
|
41
48
|
return { schemaVersion, status: 'succeeded', flowId: challenge.flowId, proposalId: challenge.proposalId,
|
|
42
49
|
proposalDigest: challenge.proposalDigest, scopeRevisionDigest: output.scopeRevisionDigest, revision: output.revision,
|
|
43
50
|
factRevision: effective.factRevision, grantsExecutionAuthority: false, claimsCompletion: false,
|
|
44
|
-
...(refresh &&
|
|
51
|
+
...(refresh && attestation.memberMutation ? { localAction: {
|
|
45
52
|
command: 'npx @entrorove/skill mutation-settle <absolute repositoryRoot>', input: {
|
|
46
|
-
flowId: challenge.flowId, taskId:
|
|
47
|
-
stepId:
|
|
53
|
+
flowId: challenge.flowId, taskId: attestation.memberMutation.consumptionReceipt.taskId,
|
|
54
|
+
stepId: attestation.memberMutation.consumptionReceipt.stepId, gatePassPath: location.identity.gatePassPath } } } : {}),
|
|
48
55
|
nextStep: output.nextStep, ...(state.feedback ? { feedback: state.feedback } : {}) };
|
|
49
56
|
}
|
|
50
57
|
async function archiveAttempt(location, state) {
|
|
@@ -56,23 +63,28 @@ async function archiveAttempt(location, state) {
|
|
|
56
63
|
await saveScopeAmendmentState(location, state);
|
|
57
64
|
}
|
|
58
65
|
async function finish(location, state, dependencies) {
|
|
59
|
-
if (!state.
|
|
60
|
-
state.attestation
|
|
61
|
-
|
|
66
|
+
if (!state.evidenceDescriptor && !state.applied) {
|
|
67
|
+
const attestation = state.attestation ?? await observeScopeAmendment(location, state);
|
|
68
|
+
const challenge = scopeAmendmentChallenge(state.challenged.challenge, location, { allowExpired: true });
|
|
69
|
+
await saveLocalScopeEvidence(attestation, challenge.purpose === 'scope-revision-refresh' ? 'scope-refresh' : 'scope-revision',
|
|
70
|
+
challenge, state, location, saveScopeAmendmentState);
|
|
71
|
+
}
|
|
72
|
+
if (!state.applied) {
|
|
73
|
+
const attestationRef = await ensureScopeEvidence(state, location, dependencies, state.challenged.challenge, saveScopeAmendmentState);
|
|
74
|
+
await amendmentRemote('applied', 'workflow-scope-apply', { proposalId: location.identity.proposalId,
|
|
75
|
+
proposalDigest: location.identity.proposalDigest, attestationRef }, state, location, dependencies);
|
|
62
76
|
}
|
|
63
|
-
const applied = state.applied
|
|
64
|
-
proposalId: location.identity.proposalId, proposalDigest: location.identity.proposalDigest,
|
|
65
|
-
attestation: state.attestation }, state, location, dependencies);
|
|
66
|
-
const result = validateApplied(applied, state, location);
|
|
77
|
+
const applied = state.applied, result = await validateApplied(applied, state, location);
|
|
67
78
|
await retainScopeAmendmentReference(location, applied); return result;
|
|
68
79
|
}
|
|
69
80
|
async function amend(location, dependencies) {
|
|
70
81
|
const state = await readScopeAmendmentState(location);
|
|
82
|
+
if (state.evidencePending || state.pending?.operation === 'scope-evidence-prepare') return finish(location, state, dependencies);
|
|
71
83
|
if (state.pending) {
|
|
72
84
|
const pending = state.pending;
|
|
73
85
|
await amendmentRemote(pending.stage, pending.input.operation, pending.input.payload, state, location, dependencies);
|
|
74
86
|
if (pending.stage === 'applied') {
|
|
75
|
-
const result = validateApplied(state.applied, state, location);
|
|
87
|
+
const result = await validateApplied(state.applied, state, location);
|
|
76
88
|
await retainScopeAmendmentReference(location, state.applied); return result;
|
|
77
89
|
}
|
|
78
90
|
return finish(location, state, dependencies);
|
|
@@ -95,7 +107,7 @@ async function amend(location, dependencies) {
|
|
|
95
107
|
const challenge = scopeAmendmentChallenge(challenged.challenge, location);
|
|
96
108
|
if (status.effective ? challenge.purpose !== 'scope-revision-refresh'
|
|
97
109
|
|| challenge.authorityRevisionDigest !== status.effective.revisionDigest || challenge.expectedFactRevision !== status.effective.factRevision + 1
|
|
98
|
-
|| challenge.currentScopeArtifactDigest !== sha256(canonical(status.effective.scope))
|
|
110
|
+
|| challenge.currentScopeArtifactDigest !== (status.effective.scopeArtifactDigest ?? sha256(canonical(status.effective.scope)))
|
|
99
111
|
: challenge.purpose !== 'scope-revision' || challenge.expectedRevision !== proposal.expectedRevision
|
|
100
112
|
|| challenge.previousDigest !== proposal.previousDigest) amendmentFail('Scope amendment challenge has a different original authority head');
|
|
101
113
|
return finish(location, state, dependencies);
|
|
@@ -115,9 +127,9 @@ export async function runScopeAmend(repositoryRoot, input, dependencies) {
|
|
|
115
127
|
message: ['ENTROROVE_SCOPE_AMENDMENT_BINDING', 'ENTROROVE_SCOPE_AMENDMENT_STATE', 'ENTROROVE_SCOPE_AMENDMENT_UNKNOWN',
|
|
116
128
|
'ENTROROVE_SCOPE_AMENDMENT_NOT_SENT', 'ENTROROVE_SCOPE_AMENDMENT_MUTATION_PENDING'].includes(error?.code) ? error.message
|
|
117
129
|
: 'Scope amendment stopped; preserve the original proposal, signer, journal and actual evidence.',
|
|
118
|
-
...(requestId ? { requestId } : {}), ...(error?.output ? { output: error.output } : {}),
|
|
130
|
+
...(requestId ? { requestId } : {}), ...(error?.uploadId ? { uploadId: error.uploadId } : {}), ...(error?.output ? { output: error.output } : {}),
|
|
119
131
|
...(error?.feedback ? { feedback: error.feedback } : {}),
|
|
120
|
-
...(error?.outcomeUnknown ? { outcomeUnknown: true, nextAction: { operation: 'scope-amend', requestId,
|
|
132
|
+
...(error?.outcomeUnknown ? { outcomeUnknown: true, nextAction: { operation: 'scope-amend', ...(requestId ? { requestId } : { uploadId: error.uploadId }),
|
|
121
133
|
method: 'GET', reuseOriginalInput: true, repeatPost: false } } : {}) };
|
|
122
134
|
}
|
|
123
135
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { canonical, sha256 } from './local-integrity.mjs';
|
|
3
|
-
import { mutationHome14, privateMutationDirectory14, readMutationJson14, atomicMutationJson14 } from './local-mutation-files.mjs';
|
|
3
|
+
import { mutationHome14, mutationFile14, privateMutationDirectory14, readMutationJson14, atomicMutationJson14 } from './local-mutation-files.mjs';
|
|
4
4
|
import { scopeRevisionAuthority, amendmentFail } from './scope-amendment-wire.mjs';
|
|
5
|
+
import { readScopeEvidence } from './scope-evidence-local.mjs';
|
|
6
|
+
import { evidenceReference } from './scope-evidence-wire.mjs';
|
|
7
|
+
import { trustedOrigin } from './remote-transport.mjs';
|
|
5
8
|
|
|
6
9
|
async function referenceLocation(root, home, flowId, revisionDigest) {
|
|
7
10
|
const stateRoot = path.join(await mutationHome14(home), '.entrorove');
|
|
@@ -11,21 +14,36 @@ async function referenceLocation(root, home, flowId, revisionDigest) {
|
|
|
11
14
|
export async function retainScopeAmendmentReference(location, output) {
|
|
12
15
|
const effective = output.effectiveAuthority, target = await referenceLocation(location.root, location.home,
|
|
13
16
|
location.identity.flowId, output.scopeRevisionDigest);
|
|
14
|
-
const
|
|
17
|
+
const compact = effective.record.schemaVersion === 'entrorove.scope-revision-authority/2.0';
|
|
18
|
+
if (compact) await readScopeEvidence(location, evidenceReference(effective.record.candidateAttestationRef, undefined, location));
|
|
19
|
+
const value = { schemaVersion: compact ? 'entrorove.scope-amendment-reference/2.0' : 'entrorove.scope-amendment-reference/1.0',
|
|
20
|
+
...(compact ? { apiOrigin: location.apiOrigin } : {}), input: {
|
|
15
21
|
flowId: location.identity.flowId, proposalId: location.identity.proposalId, proposalDigest: location.identity.proposalDigest }, record: effective.record };
|
|
16
22
|
await privateMutationDirectory14(target.directory, { privateFrom: target.stateRoot });
|
|
17
23
|
try { if (canonical(await readMutationJson14(target.file)) !== canonical(value)) amendmentFail('Scope amendment original authority reference changed'); }
|
|
18
24
|
catch (error) { if (error.code !== 'ENOENT') throw error; await atomicMutationJson14(target.file, value, { privateFrom: target.stateRoot }); }
|
|
19
25
|
}
|
|
26
|
+
async function readReferenceEvidence(reference, input) {
|
|
27
|
+
const origin = trustedOrigin(reference.apiOrigin), stateRoot = path.join(await mutationHome14(input.home), '.entrorove');
|
|
28
|
+
const base = path.join(stateRoot, 'scope-runners', sha256(`${origin}:${reference.record.flowId}:${input.repositoryRoot}`));
|
|
29
|
+
const file = path.join(base, 'identity', 'binding.json'), item = await mutationFile14(file);
|
|
30
|
+
if (item.stat.size > 1_000_000 || item.stat.nlink !== 1) amendmentFail('Original amendment signer binding is invalid');
|
|
31
|
+
const binding = await readMutationJson14(file);
|
|
32
|
+
if (binding.repositoryRoot !== input.repositoryRoot || binding.apiOrigin !== origin || binding.flowId !== reference.record.flowId) amendmentFail('Original amendment signer binding changed');
|
|
33
|
+
const location = { base, binding };
|
|
34
|
+
await readScopeEvidence(location, evidenceReference(reference.record.candidateAttestationRef, undefined, location));
|
|
35
|
+
}
|
|
20
36
|
export async function scopeAmendmentRefreshAction(input, pass) {
|
|
21
37
|
if (!pass.scopeRevisionDigest) return undefined;
|
|
22
38
|
try {
|
|
23
39
|
const target = await referenceLocation(input.repositoryRoot, input.home, pass.flowId, pass.scopeRevisionDigest);
|
|
24
40
|
const reference = await readMutationJson14(target.file);
|
|
25
|
-
const
|
|
26
|
-
|
|
41
|
+
const compact = reference.schemaVersion === 'entrorove.scope-amendment-reference/2.0';
|
|
42
|
+
const record = scopeRevisionAuthority(reference.record, `entrorove.scope-revision-authority/${compact ? '2.0' : '1.0'}`);
|
|
43
|
+
if (!['entrorove.scope-amendment-reference/1.0', 'entrorove.scope-amendment-reference/2.0'].includes(reference.schemaVersion) || sha256(canonical(record)) !== pass.scopeRevisionDigest
|
|
27
44
|
|| record.flowId !== pass.flowId || record.taskDigest !== pass.taskDigest || record.scope.keyId !== pass.memberScopeKeyId
|
|
28
45
|
|| ['flowId', 'proposalId', 'proposalDigest'].some(field => reference.input[field] !== record[field])) amendmentFail('Stored refresh reference has another original authority');
|
|
46
|
+
if (compact) await readReferenceEvidence(reference, input);
|
|
29
47
|
return { command: 'npx @entrorove/skill scope-amend <absolute repositoryRoot>',
|
|
30
48
|
input: { ...reference.input, gatePassPath: input.gatePassPath }, resumeOriginalFlow: true, requiredBefore: 'mutation-settle' };
|
|
31
49
|
} catch {
|
|
@@ -80,7 +80,7 @@ export async function scopeAmendmentLocation(repositoryRoot, input, dependencies
|
|
|
80
80
|
const directory = path.join(base, 'amendments', sha256(canonical(input)));
|
|
81
81
|
await privateMutationDirectory14(directory, { privateFrom: stateRoot });
|
|
82
82
|
const contextAuthority = await boundScopeContexts(base, binding, dependencies);
|
|
83
|
-
return { root, home, stateRoot, directory, file: path.join(directory, 'journal.json'), identity,
|
|
83
|
+
return { root, home, apiOrigin, base, stateRoot, directory, file: path.join(directory, 'journal.json'), identity,
|
|
84
84
|
binding, key, signerConfigPath, original, contextAuthority };
|
|
85
85
|
}
|
|
86
86
|
export async function readScopeAmendmentState(location) {
|