Java SDK reference
Package-level reference for installation, public interfaces, observation boundaries and delivery behaviour.
#Package and basic usage
Sigillum Finans Java SDK 0.11.0
Java 8 or newer. Add the normal io.sigillum:finans-sdk:0.11.0 Maven dependency
from the delivered local Maven repository. The package declares the official
OpenTelemetry SDK and Jackson dependencies. Public registry publication is not
required for this delivery.
One multi-release JAR contains the Java 8 shared implementation and the Java 11
native HttpClient boundary. Java 8 uses its native HttpURLConnection /
HttpsURLConnection boundary. Both expose the same observation, AI, source,
content, references, scope, private OTEL, carrier and signed delivery contract.
No global OpenTelemetry provider, institution TLS configuration or HTTP proxy is
replaced. The product's private worker has its own pinned installation CA and
HTTPS hostname validation, including on Java 8.
<dependency>
<groupId>io.sigillum</groupId>
<artifactId>finans-sdk</artifactId>
<version>0.11.0</version>
</dependency>Use the service's ready configuration from the product. Its service credential identifies one institution/environment/service. Application ownership comes from the matched entry point or authenticated incoming observation context.
The ready file uses sigillum.sdk-config/2. Its pinned scopeTrust verifies the
product's signed execution profile at every root and incoming context boundary.
The profile contains the institution, environment, actual application/root and
the selected services for that execution. The worker refreshes the available
root profiles every 30 seconds over the same installation HTTPS origin, without
waiting on the business path. A validated update is installed as one snapshot;
rollback or an inconsistent same-revision definition keeps the previous snapshot.
An already-started execution retains its original signed service scope.
#Optional local agent handoff
The ready config/2 can select the product-owned local agent:
"localTransfer": {
"endpoint": "http://127.0.0.1:29520",
"token": "<32-to-256-printable-ASCII-characters-without-spaces>"
}Use an explicit port and exact IPv4 loopback origin, with no path, trailing slash,
query, fragment or user information. localhost, other addresses, redirects and
application proxy settings are not used for this boundary. Once selected, local
mode never falls back to the remote transfer endpoint, including when the agent
is stopped. The existing direct HTTPS/SFREC001 mode is retained when the optional
property is absent.
Native calls only admit bounded RAM snapshots. The observer worker builds the
SFRAW001 packet and posts it to /v1/captures; the agent derives content hashes
and references, packages SFREC001, encrypts persistent retry and contacts upstream.
Original JSON numeric text, attachments, identity and causal links are preserved.
The worker freezes each packet for exact retry and releases its RAM credits only
after the exact token-authenticated sigillum.local-handoff/1 acknowledgement.
diagnostics().localDurableRecords() counts this local handoff;
diagnostics().delivered() continues to mean remote custody acknowledgement and
is not incremented by local handoff. Agent restart, queue saturation or process
loss before local acknowledgement cannot be reported as complete recording.
An unsuccessful local send gates the observer worker with exponential backoff
and a small bounded jitter. The first delay is the configured retryDelayMs;
subsequent delays grow up to 30 seconds, or the configured delay when it is
longer (configuration permits at most 300 seconds). New ready batches cannot
bypass this endpoint gate. A verified local acknowledgement resets the backoff.
The direct HTTPS retry policy remains unchanged.
Profile refresh uses authenticated local /v1/profiles only. The existing signed
scope and monotonic revision checks still apply. Agent calls, JSON packaging,
hashing and MAC verification are observer-worker work; no application call waits
for storage, ACK, network, retry or close/flush.
import io.sigillum.finans.Sigillum;
import java.nio.file.Paths;
Sigillum sigillum = Sigillum.start(
Paths.get("C:/application/.sigillum/config.json"));start(Path) schedules file, certificate, OpenTelemetry and transport setup on
the SDK worker. The path is explicit and absolute. The SDK does not search the
working directory or require an additional HTTP profile. Configuration errors
appear in diagnostics() and do not escape into the application.
For the supported JDK HTTP boundaries, register the ready wrappers once:
httpServer.createContext("/process", sigillum.httpHandler(nativeHandler));
HttpURLConnection connection = sigillum.httpConnection(nativeConnection);On Java 11 and newer, the ready HttpClient client = sigillum.httpClient(nativeHttpClient) wrapper also retains the native client's
synchronous/asynchronous API. httpConnection retains the original connection's
timeouts, proxy, TLS factory, hostname verifier, request settings and HTTPS
subtype. It observes application stream consumption without reading ahead.
For servlet applications, choose the delivered finans-sdk-servlet (javax) or
finans-sdk-jakarta-servlet adapter matching the project's existing servlet API;
their guides describe one standard filter registration.
The inbound wrapper selects an exact configured HTTP entry point or continues a
valid x-sigillum-context. The outbound wrapper carries that product context
without replacing traceparent, tracestate, the application's OTEL provider or
the application's existing propagation header. Conflicting headers are preserved
and reported. SDK-free intermediate components are not inspected; context
continues only when it is actually transported.
A shared service is installed once. Its incoming signed profile decides whether the current application selected that service. If it did not, the SDK creates no local operation, HTTP content, native OTEL or custom observation; it forwards the verified context unchanged through the ready HTTP wrapper. The next selected service retains the actual upstream parent. A newly connected application's signed profile works with that same installed shared SDK and service credential. Intentional exclusion does not produce a failed delivery or capture-loss record.
For a scheduled execution, use the configured operation name:
try (ObservationScope execution = sigillum.begin("daily-calculation");
Sigillum.Binding current = execution.activate()) {
nativeCalculation();
}HTTP metadata, actual request/response chunks, lifecycle and the private always-on OpenTelemetry span are automatic at these supported boundaries. Chunks are observed as the native publisher/subscriber or application stream reads/writes them. There are no eager body reads or duplicate invocations. Native response values, errors, interruption, cancellation and stream ownership remain with the application. Asynchronous calls return the original native future. Native cancellation success, refusal, original exception and the single transport invocation are preserved; completion observation does not wrap or cancel that future again.
Unread inbound requests are complete and empty only when native HTTP/1.0 or HTTP/1.1 framing proves no body: no Transfer-Encoding, and no Content-Length or one valid zero length. Finalization also requires no observed bytes/chunks or capture loss. The HTTP method alone never proves emptiness. Duplicate, conflicting or invalid framing, HTTP/2, HTTP/3 and unknown protocol metadata remain incomplete until native consumption proves completion. The SDK never reads, drains or rewinds a request to make this determination.
The JDK server wrapper preserves HttpsExchange and the original TLS session.
A successful application-owned stream reset or stream replacement marks the
capture partial, including a reset after a previously observed EOF. A rejected
native reset keeps the original exception and does not change completeness.
#Source-owned AI and additional information
Use already materialized UTF-8 JSON objects. Numeric tokens, explicit null,
absent properties and original content bytes are retained. The SDK does not
reflect arbitrary application objects, enumerate lazy business results or call
object getters to discover data.
Structural raw-JSON validation runs on the observer worker. A true capture
result means bounded RAM admission. If the supplied bytes later fail exact
object/UTF-8/duplicate-key validation, the invalid data is omitted and a bounded
loss record is emitted under the same execution, including while draining
already admitted work after close().
sigillum.ai("model", modelJson);
sigillum.ai("classification", classificationJson);
sigillum.ai("retrieval", retrievalJson);
sigillum.ai("tool", toolJson);
sigillum.ai("embedding", embeddingJson);
sigillum.ai("inference", inferenceJson);
sigillum.ai("evaluation", evaluationJson);
sigillum.ai("policy", policyJson);
sigillum.ai("explanation", actualSourceExplanationJson);The generic capture(context, family, kind, schema, rawJson, contents...)
surface covers lifecycle, ai, http, otel, context, source and custom.
CaptureContent(id, mediaType, purpose, bytes) supplies exact binary content
with its real meaning. The simpler map overload uses the observation kind as
the content purpose and application/octet-stream as media type.
Explicit causal relations use SpanLink(traceId, spanId, relation). Pass a
materialized SpanLink[] to the capture overload, with at most 128 valid links:
sigillum.capture("custom", "decision-inputs", knownJson,
new SpanLink[] { new SpanLink(actualTraceId, actualSpanId, "parallel-result") });Link identifiers must be nonzero lowercase trace/span IDs. The relation is a nonblank label of at most 64 UTF-16 code units. The SDK snapshots the array after memory admission; later changes to the source array cannot change the record.
observe(operation, inputJson, nativeCall, rawOutput) is a ready generic
operation wrapper. It invokes the native call once, preserves the original
return reference or thrown exception and records only the provided raw input
and output. An explanation or hidden model internal is never inferred.
Optional references do not create or merge executions:
ObservationContext enriched = sigillum.withReferences(sigillum.current(),
new References(sessionReference, personReference,
Collections.singletonList(new References.External("institution-trace", correlationId))));
try (Sigillum.Binding current = sigillum.activate(enriched)) {
nativeWork();
}Use wrap(Runnable) / wrap(Callable) when handing work to an executor, or
explicitly activate(context) in its callback. These carry only Sigillum's
immutable context and restore the prior context. child(context, name) creates
a real child span. exportContext / importContext provide the same signed
portable carrier used by the HTTP wrappers. An invalid carrier does not invent
an application or parent.
ObservationScope.span() exposes the actual private OTEL span for attributes,
events, links and status supported by the official API. tracer() exposes the
same private provider; an explicitly created native child must use its actual
parent. No call installs a global provider or changes Context.current().
#Delivery and limits
All capture operations try to reserve a bounded memory budget. The default
budget is 64 MiB and 1,024 records, including the pending encoded packet.
Business calls never wait for disk, network, acknowledgements, flush or worker
shutdown. close() stops new capture without joining the worker. Pending work
may drain while the process remains alive; daemon workers do not prevent exit.
The SDK worker sends exact SFREC001 packets to the product-owned HTTPS transfer
service. It keeps the same delivery ID and exact bytes on retry. Dequeue
requires the pinned P-256 P1363 custody signature and exact institution,
environment, service, delivery, packet fingerprint and ordered record package
bindings. The transfer service owns encrypted durable retry after that ACK.
RAM before the verified custody ACK is not durable. Abrupt process termination
can lose pre-ACK RAM; finite capacity drops observation instead of blocking the
institution's business. Diagnostics and capture.lossReported expose loss and
partial streams rather than claiming complete capture.
Unacknowledged packets keep their original memory reservation and exact encoded bytes while retrying with backoff. Due retries alternate with newly queued work; one refused execution cannot prevent a different application from reaching the transfer service. A response or receipt mismatch never releases its reservation.
diagnostics() reports initialization state, admitted/delivered counts,
pending bytes/records, bounded loss counters and the last observer error class.
It contains no service secret or original content.
#Verification
mvn test runs protocol vectors, receipt and carrier negatives, real HTTPS
custody/retry, native HTTP behavior, private OTEL, concurrency, saturation and
nonblocking shutdown tests. Real-runtime tests require Java 8 and Java 11 JDKs
and a Java 17 runtime, configured through sigillum.java8.home,
sigillum.java11.home and sigillum.java17.home (the local development defaults
are under .local/toolchains/temurin*). They compile and run independent probes
with the real runtimes; a missing runtime fails the test instead of skipping it.
sigillum.runtime.jar can point to the final installed artifact for the same
checks. mvn install installs the normal SDK artifact;
mvn -f consumer/pom.xml package builds the independent installed-package
consumer used by the shared product conformance run. Test-only waiting belongs
to that consumer, not to SDK startup or business calls.
