Skip to content

Introduce immutable job IDs and guided migration (#447) - #480

Draft
borg-codex-bot wants to merge 18 commits into
mainfrom
codex/issue-447-immutable-job-ids
Draft

Introduce immutable job IDs and guided migration (#447)#480
borg-codex-bot wants to merge 18 commits into
mainfrom
codex/issue-447-immutable-job-ids

Conversation

@borg-codex-bot

@borg-codex-bot borg-codex-bot commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Introduce permanent UUID job identities and a guided migration for existing
installations (#447, phases #471-#479). Renaming a job or changing its archive
prefix no longer separates schedules, live activity, history or restore proof.
Jobs have an editable display name and an explicit complete archive prefix;
current and historical prefixes remain available in their assigned repository.

Migration and operation

  • Startup detects existing data without preparing or applying a migration.
    Normal writes and scheduling remain blocked until the required gates pass.
  • An administrator explicitly prepares the migration. The plugin waits for
    existing workers, verifies private persistent storage, saves one UUID plan,
    and independently verifies an exact pre-change snapshot including managed cron.
  • A protected authenticated download and acknowledgement of a separately saved
    copy form a mandatory pause. A separate Run migration now action authorizes
    conversion for that exact plan and snapshot. Downloads and acknowledgement
    cannot start conversion.
  • Per-file staged writes and a durable journal preserve the original mapping
    across interruptions. Source changes, invalid state or failed final checks
    keep operation blocked. Unexplained state is retained for manual repair.
  • Backup, restore, retention, notifications and status records retain captured
    job/run/repository descriptors. Configuration and active API writes use full
    job IDs; historical aliases remain bounded migration/import evidence.
  • Job transfer uses explicit new/merge/skip choices and selected target mappings.
    History deletion is previewed and bound to the selected records. Existing
    settings recovery remains scoped to backup.conf; full installation restore
    and automatic plugin downgrade are not introduced.
  • German and English UI/manuals explain the workflow and recommend an independent
    Unraid flash/configuration backup before installing the migration candidate.

Preparation follow-up (#447)

Valid older restore-test reports store their descriptor as type/location.
The migration previously expected backup_type/location, rejected these
reports with invalid_identity_descriptor, and stopped before creating a
snapshot. The record projector now uses the shipped restore-test shape and
preserves report fields. Reports with a canonical job ID retain their captured
archive-prefix descriptor without treating it as a legacy foreign key.

Preparation now reports progress immediately, validates the requested location
before planning, and retains the last safe failure through readiness polling.
The German and English assistant explains the diagnostic, groups repeated
codes, preserves entered paths, and gives visible feedback for invalid paths
and unsuccessful requests. The manual explains storage selection and what
these codes mean.

Post-migration follow-up (#447)

Valid migrated restore reports were present but shown as overdue because readers
only accepted native target snapshots. API and scheduled tests now share a reader
that accepts the legacy recorded repository and actually tested archive only for
an already assigned UUID and matching owned target. Native markers remain strict.
Only recorded test timestamps determine validity; file modification times cannot
renew historical proof. Unclear targets or test dates appear as open proof in the
dashboard and widgets, separately from expired validity.

The dashboard retains recorded legacy check status and dates with an explicit
historical target limitation. Migrated-run provenance appears only in expanded
history details. Available identity fields share their row without empty cells.
Running and Never run remain configured-job states.

Support bundles again include complete sanitized job fields and configuration
settings, including source paths, exclusions, prefix history and policies.
Structured run/restore reports are preserved as complete JSON; oversized or
unreadable reports are explicitly listed with a reason. Credentials and private
migration recovery data remain excluded. Existing bounded text-log excerpts are
unchanged. Both migration guides explain the resulting displays and diagnostics.

Job presentation follow-up (#447, #479)

Migration now stores the previously automatic icon before removing the legacy
backup type. Explicit icon/color choices are retained. If a different explicit
icon used the legacy type color in lists, its automatic color is materialized
using the existing color palette. For installations already
converted with the older candidate, job_presentation_v1 uses the original
verified plan and snapshot to restore automatic appearance only in jobs whose exact
bytes and permissions still match the approved migration output. A private sibling
backup and central audit preserve recovery and interruption handling. Edited jobs
or unavailable original evidence are skipped with a reason; the original migration
recovery files remain unchanged.

Dashboard, restore, restore-test, report and repository views derive automatic
colors from the selected icon. Restore and report selections sort by location and
displayed job name, including natural numeric ordering, and restore sidebars show
the archive prefix instead of the UUID. UUID-based actions are unchanged.

Prune diagnostics and calendar follow-up (#447, #479)

Replacing native prune with one policy across owned current/historical prefixes
had dropped the detailed decision log. Restore the effective policy and prefixes,
repository/matching normal/checkpoint counts, each kept archive's winning rule,
name, local timestamp and full ID, and explicitly planned removal candidates.
Report success, warnings, failure or cancellation, including a successful no-op.

Comparison against the shipped Borg 1.4.5 also found two selection regressions:
Borg JSON inventory times are naive local timestamps, and equal-time archive
ordering must reverse an ascending stable sort. Read inventories in a UTC child
process and retain local calendar selection in the parent; match Borg's tie
ordering. Native Borg oracles cover local midnight, the DST fold, ties and
checkpoints, as well as the existing multi-prefix policy/deletion integration.
The configured retention counts are unchanged.

Manual prune results recognize successful Borg-delete output and preserve names
with spaces while excluding dates, IDs and progress metadata. Planning, dry-run
and unsuccessful deletion output cannot claim confirmed removals.

Validation

  • Prune log regressions cover each rule and archive, empty selections, failures,
    cancellation and invalidated inventories without broad or unconfirmed deletion.
  • Presentation regressions cover exact original evidence, private backup,
    explicit choices, preservation of later edits, missing evidence, writer exclusion,
    rollback, interrupted publication and idempotent retry. DE/EN UI tests use real
    icon/color renderers and check name sorting, readable subtitles and UUID actions.
    Local browser checks confirm the resulting Restore and Reports presentation.
  • Post-migration regressions cover retained proof after renaming, old prefixes,
    foreign archives/targets, missing recorded dates, native marker priority,
    unchanged original files, and consistent dashboard/widget counters.
  • Support export tests cover complete job/configuration fields, structured reports
    above the old truncation limit, explicit size/unreadable omissions, and retained
    credential redaction. Browser checks cover DE/EN display and identity row layout.
  • Restore-test regression covers exact legacy report preservation, actual
    migration, the current report writer, and detection by a fresh assistant
    after restart. Invalid and conflicting descriptors remain guarded.
  • Preparation regressions cover immediate progress, path validation before
    planning, no premature snapshot/selector writes, retained polling failures,
    secret redaction, grouped diagnostics, and repeated empty-path clicks.
  • Local browser checks confirm the actual click handler, readable errors,
    retained user input and visible feedback after polling.
  • Complete synthetic migration matrix, exact snapshot checks and independent
    post-apply record verification, including preserved unassigned history.
  • Failure, interrupted publication, original-plan continuation, writer exclusion,
    authentication/CSRF, protected streaming export and no-consent startup tests.
  • A migrated installation completed an actual bundled Borg backup and restored
    the original file bytes. Local HTTP qualification exercised the whole assistant,
    mandatory pause, safe diagnostics and normal UUID APIs after completion.
  • Browser checks cover the assistant, maintenance view and both languages.
  • Migration maintenance takes precedence over setup, including an already-open
    required dialog and delayed startup/setup responses. Nine behavioral setup
    scenarios preserve mandatory first-run setup, optional setup and saving the
    initial data directory. Six maintenance regression scenarios fail on the old
    code and pass with this fix.
  • Final commit-bound preflight: all 1,674 tests passed, no skips (207.53s),
    including both real Borg keyfile persistence/import tests. Python syntax passed.
  • Existing keyfile, wizard, live-log and storage regressions use canonical UUID
    inventories while retaining their security and data-preservation assertions.
    Settings profile usage shows distinct jobs and current names for all four
    storage types.

Review and test status

This is the single #447 integration PR. No stable manifest, version bump or
release package is included in this branch. It remains a draft awaiting maintainer/volunteer platform testing of
2026.09.07.0021. Automated qualification and test-channel publication are complete.

Real Unraid, PHP integration, Docker/VM recovery and actual Unraid filesystem
behavior require the manual checks documented in
docs/maintainer/identity-migration-qualification.md. FAT target-directory
behavior has a simulated regression test; recovery snapshots require a private
persistent POSIX filesystem. Stable promotion is a separate decision after
explicit maintainer test approval.

Verified test candidate

  • Branch: codex/issue-447-immutable-job-ids
  • Source commit: 6e0261af307022e58694046c07c94407b0fcac32
  • Test version: 2026.09.07.0021
  • Test snapshot: f561be2a51d34249cab2de5b769bf8fb185309cd
  • Package MD5: 65d21cab43649ad93c372783cb288630
  • Downloaded immutable snapshot manifest and package verified: version, plugin URL,
    package URL, matching MD5, exactly one manifest and one package, embedded source
    provenance and exact migration/status/support code and UI bytes. Both migration guides are packaged.
  • Commit-bound source preflight passed; source worktree is clean and pushed.

Test-channel manifest

Before installing this migration candidate, create an independent Unraid flash/
configuration backup. Test fresh setup and representative existing installations,
including the mandatory backup-check pause, explicit conversion, backup/restore
and restart. Record results against this exact version. No stable release or
merge approval is implied by this test candidate.

Known deferred packaging issue (#484)

At the maintainer's request, #484 remains postponed until Unraid has been
reinstalled. The confirmed shared-directory permission defect is still present
in this candidate. This migration follow-up does not fix it. Do not install
this candidate on the freshly reinstalled system before #484 is resolved.

@borg-codex-bot

Copy link
Copy Markdown
Collaborator Author

Approved migration assistant contract (#479)

Documentation-only follow-up in commit da7cda0 on the shared integration
branch. The maintainer approved the two-action workflow:

  • Read-only startup detection and plugin maintenance; no automatic conversion.
  • Explicit preparation, then snapshot creation and automatic integrity checks.
  • Mandatory pause for protected export and acknowledgement of a separately
    saved and checked backup copy.
  • A separate explicit apply action, bound to the exact plan and snapshot,
    followed by renewed precondition checks and complete final verification.
  • Persistent state across browser closure/restart, no duplicate execution on
    reconnect, no normal operation after failure or unverified partial state.

Issue #479 now includes the complete sequence and future UI/API acceptance
tests. Contract C4.1 in docs/maintainer/immutable-job-identity.md records the
decision; the phase-2 foundation documentation links to it.

Verification: 343 existing contract/planner/record/storage tests passed and
git diff --check passed. These tests do not claim that the future assistant
has been implemented. No plugin code, startup activation or release artifact
changed; no new live Unraid/UI/backup test is required for this docs-only delta.
Final source preflight and test-channel publication remain deferred until the
complete #479 integration is ready. This PR remains in draft.

@borg-codex-bot borg-codex-bot changed the title Introduce immutable job IDs across job workflows (#447) Introduce immutable job IDs and guided migration (#447) Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant