Architecture Contracts and Owner Boundaries
This page delivers the ratified architecture contracts as contributor documentation: who owns each responsibility, which import directions are legal, how long each piece of state lives, and which public surfaces are retained. The contract rows are the source of truth — this page is their delivery, and it deliberately re-curates nothing:
- Dependency, visibility and layer contracts:
tests/architecture-health/ARH1/products/dependency-contracts.json(plus the cutover register intests/architecture-health/ARH1/products/cutover-register.json) - Responsibility and owner map:
tests/architecture-health/ARH0/products/responsibility-map.json - Capability evidence (engine and version pins per capability):
tests/architecture-health/ARH0/products/capability-matrix.json
When this page and a contract row disagree, the contract wins; file an issue against the owning module instead of editing around it. The docs build validates that this page still cites those files and still covers every contract hotspot (pnpm --filter docs check).
Layer rules
Three ratified import-direction rules constrain the Rust tree. Each is enforced evidence-first by the architecture-health lane (node tests/architecture-health/ARH1/verify.mjs in CI, on ubuntu-latest with the Node version pinned by .nvmrc):
| Crate | Rule | May import | Must not import |
|---|---|---|---|
crates/verter_scheduler | scheduler-runtime stays below every orchestration crate | verter_audit, verter_debug_assert, verter_language, verter_span | verter_session, verter_compiler, verter_semantic, verter_lsp, verter_workspace, verter_parser, verter_type_expr |
crates/verter_semantic | the semantic core never depends upward on orchestration or transport | verter_audit, verter_css_syntax, verter_debug_assert, verter_language, verter_macro_dto, verter_no_typeexpr, verter_parser, verter_span, verter_type_expr, verter_type_expr_oxc | verter_session, verter_scheduler, verter_compiler, verter_lsp, verter_workspace |
crates/verter_session | editor/transport/FFI crates are leaves; the session core never imports them | the analysis, compiler, scheduler, semantic, workspace and utility crates | verter_lsp, verter_napi, verter_ffi, verter_wasm |
The full crate-by-crate owner list (every crates/ and packages/ root plus the docs, tests and tooling estates) lives in the ARH0 responsibility map linked above; nothing here duplicates it.
The five contract hotspots
ARH1 ratified five "hotspot" files — high-traffic modules whose surfaces, state and import directions are under active narrowing. Each subsection below names the surviving owners and the minimal public surface; the exact rows (per-hook consumer inventories, narrowing dispositions) are in the dependency contracts file.
Scheduler — crates/verter_scheduler/src/scheduler.rs
Responsibility split among cohesive modules:
- Pool submission and admission control:
crates/verter_scheduler/src/dag.rs(SchedulerDagis the sole readiness authority) andcrates/verter_scheduler/src/execution/pool.rs. - Batch coordination:
crates/verter_scheduler/src/driver.rs(owns all admission and ordering policy, drains theSubmissionInbox). - Cancellation and retry bookkeeping:
crates/verter_execution/src/cancellation.rs(one-shot clonable latches; dropping a handle cancels its pending work). - Snapshot-epoch source authority:
crates/verter_scheduler/src/source_root.rs.
Constructor capabilities, two modes — do not mix them:
- Threaded native constructors (
new,with_executor): host-injectedArc<dyn SourceLoader>plus CPU/I/O pool handles; spawn exactly one driver thread. Native-only (cfg(not(target_arch = "wasm32"))). - Synchronous constructors (
new_sync,new_sync_with_executor): no driver thread; the caller mustdrive_one()/drive_all()(orwait_or_drive). Waiting on a sync scheduler without driving it never completes. On native they still take host-injected pool handles; onwasm32the pool arguments are omitted and stages run inline on the calling thread.
The scheduler constructs no pool and performs no file I/O at construction; no parse, analysis or compile work happens in a constructor.
Minimal public surface is the complete minimalPublicSurface row, not a subset. Retained functions: resolved_dag_budget, len, is_empty, handles, into_handles, new, with_executor, with_executor_and_task_registry, new_sync, new_sync_with_executor, new_sync_with_executor_and_task_registry, begin_scoped_cache_node, run_transferred_producer, execute_scoped_cache_node, begin_submit_request, submit_request, begin_submit_batch_atomic, begin_owned_request, enter_execution_scope, pump_owned_dependency, submit_batch_atomic, wait_batch, account_batch_submission, subscribe_progress, dispatch_for_pending_dependency, counters, dependency_occupancy, try_get_source, try_get_witnessed_source, try_get_source_for_witness, capture_source_root, source_directory, try_get_analysis, try_get_artifact, try_get_last_known_good, has_node, node_ids, reset, restart_driver, quiesce, stage_task_boundary, wait_stage_tasks_before, register_resolved_deps, config, commit_artifact, remove_artifact_not_newer_than, overlay, invalidate, remove, close_file, has_driver_thread, driver_loop_native, drive_one, drive_all, wait_or_drive, wait_or_drive_with_caller. Retained types: SchedulerCounters, SchedulerConfig, Request, ScopedCacheNodeRequest, ScopedCacheNodeError, ScopedCacheFlight, Admission, BatchHandle, Scheduler. The remaining bookkeeping field (deferred_blocker_ids; removal tombstones and generation floors have no storage) and the test_-prefixed hooks are ratified for narrowing to pub(crate) / test configuration — do not add new consumers of them; they are not a supported API for contributions.
Owned request admission uses begin_owned_request with the waiting root task and cancellation token; polling yields without driving or parking. enter_execution_scope establishes execution authority at an external synchronous boundary. Its dependency driver may call pump_owned_dependency, which respects worker routing and the active path; poll-only dependencies do not receive this capability. On native targets, stage_task_boundary captures the submitted-stage frontier and wait_stage_tasks_before waits until those tasks finish dropping their captures. Later submissions do not extend that wait, and stage work must never call it.
Hooks used by cross-crate integration tests, including Scheduler::test_wait_until_job_queue_depth, stay pub behind cfg(any(test, feature = "test-support")). Each has a test-configuration narrowing row with its exact consumer inventory and qualified reference forms.
Flow-return dispatch — crates/verter_type_engine/src/project_semantic_dispatch/flow_return.rs
Sole owner of flow-return semantic dispatch: the demand-sliced FlowReturn authority, the one SemanticQueryKey::FlowReturn producer through ProjectSemanticDispatch. Flow product assembly (all mutable product state) lives in crates/verter_type_engine/src/project_semantic_dispatch/flow_products.rs. The module is already pub(crate) with zero cross-crate surface; the contract is that boundary itself — no widening to pub without a charter amendment.
Dispatch build/admission — crates/verter_type_engine/src/project_semantic_dispatch/build.rs
Every semantic query variant that produces a new SemanticNodeId goes through one of the build_* methods collected here, with helpers kept pub(super). The project-global dispatcher assembly is crates/verter_type_engine/src/project_semantic_dispatch/mod.rs — the single dispatch site every reusable type-resolution operation flows through.
Semantic query envelope — crates/verter_type_engine/src/semantic_query.rs
The host-owned memo table keyed by SemanticQueryKey. The cross-crate surface is cut to exactly ten retained envelope types (HashValue, SemanticNodeId, ScopeId, ResolveDeclKey, SemanticQueryKey, ResultCompleteness, PartialReason, PartialReasonSet, ProjectionMode, OriginEdgeKind) plus eleven retained associated items (PartialReasonSet::PROPAGATED, PartialReasonSet::SEMANTIC_QUERY_FAULT, PartialReasonSet::CONNECTED_MEMORY_LIMIT, PartialReasonSet::UNDECIDED_CONDITIONAL, PartialReasonSet::empty, PartialReasonSet::is_empty, PartialReasonSet::contains, PartialReasonSet::iter, ResultCompleteness::partial, ResultCompleteness::is_partial, ScopeId::file) — everything else is ratified pub(crate) (see the bulk narrowing row and its 68-file consumer migration in the contract). The per-variant key/env binding table lives in crates/verter_type_engine/src/semantic_query/query_key_spec.rs and is written only by its generator.
Flow slice content — crates/verter_semantic_source/src/flow_slice_content.rs
The owned, arena-free content lowering of exactly one planned flow slice. A pub module of the source crate; the session reaches it through the declaration-body memo. Its retained surface is the object-member policy the memo's lowering entry takes (ObjectMemberPolicy), the sibling-selection helper the session-resident slice suite pins (selected_span_child) and the test-support lowering work probe (LoweringWork). Slice publication admission stays with flow_return.rs, where the budget outcome gates admission.
Capability mapping and evidence basis
These substrate surfaces are not user-facing capabilities. Each retained hotspot surface maps onto the existing product-surface catalog (sole truth: tests/documentation/DOC0/products/generated-reference-plan.v1.json; no second matrix). Engine and version pins stay in the ARH0 capability matrix linked above.
| Hotspot | Catalog surfaces served |
|---|---|
crates/verter_scheduler/src/scheduler.rs (every retained fn/type above) | vue.language_service.typing, vue.language_service.edit, svelte.language_service.typing, svelte.language_service.edit, vue.tsc.project_check, svelte.tsc.project_check, vue.managed.compile.raw, svelte.managed.compile.raw, vue.component_meta.scalar, svelte.component_meta.scalar, vue.host_lint, svelte.host_lint |
crates/verter_type_engine/src/semantic_query.rs (every retained type/assoc item above) | vue.language_service.typing, svelte.language_service.typing, vue.tsc.project_check, svelte.tsc.project_check |
crates/verter_type_engine/src/project_semantic_dispatch/flow_return.rs (pub(crate) module boundary) | vue.language_service.typing, svelte.language_service.typing, vue.tsc.project_check, svelte.tsc.project_check |
crates/verter_type_engine/src/project_semantic_dispatch/build.rs (pub(crate) module boundary) | vue.language_service.typing, svelte.language_service.typing, vue.tsc.project_check, svelte.tsc.project_check |
crates/verter_semantic_source/src/flow_slice_content.rs (every retained fn/type above) | vue.language_service.typing, svelte.language_service.typing, vue.tsc.project_check, svelte.tsc.project_check |
The contributor-docs model joins that table to every retained fn/type/assoc item (and to the hotspot path itself when the retained list is empty). A retained surface without a catalog id, or a mapped id absent from the catalog, fails pnpm --filter docs check.
The importer, retained-surface and test-hook consumer populations are joined as sets against the live tree: every file that references a hotspot across crates is a declared importer, and every declared importer references it. Each hotspot's importDirection.measurementBasis records the measurement method (production import tree, cfg(test) stripped, use-statements and inline paths). The original host/profile of that measurement is unrecorded in ARH1 contract products. File size, line counts and item counts are not architecture evidence; no verifier records or compares them, so growing or shrinking a hotspot never needs a product update. Live verification is the CI architecture-health job on ubuntu-latest with Node from .nvmrc, running node tests/architecture-health/ARH1/verify.mjs. Historical landing titles and dates are descriptive context only. Verification checks the current tree and does not depend on historical Git objects, commit ancestry or matching history text, so squash merging cannot invalidate the proof.
Architecture-health PR checklist
For changes touching a contract hotspot or its crate dependencies, reviewers should verify:
- the owning module and one surviving authority are unchanged or explicitly migrated;
- Cargo dependencies still match the ARH1 layer rule and forbidden imports are absent;
pub/pub(crate)boundaries and every affected consumer are covered by the contract; and- the targeted architecture guard and the relevant behavioral lane were run.
The executable boundary is arh12_dependency_and_visibility_contracts_are_enforced in crates/verter_source_policy_gate/tests/cases/architecture_dependencies.rs; it derives the current manifests and source tree rather than matching historical filenames.
Related pages
- Source and map identity — span types, position encodings, stable hashes and source maps.
- Query lifetimes and determinism — lifetime classes, memo identity, scheduler fencing, deterministic ordering.
- First contribution — an end-to-end walkthrough that uses the owning interfaces above.