Architecture

OpenAPI surface review boundary

The separately non-default openapi-review feature requires explicit --openapi-review --profile web-review. Its single native action remains in the same WebAssessmentRuntime, exact-origin authority, redirect-disabled client, broker, budget, evidence registry, and final report. It selects one document at most and uses a bodyless GET candidate plus exact replay. The transport-neutral catalog cannot grant execution authority, and described API operations are not dispatched. See OpenAPI surface review.

The separately non-default rest-review feature requires explicit --profile web-review --openapi-review --rest-review. It consumes only a replay-stable OpenAPI catalog committed by that same assessment, selects at most one anonymous bodyless exact-origin zero-input GET, and runs candidate plus replay as two requests and one logical active verification through the same WebAssessmentRuntime, broker, budget, exact-origin authority, evidence registry, completeness lifecycle, and final report. It emits at most Informational / KnowledgeOnly, executes no write, materializes no parameter or body, uses no credential/cookie, and does not chain to SQL, SSTI, XSS, authorization, SSRF, or upload review.

The separately non-default secret-exposure-review feature requires explicit --profile web-review --secret-exposure-review. It adds one shared observer to the existing ordinary anonymous response commit path, not a collector client, subject, action, request, or second scanner. Only complete status-200 uncoded textual GET bodies with an exact final URL, empty explicit request headers, consistent byte/length evidence, and a successful evidence commit may enter the fixed bounded detector catalogue. The collector stages value-free counts; the committed ledger is the report authority. No matched bytes, fragments, reversible encodings, or public secret hashes cross into evidence or reports. Every observed body, including an evaluated zero-match, uses value-free replacement lineage instead of a public whole-body digest and withholds downstream generic/WordPress body-derived projection. The audit makes that suppressed coverage explicit; the finite detector catalogue cannot establish that an unmatched body contains no other low-entropy secret. Its items are Informational / KnowledgeOnly; validity, ownership, source authentication, provider acceptance, exploit execution, and impact validation are outside this slice. Authenticated supplied-session bodies are not selected. See Passive response secret-exposure review.

The separately non-default tls-observation feature requires explicit --profile web-review --tls-observation. It changes only the configuration of the assessment clients that already own selected work so successful responses can expose Reqwest TLS information to one shared bounded collector. It adds no subject, request, connection, handshake or retry. The collector reduces one backend-exposed leaf DER certificate immediately and retains no DER bytes or readable names. Negotiated protocol/cipher/ALPN, full chain, connection reuse, handshake kind and resumption remain unavailable at this backend seam; this slice does not create a second TLS client to manufacture those fields. See Existing-connection TLS observation.

The separate non-default tls-negotiation-review feature is an explicit active child, not an extension of passive TLS observation. With --profile web-review --tls-negotiation-review, the shared authority may mint one fixed, sequential TLS 1.3/TLS 1.2 matrix for the selected DNS HTTPS host/SNI/port. Direct sockets remain confined to that child and share parent request, active-verification, response-byte, deadline, and cancellation truth. The child sends no HTTP/application bytes or credentials; unsupported legacy rows perform no network work. See Active TLS negotiation review.

Local reconnaissance snapshot import uses the opposite side of the same authority boundary: the CLI owns one explicit hardened local-file read, the scanner parser owns a closed bounded inert model, and the normal runtime owns no recon transport at all. The typed snapshot is attached only after assessment composition and therefore cannot influence planning, subjects, broker permits, knowledge authority, evidence commits, or finding construction. See Local reconnaissance snapshot import.

The separately non-default wordpress-review feature also stays inside that single assessment boundary. With explicit --profile web-review --wordpress-review, it receives only the existing complete root-response HTML observation and optional CLI-validated local context/catalogue values. It owns no client, broker, budget, provider, filesystem path, or independent report and adds zero target/provider requests. Its bounded typed interpretation is folded into the same evidence registry, completeness decision, item set, and final report. Public hints may yield one Informational / KnowledgeOnly surface item; operator declarations and advisory bibliography add no execution or claim authority. Exploit execution and impact validation are not performed.

