From 25356debcce4118cdfa86842029278fde1e64518 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:43:48 +0200 Subject: Publish FOG design documentation and Merkle tree --- docs/FOG-OBSERVABILITY.md | 718 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 718 insertions(+) create mode 100644 docs/FOG-OBSERVABILITY.md (limited to 'docs/FOG-OBSERVABILITY.md') diff --git a/docs/FOG-OBSERVABILITY.md b/docs/FOG-OBSERVABILITY.md new file mode 100644 index 0000000..b72034f --- /dev/null +++ b/docs/FOG-OBSERVABILITY.md @@ -0,0 +1,718 @@ +# FOG Observability + +Status: Structural Baseline 0.1 + +Date: 2026-08-08 + +## 1. Purpose and Claim Boundary + +`FOG-OBSERVABILITY-1` defines privacy-safe local logging, operational metric +collection, aggregate submission, operator diagnosis, and public health +publication for FOG. + +The objective is to detect failed or unsafe role state without creating a +second traffic-analysis system. Observability is part of the threat model. A +log server, tracing system, dashboard, crash collector, or support workflow +can otherwise preserve exactly the timing and relationship metadata that the +data plane is intended to minimize. + +This baseline fixes: + +- a no-event-stream production default; +- a closed metric and local-summary vocabulary; +- coarse non-overlapping collection windows; +- bucketed values and low-activity suppression; +- delayed role-to-observer submissions; +- separate local, operator, and public views; +- public anti-differencing requirements; +- bounded local retention and raw-submission expiry; +- crash, support, debug, access, and conformance rules. + +It does not activate a numeric observability profile. Window duration, bucket +boundaries, minimum activity, minimum independent reporters, release delay, +merge policy, retention, serialization, signature suite, and public grouping +remain explicit evidence-gated selections. No implementation or deployment +may silently choose them as protocol defaults. + +The standard-library Go module in `../observability/` is an executable +conformance model for the role-local typed collector and bounded volatile +ring. Its test values are synthetic. It is not `fog-observer`, an IF-11 wire +codec, a signature implementation, or a public exporter. + +## 2. Governing Requirements + +This document refines: + +- `TM-OPS-01`, logging and metrics leakage; +- `TM-NET-01`, timing and volume correlation; +- `TM-NET-03`, active suppression and n-1 behavior; +- `TM-ROLE-01` through `TM-ROLE-03`, role compromise and collusion; +- `TM-AVAIL-01`, bounded work and overload handling; +- `ARC-001`, separate trust domains; +- `ARC-007`, one owner for private state and keys; +- `ARC-008`, bounded inputs, work, queues, and state; +- `ARC-009`, no privacy-weakening recovery; +- `IF-11`, role-to-observer aggregate submission; +- the logging sections of `FOG-WIRE`, `FOG-SPHINX-PROFILES`, + `FOG-STORAGE`, and `FOG-COMPOSER`. + +When this document is narrower than a generic logging or monitoring practice, +this document controls for claim-bearing FOG profiles. + +## 3. Threat Model + +The protected assets are: + +- whether one user, peer, mailbox, route, packet, or conversation was active; +- exact event time, direction, sequence, size, and duration; +- linkability across roles, hosts, epochs, restarts, or support cases; +- capabilities, keys, tokens, replay state, and opaque protocol objects; +- operator, host, deployment, and user metadata not already required in + authenticated public consensus. + +Relevant adversaries include a compromised role, observer, dashboard, +operator account, support system, backup, or log collector, as well as an +external party that later obtains retained operational data. A curious or +compromised observer is within scope. The design therefore does not assume +that centralizing raw logs is safe. + +No observability design can hide what a node operator sees directly on that +node or what a network observer sees on links. The goal is narrower: do not +create a new persistent, cross-role, queryable correlation dataset. + +## 4. Invariants + +### OBS-INV-01: No data-plane event stream + +Production roles do not emit one record for each packet, message, handshake, +storage request, read, write, retry, connection, or cryptographic operation. +They update bounded in-memory counters or health state inside one coarse +window. + +### OBS-INV-02: Closed typed vocabulary + +Every field, role, metric, state, failure class, value kind, and visibility +class is allowlisted. Production collection APIs accept no arbitrary label +map, free-form message, raw error, peer-provided string, path, address, or +identifier. + +### OBS-INV-03: Coarse windows only + +A role records one window identifier, not event timestamps. Windows are +profile-fixed, aligned, and non-overlapping. Operators and public consumers +cannot request arbitrary time ranges. + +### OBS-INV-04: No exact exported traffic values + +Raw counters exist only inside the open volatile collector. Sealing converts +them to profile-defined buckets. Exact counts, sizes, latencies, ratios, queue +depths, and durations do not enter local summaries, observer submissions, or +publications. + +### OBS-INV-05: Suppress small activity sets + +Below the profile's minimum activity, every traffic-sensitive metric carries +the fixed `suppressed` value. Suppression does not remove fields or change the +report shape. Non-traffic health state may remain available. + +### OBS-INV-06: Delayed fixed-schedule submission + +Online roles submit on a profile-fixed schedule independent of whether real +traffic occurred. Each submission declares the earliest release window. +Immediate event-triggered submission is forbidden. + +### OBS-INV-07: Public output requires multiple reporters + +No role-local report can become a public report. `fog-observer` first combines +the profile-required number of independently authenticated reporters, then +applies coarsening, delay, suppression, and differencing controls. + +### OBS-INV-08: No cumulative or subtractable public series + +Public output does not expose cumulative counters, overlapping query windows, +arbitrary filters, node-level series, or stable dimensions that allow two +answers to isolate a smaller group. + +### OBS-INV-09: Bounded retention + +Local summaries use a bounded volatile ring or a profile-authorized protected +store. Raw signed observer submissions expire after bounded processing. +Retention is fixed in the active profile and cannot be extended through a +dashboard query or support request. + +### OBS-INV-10: Observability is not required for forwarding + +Failure, absence, overload, or compromise of `fog-observer` does not alter +packet forwarding, consensus validity, storage behavior, cover scheduling, or +cryptographic validation. Roles queue at most a bounded aggregate submission +and otherwise discard it. + +### OBS-INV-11: Production tracing is unavailable + +Claim-bearing builds have no packet, record, request, span, or connection +tracing mode. `DEBUG` or `TRACE` cannot be enabled by runtime configuration. +Synthetic conformance builds are a separate artifact rejected by production +configuration. + +### OBS-INV-12: Fixed shape within role and profile + +Every local summary and observer report contains the same ordered metric +positions for its role and profile. Unset values are `unknown` or `zero`. +Sensitive low-activity values are `suppressed`. Presence or field order does +not reveal which code path ran. + +## 5. Information Planes + +FOG uses three observability planes: + +1. **Local safety summary**: one role retains bounded coarse windows needed + for local diagnosis. It never contains event records. +2. **Operator aggregate**: an online role sends a delayed fixed-shape + aggregate over mutually authenticated IF-11. The observer may use it for a + protected operator health view. +3. **Public aggregate**: the observer combines enough independent reporters + and publishes only a delayed, coarsened, non-subtractable view. + +```text +role-local raw counters, volatile within one window + | + | seal once, bucket, suppress + v + bounded local summary + delayed IF-11 aggregate + | + | authenticate, combine, expire raw + v + operator view public view + protected delayed and multi-reporter +``` + +The networkless Composer and `fog-sx-send`/`fog-sx-receive` do not submit +automatic observer reports. They may retain only the local safety summary +allowed by their deployment profile. + +## 6. Data Classes + +The following classes are forbidden in every FOG log, metric, report, +dashboard, crash artifact, and generic support bundle: + +- plaintext, drafts, rendered content, contacts, labels, fingerprints, and + application fields; +- packet or record bytes, ciphertext samples, entry capsules, KEMSphinx + packets, storage envelopes, and imported attacker input; +- capabilities, vouchers, SURBs, reply material, replay tags, receipt + material, ratchets, storage streams, and secret or private key material; +- message, session, packet, request, record, box, receipt, connection, trace, + span, route, or bundle identifiers; +- source or destination IP address, peer ID, next-hop ID, full route, replica + selection, entry set, or per-source history; +- exact event timestamps, per-operation duration, direction trace, retry + sequence, queue item, read frequency, miss streak, and tombstone timing; +- raw error strings, parser offsets, expected values, detailed cryptographic + stages, stack traces, memory dumps, or exception objects; +- hostname, username, filesystem path, locale, timezone, device serial, + billing data, private operator contact, or infrastructure detail absent from + the authenticated public consensus. + +Hashes, truncation, encryption under a central log key, or pseudonymization do +not make a forbidden identifier safe. A stable digest remains a correlation +handle. + +## 7. Production Defaults + +Before a numeric observability profile is activated, the safe defaults are: + +- no packet, request, connection, or storage-access log; +- no automatic remote logging or telemetry; +- no public metrics endpoint and no host-published Prometheus endpoint; +- no OpenTelemetry auto-instrumentation, trace ID, or span ID; +- no automatic crash upload or support bundle; +- core dumps, process-memory capture, and production debug mode disabled; +- bounded volatile local summary only; +- observer submission and public publication disabled; +- generic application errors reduced to local fixed failure classes; +- remote errors remain coarse and non-amplifying under the owning protocol. + +A deployment is not permitted to replace these defaults with a generic log +shipper, service-mesh tracer, application performance monitor, or container +log collector and still claim the same profile. + +## 8. Role-Local Window Model + +One role creates exactly one collector for each coarse window. It may update: + +- a fixed unsigned counter for an allowlisted count metric; +- a fixed level bucket for queue, age, latency, ratio, or capacity state; +- a fixed health value for consensus, clock, key, replay, or cover state; +- one internal activity counter used only for the suppression decision. + +All counters saturate on overflow. They never wrap. The collector holds no +identifiers, timestamps, strings, samples, exemplars, or per-peer maps. + +Sealing is irreversible and happens once. It produces: + +- one local report for every role; +- one delayed observer report only for an online reporting role; +- no observer report for Composer, observer, or FOG-SX roles. + +The role then discards its exact counters. A retry of IF-11 transmits the same +sealed aggregate object according to the future command-specific retry rule; +it does not reopen or recount the window. + +Discarding collector references is best-effort data minimization. The Go +runtime, allocator, swap, hibernation, crash capture, and host may retain +copies, so deployment controls remain necessary and complete erasure is not +claimed. + +## 9. Structural Report Schema + +The in-process structural report contains only: + +| Field | Meaning | Restriction | +| --- | --- | --- | +| `schema_version` | report schema version | fixed to version 1 | +| `profile_id` | authenticated observability profile | nonzero and consensus-authorized before activation | +| `scope` | `local` or `observer` | fixed enum | +| `role` | reporting security role | fixed enum, not node identity | +| `window_id` | coarse aligned window | no event time | +| `release_after_window` | earliest observer processing/release boundary | observer scope only and later than source window | +| `traffic_suppressed` | sensitive metrics are below threshold | fixed boolean, submission schedule remains constant | +| `measurements` | ordered fixed catalog for role and scope | metric and value enums only | + +The JSON emitted by the Go conformance module is a local test and diagnostic +representation, not the IF-11 wire encoding. Claim-bearing IF-11 requires a +separate byte-exact bounded encoding and signature specification. + +An aggregate-signing key identifier, signature suite, and signature belong to +the future authenticated IF-11 submission envelope. They are raw observer +input, never report measurements or public dimensions. Exact signing is not +defined until the PKI and observability suites select an encoding and +primitive. + +## 10. Value Vocabulary + +Count metrics use only: + +- `zero`; +- `low`; +- `medium`; +- `high`; +- `saturated`; +- `suppressed` when traffic-sensitive activity is below threshold. + +Level metrics use only: + +- `unknown`; +- `empty`; +- `low`; +- `medium`; +- `high`; +- `full`; +- `suppressed` when traffic-sensitive activity is below threshold. + +Health metrics use only: + +- `unknown`; +- `healthy`; +- `degraded`; +- `unavailable`. + +Bucket boundaries are part of one signed profile. Operators cannot customize +them per node. Public documentation states the boundaries and their privacy +rationale after activation. + +## 11. Metric Catalog + +The structural catalog is intentionally small. `Public eligible` means only +that a future observer may consider the metric after multi-reporter +aggregation. It never authorizes direct publication of one report. + +| Metric | Kind | Roles | Maximum visibility | Traffic-sensitive | +| --- | --- | --- | --- | --- | +| `process_start` | count | all | local | no | +| `process_stop` | count | all | local | no | +| `process_restart` | count | all | operator | no | +| `configuration_rejected` | count | all | operator | no | +| `consensus_health` | health | online reporters | public eligible | no | +| `clock_health` | health | online reporters | operator | no | +| `key_lifecycle_health` | health | online reporters | operator | no | +| `replay_database_health` | health | mix | operator | no | +| `queue_occupancy` | level | data plane | operator | yes | +| `handshake_completed` | count | online reporters | operator | yes | +| `handshake_failure` | count | online reporters | operator | yes | +| `connection_age` | level | online reporters | operator | yes | +| `profile_operations` | count | data plane | operator | yes | +| `padding_data_ratio` | level | data plane | public eligible | yes | +| `kemsphinx_failure` | count | mix, courier | operator | yes | +| `mix_latency` | level | mix | operator | yes | +| `cover_scheduler_health` | health | data plane | public eligible | no | +| `storage_success` | count | courier, store | public eligible | yes | +| `storage_overload` | count | courier, store | public eligible | yes | +| `storage_expiry` | count | store | public eligible | yes | +| `storage_corruption` | count | store | public eligible | no | +| `storage_repair` | count | store | public eligible | no | +| `capacity` | level | all | operator | no | +| `composer_boot` | count | Composer | local | no | +| `composer_lock` | count | Composer | local | no | +| `composer_integrity_failure` | count | Composer | local | no | +| `composer_failure` | count | Composer | local | no | +| `authority_validation_failure` | count | authority | operator | no | +| `observer_submission_rejected` | count | observer | local | no | +| `observer_publication_suppressed` | count | observer | local | no | + +Adding a metric, role, value, or visibility class is a protocol and threat- +model change. It requires schema versioning, conformance tests, and +differencing review. A runtime plugin cannot extend the catalog. + +## 12. Failure Classification + +Owning protocols map internal errors to the catalog before collection. Raw +errors never cross the boundary. A coarse count such as +`configuration_rejected`, `handshake_failure`, `kemsphinx_failure`, or +`authority_validation_failure` does not encode: + +- remote endpoint; +- exact parser or signature stage; +- expected or observed bytes; +- profile candidates; +- stack, file, line, or subsystem path; +- retry or connection identity. + +Where a protocol needs more than one failure class, it must add a small fixed +enum to this specification. It cannot place an exception message into a label +or diagnostic field. + +## 13. Window and Time Rules + +The active profile defines one origin and one duration. Roles derive: + +```text +window_id = floor((trusted_time - profile_origin) / window_duration) +``` + +This calculation is illustrative until the exact time profile is selected. +No event time is stored. Clock uncertainty beyond the profile bound changes +`clock_health` and follows the owning protocol's fail-closed time policy. +It does not cause a role to open shorter windows or emit immediate alerts. + +Window duration does not adapt to traffic volume. All reporting roles submit +at the same declared schedule with bounded profile-defined scheduling +behavior. Adaptive flush, inactivity flush, and event-triggered window close +are forbidden. + +## 14. Suppression and Bucketing + +The profile defines an activity unit for every reporting role, one minimum +activity threshold, and common bucket boundaries for compatible metric kinds. +Exact activity is never included in the sealed report. + +If activity is below the threshold: + +- every traffic-sensitive position is present with `suppressed`; +- non-traffic health and safety positions retain their bucketed value; +- the role still emits its scheduled observer submission; +- the public view emits no small-population inference about that role or + window. + +The suppression threshold is not an anonymity set size. It is one defense +against direct low-volume disclosure. Simulation and trace analysis must show +how it behaves under sparse use, outages, suppression attacks, and colluding +operators. + +## 15. IF-11 Aggregate Submission + +IF-11 carries one versioned aggregate submission from one authorized online +reporting role to `fog-observer`. It uses the mutually authenticated +role-specific FOG-WIRE context and an aggregate-signing key that is separate +from Noise, node identity, PKI vote, KEMSphinx, receipt, storage, and release +keys. + +The final IF-11 definition must bind at least: + +- network and schema version; +- observability profile; +- reporting role and authenticated reporter key; +- coarse window and earliest release window; +- exact ordered fixed-shape aggregate body; +- signature suite and purpose-separated signature. + +It must define exact size, padding, authentication, retry, replay, expiry, +parser limits, and failure behavior. FOG-WIRE fragmentation does not authorize +variable report geometry or arbitrary metric extensions. + +The observer rejects unknown fields, metrics, roles, profiles, values, +duplicate positions, reordered positions, stale windows, early release, +unauthorized signers, invalid signatures, and more than one accepted report +from the same reporter and window. Remote failure remains coarse and +non-amplifying. + +## 16. Observer Processing + +`fog-observer` maintains three separate stores: + +1. a bounded replay/deduplication index for accepted reporter windows; +2. short-lived raw signed submissions required for aggregation and audit; +3. derived operator and public aggregate windows. + +The stores use different access rights and retention. Raw submissions expire +after the bounded processing and dispute interval. They are not copied into a +general data lake, backup, search index, ticket, or dashboard cache. + +The observer never reads role log files, databases, queues, packet captures, +or container output. It cannot instruct a role to raise verbosity. It has no +credential accepted by data-plane, storage, authority-voting, or release +interfaces. + +## 17. Operator View + +The protected operator view may show only delayed fixed-window buckets from +metrics whose visibility is `operator` or `public eligible`. It may group by +role and declared public topology class when the active policy permits. + +It does not expose: + +- reporter or node drill-down for traffic-sensitive metrics; +- arbitrary time ranges or window overlap; +- raw submissions or signature identifiers as chart dimensions; +- correlation across roles, providers, links, or exact failure times; +- downloadable event records; +- queries parameterized by peer, route, connection, packet, or user input. + +Access is least privilege. Authentication and authorization failures are +recorded only as coarse local observer counters. Viewing a dashboard cannot +extend the underlying retention period. + +## 18. Public View and Differencing Defense + +A public aggregate requires all of the following: + +- the profile-defined minimum number of distinct authorized reporters; +- the required operator-family and role grouping; +- completion of the release delay; +- non-overlapping source and publication windows; +- bucketed output with no exact totals; +- suppression for low activity, reporter loss, or unsafe composition; +- one fixed set of published dimensions; +- no arbitrary filters, range queries, or node drill-down; +- review of adjacent releases for differencing and intersection leakage. + +Public series are not cumulative. If one group or window is suppressed, the +observer must not publish another overlapping total from which it can be +subtracted. A later merge may publish only when the merge rule was fixed in +advance and every released view remains non-subtractable. + +Reporter arrival, rejection, absence, and signature metadata are never public +dimensions. Public URLs, cache keys, ETags, and response timing must not vary +by hidden raw reporter state beyond the fixed publication schedule. + +## 19. Local Retention and Access + +The default implementation keeps sealed local summaries in a bounded volatile +ring. A role profile may instead authorize protected persistence only when it +defines: + +- exact maximum window count and age; +- owner and filesystem permissions; +- encryption and key ownership where required; +- atomic replacement and crash behavior; +- deletion and backup exclusion; +- manual export schema; +- consequences of a compromised operator account. + +No local report is retained indefinitely. Rotation removes the oldest whole +window. It does not compress old windows into cumulative history. + +The Composer stores any permitted summary inside its encrypted vault or +volatile memory. It has no automatic remote diagnostic path. A manually +exported Composer diagnostic contains only a newly created coarse report +selected and previewed by the user, never the raw ring or vault objects. + +## 20. Crash and Support Policy + +Production profiles disable: + +- core dumps and process memory capture; +- automatic panic, exception, or crash upload; +- operating-system crash collection that includes role memory; +- heap, goroutine, thread, profiler, packet, or syscall traces in support + artifacts; +- automatic attachment of logs, configuration, environment, or database + files to tickets. + +A crash increments only a coarse failure bucket after safe restart when the +owning state machine permits restart. Security-critical state such as replay, +ratchet, consensus, storage, or anchor state still follows its own fail-closed +recovery rules. Observability never authorizes bypass or state recreation. + +A manual support artifact uses a separate reviewed schema, shows the exact +fields to the operator or Composer user before export, excludes raw local +summaries by default, and has a fixed size and deletion policy. + +## 21. Debug and Test Builds + +Production artifacts contain no runtime switch that enables prohibited +logging. Environment variables, signals, command-line flags, configuration +files, remote administration, or observer requests cannot activate packet or +event tracing. + +Conformance builds may emit verbose traces only when all of the following +hold: + +- the build is distinctly labeled and rejected by production configuration; +- all keys, packets, contacts, routes, and inputs are public synthetic + fixtures generated for the test; +- the build cannot join a claim-bearing network; +- traces remain outside release artifacts and support bundles; +- tests prove that production builds omit the mode. + +## 22. Go Conformance Module + +`../observability/` follows a small library shape because future role code +will import the contract, while the observer daemon and wire codec remain +separate responsibilities. + +The module provides: + +- fixed `Role`, `Metric`, `Level`, `Health`, `Scope`, and value enums; +- role and value-kind validation; +- concurrency-safe saturating in-memory counters; +- an explicit policy with no default constructor; +- one-way collector sealing; +- fixed-shape local and observer reports; +- low-activity suppression; +- delayed observer windows; +- a concurrency-safe bounded volatile local ring; +- deterministic JSON only for conformance and local diagnostics. + +It deliberately does not provide: + +- arbitrary labels, messages, attributes, exemplars, or strings; +- exact timestamps, durations, sizes, counters, or samples in reports; +- disk persistence or remote log transport; +- OpenTelemetry, Prometheus, syslog, journald, or service-mesh adapters; +- IF-11 decoding, signing, networking, observer aggregation, or public output; +- a numeric production policy. + +The absence of those adapters is a security boundary, not an unfinished +convenience layer. + +## 23. Conformance and Adversarial Tests + +Before an observability profile becomes claim-bearing, tests must prove: + +1. every role rejects every metric outside its catalog; +2. every metric rejects the wrong value kind and unknown value; +3. exact counters saturate and never wrap; +4. sealing occurs once and exact counters are inaccessible afterward; +5. local and observer shapes are fixed for role and profile across zero, low, + threshold, and high activity; +6. low traffic produces `suppressed`, not a missing field or exact count; +7. Composer and FOG-SX roles cannot produce observer submissions; +8. observer reports cannot contain local-only fields; +9. observer release is later than the source window and overflow fails; +10. packet, message, trace, peer, route, capability, address, path, error, and + timestamp fields are absent from encoded reports; +11. local retention is bounded and chronological after rotation; +12. unknown, duplicate, reordered, stale, oversized, and trailing IF-11 input + fails before allocation or signature-dependent action; +13. duplicate reporter windows and replay fail without changing public state; +14. missing reporters, low populations, adjacent windows, and overlapping + queries cannot defeat suppression by differencing; +15. observer loss cannot alter data-plane or consensus behavior; +16. production binaries reject debug/test profiles and do not produce core + dumps or automatic support uploads; +17. malformed or attacker-controlled values never reach log formatting; +18. raw submissions expire and cannot be recovered from backups or dashboard + caches after the declared interval. + +The current Go module covers items 1 through 11 at the role-local contract +boundary. IF-11, observer, deployment, and public-release tests remain gated +on their exact implementations. + +## 24. Operational Alerts + +Alerts are delayed state conditions, not event notifications. Candidate alert +classes include: + +- consensus `degraded` or `unavailable`; +- clock `degraded` or `unavailable`; +- replay database `unavailable`; +- key lifecycle `degraded` or `unavailable`; +- cover scheduler `degraded` or `unavailable`; +- sustained capacity `high` or `full`; +- sustained storage corruption or repair failure; +- repeated configuration rejection or process restart buckets. + +The exact number of windows needed to alert is profile-defined. Alerts never +contain a packet, peer, connection, route, request, error string, or event +time. Immediate local safety shutdown remains the responsibility of the +owning role and does not wait for an alert. + +## 25. Deployment Requirements + +A claim-bearing deployment must demonstrate: + +- container or service-manager logging cannot capture stdout/stderr event + streams from the role; +- only fixed coarse startup failure output is possible before the collector; +- core dumps and automatic crash collection are disabled effectively, not + only in source configuration; +- observer credentials cannot access role state or another interface; +- no host port exposes role metrics directly; +- local summary storage and observer raw storage meet declared ownership, + permissions, capacity, backup, rotation, and deletion rules; +- dashboard and API caches do not outlive source retention; +- production configuration rejects unknown metrics, test profiles, and debug + modes; +- clock failure, observer outage, low activity, and reporter loss preserve the + declared fail-closed and suppression behavior. + +## 26. Requirements Traceability + +| Requirement | Observability response | +| --- | --- | +| `TM-OPS-01` | closed schema, forbidden data classes, coarse windows, suppression, delayed aggregation, bounded retention | +| `TM-NET-01` | no fine timing, event stream, route, peer, or cross-role trace identifiers | +| `TM-NET-03` | cover health, fixed reporting schedule, low-activity suppression, no weakened fallback | +| `TM-ROLE-01` | role-local collectors and keys, no universal log access | +| `TM-ROLE-02` | no packet, replay-tag, route, delay, or next-hop records | +| `TM-ROLE-03` | no request, selection, receipt, storage, or per-source histories | +| `TM-AVAIL-01` | saturating counters, bounded rings, fixed catalogs, bounded submissions | +| `ARC-001` | separate role collectors, observer, state, access, and reporting keys | +| `ARC-007` | one owner for local summaries and aggregate-signing material | +| `ARC-008` | fixed schema, no dynamic labels, bounded windows and retention | +| `ARC-009` | observability never authorizes a privacy-weakening recovery path | +| `IF-11` | delayed authenticated fixed-shape aggregate only | + +## 27. Open Activation Decisions + +Before enabling IF-11 or public output, FOG must select and validate: + +- window origin and duration; +- activity unit and minimum activity per reporting role; +- count, level, latency, ratio, age, queue, and capacity bucket boundaries; +- minimum independent reporters and operator-family diversity per public + group; +- role-to-observer delay, observer-to-public delay, and merge behavior; +- local, raw observer, derived operator, public, cache, and backup retention; +- the exact IF-11 body encoding, fixed size, padding, signature suite, key + certification, replay, retry, and expiry rules; +- public dimensions and anti-differencing composition analysis; +- clock-uncertainty behavior and fixed submission scheduling; +- deployment-specific storage, access, deletion, and crash controls; +- simulation and trace evidence for sparse traffic, outages, reporter loss, + malicious suppression, collusion, and long-term intersection; +- independent privacy and implementation review. + +Until those decisions are activated through signed profiles and evidence, the +safe deployment state remains local bounded summaries only, with observer and +public export disabled. + +## 28. References + +- FOG threat model: `FOG-THREAT-MODEL.md` +- FOG architecture: `FOG-ARCHITECTURE.md` +- FOG adjacent-link protocol: `FOG-WIRE.md` +- FOG KEMSphinx profiles: `FOG-SPHINX-PROFILES.md` +- FOG storage: `FOG-STORAGE.md` +- FOG Composer: `FOG-COMPOSER.md` +- FOG simulation: `FOG-SIMULATION.md` -- cgit v1.2.3