Skip to main content

Personal-data map and erasure verification

This inventory maps each personal-data store to its removal control and executable evidence. Before a store or derived copy receives personal data, complete these steps:

  1. Add it here.
  2. Implement its export and erasure operations.
  3. Add focused behavioral tests.

PersonalDataMapArchTest reads the migrated database schema. It fails the build if neither this map nor its own non-personal-data table list names a table. It also fails if a table on that list has a column that references a person. It finds such a column from foreign keys and from column names. That is a heuristic: it cannot see an ID inside a text key, such as the account ID in an auth_rate_limit_bucket key.

The test also fails if a source or test cited below has moved. It requires a single catalog owner and citations in the dedicated implementation table. A mention elsewhere in prose cannot satisfy ownership.

Workspace purge applies storage limitation when a workspace loses its purpose. A verified person-erasure request follows the instance-admin procedure. The implementation inventory below owns each store's exact selection, export and erasure citations. The frozen scope includes reviewed work where the person had any of these roles:

  • Author, merger, commenter or reviewer.
  • Assignee or requested reviewer.
  • Contributor of a linked commit.

Evidence copies use that same source scope, including when their primary author is another person. Results, problems and feedback, with their deliveries, are selected only when the person is the developer they are about or their recipient.

Provider-owned source attribution is shared by scope selection and processing suppression: server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/ScmPersonSourceIdentityContributor.java, server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/slack/SlackPersonSourceIdentityContributor.java and server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/outline/OutlinePersonSourceIdentityContributor.java. Each guard checks the requesting workspace in SQL. Mirror sync cannot bypass a native-identity control.

OAuth state nonces record only a new exact initiating account. Exports omit the nonce capability, and erasure deletes its row. Older rows have no inferred account attribution.

The self-service account export is a separate, narrower operation. Self-service account deletion runs the same person erasure as soon as the deletion is saved, for the account and the identities linked to it.

