Skip to content

Add local --back step for the workshop engine - #21

Merged
Pierre Malarme (pmalarme) merged 3 commits into
mainfrom
pmalarme-workshop-step-revert
Jul 16, 2026
Merged

Add local --back step for the workshop engine#21
Pierre Malarme (pmalarme) merged 3 commits into
mainfrom
pmalarme-workshop-step-revert

Conversation

@pmalarme

Copy link
Copy Markdown
Collaborator

What & why

Local learners who advance through the workshop without committing each step had no built-in way to move back a step. This adds a first-class --back command to the local step engine, plus supporting docs, a make back alias, and a CI pipeline.

Changes

New advance_step.py --back

  • Restores the learner's saved work from the previous step's snapshot when present, otherwise rebuilds the canonical step files with a clear warning.
  • Current work is always backed up first (workshop_backups/back-<timestamp>/); errors at step 0.

Namespaced backup layout (format v2) — addresses two deferred review findings:

workshop_backups/step-<N>/
  travel_assistant/   # agent snapshot
  _root/              # repo-root overlay targets
  backup.json         # completion manifest, written last
  • Add MIT License to the project #1 root-name collision is now structurally impossible — restore is by namespace, not by matching names, so a learner dir inside travel_assistant/ named after a root overlay target round-trips correctly.
  • Create SECURITY.md for security reporting #3 stale merged backups_snapshot_current_step publishes atomically (stage → copy → manifest → swap) and fully replaces any prior step-<N>/ snapshot, so files deleted on a revisit are never resurrected. The old snapshot is only removed once the replacement is complete (no destructive gap).

Hardening (from the rubber-duck review)

  • --back restore is gated on a valid completion manifest; legacy flattened / partial-write backups degrade gracefully to a canonical rebuild.
  • _root overlay targets that would shadow protected repo paths (travel_assistant, README.md, .workshop, .workshop_instance, .git) are rejected up front.
  • reset/back/step backup dirs are reserved via exclusive mkdir with a -N suffix, so two backups within the same UTC second never merge.

Docs & tooling

  • README: documents --back and adds the make back alias.
  • New back-workshop.yml CI pipeline.

Validation

Local learners who advance without committing each step had no way to
move back. Add `advance_step.py --back` (plus a `make back` alias, README
docs, and a `back-workshop.yml` CI pipeline) that restores the learner's
saved work from the previous step's snapshot, or rebuilds the canonical
step files when no snapshot exists.

Namespace the backup layout so the agent snapshot and repo-root overlay
targets never collide: `step-<N>/travel_assistant/`, `step-<N>/_root/`,
and a `backup.json` completion manifest written last. This makes root-name
collisions structurally impossible (#1) and lets `--back` restore
structurally rather than by name. Snapshots are now published atomically
(stage -> copy -> manifest -> swap) and fully replace any prior snapshot,
so files deleted on a revisit are never resurrected (#3).

Also: gate `--back` restore on a valid manifest (legacy/partial backups
degrade to a canonical rebuild with a clear warning), reject `_root`
overlay targets that shadow protected repo paths, and make reset/back/step
backup dirs unique within the same second.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fea011c8-1399-4f8a-a3bd-277408cae6c2
Comment on lines +1028 to +1029
"Would back up travel_assistant/ (and workshop root files) to "
".workshop_instance/workshop_backups/back-<timestamp>/.",
Resolve conflicts between the local --back feature and main's
reset-current / sync-template additions:

- advance_step.py: keep both _back/_plan_back (this branch) and
  _relay_current/_plan_relay_current (main) as sibling functions; wire
  both --back and --reset-current into main(). Align main's reset-current
  backup with this branch's namespaced backup layout and _reserve_backup_dir
  uniqueness (reset-current-<NN>-<timestamp>, deduped within the same second).
- Makefile / 00-intro.md / _push_to_advance.md: keep all local-flow
  commands (advance, back, reset, reset-current, preflight, sync-template).
- test_advance_step.py: keep both test suites; update main's reset-current
  backup assertion to the namespaced travel_assistant/ path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fea011c8-1399-4f8a-a3bd-277408cae6c2
Address rubber-duck findings on the local --back backup engine:

- Atomic publish: snapshot now renames the prior step-<N>/ aside, swaps the
  new snapshot in, and only deletes the old copy once the swap succeeds, with
  rollback on failure and staging cleanup on every failure path — so a mid-swap
  crash never leaves a step without a valid backup (#1).
- Always capture the travel_assistant/ namespace, even a lone .gitkeep, so a
  root-only snapshot restores the placeholder instead of an empty dir (#2).
- Protect repo machinery: _root overlay targets that resolve to MACHINERY_PATHS
  or .git are rejected up front, compared casefolded so case variants can't slip
  past on case-insensitive filesystems (#3).
- Exact restore: clear each destination before copying so an undeclared stale
  target (e.g. left after a template sync) is replaced, not merged (#4).
- Validate the backup manifest step is an integer before trusting it (#5).

Add regression tests for each fix.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fea011c8-1399-4f8a-a3bd-277408cae6c2
@pmalarme
Pierre Malarme (pmalarme) merged commit 5f18104 into main Jul 16, 2026
8 checks passed
@pmalarme
Pierre Malarme (pmalarme) deleted the pmalarme-workshop-step-revert branch July 16, 2026 11:36
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