Exercise Answers¶
Use this page after you have written your own answers. The point is comparison, not copying.
How to use the answer page well¶
Do not read a model answer first and then retrofit your exercise around it.
A better rhythm is:
- complete the exercise with your own repository state and commands
- write one plain-language explanation of the boundary you are reviewing
- compare that explanation with the model answer
- revise where the model answer exposes a missing proof route or a blurred policy line
The goal is not identical wording. The goal is disciplined operational reasoning.
The strongest Module 03 answers usually do four things:
- they name the owning operational boundary
- they explain why the current shape is safe or unsafe
- they choose one proportionate proof route
- they describe the repair in terms of repository discipline, not heroics
The strongest self-study packets also leave behind six concrete artifacts:
- a profile comparison table
- one paired dry-run comparison
- one failure-class matrix
- one storage lifecycle sketch
- one proof ladder
- one short maintainer review note
If your packet contains only commands and verdicts, go back and make the reasoning more visible.
Exercise 1: Separate policy from workflow meaning¶
A strong answer sounds like this:
latency-waitandshow-failed-logsbelong in a profile because they change runtime behavior without changing the intended outputs. A sample list and publish version do not belong in a profile because they change target meaning and downstream contract surfaces. If those semantic values moved into a profile, local and CI contexts could appear to be harmless policy differences while actually changing what the workflow means.
Why this is strong:
- it gives two good policy examples and two bad ones
- it explains the review risk, not only the placement rule
Exercise 2: Compare the same target across two profiles¶
A strong comparison keeps targets, semantic config, and publish paths identical. Local may use more cores and shorter latency patience; CI may serialize work, show failed logs, and wait longer for filesystem visibility. The paired dry-runs should resolve the same jobs and dependencies for the same requested target. A line-by-line table prevents a harmless operational difference from concealing semantic drift.
A compact model table might look like this:
| Surface | Local | CI | Safe difference? |
|---|---|---|---|
| target | publish/v1/manifest.json |
publish/v1/manifest.json |
must stay the same |
| cores | 4 | 1 | yes |
| latency wait | 5 | 20 | yes |
| publish root | publish/v1/ |
publish/v1/ |
must stay the same |
Why this is strong:
- it checks the boundary with the same target surface
- it treats profile differences as reviewable lines, not intuition
Exercise 3: Choose the smallest honest proof route¶
A strong answer matches the route to the question:
- planning difference between local and CI:
- compare dry-runs
- visible profile differences for review:
make profile-audit- strongest repository confidence:
make confirm
The strongest answers also explain why the routes are not interchangeable:
confirmis too heavy for a simple planning question- dry-run is too weak for the strongest clean-room claim
- profile-audit is better than intuition for context-comparison review
Exercise 4: Write a small failure policy¶
A strong answer distinguishes failure classes cleanly.
Example answer shape:
- retryable:
- transient infrastructure or storage hiccup
- fail-fast:
- wrong config value or invalid sample contract
- rerun-incomplete:
- partial output left behind after a crashed job
- logs:
- per-job logs help determine whether the failure was transient, semantic, or partial-publication related
A compact model matrix might look like this:
| Failure class | Evidence surface | Response |
|---|---|---|
| transient infrastructure issue | failed log plus external service or storage symptom | bounded retry |
| semantic defect | config value, rule contract, or deterministic traceback | fail fast |
| interrupted output | incomplete file plus interrupted execution evidence | rerun incomplete state deliberately |
Why this is strong:
- it makes retry, fail-fast, and rerun-incomplete different on purpose
- it treats logs as evidence for the decision, not as decoration
Exercise 5: Review one staging or locality assumption¶
A strong answer sounds like this:
The workflow may use a different scratch or staging location on shared infrastructure, but the declared final output paths and publish boundary must stay semantically stable. If the team confuses scratch placement with final output meaning, reviewers can no longer tell which paths are temporary and which are part of the contract.
Why this is strong:
- it allows context variation honestly
- it protects the stable trust surface
Exercise 6: Review one operational diff like a maintainer¶
A strong answer begins with the owning boundary:
- first inspect the changed profile file
- then inspect the changed proof route or target
- ask:
- does this change execution context only, or workflow meaning too
- what claim is stronger or weaker after the proof-route edit
Why this is strong:
- it reviews in boundary order
- it does not let a policy diff drift into vague trust language
Exercise 7: Inject and classify failures¶
The generated summary should read:
SCHEDULER_MAPPING_RECORDED PASS ACCEPT
MISSING_MEMORY_REJECTED PASS REJECT
UNDERPROVISIONING_REJECTED PASS REJECT
SEMANTIC_PROFILE_LEAK_REJECTED PASS REJECT
The correct reasoning is:
| Profile | Invariant | Owner | Response |
|---|---|---|---|
| accepted | declared resources survive translation | profile maintainer | accept local translation |
| missing memory | every required resource reaches request | rule/profile maintainer | restore mem_mb |
| under-provisioned | request is not smaller than declaration | profile maintainer | remove memory_scale: 0.5 |
| semantic leak | profile changes operation, not meaning | workflow owner | move threshold to semantic config |
None of the rejected requests is transient. Repetition does not add a missing field, increase memory, or move a threshold to its proper owner.
The accepted receipt contains "executed": false. Therefore the supported
conclusion is:
The adapter rendered an acceptable Slurm request from the declared resources.
The unsupported conclusion is:
Slurm accepted and ran the job.
PASS and ACCEPT answer different questions. PASS says the audit observed its expected condition. ACCEPT says the profile is suitable for the bounded local translation claim.
Exercise 8: Design a staging route¶
A strong route has these transitions:
- submit the accepted resource request;
- capture the scheduler job ID;
- allocate job-specific scratch;
- prove
data/records.tsvis readable from the worker; - compute a temporary result in scratch;
- validate header, row membership, and threshold behavior;
- atomically publish to
results/summary.tsv; - verify the published result from the orchestrator;
- remove job-specific scratch.
Evidence should include:
| Transition | Evidence |
|---|---|
| request to allocation | submission receipt and job ID |
| allocation to readable input | worker path probe or staging log |
| execution | command log and exit status |
| validation | semantic assertions |
| publication | atomic rename record and checksum |
| downstream trust | Snakemake sees the declared final path |
On failure, preserve the worker log and scheduler state. Remove only the current job's temporary output. Never rename an unvalidated scratch artifact into the final path.
The diagram is not complete unless it marks where trust starts. A reviewer should be able to point to one step and say, "before this, execution state is provisional; after this, the declared output may be trusted."
Exercise 9: Prove a clean-room run¶
Two representative mutation tests are:
test_missing_memory_case_must_remove_memoryedits the profile so it no longer removesmem_mb. The adapter accepts it, makingadapter_rejected=false; the audit exits nonzero because the promised rejection is no longer demonstrated.test_semantic_leak_case_must_change_workflow_meaningremoves the semantic override. Again, acceptance is correct, so the rejection finding must fail.
The suite also creates:
and reruns the audit. The file must disappear because the audit removes its workspace before collecting new evidence. Otherwise an old rejection could be mistaken for the current run.
Static fixture comparison would show only that checked-in files have expected text. Mutation proves that the decision changes when its cause changes.
Exercise 10: Review a production policy change¶
One defensible review is:
| Change | Decision | Reason and required proof |
|---|---|---|
| threads 4 to 8 | needs evidence | update declaration and show adapter preserves 8 |
| memory 8,000 to 6,000 in adapter | reject | request under-provisions declared need |
| threshold 10 to 30 in profile | reject | semantic field belongs in workflow config |
| latency 30 to 90 | needs evidence | show delayed visibility rather than another failure |
| retries 0 to 3 globally | reject | no eligible transient class or stop condition |
| shared to node-local scratch | needs evidence | prove staging, cleanup, and unchanged final path |
The replacement retry policy might be:
Eligible: transient object-store timeout only
Attempts: two retries
Backoff: 30 seconds, then 120 seconds
Preserve: job ID, attempt log, exit status
Stop: repeated identical exit status or any validation failure
Publish: only after semantic validation
The final contract remains:
Local evidence can approve deterministic translation and reject boundary leaks. It cannot approve the node-local scratch change for a real site. That decision needs a scheduler job ID, worker path evidence, publication evidence, and output verification.
A strong review also shows a stable order:
- inspect the changed profile keys
- classify each line as capacity, visibility, recovery, storage, or semantics
- reject any semantic leak before debating convenience
- run the scheduler-policy audit for local translation
- require site integration only for claims that cross the scheduler boundary
What all ten answers should have in common¶
flowchart TD
E["generated evidence"] --> C{"contract preserved?"}
C -->|"no"| R["REJECT and name repair owner"]
C -->|"yes"| X{"scheduler contacted?"}
X -->|"no"| L["ACCEPT local translation only"]
X -->|"yes"| S["inspect job, worker, and output evidence"]
flowchart LR
D["declaration"] --> T["translation"]
T --> J["scheduler acceptance"]
J --> W["worker execution"]
W --> P["verified publication"]
The best Module 03 answers usually:
- distinguish policy from semantics clearly
- explain recovery as a contract rather than a habit
- treat proof routes as proportionate tools instead of ritual commands
- describe operational governance as something the repository should teach
Weak answer pattern:
- "production is complicated, so more retries and more confirmation should be fine"
That sentence hides every boundary the module is trying to teach. If your answers still sound like that, keep revising.
If your answers do those four things, the module is landing in the right way.