Repository navigation
chore(framework): support both anonymous and named measurement #660
Description
Activity
- added a parent issue
on Aug 15, 2026 Decision, 2026-08-16 — support both, do not choose
Both modes are supported. The question stops being "anonymous or named" and becomes "how is one storage format made to serve both, and who decides which applies".
The shape that gives both from one format
Records always carry a pseudonym, never a name. A stable, per-person identifier with no meaning of its own.
The mapping from pseudonym to person is a separate artefact, held outside the repository, access-controlled, and optional.
- Anonymous mode = the mapping does not exist.
- Named mode = the mapping exists, and its holder is named.
One format, two modes. Switching means adding or removing a mapping rather than migrating data. #661 builds the mapping and now owns the guarantees around it.
The mode is a project decision, and the person is told
Set per project or per organisation, not per person: a mode a developer can flip individually makes any team figure meaningless. But the person is told which mode applies before anything is written about them, and can see their own records at any time. That is not a courtesy, it is what makes the measurement defensible.
Two traps, stated so nobody discovers them later
A stable pseudonym is not anonymity. Someone who is the only person committing to a given repository on a given day is identifiable by correlation, whatever the identifier says. Anonymous mode is honest protection against casual reading, not against a determined reader with access to the same repository. Claiming otherwise would be the kind of promise that ages badly — see #658 for what that costs.
The switch is asymmetric. Deleting the mapping anonymises what comes next and what is stored in the dashboard, but it cannot reach records already written into git history. Going the other way is impossible: a pseudonym never becomes a name retroactively. So the mode must be decided before the first record, and a change of mode has to state which direction it can and cannot reach.
What the journal actually adds beyond what git already reveals
Worth being precise, because it narrows the debate. With records materialised on commit (#620), the commit already names its author. The journal adds no new identity at that grain.
What it does add is how long the work took and what it cost. That is the genuinely new information about a person, and it is what this decision is really about — not who wrote the code, which git has always said.
Done When
- The mode is a documented setting with a stated default, and the default is the more conservative of the two.
- A person can see, before any record concerns them, which mode applies and what is kept.
- A person can read their own records without asking anyone.
- The documentation states plainly that a stable pseudonym resists casual reading, not correlation.
- Changing mode states what it reaches and what it cannot, in both directions.
- spike(framework): prove whether native OTel adds value beyond the measurement journal #297's decision of record is amended: anonymised identifiers become the default rather than the only option.
- changed the title
[-]chore(framework): decide whether measurement is anonymous or named[/-][+]chore(framework): support both anonymous and named measurement[/+]on Aug 16, 2026 Deferred to milestone 16, 2026-08-16
The policy work — who sets the mode, what a person sees and when, the deletion path, the mapping itself — waits for the dashboard. Nobody needs it to produce a first figure.
Deferring is safe because two guards are in place from v1, and both are irreversible if missed:
- feat(framework): an aidd-telemetry plugin whose hooks journal every session #620 — the journal never carries an identity. It goes into git history on commit; a name written there is permanent and beyond the reach of any later decision.
- feat(framework): a readable sink, since no file exporter exists #647 — vendor identity attributes are dropped at ingest and replaced by a stable salted label. Without this rule,
user.emaillands on disk in the first week and the question is answered by accident.
Together they mean no name is written anywhere before this issue is opened, so both modes stay reachable at zero cost. The decision keeps its full range instead of being narrowed by a default nobody chose.
This issue says "Excludes: any implementation. This issue produces a decision and closes", and it blocks #656 and #661. That premise no longer holds: the mechanism shipped on the telemetry v1 branch (PR #706) before the decision was recorded.
What exists now:
person_idandperson_display_nameas stored-record fields, aPersonIdentityAdapter, and two skill actions (04-identify,05-forget).What the shipped default does, so the gap is legible: nobody is named unless a person opts in on their own machine. A missing file, a damaged one, and one carrying no
person_idall read the same way - nobody chose - and the file is read only from the OS user's own profile, with no environment override, so neither a repository nor a CI can supply an identity. That is compatible with #297's "anonymised ids".So the gap is authorization, not behaviour. This can no longer close as "a decision, before anything is built". It needs rewording to a decision-of-record that amends #297 and states what already shipped.
The decision this issue asks for is written, and it covers both clauses
aidd_docs/memory/internal/decisions/measurement-may-reach-a-hosted-destination.md— decided 2026-08-31 by @blafourcade, posted on #297.This issue's scope was too narrow, and that is worth recording. #297 carries two decisions of record. The body above quotes one — Privacy — and every Done-When speaks only to privacy. As written, this issue could have closed with every box ticked while the Standard clause ("Sink is an OTel collector. No SaaS.") stayed standing and contradicted. That clause is the one a hosted product actually breaks.
Against this issue's own conditions:
- spike(framework): prove whether native OTel adds value beyond the measurement journal #297 amended in writing — yes, and for both clauses. Privacy reaffirmed unchanged; Standard superseded.
- Names who made it, and when — @blafourcade, 2026-08-31.
- What an individual can see about their own data, and when relative to their manager — locally this holds by construction: the mapping and the identity are read from the person's own profile and nothing is uploaded. That stops being automatic the day a destination exists, which the record assigns to the destination's own work.
- The deletion path, including what git history makes irreversible — not covered by the record. Still open.
- feat(framework): measurement across tools and people #652 and feat(framework): report per person, team and epic #656 reference the decision instead of naming it as an unresolved precondition — not done yet.
Two of the five are unmet, so this stays open. Also stale in the body above: measurement is no longer only refusable per project — refuses per person and wins over a repository's committed switch, which answers the "the existing safeguard protects the wrong people" argument directly.
- added 4 commits that reference this issue
on Aug 31, 2026 All five conditions are met — closing
Condition Evidence #297's decision of record amended in writing the record, posted on #297. Privacy reaffirmed unchanged; Standard superseded — both clauses, not one Names who made it, and when @blafourcade, 2026-08-31 What an individual can see about their own data, and when relative to their manager Clause 5 of the record. Structural while local — read from their own profile, no earlier reader because nothing is sent. Named as the destination's obligation once one exists, rather than promised on its behalf The deletion path, including what git history makes irreversible aidd telemetry forget. Shows every location and what is in each, removes only on confirmation, reports what went and what did not. History is reported at four honest strengths — committed / staged but never committed / not tracked and possibly held / no repository — becausegit ls-filesreads the index, not history#652 and #656 reference the decision Both bodies edited; neither still names it as an unresolved precondition Two things this issue got wrong, recorded so the next one does not.
Its scope was half the problem: #297 carries two decisions of record and this body quoted one. As written it could have closed with every box ticked while the clause a hosted product actually breaks stayed contradicted.
And its factual premise was already stale. The journal names nobody — no line it writes carries any identity field. It does not enter git history —
telemetry ongit-ignores it. And "the safeguard protects the wrong people" is answered:AIDD_TELEMETRY=0refuses per person and overrides a repository's committed switch.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Projects
- StatusShow more project fieldsDone
Outcome
The framework has one recorded, owned answer to whether measurement is anonymous or attributable to a named person, and #297 is amended rather than quietly contradicted.
Scope
This is not an open question. #297 already decided it, as a decision of record: "Privacy: explicit opt-in, anonymised ids, never code or prompt content."
Milestone 16 reverses it. #656 reports per person by name; #652 names the conflict as a precondition. A decision of record that is contradicted by a later milestone without being amended is how a project ends up with two truths and no owner.
Two things make it heavier than a preference:
The journal enters git history. On a company repository it permanently records who worked on what, when, and for how long. Not a database anyone can purge — history.
The existing safeguard protects the wrong people. Telemetry is off by default on public repositories, which shields open-source contributors and nobody who is employed.
Includes: amending or superseding spike(framework): prove whether native OTel adds value beyond the measurement journal #297 explicitly, with a date and a named owner.
Includes: what a person can see about themselves, and before whom.
Includes: whether attribution is pseudonymous by default with an opt-in to naming, or the reverse.
Includes: a deletion path, local and hosted, and what it can and cannot reach given git history.
Excludes: any implementation. This issue produces a decision and closes.
Done When
Completion Evidence
The amended decision of record, and the removal of the precondition wording from the two issues that carry it.
Relations