Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions PROJECT_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ the non-negotiable product invariant.

## Timeline

- **2026-07-31** — Replaced route-presence inference in the S-grade ingestion
score with exercised idempotent replay, chunk-preview/reprocess, and
classified-failure evidence. Added a typed `/v1/kb/query` HTTP compatibility
test plus current OpenAI Agents SDK and LangChain.js integration examples.
- **2026-07-30** — Added a product-owned changelog to the operator dashboard
with verified release history and canonical Roadmap and Source links.

Expand Down Expand Up @@ -77,6 +81,13 @@ Historical milestones live in
- **Owned release history:** the dashboard includes a same-origin `/changelog`
with verified editorial milestones. Planned work remains in GitHub Issues;
Source points to the canonical organization repository.
- **Agent integration contract:** the dependency-free `KnowledgebaseClient`
has an executable `/v1/kb/query` request/citation compatibility test, with
framework adapters documented for OpenAI Agents SDK and LangChain.js.
- **Ingest safety proof:** S-grade proof replays a seeded document and submits
a controlled invalid payload, so idempotency, preview/reprocess, and failure
classification capabilities come from exercised responses rather than route
availability.

### Deploy fingerprint

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,8 @@ pnpm run preflight
No code change is required to onboard a new domain; create or infer the schema
through the Worker, post direct records, ingest files, and query through
`/v1/kb/search` or `/v1/kb/query`.

For agent frameworks, use the checked-in
[OpenAI Agents SDK and LangChain.js examples](docs/product/agent-integration-examples.md).
Both preserve the complete citation payload returned by the typed client
contract.
91 changes: 90 additions & 1 deletion cloudflare/worker/scripts/a-plus-proof.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ function buildPlan(options) {
'deploy-readiness',
...(requiresS ? ['consumer-auth-smokes'] : []),
'seed-eval-corpus',
...(requiresS ? ['ingest-safety-proof'] : []),
'benchmark:kb-search:lexical',
'benchmark:kb-query:semantic',
'query-eval',
Expand Down Expand Up @@ -300,6 +301,73 @@ export async function seedProofCorpus(options) {
};
}