Metadata discovery remains a separately explicit use of the assessment's one broker and budget. Without a page scope it retains the entry-only schedule. --wordpress-page-scope observed stages bounded first-hop candidates from the entry, then reuses only eligible anonymous HTML GET responses after their normal same-run evidence commits. It dispatches no page request. Once the eligible general collection is complete, the runtime freezes the combined component candidates and executes metadata collection once before final composition. Callback-time transport data cannot authorize this work, and secondary pages cannot replace the application/layout authority frozen at the entry. See ADR 0028.

This document defines dependency direction and runtime ownership for the unreleased Termivar 0.10.0-alpha.3 development source line. It is a design contract, not a production-readiness claim.

The editable diagrams.net source is architecture.drawio. A presentation- and print-friendly export is available as architecture.svg.

Termivar runtime and crate architecture

Current workspace

Crate Responsibility May depend on
termivar-core Default transport-neutral evidence, reasoning, ontology, outcome, predicate, and run-report contracts; the pre-quarantine facade is feature-gated External libraries only
termivar-scanner Phase/plugin traits, deterministic reasoning, runner, detection, opt-in bounded report rendering, Experimental host-owned Lua/coordination execution, and a non-default sealed native OAST provider adapter termivar-core; termivar-oast only through the non-default native-provider client feature
termivar-exploit Preview, non-published exploit manifest/catalog plus disconnected non-default authorized orchestration contracts; only an in-memory lab fixture executes termivar-core only where shared opaque identity/evidence contracts are required
termivar-artifact Preview, non-published exact/wildcard buffer and bounded-reader signature observations; no path, network, process, exploit, or verdict authority External libraries only
termivar-oast Preview, unpublished self-hosted loopback HTTP callback mailbox plus fixed server-side management protocol and separately gated exact-origin HTTPS client; no target, evidence, report, or finding authority External libraries only
termivar-proxy Experimental fixed-upstream TCP relay; no HTTP/TLS interception External libraries only
termivar-api Library health router and its local unsupported-listener error External libraries only
termivar-cli Composition root and command routing termivar-scanner by default; termivar-api, termivar-proxy, and termivar-artifact only through explicit adapter features

xtask is repository tooling rather than a runtime layer. It may orchestrate workspace commands but application crates must not depend on it. Its scanner-salvage and waf-evasion-salvage checks validate two strict, separate historical source epochs against local Git objects and deterministic generated reports. The first covers the deleted 38-file pre-workspace scanner tree; the second covers 13 files and 39 components from the post-workspace WAF/evasion quarantine wave. Neither check compiles or executes historical source. The ledgers classify recovery candidates, superseded implementations, and rejected behavior but create no application dependency, runtime capability, execution authority, or claim authority.

The repository root is a virtual Cargo workspace and has no src/ tree. Rust source must live under a declared workspace package; otherwise it would be excluded from build, test, documentation, release, and quality gates. The architecture preflight rejects a virtual root containing src/. It also rejects any top-level .rs file in the examples package that is not declared as a Cargo target, so example source cannot silently fall outside compilation.

flowchart TD
    CLI[termivar-cli] --> Scanner[termivar-scanner]
    CLI -. "api-adapter" .-> API[termivar-api]
    CLI -. "proxy-adapter" .-> Proxy[termivar-proxy]
    CLI -. "artifact-adapter" .-> Artifact["termivar-artifact<br/>bounded observations"]
    Scanner --> Core["termivar-core<br/>Evidence / Reasoning / Outcomes / Reports"]
    Scanner -. "oast-native-provider" .-> OAST
    Exploit["termivar-exploit<br/>Preview metadata + opt-in lab orchestration"] --> Core
    OAST["termivar-oast<br/>self-hosted raw-free HTTP callback mailbox"]

termivar-oast is an auxiliary service, not a target-assessment runtime. Its production provider binds only to loopback behind an operator-controlled HTTPS reverse proxy and exposes a fixed session/allocation/poll/cleanup protocol plus constant public GET/HEAD callback handling. It retains only bounded opaque HTTP event records in memory. Its exact-origin HTTPS client has one non-default, sealed scanner host-library consumer, and both remain absent from the CLI release-bundle. On their own, neither can select a target, register a WebAssessmentRuntime action, create evidence or reports, or make an SSRF claim. See the native OAST provider contract.

