Skip to content

Purge --run-id --kind artefacts can never match the compliance bundle ForgeLM writes; generic run-id tokens select unrelated files (CR-A10-002) #477

Open

Description

@cemililik

Wave 2 · theme D2-5: Data audit, masking and ingestion: medium effort · highest severity High · 5 finding(s) · effort medium

Summary

After a 1-step SFT run (run fg-ad448c0755ea), forgelm purge --run-id fg-ad448c0755ea --kind artefacts --output-dir runA/out exits 1 with 'No 'artefacts' artefacts found' and logs erasure_failed NoMatchingArtefacts.

Primary finding

CR-A10-002 — Purge --run-id --kind artefacts can never match the compliance bundle ForgeLM writes; generic run-id tokens select unrelated files

severity High · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end · already tracked: KNOWN-OPEN TRUST-02 — docs/roadmap/phase-16-trust-surface-hardening.md:553-571 (S9 open)

What happens. _artefact_targets_for_run (_purge.py:998-1014, with _filename_contains_run_id at :1041-1064) selects only compliance/ files whose name contains the run_id as a _-. delimited token. export_compliance_artifacts (compliance.py:2173-2236) and the trainer (trainer.py:2087-2096) write fixed names with no run_id, so a real run id always ends in NoMatchingArtefacts (exit 1), while word-like ids ('report', 'json') select shared bundle files. Tests pass only because they fabricate run-id-named files.

Where.

Evidence.

  • logs/A1_artefacts_realrun.out; ls runA/out/compliance shows no run-id names. A3 deleted notes_.txt too.
  • Repro r5 uses the real export_compliance_artifacts. fpy -m forgelm purge --run-id fg-0123456789ab --kind artefacts --output-dir r5/out gives {success:false, 'No artefacts artefacts found'}, exit 1, and the audit log gains data.erasure_failed NoMatchingArtefacts. With --dry-run, --run-id report would delete [compliance_report.json, data_governance_report.json] and --run-id json would delete four JSON files.
  • Repro: generate_training_manifest + export_compliance_artifacts into out/compliance with run_id fg-abcdef123456 yields ['compliance_report.json','data_provenance.json','training_manifest.yaml']; purge --run-id fg-abcdef123456 --kind artefacts -> exit 1, "No 'artefacts' artefacts found", nothing deleted.

Recommended fix. Bind the bundle to the run through content rather than file names: for example, delete compliance/ when compliance_report.json or the manifest records this run_id, or have the exporter write run-scoped names. Restrict deletion to the documented file kinds and update the docs.

Other findings with the same root cause

