Application-service contracts
Status: implemented for the current source release line. These contracts are
the framework-independent boundary shared by the current terminal adapters and
the FastAPI/Electron foundations. ARCHITECTURE.md owns the repository-wide
dependency graph and current-versus-target status.
Public boundary
The public boundary is intentionally small:
| Module | Ownership |
|---|---|
ancestryllm.application.dto |
Strict, immutable, deterministic JSON DTOs, opaque artifact and secret capabilities, and decision/progress records. |
ancestryllm.application.operations |
Exact command request/result pairs plus reusable transport-neutral GEDCOM inspection and decision DTOs. |
ancestryllm.application.gedcom_jobs |
The bounded asynchronous façade shared by GEDCOM transports. |
ancestryllm.application.ports |
Cancellation, progress, decision, identity-resolution, and quality-resolution protocols. |
ancestryllm.application.errors |
Complete mapping from pure domain failures to stable coded application errors and transport envelopes. |
ancestryllm.domain.errors |
Framework-independent failure categories and bounded safe detail values. |
The private modules application._artifacts, application._compat,
application._rootsmagic, and application._rootsmagic_export belong to
application composition. application._rootsmagic owns RootsMagic query
runtime orchestration behind the public operation DTOs and the
rootsmagic.query.RootsMagicQueryService compatibility façade.
application._rootsmagic_export owns export validation, staging, and atomic
publication behind the public export boundary and legacy exporter compatibility
façade. These modules are not alternate service APIs or operation registries.
Every boundary dataclass is frozen and slotted. BoundaryDTO.to_json() emits a
versioned envelope with sorted keys, finite JSON numbers, and a one-megabyte
limit. BoundaryDTO.from_json() requires the exact DTO type and rejects
unknown, missing, or incorrectly typed fields. Requests and results contain no
Click, prompt-toolkit, Rich, FastAPI/Pydantic, Electron, provider-SDK,
database-session, callback, exception, or host-filesystem objects.
Operation inventory
OPERATION_CONTRACTS pairs each command dispatch identity with one request and
one result. Import-time and test-time drift checks require exact equality with
the shared command specifications:
| Command | Operations |
|---|---|
| Modules | modules.list, modules.enable, modules.disable |
| RootsMagic | rootsmagic.list, rootsmagic.query, rootsmagic.export |
| GEDCOM | gedcom.merge, gedcom.subtree, gedcom.quality, gedcom.sync |
| Prompts | prompts.list, prompts.save, prompts.show, prompts.render |
| People | people.list, people.add |
| Providers | providers.list, providers.create, providers.consent, providers.revoke |
| Secrets | secrets.set, secrets.delete, secrets.status |
| OCR | ocr.extract |
| Deployment | deployment.modes, deployment.status, deployment.preview, deployment.switch, deployment.diagnose, deployment.metadata |
| Database | database.backup, database.diagnose |
This inventory is the only application-operation registry. Terminal, HTTP, and desktop adapters may translate their inputs into these requests but must not create a second UI-specific registry or redefine result semantics.
GedcomInspectRequest and GedcomInspectResult are reusable façade contracts,
not command routes. Their presence does not create a second operation registry.
RootsMagicQueryRequest admits exactly one non-empty direct SQL statement or
natural-language question. Direct SQL is deterministic and provider-free even
when credentials are present. Questions require an explicit non-none
provider and model, then reuse the same immutable reader, SQL validator,
authorizer, row bound, timeout, and source-fingerprint checks. The serialized
RootsMagicQueryResult contains canonical scalar rows and coded execution
metadata, while progress contains only operation/stage codes and counters.
The reusable RootsMagic consumer surface also exposes sanitized
RootsMagicSourceSummary, RootsMagicQueryDefinition,
RootsMagicResultPage, and RootsMagicExportArtifact DTOs. Together with
RootsMagicQueryRequest, these are the stable application-owned values for a
future workbench adapter: opaque source references replace host paths, query
definitions carry a finite parameter schema, pages are explicitly bounded,
and exports return artifact references rather than destinations. The current
CLI/REPL direct-SQL behavior remains an application-service compatibility
contract. A future renderer must expose only allowlisted query definitions and
must translate schema-validated parameters to that trusted service request at
the adapter/application composition boundary; it must not expose raw SQL or
interpret file grants in the reusable RootsMagic core.
GEDCOM operation façade
The public GEDCOM boundary exposes GedcomInspectRequest and
GedcomInspectResult, MergeRequest and MergeResult, SubtreeRequest and
SubtreeResult, QualityRequest and QualityResult, SyncRequest and
SyncResult, and MergeDecisionRequest. Requests carry only purpose-bound
ArtifactGrantRef values. Results, progress, and coded failures are bounded,
serializable, and path-free; they never contain whole genealogy trees or
arbitrary callbacks.
GEDCOM 5.5.5 is the default output format. Callers may deliberately request
5.5.1 compatibility, and publication never overwrites an input artifact. The
merge decision contract declares retain-both as its conservative default, so
a missing or cancelled decision preserves conflicting evidence. Optional AI
adjudication requires an explicit ProviderSelection, the modular
LLMService, and the existing policy and consent checks. provider=none
remains deterministic and network-free even when ambient credentials exist.
GedcomJobFacade submits all five operations through the shared bounded job
lifecycle. Purpose-grant IDs become resource-lock keys; progress and
cooperative cancellation pass through the application ports; domain failures
retain their stable public codes; and cancellation becomes the lifecycle’s
cancelled state. A typed operation result is available only after completion.
The authenticated FastAPI adapter exposes only the fixed
POST /api/v1/gedcom/inspect, /merge, /subtree, /quality, and /sync
routes plus GET /api/v1/gedcom/jobs/{job_id}/result. It translates strict
transport payloads into the same application requests used by the CLI and REPL.
It does not expose private GEDCOM engines, a generic command registry, renderer
paths, or record trees.
Ports and adapter responsibilities
Services depend on five narrow structural protocols:
CancellationPortchecks for cooperative cancellation at safe boundaries.ProgressPortemits operation/stage codes, bounded counters, sequence numbers, and optional opaque artifact IDs. It cannot carry genealogy content, SQL, credentials, host paths, or arbitrary messages.DecisionPortreturns one declared coded option or explicit cancellation.IdentityResolutionPortresolves only opaque source/candidate references.QualityResolutionPortreturns one declared coded resolution or cancellation.
The current job and cancellation objects are translated by private compatibility adapters. Future FastAPI and Electron code must implement the same protocols at their adapter boundary. A port implementation may collect user input or update presentation state; it does not acquire genealogy, provider, persistence, or publication ownership.
Artifact and secret capabilities
Host paths never cross the public application boundary. A trusted adapter
registers a selected input or destination with the private artifact registry
and passes an ArtifactGrantRef to a request. Each unpredictable grant is
scoped to one operation and one access mode, can be revoked, and resolves to a
path only inside the owning process. Results return an ArtifactRef containing
an unpredictable identity, media type, artifact type, status, bounded size,
and optional digest—not a path.
Command results preserve that rule: tabular artifact listings contain only
ArtifactRef fields, and file-producing commands return a primary artifact
plus any related artifacts as opaque references. Terminal adapters render
those references but do not recover or expose their adapter-owned paths.
Output publication is staged, claimed, cancellation-checked, and atomically published through the hardened publication helpers. Cancellation before publication removes the staged artifact and preserves any previous destination. Publication failures map to a sanitized code; partial external outputs and raw exception details are not returned.
MediatedOperationRequest and MediatedOperationResult extend this capability
model without adding an operation registry. A request binds one unpredictable
operation ID, one allowlisted operation code, local-container or
remote-service transport, 1-16 unique read grants, and 1-8 unique write
grants. Every grant must name that same operation and exact access mode. The
result returns only ready ArtifactRef values for the same operation ID.
Both DTOs are strict, immutable, deterministic, serializable, and path-free.
Electron Main uses the corresponding shared desktop shape to select one of two trusted adapters. The local adapter may receive only private staged paths, fixed container paths, and an exact mount plan; those implementation objects do not enter the application DTO. The remote adapter may receive only bounded single-use streams with verified byte counts and digests, never host paths. This is adapter composition around the existing application inventory, not a second desktop or transport-specific API. The private artifact registry also rejects non-canonical paths, symbolic links, hard-link aliases, and identity changes before resolving a capability.
Secrets use a separate write-only SecretGrantRef. Secret values remain in the
owning adapter/secret-store boundary and never enter a request, result, error,
progress event, or deterministic JSON envelope. Secret results expose presence
only.
Provider and genealogy safety
ProviderSelection contains identifiers only. The explicit none provider is
network-disabled even when credentials or provider SDKs are present. A cloud
selection is not authorization: existing provider policy must still require a
matching explicit consent grant before any disclosure or network call.
The operation DTOs expose deterministic change, conflict, quality, and provenance records. The implemented service-owned genealogy aggregate owns the rules that produce those records. Adapters only translate and render them. RootsMagic inputs remain immutable and RootsMagic/GEDCOM outputs remain loss-visible and atomically published.
Stable failure contract
DomainFailureCode is complete for the application boundary. Every member has
one DOMAIN_ERROR_MAPPINGS entry defining its stable public code, sanitized
message, optional remediation, and exit status. Mapping ignores raw exception
text and admits only allowlisted, bounded, path-free scalar details. Unknown
exceptions are caught at the owning boundary and converted to the generic
internal category before transport rendering.
CLI and REPL compatibility continues to use the existing coded-error rendering.
Future transports serialize the corresponding ErrorEnvelope; they must not
invent transport-specific domain codes or expose tracebacks, filesystem
locations, SQL, provider payloads, credentials, or genealogy content.
Contract validation
tests/modular/test_application_contracts.py proves:
- exact operation coverage and deterministic round trips for every request and result;
- immutable DTOs and forbidden dependency/type exclusion;
- framework-free imports in an isolated interpreter;
- structural port conformance and legacy cancellation mapping;
- strict JSON, finite-number, bounded-value, and path/content rejection;
- complete stable failure mapping with sanitized envelopes;
- scoped, revocable, opaque artifact grants, including link and replacement rejection at resolution;
- strict, deterministic, path-free mediated-operation request/result round trips with local/remote transport selection and access-bound grant checks;
- atomic publication, cancellation preservation, and absence of partial external output;
- write-only secret capability use.
The GEDCOM façade evidence adds:
tests/modular/test_gedcom_service_contracts.pyfor purpose-grant execution, version selection, non-overwrite rules, conservative merge decisions, explicit provider policy, offline socket denial, cancellation, and atomic publication;tests/modular/test_gedcom_job_facade.pyfor bounded lifecycle submission, resource exclusion, progress, stable coded failures, cancellation state, and completed-only typed results;tests/api/test_gedcom_operations.pyfor authenticated fixed-route DTO translation and path-free job/result envelopes; and- the CLI/REPL boundary suites for parity with the same typed service requests and stable coded errors.
The core-contract characterization suite remains the compatibility authority
for shipped CLI/REPL behavior, JSON, errors, consent, network-free none,
RootsMagic immutability, rooted/loss-minimal GEDCOM behavior, and existing
artifact/report behavior.