The non-default native provider adapter is a single sealed host-library edge from termivar-scanner to the reviewed termivar-oast HTTPS client. It does not add another target broker or runtime. A host-minted permit narrows one parent assessment budget to one exact provider origin, one assessment and epoch, the four fixed management operations, and explicit request, byte, poll, callback, and wall-time ceilings. The adapter performs no work in Drop, and provider identifiers and secrets remain outside evidence and reporting. See native OAST provider authority.

This dependency edge supplies auxiliary callback correlation only. Its closed product callers are the separately gated SSRF OAST query review and controlled XML external-entity review. Each reuses the parent target broker/budget and one narrowing provider authority, produces one final composed report, and requires two independently bound callbacks for at most NeedsReview / KnowledgeOnly. The SSRF review binds one exact query occurrence to an inert .invalid control plus callback candidate/replay. The XML review binds one operator-owned disposable endpoint to runtime-generated control/candidate/replay POST bodies; it does not accept arbitrary XML or prove XXE, file access, exfiltration, or impact. Legacy phases, plugins, Lua, exploit orchestration, unrelated API review families, and release-bundle cannot reach either path. See SSRF OAST query review and Controlled XML external-entity review.

termivar-artifact is a separate artifact-observation domain. Its library accepts caller-supplied bytes or bounded readers and owns no filesystem path, network, process, browser, or exploit authority. Only the CLI's non-default artifact-adapter may open one explicitly selected local regular file for a read-only scan; it performs no recursion and does not alter termivar scan. Signature matches are deterministic observations, never malware verdicts, vulnerabilities, or severity assignments. Repository signature discovery is an explicit non-scanning xtask artifact-catalog operation.

termivar-exploit is an independent workspace domain rather than part of the scanner product graph. termivar-scanner, termivar-cli, termivar-api, and termivar-proxy do not depend on it. Its V1 default library accepts bounded manifest bytes and performs deterministic validation and catalog queries. A non-default Preview feature adds host-minted grants, sealed deterministic plans, typed permits/receipts, and separate impact/cleanup lifecycle accounting. Only an in-memory canary integration fixture exercises that API. The crate owns no production target/network/process/browser/filesystem adapter, CLI command, or authority derived from metadata. Source-linked implementations are cooperative trusted code, not sandboxed third-party code. Repository-owned pack file discovery belongs to xtask, not the library. The historical termivar_scanner::post_exploitation metadata scaffold remains separately quarantined behind platform-models and is not imported or expanded by this domain.

The pre-quarantine Config, shared Error, lifecycle-event, ScanFinding, raw HTTP, vulnerability, and scan-result records remain in termivar-core only behind its non-default legacy-contracts feature for the pinned alpha compatibility baseline. termivar-scanner forwards that feature only for legacy-scanner and platform-models; the default decision runtime and the reporting feature cannot import those records. The scanner owns behavior such as EventBus, ScanRunner, ScanPhase, and Plugin. ScanFinding is a legacy phase compatibility contract; the Preview plugin and reporting contracts do not accept it. termivar-api owns its small adapter error locally and has no workspace-crate dependency.

No lower-level crate may depend on termivar-cli or termivar-api. A cycle between workspace crates is a release blocker.

Runtime ownership

flowchart TD
    Host["CLI / library host"] --> LegacyRunner["Legacy runner · opt-in"]
    LegacyRunner --> Pipeline["Ordered legacy phase pipeline"]
    Pipeline --> Discovery["Bounded discovery authority<br/>phases 2–4"]
    Discovery --> Crawl
    Discovery --> Directory["Directory · explicit opt-in"]
    Discovery --> Parameters
    Pipeline --> Verification["Bounded Active verification authority<br/>phases 5–9"]
    Pipeline --> RawLegacy["Raw legacy client<br/>phase 1 / custom phases"]
    Discovery --> DiscoveryRecords["INFO discovery observations"]
    Verification --> ReviewRecords["Report projection<br/>Unknown or knowledge-only NeedsReview"]
    Verification --> KnowledgeReceipt["SSRF probe receipt<br/>knowledge only · no outcome"]
    RawLegacy --> LegacyRecords["Unverified compatibility records"]
    DiscoveryRecords --> RunReport["Typed run report · Unknown observations"]
    ReviewRecords --> RunReport
    LegacyRecords --> RunReport
    RunReport -. "explicit reporting host" .-> Renderer["Bounded renderer · Preview"]
    Renderer --> Document["Host-owned document<br/>no persistence or verdict authority"]
    PluginHost["Linked plugin host · Preview"] --> PluginContext["Host-owned PluginContext<br/>scope · budget · broker · redaction"]
    PluginContext --> PluginCode["Plugin trait implementation"]
    PluginCode --> PluginEvidence["Recorded observations"]
    PluginEvidence --> HostVerification["Host reasoning / verification"]
    LibraryHost["Explicit library host"] -. "lua" .-> Lua["Bounded Lua VM<br/>Experimental · in-process"]
    LibraryHost -. "distributed" .-> Coordinator["Bounded coordinator<br/>Experimental · process-local"]
    LegacyRunner --> Events["Event Bus"]
    Events -. "optional host projection" .-> Observers["Telemetry consumers"]

