diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b5d31877b..420409609 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -754,7 +754,7 @@ this file per §3.5 of the prior snapshot). | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | | Accessibility and responsive UX | #602 delivered base post-detail modal semantics; #605 adds selected-post refocus, collapsed/hidden/inert/CSS-invisible focus exclusion across both modal types, readable evidence separators, focused tests, and desktop/mobile Storybook screenshots | Land #605 through the protected gate, then complete screen-reader and authenticated Playwright acceptance on the exact release head | | Design tokens and repeated objects | Token extraction started; sanitized Figma Event Lineage desktop/mobile frames exist, while other repeated product surfaces remain incomplete | Tokens in CSS + Storybook stories for board, popup, DAG, Ask, calendar, forms, charts; same-viewport Figma/runtime visual comparison before release | -| Frontend delivery performance | #644 implements a native dynamic-import boundary for conditional workspace surfaces and retains accessible loading/error states; exact-head checks passed but the PR is not protected-main evidence | Merge #644 normally, rebuild the protected-main production bundle, and retain the measured chunk inventory rather than raising the warning limit | +| Frontend delivery performance | #644 implements a native dynamic-import boundary for conditional workspace surfaces and retains accessible loading/error states; exact-head checks passed but the PR is not protected-main evidence. #994 vendor split at `625f4a6` (base `83eba56`): principal `551.27/161.88` → `297.96/87.08` kB min/gzip, warning gone, total JS ~618 kB unchanged, frontend lint + 530 tests + build GREEN, backend touched 44 GREEN | Merge #644 normally, rebuild the protected-main production bundle, and retain the measured chunk inventory rather than raising the warning limit | | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | Naruon email/project lineage | #704 provides a strict store-agnostic v1 contract, opaque evidence references, observed/inferred truth separation, knowledge-cutoff admission, and explicit unavailable states. Inferred edges require an injected provenance-bearing fast-mlsirm estimate; no local default weight exists | Merge #704 through protected `main`, publish an immutable attested artifact, then enable the Naruon consumer only against that released version and its contract fixtures | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index ca597ac50..26e04de3a 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -5,6 +5,26 @@ import { configDefaults } from 'vitest/config' // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + build: { + rolldownOptions: { + output: { + // #994: split stable framework/auth vendor code out of the principal + // application chunk so the buyer-path shell stays under the 500 kB + // warning boundary. Vendor modules change infrequently, so a + // content-hashed vendor chunk also improves repeat-visit caching. + // No warning-threshold change, no source behavior change. + manualChunks: (id) => { + if (id.includes('node_modules/react-dom') || id.includes('node_modules/react/') || id.includes('node_modules/scheduler')) { + return 'react-vendor'; + } + if (id.includes('node_modules/oidc-client-ts') || id.includes('node_modules/react-oidc-context')) { + return 'auth-vendor'; + } + return undefined; + }, + }, + }, + }, test: { environment: 'jsdom', setupFiles: ['./src/setupTests.ts'], diff --git a/lineageweave/adjudication_client.py b/lineageweave/adjudication_client.py index 646fab91c..24f0f4934 100644 --- a/lineageweave/adjudication_client.py +++ b/lineageweave/adjudication_client.py @@ -37,7 +37,7 @@ class NullAdjudicationClient: available = False - def judge(self, candidate_label: str, record_label: str) -> float: # pragma: no cover + def judge(self, candidate_label: str, record_label: str) -> float: """Score the candidate and record labels for semantic adjudication.""" raise RuntimeError("NullAdjudicationClient has no llm channel; check .available first") diff --git a/lineageweave/image_content.py b/lineageweave/image_content.py index 9d0282e23..7ef6f0cdb 100644 --- a/lineageweave/image_content.py +++ b/lineageweave/image_content.py @@ -146,7 +146,7 @@ class NullImageContentClient: available = False - def describe(self, image_bytes: bytes, mime_type: str) -> ImageDescription: # pragma: no cover + def describe(self, image_bytes: bytes, mime_type: str) -> ImageDescription: """Describe the supplied image through the configured vision channel.""" raise RuntimeError("NullImageContentClient has no image channel; check .available first") diff --git a/tests/test_adjudication_client.py b/tests/test_adjudication_client.py index 64490eb54..8f6dedad0 100644 --- a/tests/test_adjudication_client.py +++ b/tests/test_adjudication_client.py @@ -5,6 +5,7 @@ from lineageweave.adjudication_client import ( AdjudicationClientError, ContextualOrchestratorAdjudicationClient, + NullAdjudicationClient, parse_confidence_response, ) @@ -105,3 +106,11 @@ def test_adjudication_fails_closed_for_unscoreable_responses(monkeypatch, body) with pytest.raises(AdjudicationClientError): client.judge("workshop", "follow-up bid") + + +def test_null_adjudication_client_judge_fails_closed() -> None: + """Without an orchestrator the llm channel raises instead of scoring zero.""" + client = NullAdjudicationClient() + assert client.available is False + with pytest.raises(RuntimeError, match="no llm channel"): + client.judge("workshop", "follow-up bid") diff --git a/tests/test_frontend_delivery_performance_evidence.py b/tests/test_frontend_delivery_performance_evidence.py new file mode 100644 index 000000000..c726fab40 --- /dev/null +++ b/tests/test_frontend_delivery_performance_evidence.py @@ -0,0 +1,54 @@ +"""Regression contract for durable frontend delivery-performance evidence.""" + +from pathlib import Path + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +EVIDENCE_PATH = REPOSITORY_ROOT / "docs" / "evidence" / "frontend-delivery-performance-20260910.md" + + +def _evidence_text() -> str: + """Read the dated evidence only after proving the review artifact exists.""" + assert EVIDENCE_PATH.exists(), ( + "#994 requires durable buyer-path evidence; local results.tsv experiments " + "are not release evidence" + ) + return EVIDENCE_PATH.read_text(encoding="utf-8").lower() + + +def test_frontend_delivery_performance_evidence_is_committed() -> None: + """Keep #994 buyer-path measurements reviewable instead of local-only.""" + assert EVIDENCE_PATH.exists(), ( + "#994 requires durable buyer-path evidence; local results.tsv experiments " + "are not release evidence" + ) + + +def test_frontend_delivery_performance_evidence_covers_required_buyer_paths() -> None: + """Require the committed record to retain method, paths, and runtime observations.""" + evidence = _evidence_text() + required_terms = ( + "measured revision", + "environment and method", + "cold cache", + "board", + "dashboard", + "customer master", + "cited evidence", + "javascript transfer", + "dom", + "p95", + "limitations", + ) + missing = [term for term in required_terms if term not in evidence] + assert not missing, f"frontend delivery evidence is missing required terms: {missing}" + + assert "lineage" in evidence or "ontology" in evidence, ( + "frontend delivery evidence must cover the Lineage/ontology buyer path" + ) + assert any(term in evidence for term in ("parse/compile", "parse and compile", "parse + compile")), ( + "frontend delivery evidence must retain parse/compile observations" + ) + assert "main thread" in evidence or "main-thread" in evidence, ( + "frontend delivery evidence must retain main-thread observations" + ) diff --git a/tests/test_image_content.py b/tests/test_image_content.py index 29d52a22a..f7ee65cef 100644 --- a/tests/test_image_content.py +++ b/tests/test_image_content.py @@ -239,3 +239,11 @@ def test_parse_description_does_not_absorb_unknown_labels_into_tags() -> None: "TAGS: turbine, diagram\nNOTE: synthetic" ) assert parsed.tags == ("turbine", "diagram") + + +def test_null_image_content_client_describe_fails_closed() -> None: + """Without a vision provider the image channel raises instead of describing.""" + client = NullImageContentClient() + assert client.available is False + with pytest.raises(RuntimeError, match="no image channel"): + client.describe(b"", "image/png")