Build an Architecture Decision Log

Create a local ADR log with evidence, validation runs, and Git history.

Introduction

30 Second Summary

A handover can look complete until someone asks why a choice was made. Months later, that unexplained setting can force an expensive guess.

In this project, you will turn supplied workload evidence into a local decision log that separates proved choices from unanswered questions. Four retained checker runs will make the final coverage result auditable.

What You'll Build

Open the finished handover to show a product manager the evidence status of every discovered choice.

By the end of this project, you'll have:

  • A Git-backed evidence trail that proves inventory.md existed before every Architecture Decision Record.
  • A five-record decision history that preserves the Amazon Linux 2 image choice beside its evidence-backed replacement after the June 30, 2026 support deadline.
  • A Python coverage readout with four retained runs ending at COVERAGE OF DECISIONS FOUND: 4 of 9.
  • Secret Mission: Audit the only AI-generated HTML draft into a tagged final commit with preserved first-draft U/T plus zero shipped untraceable claims.

Are there any prerequisites?

Python 3.11 or newer, Git, your existing editor, and your existing AI client must already be available. The supplied Terraform file remains read-only throughout the project. Everything stays local with no new accounts or package installs.

Before We Start

Before any hands-on work, lock in the 45-minute contract and confirm the required prerequisites: Python 3.11 or newer, Git, an editor, read-only Terraform capability, Mermaid, and an existing AI client. The contract reserves at least 20 minutes for building, keeps the scope unchanged after failed checks, and protects the coverage denominator by requiring every decision to be found during reading.

Initialize the Local Repository

A durable decision log needs evidence that its local toolchain existed before the build began. V1 preserves that baseline inside the same Git repository as the later decisions.

This step verifies Python 3.11 or newer plus your Git identity before any project evidence is created. Missing prerequisites therefore cannot shrink the timed scope after a failure.

In this step, get ready to:
  • Create the local repository in your existing editor.
  • Capture the V1 setup evidence.
  • Commit T01 with only the first task checked.
Establish the local baseline

V1 records the tools that were already available when your timed work began. Each command runs separately so its output remains distinct evidence.

  • Record your existing editor name here: your existing editor name.
  • Record your existing AI client name here: your existing AI client name.
  • Open your operating system's application search.
  • Start your existing editor name from the search results.
  • Use your editor's folder workflow to select the Desktop.
  • Create a folder named architecture-decision-log on the Desktop.
  • Keep architecture-decision-log open in your editor.

Why keep the repository local?

Every artifact in this project stays inside architecture-decision-log. This baseline uses no remote repository or new account.

Terraform remains read only throughout the project. Your AI client also remains unused until close-out.

  • Open your editor's integrated terminal for architecture-decision-log.
  • Check the installed Python version by running this command:
python3 --version

What should you see?

The command prints the installed Python version. Confirm that it reports 3.11 or newer.

🙋‍♀️ No Python version returned?

A missing value means the timed prerequisite is unavailable.

  • Stop the current timed run.
  • Prepare the required python3 command before starting again.
  • Restart the full scope without reducing the 20-minute build floor.
  • Check the installed Git version by running this command:
git --version

What does this confirm?

The output confirms that the Git command-line tool is available. Keep this version line visible for V1.

🙋‍♀️ No Git version returned?

The repository cannot provide commit evidence until Git is available.

  • Stop the current timed run.
  • Prepare Git before beginning a new timed run.
  • Keep the original project scope unchanged.
  • Read the existing Git commit name by running this command:
git config --get user.name

What does this value represent?

The returned user.name value is the name attached to local commits. Preserve the displayed value as execution evidence.

  • Read the existing Git commit email by running this command:
git config --get user.email

What does this value represent?

The returned user.email value completes the local commit identity. Preserve the displayed value as execution evidence.

🙋‍♀️ Is an identity value missing?

Both identity values must have existed before timing began.

  • Stop the current timed run if either command returns no value.
  • Prepare the missing Git identity before beginning again.
  • Restart with the full project scope.
  • Initialize the local repository by running this command:
git init

What does this command create?

The command initializes Git metadata inside architecture-decision-log. The repository remains local because no remote is configured.

🙋‍♀️ Could Git initialize the folder?

Initialization needs permission to write inside the Desktop folder.

  • Confirm that the terminal is attached to architecture-decision-log.
  • Confirm that your operating system allows the editor to write to the Desktop.
  • Run the initialization command again after correcting the folder access.

That baseline is now real. You have a local repository with every prerequisite result still visible in the terminal.

Capture V1 setup evidence

The task plan ties each project milestone to a commit. Its initial state proves that T01 is complete while every later task remains open.

  • Create TASKS.md inside architecture-decision-log with your editor's file-creation control.
  • Copy the following task plan into TASKS.md:
# Tasks
Done means every item is checked by its commit, V1 to V6 carry EVIDENCE or owed, check-out.txt has four runs with exits, and backlog.md is written.
- [x] T01 Setup and V1.
- [ ] T02 Copy workload and five design files.
- [ ] T03 Commit inventory first.
- [ ] T04 Copy checker.
- [ ] T05 Run 1, V3, five added lines.
- [ ] T06 ADR-0001.
- [ ] T07 ADR-0002.
- [ ] T08 ADR-0003.
- [ ] T09 ADR-0004.
- [ ] T10 ADR-0005 and supersession.
- [ ] T11 Backlog every uncovered line.
- [ ] T12 Run 2 and V4 exit 1.
- [ ] T13 Run 3 and V5 exit 1.
- [ ] T14 Run 4 exit 0.
- [ ] T15 V2 Git proof.
- [ ] T16 V6, first-draft U/T, shipped zero.
- [ ] T17 Final tag-ready commit.

How does the task plan preserve evidence?

  • The opening definition connects completed tasks to their commits.
  • T01 is the only checked item because this step creates its evidence.
  • T02 through T17 remain open for later commits.
  • Save TASKS.md.
  • Confirm that T01 is the only checked task.
  • Confirm that T02 through T17 remain unchecked.

Does the task state differ?

  • Compare every task number with the supplied plan.
  • Restore the checked marker on T01.
  • Restore unchecked markers on T02 through T17.

The validation log keeps actual command results beside the files they support. Raw values prevent later summaries from turning assumptions into evidence.

  • Create check-out.txt inside architecture-decision-log with your editor's file-creation control.
  • Enter V1 SETUP EVIDENCE as the heading.
  • Return to the integrated terminal.
  • Select the output lines produced by the four prerequisite commands.
  • Copy the selected output.
  • Paste the output beneath the V1 heading.

What belongs in V1?

V1 retains the actual Python version plus the actual Git version. It also retains the existing user.name value plus the existing user.email value.

The two vendor-neutral tool names document your environment without prompting the AI client.

  • Add a line naming your editor as your existing editor name.
  • Add a separate line naming your AI client as your existing AI client name.
  • Save check-out.txt.
  • Confirm that V1 SETUP EVIDENCE remains the heading.
  • Confirm that all four actual command outputs remain unchanged.
  • Confirm that both existing tool names are present.

✔️ Awesome, I've got everything!

Your task plan contains only the completed T01 marker. Your V1 log retains the four command outputs plus both existing tool names.

ⓧ I'd like to double check the full code

Compare TASKS.md with this complete file. Every later task must remain unchecked.

# Tasks
Done means every item is checked by its commit, V1 to V6 carry EVIDENCE or owed, check-out.txt has four runs with exits, and backlog.md is written.
- [x] T01 Setup and V1.
- [ ] T02 Copy workload and five design files.
- [ ] T03 Commit inventory first.
- [ ] T04 Copy checker.
- [ ] T05 Run 1, V3, five added lines.
- [ ] T06 ADR-0001.
- [ ] T07 ADR-0002.
- [ ] T08 ADR-0003.
- [ ] T09 ADR-0004.
- [ ] T10 ADR-0005 and supersession.
- [ ] T11 Backlog every uncovered line.
- [ ] T12 Run 2 and V4 exit 1.
- [ ] T13 Run 3 and V5 exit 1.
- [ ] T14 Run 4 exit 0.
- [ ] T15 V2 Git proof.
- [ ] T16 V6, first-draft U/T, shipped zero.
- [ ] T17 Final tag-ready commit.

What should match?

The checked state must match exactly. T01 is complete while T02 through T17 remain available for their own evidence commits.

  • Confirm that check-out.txt begins with V1 SETUP EVIDENCE.
  • Confirm that the Python version output is the value produced on your machine.
  • Confirm that the Git version output is the value produced on your machine.
  • Confirm that the Git name output is the value produced on your machine.
  • Confirm that the Git email output is the value produced on your machine.
  • Confirm that your existing editor name is present.
  • Confirm that your existing AI client name is present.
Commit T01 and V1

A commit freezes the setup evidence before workload files or decision records exist. This ordering gives later Git history a trustworthy starting point.

  • Stage the task plan plus the V1 log by running this command:
git add TASKS.md check-out.txt

What does this command stage?

The command stages only TASKS.md plus check-out.txt. These two files form the T01 evidence package.

Before you commit, what do you expect Git to record from the two staged files?

  • Create the T01 evidence commit by running this command:
git commit -m "T01 initialize local project and capture V1"

What does the commit prove?

The command records the checked T01 task plus the V1 setup evidence in local history. Its message identifies the exact milestone captured by the commit.

🙋‍♀️ Was the commit rejected?

A missing identity value can prevent Git from creating the commit.

  • Confirm that both identity commands returned values earlier in this step.
  • Stop the timed run if either value was missing before timing.
  • Prepare the missing prerequisite before a new full-scope run.

You should see Git report a new commit with the message T01 initialize local project and capture V1. This confirms that T01 plus V1 are preserved before any workload or ADR exists.

Your setup evidence is now committed at the start of the repository history. Next, you will copy the supplied evidence before any decision record is created.

Copy the Evidence Baseline

Your local Git repository now preserves the setup evidence from V1. The next safeguard is a reading baseline that exists before any decision records.

V2 eventually uses commit history to prove that the inventory came first. This order prevents later records from quietly changing the coverage denominator.

In this step, get ready to:
  • Copy the two supplied workload evidence files.
  • Copy the five supplied design documents without changing them.
  • Commit the initial inventory before creating any ADR files.
Copy the workload evidence

The workload files are the only sources that describe the existing orders service. Every initial inventory row points back to a specific line in these files.

The supplied Terraform file is read-only evidence. You will copy its declared values without running or applying it.

  • Create a folder named workload inside the open architecture-decision-log directory using your editor's file sidebar.
  • Create note.md inside the workload folder using your editor's new-file control.
  • Copy the supplied workload note into workload/note.md using this exact content:
The orders service runs on EC2 virtual machines behind a load balancer.
TLS, the encryption on web traffic, ends there, so traffic on to the machines is plain HTTP.
Orders sit in a managed PostgreSQL database reachable only from inside the network.
Everything runs in the us-east-1 region.

What evidence does this note contain?

  • Line 1 records the deployment topology behind a load balancer.
  • Line 2 records the TLS termination boundary.
  • Line 3 records the managed PostgreSQL choice.
  • Line 4 records the AWS region.
  • Save workload/note.md.
  • Confirm that your editor shows four lines in workload/note.md.

Does the workload note differ?

Check for wrapped lines that became extra paragraphs. The saved file must contain exactly four evidence lines.

Use the supplied block again if any wording changed. Help me compare my workload note with the four supplied evidence lines.

  • Create main.tf inside the workload folder using your editor's new-file control.
  • Copy the supplied evidence fixture into workload/main.tf using this exact content:
# Evidence fixture only. Read this Terraform language excerpt; do not apply it.
locals {
  instance = {
    image         = "Amazon Linux 2"
    instance_type = "t3.small"
  }
  database = {
    engine                  = "postgres"
    engine_version          = "16.4"
    backup_retention_period = 7
    multi_az                = false
  }
}

What does this fixture contribute?

  • The instance object exposes the image family and instance size.
  • The database object exposes the engine, version, backup retention period, and Multi-AZ setting.
  • The opening comment keeps this file inside the evidence boundary. The project reads the configuration without applying infrastructure.
  • Save workload/main.tf.
  • Confirm that your editor lists note.md and main.tf inside the workload folder.

Is the Terraform fixture incomplete?

Confirm that both object blocks close with matching braces. Check that the opening evidence comment remains the first line.

Do not run the file to test it. Help me compare my Terraform evidence fixture with the supplied content.

Copy the supplied design documents

The design pack defines the project rules before the checker or records exist. Copying it unchanged keeps the acceptance criteria separate from anything discovered during execution.

  • Create a folder named docs inside the open architecture-decision-log directory using your editor's file sidebar.
  • Create requirements-brief.md inside the docs folder using your editor's new-file control.
  • Copy the first part of the requirements brief into docs/requirements-brief.md using this exact content:
# Requirements Brief

## Product Manager Request
Return one local Git decision log from workload/note.md and workload/main.tf. Read Terraform but never run it. Use Python 3.11 or newer and Git, install nothing from an index, keep four checker runs and six validations, and use no remote, new account, or AI before close-out.

## Terms Up Front
EC2 is AWS virtual-machine compute. TLS encrypts network traffic. multi_az says whether the database has a standby in another Availability Zone. MADR is Markdown Architectural Decision Records. Terraform is the infrastructure configuration language whose supplied file is evidence only. PEPFAR is the US President's Emergency Plan for AIDS Relief.

Terms encountered next, in learner order: ADR means Architecture Decision Record; standard library means modules shipped with Python; Git identity is the commit name and email; coverage denominator is the count below the fraction; source trace is a supporting file or pasted result; supersession is replacement without deleting history; backlog is found decisions without records; local tag is a Git name on a local commit; H2 is a Markdown heading with two number signs; POSIX is a Unix-like command environment; Git Bash is Git for Windows' Unix-like shell; Linux subsystem means Windows Subsystem for Linux; self-contained HTML is one browser file with no fetched assets.

## Six Validations
1. V1: setup and identity output.
2. V2: Git history proves inventory.md preceded every ADR.
3. V3: run 1 lists six settings and five added keys.
4. V4: run 2 exits 1 and names the missing Consequences heading.
5. V5: run 3 exits 1 and names the one-way supersession link.
6. V6: run 4 exits 0 and the written cohort audit labels every item EVIDENCE or owed while preserving first-draft U/T.

What does this part define?

This section fixes the local-only boundary. It also defines the six validations that connect repository evidence to acceptance.

  • Append the remaining sections directly below the V6 line in docs/requirements-brief.md using this exact content:

## Acceptance Criteria
TASKS.md is completed by commits and HEAD is tagged decision-log-complete. check-out.txt has four runs with exits. Five ADRs have five headings. Drivers are RECORDED with a source or NOT RECORDED with a question. Final output is COVERAGE OF DECISIONS FOUND: 4 of 9. Five scan-added lines remain inventoried and every uncovered line remains backlogged. readout.html is self-contained and ships with zero untraceable claims after preserving first-draft U/T.

## What This Leaves Undone and the Trade
| Left undone | Traded for |
| --- | --- |
| Index, search, site | Zero install, account, and publishing overhead |
| Recovery of unwritten rationale | Questions instead of invented facts |
| ADR quality grading | A short checker |
| One-decision-per-record enforcement | No larger parser |
| Comparable learner denominators | Genuine discovery |
| Migration execution, tests, rollout, cost | No AWS risk |
| Remote collaboration | No code-host account |

## Measurement Rule
The metric is COVERAGE OF DECISIONS FOUND. Its denominator does not claim every workload decision was discovered.

Why preserve the measurement wording?

The acceptance criteria name the exact evidence required at close-out. The measurement rule limits the denominator to decisions found in the supplied workload sources.

  • Save docs/requirements-brief.md.
  • Confirm that the file ends with the Measurement Rule section.

Is the brief missing a section?

Check that the second block begins immediately after the V6 line. Confirm that the trade table contains seven rows.

Use the full-code check near the end of this step to compare the complete file. Help me locate a missing section in the supplied requirements brief.

  • Create decisions.md inside the docs folder using your editor's new-file control.
  • Copy the supplied project design decisions into docs/decisions.md using this exact content:
# Project Design Decisions

## Handover Frame
The dated trigger is Amazon Linux 2 ending support on June 30, 2026. CNN reported on July 10, 2026 that 120 CDC HIV/AIDS awards were set to expire in September, programs served more than 8.7 million patients, and no concrete replacement system was in place. The readout repeats this as CNN reporting and does not connect the orders service to PEPFAR.

## Record 1: Use Plain Markdown and One Short Checker
Choice: Plain Markdown plus one Python standard-library checker; no generator or site.
Alternative beaten: Log4brains, whose README requires Node.js plus NPM or Yarn and whose default develop branch shows no commit after December 17, 2024; and adr-tools, whose master branch shows no commit after March 30, 2020 and whose Windows instructions use Git Bash or the Linux subsystem rather than native PowerShell.
Cost: No rendered index, search, or navigation.
Reversal trigger: A maintained, install-free publisher works across macOS, Windows, and Linux.

## Record 2: Measure Coverage Against Decisions Found
Choice: Measure and name coverage against decisions the learner found.
Alternative beaten: A fixed inline list, which deletes discovery.
Cost: Learner results are not directly comparable.
Reversal trigger: The project becomes graded across learners.

## Record 3: Reserve One AI Use for Close-Out
Choice: Use AI once at close-out and score its first draft as U/T, where U is untraceable material claims and T is total material claims.
Alternative beaten: AI drafting record context and consequences, whose value is the learner thinking them through.
Cost: Five records rather than six.
Reversal trigger: Fix the design documents, never the build with a drafting prompt.

What choices does this document fix?

  • Record 1 selects plain Markdown with one standard-library checker.
  • Record 2 measures coverage against decisions found.
  • Record 3 reserves the only AI use for close-out.
  • The handover frame keeps the Amazon Linux dates and CNN reporting in their documented context.
  • Save docs/decisions.md.
  • Confirm that your editor shows the handover frame followed by three records.

Did any design wording change?

Confirm that the CNN figures remain attributed to CNN. Check that the workload is never presented as part of PEPFAR.

Replace any edited wording with the supplied text. Help me compare the design decisions without strengthening their claims.

  • Create topology.md inside the docs folder using your editor's new-file control.
  • Copy the supplied topology into docs/topology.md using this exact content:
# Decision Log Topology
```mermaid
flowchart LR
 T[TASKS] --> W[Workload] --> I[Inventory first] --> S[Run 1]
 S --> R[Five ADRs] --> B[Backlog] --> F[Runs 2 and 3 fail]
 F --> P[Run 4 passes] --> G[Git proof] --> A[Written V6]
 A --> H[HTML] --> L[Local tag]
```

What does the topology preserve?

The Mermaid flowchart places inventory before Run 1 and every ADR. It also places the final pass before Git proof, V6, HTML, and the local tag.

  • Save docs/topology.md.
  • Confirm that the diagram source begins with flowchart LR and ends at Local tag.

Is the topology block broken?

Confirm that the opening and closing code fences each contain three backticks. Check that all four flow lines remain inside those fences.

Use the supplied block again if an edge is missing. Help me compare my Mermaid topology with the supplied flow.

  • Create build-plan.md inside the docs folder using your editor's new-file control.
  • Copy the supplied build plan into docs/build-plan.md using this exact content:
# Build Plan
| Phase | Minutes | Opening reminder |
| --- | ---: | --- |
| Setup | 4 | Verify existing tools; install nothing |
| Design | 11 | Copy two workload and five design files; write none |
| Build | 20 | Checker 8, records 9, scan and backlog 3; inventory remains first |
| Validation | 6 | Keep four runs with exits and write V6 |
| Close-out | 4 | Use the only AI prompt, preserve U/T, strike unsupported claims, tag HEAD |
| Total | 45 | Setup is included and failures do not reduce scope |

The readout reports measured minutes beside these values. Measurements and match are owed until run. Acceptance requires at least 20 measured build minutes and no more than 45 total minutes.

Each T-number is checked in its commit. T03 precedes T06 through T10. Run 4 precedes T15. T17 is HEAD when tagged. Every opening reminder remains true throughout its block.

Why does the plan preserve order?

The plan protects the 20-minute build floor inside the 45-minute total. Its final paragraph fixes the commit order that later validations must prove.

  • Save docs/build-plan.md.
  • Confirm that the phase table totals 45 minutes.

Do the build minutes differ?

Check the five phase values against the supplied table. Confirm that setup remains inside the 45-minute total.

Do not rebalance the phases. Help me compare my build plan with the supplied timing table.

  • Create source-map.md inside the docs folder using your editor's new-file control.
  • Copy the supplied source map into docs/source-map.md using this exact content:
# Source Map

## Amazon Linux 2 Lifecycle
AWS says Amazon Linux 2 reached end of support on June 30, 2026 and no longer receives standard security updates.
Source: https://aws.amazon.com/amazon-linux-2/faqs/

## Amazon Linux 2023 Lifecycle
AWS says standard support ends June 30, 2027 and maintenance ends June 30, 2029.
Source: https://docs.aws.amazon.com/linux/al2023/ug/release-cadence.html

## MADR 4.0.0
Release: https://github.com/adr/madr/releases/tag/4.0.0
Template: https://github.com/adr/madr/blob/4.0.0/template/adr-template.md