These close with the same fix; update them in the same pull request.

  • DOC-D2B02-005 (docs, High) — docs/design/gdpr_erasure.md: false claim — kind=artefacts deletes a fixed allow-list (compliance/, data_audit_report.json, data_governance_report.json), never a glob, kept in forgelm.compliance. Also…
    severity High · already tracked: KNOWN-OPEN TRUST-02 (inferred) — docs/roadmap/phase-16-trust-surface-hardening.md:564-566
    Where. docs/design/gdpr_erasure.md:233 · type: false claim
    The document says. kind=artefacts deletes a fixed allow-list (compliance/, data_audit_report.json, data_governance_report.json), never a glob, kept in forgelm.compliance. Also L193 (adds 'derived JSONL snapshots'), L169 ('removes compliance/*.json for the named run') and L62 ('purge --kind artefacts rewrites them').
    What the code does. There is no allow-list in forgelm.compliance. The resolver token-matches the run_id inside filenames under compliance/ only. It never touches data_audit_report.json or JSONL snapshots, never rewrites anything, and matches none of the exporter's fixed filenames (reproduced: exit 1 NoMatchingArtefacts).
    Code references. forgelm/cli/subcommands/_purge.py:998-1038, forgelm/compliance.py:2173-2236
    Proposed correction. Fix the code to delete the run's real artefact set via an allow-list, or document the actual behaviour: 'files under compliance/ whose name contains the run id as a token; none of ForgeLM's own artefacts currently do'.

  • DOC-D2B02-007 (docs, High) — docs/guides/gdpr_erasure.md: misleading — forgelm purge --run-id <id> --kind artefacts deletes a run's compliance bundle. L60 says it removes <output_dir>/compliance/*.json files whose name embed…
    severity High · already tracked: KNOWN-OPEN TRUST-02 (inferred) — docs/roadmap/phase-16-trust-surface-hardening.md:554-566
    Where. docs/guides/gdpr_erasure.md:15 (Turkish mirror: docs/guides/gdpr_erasure-tr.md:60) · type: misleading
    The document says. forgelm purge --run-id <id> --kind artefacts deletes a run's compliance bundle. L60 says it removes <output_dir>/compliance/*.json files whose name embeds the run_id.
    What the code does. The resolver deletes only files in compliance/ whose filename contains the run_id as a delimited token. ForgeLM's exporter writes fixed names with no run_id: compliance_report.json, training_manifest.yaml, data_provenance.json, risk_assessment.json, annex_iv_metadata.json, data_governance_report.json. Against a real bundle the command finds nothing, emits data.erasure_failed (NoMatchingArtefacts)…
    Code references. forgelm/cli/subcommands/_purge.py:998-1014, forgelm/cli/subcommands/_purge.py:1044-1064, forgelm/compliance.py:2173-2236, forgelm/trainer.py:2087-2096
    Proposed correction. Fix the code: resolve the run's bundle by its real artefact names, scoped to the run (for example via run_id inside compliance_report.json), or delete an explicit allow-list. Until then, add: "Known limitation: ForgeLM's compliance artefacts do not embed the run id in their filenames, so --kind artefacts currently matches nothing for bundles pro…
    Turkish mirror. the Turkish page has the same error; fix both in the same PR

  • DOC-D3B02-004 (docs, High) — docs/usermanuals/en/compliance/gdpr-erasure.md: false claim — forgelm purge --run-id <id> --kind artefacts "atomically removes ... a compliance bundle".
    severity High · already tracked: KNOWN-OPEN TRUST-02 docs/roadmap/phase-16-trust-surface-hardening.md:553-562
    Where. docs/usermanuals/en/compliance/gdpr-erasure.md:17,32 (Turkish mirror: docs/usermanuals/tr/compliance/gdpr-erasure.md:17,32) · type: false claim
    The document says. forgelm purge --run-id <id> --kind artefacts "atomically removes ... a compliance bundle".
    What the code does. _artefact_targets_for_run only selects compliance/ files whose name contains the run_id as a token (e.g. compliance_<run_id>.json, annex_iv_<run_id>.json). The trainer writes fixed names: compliance_report.json, training_manifest.yaml, data_provenance.json, risk_assessment.json, annex_iv_metadata.json and data_governance_report.json. So the mode never finds a real bundle. Reproduced: with…
    Code references. forgelm/cli/subcommands/_purge.py:998-1016, forgelm/compliance.py:2173-2236, forgelm/trainer.py:2087-2096
    Proposed correction. Code fix (see rationale). Until then add a warning: "--kind artefacts currently matches only files whose names embed the run id; the standard compliance bundle (compliance/compliance_report.json etc.) is not matched and must be removed manually."
    Turkish mirror. the Turkish page has the same error; fix both in the same PR

  • DOC-D2B02-023 (docs, Medium) — docs/guides/gdpr_erasure.md: misleading — --kind artefacts deletes a run's compliance bundle (compliance/.json embedding run_id)
    severity Medium · already tracked: KNOWN-OPEN TRUST-02 (inferred) — docs/roadmap/phase-16-trust-surface-hardening.md:554-566
    Where. docs/guides/gdpr_erasure.md:15,60; docs/reference/purge_subcommand.md:51 · type: misleading
    The document says. --kind artefacts deletes a run's compliance bundle (compliance/
    .json embedding run_id)
    What the code does. No ForgeLM writer embeds the run_id in compliance file names, so the mode never matches a real run (A1). On matches it deletes any file type (A3). See F3.
    Code references. forgelm/cli/subcommands/_purge.py:998-1014, forgelm/compliance.py:2173,2228
    Proposed correction. See F3.
    Turkish mirror. the Turkish page has the same error; fix both in the same PR

Acceptance criteria

  • A regression test reproduces the failure scenario and asserts the corrected behaviour.
  • Documentation listed above is corrected in English and in its Turkish mirror in the same PR.
  • Every finding in this issue is resolved or explicitly closed with a reason.

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.

Activity

  1. added
    bugSomething isn't working
    documentationImprovements or additions to documentation
    backlog: knownAlready tracked in docs/roadmap
    severity: highWrong behaviour or a false claim users rely on
    source: review-2026-10Found by the October 2026 code and documentation review
    wave: 2Roadmap wave 2: high severity, larger effort; next-release tech
    on Oct 9, 2026
  2. added
    blockedWaits for another issue (see Blocked by); set and removed automatically, never by hand
    on Oct 20, 2026
  3. cemililik commented on Oct 22, 2026

    @cemililik
    CollaboratorAuthor

    Tracking note from pull request #1050 (documentation side of DOC-D1B05-005, which that pull request deliberately does not fix in code):

    • forgelm purge --run-id <id> --kind artefacts documents itself as removing the compliance bundle, but the resolver matches only files whose names embed the run id. The standard bundle has fixed basenames, so the command finds nothing, emits data.erasure_failed (NoMatchingArtefacts), exits 1 and deletes nothing. The --help text, the error message and six documents (the GDPR guide, the purge reference and the user manual, EN and TR) now say so.
    • When this issue's fix lands, remove the warning from those six documents and delete test_artefacts_kind_finds_nothing_in_the_standard_fixed_name_bundle in tests/test_gdpr_erasure.py together with test_purge_docs_warn_that_artefacts_misses_the_standard_bundle in tests/test_usermanual_reference_consistency.py. The first builds the bundle with the real exporter and also writes the run id inside the files, so it fails for a resolver that proves ownership from file contents as well as for an allow-list.
    • Acceptance criteria to add here: the resolver uses an allow-list of the exporter's fixed names plus an ownership proof from the file contents (for example the run id recorded in compliance_report.json), and refuses a bundle it cannot attribute to the run.
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

    area: gdpr-approvalCode area: gdpr-approvalbacklog: knownAlready tracked in docs/roadmapblockedWaits for another issue (see Blocked by); set and removed automatically, never by handbugSomething isn't workingdocumentationImprovements or additions to documentationseverity: highWrong behaviour or a false claim users rely onsource: review-2026-10Found by the October 2026 code and documentation reviewwave: 2Roadmap wave 2: high severity, larger effort; next-release tech

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions