Tool Connectors is an optional vendor-SDK anti-corruption library. Source currently delivers Contracts and Infrastructure projects with three groups of ports, DTOs, real adapters, and unavailable adapters. It has no Application use cases, HTTP endpoints, or business workflow.
1. Architectural position
The port hides vendor types, the adapter translates calls, the host selects SDK/configuration/lifetime, and the owner enforces authorization, trusted tenancy, input safety, idempotency, audit, retention, and interpretation.
2. Code map
| Project | Current responsibility | Does not own |
|---|---|---|
BitzOrcas.Platform.ToolConnectors.Contracts | Ports, DTOs, errors, permissions, features, module marker | SDK, workflow, endpoint |
BitzOrcas.Platform.ToolConnectors.Infrastructure | SDK adapters, conditional DI, unavailable implementations | Authorization, audit, input governance |
BitzOrcas.Api | Contracts reference for governance visibility | Adapter or SDK registration |
Infrastructure references all three 1.0.0-alpha.8 SDK packages. Contracts remains vendor-free, so consumers can depend on the stable boundary.
3. Capability matrix
| Area | Implemented | Not currently guaranteed |
|---|---|---|
| Crawler | Open URL, find element, screenshot, execute script | SSRF policy, browser-session isolation, script sandbox |
| OCR | File, bytes, Base64, URL, region, CAPTCHA | File authorization, byte/MIME/pixel limits, URL policy |
| iManage | Upload, download, checkout, checkin, history | Application authorization, idempotency, audit, reconciliation |
| Conditional DI | Enabled plus SDK-service detection | Automatic host/SDK composition |
| Governance | Three permissions and three default-off features | Request-level enforcement |
4. Boundary ownership
The connector answers “how to call the provider.” The owning application answers “who may call it, for what object, under which business state.” OCR, for example, can process bytes but cannot know whether they belong to the current tenant or passed malware scanning.
A production call path should:
- authenticate and rate-limit at the endpoint;
- obtain tenant and actor from trusted context;
- check ownership, state, purpose, and approval;
- constrain URL, file, image, script, and output budgets;
- invoke the narrow port;
- persist provider identity, idempotency outcome, audit, and reconciliation state;
- classify, redact, and retain output under an explicit policy.
5. Current OCR example
// ① The owner supplies bytes only after ownership, type, size, and scan checks.byte[] bytes = await trustedInput.ReadBoundedBytesAsync(cancellationToken);
// ② The real IOcrPort accepts byte[]; it has no LanguageHints request.Result<OcrResultDto> result = await ocr.ExtractTextFromBytesAsync(bytes, cancellationToken);
// ③ Unavailable and supported provider failures use Result.if (result.IsFailure) return Problem(result.Error);
// ④ Text, RawText, confidence, and regions remain untrusted provider output.return Ok(Sanitize(result.Value!));6. Failure model
Unavailable implementations return ProviderUnavailable for asynchronous methods. Synchronous OCR GenerateCaptcha is the exception: it returns a DTO rather than Result<T>, and unavailable mode throws InvalidOperationException.
Real adapters catch only selected SDK/IO exceptions. Parameter, network, format, memory, stream, or mapping exceptions may still escape. iManage also appends a vendor code to the application error code, so its taxonomy is not fully stable.
7. Configuration is not a feature gate
Adapter selection reads Connectors:iManage:Enabled, Connectors:Ocr:Enabled, and Connectors:Crawler:Enabled. Governance separately declares tool-connectors.imanage, .ocr, and .crawler features.
The first set affects DI only; the second set currently has no consumer. Process composition, tenant entitlement, role authorization, and business eligibility must remain four distinct checks.
8. Catalog is not enforcement
The three permissions are tool-connectors.imanage.execute, .ocr.execute, and .crawler.execute. With no Application or endpoint, no request currently enforces them.
PlatformModuleGovernance.cs also retains a duplicate legacy declaration whose comment says owner-local catalogs do not exist. They now do. GA should establish the owner-local definition as the single source and add uniqueness tests.
9. Tenancy and lifetime
iManage selects a tenant client through IManageClientFactory.Create(tenantId), but TenantId is an ordinary port argument. No current application layer proves it came from authenticated context.
The crawler port exposes no session handle. A scoped adapter can still operate on a long-lived ICrawlingService and an implicit current page; concurrent tenants can overwrite browser state. OCR has no tenant argument at all, so isolation belongs to owner-side input and output handling.
10. Observability
Adapters emit selected logs but define no connector metric contract, tracing attributes, health checks, or provider request-ID contract. URLs, provider messages, document metadata, and OCR text may be sensitive.
At minimum, measure volume, latency, timeout, unavailable, provider failure, input rejection, in-flight work, and unknown outcomes without using raw URL, document name, text, or tenant as high-cardinality labels.
Before adopting a port, a consumer review should answer:
- Which owner aggregate authorizes the call?
- Where does trusted tenant context originate?
- Which feature and permission are enforced?
- What input budget applies?
- Is the operation read-only or state-changing?
- What does timeout mean for provider state?
- Which output fields may be persisted or displayed?
- Which operation ID links audit and reconciliation?
11. Deep dives
- Composition, configuration, and governance
- Crawler security and browser sessions
- OCR input and output security
- iManage lifecycle and streaming
- Testing, operations, and commercial GA
12. Source checks
# ① Confirm that only Contracts and Infrastructure projects exist.find src/Platform/ToolConnectors -maxdepth 2 -name '*.csproj' -print# ② The primary host should currently produce no connector-registration matches.rg -n "AddBitzOrcasToolConnectorsAdapters|AddTNTIManage|AddOCRService|AddCrawlingService" \ src/Hosts -g '*.cs'# ③ Find the complete port surface and current consumers.rg -n "ICrawlerPort|IOcrPort|IIManageArchivePort" src -g '*.cs' \ --glob '!**/bin/**' --glob '!**/obj/**'