export async function runIngestSafetyProof(options) {
const documents = proofDocuments(options.input);
const document = documents[0];
if (!document) throw new Error('proof input documents are required for ingest safety proof');
const seededDocument = options.seedReport?.documents?.find((item) => item.id === document.id);
const seededSafety = seededDocument?.ingest_safety ?? {};
const embeddingSelection = proofEmbeddingSelection(options.input);
const replay = await requestJson(`${options.baseUrl}/v1/kb/ingest/text`, {
key: options.key,
method: 'POST',
body: {
domain: options.domain,
title: document.title,
text: document.text,
async: false,
idempotency_key: `proof:${document.id}`,
...embeddingSelection,
},
});

const failureResponse = await fetch(`${options.baseUrl}/v1/kb/ingest/text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${options.key}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
domain: options.domain,
title: 'proof-empty-input',
text: '',
async: false,
idempotency_key: `proof:${document.id}:empty`,
...embeddingSelection,
}),
});
const failure = await failureResponse.json().catch(() => ({}));
const replaySafety = replay?.ingest_safety ?? {};
const failureClassification = failure?.failure_classification ?? null;
const capabilities = {
idempotent_ingest:
replay?.idempotent_replay === true && replaySafety.idempotent_replay === true,
chunk_preview:
Array.isArray(seededSafety.chunk_preview) && seededSafety.chunk_preview.length > 0,
replayable_jobs:
seededSafety.replayable === true && typeof seededSafety.replay_route === 'string',
failure_classification:
failureResponse.status === 400 &&
failureClassification?.category === 'parse_empty' &&
failureClassification?.retryable === false,
};

return {
ok: Object.values(capabilities).every(Boolean),
capabilities,
replay: {
file_id: replay?.file_id ?? null,
idempotent_replay: replay?.idempotent_replay === true,
ingest_safety: replaySafety,
},
seed_ingest_safety: seededSafety,
classified_failure: {
status: failureResponse.status,
failure_classification: failureClassification,
},
};
}

export async function runQueryEvalProof(options) {
const cases = queryEvalCases(options.input);
if (cases.length === 0) throw new Error('benchmark input queries are required for query eval proof');
Expand Down Expand Up @@ -391,6 +459,15 @@ export async function runAPlusProof(options) {
domain: options.domain,
input,
});
const ingestSafetyProof = options.requireGrade === 'S'
? await runIngestSafetyProof({
baseUrl: options.baseUrl,
key: options.key,
domain: options.domain,
input,
seedReport,
})
: null;
const lexicalBenchmark = await runBenchmark({
baseUrl: options.baseUrl,
key: options.key,
Expand Down Expand Up @@ -455,6 +532,7 @@ export async function runAPlusProof(options) {
...(consumerSmokes ? { consumer_authenticated_smokes: consumerSmokes.consumers } : {}),
...(consumerSmokes ? { consumer_public_smokes: consumerSmokes.public_consumers } : {}),
consumer_eval_packs: detectConsumerEvalPacks(input),
...(ingestSafetyProof?.capabilities ?? {}),
typed_client_contract: clientContract.ok === true,
one_command_smoke: true,
consumer_integration_audit: consumerIntegrationAudit.ok === true,
Expand All @@ -475,6 +553,9 @@ export async function runAPlusProof(options) {
const artifacts = {
readiness: await writeJson(options.outputDir, 'readiness.json', readinessReport),
seed_eval_corpus: await writeJson(options.outputDir, 'seed-eval-corpus.json', seedReport),
ingest_safety: ingestSafetyProof
? await writeJson(options.outputDir, 'ingest-safety.json', ingestSafetyProof)
: null,
query_eval: await writeJson(options.outputDir, 'query-eval.json', queryEval),
query_evals: queryEvals.length > 1 ? await writeJson(options.outputDir, 'query-evals.json', queryEvals) : null,
client_contract: await writeJson(options.outputDir, 'client-contract.json', clientContract),
Expand All @@ -493,6 +574,7 @@ export async function runAPlusProof(options) {
artifacts,
readiness: readinessReport,
seed_eval_corpus: seedReport,
ingest_safety: ingestSafetyProof,
query_eval: queryEval,
query_evals: queryEvals,
client_contract: clientContract,
Expand Down Expand Up @@ -535,4 +617,11 @@ if (import.meta.url === `file://${process.argv[1]}`) {
}
}

