Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Custody declaration facts

createCustodyDeclarationFacts() produces one validated object for later machine-readable and human-readable custody outputs. It performs no network request, signature, timestamping, persistence or rendering.

import { createCustodyDeclarationFacts } from "@dataprism/sdk/evidence";
 
const facts = createCustodyDeclarationFacts({
  encoding: {
    id: "reed-solomon-systematic-v1",
    dataShards: 7,
    parityShards: 3,
  },
  providerIds: ["aws-primary", "r2-primary", "gcp-primary", "azure-primary"],
});
 
facts.largestShareOfShardsAtOneProvider;
// { numerator: 3, denominator: 10 }
 
facts.ciphertextSlicesAtThatProvider;
// { numerator: 2, denominator: 7 }

The two values are separate integer ratios. The API does not calculate a percentage. The provider order must be the same order used by the round-robin upload placement.

Placement conditions

Let k be the number of data shards, t the total number of shards, and n the number of configured providers. Round-robin placement puts at most ceil(t / n) shards at one provider.

Display labelConditionReturned field
Provider-loss availability conditiont - ceil(t / n) >= kproviderLossAvailabilityConditionHolds
No provider holds a quorumceil(t / n) <= k - 1noProviderHoldsQuorum

The second condition only bounds the single-provider case. Display a false result as does not hold; do not label it “Confidentiality” or imply that passing it establishes confidentiality.

The supported reference configuration is 7+3 over five providers. Both conditions hold, with a largest shard holding of 2 of 10. The four-provider example above also passes both conditions, with a largest holding of 3 of 10. In systematic mode both examples store 2 of 7 ciphertext slices uncoded at the most-loaded provider. Dense-Cauchy stores 0 of 7 there.

The upload policy defaults to custodyPolicy: "attested" and rejects either failed condition before writing. Callers still supply the shard counts; the policy does not choose them. An explicit "relaxed" upload does not turn a failed condition into a passing one.

Uncoded ciphertext slices

For reed-solomon-dense-cauchy-v1 with more than one data shard, the ciphertext-slice numerator is zero because no output shard is an unchanged ciphertext slice. With one data shard, the count instead reflects whether an unchanged slice lands at the declared most-loaded provider. For example, 1+0 over one provider reports 1 of 1, and the no-provider-quorum condition fails. A zero count is not a claim that a shard contains no information, and neither encoding mode provides a threshold-secrecy or general confidentiality guarantee.

Both modes require dataShards + parityShards <= 256. Dense-Cauchy also requires 2 * dataShards + parityShards <= 256 so its row and column field elements stay distinct. Unsupported configurations are rejected rather than described in custody facts.

Bucket state

Omitting bucketInspections records { status: "unknown" }. It does not infer provider settings from application configuration or infrastructure code.

When inspections are supplied, there must be one valid record for every configured provider. The input contract is versioned as dataprism.storage-configuration.v1. Pass the results from inspectStorageProviders() directly to bucketInspections; no adapter or type assertion is needed. Strict typechecks and integration tests cover this boundary. Results are normalized into provider placement order. Partial, unsupported and failed outcomes, unknown control states and bounded limitations are retained rather than presented as successful observations.

A detected bucket state means that a valid inspection result was supplied for every configured provider. It does not mean that every provider returned a complete or successful result.

These are retained observations, not a live check. Keep the source, collection time and limitations with the displayed facts. A later provider configuration change does not update an existing declaration.

import { inspectStorageProviders } from "@dataprism/sdk/storage";
 
const bucketInspections = await inspectStorageProviders(providers);
const facts = createCustodyDeclarationFacts({
  encoding,
  providerIds: providers.map((provider) => provider.id),
  bucketInspections,
});

Here, providers must be in the upload's placement order and encoding must describe its selected encoding mode and shard counts. An unavailable inspection remains unsupported or failed in the resulting facts.

Evidence boundary

The object records deterministic placement arithmetic, the selected encoding identifier and supplied storage-control observations. The two booleans report whether the most-loaded provider can be lost while retaining a reconstruction quorum, and whether any single provider holds that quorum.

These facts do not establish deletion, confidentiality, threshold secrecy, provider honesty or an independently established time. Signing, RFC 3161 timestamping, JSON and PDF generation, persistence and registry anchoring are separate operations.

Location repair preserves the original content commitment and anchor time, and advances a separate manifest version only after verifying replacement shards. Stale updates cannot overwrite a newer manifest silently. These implemented lineage checks are separate from accepting measured gas and storage costs before deployment under #65.

Copyright © 2026 DataPrism.