This diagram describes the legacy Surface-A orchestration boundary. Its phase-two-to-four discovery and phase-five-to-nine verification envelopes do not make whole-run accounting metered: phase one and host-defined custom phases can retain raw direct-I/O authority. It also does not imply that the deterministic Surface-B runtime projects verification outcomes into findings, that a legacy NeedsReview outcome is a vulnerability verdict, that the optional renderer persists a document, or that a dashboard subscriber is composed by either CLI scan command.

The runner knows ScanPhase, not concrete phase implementations. The plugin registry knows Plugin, not concrete plugin types. A linked host constructs the execution request, the registry materializes the plugin context, and the host retains authorization, transport, redaction, provenance, and verification authority. Plugin observations do not automatically become findings. An opt-in PluginDecisionExecutor can forward registry observations through the deterministic runner when a host supplies the full execution request; no stock CLI composes that bridge. Native plugin execution and the ordered phase runner remain parallel paths, and neither CLI scan command loads plugin crates dynamically.

Scanner modules

Responsibility-dense scanner domains keep their established root source module as a facade and place implementation ownership in private child modules. Eight facades remain public modules; lua_engine and distributed remain private modules with reviewed crate-root re-exports. Existing public module and re-export paths remain compatible. This is a source-organization boundary, not a second runtime or a capability change.

Facade Private responsibility modules
plugin.rs metadata, host context, registry, execution, recorder, limits, and broker transport
decision_loop.rs commands, state, transition policy, and receipts
decision_runner.rs executor registry, execution, failures, and receipts
http_evidence.rs policy, probes, response projection, form controls, passive review, request broker, and review response
knowledge.rs store, snapshots, writes, relations, and indexes
rules.rs expressions, registry, evaluation, and engine
planner.rs model, policy, scoring, and selection
api_observation.rs model, ingestion, query, review, and cursor
lua_engine.rs source, registry, VM, execution, limits, and history
distributed.rs model, limits, coordinator, queue, lease, worker, recovery, and results

The historical phases/, legacy_discovery.rs, runner.rs, and event_bus.rs remain opt-in through legacy-scanner. reporting.rs remains the single bounded typed renderer. Optional detection, platform-model, ML, monitoring, compliance, and threat-intelligence modules retain their separate feature boundaries.

The private feature-gated web_runtime/secret_exposure.rs child owns only the fixed bounded detector catalogue, response admission state, committed ledger, and informational projection. Transport remains in http_evidence, response commit and scheduling remain in WebAssessmentRuntime, and serialization remains in reporting.rs; the child cannot acquire a client, add an action, or mint a report from uncommitted callback data.

Target product-layer split

Dashboard, distributed orchestration, compliance, and web application concerns should move outward once their contracts stabilize.

flowchart TD
    Product["Optional product layer<br/>Dashboard / Distributed / Compliance / Web"] --> App["CLI / application composition"]
    App --> Scanner[termivar-scanner]
    Scanner --> Core["termivar-core<br/>Evidence / Reasoning / Outcomes / Reports"]

This target supports separate open-source and commercial distributions without making termivar-core or termivar-scanner aware of product policy. No placeholder termivar-enterprise crate should be created until ownership, licensing, and stable interfaces are defined.

