zorya-classifier 0.2.0 → 0.2.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/README.md +24 -8
- package/dist/app/classifier-config.d.ts +30 -0
- package/dist/app/classifier-config.js +46 -0
- package/dist/app/classifier-contracts.d.ts +32 -0
- package/dist/app/classifier-contracts.js +1 -0
- package/dist/app/classifier-representation.d.ts +5 -0
- package/dist/app/classifier-representation.js +33 -0
- package/dist/app/classifier-runtime.d.ts +7 -0
- package/dist/app/classifier-runtime.js +71 -0
- package/dist/app/classifier-spatial.d.ts +31 -0
- package/dist/app/classifier-spatial.js +78 -0
- package/dist/app/cli-arguments.d.ts +2 -2
- package/dist/app/create-classifier.d.ts +4 -29
- package/dist/app/create-classifier.js +37 -237
- package/dist/cli.js +1 -1
- package/dist/entities/classification.d.ts +98 -0
- package/dist/entities/classification.js +28 -0
- package/dist/entities/contracts.d.ts +6 -471
- package/dist/entities/contracts.js +6 -97
- package/dist/entities/decision.d.ts +211 -0
- package/dist/entities/decision.js +33 -0
- package/dist/entities/geometry.d.ts +37 -0
- package/dist/entities/geometry.js +26 -0
- package/dist/entities/image.d.ts +39 -0
- package/dist/entities/image.js +15 -0
- package/dist/entities/localization.d.ts +125 -0
- package/dist/entities/localization.js +13 -0
- package/dist/entities/object-proposals.d.ts +4 -1
- package/dist/entities/segmentation-metadata.d.ts +70 -0
- package/dist/entities/segmentation-metadata.js +21 -1
- package/dist/entities/segmentation-verification.d.ts +1 -0
- package/dist/entities/segmentation.d.ts +6 -1
- package/dist/entities/validation.d.ts +2 -0
- package/dist/entities/validation.js +9 -0
- package/dist/entities/whole-object.d.ts +4 -0
- package/dist/features/choice-beam-layout.js +2 -7
- package/dist/features/proposals/presentation.d.ts +21 -0
- package/dist/features/proposals/presentation.js +122 -0
- package/dist/features/proposals/validation.d.ts +138 -0
- package/dist/features/proposals/validation.js +125 -0
- package/dist/features/segmentation/box-check.js +10 -23
- package/dist/features/segmentation/mask.js +2 -7
- package/dist/features/segmentation/region-result.d.ts +18 -0
- package/dist/features/segmentation/region-result.js +171 -0
- package/dist/features/segmentation/source-mask.d.ts +6 -0
- package/dist/features/segmentation/source-mask.js +32 -0
- package/dist/features/segmentation/validation.d.ts +9 -0
- package/dist/features/segmentation/validation.js +94 -0
- package/dist/infrastructure/decision-transport/errors.d.ts +8 -0
- package/dist/infrastructure/decision-transport/errors.js +34 -0
- package/dist/infrastructure/decision-transport/images.d.ts +1 -0
- package/dist/infrastructure/decision-transport/images.js +52 -0
- package/dist/infrastructure/{openrouter-common.d.ts → decision-transport/request.d.ts} +6 -15
- package/dist/infrastructure/decision-transport/request.js +162 -0
- package/dist/infrastructure/decision-transport/response.d.ts +1 -0
- package/dist/infrastructure/decision-transport/response.js +72 -0
- package/dist/infrastructure/decision-transport/route-identity.d.ts +11 -0
- package/dist/infrastructure/decision-transport/route-identity.js +23 -0
- package/dist/infrastructure/openrouter-vision.js +1 -1
- package/dist/infrastructure/openrouter.js +7 -19
- package/dist/infrastructure/raster.js +3 -8
- package/dist/infrastructure/segmentation/grabcut/index.d.ts +5 -1
- package/dist/infrastructure/segmentation/grabcut/index.js +6 -5
- package/dist/infrastructure/segmentation/grabcut/masks.d.ts +49 -0
- package/dist/infrastructure/segmentation/grabcut/masks.js +89 -0
- package/dist/infrastructure/segmentation/grabcut/model-asset.d.ts +4 -0
- package/dist/infrastructure/segmentation/grabcut/model-asset.js +4 -0
- package/dist/infrastructure/segmentation/grabcut/runtime.d.ts +70 -0
- package/dist/infrastructure/segmentation/grabcut/runtime.js +96 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +4 -43
- package/dist/infrastructure/segmentation/grabcut/worker-inference.js +4 -187
- package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +3 -58
- package/dist/infrastructure/segmentation/mobile-sam/index.js +2 -472
- package/dist/infrastructure/segmentation/mobile-sam/input.d.ts +46 -0
- package/dist/infrastructure/segmentation/mobile-sam/input.js +83 -0
- package/dist/infrastructure/segmentation/mobile-sam/model-assets.d.ts +8 -0
- package/dist/infrastructure/segmentation/mobile-sam/model-assets.js +8 -0
- package/dist/infrastructure/segmentation/mobile-sam/object-proposals.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/object-proposals.js +124 -0
- package/dist/infrastructure/segmentation/mobile-sam/options.d.ts +43 -0
- package/dist/infrastructure/segmentation/mobile-sam/options.js +19 -0
- package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.d.ts +26 -0
- package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.js +71 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.d.ts +112 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.js +230 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmenter.d.ts +22 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmenter.js +268 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-expand.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-expand.js +188 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +6 -149
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +6 -845
- package/dist/infrastructure/segmentation/mobile-sam/worker-models.d.ts +14 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-models.js +72 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.js +159 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-segment.d.ts +4 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-segment.js +126 -0
- package/dist/infrastructure/segmentation/native-protocol.d.ts +59 -34
- package/dist/infrastructure/segmentation/native-protocol.js +26 -16
- package/dist/infrastructure/segmentation/proposal-presentation-input.d.ts +20 -0
- package/dist/infrastructure/segmentation/proposal-presentation-input.js +107 -0
- package/dist/infrastructure/segmentation/proposal-presentation-pixels.d.ts +8 -0
- package/dist/infrastructure/segmentation/proposal-presentation-pixels.js +93 -0
- package/dist/infrastructure/segmentation/proposal-presentation.js +10 -201
- package/dist/infrastructure/vision-chat/options.d.ts +62 -0
- package/dist/infrastructure/vision-chat/options.js +46 -0
- package/dist/infrastructure/vision-chat/request.d.ts +23 -0
- package/dist/infrastructure/vision-chat/request.js +109 -0
- package/dist/infrastructure/vision-chat/response.d.ts +3 -0
- package/dist/infrastructure/vision-chat/response.js +105 -0
- package/dist/infrastructure/vision-chat.d.ts +4 -61
- package/dist/infrastructure/vision-chat.js +8 -271
- package/dist/openai-compatible.js +1 -1
- package/dist/processes/extract-from-region.js +11 -216
- package/dist/processes/extract.d.ts +2 -8
- package/dist/processes/extract.js +12 -128
- package/dist/processes/proposal-location.js +5 -251
- package/docs/0.2.0-plan.md +3 -3
- package/docs/README.ru.md +42 -23
- package/docs/acceptance.md +5 -5
- package/docs/agents.ru.md +95 -0
- package/docs/api.md +4 -2
- package/docs/architecture.md +33 -5
- package/docs/architecture.ru.md +146 -0
- package/docs/benchmarks.md +4 -2
- package/docs/development.ru.md +141 -0
- package/docs/operations.md +4 -4
- package/docs/provenance.json +5 -1
- package/docs/publishing.md +8 -0
- package/docs/refactoring-plan.ru.md +183 -0
- package/docs/v02-usage.md +8 -6
- package/docs/vision-results.md +2 -0
- package/package.json +5 -3
- package/dist/infrastructure/boundary-view.d.ts +0 -2
- package/dist/infrastructure/boundary-view.js +0 -263
- package/dist/infrastructure/openrouter-common.js +0 -317
- package/dist/infrastructure/text-representation.d.ts +0 -23
- package/dist/infrastructure/text-representation.js +0 -226
- package/docs/evidence/v02/categorical-heldout-v4/README.md +0 -35
- package/docs/evidence/v02/proposal-resource-soak-261dc23.md +0 -15
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { isProxy } from 'node:util/types';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { ClassifierError } from '../entities/errors.js';
|
|
4
|
-
export const requestLimit = 32 * 1024 * 1024;
|
|
5
|
-
export const responseLimit = 1024 * 1024;
|
|
6
|
-
export const probability = z.number().finite().min(0).max(1);
|
|
7
|
-
export const key = z
|
|
8
|
-
.string()
|
|
9
|
-
.min(1)
|
|
10
|
-
.max(128)
|
|
11
|
-
.refine((value) => value !== '__proto__');
|
|
12
|
-
const text = z.string().min(1).max(64_000);
|
|
13
|
-
const imageSchema = z
|
|
14
|
-
.object({
|
|
15
|
-
type: z.literal('image_url'),
|
|
16
|
-
image_url: z.object({ url: z.string().max(22_369_656), detail: z.literal('high') }).strict(),
|
|
17
|
-
})
|
|
18
|
-
.strict();
|
|
19
|
-
const questionSchema = z.discriminatedUnion('type', [
|
|
20
|
-
z
|
|
21
|
-
.object({
|
|
22
|
-
type: z.literal('choice'),
|
|
23
|
-
rankingSize: z.union([z.literal(1), z.literal(4)]).default(4),
|
|
24
|
-
instructions: text,
|
|
25
|
-
criteria: z
|
|
26
|
-
.record(key, text)
|
|
27
|
-
.refine((value) => Object.keys(value).length >= 2 && Object.keys(value).length <= 255),
|
|
28
|
-
})
|
|
29
|
-
.strict(),
|
|
30
|
-
z.object({ type: z.literal('noul'), instructions: text }).strict(),
|
|
31
|
-
]);
|
|
32
|
-
export const requestSchema = z
|
|
33
|
-
.object({
|
|
34
|
-
state: z
|
|
35
|
-
.array(z.union([text, imageSchema]))
|
|
36
|
-
.min(1)
|
|
37
|
-
.max(64)
|
|
38
|
-
.refine((value) => value.filter((part) => typeof part !== 'string').length <= 9),
|
|
39
|
-
questions: z
|
|
40
|
-
.record(key, questionSchema)
|
|
41
|
-
.refine((value) => Object.keys(value).length >= 1 && Object.keys(value).length <= 16),
|
|
42
|
-
})
|
|
43
|
-
.strict();
|
|
44
|
-
const localErrors = new WeakSet();
|
|
45
|
-
export function ownedError(code, message, details = {}) {
|
|
46
|
-
const error = new ClassifierError(code, message, details);
|
|
47
|
-
localErrors.add(error);
|
|
48
|
-
return error;
|
|
49
|
-
}
|
|
50
|
-
export function invalid(code, message) {
|
|
51
|
-
return ownedError(code, message);
|
|
52
|
-
}
|
|
53
|
-
export function active(signal) {
|
|
54
|
-
if (!signal.aborted)
|
|
55
|
-
return;
|
|
56
|
-
const timeout = signal.reason instanceof ClassifierError && signal.reason.code === 'TIMEOUT';
|
|
57
|
-
throw ownedError(timeout ? 'TIMEOUT' : 'ABORTED', timeout ? 'Operation timed out' : 'Operation cancelled');
|
|
58
|
-
}
|
|
59
|
-
export function validated(schema, input, code) {
|
|
60
|
-
const parsed = schema.safeParse(input);
|
|
61
|
-
if (!parsed.success)
|
|
62
|
-
throw invalid(code, 'Decision schema validation failed');
|
|
63
|
-
return parsed.data;
|
|
64
|
-
}
|
|
65
|
-
function imageSize(bytes, format) {
|
|
66
|
-
if (format === 'png') {
|
|
67
|
-
if (bytes.length < 33 ||
|
|
68
|
-
!bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) ||
|
|
69
|
-
bytes.readUInt32BE(8) !== 13 ||
|
|
70
|
-
bytes.toString('ascii', 12, 16) !== 'IHDR')
|
|
71
|
-
throw invalid('INVALID_INPUT', 'Invalid PNG image header');
|
|
72
|
-
return [bytes.readUInt32BE(16), bytes.readUInt32BE(20)];
|
|
73
|
-
}
|
|
74
|
-
if (bytes[0] !== 255 || bytes[1] !== 216)
|
|
75
|
-
throw invalid('INVALID_INPUT', 'Invalid JPEG image header');
|
|
76
|
-
let offset = 2;
|
|
77
|
-
while (offset + 3 < bytes.length) {
|
|
78
|
-
if (bytes[offset++] !== 255)
|
|
79
|
-
break;
|
|
80
|
-
while (bytes[offset] === 255)
|
|
81
|
-
offset++;
|
|
82
|
-
const marker = bytes[offset++];
|
|
83
|
-
if (marker === undefined || marker === 218 || marker === 217)
|
|
84
|
-
break;
|
|
85
|
-
if (offset + 2 > bytes.length)
|
|
86
|
-
break;
|
|
87
|
-
const length = bytes.readUInt16BE(offset);
|
|
88
|
-
if (length < 2 || offset + length > bytes.length)
|
|
89
|
-
break;
|
|
90
|
-
if ([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207].includes(marker)) {
|
|
91
|
-
if (length < 8)
|
|
92
|
-
break;
|
|
93
|
-
return [bytes.readUInt16BE(offset + 5), bytes.readUInt16BE(offset + 3)];
|
|
94
|
-
}
|
|
95
|
-
offset += length;
|
|
96
|
-
}
|
|
97
|
-
throw invalid('INVALID_INPUT', 'Invalid JPEG image dimensions');
|
|
98
|
-
}
|
|
99
|
-
export function validateImage(url) {
|
|
100
|
-
const prefix = /^data:image\/(png|jpeg);base64,/u.exec(url);
|
|
101
|
-
if (!prefix)
|
|
102
|
-
throw invalid('INVALID_INPUT', 'Only inline PNG or JPEG images are supported');
|
|
103
|
-
const encoded = url.slice(prefix[0].length);
|
|
104
|
-
const padding = encoded.endsWith('==') ? 2 : Number(encoded.endsWith('='));
|
|
105
|
-
if (!encoded.length ||
|
|
106
|
-
encoded.length % 4 !== 0 ||
|
|
107
|
-
!/^[A-Za-z0-9+/]+$/u.test(encoded.slice(0, encoded.length - padding)))
|
|
108
|
-
throw invalid('INVALID_INPUT', 'Invalid image base64');
|
|
109
|
-
const bytes = Buffer.from(encoded, 'base64');
|
|
110
|
-
if (bytes.length > 16 * 1024 * 1024 || bytes.toString('base64') !== encoded)
|
|
111
|
-
throw invalid('INVALID_INPUT', 'Invalid image byte representation');
|
|
112
|
-
const [width, height] = imageSize(bytes, prefix[1] ?? '');
|
|
113
|
-
if (width < 280 || height < 280 || width > 1568 || height > 1568)
|
|
114
|
-
throw invalid('INVALID_INPUT', 'Prepared image sides must be 280..1568 pixels');
|
|
115
|
-
}
|
|
116
|
-
/** Bounded owned snapshot; schema parsing never receives caller iterators or accessors. */
|
|
117
|
-
export function preflightJson(input, limit) {
|
|
118
|
-
let remaining = limit;
|
|
119
|
-
let nodes = 0;
|
|
120
|
-
const ancestors = new Set();
|
|
121
|
-
function charge(bytes) {
|
|
122
|
-
remaining -= bytes;
|
|
123
|
-
if (remaining < 0)
|
|
124
|
-
throw ownedError('RESOURCE_LIMIT', 'Decision request exceeds byte limit');
|
|
125
|
-
}
|
|
126
|
-
function string(value) {
|
|
127
|
-
charge(2);
|
|
128
|
-
for (let index = 0; index < value.length; index++) {
|
|
129
|
-
const code = value.charCodeAt(index);
|
|
130
|
-
if (code < 32)
|
|
131
|
-
charge([8, 9, 10, 12, 13].includes(code) ? 2 : 6);
|
|
132
|
-
else if (code === 34 || code === 92)
|
|
133
|
-
charge(2);
|
|
134
|
-
else if (code < 128)
|
|
135
|
-
charge(1);
|
|
136
|
-
else if (code < 2048)
|
|
137
|
-
charge(2);
|
|
138
|
-
else if (code >= 0xd800 && code <= 0xdbff) {
|
|
139
|
-
const next = value.charCodeAt(index + 1);
|
|
140
|
-
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
141
|
-
charge(4);
|
|
142
|
-
index++;
|
|
143
|
-
}
|
|
144
|
-
else
|
|
145
|
-
charge(6);
|
|
146
|
-
}
|
|
147
|
-
else
|
|
148
|
-
charge(code >= 0xdc00 && code <= 0xdfff ? 6 : 3);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function visit(value, depth) {
|
|
152
|
-
if (++nodes > 10_000 || depth > 6)
|
|
153
|
-
throw invalid('INVALID_INPUT', 'Decision structure exceeds supported limits');
|
|
154
|
-
if (typeof value === 'string') {
|
|
155
|
-
string(value);
|
|
156
|
-
return value;
|
|
157
|
-
}
|
|
158
|
-
if (value === null || typeof value === 'boolean') {
|
|
159
|
-
charge(value === false ? 5 : 4);
|
|
160
|
-
return value;
|
|
161
|
-
}
|
|
162
|
-
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
163
|
-
charge(String(value).length);
|
|
164
|
-
return value;
|
|
165
|
-
}
|
|
166
|
-
if (typeof value !== 'object' || value === null)
|
|
167
|
-
throw invalid('INVALID_INPUT', 'Unsupported decision value');
|
|
168
|
-
if (isProxy(value))
|
|
169
|
-
throw invalid('INVALID_INPUT', 'Decision input must contain plain values');
|
|
170
|
-
// Zod reads declared object fields even when they are not enumerable; JSON does not.
|
|
171
|
-
for (const name of [
|
|
172
|
-
'state',
|
|
173
|
-
'questions',
|
|
174
|
-
'type',
|
|
175
|
-
'image_url',
|
|
176
|
-
'url',
|
|
177
|
-
'detail',
|
|
178
|
-
'instructions',
|
|
179
|
-
'criteria',
|
|
180
|
-
]) {
|
|
181
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
182
|
-
if (descriptor && !descriptor.enumerable)
|
|
183
|
-
throw invalid('INVALID_INPUT', 'Decision fields must be enumerable');
|
|
184
|
-
}
|
|
185
|
-
if (ancestors.has(value))
|
|
186
|
-
throw invalid('INVALID_INPUT', 'Circular decision structure');
|
|
187
|
-
ancestors.add(value);
|
|
188
|
-
charge(2);
|
|
189
|
-
if (Array.isArray(value)) {
|
|
190
|
-
const copy = [];
|
|
191
|
-
if (value.length > 64)
|
|
192
|
-
throw invalid('INVALID_INPUT', 'Decision array exceeds supported limits');
|
|
193
|
-
for (let index = 0; index < value.length; index++) {
|
|
194
|
-
if (index)
|
|
195
|
-
charge(1);
|
|
196
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
197
|
-
if (!descriptor || !Object.hasOwn(descriptor, 'value'))
|
|
198
|
-
throw invalid('INVALID_INPUT', 'Decision input must contain plain values');
|
|
199
|
-
copy.push(visit(descriptor.value, depth + 1));
|
|
200
|
-
}
|
|
201
|
-
ancestors.delete(value);
|
|
202
|
-
return copy;
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
const copy = {};
|
|
206
|
-
const prototype = Object.getPrototypeOf(value);
|
|
207
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
208
|
-
throw invalid('INVALID_INPUT', 'Decision input must contain plain objects');
|
|
209
|
-
let count = 0;
|
|
210
|
-
for (const name in value) {
|
|
211
|
-
if (!Object.hasOwn(value, name))
|
|
212
|
-
continue;
|
|
213
|
-
if (++count > 255)
|
|
214
|
-
throw invalid('INVALID_INPUT', 'Decision object exceeds supported limits');
|
|
215
|
-
if (count > 1)
|
|
216
|
-
charge(1);
|
|
217
|
-
string(name);
|
|
218
|
-
charge(1);
|
|
219
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
220
|
-
if (!descriptor || !Object.hasOwn(descriptor, 'value'))
|
|
221
|
-
throw invalid('INVALID_INPUT', 'Decision input must contain plain values');
|
|
222
|
-
Object.defineProperty(copy, name, {
|
|
223
|
-
value: visit(descriptor.value, depth + 1),
|
|
224
|
-
enumerable: true,
|
|
225
|
-
configurable: true,
|
|
226
|
-
writable: true,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
ancestors.delete(value);
|
|
230
|
-
return copy;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return visit(input, 0);
|
|
234
|
-
}
|
|
235
|
-
function statusError(status) {
|
|
236
|
-
const code = status === 401 || status === 403
|
|
237
|
-
? 'AUTHENTICATION'
|
|
238
|
-
: status === 413
|
|
239
|
-
? 'RESOURCE_LIMIT'
|
|
240
|
-
: status === 415
|
|
241
|
-
? 'UNSUPPORTED'
|
|
242
|
-
: 'PROVIDER';
|
|
243
|
-
return ownedError(code, 'Model provider rejected the request', { status });
|
|
244
|
-
}
|
|
245
|
-
export function failure(error, signal, cleanupFailed = false) {
|
|
246
|
-
const known = error instanceof ClassifierError && localErrors.has(error);
|
|
247
|
-
const incompleteCleanup = cleanupFailed || (known && error.details.cleanupFailed === true);
|
|
248
|
-
try {
|
|
249
|
-
active(signal);
|
|
250
|
-
}
|
|
251
|
-
catch (aborted) {
|
|
252
|
-
if (aborted instanceof ClassifierError)
|
|
253
|
-
return ownedError(aborted.code, aborted.message, incompleteCleanup ? { cleanupFailed: true } : {});
|
|
254
|
-
}
|
|
255
|
-
return ownedError(known ? error.code : 'PROVIDER', known ? error.message : 'Model provider transport failed', { ...(known ? error.details : {}), ...(incompleteCleanup ? { cleanupFailed: true } : {}) });
|
|
256
|
-
}
|
|
257
|
-
export async function readResponse(response, signal, limit) {
|
|
258
|
-
const reader = response.body?.getReader();
|
|
259
|
-
if (!reader) {
|
|
260
|
-
active(signal);
|
|
261
|
-
if (!response.ok)
|
|
262
|
-
throw statusError(response.status);
|
|
263
|
-
throw invalid('INVALID_RESPONSE', 'Provider response has no body');
|
|
264
|
-
}
|
|
265
|
-
let cancelTask;
|
|
266
|
-
function cancel() {
|
|
267
|
-
cancelTask ??= reader.cancel().then(() => true, () => false);
|
|
268
|
-
}
|
|
269
|
-
signal.addEventListener('abort', cancel, { once: true });
|
|
270
|
-
let caught;
|
|
271
|
-
let output = '';
|
|
272
|
-
let complete = false;
|
|
273
|
-
try {
|
|
274
|
-
active(signal);
|
|
275
|
-
if (!response.ok)
|
|
276
|
-
throw statusError(response.status);
|
|
277
|
-
const length = response.headers.get('content-length');
|
|
278
|
-
if (length !== null && (!/^\d+$/u.test(length) || Number(length) > limit))
|
|
279
|
-
throw ownedError('RESOURCE_LIMIT', 'Provider response exceeds byte limit');
|
|
280
|
-
const storage = Buffer.allocUnsafe(limit);
|
|
281
|
-
let bytes = 0;
|
|
282
|
-
while (true) {
|
|
283
|
-
active(signal);
|
|
284
|
-
const next = await reader.read();
|
|
285
|
-
active(signal);
|
|
286
|
-
if (next.done)
|
|
287
|
-
break;
|
|
288
|
-
if (next.value.byteLength > limit - bytes)
|
|
289
|
-
throw ownedError('RESOURCE_LIMIT', 'Provider response exceeds byte limit');
|
|
290
|
-
storage.set(next.value, bytes);
|
|
291
|
-
bytes += next.value.byteLength;
|
|
292
|
-
}
|
|
293
|
-
complete = true;
|
|
294
|
-
try {
|
|
295
|
-
output = new TextDecoder('utf-8', { fatal: true }).decode(storage.subarray(0, bytes));
|
|
296
|
-
}
|
|
297
|
-
catch {
|
|
298
|
-
throw invalid('INVALID_RESPONSE', 'Provider returned invalid UTF-8');
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
catch (error) {
|
|
302
|
-
caught = error;
|
|
303
|
-
}
|
|
304
|
-
finally {
|
|
305
|
-
signal.removeEventListener('abort', cancel);
|
|
306
|
-
if (!complete)
|
|
307
|
-
cancel();
|
|
308
|
-
const released = cancelTask ? await cancelTask : true;
|
|
309
|
-
reader.releaseLock();
|
|
310
|
-
if (!released)
|
|
311
|
-
caught = failure(caught, signal, true);
|
|
312
|
-
}
|
|
313
|
-
if (caught !== undefined)
|
|
314
|
-
throw failure(caught, signal);
|
|
315
|
-
active(signal);
|
|
316
|
-
return output;
|
|
317
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { PixelRect } from '../entities/contracts.js';
|
|
2
|
-
import type { ImageRepresentationPort, RepresentationView } from '../entities/representation.js';
|
|
3
|
-
export interface TextPixelView {
|
|
4
|
-
id: string;
|
|
5
|
-
role: RepresentationView['role'];
|
|
6
|
-
sourceRegion: PixelRect;
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
/** Clean, resized, row-major RGBA8. Grid labels remain separately available as metadata. */
|
|
10
|
-
data: Uint8Array;
|
|
11
|
-
grid?: RepresentationView['grid'];
|
|
12
|
-
}
|
|
13
|
-
export interface TextRepresentationEncoder {
|
|
14
|
-
readonly profile: string;
|
|
15
|
-
/** Hard UTF-8 upper bound for one encoded view at these dimensions. */
|
|
16
|
-
maxEncodedBytes(width: number, height: number): number;
|
|
17
|
-
encode(view: TextPixelView, signal: AbortSignal): Promise<string>;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Build request-wide text representations from clean canonical pixels. The injected encoder
|
|
21
|
-
* is intentionally internal so research codecs do not become public package exports.
|
|
22
|
-
*/
|
|
23
|
-
export declare function createTextRepresentation(encoder: TextRepresentationEncoder): ImageRepresentationPort;
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import sharp from 'sharp';
|
|
2
|
-
import { limits } from '../entities/contracts.js';
|
|
3
|
-
import { ClassifierError, assertActive } from '../entities/errors.js';
|
|
4
|
-
import { representationLimits } from '../entities/representation.js';
|
|
5
|
-
import { readCanonicalPixels } from './raster.js';
|
|
6
|
-
function isContained(outer, inner) {
|
|
7
|
-
return (inner.left >= outer.left &&
|
|
8
|
-
inner.top >= outer.top &&
|
|
9
|
-
inner.left + inner.width <= outer.left + outer.width &&
|
|
10
|
-
inner.top + inner.height <= outer.top + outer.height);
|
|
11
|
-
}
|
|
12
|
-
function key(region) {
|
|
13
|
-
return `${region.left},${region.top},${region.width},${region.height}`;
|
|
14
|
-
}
|
|
15
|
-
function dimensions(region, maxSide) {
|
|
16
|
-
const scale = Math.min(1, maxSide / Math.max(region.width, region.height));
|
|
17
|
-
return {
|
|
18
|
-
width: Math.max(1, Math.round(region.width * scale)),
|
|
19
|
-
height: Math.max(1, Math.round(region.height * scale)),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function assertGridGeometry(view, width, height) {
|
|
23
|
-
if (!view.grid)
|
|
24
|
-
return;
|
|
25
|
-
const map = (rect) => ({
|
|
26
|
-
left: Math.round(((rect.left - view.sourceRegion.left) * width) / view.sourceRegion.width),
|
|
27
|
-
top: Math.round(((rect.top - view.sourceRegion.top) * height) / view.sourceRegion.height),
|
|
28
|
-
width: Math.round((rect.width * width) / view.sourceRegion.width),
|
|
29
|
-
height: Math.round((rect.height * height) / view.sourceRegion.height),
|
|
30
|
-
});
|
|
31
|
-
const mapped = view.grid.cells.map((cell) => map(cell.region));
|
|
32
|
-
if (view.grid.cells.some((cell) => !isContained(view.sourceRegion, cell.region)))
|
|
33
|
-
throw new ClassifierError('INVALID_INPUT', 'Grid geometry lies outside its source region');
|
|
34
|
-
if (mapped.some((rect) => rect.width < 1 || rect.height < 1))
|
|
35
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Distinct grid geometry is indistinguishable at the allocated resolution', { component: 'representation' });
|
|
36
|
-
const sourceKeys = new Set(view.grid.cells.map((cell) => key(cell.region)));
|
|
37
|
-
const mappedKeys = new Set(mapped.map((rect) => key(rect)));
|
|
38
|
-
if (sourceKeys.size !== mappedKeys.size)
|
|
39
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Distinct grid geometry collapses at the allocated resolution', {
|
|
40
|
-
component: 'representation',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
async function cleanPixels(source, sourcePixels, view, width, height, signal) {
|
|
44
|
-
const region = view.sourceRegion;
|
|
45
|
-
if (!isContained({ left: 0, top: 0, width: source.width, height: source.height }, region))
|
|
46
|
-
throw new ClassifierError('INVALID_INPUT', 'Representation view lies outside the oriented source');
|
|
47
|
-
const raw = Buffer.from(sourcePixels.buffer, sourcePixels.byteOffset, sourcePixels.byteLength);
|
|
48
|
-
const pipeline = sharp(raw, {
|
|
49
|
-
raw: { width: source.width, height: source.height, channels: 4 },
|
|
50
|
-
limitInputPixels: limits.imagePixels,
|
|
51
|
-
})
|
|
52
|
-
.extract(region)
|
|
53
|
-
.resize(width, height, { kernel: 'nearest' })
|
|
54
|
-
.raw();
|
|
55
|
-
try {
|
|
56
|
-
const result = await pipeline.toBuffer({ resolveWithObject: true });
|
|
57
|
-
assertActive(signal);
|
|
58
|
-
if (result.info.channels !== 4 || result.data.byteLength !== width * height * 4)
|
|
59
|
-
throw new ClassifierError('INVALID_RESPONSE', 'Sharp returned an invalid canonical pixel view');
|
|
60
|
-
return {
|
|
61
|
-
id: view.id,
|
|
62
|
-
role: view.role,
|
|
63
|
-
sourceRegion: region,
|
|
64
|
-
width,
|
|
65
|
-
height,
|
|
66
|
-
data: result.data,
|
|
67
|
-
...(view.grid ? { grid: view.grid } : {}),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
pipeline.destroy();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function aliasesFor(view) {
|
|
75
|
-
return {
|
|
76
|
-
id: view.id,
|
|
77
|
-
role: view.role,
|
|
78
|
-
sourceRegion: view.sourceRegion,
|
|
79
|
-
...(view.grid ? { grid: view.grid } : {}),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function gridMetadata(grid) {
|
|
83
|
-
if (!grid)
|
|
84
|
-
return undefined;
|
|
85
|
-
return {
|
|
86
|
-
cells: grid.cells.map((cell) => ({
|
|
87
|
-
id: cell.id,
|
|
88
|
-
column: cell.column,
|
|
89
|
-
row: cell.row,
|
|
90
|
-
region: cell.region,
|
|
91
|
-
label: grid.labels.get(cell.id) ?? null,
|
|
92
|
-
})),
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function makePlan(groups, maxSide, encoder) {
|
|
96
|
-
const plan = [];
|
|
97
|
-
let totalBytes = 0;
|
|
98
|
-
for (const group of groups) {
|
|
99
|
-
const size = dimensions(group.sourceRegion, maxSide);
|
|
100
|
-
const metadataText = JSON.stringify({
|
|
101
|
-
representationView: {
|
|
102
|
-
id: group.aliases[0]?.id ?? group.primary.id,
|
|
103
|
-
aliases: group.aliases.map((alias) => ({
|
|
104
|
-
id: alias.id,
|
|
105
|
-
role: alias.role,
|
|
106
|
-
sourceRegion: alias.sourceRegion,
|
|
107
|
-
})),
|
|
108
|
-
sourceRegion: group.sourceRegion,
|
|
109
|
-
dimensions: size,
|
|
110
|
-
scaleX: size.width / group.sourceRegion.width,
|
|
111
|
-
scaleY: size.height / group.sourceRegion.height,
|
|
112
|
-
grid: group.aliases.flatMap((alias) => {
|
|
113
|
-
const value = gridMetadata(alias.grid);
|
|
114
|
-
return value === undefined ? [] : [{ viewId: alias.id, cells: value.cells }];
|
|
115
|
-
}),
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
const bound = encoder.maxEncodedBytes(size.width, size.height);
|
|
119
|
-
const metadataBytes = Buffer.byteLength(metadataText, 'utf8');
|
|
120
|
-
if (!Number.isSafeInteger(bound) ||
|
|
121
|
-
bound < 0 ||
|
|
122
|
-
bound > representationLimits.partCharacters ||
|
|
123
|
-
metadataText.length > representationLimits.partCharacters)
|
|
124
|
-
return undefined;
|
|
125
|
-
totalBytes += metadataBytes + bound;
|
|
126
|
-
plan.push({ group, ...size, metadataText, maxEncodedBytes: bound });
|
|
127
|
-
}
|
|
128
|
-
return totalBytes <= representationLimits.totalBytes ? plan : undefined;
|
|
129
|
-
}
|
|
130
|
-
function buildGroups(views) {
|
|
131
|
-
const groups = new Map();
|
|
132
|
-
for (const view of views) {
|
|
133
|
-
const regionKey = key(view.sourceRegion);
|
|
134
|
-
const prior = groups.get(regionKey);
|
|
135
|
-
if (!prior) {
|
|
136
|
-
groups.set(regionKey, {
|
|
137
|
-
sourceRegion: view.sourceRegion,
|
|
138
|
-
primary: view,
|
|
139
|
-
aliases: [aliasesFor(view)],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
prior.aliases.push(aliasesFor(view));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return [...groups.values()];
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Build request-wide text representations from clean canonical pixels. The injected encoder
|
|
150
|
-
* is intentionally internal so research codecs do not become public package exports.
|
|
151
|
-
*/
|
|
152
|
-
export function createTextRepresentation(encoder) {
|
|
153
|
-
return {
|
|
154
|
-
async prepare(input) {
|
|
155
|
-
assertActive(input.signal);
|
|
156
|
-
if (input.views.length > representationLimits.maxViews)
|
|
157
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'A representation request may contain at most nine views', {
|
|
158
|
-
component: 'representation',
|
|
159
|
-
});
|
|
160
|
-
const groups = buildGroups(input.views);
|
|
161
|
-
for (const group of groups) {
|
|
162
|
-
if (!isContained({ left: 0, top: 0, width: input.source.width, height: input.source.height }, group.sourceRegion))
|
|
163
|
-
throw new ClassifierError('INVALID_INPUT', 'Representation view lies outside the oriented source');
|
|
164
|
-
}
|
|
165
|
-
let plan;
|
|
166
|
-
for (let side = representationLimits.maxSide; side >= 1 && plan === undefined; side -= 1)
|
|
167
|
-
plan = makePlan(groups, side, encoder);
|
|
168
|
-
if (!plan)
|
|
169
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'No bounded text representation allocation fits the request', {
|
|
170
|
-
component: 'representation',
|
|
171
|
-
});
|
|
172
|
-
for (const item of plan)
|
|
173
|
-
for (const alias of item.group.aliases)
|
|
174
|
-
if (alias.grid)
|
|
175
|
-
assertGridGeometry({ ...item.group.primary, sourceRegion: item.group.sourceRegion, grid: alias.grid }, item.width, item.height);
|
|
176
|
-
const decoded = await readCanonicalPixels(input.source, input.signal);
|
|
177
|
-
const pixelViews = [];
|
|
178
|
-
for (const item of plan)
|
|
179
|
-
pixelViews.push(await cleanPixels(input.source, decoded.data, item.group.primary, item.width, item.height, input.signal));
|
|
180
|
-
const state = [];
|
|
181
|
-
const metadata = { profile: encoder.profile, bytes: 0, views: [] };
|
|
182
|
-
for (let index = 0; index < pixelViews.length; index += 1) {
|
|
183
|
-
const view = pixelViews[index];
|
|
184
|
-
const allocation = plan[index];
|
|
185
|
-
if (!view || !allocation)
|
|
186
|
-
throw new ClassifierError('INVALID_RESPONSE', 'Text representation allocation was incomplete');
|
|
187
|
-
assertActive(input.signal);
|
|
188
|
-
state.push(allocation.metadataText);
|
|
189
|
-
metadata.bytes += Buffer.byteLength(allocation.metadataText, 'utf8');
|
|
190
|
-
let text;
|
|
191
|
-
try {
|
|
192
|
-
text = await encoder.encode(view, input.signal);
|
|
193
|
-
}
|
|
194
|
-
catch (error) {
|
|
195
|
-
if (error instanceof ClassifierError && error.code === 'RESOURCE_LIMIT')
|
|
196
|
-
throw new ClassifierError(error.code, error.message, {
|
|
197
|
-
...error.details,
|
|
198
|
-
component: 'representation',
|
|
199
|
-
});
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
const bytes = Buffer.byteLength(text, 'utf8');
|
|
203
|
-
if (text.length > representationLimits.partCharacters || bytes > allocation.maxEncodedBytes)
|
|
204
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Encoder output exceeds its declared per-view bound', {
|
|
205
|
-
component: 'representation',
|
|
206
|
-
});
|
|
207
|
-
if (metadata.bytes + bytes > representationLimits.totalBytes)
|
|
208
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Encoded request exceeds the aggregate UTF-8 byte limit', {
|
|
209
|
-
component: 'representation',
|
|
210
|
-
});
|
|
211
|
-
metadata.bytes += bytes;
|
|
212
|
-
state.push(text);
|
|
213
|
-
metadata.views.push({
|
|
214
|
-
id: view.id,
|
|
215
|
-
sourceRegion: view.sourceRegion,
|
|
216
|
-
width: view.width,
|
|
217
|
-
height: view.height,
|
|
218
|
-
scaleX: view.width / view.sourceRegion.width,
|
|
219
|
-
scaleY: view.height / view.sourceRegion.height,
|
|
220
|
-
content: { left: 0, top: 0, width: view.width, height: view.height },
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
return { state, metadata };
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Frozen categorical heldout v4: failed qualification
|
|
2
|
-
|
|
3
|
-
Both producers completed on the frozen source and inputs before independent truth evaluation. The candidate completed 80 cases; its no-image control completed all 40 photographs. **The candidate does not qualify for release.** The [numeric report](report.json) binds the original run, source, input, truth and output hashes. The earlier [zero-HTTP admission failure](../categorical-heldout-predispatch-20261020-v3.json) remains a separate, unchanged record.
|
|
4
|
-
|
|
5
|
-
| Measurement | Candidate | No-image control |
|
|
6
|
-
| -------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------- |
|
|
7
|
-
| Classification | 69/80: 59 true positives, 10 false positives, one false negative, ten true negatives | 10/40; predicted absent on every photograph |
|
|
8
|
-
| Positive whole-object boxes | 1/60: photo 1/30, controlled UI 0/15, controlled minimap 0/15 | 0/30 photographs |
|
|
9
|
-
| False locations | 0/20 negatives; limit one | 0/10 photograph negatives |
|
|
10
|
-
| Paired positive-photo difference | 1/30; 95% bootstrap interval **[0, 0.10]** | Lower bound must be strictly positive |
|
|
11
|
-
| Physical calls | 356; 349 HTTP 200, seven HTTP 502 | 100; all HTTP 200 |
|
|
12
|
-
| Known cost | $0.1608769 plus seven unknown charges | $0.0540033 |
|
|
13
|
-
|
|
14
|
-
All 30 positive photo pairs count, including unknowns and failures. The fixed 10,000-resample paired bootstrap uses seed `0x5a4f5259` and nearest-rank percentiles. The negative gate passes, but the paired gate fails. The seven 502 calls occurred on negative cases; none explains the positive localization failures. No automatic retry, provider fallback or replacement case was used. The combined known cost is $0.2148802; retaining $0.05 for each unknown charge gives accounted exposure $0.5648802. This is admission accounting, not a verified provider invoice.
|
|
15
|
-
|
|
16
|
-
The candidate's 60 positive cases reconcile as follows: one initial absence decision, 22 final-grid failures, 15 selections of no mask, 18 rejected completeness checks, three incorrect returned boxes and one correct box. The 37 cases reaching native proposals include the latter four categories. Classification of presence and localization of a complete instance are different tasks; the 69/80 classification result does not qualify the whole-object path.
|
|
17
|
-
|
|
18
|
-
Whole-box and cutout-mask correctness remain separate. The original candidate evaluation below contains **zero joined mask references**, although the separately pinned official index contains 32 masks for 21 photographs. A strict source-canvas join then rejected 30 masks whose full-frame annotation resolution differs from the source image. Two canvases match exactly. This is a reporting/alignment issue, not the cause of the box or bootstrap failure. The original evaluation is preserved byte for byte; normalized-canvas mask calculations, if reported, must be explicitly exploratory and cannot repair its release result. Exact annotation sampling and original Flickr rotation are not independently established. A separate [exploratory normalized-canvas calculation](mask-normalized-exploratory.json) now verifies all 32 original PNGs and records all 21 annotated cases: seven reference instances have a saved prediction to score, three reach IoU 0.8 and 25 lack a returned mask. It projects source prediction pixel centers onto the original annotation canvas; raw references, box gates and the failed paired result remain unchanged. This explicitly uncertain alignment does not qualify mask accuracy.
|
|
19
|
-
|
|
20
|
-
Operation latency uses nearest rank over every completed case, including failures: candidate classification p50/p95 0.980/4.537 seconds and localization 6.746/41.875 seconds; control classification 0.605/1.722 seconds and localization 0.927/2.654 seconds. Physical-fetch distributions are recorded separately. These shared-host measurements are **unranked** under the frozen policy.
|
|
21
|
-
|
|
22
|
-
The no-image audit verified all 100 actual requests contained neither image parts nor image-derived state. Its DeepSeek/Together model differs from the native Luna/OpenAI candidate, so this compares complete recipes and does not isolate the causal contribution of image input. UI and map each use one controlled source family, Mousepad and Minetest respectively; this is not arbitrary real-game acceptance.
|
|
23
|
-
|
|
24
|
-
The 80 cases are now exposed regression data. Do not select a runner-up or claim a new blind success from them. A changed method requires separately named development evaluation and a new source-group-disjoint blind cohort, with the existing gates retained. Models and providers remain caller-owned, with no library default.
|
|
25
|
-
|
|
26
|
-
## Preserved artifacts
|
|
27
|
-
|
|
28
|
-
- [Candidate evaluation](candidate-evaluation.json) and [provenance](candidate-provenance.json): initial output without the separately indexed mask references.
|
|
29
|
-
- [Control evaluation](control-evaluation.json) and [provenance](control-provenance.json).
|
|
30
|
-
- [Original paired qualification](paired-qualification.json).
|
|
31
|
-
- [Candidate physical receipts](candidate-physical-receipts.json) and [control physical receipts](control-physical-receipts.json): metadata-only derivatives, without request bodies, media or credentials.
|
|
32
|
-
|
|
33
|
-
`report.json` records each artifact's SHA256 and byte length. The five original evaluator/provenance outputs remain byte-exact; receipt JSON preserves the original arrays as a separately identified derivative. Source, pixel and reference-mask bytes remain outside the npm package.
|
|
34
|
-
|
|
35
|
-
The exact exposed [input/truth/source metadata catalog](../../../../benchmarks/v02/evidence/exposed-regression-v4/README.md) records all corpus pins and canvas audit; source pixels require separate licensed acquisition.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# MobileSAM public-path resource acceptance
|
|
2
|
-
|
|
3
|
-
This two-hour Linux CPU run passed its monotonic duration gates and native-child cleanup checks. It exercised the public `createClassifier` locate/extract path against a deterministic synthetic 256×256 image and an injected decision fixture. It is a resource and lifecycle result, not an image-localization quality result.
|
|
4
|
-
|
|
5
|
-
The [numeric receipt](proposal-resource-soak-261dc23.json) records the run and host details. The runtime execution was a working tree at `261dc235f609934b7aa125ace52984d9dd786d83`; all 55 manifest-pinned source files matched before and after (`0fb0dae63ffd384c5c32dbc9eac98e51e7c7a67a97b75cebf87eae32b09fdc66`). The separately checked Windows installed-archive acceptance used the same archive reference and confirmed 106 distribution files plus `package.json` (107 installed files), with exact installed bytes. That archive verification is separate from this working-tree soak.
|
|
6
|
-
|
|
7
|
-
The run requested 600 seconds of warmup, then 30 seconds idle, 6,540 seconds busy, and 30 seconds idle. Monotonic observations were 600.071 seconds warmup and 6,602.024 seconds of measurement, including 30.001 seconds before load, 6,541.991 seconds busy, and 30.001 seconds after load. The parent recorded 1,324 samples at a nominal 5-second interval; median gap was 5,000.363 ms and the largest was 5,032.394 ms. Forced GC was disabled.
|
|
8
|
-
|
|
9
|
-
The busy phase completed 2,158 operations: 1,079 locates and 1,079 extracts, with 1,079 located and extracted results, no unknowns, failures, timeouts, or seed misses, and zero provider HTTP calls. The warmup separately recorded 207 operations. In the measurement window, native children started and closed 2,158 times; abort/join, capacity, dispose, and parent-loss checks passed, and no children remained owned. Cold-per-call p50/p95 were 2,993.656/3,344.590 ms. These timings are not ranked: source checks, builds, provider development requests, native diagnostics and controlled application captures overlapped the broader run.
|
|
10
|
-
|
|
11
|
-
Idle-window memory medians were compared using `max(percentage of idle-before median, absolute floor)`. For RSS the gate was `max(20%, 128 MiB)`: the increase was 121,384,960 bytes (115.76 MiB), below the 134,217,728-byte (128 MiB) threshold. Record the increase for investigation; it does not exceed the gate. Heap-used, external, and array-buffer increases were 3,842,268 bytes, 13,045,137 bytes, and 9,216 bytes, each below its `max(10%, 16 MiB)` threshold of 16,777,216 bytes.
|
|
12
|
-
|
|
13
|
-
The public receipt contains no machine-local absolute paths. Full raw data remains outside the commit in the ignored local `.run/v02` directory; the raw report SHA-256 is `0b25adcde61cc90f5faa696aa7d7ee83d840abfa159044c98c8813fa1d505d30`, and the dense process-age witness SHA-256 is `5ed02be50937f7810f1f4daea8b490b67a027654b3e35273f80f4d0615fb579e`. The witness confirmed the same process PID/start-tick identity alive at 7,200.68 seconds. The [raw report](../../../.run/v02/proposal-resource-soak-monotonic-261dc23.json), [dense witness](../../../.run/v02/proposal-resource-soak-monotonic-261dc23-proc-dense.tsv), [coarse witness](../../../.run/v02/proposal-resource-soak-monotonic-261dc23-proc-watch.tsv), [run log](../../../.run/v02/proposal-resource-soak-monotonic-261dc23.log), and host snapshots are excluded from Git; their full hashes are in the receipt.
|
|
14
|
-
|
|
15
|
-
The workload uses a synthetic fixture and does not qualify factual localization, segmentation quality, or production latency. The 106-file runtime parity check is a separate installed-archive acceptance, not a claim that this soak executed the packed archive.
|