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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ All notable product changes are recorded here. PolicyWeave is pre-release; entri
- Collection-path editing remains in the collection step while processing-purpose editing stays in its dedicated purpose step.
- Review preview applies the same whitespace-normalized purpose-completeness contract as the blocking review rule.
- Step-rail, previous/next, and review-warning navigation now transfers programmatic focus to the newly active step heading; ordinary form controls and the dedicated preview shortcut are excluded from that transfer.
- Review-warning navigation now lets the browser scroll the focused owner heading into view; the previous `preventScroll` option could leave that heading hundreds of pixels above the desktop or mobile viewport.
- The publication-area CTA describes a readiness check and directs the operator to responsible review rather than exposing internal implementation boundaries.
- Unshipped JSON export is visibly disabled as `준비 중`, the redundant no-op `검토본 생성` control was removed, and the document title is non-interactive status text.
- Authored generic and custom-checkbox keyboard focus outlines now use the high-contrast `--green` token; a CSS regression test computes and enforces at least 3:1 contrast against white instead of relying on a low-contrast focus color.
Expand All @@ -45,7 +46,7 @@ All notable product changes are recorded here. PolicyWeave is pre-release; entri

### Not yet shipped
- Authoritative legal-rule snapshots that can determine legal sufficiency beyond product-defined fact completeness.
- Full browser-matrix/accessibility evidence and screenshot verification beyond CSS focus contrast and deterministic step-focus transition tests.
- Manual zoom and screen-reader evidence beyond the automated desktop/tablet/mobile Chromium accessibility and focus checks.
- Durable versioned policy persistence and audit history.
- Authenticated immutable publication revisions and public URL lifecycle.
- Hosted tenant/security/operability evidence and endpoint load testing.
6 changes: 3 additions & 3 deletions docs/TRD.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This TRD covers the pre-release PolicyWeave browser workspace and the contracts
- Structured authoring state is in browser memory; no production database or backend exists.
- `src/policy.ts` owns deterministic review logic for collection selection/no-collection attestation/mode/purpose/path and the non-collection authoring-completeness findings for service identity, explicit retention status/period, transfer statuses/details, and privacy contact.
- `src/App.tsx` provides the seven-step authoring flow, review navigation, explicit collection/retention/transfer-status capture, stale dependent-fact invalidation, and deterministic preview projection.
- `src/AuthoringFocusController.tsx` keeps explicit step navigation and review-warning jumps aligned with the newly active step by moving programmatic focus to its heading after the React update; ordinary form controls and the dedicated preview shortcut are outside this behavior.
- `src/AuthoringFocusController.tsx` keeps explicit step navigation and review-warning jumps aligned with the newly active step by moving programmatic focus to its heading after the React update and allowing the browser to reveal that target; ordinary form controls and the dedicated preview shortcut are outside this behavior.
- The current CI contract is lint, Vitest, TypeScript/Vite build, and Playwright Chromium browser evidence plus live organization-required security/review workflows. Browser cases cover desktop/tablet/mobile rendering, keyboard-triggered focus transfer, the explicit no-collection path, horizontal overflow, serious/critical axe findings, and per-project screenshots retained as an exact-head artifact.
- Muted small text uses one authored color token whose contrast is regression-tested against every current surface background at a minimum 4.5:1 ratio; browser axe remains the integration authority for rendered combinations.

Expand All @@ -23,7 +23,7 @@ This TRD covers the pre-release PolicyWeave browser workspace and the contracts
8. Blank/whitespace authoring facts are normalized as unresolved where that fact is required by the explicit governing status.
9. Disabling a collection item invalidates dependent collection-mode, processing-purpose, and collection-path evidence; re-enabling requires renewed confirmation.
10. Every blocking finding links to the responsible editing step.
11. Explicit step navigation through the rail, previous/next controls, or a blocking-finding action transfers focus to the newly active step heading after that surface renders. This logical focus-order contract must not steal focus from ordinary editing controls or the dedicated preview shortcut.
11. Explicit step navigation through the rail, previous/next controls, or a blocking-finding action transfers focus to the newly active step heading after that surface renders. The focused heading must remain fully inside the current viewport; navigation must not suppress the browser scroll needed to reveal it. This contract must not steal focus from ordinary editing controls or the dedicated preview shortcut.
12. Preview text is derived from current structured facts, including independent collection and retention statuses; it does not become an independently editable authority.
13. UI copy distinguishes a review draft from legal advice, certification, or a compliance guarantee.