Store / copyData and access pathWorkspace removalPerson erasureResidual retention and evidence
PostgreSQL account, identity and authentication rows — account, account_feature, account_public_activity_hidden_by_default, account_export, identity, issued_jwt, consent_decision, auth_event, config_audit_eventSign-in identity. Self-service export plus instance-admin person exportAccount-global rows remainSelf-service: account purge as soon as the deletion is saved, with an hourly retry. Instance-admin person job: account purger after the other store stepsAuthentication history retains references to the account tombstone, with IP address, user agent and details cleared on erasure, and expires in rolling partitions. Settings-change history detaches actor references and expires. Exports expire. Data retention gives the periods. server/application/src/test/java/de/tum/cit/aet/hephaestus/core/auth/AccountHardDeleteSweeperIntegrationTest.java and server/application/src/test/java/de/tum/cit/aet/hephaestus/core/auth/export/AccountExportRetentionIntegrationTest.java.
PostgreSQL sign-in rate limits — auth_rate_limit_bucketThe remaining request allowance of each rate-limited endpoint. A bucket key holds the account ID after sign-in, or the client IP address before sign-in. Instance-admin person export lists the keys of the person's account and their expiry times, not the bucket stateAccount-global rows remainPerson erasure deletes the buckets of the person's account. IP address buckets and the buckets of other accounts remainThe hourly sweep in server/application/src/main/java/de/tum/cit/aet/hephaestus/core/auth/ratelimit/AuthRateLimitBucketSweeper.java deletes expired buckets. server/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/AccountErasureIntegrationTest.java
PostgreSQL product feedback — product_feedbackData supplied by the account holder. Instance-admin person exportPurge contributors remove product feedback sent from the workspaceAccount purge removes account-owned rows through server/application/src/main/java/de/tum/cit/aet/hephaestus/productfeedback/FeedbackAccountErasureAdapter.javaNo independent time-based expiry. Workspace removal: WorkspacePurgeIntegrationTest.purgeRemovesProductFeedbackFromTheWorkspace. Account erasure: AccountHardDeleteSweeperIntegrationTest.shouldEraseProductSubmissionsWhenAccountIsPurged.
PostgreSQL product feedback filing — product_feedback_filingReport draft, route, frozen destination, issue links, attempts, usage, and follow-up cursors. Person export includes the report, route, and issue linksRemoved with the source report after the cleanup envelope is copiedAccount and person erasure remove the report-owned row after the cleanup envelope is copiedNo independent age expiry. GitHub cleanup is asynchronous. See Product feedback.
PostgreSQL product feedback choices — product_feedback_consentAppend-only account choices and withdrawals with notice version and time. Person export includes the account’s eventsAccount-global events remainAccount and person erasure remove the account’s eventsA withdrawal changes the current choice without rewriting earlier events. No independent age expiry.
PostgreSQL product feedback cleanup — product_feedback_cleanupRepository and installation IDs, random marker, payload hash, known issue number and node ID, and required actions. Its scrub is an outbox action whose payload holds only the record ID. No report text or account identitySurvives source deletion until external cleanup completesCreated before source deletion, in the same transaction, so erasure can reconcile an uncertain createDeleted at once when no issue was created. Otherwise the scrubbed issue, or work still incomplete after 30 days, becomes Needs action with an admin email. The locator stays until an admin confirms the manual step.
PostgreSQL product feedback destinations — product_feedback_destinationInstance-wide repository, installation, model, limit, and pause configurationInstance configuration remainsNo reporter-owned row. Administrator attribution follows the configuration audit erasure policyRetained as instance configuration. The private repository cannot be removed while a public issue can still move there.
PostgreSQL GitHub App installations — github_installation_requestEach installation of the GitHub App with its account login, and the decision of an instance admin. Instance-admin person export lists the installations of the person's own GitHub account, adopted or not, and the decisions that the person madeWorkspace purge clears the workspace reference, and for a personal account also the login and the native id. The installation stays adoptedErasure removes an installation of the person's own GitHub account that no admin adopted, and refuses a new record for that account. For an adopted one, it clears the login and the native id. It clears the reference to an admin who decidedAfter a workspace purge or the person's erasure, an adopted installation of a personal account keeps no login and no native id. It keeps its installation id, account kind, status and times, which stop a replayed installation event from creating another workspace. An organization's record keeps its login and native id. A personal account's record keeps them until its workspace is purged or its person is erased. An uninstall removes an installation that no admin adopted. server/application/src/test/java/de/tum/cit/aet/hephaestus/integration/scm/github/installation/adoption/GitHubInstallationAdoptionIntegrationTest.java
PostgreSQL contributor profiles — userMirrored contributor identity. Self-service export plus instance-admin person exportInstance-global rows remainInstance-admin person contributor anonymizes the exact provider profile. Self-service account deletion anonymizes the profiles of the identities linked to the accountNo independent time-based expiry. The operator's record of processing defines the operator responsibility. Personal settings, such as the AI choice and feedback delivery, are columns of account.
PostgreSQL SCM mirror — organization, organization_membership, team, team_membership, team_repository_permission, repository, repository_collaborator, pull_request, pull_request_requested_reviewers, pull_request_review, pull_request_review_comment, pull_request_review_thread, issue, issue_assignee, issue_comment, milestone, git_commit, commit_contributor, commit_file_changeGitHub/GitLab profiles and authored work. Source-provider export plus instance-admin person exportRepository removal erases a source repository once no workspace monitors or keeps it. A stopped GitLab project stays kept until Remove synced work. Connection removal and workspace purge erase the active mirror, including kept projectsExact provider instance and native user matching. Authored content is cleared and shared actor roles are detached separatelyserver/application/src/test/java/de/tum/cit/aet/hephaestus/workspace/ScmWorkspaceErasureIntegrationTest.java.
PostgreSQL commit link corrections — commit_identity_changeThe column, row ID, old and new user IDs, outcome, and time of each changed commit link. Person export includes the rows that name the personRows remain after repository or workspace removalErasure deletes the rows that name the personThe server deletes a row after 90 days. server/application/src/test/java/de/tum/cit/aet/hephaestus/integration/scm/domain/commit/identity/CommitIdentityResolutionIntegrationTest.java.
PostgreSQL Slack mirror — slack_message, slack_thread, slack_monitored_channel, slack_participant_consent, slack_channel_consent_eventMessages, identities and attribution. Instance-admin person exportDisconnect and workspace purgeSlack opt-out and instance-admin person contributorsserver/application/src/test/java/de/tum/cit/aet/hephaestus/integration/slack/retention/SlackRetentionErasureIntegrationTest.java and server/application/src/test/java/de/tum/cit/aet/hephaestus/integration/slack/interactivity/SlackAppHomeOptOutErasureIntegrationTest.java. A message deleted in Slack is tombstoned by its event or, when the event is lost, by the nightly Slack sync: server/application/src/test/java/de/tum/cit/aet/hephaestus/integration/slack/sync/SlackHistoryReconcilerIntegrationTest.java. Data retention gives the limits.
PostgreSQL Outline mirror — outline_document, outline_collectionDocuments and attribution. Instance-admin person exportCollection removal, disconnect and workspace purgeInstance-admin person contributorsserver/application/src/test/java/de/tum/cit/aet/hephaestus/integration/outline/lifecycle/OutlineWorkspacePurgeAdapterIntegrationTest.java.
PostgreSQL conversations — mentor_conversation, mentor_entry, mentor_turnOne main conversation for each account in each workspace (mentor_conversation.account_id), with its threads, messages, weekly digests, votes and turn usage. Self-service export of the account's own conversations as the app shows them (AccountConversationExport, GDPR Art. 15(1)). It holds the messages, the replies and the weekly digests, without redacted ones. Tool results stay out of it. Other people's data enters a conversation through them (Art. 15(4)). Instance-admin person export of the account's own conversations, without tool results and summaries. Each exported message holds the words that the app shows, including the words of each link that Hephaestus showed. The export also has the Hephaestus messages in other conversations that showed feedback about the personWorkspace purge deletes them. Slack disconnect erases every message written in Slack and the copies of its words. It stops running Slack turns and clears the Slack DM identity of each conversationDeletes the account's own conversations. Redacts Hephaestus messages in other people's conversations that showed feedback about the person (MentorFeedbackCopyPersonDataStore). Before erasure starts, removes physical conversation sandbox copies in the selected workspaces. A missing runtime owner or failed deletion prevents acknowledgement. As the last store step, redacts every read, bash, load_context and fetch_context result in those workspaces (MentorToolResultCopyPersonDataStore). After the erasure request, Hephaestus refuses a write for the account with PERSON_ERASED, and a turn that ends stores nothingEach entry is erased in the two weeks before it is 400 days old (HEPHAESTUS_FEEDBACK_RETENTION, the window that feedback and results share). A tool result that can copy another source goes earlier, with the Slack retention of the workspace. Answers that repeat a channel message keep the conversation retention. Slack disconnection erases all of them: server/application/src/test/java/de/tum/cit/aet/hephaestus/mentor/MentorRetentionIntegrationTest.java. Account absorption moves the conversations to the claiming account and merges two main conversations of one workspace
PostgreSQL practice versions — practice_versionEach saved version of a workspace's practice definition, and the account that saved it. Instance-admin person export lists the versions that the person savedWorkspace purge removes the workspace's practices and their versionsPerson erasure clears the author reference. The practice definition remains, because the workspace and its reviews still use itserver/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/AccountErasureIntegrationTest.java
PostgreSQL practice proof — result, problem, result_mark, feedback, feedback_basis, feedback_copy, feedback_decision, feedback_responseResults, guidance, responses and actual copy receipts. Self-service export of the feedback delivered to the account, with its posted copies (AccountFeedbackExport). It holds only states that the developer may learn of. It also holds every response the account gave. Withdrawn feedback keeps its dates and drops its text. Instance-admin person export of the restWorkspace purge deletes scoped records through their ownersErasure removes affected feedback and source-person proof before membershipFeedback is erased 400 days after its delivery, or after its creation when it was never delivered (HEPHAESTUS_FEEDBACK_RETENTION, the conversation window). Its basis, copies, decisions and responses go with it. A result is erased 400 days after it was recorded, once no retained feedback cites it and no running review reads it. Its problems, marks and scan-report members go with it. A scan report keeps its aggregate counts. Feedback with a copy whose post started and never confirmed stays until that copy's cleanup receipt. A server job at 03:00 every day: server/application/src/test/java/de/tum/cit/aet/hephaestus/practices/result/FeedbackRetentionIntegrationTest.java. Evidence-copy cleanup follows Copied evidence and secondary subjects
PostgreSQL operation history — connection_audit, sync_job, item_event, review_batch, review_scheduleSource events, actor/requester attribution and operation historyWorkspace-owned records follow their owner purgeAudit actors become null without changing recorded actions. Provider restrictions survive erasureData retention gives the period of unreferenced terminal item events
PostgreSQL retained occasion evidence — item_event.evidenceA pull request or submitted review occasion's title, description, review words, branch and state, as stored when the occasion was recorded. The provider identities and logins of its author, assignees, merger and reviewer, as stored then. At most 1 MiB for each occasion. The personal export lists the occasion without these wordsWorkspace purge, SCM mirror erasure and removal of the item from the workspace's source remove it. The occasion row staysErasure of any person the evidence copied removes the whole evidence, also when that person was not the actorExpires at the item event retention horizon after it was recorded (Data retention), also while a review references the occasion. No later decision or retry extends it. The same deadline bounds writer inputs and raw session copies. Physical removal follows the existing sweep and runtime leases
PostgreSQL instance-administration records — instance_settings, instance_llm_settingsThe stable account reference of the administrator who changed silent mode or instance LLM policyInstance-scoped. Workspace purge does not reach themAccount purge detaches settings actor references.The upgrade drops old settings display-login attribution without backfill. Settings and change times remain. server/application/src/main/java/de/tum/cit/aet/hephaestus/core/settings/SettingsAccountErasureAdapter.java, server/application/src/main/java/de/tum/cit/aet/hephaestus/agent/catalog/LlmSettingsAccountErasureAdapter.java.
PostgreSQL runtime — review_job, script execution, capture receipts and diagnosticsTemporary inputs, output and provenanceWorkspace purge erases the recorded attempt inputs and starts evidence cleanup on each server before parent deletionErasure removes all source-person dependencies, including another developer’s reviewData retention gives the payload and job periods. Product reviews and results do not depend on retained jobs
PostgreSQL transient composition — review_composition_basis, review_attempt_input and person_evidence_copyOriginal bounded inputs, the recorded files of a running attempt's folder, and the receipt of each attempt's copyPurge erases the receipts and deletes the recorded files in its transactionErasure follows every copied person, not only the result developer. It erases the receipts and deletes the jobs' recorded files at onceData retention gives what removes receipts. Recorded files live only while their attempt runs
PostgreSQL product reviews — review, review_practice, review_itemPinned versions, method, per-item proof membership and aggregate reportWorkspace purge uses the report ownerPerson erasure removes personal proof and affected membership, including developerless file proofData retention gives the period of raw scan proof. Aggregate reports remain without quotes or personal identity and identify expired proof
PostgreSQL llm_usage_eventToken/cost accounting of each model call, with workspace, opaque source identifier, run and practice. First failure kind, optional HTTP status and recording time. No provider response body. Instance product feedback drafts have no workspace or run. Monthly workspace/admin reportsRetained for accounting until its retention sweep. A deleted run leaves the row without its runPerson contributors detach the selected job/conversation source identifiers while retaining accounting factsData retention gives the window and its operator control. server/application/src/test/java/de/tum/cit/aet/hephaestus/agent/usage/LlmUsageRetentionIntegrationTest.java proves the cutoff across workspaces. server/application/src/test/java/de/tum/cit/aet/hephaestus/agent/usage/LlmUsageRetentionSweeperTest.java verifies job outcomes.
PostgreSQL account passkeys — passkey_credential, passkey_challenge, passkey_recovery_codeAccount-bound public credentials, browser-session challenges, and recovery-code hashes. Self-service export includes names, dates, and the personal protection choice, not credential blobs or recovery codesAccount-global rows remainAccount purge removes all three through server/application/src/main/java/de/tum/cit/aet/hephaestus/core/auth/webauthn/PasskeyService.javaChallenges expire after five minutes and are removed on use or later challenge creation. Recovery invalidates all previous credentials and codes. server/application/src/test/java/de/tum/cit/aet/hephaestus/core/auth/webauthn/PasskeyLifecycleIntegrationTest.java.
PostgreSQL installed-client sessions — client_session, client_sign_in_handoffWhich installed clients (the browser extension) are signed in, and the hashes of their single-use sign-in codes. Refresh-secret hashes live on issued_jwtAccount-global rows remainAccount purge removes both through server/application/src/main/java/de/tum/cit/aet/hephaestus/core/auth/AccountPurger.javaA sign-in code expires after 60 seconds. A session ends at its absolute deadline, on sign-out or on revocation. It becomes eligible for deletion with its token rows at absolute expiry or one day after revocation, whichever comes first. The hourly cleanup skips locked rows until a later pass. See server/application/src/main/java/de/tum/cit/aet/hephaestus/core/auth/clientsession/ClientSessionPruner.java. server/application/src/test/java/de/tum/cit/aet/hephaestus/core/auth/clientsession/ClientSessionIntegrationTest.java.
PostgreSQL notification subscriptions — notification_subscriptionNative account id, category, opt-in state/time and opaque unsubscribe capability. The MENTOR_DIGEST category records the weekly digest choiceAccount-scoped, not workspace-ownedNotificationAccountErasureAdapter removes rows during account purge. Export includes choices but no capabilityRetained until account erasure. Each capability only disables one subscription. Unsubscribe does not erase the opt-out, so old links remain valid.
PostgreSQL outbox — agent_actionOne effect that Hephaestus sends to the outside world, such as an email or a feedback copy on the reviewed work. It names the addressed account: for feedback, the developer. While it waits, an email's payload holds the identifiers of the notification, not its text. An admin's test email also holds the test address. A product-feedback issue's payload holds the issue title and body that routing rendered from the report. A feedback send's payload holds only the feedback id. A Slack post's payload holds only the ids of its entry and turn. Instance-admin person export includes the actions that address the accountA workspace's actions are removed with it. An action of the instance, such as a product-feedback issue, stays until it ends. A pending issue of a removed report is not filedAccount purge and the instance-admin person job delete the account's actions in every state, sent ones included. Role-change notices follow Role-change security notices. A pending action is not sent. A send that already started still reaches the provider. A sent email stays with its recipient. The domain row, not the outbox, keeps the reference to a provider copy that erasure removesThe payload is cleared when the action ends. The ended row keeps the kind, outcome, reason and provider reference, such as the email Message-ID, for 30 days. Slack post outcomes and their keys stay while their source entry is unredacted. A confirmed digest receipt also keeps the posting-time Slack team and user ids, with its channel and message timestamp. They hold no payload. A durable ledger event or action settlement removes them after source redaction or deletion. Account or workspace erasure removes them
PostgreSQL durable work — event_publicationThe Spring Modulith event publication registry has one row per pending or failed durable listener, including activity recording. It holds the serialized event and its delivery attempts. The event holds source and recipient ids, bounded lifecycle information and timestamps, never an address or work text. Activity facts contain ids, event types, timestamps and an optional source key. Instance-admin person exportInstance-scoped: workspace purge does not directly reach it. Delivery rechecks source and membership. Activity recording ends without a row when the workspace or its monitored repository is goneThe row holds ids only. Role-change publications follow Role-change security notices. Person erasure deletes matching queued activity facts through ActivityPersonDataCatalog. Notification delivery resolves the address at send time from account.primary_email. Account purge clears that field. A resubmitted notification for a purged account therefore has no recipient and completes as withheldCompleted publications are deleted. Notification kinds use their bounded lifecycle window (Data retention). Source erasure, opt-out or lost eligibility completes queued mail without sending on the next attempt. Activity facts remain retryable while their source is eligible. A missing or unmonitored repository or an inactive provider connection ends them on the next attempt. server/application/src/main/java/de/tum/cit/aet/hephaestus/notification/NotificationRedeliveryJob.java.
PostgreSQL provider event inbox — provider_eventEach verified webhook delivery as received: its payload and headers, with the provider identities, names and message words that the provider put in it. A dead letter also records its error class and the account that replayed itA handled event stays for 3 days, a dead letter for 30 days (hephaestus.integration.consumer.replay-window, dead-retention). Workspace purge deletes the workspace's events. Erasing a Slack channel deletes all its events, including leased eventsEach erasure pass deletes stored events whose payload names one of the person's identities of that provider. The event must name the same source server as the identity. For GitHub and GitLab, this is a user object with the person's id. GitLab user_id, author_id, assignee_id, assignee_ids, merge_user_id, updated_by_id, and last_edited_by_id also match. For Slack and Outline, it is the person's id. Names and email addresses alone do not prove a provider identity. Such author fields remain until the event expires. Erasure also deletes leased events and deliveries that arrived after admission or before a failed request resumed. Each handler write step locks the event and checks its lease epoch in the same transaction. If erasure removed the event, further writes roll back and the consumer records erased-during-processing without a retry. The replay attribution of the person's account becomes null. The event stays only if its payload does not match the person's identityserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/core/connection/IntegrationCoreConnectionPersonDataCatalog.java
Temporary review capture and context copiesA review's existing evidence receipt supplies safe copy facts. Temporary code is not a second export storeCopies carry their workspace in the evidence home before content is written. Capture admission stays with live copies until physical removalErasure waits for capture admission. Failed closes retain custody and are retried. Startup removes unlocked orphaned copies before admitting work, or refuses to startTemporary evidence and restarts inventories the copy paths and their owners. There is no separate database ledger.
Server-local repository mirrors, checkout caches and attempt foldersPerson export lists exact-linked repository history and safe copy facts, not raw Git objects or other profilesEach server removes a workspace's mirror, with the checkouts it built from it, when the workspace stops monitoring or keeping the repository. Workspace purge erases the receipts in its transaction, and each server retries removal of its attempt folders until it succeedsPerson erasure cancels affected attempts and erases their receipts through EvidenceFolderPersonDataCatalog, without waiting for a server. Each server retries removal of its erased attempt folders until it succeeds. Repository owners erase Git authorship at the source, not by rewriting Hephaestus mirrorsAttempt-input lifetime follows ADR 0041. item-source-governance.md owns erasure requirements. A server that is gone took its folders with its volume.
Research datasets outside the instance database, held by the research team at [location]Pseudonymized copies of data that a participant allowed for research, and the key that links codes to people, stored apart from the dataWorkspace purge does not reach themThe person-erasure job does not reach them. The operator removes the account's data from datasets that are not yet anonymizedKept while the research continues, then deleted or anonymized. Anonymized datasets cannot be reached and can remain. See "Research use of existing stores".
Configured LLM providerPrompts and responses for enabled purposes. Provider/operator access processA completed request cannot be retractedProvider processDeployment-specific provider terms must define the bound before processing starts. See the processor checklist.
Product feedback model providerCode-redacted report text and public issue titles for the instance-level draft. Personal data can remain after redactionA completed request cannot be retractedProvider process under the operator’s agreementSeparate processor assessment for drafts, including retention, training terms, and transfers. The workspace AI choice does not select this instance-level model.
GitHub product feedback repositories, public and privateRendered issues, report numbers on private issues, and an optional reporter GitHub mention on public issuesCleanup follows removal of the source reportPublic issues move to private. The app replaces issue text and closes the issue. Maintainers remove revision content or delete issues where requiredGitHub controls its copy and history. Public readers can retain copies. See Product feedback legal steps.
GitHub/GitLab/Slack delivery destinationPosted feedback. Source-provider exportNot silently crawled or rewrittenBest-effort correction/removal through the operator pathThe provider controls its copy and audit history.
Application metricsAggregate operational counts without account, workspace, export or source labelsNot applicableNo subject-level series existsBackend retention is deployment-specific. Operators must record it.
Optional trace export and log collectionTrace timing and outcome. Collected log lines with stacks, account, user and provider ids, and operational correlationRecipient-specific processRecipient-specific process. A log store keeps its lines until its retention removes themOff by default. Configure and document exact recipients, lawful bases and retention before enabling either. The processor checklist owns the approval evidence.
External avatar hosts and browser cachesImage request address and visitor network metadata, including on public pagesHost/browser processHost/browser processNo Hephaestus export or erasure of a third party's request logs. Record actual hosts and their privacy terms.
Container logs and support bundlesOperational output. Logging policy excludes raw request bodies, model output, sandbox transcripts and secrets. Lines still carry identifiers: Hephaestus account and user ids, and the provider's numeric account ids, which the provider can map to a person. They carry no provider logins and no email addresses, but they can carry library exception text, so operators must assess exported bundlesNo selective deletionNo selective deletionShipped container logs rotate by size (Collecting logs). Support-bundle retention is deployment-specific.
PostgreSQL and filesystem backupsA copy of the backed-up personal-data corpusNo selective deletion inside a backupExpiry of the backup copyThe optional encrypted off-host PostgreSQL backup overlay retains full backup chains by count, not by a legal time limit. Operators must document and enforce destination retention, including copies of .env and inbox evidence. See backup and restore.

