{"id":134,"date":"2026-03-13T23:59:28","date_gmt":"2026-03-13T23:59:28","guid":{"rendered":"https:\/\/dev.harmonic-framework.com\/whitepapers\/boundary-driven-testing\/"},"modified":"2026-03-14T01:19:12","modified_gmt":"2026-03-14T01:19:12","slug":"boundary-driven-testing","status":"publish","type":"page","link":"https:\/\/dev.harmonic-framework.com\/es\/whitepapers\/boundary-driven-testing\/","title":{"rendered":"Boundary-Driven Testing"},"content":{"rendered":"<p class=\"hf-reading-time\">Published March 2026<\/p>\n<h2 id=\"a-practitioner-oriented-articulation\">A Practitioner-Oriented Articulation<\/h2>\n<p><strong>Author:<\/strong> William Christopher Anderson<br \/>\n<strong>Date:<\/strong> March 2026<br \/>\n<strong>Version:<\/strong> 1.0<\/p>\n<hr \/>\n<h2 id=\"executive-summary\">Executive Summary<\/h2>\n<p>Testing difficulty is architectural evidence. When a component cannot be exercised in isolation, when a unit test requires a running database, when a change in one module breaks tests across a dozen others \u2014 the problem is not the tests. It is the structure that the tests are attempting to exercise. The component has no coherent boundary. Its responsibilities are distributed incorrectly. Its dependencies are hidden. Tests fail not because the code is wrong, but because the code was not organized to be observable or controllable in the first place.<\/p>\n<p>Boundary-Driven Testing is the observation that the test spiral \u2014 unit, integration, end-to-end, system, user acceptance \u2014 is not a testing methodology. It is an architectural map. Each ring of the spiral corresponds to a level of architectural scope, and that scope is determined entirely by where boundaries have been placed. Get the boundaries right and the spiral populates itself: each tier has clear targets, predictable scope, and low maintenance overhead. Get them wrong and the spiral collapses \u2014 unit tests become integration tests in disguise, E2E tests become the only reliable safety net, and the entire suite grows expensive while providing diminishing confidence.<\/p>\n<p>The structural models defined in <em>Volatility-Based Decomposition<\/em> and <em>Experience-Based Decomposition<\/em> produce boundaries that localize both change and test scope simultaneously. The same line that prevents coupling prevents test contamination. The same role taxonomy that makes components replaceable makes them mockable. The same core use cases that validate structural boundaries generate test scenarios across the full spiral. This is not a coincidence. It is the intended consequence of decomposing correctly.<\/p>\n<hr \/>\n<h2 id=\"abstract\">Abstract<\/h2>\n<p>The relationship between architectural structure and testability is direct and bidirectional: clear boundaries produce testable components, and testing difficulty reveals boundary problems. Boundary-Driven Testing articulates this relationship by mapping the test spiral onto the component role taxonomy defined in Volatility-Based Decomposition (VBD) and Experience-Based Decomposition (EBD). Each role \u2014 Manager, Engine, Resource Accessor, Utility at the system level; Experience, Flow, Interaction, Utility at the UX level \u2014 has a natural test profile determined by its responsibilities, permitted dependencies, and communication rules. Mock placement, test scope, and assertion strategy follow from structural position. The spiral is a structural mirror. Difficulty at any level of the spiral points to a specific class of boundary problem \u2014 and to the structural fix.<\/p>\n<hr \/>\n<h2 id=\"1-introduction\">1. Introduction<\/h2>\n<p>The conventional framing of testing as a discipline separate from design produces a particular kind of pain. Teams adopt frameworks, mandate coverage minimums, and write guidelines about what to test. The tests improve. The pain persists. A change to a business rule breaks seventeen tests, most of which are not about business rules. An integration test requires spinning up four services to assert one value. An end-to-end test passes in isolation and fails in CI for reasons nobody can reproduce. More coverage, more pain.<\/p>\n<p>The reframe is simple but consequential: <strong>testing is not separate from design.<\/strong> The structure of the system determines what can be tested and how. A component designed around a coherent responsibility, with explicit inputs, explicit outputs, and dependencies passed rather than acquired, is inherently testable. No additional effort is required to make it so. The same structural choices that allow the component to change without cascading effects allow it to be tested without elaborate setup.<\/p>\n<p>The inverse is equally true. A component that cannot be unit-tested without mocking half the system is not badly tested \u2014 it is badly structured. The test difficulty is diagnostic. It reveals that the component has absorbed responsibilities it should not have, or that its dependencies are implicit rather than declared, or that the boundary between it and its collaborators has been drawn in the wrong place. Fix the structure; the tests follow. Paper over the structure with more elaborate test scaffolding; the problem remains and compounds.<\/p>\n<p>Boundary-Driven Testing takes the diagnostic function of tests seriously. It maps the test spiral to the structural models defined in VBD and EBD, making explicit which components belong at which level of the spiral and why. It treats mock placement as architectural evidence \u2014 you mock at boundaries, and if you are mocking everywhere, you have too many boundaries or they are in the wrong places. And it articulates the consequence of correct decomposition: a test suite that is fast at the base, targeted in the middle, and confident at the top, maintained by the natural structure of the system rather than by constant manual curation.<\/p>\n<hr \/>\n<h2 id=\"2-the-spiral-is-a-structural-map\">2. The Spiral Is a Structural Map<\/h2>\n<p>The test spiral describes a progression from the narrowest to the broadest scope:<\/p>\n<ul>\n<li><strong>Unit<\/strong> \u2014 one component, all dependencies replaced. Fast, numerous, fine-grained.<\/li>\n<li><strong>Integration<\/strong> \u2014 component collaboration across one seam, with dependencies mocked at the outer boundary. Verifies that orchestration logic and contracts are wired correctly.<\/li>\n<li><strong>End-to-End<\/strong> \u2014 a complete user flow, full stack and browser. Verifies that the system behaves correctly from the outside.<\/li>\n<li><strong>System<\/strong> \u2014 the integrated system under realistic conditions: load, failure injection, configuration variation. Verifies non-functional qualities.<\/li>\n<li><strong>User Acceptance<\/strong> \u2014 real users or proxies confirm that what was built matches what was intended.<\/li>\n<\/ul>\n<p>The common reading of the spiral is proportional: many unit tests, fewer integration tests, fewer still E2E, and so on. This is a useful heuristic, but it obscures the more important principle. The spiral is not primarily about proportion \u2014 it is about scope. Unit scope is a single component. Integration scope is a collaboration across one boundary. E2E scope is a complete journey. System scope is the whole.<\/p>\n<p>Scope is determined by architecture. Where boundaries are placed determines what constitutes a &#8220;unit,&#8221; what constitutes an &#8220;integration,&#8221; and what constitutes a &#8220;journey.&#8221; In a system with no meaningful component boundaries, unit scope and system scope are the same thing \u2014 there is nothing below the full system that can be isolated. The spiral collapses into E2E by default, because E2E is the only level at which you can exercise anything coherent.<\/p>\n<p><em>Figure 1a shows the five levels of the spiral from narrowest to broadest scope. Figure 1b shows how each architectural tier attracts tests at a specific level.<\/em><\/p>\n<p><strong>Figure 1a \u2014 The Test Spiral<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    UNIT[\"Unit\"]\n    INT[\"Integration\"]\n    E2E[\"End-to-End\"]\n    SYS[\"System\"]\n    UAT[\"User Acceptance\"]\n\n    UNIT --> INT --> E2E --> SYS --> UAT\n\n<\/div><\/p>\n<p><strong>Figure 1b \u2014 Architectural Tier \u2192 Test Level<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    MGR[\"Manager \/ Experience\"]\n    ENG[\"Engine \/ Flow\"]\n    ACC[\"Resource Accessor\"]\n    UTL[\"Interaction\"]\n\n    MGR --> ENG\n    ENG --> ACC\n    ENG --> UTL\n\n<\/div><\/p>\n<hr \/>\n<h2 id=\"3-boundaries-determine-test-profiles\">3. Boundaries Determine Test Profiles<\/h2>\n<p>Each component role in VBD and EBD has a characteristic test profile \u2014 not assigned arbitrarily, but derived from the role&#8217;s structural position, responsibilities, and communication rules.<\/p>\n<h3 id=\"31-engines-the-unit-test-core\">3.1 Engines \u2014 The Unit Test Core<\/h3>\n<p>Engines are the most logic-dense tier and the natural home of the unit test suite. An Engine encapsulates business rules: given inputs, apply policy, produce a result. It has no workflow awareness, no sibling dependencies, and no reason to reach outward unless it needs data from a Resource Accessor \u2014 which it receives through an explicit, mockable interface.<\/p>\n<p>This is what makes Engines straightforwardly testable. Mock the Accessor, supply controlled inputs, assert on the output. The Engine&#8217;s communication constraints \u2014 no peer Engine calls, no direct infrastructure access \u2014 ensure there is nothing else to mock. The test scope is exactly the Engine and nothing more.<\/p>\n<p>For Flows in EBD the same principle applies. A Flow receives shared state from the Experience, steps through Interactions, makes a backend call, and emits a completion event. Mock the backend call, simulate Interaction events through a test harness, and assert on what the Flow emits. The Flow&#8217;s rule against calling sibling Flows means the unit scope stays tight.<\/p>\n<h3 id=\"32-resource-accessors-thin-boundary-minimal-unit-surface\">3.2 Resource Accessors \u2014 Thin Boundary, Minimal Unit Surface<\/h3>\n<p>Accessors sit at the system&#8217;s external boundary, and that position defines what they are responsible for testing \u2014 which is less than it might appear. An Accessor&#8217;s job is translation: convert a domain request into an external call, convert the response back. Whether the external system is reachable, whether it is correctly provisioned, whether it performs within acceptable bounds \u2014 none of these are Accessor concerns. They are infrastructure concerns, and they belong to system testing and deployment verification.<\/p>\n<p>If an Accessor contains meaningful translation or mapping logic, that logic can be unit tested by controlling the inputs and outputs through the Accessor&#8217;s own interface. But the Accessor has no business connecting to a real database in a unit or integration test. It either connects or it doesn&#8217;t \u2014 and that is a system-level fact, not a test target. The Accessor&#8217;s correctness is about the translation. The infrastructure&#8217;s correctness is about the infrastructure.<\/p>\n<h3 id=\"33-integration-tests-the-three-seams-that-matter\">3.3 Integration Tests \u2014 The Three Seams That Matter<\/h3>\n<p>Integration tests in a VBD system are not about any single component in isolation. They are about the <em>seams<\/em> between roles \u2014 verifying that the contracts components depend on are honored, and that orchestration logic matches the design. Everything is still mocked at the external boundary. Real external systems do not enter the picture until E2E.<\/p>\n<p>The distinction from unit tests is scope, not realism. A unit test exercises one component against mocked dependencies. An integration test exercises the <em>collaboration<\/em> between two components against mocked dependencies at the outer edge. You care whether the wiring is correct \u2014 not whether the database is running.<\/p>\n<p>There are three seams worth testing at this level:<\/p>\n<p><strong>Manager \u2192 Engine.<\/strong> Does the Manager invoke the Engine with the correct inputs? Does it handle every state the Engine&#8217;s contract can emit \u2014 success, domain failure, unexpected error \u2014 and route accordingly? The Engine is mocked. Feed it controlled responses representing each state it might return. Verify that the Manager&#8217;s orchestration logic handles all of them correctly. A mock Engine returning a validation failure is just as useful as a real one \u2014 what you are testing is the Manager&#8217;s response, not the Engine&#8217;s behavior.<\/p>\n<p><strong>Engine \u2192 Resource Accessor.<\/strong> Does the Engine correctly use the Accessor&#8217;s contract? Does it correctly interpret the states the Accessor can return? The Accessor is mocked. No database is involved. You are testing whether the Engine handles the Accessor&#8217;s interface correctly \u2014 not whether the Accessor connects to anything.<\/p>\n<p><strong>Manager \u2192 Resource Accessor.<\/strong> Managers sometimes interact with Accessors directly \u2014 for reads that inform orchestration decisions, or for state persistence the Manager owns. Test these paths the same way: mock the Accessor, exercise the Manager&#8217;s handling of every response state the Accessor&#8217;s contract defines.<\/p>\n<p>In EBD, the equivalent seam is Experience \u2192 Flow: does the Experience pass correct shared state, handle Flow completion and skip signals, and advance the journey correctly? The backend is mocked. You are verifying journey composition logic \u2014 not backend behavior.<\/p>\n<h3 id=\"34-interactions-and-utilities-narrow-and-fast\">3.4 Interactions and Utilities \u2014 Narrow and Fast<\/h3>\n<p>Interactions are atomic. They render, receive user input, and emit events. They carry no flow logic, make no API calls, and have no awareness of adjacent components. Component tests \u2014 render in a harness, simulate the input event, assert what was emitted \u2014 cover them completely and quickly. No mocks are typically needed; props and callbacks are the entire interface.<\/p>\n<p>Utilities are simpler still: inputs in, outputs out, no side effects. Given input X, assert output Y. The only exception is a Utility wrapping an external sink (a log transport, a telemetry exporter), where the sink gets mocked. Everything else is pure function territory.<\/p>\n<hr \/>\n<h2 id=\"4-mock-placement-is-architectural-evidence\">4. Mock Placement Is Architectural Evidence<\/h2>\n<p>Where you place mocks tells you where your boundaries are. Where you are forced to place mocks tells you where your boundaries should be.<\/p>\n<p>The rule is simple: mock at the role boundary, not inside the role. Each component role has one natural mock point \u2014 the interface at which it hands off to the next tier. Mock that interface and nothing else.<\/p>\n<p><em>Figure 2 shows where mocks belong at each test level. Each diagram is independent \u2014 together they cover the full VBD test surface.<\/em><\/p>\n<p><strong>Figure 2a \u2014 Engine unit test:<\/strong> mock the Resource Accessor, keep the Engine real.<\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    ENG[\"Engine (real)\"]\n    ACC[\"Resource Accessor (mock)\"]\n    ENG -->|\"calls\"| ACC\n\n<\/div><\/p>\n<p><strong>Figure 2b \u2014 Accessor unit test:<\/strong> mock the data source, keep the Accessor real.<\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    ACC[\"Resource Accessor (real)\"]\n    DS[\"Data Source Driver (mock)\"]\n    ACC -->|\"calls\"| DS\n\n<\/div><\/p>\n<p><strong>Figure 2c \u2014 Integration tests: the three seams.<\/strong> Each seam tests one collaboration. Dependencies at the outer edge are mocked \u2014 no real external systems.<\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    subgraph seam1[\"Seam 1 \u2014 Manager \u2192 Engine\"]\n        M1[\"Manager (real)\"] -->|\"invokes\"| E1[\"Engine (mock)\"]\n    end\n    subgraph seam2[\"Seam 2 \u2014 Engine \u2192 Resource Accessor\"]\n        E2[\"Engine (real)\"] -->|\"calls\"| A2[\"Resource Accessor (mock)\"]\n    end\n    subgraph seam3[\"Seam 3 \u2014 Manager \u2192 Resource Accessor\"]\n        M3[\"Manager (real)\"] -->|\"reads \/ persists\"| A3[\"Resource Accessor (mock)\"]\n    end\n\n<\/div><\/p>\n<p>When a unit test requires mocking more than the single boundary below the component under test, something is wrong. Either the component has absorbed responsibilities that belong at a different tier, or its dependencies are implicit rather than injected, or an Accessor is missing and the component is reaching directly into infrastructure it should not see. Mock proliferation is always a structural signal \u2014 not a testing problem, and not a problem that better mocking frameworks solve.<\/p>\n<p>The inverse is equally worth examining. An Engine or Flow unit test that requires no mocks is either genuinely pure-computation (rare and fine) or is only exercising the easy path through logic that silently delegates to collaborators the test never reaches. Coverage numbers tell you how many lines ran. They do not tell you whether the logic that matters was actually exercised.<\/p>\n<hr \/>\n<h2 id=\"5-the-same-scenarios-validate-architecture-and-tests\">5. The Same Scenarios Validate Architecture and Tests<\/h2>\n<p>VBD and EBD both use core scenarios as architectural validation mechanisms. A core use case in VBD \u2014 Process an order, Evaluate eligibility, Onboard a new customer \u2014 should be traceable through the component hierarchy without bypassing communication rules. A core user journey in EBD \u2014 Complete developer onboarding, Publish a prism, Discover a workspace \u2014 should trace through Experience \u2192 Flow \u2192 Interaction without boundary leakage.<\/p>\n<p>These scenarios are also the test scenarios that matter most. Not because coverage demands it, but because scenarios that validate structural boundaries naturally exercise the most load-bearing code paths, the most significant collaborations, and the most complete representations of what the system is actually for.<\/p>\n<p><em>Figures 3a, 3b, and 3c show the same order-processing scenario at three levels of the spiral. Each level asks a different question. Each has a different scope.<\/em><\/p>\n<p><strong>Figure 3a \u2014 Unit: each Engine in isolation<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'actorBkg': '#e0e7ff', 'actorBorder': '#4338ca', 'activationBkg': '#ede9fe', 'activationBorderColor': '#7c3aed', 'signalColor': '#4338ca', 'signalTextColor': '#1e293b', 'noteBkgColor': '#fef3c7', 'noteBorderColor': '#d97706', 'noteTextColor': '#1e293b'}}}%%\n\nsequenceDiagram\n    participant T as Test\n    participant VE as ValidationEngine\n    participant PE as PricingEngine\n\n    Note over T,VE: All Accessor dependencies mocked per Engine\n    T->>VE: validateOrder(missingField)\n    VE-->>T: ValidationFailure \u2713\n\n    T->>VE: validateOrder(validOrder)\n    VE-->>T: ValidationPass \u2713\n\n    T->>PE: calculatePrice(highVolumeOrder)\n    PE-->>T: PricedOrder(tierDiscount) \u2713\n\n    T->>PE: calculatePrice(promotionOrder)\n    PE-->>T: PricedOrder(promotionApplied) \u2713\n<\/div><\/p>\n<p><strong>Figure 3b \u2014 Integration: Manager orchestration with mocked dependencies<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'actorBkg': '#e0e7ff', 'actorBorder': '#4338ca', 'activationBkg': '#ede9fe', 'activationBorderColor': '#7c3aed', 'signalColor': '#4338ca', 'signalTextColor': '#1e293b', 'noteBkgColor': '#fef3c7', 'noteBorderColor': '#d97706', 'noteTextColor': '#1e293b'}}}%%\n\nsequenceDiagram\n    participant T as Test\n    participant OM as OrderManager\n    participant VE as ValidationEngine\n    participant PE as PricingEngine\n    participant OR as OrderRepository\n\n    Note over VE,OR: All mocked \u2014 return controlled contract states\n\n    Note over T,OM: Path 1 \u2014 validation failure\n    T->>OM: submitOrder(invalidOrder)\n    OM->>VE: validate(order)\n    VE-->>OM: ValidationFailure\n    OM-->>T: Rejected \u2014 PE and OR never called \u2713\n\n    Note over T,OM: Path 2 \u2014 happy path\n    T->>OM: submitOrder(validOrder)\n    OM->>VE: validate(order)\n    VE-->>OM: ValidationPass\n    OM->>PE: calculatePrice(order)\n    PE-->>OM: PricedOrder\n    OM->>OR: saveOrder(pricedOrder)\n    OR-->>OM: orderId\n    OM-->>T: OrderConfirmation \u2713\n<\/div><\/p>\n<p><strong>Figure 3c \u2014 E2E: full stack, real systems<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'actorBkg': '#e0e7ff', 'actorBorder': '#4338ca', 'activationBkg': '#ede9fe', 'activationBorderColor': '#7c3aed', 'signalColor': '#4338ca', 'signalTextColor': '#1e293b', 'noteBkgColor': '#fef3c7', 'noteBorderColor': '#d97706', 'noteTextColor': '#1e293b'}}}%%\n\nsequenceDiagram\n    actor User\n    participant API as API Endpoint\n    participant OM as OrderManager\n    participant VE as ValidationEngine\n    participant PE as PricingEngine\n    participant OR as OrderRepository\n\n    Note over User,OR: No mocks \u2014 real stack, real data store\n    User->>API: POST \/orders\n    API->>OM: submitOrder(request)\n    OM->>VE: validate(order)\n    VE-->>OM: ValidationPass\n    OM->>PE: calculatePrice(order)\n    PE-->>OM: PricedOrder\n    OM->>OR: saveOrder(pricedOrder)\n    OR-->>OM: orderId\n    OM-->>API: OrderConfirmation\n    API-->>User: 201 Created\n    Note over User: Assert order visible in downstream system \u2713\n<\/div><\/p>\n<p>The same scenario, three questions:<\/p>\n<ul>\n<li><strong>Unit<\/strong> \u2014 Does ValidationEngine correctly reject a missing field? Does PricingEngine apply the right discount? One Engine, all its rule branches, mocks for anything it depends on.<\/li>\n<li><strong>Integration<\/strong> \u2014 Does OrderManager route correctly when validation fails? Does it call the right dependencies in the right order when it succeeds? Engines and Accessor are mocked \u2014 you are testing the Manager&#8217;s orchestration logic against every contract state its dependencies can emit.<\/li>\n<li><strong>End-to-End<\/strong> \u2014 Does an order submitted through the real API surface in the system correctly? No mocks. Real behavior, real infrastructure, real assertion.<\/li>\n<li><strong>User Acceptance<\/strong> \u2014 Does a stakeholder placing an order through the application experience the outcome they expected?<\/li>\n<\/ul>\n<p>Each level asks a different question about the same scenario. Each question corresponds to a structural scope. The test suite is not organized around coverage targets \u2014 it is organized around the architecture.<\/p>\n<p>When a scenario cannot be cleanly decomposed this way \u2014 when the unit tests would require mocking the Manager, or the integration tests have no obvious boundary to stop at \u2014 the scenario is exposing an architectural gap. The fix is structural. Tests that are uncomfortable to write at a given level signal that the corresponding structural tier is missing or muddled.<\/p>\n<hr \/>\n<h2 id=\"6-uat-validates-what-architecture-validated-first\">6. UAT Validates What Architecture Validated First<\/h2>\n<p>User acceptance testing is often treated as a separate world from the structural concerns of the preceding spiral levels. Stakeholders exercise the system. They are not concerned with Managers, Engines, or Flows. They care whether the product works as intended.<\/p>\n<p>But the core user journeys that structure EBD \u2014 and the core use cases that structure VBD \u2014 are precisely the scenarios that UAT exercises. The developer onboarding journey that validates EBD structural boundaries is the same journey that a UAT participant walks through. The order processing scenario that exercises VBD communication rules is the same scenario a business stakeholder confirms in acceptance.<\/p>\n<p>This alignment is not accidental. Both architectural validation and UAT begin from the same question: does the system fulfill its core purpose correctly? Architectural validation asks it structurally \u2014 can this scenario be traced without boundary violations? UAT asks it experientially \u2014 does this scenario produce the correct outcome for a real user?<\/p>\n<p>When the architecture is sound, the answers converge. Structural boundaries support real journeys without friction. UAT scenarios map cleanly onto the E2E scenarios that confirm those journeys in the automated suite. The test spiral closes: the same scenarios that entered at the unit level \u2014 as isolated assertions on Engine logic \u2014 emerge at the UAT level as confirmed product behavior.<\/p>\n<p>When they diverge \u2014 when UAT surfaces scenarios that have no corresponding structural representation, or when E2E tests cover journeys that no stakeholder actually cares about \u2014 both the tests and the architecture need reexamination.<\/p>\n<hr \/>\n<h2 id=\"7-diagnostic-signals\">7. Diagnostic Signals<\/h2>\n<p>Testing difficulty is a signal. The nature of the difficulty points to the specific structural problem.<\/p>\n<p><strong>Mock proliferation<\/strong> \u2014 a unit test mocking more than one or two dependencies is usually exercising something that spans too many concerns. The component should be decomposed, or its dependencies should be consolidated behind a single interface.<\/p>\n<p><strong>Slow unit tests<\/strong> \u2014 unit tests that require real I\/O (network, filesystem, database) are not unit tests. Something that should be an Accessor is embedded in an Engine or Flow. Extract it.<\/p>\n<p><strong>Brittle E2E tests<\/strong> \u2014 E2E tests that break for reasons unrelated to user-visible behavior are coupled to implementation detail. Either the test is asserting on internal component state (stop), or the flow being tested has no stable boundary (fix the architecture).<\/p>\n<p><strong>Inverted pyramid<\/strong> \u2014 when the E2E suite is larger than the unit suite because unit tests cannot cover meaningful scenarios, the unit-testable tiers (Engines, Flows) contain less logic than they should. Business logic has migrated into Managers or Accessors.<\/p>\n<p><strong>UAT surprises<\/strong> \u2014 when UAT surfaces behaviors that no automated test predicted, either the core scenario set is incomplete or the structural model does not reflect how the product is actually used. Both are architectural discoveries, not testing failures.<\/p>\n<hr \/>\n<h2 id=\"7a-practitioner-observations\">7A. Practitioner Observations<\/h2>\n<p>The following observations emerge from applying Boundary-Driven Testing across multiple systems of varying scale and domain. They are not prescriptive rules but recurring patterns \u2014 structural phenomena that practitioners encounter once the spiral is treated as an architectural map rather than a coverage checklist.<\/p>\n<h3 id=\"the-test-migration-pattern\">The Test Migration Pattern<\/h3>\n<p>When architecture improves \u2014 when an Engine is extracted from a Manager, or an Accessor is separated from inline infrastructure calls \u2014 tests naturally migrate from integration scope to unit scope. Logic that previously could only be exercised through the Manager&#8217;s orchestration can now be tested directly against the extracted Engine. The test count at each spiral level is therefore a leading indicator of structural health. A system with a growing unit test count and a shrinking integration test count is decomposing correctly: logic is moving into testable tiers. A system where unit tests plateau while integration tests multiply is accumulating orchestration logic in the wrong places. Tracking this ratio over time reveals architectural trajectory more reliably than any static metric.<\/p>\n<h3 id=\"the-mock-boundary-audit\">The Mock Boundary Audit<\/h3>\n<p>Periodically reviewing where mocks are placed across the test suite reveals architectural drift before it becomes visible in production behavior. When a unit test that once required a single mock \u2014 the Accessor interface below the Engine \u2014 now requires three mocks, a boundary has leaked. The Engine has acquired a dependency it should not have, or a new collaborator has been introduced without going through the established interface. The audit is mechanical: list every mock in every unit test, group by component under test, and compare to the expected mock count for that component&#8217;s role. Engines should mock Accessors. Managers should mock Engines and Accessors. Utilities should mock nothing or at most one external sink. Deviations from this pattern are not judgment calls \u2014 they are structural findings that point to specific refactoring targets.<\/p>\n<h3 id=\"the-e2e-stability-correlation\">The E2E Stability Correlation<\/h3>\n<p>E2E test stability correlates directly with Experience and Manager stability. When E2E tests become flaky \u2014 passing on one run, failing on the next, sensitive to timing or environment \u2014 the instability almost always traces to the orchestration tier rather than to infrastructure. The Manager or Experience is making decisions that depend on transient state, or it is sequencing operations in a way that is sensitive to timing that unit and integration tests never exercise. Stable Managers produce stable E2E tests. When E2E flakiness spikes, the first diagnostic step is not to add retries or increase timeouts \u2014 it is to examine what changed in the orchestration layer. The E2E suite is a Manager health monitor.<\/p>\n<h3 id=\"the-coverage-paradox\">The Coverage Paradox<\/h3>\n<p>Teams with high line coverage but poor boundary coverage consistently have worse defect rates than teams with moderate line coverage and strong boundary coverage. The explanation is structural: line coverage rewards exercising code paths, but many code paths are internal to a component and exercise only the easy branches. Boundary coverage \u2014 ensuring that every contract state a dependency can emit is handled by the caller \u2014 exercises the load-bearing logic: error handling, fallback paths, state transitions that only occur when a collaborator returns something unexpected. A team at 90% line coverage that never tests what happens when the Accessor returns a timeout has covered the lines but missed the boundary. A team at 65% line coverage that tests every Accessor contract state \u2014 success, not-found, timeout, malformed response \u2014 has covered less code but exercised far more of what matters. What matters is exercising contract states, not line counts.<\/p>\n<h3 id=\"accelerated-test-review\">Accelerated Test Review<\/h3>\n<p>BDT makes test review faster and more consistent because reviewers have a structural question to ask rather than a subjective one. Instead of evaluating whether &#8220;enough&#8221; is tested or whether the test &#8220;looks right,&#8221; a reviewer checks that the test targets the correct spiral level for the component&#8217;s role. Is this an Engine? Then the test should be a unit test with mocked Accessors. Is this a Manager? Then the test should be an integration test exercising orchestration against mocked Engines. Is this a new E2E scenario? Then it should trace a complete user journey through the real stack. The review question shifts from &#8220;is this a good test?&#8221; to &#8220;is this test at the right level?&#8221; \u2014 a question with a definitive answer derived from the component&#8217;s structural position. Review time drops because the evaluation criteria are objective.<\/p>\n<h3 id=\"natural-ci-pipeline-mapping\">Natural CI Pipeline Mapping<\/h3>\n<p>BDT interacts with CI pipelines by providing a principled mapping between spiral levels and pipeline stages. Unit tests run on every commit \u2014 they are fast, numerous, and catch logic regressions immediately. Integration tests run on pull request \u2014 they verify that the collaboration contracts between components are intact before code enters the shared branch. E2E tests run on merge to main \u2014 they confirm that the full system behaves correctly before deployment. System tests run in staging \u2014 they exercise non-functional qualities under realistic conditions. The spiral maps to the pipeline stages naturally because each stage has a different latency tolerance and a different confidence target. Teams that adopt BDT often find that their pipeline stage definitions, which previously felt arbitrary, now have a structural justification: each stage corresponds to a scope, and each scope corresponds to a tier.<\/p>\n<h3 id=\"the-diagnostic-cascade\">The Diagnostic Cascade<\/h3>\n<p>A failing E2E test should be reproducible as a failing integration test at one specific seam. If it is, the defect is localized: the collaboration between two components at that seam is broken, and the integration test pinpoints which contract state is mishandled. If it is not \u2014 if the E2E test fails but all integration tests pass \u2014 then one of two things is true. Either the E2E test is coupled to implementation detail that no integration test targets (the test is wrong), or the integration test suite is missing a contract state that the real system exercises (the suite is incomplete). The diagnostic cascade \u2014 E2E failure, then integration reproduction, then unit isolation \u2014 is how BDT converts a symptom into a structural finding. Each level of the cascade narrows the scope. A defect that survives to E2E without appearing at integration is always an architectural discovery about a missing seam or an untested contract state.<\/p>\n<h3 id=\"the-refactor-safety-observation\">The Refactor Safety Observation<\/h3>\n<p>When a system is structured according to VBD and tested according to BDT, internal refactoring within a component \u2014 changing how an Engine computes a result, optimizing an Accessor&#8217;s query strategy, restructuring a Manager&#8217;s orchestration sequence \u2014 is protected by the correct test level automatically. Refactoring an Engine&#8217;s internals is covered by its unit tests. Changing an Accessor&#8217;s implementation is covered by its unit tests against the mocked data source. Altering a Manager&#8217;s orchestration sequence is covered by its integration tests against mocked Engines. The key observation is that tests at the boundary do not care about internal restructuring \u2014 they care about the contract. This means that well-placed boundary tests provide refactoring confidence without requiring test updates for internal changes. When a refactor requires updating tests at multiple spiral levels, it is not a refactor \u2014 it is a contract change, and the test updates are the correct response.<\/p>\n<hr \/>\n<h2 id=\"8-conclusion\">8. Conclusion<\/h2>\n<p>The spiral is not a burden. It is a reflection.<\/p>\n<p>A correctly decomposed system \u2014 one where Engines contain logic and Accessors contain I\/O and Managers contain orchestration and Utilities contain nothing domain-specific \u2014 produces a test suite that follows naturally from its structure. Unit tests are fast because Engines and Flows have no hidden dependencies. Integration tests are targeted because Accessors have narrow, stable interfaces. E2E tests are confident because Experiences and Managers represent complete, semantically meaningful journeys. UAT aligns because those journeys were designed to represent actual human purpose.<\/p>\n<p>The work of creating a good test suite is mostly the work of creating a good architecture. The spiral does not impose additional design constraints \u2014 it reads off the constraints already imposed by correct decomposition. When those constraints are satisfied, testing is an expression of the structure. When they are violated, testing is a fight against it.<\/p>\n<p>Boundary-Driven Testing names that relationship precisely. Boundaries determine test scope. Boundaries define mock points. Boundaries generate test profiles. Fix the boundaries and the spiral follows.<\/p>\n<hr \/>\n<h2 id=\"appendix-a-glossary\">Appendix A: Glossary<\/h2>\n<p><strong>Architecturally Significant Boundary<\/strong> \u2014 A seam between components with distinct roles, such as Engine-Accessor or Flow-API Accessor. The correct and stable placement for test doubles.<\/p>\n<p><strong>Boundary-Driven Testing<\/strong> \u2014 A test strategy in which architectural boundaries between component roles determine test scope, mock placement, and assertion targets. Derived from VBD\/EBD decomposition rather than imposed as an external testing framework.<\/p>\n<p><strong>Contract State<\/strong> \u2014 The set of possible return types a component can emit across its boundary, including success values, domain errors, and infrastructure failures. Tests must exercise every contract state to ensure the caller handles all outcomes.<\/p>\n<p><strong>Controllability<\/strong> \u2014 The ability to place a component into a known state without invoking the full system. Required for isolation.<\/p>\n<p><strong>End-to-End Test<\/strong> \u2014 A test that exercises a full user-visible journey through the real stack with no mocks. In BDT, E2E tests target Manager and Experience components to verify that assembled paths produce correct outcomes against live dependencies.<\/p>\n<p><strong>Integration Test<\/strong> \u2014 A test that verifies coordination between components at the Manager or Experience level, with dependencies mocked at the outer architectural boundary. In BDT, integration tests confirm that orchestration wiring matches the intended design.<\/p>\n<p><strong>Inverted Pyramid<\/strong> \u2014 A test suite dominated by E2E tests because unit and integration tests cannot exercise meaningful behavior. A structural indicator of misplaced boundaries, not a testing indicator.<\/p>\n<p><strong>Mock<\/strong> \u2014 A test double placed at an architecturally significant boundary to isolate the component under test from its dependencies. In BDT, mocks are positioned exclusively at role boundaries, not at arbitrary internal call sites.<\/p>\n<p><strong>Mock Proliferation<\/strong> \u2014 A test requiring many simultaneous mocks. A signal that the component crosses too many boundaries or has absorbed too many responsibilities.<\/p>\n<p><strong>Observability<\/strong> \u2014 The ability to determine what a component did given controlled inputs. Required for meaningful assertion.<\/p>\n<p><strong>Refactoring Confidence<\/strong> \u2014 The assurance that internal changes to a component are safe so long as its boundary tests continue to pass. BDT provides this by anchoring tests to stable architectural seams rather than internal implementation details.<\/p>\n<p><strong>Seam<\/strong> \u2014 The point between two component roles where a mock is placed during testing. Seams exist at architecturally significant boundaries and represent the natural isolation surface for test doubles.<\/p>\n<p><strong>Structural Signal<\/strong> \u2014 Testing difficulty \u2014 such as excessive mocking, brittle assertions, or unclear scope \u2014 that reveals architectural misalignment rather than a testing tooling problem. BDT treats these signals as prompts to fix boundaries, not tests.<\/p>\n<p><strong>System Test<\/strong> \u2014 A test that targets non-functional qualities such as resilience, performance, and deployment correctness. System tests use failure injection, load generation, and configuration variation against the full assembled system.<\/p>\n<p><strong>Test Profile<\/strong> \u2014 The characteristic test shape of a component role, specifying what is tested, what is mocked, and what is asserted. Each VBD\/EBD role (Engine, Accessor, Manager, Utility, etc.) has a distinct test profile determined by its boundary relationships.<\/p>\n<p><strong>Test Spiral<\/strong> \u2014 A progression of test scope from unit through integration, end-to-end, system, and user acceptance. Each level corresponds to a level of architectural scope, and the spiral shape emerges naturally from correct boundary placement.<\/p>\n<p><strong>Unit Test<\/strong> \u2014 A test that exercises the internal logic of a single component \u2014 typically an Engine, Flow, or Utility \u2014 with all dependencies mocked at their architectural boundaries. In BDT, unit tests verify logic correctness and full contract-state coverage.<\/p>\n<p><strong>User Acceptance Test<\/strong> \u2014 A test performed by real users against the live system to verify that core journeys fulfill business intent. UATs use no mocks and validate that the system delivers actual value, not just technical correctness.<\/p>\n<hr \/>\n<h2 id=\"appendix-b-bdt-at-a-glance\">Appendix B: BDT at a Glance<\/h2>\n<table>\n<thead>\n<tr>\n<th>Spiral Level<\/th>\n<th>Primary Structural Target<\/th>\n<th>Mock Strategy<\/th>\n<th>Assertion Scope<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Unit<\/td>\n<td>Engine \u00b7 Flow \u00b7 Utility \u00b7 Interaction<\/td>\n<td>Mock all dependencies through their contracts<\/td>\n<td>Logic correctness; all contract states handled<\/td>\n<\/tr>\n<tr>\n<td>Integration<\/td>\n<td>Manager \u00b7 Experience coordination<\/td>\n<td>Mock at outer boundary; dependencies return controlled contract states<\/td>\n<td>Collaboration wiring; orchestration matches design<\/td>\n<\/tr>\n<tr>\n<td>End-to-End<\/td>\n<td>Manager \u00b7 Experience<\/td>\n<td>No mocks; full stack; real external systems<\/td>\n<td>User-visible outcome; journey completion<\/td>\n<\/tr>\n<tr>\n<td>System<\/td>\n<td>Full system<\/td>\n<td>Failure injection; load; configuration variation<\/td>\n<td>Non-functional qualities; resilience; deployment correctness<\/td>\n<\/tr>\n<tr>\n<td>UAT<\/td>\n<td>Core use case \/ Core user journey<\/td>\n<td>None (real users)<\/td>\n<td>Business intent fulfilled<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr \/>\n<h2 id=\"appendix-c-case-study-e-commerce-order-processing\">Appendix C: Case Study \u2014 E-Commerce Order Processing<\/h2>\n<p>This appendix presents a fictional but structurally realistic example of BDT applied to an e-commerce order processing system. The architecture follows VBD role assignments. The test suite follows the spiral. The example demonstrates how boundary placement determines test scope, mock strategy, and maintenance cost \u2014 and how adding a new capability requires minimal test changes when the boundaries are correct.<\/p>\n<h3 id=\"c1-system-architecture\">C.1 System Architecture<\/h3>\n<p>The order processing system is decomposed into the following components:<\/p>\n<ul>\n<li><strong>OrderManager<\/strong> \u2014 orchestrates the order lifecycle: validates, prices, checks inventory, processes payment, persists, and notifies. Contains no business logic. Sequences Engine calls and handles cross-cutting routing.<\/li>\n<li><strong>ValidationEngine<\/strong> \u2014 applies order validation rules: required fields, item availability constraints, customer eligibility, promotion expiration.<\/li>\n<li><strong>PricingEngine<\/strong> \u2014 calculates order totals: base pricing, volume discounts, promotional codes, tax computation, currency handling.<\/li>\n<li><strong>InventoryEngine<\/strong> \u2014 determines fulfillment feasibility: stock checks, reservation logic, partial fulfillment decisions, backorder policy.<\/li>\n<li><strong>OrderRepositoryAccessor<\/strong> \u2014 translates domain order objects to and from the persistent store. Handles serialization, query construction, and connection management.<\/li>\n<li><strong>PaymentGatewayAccessor<\/strong> \u2014 translates payment requests into gateway-specific API calls. Handles authentication, request formatting, response parsing, and error translation.<\/li>\n<li><strong>NotificationAccessor<\/strong> \u2014 translates notification requests into delivery channel calls (email, SMS, push). Handles template selection and delivery confirmation.<\/li>\n<li><strong>LoggingUtility<\/strong> \u2014 structured log emission. Pure sink: accepts log entries, formats them, writes to the configured transport. No domain awareness.<\/li>\n<\/ul>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    subgraph manager[\"Manager Tier\"]\n        OM[\"OrderManager\"]\n    end\n\n    subgraph engines[\"Engine Tier\"]\n        VE[\"ValidationEngine\"]\n        PE[\"PricingEngine\"]\n        IE[\"InventoryEngine\"]\n    end\n\n    subgraph accessors[\"Accessor Tier\"]\n        ORA[\"OrderRepositoryAccessor\"]\n        PGA[\"PaymentGatewayAccessor\"]\n        NA[\"NotificationAccessor\"]\n    end\n\n    subgraph utilities[\"Utility Tier\"]\n        LU[\"LoggingUtility\"]\n    end\n\n    OM --> VE\n    OM --> PE\n    OM --> IE\n    OM --> ORA\n    OM --> PGA\n    OM --> NA\n    VE --> ORA\n    PE --> ORA\n    IE --> ORA\n    OM --> LU\n\n<\/div><\/p>\n<h3 id=\"c2-unit-test-suite\">C.2 Unit Test Suite<\/h3>\n<p>Each Engine is tested in isolation. Accessors below each Engine are mocked. The tests exercise every branch of the Engine&#8217;s logic by controlling the inputs and the mock responses.<\/p>\n<h4 id=\"validationengine-unit-tests\">ValidationEngine Unit Tests<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Input<\/th>\n<th>Mock Setup<\/th>\n<th>Expected Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Missing required field (customer email)<\/td>\n<td>Order with null email<\/td>\n<td>None needed<\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;missing_required_field&quot;, &quot;email&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Empty line items<\/td>\n<td>Order with zero items<\/td>\n<td>None needed<\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;empty_order&quot;, null)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Expired promotional code<\/td>\n<td>Order with promo code &#8220;SUMMER2025&#8221;<\/td>\n<td>OrderRepositoryAccessor returns promo with <code class=\"\" data-line=\"\">expires: 2025-09-01<\/code><\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;expired_promotion&quot;, &quot;SUMMER2025&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Out-of-stock item (validation-level check)<\/td>\n<td>Order with item SKU-9912<\/td>\n<td>OrderRepositoryAccessor returns <code class=\"\" data-line=\"\">stock_count: 0<\/code> for SKU-9912<\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;item_unavailable&quot;, &quot;SKU-9912&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Customer account suspended<\/td>\n<td>Order with customer ID 4401<\/td>\n<td>OrderRepositoryAccessor returns customer with <code class=\"\" data-line=\"\">status: suspended<\/code><\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;customer_ineligible&quot;, &quot;account_suspended&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Valid order, all checks pass<\/td>\n<td>Complete order, all fields present<\/td>\n<td>OrderRepositoryAccessor returns valid promo, positive stock, active customer<\/td>\n<td><code class=\"\" data-line=\"\">ValidationPass(order)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"pricingengine-unit-tests\">PricingEngine Unit Tests<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Input<\/th>\n<th>Mock Setup<\/th>\n<th>Expected Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Volume discount threshold (100+ units)<\/td>\n<td>Order with 150 units of SKU-1001<\/td>\n<td>OrderRepositoryAccessor returns tier pricing: 100+ at 15% discount<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(discount_applied: &quot;volume_15pct&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Promotional code (percentage)<\/td>\n<td>Order with promo &#8220;SAVE20&#8221;<\/td>\n<td>OrderRepositoryAccessor returns promo: 20% off, no exclusions<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(promo_applied: &quot;SAVE20&quot;, discount: 20%)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Promotional code with exclusion<\/td>\n<td>Order with promo &#8220;SAVE20&#8221;, item in exclusion list<\/td>\n<td>OrderRepositoryAccessor returns promo with exclusion list containing item SKU<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(promo_applied: null, exclusion_reason: &quot;item_excluded&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Tax calculation (multi-jurisdiction)<\/td>\n<td>Order shipping to CA<\/td>\n<td>OrderRepositoryAccessor returns CA tax rate 8.25%<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(tax_rate: 8.25%, tax_amount: computed)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Combined volume + promo (stacking rules)<\/td>\n<td>150 units with promo &#8220;SAVE20&#8221;<\/td>\n<td>OrderRepositoryAccessor returns stacking policy: &#8220;best_single&#8221;<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(discount_applied: &quot;volume_15pct&quot;, stacking: &quot;best_single_applied&quot;)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Zero-cost order (full discount)<\/td>\n<td>Order fully covered by store credit<\/td>\n<td>None needed<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(total: 0.00, payment_required: false)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"inventoryengine-unit-tests\">InventoryEngine Unit Tests<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Input<\/th>\n<th>Mock Setup<\/th>\n<th>Expected Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Full stock available<\/td>\n<td>Order for 10 units, 50 in stock<\/td>\n<td>OrderRepositoryAccessor returns <code class=\"\" data-line=\"\">available: 50<\/code><\/td>\n<td><code class=\"\" data-line=\"\">InventoryReserved(full, reservation_id)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Partial stock, backorder allowed<\/td>\n<td>Order for 10 units, 3 in stock<\/td>\n<td>OrderRepositoryAccessor returns <code class=\"\" data-line=\"\">available: 3<\/code>, backorder policy: allowed<\/td>\n<td><code class=\"\" data-line=\"\">InventoryPartial(available: 3, backordered: 7, reservation_id)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Partial stock, backorder disallowed<\/td>\n<td>Order for 10 units, 3 in stock<\/td>\n<td>OrderRepositoryAccessor returns <code class=\"\" data-line=\"\">available: 3<\/code>, backorder policy: disallowed<\/td>\n<td><code class=\"\" data-line=\"\">InventoryInsufficient(available: 3, required: 10)<\/code><\/td>\n<\/tr>\n<tr>\n<td>Multi-item reservation (atomic)<\/td>\n<td>Order for 3 SKUs<\/td>\n<td>OrderRepositoryAccessor returns stock for all 3<\/td>\n<td><code class=\"\" data-line=\"\">InventoryReserved(full, reservation_ids: [r1, r2, r3])<\/code><\/td>\n<\/tr>\n<tr>\n<td>Reservation timeout recovery<\/td>\n<td>Order for 10 units<\/td>\n<td>OrderRepositoryAccessor returns reservation then timeout on confirm<\/td>\n<td><code class=\"\" data-line=\"\">InventoryError(&quot;reservation_timeout&quot;, reservation_id)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Mock placement for all Engine unit tests:<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    subgraph unit_scope[\"Unit Test Scope\"]\n        VE[\"ValidationEngine (real)\"]\n        PE[\"PricingEngine (real)\"]\n        IE[\"InventoryEngine (real)\"]\n    end\n\n    subgraph mocked[\"Mocked at Boundary\"]\n        ORA[\"OrderRepositoryAccessor (mock)\"]\n    end\n\n    VE -->|\"reads\"| ORA\n    PE -->|\"reads\"| ORA\n    IE -->|\"reads\/writes\"| ORA\n\n<\/div><\/p>\n<h3 id=\"c3-integration-test-suite\">C.3 Integration Test Suite<\/h3>\n<p>Integration tests exercise the seams between tiers. Each seam is tested with the caller real and the callee mocked, returning controlled contract states. The question is not whether the callee works \u2014 that is answered by its unit tests \u2014 but whether the caller handles every state the callee can emit.<\/p>\n<h4 id=\"seam-ordermanager-to-validationengine\">Seam: OrderManager to ValidationEngine<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Mock Response from ValidationEngine<\/th>\n<th>Expected Manager Behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Validation passes<\/td>\n<td><code class=\"\" data-line=\"\">ValidationPass(order)<\/code><\/td>\n<td>Manager proceeds to PricingEngine<\/td>\n<\/tr>\n<tr>\n<td>Validation fails (missing field)<\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;missing_required_field&quot;, &quot;email&quot;)<\/code><\/td>\n<td>Manager returns rejection, no downstream calls made<\/td>\n<\/tr>\n<tr>\n<td>Validation fails mid-order (concurrent modification)<\/td>\n<td><code class=\"\" data-line=\"\">ValidationFailure(&quot;order_modified_concurrently&quot;, order_id)<\/code><\/td>\n<td>Manager returns conflict error, logs warning, no payment attempted<\/td>\n<\/tr>\n<tr>\n<td>ValidationEngine throws unexpected error<\/td>\n<td><code class=\"\" data-line=\"\">RuntimeException(&quot;database_unavailable&quot;)<\/code><\/td>\n<td>Manager returns system error, logs critical, no downstream calls<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"seam-ordermanager-to-pricingengine\">Seam: OrderManager to PricingEngine<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Mock Response from PricingEngine<\/th>\n<th>Expected Manager Behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Pricing succeeds<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(total: 142.50)<\/code><\/td>\n<td>Manager proceeds to InventoryEngine<\/td>\n<\/tr>\n<tr>\n<td>Pricing returns zero total<\/td>\n<td><code class=\"\" data-line=\"\">PricedOrder(total: 0.00, payment_required: false)<\/code><\/td>\n<td>Manager skips PaymentGatewayAccessor, proceeds to persist<\/td>\n<\/tr>\n<tr>\n<td>PricingEngine returns error<\/td>\n<td><code class=\"\" data-line=\"\">PricingError(&quot;tax_service_unavailable&quot;)<\/code><\/td>\n<td>Manager returns pricing failure, no inventory reservation attempted<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"seam-ordermanager-to-inventoryengine\">Seam: OrderManager to InventoryEngine<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Mock Response from InventoryEngine<\/th>\n<th>Expected Manager Behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Full inventory reserved<\/td>\n<td><code class=\"\" data-line=\"\">InventoryReserved(full, reservation_id)<\/code><\/td>\n<td>Manager proceeds to payment<\/td>\n<\/tr>\n<tr>\n<td>Partial inventory, backorder<\/td>\n<td><code class=\"\" data-line=\"\">InventoryPartial(available: 3, backordered: 7)<\/code><\/td>\n<td>Manager proceeds to payment with adjusted total, notifies customer of partial fulfillment<\/td>\n<\/tr>\n<tr>\n<td>Inventory insufficient<\/td>\n<td><code class=\"\" data-line=\"\">InventoryInsufficient(available: 3, required: 10)<\/code><\/td>\n<td>Manager returns inventory failure, no payment attempted<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"seam-ordermanager-to-paymentgatewayaccessor\">Seam: OrderManager to PaymentGatewayAccessor<\/h4>\n<table>\n<thead>\n<tr>\n<th>Test Scenario<\/th>\n<th>Mock Response from PaymentGatewayAccessor<\/th>\n<th>Expected Manager Behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Payment authorized<\/td>\n<td><code class=\"\" data-line=\"\">PaymentAuthorized(transaction_id)<\/code><\/td>\n<td>Manager persists order, sends confirmation notification<\/td>\n<\/tr>\n<tr>\n<td>Payment declined<\/td>\n<td><code class=\"\" data-line=\"\">PaymentDeclined(&quot;insufficient_funds&quot;)<\/code><\/td>\n<td>Manager releases inventory reservation, returns payment failure<\/td>\n<\/tr>\n<tr>\n<td>Payment gateway timeout<\/td>\n<td><code class=\"\" data-line=\"\">PaymentTimeout(retry_after: 30)<\/code><\/td>\n<td>Manager holds reservation, returns retry-eligible error<\/td>\n<\/tr>\n<tr>\n<td>Payment gateway returns unknown error<\/td>\n<td><code class=\"\" data-line=\"\">PaymentError(&quot;unknown_gateway_error&quot;)<\/code><\/td>\n<td>Manager releases reservation, logs critical, returns system error<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Mock placement for integration tests:<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    subgraph integration_scope[\"Integration Test Scope\"]\n        OM[\"OrderManager (real)\"]\n    end\n\n    subgraph mocked_engines[\"Engines (mocked \u2014 return controlled states)\"]\n        VE[\"ValidationEngine (mock)\"]\n        PE[\"PricingEngine (mock)\"]\n        IE[\"InventoryEngine (mock)\"]\n    end\n\n    subgraph mocked_accessors[\"Accessors (mocked \u2014 return controlled states)\"]\n        ORA[\"OrderRepositoryAccessor (mock)\"]\n        PGA[\"PaymentGatewayAccessor (mock)\"]\n        NA[\"NotificationAccessor (mock)\"]\n    end\n\n    OM --> VE\n    OM --> PE\n    OM --> IE\n    OM --> ORA\n    OM --> PGA\n    OM --> NA\n\n<\/div><\/p>\n<h3 id=\"c4-end-to-end-test-scenarios\">C.4 End-to-End Test Scenarios<\/h3>\n<p>E2E tests exercise the full stack with no mocks. Real databases, real payment gateway (sandbox mode), real notification delivery (test channel). The assertions target user-visible outcomes.<\/p>\n<h4 id=\"scenario-1-happy-path-order\">Scenario 1: Happy Path Order<\/h4>\n<ol>\n<li>Submit a valid order through the API with two line items and a promotional code.<\/li>\n<li>Assert: API returns <code class=\"\" data-line=\"\">201 Created<\/code> with an order confirmation containing the order ID, applied discount, and estimated delivery.<\/li>\n<li>Assert: Order is retrievable via <code class=\"\" data-line=\"\">GET \/orders\/{id}<\/code> with status <code class=\"\" data-line=\"\">confirmed<\/code>.<\/li>\n<li>Assert: Inventory counts for both items are decremented.<\/li>\n<li>Assert: Payment transaction appears in gateway sandbox with correct amount.<\/li>\n<li>Assert: Confirmation notification delivered to test channel.<\/li>\n<\/ol>\n<h4 id=\"scenario-2-order-with-payment-failure\">Scenario 2: Order with Payment Failure<\/h4>\n<ol>\n<li>Submit a valid order through the API using a test card number that triggers decline.<\/li>\n<li>Assert: API returns <code class=\"\" data-line=\"\">402 Payment Required<\/code> with decline reason.<\/li>\n<li>Assert: Order is retrievable via <code class=\"\" data-line=\"\">GET \/orders\/{id}<\/code> with status <code class=\"\" data-line=\"\">payment_failed<\/code>.<\/li>\n<li>Assert: Inventory reservations are released (stock counts restored).<\/li>\n<li>Assert: No confirmation notification sent.<\/li>\n<\/ol>\n<h4 id=\"scenario-3-partial-inventory-fulfillment\">Scenario 3: Partial Inventory Fulfillment<\/h4>\n<ol>\n<li>Submit a valid order for 10 units where only 4 are in stock and backorder is allowed.<\/li>\n<li>Assert: API returns <code class=\"\" data-line=\"\">201 Created<\/code> with order confirmation indicating partial fulfillment.<\/li>\n<li>Assert: Order contains two fulfillment groups: 4 units immediate, 6 units backordered.<\/li>\n<li>Assert: Payment charged for full amount (backorder policy: charge upfront).<\/li>\n<li>Assert: Customer receives notification indicating partial shipment with backorder ETA.<\/li>\n<\/ol>\n<h3 id=\"c5-adding-a-new-payment-method\">C.5 Adding a New Payment Method<\/h3>\n<p>This section demonstrates the maintenance cost of adding a new capability \u2014 a cryptocurrency payment option \u2014 to the system. Because boundaries are correctly placed, the change is contained.<\/p>\n<p><strong>What changes:<\/strong><\/p>\n<ol>\n<li>\n<p><strong>PaymentGatewayAccessor<\/strong> \u2014 Add a new translation path for cryptocurrency gateway API calls. The Accessor already defines the contract: <code class=\"\" data-line=\"\">authorize(payment_request) -&gt; PaymentAuthorized | PaymentDeclined | PaymentTimeout | PaymentError<\/code>. The new payment method is a new implementation path within the Accessor, not a new contract.<\/p>\n<\/li>\n<li>\n<p><strong>One new Accessor unit test<\/strong> \u2014 Test that the Accessor correctly translates a cryptocurrency payment request into the gateway&#8217;s API format and correctly parses the response. The mock target is the cryptocurrency gateway&#8217;s HTTP client. The contract states are identical: authorized, declined, timeout, error.<\/p>\n<\/li>\n<li>\n<p><strong>One updated integration test at the Manager-to-Accessor seam<\/strong> \u2014 Add a test case confirming that the OrderManager correctly handles a cryptocurrency payment authorization. The mock PaymentGatewayAccessor returns <code class=\"\" data-line=\"\">PaymentAuthorized(transaction_id, method: &quot;crypto&quot;)<\/code>. Assert that the Manager persists the order with the correct payment method recorded.<\/p>\n<\/li>\n<li>\n<p><strong>One new E2E scenario<\/strong> \u2014 Submit an order through the API with <code class=\"\" data-line=\"\">payment_method: &quot;crypto&quot;<\/code>, using the cryptocurrency gateway sandbox. Assert the same outcomes as the happy path: order confirmed, inventory decremented, notification sent, payment recorded with the correct method.<\/p>\n<\/li>\n<\/ol>\n<p><strong>What does not change:<\/strong><\/p>\n<ul>\n<li>ValidationEngine unit tests \u2014 validation rules are payment-method-agnostic.<\/li>\n<li>PricingEngine unit tests \u2014 pricing is independent of payment method.<\/li>\n<li>InventoryEngine unit tests \u2014 inventory logic is independent of payment method.<\/li>\n<li>All existing integration tests \u2014 the Manager&#8217;s orchestration logic is unchanged; it calls <code class=\"\" data-line=\"\">PaymentGatewayAccessor.authorize()<\/code> regardless of method.<\/li>\n<li>All existing E2E scenarios \u2014 the happy path, payment failure, and partial fulfillment scenarios are unaffected.<\/li>\n<\/ul>\n<p><strong>Change impact diagram:<\/strong><\/p>\n<p><div class=\"mermaid\">%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e0e7ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#4338ca', 'lineColor': '#4338ca', 'background': '#ffffff', 'mainBkg': '#e0e7ff', 'nodeBorder': '#4338ca', 'clusterBkg': '#f5f3ff', 'edgeLabelBackground': '#ffffff'}}}%%\n\nflowchart TD\n    subgraph unchanged[\"Unchanged\"]\n        OM[\"OrderManager\"]\n        VE[\"ValidationEngine\"]\n        PE[\"PricingEngine\"]\n        IE[\"InventoryEngine\"]\n        ORA[\"OrderRepositoryAccessor\"]\n        NA[\"NotificationAccessor\"]\n        LU[\"LoggingUtility\"]\n    end\n\n    subgraph changed[\"Changed \u2014 New Payment Method\"]\n        PGA[\"PaymentGatewayAccessor\"]\n    end\n\n    subgraph tests_added[\"Tests Added\"]\n        T1[\"1 Accessor unit test\"]\n        T2[\"1 integration test (Manager-Accessor seam)\"]\n        T3[\"1 E2E scenario\"]\n    end\n\n    PGA --> T1\n    PGA --> T2\n    PGA --> T3\n\n<\/div><\/p>\n<p>This is the structural payoff of correct boundary placement. The new payment method is volatile \u2014 it is a new external integration with its own protocol, authentication, and error semantics. But the volatility is contained entirely within the Accessor, which is the role designed to absorb external integration change. The Engines do not know about payment methods. The Manager does not know about gateway protocols. The test suite reflects this containment: three new tests, zero modified tests, full confidence.<\/p>\n<hr \/>\n<h2 id=\"references-and-influences\">References and Influences<\/h2>\n<p><strong>William Christopher Anderson<\/strong><br \/>\nAnderson, William Christopher. <em>Volatility-Based Decomposition in Software Architecture.<\/em> February 2026. <code class=\"\" data-line=\"\">vbd.md<\/code><br \/>\nAnderson, William Christopher. <em>Experience-Based Decomposition.<\/em> March 2026. <code class=\"\" data-line=\"\">ebd.md<\/code><\/p>\n<p>VBD and EBD define the structural models and role taxonomies that BDT maps to the test spiral. The component roles (Manager, Engine, Resource Accessor, Utility; Experience, Flow, Interaction, Utility), communication rules, and core scenario validation mechanisms are taken from these sources. BDT establishes the testability consequences of those structures: where to test each role, what to mock, and how to read testing difficulty as structural signal.<\/p>\n<p><strong>David L. Parnas<\/strong><br \/>\nParnas, David L. &#8220;On the Criteria To Be Used in Decomposing Systems into Modules.&#8221; <em>Communications of the ACM<\/em>, 1972.<\/p>\n<p>Parnas argued that modules should hide design decisions likely to change behind stable interfaces. That same abstraction is what makes components testable: the stable interface is what callers depend on, and what tests can target without coupling to implementation. BDT extends this from the module level to the architectural level, applying the same principle across the full component role hierarchy.<\/p>\n<p><strong>Robert C. Martin<\/strong><br \/>\nMartin, Robert C. <em>Clean Architecture.<\/em> Pearson, 2017.<\/p>\n<p>Martin&#8217;s work on dependency inversion, boundary placement, and the Dependency Rule establishes the structural conditions under which testing is tractable. His principle \u2014 mock across architecturally significant boundaries, but not within them \u2014 is adopted directly in Section 4. His observation that testability is a primary benefit of correct dependency management is the foundational premise of BDT.<\/p>\n<p><strong>Martin Fowler<\/strong><br \/>\nFowler, Martin. &#8220;The Practical Test Pyramid.&#8221; <em>martinfowler.com<\/em>, 2018.<\/p>\n<p>Fowler&#8217;s test pyramid established the proportional framing \u2014 many unit tests, fewer integration tests, fewer still E2E \u2014 and the practical consequences of inverting it. BDT builds on this by grounding the pyramid&#8217;s levels in structural tiers rather than convention, explaining <em>why<\/em> the proportions emerge from correct decomposition rather than treating them as a design rule to follow.<\/p>\n<p><strong>Gregor Hohpe and Bobby Woolf<\/strong><br \/>\nHohpe, Gregor; Woolf, Bobby. <em>Enterprise Integration Patterns.<\/em> Addison-Wesley, 2003.<\/p>\n<p>Hohpe and Woolf&#8217;s treatment of integration points as volatility points reinforces the argument that Accessors are the natural integration test target. Their accessor and adapter patterns define the narrow, stable interfaces that integration tests verify \u2014 and that unit tests mock. The patterns also describe the specific behaviors (retries, error translation, protocol handling) that integration tests must exercise and unit tests must exclude.<\/p>\n<p><strong>Juval L\u00f6wy<\/strong><br \/>\nL\u00f6wy, Juval. <em>Righting Software.<\/em> Addison-Wesley, 2019.<\/p>\n<p>L\u00f6wy&#8217;s IDesign methodology is the source of the Manager-Engine-Accessor taxonomy. The communication rules and role constraints that prevent runtime coupling also prevent test complexity \u2014 an observation that BDT makes explicit. The discipline that keeps Engines from coordinating workflows keeps unit tests focused. The discipline that keeps Accessors from applying business rules keeps integration tests targeted.<\/p>\n<hr \/>\n<h2 id=\"authors-note\">Author&#8217;s Note<\/h2>\n<p>Boundary-Driven Testing does not introduce new testing techniques. Every test type described here \u2014 unit, integration, E2E, system, UAT \u2014 predates this paper by decades. What BDT contributes is a structural account of <em>why<\/em> these levels exist, what they correspond to in a correctly decomposed system, and how to read testing difficulty as a diagnostic signal about structural health.<\/p>\n<p>The intent is a reference that makes explicit the relationship between decomposition discipline and testing tractability \u2014 suitable for engineering onboarding, test strategy discussions, and architectural review in organizations building products intended to last.<\/p>\n<hr \/>\n<h2 id=\"distribution-note\">Distribution Note<\/h2>\n<p>This document is provided for informational and educational purposes. It may be shared internally within organizations, used as a reference in testing and architecture discussions, or adapted for non-commercial educational use with appropriate attribution.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Published March 2026 A Practitioner-Oriented Articulation Author: William Christopher Anderson Date: March 2026 Version: 1.0 Executive Summary Testing difficulty is architectural evidence. When a component cannot be exercised in isolation, when a unit test requires a running database, when a change in one module breaks tests across a dozen others \u2014 the problem is not &#8230; <a title=\"Boundary-Driven Testing\" class=\"read-more\" href=\"https:\/\/dev.harmonic-framework.com\/es\/whitepapers\/boundary-driven-testing\/\" aria-label=\"Read more about Boundary-Driven Testing\">Read more<\/a><\/p>","protected":false},"author":0,"featured_media":0,"parent":11,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_uag_custom_page_level_css":"","footnotes":""},"methodology":[],"class_list":["post-134","page","type-page","status-publish"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"trp-custom-language-flag":false,"post-thumbnail":false,"hf-card":false,"hf-hero":false},"uagb_author_info":{"display_name":"","author_link":"https:\/\/dev.harmonic-framework.com\/es\/author\/"},"uagb_comment_info":0,"uagb_excerpt":"Published March 2026 A Practitioner-Oriented Articulation Author: William Christopher Anderson Date: March 2026 Version: 1.0 Executive Summary Testing difficulty is architectural evidence. When a component cannot be exercised in isolation, when a unit test requires a running database, when a change in one module breaks tests across a dozen others \u2014 the problem is not&hellip;","_links":{"self":[{"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/pages\/134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/types\/page"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/comments?post=134"}],"version-history":[{"count":3,"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/pages\/134\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/pages\/134\/revisions\/161"}],"up":[{"embeddable":true,"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/pages\/11"}],"wp:attachment":[{"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/media?parent=134"}],"wp:term":[{"taxonomy":"methodology","embeddable":true,"href":"https:\/\/dev.harmonic-framework.com\/es\/wp-json\/wp\/v2\/methodology?post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}