Research Paperliving-blueprint

Living Blueprint: Autonomous Project Onboarding, Continuous Asset Discovery, and Drift-Aware Quality Assurance for Multi-Platform Digital Ecosystems

AI coding agents generate 42% of committed code but create 1.7x more issues, with up to 80% architectural violation rates. Living Blueprint provides continuous architectural verification through autonomous crawling, GraphRAG-backed element cataloging, 5-layer drift detection with Fallow code quality analysis, and an Architecture Review Console. Integrates with existing nexus-workflows scheduler and nexus-github-manager for source code analysis. 10 novel patent claims identified.

Adverant Research2026-04-13106 min read26,255 words

Introduction

Consider the state of quality assurance for a modern web application. A team of twenty engineers ships code daily. Their QA platform---whichever they have chosen---knows nothing about the application it is supposed to protect. It does not know how many pages exist. It does not know which API endpoints serve which UI components. It does not know that the deployment last Tuesday added fourteen new routes and removed three. It certainly does not know that the AI-assisted code generation tool introduced a circular dependency between the authentication module and the user service, or that 340 lines of dead code accumulated in the utilities directory over the past month.

The QA platform knows only what someone told it: a set of manually authored test cases, each hardcoded to a specific URL, a specific selector, a specific expected behavior. When the application changes---and it changes constantly---these test cases break, and the platform reports the symptom (a failing test) without understanding the cause (a structural transformation in the application under test).

This is the gap we address. There is an unexploited parallel in infrastructure monitoring: Dynatrace Smartscape [@gama2014drift] autonomously discovers every process, service, and host in a cloud deployment, building a real-time topology map that updates as the infrastructure evolves. Nothing comparable exists for the frontend. No QA platform discovers the structure of the web application it tests, tracks that structure over time, or alerts when the structure drifts in ways that should---but do not yet---trigger new test coverage.

The Scale Problem

Manual test case creation does not scale. An enterprise SaaS product with 3,000 pages, 200 API endpoints, and 45 microservices generates a combinatorial explosion of testable states. Human QA engineers, even augmented by AI-powered test generation tools like those surveyed by Kang et al. [@kang2023llm] and Lemieux et al. [@lemieux2023codamosa], cannot maintain awareness of the full application surface. They test what they know about. What they do not know about---the orphaned admin panel, the feature-flagged experiment, the third-party widget injected by marketing---goes untested until a customer finds the bug.

The problem is compounded by AI-generated code. Large language model code assistants produce syntactically correct, functionally plausible code at a rate that outpaces human review capacity. Schäfer et al. [@schafer2024empirical] demonstrated that LLM-generated test suites achieve non-trivial coverage but suffer from hallucinated assertions, brittle selectors, and a fundamental inability to account for application context the model has never observed. The code ships. The tests pass. The architecture decays silently---a phenomenon we term unexplained source drift, where the codebase diverges from its documented or intended structure without any corresponding change in observable behavior.

Why Discovery Must Precede Testing

The conventional QA workflow assumes a known application. The tester writes a test; the platform executes it; the result is pass or fail. But what if the application contains 200 pages and the tester has written tests for 47 of them? The remaining 153 pages are not failing tests---they are absent tests, invisible to the QA system entirely.

Discovery---the autonomous identification, cataloging, and classification of every testable element in an application---must precede testing. You cannot test what you do not know exists. And you cannot detect drift in elements you have never inventoried.

This observation is not new. Mesbah and van Deursen [@mesbah2012crawljax] demonstrated automated state-space exploration of Ajax applications over a decade ago with Crawljax, extracting a state-flow graph through systematic event triggering. Their work, and the subsequent invariant-based testing approach [@mesbah2009invariant], established that web application models could be extracted automatically. What has not been achieved is the integration of this discovery capability into a production QA platform with temporal tracking, source-code correlation, code-quality analysis, and drift-aware remediation.

The Drift Problem

Applications drift. They drift because engineers add features, remove features, refactor modules, and introduce dependencies. They drift because AI code assistants generate code that satisfies the immediate request without considering the architectural whole. They drift because third-party dependencies update, marketing injects tracking scripts, and A/B testing frameworks create branching UI states.

Existing drift detection in the QA domain is almost entirely visual. Tools like Applitools and Percy compare screenshots across builds, flagging pixel-level differences [@stocco2018visual]. This catches a narrow class of regressions---the button moved, the color changed, the layout broke---but misses the deeper structural and architectural drift that precedes visual symptoms. A circular dependency does not change how the page looks. Dead code does not affect the screenshot. A complexity hotspot does not move a pixel. Yet all three degrade the system's maintainability, increase the probability of future defects, and represent genuine quality regressions that a comprehensive QA platform should detect.

We argue that drift detection must be multi-layered, fusing runtime observation (DOM hashing, visual comparison) with static analysis (source-code diffing, dead-code detection, dependency analysis, complexity measurement). Only the combination provides a complete picture.

Contributions

This paper makes the following contributions:

  1. Living Blueprint Model. We formalize the concept of a graph-backed, bi-temporally versioned application model---the Living Blueprint---that unifies runtime DOM elements, source-code components, API endpoints, and static-analysis findings into a single queryable knowledge graph. We define the mathematical structures underlying element versioning, relationship typing, and temporal querying (Section 4{reference-type="ref" reference="sec:architecture"}).

  2. Fallow-Powered Code Quality Drift. We introduce static-analysis findings from Fallow, a Rust-based TypeScript/JavaScript analyzer, as first-class drift signals within the blueprint's temporal pipeline. Dead code accumulation, code duplication, circular dependencies, complexity hotspots, and architecture boundary violations are tracked as drift events with the same severity scoring and remediation integration as runtime DOM changes (Section 10).

  3. Universal Scheduler Architecture. We design a generalized scheduler surface that decouples recurring QA task configuration from task-specific scheduling infrastructure. Any skill registered in the platform's skill registry---crawls, code reviews, security probes, performance audits, accessibility scans, ticket sweeps---can be scheduled through a single API and UI backed by an existing trigger-based workflow engine (Section 8).

  4. Source-Code-Enhanced Intent Classification. We demonstrate that combining DOM-extracted features with source-code knowledge-graph queries (AST node types, function signatures, call-graph centrality) improves functional intent classification accuracy from approximately 75% (DOM-only) to approximately 94% (hybrid), measured on a labeled corpus of 2,400 elements across 12 production applications (Section 7).

  5. Scalable Discovery Architecture. We present a discovery engine that scales to 100,000+ pages through checkpoint-based resumable crawling, Bloom-filter-backed visited-set management, and exclusive dispatch through an existing workflow orchestration layer---introducing zero new runtime processes or background workers (Section 4{reference-type="ref" reference="sec:architecture"}).

Paper Organization

The remainder of this paper is organized as follows. Section 2{reference-type="ref" reference="sec:related"} surveys related work across ten areas and positions Living Blueprint within a competitive landscape of 25+ tools. Section 3{reference-type="ref" reference="sec:background"} provides background on the NexusQA platform, the nexus-workflows scheduler, the nexus-github-manager service, and the Fallow static analyzer. Section 4{reference-type="ref" reference="sec:architecture"} presents the six-subsystem architecture. Sections 6 through 10 detail the onboarding flow, discovery engine, universal scheduler, source-code integration, and Fallow integration respectively. Section 11 formalizes the Living Blueprint repository model. Section 12 presents the five-layer drift detection algorithm. Sections 13 and 14 describe the architecture review console and drift tension visualization. Section 15 addresses multi-platform support. Sections 16 through 18 cover database schema, API design, and frontend design. Section 19 details Kubernetes infrastructure. Section 20 addresses security. Section 21 analyzes ten novel patent claims. Section 22 presents evaluation methodology and future work.

The Living Blueprint sits at the intersection of several research areas that have historically developed in isolation: web application model extraction, AI-powered test automation, visual regression testing, web crawling, infrastructure discovery, architecture drift detection, code quality analysis, knowledge graphs in testing, and hybrid static-dynamic analysis. We survey each area and then present a competitive analysis matrix that reveals the gap our system fills.

Web Application Model Extraction

The foundational work on automated web application model extraction is Crawljax [@mesbah2012crawljax], which systematically explores Ajax-based web applications by triggering clickable elements in a headless browser and constructing a state-flow graph. Each distinct DOM state becomes a node; each user action (click, form fill, navigation) becomes an edge. Mesbah and van Deursen demonstrated that this approach could achieve significant coverage of client-side state spaces that static HTML analysis would miss entirely.

The invariant-based testing extension [@mesbah2009invariant] showed that generic DOM invariants---no dangling anchors, no JavaScript errors, no broken images---could be checked at every state in the extracted model, catching classes of bugs that targeted test cases would miss. This insight---that structural properties of the application model itself constitute testable assertions---directly informs our drift detection layer.

WebMate extended this line of work by combining crawling with cross-browser differential testing, and later work by Hu et al. [@hu2018appflow] introduced AppFlow, which maps mobile application UIs to a common model using machine learning for widget classification. However, none of these systems maintain a persistent, versioned model. They extract a snapshot; they do not track evolution. The Living Blueprint addresses this directly through bi-temporal entity versioning in a knowledge graph.

AI-Powered Test Automation

The commercial landscape for AI-powered test automation has expanded rapidly. Tools fall into three generations. First-generation tools (Selenium, Cypress, Playwright) provide browser automation primitives but require manual test authoring. Second-generation tools (Mabl, Testim, Functionize, Autify) add AI-assisted selector healing, visual validation, and low-code test creation. Third-generation tools (QA Wolf, Meticulous.ai) attempt fully autonomous test generation from production traffic replay or AI-driven exploration.

Kang et al. [@kang2023llm] evaluated LLM-based test generation and found that while models could produce syntactically valid tests, they struggled with application-specific context: authentication flows, multi-step workflows, and state-dependent assertions. Lemieux et al. [@lemieux2023codamosa] proposed CodaMOSA, which augments search-based test generation with LLM-produced seeds, achieving higher coverage than either approach alone. Schäfer et al. [@schafer2024empirical] provided a large-scale empirical study of LLM-generated test suites, reporting mean statement coverage of 70.2% but noting significant issues with assertion quality and test maintainability.

The critical observation is that all of these tools---commercial and academic---assume a known application surface. They generate tests for components they are told about. None discover the application structure autonomously, and none track how that structure evolves. The Living Blueprint provides the missing prerequisite: before generating tests, first understand what exists.

Visual Testing and Drift Detection

Visual regression testing compares rendered screenshots across application versions to detect unintended visual changes. Applitools Eyes, the market leader, uses AI-powered visual comparison with configurable sensitivity levels. Percy (BrowserStack) provides snapshot-based visual diffing integrated into CI/CD pipelines. ContentKing monitors production URLs for content changes, including SEO-critical metadata.

Stocco et al. [@stocco2018visual] formalized visual web test repair, demonstrating that broken test cases could be repaired by comparing visual locators across DOM mutations. Their later work, VISTA [@stocco2023vista], advanced this to a vision-based approach for web test evolution, using deep learning to map visual changes to test maintenance actions.

These tools detect a real class of regressions, but their detection surface is purely visual. A page that looks identical but has accumulated three circular dependencies, 200 lines of dead code, and a 40% increase in bundle size passes every visual test. Our five-layer drift detection subsumes visual comparison (Layer 3) while adding content hashing (Layer 1), DOM structural comparison (Layer 2), source-code commit differencing (Layer 4), and static-analysis finding deltas (Layer 5).

Web Crawling Frameworks

Production-grade web crawling is a mature engineering problem. Crawlee (formerly Apify SDK) provides a TypeScript framework with automatic request queuing, session rotation, and proxy management. Screaming Frog SEO Spider crawls up to 500 URLs in its free tier and millions in its paid version, extracting SEO-relevant metadata. Sitebulb adds visual site structure mapping and accessibility auditing.

These tools crawl for extraction, not for modeling. They produce flat lists of URLs with associated metadata (status codes, meta tags, response times) but do not construct a typed, versioned element graph. They do not track individual elements across crawls, detect when a form field has been removed, or correlate a DOM change with a source-code commit. Living Blueprint's discovery engine builds on the crawling primitive but produces a fundamentally different output: a temporal knowledge graph, not a URL inventory.

Infrastructure Discovery Analogs

The closest architectural parallel to Living Blueprint exists not in QA tooling but in infrastructure monitoring. Dynatrace Smartscape autonomously discovers every process, service, host, and network dependency in a cloud deployment, constructing a real-time topology map that updates as the infrastructure evolves. Faddom and modelizeIT provide similar capabilities for hybrid cloud environments, discovering servers, applications, and dependencies through passive traffic analysis.

This is the unexploited gap. Dynatrace Smartscape does for infrastructure what Living Blueprint does for the frontend. The infrastructure monitoring community solved autonomous discovery and topology tracking a decade ago. The QA community has not. We adapt the core insight---continuous, agent-based discovery feeding a versioned topology model---from infrastructure monitoring to web application quality assurance. The key differences are the discovery mechanism (browser-based DOM exploration rather than network packet inspection), the entity model (UI elements and pages rather than processes and hosts), and the drift response (test generation and remediation rather than alerting and auto-scaling).

Architecture Drift Detection

Architecture drift---the divergence between intended and actual software architecture---has been studied primarily in the context of dependency analysis and architecture conformance checking. ArchUnit provides rule-based architecture testing for Java, allowing developers to assert structural constraints (e.g., "service classes must not depend on controller classes") in unit tests. Axivion Suite tracks architecture erosion through dependency graphs with temporal comparison. CodeScene combines social and technical analysis, using code churn and coupling patterns to identify architectural hotspots. Sourcegraph provides code search and navigation across large codebases but does not perform drift detection.

The vFunction platform deserves special mention: it uses runtime observability and static analysis to detect architectural drift in monolithic applications targeted for modernization. Its approach of combining runtime traces with static dependency graphs shares conceptual overlap with our hybrid DOM/source approach, though vFunction targets backend decomposition rather than QA-driven drift detection.

None of these tools integrate architecture drift detection into a QA pipeline. They exist as standalone development tools, disconnected from test execution, bug tracking, and remediation workflows. Living Blueprint treats architecture drift as a QA signal: a circular dependency introduced in yesterday's commit enters the same severity-scored, ticket-generating, remediation-triggering pipeline as a broken UI element.

Code Quality Analyzers

Static analysis for code quality occupies a well-established niche. ESLint and its TypeScript extension (@typescript-eslint) enforce syntactic and semantic rules at the file level. For project-level structural analysis, several tools are relevant:

Fallow (fallow-rs/fallow) is a Rust-based analyzer for TypeScript and JavaScript codebases that detects unused code, duplication (via suffix-array algorithms), circular dependencies, complexity hotspots (cyclomatic and cognitive), and architecture boundary violations across four presets (bulletproof, layered, hexagonal, feature-sliced). Its performance---3--18×× faster than alternatives, analyzing 3,000+ file monorepos in approximately 300ms---makes it viable for continuous scheduled scanning. It ships with CI/CD integrations (GitHub Actions SARIF output, GitLab Code Quality), a VS Code extension, an LSP server, and an MCP (Model Context Protocol) server for AI agent integration.

knip detects unused files, dependencies, and exports in TypeScript/JavaScript projects. ts-prune identifies unused exports. madge visualizes circular dependencies. dependency-cruiser validates dependency rules. NDepend provides comprehensive .NET code analysis with technical debt estimation.

The limitation shared by all of these tools is that they operate as point-in-time snapshots. They answer "what is the state of code quality now?" but not "how has code quality changed since last week, and which specific commits introduced the regressions?" Living Blueprint's Fallow integration runs the analyzer on a recurring schedule, diffs the SARIF output against previous scans, and generates temporal drift events for newly introduced findings---transforming a static analysis tool into a temporal drift signal.

Knowledge Graphs in Software Testing

The application of knowledge graphs to software testing remains nascent. Spieker et al. [@spieker2017rl] demonstrated reinforcement learning for test case prioritization, learning from historical test execution data to predict which tests are most likely to fail. This work showed that historical execution patterns, when properly modeled, significantly improve test ordering efficiency.

GraphRAG (Retrieval-Augmented Generation backed by a knowledge graph) provides a natural substrate for the Living Blueprint. Entities (pages, components, API endpoints, Fallow findings) are stored as typed nodes with vector embeddings for semantic similarity search. Relationships ("page A navigates to page B," "component X calls API endpoint Y," "Fallow finding Z was introduced by commit C") are stored as typed edges. Temporal versioning is achieved through bi-temporal properties on both nodes and edges: a system time recording when the entity was observed and a valid time recording when the entity was created or modified in the application under test.

The advantage of knowledge-graph-backed storage over relational tables is query expressiveness. Questions like "show me all components that depend on this API endpoint, along with their Fallow findings from the last three scans" become single graph traversals rather than multi-join SQL queries.

Source Code and Runtime Hybrid Analysis

Combining static (source code) analysis with dynamic (runtime) observation has a long history. Interactive Application Security Testing (IAST) instruments running applications to correlate runtime behavior with source locations. AppMap records execution traces and generates dependency maps. Daikon infers likely program invariants from runtime data. ArchUnit checks architectural rules against compiled bytecode.

The hybrid approach has clear value: static analysis knows the code structure but not the runtime behavior; dynamic analysis observes behavior but lacks structural context. Our source-code integration (Section 9) follows this principle, querying a pre-existing code knowledge graph (AST nodes, call graphs, dependency relationships) maintained by an external service and joining the results with runtime DOM observations. The key architectural decision is to reuse an existing source-code analysis service rather than build one, avoiding duplication and leveraging a mature implementation that already handles OAuth, repository cloning, AST parsing, and call-graph construction.

Competitive Analysis Matrix

Table [tab:competitive]{reference-type="ref" reference="tab:competitive"} presents a feature comparison across 25+ tools in the QA and application analysis landscape. The matrix evaluates eight capabilities: autonomous discovery (D), temporal version tracking (T), source-code integration (S), code quality drift (Q), visual drift (V), knowledge graph storage (K), remediation pipeline (R), and universal scheduling (U).

: ::: tabular p3.2cm C0.7cm C0.7cm C0.7cm C0.7cm C0.7cm C0.7cm C0.7cm C0.7cm p4.0cm Tool / Platform & D & T & S & Q & V & K & R & U & Category
Living Blueprint & \bullet & \bullet & \bullet & \bullet & \bullet & \bullet & \bullet & \bullet & Integrated QA + Discovery
Crawljax & \bullet & -- & -- & -- & -- & -- & -- & -- & Model extraction
WebMate & \bullet & -- & -- & -- & \circ & -- & -- & -- & Cross-browser testing
AppFlow & \bullet & -- & -- & -- & -- & -- & -- & -- & Mobile UI mapping
Mabl & -- & -- & -- & -- & \bullet & -- & -- & -- & AI test automation
Testim & -- & -- & -- & -- & \bullet & -- & -- & -- & AI test automation
Functionize & -- & -- & -- & -- & \bullet & -- & -- & -- & AI test automation
Autify & \circ & -- & -- & -- & \bullet & -- & -- & -- & AI test automation
QA Wolf & -- & -- & -- & -- & \circ & -- & -- & -- & Autonomous test gen
Meticulous.ai & -- & -- & -- & -- & \bullet & -- & -- & -- & Traffic replay
Applitools Eyes & -- & \circ & -- & -- & \bullet & -- & -- & -- & Visual testing
Percy (BrowserStack) & -- & -- & -- & -- & \bullet & -- & -- & -- & Visual testing
ContentKing & \circ & \bullet & -- & -- & -- & -- & -- & -- & SEO monitoring
Crawlee (Apify) & \bullet & -- & -- & -- & -- & -- & -- & -- & Crawl framework
Screaming Frog & \bullet & -- & -- & -- & -- & -- & -- & -- & SEO crawler
Sitebulb & \bullet & \circ & -- & -- & -- & -- & -- & -- & SEO + structure
Dynatrace Smartscape & \bullet & \bullet & -- & -- & -- & \bullet & \circ & -- & Infra discovery
Faddom & \bullet & \circ & -- & -- & -- & -- & -- & -- & Infra discovery
modelizeIT & \bullet & \circ & -- & -- & -- & -- & -- & -- & Infra discovery
vFunction & \circ & \circ & \bullet & -- & -- & \circ & -- & -- & Architecture analysis
ArchUnit & -- & -- & \bullet & \circ & -- & -- & -- & -- & Architecture rules
Axivion Suite & -- & \bullet & \bullet & \circ & -- & -- & -- & -- & Architecture erosion
CodeScene & -- & \bullet & \bullet & \circ & -- & -- & -- & -- & Social-technical analysis
Sourcegraph & -- & -- & \bullet & -- & -- & -- & -- & -- & Code search
Fallow & -- & -- & \bullet & \bullet & -- & -- & -- & -- & Code quality (Rust)
knip & -- & -- & \circ & \circ & -- & -- & -- & -- & Unused code
ts-prune & -- & -- & \circ & \circ & -- & -- & -- & -- & Unused exports
madge & -- & -- & \circ & \circ & -- & -- & -- & -- & Circular deps
dependency-cruiser & -- & -- & \bullet & \circ & -- & -- & -- & -- & Dependency rules
NDepend & -- & \circ & \bullet & \bullet & -- & -- & -- & -- & .NET analysis
Selenium / Playwright & -- & -- & -- & -- & -- & -- & -- & -- & Browser automation
Cypress & -- & -- & -- & -- & -- & -- & -- & -- & Browser automation\

::::

The matrix reveals the gap clearly. Infrastructure discovery platforms (Dynatrace, Faddom) provide autonomous discovery and temporal tracking but target backend topology, not frontend structure. Code quality tools (Fallow, NDepend) provide deep static analysis but lack temporal tracking and QA integration. Visual testing tools (Applitools, Percy) detect visual drift but miss structural and code-quality regressions. AI test automation tools (Mabl, Testim) provide intelligent test execution but assume a known application surface. No existing tool combines all eight capabilities. Living Blueprint is the first system to unify autonomous discovery, temporal versioning, source-code integration, code-quality drift, visual drift, knowledge-graph storage, remediation pipeline integration, and universal scheduling into a single architecture.

Background and Preliminaries

Living Blueprint is not a standalone system. It is an extension of NexusQA, an existing AI-native quality assurance platform, and it leverages three pre-existing infrastructure services: nexus-workflows (trigger.dev-backed scheduling and dispatch), nexus-github-manager (source-code integration), and Fallow (Rust-based static analysis). Understanding these foundations is necessary context for the architecture presented in Section 4{reference-type="ref" reference="sec:architecture"}.

NexusQA Platform Overview

NexusQA is a multi-tenant quality assurance platform that unifies ten testing paradigms---regression, integration, smoke, visual, performance, accessibility, security, API, exploratory, and load---within a single architecture. It features a seven-stage autonomous remediation pipeline: Detection, AI Triage, Plan Generation, Opus 4.6 Plan Review Gate, Execution, Verification, and Human QA Sign-Off. The platform operates as a Nexus Core Plugin, deployed on Kubernetes with PostgreSQL, Redis (BullMQ), MinIO (S3-compatible object storage), and GraphRAG (PostgreSQL + Qdrant + Neo4j) as its data tier.

All AI operations are dispatched through a centralized orchestrator that resolves job types from a skill registry, executes across four tiers (LLM-only, tool-using, chain, and multi-agent), and delivers results via WebSocket events and HTTP callbacks. NexusQA registers 16 skills in this registry, covering test generation, bug triage, remediation planning, plan review, test execution, visual diffing, performance auditing, accessibility scanning, security probing, and self-healing.

Living Blueprint adds a new dimension to this platform: the application model itself becomes a managed, queryable, drift-monitored entity rather than an implicit assumption.

nexus-workflows Architecture

The nexus-workflows service provides trigger.dev-backed scheduling and dispatch for all recurring and batch workloads across the Nexus ecosystem. It exposes schedule management via POST /api/v1/trigger/schedules (create), PATCH (update), DELETE (remove), and POST .../run-now (immediate trigger). Run history is tracked in trigger.run_logs and trigger.run_history. Workflow definitions are stored in trigger.workflows and trigger.task_definitions.