Security retention​

provider_resource_repair holds pseudonymous personal identifiers under ADR 0101. It holds the provider origin, resource identifiers, an ownership fingerprint and repair state. An unresolved Slack authorization also holds its attempt ID and, when known, the returned team, bot-user ID and token fingerprint. A Slack token fingerprint is a domain-separated, unkeyed SHA-256 value, not the token. A GitHub installation on a personal account can identify that person.

TablePurposeLegal basisDeletion triggerDeletion proof
provider_resource_repairProtect the integrity of adopted resources against unresolved provider removals and authorization exchangesLegitimate interest in integrity and security, GDPR Art. 6(1)(f)Delete when the fence resolves or an instance admin releases itserver/application/src/test/java/de/tum/cit/aet/hephaestus/integration/core/connection/repair/ProviderResourceRepairDeletionIntegrationTest.java

These identifiers have no workspace or person pointer. They cannot select a person's records for export or erasure. A data subject response must explain this retention purpose, legal basis and deletion trigger. The operator must document necessity and balancing before it relies on Article 6(1)(f). A public authority that processes data for its official tasks must identify its applicable Article 6 basis instead. See GDPR Article 6 and Recital 49.

An unresolved fence can remain indefinitely. It stays visible to instance admins, including after its connection or workspace is deleted. An instance admin can confirm out of band that the old resource is gone, then release the exact fence. The confirmation and release are audited. The audit does not copy the provider identifier. A workspace-only role cannot release a fence.

