Timestamp Assurance — source-grounded information pack and proposed design
Status (2026-08-21): TA-1 (source-only) and TA-2 (read-only protocol adapters) are IMPLEMENTED; everything else remains PROPOSED and awaiting owner acceptance. This document answers owner-decision register item 14. It is an engineering recommendation, not an owner ruling and not a regulatory opinion. Still true after TA-2: no deployment, database, remediation, key-custody or product-claim change has been made — both libraries are referenced by no host, so nothing composes or executes them, and the adapters read no database (see §8 and §9). TA-2 does add code that CAN open a socket, which is why it lives in a separate assembly behind an explicit allowlist and a resolved-address policy. The executable proposal is
SPRINT_20260819_001_Evidence_timestamp_assurance_program.md.
1. Recommendation
Make Timestamp Assurance a subsystem of the Evidence service family:
evidence-webowns authenticated status/run/read APIs and the installation-scopeddoctor-check/v1checks;evidence-workerowns scheduled probes, tenant-scoped timestamp-evidence evaluation, and re-timestamp work;- both roles use the existing Evidence database,
stellaops_evidence, and Evidence-owned object prefixes; - the existing OpenSSL
tsacontainer remains an Evidence-family infrastructure role with no database; and - Signer remains a separate custody service, consumed only through
StellaOps.Signer.Contracts.
Do not create a Timestamping microservice, database, or central Doctor host. A separate service would either duplicate Evidence’s timestamp/token/trust state or reach across the Evidence boundary. JobEngine is also the wrong owner: it would need Evidence data, regulated trust inputs, tenant context, and privileged egress merely to schedule work in a domain it does not own. Platform should only discover and aggregate the service-owned check contract.
This recommendation follows the already-approved Evidence-family lifecycle: sign → attest → store → verify → timestamp. It is still proposed because item 14 has not accepted this disposition.
2. What exists now
2.1 The orphaned Doctor family
The project is src/Doctor/__Plugins/StellaOps.Doctor.Plugin.Timestamping/StellaOps.Doctor.Plugin.Timestamping.csproj. It targets .NET 10 and directly compiles:
StellaOps.AirGap.Policy;StellaOps.AirGap.Importer(service implementation, a P19 defect for any durable successor);- the domain-neutral
StellaOps.Cryptographyabstraction; - the legacy Doctor engine; and
- the legacy Doctor remediation library.
The project defines its own local IDoctorCheck rather than the canonical IServiceDoctorCheck. The retired Doctor WebService adapted that private surface by reflection in DoctorMountedRuntimePluginLoader; it also owned seven dashboard endpoints under /api/v1/doctor/timestamping/* and mapped three heal actions. There is no direct WebService project reference to the plugin.
devops/build/package-runtime-plugins.ps1 still lists descriptor id stellaops.doctor.timestamping for base, recommended, harness, and bad-signature profiles. The generated descriptor is a runtime-bundle.v1 Doctor bundle with capability doctor:checks, an assembly digest, and detached signature. That packaging fact does not make the family runnable:
doctor-web, its compose overlay, gateway routes, host alias, image/publish key, and release layer were retired on 2026-08-17;- the console had already stopped calling the host at its 2026-08-12 registry flip; and
- the only loader and the seven dashboard endpoints now live in buildable but undeployed source.
Therefore the measured runtime reachability of all 22 checks is zero. The bundle is a packaged orphan, not a live plugin.
2.2 The 22 checks, row by row
The canonical ids below are implemented as of TA-1 (2026-08-21) in StellaOps.Evidence.TimestampAssurance.Catalog, which is their single source of truth; the target surfaces remain proposed until TA-4. Every legacy id needs a compatibility alias during migration because the ids still occur in Doctor’s integration catalog/ratchets, AdvisoryAI’s doctor-search seed, unified-search fixtures, and Web E2E fixtures.
| # | Current legacy id | What current code tries to measure | Proposed canonical id | Scope and target surface | Required real source |
|---|---|---|---|---|---|
| 1 | check.timestamp.tsa.reachable | configured TSA reachability | doctor.evidence.timestamp.tsa.reachable | installation; /doctor/evidence/checks | allowlisted RFC3161 endpoint probe |
| 2 | check.timestamp.tsa.response-time | TSA response latency | doctor.evidence.timestamp.tsa.response-time | installation; /doctor/evidence/checks | same probe, monotonic duration |
| 3 | check.timestamp.tsa.valid-response | valid timestamp response | doctor.evidence.timestamp.tsa.valid-response | installation; /doctor/evidence/checks | nonce/imprint-correlated RFC3161 request/response |
| 4 | check.timestamp.tsa.failover-ready | usable backup TSA | doctor.evidence.timestamp.tsa.failover-ready | installation; /doctor/evidence/checks | configured provider set + read-only probes |
| 5 | check.timestamp.tsa.cert-expiry | TSA leaf expiry | doctor.evidence.timestamp.tsa.cert-expiry | installation; /doctor/evidence/checks | parsed signer certificate from token/provider material |
| 6 | check.timestamp.tsa.root-expiry | trust-root expiry | doctor.evidence.timestamp.tsa.root-expiry | installation; /doctor/evidence/checks | validated trust bundle, not configured dates |
| 7 | check.timestamp.tsa.chain-valid | TSA chain validity | doctor.evidence.timestamp.tsa.chain-valid | installation; /doctor/evidence/checks | real chain build at the relevant verification time |
| 8 | check.timestamp.ocsp.responder | OCSP responder availability | doctor.evidence.timestamp.revocation.ocsp-responder | installation; /doctor/evidence/checks | certificate-derived OCSP request/verified response |
| 9 | check.timestamp.crl.distribution | CRL distribution availability | doctor.evidence.timestamp.revocation.crl-distribution | installation; /doctor/evidence/checks | certificate-derived URI + signed CRL validation |
| 10 | check.timestamp.revocation.cache-fresh | cached OCSP/CRL freshness | doctor.evidence.timestamp.revocation.cache-fresh | installation; /doctor/evidence/checks | Evidence-owned validated snapshot metadata |
| 11 | check.timestamp.ocsp.stapling | stapled revocation evidence posture | doctor.evidence.timestamp.revocation.stapling-present | installation; /doctor/evidence/checks | current issuance/profile policy + captured evidence summary |
| 12 | check.timestamp.evidence.staleness | stale timestamp evidence | doctor.evidence.timestamp.evidence.staleness | tenant; Evidence Timestamp Assurance API | tenant-RLS timestamp inventory |
| 13 | check.timestamp.evidence.tst.expiry | tokens approaching certificate expiry | doctor.evidence.timestamp.evidence.token-expiry | tenant; Evidence Timestamp Assurance API | parsed token/certificate validity, tenant scoped |
| 14 | check.timestamp.evidence.tst.deprecated-algo | deprecated imprint/signature algorithms | doctor.evidence.timestamp.evidence.deprecated-algorithm | tenant; Evidence Timestamp Assurance API | parsed token algorithms + approved policy catalog |
| 15 | check.timestamp.evidence.tst.missing-stapling | timestamp evidence without OCSP/CRL material | doctor.evidence.timestamp.evidence.missing-stapling | tenant; Evidence Timestamp Assurance API | tenant-RLS token/evidence metadata |
| 16 | check.timestamp.evidence.retimestamp.pending | overdue re-timestamp work | doctor.evidence.timestamp.evidence.retimestamp-pending | tenant; Evidence Timestamp Assurance API | idempotent Evidence-owned work queue |
| 17 | check.timestamp.eidas.trustlist.fresh | EU trusted-list freshness | doctor.evidence.timestamp.eidas.trust-list-fresh | installation; /doctor/evidence/checks | validated signed trust-material pack and provenance |
| 18 | check.timestamp.eidas.qts.qualified | configured TSA qualified status | doctor.evidence.timestamp.eidas.qualified-status | installation; /doctor/evidence/checks | Cryptography plugin result + the three gates (§11) |
| 19 | check.timestamp.eidas.qts.status-change | recent qualified-status changes | doctor.evidence.timestamp.eidas.status-change | installation; /doctor/evidence/checks | successive validated trust snapshots |
| 20 | check.timestamp.timesync.system | system/NTP skew | doctor.evidence.timestamp.time.system-sync | installation; /doctor/evidence/checks | allowlisted time source or sealed NTP proof |
| 21 | check.timestamp.timesync.tsa-skew | TSA time versus system time | doctor.evidence.timestamp.time.tsa-skew | installation; /doctor/evidence/checks | parsed TST generation time + monotonic request bounds |
| 22 | check.timestamp.timesync.rekor-correlation | TST/Rekor chronology | doctor.evidence.timestamp.time.rekor-correlation | installation; /doctor/evidence/checks | Evidence-owned attestation/transparency metadata |
That is a deliberate 17 installation + 5 tenant split. The current ServiceDoctorContext has no tenant identity and evidence-web uses forced RLS, so registering the five tenant rows as ordinary service checks would invite either false-green results or an unsafe cross-tenant query. evidence-worker should evaluate them under an explicit tenant scope and the tenant-authenticated Evidence API should return their detail. /doctor/evidence/checks may report only a bounded, redacted installation summary such as affected-tenant count; it must never expose tenant ids, token bytes, or cross-tenant rows.
2.3 What the Doctor implementation actually does
The family is broader on paper than in composition:
AddTimestampingHealthChecksregisters options but does not bind a configuration section. The mounted loader invoked it with every optional configure delegate null, so mounted defaults had empty TSA/certificate/root inputs.- Default composition installs explicit unavailable providers for TSA statistics/client/registry, chain status, OCSP and CRL registries, revocation cache, EU trust list, qualified TSA registry, qualified-status changes, Evidence statistics, and recent attestations.
- Basic endpoint checks use HTTP
HEAD/OPTIONS, not certificate-derived OCSP/CRL protocol validation. The valid-response check depends on the unavailable TSA client. - Certificate expiry reads configured
ExpiresAtvalues. It does not parse the signer chain. - System time uses raw UDP NTP. TSA skew and Rekor correlation have unavailable default providers.
- Sealed mode reads the AirGap Importer filesystem registry under
var/lib/stellaops/airgap/timestamping, checking content digests. The LOTL path explicitly tests for XML signature-shaped content but does not cryptographically verify it. - The local result model has no Skip status. Intentional sealed skips are encoded as
HealthyplusairGapSealed=true, a false-green shape the successor must not carry. - Three heals exist (trust-list refresh, re-timestamp expiring evidence, TSA failover), but their default backends are local/in-memory and the shared gated dispatcher lived in retired doctor-web. They are not a durable operational path.
The test project covers deterministic evaluator logic, registrations, synthetic offline files, and the gated-remediation plumbing. It does not prove a live TSA round trip, production Evidence data, signed LOTL/member-state TSL validation, complete OCSP/CRL verification, qualified status, durable scheduling, or production remediation.
2.4 Real timestamp issuance is already in EvidenceLocker
This must not be confused with the dead Doctor façade. The live predecessor evidence-locker-web currently:
- hashes the bundle signature;
- builds a nonce-bearing RFC3161 request with BouncyCastle;
- POSTs
application/timestamp-query; - validates the response against the request;
- requires an accepted response status and token; and
- stores timestamp time, authority, and raw token in
evidence_bundle_signatures.
TimeStampResponse.Validate(request) proves request/response correlation (including the expected imprint/nonce contract); it is not full verification of the token signer’s certificate chain, trust anchor, timestamping EKU, or revocation status. Those remain target work in TA-2.
Outside the local harness, startup fails closed if timestamping is disabled or the endpoint is missing. Compose configures http://tsa.stella-ops.local:318/ and RequireTimestamp=true. The tsa role wraps openssl ts -reply, has no database, exposes no host port, and keeps its cert, private key, serial, and index under the tsa-data volume. Development self-provisions clearly labelled non-production material; production requires operator-provisioned material.
The assurance subsystem must reuse/re-author that real issuance, correlation, accepted-status, and token-storage path. It must then add full token signature, signer-chain/trust, timestamping-EKU, and revocation verification as separately tested target behavior. It must not replace either layer with the Doctor HEAD probe or any placeholder library.
2.5 Other timestamp code is useful evidence, not proof of production support
| Source | Current measured status | Durable disposition |
|---|---|---|
StellaOps.Attestor.Timestamping | Parses CMS/TSTInfo, checks imprint, signature, timestamping EKU, offline chain and Rekor time correlation; its issuance method always throws because no TSA transport is configured. Production consumers: CLI only; tests otherwise. | Re-author verified pure parsing/evaluator logic inside Evidence; remove the CLI source edge through a closed Evidence API/SDK seam. |
StellaOps.Attestor.Infrastructure/Timestamping/TsaMultiProvider.cs | No call sites. Builds a raw SHA-256 payload instead of RFC3161 and treats response bytes/time-now as a parsed response. | Do not carry. |
StellaOps.EvidenceLocker.Timestamping | Solution-only, zero production project consumers. Repository targets legacy evidence.timestamp_tokens/revocation_snapshots; those tables are absent from the consolidated Evidence baseline, have no tenant id, and exist only in a central pre-1.0 migration. Expiry is a three-year generation-time proxy; OCSP/CRL verification is parse-only. | Do not wire or mechanically port. Use its bundle/retimestamp vocabulary only as an inventory input. |
StellaOps.Cryptography.Plugin.Eidas | Contains trust-list parsing/signature checking, qualified timestamp verification, sealed fixture packs, and fail-closed runtime claim gates. It also contains incomplete/heuristic paths. Shipped runtime YAML does not enable a live public endpoint by default, although the library configuration type still carries an EU LOTL URL default. | Consume only through the existing cryptography plugin contract/result boundary; never compile its implementation into Evidence. |
StellaOps.AirGap.Time / AirGap Importer | Contains offline RFC3161/trust-material experiments but is dark/unrouted and belongs to the OfflineKit consolidation/retirement path. | OfflineKit transports a versioned artifact; Evidence owns validation. No source reference. |
2.6 Existing Evidence doctor checks do not overlap
The not-yet-live evidence-web skeleton already registers the three standard database checks plus five family checks:
- own-database identity;
- append-only trigger enabled;
- forced RLS;
- verdict-chain linkage; and
- legal-hold integrity.
Those checks measure database and evidence-spine invariants. None measures RFC3161 issuance, timestamp-token validity/expiry, TSA/trust/revocation state, or time correlation. Timestamp Assurance extends this family; it does not replace or duplicate those eight checks.
3. Proposed runtime and contract boundary
3.1 API surfaces
IMPLEMENTED 2026-09-07 (TA-4) — this table is the contract as it ships, verified against src/Evidence/StellaOps.Evidence.WebService/TimestampAssurance/TimestampAssuranceEndpoints.cs and pinned by EvidenceRouteInventoryTests (fixture consolidated-route-inventory.tsv). Scopes are the existing catalog scopes; no new scope name was needed.
| Surface | Scope | Purpose |
|---|---|---|
GET /doctor/evidence/checks | installation, ops.health | The 17 installation checks beside the family’s eight, through doctor-check/v1; deterministic envelope, measured values and pointers only. No tenant row is read. |
GET /api/evidence/v1/timestamp-assurance/status | evidence:read (caller’s tenant) | The latest durable run’s five tenant results plus a bounded installation posture (sources configured, provider count, check count) and the closed-gate notice. |
POST /api/evidence/v1/timestamp-assurance/runs | evidence:create (caller’s tenant) | Evaluate the five tenant checks over the caller’s stored tokens and re-timestamp queue NOW and record the run durably (evidence.timestamp_assurance_runs/_results). Idempotent on idempotencyKey; the run id is derived from tenant + key. No network probe: tenant runs read stored evidence only. |
GET /api/evidence/v1/timestamp-assurance/runs/{runId} | evidence:read (caller’s tenant) | One durable run; another tenant’s run is 404 by row-level security, not by filter. |
GET /api/evidence/v1/timestamp-assurance/providers | installation, ops.health | Provider ids, endpoint hosts, requirement, plaintext posture and whether a credential reference is configured — never a credential, never an endpoint URL with user info. |
GET /api/evidence/v1/timestamp-assurance/evidence/{bundleId} | evidence:read (bundle’s tenant) | One capsule’s parsed token facts (genTime, imprint/signature OIDs, signer expiry, revocation-material presence) and its local evidentiary classification: technical state indeterminate with reasons named, regime not claimed, every gate closed, validation basis local-validation-against:<pack>@sha256:… (pack none when no trust-anchor bundle is configured). Carries the §1.E disclaimer verbatim. |
The API takes tenant identity from the verified request context only — the tenant claim resolved through the family’s catalog replica, exactly as every Locker route — and reads no query or body tenant. Every payload carrying a classification carries TimestampClaimWording.RequiredDisclaimer verbatim; every payload carries the product-wide closed-gate notice while the operator claim gate is closed; the emitted-text guard (TimestampClaimWording.FindForbidden) is asserted over every payload by TimestampAssuranceApiTests.
3.2 Events and plugins
- Evidence publishes a versioned, tenant-bearing
evidence.timestamp-assurance.observed.v1summary through its outbox only if a real consumer is named. It never publishes token/trust payloads. - Re-timestamp requests and completions stay internal to the Evidence database/worker until a real cross-service consumer is proven; do not invent an event bus merely for scheduling.
- Regional algorithms and qualified-status evaluation enter through the existing Cryptography plugin ABI. Evidence stores the plugin id/version/digest and result, not plugin internals.
- OfflineKit produces a content-addressed
timestamp-trust-bundle/v1artifact containing signed trust lists, roots/intermediates, revocation snapshots, NTP proof, manifest, and provenance. Evidence validates and imports it. The seam is wire/artifact based and versioned. SPECIFIED 2026-08-22 (TA-5) — read the specification, not this bullet:timestamp-trust-bundle/v1. The consumer (StellaOps.Evidence.TimestampAssurance.TrustBundle) and the closed producer-owned contract project (src/OfflineKit/__Libraries/StellaOps.OfflineKit.TrustBundle.Contracts) exist; the PRODUCER does not yet, and building it is OfflineKit’s work. The one thing to carry away if you read nothing else: the manifest declares identity and integrity only — nonotAfter, nonextUpdate, nostatus— because a manifest field stating a fact about the material would be the configured-ExpiresAtfalse green this programme exists to retire, reappearing one layer out and inside a signature.
3.3 Privilege and network isolation
evidence-webremains read-oriented. It does not hold TSA private keys and does not execute automatic remediation.evidence-workerreceives outbound egress only to installation-allowlisted TSA, OCSP, CRL, trusted-list, NTP, and transparency endpoints. DNS resolution, resolved-address policy, redirect handling, response-size caps, and timeouts are enforced on every hop.- The local
tsais reachable only on the compose network. It owns/mountstsa-data; neither Evidence role mounts that volume. - TSA authentication values are Vault/secret references resolved at runtime. They are not stored in
stellaops_evidence, logged, returned by the API, or copied into evidence outputs. - Signer custody does not move. Timestamp Assurance neither calls Signer for TSA issuance nor gains access to Signer material.
4. Online, sealed, degraded, and scheduling semantics
4.1 Online
- A valid-response probe sends a real nonce/imprint-correlated RFC3161 request, verifies the response, and discards the probe token after recording bounded metadata unless retention policy explicitly requires the token as audit evidence.
- OCSP and CRL checks derive identifiers and distribution points from the actual TSA certificate;
HEAD,OPTIONS, and arbitrary configured URI checks are insufficient. - Qualified-status output is emitted only after all three counsel-ruled gates pass (§11). Otherwise the result carries the approved technical-only wording.
4.2 Sealed/offline
- No external egress occurs.
- The local TSA can continue issuance when configured with operator-controlled material.
- Trust, revocation, and time checks use
timestamp-trust-bundle/v1and report its digest, issuer, issued/valid-until times, and verification result. - What the artifact can and cannot answer, measured at TA-5. It genuinely serves TRUST ANCHORS and the REVOCATION SNAPSHOT, both parsed from the material. It does not serve system time: a static signed proof is a lower bound on the current instant, so
now - genTimereturns the age of the bundle and would report a correctly-set clock as days fast, andSystemTimeObservationcannot express “bounded below only”. It does not serve trusted-list freshness either, even when a trust-list part is present, because interpreting an ETSI list needs the Eidas implementation and D-TA-11 measured that the Cryptography plugin ABI has no contract to reach it through. Both stay explicitly unavailable rather than approximated. - Missing, invalid, or stale mandatory material is unhealthy/degraded with an explicit reason. It is never encoded as Healthy merely because the installation is sealed.
- A provider declared external-only is
unavailable-by-sealed-policy; whether that is warning or critical follows the installation’s provider policy (mandatory versus optional).
4.3 Schedules
IMPLEMENTED 2026-08-22 (TA-5) as StellaOps.Evidence.TimestampAssurance.Scheduling; COMPOSED into evidence-worker 2026-09-07 (TA-5, §13). The seven intervals below are carried VERBATIM into TimestampSchedulePlan.DesignDefaults and pinned one-per-interval by test, following D-TA-8’s reasoning: the rehome already changes where checks run and what feeds them, and changing the cadence at the same time would make any behaviour difference unattributable. Jitter (a tenth of the interval, subtractive only) and backoff (one minute, doubling, clamped to the interval) are TA-5’s additions, not the design’s.
All schedules are worker-owned, configurable, jittered, single-flight, and fenced. Safe defaults (subject to acceptance testing):
- system/TSA time and local TSA reachability: every 5 minutes;
- active TSA/OCSP checks: every 15 minutes;
- CRL/cache validation: hourly;
- chain/root/provider posture: daily and whenever provider/trust material changes;
- trust-list freshness/status comparison: daily, while preserving the current 3-day warning and 7-day critical policy as compatibility defaults until owner/legal review;
- tenant timestamp-evidence evaluation: hourly, partitioned and bounded; and
- re-timestamp candidate planning: daily with the current 180/90-day warning/critical windows as compatibility inputs, not legal guarantees.
On-demand calls coalesce with an in-flight scheduled run. A failed source never causes a tight retry loop; exponential backoff is bounded by the next normal schedule.
How those two sentences are enforced, and why it takes two mechanisms. The LEASE (ITimestampScheduleLeaseSource, implemented over a PostgreSQL session advisory lock on the family’s own database) is cross-replica single-flight — on a two-role family where web and worker host the same loop, it is the only thing stopping two processes probing the same TSA. COALESCING is in-process: an on-demand caller that merely failed to take the lease would get NotLeader and no answer, when the answer it wants is being computed in the same process. Ordering is coalesce, then lease, then the P7 writer budget — the budget bounds WRITES, so a run that never happened because another replica held the lease must not spend a unit of it.
Backoff is CLAMPED to the interval, and the clamp is the contract rather than a safety net. An unbounded backoff eventually stops reporting on exactly the source that is broken, and the health output goes quiet rather than red.
Replay-safety is deliberately NOT in the scheduler. A lease bounds concurrency; it cannot make a run that already committed harmless to repeat, because the retry may happen minutes later on another replica with the lease legitimately free. That guard is the content key on evidence.timestamp_assurance_runs — the UNIQUE (tenant_id, idempotency_key) TA-3 added and documented as “the replay guard”.
5. State, migrations, retention, and evidence
5.1 Database and object ownership
No new database. If implementation proves durable state is required, it belongs in stellaops_evidence and auto-migrates from embedded forward-only Evidence migrations. Proposed logical state (names are design labels, not approved DDL):
- provider/trust metadata and content digests (installation scoped);
- bounded run/result summaries (installation or tenant scope explicit on every row);
- idempotent re-timestamp work items (tenant scoped); and
- immutable observation/audit pointers.
Raw timestamp tokens already stored with evidence bundles are not duplicated. Large trust lists, certificate chains, OCSP/CRL snapshots, and proof bundles live content-addressed in an Evidence-owned object prefix; PostgreSQL stores digest, media type, size, validity, provenance, and reader keys.
5.2 ADR-039 implications
- P7: every snapshot, run, result, and queue writer declares row/byte/WAL/batch budgets. The worker pauses before its safety floor and exposes the reason through the standard capacity check.
- P13: trust snapshots and assurance observations are append-audit; run detail is partitioned/bounded; derived summaries are rebuildable; payloads are separated from hot rows; indexes name their reader; all writers use content/idempotency guards. No second semantic copy of a TST is allowed.
- P16: name and budget the Evidence timestamp-assurance object prefix and
tsa-dataownership. No Valkey state is needed initially. Cross-service artifacts are consumed by versioned contract, never by reading another service’s prefix. - P19: the Evidence host graph may use the shared Doctor contract, closed Evidence/Signer SDKs, and the Cryptography plugin ABI. It must not compile Doctor engine/host, AirGap Importer, OfflineKit implementation, Cryptography Eidas implementation, legacy EvidenceLocker/Attestor implementation, or another service’s tests.
5.3 Retention and legal holds
- Bundle-attached timestamp evidence follows the bundle’s evidence/regulatory retention and legal hold. Re-timestamping appends a successor; it never rewrites or deletes the original token.
- Trust/revocation snapshots needed to reproduce a historical verification are append-audit and retained at least as long as the evidence they justify.
- Transient probe bodies that justify no retained evidence are discarded after verification; bounded metadata remains.
- RULED 2026-08-23 (§11): there is no single eIDAS retention period for Stella Ops as a relying-party evidence system — Article 24’s “as long as necessary” obligation is directed at QTSPs. The governing period is
R = the longest of the parent release-evidence retention period, applicable statutory or sector record period, contractual/CP-CPS period, relevant dispute or limitation period, active investigation period, and legal hold, modelled asTimestampRetentionProfile. A positive claim profile may not open without aretention_profile_id. - The 180-day / 90-day re-timestamp windows and the 3-day / 7-day trusted-list windows remain product policy — counsel confirmed that characterisation explicitly. They are advance operational warnings, never legal minima and never grace periods.
6. Compatibility, rollout, rollback, and observability
6.1 Compatibility
- Superseded 2026-09-07 (TA-8, D-TA-32): there is no deprecation window and no runtime alias. The 22 legacy ids were cut over to their canonical ids in one change; the catalog keeps the legacy→canonical map as history, and
LegacyTimestampCheckIdRatchetConformanceTestsforbids a legacy id anywhere outside that map and the orphan plugin tree TA-9 retires. - Each rendered result still records
check.canonicalIdandcheck.legacyId(TA-1), as history. - Doctor IntegrationCatalog and its ratchets, the AdvisoryAI search seed, the Web e2e fixtures, the unified-search QA cases and the 22 operator articles migrated together (§14).
- The seven retired Doctor timestamp dashboard endpoints have no source callers. Do not resurrect doctor-web for compatibility. If an operator-facing dashboard is required, build it against the Evidence API.
6.2 Rollout and rollback
Land a source-only catalog/evaluator slice in the idle Evidence tree; no host wiring.DONE 2026-08-21 (TA-1) — see §8.- Add real read-only adapters and red-proof every unavailable/error branch.
- Compose into
evidence-web/evidence-workeronly after the Evidence API/cutover program permits it; registration stays default-off. - Shadow-run against current EvidenceLocker/TSA without changing issuance, compare results, and record divergences.
- Enable read-only installation checks, then tenant evaluations.
- Enable durable scheduling. Remediation remains disabled until its own gate is complete.
- Stop packaging the orphan bundle and retire legacy source only after all consumers and ids have migrated and parity is proven.
Rollback disables registration/scheduling and returns to the prior Evidence issuance path. It does not roll back migrations; recovery follows ADR-004 forward-only rules. No step changes TSA or Signer key custody, so rollback never moves private material.
6.3 Observability and security acceptance
- Metrics: run counts/durations by canonical check/source/result; source freshness; queue age/depth; provider latency/failure; trust-bundle age; re-timestamp success/failure; budget utilization.
- Logs carry run/check/provider ids, tenant-safe correlation, source type, and failure class; no tokens, certificate bodies, URLs with credentials, secret refs, or tenant evidence identifiers.
- Every retained result identifies code/plugin version and digest, configuration revision digest, trust-bundle digest, observation time, and source mode (
online,local-tsa,sealed-bundle). - Tests include real RFC3161 fixture responder round trips, nonce/imprint mismatch, malformed and oversized responses, redirect/SSRF/address-policy cases, chain/EKU/time validity, signed and tampered trust material, OCSP/CRL signature/status/time, RLS cross-tenant denial, sealed no-egress, P7 backpressure, idempotent replay, legacy aliases, and isolated publish closure.
7. What local source proves, and what it does not
| Locally proved | Not proved; validation still required |
|---|---|
| The Doctor family has 22 registrations and zero runtime host after doctor-web retirement. | That the 22 checks are legally sufficient for any jurisdiction or certification. |
| EvidenceLocker currently performs real RFC3161 request/response correlation, requires an accepted response with a token, stores it, and requires a TSA in non-harness mode. | Full signer-chain/trust/EKU/revocation verification by that issuance client, or that the development OpenSSL TSA/any operator certificate is a qualified TSA/QTSP. |
| The eIDAS plugin can technically parse/verify configured material and its claim gate denies affirmative qualified-service claims without the pack/agreement conditions. | Whether any particular deployment’s provider, exact service, jurisdiction and agreement satisfy the three gates — counsel ruled on the RULES (§11), not on any deployment’s facts. No external regulatory research was performed by engineering. |
| The consolidated Evidence model stores bundle timestamp metadata and enforces forced tenant RLS/legal holds. | Exact regulatory retention periods or whether every OCSP/CRL/trust snapshot must be retained. |
| Signer is a separately approved custody boundary and the TSA has its own key volume. | Any authority to move, share, or reuse either private-key population. This proposal explicitly does not. |
The legal/claim question was put to counsel and answered on 2026-08-23; §11 carries the ruling and is authoritative over any wording earlier in this document. In short: Stella Ops never describes itself as providing a qualified trust service, and it may describe a specific token as an EU qualified electronic time stamp at issuance only under an approved provider/service/jurisdiction/ deployment claim profile that passes all three gates. No such profile exists, so the positive path is unreachable today by construction rather than by policy.
8. First safe implementation slice — LANDED 2026-08-21 (TA-1)
The source-only slice is implemented. What exists:
| Path | What it holds |
|---|---|
src/Evidence/__Libraries/StellaOps.Evidence.TimestampAssurance/Catalog/ | The 22-row catalog: legacy id, canonical id, scope, category, default severity, surface, what it measures, and the real source it may not report without. Alias resolution both ways lives here and nowhere else. |
.../Evaluation/TimestampSource.cs | The availability wrapper plus the stable unavailable-reason codes. |
.../Evaluation/TimestampAssuranceVerdict.cs | The verdict type and Match, which short-circuits before an evaluator body can run without an observation. |
.../Evaluation/TimestampObservations.cs | The explicit input records — every field a measurement, none fillable from configuration. |
.../Evaluation/TimestampAssurancePolicy.cs | The legacy-compatible thresholds, transcribed from the orphaned Doctor options so the rehome changes ids and sources without changing when an operator is paged. |
.../Evaluation/TimestampAssuranceEvaluators.cs | The 17 deterministic installation evaluators. |
.../Checks/ | ITimestampAssuranceSources (the read port), UnavailableTimestampAssuranceSources (the TA-1 default: every source unavailable), and the 17 IServiceDoctorCheck types. |
src/Evidence/__Tests/StellaOps.Evidence.TimestampAssurance.Tests/ | 98 tests: catalog conformance, the false-green ratchet, per-evaluator happy/malformed branches, determinism, and the structural inertness proofs. |
What is deliberately absent, and is TA-2/TA-3/TA-4 work:
- No adapter. The only
ITimestampAssuranceSourcesimplementation in the assembly reportssource-not-configuredfor all fifteen reads, so all 17 checks are unhealthy-and-explicit. - No host wiring. There is no
IServiceCollectionextension and no DI package reference; a test asserts the assembly exposes no method taking anIServiceCollection, so registration cannot happen by accident.evidence-webandevidence-workerdo not reference the project. - No tenant check type. The five tenant rows are catalogued and the base class throws if given one, because
ServiceDoctorContextcarries no tenant identity. - No database, network, schedule, remediation, or compose change. The assembly’s only non-BCL reference is
StellaOps.Doctor.Plugin.Abstractions, asserted at runtime against the loaded assembly rather than against the project file.
The slice is independent of owner/legal claim approval and safe before the Evidence live cutover because nothing can execute it. The qualified-status evaluator is where that separation is visible: a passing technical verdict with the TA-6 gate closed reports technical validation only in wording pinned verbatim by test, and never asserts a qualified timestamping service claim.
9. Read-only protocol adapters — LANDED 2026-08-21 (TA-2)
StellaOps.Evidence.TimestampAssurance.Adapters supplies the six observations TA-2’s criteria name. It is a separate assembly from the TA-1 core on purpose: everything that can open a socket lives here, so the core’s runtime assertion that its only non-BCL reference is the shared doctor contract survives unchanged, and a future edit that gives the core an HTTP dependency fails the core’s own test.
| Adapter | Legacy placeholder it replaces | What it now measures |
|---|---|---|
Rfc3161/Rfc3161ProbeClient | HTTP HEAD/OPTIONS and the unavailable TSA client | A real nonce-bearing RFC3161 exchange. Status, token presence, nonce match and imprint match are measured separately, so the check can name which one failed; TimeStampResponse.Validate runs as an independent cross-check and a disagreement between the two is itself reported. |
Certificates/CertificateChainInspector | the configured ExpiresAt date | Validity, signature algorithm and SHA-256 thumbprint parsed from DER; a real chain build at a stated verification time against the operator’s anchors; id-kp-timeStamping presence and criticality (RFC 3161 §2.3). |
Revocation/OcspProbe | an HTTP probe of a configured URI | A request built from the certificate’s own AIA, with the response’s signature, CertID equality, status and validity window each verified. Delegated responders are accepted only when the issuer certified them with id-kp-OCSPSigning. |
Revocation/CrlProbe | parse-only | A CRL fetched from the certificate’s own distribution point, signature-verified against the issuer, checked for the subject’s serial and for a current nextUpdate. |
9.1 The egress control, and why IEgressPolicy is not it
IEgressPolicy is used as the estate’s sealed-mode gate and nothing more. Read before assuming: EgressPolicy.Evaluate opens with if (!IsSealed) return EgressDecision.Allowed;, so on an unsealed installation it permits every destination unconditionally; its IsLoopback/IsPrivateNetwork helpers are allow-list widenings inside sealed mode, and both classify by host string, so a host that is a name is never recognised as private.
That gap matters here more than anywhere else in the estate, because two of the four adapters fetch URLs chosen by whoever issued the certificate. TimestampEgressGuard therefore owns the SSRF half outright, in this order: scheme → explicit host allowlist (no wildcards, applied in every mode, and applied to certificate-derived destinations too) → sealed-mode gate → DNS resolved here with every resolved address vetted → the connection pinned to a vetted address so the name cannot be re-resolved between check and connect → redirects refused rather than followed, bytes-read capped (never a declared Content-Length), one budget over the whole sequence.
X509Chain is built with RevocationMode = NoCheck as a security choice: it does its own AIA/OCSP/CRL fetching on its own HTTP stack, which would bypass the allowlist, the address policy and the sealed gate entirely.
9.2 What TA-2 deliberately does not supply
Nine of the fifteen port reads still return source-not-configured, each naming the task that will supply it: the revocation-snapshot cache, the stapling summary and transparency correlation need Evidence-owned state (TA-3); the trusted-list pack needs the signed timestamp-trust-bundle/v1 artifact and the NTP proof needs its sealed form (TA-5); qualified status needs the Cryptography plugin ABI and the owner/legal claim gate (TA-6). A partially wired adapter that returned a plausible observation instead would be the exact false green this program exists to retire, so the honest unavailable is the correct output rather than a gap.
The trust anchors TA-2 uses are an operator-supplied PEM bundle, recorded by digest. TA-5 replaces the transport with a signature-verified content-addressed pack; the parsing and chain building do not change. Because that bundle is unsigned operator material, eidas.trust-list-fresh continues to report unavailable rather than reporting on it.
10. Evidence-owned state — DELIVERED SLICE 2026-08-25 (remaining TA-3 work is pending)
002_timestamp_assurance.sql adds four tables to the family’s own evidence schema, inside the existing stellaops_evidence database. After TA-6 supplied counsel’s disposition, 003_timestamp_assurance_reproducibility.sql adds the reproducible-result, exact-snapshot, retention and legal-hold dependency state that 002 correctly refused to guess. Migration 002 is applied history and was not edited. This slice covers parsed-token conclusions; counsel §7’s pre-token failed-probe evidence remains the explicit gap in §10.4. No new deployable and no new database.
| §5.1 candidate | Verdict | Reason |
|---|---|---|
| bounded run/result summaries | ADDED — timestamp_assurance_runs, timestamp_assurance_results | Only the five TENANT results are stored. Installation results are not: the 17 are pure functions over live probes served pull-based, and doctor-check/v1 carries no timestamp by contract, so a stored copy holds nothing a re-run cannot produce while being able to contradict it. The runs table is kept for the TA-5 replay guard, not for normalisation. |
| idempotent re-timestamp work items | ADDED — timestamp_retimestamp_queue | …evidence.retimestamp-pending counts overdue work; you cannot count work that was never recorded. |
| immutable observation/audit pointers | ADDED — timestamp_reissues | On a measured constraint: evidence_bundle_signatures is PRIMARY KEY (bundle_id, tenant_id), one row per bundle, so a successor written there would OVERWRITE the original that criterion 5 requires preserved. |
| provider/trust metadata and content digests | ADDED BY FORWARD MIGRATION 003 after TA-6 — timestamp_assurance_objects, timestamp_trust_snapshots, timestamp_snapshot_authentication, timestamp_qualification_results, result dependency tables, retention profiles and exact hold pins | Counsel §§4/7/9 now define the exact retained material, R, supersession and reproducibility rules. The earlier refusal remains in migration 002 as the correct historical decision; 003 is its forward-only successor. |
10.1 Why the successor table is not a second TST representation
§5.1 says raw timestamp tokens already stored with evidence bundles are not duplicated, and that still holds exactly. timestamp_reissues never reads, copies or modifies evidence_bundle_signatures; a successor is new material from a later exchange, and the row stores a content-addressed pointer plus bounded metadata rather than token bytes. The original row is what the table exists to avoid overwriting, and a test reads it back byte for byte after two successors are appended.
10.2 Invariants the DATABASE enforces, not the application
- Forced RLS on all twelve Timestamp Assurance tables, through the one existing
evidence_locker_app.require_current_tenant()resolver — one tenant rule per database cannot drift from itself. FORCE is load-bearing: without it the table owner (the account the service connects as) is exempt whilerelrowsecuritystill reads true. Dropping it from one table drove four tests red. - The tenant-result table CHECK-refuses an installation check id (R-TA-2), so the two populations cannot mix even if a future writer is careless.
- Evidence payloads are capped at 8 KiB and messages at 2000 chars — “pointers and measured values, never dumps” stays true only if something enforces it.
- P16 is database-enforced: existing successor-token pointers remain under
evidence/timestamp-assurance/tokens/<sha256>and counsel-disposed shared objects must matchevidence/timestamp-assurance/objects/<sha256>. The prefix is registered in the database ownership matrix.tsa-dataremains the TSA container’s registered volume and no Evidence role mounts it. timestamp_reissuesis append-only by trigger (EVIDENCE_REISSUE_IMMUTABLE): a correction is a new ordinal, never an edit.- Both bundle FKs are
ON DELETE RESTRICT, following the EVD-4evidence_holdsruling — the database refuses to delete a bundle whose re-timestamp history or queued work still names it, rather than leaving a row scoped to nothing.
10.3 Counsel-disposed reproducibility state (migration 003)
timestamp_qualification_resultspersists counsel §9’s complete result vocabulary and the ten §2 machine fields. A deferred database trigger refuses an operator-gate-open result unless the exact token, canonical response facts (or the optional retained raw response), chain, CP/CPS, agreement, signed national TL, LOTL, revocation object and role-appropriate authentication path are all retained. It performs no live lookup. Blank positive identifiers and a validation-basis digest that differs fromoperator_pack_digestare CHECK-refused.- Exact signed TL/LOTL/OCSP/CRL bytes remain outside hot rows at their content-addressed object pointer. Snapshot rows retain issue time,
NextUpdate, sequence/version, source, retrieval time, signature-validation result, validator provenance and the LOTL/OJEU/pivot or issuer/responder authentication objects. Legacy TLv5 bytes carrylegacy-trusted-list-format:v5; a normalised TLv6 representation cannot stand in for them. timestamp_retention_profilesstores every explicit component ofR; none has a period default and the database derives the longest supplied period. Active legal holds are dynamic pins, not a fabricated fixed duration. Object deletion calls a database truth table that returns true only when reference count AND active-hold count are both zero. Pin insertion proves the object is an actual dependency of that result, so a hold cannot capture an unrelated global trust pack.- All five text-rich tables have an aggregate 64 KiB logical UTF-8 metadata CHECK. It sums every variable-width field rather than relying on
pg_column_size, so compression/TOAST cannot turn an arbitrarily large caller value into a false pass. Exact evidence bytes remain outside the row. - Results and dependency edges are append-only. A successor names
supersedes_result_id; the security-invoker current-result view excludes the predecessor while both rows survive. An offline replay must preserve its originalevaluated_at, storecurrent_service_status=not-checked, and still prove every source was valid at that original evaluation time.
10.4 §7 failed-probe evidence (gap closed by migration 004, 2026-09-02)
Counsel requires a failed active probe’s raw request/response, headers and parser/transport error to survive through incident closure and the failed-run audit period, for R when it influenced a retained decision, and under a release/incident hold. Migrations 002/003 could not represent a pre-token failure (a qualification result requires timestamp_token_object_id and gen_time; 002’s doctor-result JSON is derived/rebuildable with no content-object or hold edge). 004_timestamp_failed_probe_observations supplies the state: an append-only timestamp_failed_probe_observations row per failed attempt (failure taxonomy, bounded error detail, retention-profile linkage, decision_relevant requiring a linked retained result) whose raw request/response/header bytes are content-addressed capture objects (probe-request/probe-response/probe-response-headers kinds) referenced through kind-validated, role-unique edges that the object-deletion blockers count; the existing timestamp_object_hold_pins path pins them under a release/incident hold. The TA-4/TA-5 runtime boundary is unchanged: no writer is composed into a host, so no host may yet CLAIM live failed-probe retention - the schema and its Testcontainers proofs are executable now.
10.5 Runtime boundary still owed
No object-store writer or qualification-result writer is composed into a host (TA-4 and TA-5 both declined to add one: with every claim gate closed the only classification that exists is indeterminate, D-TA-28). Whichever row can open a gate must add the fail-closed byte-capacity check named by the P16 registry before the first object write. The schema and acceptance tests are executable now; they do not claim the standing estate uses them. The worker-owned schedules (§13) write only the two things TA-3 already modelled — tenant run rows and PENDING queue rows.
11. The counsel disposition — what may be SAID and what must be RETAINED (TA-6, 2026-08-23)
Source of record: timestamp-assurance-counsel-thread-claims-trust-and-retention-reply.md. Disposition: APPROVED WITH CONDITIONS — the qualified-claim gate remains CLOSED by default. This section is authoritative over any wording earlier in this document.
11.1 THREE gates, not two
The two-gate model this design and its counsel inquiry both proposed is replaced:
| Gate | Answers | Implemented as |
|---|---|---|
| 1 — technical verification | Does the token parse, correlate, verify and chain? | TimestampQualificationInputs.TechnicalState (passed / failed / indeterminate) |
| 2 — regulatory classification | Was the EXACT service qualified at genTime? | RegulatoryClassificationEvidence → regulatory_gate |
| 3 — rights and claim publication | May we SAY so? | TimestampClaimProfile → rights_gate |
operator_claim_gate opens only when all three pass and an approved claim-text version exists. The separation is not cosmetic: folding gate 3 into gate 1 is how “the owner/legal claim gate is approved” ended up in an operator-facing sentence — an internal approval presented as evidence of qualification, which is now a prohibited expression.
11.2 indeterminate is the answer to absence
Missing, stale, ambiguous or disputed evidence produces indeterminate— never not-qualified, and never a warning-only positive. not-qualified requires affirmative contrary evidence: a signature-verified, in-date trusted list whose status history covers genTime, with the token signer mapped onto the listed service, saying so. There is no post-expiry grace period; the 3-day / 7-day product windows play no part in the gate.
§8 of the disposition names four conditions that may degrade to a warning (all future-risk) and seven that may not. Both lists are a closed enum, TimestampAssuranceCondition, with no default arm: an unclassified condition throws rather than defaulting to warnable.
11.3 Approved wording, verbatim
TimestampClaimWording carries wordings A–E, the UK sentence, the historical sentence, the seven prohibited expressions and the sentences this disposition superseded. Every string is asserted character-for-character against the disposition document on every test run, and an emitted-text guard scans every check message and every evidence value for a prohibited or superseded expression.
Two honest gaps, recorded rather than papered over: counsel approved no operator-facing wording for a not-qualified outcome, and none for the EEA-country-profile or third-country-equivalent regimes. Those outcomes emit no prose at all — the machine-readable fields carry the result and approved-claim-wording-unavailable says why. Inventing regulated claim text would be the D-TA-10 defect repeated.
11.4 Machine-readable state
Ten fields, counsel’s own names, exported by TimestampQualificationClassification.Fields(): technical_state, qualification_regime, qualified_status_at_issuance, current_service_status, regulatory_gate, rights_gate, operator_claim_gate, validation_basis, reason_codes, claim_profile_id. The validation basis is local-validation-against:<operator-pack-id>@sha256:<digest>; claimed-against: and bare validated-against: were rejected by name and the parser refuses both. Every state enum’s default member is its conservative value, so a skipped field lands on indeterminate / closed / not-checked / none rather than on a positive.
11.5 What this does NOT change
No runtime, deployment or distribution gate. TA-3 adds forward-only database state but composes no writer into a host (TA-4 is gated on EVD-5/EVD-9), and no claim profile exists anywhere, so the positive path is unreachable by construction — which is exactly counsel’s implementation gate: “No positive qualified-status output may ship until a concrete provider/service/jurisdiction/deployment claim profile passes all three gates.”
12. Tenant API and installation composition — LANDED 2026-09-07 (TA-4)
What §3.1 proposed now runs in evidence-web; what §10.5 owed is discharged for the tenant half.
- Installation composition.
TimestampAssuranceInstallationCompositionregisters the 17 checks as 17 distinct implementation types behind the doctor’sops.healthpolicy. With noEvidence:TimestampAssurance:Adaptersprovider the host wiresUnavailableTimestampAssuranceSourcesand all 17 report unhealthy withsource-not-configured; with a provider section it wires TA-2’s HTTP adapters behind the AirGap egress policy./doctor/evidence/checksanswers 25 entries. - The five tenant checks exist now. TA-1 built the 17 installation evaluators; the five tenant rows (12-16) had no evaluator until this slice:
TenantTimestampAssuranceEvaluatorsover aTenantTimestampInventoryObservation— the tenant’s stored RFC 3161 tokens parsed byStoredTimestampTokenParser(genTime, imprint/signature OIDs, signernotAfter, CRL/OCSP presence; a token that does not parse is a failure CLASS on the observation, never a pass) and its re-timestamp queue as counts. Thresholds joinedTimestampAssurancePolicy(EvidenceTimestampMaxAge365 d,TokenSignerExpiryWarnWindow180 d,DeprecatedImprintAlgorithmOidsMD5/SHA-1,RetimestampOverdueGrace1 d). - Durable runs.
PostgresTenantTimestampInventorySourceandPostgresTimestampAssuranceRunStore(family DAL) read and write under the tenant GUC the RLS policies test, transaction-scoped; proven against a converged container owned by a non-superuser role with two tenants seeded — each read and write sees exactly one. A run recordscode_version/code_digest(the evaluator assembly’s bytes) andconfig_revision_digest(policy + provider ids/endpoints, never credentials), so a threshold change is visible on every later run. - Not in this slice, still owed: the object-store writer and the qualification-result writer (§10.5 — no
timestamp_assurance_objects/timestamp_qualification_resultsrow is written; the evidence route classifies in memory and every gate stays closed); the Platform doctor registration stays default-off (R-TA-11); the installation checks on this lab estate run with no provider configured until the compose overlay names the local TSA (TA-9’s activation).
13. Sealed seam and schedules composed — LANDED 2026-09-07 (TA-5)
What §4.2 and §4.3 owed a host now has one, and both Evidence roles compose it from the same configuration through the family’s StellaOps.Evidence.TimestampAssurance.Hosting assembly.
- One source graph, four shapes (
TimestampAssuranceSourceComposition): no provider and no bundle →UnavailableTimestampAssuranceSources; providers only → TA-2’s HTTP path behind the AirGap egress policy; a bundle directory only (Evidence:TimestampAssurance:TrustBundle) →ReloadingSealedTimestampAssuranceSourcesover the TA-5 reader, with NO probe client constructed at all; both →LayeredTimestampAssuranceSources, which gives every observation ONE authority (trust anchors and the revocation snapshot from the artifact; the TSA-path measurements from the local responder through the egress guard; the two genuinely external sources heldunavailable-by-sealed-policyunder a seal). A named bundle is validated and its anchor keys loaded at composition, so a broken mount fails startup rather than the first probe; a replaced artifact is re-decoded when its documents’ stamps move (checked at most once a minute). - The seven schedules run in
evidence-worker(TimestampAssuranceScheduleHost, one loop per design interval overTimestampScheduleCoordinatorand the family’s Postgres advisory-lock lease; every delay throughTimeProvider, so the loop is driven by a fake clock in tests). The five installation schedules run their check subsets and LOG verdicts and transitions — nothing persists, per D-TA-12. Tenant evaluation visits every active tenant and records one durable run per tenant per interval bucket under a derived key (schedule:tenant-evaluation:<bucket>), so a second replica or a repeated tick collides on TA-3’s content key. Only the two writing schedules carry a P7 writer budget.Evidence:TimestampAssurance:Schedules:Enabled=falseis the rollback lever (R-TA-11’s worker half). - Re-timestamp PLANNING enqueues, never executes.
RetimestampCandidatePlanner(core, pure) derives candidates from the SAME predicates the tenant evaluators use, restricted to counsel §7’s loss-of-verifiability events: an algorithm sunset (deprecated-algorithm) and an already-expired signer (token-expiring). The 180-day warn window, the 365-day staleness window and missing stapling stay WARNINGS and are not wired as triggers (D-TA-29). Rows land aspendingunder the queue’s derived key (tenant + bundle + reason + planning window), so a re-plan in the same window is a no-op by the database; nothing dequeues until TA-7. - Which tenants a schedule visits comes from the family’s OWN replica of the tenants catalog (
catalog_replica.replica_rows, drained by the web role’sCatalog:Replication:Tenantsseam) — the architecture pack refused a directshared.tenantsread (DC-12 / SCR-3). An unconverged replica (no drain checkpoint) makes the tick FAIL rather than answer “no tenants”. - Run metadata is shared.
TimestampAssuranceRunMetadatamoved from evidence-web into the Hosting assembly, so a scheduled run and an on-demand API run stamp identical code and configuration digests; the bundle directory joined the configuration digest. - Proven live 2026-09-07 (receipt
docs/implplan/_evidence/20260907-ta5-sealed-seam-and-schedules.md): seven loops started, seven first ticks completed, five durable scheduled runs for the five replicated tenants, no planned work on this estate, every lease released. Criterion 2: the worker sealed for one window and observed in its own network namespace across the first tick of every schedule reached exactly one remote endpoint — the family database — and nothing else. - A sealed estate must name its own TSA explicitly.
IEgressPolicyclassifies by host string (TA-2 §9.1), so under a sealAllowPrivateNetworks=truedoes NOT admittsa.stella-ops.local; the guard refused it before DNS and every TSA-path check reportedunavailable-by-sealed-policy. Fail-closed and correct, and an operator fact: name the local TSA through an AirGap allow rule or an IP-literal endpoint. - Still owed: the object-store and qualification-result writers (§10.5); the trusted-list and qualified-status interpretation behind an ABI that does not exist (D-TA-11); the Platform doctor registration (R-TA-11, TA-9).
14. Consumer cutover — LANDED 2026-09-07 (TA-8)
Every consumer of the Timestamp Assurance checks names the canonical doctor.evidence.timestamp.* id.
- Operator articles.
docs/doctor/articles/timestamping/was rewritten fromsrc/truth (the evaluators’ pass/fail rules, evidence keys andTimestampAssurancePolicydefaults), one article per canonical id, each carrying the product-wide closed-gate notice and the required disclaimer verbatim and a truthful “how to verify” (the Evidence doctor path withops.health, probed directly; the tenant API through the gateway).tools/scripts/validate/validate-doctor-timestamp-articles.pyguards all of it mechanically (canonical ids, wording verbatim, no prohibited expression, no legacy id on the consumer surfaces) with a--self-test; wired in.gitea/workflows/docs-timestamp-articles.yml. - Search. The AdvisoryAI doctor seed’s 22 entries carry the canonical ids and a probe command that works;
UnifiedSearchServicetreats adoctor.<service>.*id as host-served (copy the probe, nostella doctor run, no Doctor-UI route — D-TA-34). The Web e2e fixtures and the unified-search QA cases use the canonical ids. - Doctor registries.
IntegrationCatalogcites the canonical Evidence check for the TSA, OCSP, CRL and EU trust-list integrations; its tests and the P0/regional coverage ratchets follow. The coverage meta-check reads those integrations as uncovered until the Evidence doctor registers with the Platform aggregator and a doctor-check/v1-aware live-id resolver exists (D-TA-33, TA-9). - Not in this slice: a Timestamp Assurance Web UI (§1.C/§1.D wording rules apply when one is built against the Evidence API); the orphan plugin tree and the Doctor WebService bridge that mounts it (TA-9).