Boundary rules

  1. The CLI or application crate is the composition root.
  2. The runner owns scheduling, timeout, cancellation, events, and aggregation, not detection logic.
  3. Legacy phases implement their documented observation/verification contracts; plugins record observations through host policy and never own finding or transport authority.
  4. The event bus carries immutable lifecycle facts; subscribers do not control execution through hidden callbacks.
  5. The opt-in distributed contract owns bounded/versioned process-local records, explicit logical time, and ordered state transitions. Callers own any wire encoding, authenticated transport, persistence, coordinator epoch, and background execution; the public types intentionally define no serialization protocol.
  6. The opt-in Lua contract snapshots approved-root text source and exposes only a private scalar context/output environment in a fresh no-standard-library VM. Its memory, instruction, deadline, and cancellation controls are cooperative in-process limits, not process isolation.
  7. The opt-in report renderer consumes an immutable typed RunReport, performs no I/O or redaction, and neither mutates scanner state nor creates findings or verdicts. Hosts must pre-redact projected target, authorized-origin, action-identifier, and outcome-summary fields.

Reasoning and runtime boundary

The decision engine remains inside termivar-scanner during alpha, but its module direction is treated as an extraction boundary rather than an informal style preference.

flowchart TD
    Runtime["Scanner runtime / HTTP / plugins"] --> PlanVerify["Planning / verification / domain profiles"]
    PlanVerify --> Contracts["Knowledge / rules / experience / semantic actions"]
    Contracts --> Core["termivar-core"]
Protected layer Modules May import
Evidence preparation api_evidence termivar-core plus bounded JSON/hash libraries; never network, runtime, planner, or knowledge state
Reasoning state experience, rules termivar-core; rules may also use knowledge
Payload derivation contract payload_strategy Bounded collections, serialization, and hashing only; never knowledge, runtime state, clocks, randomness, or transport
Planning and verification planner, verification knowledge, rules, payload_strategy, termivar-core
Semantic action, ingestion, and domain profiles web_actions, web_reasoning, api_reasoning, api_observation, web_planning, web_verification The lower rows above; never execution or HTTP modules
Execution and composition decision_runner, http_evidence, web_execution, web_runtime All inward contracts needed to perform and account for work

Within the bounded standard runtime, http_evidence/request_broker.rs is the sole owner of a raw HTTP client. Built-in bootstrap, planned, adaptive, retry, and active-verification traffic must pass through its shared atomic accounting authority. The architecture check rejects direct client or socket acquisition from the surrounding decision/runtime modules. The standard runtime must call the explicitly metered broker constructor; the architecture gate rejects a switch to the named legacy unmetered constructor.

WebAssessmentRuntime is an orchestrator over that same Standard primitive, not a second engine. Explicit web-review composes its root-scoped native CORS and optional redirect/reflection actions into the authorized root's existing Standard session without replacing its eligible standard actions. Their executors receive the assessment broker, and their actions are KnowledgeOnly. The closed response observer and committed ledger can project only Informational or NeedsReview; action success cannot authorize a confirmed finding. CORS additionally requires a typed matched successful-status relationship, and redirect classification is the closed 301/302/303/307/308 set. Defense shadow/enforcement may retain or suppress these already-planned differential reads but cannot add a native action, refill the plan, increase intensity, or broaden scope.

Passive secret-exposure review preserves the same ownership split. When both its non-default compile feature and explicit runtime option are selected, the ordinary response observer receives one shared assessment-owned bounded collector. It inspects no response until the request/final-URL, status, completeness, representation, media-type, byte, and context assurances have passed. The resulting value-free evidence must commit with the parent response evidence before the separate committed ledger can project an audit or item. Disabling the option leaves no collector or secret-exposure audit. Selecting a supplied session does not transfer its response body or credentials into this anonymous V1 observer. See Passive response secret-exposure review.

Passive TLS observation uses the same ownership split. Explicit selection creates one assessment-owned collector and enables tls_info on every client constructed by that assessment; the owning path still selects and accounts for the request. After a successful response, the broker reduces available TLS metadata before body processing. Disabling the option leaves no collector or TLS audit and does not change client behavior. The collector cannot authorize a request or handshake, and saved leaf repetitions cannot be used as connection or resumption evidence. See Existing-connection TLS observation.

