Skip to content

chore(framework): support both anonymous and named measurement #660

Description

@blafourcade

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

Field Value
parent #652
blocks #656
related #297, #620

Activity

  1. added this to the milestone on Aug 15, 2026
  2. added theissue type on Aug 15, 2026
  3. blafourcade commented on Aug 16, 2026

    @blafourcade
    ContributorAuthor

    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.
  4. changed the title [-]chore(framework): decide whether measurement is anonymous or named[/-] [+]chore(framework): support both anonymous and named measurement[/+] on Aug 16, 2026
  5. blafourcade commented on Aug 16, 2026

    @blafourcade
    ContributorAuthor

    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:

    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.

  6. blafourcade commented on Aug 23, 2026

    @blafourcade
    ContributorAuthor

    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_id and person_display_name as stored-record fields, a PersonIdentityAdapter, 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_id all 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.

  7. added 2 commits that reference this issue on Aug 24, 2026
  8. blafourcade commented on Aug 31, 2026

    @blafourcade
    ContributorAuthor

    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:

    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.

  9. blafourcade commented on Aug 31, 2026

    @blafourcade
    ContributorAuthor

    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 — because git ls-files reads 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 on git-ignores it. And "the safeguard protects the wrong people" is answered: AIDD_TELEMETRY=0 refuses per person and overrides a repository's committed switch.

  10. moved this from Ideation to Done in AIDD Roadmapon Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    High

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions