Skip to content

Commit fed6e59

Browse files
V48 Gate 3 (implementation-only): absolute material-property measuring — quantity Tools + quality measure-agent
Data is digital material. Absolutes catalog splits quantity (size, symbolic richness, modularity via SourceStaticAnalysisTool) from quality (correctness, objectives fidelity, computational-usage via factoryMeasureAgentAbsolutes). Implementation synthesizes patches only; Validation measures. runSDIVFPipeline aliases the real SDIVF entry; deposit route rolls up execution-tree tokens.
1 parent dbcb65d commit fed6e59

10 files changed

Lines changed: 369 additions & 172 deletions

File tree

packages/agent-generics/src/agents/measure-agent-absolutes.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ import {
1919
} from './measure-agent';
2020

2121
const ABSOLUTES_FRAMING =
22-
'You measure ABSOLUTES — INTRINSIC properties of the artifact itself: its sizes, ' +
23-
'its correctness, and the amount of knowledge it encodes. Absolutes depend ONLY on ' +
24-
'the artifact, never on any reader, demand, market, or buyer. Measure what IS ' +
25-
'present, not what anyone wants or would pay for.';
22+
'You measure ABSOLUTES — INTRINSIC properties of digital material. Data is digital ' +
23+
'material; material has properties. QUANTITY properties include size, symbolic ' +
24+
'richness, modularity (often tool-measured counts). QUALITY properties include ' +
25+
'objectives fidelity, correctness, computational-usage requirements (judgment ' +
26+
'readings you ground in the tool-measured quantities + the source-safe descriptor). ' +
27+
'Absolutes depend ONLY on the artifact, never on any reader, demand, market, or buyer. ' +
28+
'Measure what IS present, not what anyone wants or would pay for. Prefer tool-measured ' +
29+
'magnitudes for quantity; do not invent sizes that contradict static-analysis counts.';
2630