Expand All @@ -33,7 +33,7 @@ The separation between collection and retention follows the PIPC Standard Person
- Touched production behavior requires regression and edge-case tests first.
- Touched production functions carry descriptive JSDoc rather than relying on implicit behavior.
- Do not suppress deprecation warnings to pass CI.
- Browser/accessibility validation must include keyboard/focus order, WCAG 2.2 automated checks, responsive desktop/tablet/mobile interactions, and screenshot evidence before a buyer-facing accessibility claim. Deterministic jsdom focus-transition coverage is supporting evidence only and does not substitute for real-browser focus-not-obscured, zoom, screen-reader, or responsive verification.
- Browser/accessibility validation must include keyboard/focus order, focus-target viewport visibility, WCAG 2.2 automated checks, responsive desktop/tablet/mobile interactions, and screenshot evidence before a buyer-facing accessibility claim. Deterministic jsdom focus-transition coverage is supporting evidence only and does not substitute for real-browser, zoom, screen-reader, or responsive verification.
- Hosted web endpoints, when introduced, use non-blocking/asynchronous handling and require realistic k6 tests before a p95 <=20 ms page/API claim is recorded.
- Production does not depend on synthetic demo data.

Expand Down
12 changes: 7 additions & 5 deletions docs/product-technical-gap-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,23 @@ The following buyer-security pass found that the service URL validator accepted

The browser-evidence slice adds a bounded Playwright/axe harness to the existing product CI rather than creating a second workflow. Six cases span desktop, tablet, and mobile Chromium projects and exercise truthful startup, horizontal overflow, serious/critical automated accessibility findings, keyboard activation, focus visibility, and the explicit no-collection transition. Each viewport writes an exact-run screenshot beneath `test-results` for SHA-bound artifact upload. Local test discovery, lint, 45 Vitest cases, and production build are verified; the local executor could not download Chromium because the Playwright CDN timed out repeatedly, so actual browser GREEN and screenshots remain unproven until the exact-head CI run completes.

Exact-head CI `34073373104` then supplied the missing real-browser evidence. Dependency installation, lint, 45 tests, production build, Chromium installation, all three keyboard/no-collection cases, and artifact upload succeeded; the three viewport accessibility cases consistently failed on the same muted token. Axe measured `#6d756f` at 4.17–4.45:1 against the authored rail, conditional-field, and metadata backgrounds. A RED stylesheet contract reproduces those exact background combinations and requires 4.5:1; the single shared token is darkened to `#656d67`, whose weakest current authored pairing is above the threshold. This is a bounded text-contrast repair, not a claim of WCAG conformance, and remains pending an exact-head browser rerun.
Exact-head CI `34073373104` then supplied the missing real-browser evidence. Dependency installation, lint, 45 tests, production build, Chromium installation, all three keyboard/no-collection cases, and artifact upload succeeded; the three viewport accessibility cases consistently failed on the same muted token. Axe measured `#6d756f` at 4.17–4.45:1 against the authored rail, conditional-field, and metadata backgrounds. A RED stylesheet contract reproduces those exact background combinations and requires 4.5:1; the single shared token is darkened to `#656d67`, whose weakest current authored pairing is above the threshold. This is a bounded text-contrast repair, not a claim of WCAG conformance; its browser rerun is included in the later exact-head GREEN evidence below.

The focus-not-obscured slice preserved the reviewed PR #1 head and stacked a browser contract above it. Its first hosted RED (`34079868713`) exposed an ambiguous test locator rather than product behavior, so the locator was narrowed to the specific service-name finding without changing production. The corrected exact-head RED (`34080045989`) then proved the product defect: keyboard activation focused the correct owner heading but left it at `y=-656` on desktop and `y=-581` on mobile; tablet passed and the matrix finished 7/9. `AuthoringFocusController` no longer suppresses focus scrolling, allowing the browser to reveal the focused heading. Exact-head CI `34080286158` then completed clean installation, lint, 46/46 Vitest, the production build, and 9/9 desktop/tablet/mobile Playwright/axe cases; artifact `10003466673` is bound by SHA-256 digest `014c4b0efc1b3da0cabf398553325c70c9f249e3ce3c92a775f8cea20d025880`. This is bounded responsive focus-target evidence; zoom and screen-reader evidence remain open.

