Start from the usable outcome
In a fictional funds project, recovering servers is only part of the outcome. The service must obtain files, query data, run the application, and present a reconciled result to the business. Write the measurement start and completion condition before estimating durations. Associate each dependency with an owner, access method, and recent evidence. Include shared components, external services, and people in the map. A common key-service connection can interrupt two stacks in different zones. A replica diagram needs failure scenarios alongside it to explain what independence has actually been demonstrated.
Find the sequence determining elapsed time
This lesson’s original model has ten-minute identity work and fifteen-minute network work in parallel. Database waits for both and takes twenty-five. Middleware takes twelve after identity; application waits for database and middleware and takes twenty. Acceptance needs another ten. Completion is seventy minutes although all tasks sum to ninety-two. Accelerating identity to five does not change completion: network still constrains database start. Reducing database work to fifteen permits sixty under the same assumptions. These are arithmetic results for supplied inputs rather than measurements of an actual recovery environment.
Check that parallel execution is available
A schedule can draw parallel tasks that depend on one authorized person. If identity and network work must be performed by one specialist, they consume twenty-five minutes before database work and completion rises to eighty. The solution may require demonstrated additional coverage or a different window. Adding names to a plan creates neither access nor competence. During rehearsal, record who performed each step and what help was required. An outcome achieved through an off-roster developer does not establish that the intended shift can repeat the procedure independently under its planned coverage.
Estimate backlog recovery
For a twelve-thousand-item queue, one thousand completions per minute appears to imply twelve minutes. That calculation holds only in the model without new arrivals. If eight hundred keep arriving each minute, net capacity is two hundred and draining takes sixty. With twelve hundred completions and unchanged arrivals, it takes thirty. If arrivals equal completions, positive backlog never disappears. Also observe item age and completion quality. Removing a message from a queue without producing its correct outcome should not count as successful business close. Define the completion measure before comparing rates.
Connect capacity to the actual workload
Constant rates help expose calculation errors but do not remove variability. A check using light requests may not represent close, which shares its database with reporting and uses more expensive operations. Compare mix, volume, concurrency, and dependency limits. If policy permits delaying a nonurgent export, that action may free capacity without removing critical reconciliation. Define authority, duration, and monitoring for the mitigation. Do not turn a forecast using fictional inputs into a deadline promise for a system not yet observed under those conditions. Record assumptions beside each calculated estimate.
Execute and discuss the model
Save this lesson’s code as run.py and execute python3 run.py --output evidence.json in a temporary directory. The program checks thirty-two deterministic observations about dependencies, queues, margins, and reconciliation. It opens no ports, uses no credentials, and performs no actual recovery. Read the result and explain why seventy minutes is model completion rather than measured duration. Then prepare a table with assumption, required evidence, owner, and action. The exercise’s output is a reasoned decision about what remains to be demonstrated as well as the automatic results file.
"""Original planning model, not a bank system or recovery benchmark.
Run: python3 run.py --output evidence.json
No network, credentials, live service, human approval, or real elapsed-time claim.
"""
import argparse
import hashlib
import json
import platform
from pathlib import Path
def finish_times(tasks):
pending = dict(tasks)
done = {}
while pending:
ready = [name for name, task in pending.items if all(d in done for d in task['depends'])]
if not ready:
raise ValueError('cycle or missing dependency')
for name in ready:
task = pending.pop(name)
if task['minutes'] < 0:
raise ValueError('negative duration')
done[name] = max((done[d] for d in task['depends']), default=0) + task['minutes']
return done
def drain(backlog, arrivals, completions):
if min(backlog, arrivals, completions) < 0:
raise ValueError('negative workload')
if backlog == 0:
return 0
return backlog / (completions - arrivals) if completions > arrivals else None
def reconciliation(expected, actual):
return {
'missing': sorted(set(expected) - set(actual)),
'unexpected': sorted(set(actual) - set(expected)),
'changed': sorted(k for k in set(expected) & set(actual) if expected[k]!= actual[k]),
}
def run:
checks = []
def check(name, actual, expected):
assert actual == expected, (name, actual, expected)
checks.append(dict(name=name, actual=actual, expected=expected, passed=True))
tasks = {
'identity': {'minutes': 10, 'depends': []},
'network': {'minutes': 15, 'depends': []},
'database': {'minutes': 25, 'depends': ['identity', 'network']},
'middleware': {'minutes': 12, 'depends': ['identity']},
'application': {'minutes': 20, 'depends': ['database', 'middleware']},
'acceptance': {'minutes': 10, 'depends': ['application']},
}
finish = finish_times(tasks)
check('parallel prerequisites', [finish['identity'], finish['network']], [10, 15])
check('database waits for both prerequisites', finish['database'], 40)
check('middleware finishes before database', finish['middleware'], 22)
check('usable service includes acceptance', finish['acceptance'], 70)
check('sixty minute target fails', finish['acceptance'] <= 60, False)
check('seventy five minute target margin', 75 - finish['acceptance'], 5)
faster_identity = {k: dict(v) for k, v in tasks.items}
faster_identity['identity']['minutes'] = 5
check('noncritical acceleration leaves completion unchanged', finish_times(faster_identity)['acceptance'], 70)
faster_database = {k: dict(v) for k, v in tasks.items}
faster_database['database']['minutes'] = 15
check('critical branch acceleration', finish_times(faster_database)['acceptance'], 60)
shared_operator = {k: dict(v) for k, v in tasks.items}
shared_operator['network']['depends'] = ['identity']
check('shared operator serializes prerequisite work', finish_times(shared_operator)['acceptance'], 80)
invalid = {'a': {'minutes': 1, 'depends': ['b']}, 'b': {'minutes': 1, 'depends': ['a']}}
try:
finish_times(invalid)
except ValueError as error:
check('dependency cycle rejected', str(error), 'cycle or missing dependency')
else:
raise AssertionError('cycle accepted')
check('continued arrivals reduce net drain', drain(12000, 800, 1000), 60)
check('no arrivals changes the estimate', drain(12000, 0, 1000), 12)
check('higher demonstrated completion rate', drain(12000, 800, 1200), 30)
check('equal rates never drain positive backlog', drain(12000, 1000, 1000), None)
check('overload never drains positive backlog', drain(12000, 1100, 1000), None)
check('empty backlog needs no drain time', drain(0, 800, 1000), 0)
check('fifteen minutes of overload', (1100 - 1000) * 15, 1500)
check('rollback validation and contingency budget', 35 + 15 + 10, 60)
check('latest rollback start in 150 minute window', 150 - (35 + 15 + 10), 90)
check('five minutes before latest rollback start', 150 - 85 - (35 + 15 + 10), 5)
check('five minutes after latest rollback start', 150 - 95 - (35 + 15 + 10), -5)
check('data recovery point lag', 180 - 168, 12)
check('data point meets fifteen minute RPO', (180 - 168) <= 15, True)
check('backup completion is not data point', 180 - 178 == 180 - 168, False)
expected = {'A': 100, 'B': 200, 'C': 300}
actual = {'A': 100, 'B': 250, 'D': 250}
check('counts agree despite wrong records', len(expected) == len(actual), True)
check('totals agree despite wrong records', sum(expected.values) == sum(actual.values), True)
check('reference reconciliation exposes divergence', reconciliation(expected, actual), {'missing': ['C'], 'unexpected': ['D'], 'changed': ['B']})
check('identical records reconcile', reconciliation(expected, dict(expected)), {'missing': [], 'unexpected': [], 'changed': []})
required = ['runtime', 'functional', 'integrity', 'access', 'dependencies', 'owner']
gates = dict.fromkeys(required, True)
gates['integrity'] = False
check('green runtime cannot override integrity failure', all(gates[k] for k in required), False)
gates['integrity'] = True
check('all fictional evidence criteria met', all(gates[k] for k in required), True)
check('missing criterion fails closed', all(gates.get(k, False) for k in required + ['return_path']), False)
check('critical chain distinct from sum of all tasks', sum(t['minutes'] for t in tasks.values), 92)
return dict(runtime=platform.python_version,scope='Deterministic arithmetic, dependency-graph and record-comparison model with fictional inputs. No measured recovery, bank transaction, network service or human acceptance.',passed=len(checks),checks=checks,runnerSha256=hashlib.sha256(Path(__file__).read_bytes).hexdigest)
if __name__ == '__main__':
parser = argparse.ArgumentParser
parser.add_argument('--output')
args = parser.parse_args
result = json.dumps(run, indent=2) + '\n'
if args.output:
Path(args.output).write_text(result)
else:
print(result, end='')
With 12000 items, 800 arrivals/min, and 1000 completions/min, estimated drain time is 60 minutes; a 40-minute window needs another demonstrated option.
Common pitfalls
Adding everything despite parallelism, accelerating a task without deadline impact, ignoring new arrivals, or assuming two people when only one is available.
Related topics: Services, dependencies, and evidence · Resilience and data recovery · Cloud, costs, and RUN autonomy
A forecast depends on sequence, people, and net capacity; each assumption needs evidence from the relevant environment.
Reference: REL13-BP01 Define recovery objectives for downtime and data loss · BigSavant banking infrastructure professional assessment2026.10