fluid-telegram/docs/observation.md

88 lines
3.8 KiB
Markdown
Raw Normal View History

# Cohorts, telemetry and redaction
## Cohorts
Four populations, deliberately coarse. Blueprint §6.3 asks for cohorts stable
enough to compare over time and no more granular than the analysis requires.
| Cohort | Assigned by | Why it is distinct |
|---|---|---|
Reframe the interface around composed posts, not republished entries The channel publishes a post written from a hall entry -- condensed, personal, reach-optimized -- not the entry itself. That changes what this interface is for and where its boundary sits. Composition is deliberately outside the interface. Composing is a probabilistic editorial task, and Blueprint 48.1 forbids an LLM in the mandatory request path, so an interface that composed on demand would be non-deterministic exactly where determinism is the whole claim. It is also editorial: a post speaks about a named person's work in HelixForge's voice, and a review step inside the request path is a review step nobody performs. The contract now takes a composed post with a required reviewer, a cited source entry and a consent basis. A post carrying none of those is refused. Absence of objection is not consent, and in an audit trail an unfaithful post looks exactly like a faithful one -- the defence is that a human read it, the source is named, and both are recorded. The first experiment is rebuilt accordingly. The old competition asked how to fit a whole entry into Telegram; that question no longer exists. The new one asks whether the portrait earns the 3072 characters of caption limit it costs, which is a delivery question this interface actually owns. Competition over editorial voice belongs to the campaign and runs on the per-variant engagement this interface reports. Adds T05b (composition and review), T05c (consent basis for the 94 existing participants, blocking public publication) and T11 (extracting the campaign into pr-hall-of-helix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu Assistant: claude-code Assistant-Model: opus Assistant-Process: 1116572@bnt-lap001 Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 11:57:28 +02:00
| `hall-publishing-jobs` | `X-FLUID-Consumer` prefix `hall-` | Batch behaviour; publishes many posts at once. Becomes the `pr-hall-of-helix` campaign job |
| `helix-forge-agents` | `X-FLUID-Consumer` prefix `agent-` | One post at a time, at session end |
| `operators` | `X-FLUID-Consumer` prefix `op-` | Rare, deliberate, often corrective |
| `telegram-subscribers` | Not a caller | An observed population, never an API consumer |
`telegram-subscribers` deserves care. It appears in experiment allocation and in
engagement metrics, but it never authenticates and never appears as
`ConsumerRef`. Treating readers as consumers would be the first step toward
observing them individually.
## Redaction
```
CohortMinimumSize: 5
RetentionDays: 365
AllowRawPayload: false
```
Beyond the fluid-core defaults, this interface adds:
- **No Telegram user identity, ever.** Canon ID-01 identities — user ids,
usernames, display names of subscribers — must not reach the evidence store
in any form, redacted or otherwise. There is no legitimate analysis that
needs them, so the safe rule is that they never arrive.
Reframe the interface around composed posts, not republished entries The channel publishes a post written from a hall entry -- condensed, personal, reach-optimized -- not the entry itself. That changes what this interface is for and where its boundary sits. Composition is deliberately outside the interface. Composing is a probabilistic editorial task, and Blueprint 48.1 forbids an LLM in the mandatory request path, so an interface that composed on demand would be non-deterministic exactly where determinism is the whole claim. It is also editorial: a post speaks about a named person's work in HelixForge's voice, and a review step inside the request path is a review step nobody performs. The contract now takes a composed post with a required reviewer, a cited source entry and a consent basis. A post carrying none of those is refused. Absence of objection is not consent, and in an audit trail an unfaithful post looks exactly like a faithful one -- the defence is that a human read it, the source is named, and both are recorded. The first experiment is rebuilt accordingly. The old competition asked how to fit a whole entry into Telegram; that question no longer exists. The new one asks whether the portrait earns the 3072 characters of caption limit it costs, which is a delivery question this interface actually owns. Competition over editorial voice belongs to the campaign and runs on the per-variant engagement this interface reports. Adds T05b (composition and review), T05c (consent basis for the 94 existing participants, blocking public publication) and T11 (extracting the campaign into pr-hall-of-helix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu Assistant: claude-code Assistant-Model: opus Assistant-Process: 1116572@bnt-lap001 Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 11:57:28 +02:00
- **Post text is not telemetry.** The body appears in the request and is kept
in the publication record, because it is what was said in HelixForge's name.
It must not appear in a telemetry event: observation is for measuring how
posts performed, not for accumulating a second copy of what they said.
- **The bot token appears nowhere.** Not in errors, not in traces, not in
redacted form.
## The pseudonymization salt
Generate once, store in OpenBao alongside the bot token, inject as
`FLUID_REDACTION_SALT`:
```bash
openssl rand -hex 32
```
It must never change. Rotating it makes every previously-seen consumer look
new, which silently invalidates every longitudinal comparison the interface has
accumulated. If it is ever compromised, the correct response is to accept the
loss and start a fresh evidence baseline, not to rotate quietly.
## Metrics
| Metric | Role | Source |
|---|---|---|
Reframe the interface around composed posts, not republished entries The channel publishes a post written from a hall entry -- condensed, personal, reach-optimized -- not the entry itself. That changes what this interface is for and where its boundary sits. Composition is deliberately outside the interface. Composing is a probabilistic editorial task, and Blueprint 48.1 forbids an LLM in the mandatory request path, so an interface that composed on demand would be non-deterministic exactly where determinism is the whole claim. It is also editorial: a post speaks about a named person's work in HelixForge's voice, and a review step inside the request path is a review step nobody performs. The contract now takes a composed post with a required reviewer, a cited source entry and a consent basis. A post carrying none of those is refused. Absence of objection is not consent, and in an audit trail an unfaithful post looks exactly like a faithful one -- the defence is that a human read it, the source is named, and both are recorded. The first experiment is rebuilt accordingly. The old competition asked how to fit a whole entry into Telegram; that question no longer exists. The new one asks whether the portrait earns the 3072 characters of caption limit it costs, which is a delivery question this interface actually owns. Competition over editorial voice belongs to the campaign and runs on the per-variant engagement this interface reports. Adds T05b (composition and review), T05c (consent basis for the 94 existing participants, blocking public publication) and T11 (extracting the campaign into pr-hall-of-helix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu Assistant: claude-code Assistant-Model: opus Assistant-Process: 1116572@bnt-lap001 Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 11:57:28 +02:00
| `engagement_rate` | primary | Telegram channel statistics, aggregate |
| `unreviewed_publication` | guardrail | Adapter |
| `missing_source_attribution` | guardrail | Adapter |
| `missing_subject_consent` | guardrail | Adapter |
| `error_rate` | guardrail | Gateway |
Reframe the interface around composed posts, not republished entries The channel publishes a post written from a hall entry -- condensed, personal, reach-optimized -- not the entry itself. That changes what this interface is for and where its boundary sits. Composition is deliberately outside the interface. Composing is a probabilistic editorial task, and Blueprint 48.1 forbids an LLM in the mandatory request path, so an interface that composed on demand would be non-deterministic exactly where determinism is the whole claim. It is also editorial: a post speaks about a named person's work in HelixForge's voice, and a review step inside the request path is a review step nobody performs. The contract now takes a composed post with a required reviewer, a cited source entry and a consent basis. A post carrying none of those is refused. Absence of objection is not consent, and in an audit trail an unfaithful post looks exactly like a faithful one -- the defence is that a human read it, the source is named, and both are recorded. The first experiment is rebuilt accordingly. The old competition asked how to fit a whole entry into Telegram; that question no longer exists. The new one asks whether the portrait earns the 3072 characters of caption limit it costs, which is a delivery question this interface actually owns. Competition over editorial voice belongs to the campaign and runs on the per-variant engagement this interface reports. Adds T05b (composition and review), T05c (consent basis for the 94 existing participants, blocking public publication) and T11 (extracting the campaign into pr-hall-of-helix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu Assistant: claude-code Assistant-Model: opus Assistant-Process: 1116572@bnt-lap001 Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 11:57:28 +02:00
| `source_link_rate` | secondary | Telegram channel statistics, aggregate |
| `forward_rate` | secondary | Telegram channel statistics, aggregate |
| `time_to_first_view` | learning | Telegram channel statistics, aggregate |
`engagement_rate` is the one to be careful about. Telegram reports views,
reactions and forwards per message, not per reader, and a "rate" therefore has
subscribers as its denominator rather than people who saw the post. It is a
proxy, and a noisy one at small subscriber counts. Say so in the experiment's
amendment record rather than letting the comparison look cleaner than it is.
## Variant attribution
Every post carries a `variant` label naming the composition strategy that
produced it. This interface treats it as opaque: it records the label, and
reports engagement grouped by it.
That is deliberately the whole of the interface's involvement in composition.
The campaign compares its own strategies using this data, running its own FLUID
experiments over its own artifacts. The interface does not know what
`variant: warm-specific-v2` means and must not acquire an opinion about it.
Without this field the campaign would have to infer which post came from which
strategy by timestamp, which is exactly the kind of reconstruction that quietly
stops being accurate.