## Current baseline

| Area | Evidence | Status | Commercialization gap | Owner/action | Next verification |
| --- | --- | --- | --- | --- | --- |
| Guided authoring | PRD, ADR-0002, seven routed editors, first-responsibility startup, `getReview`, explicit retention `getDraftReview`, no-collection/transfer states | Repaired foundation | Fresh state no longer skips or falsely completes step 1; collection, retention, transfer and other responsibilities fail closed independently; collection-path evidence remains unstructured free text and legal sufficiency is deliberately separate | Policy Fact Authoring: preserve deterministic completeness and independent authority; add structured path-evidence types only when a real integration/use case proves the need | Exact-head unit/UI edge tests, then browser E2E |
| Customer-fact authority | Zero-inferred startup facts; truthful initial rail state; explicit no-collection; independent explicit retention status; explicit transfer states; stale dependent-fact invalidation | Repaired | No known buyer-facing authority dead end remains in the in-memory seven-step fact model; hosted persistence must preserve these independent states without deriving one from another | Policy Fact Authoring: encode collection and retention as separate revision-owned facts; no automatic no-collection→no-retention rule | Persistence/schema invariant tests and exact-head UI tests |
| Review workspace | Live preview, total blocker count, warning-to-owner navigation, buyer-facing readiness guidance, deterministic step-heading focus transfer, proposed Playwright viewport/screenshot harness | Implemented foundation; browser execution pending | Exact-head browser artifact has not yet proved the new desktop/tablet/mobile cases | UX: run the proposed harness in exact-head CI, repair real failures, then extend interaction coverage | Exact-head screenshots, keyboard/focus and accessibility checks |
| Accessibility | Semantic controls, visible focus behavior, focus-token >=3:1 regression, muted-text >=4.5:1 authored-surface regression, jsdom focus transition, axe/browser checks | Partial; browser-discovered contrast repaired, rerun pending | Zoom, screen-reader, full focus-not-obscured scenarios, and manual WCAG evidence remain absent even if the automated run passes | UX/Test Engineering: verify the contrast repair in exact-head axe/Playwright and add a manual interaction record without claiming conformance from automation alone | Exact-head WCAG/browser matrix including no-collection and retention transitions |
| Review workspace | Live preview, total blocker count, warning-to-owner navigation, buyer-facing readiness guidance, deterministic step-heading focus transfer, Playwright viewport/screenshot harness | Implemented foundation; offscreen focus repaired and exact-head browser verified | Automated desktop/tablet/mobile focus-scroll evidence is GREEN; broader interaction coverage remains bounded | UX: retain exact-head artifacts, then extend interaction coverage | Exact-head screenshots, keyboard/focus and accessibility checks |
| Accessibility | Semantic controls, visible focus behavior, focus-token >=3:1 regression, muted-text >=4.5:1 authored-surface regression, jsdom focus transition, axe/browser and focused-heading viewport checks | Partial; bounded exact-head browser GREEN | Zoom, screen-reader, retention-transition and manual WCAG evidence remain absent | UX/Test Engineering: add a manual interaction record and remaining cases without claiming conformance from automation alone | Exact-head WCAG/browser matrix including no-collection and retention transitions |
| Legal/rule traceability | `docs/research-traceability.md`; PIPA/PIPC source/effective-date model; PIPC Notice No. 2025-4 terminology bound to collection/retention separation | Source baseline established | Current readiness rules are product completeness only; no versioned article/section-level legal-rule engine | Legal Source Registry: map future legal validations to source/effective date/revision | Snapshot fixtures across effective dates |
| Policy model | ADRs, ARCHITECTURE, TRD | Designed, browser-memory only | No versioned durable schema, migrations, audit history, 3NF implementation, or explicit UPSERT/idempotency | Platform: define `policy_revision` schema and item-level conflict contracts before storage; persist no-collection and retention status independently on the revision-owned fact model | Schema tests and migration round trip |
| Publication | Readiness CTA truthfully does not pretend to publish; immutable `publication_revision` is designed | Planned | No authenticated approval, immutable publication, supersession, rollback, or public URL lifecycle | Review & Publication: implement after persistence/security entry criteria | Authorization, replay/digest, supersession tests |
| Security/privacy | `docs/SECURITY.md`; local-first runtime; SHA-pinned checkout | Baseline documented | Hosted tenant model, encryption/key handling, audit/incident/retention evidence absent | Platform/Security: threat-model hosted boundary before backend | Exact-head security tests and org scans |
| Tests | 46 unit/UI regressions plus a six-case desktop/tablet/mobile Playwright/axe matrix and screenshot artifact contract | Improved; first browser RED repaired, rerun pending | Exact-head all-GREEN browser execution and repository-wide 100% execution/docstring coverage are not yet evidenced | Test Engineering: verify the current browser repair, then measure coverage | Exact-head coverage + browser evidence |
| Tests | 46 unit/UI regressions plus a nine-case desktop/tablet/mobile Playwright/axe matrix and screenshot artifact contract | Improved; exact-head unit/build/browser GREEN | Repository-wide 100% execution/docstring coverage is not yet evidenced | Test Engineering: measure coverage and extend realistic edge cases | Exact-head coverage + browser evidence |
| Performance | Static Vite client | Unevidenced | No realistic buyer-flow browser performance baseline; no network backend exists for meaningful k6 endpoint evidence | Operability: record browser baseline now; add k6 only when hosted network surfaces exist | Real measurements before latency claims |
| CI/security merge gate | Repo CI plus active organization ruleset-required workflows | Live external gate | Every branch movement invalidates predecessor evidence and stale approval; current hosted jobs may remain queued before runner assignment and dependency/reviewer control-plane failures can fail closed independently | Re-fetch exact-head workflows/reviews; use the central owner path for runner/dependency-review incidents rather than leaf-side churn or bypass | Terminal exact-head checks + independent approval + resolved threads |