connection_provider_repair holds the workspace authorization reference. It has no credential, provider payload or signed callback URL. Workspace and connection deletion cascade to these references, without deleting the unresolved security identity. Credential erasure keeps its existing deadlines. Connection repair describes the admin action.

Operator verification​

Each erasure, export and retention job publishes a bounded success/failure counter and an affected-row counter. The names, labels and cardinality guarantee are in the observability contract. Alert configuration remains deployment-owned.

  1. Alert on outcome="failure".
  2. Alert on outcome="incomplete". This means a retention pass exhausted its time budget with expired rows still in place.
  3. Alert if more than 48 hours pass without a successful daily llm_usage_retention run.

Review this map with your record of processing, source governance, and the public privacy statement.

Member onboarding and AI choices​

account stores an account's AI choice (ai_choice: NO_AI, IN_HOUSE_ONLY or CLOUD) and when it was last changed. It is answered once and holds in every workspace the account is a member of. A row exists only once the person has answered. The account export includes it with the choice as that literal. Account erasure deletes it. Workspace purge never touches it.

membership stores which settings revision an account finished or skipped a workspace's setup page at (seen_revision). It carries no choice and no free text, and is removed with account erasure and with workspace purge.

workspace_onboarding_settings stores whether the setup page is on, whether a choice is required, and required integration identifiers. It holds no free text and is removed with workspace purge.

llm_model and workspace_llm_model carry the declared operator (operated_by) and a data-handling note (data_handling_note), an admin-only field for region, agreement, renewal date and retention details. It is shown to admins only, never to developers, and must not name individuals. None of these tables has an independent expiry. Configuration changes also follow the existing configuration-audit retention policy.