Active TLS negotiation deliberately has a different ownership split. The assessment authority supplies the already narrowed endpoint, accounting broker, cancellation token, deadline, and single-use mint; the child owns only its fixed Rustls configurations, one bounded DNS result, and sequential handshake I/O. It cannot authorize another destination or enter the ordinary HTTP pool. Its strict value-free audit remains separate from passive leaf-certificate observations and produces no finding.

Normalization resilience is a separate opt-in composition rather than a responsibility of defense. Both the scanner/CLI normalization-resilience feature and the explicit --normalization-resilience --profile web-review runtime choice are required. The feature consumes one already committed XSS parent control/canonical pair only after a typed candidate-specific blocking transition. Fingerprints and status codes do not authorize it. Metadata selection admits at most one depth-one source-linked serializer: HTML scanner-token case for an HTML-text parent, or one horizontal scanner-owned inter-token separator for an anchored ordinary/URI/event-handler attribute parent. Percent decode-depth entries are metadata-only.

The parent requests are reused rather than resent. A selected child has one shared-authority bootstrap, transformed candidate, and distinct transformed replay—three requests and one active verification through the existing broker. Both transformed legs must avoid the canonical block and satisfy the same existing inert DOM semantic verifier. Projection registers shared evidence once and can emit only a defensive-normalization-gap NeedsReview item under KnowledgeOnly authority. The boundary adds no waf.rs, generic dispatcher, second client, redirect/origin expansion, request-shape mutation, rate-limit evasion, browser/process/exploit dependency, or confirmed/product-specific bypass claim. See Normalization-resilience review.

The ordered legacy runner is separate. Its phases two through four share a context-owned passive discovery authority that accepts exact-origin requests, disables redirects, applies one configurable request/time/body envelope, and commits typed discovery deltas atomically. Phases five through nine share a second context-owned authority with its own VerificationLimits; it admits bodyless exact-origin requests, disables redirects and retries, and accounts them at the Active stage under a separate request/time/body envelope. Neither authority composes StandardWebDecisionRuntime or extends its RuntimeBudget.

The architecture gate prevents built-in phases two through nine from reacquiring a raw client or dispatching outside the authority assigned to their phase class. The raw legacy client remains available to phase one and host-defined custom ScanPhase extensions, so the whole ordered run remains Unmetered. Within the active slice, only the SQL-behavior, template-arithmetic, and explicitly configured local-file-canary action IDs may cross a verifier-owned bridge, and only as case-correlated, knowledge-only NeedsReview outcomes. Exact reflection has no browser verifier; XXE dispatch is disabled; and configured SSRF OOB delivery records a probe receipt without a callback conclusion.

web_actions owns stable semantic action and route identities. Planning, verification, and execution are sibling consumers; an executor's HTTP method or client policy never defines what the verifier is allowed to reason about.

termivar-core::predicates owns the canonical HTTP observations, web conclusions, API conclusions, and atomic paired-visibility contract shared by producers and reasoners. api_reasoning consumes those transport-neutral contracts to infer JSON/GraphQL fingerprints and reviewable visibility boundaries. It performs no requests, does not combine independent observations into a pair, and never declares a vulnerability.

GraphQL surface review preserves that boundary. The non-default scanner/CLI graphql-review feature and explicit --graphql-review --profile web-review runtime choice create one anonymous scanner child; the reasoner does not create it. The child deterministically selects at most one exact-origin endpoint and uses the existing redirect-disabled broker and RuntimeBudget for an aliased __typename control, bounded schema-root introspection candidate, and distinct replay—up to three POST/JSON requests; the complete candidate/replay path uses one active verification. Committed typed protocol observations may feed existing API reasoning, but projections remain Informational / KnowledgeOnly. There is no mutation, full schema enumeration, authorization testing, depth/complexity probing, second client, or WebSocket transport. See GraphQL surface review.

REST read-only review also preserves that boundary. The scanner/CLI rest-review feature and explicit same-run openapi-review plus web-review choice are required. Only a replay-stable catalog can constrain one anonymous, bodyless, exact-origin GET with no required inputs. Candidate and replay are two parent-broker requests and one active verification; a positive surface observation requires stable successful JSON Status, Fields, and value-sensitive Resources. It is Informational / KnowledgeOnly only. There is no RestScanner, second runtime/client/broker/budget, detached pass, write, credential, cookie, parameter/body materialization, or chaining to another review family. See REST read-only review.