Expand All @@ -66,7 +68,7 @@ A publishable release requires complete fact-to-warning navigation, deterministi

## Active commercialization order
1. Reacquire exact-current-head CI/security/SAST/central workflow execution and independent approval; merge PR #1 only through ordinary protection.
2. Complete real-browser responsive/accessibility evidence for the fail-closed seven-step workflow, including keyboard traversal, no-collection/retention transitions, focus-not-obscured behavior, zoom/screen-reader checks and screenshots; CSS focus contrast and deterministic logical step-focus transfer are already repaired.
2. Extend the exact-head responsive/accessibility evidence with retention transitions, zoom, screen-reader checks, and manual records; CSS focus contrast, logical step-focus transfer, focused-heading viewport visibility, and current desktop/tablet/mobile screenshots are already verified.
3. Define and test versioned `policy_revision` 3NF persistence/audit, explicit no-collection storage, independent retention status/rule state, and item-level UPSERT contracts.
4. Implement secure review/publication with immutable releases and explicit supersession.
5. Add hosted tenant isolation, audit/incident evidence, compose deployment, and realistic performance/load tests when network services exist.
2 changes: 1 addition & 1 deletion src/AuthoringFocusController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function AuthoringFocusController() {
const heading = document.querySelector<HTMLElement>('.form-panel .section-head h1')
if (!heading) return
heading.tabIndex = -1
heading.focus({ preventScroll: true })
heading.focus()
}, 0)
pendingFocusTransfers.add(timer)
}
Expand Down
19 changes: 19 additions & 0 deletions tests/e2e/authoring.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,22 @@ test('preserves keyboard context through the explicit no-collection path', async
await expect(page.getByRole('heading', { level: 1, name: '3. 처리 목적' })).toBeFocused()
await expect(page.getByText('개인정보를 수집하지 않음으로 확인되었습니다.')).toBeVisible()
})

test('keeps the owning step heading visible after keyboard navigation from a review warning', async ({ page }) => {
await page.goto('/')

const serviceWarning = page
.locator('.document-warning')
.filter({ hasText: '서비스 이름 확인이 필요합니다.' })
.getByRole('button', { name: '서비스 정보 확인', exact: true })
await serviceWarning.scrollIntoViewIfNeeded()
await serviceWarning.focus()
await page.keyboard.press('Enter')

const serviceHeading = page.getByRole('heading', { level: 1, name: '1. 서비스 정보' })
await expect(serviceHeading).toBeFocused()
const headingBounds = await serviceHeading.boundingBox()
expect(headingBounds).not.toBeNull()
expect(headingBounds!.y).toBeGreaterThanOrEqual(0)
expect(headingBounds!.y + headingBounds!.height).toBeLessThanOrEqual(page.viewportSize()!.height)
})
Loading