2731
export interface MeasureAgentAbsolutesConfig {
2832
name: string;

packages/pipelines/asset-pack/src/__tests__/agent-measure-absolutes.test.ts

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,44 @@ describe('agent-measure-absolutes', () => {
6363
it('maps agent readings onto the catalog and falls back per-missing-reading', () => {
6464
const readings = [
6565
{ measurementKind: 'function-count', volume: 0.5, magnitude: 20 },
66-
{ measurementKind: 'semantic-volume', volume: 0.66 },
67-
// type-count, file-span, correctness-estimate omitted -> deterministic fallback
66+
{ measurementKind: 'objectives-fidelity', volume: 0.66 },
67+
// other kinds omitted -> deterministic fallback
6868
];
6969
const measurements = mapReadingsToAbsoluteMeasurements(readings, PATCH);
7070
expect(measurements).toHaveLength(ASSET_PACK_ABSOLUTES_CATALOG.length);
7171
const fn = measurements.find((m) => m.measurementKind === 'function-count');
7272
expect(fn?.volume).toBe(0.5);
7373
expect(fn?.magnitude).toBe(20);
74-
const sem = measurements.find((m) => m.measurementKind === 'semantic-volume');
75-
expect(sem?.volume).toBe(0.66);
74+
const objectives = measurements.find((m) => m.measurementKind === 'objectives-fidelity');
75+
expect(objectives?.volume).toBe(0.66);
7676
// omitted file-span falls back to the deterministic exact count (2)
7777
const fileSpan = measurements.find((m) => m.measurementKind === 'file-span');
7878
expect(fileSpan?.magnitude).toBe(2);
7979
});
8080

81+
it('catalog splits quantity vs quality material properties', () => {
82+
const quantity = ASSET_PACK_ABSOLUTES_CATALOG.filter((s) => s.propertyClass === 'quantity');
83+
const quality = ASSET_PACK_ABSOLUTES_CATALOG.filter((s) => s.propertyClass === 'quality');
84+
expect(quantity.map((s) => s.measurementKind)).toEqual(
85+
expect.arrayContaining([
86+
'function-count',
87+
'type-count',
88+
'file-span',
89+
'symbolic-richness',
90+
'modularity',
91+
]),
92+
);
93+
expect(quality.map((s) => s.measurementKind)).toEqual(
94+
expect.arrayContaining([
95+
'correctness-estimate',
96+
'objectives-fidelity',
97+
'computational-usage',
98+
]),
99+
);
100+
expect(quantity.every((s) => s.hasMagnitude)).toBe(true);
101+
expect(quality.every((s) => !s.hasMagnitude)).toBe(true);
102+
});
103+
81104
it('builds a lens-parameterized measurer agent', () => {
82105
const deposit = factoryAssetPackMeasureAbsolutesAgent('deposit');
83106
const read = factoryAssetPackMeasureAbsolutesAgent('read');
@@ -107,12 +130,12 @@ describe('validateDepositSynthesisOptions absolutes wiring', () => {
107130

108131
it('prefers the formal absolutes over the placeholder catalog', () => {
109132
const absolutes = [
110-
{ measurementKind: 'function-count', label: 'Functions', weight: 0.18, volume: 0.5, category: 'absolute', magnitude: 12, unit: 'functions' },
111-
{ measurementKind: 'semantic-volume', label: 'Semantic volume', weight: 0.28, volume: 0.66, category: 'absolute', unit: 'normalized' },
133+
{ measurementKind: 'function-count', label: 'Functions', weight: 0.12, volume: 0.5, category: 'absolute', magnitude: 12, unit: 'functions' },
134+
{ measurementKind: 'correctness-estimate', label: 'Correctness', weight: 0.18, volume: 0.66, category: 'absolute', unit: 'estimate' },
112135
];
113136
const out = validateDepositSynthesisOptions([{ ...baseOption, absolutes }], context);
114137
const measurements = out.candidates[0].measurements;
115-
expect(measurements.map((m) => m.measurementKind)).toEqual(['function-count', 'semantic-volume']);
138+
expect(measurements.map((m) => m.measurementKind)).toEqual(['function-count', 'correctness-estimate']);
116139
const fn = measurements.find((m) => m.measurementKind === 'function-count');
117140
expect(fn?.magnitude).toBe(12);
118141
expect(fn?.category).toBe('absolute');
@@ -154,43 +177,60 @@ describe('tool-grounded absolutes (legitimate static-analysis sizes)', () => {
154177
title: 'x', summary: 'y', coveredSourcePaths: ['a.ts', 'b.ts'], confidence: 0.6,
155178
};
156179
const measured = computeAbsolutesFromReport(
157-
{ measuredFromSamples: true, estimatedFunctionCount: 30, estimatedTypeCount: 12, targetFileCount: 2,
158-
sampledFileCount: 2, lineCount: 0, tokenCount: 0, functionCount: 30, typeCount: 12, symbolCount: 0,
159-
configKeyCount: 0, languageDensities: [], targetLanguageBreakdown: {}, coverageRatio: 1 } as any,
180+
{
181+
measuredFromSamples: true,
182+
estimatedFunctionCount: 30,
183+
estimatedTypeCount: 12,
184+
estimatedSymbolCount: 100,
185+
moduleCount: 2,
186+
targetFileCount: 2,
187+
sampledFileCount: 2,
188+
lineCount: 0,
189+
tokenCount: 0,
190+
functionCount: 30,
191+
typeCount: 12,
192+
symbolCount: 100,
193+
configKeyCount: 0,
194+
languageDensities: [],
195+
targetLanguageBreakdown: {},
196+
coverageRatio: 1,
197+
} as any,
160198
patch,
161199
);
162200
expect(measured.find((m) => m.measurementKind === 'function-count')?.magnitude).toBe(30);
201+
expect(measured.find((m) => m.measurementKind === 'symbolic-richness')?.magnitude).toBe(100);
202+
expect(measured.find((m) => m.measurementKind === 'modularity')?.magnitude).toBe(2);
163203
// no source -> heuristic from covered-path span (2 paths * 3 = 6)
164204
const heuristic = computeDeterministicAbsolutes(patch);
165205
expect(heuristic.find((m) => m.measurementKind === 'function-count')?.magnitude).toBe(6);
166206
});
167207

168-
it('mergeReportAndReadings clamps agent judgment readings into [0,1]', () => {
208+
it('mergeReportAndReadings clamps agent quality readings into [0,1]', () => {
169209
const patch: MeasurableAssetPackPatch = {
170210
title: 'x', summary: 'y', coveredSourcePaths: ['a.ts'], fileChanges: [{ path: 'a.ts', op: 'modify' }], confidence: 0.5,
171211
};
172212
const merged = mergeReportAndReadings(computeDeterministicAbsolutes(patch), [
173213
{ measurementKind: 'correctness-estimate', volume: 7 }, // clamped down
174-
{ measurementKind: 'semantic-volume', volume: -3 }, // clamped up
214+
{ measurementKind: 'objectives-fidelity', volume: -3 }, // clamped up
175215
]);
176216
expect(merged.find((m) => m.measurementKind === 'correctness-estimate')?.volume).toBe(1);
177-
expect(merged.find((m) => m.measurementKind === 'semantic-volume')?.volume).toBe(0);
217+
expect(merged.find((m) => m.measurementKind === 'objectives-fidelity')?.volume).toBe(0);
178218
});
179219

180-
it('mergeReportAndReadings keeps sizes authoritative, takes agent judgment', () => {
220+
it('mergeReportAndReadings keeps quantity tool-authoritative, takes agent quality', () => {
181221
const patch: MeasurableAssetPackPatch = {
182222
title: 'x', summary: 'y', coveredSourcePaths: ['a.ts'], fileChanges: [{ path: 'a.ts', op: 'modify' }], confidence: 0.5,
183223
};
184224
const base = computeDeterministicAbsolutes(patch);
185225
const baseFnVolume = base.find((m) => m.measurementKind === 'function-count')!.volume;
186226
const merged = mergeReportAndReadings(base, [
187-
{ measurementKind: 'function-count', volume: 0.99 }, // ignored — size is tool-authoritative
227+
{ measurementKind: 'function-count', volume: 0.99 }, // ignored — quantity is tool-authoritative
188228
{ measurementKind: 'correctness-estimate', volume: 0.91 }, // taken
189-
{ measurementKind: 'semantic-volume', volume: 0.4 }, // taken
229+
{ measurementKind: 'computational-usage', volume: 0.4 }, // taken
190230
]);
191231
expect(merged.find((m) => m.measurementKind === 'function-count')?.volume).toBe(baseFnVolume);
192232
expect(merged.find((m) => m.measurementKind === 'correctness-estimate')?.volume).toBe(0.91);
193-
expect(merged.find((m) => m.measurementKind === 'semantic-volume')?.volume).toBe(0.4);
233+
expect(merged.find((m) => m.measurementKind === 'computational-usage')?.volume).toBe(0.4);
194234
});
195235
});
196236

@@ -219,15 +259,14 @@ describe('measureAssetPackAbsolutes real-inference path (boundary-mocked measure
219259
const executeSpy = jest.spyOn(SourceStaticAnalysisTool.prototype, 'execute');
220260
setBoundaryLLMOutput({
221261
measurements: [
222-
// Judgment readings — taken from the agent (pins the envelope unwrap: if the
223-
// PTRR envelope were read directly these would be lost and correctness would
224-
// fall back to the confidence-derived 0.7).
262+
// Quality readings — taken from the agent (pins the envelope unwrap).
225263
{ measurementKind: 'correctness-estimate', volume: 0.91, rationale: 'Grounded in the measured counts.' },
226-
{ measurementKind: 'semantic-volume', volume: 0.44, rationale: 'Moderate legible knowledge volume.' },
227-
// A size reading — MUST be ignored: sizes are static-analysis-authoritative.
264+
{ measurementKind: 'objectives-fidelity', volume: 0.44, rationale: 'Aligned with deposit objectives.' },
265+
{ measurementKind: 'computational-usage', volume: 0.33, rationale: 'Moderate complexity surface.' },
266+
// A quantity reading — MUST be ignored: quantities are tool-authoritative.
228267
{ measurementKind: 'function-count', volume: 0.99, magnitude: 999, rationale: 'Inflated size reading.' },
229268
],
230-
summary: 'Measured the absolutes of the patch descriptor.',
269+
summary: 'Measured the absolute material properties of the patch.',
231270
});
232271

233272
const absolutes = await measureAssetPackAbsolutes(PATCH, {
@@ -237,13 +276,14 @@ describe('measureAssetPackAbsolutes real-inference path (boundary-mocked measure
237276
});
238277

239278
expect(absolutes.map((m) => m.measurementKind).sort()).toEqual([...ASSET_PACK_ABSOLUTE_KINDS].sort());
240-
// Sizes stay tool-grounded (2 functions in the provided source, not the agent's 999).
279+
// Quantity stays tool-grounded (2 functions in the provided source, not the agent's 999).
241280
const fn = absolutes.find((m) => m.measurementKind === 'function-count');
242281
expect(fn?.magnitude).toBe(2);
243282
expect(fn?.volume).toBe(0.05); // 2 / 40 normalizer
244-
// Agent judgment readings are taken.
283+
// Agent quality readings are taken.
245284
expect(absolutes.find((m) => m.measurementKind === 'correctness-estimate')?.volume).toBe(0.91);
246-
expect(absolutes.find((m) => m.measurementKind === 'semantic-volume')?.volume).toBe(0.44);
285+
expect(absolutes.find((m) => m.measurementKind === 'objectives-fidelity')?.volume).toBe(0.44);
286+
expect(absolutes.find((m) => m.measurementKind === 'computational-usage')?.volume).toBe(0.33);
247287
// Source-safety: only use() runs (in-memory samples); execute() would persist the
248288
// raw source args into a tool child execution and must never be called.
249289
expect(executeSpy).not.toHaveBeenCalled();

packages/pipelines/asset-pack/src/__tests__/deposit-agent-prompt-contracts.test.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jest.mock('@bitcode/generic-llms', () =>
2424
require('./support/generic-llms-prompt-capture-mock').makeGenericLLMsMock());
2525

2626
import { Execution } from '@bitcode/execution-generics';
27-
import { DEPOSIT_MEASUREMENT_CATALOG } from '../asset-packs-synthesis';
27+
import { ASSET_PACK_ABSOLUTES_CATALOG } from '../asset-packs-synthesis';
2828
import { DepositInputComprehensionAgent } from '../agents/setup/deposit-input-comprehension-agent';
2929
import { DepositCodebaseComprehensionAgent } from '../agents/discovery/deposit-codebase-comprehension-agent';
3030
import { DepositDepositorySearchAgent } from '../agents/discovery/deposit-depository-search-agent';
@@ -196,18 +196,16 @@ const SPECS: DepositAgentPromptSpec[] = [
196196
input: {},
197197
},
198198
{
199-
title: 'DepositAssetPackSynthesisAgent (Implementation: measured patches)',
199+
title: 'DepositAssetPackSynthesisAgent (Implementation: digital material patches)',
200200
agent: DepositAssetPackSynthesisAgent,
201201
identity: 'You are SynthesizeAssetPacks in DEPOSIT mode.',
202-
requirements: 'Ground every candidate in the provided Discovery comprehension',
203-
wrapper: 'Return ONLY {"options":[ ... ]} — the top-level key MUST be "options".',
202+
requirements: 'Ground every candidate in Discovery comprehension',
203+
wrapper: 'Return ONLY {"options":[ ... ]} — top-level key MUST be "options".',
204204
schemaFields: [
205205
'kind',
206206
'title',
207207
'summary',
208208
'coveredSourcePaths',
209-
'measurements',
210-
'measurementRationale',
211209
'confidence',
212210
'patch',
213211
'fileChanges',
@@ -219,9 +217,9 @@ const SPECS: DepositAgentPromptSpec[] = [
219217
],
220218
ptrr: [
221219
'Plan: from the explored repository inventory, the Discovery comprehension, and depositor steering',
222-
'Try: synthesize each candidate as a measured patch',
220+
'Try: synthesize each candidate as digital material',
223221
'Refine: ensure each option is distinct, source-safe, obfuscation- and exclusion-honoring',
224-
'Retry: complete any missing option as a minimal valid source-safe measured patch',
222+
'Retry: complete any missing option as a minimal valid source-safe patch',
225223
],
226224
boundaryOutput: {
227225
options: [
@@ -246,7 +244,7 @@ const SPECS: DepositAgentPromptSpec[] = [
246244
title: 'DepositValidationAgent (Validation: deposit supply quality)',
247245
agent: DepositValidationAgent,
248246
identity: 'You are the SynthesizeAssetPacks Validation agent in DEPOSIT mode.',
249-
requirements: 'Validate the synthesized deposit AssetPacks against these checks',
247+
requirements: 'Data is digital material; material has properties',
250248
wrapper:
251249
'Return ONLY {"issues":[...],"qualityScore":n,"coverageGaps":[...],"recommendation":"complete"|"iterate"}',
252250
schemaFields: ['issues', 'qualityScore', 'coverageGaps', 'recommendation'],
@@ -339,9 +337,9 @@ describe('Deposit SDIVF agent prompt contracts (boundary-mocked PTRR)', () => {
339337
);
340338
}
341339

342-
it('DepositAssetPackSynthesisAgent + DepositValidationAgent instructions carry the deposit measurement catalog', async () => {
343-
// The deposit lens measures with the DEPOSIT catalog kinds (never the read
344-
// lens's need-fit measurement) — pin the catalog into both prompt contracts.
340+
it('synthesis synthesizes material; validation names absolute material-property kinds', async () => {
341+
// Implementation no longer self-scores absolute volumes; Validation's
342+
// measure-agent catalog (quantity + quality) is pinned in the validation prompt.
345343
const synthesisSpec = SPECS.find((spec) => spec.agent === DepositAssetPackSynthesisAgent)!;
346344
const validationSpec = SPECS.find((spec) => spec.agent === DepositValidationAgent)!;
347345

@@ -350,10 +348,14 @@ describe('Deposit SDIVF agent prompt contracts (boundary-mocked PTRR)', () => {
350348
const validationCalls = await runAgentAndCapture(validationSpec);
351349
const validationSystem = validationCalls[0].system;
352350

353-
expect(DEPOSIT_MEASUREMENT_CATALOG.length).toBeGreaterThan(0);
354-
for (const measurementSpec of DEPOSIT_MEASUREMENT_CATALOG) {
355-
expect(synthesisSystem).toContain(measurementSpec.measurementKind);
351+
expect(synthesisSystem).toMatch(/digital material/i);
352+
expect(synthesisSystem).toMatch(/do NOT invent measurement volumes/i);
353+
expect(ASSET_PACK_ABSOLUTES_CATALOG.length).toBeGreaterThan(0);
354+
for (const measurementSpec of ASSET_PACK_ABSOLUTES_CATALOG) {
356355
expect(validationSystem).toContain(measurementSpec.measurementKind);
357356
}
357+
// Placeholder catalog kinds must not drive synthesis prompts.
358+
expect(synthesisSystem).not.toContain('source-coverage');
359+
expect(synthesisSystem).not.toContain('demand-alignment');
358360
}, 60000);
359361
});

0 commit comments

Comments
 (0)