Files
rust_browser/_bmad-output/planning-artifacts/epics.md
Zachary D. Rowitsch 0863153acd Implement parent-child margin collapsing (CSS 2.1 §8.3.1)
Add parent-first-child top and parent-last-child bottom margin collapsing
using a two-level approach (Level A shifts child inside parent, Level B
adjusts grandparent for effective collapsed margin). Fix pre-existing bug
in shift_subtree_x that incorrectly skipped absolute/fixed children.
Extract shared MARGIN_EPSILON constant, add 9 unit tests and 4 golden
tests (209-212), promote 31 WPT tests to pass. Includes code review
fixes: pub(crate) visibility for is_root_element, known-limitation docs,
and inline-content shift test coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 18:41:50 -04:00

1569 lines
78 KiB
Markdown

---
stepsCompleted:
- step-01-validate-prerequisites
- step-02-design-epics
- step-03-create-stories
- step-04-final-validation
status: complete
completedAt: '2026-03-12'
inputDocuments:
- _bmad-output/planning-artifacts/prd.md
- _bmad-output/planning-artifacts/architecture.md
scopeExclusions:
- "P3 (Phase 3 / Daily Driver) requirements excluded: FR32, FR37, FR40, FR43, FR44, FR45, FR46"
---
# rust_browser - Epic Breakdown
## Overview
This document provides the complete epic and story breakdown for rust_browser, decomposing the requirements from the PRD, UX Design if it exists, and Architecture requirements into implementable stories.
## Requirements Inventory
### Functional Requirements
FR1: The browser parses HTML documents and constructs a DOM tree from arbitrary web content. Acceptance: all WPT tree-construction tests pass.
FR2: The browser parses CSS stylesheets (inline, embedded, and external) and computes styles for all DOM nodes. Acceptance: computed style output matches WPT expectations for supported properties.
FR3: The browser performs layout computation for block, inline, flexbox, table, and positioned elements. Acceptance: golden test output matches expected layout trees for each layout mode.
FR4: The browser generates a display list from the layout tree and rasterizes it to pixels. Acceptance: golden test pixel output matches expected display list dumps.
FR5a: The browser selects the correct font based on CSS font-family, font-weight, and font-style declarations. Acceptance: golden tests with multiple font stacks render the expected glyphs.
FR5b: The browser performs line breaking per UAX#14 and renders text with correct line-height, font-size, and baseline alignment. Acceptance: golden tests with multi-line text match expected output.
FR6: The browser renders images in PNG, JPEG, GIF, WebP, and SVG formats as both inline content and CSS background-image. Acceptance: golden tests with each format produce correct visual output.
FR7a: The browser renders CSS backgrounds (color, image, repeat, position, attachment) and borders (all border-style values including double, groove, ridge, inset, outset). Acceptance: WPT background/border tests pass.
FR7b: The browser renders box-shadow, CSS gradients (linear-gradient, radial-gradient), and opacity. Acceptance: golden tests for each effect match expected output.
FR8: [P2] The browser renders CSS generated content (::before, ::after) with content property values including strings, attr(), and counter(). Acceptance: WPT generated-content tests pass.
FR9: The browser performs CSS selector matching with full specificity calculation and cascade resolution per CSS 2.1 sections 6 and 6.4. Acceptance: WPT cascade/specificity tests pass.
FR10: [P2] The browser resolves CSS inheritance, initial values, and inherit/initial/unset keywords for all CSS 2.1 properties. Acceptance: WPT inheritance tests pass for each supported property.
FR11: The browser parses and executes JavaScript programs. Acceptance: Test262 pass rate reaches 95%+ against the full tc39/test262 suite (50,000+ tests).
FR12: The browser executes scripts from inline <script> elements and external script resources, including deferred and asynchronous loading. Acceptance: WPT script-loading tests pass for each loading mode.
FR13: The browser exposes DOM manipulation APIs to JavaScript: getElementById, querySelector, querySelectorAll, createElement, appendChild, removeChild, insertBefore, replaceChild, classList, and style property access. Acceptance: WPT DOM manipulation tests pass for each listed API.
FR14: The browser dispatches events to JavaScript listeners with capture, target, and bubble phases per the DOM Events specification. Acceptance: WPT event dispatch tests pass including stopPropagation and preventDefault.
FR15: The browser executes microtasks (Promise.then), macrotasks (setTimeout, setInterval), and requestAnimationFrame callbacks in spec-defined order. Acceptance: event loop ordering tests produce correct execution sequences.
FR16: The browser exposes these Web APIs to JavaScript: console (log/warn/error), JSON (parse/stringify), fetch, localStorage, sessionStorage, and all DOM/event APIs listed in FR13-FR14. Acceptance: each API has at least one integration test verifying correct behavior.
FR17: The browser catches JavaScript runtime errors (TypeError, ReferenceError, SyntaxError) without crashing and reports them to console.error. Acceptance: a test script with each error type runs without process termination and produces console output.
FR18: The user enters a URL in the address bar and the browser navigates to it. Acceptance: URL entry triggers resource fetch and page render within the performance bounds defined in NFR1.
FR19: The browser loads resources over HTTP, HTTPS, file://, and data: URI schemes. Acceptance: integration tests verify successful resource loading for each scheme.
FR20a: The browser follows HTTP 301, 302, 303, 307, and 308 redirects up to a maximum of 20 hops. Acceptance: redirect chain tests verify correct final destination and hop limit enforcement.
FR20b: The browser displays HTTP error responses (4xx, 5xx) to the user with the status code and a descriptive message. Acceptance: error page tests verify status code display for 404 and 500 responses.
FR21: [P1 -- done] The browser manages cookies per RFC 6265: domain scoping, path matching, Secure/HttpOnly flags, and Max-Age/Expires expiry. Acceptance: cookie integration tests verify correct set/send behavior for each attribute.
FR22: [P1 -- done] The browser caches HTTP responses using ETag and Last-Modified headers, sends conditional requests (If-None-Match, If-Modified-Since), and honors Cache-Control directives (max-age, no-cache, no-store). Acceptance: caching integration tests verify 304 responses and cache hit/miss behavior.
FR23: [P1 -- done] The browser maintains cookie-based session state across navigations within a browsing session: cookies set on page A are sent with requests to the same domain on page B. Acceptance: a multi-navigation test verifies session cookie persistence across 3+ page loads.
FR24: The user navigates forward and backward through browsing history. Acceptance: history navigation tests verify correct page restoration for 3+ history entries.
FR25: The browser resolves relative URLs against the document base URL (including <base href> if present). Acceptance: URL resolution tests cover relative paths, query strings, fragments, and base element override.
FR26: The user interacts with form controls: text inputs, buttons, checkboxes, radio buttons, select menus, and textareas. Acceptance: integration tests verify user input produces correct form control state for each control type.
FR27: The browser submits forms via GET and POST with application/x-www-form-urlencoded encoding. [P2] multipart/form-data encoding for file uploads. Acceptance: form submission tests verify correct request body encoding for each method and encoding type.
FR28: [P2] The browser performs client-side form validation for required, pattern, min, max, minlength, maxlength, and type-based constraints (email, url, number). Acceptance: validation tests verify correct constraint enforcement and user-visible error indication for each constraint type.
FR29: The user interacts with the page via click, keyboard input, and scroll. Acceptance: input event tests verify correct event dispatch and default behavior for each input type.
FR30: The browser manages focus state and supports keyboard navigation (Tab/Shift+Tab) between focusable elements in document order. Acceptance: focus management tests verify correct tab order across form controls, links, and elements with tabindex.
FR31: The user views and edits the current URL in an address bar that updates on navigation. Acceptance: address bar reflects the current page URL after each navigation.
FR32: [P3] The user opens new tabs, switches between tabs, and closes tabs. Each tab maintains independent navigation history, DOM state, and scroll position. Acceptance: multi-tab tests verify independent state across 3+ tabs.
FR33: The user scrolls page content vertically and horizontally when content exceeds the viewport. Acceptance: scroll tests verify content accessibility for pages taller and wider than the viewport.
FR34: The browser displays a loading indicator during page load and clears it on completion or failure. Acceptance: loading state tests verify indicator visibility during fetch and removal after load/error events.
FR35: The user reloads the current page (re-fetches all resources) and stops a loading navigation (cancels pending fetches). Acceptance: reload/stop tests verify correct behavior for each action.
FR36: The browser renders a chrome UI containing the address bar, navigation buttons (back/forward/reload/stop), and a tab bar (Phase 3). Acceptance: chrome UI renders correctly at window widths from 800px to 2560px.
FR37: [P3] The browser blocks tracker and advertisement requests by matching URLs against a bundled blocklist (e.g., EasyList format). Acceptance: blocking tests verify that requests matching 10+ known tracker patterns are prevented, and non-matching requests proceed normally.
FR38: The browser enforces same-origin policy: JavaScript on origin A cannot read DOM content, cookies, or network responses from origin B (where A and B differ in scheme, host, or port). Acceptance: cross-origin access tests verify blocked read access for each resource type.
FR39: The browser blocks top-level navigation to javascript: URIs and data: URIs. Sub-resource loading of data: URIs is permitted. Acceptance: navigation blocking tests verify blocked and permitted cases.
FR40: [P3] The browser persists cookies and session data to disk and restores them on application restart. Acceptance: restart persistence tests verify cookie availability after process termination and relaunch.
FR41: [P1 -- done] The browser serves previously cached HTTP responses when the origin server is unreachable, subject to Cache-Control freshness rules. Acceptance: offline tests verify cached page display when network requests fail.
FR42: [P2] The browser provides localStorage (persistent, 5MB per origin) and sessionStorage (per-tab, cleared on tab close) to JavaScript. Acceptance: Web Storage tests verify getItem/setItem/removeItem/clear behavior, storage limits, and cross-origin isolation.
FR43: [P3] The browser discovers and uses OS-installed fonts on macOS (Core Text) and Linux (fontconfig), falling back to bundled Noto Sans. Acceptance: font discovery tests verify at least 3 system fonts are available beyond the bundled set on each supported platform.
FR44: [P3] The user copies selected text to the system clipboard and pastes text from the clipboard into form inputs. Acceptance: clipboard tests verify round-trip copy/paste of plain text content.
FR45: [P3] The browser presents native file dialogs for file upload (<input type="file">) and download (Content-Disposition: attachment). Acceptance: file dialog tests verify dialog presentation and correct file data transfer.
FR46: [P3] The browser registers as the default URL handler on macOS and Linux so that clicking links in other applications opens rust_browser. Acceptance: URL handler registration tests verify correct launch from an external link on each platform.
FR47: [P2] The browser passes 90%+ of CSS 2.1 Web Platform Tests as measured by the WPT harness in CI.
FR48: [P2] The browser passes 95%+ of the full tc39/test262 ECMAScript conformance suite (50,000+ tests) as measured by the Test262 harness.
FR49: [P2] The browser passes 90%+ of HTML5 Web Platform Tests as measured by the WPT harness in CI.
FR50: The browser handles malformed HTML, CSS, and JavaScript input without crashing. Acceptance: fuzz tests and malformed-input test suites covering each parser run without panics.
### NonFunctional Requirements
NFR1: Page load and first paint for a content-heavy site (CNN, Hacker News) completes within 3 seconds on an M1 MacBook or equivalent. Measured by timing from navigation start to first paint event in debug logs.
NFR2: Scrolling maintains 30+ frames per second on pages with up to 500 DOM elements. Measured by frame timing instrumentation in the render loop.
NFR3: No single JavaScript task blocks the rendering thread for more than 100ms. Measured by task duration logging in the event loop.
NFR4: The browser starts up and displays the address bar ready for URL input within 2 seconds from process launch. Measured by startup timing instrumentation.
NFR5: Resident memory usage does not grow by more than 50MB after navigating to 20 different pages and returning to the first. Measured by RSS sampling before and after the navigation sequence.
NFR6: All parsers (HTML, CSS, JavaScript) handle malformed and adversarial input without panics or undefined behavior. Verified by fuzz test suites covering each parser with 10,000+ random inputs without crashes.
NFR7: The unsafe keyword is forbidden in all crates except the two designated platform-integration crates. Verified by an automated CI check that scans source files and fails the build on violations.
NFR8: JavaScript on origin A cannot read DOM content, cookies, or fetch responses from origin B (different scheme, host, or port). Verified by cross-origin integration tests covering each resource type.
NFR9: Top-level navigation to javascript: and data: URIs is blocked; sub-resource data: URIs are permitted. Verified by navigation tests for each URI scheme.
NFR10: The browser binary contains zero telemetry, analytics, or tracking code. Verified by code audit: no outbound network requests are made except those explicitly initiated by page content or user navigation.
NFR11: The browser does not crash on any valid or malformed web content. Parser, layout, and render failures produce user-visible error messages instead of panics. Verified by running the full WPT and Test262 suites plus malformed-input tests without process termination.
NFR12: The CI gate passes on every merged change, covering formatting, linting, all test suites, safety policy, and metrics. Verified by CI pass/fail status on every merge.
NFR13: Every bug fix includes at least one regression test that reproduces the bug and verifies the fix. Verified by code review policy.
NFR14: Conformance test suites (golden tests, WPT, Test262) run on every CI build. Any test that previously passed and now fails blocks the merge. Verified by CI harness exit codes.
NFR15: The browser displays a user-visible error page (not a blank screen or hang) within 10 seconds of a network failure (timeout, DNS error, connection refused). Verified by network failure integration tests with simulated failures.
NFR16: No crate in a lower architectural layer depends on a crate in a higher layer. Verified by an automated dependency check in CI that parses Cargo.toml files and fails on violations.
NFR17: Each crate has a single documented responsibility. No crate's public API surface exceeds 50 exported items. Verified by periodic API surface audit.
NFR18: No source file exceeds 1,000 lines. Verified by an automated file-size check in CI.
NFR19: New external dependencies require documented rationale and workspace-level version pinning. Verified by code review policy.
NFR20: Implementation of non-obvious spec behavior includes a comment citing the relevant spec section (e.g., CSS 2.1 section 8.3.1). Verified by code review policy.
NFR21: The total crate count does not exceed 30 and total source file count does not exceed 500. Verified by periodic metrics collection in CI.
### Additional Requirements
From Architecture document:
- **Brownfield project** -- no starter template needed; all new work extends existing 22-crate, 4-layer architecture
- **Cookie jar module in `net`** with domain scoping and swappable backing store interface for later `storage`-backed persistence
- **HTTP cache** -- in-memory first, disk persistence later via `storage` crate
- **Storage crate** serves as general-purpose persistence layer for all disk-persisted data (cookies, cache, localStorage, sessionStorage)
- **CSS property implementation order** enforced: parse (css/) → computed style (style/) → layout effect (layout/) → paint effect (display_list/) → golden test → checklist update → CI
- **HTML element implementation order** enforced: parse (html/) → DOM (dom/) → UA styling (style/) → layout (layout/) → paint (display_list/) → runtime behavior (web_api/) → golden test → checklist update → CI
- **JS feature implementation order** enforced: tokenization (js_parser/) → AST (js_parser/) → execution (js_vm/) → unit tests → Test262 manifest → feature matrix update → CI
- **Bytecode IR introduction** deferred until generators/async-await become priority -- AST walker sufficient for current spec compliance work
- **Compositor thread** as first concurrency step -- consuming immutable display lists for async rasterization
- **JS yield mechanism** via cooperative yielding with statement counter (existing `max_statements` in VmConfig)
- **Web API crate scaling** -- module-per-domain initially, extract to `web_api_<domain>` crates when complexity warrants (~10-15 files)
- **System font discovery** through `platform/` OS-specific trait, `fonts` crate provides `FontProvider` facade
- **Clipboard & file dialogs** wrapped in `platform/` behind traits, consumed by `app_browser`
- **Single-process model** now; multi-process architecture designed when tabs are implemented
- **Tab state isolation** -- fully isolated per tab (own DOM, JS engine, styles, layout); cookie jar shared semantically
- **Error handling** -- thiserror-derived specific error types in parsers, SharedResult<T> in engine crates, domain conversions at bridge boundaries
- **Spec citations** required for non-obvious behavior (CSS 2.1 §X.Y.Z, HTML §X.Y.Z, ECMAScript §X.Y.Z)
- **Dependency addition protocol** -- check std first, pin in workspace, document rationale, pass deny.toml
### FR Coverage Map
FR1: Epic 2 - HTML parsing and DOM tree construction
FR2: Epic 1 - CSS parsing and style computation
FR3: Epic 1 - Layout computation (block, inline, flex, table, positioned)
FR4: Epic 1 - Display list generation and rasterization
FR5a: Epic 1 - Font selection (font-family, font-weight, font-style)
FR5b: Epic 1 - Line breaking and text rendering
FR6: Epic 2 - Image rendering (PNG, JPEG, GIF, WebP, SVG)
FR7a: Epic 1 - CSS backgrounds and borders
FR7b: Epic 1 - Box-shadow, gradients, opacity
FR8: Epic 1 - CSS generated content (::before, ::after)
FR9: Epic 1 - Selector matching and cascade resolution
FR10: Epic 1 - CSS inheritance and initial/inherit/unset keywords
FR11: Epic 3 - JavaScript parsing and execution
FR12: Epic 2 - Script loading (inline, external, async, defer)
FR13: Epic 2 (DOM infrastructure) + Epic 3 (JS bindings) - DOM manipulation APIs
FR14: Epic 3 - Event dispatch (capture, target, bubble phases)
FR15: Epic 3 - Microtasks, macrotasks, requestAnimationFrame
FR16: Epic 3 - Web API exposure (console, JSON, fetch, storage APIs)
FR17: Epic 3 - JavaScript error handling without crashing
FR18: Epic 5 - URL navigation
FR19: Epic 5 - Resource loading (HTTP, HTTPS, file://, data:)
FR20a: Epic 5 - HTTP redirect following
FR20b: Epic 5 - HTTP error response display
FR21: Epic 5 - Cookie management (P1 -- done, maintained)
FR22: Epic 5 - HTTP caching (P1 -- done, maintained)
FR23: Epic 5 - Session state persistence (P1 -- done, maintained)
FR24: Epic 5 - Forward/backward history navigation
FR25: Epic 2 - Base URL resolution (<base href>)
FR26: Epic 4 - Form control interaction
FR27: Epic 4 - Form submission (GET/POST, multipart/form-data)
FR28: Epic 4 - Client-side form validation
FR29: Epic 4 - Click, keyboard, scroll interaction
FR30: Epic 4 - Focus management and keyboard navigation
FR31: Epic 5 - Address bar display and editing
FR33: Epic 5 - Vertical and horizontal scrolling
FR34: Epic 5 - Loading indicator
FR35: Epic 5 - Reload and stop navigation
FR36: Epic 5 - Chrome UI rendering
FR38: Epic 6 - Same-origin policy enforcement
FR39: Epic 6 - javascript:/data: URI navigation blocking
FR41: Epic 5 - Offline cached response serving (P1 -- done, maintained)
FR42: Epic 6 - localStorage and sessionStorage
FR47: Epic 1 - CSS 2.1 WPT 90%+ pass rate
FR48: Epic 3 - Test262 95%+ pass rate
FR49: Epic 2 - HTML5 WPT 90%+ pass rate
FR50: Epic 6 - Malformed input handling without crashes
## Epic List
### Epic 1: Visual Fidelity -- CSS 2.1 Complete
Web pages render with full CSS 2.1 visual fidelity. Margin collapsing, stacking contexts, positioning, generated content, tables, backgrounds, borders, text, and overflow all work correctly. Sites like CNN and Hacker News look right.
**FRs covered:** FR2, FR3, FR4, FR5a, FR5b, FR7a, FR7b, FR8, FR9, FR10, FR47
## Epic 1: Visual Fidelity -- CSS 2.1 Complete
Web pages render with full CSS 2.1 visual fidelity. Margin collapsing, stacking contexts, positioning, generated content, tables, backgrounds, borders, text, and overflow all work correctly. Sites like CNN and Hacker News look right.
**FRs covered:** FR2, FR3, FR4, FR5a, FR5b, FR7a, FR7b, FR8, FR9, FR10
**Exit criterion:** FR47 -- CSS 2.1 WPT 90%+ pass rate
### Story 1.1: Margin Collapsing Completeness
As a web user,
I want pages to render with correct vertical spacing between elements,
So that text, headings, and content blocks have proper visual separation matching other browsers.
**Acceptance Criteria:**
**Given** two adjacent block-level siblings with bottom and top margins
**When** the page is rendered
**Then** the margins collapse to the larger of the two values per CSS 2.1 §8.3.1
**Given** a parent element with no border, padding, or clearance and a first/last child with margin
**When** the page is rendered
**Then** the child's margin collapses through the parent per CSS 2.1 §8.3.1
**Given** an empty block with top and bottom margins and no border, padding, or height
**When** the page is rendered
**Then** the top and bottom margins collapse into a single margin
**Given** an element with clearance set
**When** the page is rendered
**Then** margin collapsing is prevented at the clearance boundary
**And** golden tests cover each collapsing case, `docs/CSS2.1_Implementation_Checklist.md` is updated, and `just ci` passes.
### Story 1.2: Stacking Contexts & Z-Index
As a web user,
I want overlapping elements to render in the correct front-to-back order,
So that menus, modals, and layered content display correctly.
**Acceptance Criteria:**
**Given** an element with `position: relative/absolute/fixed` and a `z-index` value other than `auto`
**When** the page is rendered
**Then** a new stacking context is created per CSS 2.1 §9.9.1
**Given** elements within the same stacking context
**When** the page is rendered
**Then** painting order follows CSS 2.1 §E.2: backgrounds/borders → negative z-index → block flow → floats → inline flow → z-index 0/auto → positive z-index
**Given** nested stacking contexts
**When** the page is rendered
**Then** child stacking contexts are painted atomically within their parent's z-order position
**And** golden tests cover overlapping positioned elements with various z-index values, checklist is updated, and `just ci` passes.
### Story 1.3: Positioning Completeness
As a web user,
I want fixed-position headers, tooltips, and absolutely positioned elements to appear in the correct location,
So that page layouts with positioned elements render correctly.
**Acceptance Criteria:**
**Given** an element with `position: fixed`
**When** the page is scrolled
**Then** the element remains fixed relative to the viewport
**Given** a positioned element with `top`, `right`, `bottom`, `left` set to `auto`
**When** the page is rendered
**Then** auto values resolve per CSS 2.1 §10.6.4 and §10.3.7 based on the element's static position
**Given** a positioned element with `clip: rect(...)`
**When** the page is rendered
**Then** the element's visible area is clipped to the specified rectangle per CSS 2.1 §11.1.2
**Given** an absolutely positioned element within a relatively positioned container
**When** the page is rendered
**Then** the element is positioned relative to its containing block's padding edge
**And** golden tests cover fixed positioning, auto resolution, and clip, checklist is updated, and `just ci` passes.
### Story 1.4: Generated Content
As a web user,
I want CSS-generated content (bullets, quotes, labels) to render correctly,
So that pages using `::before` and `::after` pseudo-elements display as intended.
**Acceptance Criteria:**
**Given** a CSS rule with `::before` or `::after` and a `content` property with a string value
**When** the page is rendered
**Then** the string content is inserted as an inline box before/after the element's content per CSS 2.1 §12.1
**Given** a `content` value using `attr()`
**When** the page is rendered
**Then** the attribute value from the HTML element is inserted as generated content
**Given** a `content` value using `counter()` with `counter-reset` and `counter-increment`
**When** the page is rendered
**Then** the counter value is computed and displayed per CSS 2.1 §12.4
**Given** generated content with styling (color, font-size, display)
**When** the page is rendered
**Then** the pseudo-element is styled independently from its originating element
**And** golden tests cover string content, attr(), counter(), checklist is updated, and `just ci` passes.
### Story 1.5: Table Layout Completeness
As a web user,
I want HTML tables to render with correct cell sizing, borders, and captions,
So that tabular data displays correctly on real websites.
**Acceptance Criteria:**
**Given** a table with `border-collapse: collapse`
**When** the page is rendered
**Then** adjacent cell borders are merged using the conflict resolution rules per CSS 2.1 §17.6.2
**Given** a table with `border-collapse: separate` and `border-spacing`
**When** the page is rendered
**Then** cells are separated by the specified spacing
**Given** a table with `caption-side: top` or `caption-side: bottom`
**When** the page is rendered
**Then** the caption is placed above or below the table box respectively
**Given** a table with `empty-cells: hide` and cells containing no content
**When** the page is rendered
**Then** borders and backgrounds of empty cells are not drawn
**Given** a table with cells spanning rows/columns and percentage/fixed widths
**When** the page is rendered
**Then** the table layout algorithm distributes space correctly per CSS 2.1 §17.5
**And** golden tests cover each table feature, checklist is updated, and `just ci` passes.
### Story 1.6: Lists & Counters
As a web user,
I want ordered and unordered lists to render with correct markers and numbering,
So that list content displays properly on real websites.
**Acceptance Criteria:**
**Given** a list element with `list-style-position: inside` or `outside`
**When** the page is rendered
**Then** the marker is positioned inside or outside the list item's content area per CSS 2.1 §12.5.1
**Given** a list with `list-style-image` pointing to a valid URL
**When** the page is rendered
**Then** the specified image is used as the list marker
**Given** elements with `counter-reset` and `counter-increment` properties
**When** the page is rendered
**Then** counters are created, incremented, and scoped correctly per CSS 2.1 §12.4
**Given** nested lists with automatic counter numbering
**When** the page is rendered
**Then** each nesting level maintains its own counter scope
**And** golden tests cover list marker positioning, custom images, and nested counters, checklist is updated, and `just ci` passes.
### Story 1.7: Backgrounds
As a web user,
I want page and element backgrounds to render correctly with images, patterns, and positioning,
So that visually rich websites display as intended.
**Acceptance Criteria:**
**Given** an element with the full `background` shorthand property
**When** the page is rendered
**Then** all background sub-properties (color, image, repeat, attachment, position) are parsed and applied correctly per CSS 2.1 §14.2.1
**Given** an element with `background-image: url(...)` and `background-repeat`
**When** the page is rendered
**Then** the image is tiled according to the repeat value (repeat, repeat-x, repeat-y, no-repeat)
**Given** an element with `background-attachment: fixed`
**When** the page is scrolled
**Then** the background image remains fixed relative to the viewport
**Given** an element with `background-position` using keyword, percentage, or length values
**When** the page is rendered
**Then** the background image is positioned correctly within the element's padding box
**And** golden tests cover each background property combination, checklist is updated, and `just ci` passes.
### Story 1.8: Borders & Outline
As a web user,
I want all CSS border styles and outlines to render correctly,
So that element borders display with the correct visual appearance.
**Acceptance Criteria:**
**Given** an element with `border-style` set to `double`
**When** the page is rendered
**Then** two parallel lines with a gap between them are drawn per CSS 2.1 §8.5.3
**Given** an element with `border-style` set to `groove`, `ridge`, `inset`, or `outset`
**When** the page is rendered
**Then** the 3D border effect is rendered with appropriate light/dark color variations
**Given** an element with `outline` properties (outline-style, outline-width, outline-color)
**When** the page is rendered
**Then** the outline is drawn outside the border edge without affecting layout per CSS 2.1 §18.4
**Given** an element with `outline-offset`
**When** the page is rendered
**Then** the outline is offset from the border edge by the specified amount
**And** golden tests cover each border style and outline, checklist is updated, and `just ci` passes.
### Story 1.9: Text Properties
As a web user,
I want text to render with correct indentation, decoration, spacing, and directionality,
So that text-heavy pages display properly across languages and styles.
**Acceptance Criteria:**
**Given** an element with `text-indent`
**When** the page is rendered
**Then** the first line of the block is indented by the specified amount per CSS 2.1 §16.1
**Given** an element with `text-decoration: underline | overline | line-through` (including inherited/accumulated values)
**When** the page is rendered
**Then** the decorations are drawn correctly and propagate to inline descendants per CSS 2.1 §16.3
**Given** an element with `word-spacing` or `letter-spacing`
**When** the page is rendered
**Then** additional spacing is applied between words or characters respectively
**Given** an element with `direction: rtl` and `unicode-bidi`
**When** the page is rendered
**Then** text is laid out right-to-left with correct bidi reordering per CSS 2.1 §9.10
**And** golden tests cover each text property, checklist is updated, and `just ci` passes.
### Story 1.10: Font Properties
As a web user,
I want font styles to render correctly including shorthand declarations and variant styles,
So that typography on web pages matches the designer's intent.
**Acceptance Criteria:**
**Given** an element with the `font` shorthand property
**When** the page is rendered
**Then** all font sub-properties (style, variant, weight, size, line-height, family) are parsed and applied correctly per CSS 2.1 §15.8
**Given** an element with `font-variant: small-caps`
**When** the page is rendered
**Then** lowercase characters are rendered as small capital letters
**Given** a CSS value using `ex` units
**When** the page is rendered
**Then** the unit resolves to the x-height of the element's font per CSS 2.1 §4.3.2
**Given** font metrics from the bundled font set
**When** computing line-height and baseline alignment
**Then** the correct ascent, descent, and x-height values are used for layout calculations
**And** golden tests cover font shorthand, small-caps, and ex units, checklist is updated, and `just ci` passes.
### Story 1.11: Overflow
As a web user,
I want content that exceeds its container to be clipped or scrollable as specified,
So that pages with constrained containers display correctly.
**Acceptance Criteria:**
**Given** an element with `overflow: hidden` and content exceeding its bounds
**When** the page is rendered
**Then** overflowing content is clipped at the element's padding edge
**Given** an element with `overflow: scroll`
**When** the page is rendered
**Then** a scrolling mechanism is provided regardless of whether content overflows
**Given** an element with `overflow: auto` and content exceeding its bounds
**When** the page is rendered
**Then** a scrolling mechanism is provided only when content overflows
**Given** an element with overflow clipping and positioned children
**When** the page is rendered
**Then** clipping is applied correctly to the element's content and descendants per CSS 2.1 §11.1.1
**And** golden tests cover each overflow value, checklist is updated, and `just ci` passes.
### Story 1.12: Media Rules
As a web user,
I want stylesheets imported via `@import` and conditional `@media` rules to apply correctly,
So that pages load external stylesheets and respond to media types.
**Acceptance Criteria:**
**Given** a stylesheet with `@import url("other.css")`
**When** the page is rendered
**Then** the imported stylesheet's rules are fetched and applied with correct cascade order per CSS 2.1 §6.3
**Given** a stylesheet with `@import url("print.css") print`
**When** rendering for screen media type
**Then** the imported stylesheet is not applied
**Given** a `@media screen { ... }` block
**When** rendering for screen media type
**Then** the rules inside the block are applied
**Given** a `@media print { ... }` block
**When** rendering for screen media type
**Then** the rules inside the block are not applied
**And** golden tests cover @import and @media rules, checklist is updated, and `just ci` passes.
### Story 1.13: CSS Inheritance Completeness
As a web user,
I want CSS property values to correctly inherit, reset, and cascade,
So that styling behaves predictably across nested elements.
**Acceptance Criteria:**
**Given** an element with a property set to `inherit`
**When** the page is rendered
**Then** the element uses its parent's computed value for that property per CSS 2.1 §6.2.1
**Given** an element with a property set to `initial`
**When** the page is rendered
**Then** the element uses the property's initial value per its specification
**Given** an element with a property set to `unset`
**When** the page is rendered
**Then** the property behaves as `inherit` if it's an inherited property, or `initial` if it's not
**Given** all CSS 2.1 properties
**When** checking inheritance behavior
**Then** each property correctly defaults to inherited or non-inherited per its CSS 2.1 specification
**And** golden tests cover inherit/initial/unset for both inherited and non-inherited properties, checklist is updated, and `just ci` passes.
---
## Epic 2: Document Completeness -- HTML5 Full Support
All HTML5 elements and document features work correctly. Full tokenizer state machine, tree builder insertion modes, DOM core APIs (DocumentFragment, insertBefore, replaceChild, live collections, querySelector/querySelectorAll), document lifecycle events, script loading modes, and base URL resolution.
**FRs covered:** FR1, FR6, FR12, FR13 (DOM infrastructure), FR25
**Exit criterion:** FR49 -- HTML5 WPT 90%+ pass rate
### Story 2.1: HTML5 Tokenizer Completeness
As a web user,
I want all HTML content to be parsed correctly regardless of markup patterns,
So that pages render properly even with unusual or complex HTML.
**Acceptance Criteria:**
**Given** HTML content using all tokenizer states (data, RCDATA, RAWTEXT, script data, PLAINTEXT, etc.)
**When** the HTML is parsed
**Then** each state transition produces the correct tokens per WHATWG HTML §13.2.5
**Given** HTML with character references (named, numeric, hexadecimal) in various contexts
**When** the HTML is parsed
**Then** character references are resolved correctly per their context (attribute vs. content)
**Given** HTML with CDATA sections, processing instructions, and bogus comments
**When** the HTML is parsed
**Then** each construct is tokenized according to the spec without errors
**Given** malformed HTML with unclosed tags, missing quotes, and invalid characters
**When** the HTML is parsed
**Then** the tokenizer recovers gracefully without panics per the spec's error handling rules
**And** golden tests cover edge-case tokenizer states, `docs/HTML5_Implementation_Checklist.md` is updated, and `just ci` passes.
### Story 2.2: Tree Builder Insertion Modes
As a web user,
I want the browser to construct the correct DOM tree from any HTML document,
So that page structure matches what other browsers produce.
**Acceptance Criteria:**
**Given** HTML content triggering each tree builder insertion mode (initial, before html, before head, in head, in body, in table, in select, after body, etc.)
**When** the HTML is parsed
**Then** elements are inserted into the correct location in the DOM tree per WHATWG HTML §13.2.6
**Given** HTML with implicit element creation (e.g., `<td>` without `<table>`, text before `<html>`)
**When** the HTML is parsed
**Then** missing elements are created automatically per the spec's implied open/close rules
**Given** HTML with misnested block/inline elements (e.g., `<p><div></div></p>`)
**When** the HTML is parsed
**Then** the tree builder splits and restructures elements per the spec
**Given** HTML with elements that change insertion mode (tables, select, template, etc.)
**When** the HTML is parsed
**Then** the correct insertion mode is activated and deactivated at the right boundaries
**And** WPT tree-construction tests pass for all covered insertion modes, checklist is updated, and `just ci` passes.
### Story 2.3: Adoption Agency & Foster Parenting
As a web user,
I want misnested formatting tags and misplaced table content to render correctly,
So that real-world pages with imperfect HTML display as expected.
**Acceptance Criteria:**
**Given** HTML with misnested formatting elements (e.g., `<b>text<i>more</b>rest</i>`)
**When** the HTML is parsed
**Then** the adoption agency algorithm restructures the DOM tree so formatting is correctly applied per WHATWG HTML §13.2.6.4.7
**Given** the adoption agency algorithm running on deeply nested formatting (8+ levels)
**When** the HTML is parsed
**Then** the algorithm respects the iteration and nesting limits defined in the spec
**Given** HTML with non-table content directly inside `<table>`, `<tbody>`, `<tr>` elements
**When** the HTML is parsed
**Then** the content is foster-parented to the correct location before the table per WHATWG HTML §13.2.6.1
**Given** a combination of foster parenting and adoption agency in the same document
**When** the HTML is parsed
**Then** both algorithms interact correctly producing the spec-defined DOM tree
**And** WPT tree-construction tests covering adoption agency and foster parenting pass, checklist is updated, and `just ci` passes.
### Story 2.4: DOM Tree Mutation APIs
As a web developer using JavaScript,
I want to create, insert, replace, and move DOM nodes programmatically,
So that dynamic web pages can modify their structure at runtime.
**Acceptance Criteria:**
**Given** JavaScript calling `document.createDocumentFragment()`
**When** nodes are appended to the fragment and the fragment is inserted into the DOM
**Then** all child nodes transfer to the insertion point and the fragment becomes empty per DOM §4.5
**Given** JavaScript calling `parentNode.insertBefore(newNode, referenceNode)`
**When** the operation completes
**Then** the new node is inserted before the reference node, or appended if reference is null
**Given** JavaScript calling `parentNode.replaceChild(newChild, oldChild)`
**When** the operation completes
**Then** the old child is removed and the new child takes its place in the DOM tree
**Given** a node being inserted that already exists elsewhere in the DOM
**When** the insertion API is called
**Then** the node is moved (removed from its current parent and inserted at the new location)
**And** integration tests verify each mutation API, `docs/DOM_Implementation_Checklist.md` is updated, and `just ci` passes.
### Story 2.5: DOM Query APIs & Live Collections
As a web developer using JavaScript,
I want to query the DOM by CSS selectors and access live element collections,
So that scripts can efficiently find and track elements in the document.
**Acceptance Criteria:**
**Given** JavaScript calling `document.querySelector(selector)` with a valid CSS selector
**When** the query executes
**Then** the first matching element is returned, or null if no match exists
**Given** JavaScript calling `document.querySelectorAll(selector)`
**When** the query executes
**Then** a static NodeList of all matching elements is returned in document order
**Given** JavaScript calling `document.getElementsByTagName(name)` or `document.getElementsByClassName(name)`
**When** the DOM is subsequently modified (elements added/removed)
**Then** the returned HTMLCollection reflects the changes automatically (live collection)
**Given** complex CSS selectors (combinators, pseudo-classes like `:first-child`, `:nth-child`, attribute selectors)
**When** used with querySelector/querySelectorAll
**Then** the selectors match correctly using the existing selector matching engine
**And** integration tests verify query APIs and live collection behavior, DOM checklist is updated, and `just ci` passes.
### Story 2.6: Script Loading -- async/defer
As a web user,
I want pages to load faster by running scripts asynchronously or after parsing,
So that script-heavy pages don't block rendering unnecessarily.
**Acceptance Criteria:**
**Given** a `<script defer src="...">` element
**When** the HTML is parsed
**Then** the script is fetched in parallel with parsing and executed after the document is fully parsed, in document order per WHATWG HTML §4.12.1
**Given** a `<script async src="...">` element
**When** the HTML is parsed
**Then** the script is fetched in parallel and executed as soon as it's available, regardless of document order
**Given** multiple `<script defer>` elements in a document
**When** all scripts have loaded and the document is parsed
**Then** they execute in the order they appear in the document
**Given** a `<script>` with both `async` and `defer` attributes
**When** the HTML is parsed
**Then** the `async` attribute takes precedence per the spec
**And** integration tests verify each loading mode's execution timing and ordering, checklist is updated, and `just ci` passes.
### Story 2.7: Document Lifecycle
As a web developer using JavaScript,
I want document lifecycle events to fire at the correct times,
So that scripts can initialize at the right point in page loading.
**Acceptance Criteria:**
**Given** a page with a `DOMContentLoaded` event listener
**When** the HTML has been fully parsed (but stylesheets/images may still be loading)
**Then** the `DOMContentLoaded` event fires on the document
**Given** a page with a `load` event listener on the window
**When** all resources (images, stylesheets, scripts) have finished loading
**Then** the `load` event fires
**Given** JavaScript reading `document.readyState`
**When** the document is in different loading phases
**Then** it returns `"loading"` during parsing, `"interactive"` after parsing (before load), and `"complete"` after all resources load
**Given** a `readystatechange` event listener
**When** `document.readyState` changes
**Then** the event fires for each transition
**And** integration tests verify event timing and readyState transitions, checklist is updated, and `just ci` passes.
### Story 2.8: iframe Support
As a web user,
I want embedded content in iframes to load and render,
So that pages using iframes for embedded documents display correctly.
**Acceptance Criteria:**
**Given** an `<iframe src="...">` element in a page
**When** the page is rendered
**Then** the iframe's source document is fetched, parsed, and rendered within the iframe's content area
**Given** an iframe with `width` and `height` attributes or CSS sizing
**When** the page is rendered
**Then** the iframe's content area matches the specified dimensions
**Given** an iframe document with its own stylesheets and scripts
**When** the iframe is rendered
**Then** styles and scripts are scoped to the iframe's document and do not affect the parent
**Given** an iframe with `srcdoc` attribute
**When** the page is rendered
**Then** the inline HTML content is parsed and rendered as the iframe's document
**And** golden tests cover iframe rendering, checklist is updated, and `just ci` passes.
### Story 2.9: Base URL Resolution & Image Rendering Completeness
As a web user,
I want all relative URLs to resolve correctly and all image formats to render,
So that pages with relative links and various image types display properly.
**Acceptance Criteria:**
**Given** a document with `<base href="https://example.com/path/">`
**When** relative URLs are resolved (in links, images, scripts, stylesheets)
**Then** the base URL is used instead of the document's URL per WHATWG HTML §4.2.3
**Given** multiple `<base>` elements in a document
**When** URLs are resolved
**Then** only the first `<base>` with an `href` attribute is used
**Given** images in PNG, JPEG, GIF, WebP, and SVG formats referenced as `<img>` or CSS `background-image`
**When** the page is rendered
**Then** each format decodes and renders correctly at the specified dimensions
**Given** an `<img>` with `width`/`height` attributes and/or CSS sizing
**When** the image is rendered
**Then** the image scales to the specified dimensions while the intrinsic aspect ratio is used for `auto` dimensions
**And** golden tests cover base URL resolution and each image format, checklists are updated, and `just ci` passes.
---
## Epic 3: Interactive Web -- JavaScript Engine Maturity
JS-heavy websites function. Generators, async/await, ES modules, complete built-in coverage, and 95%+ Test262 conformance. DOM manipulation via JS bindings, full event dispatch, microtask/macrotask scheduling, Web API exposure, and robust error handling.
**FRs covered:** FR11, FR13 (JS bindings), FR14, FR15, FR16, FR17
**Exit criterion:** FR48 -- Test262 95%+ pass rate
### Story 3.1: Bytecode IR Introduction
As a browser developer,
I want the JavaScript engine to execute via a bytecode interpreter instead of an AST walker,
So that suspension semantics (generators, async/await) can be cleanly implemented and execution performance improves.
**Acceptance Criteria:**
**Given** the existing JavaScript test suite (vendored Test262 + unit tests)
**When** execution is switched from AST walker to bytecode interpreter
**Then** all previously passing tests continue to pass with identical results
**Given** a JavaScript program
**When** it is executed
**Then** the js_parser produces an AST, a bytecode compiler emits bytecode instructions, and the bytecode interpreter executes them
**Given** the bytecode instruction set
**When** reviewed against the ECMAScript spec
**Then** it supports all currently implemented language features (variables, functions, closures, control flow, try/catch, classes, etc.)
**Given** the bytecode interpreter's execution model
**When** a suspension point is needed (for future generators/async-await)
**Then** the interpreter's frame/stack design supports saving and restoring execution state
**And** `docs/js_feature_matrix.md` is updated to note the bytecode transition, and `just ci` passes.
### Story 3.2: Generators & Iterator Protocol
As a web developer using JavaScript,
I want generator functions and the iterator protocol to work,
So that lazy sequences, custom iterables, and for...of loops function correctly.
**Acceptance Criteria:**
**Given** a generator function declared with `function*`
**When** called
**Then** it returns a generator object without executing the body
**Given** a generator object
**When** `next()` is called
**Then** execution resumes from the last `yield` point and returns `{value, done}` per ECMAScript §27.5
**Given** a generator with `yield*` delegating to another iterable
**When** iterated
**Then** values from the inner iterable are yielded one at a time
**Given** an object implementing the iterator protocol (`Symbol.iterator`, `next()`)
**When** used with `for...of`, spread syntax, or destructuring
**Then** the iteration protocol is followed correctly
**Given** a generator with `return()` or `throw()` called on it
**When** the method is invoked
**Then** the generator completes or throws at the current suspension point
**And** Test262 generator/iterator tests are promoted in the manifest, feature matrix is updated, and `just ci` passes.
### Story 3.3: async/await
As a web developer using JavaScript,
I want async functions and await expressions to work,
So that asynchronous code can be written in a readable, sequential style.
**Acceptance Criteria:**
**Given** a function declared with `async function`
**When** called
**Then** it returns a Promise that resolves with the function's return value
**Given** an `await` expression inside an async function
**When** the awaited value is a Promise
**Then** execution suspends until the Promise settles, then resumes with the resolved value or throws the rejection
**Given** an `await` expression with a non-Promise value
**When** executed
**Then** the value is wrapped in a resolved Promise and execution continues
**Given** a `try/catch` block inside an async function with an awaited rejected Promise
**When** the Promise rejects
**Then** the rejection is caught by the catch block
**Given** multiple async functions with interleaved awaits
**When** executed
**Then** microtask scheduling follows the correct order per ECMAScript §27.7
**And** Test262 async/await tests are promoted in the manifest, feature matrix is updated, and `just ci` passes.
### Story 3.4: ES Modules
As a web developer using JavaScript,
I want import/export statements and `<script type="module">` to work,
So that modular JavaScript code loads and executes correctly.
**Acceptance Criteria:**
**Given** a `<script type="module" src="...">` element
**When** the page is loaded
**Then** the module is fetched, parsed, and executed in strict mode with deferred timing per WHATWG HTML §4.12.1
**Given** a module with `import { foo } from './other.js'`
**When** the module is executed
**Then** the binding is resolved from the target module's exports per ECMAScript §16.2
**Given** a module with `export default` and named `export` declarations
**When** imported by another module
**Then** the exported bindings are available to the importing module
**Given** circular module dependencies (A imports B, B imports A)
**When** the modules are loaded
**Then** the module registry handles the cycle without deadlock, with uninitialized bindings where appropriate per ECMAScript §16.2.1.5.2
**Given** a module imported by multiple other modules
**When** the page is loaded
**Then** the module is fetched and evaluated exactly once (singleton semantics)
**And** Test262 module tests are promoted, feature matrix is updated, and `just ci` passes.
### Story 3.5: Built-in Completeness -- Array/String/Object
As a web developer using JavaScript,
I want all standard Array, String, and Object methods to be available,
So that common JavaScript patterns and library code work correctly.
**Acceptance Criteria:**
**Given** Array methods (flat, flatMap, findIndex, findLast, findLastIndex, from, of, at, toReversed, toSorted, toSpliced, with, etc.)
**When** called on arrays
**Then** each method behaves per its ECMAScript specification
**Given** String methods (replaceAll, matchAll, trimStart, trimEnd, padStart, padEnd, startsWith, endsWith, at, etc.)
**When** called on strings
**Then** each method behaves per its ECMAScript specification
**Given** Object methods (fromEntries, hasOwn, entries, keys, values, assign, getOwnPropertyDescriptors, etc.)
**When** called
**Then** each method behaves per its ECMAScript specification
**Given** methods that accept callback functions (map, filter, reduce, sort, etc.)
**When** the callback throws an error
**Then** the error propagates correctly without corrupting internal state
**And** Test262 tests for each built-in are promoted in the manifest, feature matrix is updated, and `just ci` passes.
### Story 3.6: Built-in Completeness -- Date/RegExp/Map/Set
As a web developer using JavaScript,
I want Date, RegExp, Map, Set, WeakMap, and WeakSet to work completely,
So that date handling, pattern matching, and collection types function correctly.
**Acceptance Criteria:**
**Given** Date construction, parsing, and formatting methods
**When** called with various inputs (ISO strings, timestamps, individual components)
**Then** each method behaves per ECMAScript §21.4 including edge cases (invalid dates, timezone handling)
**Given** RegExp with all flags (g, i, m, s, u, y, d) and advanced features (named groups, lookbehind, Unicode property escapes)
**When** used with `test()`, `exec()`, `match()`, `matchAll()`, `replace()`, `split()`
**Then** each operation behaves per ECMAScript §22.2
**Given** Map and Set with their full method sets (set/get/has/delete/clear/forEach/entries/keys/values)
**When** used with various key types (objects, primitives, NaN, -0)
**Then** each method behaves per ECMAScript §24.1-24.2
**Given** WeakMap and WeakSet with object keys
**When** keys are no longer referenced elsewhere
**Then** entries are eligible for garbage collection (not required to be immediate)
**And** Test262 tests for each built-in are promoted in the manifest, feature matrix is updated, and `just ci` passes.
### Story 3.7: WeakRef, FinalizationRegistry & Strict Mode Edge Cases
As a web developer using JavaScript,
I want advanced memory management APIs and complete strict mode support,
So that all ECMAScript edge cases are handled correctly.
**Acceptance Criteria:**
**Given** a `WeakRef` wrapping an object
**When** `deref()` is called
**Then** the target object is returned if still alive, or `undefined` if collected per ECMAScript §26.1
**Given** a `FinalizationRegistry` with a registered target
**When** the target is garbage collected
**Then** the cleanup callback is eventually called with the held value per ECMAScript §26.2
**Given** strict mode code with assignments to undeclared variables
**When** executed
**Then** a ReferenceError is thrown instead of creating a global
**Given** strict mode edge cases (duplicate parameter names, `with` statement, octal literals, `delete` on unqualified identifiers)
**When** parsed or executed in strict mode
**Then** SyntaxError or appropriate errors are thrown per ECMAScript §10.2.1
**And** Test262 tests for WeakRef, FinalizationRegistry, and strict mode are promoted, feature matrix is updated, and `just ci` passes.
### Story 3.8: DOM Bindings via web_api
As a web developer using JavaScript,
I want full DOM manipulation capabilities from JavaScript,
So that dynamic web pages can create, modify, and style elements at runtime.
**Acceptance Criteria:**
**Given** JavaScript calling `document.createElement(tagName)`
**When** the element is created and appended to the DOM
**Then** the element is rendered with correct default styling and behavior
**Given** JavaScript accessing `element.classList` (add, remove, toggle, contains)
**When** classes are modified
**Then** the element's class attribute updates and styles are recomputed on the next render
**Given** JavaScript accessing `element.style.propertyName` for reading and writing
**When** inline styles are set or read
**Then** the values affect rendering and reflect the current inline style
**Given** JavaScript accessing `element.getAttribute()`, `setAttribute()`, `removeAttribute()`
**When** attributes are modified
**Then** the DOM reflects the changes and dependent behavior updates (e.g., `src` triggers fetch)
**Given** JavaScript accessing node properties (`textContent`, `innerHTML`, `childNodes`, `parentNode`, `nextSibling`)
**When** read or written
**Then** the values reflect the current DOM state and mutations trigger re-rendering
**And** integration tests verify each binding, DOM checklist is updated, and `just ci` passes.
### Story 3.9: Event Dispatch Completeness
As a web developer using JavaScript,
I want all event types and dispatch phases to work correctly,
So that interactive elements respond to user actions as expected.
**Acceptance Criteria:**
**Given** an event listener registered with `addEventListener(type, handler, {capture: true})`
**When** the event is dispatched
**Then** the handler fires during the capture phase (root to target) per DOM §2.9
**Given** mouse events (click, mousedown, mouseup, mouseover, mouseout, mousemove)
**When** dispatched to JavaScript handlers
**Then** event objects include correct properties (clientX, clientY, button, target)
**Given** keyboard events (keydown, keyup, keypress)
**When** dispatched to JavaScript handlers
**Then** event objects include correct properties (key, code, ctrlKey, shiftKey, altKey)
**Given** focus events (focus, blur, focusin, focusout)
**When** focus changes between elements
**Then** events fire in the correct order with correct relatedTarget values
**Given** `event.stopPropagation()` or `event.stopImmediatePropagation()` called in a handler
**When** the event continues dispatching
**Then** propagation stops at the current target (stopPropagation) or current handler (stopImmediatePropagation)
**And** integration tests verify each event type and dispatch behavior, and `just ci` passes.
### Story 3.10: Web API Exposure
As a web developer using JavaScript,
I want fetch, console, and scheduling APIs to work correctly,
So that network requests, debugging, and async task scheduling function properly.
**Acceptance Criteria:**
**Given** JavaScript calling `fetch(url)`
**When** the request completes
**Then** a Response object is returned with correct status, headers, and body methods (text(), json(), arrayBuffer())
**Given** JavaScript calling `console.log()`, `console.warn()`, `console.error()` with multiple arguments
**When** executed
**Then** all arguments are formatted and output correctly including object inspection
**Given** `setTimeout` and `setInterval` with callbacks and delay values
**When** the event loop runs
**Then** callbacks execute after the specified delay in correct macrotask order per HTML §8.6
**Given** `Promise.then()` microtasks interleaved with `setTimeout` macrotasks
**When** the event loop runs
**Then** all microtasks drain before the next macrotask executes
**Given** `requestAnimationFrame` callbacks
**When** the render loop runs
**Then** callbacks execute before the next paint in registration order
**And** integration tests verify each API's behavior, and `just ci` passes.
---
## Epic 4: User Input & Forms
Users fill out and submit forms on real websites. All form controls work, client-side validation provides feedback, multipart/form-data supports file uploads, focus and keyboard navigation work correctly.
**FRs covered:** FR26, FR27, FR28, FR29, FR30
### Story 4.1: Text Inputs & Textareas
As a web user,
I want to type text into input fields and textareas,
So that I can enter data into forms on websites.
**Acceptance Criteria:**
**Given** an `<input type="text">` element
**When** the user clicks on it and types
**Then** text appears in the input field with a visible cursor at the insertion point
**Given** an `<input>` with `type="password"`
**When** the user types
**Then** characters are masked (displayed as dots or asterisks)
**Given** an `<input>` with `placeholder` attribute and no value
**When** the input is rendered
**Then** the placeholder text is displayed in a dimmed style and disappears when the user types
**Given** a `<textarea>` element
**When** the user types multiple lines of text
**Then** the text wraps and the textarea scrolls to accommodate content exceeding its height
**Given** an `<input>` with `value`, `maxlength`, or `readonly` attributes
**When** the user interacts with it
**Then** the initial value is displayed, input is limited to maxlength characters, and readonly inputs reject editing
**And** integration tests verify each input type's behavior, golden tests cover rendering, and `just ci` passes.
### Story 4.2: Buttons, Checkboxes & Radio Buttons
As a web user,
I want to click buttons, toggle checkboxes, and select radio options,
So that I can make choices and trigger actions in web forms.
**Acceptance Criteria:**
**Given** a `<button>` or `<input type="submit">` element
**When** the user clicks it
**Then** the button's click event fires and submit buttons trigger form submission
**Given** an `<input type="checkbox">`
**When** the user clicks it
**Then** the checked state toggles and the `change` event fires
**Given** multiple `<input type="radio">` elements with the same `name` attribute
**When** the user selects one
**Then** the previously selected radio in the group is deselected and the `change` event fires
**Given** a `<label>` element associated with a form control (via `for` attribute or nesting)
**When** the user clicks the label
**Then** the associated control is activated (focused, toggled, or clicked)
**Given** form controls with `disabled` attribute
**When** the user attempts to interact
**Then** the control does not respond and is rendered in a disabled visual style
**And** integration tests verify each control type, golden tests cover rendering states, and `just ci` passes.
### Story 4.3: Select Menus & Option Elements
As a web user,
I want to choose from dropdown menus on web forms,
So that I can select options from predefined lists.
**Acceptance Criteria:**
**Given** a `<select>` element with `<option>` children
**When** the user clicks the select element
**Then** a dropdown list of options is displayed
**Given** an open select dropdown
**When** the user clicks an option
**Then** the option is selected, the dropdown closes, and the `change` event fires
**Given** a `<select>` with an `<option selected>` attribute
**When** the page is rendered
**Then** the pre-selected option is displayed as the current value
**Given** a `<select multiple>` element
**When** the user clicks options (with Ctrl/Cmd for multi-select)
**Then** multiple options can be selected simultaneously
**Given** a `<select>` with `<optgroup>` elements
**When** the dropdown is displayed
**Then** options are grouped under non-selectable group labels
**And** integration tests verify select behavior, golden tests cover dropdown rendering, and `just ci` passes.
### Story 4.4: Form Submission
As a web user,
I want forms to submit my data to the server,
So that I can log in, search, and interact with web applications.
**Acceptance Criteria:**
**Given** a `<form method="GET">` with filled form controls
**When** the form is submitted
**Then** form data is serialized as `application/x-www-form-urlencoded` and appended to the action URL as a query string
**Given** a `<form method="POST">` with filled form controls
**When** the form is submitted
**Then** form data is serialized as `application/x-www-form-urlencoded` in the request body
**Given** a `<form enctype="multipart/form-data" method="POST">`
**When** the form is submitted
**Then** form data is encoded using multipart MIME format with correct boundary delimiters
**Given** a form with disabled controls or controls without `name` attributes
**When** the form is submitted
**Then** those controls are excluded from the submitted data per HTML §4.10.21.3
**Given** a form with `action`, `method`, and `target` attributes
**When** submitted
**Then** the request is sent to the action URL using the specified method
**And** integration tests verify each submission method and encoding, and `just ci` passes.
### Story 4.5: Client-Side Form Validation
As a web user,
I want the browser to validate my form input before submission,
So that I get immediate feedback on errors without a server round-trip.
**Acceptance Criteria:**
**Given** an `<input required>` that is empty
**When** the form is submitted
**Then** submission is blocked and a validation message is shown on the invalid control
**Given** an `<input pattern="[A-Z]{3}">` with a value that doesn't match
**When** the form is submitted
**Then** submission is blocked and a pattern mismatch message is shown
**Given** an `<input type="number" min="1" max="100">` with a value outside the range
**When** the form is submitted
**Then** submission is blocked with a range overflow/underflow message
**Given** an `<input minlength="3" maxlength="50">` with a value outside the length bounds
**When** the form is submitted
**Then** submission is blocked with a too-short/too-long message
**Given** an `<input type="email">` or `<input type="url">` with an invalid value
**When** the form is submitted
**Then** submission is blocked with a type mismatch message
**Given** a form with `novalidate` attribute or a submit button with `formnovalidate`
**When** the form is submitted
**Then** client-side validation is skipped
**And** integration tests verify each constraint type, and `just ci` passes.
### Story 4.6: Click, Keyboard & Scroll Interaction
As a web user,
I want my clicks, key presses, and scroll actions to work correctly on all page content,
So that I can interact with web pages naturally.
**Acceptance Criteria:**
**Given** the user clicks on an element
**When** the click event is processed
**Then** the correct element receives the event based on hit testing (topmost visible element at the click coordinates)
**Given** the user presses keys while an element is focused
**When** the keydown/keyup events are processed
**Then** the correct key information is delivered to the focused element and default behaviors fire (e.g., typing in inputs, Enter on links)
**Given** the user scrolls via mouse wheel or trackpad
**When** the scroll event is processed
**Then** the correct scrollable container scrolls by the appropriate amount
**Given** a page with nested scrollable containers
**When** the inner container reaches its scroll boundary
**Then** scroll events propagate to the outer container (scroll chaining)
**And** integration tests verify hit testing, keyboard dispatch, and scroll behavior, and `just ci` passes.
### Story 4.7: Focus Management & Keyboard Navigation
As a web user,
I want to navigate between interactive elements using the Tab key,
So that I can use web forms and pages without a mouse.
**Acceptance Criteria:**
**Given** a page with focusable elements (links, form controls, elements with tabindex)
**When** the user presses Tab
**Then** focus moves to the next focusable element in document order
**Given** the user pressing Shift+Tab
**When** an element is focused
**Then** focus moves to the previous focusable element in document order
**Given** elements with `tabindex="0"`
**When** the user tabs through the page
**Then** those elements are included in the tab order at their document position
**Given** elements with `tabindex="-1"`
**When** the user tabs through the page
**Then** those elements are skipped but can be focused programmatically via JavaScript
**Given** elements with positive `tabindex` values
**When** the user tabs through the page
**Then** those elements are visited first in ascending tabindex order, before tabindex="0" elements
**And** integration tests verify tab order with various tabindex configurations, and `just ci` passes.
---
## Epic 5: Navigation & Browser Shell
Complete browsing experience -- history navigation, error pages, loading indicators, reload/stop, and polished chrome UI. Maintains already-delivered networking capabilities (cookies, caching, sessions).
**FRs covered:** FR18, FR19, FR20a, FR20b, FR24, FR31, FR33, FR34, FR35, FR36 (+ maintained: FR21, FR22, FR23, FR41)
### Story 5.1: URL Navigation & Protocol Schemes
As a web user,
I want to navigate to any URL and have the correct content load,
So that I can browse websites, local files, and embedded data content.
**Acceptance Criteria:**
**Given** the user enters an HTTP or HTTPS URL in the address bar
**When** the navigation is initiated
**Then** the resource is fetched over the network, parsed, and rendered
**Given** the user enters a `file://` URL
**When** the navigation is initiated
**Then** the local file is read from disk and rendered
**Given** the user enters a URL without a scheme (e.g., `example.com`)
**When** the navigation is initiated
**Then** a reasonable default scheme is prepended (e.g., `https://`)
**And** integration tests verify navigation for each protocol scheme, and `just ci` passes.
### Story 5.2: Redirect Handling
As a web user,
I want the browser to follow redirects automatically,
So that I reach the correct page even when URLs have moved.
**Acceptance Criteria:**
**Given** an HTTP response with status 301 or 302 and a `Location` header
**When** the browser processes the response
**Then** the browser automatically navigates to the redirect target URL
**Given** an HTTP 303 redirect after a POST request
**When** the browser follows the redirect
**Then** the subsequent request uses the GET method
**Given** an HTTP 307 or 308 redirect
**When** the browser follows the redirect
**Then** the original request method and body are preserved
**Given** a redirect chain exceeding 20 hops
**When** the browser follows the chain
**Then** navigation stops and an error is displayed to the user
**And** integration tests verify each redirect status code and the hop limit, and `just ci` passes.
### Story 5.3: Error Pages
As a web user,
I want to see a clear error message when a page fails to load,
So that I understand what went wrong instead of seeing a blank screen.
**Acceptance Criteria:**
**Given** an HTTP response with a 404 status code
**When** the page is rendered
**Then** the user sees an error page displaying the status code and a descriptive message
**Given** an HTTP response with a 500 status code
**When** the page is rendered
**Then** the user sees an error page indicating a server error
**Given** a DNS resolution failure
**When** the navigation fails
**Then** the user sees an error page indicating the domain could not be found
**Given** a connection timeout or connection refused error
**When** the navigation fails
**Then** the user sees an error page within 10 seconds of the failure per NFR15
**Given** any network or HTTP error
**When** the error page is displayed
**Then** the address bar still shows the attempted URL so the user can retry or edit it
**And** integration tests verify error page display for each failure type, and `just ci` passes.
### Story 5.4: History Navigation
As a web user,
I want to go back and forward through pages I've visited,
So that I can return to previously viewed content.
**Acceptance Criteria:**
**Given** the user has navigated to 3+ pages in sequence
**When** the user clicks the back button or presses the back shortcut
**Then** the previous page is restored with its content re-rendered
**Given** the user has gone back one or more pages
**When** the user clicks the forward button
**Then** the next page in the forward history is restored
**Given** the user is on the first page in history
**When** the back button is rendered
**Then** it appears disabled or inactive
**Given** the user navigates to a new page after going back
**When** the navigation completes
**Then** the forward history is cleared (standard browser behavior)
**And** integration tests verify history navigation across 3+ entries, and `just ci` passes.
### Story 5.5: Page Scrolling
As a web user,
I want to scroll through pages that are taller or wider than my window,
So that I can access all content on the page.
**Acceptance Criteria:**
**Given** a page with content taller than the viewport
**When** the user scrolls vertically (mouse wheel, trackpad, or keyboard)
**Then** the page content scrolls smoothly revealing content below
**Given** a page with content wider than the viewport
**When** the user scrolls horizontally
**Then** the page content scrolls horizontally revealing content to the right
**Given** the user presses Page Down, Page Up, Home, or End keys
**When** the page is scrollable
**Then** the page scrolls by the appropriate amount (viewport height for Page keys, top/bottom for Home/End)
**Given** the user scrolls to the top or bottom of the page
**When** further scroll input is received in that direction
**Then** no further scrolling occurs (scroll position clamps to content bounds)
**And** integration tests verify vertical/horizontal scrolling and keyboard scroll, and `just ci` passes.
### Story 5.6: Browser Chrome Completeness
As a web user,
I want a polished browser interface with working navigation controls and loading feedback,
So that I have a complete browsing experience.
**Acceptance Criteria:**
**Given** the browser is running
**When** the chrome UI is rendered
**Then** the address bar, back/forward buttons, reload button, and stop button are visible and correctly laid out at window widths from 800px to 2560px
**Given** the user navigates to a page
**When** the page is loading
**Then** a loading indicator is visible in the chrome UI
**Given** a page has finished loading or failed to load
**When** the loading completes
**Then** the loading indicator is cleared
**Given** the user clicks the reload button
**When** a page is currently displayed
**Then** all resources are re-fetched and the page is re-rendered
**Given** the user clicks the stop button
**When** a page is currently loading
**Then** pending resource fetches are cancelled and the page displays whatever has loaded so far
**Given** the user navigates to a new page
**When** the navigation completes
**Then** the address bar updates to reflect the current URL
**And** integration tests verify each chrome UI behavior, and `just ci` passes.
---
## Epic 6: Security, Storage & Robustness
Safe browsing with same-origin policy enforcement, URI navigation blocking, localStorage/sessionStorage for web apps, and crash-free handling of malformed input across all parsers.
**FRs covered:** FR38, FR39, FR42, FR50
### Story 6.1: Same-Origin Policy Enforcement
As a web user,
I want the browser to prevent malicious scripts from accessing my data on other sites,
So that my browsing sessions are secure.
**Acceptance Criteria:**
**Given** JavaScript on origin A attempting to read DOM content from an iframe on origin B
**When** the access is attempted
**Then** a SecurityError is thrown and access is denied
**Given** JavaScript on origin A attempting to read cookies scoped to origin B
**When** the access is attempted
**Then** the cookies are not accessible
**Given** JavaScript on origin A making a fetch request to origin B without CORS headers
**When** the response is received
**Then** the response body is opaque and not readable by the script
**Given** two pages on the same origin (same scheme, host, and port)
**When** JavaScript on one page accesses the other's resources
**Then** access is permitted
**And** cross-origin integration tests verify blocked access for DOM, cookies, and fetch responses, and `just ci` passes.
### Story 6.2: URI Navigation Blocking
As a web user,
I want the browser to block dangerous URI navigations,
So that I am protected from `javascript:` and `data:` URI attacks.
**Acceptance Criteria:**
**Given** a top-level navigation to a `javascript:` URI (e.g., clicking a link with `href="javascript:alert(1)"`)
**When** the navigation is initiated
**Then** the navigation is blocked and no script is executed
**Given** a top-level navigation to a `data:` URI (e.g., `data:text/html,...`)
**When** the navigation is initiated
**Then** the navigation is blocked
**Given** a sub-resource using a `data:` URI (e.g., `<img src="data:image/png;base64,...">`)
**When** the resource is loaded
**Then** the `data:` URI is permitted and the resource loads correctly
**Given** JavaScript attempting `window.location = "javascript:..."` or `window.location = "data:..."`
**When** the assignment is executed
**Then** the navigation is blocked
**And** integration tests verify blocked and permitted cases for each URI scheme, and `just ci` passes.
### Story 6.3: localStorage & sessionStorage
As a web developer using JavaScript,
I want localStorage and sessionStorage APIs to work,
So that web applications can persist data on the client side.
**Acceptance Criteria:**
**Given** JavaScript calling `localStorage.setItem(key, value)` and `localStorage.getItem(key)`
**When** the operations execute
**Then** the value is stored persistently and retrievable across page navigations within the same origin
**Given** JavaScript calling `sessionStorage.setItem(key, value)`
**When** the value is retrieved in the same browsing session
**Then** the value is available, but cleared when the tab/session closes
**Given** JavaScript calling `localStorage.removeItem(key)` or `localStorage.clear()`
**When** the operation executes
**Then** the specified key or all keys are removed from storage
**Given** JavaScript on origin A accessing localStorage
**When** JavaScript on origin B attempts to access the same storage
**Then** each origin has isolated storage and cannot access the other's data
**Given** localStorage data exceeding 5MB for a single origin
**When** a `setItem` call would exceed the limit
**Then** a QuotaExceededError is thrown
**And** integration tests verify getItem/setItem/removeItem/clear, storage limits, and cross-origin isolation, and `just ci` passes.
### Story 6.4: Malformed Input Resilience
As a web user,
I want the browser to handle broken or adversarial content without crashing,
So that I can browse safely even on malformed pages.
**Acceptance Criteria:**
**Given** malformed HTML (unclosed tags, invalid nesting, truncated documents, binary content)
**When** the HTML parser processes it
**Then** parsing completes without panics, producing a best-effort DOM tree
**Given** malformed CSS (invalid property names, unclosed blocks, garbage bytes, deeply nested selectors)
**When** the CSS parser processes it
**Then** parsing completes without panics, skipping invalid rules per CSS error recovery
**Given** malformed JavaScript (syntax errors, deeply nested expressions, extremely long strings, invalid Unicode)
**When** the JS parser/engine processes it
**Then** a SyntaxError or appropriate error is reported to console.error without process termination
**Given** adversarial input designed to trigger resource exhaustion (billion-laughs HTML, regex backtracking, deeply recursive structures)
**When** the parsers process it
**Then** processing terminates gracefully within reasonable time and memory bounds
**And** fuzz tests and malformed-input test suites covering each parser run without panics, and `just ci` passes.