export { buildPlan, parseArgs, proofDocuments, proofEmbeddingSelection, queryEvalCases, validateProofInput };
export {
buildPlan,
parseArgs,
proofDocuments,
proofEmbeddingSelection,
queryEvalCases,
validateProofInput,
};
10 changes: 6 additions & 4 deletions cloudflare/worker/scripts/operator-report.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,12 @@ export async function runOperatorReport(options = {}) {
...report.capabilities,
project_data_api: projects.ok && domains.ok && files.ok && jobs.ok,
ingest_contracts: files.ok && jobs.ok && sourceSets.ok ? ['text', 'record', 'url', 'file'] : [],
idempotent_ingest: files.ok && jobs.ok,
chunk_preview: files.ok && jobs.ok,
replayable_jobs: files.ok && jobs.ok,
failure_classification: files.ok && jobs.ok,
// These require exercised ingest responses. Route/inventory availability
// alone is not evidence that replay and failure contracts still work.
idempotent_ingest: false,
chunk_preview: false,
replayable_jobs: false,
failure_classification: false,
trace_export: traceExport?.ok === true,
trace_drilldown: traceDrilldown?.ok === true,
stage_timings: traceRows.some(traceHasStageTimings),
Expand Down
15 changes: 14 additions & 1 deletion cloudflare/worker/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ export interface KnowledgebaseResult {
metadata?: Record<string, unknown>;
}

export interface KnowledgebaseCitation {
index: number;
document_id: string;
chunk_id: string;
file_id: string | null;
filename: string | null;
page_start: number;
page_end: number;
excerpt: string;
score: number;
metadata: Record<string, unknown>;
}

export interface KnowledgebaseAnswer {
project: string;
domain: string;
Expand All @@ -52,7 +65,7 @@ export interface KnowledgebaseAnswer {
answer_model: string | null;
question: string;
answer: string;
citations: Array<Record<string, unknown>>;
citations: KnowledgebaseCitation[];
confidence: Record<string, unknown>;
data: KnowledgebaseResult[];
}
Expand Down
95 changes: 94 additions & 1 deletion cloudflare/worker/tests/a-plus-proof.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { buildPlan, parseArgs, proofDocuments, proofEmbeddingSelection, queryEvalCases, runAPlusProof, runQueryEvalProof, seedProofCorpus, validateProofInput } from '../scripts/a-plus-proof.mjs';
import {
buildPlan,
parseArgs,
proofDocuments,
proofEmbeddingSelection,
queryEvalCases,
runAPlusProof,
runIngestSafetyProof,
runQueryEvalProof,
seedProofCorpus,
validateProofInput,
} from '../scripts/a-plus-proof.mjs';

const originalFetch = globalThis.fetch;

Expand Down Expand Up @@ -101,6 +112,7 @@ describe('a-plus-proof', () => {
'deploy-readiness',
'consumer-auth-smokes',
'seed-eval-corpus',
'ingest-safety-proof',
'benchmark:kb-search:lexical',
'benchmark:kb-query:semantic',
'query-eval',
Expand Down Expand Up @@ -219,6 +231,87 @@ describe('a-plus-proof', () => {
});
});

it('proves replay, preview, reprocess, and classified-failure behavior', async () => {
const calls: Array<{ url: string; body: Record<string, unknown> }> = [];
globalThis.fetch = vi.fn(
async (url: string | URL | Request, init?: RequestInit) => {
const href = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
const body = JSON.parse(String(init?.body ?? '{}')) as Record<string, unknown>;
calls.push({ url: href, body });
if (body.text === '') {
return new Response(
JSON.stringify({
error: 'text must be non-empty',
failure_classification: { category: 'parse_empty', retryable: false },
}),
{ status: 400, headers: { 'Content-Type': 'application/json' } }
);
}
return new Response(
JSON.stringify({
file_id: 'file-1',
idempotent_replay: true,
ingest_safety: {
idempotent_replay: true,
chunk_preview: [{ text_preview: 'Alpha proof document.' }],
replayable: true,
replay_route: '/v1/kb/files/file-1/reprocess',
},
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
);
}
) as typeof fetch;

await expect(
runIngestSafetyProof({
baseUrl: 'https://kb.example',
key: 'service-key',
domain: 'manuals',
input: {
documents: [{ external_id: 'doc-1', content: 'Alpha proof document.' }],
},
seedReport: {
documents: [
{
id: 'doc-1',
ingest_safety: {
chunk_preview: [{ text_preview: 'Alpha proof document.' }],
replayable: true,
replay_route: '/v1/kb/files/file-1/reprocess',
},
},
],
},
})
).resolves.toMatchObject({
ok: true,
capabilities: {
idempotent_ingest: true,
chunk_preview: true,
replayable_jobs: true,
failure_classification: true,
},
replay: {
file_id: 'file-1',
idempotent_replay: true,
},
classified_failure: {
status: 400,
failure_classification: { category: 'parse_empty', retryable: false },
},
});
expect(calls).toHaveLength(2);
expect(calls[0]?.body).toMatchObject({
idempotency_key: 'proof:doc-1',
text: 'Alpha proof document.',
});
expect(calls[1]?.body).toMatchObject({
idempotency_key: 'proof:doc-1:empty',
text: '',
});
});

it('validates proof inputs before live proof requests', () => {
expect(validateProofInput({
queries: [
Expand Down
Loading
Loading