<a id="ch-10"></a>

## Chapter 10 — One row can carry more than one note

<!-- open-cyber-academy:lesson-figures:start ch-10 -->
### Lesson map

Lesson 10. Map, example, EX056.

```mermaid
flowchart TD
  A["UPDATE if the version test passes"] --> B["UNMAINTAINED if age passes"]
  B --> C["REMOVE if unused"]
  C --> J["Join with semicolon-space, in that order"]
```

The three tests are independent. This file never makes two of them true on one row.

### Logical drawing

```text
separator in source: '; '
visible separators in the four lines: none
donate-form notes: one
event-calendar notes: one
photo-gallery notes: one
newsletter notes: none
```
<!-- open-cyber-academy:lesson-figures:end ch-10 -->

### Learning outcomes

After this chapter, you should be able to:

1. State the order in which notes are appended.
2. Explain why the separator is invisible in this output.
3. Refuse a merged note that this file did not produce.

### 10.1 The `if` statements do not stop each other.

Nothing in the loop uses `elif`. A row can collect an update note, an age note, and a remove note. `'; '.join(notes)` would place a semicolon and a space between them, in the order the three `if` blocks appear: UPDATE, then UNMAINTAINED, then REMOVE. That order is source order. It is not an estimate of which problem matters more.

In these four tuples the separator never appears. donate-form triggers only the version test. event-calendar triggers only the age test: its fixed version is `None`, and it is in use. photo-gallery triggers only the unused test. newsletter triggers none. A row that was old, unused, and behind a fixed version would print three clauses. No such row is stored, so a note that glues two clauses together is an invention.

The UPDATE text copies the fixed version from the tuple. It does not copy a CWE identifier, a CVE identifier, or a CVSS number. MITRE's CWE Top 25 is a public catalog. This script does not map a tuple onto a CWE entry. Ladisa et al. (2023) and Ohm et al. (2020) classify attacks against open-source supply chains. Their class names are not fields here, and this chapter does not reproduce an attack. The fixed string `3.2.4` remains a version, not a vulnerability key.

| Row | Notes appended | Separator shown? |
|---|---|---|
| donate-form | UPDATE only | no |
| event-calendar | UNMAINTAINED only | no |
| photo-gallery | REMOVE only | no |
| newsletter | none, so `ok` | no |
| A triple-fault row | not stored | would show two separators |

### 10.2 Worked example

| Proposed line | Why it fails or stands | Decision |
|---|---|---|
| donate-form has one UPDATE clause | Only the version test passed | Keep |
| The separator is `'; '` in the source | No output line contains it | Keep as source |
| "event-calendar prints UPDATE and UNMAINTAINED." | `fixed` is `None` | Refuse |
| "3.2.4 is a CWE identifier." | It is the fixed version string | Refuse |

> **Synthetic case.** The four note lists are disjoint. None is a combined finding.

### Errors and limits

Do not join clauses the loop never appended, and do not invent an identifier the tuple lacks.

### Apply

- **EX056 — Separator.** A classmate prints event-calendar as both UPDATE and UNMAINTAINED, separated by a semicolon, and treats `3.2.4` as a weakness identifier. What does this file actually join, and what is `3.2.4`? *Rubric:* 3 = no row has two notes, so the semicolon is not in the output; event-calendar has only the age note; `3.2.4` is donate-form's fixed version, not a CWE or CVE;; 2 = one note per flagged row and the version string stays a version;; 1 = one clause;; 0 = none.

<!-- open-cyber-academy:chapter-navigation:start ch-10 -->
### Continue studying — lesson 10 (chapter 10 of 20)

[← Chapter 09](#ch-09) · [Course chapter index](../SUBJECTS.md) · [Chapter 11 →](#ch-11)

Continue to the next authored lesson.
<!-- open-cyber-academy:chapter-navigation:end -->

## Worked answers

<a id="answer-ex056"></a>
**EX056.** No row carries two notes, so the semicolon-space separator is not in the output. event-calendar has only the age note. `3.2.4` is a fixed version string, not a weakness identifier.
