I made an independent example of processing one folder before advancing to another. It actually copies small synthetic files and moves only the current working copy after receiving a declared completion receipt. It performs no external upload or publication, letting readers examine the relationship between retained files and advancement state.

Separate originals, pending copies and completed copies

The caller supplies an absolute workspace containing source, pending and done. Preparation reads file fingerprints and copies selected source folders into pending. Completion never moves or edits the original source. Input material, working copies and completed copies have distinct roles.

Names are restricted identifiers, with checks rejecting links and reparse entries. This still does not create a hostile-filesystem sandbox or eliminate every concurrent path race. The example assumes an owned trusted workspace with one writer. No customer files or authentication material are included in the public package.

Reject insufficient material instead of duplicating it

Preparation validates the full provided list, uniqueness, requested count and file fingerprints before copying. An omitted count means the whole list; an explicit count selects its prefix. A request exceeding the available items fails before copies are created, without duplicating a folder to meet the number.

The example uses deliberately small bounds: one hundred items, fifty files per folder and one MiB per file. These are not the original runtime limits. Large-media processing and platform execution are absent. The narrow limits make ordering and stop conditions inspectable using small synthetic material.

Only the current declared result opens the next item

Completion requires the current folder name and a strictly shaped receipt declaring verification. Attempting to finish the second folder first is rejected. An unresolved result puts the batch into review-needed and prevents advancement. There is no detector that searches a website for a reassuring success string.

The receipt is the caller's declaration, not remote success verified by this module. Its execution flag always remains false. A real integration needs an adapter that checks service outcomes before producing that declaration. A field called verified cannot itself prove upload or publication; this example shows only how completion evidence is consumed.

Explore the implementation

Complete independent synthetic implementation

"""Owned-directory synthetic folder copies; advancement needs a declared receipt."""
from pathlib import Path
import hashlib,os,re,shutil

class LoopError(ValueError):pass

def _linked(path):
    return path.is_symlink() or bool(getattr(path.lstat(),'st_file_attributes',0)&0x400)