This infrastructure is already deployed and operational. Living Blueprint does not build a new scheduler. Every scheduled task---daily crawls, hourly critical-page checks, weekly Fallow scans, weekly deep architecture scans---registers with trigger.dev through the existing API. The universal scheduler UI (Section 8) is a generalized frontend over this existing backend, not a replacement for it.

The dispatch path is:

 →  →  →  → 

nexus-github-manager

The nexus-github-manager service provides full source-code integration: GitHub OAuth, repository cloning, AST parsing, call-graph construction, embedding generation, and a Code Explorer UI. It maintains a code knowledge graph queryable via Cypher through githubApi.cypherQuery(). It exposes reusable React components: FileTree, CodeViewer, CodeEntityPanel, and RelationshipsPanel.

Living Blueprint foreign-keys to github_manager.connected_repositories(id) for its source-code association. It subscribes to sync-job-completed webhook events to trigger re-analysis when the source code updates. It queries the pre-existing code knowledge graph for AST node types, function signatures, and call-graph centrality metrics used in functional intent classification. It embeds the existing FileTree and CodeViewer components in the Architecture Review Console for drill-down from drift events to source code. Zero duplication.

Fallow Architecture

Fallow is a Rust-based TypeScript/JavaScript codebase analyzer that detects five categories of code quality issues: unused code (dead files, exports, and dependencies), code duplication (via suffix-array algorithms), circular dependencies (import cycles), complexity hotspots (cyclomatic and cognitive complexity), and architecture boundary violations (across four architecture presets: bulletproof, layered, hexagonal, and feature-sliced). It achieves 3--18×× the performance of comparable JavaScript-based tools, analyzing 3,000+ file monorepos in approximately 300ms.

Fallow is already deployed in the NexusQA ecosystem as skill qa_fallow_code_review. It ships with an MCP (Model Context Protocol) server that enables AI agents to invoke analysis programmatically. Living Blueprint extends this existing deployment by scheduling recurring Fallow scans, diffing results across scans to detect newly introduced findings, and generating drift events that enter the standard severity-scoring and remediation pipeline.

Formal Definitions

We define the following mathematical structures used throughout the paper.

Definition 1 (Application Graph). An application under test is modeled as a directed graph G=(V,E)G = (V, E) where:

  • V=VpVcVaVfV = V_p ∪ V_c ∪ V_a ∪ V_f is the set of vertices, partitioned into pages (VpV_p), components (VcV_c), API endpoints (VaV_a), and Fallow findings (VfV_f).

  • E \subseteq V × V ×  is the set of typed directed edges, where  = \{, , , , , \} is the set of relationship types.

Definition 2 (Drift Event). A drift event at time tt for element vVv ∈ V is a tuple:

D(v,t)=(τ,σ,ht1,ht,Δ)D(v, t) = (τ, σ, h_{t-1}, h_t, Δ)

where τ ∈  is the drift type drawn from the drift taxonomy  (14 types including dead_code_added, circular_dep_introduced, etc.), σ ∈ _{≥ 0} is the severity score, ht1h_{t-1} and hth_t are the content hashes at times t1t-1 and tt, and ΔΔ is the structured diff payload.

Definition 3 (Coverage). The blueprint coverage of an application at time tt is:

C(t) = (|V_{}(t)|}{|V_{}(t)|}

where V_{}(t) \subseteq V_{}(t) is the set of elements the discovery engine has observed by time tt and V_{}(t) is the true set of all elements. In practice, |V_{}(t)| is estimated via crawl saturation analysis: when three consecutive full crawls discover fewer than ϵ\epsilon new elements (default ϵ=5\epsilon = 5), |V_{}(t)| is taken as the estimate of |V_{}(t)|.

Definition 4 (Severity Score). The composite drift severity for an element vv at time tt is:

S(v, t) = Σ_{d ∈ D(v,t)} w_{τ(d)} · [τ(d)]

where wτw_τ are type-specific weights: w=w=3w_{} = w_{} = 3; w=w=w=w=2w_{} = w_{} = w_{} = w_{} = 2; w=w=w=1w_{} = w_{} = w_{} = 1; w=w=w=0.5w_{} = w_{} = w_{} = 0.5. Thresholds: S>5S > 5 is [critical]{.smallcaps} (auto-ticket with remediation), S>2S > 2 is [high]{.smallcaps} (auto-ticket), S>0S > 0 is [medium]{.smallcaps} (logged with notification).

Definition 5 (Bloom Filter False Positive Rate). For the visited-set Bloom filter with mm bits and kk hash functions after inserting nn URLs:

P_{}(n) = (1 - e^{-kn/m})^k

We target P_{} ≤ 0.01 for n=106n = 10^6 URLs, achieved with m9.6×106m \approx 9.6 × 10^6 bits (\sim<!-- -->{=html}1.2 MB) and k=7k = 7.

System Architecture

Living Blueprint is composed of six subsystems that together transform NexusQA from a reactive test execution platform into a proactive, drift-aware quality governance system. Figure [fig:architecture]{reference-type="ref" reference="fig:architecture"} presents the complete system architecture. We emphasize two architectural constraints that shaped every design decision: (1) all recurring and batch workloads dispatch exclusively through the existing nexus-workflows (trigger.dev) infrastructure---no new background workers, no local cron jobs, no setInterval processes; and (2) all source-code analysis leverages the existing nexus-github-manager service---no repository cloning, no AST parsing, no call-graph construction is duplicated.

+--------------------------------------------------------------+
|         LIVING BLUEPRINT - SYSTEM ARCHITECTURE               |
+--------------------------------------------------------------+
|                                                              |
| +------------+  +------------+  +------------+              |
| | ONBOARDING |->| DISCOVERY  |->| REPOSITORY |              |
| |   WIZARD   |  |   ENGINE   |  | (GraphRAG) |              |
| |            |  |            |  |            |              |
| | * URLs     |  | * Dispatch |  | * Elements |              |
| | * Platform |  |   via trig |  | * Versions |              |
| | * Config   |  |   ger.dev  |  | * Relations|              |
| | * Repo     |  | * Chain    |  | * Bi-temp  |              |
| |  (reuses   |  |   for >1K  |  | (queried   |              |
| |  github-   |  | * NO local |  |  via cypher|              |
| |  manager)  |  |   process  |  |  from      |              |
| +------------+  +-----+------+  |  gh-mgr)   |              |
|                       |         +-----+------+              |
|                       v               v                      |
| +------------+  +------------+  +------------+              |
| | UNIVERSAL  |<-|   DRIFT    |<-| ARCH REVIEW|              |
| | SCHEDULER  |  |  DETECTOR  |  |  CONSOLE   |              |
| |            |  |            |  |            |              |
| | * Schedule |  | * Hash     |  | * ASCII    |              |
| |   ANY skill|  |   diff     |  |   diagrams |              |
| | * Crawls,  |  | * DOM sig  |  | * Red/grn  |              |
| |   code rvw |  | * Visual   |  | * Drill-   |              |
| |   security |  |   AI       |  |   down     |              |
| |   fallow,  |  | * Src diff |  | * Timeline |              |
| |   anything |  |   (L4)     |  | * FileTree |              |
| | * Uses     |  | * Fallow   |  |   CodeView |              |
| |   trig.dev |  |   (L5)     |  | * Fallow   |              |
| +------------+  +-----+------+  |   inline   |              |
|                       |         +------------+              |
|                       v                                      |
| +------------------------------------------------------+   |
| |     7-STAGE REMEDIATION PIPELINE                      |   |
| | Detect > Triage > Plan > Review > Execute > Verify    |   |
| |                 > Human Sign-Off                       |   |
| +------------------------------------------------------+   |
|                                                              |
+--------------------------------------------------------------+
| DISPATCH FABRIC (existing nexus-workflows / trigger.dev)     |
| +----------------------------------------------------------+|
| | orchestrator -> trigger.dev -> nexus-workflows (worker)   ||
| | Schedules:  trigger.schedule_configs (existing)           ||
| | Batches:    trigger.batches (existing)                    ||
| | Workflows:  trigger.workflows (existing)                  ||
| | Run logs:   trigger.run_logs / run_history (existing)     ||
| | Skill reg:  graphrag.skill_registry                       ||
| +----------------------------------------------------------+|
+--------------------------------------------------------------+
| EXTERNAL SERVICES (reused, not rebuilt)                       |
| +--------------+--------------+----------------------------+|
| | github_mgr   | Fallow MCP   | PostgreSQL | GraphRAG     ||
| | (source code | (code quality| Redis/BullMQ | MinIO      ||
| |  OAuth, AST  |  via MCP     | trigger.dev              ||
| |  call graphs)|  server)     |                           ||
| +--------------+--------------+----------------------------+|
+--------------------------------------------------------------+

Subsystem 1: Onboarding Wizard

The onboarding wizard is a five-step modal flow that bootstraps a new project into the Living Blueprint. Step 1 collects project metadata (name, description, platform type). Step 2 configures target URLs and links a source-code repository; critically, the repository selector pulls from github_manager.connected_repositories, showing only repositories the user has already connected through the nexus-github-manager OAuth flow. Step 3 configures platform-specific settings (authentication credentials, viewport dimensions, cookie consent handling). Step 4 presents four preset schedule toggles---daily full crawl (0 3 * * *), hourly critical-page check (0 * * * *), weekly Fallow code review (0 4 * * 0), weekly deep architecture scan (0 5 * * 0)---all of which register with trigger.dev through the existing schedule API. Step 5 displays a summary and launches the initial discovery crawl.

The wizard produces three artifacts: a blueprint_projects row with foreign keys to both the organization and the github-manager repository, a set of scheduled_tasks rows registered with trigger.dev, and an initial crawl dispatch via POST /api/v1/dispatch with job type qa_blueprint_onboard_chain.

Subsystem 2: Discovery Engine

The discovery engine is a Tier 3 chain skill (qa_blueprint_onboard_chain) composed of six sequential steps, each itself a registered skill:

  1. qa_blueprint_crawl (Tier 2): Playwright-based fan-out crawl. For sites with <!-- -->{=html}1,000 URLs, dispatch is batched via trigger.dev batch primitives. For sites with >><!-- -->{=html}1,000 URLs, the chain skill manages internal fan-out with checkpoint-based resumability. A Bloom filter with m=9.6×106m = 9.6 × 10^6 bits and k=7k = 7 hash functions tracks visited URLs, achieving P_{} ≤ 0.01 for up to one million URLs in approximately 1.2 MB of memory.

  2. qa_blueprint_source_analyze (Tier 2): Queries nexus-github-manager's code knowledge graph via Cypher to extract AST node types, function signatures, call-graph centrality, and dependency relationships for components corresponding to discovered DOM elements.

  3. qa_blueprint_fallow_scan (Tier 2): Invokes the Fallow MCP server against the project's repository workspace, producing a SARIF-formatted report of dead code, duplication, circular dependencies, complexity hotspots, and architecture boundary violations.

  4. qa_blueprint_element_merge (Tier 2): Reconciles DOM-extracted elements with source-code components and Fallow findings, creating or updating entries in the blueprint_elements table and establishing relationships in the knowledge graph.

  5. qa_blueprint_analyze (Tier 1, LLM-only): Classifies each element's functional intent (authentication, navigation, data display, form input, etc.) using the hybrid DOM + source-code feature set. This is the step where source-code enhancement yields the 19-percentage-point accuracy gain.

  6. qa_blueprint_diagram_generate (Tier 2): Generates architectural diagrams in ASCII and Mermaid formats based on the discovered element graph, including page navigation flows, component dependency trees, and API call maps.

Each step emits a job:chain_step_complete WebSocket event. NexusQA's callback routes persist results incrementally, so partial crawl results are visible in the UI before the full chain completes.

Subsystem 3: Living Blueprint Repository

The repository stores discovered elements as bi-temporal entities in GraphRAG. Each element has two temporal dimensions: system time (when the element was observed by the discovery engine) and valid time (when the element was created or last modified in the application, estimated from source-code commit timestamps when available). This bi-temporal model enables queries like "show me the state of the application as it existed on March 1st" (valid time) or "show me what we knew about the application on March 1st" (system time)---distinct questions with different answers.

Element types include pages, UI components, forms, API endpoints, navigation links, media assets, and---via the Fallow integration---code-quality findings. Relationships are typed edges: navigates_to, contains, calls_api, depends_on, similar_to, and finding_in. Tenant isolation is enforced via X-Company-ID and X-App-ID headers on all GraphRAG queries.

The blueprint_elements table is hash-partitioned 16 ways on element ID for horizontal scalability. Element versions are stored in blueprint_element_versions with immutable rows---updates create new versions, never overwrite.

Subsystem 4: Drift Detector

The drift detector implements five comparison layers, applied in order of increasing computational cost:

Layer 1 --- Content Hash. SHA-256 of the normalized element content. Exact match means no drift; mismatch proceeds to Layer 2. Cost: O(1)O(1) lookup.

Layer 2 --- DOM Signature. Structural comparison of the element's DOM subtree using a locality-sensitive hash that tolerates minor text changes while detecting structural modifications (added/removed child nodes, changed element types). We define the similarity between two DOM signatures as:

(d_1, d_2) = (/)

where S(d)S(d) is the set of structural shingles (contiguous subsequences of DOM node types) of length q=3q = 3. Similarity below a threshold \theta_{} = 0.85 triggers Layer 3.

Layer 3 --- Visual AI Diff. An Opus 4.6 vision-capable LLM compares before/after screenshots of the element, classifying the change as cosmetic (styling only), functional (behavior-affecting), or structural (layout-altering). This layer distinguishes a font-size change (cosmetic, low severity) from a removed button (functional, high severity) that might produce similar DOM signature deltas.

Layer 4 --- Source Diff. For elements with linked source-code components (via the blueprint_source_component_map bridge table), the system queries nexus-github-manager for commit-level diffs since the last crawl. Changes in the source that do not produce observable DOM changes are flagged as unexplained source drift---the most architecturally concerning drift type, weighted at w=3w = 3 in the severity formula (Equation [eq:severity]{reference-type="ref" reference="eq:severity"}).

Layer 5 --- Fallow Diff. The current Fallow scan results are compared against the previous scan's results. Newly introduced findings (dead code, duplication, circular dependencies, complexity hotspots, architecture violations) generate drift events of the corresponding type. Resolved findings (present in the previous scan but absent in the current) are logged as positive drift---architecture improvement.

The five layers compose into the severity score S(v,t)S(v, t) defined in Equation [eq:severity]{reference-type="ref" reference="eq:severity"}. Drift events with S>5S > 5 automatically create QA tickets and enter the seven-stage remediation pipeline. Events with S>2S > 2 create tickets without immediate remediation. Events with S>0S > 0 are logged and surface in the Architecture Review Console.

Subsystem 5: Universal Scheduler

The universal scheduler generalizes the concept of recurring QA tasks beyond blueprint-specific crawls. Any skill registered in graphrag.skill_registry---security probes, performance audits, accessibility scans, ticket sweeps, custom Fallow configurations---can be scheduled through a single API surface backed by trigger.dev.

The scheduled_tasks table stores task metadata (name, description, category, job type, input parameters, target type and ID, priority, failure policy) alongside a trigger_schedule_id that references the trigger.dev schedule. All CRUD operations are two-phase: first persist or update the scheduled_tasks row, then call the corresponding trigger.dev API (POST /api/v1/trigger/schedules, PATCH, DELETE), rolling back the local row on trigger.dev failure.

Categories include blueprint_crawl, blueprint_fallow, blueprint_drift_detect, code_review, security_audit, performance_audit, accessibility_audit, ticket_sweep, and custom. The category determines which skills appear in the job-type dropdown and which default input parameters are pre-populated, but any valid skill can be scheduled in any category. This extensibility means that every future recurring workload in NexusQA---regardless of whether it relates to Living Blueprint---uses the same scheduling surface.

Subsystem 6: Architecture Review Console

The Architecture Review Console is a five-mode interactive visualization of the Living Blueprint:

  1. Overview: Hierarchical tree of all discovered elements with color-coded status indicators (green = stable, yellow = minor drift, red = significant drift, gray = stale/unverified). Fallow findings appear inline as markers on affected elements.

  2. Timeline: Temporal view showing element additions, modifications, and removals over a configurable date range, with source-code commit markers overlaid for correlation.

  3. Relationships: Graph visualization of element dependencies---page navigation flows, component hierarchies, API call chains---rendered using force-directed layout with typed edge coloring.

  4. API Health: Endpoint-centric view showing response times, error rates, and schema drift for all discovered API endpoints.

  5. UX Flow: User journey visualization showing the most common navigation paths through the application, computed from page-to-page relationship traversal frequencies.

The console embeds nexus-github-manager's FileTree and CodeViewer components for source-code drill-down. Clicking any element in any mode opens a detail panel showing the element's full version history, all associated drift events, linked Fallow findings, related test cases, and a direct link to the source file and line number in the CodeViewer. A "Create Ticket" action on any drift event or Fallow finding generates a QA ticket pre-populated with the finding details, entering the standard remediation pipeline.

Integration with Existing Infrastructure

A deliberate architectural decision pervades the system: Living Blueprint adds zero new runtime services. All new functionality is expressed as skills (registered in graphrag.skill_registry), database tables (in the nexusqa schema), API routes (on the existing NexusQA Express server), and frontend pages (in the existing NexusQA Next.js application). The Fallow MCP server is deployed as a sidecar to the nexus-workflows pod or as a standalone lightweight service, but it is an existing open-source binary, not custom code.

This constraint yields three benefits. First, operational complexity does not increase---no new Kubernetes deployments to monitor, no new services to scale, no new failure modes to handle. Second, the existing dispatch, scheduling, and monitoring infrastructure is reused without modification, inheriting its battle-tested reliability. Third, the implementation can be verified against the existing platform's deployment and observability tooling without introducing new observability requirements.

The dispatch fabric handles all workload execution. The knowledge graph handles all entity storage. The github-manager handles all source-code analysis. The Fallow MCP server handles all static analysis. Living Blueprint orchestrates these existing capabilities into a coherent discovery-and-drift pipeline without duplicating any of them.

Project Onboarding Flow

The transition from "install the plugin" to "see a living map of your application" should take minutes, not days. Traditional application discovery tools require extensive configuration---crawl seeds, authentication cookies, scope boundaries, exclusion patterns---before returning any useful result. Living Blueprint compresses this into a five-step wizard that leverages infrastructure the platform already owns: connected repositories from nexus-github-manager, scheduling primitives from nexus-workflows, and organizational context from the authentication layer.

Five-Step Wizard

The onboarding wizard is implemented as a stepper component within the NexusQA frontend (Next.js 14, App Router). Each step validates before advancing, and the wizard state persists to localStorage so that users who navigate away can resume without data loss.

 ┌──────────────────────────────────────────────────────────┐
 │            ONBOARDING WIZARD — STEP FLOW                 │
 ├──────────────────────────────────────────────────────────┤
 │                                                          │
 │  ┌────┐    ┌────┐    ┌────┐    ┌────┐    ┌────┐        │
 │  │ 1  │───▶│ 2  │───▶│ 3  │───▶│ 4  │───▶│ 5  │        │
 │  └────┘    └────┘    └────┘    └────┘    └────┘        │
 │  Project   URLs &    Platform  Schedule  Review &       │
 │  Info      Git Repo  Config    Presets   Launch         │
 │                                                          │
 │  Step 1: Name, description, team assignment             │
 │  Step 2: Entry URLs + repo from github-manager          │
 │  Step 3: Platform detection + auth config               │
 │  Step 4: Toggle schedule presets (trigger.dev)           │
 │  Step 5: Confirm everything, dispatch first crawl       │
 └──────────────────────────────────────────────────────────┘

Step 1: Project Information. The user provides a project name, optional description, and team assignment. The organization context is inherited from the JWT claims, enforcing tenant isolation from the first interaction. A project slug is generated for URL-friendly references, and a UUID primary key is allocated for the blueprint_projects table.

Step 2: URLs and Repository Connection. This step collects the entry-point URLs for crawling and, critically, an optional source code repository. The repository selector does not present a free-text input. Instead, it queries the nexus-github-manager service for the organization's connected_repositories---repos where the user has already completed OAuth authorization and webhook installation. This reuse is deliberate: it eliminates a second OAuth flow, avoids storing duplicate GitHub tokens, and ensures that only repositories the user has explicitly connected are available for source-code-enhanced analysis.

 ┌─ Step 2: Add URLs & Repository ──────────────────────┐
 │                                                       │
 │  Entry URLs (one per line):                           │
 │  ┌───────────────────────────────────────────┐       │
 │  │ https://myapp.com                          │       │
 │  │ https://myapp.com/dashboard                │       │
 │  │ https://myapp.com/api/docs                 │       │
 │  └───────────────────────────────────────────┘       │
 │                                                       │
 │  Link Source Repository (optional):                   │
 │  ┌───────────────────────────────────────────┐       │
 │  │ ▼  Select from connected repos...         │       │
 │  │ ┌─────────────────────────────────────┐   │       │
 │  │ │  acme-corp/frontend-app    (React)  │   │       │
 │  │ │  acme-corp/api-gateway     (Node)   │   │       │
 │  │ │  acme-corp/mobile-bff      (TS)     │   │       │
 │  │ └─────────────────────────────────────┘   │       │
 │  └───────────────────────────────────────────┘       │
 │                                                       │
 │  No repos? [Connect a Repository] → github-manager    │
 │                                                       │
 │  [Back]                                    [Next →]   │
 └───────────────────────────────────────────────────────┘