## Alternatives
Log4brains: https://github.com/thomvaill/log4brains and https://github.com/thomvaill/log4brains/commits/develop/
adr-tools: https://github.com/npryce/adr-tools and https://github.com/npryce/adr-tools/commits/master/ and https://github.com/npryce/adr-tools/blob/master/INSTALL.md

## Handover Context
CNN reported on July 10, 2026 that 120 CDC HIV/AIDS awards were set to expire in September, programs served more than 8.7 million patients, and no concrete replacement system was in place.
Source: https://www.cnn.com/2026/07/10/africa/cdc-pepfar-hiv-aids-program-cliff-intl

What does the source map control?

The source map ties lifecycle dates, template references, alternative-tool observations, and handover context to named sources. This keeps later records from presenting unsupported certainty.

  • Save docs/source-map.md.
  • Confirm that your editor lists five files inside the docs folder.

Is a source missing?

Confirm that the file contains two Amazon Linux sections, one MADR section, one alternatives section, and one handover-context section.

Restore any missing source from the supplied block. Help me compare my source map with the five supplied sections.

The supplied evidence pack is now present. That gives the repository a fixed reading baseline before the inventory or any Architecture Decision Record is created.

  • In TASKS.md from earlier, find the unchecked T02 line.
  • Replace its empty checkbox with the checked T02 line shown below:
- [x] T02 Copy workload and five design files.

What does T02 record?

T02 records that both workload files and all five design documents were copied. The next commit binds that completed task to the supplied files.

  • Save TASKS.md.
  • Stage the supplied evidence pack and T02 by running this command:
git add workload docs TASKS.md

What does this command stage?

The command stages the two workload files, the five design documents, and the updated task list. It does not stage check-out.txt because V1 remains unchanged.

  • Commit the supplied evidence baseline by running this command:
git commit -m "T02 copy supplied workload and five design documents"

What does this commit prove?

The commit preserves the supplied workload and design files as one reading baseline. Its message links the checked T02 item to that exact change.

Good progress. Your repository now has a committed evidence pack that later records can cite without rewriting the source material.

Did the T02 commit fail?

Confirm that all seven supplied files are saved inside workload and docs.

Check that TASKS.md has T02 checked. Help me diagnose why the T02 evidence commit did not complete.

Commit inventory before any ADR

The initial inventory captures four decisions stated in the workload note. Committing it now freezes the first coverage denominator before the decisions directory exists.

  • Create inventory.md directly inside the open architecture-decision-log directory using your editor's new-file control.
  • Copy the initial decision inventory into inventory.md using this exact content:
# Decision Inventory
deployment_topology: Run the orders service on EC2 virtual machines behind a load balancer | workload/note.md:1 | ADR-0001
tls_termination: End TLS at the load balancer and send plain HTTP to the machines | workload/note.md:2 | ADR-0002
engine: Use a managed PostgreSQL database reachable only from inside the network | workload/note.md:3 | ADR-0003
region: Run everything in us-east-1 | workload/note.md:4 | BACKLOG

How does the inventory stay traceable?

  • Each row begins with a stable decision key.
  • Each row cites one exact line from workload/note.md.
  • Three rows reserve future ADR identifiers.
  • The region row remains in the backlog because no record covers it.
  • Save inventory.md.
  • Confirm that the file contains four decision rows below the heading.

Does an inventory row lack a trace?

Confirm that every row contains a workload path with a line number. Check that only the region row ends with BACKLOG.

Restore the supplied row if a delimiter or identifier changed. Help me compare my initial inventory with the four supplied rows.

  • In TASKS.md from earlier, find the unchecked T03 line.
  • Replace its empty checkbox with the checked T03 line shown below:
- [x] T03 Commit inventory first.

What does T03 protect?

T03 records the inventory-first boundary. Later Git history must place this commit before T06 through T10.

  • Save TASKS.md.
  • Stage the initial inventory and T03 by running this command:
git add inventory.md TASKS.md

What does this command stage?

The command stages only the four-row inventory and the updated task list. No ADR file exists in this change.

Before you run the final commit, which two files do you expect the commit to contain?

  • Commit the inventory-first boundary by running this command:
git commit -m "T03 commit inventory before records"

What should the commit confirm?

The terminal confirms a new commit with the T03 message. Its changed files are inventory.md and TASKS.md.

  • Confirm that your editor lists inventory.md beside the workload and docs folders.
  • Confirm that no decisions folder or ADR file exists yet.
  • Confirm that check-out.txt still contains only the retained V1 setup evidence.

That is the key ordering proof prepared: the initial inventory is committed before any ADR. V2 remains owed until a later step pastes the Git history.

Did an ADR appear too early?

Remove the uncommitted ADR file from the repository. Keep the four-row inventory unchanged.

Commit T03 before restoring the later project scope. Help me restore the inventory-first order without reducing the project scope.

✔️ Awesome, I've got everything!

Your repository contains the unchanged evidence pack and the four-row inventory. T03 is committed before any ADR exists.

ⓧ I'd like to double check the full code

Compare your current files with this complete step state. Keep the retained values inside check-out.txt unchanged.

# Tasks
Done means every item is checked by its commit, V1 to V6 carry EVIDENCE or owed, check-out.txt has four runs with exits, and backlog.md is written.
- [x] T01 Setup and V1.
- [x] T02 Copy workload and five design files.
- [x] T03 Commit inventory first.
- [ ] T04 Copy checker.
- [ ] T05 Run 1, V3, five added lines.
- [ ] T06 ADR-0001.
- [ ] T07 ADR-0002.
- [ ] T08 ADR-0003.
- [ ] T09 ADR-0004.
- [ ] T10 ADR-0005 and supersession.
- [ ] T11 Backlog every uncovered line.
- [ ] T12 Run 2 and V4 exit 1.
- [ ] T13 Run 3 and V5 exit 1.
- [ ] T14 Run 4 exit 0.
- [ ] T15 V2 Git proof.
- [ ] T16 V6, first-draft U/T, shipped zero.
- [ ] T17 Final tag-ready commit.
The orders service runs on EC2 virtual machines behind a load balancer.
TLS, the encryption on web traffic, ends there, so traffic on to the machines is plain HTTP.
Orders sit in a managed PostgreSQL database reachable only from inside the network.
Everything runs in the us-east-1 region.
# Evidence fixture only. Read this Terraform language excerpt; do not apply it.
locals {
  instance = {
    image         = "Amazon Linux 2"
    instance_type = "t3.small"
  }
  database = {
    engine                  = "postgres"
    engine_version          = "16.4"
    backup_retention_period = 7
    multi_az                = false
  }
}
# Requirements Brief

## Product Manager Request
Return one local Git decision log from workload/note.md and workload/main.tf. Read Terraform but never run it. Use Python 3.11 or newer and Git, install nothing from an index, keep four checker runs and six validations, and use no remote, new account, or AI before close-out.

## Terms Up Front
EC2 is AWS virtual-machine compute. TLS encrypts network traffic. multi_az says whether the database has a standby in another Availability Zone. MADR is Markdown Architectural Decision Records. Terraform is the infrastructure configuration language whose supplied file is evidence only. PEPFAR is the US President's Emergency Plan for AIDS Relief.

Terms encountered next, in learner order: ADR means Architecture Decision Record; standard library means modules shipped with Python; Git identity is the commit name and email; coverage denominator is the count below the fraction; source trace is a supporting file or pasted result; supersession is replacement without deleting history; backlog is found decisions without records; local tag is a Git name on a local commit; H2 is a Markdown heading with two number signs; POSIX is a Unix-like command environment; Git Bash is Git for Windows' Unix-like shell; Linux subsystem means Windows Subsystem for Linux; self-contained HTML is one browser file with no fetched assets.

## Six Validations
1. V1: setup and identity output.
2. V2: Git history proves inventory.md preceded every ADR.
3. V3: run 1 lists six settings and five added keys.
4. V4: run 2 exits 1 and names the missing Consequences heading.
5. V5: run 3 exits 1 and names the one-way supersession link.
6. V6: run 4 exits 0 and the written cohort audit labels every item EVIDENCE or owed while preserving first-draft U/T.

## Acceptance Criteria
TASKS.md is completed by commits and HEAD is tagged decision-log-complete. check-out.txt has four runs with exits. Five ADRs have five headings. Drivers are RECORDED with a source or NOT RECORDED with a question. Final output is COVERAGE OF DECISIONS FOUND: 4 of 9. Five scan-added lines remain inventoried and every uncovered line remains backlogged. readout.html is self-contained and ships with zero untraceable claims after preserving first-draft U/T.

## What This Leaves Undone and the Trade
| Left undone | Traded for |
| --- | --- |
| Index, search, site | Zero install, account, and publishing overhead |
| Recovery of unwritten rationale | Questions instead of invented facts |
| ADR quality grading | A short checker |
| One-decision-per-record enforcement | No larger parser |
| Comparable learner denominators | Genuine discovery |
| Migration execution, tests, rollout, cost | No AWS risk |
| Remote collaboration | No code-host account |

## Measurement Rule
The metric is COVERAGE OF DECISIONS FOUND. Its denominator does not claim every workload decision was discovered.
# Project Design Decisions

## Handover Frame
The dated trigger is Amazon Linux 2 ending support on June 30, 2026. CNN reported on July 10, 2026 that 120 CDC HIV/AIDS awards were set to expire in September, programs served more than 8.7 million patients, and no concrete replacement system was in place. The readout repeats this as CNN reporting and does not connect the orders service to PEPFAR.

## Record 1: Use Plain Markdown and One Short Checker
Choice: Plain Markdown plus one Python standard-library checker; no generator or site.
Alternative beaten: Log4brains, whose README requires Node.js plus NPM or Yarn and whose default develop branch shows no commit after December 17, 2024; and adr-tools, whose master branch shows no commit after March 30, 2020 and whose Windows instructions use Git Bash or the Linux subsystem rather than native PowerShell.
Cost: No rendered index, search, or navigation.
Reversal trigger: A maintained, install-free publisher works across macOS, Windows, and Linux.

## Record 2: Measure Coverage Against Decisions Found
Choice: Measure and name coverage against decisions the learner found.
Alternative beaten: A fixed inline list, which deletes discovery.
Cost: Learner results are not directly comparable.
Reversal trigger: The project becomes graded across learners.