Resource authorization review follows the same single-scanner rule. The non-default scanner/CLI authorization-review feature and one explicit security.authorization-review-policy/v1 file add exactly one native action to WebAssessmentRuntime. The operator supplies one exact-origin JSON GET resource plus distinct primary and peer credentials through the existing bounded env/file/stdin input boundary. The parent broker creates a fresh ambient-proxy-free connection pool for each leg while retaining one shared RuntimeBudget, exact-origin authority, cancellation, deadline, evidence registry, completeness lifecycle, and final report for four ordered views: primary candidate, peer candidate, primary replay, and peer replay. Those four dispatches are one logical active verification: the lease is charged when the primary replay begins, while the peer replay is passive-accounted in the same active decision phase.

No separate authorization scanner, nested Standard runtime, capability-owned authority or budget, detached pass, or independently finalized report exists. The broker-owned per-leg clients do not create new authority. The only principal-varying request material is the complete Authorization header; requests are bodyless GET, carry no cookies, disable redirects and retries, and never mutate or enumerate identifiers. Positive projection requires both role replays and both cross-principal rounds to match in Status, Fields, and value-sensitive Resources. At most one authorization.resource-cross-principal-equivalence@1 item can be emitted, with NeedsReview disposition and KnowledgeOnly authority. It is not a confirmed IDOR, BOLA, authorization bypass, or secure-negative result. The existing exact-root authorization-context compatibility path retains its public types, two-request accounting, evidence identity, and report shape. See Resource authorization differential review.

HTTP execution emits normalized protocol observations for API reasoning: validated lowercase media-type essences, an explicit JSON-compatibility flag, and bounded path segments. A host-paired comparison becomes an ApiVisibilityObservation containing one pseudonymous evidence record and one stable, evidence-backed api.visibility.resource-scope edge. The knowledge base's insert_evidence_with_relation operation preflights and commits that pair under one write lock, so an identity or linkage conflict cannot leave an orphaned half of the bundle. This is storage consistency, not proof that a producer's comparison is true.

api_evidence is the pure Evidence Engine boundary for paired JSON views. It canonicalizes under explicit hard ceilings, retains only raw-value-free signatures, and produces the transport-neutral comparison contract. The api_observation ingress then validates the expected resource, commits the evidence/relation pair, applies rules to the isolated comparison subject, and returns an auditable receipt. It does not weaken the decision runner's rule that executor evidence must match the outstanding case subject. Resource-scoped review is a cursor-bounded relation projection, not an implicit cross-subject planner input. Rejected relation shapes consume the page budget and a compiled ceiling prevents unbounded projection work. Stored relation IDs, endpoints, custom kinds, and provenance sets also have hard size ceilings; pagination checks look-ahead on the borrowed index without cloning the next record.

Bayesian contribution aggregation remains an explicit rule-level choice. EvidenceCalibration::new defaults to Independent, preserving the behavior of existing profiles. Each standard API policy likelihood alone selects MaxContributions(1), limiting retry-driven posterior inflation for one selector without changing other reasoning profiles.

A rule cycle evaluates every rule against one immutable subject snapshot and preflights every matched hypothesis before committing the batch. Verifier-owned Confirmed and Rejected states are preserved under that same write lock. A late identity conflict therefore cannot commit only the earlier rule conclusions or race a terminal verifier transition back to Supported. Subject-local and ontology revisions provide a compare-and-swap boundary; a stale cycle is re-evaluated under a fixed retry limit and then fails explicitly. Verifier lifecycle transitions mutate only the latest stored state under the knowledge lock, preserving concurrent belief and strength updates. Complete verification reports carry the evaluated subject/ontology revisions; stale reports are rejected, same-terminal replay is idempotent, and opposite terminal transitions conflict instead of becoming last-writer-wins.

Planning prepares its session transition on a clone and swaps it only after planner validation and command construction succeed. A final subject/ontology revision check holds the knowledge read lock through that short swap, so a stale plan cannot advance the session. Rule writes still precede planning and remain append-only. A later planning failure therefore returns a typed reasoning receipt with exact application write statuses and planner snapshot revisions while leaving the replayable session unchanged.

Run the machine-enforced boundary locally:

cargo xtask architecture

