fix(coding): tighten Pi Data Service schemas

This commit is contained in:
2026-08-26 20:03:07 +08:00
parent 1d63233cd0
commit f61990f3a7
3 changed files with 28 additions and 5 deletions

View File

@@ -101,6 +101,9 @@
- Preserved the bundled parent-role registration gate and extension-host child - Preserved the bundled parent-role registration gate and extension-host child
bridge `403`; added tests for all ten registrations, dispatch routing, bridge `403`; added tests for all ten registrations, dispatch routing,
trusted path authority, forbidden input fields, and confirmation rejection. trusted path authority, forbidden input fields, and confirmation rejection.
- Follow-up correction tightened the bundled document and revision schemas to
match Main-side validation: `document_id` rejects `.`/`..`, and `if_revision`
is capped at `Number.MAX_SAFE_INTEGER`; focused assertions cover both rules.
- No canonical project memory was changed. The only non-Main contract touch is - No canonical project memory was changed. The only non-Main contract touch is
the minimal conversation timeline summary required for the new discriminated the minimal conversation timeline summary required for the new discriminated
safe-detail type to remain type-safe and visible. safe-detail type to remain type-safe and visible.
@@ -108,6 +111,8 @@
## Verification ## Verification
- `pnpm exec vitest run tests/unit/pi-product-tools.test.ts tests/unit/pi-extension-bundle.test.ts tests/unit/pi-extension-host.test.ts --maxWorkers=1` — 23 passed. - `pnpm exec vitest run tests/unit/pi-product-tools.test.ts tests/unit/pi-extension-bundle.test.ts tests/unit/pi-extension-host.test.ts --maxWorkers=1` — 23 passed.
- Schema-hardening rerun of the focused Pi suite — 23 passed, including the
`document_id` and `if_revision` bundled-schema assertions.
- Data Service/projector plus Pi focused suites — 62 passed. - Data Service/projector plus Pi focused suites — 62 passed.
- Full unit suite excluding the separately serialized pressure test — 186 - Full unit suite excluding the separately serialized pressure test — 186
files, 1,574 passed, 2 skipped. files, 1,574 passed, 2 skipped.

View File

@@ -327,7 +327,10 @@ export default function makeloreRuntime(pi) {
type: 'object', additionalProperties: false, required: ['collection', 'document_id'], type: 'object', additionalProperties: false, required: ['collection', 'document_id'],
properties: { properties: {
collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' }, collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' },
document_id: { type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$' }, document_id: {
type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$',
not: { enum: ['.', '..'] },
},
}, },
}, },
); );
@@ -355,9 +358,12 @@ export default function makeloreRuntime(pi) {
required: ['collection', 'document_id', 'data'], required: ['collection', 'document_id', 'data'],
properties: { properties: {
collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' }, collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' },
document_id: { type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$' }, document_id: {
type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$',
not: { enum: ['.', '..'] },
},
data: { type: 'object' }, data: { type: 'object' },
if_revision: { type: 'integer', minimum: 1 }, if_revision: { type: 'integer', minimum: 1, maximum: 9007199254740991 },
}, },
}, },
); );
@@ -371,8 +377,11 @@ export default function makeloreRuntime(pi) {
required: ['collection', 'document_id', 'confirmed'], required: ['collection', 'document_id', 'confirmed'],
properties: { properties: {
collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' }, collection: { type: 'string', minLength: 1, maxLength: 48, pattern: '^[a-z][a-z0-9_-]{0,47}$' },
document_id: { type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$' }, document_id: {
if_revision: { type: 'integer', minimum: 1 }, type: 'string', minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9._~-]{1,128}$',
not: { enum: ['.', '..'] },
},
if_revision: { type: 'integer', minimum: 1, maximum: 9007199254740991 },
confirmed: { type: 'boolean', const: true }, confirmed: { type: 'boolean', const: true },
}, },
}, },

View File

@@ -243,6 +243,15 @@ describe('Makelore Pi extension bundle', () => {
expect(Object.keys(tool?.parameters?.properties ?? {})).not.toEqual( expect(Object.keys(tool?.parameters?.properties ?? {})).not.toEqual(
expect.arrayContaining(['owner', 'project', 'path', 'token', 'endpoint', 'url', 'handle']), expect.arrayContaining(['owner', 'project', 'path', 'token', 'endpoint', 'url', 'handle']),
); );
const properties = tool?.parameters?.properties as Record<string, Record<string, unknown>>;
if (name === 'data_service_get_document'
|| name === 'data_service_put_document'
|| name === 'data_service_delete_document') {
expect(properties.document_id?.not).toEqual({ enum: ['.', '..'] });
}
if (name === 'data_service_put_document' || name === 'data_service_delete_document') {
expect(properties.if_revision?.maximum).toBe(Number.MAX_SAFE_INTEGER);
}
} }
const updates: unknown[] = []; const updates: unknown[] = [];