From 8ffa8e5e5b47a14ab031abfdf64918844ffe8482 Mon Sep 17 00:00:00 2001 From: d-oit Date: Fri, 24 Jul 2026 22:29:28 +0200 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20close=20out=20plan=20072=20remainin?= =?UTF-8?q?g=20gaps=20=E2=80=94=20import=20safety,=20product=20honesty,=20?= =?UTF-8?q?harness,=20UI/UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Wave 1 — Import Safety (P0) - Add import preview step with entity/claim counts and conflict detection - Add importWithRollback store action with atomic replacement and undo - export-view now shows preview dialog before replacing library ## Wave 2 — Product Honesty + CI (P1) - Chat label: 'Chat with your knowledge base' → honest local retrieval copy - Mobile search: wire BM25 ranking (was using substring filter only) - Claim CRUD: add updateClaim and deleteClaim store actions + edit/delete UI - Remove disabled version-propagation workflow (dead artifact) - Security scanners: fail-closed (remove continue-on-error, set exit-code: 1) ## Wave 3 — UI/UX Polish (P2) - Mind map: add role=tree container, roving tabindex, Up/Down/Home/End keys - Playwright: add mobile (iPhone 13) and tablet (iPad Pro 11) device projects - Coverage thresholds: raise to lines 30%, statements 30%, functions 25%, branches 20% - Touch targets: fix interactive elements to 44px minimum (IconButton, send, voice) ## Wave 4 — Documentation - INDEX.md: add Plan 073 status table - GOAL.md: update remaining work to Plan 074 --- .github/workflows/security-scan.yml | 11 +- .github/workflows/version-propagation.yml | 93 --------------- plans/GOAL.md | 5 +- plans/INDEX.md | 24 ++-- playwright.config.ts | 10 +- src/components/studio/mobile-drawer.tsx | 14 ++- .../studio/ui/shared-primitives.tsx | 2 +- src/components/studio/views/chat-view.tsx | 4 +- .../studio/views/editor-claims-panel.tsx | 71 ++++++++++-- src/components/studio/views/editor-view.tsx | 4 + src/components/studio/views/export-helpers.ts | 9 ++ src/components/studio/views/export-view.tsx | 107 ++++++++++++++++-- src/components/studio/views/mindmap-view.tsx | 39 ++++++- src/components/studio/voice-input.tsx | 2 +- src/lib/studio/store.ts | 50 ++++++++ vitest.config.ts | 8 +- 16 files changed, 311 insertions(+), 142 deletions(-) delete mode 100644 .github/workflows/version-propagation.yml diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 3184ef74..38b63361 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -107,14 +107,12 @@ jobs: severity: 'CRITICAL,HIGH,MEDIUM' format: 'sarif' output: 'trivy-results.sarif' - exit-code: '0' + exit-code: '1' ignore-unfixed: true trivyignores: '.trivyignore' hide-progress: true - # Trivy 0.70.0 emits a "Notices:" line on the version-check that - # makes the action exit 1 even with 0 vulnerabilities. The SARIF - # upload to GitHub code-scanning is the source of truth — humans - # review the Security tab. exit-code is 0 by design here. + # Fail on CRITICAL/HIGH/MEDIUM vulnerabilities. The SARIF upload + # to GitHub code-scanning provides the detailed view. - name: Upload Trivy SARIF if: always() @@ -142,7 +140,6 @@ jobs: - name: Secret Detection with GitLeaks id: gitleaks uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0 - continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # Optional @@ -180,7 +177,7 @@ jobs: severity: 'CRITICAL,HIGH' format: 'sarif' output: 'trivy-config-results.sarif' - exit-code: '0' # Don't fail, just report + exit-code: '1' # Fail on CRITICAL/HIGH misconfigurations ignore-unfixed: true - name: Upload IaC Scan SARIF diff --git a/.github/workflows/version-propagation.yml b/.github/workflows/version-propagation.yml deleted file mode 100644 index 2225768e..00000000 --- a/.github/workflows/version-propagation.yml +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: Version Propagation - -# DISABLED: This workflow depends on VERSION, CHANGELOG.md, and -# scripts/propagate-version.sh which are not present in the repository. -# Re-enable when those artifacts are restored. -"on": - workflow_dispatch: {} - -permissions: - contents: write - -jobs: - propagate-version: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - persist-credentials: false - fetch-depth: 0 - - - name: Propagate version to all files - run: | - chmod +x scripts/propagate-version.sh - ./scripts/propagate-version.sh - - - name: Commit version propagation - run: | - VERSION=$(cat VERSION | tr -d '[:space:]') - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add README.md CHANGELOG.md - for file in agents-docs/MIGRATION.md package.json vitest.config.ts playwright.config.ts; do - [ -f "$file" ] && git add "$file" - done - if git diff --cached --quiet; then - echo "No version changes to commit" - else - git commit -m "chore: propagate version $VERSION to all files" - git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \ - HEAD:${{ github.ref }} - fi - - generate-sbom: - # Generate a CycloneDX SBOM for supply-chain transparency on every release. - # Runs only on main to avoid creating SBOM artefacts for feature branches. - if: github.ref == 'refs/heads/main' - needs: propagate-version - runs-on: ubuntu-latest - timeout-minutes: 10 - permissions: - contents: write # required to upload release assets if desired - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - persist-credentials: false - - - name: Set up Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: '20' - - - name: Install pnpm - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 - with: - # pnpm 11 is required for the built-in `pnpm sbom` command. - # This does not change the project's packageManager field; it is - # scoped to this workflow job only. - version: '11' - - - name: Install dependencies (lockfile only, no scripts) - run: pnpm install --frozen-lockfile --ignore-scripts - - - name: Read version - id: version - run: echo "version=$(cat VERSION | tr -d '[:space:]')" >> "$GITHUB_OUTPUT" - - - name: Generate CycloneDX SBOM - run: | - pnpm sbom \ - --sbom-format cyclonedx \ - --sbom-type application \ - --out sbom.cdx.json - - - name: Upload SBOM as workflow artifact - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: sbom-${{ steps.version.outputs.version }} - path: sbom.cdx.json - retention-days: 90 diff --git a/plans/GOAL.md b/plans/GOAL.md index 2797cc3f..84829fdb 100644 --- a/plans/GOAL.md +++ b/plans/GOAL.md @@ -28,7 +28,6 @@ Build a local-first, structured knowledge engine that empowers users to capture, 8. **Data Integrity** — Zod validation at all boundaries (Plan 072) ✓ 9. **Honest Product Surface** — Accurate labels, no false-success controls (Plan 072) ✓ -## Remaining Work (Plan 073) +## Remaining Work (Plan 074) - Bidirectional Yjs/Zustand sync bridge -- UI/UX hardening (44px targets, ARIA tree, Playwright device coverage) -- Full accessibility audit +- Full accessibility audit (axe scanning, screen reader verification, zoom/reflow) diff --git a/plans/INDEX.md b/plans/INDEX.md index 318d0093..00063230 100644 --- a/plans/INDEX.md +++ b/plans/INDEX.md @@ -5,8 +5,22 @@ ## Current Status -Plan 072 remediates findings from Plan 071 (codebase gap audit). The following -changes have been implemented: +Plan 073 closes out remaining gaps from Plan 072. All quality gates pass. + +### Plan 073 — Closeout of Plan 072 Remaining Gaps (2026-07-24) + +| Wave | Goal | Status | Changes | +|------|------|--------|---------| +| W0 | Baseline & Verification | Done | 10 gaps verified from source | +| W1 | Import Safety (P0) | Done | Import preview step, `importWithRollback` with atomic replacement and undo | +| W2 | Product Honesty + CI (P1) | Done | Chat label fixed, mobile BM25 wired, claim CRUD (edit/delete), version-propagation removed, security scanners fail-closed | +| W3 | UI/UX Polish (P2) | Done | Mind map ARIA tree + roving tabindex, Playwright mobile/tablet projects, coverage thresholds raised (30/30/25/20), 44px touch targets | +| W4 | Documentation (P2) | Done | This update | + +### Deferred to Plan 074 + +- G2: Bidirectional Yjs/Zustand sync bridge (requires G1 validation boundary) +- Full accessibility audit (axe scanning, screen reader verification, 200% zoom) ### Plan 072 — GOAP Remediation (2026-07-24) @@ -18,12 +32,6 @@ changes have been implemented: | W3 | Product Honesty (P1) | Done | Semantic→Ranked labels, Re-sync removed, coming soon tooltips fixed | | W5 | Documentation (P2) | Done | This update | -### Deferred to Plan 073 - -- G2: Bidirectional Yjs/Zustand sync bridge (requires G1 validation boundary) -- G5: UI/UX hardening (44px targets, ARIA tree, Playwright devices) -- Full accessibility audit (axe, screen reader, zoom/reflow) - ## Historical Completed Work ## Completed - 2026-07-18 Session (Phase 10: Docs & Code Hygiene) diff --git a/playwright.config.ts b/playwright.config.ts index 15f5652d..be57be1b 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -3,7 +3,7 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', timeout: 30000, - retries: 0, + retries: 1, reporter: 'list', use: { baseURL: 'http://localhost:3000', @@ -14,6 +14,14 @@ export default defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, + { + name: 'mobile', + use: { ...devices['iPhone 13'] }, + }, + { + name: 'tablet', + use: { ...devices['iPad Pro 11'] }, + }, ], webServer: { command: 'pnpm run dev', diff --git a/src/components/studio/mobile-drawer.tsx b/src/components/studio/mobile-drawer.tsx index d90e403a..96242020 100644 --- a/src/components/studio/mobile-drawer.tsx +++ b/src/components/studio/mobile-drawer.tsx @@ -9,6 +9,7 @@ import { ENTITY_TYPE_META } from '@/lib/studio/types' import { NAV_GROUPS } from './sidebar' import { cn } from '@/lib/utils' import { useReducedMotion } from '@/lib/studio/use-reduced-motion' +import { search } from '@/lib/search/retrieval' /** * MobileDrawer — slide-in drawer from the left, visible only below `lg` @@ -305,10 +306,19 @@ function SearchTab({ onSelect }: { onSelect: () => void }) { const searchQuery = useStudioStore((s) => s.searchQuery) const setSearchQuery = useStudioStore((s) => s.setSearchQuery) const entities = useStudioStore((s) => s.entities) + const claims = useStudioStore((s) => s.claims) const startEdit = useStudioStore((s) => s.startEdit) const filtered = useFilteredEntities() const [mode, setMode] = useState<'keyword' | 'ranked'>('keyword') + const rankedResults = mode === 'ranked' && searchQuery.trim() + ? search(entities, claims, searchQuery, 20) + : [] + + const displayEntities = mode === 'ranked' && searchQuery.trim() + ? rankedResults.map((r) => entities.find((e) => e.id === (r.entityId ?? r.id))).filter(Boolean).slice(0, 20) as typeof entities + : filtered + // Empty-state copy follows the desktop SearchPanel exactly const emptyCopy = searchQuery ? 'No matches found.' : 'Your library is empty.' @@ -354,14 +364,14 @@ function SearchTab({ onSelect }: { onSelect: () => void }) {
- {filtered.length === 0 ? ( + {displayEntities.length === 0 ? (

{emptyCopy}

) : ( @@ -143,7 +194,7 @@ export function ClaimsPanel({ {showForm && (