Skip to content

Activate the Bulk PDF notifier authority

The Bulk PDF notifier authority (BulkPdfNotifierAuthority) is default-off. This guide lists the chart values an environment sets in cluster-gitops to turn it on, the zero-usage proof it requires, and the order in which it and featureFlags.bulkPdfUpload are enabled.

Changing these values is a GitOps change to environment configuration. Nothing in the SyRF repository activates an environment, and a merged PR does not prove one is ready. The other activation gates in the durable-capture evidence and in syrf#3168 still apply.

What each chart renders

Values key API Project Management Identity
bulkPdfNotifierAuthority.enabled yes yes yes
bulkPdfNotifierAuthority.zeroUsageProof.* yes yes yes
bulkPdfNotifierAuthority.clients[] clientId, environmentRoot, cleanupAuthorityId no same, plus clientSecret by Secret reference
bulkPdfNotifierAuthority.revokedClientIds[] yes no yes

While enabled is false the charts render no SYRF__BulkPdfNotifierAuthority__* variable, so the hosts keep their disabled defaults. The one exception is revokedClientIds, which renders regardless of enabled: Identity deletes revoked notifier clients on every start, and revoking is how an activated environment is turned back off.

Rendering fails if an enabled client omits any field. Identity never takes a literal client secret: each client names a Kubernetes Secret and the key inside it.

Prerequisites

  • The API has a complete OpenIddict introspection client: identityService.baseUrl (an absolute http(s) URL), identityService.audience, identityService.clientSecretName and, if not syrf-api, identityService.clientId. With the authority enabled, the API refuses to start and names every missing setting.
  • bulkPdfStorage.environmentRoot (or the preview root derived from syrf.prNumber) is the root the clients will name. Every client in one deployment uses the same single root, and production is rejected.
  • A Kubernetes Secret holds each notifier client secret for Identity. Its name and key go in the values; the secret material never does.
  • featureFlags.bulkPdfUpload is still false.

Values to set

Set the same enabled and zeroUsageProof on all three services. Set clients on API and Identity (Identity also needs clientSecret).

bulkPdfNotifierAuthority:
  enabled: true
  clients:
    - clientId: bulk-pdf-notifier-staging            # OpenIddict client the s3-notifier uses
      clientSecret:                                  # Identity chart only
        secretName: bulk-pdf-notifier-staging
        key: clientSecret
      environmentRoot: staging                       # single root for the whole deployment
      cleanupAuthorityId: 7b0c6f55-4d4c-4d41-9a55-2f2a1b8d7c01
  revokedClientIds: []
  zeroUsageProof:
    proofId: 0f4d2a9e-3c1b-4b8e-9d7a-5e6f7a8b9c0d   # new GUID per proof
    observedAt: "2026-09-16T09:00:00Z"
    expiresAt: "2026-09-16T09:45:00Z"               # later than observedAt, at most 1 hour after it
    activationRecordedAt: "2026-09-16T09:10:00Z"    # see "Record activation" below
    releaseRecordCount: 0
    storageBindingCount: 0
    quarantineFenceCount: 0
    queueMessageCount: 0
    embeddedJobCount: 0
    storageObjectCount: 0
    multipartUploadCount: 0

These values become SYRF__BulkPdfNotifierAuthority__Enabled, SYRF__BulkPdfNotifierAuthority__Clients__<n>__{ClientId,ClientSecret,EnvironmentRoot,CleanupAuthorityId}, SYRF__BulkPdfNotifierAuthority__RevokedClientIds__<n> and SYRF__BulkPdfNotifierAuthority__ZeroUsageProof__<Field>.

The zero-usage proof

The proof shows that the environment holds no Bulk PDF state the authority could take over. The hosts accept only a proof in which every counter is explicitly zero. An omitted counter does not render and binds as unset, which fails the proof, so every counter must be present.

Observe each count for the exact environment root, all within one window that starts at observedAt:

Counter What it counts
releaseRecordCount Notifier release records held by Project Management
storageBindingCount Bulk PDF upload storage bindings
quarantineFenceCount Bulk PDF upload quarantine fences
queueMessageCount Messages on the Bulk PDF notifier queues, visible and in flight
embeddedJobCount Bulk PDF upload jobs embedded in projects
storageObjectCount Object versions under the environment root's reserved Bulk PDF prefix
multipartUploadCount Incomplete S3 multipart uploads under that prefix

No script produces these counts yet. Record how each was observed with the change.

If any count is not zero, do not activate. The authority is a zero-only contract: an environment that already holds Bulk PDF state needs a separately designed migration. The hosts reject any non-zero counter, and Helm renders large numbers in scientific notation that does not bind at all.

The hosts check the proof at startup:

  • expiresAt must be later than observedAt and at most one hour after it.
  • Startup succeeds while the proof is fresh (observedAt ≤ now < expiresAt), or at any later time once activationRecordedAt is recorded.

Record activation

Upload admission needs a recorded activation, not just a fresh proof. Set activationRecordedAt to a time that is:

  • at or after observedAt,
  • before expiresAt, and
  • not in the future when the services start.

Commit it while the proof is still fresh. The recorded proof then survives restarts after expiresAt. If the window closes before activation is recorded, take a new proof with a new proofId.

Order of operations

  1. Confirm the prerequisites, with featureFlags.bulkPdfUpload still false.
  2. Take the zero-usage proof and commit the bulkPdfNotifierAuthority values for API, Project Management and Identity, with activationRecordedAt inside the proof window. Let ArgoCD sync.
  3. Check that API, Project Management and Identity start, and that Identity seeded the notifier clients.
  4. Only then set featureFlags.bulkPdfUpload: true in a separate change.

Do not reverse this order. API and Project Management refuse to start with uploads enabled and the authority disabled. Completed uploads record cleanup obligations that only the authority can discharge, and once uploads exist the zero-usage proof can no longer pass.

Turning the authority off

There is no designed deactivation procedure yet. Once uploads exist, their cleanup obligations can only be discharged by an active authority, so disabling it strands them; plan any rollback in syrf#3168 first. The mechanics available today: setting enabled: false stops rendering the clients and proof, and listing notifier client IDs in revokedClientIds makes Identity delete those OpenIddict clients and the API refuse their tokens. A revoked client ID cannot also be an active client.