class FolderLoop:
    MAX_FILES=50
    MAX_BYTES=1024*1024
    def __init__(self,root):
        raw=Path(root)
        if not raw.is_absolute():raise LoopError('ABSOLUTE_ROOT_REQUIRED')
        self.root=raw.resolve();self.root.mkdir(parents=True,exist_ok=True)
        self.source=self.root/'source';self.pending=self.root/'pending';self.done=self.root/'done'
        for folder in [self.source,self.pending,self.done]:
            if folder.exists() and _linked(folder):raise LoopError('LINK_DENIED')
            if not folder.resolve().is_relative_to(self.root):raise LoopError('OUTSIDE_WORKSPACE')
            folder.mkdir(exist_ok=True)
        self.items=[];self.index=0;self.state='new'

    def _child(self,parent,name):
        if not isinstance(name,str) or not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9_-]{0,79}',name):raise LoopError('INVALID_NAME')
        if _linked(parent) or not parent.resolve().is_relative_to(self.root):raise LoopError('OUTSIDE_WORKSPACE')
        path=parent/name
        if path.exists() and _linked(path):raise LoopError('LINK_DENIED')
        if not path.resolve().is_relative_to(parent.resolve()):raise LoopError('OUTSIDE_WORKSPACE')
        return path

    def _snapshot(self,folder):
        if not folder.is_dir() or _linked(folder):raise LoopError('SOURCE_FOLDER_REQUIRED')
        result={}
        for directory,names,files in os.walk(folder,topdown=True,followlinks=False):
            for name in names:
                if _linked(Path(directory)/name):raise LoopError('LINK_DENIED')
            for name in files:
                path=Path(directory)/name
                if _linked(path) or not path.is_file():raise LoopError('REGULAR_FILE_REQUIRED')
                with path.open('rb') as stream:data=stream.read(self.MAX_BYTES+1)
                if len(data)>self.MAX_BYTES:raise LoopError('FILE_TOO_LARGE')
                result[path.relative_to(folder).as_posix()]=hashlib.sha256(data).hexdigest()
                if len(result)>self.MAX_FILES:raise LoopError('TOO_MANY_FILES')
        if not result:raise LoopError('EMPTY_SOURCE')
        return dict(sorted(result.items()))

    def prepare(self,names,count=None):
        if self.state!='new':raise LoopError('ALREADY_PREPARED')
        if type(names) is not list or not 1<=len(names)<=100:raise LoopError('INVALID_ITEMS')
        for name in names:self._child(self.source,name)
        if len(set(names))!=len(names):raise LoopError('DUPLICATE_ITEM')
        if count is None:count=len(names)
        if type(count) is not int or not 1<=count<=100:raise LoopError('INVALID_COUNT')
        if count>len(names):raise LoopError('INSUFFICIENT_ITEMS')
        snapshots={name:self._snapshot(self._child(self.source,name)) for name in names}
        selected=names[:count]
        for name in selected:
            if self._child(self.pending,name).exists() or self._child(self.done,name).exists():raise LoopError('COPY_COLLISION')
        try:
            for name in selected:
                destination=self._child(self.pending,name)
                shutil.copytree(self._child(self.source,name),destination)
                if self._snapshot(destination)!=snapshots[name]:raise LoopError('COPY_CHANGED')
                self.items.append({'name':name,'snapshot':snapshots[name],'status':'queued','receipt':None})
        except Exception:
            self.state='needs_review';raise
        self.state='ready'
        return self.current()

    def current(self):
        item=self.items[self.index] if self.index<len(self.items) else None
        return {'state':self.state,'name':item['name'] if item else None,'completed':self.index,'total':len(self.items),'executed_here':False}

    def complete(self,name,receipt):
        if self.state!='ready':raise LoopError('BATCH_NOT_READY')
        if name!=self.items[self.index]['name']:raise LoopError('OUT_OF_ORDER')
        if type(receipt) is not dict or set(receipt)!={'verified','receipt'} or receipt['verified'] is not True or not isinstance(receipt['receipt'],str) or not receipt['receipt'].strip() or len(receipt['receipt'])>120:
            self.state='needs_review';raise LoopError('UNVERIFIED_RESULT')
        item=self.items[self.index]
        try:
            source=self._child(self.pending,name);target=self._child(self.done,name)
            if target.exists():raise LoopError('DONE_COLLISION')
            if self._snapshot(source)!=item['snapshot']:raise LoopError('WORK_COPY_CHANGED')
            # Both resolved endpoints are checked within this owned workspace
            # before moving a directory; original source folders never move.
            if not source.resolve().is_relative_to(self.pending.resolve()) or not target.resolve().is_relative_to(self.done.resolve()):raise LoopError('OUTSIDE_WORKSPACE')
            os.replace(source,target)
        except Exception:
            self.state='needs_review';raise
        item.update(status='done',receipt=receipt['receipt']);self.index+=1
        if self.index==len(self.items):self.state='completed'
        return self.current()

    def stop(self):
        if self.state=='ready':self.state='stopped'
        return self.current()

Recheck the working copy and resolved move endpoints

Before completion, pending file fingerprints must still match preparation. Changed bytes or an existing done destination stop the batch instead of overwriting earlier material. Before the directory move, both resolved endpoints are checked within the owned pending and done locations. The source location is never the move target.

A copying failure can leave inert partial copies for review, and a move failure does not open the next item. There is no atomic whole-batch copy or automatic rollback guarantee. Retaining material for diagnosis and completing recovery are different results; neither should be inferred simply because an exception was handled.

Share twenty-four tests and five generated folder records

Tests check original-byte preservation, counts, ordering, unresolved results, changed copies and destination collisions. Injecting a move failure must retain source and pending material and stop advancement. Editing a returned state view must not change internal progress.

The same twenty-four tests run after ZIP extraction. The viewer reads five records generated through actual synthetic local folders. Both language selectors use DOM-stub checks, without running a rendered browser or the original scheduler. These checks establish neither successful platform uploading nor exactly-once remote execution.

A read-only viewer of synthetic local records

Connect durable records and actual verification separately

Full implementation, tests, examples, record generation and README permit modification and reuse. Scratch material is created beside the package and cleaned afterward. Batch progress remains in memory; restarting does not safely reconstruct interrupted business work. Retained folders are not permission to replay it.

Real operations need durable records, present authorization, service reconciliation, cancellation and timing conditions. The original browser has separate execution and submission journals. I share this component to examine preservation and advancement rules rather than call it production automation. Making the basis of trusted completion explicit is the starting point for reuse.

Download code, tests and records
Python standard library, synthetic data, modification and reuse permitted