Account membership and choices​

Membership keeps the account, workspace role, review selection and hidden preference. Logical removal records leftAt without granting current access. Unclaimed human accounts can exist before sign-in. Bots remain provider actors.

AI choice and external delivery preference apply across the person's identities and workspaces. Erasure deletes dependent proof and feedback before membership, without anonymizing personal results by clearing developer identity. Identity restrictions retain provider and team keys after account removal.

Role-change security notices​

A security notice belongs to its recipient. Erasing that recipient deletes their notice from the outbox and from pending event publications. A notice addressed to someone else stays.

Erasure removes the erased account's identifiers from that notice, whether the account made the change or held the role. The email describes an erased actor as “an administrator” and an erased affected person as “an account”. The notice keeps its change identifier, recipient, role change, delivery state and receipt. The outbox permits only this identity redaction. It rejects changes to the recipient, role, change identifier or other payload fields.

Research use of existing stores​

Research use processes stores that this map already lists. The latest RESEARCH_PARTICIPATION decision in consent_decision gates it.

A research dataset release adds one store, the disclosure record: research_disclosure and research_disclosure_subject. It holds no dataset payload. It records which participant key each released file used for each account, and the exact grant that allowed the release. An instance administrator with a fresh passkey can read which keys must be removed, and why.

Person erasure drops the account link, but keeps the key and records that removal is owed. Recording that the researchers removed a participant drops the link and the grant reference. Recording that the whole copy was deleted or anonymized deletes the subject rows.

The disclosure header keeps the releasing administrator's account until that account is erased. An open disclosure blocks workspace purge. Before any further analysis, the research team checks the removal list. Hephaestus cannot revoke a downloaded copy.

A research decision must cover the retained scope and name the current research organization (consent_decision.research_organization). Legal pages defines when changed wording requires a new decision.

The research can use this data of a participant who allowed it:

  • Work in connected repositories and tools: pull/merge requests, issues, reviews, comments and chat.
  • Hephaestus practice results, their problems and practice feedback about that work.
  • The participant's responses to that feedback.
  • How the participant uses Hephaestus, including conversations with Hephaestus.

The research uses no sign-in credentials or access tokens. A participant who stops Hephaestus from using their Slack messages has those messages erased from the instance database. The research team removes them from datasets that are not yet anonymized, and research does not use them again. Anonymized datasets cannot be linked to the participant and can remain.

Where research copies live​

The research team holds research datasets outside the instance database, at [location]. Before analysis, a code replaces name, username and contact details. The key that links the code to the person is stored apart from the data. Only the research team can reach the key.

How withdrawal and erasure reach research copies​

Withdrawal and person erasure act on the instance database. They do not reach research copies. The operator must close that gap:

  1. Apply the latest RESEARCH_PARTICIPATION decision of each account before any export or analysis.
  2. After withdrawal or a verified erasure request, remove the account's data from datasets that are not yet anonymized. After a Slack message-use opt-out, remove the affected messages the same way. For a released research dataset, the removal list names the dataset and the participant keys to remove. It also names a key whose grant was withdrawn and later given again. Remove the participant's own rows. Also remove every review whose subject list contains the key. Include each such review's shared facts, such as usage and assignment counts. A participant can be named on a review with no row of their own in the file. If the copy cannot be cleaned selectively, delete it and record the closure. A new release can replace it.
  3. Finish the removal without undue delay. This is a manual step of the research team. Record the removal, or record that the whole copy was deleted or anonymized. Hephaestus cannot check the research team's storage. The record is the operator's statement.

An anonymized dataset holds no link to a person. Withdrawal and erasure cannot reach it, so its data cannot be removed.

Residual retention of research copies​

  • Pseudonymized research data and the key: the record of processing and the public notice give the retention criterion. No fixed period applies. The team then deletes or anonymizes them.
  • Anonymized datasets: outside the GDPR. They can remain and be published with no end date. They cannot be removed.
  • Consent ledger rows: unchanged. They are append-only.

The operator's record of processing owns the research purpose, safeguards and retention reasoning. The operator's DPIA owns the risks.

Person request implementation inventory​

Exact identity resolution also includes registered provider rows whose type and normalized network origin are identical. Host case and a default port do not create a different provider instance. The native subject and Slack workspace key must still match exactly. A conflicting account link on any such row stops the request. Display attribution is never used to resolve it.

Permanent suppression and native write locks use that same type, origin and native subject, including provider rows registered after erasure. Adding an equivalent provider row cannot reset a processing control.

Slack workspace keys still distinguish suppression decisions. Sharing a lock does not merge teams. Hephaestus checks these exact processing controls when a question arrives and again when a server starts its turn. An eligible model or a recreated mirrored profile cannot bypass an erased developer identity. This entry-point check does not itself remove copies that a running turn already holds.

The user, workspace and authored-work context sources read their current data for each turn. They do not retain formatted personal-content caches. The unrelated practice-catalog cache remains. It contains workspace practice definitions, not copied developer profiles.

Source connections register their provider instance even when nobody signs in through that provider. server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/core/connection/SourceProviderNamespaces.java runs before activation and before an exact source URL spelling changes. Registration and native-control inheritance commit together, under capture admission. The synchronous listener in server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/IdentityRestrictionService.java copies only exact type/origin/subject/Slack-workspace controls. It does not infer account ownership.

A bound connection cannot be changed to a different network origin.

Each active database store has an export and erasure contributor in its owning module. The shared mechanics in server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/spi/JdbcPersonDataStore.java apply frozen row keys. The catalog owns its exact identity predicate, export fields and erasure policy. A new store must have both export and erasure. Shared provider metadata has an explicit empty selection.

The inbox and replay-attribution stores also erase current matches of the frozen identity scope. Arrivals and retention do not invalidate their preview. Resume repeats them after an earlier receipt. Each pass covers deliveries stored before its inbox step. New deliveries remain admissible during erasure. Other stores keep their frozen-selection contract.