The command rejects uncompiled source at the virtual workspace root and undeclared top-level Rust sources in the examples package, validates workspace dependencies and centrally inherited lint policy through locked Cargo metadata, inspects protected production imports through the Rust AST, enforces standard-runtime transport ownership, prevents migrated discovery and verification phases from reacquiring direct I/O or crossing each other's authority seam, freezes the remaining built-in legacy direct-I/O inventory, verifies canonical lib.rs module and external-root wiring, and compiles termivar-scanner with no default features. For Lua and distributed coordination, it also pins independent raw feature closures, private modules and exact root reexports, public symbol/constant inventories, private ownership snapshots, ordered/integer-only state, absence of ambient filesystem/network/process/time authority, exact VM construction and text/private-environment loading, and source fingerprints with adversarial mutations. See ADR 0004 and ADR 0012, which supersedes ADR 0009. Planner-selected, raw-value-free execution strategy references are specified by ADR 0010. The scoped legacy discovery migration is specified by ADR 0016; the separate active verification authority and claim bridge are specified by ADR 0018. The host-owned, evidence-only plugin contract is specified by ADR 0019. The two Experimental host-execution contracts are specified by ADR 0022. The additive profiled assessment-reporting composition and CLI publication boundary are specified by ADR 0023. The pre-workspace component-level historical recovery inventory and its no-runtime boundary are specified by ADR 0025. The separate post-workspace WAF/evasion quarantine inventory is specified by ADR 0027; it does not restore waf.rs, the retired adaptive modules, or a transformation dispatcher. The ledger marks only the typed HTML token-case and inter-token-whitespace concepts restored by normalization resilience; all blind, unsafe, and misleading historical behavior retains its prior disposition.

For the ten responsibility-split domains above, the same gate also requires the reviewed private child-module inventory, pins facade-resident authority, rejects a responsibility collapsing back into a root facade or moving to a sibling, rejects parent-facade glob imports, and checks allowed cross-domain dependencies. These checks preserve the root source facade and its existing public module or crate-root re-export paths while keeping authority ownership explicit; they do not declare the Preview or Experimental APIs stable.

Runtime evidence boundaries

The Rust 1.88.0 runtime-smoke matrix exercises the default CLI and a narrow loopback-only contract set on Ubuntu, Windows, and macOS. Passing those jobs is host-native smoke evidence, not platform certification or an all-features release claim.

The compat/current-head/ workspace uses one dedicated lockfile and four separately tested packages for default core, deterministic assessment/reporting, the Legacy ScannerSdk facade, and plugin API 0.2 against the same checkout. They are same-revision source-shape evidence only: they establish neither cross-version compatibility nor external adoption. See Public API compatibility status.

The endpoint harness runs the real WebAssessmentRuntime only against its hard-coded loopback fixture. Initial controlled evidence for source commit 27321efbbf49cb2adbc72afb699d1b31ea407486 is retained from workflow run 33292247976, with human-readable and machine-readable records. One controlled run is not an SLA, capacity certification, accepted repeatable baseline, or regression threshold.

Dependency review

Before adding an edge, ask:

  • Is the type transport-neutral and behavior-free enough for termivar-core?
  • Can the behavior live behind an existing trait?
  • Does any API, dashboard, database, or deployment type leak into scanner logic?
  • Can the module be tested without starting the CLI, API, proxy, or web panel?

Known alpha debt

  • Native plugin execution is linked and in-process, with no sandbox, dynamic discovery, signing, or stable compatibility baseline. It remains separate from both CLI orchestration paths.
  • The ordered phase runner still exposes a raw HTTP client to phase one and custom extensions and is not covered as a whole by StandardWebDecisionRuntime or RuntimeBudget. Phases two through four use a separate bounded passive discovery authority and phases five through nine a separate bounded active-verification authority; the directory phase still requires the explicit --legacy-directory-fuzz option.
  • Dashboard, compliance, and the implemented Experimental distributed and Lua host APIs still live in termivar-scanner; neither execution API has a repository runtime caller, stable compatibility baseline, or production deployment contract.
  • Several optional modules expose broad APIs that require stability review.
  • DecisionExecutionLimits still names an HTTP response-body allowance in a generic executor request; it should become a transport-neutral resource allowance before extracting runner contracts.