From 27f9730f64b41df6bc664ca650152aa8e256be8d Mon Sep 17 00:00:00 2001 From: Enrico Piovesan Date: Wed, 9 Sep 2026 19:56:17 -0600 Subject: [PATCH] =?UTF-8?q?feat(discover):=20replace=20goal=20set=20?= =?UTF-8?q?=E2=80=94=20doc-approval=20review=20chain=20+=20drop=20no-plan?= =?UTF-8?q?=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Feedback: the examples weren't representative and the no-plan card read as broken. New three-goal set, all real: - "Price a quote" — core.calculate-price@1.2.0 (goal 1, auto-plans on load). - "Review a document for approval" — doc-approval.analyze -> doc-approval.recommend, a named-reference-app 2-capability governed chain (document text -> extracted type/parties/amounts/confidence -> approve-or-route recommendation + rationale). Verified: browserLocalPlan chains analyze -> recommend from a {document} fact. 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); until then this card plans and then fails closed on the authorization check. - "Check a card number" — validation.validate-luhn@1.2.0. Dropped: the abstract uncertainty.score chain and the no-plan card. renderNoPlan stays as defensive handling for a live goal that returns zero candidates. Supersedes the still-open #76 (same intent, better multi-cap example). E2E updated: goal-1 (price) + luhn plan+execute; doc-approval spec added when the registry PRs merge. npm test 5/5 (+1 skip), test:e2e 2/2, build clean. Co-Authored-By: Claude Sonnet 5 --- src/scripts/discover.js | 50 +++++++++++++++++-------------------- tests/e2e/discover.spec.mjs | 25 ++++++++++++------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/scripts/discover.js b/src/scripts/discover.js index f29502a..2081f65 100644 --- a/src/scripts/discover.js +++ b/src/scripts/discover.js @@ -20,27 +20,10 @@ 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: 'coverage', - label: 'Score the uncertainty of a reporting period', - blurb: 'Target: uncertainty.score. Facts: a partial coverage state with two included and one pending reference.', - kind: 'chain', - target: { capability_id: 'uncertainty.score', capability_version: '1.1.0' }, - candidate_refs: [ - { namespace: 'summary', id: 'summary.aggregate', versionRange: '1.1.0' }, - { namespace: 'uncertainty', id: 'uncertainty.score', versionRange: '1.1.0' }, - ], - starting_facts: { - coverage_state: 'partial', - period_key: '2026-08-17', - scope_id: 'golden-bc', - policy: { version: 'policy-1' }, - }, - }, { id: 'price', - label: 'Price a small quote', - blurb: 'Target: core.calculate-price. Facts: one line item, a versioned pricing config.', + label: 'Price a quote', + blurb: 'One line item, two units at $50, a versioned pricing config with no discounts or tax — target core.calculate-price.', kind: 'single', target: { capability_id: 'core.calculate-price', capability_version: '1.2.0' }, candidate_refs: [ @@ -56,16 +39,29 @@ const GOALS = [ }, }, { - id: 'noplan', - label: 'A goal with no structural path', - blurb: 'Target: core.calculate-price. Facts: only a currency — nothing produces the line items or pricing config it needs.', - kind: 'none', - target: { capability_id: 'core.calculate-price', capability_version: '1.2.0' }, + 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: 'core', id: 'core.calculate-price', versionRange: '1.2.0' }, - { namespace: 'summary', id: 'summary.aggregate', versionRange: '1.1.0' }, + { 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', + blurb: 'Does a 16-digit number pass the Luhn checksum? Facts: one number string — target validation.validate-luhn.', + kind: 'single', + target: { capability_id: 'validation.validate-luhn', capability_version: '1.2.0' }, + candidate_refs: [ + { namespace: 'validation', id: 'validation.validate-luhn', versionRange: '1.2.0' }, ], - starting_facts: { currency: 'USD' }, + starting_facts: { number: '4242424242424242' }, }, ]; diff --git a/tests/e2e/discover.spec.mjs b/tests/e2e/discover.spec.mjs index 7ed67f6..3a3c0eb 100644 --- a/tests/e2e/discover.spec.mjs +++ b/tests/e2e/discover.spec.mjs @@ -7,7 +7,7 @@ test('goal 1 auto-plans on load, then review + execute for real against the live // 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('uncertainty.score@1.1.0'); + await expect(page.locator('#discover-plan-target')).toHaveText('core.calculate-price@1.2.0'); await expect(page.locator('#discover-plan-mappings')).toContainText('unconfirmed'); await expect(page.locator('#discover-stats')).toContainText('namespaces'); @@ -16,19 +16,26 @@ test('goal 1 auto-plans on load, then review + execute for real against the live 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('uncertainty.score@1.1.0'); + await expect(page.locator('#discover-trace')).toContainText('core.calculate-price@1.2.0'); await expect(page.locator('#discover-log')).toContainText('executed offline in your browser'); }); -test('the no-structural-path goal returns "no plan" as a real outcome, not an error', async ({ page }) => { +test('a single-capability goal (card checksum) 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="noplan"]').click(); - await expect(page.locator('#discover-badge')).toHaveText('No plan — the goal has no structural path', { timeout: 45_000 }); - await expect(page.locator('#discover-result')).toHaveAttribute('data-outcome', 'noplan'); - await expect(page.locator('#discover-plan-mappings')).toContainText('No structural candidate'); - await expect(page.locator('#discover-exec')).toBeHidden(); - await expect(page.locator('#discover-log')).toContainText('0 candidates'); + await page.locator('.discover-goal[data-goal="luhn"]').click(); + await expect(page.locator('#discover-plan-target')).toHaveText('validation.validate-luhn@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('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.