From 394519ccfb0cd508d9a1d6361603105027047cf2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:24:10 +0900 Subject: [PATCH 01/13] docs(ddd): add explicit bounded-context map --- docs/context-map.md | 111 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 docs/context-map.md diff --git a/docs/context-map.md b/docs/context-map.md new file mode 100644 index 000000000..f71f4458d --- /dev/null +++ b/docs/context-map.md @@ -0,0 +1,111 @@ +# OriginWeave Context Map + +This map records bounded-context ownership and allowed dependency direction. Protected `main` remains shipment truth. A context marked **active PR** exists only on the referenced branch until it is integrated. + +## Subdomains + +| Subdomain | Classification | Current owner | Responsibility | +|---|---|---|---| +| Browser authority contracts | Core | `originweave-core` | Stable no-I/O values for origin identity, action intent, capability, risk, approval scope, action requests, and policy context | +| Policy decision | Core | `originweave-policy` | Deterministic fail-closed authorization over typed action requests and explicit context | +| Destination authority | Core | `originweave-destination` | Resolved-address classification, approved resolution snapshots, redirect authorization, and DNS-rebinding resistance | +| Direct transport authority | Supporting | `originweave-network` | Single-use direct TCP plans and exact operating-system peer proof | +| TLS service identity | Supporting | `originweave-tls` | WebPKI authentication for an already verified direct TCP stream | +| Resource governance | Supporting | `originweave-resource` | Bounded task budgets and deterministic mitigation plans | +| Evidence contracts | Supporting | `originweave-evidence` | Value-redacted network evidence and source-bound provenance records | +| Browser Agent Protocol | Supporting | `originweave-bap` | Browser-agent protocol contracts and lifecycle vocabulary | +| MCP protocol adapter | Generic integration | `originweave-mcp` (**active PR #272**) | MCP version/method/tool discovery and routing into typed OriginWeave action contracts; grants no execution authority | + +Planned contexts such as browser sessions, HTTP, proxy, observation, typed browser execution, secret brokering, WebDriver BiDi/CDP adapters, WARC/PROV persistence, and release benchmarks remain planned until code reaches protected `main`. Their planned names do not grant ownership to unrelated current crates. + +## Context relationships + +```text +External MCP client + | + v ++--------------------+ +| MCP adapter | generic integration / ACL +| originweave-mcp | ++---------+----------+ + | typed ActionKind / Capability / RiskClass + v ++--------------------+ +----------------------+ +| Policy decision |------->| Browser authority | +| originweave-policy | | originweave-core | ++--------------------+ +----------------------+ + ^ + | + +-------------------+-------------------+ + | | | + | | | + +-------+--------+ +-------+--------+ +-------+--------+ + | Destination | | Evidence | | Resource | + | authority | | contracts | | governance | + +-------+--------+ +----------------+ +----------------+ + | + v + +-------+--------+ + | Direct TCP | + | authority | + +-------+--------+ + | + v + +-------+--------+ + | TLS identity | + +----------------+ +``` + +The arrows show allowed contract dependence, not runtime authority transfer. A downstream context must still validate its own invariants. In particular, an origin grant does not authorize a DNS result, a destination approval does not prove the connected peer, a verified peer does not prove TLS service identity, and an MCP route does not authorize an action. + +## Relationship contracts + +### MCP adapter → browser authority contracts + +Relationship: **Anti-Corruption Layer / conformist at the protocol edge**. + +The MCP adapter may depend on stable OriginWeave action vocabulary from `originweave-core`. External MCP method names, tool names, protocol versions, cursors, and request metadata remain adapter types. They must not be promoted into `originweave-core` domain entities. The adapter maps a bounded, validated MCP request to an existing typed action kind and does not invent capabilities or approvals. + +### Policy decision → MCP adapter + +Relationship: **published contract consumption**. + +`originweave-policy` may consume the adapter's validated route token only to prove route/action equality before applying the normal policy decision. Policy owns authorization invariants; MCP owns protocol validation. Neither context may absorb the other's responsibility. + +### Destination authority → browser authority contracts + +Relationship: **customer/supplier through stable values**. + +Destination policy consumes canonical origin identity but owns address classification, resolution snapshots, rebinding checks, and redirect destination decisions. `Origin` is a logical web identity, not an SSRF decision. + +### Direct transport authority → destination authority + +Relationship: **customer/supplier through an approved snapshot**. + +The network boundary accepts only a concrete address authorized by an origin-bound `ResolutionSnapshot`. It performs no DNS resolution and cannot reinterpret an origin grant as socket authority. + +### TLS service identity → direct transport and destination authority + +Relationship: **customer/supplier through verified transport evidence**. + +TLS consumes the already connected direct stream, the canonical HTTPS origin, and explicit trust material. It may not reconnect, re-resolve, or replace exact peer evidence with certificate success. + +### Evidence and resource contexts + +Relationship: **published contracts, no shared mutable kernel**. + +Evidence and resource governance expose bounded value contracts. Browser/protocol adapters may produce telemetry or evidence inputs, but these contexts do not acquire browser, network, policy, or secret authority from those callers. + +## Dependency rules + +1. Domain/security contracts must not import MCP, BiDi, CDP, Chromium SDK, HTTP client, persistence, UI, or provider DTOs. +2. Protocol adapters may depend inward on stable OriginWeave contracts; stable contracts must not depend outward on protocol adapters. +3. Policy authorization remains centralized in `originweave-policy`; adapters cannot duplicate or weaken it. +4. Cross-context calls use public crate APIs or explicit application ports. Direct access to another context's internals is forbidden. +5. No context may infer authority from another context's success. Each boundary emits evidence specific to the invariant it proves. +6. Shared Kernel additions require an accepted ADR and must be smaller than the contexts that consume them. `originweave-core` is not a dumping ground for integration DTOs. +7. Planned contexts remain separate responsibilities even before their crates exist. New work must not be parked temporarily in `originweave-core` merely because the final context has not yet been created. + +## Machine-checkable fitness + +`tests/test_repository_contract.py` enforces the first MCP ownership slice introduced with PR #272: `originweave-mcp` is a workspace package, MCP routing does not live under `originweave-core`, the adapter depends only on `originweave-core`, and policy imports the validated MCP route from the adapter crate. Additional context relationships should gain equivalent import/dependency fitness checks when their production boundaries land. From b70f06376cfd0d3f728100e7ae4f19e4665c406a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:24:37 +0900 Subject: [PATCH 02/13] docs(ddd): define OriginWeave ubiquitous language --- docs/ubiquitous-language.md | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/ubiquitous-language.md diff --git a/docs/ubiquitous-language.md b/docs/ubiquitous-language.md new file mode 100644 index 000000000..90052312b --- /dev/null +++ b/docs/ubiquitous-language.md @@ -0,0 +1,53 @@ +# OriginWeave Ubiquitous Language + +This glossary defines terms that must mean the same thing in code, tests, ADRs, APIs, issues, and product documentation. When an external protocol uses a conflicting term, the adapter translates it at the boundary instead of changing the OriginWeave meaning. + +| Term | Meaning in OriginWeave | Ownership / invariant | +|---|---|---| +| Origin | Canonical logical web identity: scheme, host, and effective port | `originweave-core`; never means a resolved IP address or an SSRF authorization | +| Destination | Concrete network address proposed or approved for connection | `originweave-destination`; must be classified and explicitly authorized | +| Resolution Snapshot | Non-empty, origin-bound set of approved resolver results | `originweave-destination`; later DNS answers may contract but not expand without reauthorization | +| Connection Plan | Bounded, single-use authority to attempt one or more exact direct TCP connections | `originweave-network`; contains no hostname-resolution authority | +| Direct TCP Connection | Connected stream whose operating-system peer has been checked against the requested canonical socket | `originweave-network`; proves peer equality, not TLS identity | +| TLS Service Identity | WebPKI-authenticated service identity for the canonical HTTPS origin on an existing verified TCP stream | `originweave-tls`; cannot reconnect or re-resolve | +| Session Mode | Human, Assist, Agent Task, or Crawler execution posture | `originweave-core`; determines the authority model, not just UI presentation | +| Execution Purpose | Explicit reason for a governed execution, such as a user-delegated task or public crawl | `originweave-core`; must agree with the allowed session mode | +| Capability | Explicit permission category required by an `ActionKind` | `originweave-core`; absence is denial, never inferred from ambient browser state | +| Action Kind | Closed typed operation that an agent may request | `originweave-core`; production agents do not receive unrestricted JavaScript as a standard action | +| Action Request | Complete typed request binding action, source/target origin, instruction source, secret-delivery mode, and intent digest | `originweave-core`; input to policy, not proof of authorization | +| Action Intent Digest | Immutable digest of the canonical complete user/enterprise intent relevant to approval | `originweave-core`; approval must bind to it exactly | +| Approval Scope | Exact action + target origin + intent digest tuple to which approval applies | `originweave-core`; scopes are not fungible across actions or destinations | +| Approval Evidence | User or enterprise evidence authorizing one exact `ApprovalScope` | `originweave-core`; stale or mismatched evidence fails closed | +| Policy Decision | `Allow`, `Deny`, or `RequireApproval` result for a typed request and explicit context | `originweave-policy`; adapters do not manufacture this decision | +| Instruction Source | Provenance category describing where an instruction originated | `originweave-core`; web/page content is data and cannot promote itself to trusted authority | +| Secret Delivery | Whether an action receives no secret or an opaque broker handle | `originweave-core`; raw secret values must not enter model context or generic action payloads | +| Risk Class | R0–R5 action-risk classification used by policy | `originweave-core`; R5 is non-delegable under the current contract | +| Evidence | Bounded, credential-free or value-redacted proof emitted by a boundary about the invariant it actually checked | `originweave-evidence` and producing contexts; evidence from one boundary cannot stand in for another | +| Resource Budget | Explicit bounded allowance for task/resource consumption | `originweave-resource`; hard pressure must reduce the active consumer and reject unsafe admission | +| Mitigation Plan | Deterministic cumulative response to observed resource pressure | `originweave-resource`; may combine actions rather than collapse simultaneous pressures into one flag | +| MCP Route | Validated MCP protocol-version/method/tool binding that maps to an OriginWeave `ActionKind` | `originweave-mcp` active PR #272; proves routing consistency only, not authorization | +| MCP Tool | External MCP-visible name for one supported typed OriginWeave action | `originweave-mcp`; unknown or malformed names fail closed | +| Browser Agent Protocol (BAP) | OriginWeave browser-agent protocol contract and lifecycle vocabulary | `originweave-bap`; it is not a synonym for MCP, WebDriver BiDi, or CDP | +| Adapter | Boundary translating an external protocol/runtime representation into OriginWeave contracts | Protocol/infrastructure context; must not leak provider DTOs into domain contracts | +| Anti-Corruption Layer | Translation boundary that prevents an external model or foreign bounded context from redefining OriginWeave domain terms | Required at protocol/provider edges when vocabularies or authority models differ | +| Shared Kernel | Deliberately tiny, versioned contract surface shared by bounded contexts | `originweave-core` is the current kernel; additions require stable cross-context meaning, not convenience | +| Protected-main truth | Behavior and documentation integrated into protected `main` with its required governance evidence | Open PRs, predecessor checks, model comments, and planned modules are not protected-main truth | +| Active-PR evidence | Code, tests, checks, or documentation that exists on an open PR exact head but is not yet shipped | Must remain labeled as active until protected integration | + +## Terms that must not be collapsed + +These distinctions are security and product invariants, not editorial preferences: + +- **Origin ≠ destination ≠ TCP peer ≠ TLS service identity.** Each is proven at a different boundary. +- **MCP route ≠ policy decision ≠ browser execution.** Protocol validity cannot grant capability or approval. +- **Capability ≠ approval.** Possessing the capability to request an action does not satisfy approval requirements for its risk class. +- **Action request ≠ observed post-condition.** Dispatch success is not proof that the intended browser state was reached. +- **Evidence ≠ authority.** Evidence records what a boundary proved; possession of an evidence object does not create new permission. +- **Crawler policy ≠ access authorization.** Robots decisions govern crawl behavior but do not create authentication or data-access rights. +- **Planned context ≠ current implementation.** A name in the architecture roadmap is not shipped ownership until code and tests reach protected `main`. + +## Naming rules + +Public Rust types, modules, tests, API fields, database objects, and documentation should use these terms directly where they express the same concept. External names such as MCP `tools/call`, WebDriver BiDi command names, CDP domains, provider SDK objects, Chromium internals, or persistence DTOs stay at their adapters. Do not rename a domain concept merely to match an external provider vocabulary. + +Generic names such as `utils`, `helpers`, `common`, `services`, `models`, `misc`, `legacy`, or an unqualified `data`/`security`/`browser` directory do not establish domain ownership. A new package or module should name the stable responsibility it owns or live inside the already accepted bounded context that owns that responsibility. From 4d8756f845d942887c7437615db43dbeec3e1571 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:25:17 +0900 Subject: [PATCH 03/13] docs(ddd): reconcile MCP ownership traceability --- docs/traceability/mcp-authority-route.md | 50 +++++++++++++++++------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/docs/traceability/mcp-authority-route.md b/docs/traceability/mcp-authority-route.md index 94f181ed4..b16d8d8ed 100644 --- a/docs/traceability/mcp-authority-route.md +++ b/docs/traceability/mcp-authority-route.md @@ -1,25 +1,40 @@ # MCP 2026-07-28 authority-route traceability - **`tools/call` capability maturity:** `IMPLEMENTED_ON_PROTECTED_MAIN` -- **`tools/list` capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` -- **Protected-main owning work:** merged PR #168 `feat(mcp): bind stateless tool routing to typed actions` -- **Active follow-on:** PR #170 `feat(mcp): expose conservative tools list cache contract` +- **`tools/list` capability maturity:** `IMPLEMENTED_ON_PROTECTED_MAIN` +- **Protected-main owning work:** merged PR #168 (`tools/call`) and merged PR #170 (`tools/list`) +- **Bounded-context correction:** active PR #272 moves MCP protocol contracts from `originweave-core` to `originweave-mcp` without changing routing or policy semantics - **Complete MCP adapter status:** `PLANNED` - **Governing decision:** ADR 0107 ## Scope -Protected main at `b05d5acca82b9d916ada2c8e82f59f92a89817e1` contains the bounded Rust control-plane foundation for MCP `2026-07-28` `tools/call` routing that merged through PR #168. It validates the represented stateless routing envelope, bounds and syntax-validates both attacker-controlled method fields and both attacker-controlled tool-name fields before correlation, maps only an explicit reviewed `originweave.*` catalog to existing typed `ActionKind` values, derives discovery metadata from the same catalog, and rejects route/action mismatch before ordinary deterministic policy evaluation. Methods are nonempty reviewed-ASCII routing tokens of at most 64 bytes; tool names are nonempty reviewed-ASCII identifiers of at most 128 bytes. Invalid method metadata is rejected distinctly from a bounded but unsupported MCP method. +Protected main at `542ca1e9c0a863595b8b6697790005d2471f5413` contains the bounded Rust control-plane foundations for MCP `2026-07-28` `tools/call` routing and conservative `tools/list` discovery. PR #168 established stateless route validation and mapping to existing typed `ActionKind` values. PR #170, merged on 2026-08-27 as `c4e127036e75cd3c5682ef15b69fb9ec29ff1dd2`, added the fixed discovery page and request metadata validation. + +The protected-main implementation validates represented stateless routing envelopes, bounds and syntax-validates attacker-controlled method and tool-name fields before correlation, maps only the reviewed `originweave.*` catalog to existing typed actions, derives discovery metadata from the same catalog, and rejects route/action mismatch before ordinary deterministic policy evaluation. Methods are nonempty reviewed-ASCII routing tokens of at most 64 bytes; tool names are nonempty reviewed-ASCII identifiers of at most 128 bytes. Invalid method metadata remains distinct from a bounded but unsupported MCP method. A successful `ValidatedMcpToolCall` proves routing integrity only. It grants no capability, origin, approval, secret, browser, tenant, persistence, network, or evidence authority. `originweave_policy::evaluate_mcp` still delegates to the ordinary policy evaluator after the route/action match. -Active PR #170 builds on that protected-main catalog with a conservative typed `tools/list` request/result boundary. Its current branch requires matching MCP protocol metadata, required client-capability presence, bounded and syntax-validated routing/body methods, exact `tools/list` routing, and no caller-supplied cursor because the fixed catalog issues none. Its result is one complete page with zero freshness, private cache scope, and no continuation cursor. This active-PR slice remains non-shipped until it reaches protected main and does not grant any OriginWeave action authority. +The protected-main `tools/list` contract requires matching MCP protocol metadata, required client-capability presence, bounded and syntax-validated routing/body methods, exact `tools/list` routing, and no caller-supplied cursor because the fixed catalog issues none. Its result is one complete page with zero freshness, private cache scope, and no continuation cursor. Discovery metadata grants no OriginWeave action authority. + +## Bounded-context correction + +Protected main still places the MCP protocol implementation under `crates/originweave-core/src/mcp.rs`. That placement conflicts with the architecture rule that stable shared domain/security contracts remain free of external protocol DTOs and adapters. Active PR #272 is the canonical DDD repair for that ownership drift: + +- introduces `crates/originweave-mcp` as the MCP protocol-adapter bounded context; +- moves the existing routing/discovery implementation without semantic changes; +- moves protocol-boundary tests with the adapter; +- keeps `originweave-core` as the stable shared action/authority vocabulary; +- makes `originweave-policy` consume `ValidatedMcpToolCall` from the adapter boundary; and +- adds a machine-checkable repository fitness test preventing MCP protocol code from returning to core. + +PR #272 is active-PR evidence, not protected-main behavior. Until it merges, the protected-main source paths below remain the shipped ownership truth even though the architectural defect is known. ## Product-status reconciliation -`docs/PRD.md` PRD-INT-004 and `docs/TRD.md` Section 12 intentionally remain **Planned** at the complete-adapter level. That status is not contradicted by the bounded `tools/call` foundation now on protected main or by active PR #170: both are reusable control-plane contracts below the complete product adapter. `README.md` and `CHANGELOG.md` distinguish protected-main routing from the active discovery refinement, and ADR 0107 records the protocol/version and authority boundary. +`docs/PRD.md` PRD-INT-004 and `docs/TRD.md` Section 12 intentionally remain **Planned** at the complete-adapter level. That status is not contradicted by the protected-main `tools/call` and `tools/list` foundations: both are reusable protocol contracts below the complete product adapter. -The following remain outside protected main and PR #170 and must not be inferred from either: +The following remain outside the complete protected-main adapter and must not be inferred from the routing/discovery foundations or PR #272: - Streamable HTTP transport parsing and header materialization; - JSON-RPC/HTTP response serialization of the typed discovery page; @@ -32,7 +47,7 @@ The following remain outside protected main and PR #170 and must not be inferred ## Version boundary -The protected-main routing foundation and active discovery refinement accept only protocol generation `2026-07-28`. MCP versioning is independent of the OriginWeave Protocol. A later MCP revision does not silently change OriginWeave action, risk, capability, approval, secret, origin, tenant, browser, or evidence semantics. +The routing and discovery foundations accept only protocol generation `2026-07-28`. MCP versioning is independent of the OriginWeave Protocol. A later MCP revision does not silently change OriginWeave action, risk, capability, approval, secret, origin, tenant, browser, or evidence semantics. The reviewed primary source is: @@ -42,17 +57,24 @@ The canonical bibliography remains `docs/doctoring.md`. ## Executable evidence -Protected-main PR #168 production/test surfaces include: +Protected-main production/test surfaces before PR #272 are: -- `crates/originweave-core/src/mcp.rs` — bounded deterministic catalog plus method/tool routing validation in the `ValidatedMcpToolCall` primitive; -- `crates/originweave-core/tests/mcp_authority_route.rs` — mapping, exact method/tool bounds, empty/oversized/malformed inputs, version/method/header-body correlation, and error-contract evidence; +- `crates/originweave-core/src/mcp.rs` — bounded deterministic catalog plus `tools/call` and `tools/list` protocol validation; +- `crates/originweave-core/tests/mcp_authority_route.rs` — action mapping, method/tool bounds, malformed inputs, version/method/header-body correlation, and error contracts; +- `crates/originweave-core/tests/mcp_tools_list_cache.rs` — fixed discovery result/cache semantics, protocol/client metadata, method validation, routing correlation, cursor rejection, and public errors; - `crates/originweave-policy/src/lib.rs` — `evaluate_mcp` route/action guard before normal policy evaluation; and - `crates/originweave-policy/tests/mcp_route_binding.rs` — confused-deputy and policy-preservation evidence. -Active PR #170 additionally exercises its discovery contract in `crates/originweave-core/tests/mcp_tools_list_cache.rs`, including result/cache semantics, required protocol/client metadata, bounded protocol and method validation, routing correlation, cursor rejection, and public error contracts. +On active PR #272 the same protocol implementation and its tests move to: + +- `crates/originweave-mcp/src/routing.rs`; +- `crates/originweave-mcp/tests/mcp_authority_route.rs`; and +- `crates/originweave-mcp/tests/mcp_tools_list_cache.rs`. + +The repository fitness contract in `tests/test_repository_contract.py` verifies the new package boundary, prevents `originweave-core/src/mcp.rs` from reappearing, restricts `originweave-mcp` to the stable core dependency, and requires policy to import the validated MCP route through the adapter crate. -Exact current-head CI/security/review evidence must be regenerated after every branch mutation. Protected-main evidence proves only the merged `tools/call` foundation; predecessor or protected-main results are not current-head proof for active PR #170. +Exact current-head CI/security/review evidence must be regenerated after every branch mutation. Protected-main evidence proves only the integrated foundations; predecessor or protected-main results are not current-head proof for PR #272. ## Promotion rule -The bounded `tools/call` routing foundation is already `IMPLEMENTED_ON_PROTECTED_MAIN`. The `tools/list` discovery refinement may change to `IMPLEMENTED_ON_PROTECTED_MAIN` only after PR #170 reaches protected `main` under live governance and exact-head acceptance. Neither promotion makes the complete MCP adapter implemented; each remaining transport/runtime boundary requires its own integrated evidence. +The bounded `tools/call` and `tools/list` foundations are already `IMPLEMENTED_ON_PROTECTED_MAIN`. The ownership correction may be described as protected-main architecture only after PR #272 reaches protected `main` under live governance and exact-head acceptance. That promotion still does not make the complete MCP server implemented; each remaining transport/runtime boundary requires its own integrated evidence. From d0558d5859d5e91715452c29672a4dc7ffd1cc11 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:25:39 +0900 Subject: [PATCH 04/13] test(ddd): enforce context-map documentation contract --- tests/test_ddd_documentation_contract.py | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/test_ddd_documentation_contract.py diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py new file mode 100644 index 000000000..24c8d28b1 --- /dev/null +++ b/tests/test_ddd_documentation_contract.py @@ -0,0 +1,55 @@ +"""Architectural documentation fitness for bounded-context ownership.""" + +from __future__ import annotations + +import pathlib +import unittest + +ROOT = pathlib.Path(__file__).resolve().parents[1] + + +class DddDocumentationContractTests(unittest.TestCase): + """Keep the Context Map and Ubiquitous Language executable as repository contracts.""" + + def test_context_map_records_mcp_as_protocol_adapter_not_shared_kernel(self) -> None: + context_map = (ROOT / "docs/context-map.md").read_text(encoding="utf-8") + self.assertIn("originweave-mcp", context_map) + self.assertIn("Anti-Corruption Layer", context_map) + self.assertIn("MCP adapter", context_map) + self.assertIn("originweave-core", context_map) + self.assertIn("Adapters", context_map) + self.assertIn("must not depend outward on protocol adapters", context_map) + + def test_ubiquitous_language_keeps_authority_terms_distinct(self) -> None: + glossary = (ROOT / "docs/ubiquitous-language.md").read_text(encoding="utf-8") + for term in ( + "Origin", + "Destination", + "Resolution Snapshot", + "Direct TCP Connection", + "TLS Service Identity", + "Action Request", + "Approval Scope", + "Policy Decision", + "MCP Route", + "Anti-Corruption Layer", + "Protected-main truth", + ): + with self.subTest(term=term): + self.assertIn(term, glossary) + self.assertIn("Origin ≠ destination ≠ TCP peer ≠ TLS service identity", glossary) + self.assertIn("MCP route ≠ policy decision ≠ browser execution", glossary) + + def test_mcp_traceability_names_current_and_active_ownership_separately(self) -> None: + trace = (ROOT / "docs/traceability/mcp-authority-route.md").read_text( + encoding="utf-8" + ) + self.assertIn("IMPLEMENTED_ON_PROTECTED_MAIN", trace) + self.assertIn("active PR #272", trace) + self.assertIn("crates/originweave-core/src/mcp.rs", trace) + self.assertIn("crates/originweave-mcp/src/routing.rs", trace) + self.assertIn("active-PR evidence, not protected-main behavior", trace) + + +if __name__ == "__main__": + unittest.main() From 789bb1d4e1c10d9e3230586b7a07caa9c4375c59 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:25:55 +0900 Subject: [PATCH 05/13] test(ddd): correct context-map fitness assertion --- tests/test_ddd_documentation_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py index 24c8d28b1..584fcbcf6 100644 --- a/tests/test_ddd_documentation_contract.py +++ b/tests/test_ddd_documentation_contract.py @@ -17,7 +17,6 @@ def test_context_map_records_mcp_as_protocol_adapter_not_shared_kernel(self) -> self.assertIn("Anti-Corruption Layer", context_map) self.assertIn("MCP adapter", context_map) self.assertIn("originweave-core", context_map) - self.assertIn("Adapters", context_map) self.assertIn("must not depend outward on protocol adapters", context_map) def test_ubiquitous_language_keeps_authority_terms_distinct(self) -> None: From 68d8a670ccfe0efde2543722d660dc235673402b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:43:25 +0900 Subject: [PATCH 06/13] docs(ddd): correct MCP-to-policy dependency direction --- docs/context-map.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/context-map.md b/docs/context-map.md index f71f4458d..ef5c68132 100644 --- a/docs/context-map.md +++ b/docs/context-map.md @@ -28,17 +28,18 @@ External MCP client | MCP adapter | generic integration / ACL | originweave-mcp | +---------+----------+ - | typed ActionKind / Capability / RiskClass + | route/action equality, then ordinary policy evaluation v +--------------------+ +----------------------+ | Policy decision |------->| Browser authority | | originweave-policy | | originweave-core | +--------------------+ +----------------------+ - ^ + ^ ^ + | | + +------ typed request ------+ | +-------------------+-------------------+ | | | - | | | +-------+--------+ +-------+--------+ +-------+--------+ | Destination | | Evidence | | Resource | | authority | | contracts | | governance | @@ -66,11 +67,11 @@ Relationship: **Anti-Corruption Layer / conformist at the protocol edge**. The MCP adapter may depend on stable OriginWeave action vocabulary from `originweave-core`. External MCP method names, tool names, protocol versions, cursors, and request metadata remain adapter types. They must not be promoted into `originweave-core` domain entities. The adapter maps a bounded, validated MCP request to an existing typed action kind and does not invent capabilities or approvals. -### Policy decision → MCP adapter +### MCP adapter → policy decision Relationship: **published contract consumption**. -`originweave-policy` may consume the adapter's validated route token only to prove route/action equality before applying the normal policy decision. Policy owns authorization invariants; MCP owns protocol validation. Neither context may absorb the other's responsibility. +After the adapter proves MCP route/action equality, it may call the protocol-independent policy API published by `originweave-policy`. Policy owns authorization invariants and depends only on stable OriginWeave domain contracts; it does not import MCP DTOs or `ValidatedMcpToolCall`. MCP owns protocol validation and the protocol-to-policy bridge. Neither context may absorb the other's responsibility. ### Destination authority → browser authority contracts @@ -99,7 +100,7 @@ Evidence and resource governance expose bounded value contracts. Browser/protoco ## Dependency rules 1. Domain/security contracts must not import MCP, BiDi, CDP, Chromium SDK, HTTP client, persistence, UI, or provider DTOs. -2. Protocol adapters may depend inward on stable OriginWeave contracts; stable contracts must not depend outward on protocol adapters. +2. Protocol adapters may depend inward on stable OriginWeave contracts and policy ports; stable contracts and policy must not depend outward on protocol adapters. 3. Policy authorization remains centralized in `originweave-policy`; adapters cannot duplicate or weaken it. 4. Cross-context calls use public crate APIs or explicit application ports. Direct access to another context's internals is forbidden. 5. No context may infer authority from another context's success. Each boundary emits evidence specific to the invariant it proves. @@ -108,4 +109,4 @@ Evidence and resource governance expose bounded value contracts. Browser/protoco ## Machine-checkable fitness -`tests/test_repository_contract.py` enforces the first MCP ownership slice introduced with PR #272: `originweave-mcp` is a workspace package, MCP routing does not live under `originweave-core`, the adapter depends only on `originweave-core`, and policy imports the validated MCP route from the adapter crate. Additional context relationships should gain equivalent import/dependency fitness checks when their production boundaries land. +`tests/test_repository_contract.py` enforces the first MCP ownership slice introduced with PR #272: `originweave-mcp` is a workspace package, MCP routing does not live under `originweave-core`, the adapter depends inward on `originweave-core` and `originweave-policy`, and policy depends only on `originweave-core` without importing MCP protocol types. The adapter owns the route/action guard and delegates accepted routes to the ordinary policy evaluator. Additional context relationships should gain equivalent import/dependency fitness checks when their production boundaries land. From a888359a2bc0d3ad009816cccbf7528833e7f9d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:43:48 +0900 Subject: [PATCH 07/13] docs(ddd): align MCP traceability with inward dependency direction --- docs/traceability/mcp-authority-route.md | 25 +++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/traceability/mcp-authority-route.md b/docs/traceability/mcp-authority-route.md index b16d8d8ed..ef4a4a817 100644 --- a/docs/traceability/mcp-authority-route.md +++ b/docs/traceability/mcp-authority-route.md @@ -3,7 +3,7 @@ - **`tools/call` capability maturity:** `IMPLEMENTED_ON_PROTECTED_MAIN` - **`tools/list` capability maturity:** `IMPLEMENTED_ON_PROTECTED_MAIN` - **Protected-main owning work:** merged PR #168 (`tools/call`) and merged PR #170 (`tools/list`) -- **Bounded-context correction:** active PR #272 moves MCP protocol contracts from `originweave-core` to `originweave-mcp` without changing routing or policy semantics +- **Bounded-context correction:** active PR #272 moves MCP protocol contracts from `originweave-core` to `originweave-mcp` without changing routing or authorization semantics - **Complete MCP adapter status:** `PLANNED` - **Governing decision:** ADR 0107 @@ -13,7 +13,7 @@ Protected main at `542ca1e9c0a863595b8b6697790005d2471f5413` contains the bounde The protected-main implementation validates represented stateless routing envelopes, bounds and syntax-validates attacker-controlled method and tool-name fields before correlation, maps only the reviewed `originweave.*` catalog to existing typed actions, derives discovery metadata from the same catalog, and rejects route/action mismatch before ordinary deterministic policy evaluation. Methods are nonempty reviewed-ASCII routing tokens of at most 64 bytes; tool names are nonempty reviewed-ASCII identifiers of at most 128 bytes. Invalid method metadata remains distinct from a bounded but unsupported MCP method. -A successful `ValidatedMcpToolCall` proves routing integrity only. It grants no capability, origin, approval, secret, browser, tenant, persistence, network, or evidence authority. `originweave_policy::evaluate_mcp` still delegates to the ordinary policy evaluator after the route/action match. +A successful `ValidatedMcpToolCall` proves routing integrity only. It grants no capability, origin, approval, secret, browser, tenant, persistence, network, or evidence authority. On protected main the route/action bridge still resides in `originweave-policy`; active PR #272 moves that protocol-specific bridge to `originweave-mcp`, where `originweave_mcp::evaluate_mcp` checks route/action equality and then delegates to the protocol-independent `originweave_policy::evaluate`. The protected-main `tools/list` contract requires matching MCP protocol metadata, required client-capability presence, bounded and syntax-validated routing/body methods, exact `tools/list` routing, and no caller-supplied cursor because the fixed catalog issues none. Its result is one complete page with zero freshness, private cache scope, and no continuation cursor. Discovery metadata grants no OriginWeave action authority. @@ -23,10 +23,11 @@ Protected main still places the MCP protocol implementation under `crates/origin - introduces `crates/originweave-mcp` as the MCP protocol-adapter bounded context; - moves the existing routing/discovery implementation without semantic changes; -- moves protocol-boundary tests with the adapter; +- moves protocol-boundary tests and the MCP-to-policy binding tests with the adapter; - keeps `originweave-core` as the stable shared action/authority vocabulary; -- makes `originweave-policy` consume `ValidatedMcpToolCall` from the adapter boundary; and -- adds a machine-checkable repository fitness test preventing MCP protocol code from returning to core. +- keeps `originweave-policy` protocol-independent and dependent only on `originweave-core`; +- makes `originweave-mcp` depend inward on the stable core vocabulary and the published policy evaluator; and +- adds a machine-checkable repository fitness test preventing MCP protocol code from returning to core or policy from depending outward on MCP. PR #272 is active-PR evidence, not protected-main behavior. Until it merges, the protected-main source paths below remain the shipped ownership truth even though the architectural defect is known. @@ -62,16 +63,18 @@ Protected-main production/test surfaces before PR #272 are: - `crates/originweave-core/src/mcp.rs` — bounded deterministic catalog plus `tools/call` and `tools/list` protocol validation; - `crates/originweave-core/tests/mcp_authority_route.rs` — action mapping, method/tool bounds, malformed inputs, version/method/header-body correlation, and error contracts; - `crates/originweave-core/tests/mcp_tools_list_cache.rs` — fixed discovery result/cache semantics, protocol/client metadata, method validation, routing correlation, cursor rejection, and public errors; -- `crates/originweave-policy/src/lib.rs` — `evaluate_mcp` route/action guard before normal policy evaluation; and -- `crates/originweave-policy/tests/mcp_route_binding.rs` — confused-deputy and policy-preservation evidence. +- `crates/originweave-policy/src/lib.rs` — protected-main `evaluate_mcp` route/action guard before normal policy evaluation; and +- `crates/originweave-policy/tests/mcp_route_binding.rs` — protected-main confused-deputy and policy-preservation evidence. -On active PR #272 the same protocol implementation and its tests move to: +On active PR #272 the protocol implementation and protocol-owned evidence move to: - `crates/originweave-mcp/src/routing.rs`; -- `crates/originweave-mcp/tests/mcp_authority_route.rs`; and -- `crates/originweave-mcp/tests/mcp_tools_list_cache.rs`. +- `crates/originweave-mcp/src/lib.rs` — adapter-owned `evaluate_mcp` bridge that delegates to `originweave_policy::evaluate` only after route/action equality; +- `crates/originweave-mcp/tests/mcp_authority_route.rs`; +- `crates/originweave-mcp/tests/mcp_tools_list_cache.rs`; and +- `crates/originweave-mcp/tests/policy_route_binding.rs`. -The repository fitness contract in `tests/test_repository_contract.py` verifies the new package boundary, prevents `originweave-core/src/mcp.rs` from reappearing, restricts `originweave-mcp` to the stable core dependency, and requires policy to import the validated MCP route through the adapter crate. +The repository fitness contract in `tests/test_repository_contract.py` verifies the new package boundary, prevents `originweave-core/src/mcp.rs` from reappearing, requires `originweave-mcp` to depend inward on `originweave-core` and `originweave-policy`, and requires `originweave-policy` to depend only on core without importing MCP protocol types. Exact current-head CI/security/review evidence must be regenerated after every branch mutation. Protected-main evidence proves only the integrated foundations; predecessor or protected-main results are not current-head proof for PR #272. From bdb38c25b40d5155f4390ee2a2ad5fb3e1ba07be Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 13:44:04 +0900 Subject: [PATCH 08/13] test(ddd): enforce documented MCP dependency direction --- tests/test_ddd_documentation_contract.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py index 584fcbcf6..400a8b391 100644 --- a/tests/test_ddd_documentation_contract.py +++ b/tests/test_ddd_documentation_contract.py @@ -17,7 +17,11 @@ def test_context_map_records_mcp_as_protocol_adapter_not_shared_kernel(self) -> self.assertIn("Anti-Corruption Layer", context_map) self.assertIn("MCP adapter", context_map) self.assertIn("originweave-core", context_map) + self.assertIn("originweave-policy", context_map) self.assertIn("must not depend outward on protocol adapters", context_map) + self.assertIn("MCP adapter → policy decision", context_map) + self.assertNotIn("Policy decision → MCP adapter", context_map) + self.assertIn("policy depends only on `originweave-core`", context_map) def test_ubiquitous_language_keeps_authority_terms_distinct(self) -> None: glossary = (ROOT / "docs/ubiquitous-language.md").read_text(encoding="utf-8") @@ -47,6 +51,9 @@ def test_mcp_traceability_names_current_and_active_ownership_separately(self) -> self.assertIn("active PR #272", trace) self.assertIn("crates/originweave-core/src/mcp.rs", trace) self.assertIn("crates/originweave-mcp/src/routing.rs", trace) + self.assertIn("originweave_mcp::evaluate_mcp", trace) + self.assertIn("originweave_policy::evaluate", trace) + self.assertIn("protocol-independent", trace) self.assertIn("active-PR evidence, not protected-main behavior", trace) From ace24ead793d171b01b346a7ace08333b734eb87 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 17:02:06 +0900 Subject: [PATCH 09/13] test(ddd): require product bounded-context vocabulary --- tests/test_ddd_documentation_contract.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py index 144bb9715..f594e44f4 100644 --- a/tests/test_ddd_documentation_contract.py +++ b/tests/test_ddd_documentation_contract.py @@ -24,6 +24,27 @@ def test_context_map_records_mcp_as_protocol_adapter_not_shared_kernel(self) -> self.assertIn("policy depends only on `originweave-core`", context_map) self.assertIn("route/action mismatch remains adapter-owned", context_map) + def test_context_map_names_product_bounded_contexts_explicitly(self) -> None: + context_map = (ROOT / "docs/context-map.md").read_text(encoding="utf-8") + for bounded_context in ( + "Browser Session", + "Profile/Identity Boundary", + "Semantic Observation", + "Typed Action Execution", + "Resource Governance", + "Scraping/Extraction", + "Provenance", + "Extension Policy", + "Secret Broker", + "Agent Integration", + ): + with self.subTest(bounded_context=bounded_context): + self.assertIn(bounded_context, context_map) + self.assertIn("protected-main", context_map) + self.assertIn("active PR", context_map) + self.assertIn("planned", context_map) + self.assertIn("does not transfer authority", context_map) + def test_ubiquitous_language_keeps_authority_terms_distinct(self) -> None: glossary = (ROOT / "docs/ubiquitous-language.md").read_text(encoding="utf-8") for term in ( From d75462b91fb3b3d2dbbaf01a153e3e0ca6b7a539 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 17:09:32 +0900 Subject: [PATCH 10/13] docs(ddd): name product bounded contexts explicitly --- docs/context-map.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/context-map.md b/docs/context-map.md index 96eba2f95..0546dcc01 100644 --- a/docs/context-map.md +++ b/docs/context-map.md @@ -16,7 +16,26 @@ This map records bounded-context ownership and allowed dependency direction. Pro | Browser Agent Protocol | Supporting | `originweave-bap` | Browser-agent protocol contracts and lifecycle vocabulary | | MCP protocol adapter | Generic integration | `originweave-mcp` (**active PR #272**) | MCP version/method/tool discovery, routing integrity, and translation into typed OriginWeave action contracts; grants no execution authority | -Planned contexts such as browser sessions, HTTP, proxy, observation, typed browser execution, secret brokering, WebDriver BiDi/CDP adapters, WARC/PROV persistence, and release benchmarks remain planned until code reaches protected `main`. Their planned names do not grant ownership to unrelated current crates. +## Product bounded contexts + +The product vocabulary below names stable responsibility boundaries even when the final implementation has not reached protected `main`. A planned or active-PR context is not shipment truth and must not be used to claim implemented browser behavior. + +| Bounded Context | Classification | Current implementation status | Authority boundary | +|---|---|---|---| +| Browser Session | Core | **planned / active-PR work**, not integrated on protected-main | Owns browser-process/session lifetime and attachment identity; session existence does not grant action, network, profile, secret, or evidence authority | +| Profile/Identity Boundary | Core | **planned / active-PR work**, not integrated on protected-main | Owns explicit profile selection, isolation, and identity attachment; the user default profile is never ambient agent authority | +| Semantic Observation | Core | **planned / active-PR work**, not integrated on protected-main | Owns source-bound semantic observation and node identity; observed page text remains untrusted input and does not become an instruction | +| Typed Action Execution | Core | **planned / active-PR work**, not integrated on protected-main | Owns execution of already-authorized typed browser actions; protocol or selector validity alone does not authorize execution | +| Resource Governance | Supporting | `originweave-resource` contracts are on protected-main; wider browser/process enforcement remains incremental | Owns bounded resource budgets and deterministic mitigation; budget availability does not confer browser or policy authority | +| Scraping/Extraction | Supporting | **planned / active-PR work**, not integrated as a complete bounded context on protected-main | Owns extraction semantics and crawl-specific constraints; extracted content is data, not trusted control input | +| Provenance | Supporting | `originweave-evidence` contracts are on protected-main; durable WARC/PROV persistence remains planned | Owns source/evidence identity and redaction-safe provenance; an evidence record proves only its declared invariant | +| Extension Policy | Supporting | **planned / active-PR work**, not integrated as a complete bounded context on protected-main | Owns extension/native-messaging admission and isolation; extension installation or connection does not inherit session authority | +| Secret Broker | Supporting | policy contracts for broker-handle use exist; complete broker lifecycle remains planned | Owns opaque secret-handle lifecycle and delivery; secret values never enter model-visible context and handles grant only their explicit scope | +| Agent Integration | Generic integration | BAP contracts are on protected-main; MCP ownership repair is **active PR #272**; complete MCP/WebMCP runtime remains planned | Owns external agent-protocol anti-corruption adapters; protocol success does not transfer policy, browser, network, secret, approval, or evidence authority | + +These contexts may share published contracts, but cross-context success **does not transfer authority**. New implementation must land in the context that owns the invariant instead of using `originweave-core`, an adapter, or another convenient technical package as a temporary dumping ground. + +Planned contexts such as HTTP, proxy, WebDriver BiDi/CDP adapters, WARC/PROV persistence, and release benchmarks remain planned until code reaches protected `main`. Their planned names do not grant ownership to unrelated current crates. ## Context relationships @@ -110,4 +129,4 @@ Evidence and resource governance expose bounded value contracts. Browser/protoco ## Machine-checkable fitness -`tests/test_repository_contract.py` enforces the first MCP ownership slice introduced with PR #272: `originweave-mcp` is a workspace package, MCP routing does not live under `originweave-core`, the adapter depends inward on `originweave-core` and `originweave-policy`, and policy depends only on `originweave-core` without MCP protocol or adapter vocabulary. The adapter owns route/action integrity rejection and delegates only matching routes to the ordinary policy evaluator. `tests/test_ddd_documentation_contract.py` binds this Context Map to the same ownership language. Additional context relationships should gain equivalent import/dependency fitness checks when their production boundaries land. +`tests/test_repository_contract.py` enforces the first MCP ownership slice introduced with PR #272: `originweave-mcp` is a workspace package, MCP routing does not live under `originweave-core`, the adapter depends inward on `originweave-core` and `originweave-policy`, and policy depends only on `originweave-core` without MCP protocol or adapter vocabulary. The adapter owns route/action integrity rejection and delegates only matching routes to the ordinary policy evaluator. `tests/test_ddd_documentation_contract.py` binds this Context Map to the same ownership language and the explicit product bounded-context vocabulary above. Additional context relationships should gain equivalent import/dependency fitness checks when their production boundaries land. From 40796205c6c5054be24d057277e229f987b1a5b0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 17:11:57 +0900 Subject: [PATCH 11/13] docs(ddd): map tactical building blocks to live contracts --- docs/tactical-ddd-map.md | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/tactical-ddd-map.md diff --git a/docs/tactical-ddd-map.md b/docs/tactical-ddd-map.md new file mode 100644 index 000000000..2f2d3d6e2 --- /dev/null +++ b/docs/tactical-ddd-map.md @@ -0,0 +1,70 @@ +# OriginWeave Tactical DDD Map + +This document classifies the tactical DDD building blocks that actually exist in OriginWeave. It is deliberately conservative: a type is not called an Entity, Aggregate, Repository, or Domain Event merely because that pattern may be useful later. Protected `main` is shipment truth; active PR #272 is identified separately; planned work is not promoted into the current model. + +## Classification rules + +- **Value Object**: immutable domain/security meaning is carried by validated values and equality, not by a mutable lifecycle identity. +- **Entity**: identity persists while domain state changes through an owned lifecycle. +- **Aggregate / Aggregate Root**: one root owns a consistency boundary and is the only mutation entry point for the aggregate invariant. +- **Domain Service**: protocol-independent domain logic that does not naturally belong to one Value Object or Entity. +- **Repository**: an inward-facing domain/application port for loading and persisting an Aggregate or other explicitly durable domain state. A database client, table, object-store SDK, or adapter is not itself the domain Repository contract. +- **Domain Event**: a domain-owned fact emitted after a domain state transition. External protocol events such as WebDriver BiDi notifications are integration events until an adapter translates and admits them into a domain-owned fact. +- **Invariant**: a condition that must remain true at the owning boundary and must fail closed when it cannot be established. + +## Current tactical model + +| Building block | Current code/API truth | Status | Required interpretation | +|---|---|---|---| +| Value Object | `originweave_core::Origin`, `BrowserSessionId`, `BrowsingContextId`, `DocumentEpoch`, `ObservedNodeHandle`, `ActionRequest`, `PolicyContext`, `ApprovalScope` | protected-main | Validated immutable authority/security values. Their identifiers do not by themselves imply mutable Entity semantics. | +| Value Object | `originweave_policy::SensitiveDataAuthority`, `SensitiveDataRequest`, `DisclosureScope`, `SensitiveValueHandleScope`, `HandleUseRequest`, `Decision`, `DisclosureDecision`, `HandleUseDecision` | protected-main | Purpose-bound authority and deterministic decision values; none stores protected field bytes or owns broker persistence. | +| Entity | No explicit mutable domain Entity is owned by protected-main core/policy or active PR #272 | current truth | `BrowserSessionId` and `BrowsingContextId` are identities, not Entities. Do not call a future browser process/session object an Entity until its lifecycle state and invariants are implemented behind an owned API. | +| Aggregate / Aggregate Root | No explicit Aggregate Root is implemented by protected-main core/policy or active PR #272 | current truth | The planned Browser Session bounded context may eventually own an Aggregate Root, but the name is not a shipment claim. Protocol adapters must not become substitute aggregate roots. | +| Domain Service | `originweave_policy::evaluate`, `evaluate_disclosure`, `evaluate_handle_use` | protected-main | Pure deterministic policy services. They perform no browser/network/storage I/O and return explicit fail-closed decisions. | +| Repository | No domain Repository contract is introduced by protected-main core/policy or active PR #272 | current truth | Durable WARC/PROV, tenant persistence, KMS/object storage, retention, legal hold, deletion, and offline replay remain issue #199 work. When persistence lands, inward repository ports must remain provider-neutral and storage adapters must depend inward on them. | +| Domain Event | No explicit OriginWeave domain-event type is introduced by protected-main core/policy or active PR #272 | current truth | WebDriver BiDi `browsingContext.navigationCommitted`, MCP requests, HTTP messages, and other wire events are adapter-owned integration events. They cannot be placed in core or treated as domain authority without translation, correlation, and invariant admission. | +| Invariant | Canonical origin admission, authority-bound observed-node reuse, deterministic action policy, purpose-bound sensitive-data scope, and fail-closed approval/secret rules | protected-main | Constructors/evaluators own these conditions. Callers cannot recover authority from a failed or ambiguous validation. | +| Invariant | MCP method/tool/action correlation and route/action equality | active PR #272 | This is adapter-owned protocol integrity. `McpRouteRejection` does not become a policy denial and the adapter delegates only an admitted typed action to protocol-independent policy. | + +## Aggregate and Entity admission rule + +The first real Chromium Agent Task vertical must not manufacture an Aggregate merely to satisfy a diagram. When browser-session lifecycle code reaches its owning bounded context, classify it as an Entity or Aggregate Root only if all of the following are true in code and tests: + +1. a stable domain identity survives meaningful state transitions; +2. one owning API controls those transitions; +3. the consistency boundary is explicit, including session/context/origin/document-epoch relationships; +4. teardown and crash recovery close the lifecycle rather than leaving adapter-owned ambient state; +5. external BiDi/CDP/MCP identifiers remain ACL/integration values and cannot mutate the domain object directly; +6. tests prove stale epoch, wrong context, wrong origin, replay, teardown, and crash paths fail closed. + +Until then, current identifiers and immutable authority values remain Value Objects. + +## Domain-service boundary + +`originweave-policy` is the current clearest Domain Service boundary. Its evaluators accept complete typed domain values and return deterministic decisions. They do not open sockets, call Chromium, parse MCP wire DTOs, resolve secrets, persist records, or invoke an LLM. Browser/network/secret/evidence adapters may consume a decision, but successful adapter I/O cannot reverse or widen that decision. + +MCP remains an external protocol ACL. Active PR #272 may translate MCP method/tool vocabulary into an existing typed `ActionRequest` and call the published policy API. Core and policy must not import MCP, WebDriver BiDi, CDP, Chromium SDK, HTTP-client, provider, persistence, or UI DTOs. + +## Repository and database truth + +There is no OriginWeave-owned production database or domain Repository introduced by PR #272/#273. That absence is intentional and machine-visible; documentation must not draw repository boxes or ERD tables as if they were shipped. + +Issue #199 owns the durable extraction/evidence direction. When that work introduces persistence: + +- the domain/application Repository port is defined independently of PostgreSQL, object-storage, KMS, WARC transport, or cloud-provider SDK types; +- adapters implement the port and preserve tenant, retention, legal-hold, deletion, replay, and cryptographic-evidence invariants; +- database objects use multi-word `snake_case` names and represent only data owned by the bounded context; +- cross-context authoritative tables are not copied into OriginWeave and cross-service SQL is not used as an integration contract; +- `context-graph-contracts` and `enterprise-architecture-core` remain the owners of shared provenance/context/identity/architecture contracts when those shared contracts are required. + +## Domain-event boundary + +A protocol notification is not a Domain Event. In particular, WebDriver BiDi `browsingContext.navigationCommitted` is external evidence from a browser adapter. It becomes usable domain state only after the adapter correlates the event to the pinned session/context, establishes the canonical origin/document epoch transition, applies bounds, and invokes the owning domain/application contract. A command ACK is likewise not a post-condition event. + +If OriginWeave later publishes domain events, each event must have an owning bounded context, typed payload, version, causation/correlation identity, explicit invariant that was established before emission, and tests proving that wire/protocol DTOs do not leak into the event contract. Shared event/provenance schemas should reuse released `context-graph-contracts` contracts rather than duplicate them locally. + +## Fitness and traceability + +`tests/test_ddd_documentation_contract.py` keeps this tactical classification explicit alongside `docs/context-map.md` and `docs/ubiquitous-language.md`. `tests/test_repository_contract.py` enforces the MCP dependency direction introduced by active PR #272. Rust unit/integration tests remain the authority for the constructors and deterministic evaluators named above; documentation tests do not substitute for production behavior, exact-head CI, coverage, security, or a real Chromium E2E. + +Any future code change that introduces an Entity, Aggregate Root, Repository, or Domain Event must update this file, the Context Map, relevant ADR/API/ERD material, and executable fitness tests in the same change. Planned work must remain marked planned until it reaches protected `main`. \ No newline at end of file From 6dd4f1d71bc1c00684629b6cfe1c1f6e35cafe72 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 17:12:21 +0900 Subject: [PATCH 12/13] test(ddd): enforce tactical pattern truth --- tests/test_ddd_documentation_contract.py | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py index f594e44f4..68f97f606 100644 --- a/tests/test_ddd_documentation_contract.py +++ b/tests/test_ddd_documentation_contract.py @@ -45,6 +45,32 @@ def test_context_map_names_product_bounded_contexts_explicitly(self) -> None: self.assertIn("planned", context_map) self.assertIn("does not transfer authority", context_map) + def test_tactical_ddd_map_keeps_patterns_truthful_and_protocol_independent(self) -> None: + tactical_map = (ROOT / "docs/tactical-ddd-map.md").read_text(encoding="utf-8") + for pattern in ( + "Value Object", + "Entity", + "Aggregate / Aggregate Root", + "Domain Service", + "Repository", + "Domain Event", + "Invariant", + ): + with self.subTest(pattern=pattern): + self.assertIn(pattern, tactical_map) + + self.assertIn("No explicit mutable domain Entity", tactical_map) + self.assertIn("No explicit Aggregate Root", tactical_map) + self.assertIn("No domain Repository contract", tactical_map) + self.assertIn("No explicit OriginWeave domain-event type", tactical_map) + self.assertIn("originweave_policy::evaluate", tactical_map) + self.assertIn("browsingContext.navigationCommitted", tactical_map) + self.assertIn("integration events", tactical_map) + self.assertIn("A command ACK is likewise not a post-condition event", tactical_map) + self.assertIn("multi-word `snake_case`", tactical_map) + self.assertIn("context-graph-contracts", tactical_map) + self.assertIn("must not import MCP, WebDriver BiDi, CDP", tactical_map) + def test_ubiquitous_language_keeps_authority_terms_distinct(self) -> None: glossary = (ROOT / "docs/ubiquitous-language.md").read_text(encoding="utf-8") for term in ( From f34212f9dff07deb70dd5265ecbb00f36b0f69b0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:07:00 +0900 Subject: [PATCH 13/13] test(ddd): enforce MCP adapter dependency direction --- tests/test_ddd_documentation_contract.py | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_ddd_documentation_contract.py b/tests/test_ddd_documentation_contract.py index 68f97f606..a463a0a26 100644 --- a/tests/test_ddd_documentation_contract.py +++ b/tests/test_ddd_documentation_contract.py @@ -3,6 +3,7 @@ from __future__ import annotations import pathlib +import tomllib import unittest ROOT = pathlib.Path(__file__).resolve().parents[1] @@ -24,6 +25,31 @@ def test_context_map_records_mcp_as_protocol_adapter_not_shared_kernel(self) -> self.assertIn("policy depends only on `originweave-core`", context_map) self.assertIn("route/action mismatch remains adapter-owned", context_map) + def test_cargo_dependency_direction_enforces_mcp_anti_corruption_layer(self) -> None: + manifests: dict[str, dict[str, object]] = {} + for crate in ("originweave-core", "originweave-policy", "originweave-mcp"): + manifest_path = ROOT / "crates" / crate / "Cargo.toml" + manifests[crate] = tomllib.loads(manifest_path.read_text(encoding="utf-8")) + + core_dependencies = manifests["originweave-core"].get("dependencies", {}) + policy_dependencies = manifests["originweave-policy"].get("dependencies", {}) + mcp_dependencies = manifests["originweave-mcp"].get("dependencies", {}) + + self.assertNotIn("originweave-mcp", core_dependencies) + self.assertNotIn("originweave-mcp", policy_dependencies) + self.assertEqual( + policy_dependencies.get("originweave-core"), + {"path": "../originweave-core"}, + ) + self.assertEqual( + mcp_dependencies.get("originweave-core"), + {"path": "../originweave-core"}, + ) + self.assertEqual( + mcp_dependencies.get("originweave-policy"), + {"path": "../originweave-policy"}, + ) + def test_context_map_names_product_bounded_contexts_explicitly(self) -> None: context_map = (ROOT / "docs/context-map.md").read_text(encoding="utf-8") for bounded_context in (