{
  "$schema": "dss-knowledge-v1",
  "type": "coding_standards",
  "version": "1.0.0",
  "last_updated": "2025-12-08",
  "description": "Immutable coding best practices for all DSS code. These standards are enforced via pre-commit hooks and guide all code contributions.",

  "web_components": {
    "principle": "All UI components MUST be Web Components using Custom Elements API",
    "rules": [
      {
        "id": "WC-001",
        "rule": "Shadow DOM Required",
        "requirement": "MUST use attachShadow({ mode: 'open' }) for all components",
        "exceptions": "None - this is non-negotiable for style encapsulation",
        "rationale": "Prevents global CSS pollution and ensures component isolation",
        "enforcement": "Pre-commit hook fails if component extends HTMLElement without Shadow DOM"
      },
      {
        "id": "WC-002",
        "rule": "Lifecycle Management",
        "requirement": "MUST implement connectedCallback, disconnectedCallback, and attributeChangedCallback where appropriate",
        "pattern": "Always clean up event listeners and subscriptions in disconnectedCallback",
        "example": "disconnectedCallback() { if (this.unsubscribe) this.unsubscribe(); if (this.abortController) this.abortController.abort(); }"
      },
      {
        "id": "WC-003",
        "rule": "Observable Attributes",
        "requirement": "Define observedAttributes static getter for reactive attributes",
        "pattern": "static get observedAttributes() { return ['title', 'value', 'color']; }",
        "rationale": "Enables reactive attribute changes without manual DOM manipulation"
      },
      {
        "id": "WC-004",
        "rule": "Component Registration",
        "requirement": "Define custom element in component file using customElements.define()",
        "pattern": "customElements.define('ds-component-name', ComponentClass);",
        "naming": "All DSS components prefixed with 'ds-' to avoid conflicts"
      }
    ]
  },

  "style_management": {
    "principle": "Zero inline styles policy - all styles in Shadow DOM or external stylesheets",
    "rules": [
      {
        "id": "STYLE-001",
        "rule": "NO Inline Styles",
        "requirement": "FORBIDDEN: style=\"...\" attributes in templates",
        "exceptions": "ONLY dynamic computed values (e.g., transform: translateX(${x}px), width: ${percent}%)",
        "enforcement": "Pre-commit hook fails if >10 inline styles detected",
        "rationale": "Maintainability, separation of concerns, style encapsulation"
      },
      {
        "id": "STYLE-002",
        "rule": "Shadow DOM Styles",
        "requirement": "All component styles in <style> block within shadowRoot.innerHTML",
        "pattern": "this.shadowRoot.innerHTML = `<style>:host { display: block; } .card { padding: 16px; }</style><div class=\"card\">...</div>`;",
        "best_practice": "Define styles at top of template for clarity"
      },
      {
        "id": "STYLE-003",
        "rule": "VSCode Theme Tokens",
        "requirement": "MUST use CSS custom properties from VSCode theme",
        "required_variables": [
          "--vscode-foreground",
          "--vscode-background",
          "--vscode-sidebar-background",
          "--vscode-button-background",
          "--vscode-button-foreground",
          "--vscode-button-secondaryBackground",
          "--vscode-button-secondaryForeground",
          "--vscode-focusBorder",
          "--vscode-list-hoverBackground",
          "--vscode-list-activeSelectionBackground",
          "--vscode-list-activeSelectionForeground",
          "--vscode-descriptionForeground",
          "--vscode-widget-border",
          "--vscode-errorForeground"
        ],
        "rationale": "Ensures consistent theming with VSCode dark/light mode"
      },
      {
        "id": "STYLE-004",
        "rule": "Constructable Stylesheets",
        "requirement": "Use for shared styles across multiple components",
        "pattern": "const sheet = new CSSStyleSheet(); sheet.replaceSync(css); shadowRoot.adoptedStyleSheets = [sheet];",
        "use_cases": ["Common button styles", "Typography system", "Layout utilities"]
      },
      {
        "id": "STYLE-005",
        "rule": "CSS Hover Effects",
        "requirement": "Use :hover pseudo-class, NOT onmouseover/onmouseout",
        "correct": ".card:hover { background: var(--vscode-list-hoverBackground); }",
        "forbidden": "onmouseover=\"this.style.background='...'\" onmouseout=\"this.style.background=''\"",
        "rationale": "Performance, maintainability, separation of concerns"
      }
    ]
  },

  "event_handling": {
    "principle": "Event delegation pattern - NO inline event handlers",
    "rules": [
      {
        "id": "EVENT-001",
        "rule": "NO Inline Events",
        "requirement": "FORBIDDEN: onclick, onmouseover, onmouseout, onkeydown, onkeyup, etc. in HTML",
        "enforcement": "Pre-commit hook fails if ANY inline event handlers detected",
        "rationale": "Security (CSP compliance), maintainability, testability, separation of concerns"
      },
      {
        "id": "EVENT-002",
        "rule": "Event Delegation Pattern",
        "requirement": "Single delegated listener per component using data-action attributes",
        "pattern": "this.shadowRoot.addEventListener('click', (e) => { const action = e.target.closest('[data-action]')?.dataset.action; if (action && this[`handle${action}`]) { this[`handle${action}`](e); } });",
        "html_example": "<button data-action=\"save\" type=\"button\">Save</button>",
        "js_example": "handleSave(e) { /* implementation */ }"
      },
      {
        "id": "EVENT-003",
        "rule": "Custom Events for Communication",
        "requirement": "Component communication via CustomEvent with composed: true",
        "pattern": "this.dispatchEvent(new CustomEvent('ds-action', { detail: { action, data }, bubbles: true, composed: true }));",
        "rationale": "composed: true allows events to bubble out of Shadow DOM boundaries"
      },
      {
        "id": "EVENT-004",
        "rule": "Event Listener Cleanup",
        "requirement": "Always remove event listeners in disconnectedCallback",
        "pattern": "this.abortController = new AbortController(); addEventListener('click', handler, { signal: this.abortController.signal }); // disconnectedCallback: this.abortController.abort();",
        "alternative": "Store handlers as methods and call removeEventListener explicitly"
      },
      {
        "id": "EVENT-005",
        "rule": "Keyboard Navigation",
        "requirement": "Support Tab, Enter, Escape, Arrow keys for interactive components",
        "pattern": "this.shadowRoot.addEventListener('keydown', (e) => { if (e.key === 'Escape') this.close(); if (e.key === 'Enter') this.submit(); });",
        "rationale": "Accessibility requirement for keyboard-only users"
      }
    ]
  },

  "accessibility": {
    "principle": "WCAG 2.1 Level AA compliance minimum",
    "rules": [
      {
        "id": "A11Y-001",
        "rule": "Semantic HTML",
        "requirement": "MUST use semantic elements: <button>, <nav>, <main>, <aside>, <header>, <footer>, <article>, <section>",
        "forbidden": "<div onclick=\"...\"> for interactive elements, <div class=\"button\">",
        "correct": "<button type=\"button\">Click me</button>",
        "rationale": "Screen readers rely on semantic HTML for navigation and interaction"
      },
      {
        "id": "A11Y-002",
        "rule": "Button Type Attribute",
        "requirement": "ALL <button> elements MUST have type=\"button\" (or type=\"submit\" in forms)",
        "pattern": "<button type=\"button\">Action</button>",
        "rationale": "Prevents accidental form submission in HTML forms",
        "enforcement": "Pre-commit hook warns about buttons without type attribute"
      },
      {
        "id": "A11Y-003",
        "rule": "ARIA Attributes",
        "requirement": "Use when semantic HTML insufficient",
        "required_patterns": [
          "aria-label for icon-only buttons",
          "aria-labelledby for complex widgets",
          "aria-describedby for additional context",
          "role for custom interactive elements"
        ],
        "examples": [
          "<button aria-label=\"Close dialog\" type=\"button\">×</button>",
          "<div role=\"group\" aria-labelledby=\"tools-heading\">...</div>"
        ]
      },
      {
        "id": "A11Y-004",
        "rule": "Focus Management",
        "requirement": "Keyboard navigation support for all interactive elements",
        "css_pattern": ".btn:focus-visible { outline: 2px solid var(--vscode-focusBorder); outline-offset: 2px; }",
        "js_requirements": [
          "trapFocus() for modals",
          "restoreFocus() on close",
          "Skip links for main content",
          "Focus first invalid field on validation error"
        ]
      },
      {
        "id": "A11Y-005",
        "rule": "Color Contrast",
        "requirement": "Minimum 4.5:1 for normal text, 3:1 for large text",
        "tool": "Use VSCode theme tokens which meet contrast requirements",
        "testing": "Chrome DevTools Lighthouse audit"
      },
      {
        "id": "A11Y-006",
        "rule": "Screen Reader Testing",
        "requirement": "Test all components with NVDA/JAWS (Windows) or VoiceOver (Mac)",
        "checklist": [
          "Navigation order makes sense",
          "All buttons have clear labels",
          "Error messages announced",
          "Status updates announced with aria-live"
        ]
      }
    ]
  },

  "state_management": {
    "principle": "Centralized state with reactive updates",
    "rules": [
      {
        "id": "STATE-001",
        "rule": "Context Store for Global State",
        "requirement": "Use contextStore for application-wide state (projectId, teamId, userId)",
        "pattern": "this.unsubscribe = contextStore.subscribeToKey('projectId', (newValue) => { this.projectId = newValue; this.render(); });",
        "path": "admin-ui/js/stores/context-store.js"
      },
      {
        "id": "STATE-002",
        "rule": "Component Local State",
        "requirement": "Component-specific state in this.state object",
        "pattern": "this.state = { isLoading: false, data: null, error: null }; setState(updates) { Object.assign(this.state, updates); this.render(); }",
        "best_practice": "Initialize state in constructor"
      },
      {
        "id": "STATE-003",
        "rule": "NO Direct DOM Manipulation",
        "requirement": "State changes trigger re-renders, not direct DOM updates",
        "forbidden": "document.getElementById('foo').textContent = 'bar'; element.style.display = 'none';",
        "correct": "this.setState({ foo: 'bar', visible: false }); // render() handles DOM updates",
        "rationale": "Maintains single source of truth, prevents state/view desync"
      },
      {
        "id": "STATE-004",
        "rule": "Subscription Cleanup",
        "requirement": "Always unsubscribe in disconnectedCallback",
        "pattern": "connectedCallback() { this.unsubscribe = store.subscribe(...); } disconnectedCallback() { if (this.unsubscribe) this.unsubscribe(); }",
        "rationale": "Prevents memory leaks from orphaned subscriptions"
      },
      {
        "id": "STATE-005",
        "rule": "Immutable State Updates",
        "requirement": "Create new state objects, don't mutate existing",
        "correct": "this.state = { ...this.state, count: this.state.count + 1 };",
        "forbidden": "this.state.count++; // direct mutation",
        "rationale": "Enables change detection and debugging"
      }
    ]
  },

  "code_organization": {
    "principle": "Single Responsibility, clear structure, modular design",
    "rules": [
      {
        "id": "ORG-001",
        "rule": "File Size Limit",
        "requirement": "Maximum 500 lines per file",
        "action": "If larger, split into multiple modules",
        "enforcement": "Quality check warns on files >500 lines",
        "current_violation": "app.js at 4,347 lines must be decomposed"
      },
      {
        "id": "ORG-002",
        "rule": "Directory Structure",
        "requirement": "Strict organization by type and purpose",
        "structure": {
          "admin-ui/js/components/": "Web components (*.js)",
          "admin-ui/js/components/layout/": "Layout components (shell, header, sidebar)",
          "admin-ui/js/components/metrics/": "Dashboard and metric components",
          "admin-ui/js/components/tools/": "Tool-specific components",
          "admin-ui/js/components/listings/": "List/table components",
          "admin-ui/js/stores/": "State management",
          "admin-ui/js/utils/": "Helper functions and utilities",
          "admin-ui/js/core/": "Core modules (router, messaging, workflows)",
          "admin-ui/js/workdesks/": "Team workdesk controllers",
          "admin-ui/js/config/": "Configuration files"
        }
      },
      {
        "id": "ORG-003",
        "rule": "Import Style",
        "requirement": "Explicit named imports, no wildcards",
        "correct": "import { hydrateComponent } from '../config/component-registry.js';",
        "forbidden": "import * as registry from '../config/component-registry.js';",
        "rationale": "Tree-shaking, explicit dependencies, better IDE support"
      },
      {
        "id": "ORG-004",
        "rule": "Export Style",
        "requirement": "Named exports for utilities, default export for components",
        "utility_pattern": "export function debounce(fn, ms) { ... } export function throttle(fn, ms) { ... }",
        "component_pattern": "export default class MyComponent extends HTMLElement { ... }",
        "rationale": "Convention clarity, supports tree-shaking"
      },
      {
        "id": "ORG-005",
        "rule": "Single Responsibility Principle",
        "requirement": "One component = one concern, one file = one primary export",
        "examples": [
          "ds-metric-card.js: Displays a single metric card",
          "ds-frontpage.js: Orchestrates dashboard layout",
          "context-store.js: Manages global application state"
        ],
        "anti_pattern": "utility-functions.js with 50 unrelated functions"
      }
    ]
  },

  "error_handling": {
    "principle": "Structured logging, user-friendly errors, graceful degradation",
    "rules": [
      {
        "id": "ERROR-001",
        "rule": "Centralized Logger",
        "requirement": "Use logger utility for all logging",
        "path": "admin-ui/js/utils/logger.js",
        "methods": [
          "logger.debug(msg, ...args): Development-only logging",
          "logger.info(msg, ...args): Informational messages",
          "logger.warn(msg, ...args): Warning conditions",
          "logger.error(msg, ...args): Error conditions"
        ],
        "pattern": "import { logger } from '../utils/logger.js'; logger.info('[ComponentName] Action completed', { data });"
      },
      {
        "id": "ERROR-002",
        "rule": "NO console.log in Production",
        "requirement": "Replace all console.log/warn/error with logger methods",
        "enforcement": "Pre-commit hook warns if >10 console statements",
        "exceptions": "Core initialization logging in app.js only",
        "migration": "console.log('foo') → logger.debug('foo')"
      },
      {
        "id": "ERROR-003",
        "rule": "User-Friendly Error Messages",
        "requirement": "Error messages must be actionable and clear",
        "good": "Failed to load projects. Please check your internet connection and try again.",
        "bad": "Error: HTTP 500", "TypeError: Cannot read property 'id' of undefined",
        "pattern": "Show what failed + why it might have failed + what user can do"
      },
      {
        "id": "ERROR-004",
        "rule": "Error Taxonomy",
        "requirement": "Use structured error codes from messaging.js",
        "codes": {
          "E1xxx": "User errors (invalid input, forbidden actions)",
          "E2xxx": "Validation errors (missing fields, invalid formats)",
          "E3xxx": "API errors (request failed, timeout, unauthorized)",
          "E4xxx": "System errors (unexpected, network, storage)",
          "E5xxx": "Integration errors (Figma, external APIs)",
          "S1xxx": "Success codes"
        },
        "usage": "notifyError('E3001', 'Failed to fetch projects', error);"
      },
      {
        "id": "ERROR-005",
        "rule": "Graceful Degradation",
        "requirement": "Components must handle missing/invalid data gracefully",
        "patterns": [
          "if (!data) return this.renderEmptyState();",
          "if (error) return this.renderError(error);",
          "const items = data?.items ?? [];"
        ],
        "anti_pattern": "Assuming data exists and causing cascading failures"
      },
      {
        "id": "ERROR-006",
        "rule": "Try-Catch for Async Operations",
        "requirement": "Wrap all async operations in try-catch",
        "pattern": "async loadData() { try { const data = await fetch(...); } catch (error) { logger.error('[Component] Failed to load', error); this.handleError(error); } }",
        "rationale": "Prevents unhandled promise rejections"
      }
    ]
  },

  "performance": {
    "principle": "Optimize for user experience, measure and improve",
    "rules": [
      {
        "id": "PERF-001",
        "rule": "Lazy Loading",
        "requirement": "Non-critical components loaded on-demand via hydrateComponent()",
        "pattern": "await hydrateComponent('ds-screenshot-gallery', container);",
        "benefits": "Faster initial load, reduced bundle size",
        "applies_to": ["Tool components", "Heavy visualizations", "Rarely-used features"]
      },
      {
        "id": "PERF-002",
        "rule": "Virtual Scrolling",
        "requirement": "Use for lists >100 items",
        "libraries": ["lit-virtualizer", "virtual-scroller"],
        "pattern": "import { VirtualScroller } from 'virtual-scroller'; new VirtualScroller(container, { items, renderItem });",
        "applies_to": ["Token lists", "Component catalogs", "Log viewers"]
      },
      {
        "id": "PERF-003",
        "rule": "Debouncing and Throttling",
        "requirement": "Debounce search inputs, throttle scroll/resize handlers",
        "debounce_pattern": "this.searchDebounced = debounce(() => this.performSearch(), 300);",
        "throttle_pattern": "this.onScrollThrottled = throttle(() => this.handleScroll(), 100);",
        "use_cases": {
          "debounce": "Search inputs, form validation, autosave",
          "throttle": "Scroll handlers, resize handlers, mousemove tracking"
        }
      },
      {
        "id": "PERF-004",
        "rule": "Avoid Unnecessary Re-renders",
        "requirement": "Only re-render when state actually changes",
        "pattern": "attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) return; this.render(); }",
        "best_practice": "Compare old vs new state before rendering"
      },
      {
        "id": "PERF-005",
        "rule": "Bundle Size Monitoring",
        "requirement": "Monitor and optimize JavaScript bundle sizes",
        "targets": {
          "individual_component": "<50KB",
          "total_bundle": "<500KB",
          "critical_path": "<200KB"
        },
        "tools": ["webpack-bundle-analyzer", "source-map-explorer"]
      },
      {
        "id": "PERF-006",
        "rule": "Minimize DOM Operations",
        "requirement": "Batch DOM updates, use DocumentFragment for multiple inserts",
        "pattern": "const fragment = document.createDocumentFragment(); items.forEach(item => fragment.appendChild(createNode(item))); container.appendChild(fragment);",
        "anti_pattern": "items.forEach(item => container.appendChild(createNode(item))); // causes multiple reflows"
      }
    ]
  },

  "security": {
    "principle": "Secure by default, defense in depth",
    "rules": [
      {
        "id": "SEC-001",
        "rule": "NO Hardcoded Secrets",
        "requirement": "FORBIDDEN: API keys, passwords, tokens, credentials in code",
        "enforcement": "Pre-commit hook fails if secret patterns detected (apiKey, api_key, password, secret, token)",
        "correct": "Use environment variables or secure configuration service",
        "rationale": "Prevents credential leaks in version control"
      },
      {
        "id": "SEC-002",
        "rule": "Input Sanitization",
        "requirement": "ALWAYS escape user input before rendering to DOM",
        "utility": "ComponentHelpers.escapeHtml(userInput)",
        "pattern": "<div>${ComponentHelpers.escapeHtml(project.name)}</div>",
        "forbidden": "<div>${project.name}</div> // XSS vulnerability",
        "rationale": "Prevents XSS attacks"
      },
      {
        "id": "SEC-003",
        "rule": "CSP Compliance",
        "requirement": "NO eval(), NO new Function(), NO inline scripts",
        "forbidden": [
          "eval(code)",
          "new Function('x', 'return x * 2')",
          "<script>alert(1)</script> in templates"
        ],
        "rationale": "Content Security Policy compatibility, prevents code injection"
      },
      {
        "id": "SEC-004",
        "rule": "HTTPS Only",
        "requirement": "All external requests use HTTPS",
        "enforcement": "No http:// URLs in fetch() calls",
        "correct": "fetch('https://api.example.com/data')",
        "forbidden": "fetch('http://api.example.com/data')",
        "exceptions": "localhost development only"
      },
      {
        "id": "SEC-005",
        "rule": "Validate API Responses",
        "requirement": "Always validate structure and content of API responses",
        "pattern": "const data = await response.json(); if (!data || !Array.isArray(data.items)) throw new Error('Invalid response');",
        "rationale": "Prevents errors from malformed/malicious responses"
      },
      {
        "id": "SEC-006",
        "rule": "Authentication Token Handling",
        "requirement": "Store auth tokens securely, never in localStorage",
        "correct": "sessionStorage (better: httpOnly cookies)",
        "forbidden": "localStorage for sensitive tokens",
        "rationale": "localStorage accessible to XSS attacks"
      }
    ]
  },

  "testing_and_quality": {
    "principle": "Automated quality gates, comprehensive testing",
    "rules": [
      {
        "id": "TEST-001",
        "rule": "Pre-commit Hooks",
        "requirement": "MUST pass all quality checks before commit",
        "script": "scripts/verify-quality.sh",
        "thresholds": {
          "inline_styles": "≤10 (exceptions for dynamic values only)",
          "inline_events": "0 (zero tolerance)",
          "console_statements": "≤10 (production code only)",
          "file_size": "≤100KB per file",
          "syntax_errors": "0 (zero tolerance)"
        },
        "bypass": "git commit --no-verify (not recommended, requires justification)"
      },
      {
        "id": "TEST-002",
        "rule": "Component Unit Tests",
        "requirement": "Unit tests for all components",
        "coverage": "Minimum 80% for critical paths",
        "framework": "Web Test Runner or Vitest",
        "test_cases": [
          "Component renders correctly",
          "Props/attributes update component",
          "Event handlers work",
          "Cleanup happens on disconnect"
        ]
      },
      {
        "id": "TEST-003",
        "rule": "Integration Tests",
        "requirement": "Test critical user flows end-to-end",
        "examples": [
          "Project creation workflow",
          "Token extraction from Figma",
          "Component audit process",
          "User authentication flow"
        ],
        "tools": ["Playwright", "Cypress"]
      },
      {
        "id": "TEST-004",
        "rule": "Visual Regression Testing",
        "requirement": "Screenshot comparison for UI changes",
        "tools": ["Playwright screenshots", "Percy", "Chromatic"],
        "process": "Capture baseline → Make changes → Compare → Approve/reject",
        "applies_to": "All visible UI components"
      },
      {
        "id": "TEST-005",
        "rule": "Documentation",
        "requirement": "JSDoc comments for public APIs and complex logic",
        "pattern": "/**\n * Load project data from API\n * @param {string} projectId - The project identifier\n * @returns {Promise<Project>} The loaded project\n * @throws {Error} If project not found or network error\n */\nasync loadProject(projectId) { ... }",
        "applies_to": ["Public component methods", "Utility functions", "Store APIs"]
      },
      {
        "id": "TEST-006",
        "rule": "Code Review Checklist",
        "requirement": "All PRs reviewed against these standards",
        "checklist": [
          "✓ Shadow DOM used for all components",
          "✓ No inline styles or event handlers",
          "✓ Proper accessibility attributes",
          "✓ Event listeners cleaned up",
          "✓ User input sanitized",
          "✓ Error handling implemented",
          "✓ Tests added/updated"
        ]
      }
    ]
  },

  "enforcement": {
    "description": "How these standards are enforced in the development workflow",
    "mechanisms": [
      {
        "type": "Pre-commit Hooks",
        "file": ".git/hooks/pre-commit",
        "action": "Runs scripts/verify-quality.sh automatically",
        "can_bypass": "git commit --no-verify (requires justification)"
      },
      {
        "type": "Quality Verification Script",
        "file": "scripts/verify-quality.sh",
        "checks": [
          "Inline event handlers detection",
          "Inline styles counting",
          "Missing ARIA attributes",
          "Console.log statements",
          "JavaScript syntax validation",
          "Hardcoded secrets detection",
          "Shadow DOM usage statistics",
          "File size warnings"
        ]
      },
      {
        "type": "Immutability Protection",
        "file": ".clauderc",
        "protection": "This file listed in protected_core_files",
        "requirement": "ALLOW_CORE_CHANGES=true to modify"
      },
      {
        "type": "AI Agent Instructions",
        "description": "AI assistants programmed to follow these standards",
        "behavior": [
          "Always use Shadow DOM for components",
          "Never generate inline event handlers",
          "Extract inline styles to style blocks",
          "Add proper accessibility attributes",
          "Use logger instead of console.log"
        ]
      }
    ]
  },

  "migration_strategy": {
    "description": "How to migrate existing code to these standards",
    "phases": [
      {
        "phase": 1,
        "name": "Foundation Fixes",
        "duration": "Week 1",
        "priority": "Critical",
        "tasks": [
          "Refactor tool-templates.js to generate compliant HTML",
          "Create logger utility (admin-ui/js/utils/logger.js)",
          "Update verify-quality.sh thresholds",
          "Create migration guide with examples"
        ]
      },
      {
        "phase": 2,
        "name": "Component Migration - Batch A",
        "duration": "Week 2",
        "priority": "High",
        "targets": [
          "Layout components (ds-project-selector, ds-shell, ds-header)",
          "Most violated: ds-screenshot-gallery, ds-network-monitor"
        ],
        "pattern": "Add Shadow DOM → Extract styles → Replace inline events → Add ARIA"
      },
      {
        "phase": 3,
        "name": "Component Migration - Batch B",
        "duration": "Week 3",
        "priority": "High",
        "targets": [
          "Tool components (ds-activity-log, ds-test-results)",
          "Admin/listings (ds-project-list, ds-token-list)"
        ]
      },
      {
        "phase": 4,
        "name": "Monolith Decomposition",
        "duration": "Week 4",
        "priority": "Critical",
        "target": "app.js (4,347 lines → 7 modules)",
        "modules": [
          "app.js: Main orchestrator (<500 lines)",
          "router.js: Hash routing",
          "auth-manager.js: Authentication",
          "api-client.js: Fetch wrapper",
          "error-handler.js: Global errors",
          "state-manager.js: State coordination",
          "init.js: Initialization"
        ]
      },
      {
        "phase": 5,
        "name": "Quality Enforcement",
        "duration": "Week 5",
        "priority": "Medium",
        "tasks": [
          "Update thresholds (inline styles ≤10, events = 0)",
          "Add ESLint/Stylelint rules",
          "CI/CD integration",
          "Developer training"
        ]
      }
    ]
  },

  "reference_implementations": {
    "description": "Examples of components that follow these standards",
    "files": [
      {
        "file": "admin-ui/js/workdesks/base-workdesk.js",
        "demonstrates": [
          "Semantic HTML (buttons not divs)",
          "Event delegation pattern",
          "Extracted styles in style block",
          "ARIA attributes",
          "Focus management"
        ]
      },
      {
        "file": "admin-ui/js/components/metrics/ds-frontpage.js",
        "demonstrates": [
          "Shadow DOM implementation",
          "Zero inline styles",
          "Lifecycle management",
          "State subscription pattern",
          "Event cleanup"
        ]
      },
      {
        "file": "admin-ui/js/components/metrics/ds-metric-card.js",
        "demonstrates": [
          "Observable attributes",
          "Shadow DOM encapsulation",
          "Reactive rendering",
          "Component composition"
        ]
      }
    ]
  },

  "success_metrics": {
    "description": "Measurable goals for DSS code quality",
    "current_state": {
      "shadow_dom_adoption": "23% (12/53 components)",
      "inline_event_handlers": "20+",
      "inline_styles": "1,288",
      "console_statements": "100+",
      "largest_file": "app.js at 4,347 lines / 156KB"
    },
    "target_state": {
      "shadow_dom_adoption": "100% (53/53 components)",
      "inline_event_handlers": "0 (zero tolerance)",
      "inline_styles": "<10 (dynamic values only)",
      "console_statements": "<10 (core only)",
      "largest_file": "<500 lines per file"
    },
    "tracking": {
      "method": "Pre-commit hook statistics",
      "frequency": "Every commit",
      "reporting": "Monthly code quality dashboard"
    }
  }
}