## Record 3: Reserve One AI Use for Close-Out
Choice: Use AI once at close-out and score its first draft as U/T, where U is untraceable material claims and T is total material claims.
Alternative beaten: AI drafting record context and consequences, whose value is the learner thinking them through.
Cost: Five records rather than six.
Reversal trigger: Fix the design documents, never the build with a drafting prompt.
# Decision Log Topology
```mermaid
flowchart LR
 T[TASKS] --> W[Workload] --> I[Inventory first] --> S[Run 1]
 S --> R[Five ADRs] --> B[Backlog] --> F[Runs 2 and 3 fail]
 F --> P[Run 4 passes] --> G[Git proof] --> A[Written V6]
 A --> H[HTML] --> L[Local tag]
```
# Build Plan
| Phase | Minutes | Opening reminder |
| --- | ---: | --- |
| Setup | 4 | Verify existing tools; install nothing |
| Design | 11 | Copy two workload and five design files; write none |
| Build | 20 | Checker 8, records 9, scan and backlog 3; inventory remains first |
| Validation | 6 | Keep four runs with exits and write V6 |
| Close-out | 4 | Use the only AI prompt, preserve U/T, strike unsupported claims, tag HEAD |
| Total | 45 | Setup is included and failures do not reduce scope |

The readout reports measured minutes beside these values. Measurements and match are owed until run. Acceptance requires at least 20 measured build minutes and no more than 45 total minutes.

Each T-number is checked in its commit. T03 precedes T06 through T10. Run 4 precedes T15. T17 is HEAD when tagged. Every opening reminder remains true throughout its block.
# Source Map

## Amazon Linux 2 Lifecycle
AWS says Amazon Linux 2 reached end of support on June 30, 2026 and no longer receives standard security updates.
Source: https://aws.amazon.com/amazon-linux-2/faqs/

## Amazon Linux 2023 Lifecycle
AWS says standard support ends June 30, 2027 and maintenance ends June 30, 2029.
Source: https://docs.aws.amazon.com/linux/al2023/ug/release-cadence.html

## MADR 4.0.0
Release: https://github.com/adr/madr/releases/tag/4.0.0
Template: https://github.com/adr/madr/blob/4.0.0/template/adr-template.md

## Alternatives
Log4brains: https://github.com/thomvaill/log4brains and https://github.com/thomvaill/log4brains/commits/develop/
adr-tools: https://github.com/npryce/adr-tools and https://github.com/npryce/adr-tools/commits/master/ and https://github.com/npryce/adr-tools/blob/master/INSTALL.md

## Handover Context
CNN reported on July 10, 2026 that 120 CDC HIV/AIDS awards were set to expire in September, programs served more than 8.7 million patients, and no concrete replacement system was in place.
Source: https://www.cnn.com/2026/07/10/africa/cdc-pepfar-hiv-aids-program-cliff-intl
# Decision Inventory
deployment_topology: Run the orders service on EC2 virtual machines behind a load balancer | workload/note.md:1 | ADR-0001
tls_termination: End TLS at the load balancer and send plain HTTP to the machines | workload/note.md:2 | ADR-0002
engine: Use a managed PostgreSQL database reachable only from inside the network | workload/note.md:3 | ADR-0003
region: Run everything in us-east-1 | workload/note.md:4 | BACKLOG

Your evidence baseline now predates every decision record. Next, you'll build the checker that discovers the five configuration decisions missing from the note.

Build the Checker and Record Run 1

Your reading baseline now preserves four decisions before any Architecture Decision Record exists. The Terraform fixture still contains configuration choices that the note never names.

V3 uses a Python standard library checker to expose those omitted settings. The checker reads the fixture as text.

Terraform remains untouched throughout this step.

In this step, get ready to:
  • Commit the supplied checker before executing it.
  • Keep checker run 1 as V3 evidence.
  • Expand the inventory from four decisions to nine.
Copy and commit the checker

The checker uses Path for local files. It uses sys for arguments and exit statuses.

A Git commit before execution proves the checker existed before it produced V3.

  • Create check.py directly inside the open architecture-decision-log directory using your editor's new-file control.
  • Copy Parts 1 through 7 below into check.py in order.
  • Add the imports, project paths, run numbering, and output helper by copying Part 1:
from pathlib import Path
import sys

# Resolve every project file from the folder containing this script.
ROOT = Path(__file__).resolve().parent
WORKLOAD = ROOT / "workload" / "main.tf"
INVENTORY = ROOT / "inventory.md"
DECISIONS = ROOT / "decisions"
BACKLOG = ROOT / "backlog.md"
LOG = ROOT / "check-out.txt"

# Keep the required ADR headings and note-derived keys in one place.
HEADINGS = ("## Status", "## Context and Problem Statement", "## Considered Options", "## Decision Outcome", "## Consequences")
NOTE_KEYS = {"deployment_topology", "tls_termination", "engine", "region"}


def run_number():
    # Count retained checker headings so each run receives the next number.
    return 1 if not LOG.exists() else LOG.read_text(encoding="utf-8").count("=== CHECKER RUN ") + 1


def emit(lines, run, status):
    # Print one result block and retain the same evidence in the log.
    block = [f"=== CHECKER RUN {run} ===", *lines, f"EXIT STATUS: {status}"]
    print("\n".join(block))
    with LOG.open("a", encoding="utf-8") as handle:
        handle.write("\n" + "\n".join(block) + "\n")
    return status
  • Add the Terraform scanner and inventory reader directly below Part 1 by copying Part 2:
