Skip to content

[Wave 3] Medium — Docs: docs/design/gdpr_erasure.md #574

Open

Description

@cemililik

Wave 3 · 9 finding(s) in 9 fix package(s). One pass over this document; keep the Turkish mirror in sync.

Findings

  • DOC-BLEGAL-065 (docs, Medium) — docs/design/gdpr_erasure.md: wrong detail — Article 17(2) requires the controller to inform downstream processors / publishers of the erasure when the data has been disclosed.
    severity Medium
    Where. docs/design/gdpr_erasure.md:46 · type: wrong detail
    The document says. Article 17(2) requires the controller to inform downstream processors / publishers of the erasure when the data has been disclosed.
    What the code does. Art. 17(2) applies only 'Where the controller has made the personal data public' and concerns informing other controllers about links, copies or replications. The duty to inform recipients the data was disclosed to is Art. 19.
    Proposed correction. 'Article 19 requires the controller to communicate the erasure to each recipient the data was disclosed to (unless impossible or disproportionate); Article 17(2) adds reasonable steps to inform other controllers where the data was made public.'

  • DOC-D2B02-015 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — Synthetic / GRPO logs at <output_dir>/synthetic_data.jsonl can be deleted row by row with the same row-id mechanism as the training corpus.
    severity Medium
    Where. docs/design/gdpr_erasure.md:64 · type: false claim
    The document says. Synthetic / GRPO logs at <output_dir>/synthetic_data.jsonl can be deleted row by row with the same row-id mechanism as the training corpus.
    What the code does. Synthetic entries carry no id or row_id field (messages/instruction/chatml/prompt_response shapes), and purge requires one, so rows cannot be targeted. synthetic.output_file defaults to the cwd-relative 'synthetic_data.jsonl', not <output_dir>. No GRPO completion log is written.
    Code references. forgelm/synthetic.py:387-412, forgelm/config.py:1363, forgelm/cli/subcommands/_purge.py:87, forgelm/cli/subcommands/_purge.py:272-295
    Proposed correction. "Synthetic rows have no id field; add ids (or regenerate) before using purge --row-id; the file lands at synthetic.output_file (cwd-relative by default)."

  • DOC-D2B02-016 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — The operator can act in-tool on four artefact kinds: corpus_rows, staging, artefacts, logs.
    severity Medium
    Where. docs/design/gdpr_erasure.md:67 · type: false claim
    The document says. The operator can act in-tool on four artefact kinds: corpus_rows, staging, artefacts, logs.
    What the code does. --kind accepts only staging and artefacts. logs is intentionally absent (argparse choices; _VALID_RUN_KINDS).
    Code references. forgelm/cli/_parser.py:1123-1129, forgelm/cli/subcommands/_purge.py:89-93
    Proposed correction. "Three in-tool scopes: corpus rows (--row-id), --kind staging, --kind artefacts; there is no logs kind."

  • DOC-D2B02-017 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — Implementation note: --check-policy ages each raw_documents/<run_id>/ directory against its owning run's audit genesis.
    severity Medium
    Where. docs/design/gdpr_erasure.md:127-131 · type: false claim
    The document says. Implementation note: --check-policy ages each raw_documents/<run_id>/ directory against its owning run's audit genesis.
    What the code does. The scan checks <output_dir>/raw_documents and <output_dir>/ingestion_output as single paths with run_id=None, so they age from the global genesis or from mtime. There is no per-run raw_documents handling.
    Code references. forgelm/cli/subcommands/_purge.py:1292-1312
    Proposed correction. "…the scan treats <output_dir>/raw_documents/ (and legacy ingestion_output/) as one artefact aged from the audit-log genesis (or mtime)."

  • DOC-D2B02-018 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — §3.4 site 3: forgelm audit lists retention violations in the report's notes when retention is set in the loaded config.
    severity Medium
    Where. docs/design/gdpr_erasure.md:160 · type: false claim
    The document says. §3.4 site 3: forgelm audit lists retention violations in the report's notes when retention is set in the loaded config.
    What the code does. forgelm audit has no retention logic. Retention appears in _audit.py only in a docstring.
    Code references. forgelm/cli/subcommands/_audit.py:57-60
    Proposed correction. Remove site 3 or mark it "not implemented".

  • DOC-D2B02-019 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — --check-policy --config defaults to ./forgelm.yaml and then walks up.
    severity Medium
    Where. docs/design/gdpr_erasure.md:196 · type: false claim
    The document says. --check-policy --config defaults to ./forgelm.yaml and then walks up.
    What the code does. There is no discovery. Without --config, _maybe_load_config returns None and the command prints 'No retention: block … nothing to enforce' and exits 0. Reproduced: with forgelm.yaml in cwd and a 639-day-old staging dir, the output was 'nothing to enforce', exit 0.
    Code references. forgelm/cli/subcommands/_purge.py:1126-1150, forgelm/cli/subcommands/_purge.py:1426-1427
    Proposed correction. "--config <path> — required for a meaningful report; without it the command prints a 'no retention block' notice and exits 0 (no discovery)."

  • DOC-D2B02-020 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — The three warning events carry a recommendation field with fixed literal text.
    severity Medium
    Where. docs/design/gdpr_erasure.md:260-262 · type: false claim
    The document says. The three warning events carry a recommendation field with fixed literal text.
    What the code does. No warning event carries recommendation. Payloads are the completed fields plus affected_run_ids, synthetic_files or webhook_targets. This matches the canonical catalog.
    Code references. forgelm/cli/subcommands/_purge.py:398-416, forgelm/cli/subcommands/_purge.py:678-684, docs/reference/audit_event_catalog.md:80-82
    Proposed correction. Remove the recommendation field from the §5.1 table, or point the table at audit_event_catalog.md as the authority.

  • DOC-D2B02-021 (docs, Medium) — docs/design/gdpr_erasure.md: false claim — The operator guide says: 'Do not paste subject identifiers into --justification'. L291-293: the guide flags the corpus_path/output_dir naming risk and recom…
    severity Medium
    Where. docs/design/gdpr_erasure.md:279 · type: false claim
    The document says. The operator guide says: 'Do not paste subject identifiers into --justification'. L291-293: the guide flags the corpus_path/output_dir naming risk and recommends symlinking.
    What the code does. docs/guides/gdpr_erasure.md contains neither warning. Only the CLI help for --justification carries the identifier warning. Justification is written to the append-only chain unscrubbed.
    Code references. forgelm/cli/_parser.py:1151-1157, forgelm/cli/subcommands/_purge.py:728, docs/guides/gdpr_erasure.md:35-42
    Proposed correction. Add the warnings to docs/guides/gdpr_erasure.md, or change the design text to "the CLI --help warns…".

  • DOC-D2B02-022 (docs, Medium) — docs/design/gdpr_erasure.md: wrong detail — Salt = first 16 bytes of FORGELM_AUDIT_SECRET if set, else the per-output-dir salt.
    severity Medium
    Where. docs/design/gdpr_erasure.md:288 · type: wrong detail
    The document says. Salt = first 16 bytes of FORGELM_AUDIT_SECRET if set, else the per-output-dir salt.
    What the code does. The persistent per-dir salt is always created and read. When the secret is set, its first 16 bytes (zero-padded) are XORed with the persistent salt. The secret is never used alone.
    Code references. forgelm/cli/subcommands/_purge.py:196-224
    Proposed correction. "Salt = persistent per-dir salt (16 random bytes, 0600, created on first use), XORed with the first 16 bytes of FORGELM_AUDIT_SECRET when that variable is set."

Done when

  • Every finding above is fixed or closed with a reason (tick it here).
  • Code fixes carry a test; doc fixes update the Turkish mirror in the same PR.

Found by the October 2026 ForgeLM code and documentation review against commit cab2947. Code links point at that commit; line numbers may have moved since. Finding IDs (CR-…, DOC-…, TECH-…) are stable references for this backlog.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationseverity: mediumReal defect with limited reach or a workaroundsource: review-2026-10Found by the October 2026 code and documentation reviewwave: 3Roadmap wave 3: medium severity, module sweeps

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions