diff --git a/src/scripts/discover.js b/src/scripts/discover.js index 2081f65..33734ab 100644 --- a/src/scripts/discover.js +++ b/src/scripts/discover.js @@ -20,6 +20,20 @@ const CONTRACT_SCHEMA_VERSION = '1.0.0'; /* Three committed goals — a structured Spec-113 target + starting facts each. No natural language: the target is an exact capability identity. */ const GOALS = [ + { + id: 'docapproval', + label: 'Review a document for approval', + blurb: 'From the document text alone the planner chains doc-approval.analyze (extract type, parties, amounts, a confidence) into doc-approval.recommend (approve or route, with a rationale).', + kind: 'chain', + target: { capability_id: 'doc-approval.recommend', capability_version: '1.4.0' }, + candidate_refs: [ + { namespace: 'doc-approval', id: 'doc-approval.analyze', versionRange: '1.4.0' }, + { namespace: 'doc-approval', id: 'doc-approval.recommend', versionRange: '1.4.0' }, + ], + starting_facts: { + document: 'INVOICE\nVendor: Acme Corp\nBill to: Globex Industries\nInvoice #: AC-20481\nTotal due: $4,200.00\nDue date: 2026-10-01\nTerms: Net 30', + }, + }, { id: 'price', label: 'Price a quote', @@ -38,20 +52,6 @@ const GOALS = [ }, }, }, - { - id: 'docapproval', - label: 'Review a document for approval', - blurb: 'From the document text alone the planner chains doc-approval.analyze (extract type, parties, amounts, a confidence) into doc-approval.recommend (approve or route, with a rationale).', - kind: 'chain', - target: { capability_id: 'doc-approval.recommend', capability_version: '1.4.0' }, - candidate_refs: [ - { namespace: 'doc-approval', id: 'doc-approval.analyze', versionRange: '1.4.0' }, - { namespace: 'doc-approval', id: 'doc-approval.recommend', versionRange: '1.4.0' }, - ], - starting_facts: { - document: 'INVOICE\nVendor: Acme Corp\nBill to: Globex Industries\nInvoice #: AC-20481\nTotal due: $4,200.00\nDue date: 2026-10-01\nTerms: Net 30', - }, - }, { id: 'luhn', label: 'Check a card number', diff --git a/tests/e2e/discover.spec.mjs b/tests/e2e/discover.spec.mjs index 3a3c0eb..88504dd 100644 --- a/tests/e2e/discover.spec.mjs +++ b/tests/e2e/discover.spec.mjs @@ -1,25 +1,41 @@ import { test, expect } from '@playwright/test'; -test('goal 1 auto-plans on load, then review + execute for real against the live registry', async ({ page }) => { +test('goal 1 (doc-approval chain) auto-plans on load, then review + execute for real against the live registry', async ({ page }) => { test.slow(); // fetches the live catalog + prepares artifacts await page.goto('/discover.html'); // Auto-run to the review gate. await expect(page.locator('#discover-badge')).toHaveText('Planned — review the mappings', { timeout: 45_000 }); - await expect(page.locator('#discover-plan-target')).toHaveText('core.calculate-price@1.2.0'); + await expect(page.locator('#discover-plan-target')).toHaveText('doc-approval.recommend@1.4.0'); await expect(page.locator('#discover-plan-mappings')).toContainText('unconfirmed'); await expect(page.locator('#discover-stats')).toContainText('namespaces'); - // Explicit review gate → real composed execution. + // Explicit review gate → real composed execution of the two-node chain. await page.locator('#discover-exec').click(); await expect(page.locator('#discover-badge')).toHaveText('Executed — real, offline, governed', { timeout: 45_000 }); await expect(page.locator('#discover-result')).toHaveAttribute('data-outcome', 'executed'); await expect(page.locator('#discover-trace')).toContainText('terminal: succeeded'); - await expect(page.locator('#discover-trace')).toContainText('core.calculate-price@1.2.0'); + await expect(page.locator('#discover-trace')).toContainText('doc-approval.analyze@1.4.0'); + await expect(page.locator('#discover-trace')).toContainText('doc-approval.recommend@1.4.0'); await expect(page.locator('#discover-log')).toContainText('executed offline in your browser'); }); +test('a single-capability goal (price a quote) plans and executes for real', async ({ page }) => { + test.slow(); + await page.goto('/discover.html'); + await expect(page.locator('#discover-badge')).toHaveText('Planned — review the mappings', { timeout: 45_000 }); + + await page.locator('.discover-goal[data-goal="price"]').click(); + await expect(page.locator('#discover-plan-target')).toHaveText('core.calculate-price@1.2.0', { timeout: 45_000 }); + await expect(page.locator('#discover-badge')).toHaveText('Planned — review the mappings'); + + await page.locator('#discover-exec').click(); + await expect(page.locator('#discover-badge')).toHaveText('Executed — real, offline, governed', { timeout: 45_000 }); + await expect(page.locator('#discover-trace')).toContainText('terminal: succeeded'); + await expect(page.locator('#discover-trace')).toContainText('core.calculate-price@1.2.0'); +}); + test('a single-capability goal (card checksum) plans and executes for real', async ({ page }) => { test.slow(); await page.goto('/discover.html'); @@ -34,8 +50,3 @@ test('a single-capability goal (card checksum) plans and executes for real', asy await expect(page.locator('#discover-trace')).toContainText('terminal: succeeded'); await expect(page.locator('#discover-trace')).toContainText('validation.validate-luhn@1.2.0'); }); - -// The "Review a document for approval" goal (doc-approval.analyze -> doc-approval.recommend) -// plans today but only *executes* once doc-approval.analyze@1.4.0 / recommend@1.4.0 land -// on the live catalog with a pure_read risk class (traverse-framework/registry#424, #425). -// Add its plan+execute spec once those merge.