def scan():
    # Collect simple assignment lines from the read-only Terraform fixture.
    found = []
    for line_no, raw in enumerate(WORKLOAD.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if line and not line.startswith("#") and "=" in line:
            key, value = (part.strip() for part in line.split("=", 1))
            if key.isidentifier() and value != "{":
                found.append((key, value, line_no))
    return found


def load_inventory():
    # Parse each inventory row into its decision, source, and record fields.
    rows, errors = {}, []
    for line_no, raw in enumerate(INVENTORY.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if not line or line.startswith("#"):
            continue
        fields = [field.strip() for field in line.split("|")]
        if len(fields) != 3 or ":" not in fields[0]:
            errors.append(f"inventory.md:{line_no}: malformed row")
            continue
        key, decision = (part.strip() for part in fields[0].split(":", 1))
        rows[key] = {"decision": decision, "source": fields[1], "record": fields[2]}
    return rows, errors
  • Add the backlog reader and reference extractor directly below Part 2 by copying Part 3:
def load_backlog():
    # Separate pending decisions, source-gap questions, and malformed rows.
    rows, questions, errors = {}, [], []
    for line_no, raw in enumerate(BACKLOG.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if not line or line.startswith("#"):
            continue
        if line.startswith("Question absent from both sources:"):
            questions.append(line)
        elif "|" in line:
            key, reason = (part.strip() for part in line.split("|", 1))
            rows[key] = reason
        else:
            errors.append(f"backlog.md:{line_no}: malformed row")
    return rows, questions, errors


def refs(text, marker):
    # Extract the ADR identifier that follows a supersession marker.
    return [line.split(marker, 1)[1].strip().split()[0].strip(".,;()") for line in text.splitlines() if marker in line]
  • Add the ADR structure validator directly below Part 3 by copying Part 4:
def validate_record(path):
    # Enforce the five headings and evidence-aware driver markers.
    text = path.read_text(encoding="utf-8")
    headings = [line for line in text.splitlines() if line.startswith("## ")]
    errors = [f"{path.as_posix()}: missing heading {heading}" for heading in HEADINGS if heading not in headings]
    if headings != list(HEADINGS):
        errors.append(f"{path.as_posix()}: headings differ from required five")
    drivers = [line for line in text.splitlines() if line.startswith("- DRIVER |")]
    if not drivers:
        errors.append(f"{path.as_posix()}: no driver lines")
    for driver in drivers:
        known = "| RECORDED |" in driver and "source=" in driver and "concern=" in driver
        unknown = "| NOT RECORDED |" in driver and "question=" in driver
        if not known and not unknown:
            errors.append(f"{path.as_posix()}: invalid driver marker")
    return text, errors
  • Start the full validation path directly below Part 4 by copying Part 5:
def check(run):
    # Compare scanned settings with the complete decision inventory.
    rows, errors = load_inventory()
    scanned = scan()
    added = [key for key, _value, _line in scanned if key not in NOTE_KEYS]
    for key, _value, line_no in scanned:
        if key not in rows:
            errors.append(f"workload/main.tf:{line_no}: {key} missing from inventory")

    # Load each ADR and keep identifiers for structurally valid records.
    paths = sorted(DECISIONS.glob("*.md"))
    if len(paths) != 5:
        errors.append(f"decisions: expected 5 records, found {len(paths)}")
    records, valid = {}, set()
    for path in paths:
        rid = f"ADR-{path.name[:4]}"
        text, problems = validate_record(path)
        records[rid] = {"path": path, "text": text}
        errors.extend(problems)
        if not problems:
            valid.add(rid)

    # Require both sides of every supersession relationship.
    for sid, item in records.items():
        for tid in refs(item["text"], "Supersedes "):
            if tid not in records or f"Superseded by {sid}" not in records[tid]["text"]:
                errors.append(f"{item['path'].as_posix()}: one-way supersession to {tid}")
        for tid in refs(item["text"], "Superseded by "):
            if tid not in records or f"Supersedes {sid}" not in records[tid]["text"]:
                errors.append(f"{item['path'].as_posix()}: one-way supersession from {tid}")
  • Continue the indented check() function directly below Part 5 by copying Part 6:
    # Match uncovered decisions to the backlog and calculate coverage.
    pending, questions, backlog_errors = load_backlog()
    errors.extend(backlog_errors)
    covered, uncovered = [], []
    for key, row in rows.items():
        if row["record"] == "BACKLOG":
            uncovered.append(key)
            if key not in pending:
                errors.append(f"backlog.md: missing {key}")
        elif row["record"] in valid:
            covered.append(key)
        else:
            uncovered.append(key)
            errors.append(f"inventory.md: {key} points to missing or invalid {row['record']}")
    if not questions:
        errors.append("backlog.md: missing source-gap question")
    if not errors and run != 4:
        errors.append(f"clean pass must be checker run 4, not run {run}")

    # Build the retained report and choose its process exit status.
    lines = [*(f"ERROR: {error}" for error in errors)]
    lines += [f"SCAN-ADDED KEYS: {', '.join(added)}", f"SCAN-ADDED KEYS RECORDED: {sum(key in rows for key in added)} of {len(added)}", f"DECISIONS FOUND: {len(rows)}", f"COVERED: {', '.join(covered)}", f"UNCOVERED: {', '.join(uncovered)}", f"COVERAGE OF DECISIONS FOUND: {len(covered)} of {len(rows)}"]
    if questions:
        lines.append(f"SOURCE-GAP QUESTION: {questions[0]}")
    status = 1 if errors else 0
    lines.append("RESULT: FAIL" if status else "RESULT: PASS")
    return emit(lines, run, status)
  • Add the first-run scanner and command dispatcher directly below Part 6 by copying Part 7:
def scan_only(run):
    # Keep run 1 focused on discovering settings before ADR files exist.
    rows, errors = load_inventory()
    found = scan()
    new = [key for key, _value, _line in found if key not in rows]
    if run != 1:
        errors.append(f"scan must be checker run 1, not run {run}")
    lines = [*(f"ERROR: {error}" for error in errors), "SCAN: workload/main.tf"]
    lines += [f"workload/main.tf:{line} | {key} = {value}" for key, value, line in found]
    lines += [f"SETTINGS FOUND: {len(found)}", f"NEW SETTINGS: {len(new)}", f"NEW KEYS: {', '.join(new)}"]
    status = 1 if errors else 0
    lines.append("RESULT: FAIL" if status else "RESULT: PASS")
    return emit(lines, run, status)


def main():
    # Dispatch scan mode, full validation mode, or the usage failure.
    run = run_number()
    if sys.argv[1:] == ["--scan"]:
        return scan_only(run)
    if not sys.argv[1:]:
        return check(run)
    return emit(["USAGE: python3 check.py [--scan]", "RESULT: FAIL"], run, 1)


if __name__ == "__main__":
    sys.exit(main())
  • Save check.py.
  • Confirm the file begins with from pathlib import Path.
  • Confirm the file ends with sys.exit(main()).

✔️ Awesome, I've got everything!

Your saved check.py contains the complete supplied checker. Continue with the T04 commit.

ⓧ I'd like to double check the full code

from pathlib import Path
import sys

# Resolve every project file from the folder containing this script.
ROOT = Path(__file__).resolve().parent
WORKLOAD = ROOT / "workload" / "main.tf"
INVENTORY = ROOT / "inventory.md"
DECISIONS = ROOT / "decisions"
BACKLOG = ROOT / "backlog.md"
LOG = ROOT / "check-out.txt"

# Keep the required ADR headings and note-derived keys in one place.
HEADINGS = ("## Status", "## Context and Problem Statement", "## Considered Options", "## Decision Outcome", "## Consequences")
NOTE_KEYS = {"deployment_topology", "tls_termination", "engine", "region"}


def run_number():
    # Count retained checker headings so each run receives the next number.
    return 1 if not LOG.exists() else LOG.read_text(encoding="utf-8").count("=== CHECKER RUN ") + 1


def emit(lines, run, status):
    # Print one result block and retain the same evidence in the log.
    block = [f"=== CHECKER RUN {run} ===", *lines, f"EXIT STATUS: {status}"]
    print("\n".join(block))
    with LOG.open("a", encoding="utf-8") as handle:
        handle.write("\n" + "\n".join(block) + "\n")
    return status


def scan():
    # Collect simple assignment lines from the read-only Terraform fixture.
    found = []
    for line_no, raw in enumerate(WORKLOAD.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if line and not line.startswith("#") and "=" in line:
            key, value = (part.strip() for part in line.split("=", 1))
            if key.isidentifier() and value != "{":
                found.append((key, value, line_no))
    return found


def load_inventory():
    # Parse each inventory row into its decision, source, and record fields.
    rows, errors = {}, []
    for line_no, raw in enumerate(INVENTORY.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if not line or line.startswith("#"):
            continue
        fields = [field.strip() for field in line.split("|")]
        if len(fields) != 3 or ":" not in fields[0]:
            errors.append(f"inventory.md:{line_no}: malformed row")
            continue
        key, decision = (part.strip() for part in fields[0].split(":", 1))
        rows[key] = {"decision": decision, "source": fields[1], "record": fields[2]}
    return rows, errors


def load_backlog():
    # Separate pending decisions, source-gap questions, and malformed rows.
    rows, questions, errors = {}, [], []
    for line_no, raw in enumerate(BACKLOG.read_text(encoding="utf-8").splitlines(), 1):
        line = raw.strip()
        if not line or line.startswith("#"):
            continue
        if line.startswith("Question absent from both sources:"):
            questions.append(line)
        elif "|" in line:
            key, reason = (part.strip() for part in line.split("|", 1))
            rows[key] = reason
        else:
            errors.append(f"backlog.md:{line_no}: malformed row")
    return rows, questions, errors


def refs(text, marker):
    # Extract the ADR identifier that follows a supersession marker.
    return [line.split(marker, 1)[1].strip().split()[0].strip(".,;()") for line in text.splitlines() if marker in line]


def validate_record(path):
    # Enforce the five headings and evidence-aware driver markers.
    text = path.read_text(encoding="utf-8")
    headings = [line for line in text.splitlines() if line.startswith("## ")]
    errors = [f"{path.as_posix()}: missing heading {heading}" for heading in HEADINGS if heading not in headings]
    if headings != list(HEADINGS):
        errors.append(f"{path.as_posix()}: headings differ from required five")
    drivers = [line for line in text.splitlines() if line.startswith("- DRIVER |")]
    if not drivers:
        errors.append(f"{path.as_posix()}: no driver lines")
    for driver in drivers:
        known = "| RECORDED |" in driver and "source=" in driver and "concern=" in driver
        unknown = "| NOT RECORDED |" in driver and "question=" in driver
        if not known and not unknown:
            errors.append(f"{path.as_posix()}: invalid driver marker")
    return text, errors


def check(run):
    # Compare scanned settings with the complete decision inventory.
    rows, errors = load_inventory()
    scanned = scan()
    added = [key for key, _value, _line in scanned if key not in NOTE_KEYS]
    for key, _value, line_no in scanned:
        if key not in rows:
            errors.append(f"workload/main.tf:{line_no}: {key} missing from inventory")

    # Load each ADR and keep identifiers for structurally valid records.
    paths = sorted(DECISIONS.glob("*.md"))
    if len(paths) != 5:
        errors.append(f"decisions: expected 5 records, found {len(paths)}")
    records, valid = {}, set()
    for path in paths:
        rid = f"ADR-{path.name[:4]}"
        text, problems = validate_record(path)
        records[rid] = {"path": path, "text": text}
        errors.extend(problems)
        if not problems:
            valid.add(rid)

    # Require both sides of every supersession relationship.
    for sid, item in records.items():
        for tid in refs(item["text"], "Supersedes "):
            if tid not in records or f"Superseded by {sid}" not in records[tid]["text"]:
                errors.append(f"{item['path'].as_posix()}: one-way supersession to {tid}")
        for tid in refs(item["text"], "Superseded by "):
            if tid not in records or f"Supersedes {sid}" not in records[tid]["text"]:
                errors.append(f"{item['path'].as_posix()}: one-way supersession from {tid}")

    # Match uncovered decisions to the backlog and calculate coverage.
    pending, questions, backlog_errors = load_backlog()
    errors.extend(backlog_errors)
    covered, uncovered = [], []
    for key, row in rows.items():
        if row["record"] == "BACKLOG":
            uncovered.append(key)
            if key not in pending:
                errors.append(f"backlog.md: missing {key}")
        elif row["record"] in valid:
            covered.append(key)
        else:
            uncovered.append(key)
            errors.append(f"inventory.md: {key} points to missing or invalid {row['record']}")
    if not questions:
        errors.append("backlog.md: missing source-gap question")
    if not errors and run != 4:
        errors.append(f"clean pass must be checker run 4, not run {run}")

    # Build the retained report and choose its process exit status.
    lines = [*(f"ERROR: {error}" for error in errors)]
    lines += [f"SCAN-ADDED KEYS: {', '.join(added)}", f"SCAN-ADDED KEYS RECORDED: {sum(key in rows for key in added)} of {len(added)}", f"DECISIONS FOUND: {len(rows)}", f"COVERED: {', '.join(covered)}", f"UNCOVERED: {', '.join(uncovered)}", f"COVERAGE OF DECISIONS FOUND: {len(covered)} of {len(rows)}"]
    if questions:
        lines.append(f"SOURCE-GAP QUESTION: {questions[0]}")
    status = 1 if errors else 0
    lines.append("RESULT: FAIL" if status else "RESULT: PASS")
    return emit(lines, run, status)


def scan_only(run):
    # Keep run 1 focused on discovering settings before ADR files exist.
    rows, errors = load_inventory()
    found = scan()
    new = [key for key, _value, _line in found if key not in rows]
    if run != 1:
        errors.append(f"scan must be checker run 1, not run {run}")
    lines = [*(f"ERROR: {error}" for error in errors), "SCAN: workload/main.tf"]
    lines += [f"workload/main.tf:{line} | {key} = {value}" for key, value, line in found]
    lines += [f"SETTINGS FOUND: {len(found)}", f"NEW SETTINGS: {len(new)}", f"NEW KEYS: {', '.join(new)}"]
    status = 1 if errors else 0
    lines.append("RESULT: FAIL" if status else "RESULT: PASS")
    return emit(lines, run, status)


def main():
    # Dispatch scan mode, full validation mode, or the usage failure.
    run = run_number()
    if sys.argv[1:] == ["--scan"]:
        return scan_only(run)
    if not sys.argv[1:]:
        return check(run)
    return emit(["USAGE: python3 check.py [--scan]", "RESULT: FAIL"], run, 1)


if __name__ == "__main__":
    sys.exit(main())

How is the checker organized?

  • The path constants connect the checker to the workload, inventory, future records, backlog, and retained log.
  • The scan functions discover settings in workload/main.tf.
  • The validation functions enforce the later ADR, backlog, supersession, and coverage rules.
  • The output functions print each run and append its exit status to check-out.txt.
  • In TASKS.md from earlier, change the checkbox for T04 Copy checker. to checked.
  • Save TASKS.md.
  • Stage the checker and task update by running this command:
git add check.py TASKS.md

What does this stage?

This stages only check.py and TASKS.md for the T04 commit.

  • Commit the checker before its first execution by running this command:
git commit -m "T04 copy standard-library checker"

What does this commit prove?

The commit places the supplied checker in history before run 1. Its summary should name the T04 checker commit.

🙋‍♀️ Missing a required file?

  • Confirm the terminal is inside architecture-decision-log.
  • Confirm check.py is saved beside TASKS.md.
  • Confirm the T04 checkbox is checked before repeating the staging command.
Run the Terraform scan

Run 1 compares the Terraform setting names with the four keys already captured from the note. Any setting absent from the initial inventory becomes scan evidence.

Before you run the checker, how many settings do you think the Terraform fixture contains?

  • Run the scanner from the architecture-decision-log terminal by using this command:
python3 check.py --scan

What does run 1 do?

  • The --scan option selects scan_only().
  • The scanner reads assignment lines from workload/main.tf.
  • The inventory comparison identifies setting names absent from the original four rows.
  • The emit() function appends the numbered result to check-out.txt.

The scan reports SETTINGS FOUND: 6. It also reports NEW SETTINGS: 5.

The new keys are image, instance_type, engine_version, backup_retention_period, and multi_az.

Run 1 ends with RESULT: PASS. The retained block ends with EXIT STATUS: 0.

That is your first build proof. V3 now records the decisions that reading the note alone missed.

Did run 1 fail?

  • Confirm workload/main.tf still matches the supplied evidence fixture.
  • Confirm inventory.md still contains only the original four rows at scan time.
  • Restore the T04 state before repeating the scan if the displayed run number is not 1.
Add the five discovered decisions

The inventory denominator must now include every decision exposed by the scan. Keeping all nine rows prevents later ADR work from hiding uncovered choices.

  • In inventory.md from earlier, place your cursor below the region row.
  • Append the five scan-added rows by copying this block:
image: Pin the instance image family to Amazon Linux 2 | workload/main.tf:4 | ADR-0004
instance_type: Use t3.small | workload/main.tf:5 | BACKLOG
engine_version: Pin PostgreSQL 16.4 | workload/main.tf:9 | BACKLOG
backup_retention_period: Retain backups for 7 days | workload/main.tf:10 | BACKLOG
multi_az: Do not configure Multi-AZ | workload/main.tf:11 | BACKLOG

What do these rows preserve?

Each row names the decision and traces it to an exact line in workload/main.tf.

The image row reserves ADR-0004 for the recorded image choice. The other four rows remain in BACKLOG.

  • Save inventory.md.
  • Confirm the file now contains nine decision rows beneath # Decision Inventory.
  • In TASKS.md from earlier, change the checkbox for T05 Run 1, V3, five added lines. to checked.
  • Save TASKS.md.
  • Stage the revised inventory, retained V3 output, and task update by running this command:
git add inventory.md check-out.txt TASKS.md

What does this stage?

This stages the nine-row inventory. It also stages the retained run 1 block and checked T05 task.

Before you make the commit, do you expect its summary to represent both the V3 evidence and the five added rows?

  • Commit T05 by running this command:
git commit -m "T05 retain V3 and five added lines"

What does this commit retain?

The T05 commit keeps the scan evidence beside the expanded inventory. The history now shows that T03 established the four-row baseline before this discovery.

🙋‍♀️ Does the commit omit V3?

  • Confirm check-out.txt contains the retained run 1 block.
  • Confirm inventory.md contains all five added keys.
  • Confirm TASKS.md shows T05 as checked.

Before the final check, which run number and exit status should still be retained?

  • Return to check-out.txt in your editor.
  • Confirm it contains exactly one === CHECKER RUN 1 === heading.
  • Confirm the run records SETTINGS FOUND: 6.
  • Confirm the run records NEW SETTINGS: 5.
  • Confirm the run ends with RESULT: PASS.
  • Confirm the retained block ends with EXIT STATUS: 0.

✔️ The checker and V3 are complete

Your repository now contains the committed checker, retained run 1 evidence, and nine-row inventory.

ⓧ I'd like to double check the final state

  • Confirm check.py contains the complete supplied checker.
  • Confirm T04 was committed before the checker ran.
  • Confirm check-out.txt retains V1 plus checker run 1.
  • Confirm the run lists six settings and five new keys.
  • Confirm inventory.md contains the original four rows plus five scan-added rows.
  • Confirm TASKS.md has T01 through T05 checked.

Your checker has turned hidden configuration into retained evidence. Next, you will write the five records and preserve every uncovered decision in the backlog.

Write Records and Backlog

The first checker run exposed nine decisions in the workload evidence. Four of those decisions now need durable records.

Each record must separate source facts from unanswered questions. The image history must also show that AWS ended Amazon Linux 2 support on June 30, 2026.

In this step, get ready to:
  • Copy five supplied MADR-style decision records.
  • Commit T06 through T10 separately.
  • Complete the five-line backlog in its T11 commit.
Record the three note-backed decisions

An Architecture Decision Record preserves a choice beside its evidence. A source gap stays visible as a question for the next owner.

  • Create a folder named decisions inside architecture-decision-log with your editor's folder-creation control.
  • Create decisions/0001-use-ec2-behind-a-load-balancer.md inside the new decisions folder by copying this complete record:
# Use EC2 Virtual Machines Behind a Load Balancer
## Status
Accepted.
## Context and Problem Statement
The note states the deployed shape.
- DRIVER | RECORDED | source=workload/note.md:1 | concern=The service runs on EC2 virtual machines behind a load balancer.
- DRIVER | NOT RECORDED | question=Which requirement ruled out managed containers or serverless compute?
## Considered Options
- EC2 behind a load balancer
- Managed containers
- Serverless compute
## Decision Outcome
Record the stated choice without reconstructing rationale.
## Consequences
The record matches the source. Image support, patching, sizing, and the original comparison remain responsibilities or unknowns.

What does this record establish?

  • The RECORDED driver traces the deployment shape to workload/note.md:1.
  • The NOT RECORDED driver keeps the missing compute rationale as a question.
  • The five H2 headings give the checker a consistent record structure.
  • The consequences preserve operational unknowns without inventing an explanation.
  • Save decisions/0001-use-ec2-behind-a-load-balancer.md.
  • Count the five H2 headings in the saved record.

You should see one heading each for status, context, options, outcome, and consequences. The record now separates its source fact from its unanswered question.

  • Check T06 in TASKS.md.
  • Stage ADR-0001 with its task update by running:
git add decisions/0001-use-ec2-behind-a-load-balancer.md TASKS.md
  • Commit the compute topology record by running:
git commit -m "T06 record compute topology"

You should see a new commit summary for T06. ADR-0001 is now part of the repository history.

Did the T06 commit stop?

Confirm that the ADR file is saved inside decisions.

Check that T06 is selected in TASKS.md.

Keep AI unused during this check. Fix only the missing file or task update.

  • Create decisions/0002-terminate-tls-at-load-balancer.md inside architecture-decision-log by copying this complete record:
# Terminate TLS at the Load Balancer
## Status
Accepted.
## Context and Problem Statement
The note places the encrypted boundary at the load balancer.
- DRIVER | RECORDED | source=workload/note.md:2 | concern=TLS ends at the load balancer and traffic onward is plain HTTP.
- DRIVER | NOT RECORDED | question=Which certificate, compliance, or threat-model requirement selected this boundary?
## Considered Options
- Terminate at the load balancer
- Re-encrypt onward
- Pass TLS through
## Decision Outcome
Record the stated boundary.
## Consequences
Public traffic has a named boundary. Internal traffic is plain HTTP. The justification remains unknown.

What does this record establish?

  • The recorded driver traces the TLS boundary to workload/note.md:2.
  • The unanswered driver asks which security requirement selected that boundary.
  • The options preserve the alternatives that a future review may reconsider.
  • The consequences state that internal traffic uses plain HTTP.
  • Save decisions/0002-terminate-tls-at-load-balancer.md.
  • Count the five H2 headings in the saved record.

You should see the same five-heading shape as ADR-0001. The source trace now points to the second line of the workload note.

  • Check T07 in TASKS.md.
  • Stage ADR-0002 with its task update by running:
git add decisions/0002-terminate-tls-at-load-balancer.md TASKS.md
  • Commit the TLS boundary record by running:
git commit -m "T07 record TLS boundary"

You should see a new commit summary for T07. ADR-0002 now preserves the encrypted boundary as a separate decision.

Did the T07 commit stop?

Confirm that the filename starts with 0002.

Check that the recorded source is workload/note.md:2.

Keep AI unused during this check. Correct only the copied record or task state.

  • Create decisions/0003-use-managed-postgresql.md inside architecture-decision-log by copying this complete record:
# Use Managed PostgreSQL Inside the Network
## Status
Accepted.
## Context and Problem Statement
The note states the persistence product and reachability.
- DRIVER | RECORDED | source=workload/note.md:3 | concern=Orders use managed PostgreSQL reachable only inside the network.
- DRIVER | NOT RECORDED | question=Which data and transaction requirements selected PostgreSQL?
## Considered Options
- Managed PostgreSQL
- Self-managed PostgreSQL
- Managed non-relational database
## Decision Outcome
Record the stated choice.
## Consequences
Operations are delegated and reachability is limited. Version, backup, availability, encryption, and deletion-protection reasoning remain unknown.

What does this record establish?

  • The recorded driver traces managed PostgreSQL to workload/note.md:3.
  • The unanswered driver preserves the missing data rationale as a question.
  • The alternatives retain managed, self-managed, and non-relational options.
  • The consequences identify availability and protection reasoning as unknown.
  • Save decisions/0003-use-managed-postgresql.md.
  • Count the five H2 headings in the saved record.

You should see ## Consequences as the final heading. That heading becomes important when the checker tests a missing-heading failure later.

  • Check T08 in TASKS.md.
  • Stage ADR-0003 with its task update by running:
git add decisions/0003-use-managed-postgresql.md TASKS.md
  • Commit the managed database record by running:
git commit -m "T08 record managed PostgreSQL"

You should see a new commit summary for T08. The three note-backed decisions now have separate records.

Did the T08 commit stop?

Confirm that ## Consequences remains in ADR-0003.

Check that the driver source is workload/note.md:3.

Keep AI unused during this check. Restore the supplied record without changing its claims.

Preserve the image decision and supersession

Supersession replaces an active decision while preserving its history. ADR-0004 records the observed image choice.

ADR-0005 records the supported direction. Reciprocal links make the replacement visible from either record.

  • Create decisions/0004-use-amazon-linux-2.md inside architecture-decision-log by copying this complete record:
# Use an Amazon Linux 2 Image
## Status
Superseded by ADR-0005.
## Context and Problem Statement
The Terraform file pins Amazon Linux 2 without rationale.
- DRIVER | RECORDED | source=workload/main.tf:4 | concern=The image is Amazon Linux 2.
- DRIVER | NOT RECORDED | question=Which dependency required Amazon Linux 2?
## Considered Options
- Amazon Linux 2
- Another supported Linux image
- Container-focused host image
## Decision Outcome
Record the observed image without inventing rationale.
## Consequences
The choice is visible, its comparison is unknown, and AWS ended support June 30, 2026.

What does this record preserve?

  • The recorded driver traces the image family to workload/main.tf:4.
  • The unanswered driver asks which dependency required that image.
  • The status points forward to ADR-0005.
  • The consequences retain the June 30, 2026 support deadline.
  • Save decisions/0004-use-amazon-linux-2.md.
  • Inspect the status line in the saved record.

You should see Superseded by ADR-0005. under ## Status. The historical decision now points toward its replacement.

  • Check T09 in TASKS.md.
  • Stage ADR-0004 with its task update by running:
git add decisions/0004-use-amazon-linux-2.md TASKS.md
  • Commit the observed image decision by running:
git commit -m "T09 preserve Amazon Linux 2"

You should see a new commit summary for T09. The original image decision remains available in Git history.

Did the T09 commit stop?

Confirm that the source remains workload/main.tf:4.

Check that the status names ADR-0005.

Keep AI unused during this check. Preserve the supplied historical wording.

  • Create decisions/0005-migrate-to-amazon-linux-2023.md inside architecture-decision-log by copying this complete record:
# Replace Amazon Linux 2 with Amazon Linux 2023
## Status
Accepted. Supersedes ADR-0004.
## Context and Problem Statement
AWS states Amazon Linux 2 ended support June 30, 2026. This chooses a direction, not an executed migration.
- DRIVER | RECORDED | source=docs/source-map.md#amazon-linux-2-lifecycle | concern=Amazon Linux 2 ended support June 30, 2026.
- DRIVER | RECORDED | source=docs/source-map.md#amazon-linux-2023-lifecycle | concern=Amazon Linux 2023 standard support ends June 30, 2027 and maintenance ends June 30, 2029.
- DRIVER | NOT RECORDED | question=Which tests prove migration compatibility?
## Considered Options
- Amazon Linux 2023
- Unsupported Amazon Linux 2
- Another supported image
## Decision Outcome
Choose Amazon Linux 2023 because AWS recommends migration. Preserve ADR-0004 and reopen before June 30, 2027.
## Consequences
History remains traceable. The next deadline is explicit. Compatibility, rollout, and cost remain undone. Terraform remains unchanged.

How does supersession work here?

  • The status points back to ADR-0004 with Supersedes ADR-0004..
  • The lifecycle drivers trace both dates to docs/source-map.md.
  • The unanswered driver keeps migration compatibility as an open question.
  • The consequences preserve Terraform as unchanged evidence.
  • Save decisions/0005-migrate-to-amazon-linux-2023.md.
  • Compare its status with the status in ADR-0004.

ADR-0004 points forward to ADR-0005. ADR-0005 points back to ADR-0004.

  • Check T10 in TASKS.md.
  • Stage ADR-0005 with its task update by running:
git add decisions/0005-migrate-to-amazon-linux-2023.md TASKS.md
  • Commit the superseding image decision by running:
git commit -m "T10 supersede Amazon Linux 2"

You should see a new commit summary for T10. The repository now preserves both sides of the image decision history.

Is one supersession link missing?

Check ADR-0004 for Superseded by ADR-0005..

Check ADR-0005 for Accepted. Supersedes ADR-0004..

Keep AI unused during this check. Restore the supplied status lines exactly.

Backlog every uncovered decision

A decision backlog keeps uncovered inventory lines visible after the recorded decisions are complete. Each row preserves the gap that a future owner needs to investigate.

  • Create backlog.md inside architecture-decision-log by copying this complete backlog:
# Decision Backlog
region | The note names us-east-1 but no rationale.
instance_type | The file selects t3.small but no capacity, latency, or cost driver.
engine_version | The file pins PostgreSQL 16.4 but no compatibility or support rationale.
backup_retention_period | The file retains 7 days but no recovery objective or policy.
multi_az | The file disables Multi-AZ but no availability target or accepted risk.
Question absent from both sources: Should deletion protection and storage encryption be explicit requirements?

What does the backlog retain?

  • The five rows match the inventory entries marked BACKLOG.
  • Each reason identifies the missing rationale without filling it in.
  • The source-gap question captures a concern absent from both workload files.
  • The original nine-line inventory remains unchanged.
  • Save backlog.md.
  • Count the five decision rows below its title.

You should find one row each for region, instance type, engine version, backup retention, and Multi-AZ. The source-gap question appears beneath those rows.

  • Check T11 in TASKS.md.
  • Stage the backlog with its task update by running:
git add backlog.md TASKS.md
  • Commit the uncovered decision backlog by running:
git commit -m "T11 retain every uncovered line"

You should see a new commit summary for T11. Every uncovered inventory line now has a durable backlog entry.

Is a backlog row missing?

Compare backlog.md with the five inventory rows marked BACKLOG.

Restore any missing row without deleting its inventory entry.

Keep AI unused during this check. Use only the supplied backlog text.

✔️ Awesome, I've got everything!

Your five records and complete backlog are saved. T06 through T11 are committed separately.

ⓧ I'd like to double check the full code

# Use EC2 Virtual Machines Behind a Load Balancer
## Status
Accepted.
## Context and Problem Statement
The note states the deployed shape.
- DRIVER | RECORDED | source=workload/note.md:1 | concern=The service runs on EC2 virtual machines behind a load balancer.
- DRIVER | NOT RECORDED | question=Which requirement ruled out managed containers or serverless compute?
## Considered Options
- EC2 behind a load balancer
- Managed containers
- Serverless compute
## Decision Outcome
Record the stated choice without reconstructing rationale.
## Consequences
The record matches the source. Image support, patching, sizing, and the original comparison remain responsibilities or unknowns.
# Terminate TLS at the Load Balancer
## Status
Accepted.
## Context and Problem Statement
The note places the encrypted boundary at the load balancer.
- DRIVER | RECORDED | source=workload/note.md:2 | concern=TLS ends at the load balancer and traffic onward is plain HTTP.
- DRIVER | NOT RECORDED | question=Which certificate, compliance, or threat-model requirement selected this boundary?
## Considered Options
- Terminate at the load balancer
- Re-encrypt onward
- Pass TLS through
## Decision Outcome
Record the stated boundary.
## Consequences
Public traffic has a named boundary. Internal traffic is plain HTTP. The justification remains unknown.
# Use Managed PostgreSQL Inside the Network
## Status
Accepted.
## Context and Problem Statement
The note states the persistence product and reachability.
- DRIVER | RECORDED | source=workload/note.md:3 | concern=Orders use managed PostgreSQL reachable only inside the network.
- DRIVER | NOT RECORDED | question=Which data and transaction requirements selected PostgreSQL?
## Considered Options
- Managed PostgreSQL
- Self-managed PostgreSQL
- Managed non-relational database
## Decision Outcome
Record the stated choice.
## Consequences
Operations are delegated and reachability is limited. Version, backup, availability, encryption, and deletion-protection reasoning remain unknown.
# Use an Amazon Linux 2 Image
## Status
Superseded by ADR-0005.
## Context and Problem Statement
The Terraform file pins Amazon Linux 2 without rationale.
- DRIVER | RECORDED | source=workload/main.tf:4 | concern=The image is Amazon Linux 2.
- DRIVER | NOT RECORDED | question=Which dependency required Amazon Linux 2?
## Considered Options
- Amazon Linux 2
- Another supported Linux image
- Container-focused host image
## Decision Outcome
Record the observed image without inventing rationale.
## Consequences
The choice is visible, its comparison is unknown, and AWS ended support June 30, 2026.
# Replace Amazon Linux 2 with Amazon Linux 2023
## Status
Accepted. Supersedes ADR-0004.
## Context and Problem Statement
AWS states Amazon Linux 2 ended support June 30, 2026. This chooses a direction, not an executed migration.
- DRIVER | RECORDED | source=docs/source-map.md#amazon-linux-2-lifecycle | concern=Amazon Linux 2 ended support June 30, 2026.
- DRIVER | RECORDED | source=docs/source-map.md#amazon-linux-2023-lifecycle | concern=Amazon Linux 2023 standard support ends June 30, 2027 and maintenance ends June 30, 2029.
- DRIVER | NOT RECORDED | question=Which tests prove migration compatibility?
## Considered Options
- Amazon Linux 2023
- Unsupported Amazon Linux 2
- Another supported image
## Decision Outcome
Choose Amazon Linux 2023 because AWS recommends migration. Preserve ADR-0004 and reopen before June 30, 2027.
## Consequences
History remains traceable. The next deadline is explicit. Compatibility, rollout, and cost remain undone. Terraform remains unchanged.
# Decision Backlog
region | The note names us-east-1 but no rationale.
instance_type | The file selects t3.small but no capacity, latency, or cost driver.
engine_version | The file pins PostgreSQL 16.4 but no compatibility or support rationale.
backup_retention_period | The file retains 7 days but no recovery objective or policy.
multi_az | The file disables Multi-AZ but no availability target or accepted risk.
Question absent from both sources: Should deletion protection and storage encryption be explicit requirements?
  • Predict which two records should point to each other before you begin the final review.
  • Count the H2 headings in each ADR.
  • Inspect every driver line across the five ADRs.
  • Compare the status lines in ADR-0004 and ADR-0005.
  • Count the decision rows in backlog.md.
  • Switch back to check-out.txt from earlier.
  • Count the checker run headings in check-out.txt.

You should find exactly five required headings in every ADR. Every driver uses either RECORDED with a source plus concern or NOT RECORDED with a question.

ADR-0004 points to ADR-0005. ADR-0005 points back to ADR-0004.

The backlog contains five decision rows. check-out.txt still contains checker run 1 only.

That is the hard part complete. Your repository now preserves source-backed decisions without hiding the gaps that still need answers.

Your records and backlog are ready. Next, you will keep two intentional checker failures before proving the restored repository passes.

Validate Runs and Git History

Your five MADR records now separate sourced facts from unanswered questions. The next risk is that a clean final result could hide whether the checker catches broken records.

A final pass alone cannot prove those safeguards work. This step retains two deliberate failures before using Git history to prove that inventory came before every ADR.

In this step, get ready to:
  • Record two checker failures with their exit statuses.
  • Capture a final checker pass at 4 of 9.
  • Prove the inventory commit preceded every ADR commit.
Capture the missing-heading failure

Run 2 tests the five-heading contract by removing one required H2 from ADR-0003. A retained exit status of 1 proves the checker rejects an incomplete record.

  • Switch back to the editor from earlier.
  • Select decisions/0003-use-managed-postgresql.md in the file sidebar.
  • Find the ## Consequences heading.
  • Delete only the ## Consequences heading.
  • Save decisions/0003-use-managed-postgresql.md.

Before you run the checker, which required heading do you expect the error to name?

  • Create checker run 2 by running this command:
python3 check.py

What does run 2 prove?

  • The output names decisions/0003-use-managed-postgresql.md as the invalid record.
  • The error names the missing ## Consequences heading.
  • The run reports RESULT: FAIL.
  • The retained block ends with EXIT STATUS: 1.

🚨 This failure is deliberate

The checker has rejected the incomplete ADR as designed. Run 2 is now evidence that the heading rule is enforced.

🙋‍♀️ Run number not 2?

Stop if the new heading does not say === CHECKER RUN 2 ===. An extra checker invocation changes the four-run sequence.

Restore check-out.txt to the state containing run 1 only. Repeat this deliberate failure once.

  • Reinsert ## Consequences above the paragraph beginning The record matches the source..
  • Save decisions/0003-use-managed-postgresql.md.
  • Confirm the restored heading appears between ## Decision Outcome and the consequences paragraph.
  • Mark T12 Run 2 and V4 exit 1. as checked in TASKS.md.
  • Save TASKS.md.
  • Stage the retained run by running this command:
git add check-out.txt TASKS.md

What did Git stage?

Git stages the run 2 evidence in check-out.txt plus the T12 update in TASKS.md. ADR-0003 has returned to its committed content.

  • Commit the run 2 evidence by running this command:
git commit -m "T12 retain V4 exit"

What does this commit preserve?

The commit preserves the expected exit-1 evidence without preserving the broken ADR. Your repository remains ready for the next validation.

That first safeguard is proven. The missing-heading failure now survives as evidence while ADR-0003 remains valid.

Capture the one-way-link failure

Supersession must point in both directions so a reader can follow a decision forward or backward. Run 3 tests that rule by temporarily directing ADR-0005 at the wrong record.

  • Select decisions/0005-migrate-to-amazon-linux-2023.md in the editor sidebar.
  • Find Accepted. Supersedes ADR-0004. in the ## Status section.
  • Replace ADR-0004 with ADR-0002.
  • Save decisions/0005-migrate-to-amazon-linux-2023.md.

Before you run the checker, which record do you expect it to flag for the broken reciprocal link?

  • Create checker run 3 by running this command:
python3 check.py

What does run 3 prove?

  • The checker reports a one-way supersession from ADR-0005 in decisions/0004-use-amazon-linux-2.md.
  • The checker reports a one-way supersession to ADR-0002 in decisions/0005-migrate-to-amazon-linux-2023.md.
  • The run reports RESULT: FAIL.
  • The retained block ends with EXIT STATUS: 1.

🚨 The reciprocal check worked

The checker has caught both sides of the mismatch. Run 3 proves that a one-way supersession cannot pass silently.

🙋‍♀️ Run 3 shows another error?

Confirm ADR-0003 still contains all five required headings. An uncommitted heading change adds a second failure.

Confirm the only temporary edit changes ADR-0004 to ADR-0002 in ADR-0005's status.

  • Replace ADR-0002 with ADR-0004 in ADR-0005's status.
  • Save decisions/0005-migrate-to-amazon-linux-2023.md.
  • Confirm ADR-0004 still says Superseded by ADR-0005..
  • Confirm ADR-0005 now says Accepted. Supersedes ADR-0004..
  • Mark T13 Run 3 and V5 exit 1. as checked in TASKS.md.
  • Save TASKS.md.
  • Stage the retained one-way-link failure by running this command:
git add check-out.txt TASKS.md

What did Git stage?

Git stages run 3 plus the T13 update. Both supersession links have returned to their committed values.

  • Commit the run 3 evidence by running this command:
git commit -m "T13 retain V5 exit"

What does this commit preserve?

The commit retains the second intentional failure. It leaves ADR-0004 and ADR-0005 with reciprocal links.

You have now proven both structural safeguards. The repository is ready for its clean fourth run.

Keep the final pass and Git proof

Run 4 tests the restored repository as a complete system. The result must retain all five scan-added keys while covering four of the nine decisions found.

The path-limited history then proves the reading-first contract. T03 must be older than every ADR commit from T06 through T10.

Before you run the final checker, do you expect the restored repository to pass or fail?

  • Create checker run 4 by running this command:
python3 check.py

What should run 4 report?

  • The checker rescans the six Terraform settings from run 1.
  • The output reports SCAN-ADDED KEYS RECORDED: 5 of 5.
  • The output reports COVERAGE OF DECISIONS FOUND: 4 of 9.
  • The run closes with RESULT: PASS plus EXIT STATUS: 0.

🙋‍♀️ Final run still failing?

Confirm ADR-0003 contains ## Consequences. Confirm ADR-0004 points forward to ADR-0005.

Confirm ADR-0005 points back to ADR-0004. Rerun the checker only after all supplied contents are restored.

  • Mark T14 Run 4 exit 0. as checked in TASKS.md.
  • Save TASKS.md.
  • Stage the final checker pass by running this command:
git add check-out.txt TASKS.md

What did Git stage?

Git stages run 4 with its exit status. It also stages the completed T14 task.

  • Commit the final checker pass by running this command:
git commit -m "T14 retain final exit"

What does T14 preserve?

T14 preserves the clean pass after both deliberate failures. The validation log now has exactly four checker runs with four exit lines.

  • Add a GIT PROOF heading below run 4 in check-out.txt.
  • Save check-out.txt.

Before you inspect the path history, where should T03 appear relative to T06 through T10 in newest-first output?

  • Display the inventory and ADR history by running this command:
git log --oneline -- inventory.md decisions

How does this prove inventory came first?

Git prints the newest matching commit first. T03 appears below T06 through T10 because the inventory commit is older than every ADR commit.

T05 may also appear because it updated inventory.md after the scan. T03 remains the original inventory-first baseline.

  • Copy the full path-history output from the terminal.
  • Paste the output beneath GIT PROOF in check-out.txt.
  • Save check-out.txt.
  • Display the task history by running this command:
git log --oneline -- TASKS.md

What does the task history show?

The task history shows the sequence of T01 through T14 commits in newest-first order. It gives the second half of the V2 evidence trail.

  • Copy the full task-history output from the terminal.
  • Paste the output below the first Git log in check-out.txt.
  • Save check-out.txt.
  • Mark T15 V2 Git proof. as checked in TASKS.md.
  • Save TASKS.md.
  • Stage the Git proof by running this command:
git add check-out.txt TASKS.md

What did Git stage?

Git stages both pasted history outputs plus the T15 update. The resulting commit closes the inventory-first validation.

  • Commit the V2 Git proof by running this command:
git commit -m "T15 retain inventory-first proof"

What does T15 complete?

T15 preserves the history output inside the repository it verifies. The task trail now reaches T15 without changing the supplied workload or design evidence.

🙋‍♀️ T03 missing from the path history?

Confirm the command includes both inventory.md and decisions after the double hyphen. A path-limited log omits commits that did not touch either path.

Confirm you are still inside architecture-decision-log before repeating the history command.

Strong finish. Your retained evidence now shows two enforced safeguards plus a clean 4-of-9 result.

✔️ Awesome, I've got everything!

Your repository contains four retained checker runs plus the inventory-first Git proof. T01 through T15 are committed.

ⓧ I'd like to double check the final state

  • Confirm check-out.txt contains exactly four checker-run headings plus four EXIT STATUS lines.
  • Confirm run 2 names ADR-0003's missing ## Consequences heading plus exit status 1.
  • Confirm run 3 names the one-way supersession problem plus exit status 1.
  • Confirm run 4 reports COVERAGE OF DECISIONS FOUND: 4 of 9 plus exit status 0.
  • Confirm all five ADR files match their supplied final contents.
  • Confirm T01 through T15 are checked in TASKS.md.
  • Confirm T16 and T17 remain unchecked in TASKS.md.
  • Confirm the checker, inventory, backlog, workload files, and design documents remain unchanged.

The repository remains local. Terraform remains read-only.

No AI prompt has been used.

Secret mission

Audit the First Draft and Tag the Last Commit

Use your one permitted AI prompt to turn the repository evidence into a product-manager readout. Audit every material claim before freezing the result with a local Git tag.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep your local project, pause your work for later, or delete it entirely. Keeping the local files has no ongoing project cost.

Resources you used:

  • The local architecture-decision-log folder containing every project artifact.
  • The local Git history containing the decision-log-complete tag.

Keep everything running

No action is needed. Choose this if you want to keep the complete evidence trail for future reference.

  • Keep the architecture-decision-log folder in its current location.
  • Retain the decision-log-complete tag as the marker for the final T17 commit.
  • Use readout.html when you need the product-manager handover.

Pause - I'll come back to this later

The checker exits after every run. No local service needs to be stopped.

  • Close any editor window that still has the project open.
  • Leave the architecture-decision-log folder unchanged.
  • Use the decision-log-complete tag to identify the final project state when you return.

Delete - I don't want to use this again

The delete option is for a project you no longer need. The repository history and local tag disappear with the project folder.

This is the only destructive choice in this section. Your preinstalled tools remain untouched.

Check before emptying

Your deleted-items area may contain unrelated files. Emptying it removes those items too.

  • Select your operating system below to remove the complete project folder.

macOS

  • Select Finder from the Dock.
  • Navigate to the parent location where you created the architecture-decision-log folder.
  • Select the architecture-decision-log folder.
  • Move the selected folder to the deleted-items area with Finder's delete action.
  • Confirm the deleted-items area contains no unrelated file you need.
  • Empty the deleted-items area.
  • Return to the folder's parent location.
  • Confirm the architecture-decision-log folder no longer appears.

The decision-log-complete tag disappears with the repository metadata inside the deleted folder.

Windows

  • Use the Start menu to open File Explorer.
  • Navigate to the parent location where you created the architecture-decision-log folder.
  • Select the architecture-decision-log folder.
  • Move the selected folder to the deleted-items area with File Explorer's delete action.
  • Confirm the deleted-items area contains no unrelated file you need.
  • Empty the deleted-items area.
  • Return to the folder's parent location.
  • Confirm the architecture-decision-log folder no longer appears.

The decision-log-complete tag disappears with the repository metadata inside the deleted folder.

Linux

  • Use your application launcher to open the system file manager.
  • Navigate to the parent location where you created the architecture-decision-log folder.
  • Select the architecture-decision-log folder.
  • Move the selected folder to the deleted-items area with the file manager's delete action.
  • Confirm the deleted-items area contains no unrelated file you need.
  • Empty the deleted-items area.
  • Return to the folder's parent location.
  • Confirm the architecture-decision-log folder no longer appears.

The decision-log-complete tag disappears with the repository metadata inside the deleted folder.

Nice Work!

Nice Work!

You did it! You built a local evidence-led decision log that distinguishes proof from work still owed. Your self-contained readout.html gives a product manager a traceable 4-of-9 handover.

What you learned:

  • Committed the decision inventory before every Architecture Decision Record. Used Git history to prove that the reading baseline came first.
  • Built a Python standard library checker that surfaced five configuration decisions. Preserved four checker runs with exit statuses. Finished at COVERAGE OF DECISIONS FOUND: 4 of 9.
  • Created five ADRs that separate recorded sources from unanswered driver questions. Preserved five backlog lines for uncovered decisions. Recorded Amazon Linux 2 ending support on June 30, 2026. Set Amazon Linux 2023 as the next direction before standard support ends June 30, 2027.
  • Secret Mission: Audited the only AI draft while preserving first-draft U/T. Removed every unsupported material claim from readout.html. Reported V1 through V6 as EVIDENCE or owed. Finished with the local tag decision-log-complete pointing at HEAD.

Ready to quiz yourself?