StorePerson export implementationPerson erasure implementation
activity_eventserver/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
activity_automationserver/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
activity_publicationserver/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/activity/adapter/ActivityPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
person_evidence_copyserver/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/EvidenceFolderPersonDataCatalog.java (selectCopies, safe copy facts, raw Git objects excluded)server/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/EvidenceFolderPersonDataCatalog.java (prepareErasure erases the receipts in PostgreSQL, removeErasedFolders on each server, erase, idempotent receipt removal)
review_attempt_inputserver/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/EvidenceFolderPersonDataCatalog.java (select through the person's copies, job and workspace only, no file content)server/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/EvidenceFolderPersonDataCatalog.java (prepareErasure of the copies deletes the jobs' recorded files, erase deletes what remains)
person_data_store_administrationserver/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CorePrivacyPersonDataCatalog.java, server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/PersonDataStoreAdministrationContributor.java (select, exact acting account, export, operational step facts)server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CorePrivacyPersonDataCatalog.java, server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/PersonDataStoreAdministrationContributor.java (erase, clear the exact account reference and retain counts and times)
review_job, review_composition_basis, llm_usage_event, instance_llm_settingsserver/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/AgentPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/agent/adapter/AgentPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
accountserver/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CoreAccountPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CoreAccountPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
auth_rate_limit_bucket, passkey_credential, passkey_challenge, passkey_recovery_code, account_feature, account_public_activity_hidden_by_default, identity, issued_jwt, client_session, client_sign_in_handoff, account_export, consent_decision, auth_event, config_audit_event, config_audit_event_acting_account, config_audit_event_membership_subject, instance_settings, event_publication, person_data_request, person_data_request_administration, identity_restrictionserver/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CorePrivacyPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/CorePrivacyPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
installation_accountserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (InstallationAccountPersonDataStore.select, the connections of workspaces installed on the person's own provider account)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (InstallationAccountPersonDataStore.erase, replaces the login in a purged workspace and keeps it in an active one)
git_repository_historyserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (GitRepositoryHistoryPersonDataStore.select, repository references only)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (GitRepositoryHistoryPersonDataStore.erase, preserves upstream caches. Affected attempt folders use the evidence-erasure hook)
user, organization_membership, team_membership, repository_collaborator, issue_assignee, pull_request_requested_reviewers, organization, team, team_repository_permission, repository, milestone, issue_comment, pull_request_review, pull_request_review_comment, issue, pull_request_review_thread, git_commit, commit_contributor, commit_identity_change, commit_file_change, git_commit_committer, git_commit_authored_content, issue_mergerserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/privacy/ScmPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
oauth_state_nonce, connection_audit, provider_event, provider_event_replay, sync_job, item_event, item_event_evidence, item_event_requesterserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/core/connection/IntegrationCoreConnectionPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/core/connection/IntegrationCoreConnectionPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
outline_document, outline_collection, outline_document_editor, outline_document_content, outline_document_collaboratorserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/outline/adapter/IntegrationOutlinePersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/outline/adapter/IntegrationOutlinePersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
slack_thread, slack_message, slack_participant_consent, slack_channel_consent_event, slack_monitored_channelserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/slack/adapter/IntegrationSlackPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/slack/adapter/IntegrationSlackPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
mentor_entry_tool_result_copy, mentor_entry_feedback_copy, mentor_entry, mentor_turn, mentor_conversationserver/application/src/main/java/de/tum/cit/aet/hephaestus/mentor/adapter/MentorPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export), server/application/src/main/java/de/tum/cit/aet/hephaestus/mentor/adapter/MentorEntryPersonDataStore.java (the words that the app shows for each message)server/application/src/main/java/de/tum/cit/aet/hephaestus/mentor/adapter/MentorPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
notification_subscriptionserver/application/src/main/java/de/tum/cit/aet/hephaestus/notification/preferences/adapter/NotificationPreferencesPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/notification/preferences/adapter/NotificationPreferencesPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
agent_actionserver/application/src/main/java/de/tum/cit/aet/hephaestus/core/action/ActionPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/core/action/ActionPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase, eraseAccount)
research_disclosure_subject, research_disclosureserver/application/src/main/java/de/tum/cit/aet/hephaestus/practices/research/adapter/ResearchDisclosurePersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/practices/research/adapter/ResearchDisclosurePersonDataCatalog.java (erase policy: drop the account link and record the owed removal, JdbcPersonDataStore.erase)
practice_version, feedback_response, feedback_copy, feedback_basis, feedback_decision, feedback, result_mark, review_item, problem, result, result_mark_created_actor, result_mark_removed_actor, feedback_decision_actor, review, review_batch, review_scheduleserver/application/src/main/java/de/tum/cit/aet/hephaestus/practices/adapter/PracticesPersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/practices/adapter/PracticesPersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)
github_installation_request, github_installation_request_adopted, github_installation_request_deciderserver/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/github/installation/adoption/GitHubInstallationRequestPersonDataCatalog.java (the installations of the person's own GitHub account, adopted or not, matched by exact native identity, and the decisions that the person made)server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/github/installation/adoption/GitHubInstallationRequestPersonDataCatalog.java (deletes the unadopted installations, clears the login and native id of an adopted one, and clears the decider reference)
product_feedback, product_feedback_resolver, product_feedback_filing, product_feedback_consent, product_feedback_destinationserver/application/src/main/java/de/tum/cit/aet/hephaestus/productfeedback/adapter/ProductfeedbackPersonDataCatalog.java (account-owned reports, choices, routes, and issue links)server/application/src/main/java/de/tum/cit/aet/hephaestus/productfeedback/adapter/ProductfeedbackPersonDataCatalog.java (source removal after the cleanup envelope is copied)
membership, workspace_onboarding_settingsserver/application/src/main/java/de/tum/cit/aet/hephaestus/workspace/adapter/WorkspacePersonDataCatalog.java (select, explicit export fields, JdbcPersonDataStore.export)server/application/src/main/java/de/tum/cit/aet/hephaestus/workspace/adapter/WorkspacePersonDataCatalog.java (erase policy, JdbcPersonDataStore.erase)

A HIDE_PUBLIC row in identity_restriction retains only the provider id and provider user key. It honors a public-page objection, or the absence of an answer, after identity unlink or account purge. An account that never chose to show is hidden by default, so an unlink also writes this row for an account that has not answered. It is included in the person export and retained on erasure, like a suppression key. It does not stop internal processing. An explicit Show me choice clears only currently owned, linked identities.

account_public_activity_hidden_by_default holds only the ids of the accounts that the hidden-until-answered upgrade hid. A rollback of that upgrade restores exactly those accounts. An explicit choice removes the row of the account. Erasure deletes it, and the person export includes it.

Shared source content and Hephaestus tool results​

Milestones are selected by their exact creator reference. Commit file-change copies are selected by the exact author or co-author reference, never by a path, name or email. Erasure clears milestone content and attribution while retaining its operational row, and deletes selected file-change copies before contributor attribution is detached. A person who only applied another developer's commit loses their committer attribution. The other developer's file-change rows remain.

Erasure also clears the login of the commit signature on the person's authored and committed commits. The diff context of a review comment stays: it is the repository code that the comment points at.

A mark that an erased administrator removed, and a decision that an erased administrator took on another person's feedback, both stay. Each loses its actor. Its words become the fixed text Erased administrator text, and a decision's note is cleared.

Hephaestus exports the person's conversations and threads, their questions, Hephaestus's answers, weekly digest entries, votes and turn usage. It does not export tool results, summaries or Pi runtime entries: these can contain context about other people rather than only the person's conversation. They are deleted with an erased person's conversations.

Another member's conversation can hold tool results that read data about the person. These include their membership, conversations, documents, authored work, the reviews and comments they wrote, the commits they authored, or a review whose evidence contained them.

A read, bash or load_context tool result can copy the data of anyone in its workspace. These tools read Hephaestus's context folder. A search_conversation result quotes the conversation's own entries, and these entries can repeat what a context folder result showed. Erasing an entry also erases the search_conversation results that quote it. Other tool results copy no one's data.

The preview freezes every workspace that holds the person's data. Erasure redacts every context folder result in those workspaces, including results written after the preview, and exports none of them. This is the last step of the erasure. It runs after every step that erases data that a context folder result can read. It also removes the turn sandboxes of those workspaces.

Other tool results stay. Hephaestus's messages stay whole, including their stored hidden reasoning and tool-call arguments. These can repeat what a context folder result showed.

A conversation turn stores its context folder results when it ends. Its end waits until a running erasure finishes. If the last step of an erasure ran after the turn started, the end stores those results redacted. That step does not record its workspaces, so this applies to turns in every workspace.

A turn that starts after that step reads only data that the erasure already removed. If an earlier step fails, the last step has not run yet. It runs when the erasure resumes and then redacts the results that turns wrote in the meantime.

A redacted entry keeps its row and position. Every summary that could have read it is redacted too, so Hephaestus's next turn summarizes the conversation again from the remaining entries. A redacted tool call and its result keep only their pairing. A redacted question keeps only its Pi entry id.

Content admission and erasure use transaction-scoped native-identity locks through server/application/src/main/java/de/tum/cit/aet/hephaestus/core/privacy/NativePersonDataWriteFence.java. The erasure side obtains its locks before the final preview check. Writers use READ_COMMITTED, hold a shared lock until their content transaction commits and check the permanent control after acquiring it. A lock can serialize team variants or hash collisions, but it never makes them the same person.

Shared Outline documents and co-authored commits can contain the person's work even when another person is the primary author. Export includes those exact source-content copies without the other author's profile. Erasure clears the inseparable local content copy and keeps the other author's stable attribution and operational facts. Names and email addresses are not used to split content.

Conversation exports contain visible message text and numeric usage facts. Tool input/output, error text, Pi payloads and hidden reasoning are excluded: they can contain credentials or copied profiles from another person. The export columns are declared in server/application/src/main/java/de/tum/cit/aet/hephaestus/mentor/adapter/MentorPersonDataCatalog.java. Canonical stored messages are not changed by export.

Slack AI projections check the native author and Slack team in SQL. Outline AI projections check native creator, editor and collaborator subjects in the document's provider instance. These checks apply to direct reads, workspace inputs and ranked search before its result limit. Provider sync may still mirror upstream records. The controlled rows do not return to these AI input queries.

Feedback copied into another person's conversation is selected from its exact delivery message ID and workspace. The export includes the copied message, not the other person's profile or replies. Erasure redacts the linked message and every summary that could have read it. It preserves replies, message order and conversation times. A delivery workspace mismatch stops preview.

Activity reconciliation acquires one ordered set of native-identity transaction locks before filling unresolved commit actors. It updates only admitted authors. An erased author cannot reappear in the activity ledger. This does not prevent reconciliation of other authors in the same batch.

An activity row with no resolved actor is still included when its stable work reference identifies the person's authored commit, issue, pull request or comment. Another person's resolved actor is not replaced or removed by that source-based selection.

Git repository history and short-lived attempts​

Person export lists repositories whose history may contain the person's commits under git_repository_history, using exact stored provider-user references for authors, committers and contributors. It never matches Git names or email addresses. The list includes provider and native repository IDs and the repository URL, not another person's profile.

Raw Git objects in mirrors are caches of the provider's repository. The provider is the source of truth for Git authorship, and the workspace's organization controls it. Person erasure does not delete a mirror or rewrite Git history. A rewrite would change commit IDs and break citations, and the next fetch would undo it. To erase authorship in Git history, the repository owner erases it at the provider. Until then, sync can mirror records that remain there.

A mirror can still hold the earlier objects after the provider erases them. Each workspace has its own mirror. To remove the objects, remove the repository from each workspace that monitors it. Wait for the mirror removal below, and then add the repository again.

Each server keeps its own mirrors, one for each workspace and repository. Each process checks its mirrors every minute. It removes a workspace's mirror when that workspace no longer monitors the repository and no longer keeps its synced work. A stopped GitLab project keeps its synced work, so its mirror stays. Thus, repository removal and workspace purge remove the mirrors on every server. A process that is offline removes them within a minute after it starts again.

Other workspaces keep their own mirrors of the same repository. server/application/src/main/java/de/tum/cit/aet/hephaestus/integration/scm/domain/workdir/GitMirrorRetention.java and server/application/src/test/java/de/tum/cit/aet/hephaestus/workspace/ScmWorkspaceErasureIntegrationTest.java.

Login of a personal installation​

A workspace can be installed on a personal GitHub or GitLab account. Then the login of that account is the name and namespace of the workspace. It is in the workspace slug, the display name, the account login, the connection name and the monitored repository paths. This is the same kind of data as the owner/name path of a repository. Instance-admin person export lists the connections of these workspaces under installation_account.

While the workspace exists, person erasure keeps the login, because the workspace still uses it. An uninstall of the app and a workspace purge also keep it. The purged workspace keeps its row, so that nobody else can take its slug.

Person erasure removes the login from a purged workspace:

  • The slug, the account login and the connection names become erased-<id>.
  • The display name becomes Erased workspace.
  • The connection settings lose the login.
  • The old slug stays reserved, so that nobody else can take it. For this, Hephaestus keeps a keyed hash of the slug, never the slug itself. It keeps the same for the slug that the login names.

Erasure needs the system key, which the prod profile always has. If the person asks for the login to go, purge their personal workspace first, then request the erasure. A purge after the erasure keeps the login, because the erasure no longer knows the person's account. A slug that the workspace had for an earlier login of the account stays reserved as it was written. The hash key derives from HEPHAESTUS_SECURITY_ENCRYPTION_KEY. A new system key releases these reservations: the slug becomes free again.

Hephaestus erases its own person records, derived data and collected copies. Person erasure cancels affected in-flight attempts and deletes their evidence folders through the evidence-erasure hook. The job-folder contract does not change: admission deletes the verified folder, ended attempts have a one-hour cleanup grace, and restart cleanup removes abandoned folders. One owner at a time removes a job's folders, and cleanup retries a job that another owner holds on its next pass. Repository history is not exported as an unfiltered Git object archive.

Person erasure and workspace purge mark the selected evidence-copy receipts ERASED, clear their copied identities and delete the recorded attempt inputs in their transaction. They wait for no server acknowledgement. Each running server checks its local erased copies every 30 seconds and after a PostgreSQL notification. Held leases and failed removal can delay cleanup, which retries until it succeeds. A server that returns later removes its erased copies in its next reconcile. An erased receipt cannot authorize a restored folder.

A receipt keeps its sandbox ID until sandbox deletion succeeds. Servers with agent jobs on delete those sandboxes. Every server removes its own affected attempt folders and gateway archives, also with agent jobs off.

A failed sandbox or archive deletion does not prevent removal of the other local copies. Cleanup retries automatically, and HephaestusEvidenceReconcileStalled reports failed cleanup on the server that owns it. See Alert response. Preparation that waits for capture admission does not block release.

Copied evidence and secondary subjects​

A person can appear in a review's captured evidence without being its primary developer. The preview freezes the exact job IDs from native-identity capture receipts. That job is not exported. Its evidence snapshot and diagnostics, its evidence folder and the Hephaestus tool results in its workspace are erased through those IDs. The practice results and feedback it recorded about another developer stay and are not exported.

The person-erasure transaction clears a selected receipt's native provenance. Review job retention removes receipts whose job is gone, except a receipt that still names a sandbox to delete. That cleanup identity stays until sandbox deletion succeeds. Unrelated review jobs and other people's profiles and replies are not selected through repository history alone.

Provider-feedback inspection also covers unconfirmed summary and inline writes. ExternalFeedbackPersonDataStore includes the exact reviewed-work locator when the provider has not returned a comment handle and freezes a SHA-256 fingerprint of operational delivery facts in PersonDataSelection.externalDeliveryRevision. A changed write on the same selected row invalidates the preview. No feedback body, profile, credential or subject is placed in this fingerprint.

An unconfirmed write with no exact inspection locator fails closed. Erasure cannot silently discard its delivery record. The JSON export includes feedback_copy.external_url.

PersonProcessingSuppression.isReviewJobSuppressed reads the exact frozen job keys in a fresh transaction while an erasure is active or resumable. A leased-session check of the job capability hash rejects stale queued callers after completion. Erasure revokes that hash without retaining a second subject identity. This applies to automatic feedback, approved feedback and recovery.

AgentPersonDataCatalog also includes legacy provider comment references retained on jobs, even when no feedback copy was recorded. It lists the exact reviewed-work locator and freezes those inspection facts with the same fingerprint rule. A changed legacy comment reference requires a new preview. A missing exact locator fails closed before deletion.

Contributor change contract​

Keep each store in its owning module's PersonDataCatalog. The core privacy service coordinates frozen selections and receipts, not provider-specific matching. Use the existing contributor SPI instead of a second deletion service or an operator-SQL fallback. A new store cannot ship until:

  1. Its physical table or derived-copy kind is classified here, and exactly one catalog declares it.
  2. The catalog implements exact identity selection, an explicit export projection and idempotent erasure. Credentials and other people's profiles are excluded. A shared operational row needs an explicit anonymization or empty-selection policy, not a name/email match.
  3. Both implementation citations are in the inventory table above. Runtime registration verifies that declared stores equal implemented contributors. Architecture checks verify coverage.
  4. Focused tests cover a source-only identity, two workspaces and another person left intact. They also cover changed preview, failure/resume and any writer or derived-copy boundary relevant to the new store.
  5. The controller-facing retention and source-governance records and data-subject disclosure match the implementation. Declare inbox, backup and provider limits rather than promising their erasure.

The existing executable proof includes server/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/AccountErasureIntegrationTest.java, server/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/PersonDataJobResumptionIntegrationTest.java, server/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/EvidenceFolderAccountErasureIntegrationTest.java and server/application/src/test/java/de/tum/cit/aet/hephaestus/core/privacy/PersonDataRegistryTest.java. The architecture test proves ownership and documentation coverage. It does not prove arbitrary contributor behavior. Those behavior tests remain required.

Upgrade attribution clearing​

The person-data migration clears these old references:

  • Administrator attribution on instance/silent-mode and model settings.
  • Legacy ADMIN/USER connection-audit actor references and details.
  • Membership-history subject references without an exact contributor ID.

It also invalidates pending integration authorizations. No identity is inferred from a display name, login or email. A legacy Outline mirror without an exact provider instance stops the upgrade. Before applying the upgrade, complete these steps:

  1. Back up.
  2. Verify recovery.

The shipped migration fragment owns the exact operator procedure.

The contributor-link migration clears commit_contributor.user_id where the linked user is on another kind of provider than the commit's repository. A cleared row stays in the mirror without a user. Person export and erasure of that account no longer reach the row or the commit data found through it, because they follow user_id. Capture consent no longer counts that account for the commit. This is the same state as any unlinked contributor. The migration logs a count and no personal values.

The first-author migration sets commit_contributor.user_id on GitHub commits where the row proves the user. The proof is a noreply address that holds the author's account id, or an email stored on exactly one user of that provider. Person export and erasure of that account then reach the row. The migration infers no identity from a display name, a login, or git_commit.author_id alone. It marks no row, so an administrator can clear one link by hand, and only a backup restore undoes all of them. It logs a count and no personal values.

Earlier releases could set a commit's author or contributor without an answer from the provider. Person export and erasure follow those values, so they can reach a commit that the person did not write, or miss one that they did. The commit link correction job reads these values from GitHub and GitLab again by default. GitLab answers only for the author email of the representative commit. An email that appears only as a committer or co-author has no answer, so its value stays.

The commit link correction job overwrites git_commit.author_id, git_commit.committer_id, and commit_contributor.user_id with the provider’s answer for an email on a repository. If the provider says that no account owns the email, the job clears these values. The stored-email pass of later enrichment does not restore cleared links.

Commit ingestion can still link a new or existing commit through an email stored on exactly one user of its provider. That ingestion can refill a link that the job cleared. The queue does not reopen automatically. Stored-email capture preserves an existing actor link, including a link from the provider’s answer. A new GitHub commit can also link through the account id in a noreply address. If the provider gives no answer, the job changes nothing.

The job never links an erased person. It clears a link that the provider contradicts when it names an erased person. Person export and erasure follow the new values from then on, and earlier exports are not recalled.

Each provider answer also corrects the actor of existing commit Activity events, including an explicit clear. The commit links, queue result, and Activity correction commit in one transaction. A failed Activity correction rolls them back together. Person export and erasure follow the corrected Activity actor. If ingestion links a cleared commit again from a stored email, its Activity follows that link. The queue does not reopen.

commit_identity_resolution holds the job's queue. It points at a commit and holds no email. commit_identity_change holds one row for each changed link: the column, the row id, the old and new user ids, the outcome, and the time. It holds numbers and fixed labels only, so an administrator can undo a wrong correction from it. Person export includes the rows that name the person, and erasure deletes them. The server deletes a row after 90 days, whether the job is enabled or not.

The conversation store holds no data from releases before it. The upgrade that added it deleted every earlier conversation, including the Hephaestus copies of Slack DMs. Slack keeps its own copy of each DM. Feedback shown in an earlier conversation keeps its state, but its copy no longer names the message that showed it.

Erasure after recovery​

Completed erasure receipts discard identifying scope. A database restored to an earlier point cannot reconstruct a later erasure from those receipts or from WAL after the chosen recovery point. The operator supplies exact account and provider identities from the restricted incident record. The erasure-recovery profile reapplies them through the existing store inventory before processing starts. It fails closed until every request completes or the operator explicitly declares no later erasures. It creates no second decision journal and stores no manifest.

The restore procedure owns the manifest, sequence and retention requirements.

Running conversation copies​

Person erasure clears copying tool results, later Hephaestus answers in those conversations, and answers in their child conversations. It also clears summaries and search results that could copy those words. The ledger reports each changed message to open conversations. A running turn drops its partial answer and sandbox when the context changes. A reconnected server checks the durable erasure receipts before keeping an older attempt.

Partial-answer writes and attempt completion share the erasure fence, so a late callback cannot restore copied content. This includes an answer that used earlier context without another tool call. A turn started after erasure reads the erased sources.