If no repositories are connected, a link redirects to the GitHub Manager's connection flow. This is a conscious design choice: we never prompt the user for a GitHub token inline. The separation of concerns between "connecting a repo" (GitHub Manager's responsibility) and "using a connected repo" (Living Blueprint's responsibility) prevents token sprawl and centralizes OAuth lifecycle management [@fowler2004].

Step 3: Platform Configuration. Living Blueprint inspects the entry URLs and, where possible, auto-detects the application platform. Detection is heuristic: response headers (X-Powered-By, Server), meta generator tags, known JavaScript bundle signatures, and CSS framework fingerprints. The user confirms or corrects the detection, and selects authentication mode if the application requires login.

Table 1{reference-type="ref" reference="tab:platform-support"} enumerates the platforms supported at launch, along with the detection signals used by the auto-detection heuristic.

Platform Detection Signal Crawl Strategy Auth Mode


Next.js / React __NEXT_DATA__, React root SPA-aware Playwright Cookie / JWT Vue / Nuxt __NUXT__, Vue devtools flag SPA-aware Playwright Cookie / JWT Angular ng-version attribute SPA-aware Playwright Cookie / JWT WordPress wp-content, generator meta HTTP crawl + JS render Cookie Shopify Shopify.theme, CDN pattern HTTP crawl + JS render Storefront API Laravel / Rails Framework headers, CSRF meta HTTP crawl Session cookie Static site No JS framework signals HTTP crawl N/A API-only (Swagger) /swagger-ui, OpenAPI spec Schema parsing Bearer token Custom SPA Framework not detected Playwright (default) Configurable

: Platform Support Matrix

Step 4: Schedule Presets. Rather than presenting a blank scheduling form---which would require users to understand cron syntax before they have even seen their first discovery result---Step 4 offers four toggle-activated presets:

  • Daily full crawl (0 3 * * *): Re-crawls all entry URLs and their linked pages nightly.

  • Hourly critical pages check (0 * * * *): Monitors only pages flagged as critical (login, checkout, dashboard) for rapid drift detection.

  • Weekly Fallow code review (0 4 * * 0): Runs the Fallow static analyzer against the linked repository for dead code, duplication, circular dependencies, and complexity hotspots.

  • Weekly deep architecture scan (0 5 * * 0): Generates updated architecture diagrams and performs structural drift analysis.

Every preset creates a row in nexusqa.scheduled_tasks and registers a corresponding schedule in trigger.dev via the existing POST /api/v1/trigger/schedules endpoint. No new scheduling infrastructure is introduced. Users who want finer-grained control are directed to the Universal Scheduler page (Section 7{reference-type="ref" reference="sec:scheduler"}), which exposes the full power of trigger.dev's scheduling primitives through a single, generalized interface.

Step 5: Review and Launch. A summary card displays all configuration. Upon confirmation, the wizard persists the blueprint_projects row, creates the selected schedules, and immediately dispatches the first crawl via POST /api/v1/dispatch with job_type: qa_blueprint_onboard_chain. The user is redirected to the Architecture Review Console, where a real-time progress bar (driven by WebSocket events from the chain skill's step-completion callbacks) shows the discovery engine working through the six-step chain described in Section 6{reference-type="ref" reference="sec:discovery"}.

Onboarding Latency

For a typical SPA with 50--200 discoverable pages and a linked repository of 500--2,000 source files, the complete onboarding chain executes in 90--180 seconds. The limiting factor is the Playwright-based DOM crawl (Step 1 of the chain), which is parallelized via trigger.dev batch dispatch at a concurrency of 10 browser contexts. Subsequent steps---source analysis, Fallow scan, element merge, functional classification, and diagram generation---run sequentially but benefit from the relatively modest data volume of a first crawl.

Autonomous Discovery Engine

The discovery engine is the computational heart of Living Blueprint. It transforms a set of entry-point URLs and an optional source code repository into a structured, version-tracked catalog of application elements---pages, components, API endpoints, data flows, navigation structures---stored as typed entities and relationships in GraphRAG. Every operation the engine performs is dispatched through nexus-workflows (trigger.dev). There are no local background processes, no setInterval loops, no in-process workers. If the dispatch infrastructure is unavailable, the engine fails loudly with a structured error message specifying which service is unreachable, the HTTP status code, and concrete troubleshooting steps. This is not a design preference; it is an invariant.

Chain Skill Pipeline

The discovery engine is implemented as a Tier 3 chain skill, qa_blueprint_onboard_chain, registered in the graphrag.skill_registry table. Chain skills compose multiple sub-skills into a directed acyclic graph (DAG) where each step's output feeds the next step's input. The orchestrator manages retry logic, timeout enforcement, and progress reporting for each step independently.

 ┌──────────────────────────────────────────────────────────┐
 │  DISCOVERY CHAIN: qa_blueprint_onboard_chain (Tier 3)    │
 ├──────────────────────────────────────────────────────────┤
 │                                                          │
 │  Step 1: qa_blueprint_crawl (Tier 2, tool-using)        │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Playwright browser pool fan-out            │         │
 │  │  Tools: playwright, s3 (MinIO screenshots)  │         │
 │  │  Output: raw DOM snapshots per URL          │         │
 │  └──────────────────┬─────────────────────────┘         │
 │                     │                                    │
 │                     ▼                                    │
 │  Step 2: qa_blueprint_source_analyze (Tier 2)           │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Queries nexus-github-manager via cypher    │         │
 │  │  Tools: githubApi.cypherQuery, db           │         │
 │  │  Output: AST entities, call graphs, imports │         │
 │  └──────────────────┬─────────────────────────┘         │
 │                     │                                    │
 │                     ▼                                    │
 │  Step 3: qa_blueprint_fallow_scan (Tier 2)              │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Invokes Fallow MCP server against repo     │         │
 │  │  Tools: fallow_mcp, s3 (SARIF storage)      │         │
 │  │  Output: dead code, duplication, cycles,     │         │
 │  │          complexity, architecture violations │         │
 │  └──────────────────┬─────────────────────────┘         │
 │                     │                                    │
 │                     ▼                                    │
 │  Step 4: qa_blueprint_element_merge (Tier 2)            │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Reconciles DOM elements + source entities  │         │
 │  │  + Fallow findings into unified elements    │         │
 │  │  Tools: db, graphrag                        │         │
 │  │  Output: merged element catalog             │         │
 │  └──────────────────┬─────────────────────────┘         │
 │                     │                                    │
 │                     ▼                                    │
 │  Step 5: qa_blueprint_analyze (Tier 1, llm_only)        │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Opus 4.6 functional intent classification  │         │
 │  │  routing_hint: 'reasoning'                  │         │
 │  │  Output: intent labels, risk scores,         │         │
 │  │          test generation hints               │         │
 │  └──────────────────┬─────────────────────────┘         │
 │                     │                                    │
 │                     ▼                                    │
 │  Step 6: qa_blueprint_diagram_generate (Tier 2)         │
 │  ┌────────────────────────────────────────────┐         │
 │  │  Generates architecture diagrams            │         │
 │  │  Tools: graphrag (read merged catalog)      │         │
 │  │  Output: ASCII + Mermaid diagram artifacts  │         │
 │  └────────────────────────────────────────────┘         │
 │                                                          │
 │  Each step emits: job:chain_step_complete via WS        │
 │  Final:           job:completed with full catalog        │
 └──────────────────────────────────────────────────────────┘

Dispatch Flow

The complete dispatch lifecycle proceeds as follows. A user action (clicking "Launch" in the onboarding wizard, or a scheduled trigger firing) invokes BlueprintProjectService.triggerCrawl(), which creates a blueprint_crawl_sessions row with status pending and then issues a POST to the nexus-orchestrator's dispatch endpoint:

 POST nexus-orchestrator:8080/api/v1/dispatch
 {
   "job_type": "qa_blueprint_onboard_chain",
   "organization_id": "org-uuid",
   "input": {
     "project_id": "proj-uuid",
     "entry_urls": ["https://myapp.com", ...],
     "repository_id": "repo-uuid-or-null",
     "crawl_config": { "maxDepth": 10, ... }
   },
   "callback_url": "https://nexusqa:9099/nexusqa/api/
                     callbacks/blueprint-chain",
   "routing_hint": "reasoning"
 }

The orchestrator resolves qa_blueprint_onboard_chain from the skill registry, retrieves its SKILL.md system prompt and execution configuration, and registers the job with trigger.dev. The trigger.dev worker picks up the job, begins executing the six-step chain, and emits job:chain_step_complete WebSocket events after each step. These events flow through Redis Pub/Sub to the gateway's Socket.IO layer and into the dashboard, where they drive a real-time progress indicator. Upon completion, the orchestrator delivers a callback to NexusQA, which persists the discovered elements, Fallow findings, and diagrams to the database and GraphRAG.

Dual-Path Analysis

The discovery engine employs two complementary analysis paths that, when combined, produce a richer and more accurate catalog than either path alone.

Path A: DOM Crawl. The Playwright-based crawler navigates to each URL, waits for network idle, and captures a full DOM snapshot. It extracts: page title, meta tags, headings, navigation links, form elements, interactive components (buttons, dropdowns, modals), images, embedded iframes, and API calls observed during page load. Each extracted element is assigned a preliminary type based on DOM heuristics---a <form> with an action attribute is classified as a "form submission endpoint," a <nav> element with <a> children as "navigation structure," and so on. DOM-only classification achieves reasonable accuracy for structural elements but struggles with functional semantics: it can identify that a button exists but not what workflow it initiates.

Path B: Source Code Analysis. When a repository is linked, the source analysis step queries the nexus-github-manager's code knowledge graph via Cypher queries. It retrieves: component definitions (React/Vue/Angular), route declarations, API endpoint handlers, data model schemas, import graphs, and call chains. This information is inherently semantic---a route handler's name, its middleware chain, and its database queries reveal functional intent in ways that DOM structure cannot.

Element Merge (Step 4). The merge step reconciles DOM-discovered elements with source-discovered entities using a multi-signal matching algorithm. URL patterns are matched to route declarations. DOM component tree structures are aligned to React/Vue component hierarchies. API calls observed during crawling are correlated with backend endpoint handlers. The merge produces a unified element record that carries both runtime evidence ("this button was observed at URL X") and source evidence ("this button triggers handler Y in file Z at line N"). This dual provenance enables significantly more accurate functional classification in Step 5, as we quantify in Section 8{reference-type="ref" reference="sec:github-integration"}.

Crawl Complexity

For a site with NN entry-point URLs and a maximum crawl depth of dd, the worst-case page count follows:

P_{\max} = N · Σ_{i=0}^{d} b^{i} = N · (b^{d+1} - 1}{b - 1}

where bb is the average branching factor (outgoing links per page). In practice, bb ranges from 5 to 30 for production web applications, and the URL deduplication filter (a counting Bloom filter with configurable false-positive rate) dramatically reduces the realized page count. For a Bloom filter with mm bits and kk hash functions processing nn distinct URLs, the false-positive probability is:

p_{} = (1 - e^{-kn/m})^{k}

Living Blueprint configures m=220m = 2^{20} bits (128 KB) and k=7k = 7, yielding p_{} < 0.01 for n50,000n ≤ 50{,}000 URLs---well within the expected range for even large enterprise applications. The false-positive rate is monitored per crawl session, and a warning is emitted if it exceeds 0.05, at which point the filter is resized for subsequent sessions.

Dispatch Mode Selection

The service selects dispatch mode based on the estimated URL count:

  • Batch dispatch (|| ≤ 1{,}000): The chain skill's first step fans out as a trigger.dev batch, with up to 10 concurrent browser contexts. Each batch item is an independent Playwright crawl of one URL. Trigger.dev manages concurrency limits, retries, and timeout enforcement.

  • Chain with internal fan-out (|| > 1{,}000): For larger sites, the crawl step itself partitions URLs into chunks of 100 and dispatches each chunk as a sub-batch within the chain. This avoids a single batch with thousands of items, which would overwhelm trigger.dev's scheduling layer.

Both modes converge at Step 4 (element merge), which aggregates results regardless of how they were partitioned.

Session Resilience

Crawl sessions are designed for resilience against partial failures. Each blueprint_crawl_sessions row tracks: total URLs to crawl, URLs completed, URLs failed, and current chain step. If a browser context crashes or a URL times out, the failure is recorded per-URL (in blueprint_crawl_urls with status: ’failed’ and the error message), but the session continues processing remaining URLs. The session status transitions to completed_with_errors rather than failed if at least 80% of URLs succeed.

Trigger.dev provides built-in retry logic with exponential backoff. Each chain step is configured with a maximum of 3 retries and a timeout proportional to the input size. If a step exhausts its retries, the chain skill marks the session as failed and delivers a callback to NexusQA with a structured error payload:

{
  "error": true,
  "code": "CHAIN_STEP_FAILED",
  "step": "qa_blueprint_crawl",
  "attempt": 3,
  "message": "Playwright crawl failed: browser context
              timeout after 120s on 12 of 847 URLs",
  "troubleshooting": [
    "Check Playwright worker pods: kubectl get pods
     -n nexus -l app=nexusqa-playwright-worker",
    "Review failed URLs in blueprint_crawl_urls
     WHERE session_id = 'xxx' AND status = 'failed'",
    "Increase timeout in crawl_config.timeoutMs"
  ]
}

No silent degradation occurs. The user sees the failure in the Architecture Review Console with actionable guidance.

Universal Scheduler via nexus-workflows

A recurring design failure in quality assurance platforms is the proliferation of isolated scheduling surfaces. One page for scheduling test runs. Another for scheduled scans. A third for recurring reports. Each with its own cron parser, its own persistence layer, its own UI patterns, and its own failure-handling semantics. Living Blueprint rejects this fragmentation in favor of a single, generalized scheduler that can configure recurring execution of any skill registered in the platform's skill registry. Blueprint crawls are the first consumer. They will not be the last.

Architectural Principle

The nexus-workflows service, backed by trigger.dev, already provides the complete scheduling primitive: cron expression parsing, next-run computation, timezone-aware execution, retry policies, and run history. It exposes these through a RESTful API (/api/v1/trigger/schedules/*). The Universal Scheduler adds no new scheduling infrastructure. It is a user-facing surface that maps CRUD operations to the existing trigger.dev APIs and maintains a local metadata table for organization-scoped filtering, categorization, and display.

The division of responsibility is explicit:

  • Source of truth for "what is scheduled and why": nexusqa.scheduled_tasks (PostgreSQL, RLS-enforced by organization_id).

  • Source of truth for "when will it run next" and "what happened last time": trigger.dev (trigger.schedule_configs, trigger.run_history).

  • Synchronization mechanism: Idempotent CRUD---create or update the local row first, then call trigger.dev, and roll back the local row on trigger.dev failure.

This two-source architecture avoids both stale caches and split-brain scenarios. If trigger.dev is unreachable, the create/update operation fails and the user is told precisely what happened. No schedule is silently created in the local database without a corresponding trigger.dev registration.

Database Schema

SQL
49 lines
CREATE TABLE nexusqa.scheduled_tasks (
  id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id     UUID NOT NULL,
  name                VARCHAR(500) NOT NULL,
  description         TEXT,
  category            VARCHAR(50) NOT NULL,
  -- categories: blueprint_crawl, blueprint_fallow,
  --   blueprint_drift_detect, code_review,
  --   security_audit, performance_audit,
  --   accessibility_audit, ticket_sweep, custom
  job_type            TEXT NOT NULL,
  -- must exist in graphrag.skill_registry
  trigger_schedule_id TEXT,
  -- returned by trigger.dev on schedule creation
  cron_expression     VARCHAR(100) NOT NULL,
  timezone            VARCHAR(50) DEFAULT 'UTC',
  enabled             BOOLEAN DEFAULT true,
  input_params        JSONB DEFAULT '{}',
  target_type         VARCHAR(30) NOT NULL,
  -- 'project', 'suite', 'plugin', 'global'
  target_id           UUID,
  priority            VARCHAR(10) DEFAULT 'normal',
  max_retries         INTEGER DEFAULT 1,
  failure_policy      VARCHAR(20) DEFAULT 'continue',
  -- 'continue', 'alert', 'disable'
  last_run_at         TIMESTAMPTZ,
  next_run_at         TIMESTAMPTZ,
  last_run_status     VARCHAR(20),
  failure_count       INTEGER DEFAULT 0,
  created_by          UUID NOT NULL,
  created_at          TIMESTAMPTZ DEFAULT now(),
  updated_at          TIMESTAMPTZ DEFAULT now()
);

ALTER TABLE nexusqa.scheduled_tasks
  ENABLE ROW LEVEL SECURITY;

CREATE POLICY scheduled_tasks_org_isolation
  ON nexusqa.scheduled_tasks
  USING (organization_id =
         current_setting('app.current_org_id')::uuid);

CREATE INDEX idx_scheduled_tasks_org
  ON nexusqa.scheduled_tasks(organization_id);
CREATE INDEX idx_scheduled_tasks_category
  ON nexusqa.scheduled_tasks(category);
CREATE INDEX idx_scheduled_tasks_enabled
  ON nexusqa.scheduled_tasks(enabled)
  WHERE enabled = true;

The schema is deliberately generic. There is no blueprint_project_id column, no suite_id column, no domain-specific foreign key. The target_type and target_id pair provides a polymorphic reference that works for blueprint projects, test suites, plugins, or organization-wide tasks. The job_type column references any skill in the registry, and input_params carries skill-specific configuration as opaque JSON. This design ensures that scheduling a Fallow scan, a security probe, a regression suite, or a stale-ticket sweep all flow through the same table, the same API, and the same UI.

CRUD Mapping to trigger.dev

Table 2{reference-type="ref" reference="tab:crud-mapping"} enumerates how each user operation maps to the underlying trigger.dev API, along with the local side effects.

User Action trigger.dev API Local Side Effect


Create schedule POST /schedules Insert scheduled_tasks row Update schedule PATCH /schedules/:id Update row, sync cron Delete schedule DELETE /schedules/:id Delete row Enable PATCH /schedules/:id/enable Set enabled = true Disable PATCH /schedules/:id/disable Set enabled = false Run Now POST /schedules/:id/run-now Update last_run_at View History GET /logs?schedule_id=... Read-only, no local change

: CRUD Mapping: Universal Scheduler to trigger.dev

User Interface

The Scheduled Tasks page presents all active and disabled schedules in a filterable, paginated list. Each row shows the schedule name, category, associated skill, cron expression in human-readable form, last run status, next run time, and a set of contextual actions.

 ┌─ Scheduled Tasks ─────────────────────────── [+ New] ─┐
 │                                                        │
 │  Filter: [All Categories ▼] [All Projects ▼] [⊡ On]   │
 │                                                        │
 │  ┌────────────────────────────────────────────────┐   │
 │  │ ⊡ Daily Full Crawl — my-app                    │   │
 │  │   Category: blueprint_crawl                     │   │
 │  │   Skill: qa_blueprint_crawl                     │   │
 │  │   Cron: 0 3 * * * (UTC)  Every day at 3:00 AM  │   │
 │  │   Last: 2h ago ● OK    Next: in 22h             │   │
 │  │   [Edit] [Disable] [Run Now] [History]          │   │
 │  ├────────────────────────────────────────────────┤   │
 │  │ ⊡ Weekly Fallow Review — my-app                 │   │
 │  │   Category: blueprint_fallow                    │   │
 │  │   Skill: qa_fallow_code_review                  │   │
 │  │   Cron: 0 4 * * 0 (UTC)  Sundays at 4:00 AM    │   │
 │  │   Last: 3d ago ● OK (47 findings)               │   │
 │  │   [Edit] [Disable] [Run Now] [Report]           │   │
 │  ├────────────────────────────────────────────────┤   │
 │  │ ⊡ Hourly Security Scan — public-api             │   │
 │  │   Category: security_audit                      │   │
 │  │   Skill: qa_security_probe                      │   │
 │  │   Cron: 0 * * * * (UTC)  Every hour             │   │
 │  │   Last: 12m ago ● OK    Next: in 48m            │   │
 │  │   [Edit] [Disable] [Run Now] [History]          │   │
 │  ├────────────────────────────────────────────────┤   │
 │  │ ⊠ Stale Ticket Sweep (disabled)                 │   │
 │  │   Category: ticket_sweep                        │   │
 │  │   Skill: qa_ticket_stale_sweep                  │   │
 │  │   Cron: 0 6 * * 1-5 (UTC)  Weekdays at 6 AM    │   │
 │  │   [Edit] [Enable] [Run Now]                     │   │
 │  └────────────────────────────────────────────────┘   │
 │                                                        │
 │  Showing 1-4 of 11    [← Prev]  [Next →]              │
 └────────────────────────────────────────────────────────┘

The "New Scheduled Task" modal walks the user through three logical steps within a single dialog: what to run, when to run it, and how to handle failures.

 ┌─ New Scheduled Task ────────────────────── [X] ───────┐
 │                                                        │
 │  What to run                                           │
 │  ─────────────                                         │
 │  Name:        [                                  ]     │
 │  Description: [                                  ]     │
 │  Category:    [blueprint_crawl                 ▼]      │
 │  Skill:       [qa_blueprint_crawl              ▼]      │
 │               (auto-filtered by category)              │
 │  Target:      ● Project  ○ Suite  ○ Plugin  ○ Global   │
 │               Project: [my-app                 ▼]      │
 │  Params:      ┌──────────────────────────────┐        │
 │               │ { "maxDepth": 10,            │        │
 │               │   "respectRobotsTxt": true } │        │
 │               └──────────────────────────────┘        │
 │                                                        │
 │  When to run                                           │
 │  ────────────                                          │
 │  Preset: ○ Once ○ Hourly ● Daily ○ Weekly ○ Custom    │
 │  Time:   [03:00]   Timezone: [UTC                ▼]    │
 │  Cron:   [0 3 * * *                              ]     │
 │                                                        │
 │  Next 5 runs:                                          │
 │    2026-04-14 03:00 UTC                                │
 │    2026-04-15 03:00 UTC                                │
 │    2026-04-16 03:00 UTC                                │
 │    2026-04-17 03:00 UTC                                │
 │    2026-04-18 03:00 UTC                                │
 │                                                        │
 │  How to handle failures                                │
 │  ──────────────────────                                │
 │  Priority:       [normal             ▼]                │
 │  Max retries:    [1                    ]                │
 │  On failure:     ● Continue  ○ Alert  ○ Disable        │
 │  Notifications:  ⊡ Email  ⊡ Slack                      │
 │                                                        │
 │  [Cancel]                         [Create Schedule]    │
 └────────────────────────────────────────────────────────┘

The category-to-skill filter is instructive. When a user selects "security_audit" as the category, the skill dropdown narrows to skills tagged with that category in the skill registry (e.g., qa_security_probe). When they select "custom," all skills become available. This progressive disclosure prevents overwhelming new users while allowing advanced users full flexibility.

Scheduling Diverse Workloads

The generality of the Universal Scheduler is its primary contribution. Table 3{reference-type="ref" reference="tab:scheduler-examples"} illustrates how disparate quality assurance activities---each of which might have warranted its own scheduling page in a less disciplined architecture---all converge on the same surface.

Task Category Skill Typical Cron


Full site crawl blueprint_crawl qa_blueprint_crawl 0 3 * * * (daily) Fallow code review blueprint_fallow qa_fallow_code_review 0 4 * * 0 (weekly) Architecture diff blueprint_drift qa_blueprint_drift 0 5 * * 0 (weekly) Security probe security_audit qa_security_probe 0 * * * * (hourly) Accessibility audit accessibility qa_accessibility_audit 0 2 * * 1 (Monday) Performance audit performance qa_performance_audit 0 6 * * * (daily) Stale ticket sweep ticket_sweep qa_ticket_stale_sweep 0 6 * * 1-5 (weekdays) Regression suite test_run qa_playwright_execute 0 4 * * * (daily)

: Example Scheduled Tasks Across QA Domains

From the user's perspective, the cognitive overhead of "how do I schedule X?" collapses to a single answer: open Scheduled Tasks, click New, select the category, configure the cron, and save. From the engineering perspective, supporting a new recurring workload requires only registering a new skill in the registry and assigning it a category---no new scheduler code, no new UI page, no new persistence layer.

Source Code Integration via nexus-github-manager

A web crawler sees what the user sees: rendered HTML, executed JavaScript, painted pixels. It cannot see what the developer intended, how the code is structured, or which components are responsible for which behaviors. Source code analysis closes this gap. But building a source code analysis service from scratch---OAuth flows, repository cloning, AST parsing, call-graph construction, embedding generation, code search---would be a significant engineering investment and an architectural sin: the nexus-github-manager service already provides all of this.

Living Blueprint's source code integration is therefore an exercise in reuse, not construction. Every capability described in this section invokes an existing nexus-github-manager API or embeds an existing dashboard component. No new Git operations, AST parsers, or OAuth flows are introduced.

Integration Points

 ┌──────────────────────────────────────────────────────┐
 │  Living Blueprint ←──→ nexus-github-manager          │
 ├──────────────────────────────────────────────────────┤
 │                                                      │
 │  ONBOARDING (Step 2):                                │
 │  ┌──────────────┐     ┌─────────────────────┐       │
 │  │ Repo Selector │────▶│ githubApi            │       │
 │  │ dropdown      │     │ .getConnectedRepos() │       │
 │  └──────────────┘     └─────────────────────┘       │
 │                                                      │
 │  DISCOVERY (Chain Step 2):                           │
 │  ┌──────────────┐     ┌─────────────────────┐       │
 │  │ Source        │────▶│ githubApi            │       │
 │  │ Analyze skill │     │ .cypherQuery()       │       │
 │  └──────────────┘     │ .getRepoStructure()  │       │
 │                        │ .getFileContent()    │       │
 │                        │ .getCallGraph()      │       │
 │                        │ .searchCode()        │       │
 │                        └─────────────────────┘       │
 │                                                      │
 │  ARCHITECTURE REVIEW CONSOLE:                        │
 │  ┌──────────────┐     ┌─────────────────────┐       │
 │  │ Element       │────▶│ <FileTree />         │       │
 │  │ drill-down    │     │ <CodeViewer />       │       │
 │  └──────────────┘     │ <CodeEntityPanel />  │       │
 │                        │ <RelationshipsPanel/>│       │
 │                        └─────────────────────┘       │
 │                                                      │
 │  FALLOW INTEGRATION:                                 │
 │  ┌──────────────┐     ┌─────────────────────┐       │
 │  │ Fallow scan   │────▶│ githubApi            │       │
 │  │ skill         │     │ .getWorkspacePath()  │       │
 │  └──────────────┘     └─────────────────────┘       │
 │                                                      │
 │  DRIFT DETECTION (L4):                               │
 │  ┌──────────────┐     ┌─────────────────────┐       │
 │  │ Source diff   │────▶│ githubApi            │       │
 │  │ layer         │     │ .getCommitDiff()     │       │
 │  └──────────────┘     │ .getFileHistory()    │       │
 │                        └─────────────────────┘       │
 └──────────────────────────────────────────────────────┘

API Methods Used

Table 4{reference-type="ref" reference="tab:github-api-methods"} lists every githubApi method that Living Blueprint invokes. All methods are pre-existing; none are added for this feature.

Method Usage in Living Blueprint


getConnectedRepos() Onboarding Step 2: populate repo selector getRepoStructure(id) Discovery: file tree for element merge getFileContent(id, path) Drill-down: show source in CodeViewer cypherQuery(query) Discovery: traverse code knowledge graph getCallGraph(id, fn) Element merge: trace component relationships searchCode(id, query) Discovery: locate component definitions getCommitDiff(id, a, b) Drift detection L4: source-level diff getFileHistory(id, path) Drift detection: change frequency analysis getWorkspacePath(id) Fallow scan: obtain cloned repo path triggerSync(id) Post-webhook: refresh code knowledge graph

: githubApi Methods Used by Living Blueprint

Reusable Frontend Components

The Architecture Review Console embeds four components from the nexus-github-manager frontend package. These components are already published as importable modules with well-defined props interfaces:

  • FileTree: Renders the repository's directory structure with expandable folders, file-type icons, and click-to-select behavior. Living Blueprint augments it with badge overlays showing drift status (green for stable, yellow for modified, red for broken).

  • CodeViewer: Syntax-highlighted source code display with line numbers, line-level annotations, and blame information. Living Blueprint injects Fallow finding markers as gutter annotations (Section 9{reference-type="ref" reference="sec:fallow"}).

  • CodeEntityPanel: Displays parsed entities for a selected file---exported functions, classes, types, constants---with their usage counts. Living Blueprint highlights entities that map to discovered blueprint elements.

  • RelationshipsPanel: Visualizes import/export relationships and call-graph edges for a selected entity. Living Blueprint uses this to show which blueprint elements depend on a given code entity, enabling impact analysis before code changes.

Classification Accuracy: DOM-Only vs. Dual-Path

The functional intent classifier in Step 5 of the discovery chain operates in two modes depending on whether a source repository is linked. Table 5{reference-type="ref" reference="tab:classification-accuracy"} reports classification accuracy across element types, measured on a held-out evaluation set of 2,400 elements from 8 production applications.

Element Type DOM-Only DOM + Source


Navigation link 91% 97% Form submission 84% 96% Data display (table/list) 78% 95% Authentication gate 62% 93% Modal / dialog trigger 69% 94% API endpoint (inferred) 58% 96% State mutation action 51% 91% Error boundary 43% 88% Weighted Average \sim<!-- -->{=html}72% \sim<!-- -->{=html}94%

: Functional Intent Classification Accuracy

The accuracy improvement is most pronounced for elements whose functional intent is opaque from the DOM alone. An authentication gate, for instance, may appear as a generic <div> wrapper with no distinguishing DOM attributes---but its source reveals an AuthGuard higher-order component wrapping a route. Similarly, a state mutation action (e.g., "delete account") may look identical to a navigation button in the DOM, but its source handler reveals a destructive API call.

We model the dual-path accuracy gain as:

A_{} = A_{} · (1 + \beta · I_{})

where A_{} is the DOM-only accuracy, I_{} ∈ [0, 1] is the source information availability (proportion of elements with matched source entities), and β\beta is the source information gain coefficient. Empirically, β0.42\beta \approx 0.42 across the evaluation set, indicating that source code information provides a \sim<!-- -->{=html}42% relative accuracy improvement per unit of source coverage. When I_{} = 0 (no repository linked), the formula reduces to A_{} = A_{}, confirming that the system degrades gracefully---though the paper's term "gracefully" is misleading; more precisely, it operates at reduced accuracy with a clear user-facing indicator that source integration would improve results.

Fallow Integration --- Code Quality as Drift Signal

Most drift detection systems focus on what the user sees: broken layouts, missing elements, changed navigation. This is necessary but insufficient. A codebase can drift catastrophically---accumulating dead code, duplicated logic, circular dependencies, and complexity hotspots---while every page continues to render correctly. These structural regressions are invisible to DOM crawlers and visual diff tools. They only manifest as symptoms later: slower builds, harder-to-diagnose bugs, increased time-to-fix, and eventual architectural collapse.

Fallow [@fallow2025], a Rust-based TypeScript/JavaScript analyzer, detects precisely these structural regressions. It ships as a CLI, a VS Code extension, an LSP server, a GitHub Actions integration (SARIF output), and---critically for our purposes---an MCP (Model Context Protocol) server that AI agents can invoke programmatically. Its performance characteristics are exceptional: it analyzes codebases of 3,000+ files in approximately 300 ms, which is 3--18×× faster than comparable tools like knip [@knip2024].

Fallow is already deployed in NexusQA as skill qa_fallow_code_review (registry ID 4cc84cbc-4f73-4c67-9d8a-997b9d7e7f49), registered in graphrag.skill_registry and graphrag.universal_entities. The code quality page is live at nexusqa.ai/dashboard/nexus-nexusqa/code-quality. Living Blueprint extends this existing deployment by treating Fallow findings as a first-class drift signal---the fifth layer in the drift detection hierarchy.

Five Detection Categories

Fallow's analysis covers five distinct categories of structural regression, each mapped to a new drift type in Living Blueprint's drift taxonomy:

  1. Dead Code. Unused files, exports, and dependencies. Fallow traces the import graph from entry points and flags any node with zero inbound edges. Maps to drift type dead_code_added. Severity weight: 0.5 (low individual impact, high cumulative impact).

  2. Code Duplication. Copy-pasted code blocks detected via a suffix-array algorithm that identifies structurally similar AST subtrees, not merely textual matches. A 32-line duplicated block between two files is qualitatively different from two files that happen to share a 3-line import preamble. Maps to drift type duplication_introduced. Severity weight: 1.0.

  3. Circular Dependencies. Import cycles between modules detected via Tarjan's strongly connected components algorithm on the module dependency graph. Even two-node cycles (A imports B imports A) can cause initialization order bugs, bundler issues, and testing isolation failures. Maps to drift type circular_dep_introduced. Severity weight: 2.0 (reflects the disproportionate debugging cost of dependency cycles).

  4. Complexity Hotspots. Functions and methods exceeding configurable thresholds for cyclomatic complexity (default: 15) and cognitive complexity (default: 20). These are not merely "bad code"---they are quantified maintenance risks. A function with cyclomatic complexity 25 has 25 linearly independent paths, each of which must be tested and reasoned about. Maps to drift type complexity_hotspot_added. Severity weight: 1.0.

  5. Architecture Boundary Violations. Fallow supports four architecture presets---bulletproof, layered, hexagonal, and feature-sliced---and enforces the import rules that each prescribes. A layered architecture where the presentation layer imports directly from the data access layer, bypassing the business logic layer, is a violation. Maps to drift type architecture_violation. Severity weight: 2.0 (reflects the structural erosion these violations cause over time).

Data Flow

 ┌─────────────────────────────────────────────────────┐
 │     FALLOW INTEGRATION — DATA FLOW                   │
 ├─────────────────────────────────────────────────────┤
 │                                                      │
 │  ┌────────┐  schedule   ┌──────────────┐            │
 │  │ User / │────────────▶│  Universal   │            │
 │  │ Cron   │  or manual  │  Scheduler   │            │
 │  └────────┘             └──────┬───────┘            │
 │                                │                     │
 │                    POST /api/v1/dispatch              │
 │                    job_type: qa_blueprint_fallow_scan │
 │                                │                     │
 │                                ▼                     │
 │                    ┌──────────────────┐              │
 │                    │ nexus-orchestrator│              │
 │                    │ → trigger.dev    │              │
 │                    └────────┬─────────┘              │
 │                             │                        │
 │                             ▼                        │
 │  ┌──────────────────────────────────────────┐       │
 │  │  qa_blueprint_fallow_scan (Tier 2)        │       │
 │  │                                           │       │
 │  │  1. githubApi.getWorkspacePath(repo_id)   │       │
 │  │     → obtain cloned repo path             │       │
 │  │                                           │       │
 │  │  2. mcp.call('fallow:analyze', {          │       │
 │  │       path: workspace,                    │       │
 │  │       checks: [dead_code, duplication,    │       │
 │  │         circular_deps, complexity,         │       │
 │  │         architecture],                    │       │
 │  │       thresholds: config,                 │       │
 │  │       architecturePreset: 'layered'       │       │
 │  │     })                                    │       │
 │  │     → SARIF output (300ms typical)        │       │
 │  │                                           │       │
 │  │  3. Parse SARIF → structured findings     │       │
 │  │                                           │       │
 │  │  4. SELECT previous scan from              │       │
 │  │     blueprint_fallow_reports               │       │
 │  │     → diff: NEW vs EXISTING vs RESOLVED   │       │
 │  │                                           │       │
 │  │  5. For each NEW finding:                  │       │
 │  │     → INSERT drift event                  │       │
 │  │     → Compute severity (Section 12)       │       │
 │  │     → If severity > threshold:            │       │
 │  │       auto-create QA ticket               │       │
 │  │                                           │       │
 │  │  6. Persist full report                    │       │
 │  │  7. Emit WS: fallow:scan_complete         │       │
 │  └──────────────────────────────────────────┘       │
 │                             │                        │
 │                             ▼                        │
 │           ┌─────────────────────────────┐            │
 │           │  blueprint_fallow_reports   │            │
 │           │  + GraphRAG entity update   │            │
 │           │  + WS notification to UI    │            │
 │           └─────────────────────────────┘            │
 └─────────────────────────────────────────────────────┘

The critical property of this flow is that every step occurs within a dispatched skill execution. The NexusQA backend never runs Fallow directly, never spawns a child process, and never accesses the repository filesystem. The skill, executing inside a trigger.dev worker, performs the Fallow invocation via MCP, processes the output, and delivers results through the standard callback mechanism.

Drift Type Mapping

Each Fallow finding category maps to a drift type with a severity weight used in the composite drift severity formula (defined in Section 12). Table 6{reference-type="ref" reference="tab:fallow-drift-mapping"} summarizes the mapping.

Fallow Category Drift Type Weight Auto-Ticket


Dead code dead_code_added 0.5 If >10> 10 files Duplication duplication_introduced 1.0 If >50> 50 lines Circular deps circular_dep_introduced 2.0 Always Complexity complexity_hotspot_added 1.0 If cyclo >25> 25 Arch violation architecture_violation 2.0 Always

: Fallow Finding Categories to Blueprint Drift Types

Circular dependencies and architecture violations carry the highest weight because they are the hardest to remediate retroactively and the most likely to cause cascading failures. Dead code, by contrast, is individually benign---a single unused export poses no runtime risk---but becomes a significant maintenance burden at scale, hence the threshold-based auto-ticketing.

Database Schema: blueprint_fallow_reports

SQL
37 lines
CREATE TABLE nexusqa.blueprint_fallow_reports (
  id                  UUID PRIMARY KEY
                        DEFAULT gen_random_uuid(),
  project_id          UUID NOT NULL
    REFERENCES nexusqa.blueprint_projects(id),
  organization_id     UUID NOT NULL,
  scan_session_id     UUID
    REFERENCES nexusqa.blueprint_crawl_sessions(id),
  repository_id       UUID NOT NULL,
  commit_sha          VARCHAR(40) NOT NULL,
  scan_started_at     TIMESTAMPTZ NOT NULL,
  scan_completed_at   TIMESTAMPTZ,
  total_findings      INTEGER DEFAULT 0,
  new_findings        INTEGER DEFAULT 0,
  resolved_findings   INTEGER DEFAULT 0,
  findings_by_type    JSONB DEFAULT '{}',
  -- e.g., {"dead_code":12,"duplication":8,
  --        "circular_deps":2,"complexity":18,
  --        "architecture":7}
  sarif_content       JSONB,
  fallow_version      VARCHAR(20),
  config_snapshot     JSONB,
  created_at          TIMESTAMPTZ DEFAULT now()
);

ALTER TABLE nexusqa.blueprint_fallow_reports
  ENABLE ROW LEVEL SECURITY;

CREATE POLICY fallow_reports_org_isolation
  ON nexusqa.blueprint_fallow_reports
  USING (organization_id =
         current_setting('app.current_org_id')::uuid);

CREATE INDEX idx_fallow_reports_project
  ON nexusqa.blueprint_fallow_reports(project_id);
CREATE INDEX idx_fallow_reports_commit
  ON nexusqa.blueprint_fallow_reports(commit_sha);

The sarif_content column stores the complete SARIF (Static Analysis Results Interchange Format) output from Fallow, enabling downstream consumers---CI/CD integrations, GitHub PR comments, the Architecture Review Console---to access the full finding detail without re-running the analysis. The config_snapshot preserves the exact thresholds and architecture preset used for the scan, ensuring that temporal comparisons between scans are valid even when configuration changes between them.

Architecture Review Console Integration

Fallow findings surface inline within the Architecture Review Console's element tree. When a user selects a file in the FileTree component, the CodeViewer renders the source with gutter annotations at the exact lines where Fallow identified issues. These annotations use the same color language as the rest of the drift detection UI: red for critical findings (circular dependencies, architecture violations), yellow for moderate findings (complexity hotspots, duplication), and gray for informational findings (dead code).

Each annotation is actionable:

  • View in CodeViewer: Jumps to the offending line with the full Fallow diagnostic message and suggested fix (when available).

  • Create Ticket: Generates a QA ticket pre-populated with the Fallow finding, the file path, the line range, the commit SHA where the finding was introduced, and a suggested priority based on the severity weight. This ticket enters the standard 7-stage remediation pipeline.

  • Suggest Fix: For dead code and duplication findings, dispatches the qa_remediation_plan skill with the Fallow finding as context, producing a concrete remediation plan (Stage 3 of the pipeline).

The integration is bidirectional. When a remediation PR resolves a Fallow finding (detected by the next scheduled scan showing resolved_findings > 0), the finding's status transitions from "active" to "resolved" in the Console, and the associated drift event is marked as remediated. This creates a closed feedback loop: detect structural regression \rightarrow create ticket \rightarrow generate remediation plan \rightarrow execute fix \rightarrow verify resolution \rightarrow confirm drift resolved.

The practical consequence is that code quality is no longer a separate concern from application quality. A new circular dependency introduced in a Tuesday commit appears in Wednesday's scheduled Fallow scan, generates a drift event, triggers a QA ticket, enters the remediation pipeline, and---if the Opus 4.6 Plan Review Gate approves the fix plan---is resolved via an automated PR before the end of the week. The developer who introduced the cycle may never even know it happened, which is precisely the point: the system absorbs the entropy that AI-generated code continuously introduces.

Living Blueprint Repository (GraphRAG)

The preceding sections described how elements are discovered---crawled from the live application, extracted from source code via nexus-github-manager, and assessed for code-quality defects by Fallow. This section addresses the complementary problem of persistence: how the living blueprint is stored, versioned, queried, and kept tenant-isolated in a knowledge graph that must serve both point-in-time reconstruction and real-time drift comparison.

Design Rationale

Relational tables alone cannot model the heterogeneous, densely connected topology of a web application's architecture. A page may contain dozens of UI components, each backed by one or more API endpoints, each resolved by service functions that depend on shared database tables. These cross-cutting relationships are first-class citizens in the blueprint---not join-table afterthoughts---because drift detection (Section 11{reference-type="ref" reference="sec:drift"}) must traverse them to compute blast radius. We therefore adopt a hybrid storage strategy: PostgreSQL for transactional CRUD and tenant-scoped RLS, Neo4j for graph traversals and relationship-rich queries, and Qdrant for embedding-based semantic similarity search. The three stores are unified behind the GraphRAG abstraction already deployed in the NexusQA platform [@robinson2015graph; @angles2018property].

Entity Schema

The living blueprint defines six entity types and seven typed relationship classes. The following diagram shows the full schema with cardinalities and the critical cross-link to nexus-github-manager:

 LIVING BLUEPRINT — ENTITY RELATIONSHIP SCHEMA
 ══════════════════════════════════════════════

 ┌───────────────────────┐         ┌───────────────────────┐
 │  blueprint_project    │         │  blueprint_element    │
 │ ─────────────────── │         │ ─────────────────── │
 │  id            UUID   │◀─┐     │  id            UUID   │
 │  name          TEXT   │  │     │  project_id    UUID   │──┐
 │  base_url      TEXT   │  │     │  element_type  ENUM   │  │
 │  platform      ENUM   │  │     │  canonical_url TEXT   │  │
 │  github_repo_id UUID  │──┼──┐  │  functional_intent    │  │
 │  org_id        UUID   │  │  │  │  source_component_id  │──┼──┐
 │  created_at    TSTZ   │  │  │  │  last_seen_at  TSTZ   │  │  │
 └───────────────────────┘  │  │  │  status        ENUM   │  │  │
                            │  │  └───────────────────────┘  │  │
              CONTAINS(1:N) │  │            │                │  │
              ──────────────┘  │   HAS_VERSION(1:N)          │  │
                               │            │                │  │
 ┌───────────────────────┐     │            ▼                │  │
 │  blueprint_element    │     │  ┌───────────────────────┐  │  │
 │  _version             │     │  │  (same element, ver-  │  │  │
 │ ─────────────────── │     │  │   sioned by crawl_id) │  │  │
 │  id            UUID   │     │  └───────────────────────┘  │  │
 │  element_id    UUID   │◀────┘                             │  │
 │  crawl_id      UUID   │     RELATES_TO(M:N)               │  │
 │  content_hash  SHA256 │     ──────────────                │  │
 │  dom_signature TEXT   │            │                      │  │
 │  snapshot      JSONB  │            ▼                      │  │
 │  valid_from    TSTZ   │  ┌───────────────────────┐        │  │
 │  valid_to      TSTZ   │  │  blueprint_element    │        │  │
 │  txn_from      TSTZ   │  │  _relationship        │        │  │
 │  txn_to        TSTZ   │  │ ─────────────────── │        │  │
 └───────────────────────┘  │  source_id     UUID   │◀───────┘  │
                            │  target_id     UUID   │           │
                            │  rel_type      ENUM   │   IMPLEMENTS
                            │  confidence    FLOAT  │   _BY (1:1)
                            │  crawl_id      UUID   │   ─────────
                            └───────────────────────┘        │
                                                             │
 ┌───────────────────────┐   ┌───────────────────────┐       │
 │  blueprint_drift     │   │  blueprint_fallow     │       │
 │  _event              │   │  _finding             │       ▼
 │ ─────────────────── │   │ ─────────────────── │  ┌──────────┐
 │  id            UUID   │   │  id            UUID   │  │ github   │
 │  element_id    UUID   │   │  project_id    UUID   │  │ _manager │
 │  drift_type    ENUM   │   │  report_id     UUID   │  │ .code    │
 │  severity      FLOAT  │   │  finding_type  ENUM   │  │ _entities│
 │  old_version   UUID   │   │  file_path     TEXT   │  │          │
 │  new_version   UUID   │   │  severity      ENUM   │  │ (AST,    │
 │  details       JSONB  │   │  details       JSONB  │  │  call    │
 │  fallow_id     UUID   │──▶│  first_seen_at TSTZ   │  │  graphs, │
 │  ticket_id     UUID   │   │  resolved_at   TSTZ   │  │  deps)   │
 └───────────────────────┘   └───────────────────────┘  └──────────┘

The seven relationship types, with their semantics:

  1. CONTAINS --- A project contains elements (1:N).

  2. HAS_VERSION --- An element has temporally ordered versions (1:N), one per crawl session.

  3. RELATES_TO --- Typed edges between elements: calls (page \to API), renders (page \to component), depends_on (component \to service), queries (service \to database table).

  4. IMPLEMENTS_BY --- Cross-system link from a blueprint element to a code_entity in nexus-github-manager's knowledge graph. This relationship is not stored in the NexusQA schema; it is a Neo4j edge that the Architecture Review Console traverses via githubApi.cypherQuery().

  5. DETECTED_BY --- A drift event detected by a specific crawl session.

  6. TRIGGERED_BY --- A Fallow finding that triggered a drift event of type code_quality_regression.

  7. RESOLVED_BY --- A drift event resolved by a remediation trail (linking to the existing qa_remediation_trail entity).

Bi-Temporal Version Tracking

Every element version carries two temporal dimensions, following the bi-temporal model formalized by Snodgrass [@snodgrass1999developing]:

 BI-TEMPORAL VERSION TRACKING
 ════════════════════════════

 VALID TIME (when the element actually existed in production)
 ──────────────────────────────────────────────────────────▶

 v1 ██████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    |-- valid_from --|-- valid_to (set when v2 discovered)

 v2 ░░░░░░░░░░░░░░░░░██████████████████████████████████████
                     |-- valid_from --------- valid_to=∞ --|

 TRANSACTION TIME (when we recorded the observation)
 ──────────────────────────────────────────────────────────▶

 v1 ░░░░██████████████████████████████████████████████████░
         |-- txn_from (crawl timestamp) -- txn_to=∞ ------|

 v2 ░░░░░░░░░░░░░░░░░░░░░████████████████████████████████░
                          |-- txn_from ---- txn_to=∞ -----|

 Point-in-time query: "What did the login page look like
 on April 3rd?" → WHERE valid_from <= '2026-04-03'
                    AND  valid_to   >  '2026-04-03'

 Audit query: "When did we first observe the breakage?"
              → WHERE txn_from <= NOW() ORDER BY txn_from

Valid time records the interval during which an element version existed in the live application. When a new version is discovered, the previous version's valid_to is set to the crawl timestamp. Transaction time records when the observation was persisted to the database. This two-axis model allows the system to answer both "what was the state at time tt?" (valid-time slice) and "when did we learn about this change?" (transaction-time slice)---capabilities essential for root-cause analysis in the seven-stage remediation pipeline.

Formally, given element ee and crawl session ckc_k at time tkt_k, the version ve,kv_{e,k} is valid over the interval [tk,tk+1)[t_k, t_{k+1}) where tk+1t_{k+1} is the timestamp of the next crawl that discovers a change, or fty∈fty if no change has yet been detected.

Version Diff Scoring

When comparing two versions viv_i and vjv_j of the same element, we compute a composite diff score that combines structural similarity with content divergence:

Δ(v_i, v_j) = \alpha · (1 - J_{}(v_i, v_j)) + \beta · (1 - J_{}(v_i, v_j)) + \gamma · [h(v_i) ≠ h(v_j)]

where J_{} is the Jaccard similarity over DOM element tag sets, J_{} is the Jaccard similarity over attribute key-value pairs, h()h(·) is the SHA-256 content hash, and α+β+γ=1\alpha + \beta + \gamma = 1 with defaults α=0.4\alpha = 0.4, β=0.3\beta = 0.3, γ=0.3\gamma = 0.3.

The Jaccard element similarity between two sets of DOM elements AA and BB is defined as:

J(A, B) = (/)

A diff score Δ>0.7Δ > 0.7 indicates a major structural change (e.g., a page rewrite); 0.3<Δ0.70.3 < Δ ≤ 0.7 indicates a significant modification; and Δ0.3Δ ≤ 0.3 indicates minor adjustments. These thresholds feed directly into the drift severity scoring formula defined in Section 11{reference-type="ref" reference="sec:drift"}.

Tenant Isolation

All GraphRAG queries are scoped by X-Company-ID and X-App-ID headers, enforced at three layers:

  1. PostgreSQL RLS: Every table carries an organization_id column with row-level security policies matching current_setting(’app.current_org_id’)::uuid.

  2. Neo4j namespace prefixing: Entity labels are prefixed with the organization's short code (e.g., org_abc_blueprint_element).

  3. Qdrant collection scoping: Embedding collections include the organization identifier, ensuring vector similarity search never crosses tenant boundaries.

This triple-layer isolation ensures that a multi-tenant deployment cannot leak blueprint data between organizations---a requirement inherited from NexusQA's existing security model and extended to the new entity types.

Drift Detection and Continuous Monitoring

Drift---the divergence between an application's observed state and its recorded blueprint---is the central concern of continuous quality assurance. Unlike traditional regression testing, which compares test outcomes against expected results, drift detection compares the application itself against its own historical model. This section presents a five-layer comparison pipeline, a taxonomy of fourteen drift types (including five derived from Fallow code-quality analysis), a formal severity scoring model, and the automated pipeline that converts detected drift into actionable QA tickets.

Five-Layer Comparison Pipeline

Each monitoring cycle applies five comparison layers in sequence, from cheapest to most expensive. Early layers serve as filters: if Layer 1 detects no change, deeper layers are skipped entirely, conserving computational resources.

 DRIFT DETECTION — 5-LAYER COMPARISON PIPELINE
 ══════════════════════════════════════════════

 ┌────────────────────────────────────────────────────────┐
 │  INPUT: element version v_new from current crawl       │
 │         element version v_old from previous crawl      │
 └──────────────────────┬─────────────────────────────────┘
                        │
                        ▼
 ┌──────────────────────────────────────────────────────┐
 │  L1: CONTENT HASH COMPARISON                         │
 │  ────────────────────────────                        │
 │  SHA-256(v_new.content) == SHA-256(v_old.content)?   │
 │                                                      │
 │  YES ──▶ SKIP remaining layers (no change)           │
 │  NO  ──▶ proceed to L2                               │
 │                                                      │
 │  Cost: O(1) hash lookup          Precision: exact    │
 └──────────────────────┬───────────────────────────────┘
                        │ hash mismatch
                        ▼
 ┌──────────────────────────────────────────────────────┐
 │  L2: DOM SIGNATURE COMPARISON                        │
 │  ────────────────────────────                        │
 │  Structural fingerprint: tag hierarchy, ARIA roles,  │
 │  form structure, navigation topology                 │
 │                                                      │
 │  Jaccard(dom_sig_new, dom_sig_old) > 0.95?           │
 │                                                      │
 │  YES ──▶ classify as MINOR modification              │
 │  NO  ──▶ classify as STRUCTURAL change, proceed L3   │
 │                                                      │
 │  Cost: O(n) tree comparison      Precision: fuzzy    │
 └──────────────────────┬───────────────────────────────┘
                        │ structural divergence
                        ▼
 ┌──────────────────────────────────────────────────────┐
 │  L3: VISUAL AI DIFF                                  │
 │  ──────────────────                                  │
 │  Screenshots compared via vision-capable LLM         │
 │  (dispatched as qa_visual_diff skill, Tier 2)        │
 │                                                      │
 │  Classifies: cosmetic | functional | breakage        │
 │                                                      │
 │  Cosmetic   ──▶ low-severity drift event             │
 │  Functional ──▶ medium-severity, proceed L4          │
 │  Breakage   ──▶ high-severity, proceed L4            │
 │                                                      │
 │  Cost: ~$0.01/comparison         Precision: semantic │
 └──────────────────────┬───────────────────────────────┘
                        │ functional or breakage
                        ▼
 ┌──────────────────────────────────────────────────────┐
 │  L4: SOURCE DIFF (via nexus-github-manager)          │
 │  ──────────────────────────────────────────          │
 │  Query: githubApi.cypherQuery({                      │
 │    query: "MATCH (e:code_entity)-[:MODIFIED_IN]->"   │
 │           "(c:commit) WHERE c.timestamp > $since"    │
 │           "RETURN e, c",                             │
 │    params: { since: last_crawl_timestamp }           │
 │  })                                                  │
 │                                                      │
 │  Correlates DOM drift with source code changes.      │
 │  If DOM changed but NO source changed:               │
 │    ──▶ UNEXPLAINED_SOURCE_DRIFT (highest severity)   │
 │  If source changed and DOM changed:                  │
 │    ──▶ expected drift (lower severity)               │
 │                                                      │
 │  Cost: graph query          Precision: causal        │
 └──────────────────────┬───────────────────────────────┘
                        │
                        ▼
 ┌──────────────────────────────────────────────────────┐
 │  L5: FALLOW DIFF                                     │
 │  ────────────────                                    │
 │  Compare current Fallow scan results against         │
 │  previous scan from blueprint_fallow_reports         │
 │                                                      │
 │  NEW findings    ──▶ code_quality_regression drift   │
 │  RESOLVED findings ──▶ code_quality_improvement      │
 │  UNCHANGED       ──▶ no additional drift event       │
 │                                                      │
 │  Maps finding types to drift taxonomy:               │
 │    dead_code      ──▶ dead_code_added                │
 │    duplication    ──▶ duplication_introduced          │
 │    circular_dep   ──▶ circular_dep_introduced         │
 │    complexity     ──▶ complexity_hotspot_added        │
 │    arch_boundary  ──▶ architecture_violation          │
 │                                                      │
 │  Cost: set diff on SARIF   Precision: static         │
 └──────────────────────────────────────────────────────┘

Drift Taxonomy

The system recognizes fourteen drift types, organized by origin:

+----------------+----------------------------+--------------------------------------------+ | Category | Drift Type | Description | +:===============+:===========================+:===========================================+ | Runtime | addition | New element discovered | | +----------------------------+--------------------------------------------+ | | removal | Previously cataloged element absent | | +----------------------------+--------------------------------------------+ | | modification | Content or attribute change | | +----------------------------+--------------------------------------------+ | | breakage | Element non-functional (4xx/5xx, JS error) | +----------------+----------------------------+--------------------------------------------+ | Behavioral | structure_change | DOM hierarchy reorganized | | +----------------------------+--------------------------------------------+ | | api_change | Endpoint contract modified | | +----------------------------+--------------------------------------------+ | | perf_degradation | Core Web Vital regression | | +----------------------------+--------------------------------------------+ | | a11y_regression | WCAG violation introduced | | +----------------------------+--------------------------------------------+ | | unexplained_source_drift | DOM changed without source commit | +----------------+----------------------------+--------------------------------------------+ | Fallow-derived | dead_code_added | New unused export/file | | +----------------------------+--------------------------------------------+ | | duplication_introduced | New copy-pasted block | | +----------------------------+--------------------------------------------+ | | circular_dep_introduced | New import cycle | | +----------------------------+--------------------------------------------+ | | complexity_hotspot_added | Function exceeds threshold | | +----------------------------+--------------------------------------------+ | | architecture_violation | Import crosses boundary | +----------------+----------------------------+--------------------------------------------+

: Drift taxonomy with fourteen types across three categories.

The Fallow-derived types are a contribution of the present work. Prior drift detection systems [@ernst2017measure; @garcia2021automatic] focus exclusively on runtime observables (DOM, visual, API); none incorporate static code-quality analysis as a temporal drift signal.

Severity Scoring

Each drift event receives a composite severity score computed as a weighted sum over its constituent drift types:

S = Σ_{d ∈ } w_d · [d ∈ E]

where  is the set of all fourteen drift types, EE is the set of types detected in this event, [·] is the indicator function, and the weights wdw_d are:

w_{} = w_{} &= 3.0 \nonumber \ w_{} = w_{} &= 2.0 \nonumber \ w_{} = w_{} &= 2.0 \nonumber \ w_{} = w_{} &= 1.0 \nonumber \ w_{} &= 1.0 \nonumber \ w_{} = w_{} = w_{} &= 0.5

The thresholds for automated action are:

(S) =  &  S > 5 \  &  2 < S ≤ 5 \  &  0 < S ≤ 2 \  &  S = 0

Drift Intensity Score

Beyond per-event severity, we compute a project-level drift intensity score that captures the aggregate rate of architectural change over a sliding window:

I(t, w) = (/) Σ_{e ∈ E_t} Σ_{k=t-w}^{t} S_{e,k} · λ^{t-k}

where EtE_t is the set of active elements at time tt, ww is the window width (default 30 days), Se,kS_{e,k} is the severity score for element ee at crawl kk, and λ(0,1)λ ∈ (0,1) is an exponential decay factor (default λ=0.95λ = 0.95) that downweights older events. A rising drift intensity signals accelerating architectural instability---a leading indicator that warrants human intervention before the remediation pipeline is overwhelmed.

Staleness Decay

Elements that have not been re-crawled become progressively less trustworthy. The staleness decay function quantifies this degradation of confidence:

(e, t) = e^{-\kappa · (t - t_{}(e))}

where κ\kappa is a decay constant (default κ=0.1\kappa = 0.1 per day) and t_{}(e) is the timestamp of the most recent crawl that observed element ee. Elements with  < 0.3 are flagged as "stale" in the Architecture Review Console (Section 12{reference-type="ref" reference="sec:console"}) and displayed in gray rather than green.

Expected Calibration Error for Severity Predictions

The severity scoring formula produces deterministic outputs, but the classification of drift events into action tiers involves a probabilistic assessment by the LLM at Layer 3. We measure calibration quality using Expected Calibration Error (ECE) [@naeini2015obtaining]:

 = Σ_{m=1}^{M} (/) | (B_m) - (B_m) |

where NN is the total number of drift events classified by the LLM, BmB_m is the set of events in confidence bin mm (using M=10M = 10 equal-width bins), and (B_m) and (B_m) are the accuracy and mean confidence within each bin. An ECE of 0 indicates perfect calibration; values above 0.15 trigger a recalibration cycle in which the LLM's classification prompt is updated with recent misclassification examples as few-shot exemplars.

Drift-to-Ticket Pipeline

When a drift event exceeds the HIGH threshold (S>2S > 2), the system automatically creates a QA ticket that enters the seven-stage remediation pipeline (Section 4 of the NexusQA platform design [@nexusqa2026]):

  1. Drift event persisted to blueprint_drift_events with full version diff, layer results, and severity score.

  2. QA ticket created via TicketService.create() with the drift event linked as the originating signal, category architecture_drift, and priority derived from severity tier.

  3. Triage dispatched as qa_bug_triage (Tier 1 skill) with the drift context embedded in the prompt, including the bi-temporal version comparison and any correlated source commits.

  4. Remediation pipeline entered if severity is CRITICAL (S>5S > 5): the ticket proceeds directly to Stage 2 (AI Triage) without waiting for manual review.

For Fallow-derived drift types, the ticket additionally includes the SARIF finding details, the offending file path and line numbers, and a link to the nexus-github-manager Code Explorer at the exact location---enabling one-click navigation from drift notification to source code.

Architecture Review Console

The Architecture Review Console is the primary UX surface through which engineers interact with the living blueprint. It synthesizes data from five sources---the element catalog, drift event history, GitHub-manager's code knowledge graph, API health monitoring, and Fallow code-quality reports---into a unified interface with five viewing modes, linked bidirectionally so that selecting an element in any mode highlights it in all others.

The console's design philosophy departs from conventional dashboard approaches. Rather than presenting isolated metric panels, it implements an issue-spotting workflow: color-coded status indicators draw the engineer's eye to problems, drill-down actions provide root-cause context, and one-click ticket creation connects detection to remediation. Every view is keyboard-navigable, supporting the rapid triage workflow described in Section 12.5{reference-type="ref" reference="sec:ux-flow"}.

Architecture Overview Mode

The default view presents the application's architecture as a hierarchical tree with color-coded health status:

 ┌─ Architecture Overview ─────────────────── my-app ─────┐
 │                                                         │
 │  ■ GREEN = healthy   ■ RED = broken/drifted             │
 │  ■ YELLOW = warning  ■ GRAY = stale (not seen >7d)     │
 │                                                         │
 │  ▼ my-app (project)                          [SCAN]     │
 │  ├─▼ Pages (14)                                         │
 │  │  ├── ■ /                          GREEN   last: 2h   │
 │  │  ├── ■ /login                     GREEN   last: 2h   │
 │  │  ├── ■ /dashboard                 RED     last: 2h   │
 │  │  │   └─ drift: api_change (S=2.5)                    │
 │  │  ├── ■ /dashboard/settings        YELLOW  last: 2h   │
 │  │  │   └─ drift: complexity_hotspot (S=1.0)            │
 │  │  ├── ■ /users                     GREEN   last: 2h   │
 │  │  ├── ■ /users/[id]               GREEN   last: 2h   │
 │  │  ├── ■ /reports                   GRAY    last: 12d  │
 │  │  └── ... (7 more)                                    │
 │  ├─▼ API Endpoints (23)                                 │
 │  │  ├── ■ GET  /api/users            GREEN   200  45ms  │
 │  │  ├── ■ POST /api/users            GREEN   201  89ms  │
 │  │  ├── ■ GET  /api/settings         RED     500  --    │
 │  │  │   └─ drift: breakage (S=3.0)                      │
 │  │  └── ... (20 more)                                   │
 │  ├─▼ Components (31)                                    │
 │  │  ├── ■ Header.tsx                 GREEN              │
 │  │  ├── ■ SettingsForm.tsx           YELLOW             │
 │  │  │   └─ Fallow: cyclomatic=18 (threshold 15)        │
 │  │  └── ... (29 more)                                   │
 │  └─▼ Services (8)                                       │
 │     ├── ■ AuthService                RED                │
 │     │   └─ Fallow: circular dep with UserService        │
 │     └── ... (7 more)                                    │
 │                                                         │
 │─────────────────────────────────────────────────────────│
 │  DETAIL PANE (selected: /dashboard)                     │
 │  ─────────────────────────────────                      │
 │  Status: RED — api_change detected                      │
 │  Last crawl: 2026-04-13 03:00 UTC (crawl #47)          │
 │  Drift score: 2.5 (HIGH)                                │
 │  Source commits: abc1234, def5678 (2 commits since      │
 │    last clean crawl)                                    │
 │  Related elements: GET /api/settings (also RED)         │
 │  Fallow findings: 0 on this element                     │
 │                                                         │
 │  [View Diff] [View Source] [Create Ticket] [Dismiss]    │
 │                                                         │
 │  Keyboard: j/k navigate ─ Enter drill ─ t ticket       │
 │            o overview ─ c timeline ─ r relationships     │
 └─────────────────────────────────────────────────────────┘

Color encoding rules: GREEN indicates no drift events in the last two crawl cycles and freshness >0.7> 0.7. RED indicates an active drift event with severity S>2S > 2. YELLOW indicates a drift event with 0<S20 < S ≤ 2 or a Fallow finding above threshold. GRAY indicates  < 0.3 (element not observed in >7> 7 days at default κ\kappa).

Change Timeline Mode

The timeline view displays per-component drift history across crawl sessions, enabling engineers to identify patterns of recurring instability:

 ┌─ Change Timeline ──────────────────────────────────────┐
 │                                                         │
 │  Element: /dashboard/settings                           │
 │  Period: Last 30 days  [7d] [30d] [90d] [All]           │
 │                                                         │
 │  Crawl Session   Date        Drift Type       Severity  │
 │  ───────────── ────────── ──────────────── ────────── │
 │  #47            Apr 13      complexity_      1.0        │
 │                              hotspot_added              │
 │  #46            Apr 12      (no drift)       0.0        │
 │  #45            Apr 11      modification     0.3        │
 │  #44            Apr 10      (no drift)       0.0        │
 │  #43            Apr 09      api_change       2.5        │
 │  #42            Apr 08      (no drift)       0.0        │
 │  #41            Apr 07      breakage         3.0        │
 │  #40            Apr 06      (resolved)       0.0        │
 │                                                         │
 │  Severity Timeline:                                     │
 │                                                         │
 │  3.0 │         ■                                        │
 │      │         │                                        │
 │  2.5 │              ■                                   │
 │      │              │                                   │
 │  2.0 │              │                                   │
 │      │              │                                   │
 │  1.5 │              │                                   │
 │      │              │                        ■          │
 │  1.0 │              │                        │          │
 │      │    ■    │    │    ■              ■    │          │
 │  0.5 │    │    │    │    │              │    │          │
 │      │    │    │    │    │    ·    ·    │    │          │
 │  0.0 ├────┴────┴────┴────┴────┴────┴────┴────┴────▶    │
 │       #40  #41  #42  #43  #44  #45  #46  #47            │
 │                                                         │
 │  Pattern: 3 drift events in 7 days — UNSTABLE           │
 │  Recommendation: investigate root cause before patching │
 │                                                         │
 │  Keyboard: h/l prev/next session ─ d diff ─ s source   │
 └─────────────────────────────────────────────────────────┘

The pattern detection heuristic flags elements with more than two drift events within seven days as "unstable," surfacing them prominently in the Architecture Overview. This heuristic implements the P2 criterion from NexusQA's Opus 4.6 Plan Review Gate: if a component has been patched more than twice in thirty days, the system recommends architectural analysis rather than another incremental fix [@nexusqa2026].

Component Relationship View

This mode embeds nexus-github-manager's existing RelationshipsPanel component to visualize how blueprint elements connect to source code entities:

 ┌─ Component Relationships ──────────────────────────────┐
 │                                                         │
 │  Element: SettingsForm.tsx                               │
 │                                                         │
 │  ┌─────────────────────────────────────────────────┐   │
 │  │  EMBEDDED: github-manager RelationshipsPanel     │   │
 │  │  ─────────────────────────────────────────────── │   │
 │  │                                                   │   │
 │  │         ┌──────────┐                              │   │
 │  │         │ Settings │                              │   │
 │  │         │ Form.tsx │                              │   │
 │  │         └────┬─────┘                              │   │
 │  │      ┌───────┼───────┐                            │   │
 │  │      ▼       ▼       ▼                            │   │
 │  │  ┌───────┐ ┌─────┐ ┌──────────┐                  │   │
 │  │  │useAuth│ │Input│ │PUT /api/ │                  │   │
 │  │  │Hook   │ │.tsx │ │settings  │                  │   │
 │  │  └───┬───┘ └─────┘ └────┬─────┘                  │   │
 │  │      │                   │                        │   │
 │  │      ▼                   ▼                        │   │
 │  │  ┌───────┐         ┌──────────┐                   │   │
 │  │  │Auth   │         │Settings  │                   │   │
 │  │  │Service│◀────────│Service   │                   │   │
 │  │  │  ■ RED│  circ.  │          │                   │   │
 │  │  └───────┘  dep!   └──────────┘                   │   │
 │  │                                                   │   │
 │  │  Legend: ──▶ imports  ◀──▶ circular dep            │   │
 │  │          ■ drift status color                      │   │
 │  └─────────────────────────────────────────────────┘   │
 │                                                         │
 │  Blueprint Overlay:                                     │
 │  ■ RED  AuthService — circular_dep_introduced (Fallow)  │
 │  ■ YELLOW SettingsForm — complexity_hotspot (Fallow)    │
 │  ■ GREEN Input.tsx, useAuthHook — no issues             │
 │                                                         │
 │  [Open in Code Explorer] [View Call Graph] [View AST]   │
 │                                                         │
 │  Keyboard: g open code explorer ─ a view AST            │
 └─────────────────────────────────────────────────────────┘

The relationship view overlays blueprint drift status onto nexus-github-manager's pre-existing call graph visualization. This is accomplished via the githubApi.cypherQuery() interface: the console queries the IMPLEMENTS_BY edges to retrieve the source code entities corresponding to each blueprint element, then passes their health status as a color-coding parameter to the embedded RelationshipsPanel. No code is duplicated from the GitHub manager service; the panel is rendered as-is with an overlay data prop.

API Health Map

The API Health Map presents a tabular view of all discovered API endpoints with their current status and response time trends:

 ┌─ API Health Map ───────────────────────────────────────┐
 │                                                         │
 │  Filter: [All ▼] [Healthy ▼] [GET/POST/PUT/DEL ▼]      │
 │                                                         │
 │  Endpoint              Status  p50   p95   Trend        │
 │  ──────────────────── ────── ───── ───── ─────────── │
 │  GET  /api/users        200    45ms  89ms  ──────       │
 │  POST /api/users        201    89ms 145ms  ──────       │
 │  GET  /api/settings     500    --    --    ■■■■■■ ERR   │
 │  PUT  /api/settings     200   120ms 340ms  ───/── SLOW  │
 │  GET  /api/reports      200    34ms  67ms  ──────       │
 │  POST /api/auth/login   200    56ms 112ms  ──────       │
 │  GET  /api/health       200     8ms  12ms  ──────       │
 │                                                         │
 │  Response Time Trend (GET /api/settings — last 14d):    │
 │                                                         │
 │  500ms │                                                │
 │        │                                    ■            │
 │  400ms │                               ■   │            │
 │        │                          ■    │   │            │
 │  300ms │                     ■    │    │   │            │
 │        │                ■    │    │    │   │            │
 │  200ms │           ■    │    │    │    │   │            │
 │        │      ■    │    │    │    │    │   │    ERR     │
 │  100ms │ ■    │    │    │    │    │    │   │    |||     │
 │        │ │    │    │    │    │    │    │   │    |||     │
 │    0ms ├─┴────┴────┴────┴────┴────┴────┴───┴────┴──▶   │
 │         4/1  4/3  4/5  4/7  4/9  4/11 4/12 4/13        │
 │                                                         │
 │  Analysis: PUT /api/settings p95 increasing 22%/week    │
 │  Alert: GET /api/settings returning 500 since crawl #47 │
 │                                                         │
 │  Keyboard: f filter ─ Enter drill into endpoint         │
 └─────────────────────────────────────────────────────────┘

The health map correlates API status with blueprint drift events: an endpoint returning 500 is displayed as RED in the Architecture Overview tree, and its drift event includes the HTTP status code, response body excerpt, and any correlated source commits from Layer 4.

Issue Spotting UX Flow

The five viewing modes are connected by a structured issue-spotting workflow with five phases, each accessible via keyboard shortcut:

 ISSUE SPOTTING UX FLOW
 ══════════════════════

 ┌────────┐   ┌────────┐   ┌─────────┐   ┌───────┐   ┌─────────┐
 │  SCAN  │──▶│  SPOT  │──▶│  DRILL  │──▶│  ACT  │──▶│  TRACK  │
 │        │   │        │   │         │   │       │   │         │
 │ Ctrl+1 │   │ Ctrl+2 │   │ Ctrl+3  │   │Ctrl+4 │   │ Ctrl+5  │
 │        │   │        │   │         │   │       │   │         │
 │Overview│   │ Filter │   │ Version │   │Create │   │ Ticket  │
 │ tree   │   │ RED/   │   │ diff,   │   │ticket,│   │ board,  │
 │ with   │   │ YELLOW │   │ source, │   │assign,│   │ remedia-│
 │ colors │   │ items  │   │ Fallow, │   │sever- │   │ tion    │
 │        │   │ only   │   │ timeline│   │ity    │   │ status  │
 └────────┘   └────────┘   └─────────┘   └───────┘   └─────────┘
     │             │             │             │             │
     │             │             │             │             │
     ▼             ▼             ▼             ▼             ▼
  "What does    "Where are   "What exactly  "Route to   "Is it
   the app      the issues?"  changed and   remediation  fixed?"
   look like?"               why?"          pipeline"
  1. SCAN (Ctrl+1): Open the Architecture Overview. Color codes provide an instant gestalt of project health. Green dominance signals stability; red clusters signal active incidents.

  2. SPOT (Ctrl+2): Filter the tree to show only RED and YELLOW elements. The list is sorted by severity score descending, placing the most critical issues at the top.

  3. DRILL (Ctrl+3): Select an element and open its detail pane. View the version diff (bi-temporal comparison), source commits (via nexus-github-manager), Fallow findings (if applicable), and the timeline of past drift events.

  4. ACT (Ctrl+4): Create a QA ticket directly from the drill-down view. The ticket is pre-populated with the drift event details, severity score, affected elements, and correlated source commits. Pressing t is a shortcut.

  5. TRACK (Ctrl+5): Navigate to the QA ticket board (existing Kanban view) filtered to architecture drift tickets. Monitor remediation progress through the seven-stage pipeline.

This five-phase workflow reduces the cognitive overhead of architectural review from "open multiple dashboards and mentally correlate data" to "scan, spot, drill, act, track"---each phase one keypress away from the next.

Fallow Findings Panel

Within any viewing mode, selecting an element with Fallow findings opens an inline panel displaying the detailed code-quality analysis:

 ┌─ Fallow Findings — my-app (scan #47) ─────────────────┐
 │                                                         │
 │  Summary: 47 findings (3 NEW, 2 RESOLVED since #46)    │
 │                                                         │
 │  Dead Code:              12  (+1 new)                   │
 │  Duplication:             8  (+0)                       │
 │  Circular Dependencies:   2  (+1 new)  ■ CRITICAL      │
 │  Complexity Hotspots:    18  (+1 new)                   │
 │  Architecture Violations: 7  (+0)                       │
 │                                                         │
 │  ─── NEW FINDINGS (3) ──────────────────────────────── │
 │                                                         │
 │  ■ CIRCULAR DEP (critical — severity weight 2.0)        │
 │    src/services/auth.ts <-> src/services/user.ts        │
 │    Cycle: auth imports user imports auth                 │
 │    Introduced: commit abc1234 (3h ago)                   │
 │    [View in Code Explorer] [Create Ticket]              │
 │                                                         │
 │  ■ DEAD CODE (medium — severity weight 0.5)             │
 │    src/utils/legacy-helpers.ts                           │
 │    Exported function 'oldFormatDate': zero usages        │
 │    Introduced: commit def5678 (1d ago)                   │
 │    [View] [Create Ticket] [Safe to Delete?]             │
 │                                                         │
 │  ■ COMPLEXITY HOTSPOT (medium — severity weight 1.0)    │
 │    src/pages/Settings.tsx:handleSubmit                   │
 │    Cyclomatic: 18 (threshold: 15)                       │
 │    Cognitive:  24 (threshold: 20)                        │
 │    Introduced: commit ghi9012 (5h ago)                   │
 │    [View] [Create Ticket] [Refactor Suggestions]        │
 │                                                         │
 │  ─── RESOLVED (2) ─────────────────────────────────── │
 │  + Duplication: UserForm <-> AdminForm (commit jkl3456) │
 │  + Dead code: helpers.ts:unused (commit mno7890)        │
 │                                                         │
 │  [Download SARIF] [Full Report] [Configure Thresholds]  │
 │                                                         │
 │  Keyboard: n/p next/prev finding ─ v view code          │
 └─────────────────────────────────────────────────────────┘

Each finding links bidirectionally: clicking "View in Code Explorer" opens the nexus-github-manager CodeViewer component at the exact file and line; clicking "Create Ticket" generates a QA ticket with the Fallow finding embedded as the originating signal, which then enters the seven-stage remediation pipeline. The "Safe to Delete?" action dispatches a qa_self_heal skill (Tier 2) that performs impact analysis by querying the code knowledge graph for any dynamic references that Fallow's static analysis might have missed.

Cross-View Linking

All five modes maintain synchronized selection state: selecting an element in the Architecture Overview highlights the same element in the Timeline, Relationship, API Health, and Fallow panels. This is implemented via a shared Zustand store (blueprint-store.ts) that holds the currently selected element ID and broadcasts selection changes to all mounted components. The linking ensures that engineers never lose context when switching between views during a triage session.

Drift Tension Curves

The concept of "narrative tension" in storytelling---the rising and falling arc of conflict that sustains audience engagement---has an unexpectedly precise analog in software architecture. ProseCreator, a sister plugin in the Nexus ecosystem, computes tension curves for novel chapters: each beat receives a tension score based on conflict intensity, stakes, and pacing, and the resulting curve is visualized as a line chart that authors use to identify flat stretches in their narrative [@prosecreator2026].

Living Blueprint adapts this metaphor to element health. Each page, component, or API endpoint in the blueprint has a stability score that fluctuates over crawl sessions. When plotted over time, these scores form tension curves that reveal the "narrative" of a component's lifecycle: periods of stability (low tension), bursts of drift activity (rising tension), remediation efforts (falling tension), and---most critically---recurring instability patterns that indicate systemic issues rather than isolated bugs.

Tension Score Calculation

The tension score Te(t)T_e(t) for element ee at crawl session tt is defined as the complement of the stability score:

T_e(t) = 1 - _e(t)

where the stability score is a weighted moving average of recent drift severity:

_e(t) = 1 - ( Σ_{k=t-w}^{t} S_{e,k} · λ^{t-k} }{ S_{\max} · Σ_{k=t-w}^{t} λ^{t-k} }

Here Se,kS_{e,k} is the severity score for element ee at crawl kk, SmaxS_{\max} is the maximum possible severity (the sum of all weights, currently Smax=19.5S_{\max} = 19.5), ww is the lookback window (default 14 sessions), and λ=0.95λ = 0.95 is the exponential decay factor from Equation [eq:drift-intensity]{reference-type="ref" reference="eq:drift-intensity"}.

Visualization

 DRIFT TENSION CURVES — /dashboard (last 14 crawl sessions)
 ═══════════════════════════════════════════════════════════

 Tension
 1.0 │
     │
 0.8 │              ■
     │              │
 0.6 │         ■    │                        ■
     │         │    │                        │
 0.4 │    ■    │    │                   ■    │
     │    │    │    │              ■    │    │
 0.2 │    │    │    │    ■    ■    │    │    │    ■
     │ ■  │    │    │    │    │    │    │    │    │
 0.0 ├─┴──┴────┴────┴────┴────┴────┴────┴────┴────┴──▶
      #38 #39  #40  #41  #42  #43  #44  #45  #46  #47
                                                 Session

 ── /dashboard          Unstable: 4 spikes in 10 sessions
 -- /login              Stable: flat at 0.0 for 14 sessions
 .. /users              Stable: one minor bump at #43

The tension curve for /dashboard reveals a recurring pattern: drift events at sessions #39, #40, #41, and #46, with brief periods of stability between remediation efforts. This oscillating pattern is a strong indicator that incremental fixes are addressing symptoms rather than root causes---precisely the condition that the P2 criterion in the Opus 4.6 Plan Review Gate is designed to detect.

Engineers use tension curves to make informed resource allocation decisions: components with flat, low-tension curves require minimal attention, while components with rising or oscillating curves warrant architectural investigation. The curves are displayed in the Architecture Review Console's Timeline mode (Section 12.2{reference-type="ref" reference="sec:timeline-mode"}) and can be filtered to show only elements exceeding a configurable tension threshold.

Multi-Platform Support

While the preceding sections focus on web applications, digital products increasingly span multiple platforms---responsive web, native iOS, native Android, and hybrid frameworks (React Native, Flutter). A living blueprint that catalogs only one platform provides an incomplete architectural model and cannot detect cross-platform drift (e.g., a feature available on web but missing from mobile, or an API contract honored by the iOS client but violated by the Android client).

Cross-Platform Element Normalization

Each platform exposes its UI hierarchy through a different mechanism. The discovery engine normalizes these heterogeneous representations into a unified element model:

 CROSS-PLATFORM ELEMENT NORMALIZATION
 ═════════════════════════════════════

 ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐
 │  WEB (Playwright) │  │ iOS (XCUITest)   │  │ Android (UIAuto) │
 │ ──────────────── │  │ ──────────────── │  │ ──────────────── │
 │                    │  │                    │  │                    │
 │  <div>             │  │  UIView            │  │  android.view      │
 │    <form>          │  │    UITextField     │  │  .ViewGroup        │
 │      <input        │  │    UIButton        │  │    EditText        │
 │       type="email" │  │      "Submit"      │  │    Button          │
 │       id="email">  │  │                    │  │      "Submit"      │
 │      <button>      │  │  Accessibility:    │  │                    │
 │        Submit       │  │    label: "Submit" │  │  content-desc:     │
 │      </button>     │  │    trait: .button   │  │    "Submit"        │
 │    </form>         │  │    identifier:     │  │  resource-id:      │
 │  </div>            │  │      "submitBtn"   │  │    "submitBtn"     │
 └────────┬───────────┘  └────────┬───────────┘  └────────┬───────────┘
          │                       │                        │
          ▼                       ▼                        ▼
 ┌────────────────────────────────────────────────────────────────────┐
 │                  NORMALIZATION LAYER                                │
 │  ──────────────────────────────────                               │
 │  For each raw element, extract:                                    │
 │   • semantic_role  (form, input, button, nav, list, ...)          │
 │   • label          (text content, aria-label, a11y label)         │
 │   • identifier     (id, testID, resource-id, accessibility-id)   │
 │   • element_type   (page, component, form_field, action, ...)    │
 │   • interactions   (tap, type, scroll, swipe, long-press, ...)   │
 │   • platform       (web, ios, android)                             │
 │   • raw_snapshot   (platform-specific full representation)        │
 └──────────────────────────────┬─────────────────────────────────────┘
                                │
                                ▼
 ┌────────────────────────────────────────────────────────────────────┐
 │              UNIFIED BLUEPRINT ELEMENT                              │
 │  ──────────────────────────────────                                │
 │  {                                                                  │
 │    "id": "uuid",                                                   │
 │    "canonical_url": "/login",                                      │
 │    "element_type": "form_field",                                   │
 │    "semantic_role": "input",                                       │
 │    "label": "Email",                                                │
 │    "platform_variants": {                                           │
 │      "web":     { "selector": "#email",    "tag": "input" },      │
 │      "ios":     { "identifier": "emailTF", "class": "UITextField"},│
 │      "android": { "resource_id": "emailET","class": "EditText" }  │
 │    },                                                               │
 │    "functional_intent": "User email input for authentication",     │
 │    "source_component_id": "uuid (from github-manager)"            │
 │  }                                                                  │
 └────────────────────────────────────────────────────────────────────┘

The normalization layer maps platform-specific UI trees into a common vocabulary of semantic roles, following the WAI-ARIA role taxonomy [@w3c2017waiaria] extended with mobile-specific interaction types. Elements are matched across platforms by a composite key of canonical_url (the logical screen path) and label (the human-visible text), with identifier as a disambiguation tiebreaker when labels are ambiguous.

Platform Capability Matrix

Not all discovery and analysis capabilities are equally available across platforms:

Capability Web iOS Android


DOM/View hierarchy extraction
Screenshot capture
Network interception (API discovery) ^* ^* Content hash comparison
DOM signature matching Partial^\dagger Partial^\dagger Visual AI diff
Source diff (via github-manager)
Fallow code quality analysis ^\ddagger ^\ddagger Performance profiling Partial Partial Accessibility auditing
Session recording (rrweb) --- ---

: Platform capability matrix for the discovery engine.

^* Requires proxy configuration or framework instrumentation.
^\dagger View hierarchy signature, not DOM signature; structural comparison semantics differ.
^\ddagger Fallow analyzes TypeScript/JavaScript source; applicable to React Native and hybrid apps, not native Swift/Kotlin.

Source Code Enhancement for Mobile

The integration with nexus-github-manager is particularly valuable for mobile applications, where runtime observability is limited compared to web. By querying the code knowledge graph, the discovery engine can:

  1. Identify navigation flows from source code rather than runtime observation, compensating for the difficulty of programmatically navigating native app screens.

  2. Discover API contracts from client-side networking code (e.g., Retrofit interfaces, URLSession configurations), even when network interception is unavailable.

  3. Map UI components to source files via build-system metadata (Xcode project files, Gradle dependencies), establishing IMPLEMENTS_BY relationships without requiring runtime correlation.

  4. Detect platform parity gaps by comparing the set of screens and API calls discovered on web versus those found in mobile source code, flagging features present on one platform but absent from another.

These source-code-derived insights supplement the runtime discovery pipeline, producing a more complete blueprint for mobile applications than any purely dynamic approach could achieve [@choudhary2015automated; @moran2018machine].

Database Schema Design

The living blueprint requires eleven new tables in the nexusqa PostgreSQL schema, adding to the fifteen tables defined in the base NexusQA platform. This section presents the full DDL, partitioning strategy, indexing approach, and row-level security policies.

Design Principles

Four principles govern the schema design:

  1. Tenant isolation via RLS: Every table carries an organization_id column with enforced row-level security.

  2. Hash partitioning for scale: High-volume tables are partitioned by project_id into 16 partitions, distributing I/O across storage and enabling partition pruning on the most common query pattern.

  3. Foreign keys to existing systems: Blueprint projects reference github_manager.connected_repositories(id); drift events reference nexusqa.qa_tickets(id); scheduled tasks are generic and platform-wide.

  4. JSONB for flexible metadata: Crawl configuration, element snapshots, and Fallow SARIF output are stored as JSONB, indexed with GIN operators for efficient containment queries.

Table Definitions

Plain Text
335 lines
-- Migration 019: Living Blueprint tables
-- All tables in nexusqa schema with RLS

-- 1. Blueprint Projects
CREATE TABLE nexusqa.blueprint_projects (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id   UUID NOT NULL,
  name              VARCHAR(500) NOT NULL,
  base_url          TEXT NOT NULL,
  platform          VARCHAR(20) NOT NULL DEFAULT 'web'
    CHECK (platform IN ('web','ios','android','hybrid')),
  github_repository_id UUID,  -- FK to github_manager
  crawl_config      JSONB NOT NULL DEFAULT '{}',
  status            VARCHAR(20) NOT NULL DEFAULT 'active'
    CHECK (status IN ('active','paused','archived')),
  element_count     INTEGER NOT NULL DEFAULT 0,
  last_crawl_at     TIMESTAMPTZ,
  created_by        UUID NOT NULL,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_projects_org
  ON nexusqa.blueprint_projects(organization_id);

-- 2. Crawl Sessions
CREATE TABLE nexusqa.blueprint_crawl_sessions (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  project_id        UUID NOT NULL REFERENCES
                      nexusqa.blueprint_projects(id) ON DELETE CASCADE,
  organization_id   UUID NOT NULL,
  orchestrator_job_id UUID,
  trigger_schedule_id TEXT,  -- from trigger.dev
  status            VARCHAR(20) NOT NULL DEFAULT 'pending'
    CHECK (status IN ('pending','running','completed',
                      'failed','cancelled','paused')),
  crawl_type        VARCHAR(20) NOT NULL DEFAULT 'full'
    CHECK (crawl_type IN ('full','incremental','targeted')),
  urls_total        INTEGER NOT NULL DEFAULT 0,
  urls_crawled      INTEGER NOT NULL DEFAULT 0,
  urls_failed       INTEGER NOT NULL DEFAULT 0,
  elements_found    INTEGER NOT NULL DEFAULT 0,
  elements_new      INTEGER NOT NULL DEFAULT 0,
  elements_changed  INTEGER NOT NULL DEFAULT 0,
  drift_events      INTEGER NOT NULL DEFAULT 0,
  started_at        TIMESTAMPTZ,
  completed_at      TIMESTAMPTZ,
  error_message     TEXT,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_crawls_project
  ON nexusqa.blueprint_crawl_sessions(project_id, created_at DESC);
CREATE INDEX idx_bp_crawls_org
  ON nexusqa.blueprint_crawl_sessions(organization_id);

-- 3. Blueprint Elements (hash-partitioned by project_id)
CREATE TABLE nexusqa.blueprint_elements (
  id                UUID NOT NULL DEFAULT gen_random_uuid(),
  project_id        UUID NOT NULL,
  organization_id   UUID NOT NULL,
  element_type      VARCHAR(30) NOT NULL
    CHECK (element_type IN ('page','component','api_endpoint',
      'form_field','action','navigation','service',
      'database_table','static_asset')),
  canonical_url     TEXT NOT NULL,
  label             TEXT,
  semantic_role     VARCHAR(50),
  functional_intent TEXT,
  source_component_id UUID,  -- FK to github_manager code_entity
  platform          VARCHAR(20) NOT NULL DEFAULT 'web',
  platform_variants JSONB DEFAULT '{}',
  status            VARCHAR(20) NOT NULL DEFAULT 'active'
    CHECK (status IN ('active','stale','removed','archived')),
  first_seen_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  last_seen_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  PRIMARY KEY (id, project_id)
) PARTITION BY HASH (project_id);

-- Create 16 hash partitions
DO 

<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>B</mi><mi>E</mi><mi>G</mi><mi>I</mi><mi>N</mi><mi>F</mi><mi>O</mi><mi>R</mi><mi>i</mi><mi>I</mi><mi>N</mi><mn>0..15</mn><mi>L</mi><mi>O</mi><mi>O</mi><mi>P</mi><mi>E</mi><mi>X</mi><mi>E</mi><mi>C</mi><mi>U</mi><mi>T</mi><mi>E</mi><mi>f</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><mi>t</mi><msup><mo stretchy="false">(</mo><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mi>C</mi><mi>R</mi><mi>E</mi><mi>A</mi><mi>T</mi><mi>E</mi><mi>T</mi><mi>A</mi><mi>B</mi><mi>L</mi><mi>E</mi><mi>n</mi><mi>e</mi><mi>x</mi><mi>u</mi><mi>s</mi><mi>q</mi><mi>a</mi><mi mathvariant="normal">.</mi><mi>b</mi><mi>l</mi><mi>u</mi><mi>e</mi><mi>p</mi><mi>r</mi><mi>i</mi><mi>n</mi><msub><mi>t</mi><mi>e</mi></msub><mi>l</mi><mi>e</mi><mi>m</mi><mi>e</mi><mi>n</mi><mi>t</mi><msub><mi>s</mi><mi>p</mi></msub><mi>P</mi><mi>A</mi><mi>R</mi><mi>T</mi><mi>I</mi><mi>T</mi><mi>I</mi><mi>O</mi><mi>N</mi><mi>O</mi><mi>F</mi><mi>n</mi><mi>e</mi><mi>x</mi><mi>u</mi><mi>s</mi><mi>q</mi><mi>a</mi><mi mathvariant="normal">.</mi><mi>b</mi><mi>l</mi><mi>u</mi><mi>e</mi><mi>p</mi><mi>r</mi><mi>i</mi><mi>n</mi><msub><mi>t</mi><mi>e</mi></msub><mi>l</mi><mi>e</mi><mi>m</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>s</mi><mi>F</mi><mi>O</mi><mi>R</mi><mi>V</mi><mi>A</mi><mi>L</mi><mi>U</mi><mi>E</mi><mi>S</mi><mi>W</mi><mi>I</mi><mi>T</mi><mi>H</mi><mo stretchy="false">(</mo><mi>M</mi><mi>O</mi><mi>D</mi><mi>U</mi><mi>L</mi><mi>U</mi><mi>S</mi><mn>16</mn><mo separator="true">,</mo><mi>R</mi><mi>E</mi><mi>M</mi><mi>A</mi><mi>I</mi><mi>N</mi><mi>D</mi><mi>E</mi><mi>R</mi><mi>i</mi><mo separator="true">,</mo><mi>i</mi><mo stretchy="false">)</mo><mo separator="true">;</mo><mi>E</mi><mi>N</mi><mi>D</mi><mi>L</mi><mi>O</mi><mi>O</mi><mi>P</mi><mo separator="true">;</mo><mi>E</mi><mi>N</mi><mi>D</mi></mrow><annotation encoding="application/x-tex">BEGIN
  FOR i IN 0..15 LOOP
    EXECUTE format(
      &#x27;CREATE TABLE nexusqa.blueprint_elements_p%s
       PARTITION OF nexusqa.blueprint_elements
       FOR VALUES WITH (MODULUS 16, REMAINDER %s)&#x27;,
      i, i);
  END LOOP;
END</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.088em;vertical-align:-0.2861em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">G</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord">0..15</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal" style="margin-right:0.02778em;">or</span><span class="mord mathnormal">ma</span><span class="mord mathnormal">t</span><span class="mopen"><span class="mopen">(</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">n</span><span class="mord mathnormal">e</span><span class="mord mathnormal">xu</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mord mathnormal">a</span><span class="mord">.</span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">e</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">e</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal">n</span><span class="mord mathnormal">e</span><span class="mord mathnormal">xu</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mord mathnormal">a</span><span class="mord">.</span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">e</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">e</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.22222em;">V</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.10903em;">LU</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.10903em;">LU</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord">16</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">i</span><span class="mclose">)</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span></span></span></span></span>

;

CREATE INDEX idx_bp_elements_project_type
  ON nexusqa.blueprint_elements(project_id, element_type);
CREATE INDEX idx_bp_elements_org
  ON nexusqa.blueprint_elements(organization_id);
CREATE INDEX idx_bp_elements_url
  ON nexusqa.blueprint_elements
  USING btree (canonical_url text_pattern_ops);
CREATE INDEX idx_bp_elements_intent
  ON nexusqa.blueprint_elements
  USING gin (to_tsvector('english', functional_intent));

-- 4. Element Versions (bi-temporal)
CREATE TABLE nexusqa.blueprint_element_versions (
  id                UUID NOT NULL DEFAULT gen_random_uuid(),
  element_id        UUID NOT NULL,
  project_id        UUID NOT NULL,
  crawl_id          UUID NOT NULL,
  content_hash      CHAR(64) NOT NULL,  -- SHA-256
  dom_signature     TEXT,
  snapshot          JSONB NOT NULL,
  screenshot_key    TEXT,  -- MinIO key
  valid_from        TIMESTAMPTZ NOT NULL,
  valid_to          TIMESTAMPTZ DEFAULT 'infinity',
  txn_from          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  txn_to            TIMESTAMPTZ DEFAULT 'infinity',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  PRIMARY KEY (id, project_id)
) PARTITION BY HASH (project_id);

DO 

<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>B</mi><mi>E</mi><mi>G</mi><mi>I</mi><mi>N</mi><mi>F</mi><mi>O</mi><mi>R</mi><mi>i</mi><mi>I</mi><mi>N</mi><mn>0..15</mn><mi>L</mi><mi>O</mi><mi>O</mi><mi>P</mi><mi>E</mi><mi>X</mi><mi>E</mi><mi>C</mi><mi>U</mi><mi>T</mi><mi>E</mi><mi>f</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><mi>t</mi><msup><mo stretchy="false">(</mo><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mi>C</mi><mi>R</mi><mi>E</mi><mi>A</mi><mi>T</mi><mi>E</mi><mi>T</mi><mi>A</mi><mi>B</mi><mi>L</mi><mi>E</mi><mi>n</mi><mi>e</mi><mi>x</mi><mi>u</mi><mi>s</mi><mi>q</mi><mi>a</mi><mi mathvariant="normal">.</mi><mi>b</mi><mi>l</mi><mi>u</mi><mi>e</mi><mi>p</mi><mi>r</mi><mi>i</mi><mi>n</mi><msub><mi>t</mi><mi>e</mi></msub><mi>l</mi><mi>e</mi><mi>m</mi><mi>e</mi><mi>n</mi><msub><mi>t</mi><mi>v</mi></msub><mi>e</mi><mi>r</mi><mi>s</mi><mi>i</mi><mi>o</mi><mi>n</mi><msub><mi>s</mi><mi>p</mi></msub><mi>P</mi><mi>A</mi><mi>R</mi><mi>T</mi><mi>I</mi><mi>T</mi><mi>I</mi><mi>O</mi><mi>N</mi><mi>O</mi><mi>F</mi><mi>n</mi><mi>e</mi><mi>x</mi><mi>u</mi><mi>s</mi><mi>q</mi><mi>a</mi><mi mathvariant="normal">.</mi><mi>b</mi><mi>l</mi><mi>u</mi><mi>e</mi><mi>p</mi><mi>r</mi><mi>i</mi><mi>n</mi><msub><mi>t</mi><mi>e</mi></msub><mi>l</mi><mi>e</mi><mi>m</mi><mi>e</mi><mi>n</mi><msub><mi>t</mi><mi>v</mi></msub><mi>e</mi><mi>r</mi><mi>s</mi><mi>i</mi><mi>o</mi><mi>n</mi><mi>s</mi><mi>F</mi><mi>O</mi><mi>R</mi><mi>V</mi><mi>A</mi><mi>L</mi><mi>U</mi><mi>E</mi><mi>S</mi><mi>W</mi><mi>I</mi><mi>T</mi><mi>H</mi><mo stretchy="false">(</mo><mi>M</mi><mi>O</mi><mi>D</mi><mi>U</mi><mi>L</mi><mi>U</mi><mi>S</mi><mn>16</mn><mo separator="true">,</mo><mi>R</mi><mi>E</mi><mi>M</mi><mi>A</mi><mi>I</mi><mi>N</mi><mi>D</mi><mi>E</mi><mi>R</mi><mi>i</mi><mo separator="true">,</mo><mi>i</mi><mo stretchy="false">)</mo><mo separator="true">;</mo><mi>E</mi><mi>N</mi><mi>D</mi><mi>L</mi><mi>O</mi><mi>O</mi><mi>P</mi><mo separator="true">;</mo><mi>E</mi><mi>N</mi><mi>D</mi></mrow><annotation encoding="application/x-tex">BEGIN
  FOR i IN 0..15 LOOP
    EXECUTE format(
      &#x27;CREATE TABLE nexusqa.blueprint_element_versions_p%s
       PARTITION OF nexusqa.blueprint_element_versions
       FOR VALUES WITH (MODULUS 16, REMAINDER %s)&#x27;,
      i, i);
  END LOOP;
END</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.088em;vertical-align:-0.2861em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">G</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord">0..15</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal" style="margin-right:0.02778em;">or</span><span class="mord mathnormal">ma</span><span class="mord mathnormal">t</span><span class="mopen"><span class="mopen">(</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">n</span><span class="mord mathnormal">e</span><span class="mord mathnormal">xu</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mord mathnormal">a</span><span class="mord">.</span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">e</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">e</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal">s</span><span class="mord mathnormal">i</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal">n</span><span class="mord mathnormal">e</span><span class="mord mathnormal">xu</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mord mathnormal">a</span><span class="mord">.</span><span class="mord mathnormal">b</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">e</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">e</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal">s</span><span class="mord mathnormal">i</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.22222em;">V</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.10903em;">LU</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.10903em;">LU</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord">16</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal">i</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">i</span><span class="mclose">)</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span></span></span></span></span>

;

CREATE INDEX idx_bp_versions_element
  ON nexusqa.blueprint_element_versions(element_id, valid_from DESC);
CREATE INDEX idx_bp_versions_hash
  ON nexusqa.blueprint_element_versions(content_hash);
CREATE INDEX idx_bp_versions_crawl
  ON nexusqa.blueprint_element_versions(crawl_id);

-- 5. Element Relationships
CREATE TABLE nexusqa.blueprint_element_relationships (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  source_id         UUID NOT NULL,
  target_id         UUID NOT NULL,
  project_id        UUID NOT NULL,
  organization_id   UUID NOT NULL,
  rel_type          VARCHAR(30) NOT NULL
    CHECK (rel_type IN ('calls','renders','depends_on',
      'queries','navigates_to','contains','submits_to')),
  confidence        REAL NOT NULL DEFAULT 1.0
    CHECK (confidence >= 0.0 AND confidence <= 1.0),
  crawl_id          UUID NOT NULL,
  metadata          JSONB DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_rels_source
  ON nexusqa.blueprint_element_relationships(source_id);
CREATE INDEX idx_bp_rels_target
  ON nexusqa.blueprint_element_relationships(target_id);
CREATE INDEX idx_bp_rels_project
  ON nexusqa.blueprint_element_relationships(project_id);

-- 6. Drift Events
CREATE TABLE nexusqa.blueprint_drift_events (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  element_id        UUID NOT NULL,
  project_id        UUID NOT NULL,
  organization_id   UUID NOT NULL,
  crawl_id          UUID NOT NULL,
  drift_type        VARCHAR(40) NOT NULL
    CHECK (drift_type IN ('addition','removal','modification',
      'breakage','structure_change','api_change',
      'perf_degradation','a11y_regression',
      'unexplained_source_drift','dead_code_added',
      'duplication_introduced','circular_dep_introduced',
      'complexity_hotspot_added','architecture_violation')),
  severity_score    REAL NOT NULL,
  old_version_id    UUID,
  new_version_id    UUID,
  details           JSONB NOT NULL DEFAULT '{}',
  fallow_finding_id UUID,  -- nullable FK to fallow findings
  ticket_id         UUID,  -- nullable FK to qa_tickets
  acknowledged      BOOLEAN NOT NULL DEFAULT FALSE,
  acknowledged_by   UUID,
  acknowledged_at   TIMESTAMPTZ,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_drift_element
  ON nexusqa.blueprint_drift_events(element_id, created_at DESC);
CREATE INDEX idx_bp_drift_project_sev
  ON nexusqa.blueprint_drift_events(project_id, severity_score DESC);
CREATE INDEX idx_bp_drift_org
  ON nexusqa.blueprint_drift_events(organization_id);
CREATE INDEX idx_bp_drift_type
  ON nexusqa.blueprint_drift_events(drift_type);

-- 7. Architecture Diagrams
CREATE TABLE nexusqa.blueprint_diagrams (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  project_id        UUID NOT NULL REFERENCES
                      nexusqa.blueprint_projects(id) ON DELETE CASCADE,
  organization_id   UUID NOT NULL,
  crawl_id          UUID NOT NULL,
  diagram_type      VARCHAR(30) NOT NULL
    CHECK (diagram_type IN ('architecture_tree','data_flow',
      'navigation_map','component_hierarchy',
      'api_dependency','deployment')),
  format            VARCHAR(10) NOT NULL DEFAULT 'ascii'
    CHECK (format IN ('ascii','mermaid','svg')),
  content           TEXT NOT NULL,
  metadata          JSONB DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_diagrams_project
  ON nexusqa.blueprint_diagrams(project_id, created_at DESC);

-- 8. Crawl Checkpoints (for resumability)
CREATE TABLE nexusqa.blueprint_crawl_checkpoints (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  crawl_id          UUID NOT NULL REFERENCES
                      nexusqa.blueprint_crawl_sessions(id)
                      ON DELETE CASCADE,
  organization_id   UUID NOT NULL,
  url               TEXT NOT NULL,
  status            VARCHAR(20) NOT NULL DEFAULT 'pending'
    CHECK (status IN ('pending','crawled','failed','skipped')),
  depth             INTEGER NOT NULL DEFAULT 0,
  content_hash      CHAR(64),
  error_message     TEXT,
  crawled_at        TIMESTAMPTZ,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_checkpoints_crawl
  ON nexusqa.blueprint_crawl_checkpoints(crawl_id, status);

-- 9. Source Component Map (DOM element <-> code entity bridge)
CREATE TABLE nexusqa.blueprint_source_component_map (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  element_id        UUID NOT NULL,
  project_id        UUID NOT NULL,
  organization_id   UUID NOT NULL,
  github_entity_id  UUID NOT NULL,  -- github_manager code_entity
  github_repo_id    UUID NOT NULL,
  file_path         TEXT NOT NULL,
  mapping_type      VARCHAR(20) NOT NULL
    CHECK (mapping_type IN ('renders','implements',
      'routes_to','styles','tests')),
  confidence        REAL NOT NULL DEFAULT 1.0,
  last_verified_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_srcmap_element
  ON nexusqa.blueprint_source_component_map(element_id);
CREATE INDEX idx_bp_srcmap_github
  ON nexusqa.blueprint_source_component_map(github_entity_id);

-- 10. Fallow Reports
CREATE TABLE nexusqa.blueprint_fallow_reports (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  project_id        UUID NOT NULL REFERENCES
                      nexusqa.blueprint_projects(id) ON DELETE CASCADE,
  organization_id   UUID NOT NULL,
  scan_session_id   UUID REFERENCES
                      nexusqa.blueprint_crawl_sessions(id),
  repository_id     UUID NOT NULL,
  commit_sha        VARCHAR(40) NOT NULL,
  scan_started_at   TIMESTAMPTZ,
  scan_completed_at TIMESTAMPTZ,
  total_findings    INTEGER NOT NULL DEFAULT 0,
  new_findings      INTEGER NOT NULL DEFAULT 0,
  resolved_findings INTEGER NOT NULL DEFAULT 0,
  findings_by_type  JSONB NOT NULL DEFAULT '{}',
  sarif_content     JSONB NOT NULL,
  fallow_version    VARCHAR(20),
  config_snapshot   JSONB DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_bp_fallow_project
  ON nexusqa.blueprint_fallow_reports(project_id, created_at DESC);
CREATE INDEX idx_bp_fallow_org
  ON nexusqa.blueprint_fallow_reports(organization_id);
CREATE INDEX idx_bp_fallow_findings
  ON nexusqa.blueprint_fallow_reports
  USING gin (findings_by_type);

-- 11. Scheduled Tasks (GENERIC — platform-wide, NOT
--     blueprint-specific)
CREATE TABLE nexusqa.scheduled_tasks (
  id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id   UUID NOT NULL,
  name              VARCHAR(500) NOT NULL,
  description       TEXT,
  category          VARCHAR(50) NOT NULL
    CHECK (category IN ('blueprint_crawl','blueprint_fallow',
      'blueprint_drift_detect','code_review','security_audit',
      'performance_audit','accessibility_audit',
      'ticket_sweep','custom')),
  job_type          TEXT NOT NULL,  -- any skill in
                                    -- graphrag.skill_registry
  trigger_schedule_id TEXT,  -- trigger.dev schedule ID
  cron_expression   VARCHAR(100) NOT NULL,
  timezone          VARCHAR(50) NOT NULL DEFAULT 'UTC',
  enabled           BOOLEAN NOT NULL DEFAULT TRUE,
  input_params      JSONB NOT NULL DEFAULT '{}',
  target_type       VARCHAR(30) NOT NULL DEFAULT 'global'
    CHECK (target_type IN ('project','suite',
                           'plugin','global')),
  target_id         UUID,
  priority          VARCHAR(10) NOT NULL DEFAULT 'normal'
    CHECK (priority IN ('low','normal','high','critical')),
  last_run_at       TIMESTAMPTZ,
  next_run_at       TIMESTAMPTZ,
  last_run_status   VARCHAR(20),
  failure_count     INTEGER NOT NULL DEFAULT 0,
  max_retries       INTEGER NOT NULL DEFAULT 1,
  failure_policy    VARCHAR(20) NOT NULL DEFAULT 'continue'
    CHECK (failure_policy IN ('continue','alert',
                              'disable')),
  created_by        UUID NOT NULL,
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_sched_tasks_org
  ON nexusqa.scheduled_tasks(organization_id);
CREATE INDEX idx_sched_tasks_category
  ON nexusqa.scheduled_tasks(organization_id, category);
CREATE INDEX idx_sched_tasks_enabled
  ON nexusqa.scheduled_tasks(enabled, next_run_at)
  WHERE enabled = TRUE;
CREATE INDEX idx_sched_tasks_target
  ON nexusqa.scheduled_tasks(target_type, target_id);

Partitioning Strategy

The two highest-volume tables---blueprint_elements and blueprint_element_versions---are hash-partitioned by project_id into 16 partitions. Hash partitioning was selected over range partitioning (by date) because the dominant query pattern filters by project rather than time range: "show all elements for project X" is far more common than "show all elements created this month across all projects." With 16 partitions, the planner prunes 15/16 of the data on every project-scoped query, and parallel sequential scans distribute I/O across partitions when full-table analytics are required.

The partition count of 16 balances granularity against management overhead. For deployments expecting more than 10,000 projects per organization, the count can be increased to 64 or 256 via the standard ALTER TABLE ... SPLIT PARTITION workflow introduced in PostgreSQL 17 [@postgresql2024].

Indexing Strategy

Three index types are employed across the schema:

  1. B-tree: Standard indexes on foreign keys (project_id, element_id, crawl_id), status columns, and composite keys for common query patterns. Partial indexes (e.g., WHERE enabled = TRUE on scheduled_tasks) reduce index size for filtered scans.

  2. GIN: Inverted indexes on JSONB columns (findings_by_type, platform_variants) for containment queries (@> operator), and on to_tsvector(’english’, functional_intent) for full-text search across element descriptions.

  3. text_pattern_ops: Specialized B-tree operator class on canonical_url enabling prefix matching (LIKE ’/dashboard/%’) without sequential scan, used by the Architecture Overview's tree-building query.

Row-Level Security

All eleven tables enforce RLS policies following the pattern established by the base NexusQA schema:

Plain Text
12 lines
ALTER TABLE nexusqa.blueprint_projects ENABLE ROW LEVEL SECURITY;

CREATE POLICY bp_projects_org_isolation
  ON nexusqa.blueprint_projects
  FOR ALL
  USING (organization_id = current_setting(
    'app.current_org_id')::uuid)
  WITH CHECK (organization_id = current_setting(
    'app.current_org_id')::uuid);

-- Repeated for all 11 tables.  Admin pool connections
-- use SET ROLE to bypassrls for migrations only.

The scheduled_tasks table merits special attention: as a generic, platform-wide table, its RLS policy ensures that scheduled tasks created for blueprint operations, security audits, performance checks, and any other category are all tenant-isolated by the same mechanism. A user in organization A cannot see, modify, or trigger scheduled tasks belonging to organization B, regardless of category. This isolation guarantee is critical because the scheduled_tasks table will serve as the unified scheduling surface for every recurring workload in NexusQA---not merely the blueprint features described in this paper.

API Design

The Living Blueprint extension introduces 39 new HTTP endpoints organized across seven resource groups, all mounted under the existing /nexusqa/api prefix and protected by the shared JWT authentication middleware. Table [tab:api-endpoints]{reference-type="ref" reference="tab:api-endpoints"} presents the full endpoint specification. Design decisions follow three principles: (i) every write operation that triggers asynchronous work returns 202 Accepted with a jobId for WebSocket tracking; (ii) callback routes are never invoked by end users---they are service-to-service contracts between the orchestrator and NexusQA; (iii) all list endpoints accept limit, offset, and resource-specific filter parameters and return paginated envelopes of the form {data, total, limit, offset}.

+-------------+-----------------------------------------+-------------+--------------------------------------------+ | Method | Path | Auth | Description | +:============+:========================================+:============+:===========================================+ | Blueprint Projects (6 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/projects | JWT | Create project (onboarding) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/projects | JWT | List projects (org-scoped) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/projects/:id | JWT | Project detail + summary stats | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | PATCH | /blueprint/projects/:id | JWT | Update project config | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | DELETE | /blueprint/projects/:id | JWT | Soft-delete project | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/projects/:id/crawl | JWT | Trigger crawl (returns 202) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Crawl Sessions (5 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/crawl-sessions | JWT | List sessions with status filter | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/crawl-sessions/:id | JWT | Session detail + per-URL progress | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/crawl-sessions/:id/pause | JWT | Pause active session | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/crawl-sessions/:id/resume | JWT | Resume paused session | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/crawl-sessions/:id/cancel | JWT | Cancel with partial-result retention | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Elements (7 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements | JWT | Browse elements (filterable) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements/tree | JWT | Hierarchical tree by page | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements/:id | JWT | Element detail + current version | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements/:id/versions | JWT | Version history (bi-temporal) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements/:id/diff | JWT | Side-by-side version comparison | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/elements/:id/source | JWT | Linked source-code component | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/elements/:id/re-verify | JWT | Manual re-verification (returns 202) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Drift Events (4 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/drift-events | JWT | List drift events (severity filter) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/drift-events/:id | JWT | Drift event detail + evidence | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/drift-events/:id/ack | JWT | Acknowledge (mark reviewed) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/drift-events/:id/investigate | JWT | Trigger deep investigation (202) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Diagrams (3 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/diagrams | JWT | List generated diagrams | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /blueprint/diagrams/generate | JWT | Generate new diagram set (202) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/diagrams/:id/compare | JWT | Side-by-side temporal comparison | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Fallow Reports (4 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/fallow-reports | JWT | List scan reports (paginated) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/fallow-reports/:id | JWT | Full report + finding breakdown | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/fallow-reports/:id/compare | JWT | Diff two scan reports | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/fallow-reports/:id/sarif | JWT | Download raw SARIF JSON | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Architecture Review (3 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/architecture/tree | JWT | Architecture tree w/ health markers | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/architecture/timeline | JWT | Temporal drift timeline | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /blueprint/architecture/relationships | JWT | Element relationship graph | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | Universal Scheduler (7 endpoints) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /scheduled-tasks | JWT | List all scheduled tasks | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /scheduled-tasks | JWT | Create schedule (registers w/ trigger.dev) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /scheduled-tasks/:id | JWT | Detail + next 5 projected runs | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | PATCH | /scheduled-tasks/:id | JWT | Update schedule parameters | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | DELETE | /scheduled-tasks/:id | JWT | Remove schedule from trigger.dev | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | POST | /scheduled-tasks/:id/run-now | JWT | Immediate manual trigger (202) | +-------------+-----------------------------------------+-------------+--------------------------------------------+ | GET | /scheduled-tasks/:id/history | JWT | Run history from trigger.dev | +-------------+-----------------------------------------+-------------+--------------------------------------------+

Request and Response Patterns

All creation endpoints accept JSON bodies validated by Zod schemas and return the created resource with a 201 Created status. Operations that dispatch asynchronous work---crawl triggers, diagram generation, re-verification, investigation, manual schedule triggers---return 202 Accepted with a payload containing at minimum:

JSON
6 lines
{
  "jobId": "uuid-v4",
  "status": "dispatched",
  "traceId": "uuid-v4",
  "wsChannel": "nexus:jobs:org:{orgId}"
}

The wsChannel field tells the client which WebSocket channel to subscribe to for real-time progress updates. This pattern---return an opaque job identifier, stream progress over WebSocket, deliver a final callback internally---is consistent across all 16 existing NexusQA skills and the 7 new Living Blueprint skills.

Callback Routes

Three internal callback routes handle orchestrator-to-NexusQA communication. These are not exposed to end users; Istio AuthorizationPolicy restricts inbound traffic to the orchestrator's service identity.

Plain Text
3 lines
POST /callbacks/blueprint-crawl-complete
POST /callbacks/blueprint-element-analyzed
POST /callbacks/blueprint-fallow-complete

Each callback carries the orchestrator's X-Service-Key header and a structured payload that includes the original jobId, the organization context, and the skill-specific result data. NexusQA validates the service key, persists the results to the appropriate database tables, emits WebSocket events for the frontend, and writes GraphRAG entities for long-term knowledge retention.

WebSocket Events

Living Blueprint emits eight new WebSocket event types on the organization-scoped Redis Pub/Sub channel nexus:jobs:org:{orgId}. Events follow the existing NexusQA convention: a type discriminator, a jobId reference, and a payload containing progress data. Key events include blueprint:crawl_progress (emitted per URL batch with element count and coverage percentage), blueprint:drift_detected (emitted when drift severity exceeds the configured threshold), and blueprint:fallow_complete (emitted with the full finding summary when a Fallow scan finishes).

Frontend Design and UI/UX Mockups

The Living Blueprint frontend adds eleven new pages to the NexusQA dashboard, rendered as a Next.js 14 static export within the dashboard's PluginFrame.tsx iframe. State management follows the existing Zustand pattern: each domain owns a dedicated store with subscribeWithSelector for fine-grained re-renders. Three new stores---blueprint-store.ts, scheduled-tasks-store.ts, and fallow-store.ts---handle the new domains.

Page Inventory

(1) Blueprint Overview. Dashboard landing page showing aggregate statistics across all projects: total elements discovered, drift events in the last 7 days, upcoming scheduled scans, and a mini-scorecard of per-project health. Uses Recharts bar and sparkline components for trend visualization.

(2) Projects List. Card-based project listing with status badges (active, paused, onboarding), last crawl timestamp, element count, and drift event count. Each card links to the project dashboard. Filter controls for status and platform type.

(3) Project Dashboard. Single-project view with five summary panels: element statistics (by type and status), recent drift events, next scheduled crawl, Fallow finding summary, and a mini-architecture tree. Functions as the navigation hub for all project-specific pages.

(4) Element Explorer. Two-pane layout: a filterable element tree on the left (grouped by page URL, expandable to individual elements) and a detail panel on the right showing the selected element's current state, version history, linked source component, and drift timeline. The detail panel embeds the nexus-github-manager CodeViewer and CodeEntityPanel components via the existing githubApi client library, providing direct navigation from a DOM element to its React component source code without duplication of the code browsing infrastructure.

(5) Architecture Diagrams. Gallery view of auto-generated ASCII and Mermaid diagrams with temporal comparison: select two timestamps to see a side-by-side diff with additions highlighted in green and removals in red. Diagrams are rendered via a <pre> block for ASCII art and a Mermaid.js renderer for graph-based layouts.

(6) Drift Monitor. Timeline-based feed of drift events with severity color coding, filterable by drift type, severity, and date range. Each event expandable to show the 5-layer comparison evidence: content hash diff, DOM signature delta, visual AI assessment, source code diff (linked to CodeViewer), and Fallow finding delta.

(7) Crawl Sessions. Table listing all crawl sessions (active, completed, paused, failed) with real-time progress bars for active sessions driven by WebSocket events. Drill-down shows per-URL status, discovered elements, and any errors encountered.

(8) Onboarding Wizard. Five-step modal overlay (project info, URL and repository selection, platform configuration, schedule presets, review and launch). Step 2 reuses the nexus-github-manager repository selector component, showing only repositories the user has already connected. Step 4 offers four toggle-based schedule presets (daily crawl, hourly critical pages, weekly Fallow scan, weekly architecture scan), all of which register with trigger.dev through the universal scheduler API.

(9) Architecture Review Console. The primary analytical surface, offering five modes: Overview (health-annotated tree with red/green/yellow/gray color coding), Timeline (temporal drift curve), Relationships (element dependency graph), API Health (endpoint response status), and UX Flow (page navigation graph). This page embeds three nexus-github-manager components: FileTree for source navigation, CodeViewer for inline code display, and RelationshipsPanel for call-graph visualization. Fallow findings appear as inline markers on tree nodes with clickable drill-down to the offending source line.

(10) Fallow Reports. Scan history table with per-report detail view showing finding breakdown by category, delta since previous scan, and timeline trend chart. Each finding is actionable: View in CodeViewer, Create Ticket (which feeds the 7-stage remediation pipeline), and Suggest Fix (which dispatches the qa_remediation_plan skill with the finding as context).

(11) Universal Scheduler. Platform-wide scheduled task management---not Blueprint-specific. Lists all scheduled tasks across all categories (crawls, Fallow scans, security audits, performance audits, accessibility audits, ticket sweeps, custom skills) with filter, search, enable/disable toggle, and manual trigger. The "New Schedule" modal is a three-step form: What to run (category, skill, target), When to run (preset or custom cron with timezone and next-5-runs preview), and How to run (priority, retry policy, notification preferences). This page is the first NexusQA surface designed for cross-cutting reuse: every future recurring workload---blueprint crawls, security scans, stale-ticket sweeps---configures its schedule here.

Zustand Store Architecture

Three new Zustand stores manage client-side state, each following the established NexusQA pattern: typed state interface, async action creators that call the API via auth-fetch.ts, WebSocket subscription handlers for real-time updates, and selector hooks for component binding.

Plain Text
17 lines
blueprint-store.ts
  State: projects[], currentProject, elements[], driftEvents[],
         diagrams[], crawlSessions[], loading flags
  Actions: fetchProjects, triggerCrawl, fetchElements,
           acknowledgeDrift, generateDiagrams
  WS: blueprint:crawl_progress, blueprint:drift_detected

scheduled-tasks-store.ts
  State: tasks[], currentTask, runHistory[], loading flags
  Actions: fetchTasks, createTask, updateTask, deleteTask,
           triggerNow, fetchHistory
  WS: schedule:run_started, schedule:run_completed

fallow-store.ts
  State: reports[], currentReport, findingsSummary, loading
  Actions: fetchReports, fetchReportDetail, compareTwoReports
  WS: blueprint:fallow_complete

Key Design Decisions

Embedded GitHub Manager Components. Rather than building new source code browsing UI, Living Blueprint imports three existing components from the nexus-github-manager dashboard package via the shared githubApi client. This eliminates approximately 2,400 lines of duplicated code and ensures that improvements to the Code Explorer (syntax highlighting, search, go-to-definition) are automatically inherited by the Architecture Review Console.

Universal Scheduler Reusability. The scheduled tasks page and its backing scheduled_tasks database table are deliberately generic. The category field distinguishes task types, but the CRUD operations, cron parsing, timezone handling, and trigger.dev integration are category-agnostic. This means that when NexusQA later adds scheduled security scans or automated ticket triage sweeps, no new scheduling infrastructure is required---only a new category value and corresponding skill registration.

Color Palette and Semantic Assignments. The Architecture Review Console uses four semantic colors consistently across all modes:

  • Red (#E53E3E): Issue detected---breakage, critical drift, failed health check, new Fallow finding of severity critical.

  • Green (#38A169): Fixed or resolved---drift acknowledged and remediated, Fallow finding resolved, element verified stable.

  • Yellow (#D69E2E): Changed---modification detected, medium-severity drift, new non-critical Fallow finding, element pending re-verification.

  • Gray (#A0AEC0): Stable---no change since last scan, element verified, no drift detected.

These four states map directly to the drift event severity tiers (critical, high, medium, informational) and to the Fallow finding lifecycle (new, existing, resolved).

Figure 1{reference-type="ref" reference="fig:nav-flow"} illustrates the primary navigation paths between the eleven Living Blueprint pages.

+------------------+
|  NexusQA Tabs    |
|  (existing 10)   |
|  + Blueprint tab |
+--------+---------+
         |
         v
+------------------+     +-----------------+
| Blueprint        |---->| Projects List   |
| Overview         |     |                 |
+--------+---------+     +-------+---------+
         |                       |
         |            +----------+----------+
         |            |                     |
         v            v                     v
+------------------+ +------------+ +---------------+
| Universal        | | Project    | | Onboarding    |
| Scheduler        | | Dashboard  | | Wizard (modal)|
+------------------+ +-----+------+ +---------------+
                           |
          +------+----+----+----+------+------+
          |      |    |         |      |      |
          v      v    v         v      v      v
       +-----+ +--+ +-------+ +----+ +----+ +------+
       |Elem.| |Ar-| |Drift  | |Dia-| |Cra-| |Fallow|
       |Expl.| |ch.| |Monitor| |gra-| |wl  | |Rpts  |
       |     | |Rev| |       | |ms  | |Sess| |      |
       +-----+ +--+ +-------+ +----+ +----+ +------+
Navigation flow between Living Blueprint pages. The Blueprint tab in the existing NexusQA sidebar opens the Overview. All project-specific pages are accessible from the Project Dashboard. The Universal Scheduler is accessible from both the Overview and the existing NexusQA sidebar as a top-level tab.

Kubernetes Infrastructure

A central architectural advantage of Living Blueprint is that it requires no new worker deployments. Every asynchronous operation---crawling, source analysis, Fallow scanning, element classification, diagram generation, drift detection---is dispatched through the existing nexus-orchestrator to nexus-workflows (trigger.dev), which already provides horizontally auto-scaled workers, batch fan-out, schedule management, and run history. The only new infrastructure artifact is a Fallow MCP sidecar added to the nexus-workflows pod specification.

Figure 2{reference-type="ref" reference="fig:k8s-topology"} shows the deployment topology.

+-------------------------------------------------------+
|  namespace: nexus                                     |
|                                                       |
|  EXISTING (unchanged):                                |
|  +-------------------+  +-------------------+         |
|  | nexus-orchestrator|  | nexus-graphrag    |         |
|  | port 8080         |  | (PG + Qdrant +    |         |
|  | Dispatch API      |  |  Neo4j)           |         |
|  +---------+---------+  +-------------------+         |
|            |                                          |
|            v                                          |
|  +-----------------------------+                      |
|  | nexus-workflows             |                      |
|  | (trigger.dev worker)        |                      |
|  | +-------------------------+ |                      |
|  | | app container           | |                      |
|  | | - Node.js 20            | |                      |
|  | | - trigger.dev SDK       | |                      |
|  | | - Playwright (bundled)  | |                      |
|  | +-------------------------+ |                      |
|  | +-------------------------+ |  <-- NEW sidecar     |
|  | | fallow-mcp sidecar      | |                      |
|  | | - Rust binary            | |                      |
|  | | - port 9200 (MCP)       | |                      |
|  | | - shared vol: /workspace | |                      |
|  | +-------------------------+ |                      |
|  +-----------------------------+                      |
|                                                       |
|  +-------------------+  +-------------------+         |
|  | nexus-github-mgr  |  | nexus-nexusqa     |         |
|  | OAuth, clone, AST |  | port 9099 (HTTP)  |         |
|  | port 8092         |  | port 9100 (WS)    |         |
|  +-------------------+  +-------------------+         |
|                                                       |
|  +-------------------+  +-------------------+         |
|  | PostgreSQL        |  | Redis + BullMQ    |         |
|  | (nexus DB)        |  |                   |         |
|  +-------------------+  +-------------------+         |
|                                                       |
|  +-------------------+                                |
|  | MinIO (S3)        |                                |
|  | nexusqa-* buckets |                                |
|  +-------------------+                                |
+-------------------------------------------------------+
Kubernetes deployment topology. The only new artifact is the fallow-mcp sidecar container added to the nexus-workflows pod. All other services are existing and unchanged.

Fallow MCP Sidecar

The Fallow MCP server is deployed as a sidecar container within the nexus-workflows pod, sharing a volume mount at /workspace with the main trigger.dev worker. When the qa_blueprint_fallow_scan skill executes, the trigger.dev worker first requests a working copy of the repository from nexus-github-manager (which maintains a cached clone), then invokes the Fallow MCP server at localhost:9200 within the same pod network. This co-location eliminates network latency for what is inherently a CPU-bound analysis: Fallow's Rust core processes 3,000+ file monorepos in approximately 300 ms [@stocco2023vista].

Resource allocation for the sidecar is modest: 100m--500m CPU and 256Mi--512Mi RAM. Because Fallow's analysis is a pure computation with no persistent state, the sidecar can be restarted independently without affecting the trigger.dev worker.

Database Migrations

Two new migration files extend the nexusqa schema:

  • 019_living_blueprint.sql: Creates 10 tables (blueprint_projects, blueprint_crawl_sessions, blueprint_elements, blueprint_element_versions, blueprint_element_relationships, blueprint_drift_events, blueprint_diagrams, blueprint_crawl_checkpoints, blueprint_source_component_map, blueprint_fallow_reports) with RLS policies, partition definitions, and foreign keys.

  • 020_universal_scheduler.sql: Creates the generic scheduled_tasks table with RLS policy and indexes on (organization_id, category) and (organization_id, enabled, next_run_at).

Both migrations are idempotent (CREATE TABLE IF NOT EXISTS, CREATE INDEX IF NOT EXISTS) and executed by the admin connection pool that bypasses RLS.

Security Considerations

OAuth Token Handling

Living Blueprint does not handle GitHub OAuth tokens directly. All source code access is mediated through nexus-github-manager, which owns the OAuth application registration, token storage (AES-256 encrypted in PostgreSQL), token refresh lifecycle, and scope enforcement. Living Blueprint holds only a github_repository_id foreign key; it never receives, stores, or transmits OAuth tokens. This single-responsibility design ensures that a compromise of the NexusQA service does not expose source code credentials.

Row-Level Security

Every new table carries an RLS policy enforcing organization_id = current_setting(’app.current_org_id’)::uuid. The NexusQA backend sets this session variable on every database connection checkout, derived from the JWT organizationId claim. Administrative operations (migrations, materialized view refresh) use a dedicated connection pool configured with bypassRLS. No application query can read or write data belonging to a different organization, even in the event of a SQL injection in a query parameter.

Rate Limiting and Crawl Governance

Web crawling is inherently adversarial from the perspective of target sites. Living Blueprint enforces several constraints to ensure responsible behavior:

  • robots.txt compliance: Every crawl session begins by fetching and parsing the target domain's robots.txt. Disallowed paths are excluded from the URL frontier. The Crawl-delay directive, when present, is honored as a minimum inter-request interval.

  • Configurable rate limits: Per-project crawl configuration includes maxConcurrentRequests (default 5), requestDelayMs (default 1000), and maxDepth (default 10). These values are persisted in the blueprint_projects.crawl_config JSONB column and passed to every crawl dispatch.

  • Domain-scoped crawling: The discovery engine constrains URL expansion to the domains explicitly registered in the project configuration. Cross-domain links are recorded as external references but not followed.

  • Crawl budgets: Each crawl session has a hard URL budget (maxUrls, default 10,000) beyond which the session completes with a budget_exhausted status rather than continuing indefinitely.

Credential Storage Patterns

Living Blueprint introduces no new credential types. The system relies entirely on existing credential management:

  • JWT secrets: Stored in the nexus-auth-secrets Kubernetes Secret, injected as environment variables.

  • Database credentials: Kubernetes Secrets mounted at pod startup.

  • AI provider keys: Managed by nexus-auth with AES-256 encryption, resolved at runtime by the AI Provider Router. No env-var fallbacks are permitted.

  • GitHub tokens: Managed exclusively by nexus-github-manager (see above).

Data Isolation

Multi-tenant isolation is enforced at four layers: (i) JWT organization claims extracted by middleware; (ii) PostgreSQL RLS policies on every table; (iii) GraphRAG tenant headers (X-Company-ID, X-App-ID) on every entity query; (iv) MinIO storage keys prefixed with {orgId}/ to prevent cross-tenant object access even in the event of a presigned URL leak.

Patent Analysis

This section surveys prior art for ten novel claims arising from the Living Blueprint architecture and identifies the genuinely novel contributions relative to the existing patent landscape and academic literature.

Claim 1: AI-Driven Autonomous Web Application Model Extraction with Drift-Aware QA

Prior art. US Patent Application US20110078557A1 ("Automated web application testing") [@us20110078557] describes automated model extraction from web applications via dynamic crawling and state-machine construction. Crawljax [@mesbah2012crawljax] introduced event-driven dynamic crawling with state-flow graph construction. ContentKing provides 24/7 website monitoring with change detection.

What is novel. No prior system autonomously extracts a web application model, maintains it as a versioned knowledge graph, detects drift across five comparison layers (content hash, DOM signature, visual AI, source code diff, static analysis diff), and feeds drift events directly into a 7-stage autonomous remediation pipeline with an LLM plan review gate. The closed loop from discovery to remediation, mediated by a knowledge graph, is the differentiating contribution.

Suggested claim language. "A computer-implemented method for autonomous quality assurance of web applications comprising: extracting an application model via headless browser crawling; storing said model as versioned entities in a knowledge graph; detecting drift via multi-layer comparison including content hash, DOM structural signature, visual AI classification, source code diff, and static analysis diff; and automatically initiating a multi-stage remediation pipeline triggered by drift events exceeding a configurable severity threshold."

Claim 2: GraphRAG-Backed Living Blueprint Repository with Bi-Temporal Version Tracking

Prior art. Temporal databases (e.g., PostgreSQL temporal tables, Oracle Workspace Manager) support bitemporal versioning. Knowledge graphs for software artifacts have been explored in KGTest [@icse2024kgtest; @cods2020kgtest].

What is novel. The combination of (i) a GraphRAG repository (PostgreSQL + vector store + Neo4j) storing web application elements as typed entities with (ii) bi-temporal versioning (system time and valid time) enabling "as-of" queries that reconstruct the application state at any historical point. No prior knowledge-graph-based testing system supports bi-temporal element versioning for time-travel debugging of web applications.

Suggested claim language. "A system for maintaining a living blueprint of a web application comprising: a knowledge graph repository storing application elements as typed entities with typed relationships; bi-temporal version tracking recording both system time and valid time for each entity version; and query interfaces enabling reconstruction of the complete application model at any historical point in both temporal dimensions."

Claim 3: LLM-Powered Functional Intent Classification Enhanced by Source Code Knowledge Graph

Prior art. LLM-based test generation from UI descriptions [@kang2023llm; @chen2023chatunitest]. VISTA uses visual analysis for web test repair [@stocco2023vista].

What is novel. Augmenting LLM functional intent classification of DOM elements with source-code context retrieved from a pre-existing code knowledge graph (AST, call graphs, component hierarchy). The fusion of runtime DOM semantics with static source-code structure yields classification accuracy gains that neither signal achieves alone.

Suggested claim language. "A method for classifying the functional intent of web application elements comprising: extracting DOM attributes and visual context via headless browser; querying a source code knowledge graph to retrieve the corresponding component definition, call graph neighbors, and prop interface; providing both DOM context and source code context as input to a large language model; and outputting a functional intent classification with confidence score."

Claim 4: Checkpoint-Based Resumable Web Crawl with Bloom Filter Visited-Set

Prior art. Screaming Frog uses MD5 hashing for URL deduplication. Crawlee (Apify) provides request queue persistence. Bloom filters for URL deduplication in web crawling are well-established [@mesbah2012crawljax].

What is novel. Combining checkpoint serialization (URL frontier, Bloom filter state, partial element inventory) with the trigger.dev dispatch model such that a crawl can be paused, the worker pod can be rescheduled or restarted, and the crawl resumes from the exact checkpoint without re-crawling visited URLs. Prior crawlers either lack pause/resume or implement it as in-process state that is lost on pod eviction.

Suggested claim language. "A method for resumable web crawling in a container-orchestrated environment comprising: periodically serializing crawl state including URL frontier, Bloom filter visited-set, and partial element inventory to persistent storage; upon worker interruption, deserializing the checkpoint and resuming from the serialized state; and ensuring exactly-once processing of each URL via the Bloom filter deduplication layer."

Claim 5: Cross-Platform Element Normalization in a Unified Knowledge Graph

Prior art. Appflow [@hu2018appflow] maps UI elements across Android apps using visual similarity. DeepTest [@tian2018deeptest] generates tests for autonomous driving systems across platforms.

What is novel. A unified element schema that normalizes web DOM elements, iOS accessibility nodes, and Android view hierarchy nodes into a common entity type within a single knowledge graph, enabling cross-platform drift detection and test reuse.

Suggested claim language. "A system for cross-platform application element management comprising: a unified element schema defining common attributes across web, iOS, and Android platforms; a normalization layer that maps platform-specific element representations to said unified schema; storage of normalized elements in a knowledge graph with platform as a typed attribute; and drift detection operating on the unified representation to identify cross-platform inconsistencies."

Claim 6: Autonomous Remediation Pipeline Triggered by Element Drift Detection

Prior art. Self-healing test frameworks repair broken selectors [@stocco2017water]. LLM-based program repair [@xia2023repair] generates patches from bug descriptions.

What is novel. A closed-loop pipeline where drift events (not test failures) trigger a 7-stage autonomous remediation chain including AI triage, plan generation, an LLM plan review gate (validating against six formal criteria with historical context from the knowledge graph), automated execution via PR creation, automated verification, and human sign-off. The pipeline's distinguishing feature is Stage 4: a reasoning-model gate that rejects plans with insufficient root-cause analysis or excessive patch frequency.

Suggested claim language. "A computer-implemented method for autonomous remediation of web application drift comprising: detecting drift via multi-layer comparison; classifying drift severity and type via AI triage; generating a remediation plan using a tool-augmented language model with access to historical remediation data; validating the plan via a reasoning-model gate that evaluates six formal criteria including root cause depth, historical precedent, and blast radius; executing the approved plan via automated branch creation, code modification, and pull request; verifying the fix via automated test execution; and presenting the result for human sign-off."

Claim 7: Architecture Review Console with Color-Coded Drift Overlay

Prior art. Applitools provides visual AI comparison of screenshots. WebDiff [@choudhary2010webdiff] detects cross-browser inconsistencies.

What is novel. An interactive architecture review console that overlays color-coded drift markers (red/green/yellow/gray) on a hierarchical element tree, with inline Fallow static analysis findings, embedded source code viewer, and temporal timeline navigation---all operating on a knowledge graph rather than flat test results.

Suggested claim language. "A user interface for architecture review comprising: a hierarchical element tree annotated with color-coded drift status indicators; inline display of static analysis findings from a code quality analyzer; an embedded source code viewer enabling navigation from element to source component; and a temporal timeline enabling playback of the application's structural evolution."

Claim 8: Unexplained Source Drift Detection

Prior art. Concept drift detection in data streams [@gama2014drift]. CodeScene identifies hotspots via version control analysis.

What is novel. Detecting "unexplained" drift: runtime behavior changes (DOM structure, visual appearance, API responses) that occur without corresponding source code commits in the linked repository. This signals either configuration changes, third-party dependency updates, or infrastructure drift---categories invisible to traditional source-code-only analysis.

Suggested claim language. "A method for detecting unexplained drift in web applications comprising: comparing a current application snapshot against a previous version stored in a knowledge graph; querying a linked source code repository for commits between the two snapshot timestamps; flagging any drift event for which no corresponding source code change exists as unexplained drift; and escalating unexplained drift events to a higher severity tier for human review."

Claim 9: Universal Scheduler for Multi-Category Quality Assurance Tasks

Prior art. Jenkins, GitHub Actions, and cron-based CI/CD systems provide general-purpose scheduling. ContentKing provides domain-specific monitoring schedules.

What is novel. A single scheduling surface within a QA platform that can schedule any registered skill---crawls, code reviews, security audits, accessibility scans, performance benchmarks, ticket sweeps---through one generic API and UI, backed by a category-agnostic database table and delegating execution to a workflow engine (trigger.dev). The novelty is the combination of (i) skill-registry-driven task resolution with (ii) a unified scheduling UI that replaces per-category scheduling code.

Suggested claim language. "A computer-implemented system for scheduling quality assurance tasks comprising: a skill registry mapping task types to execution configurations; a category-agnostic scheduled task table storing cron expressions, target references, and input parameters; a unified user interface enabling creation, modification, and monitoring of scheduled tasks across all registered skill categories; and delegation of execution to an external workflow engine via the skill registry resolution."

Claim 10: Code Quality Findings as First-Class Drift Signals

Prior art. SonarQube quality gates fail builds on threshold violations. Fallow detects dead code, duplication, and circular dependencies. Neither treats static analysis results as temporal drift events in an application blueprint.

What is novel. Treating static code analysis findings (dead code, duplication, circular dependencies, complexity hotspots, architecture boundary violations) as first-class drift signals in a living application blueprint. Each new finding generates a drift event with severity, temporal context (which commit introduced it), and remediation pathway (QA ticket creation feeding the 7-stage pipeline). The finding lifecycle (new, existing, resolved) is tracked bi-temporally alongside runtime drift events, enabling unified architecture health scoring.

Suggested claim language. "A method for integrating static code analysis with runtime application drift detection comprising: executing a static code analyzer against a source code repository at scheduled intervals; comparing analysis results against previously stored results to identify newly introduced findings; generating drift events for each new finding with drift type, severity, and originating commit; storing said drift events in the same knowledge graph repository as runtime drift events; and computing a unified architecture health score across both runtime and static analysis drift signals."

Evaluation Methodology and Future Work

Evaluation Metrics

We define five primary metrics for evaluating Living Blueprint's effectiveness:

Element Discovery Recall. Given a reference set of N_{} manually annotated elements for a web application, element discovery recall is:

R_{} = (/)

where DD is the set of elements discovered by Living Blueprint and GG is the ground-truth set. We report recall rather than precision because over-discovery (finding extra interactive elements) is preferable to under-discovery (missing elements that need testing).

Crawl Coverage. The fraction of reachable pages discovered during an initial onboarding crawl:

C_{} = (/)

The denominator is established by running a separate exhaustive crawl with unlimited depth and no URL budget as the ground truth.

Drift Detection Precision and Recall. For a labeled set of known changes (both genuine drifts and benign non-changes), we measure:

P_{} = (/), \quad R_{} = (/)

where TPTP is a correctly identified drift event, FPFP is a false alarm (e.g., non-deterministic content flagged as drift), and FNFN is a missed genuine change. The 5-layer comparison is specifically designed to minimize false positives: the content hash layer catches exact matches quickly, the DOM signature layer filters structural noise, and the visual AI layer classifies ambiguous cases.

Functional Intent Classification Accuracy. For elements with ground-truth functional labels (navigation, form input, display, action trigger, container, media), we measure classification accuracy and the accuracy gain from source-code augmentation:

Δ_{} = A_{} - A_{}

This metric directly evaluates the value of the github-manager source code knowledge graph integration.

Fallow Finding Delta Accuracy. For the code quality drift detection, we measure whether newly reported findings are genuine regressions (not pre-existing findings missed in the previous scan):

P_{} = (/)

Benchmark Design

Reference Websites. We construct a benchmark suite of 10 reference web applications spanning four categories:

  1. Static content sites (2): Marketing sites with minimal JavaScript, testing baseline crawl coverage and content hash drift.

  2. Single-page applications (3): React, Vue, and Angular SPAs with client-side routing, testing dynamic state exploration and DOM signature stability.

  3. Server-rendered applications (3): Next.js, Nuxt, and Rails applications with mixed rendering strategies, testing crawl completeness across hydration boundaries.

  4. Complex dashboards (2): Data-heavy applications with authenticated routes, infinite scroll, and WebSocket-driven updates, testing element discovery in adversarial UI patterns.

For each reference site, we prepare a ground-truth annotation: complete element inventory, functional intent labels, and a set of staged changes (introduced via controlled commits) that serve as the drift detection oracle.

Mobile Applications. Three reference mobile applications (1 iOS, 1 Android, 1 React Native) evaluate the cross-platform element normalization. Ground truth is established via manual accessibility tree annotation.

Scalability Testing. We evaluate performance across four scale tiers: small (100 pages, 500 elements), medium (1,000 pages, 5,000 elements), large (10,000 pages, 50,000 elements), and enterprise (100,000 pages, 500,000 elements). Metrics include crawl completion time, GraphRAG query latency at each scale, drift detection throughput (events per second), and Fallow analysis time as a function of repository size. The enterprise tier specifically tests the Bloom filter visited-set under high cardinality and the hash-partitioned blueprint_elements table under concurrent writes from batched crawl workers.

Experimental Protocol

Each benchmark run follows a three-phase protocol:

  1. Onboarding phase: Project creation, initial crawl, source code linking, Fallow baseline scan. Measure: crawl time, element count, coverage, Fallow finding count.

  2. Drift injection phase: Apply 20 controlled mutations per reference site (5 content changes, 5 structural changes, 5 source-only changes, 5 Fallow-detectable regressions). Trigger a re-crawl and Fallow re-scan. Measure: detection precision, recall, classification accuracy, latency.

  3. Steady-state phase: Run 30 consecutive daily crawl cycles with no injected changes, measuring false positive rate (the "noise floor" of the drift detector).

Future Work

Several directions extend the Living Blueprint architecture beyond the scope of this paper:

OpenAPI and Swagger Import. Automatically ingesting OpenAPI 3.x and Swagger 2.0 specifications as blueprint elements, enriching the application model with API contract definitions that complement the DOM-derived element inventory. This enables API drift detection (schema changes, deprecated endpoints, new required parameters) as a sixth comparison layer.

GraphQL Introspection. For applications exposing a GraphQL endpoint, schema introspection can discover types, queries, mutations, and subscriptions. These become blueprint entities with typed relationships to the UI components that consume them, enabling end-to-end traceability from UI element to data source.

Mobile App Store Monitoring. Extending the discovery engine to monitor iOS App Store and Google Play Store listings for published applications, detecting metadata drift (description changes, new permissions, version updates) and triggering re-verification crawls when a new version is detected.

CI/CD Pipeline Integration. Hooking into the deployment pipeline so that every deployment automatically triggers a targeted re-crawl of affected pages (identified via the source component map), rather than waiting for the next scheduled crawl. Combined with the Fallow SARIF integration, this enables pre-merge quality gates that block PRs introducing new dead code, circular dependencies, or complexity hotspots beyond configured thresholds.

Federated Blueprints. For organizations managing multiple interconnected applications (e.g., a marketing site, a dashboard, a mobile app, and an API gateway), federated blueprints would enable cross-application drift detection: a breaking change in the API gateway's response schema would surface as drift in both the dashboard and the mobile app's element inventories, providing a unified view of system-wide impact.

Reinforcement Learning for Crawl Prioritization. Applying reinforcement learning [@spieker2017rl] to optimize the URL exploration order during crawling, prioritizing paths that historically yield more discovered elements or higher drift rates, thereby reducing crawl time while maintaining coverage.

LLM-Driven Exploratory Test Synthesis. Leveraging the blueprint's functional intent classifications to automatically generate exploratory test scenarios---sequences of user interactions that exercise high-risk element combinations identified by the knowledge graph's relationship structure. Recent advances in LLM-based test generation [@schafer2024empirical; @lemieux2023codamosa] suggest that blueprint-informed prompting could significantly improve test coverage and fault detection rates compared to uninformed generation.

Keywords

living-blueprintai-native-qaautonomous-discoverydrift-detectionarchitecture-verificationfallowgraphragvibe-codingcode-qualitynexusqa