# Findings Ledger — Workflow Inference Notes > **Audience:** Findings Ledger Guild, Vuln Explorer API, Console Guild > **Scope:** How workflow mutations (assign/comment/accept-risk/etc.) derive canonical ledger inputs when the caller omits low-level fields. ## 1. Chain + sequencing - **Chain derivation.** When a request does not provide `chainId`, we deterministically derive it from `tenantId :: policyVersion` (`Guid` from SHA-256 first 16 bytes). This keeps per-policy ordering stable and avoids callers leaking raw GUID logic. - **Sequence number.** We fetch the current chain head and expect `head.sequence + 1`. If the chain has no entries, the expected sequence is `1`. The append path still enforces optimistic concurrency and rejects mismatches. - **Previous hash.** We reuse the head’s `event_hash` (defaulting to the all-zero hash for genesis events) so writers don’t need to manage hash pointers. ## 2. Event identifiers + timestamps - **Event IDs.** If the caller omits `eventId`, we mint a V7 GUID to keep chronological ordering while remaining globally unique. - **Occurred / recorded timestamps.** `occurredAt` defaults to “now” in UTC (based on `TimeProvider`). `recordedAt` always comes from the service’s `TimeProvider` to avoid caller-provided drift. ## 3. Status & severity fallbacks - The reducer already maps event types to canonical statuses. Workflow service only writes `status` when the mutation explicitly changes it (e.g., `accept-risk` → `accepted_risk`, `target-fix` → `in_progress`, `verify-fix` → `verified`, `reopen` → `affected`). Otherwise we leave status null and let the reducer infer it. - Severity is never inferred inside workflow handlers—they rely on policy evaluation or reducer logic. ## 4. Attachments metadata - Attachments now include security context: every entry captures an AES-256-GCM envelope (`algorithm`, `ciphertext`, `nonce`, `tag`, `expiresAt`) derived from `attachments.encryptionKey`. - Signed URLs are generated with HMAC-SHA256 using `attachments.signedUrlSecret` and inherit `attachments.signedUrlLifetime` (default 15 minutes). URLs plus envelopes share the same expiry window. - Metadata is normalized (trimmed keys, deterministic ordering) before encryption so ledger hashes remain stable; duplicate IDs are deduplicated. - Actual binary blobs stay in Evidence Locker/S3; the envelope is what downstream services use to decrypt the blob once downloaded. ## 5. Validation surface - All handlers enforce tenant/policy/finding/artifact/vuln IDs, actor identity, and supported actor types. - Mutation-specific requirements (e.g., assignment requires assignee, accept-risk needs justification) are validated before any ledger append occurs. - Attachments are validated for ID/file name/MIME type/positive size and 64-char SHA-256 digests before encryption, preventing malformed payloads from burning hashes or emitting invalid URLs. These rules let upstream APIs/clients send high-level workflow intents without micromanaging ledger sequencing or hashing, while preserving deterministic ledger entries. LEDGER-29-005 implements the service described here; LEDGER-29-006 builds on it for secure attachment handling.