# NIDS Assignment Style Guide

The exact file layout, naming, and markup conventions every NIDS assignment repository
follows: file set, breadcrumb navigation, README section order, task and question
numbering, notebook stubs, and the required contents of the paired private answer-key
repository. Written to be followed literally, by a person or by an AI coding agent
building an assignment.

Where a rule here differs from an already-published assignment, this page wins — the
assignments published to date predate it, and several carry drift that is being
corrected rather than copied.

For the reasoning behind these conventions, see the narrative version of this guide:
[NIDS Assignment Style Guide](https://www.caida.org/projects/nids/how-to/create-assignment/style-guide/)
on the CAIDA website.

## The repository pair

Every assignment is two GitHub repositories under the CAIDA organization:

| Repository | Visibility | Contents |
| --- | --- | --- |
| `nids-<topic>` | Public | Everything the student receives |
| `nids-<topic>-key` | Private | The answer key and the instructor's resource-prep material |

Name the topic in lowercase with hyphens, describing the dataset or subject rather
than the course or term: `nids-dns-ecosystem`, `nids-bgp-control-plane`, `nids-itdk`.

## Conventions in every Markdown file

### Breadcrumb navigation

Every `.md` file in the public repository opens and closes with the same
pipe-separated breadcrumb bar listing every document in the assignment, in reading
order. The current page is **not** a link and is suffixed with `⮕`; every other entry
is a relative link.

```markdown
[README](README.md) | [Introduction](Introduction.md) | [Datasets](Datasets.md) | [Spark](Spark.md) | Tasks ⮕ | [Task 1](Task-1-centralization.md) | [Task 2](Task-2-resilience.md) | [Task 3](Task-3-security.md) | [Notebook](nids-dns-ecosystem.ipynb)
```

The bar is the first line of the file and, repeated identically, the last. Adding a
document means updating the bar in every file — keep them consistent.

### The NIDS banner

Directly below the opening breadcrumb, `README.md` carries the banner, a horizontal
rule, and then the assignment title:

```markdown
### [Network Infrastructure Data Science (NIDS) Assignment]

---

# Understanding the DNS Ecosystem
```

Use this exact wording, including the square brackets. Earlier assignments say
"Module" instead of "Assignment", or omit the brackets, or omit the banner entirely;
all three are drift.

### Linking to a resource

When one resource has several useful destinations, use the bracketed multi-link
idiom rather than separate bullets:

```markdown
- **CAIDA AS Customer Cone and Relationships** — an ASN's customer cone and its relationships with other ASNs [ [paper](https://catalog.caida.org/paper/2013_asrank) | [webpage](https://catalog.caida.org/dataset/as_relationships_serial_1) | [download](https://publicdata.caida.org/datasets/as-relationships/serial-1/) ]
```

### Callouts

Use a blockquote with a bold lead-in for anything that interrupts the reading flow —
a trap the student is likely to fall into, or an aside that is not part of the main
argument:

```markdown
> **Gotcha:** `collect_set` deduplicates, so a domain listing four nameservers from
> one provider counts once, not four times.
```

`**Gotcha:**` for a mistake worth preventing, `**Note:**` for an aside.

## `README.md`

Headings appear in this order and at these levels. Nothing else belongs at `##`.

```markdown
### [Network Infrastructure Data Science (NIDS) Assignment]
---
# <Assignment Title>
**GitHub:** <repository URL>     ← optional
## Authors
## Learning Objectives
## Overview
### Running Locally          ← only if the assignment ships its own database
### Directory Structure
### Glossary
```

**Authors** is a single line of comma-separated names, and it credits everyone who built
the assignment — including collaborators outside CAIDA. It sits directly below the title
and the optional `**GitHub:**` line:

```markdown
# Exploring the Internet Yellow Pages (IYP): A Graph Model of Internet Infrastructure

**GitHub:** https://github.com/CAIDA/nids-iyp

## Authors

Bradley Huffaker, Romain Fontugne, Malte Tashiro

## Learning Objectives
```

**Learning Objectives** is a short paragraph, not a bulleted list. Name what the
assignment introduces — the dataset, and the tool, practice, or idea that comes with it —
and state what the student will be able to do afterwards. Name any new tool explicitly:
*"you will learn Cypher, Neo4j's graph query language"* leaves no doubt that learning the
tool is part of the assignment, not incidental scaffolding.

**Overview** is the ordered path through the assignment. Each step links to the
document or action it names, and the final steps cover producing and submitting the
deliverable:

```markdown
- step 1 [read the introduction](Introduction.md)
- step 2 [read dataset overviews](Datasets.md)
- step 3 [review the tasks](Tasks.md)
- step 4 log into NRP's JupyterHub, upload and complete the nids-dns-ecosystem.ipynb
  - Detailed instructions to access NRP: [How to access NRP](https://www.caida.org/projects/nids/how-to/nrp-access/)
  - complete each task by replacing the `# YOUR CODE HERE` sections
  - answer all questions
- step 5 download your working notebook and replace ⬅ deliverable
- step 6 commit and push to github
```

### Directory Structure

A fenced tree listing every shipped file with an aligned comment — including the tool
guide, which is easy to forget. Each entry is prefixed `├-`, and every deliverable the
student submits is flagged with `⬅`:

```text
nids-dns-ecosystem
├- Introduction.md                          # Introduction and background
├- Datasets.md                              # Dataset overview and access instructions
├- Spark.md                                 # PySpark and query reference
├- Tasks.md                                 # Task checklist and instructions
├- Task-1-centralization.md                 # Guidance for Task 1
├- Task-2-resilience.md                     # Guidance for Task 2
├- Task-3-security.md                       # Guidance for Task 3
├- data/                                    # Place downloaded parquet files here
├- nids-dns-ecosystem.ipynb             ⬅  # Complete / Commit / Push
```

### Glossary

An alphabetized list of `- **Term**: definition.` entries covering every acronym and
piece of jargon the assignment uses. Expand initialisms on first use and attach a
bracketed link where one exists.

## `Introduction.md`

Opens with the reading list and prerequisites, then the conceptual background.

```markdown
### Reading
### Prerequisite NIDS Assignments
```

**`### Reading`** lists what the student should read before starting, one line each,
with a parenthetical type tag — `(paper)`, `(slides)`, `(webpage)` — where the format
is not obvious. Material that is genuinely optional goes in a `#### Optional Reading`
subsection later in the file, not mixed into this list.

**`### Prerequisite NIDS Assignments`** lists earlier assignments the student needs, by
full GitHub URL, each with a short note on what it supplies. The note is what makes the
boundary between assumed and new material legible — and that boundary decides whether
this assignment owes the student a tool guide:

```markdown
- [nids-dns-ecosystem](https://github.com/CAIDA/nids-dns-ecosystem) — PySpark fundamentals this assignment builds on
- [nids-telescope-traffic](https://github.com/CAIDA/nids-telescope-traffic) — network telescope and flow concepts
```

If there are none, say so explicitly rather than omitting the heading:

```markdown
- None — this assignment is self-contained and does not depend on material from other NIDS assignments.
```

Background material belongs in this file, under `##` sections named for the concept
or the task they support (`## Task 1 Background: DNS Hosting Centralization`). Split
it into a separate `Background.md` only when it is long enough to stand as its own
reference — `nids-itdk`, whose background documents a full database schema, is the
one precedent. If you do split it, add `Background.md` to every breadcrumb bar.

## `Datasets.md`

One `####` section per dataset, giving what the dataset is, how to reach it, and its
schema — table or field listings with a column for name, type, and description.
Where a dataset is a queryable database large enough that a naive query will time
out, add a `### Writing Efficient Queries` section covering which columns are
indexed and how to structure a query that uses them.

If the dataset needs credentials, document the flow here: copy
`<x>_credentials.env.example` to `<x>_credentials.env`, fill in the values supplied
by the instructor, and place it next to the notebook.

## Tool guides

**A tool guide is required for every tool the assignment uses that a prerequisite
assignment does not already cover.** If a prerequisite covers it, cite the prerequisite
instead of repeating it. If a prerequisite covers it partly, ship a guide covering only
the difference.

Name the file for the tool, whatever kind of tool it is — a query language (`SQL.md`,
`Cypher.md`), a processing framework (`Spark.md`), or a library (`Dpkt.md`,
`Pyarrow.md`). An assignment may need more than one:
`nids-telescope-traffic` ships `Dpkt.md` for parsing packets and `Pyarrow.md` for
writing Parquet.

Number the sections (`## 1.`, `### 3.4`) so `Tasks.md` and the per-task guides can
deep-link to a specific technique instead of the whole file.

A guide has three placements, and all three are required:

1. The breadcrumb bar in every file.
2. An entry in the README's `### Directory Structure` tree.
3. A numbered step in the README's `## Overview`, positioned **before** the tasks — the
   student needs the tool before the work that uses it.

### Delta guides

When a prerequisite taught the tool but this assignment uses it differently, cover only
what changed and say so in the title and opening line.
`nids-ucsdnt-expanse`'s `PySpark-Parquet.md` is the model:

```markdown
# PySpark & Parquet Guide: What's Different in This Module

This page assumes you've already completed `nids-dns-ecosystem` and its `Spark.md`
guide — SparkSession setup, filtering/selecting, groupBy/agg, joins, and broadcast
variables all carry over unchanged. It covers only what is genuinely different here:
the input format, running Spark on a single HPC node instead of a cluster, and the
Parquet handoff between this module's scripts.
```

Naming the prerequisite guide and listing what carries over unchanged is the whole
point — it tells the student exactly which knowledge to bring and which to build.

## `Tasks.md`

The checklist the student works through. The filename is `Tasks.md`, plural.

Open with a sentence naming the notebook and stating that the work happens there.
Then one `##` section per task, `### Task N.M` subsections for the steps within it,
and the questions as GitHub checkboxes.

Number questions **sequentially across the whole assignment** — `Q1` through `Q18`,
continuing across task boundaries — and bold the label:

```markdown
### Task 1.3 — Market share and HHI

Compute each provider's market share (fraction of domains it serves). Compute the
HHI. Print the top-10 providers.

- [ ] **Q2** What is the HHI? How does it compare to the monopoly bound (1.0) and to a perfectly even split across all providers (1/N)?
- [ ] **Q3** What fraction of all domains are served by the top-3 providers combined? What systemic risk does this represent?
```

Do not use per-task lettering (`Q1.a`, `Q1.b`). Each `##` task section links to its
per-task guide on the line below the heading:

```markdown
Detailed guidance: [Task 1 — Centralization](Task-1-centralization.md)
```

**Task 0** is the setup task: reaching the execution environment, uploading the
notebook, and confirming data access. It ends in verification checkboxes, not
questions.

## Per-task guides

One file per task, named `Task-<N>-<slug>.md`, where the slug names the analysis:
`Task-1-centralization.md`, `Task-2-resilience.md`, `Task-3-security.md`. Do not use
bare `Task-1.md`.

Title the file `# Task N Guidance: <Title>` and open with a line pointing back at the
notebook:

```markdown
# Task 1 Guidance: DNS Hosting Centralization

This page provides implementation guidance for Task 1 of [nids-dns-ecosystem.ipynb](nids-dns-ecosystem.ipynb).
```

The body gives the student the pieces they need — the technique, the library call,
the formula, a worked snippet on a simplified input — organized under `##` headings
and separated by horizontal rules. It must **never** contain the assembled answer,
the final numbers, or code that can be pasted straight into the notebook to complete
the task. That belongs in the private key repository.

Close with `## What Your Write-Up Should Address`, restating what the student has to
produce for each of the task's questions.

## Notebooks and deliverables

Default to a single notebook named for the repository — `nids-<topic>.ipynb`. Ship more
than one deliverable only when the work genuinely divides into separate artifacts:
`nids-telescope-traffic` ships two notebooks, and `nids-ucsdnt-expanse` ships a
prototype notebook, a full-period analysis notebook, a batch script, and a Slurm
submission file, because a prototype and a batch run really are different things.
Splitting one continuous analysis across two files is not a reason.

Every deliverable gets a `⬅` in the directory tree, and non-notebook deliverables — a
batch script, a submission file — are held to the same standard as notebooks: stubbed
where the student must write code, complete and runnable everywhere else.

Cells run in this repeating sequence:

1. A markdown cell heading the step, matching the `### Task N.M` heading in
   `Tasks.md` — `### Task 2.2 — DNS provider diversity`.
2. A code cell whose body is the stub `# YOUR CODE HERE`, followed by comment lines
   naming the variable the student must produce and its shape, plus one or more
   `# Hint:` lines pointing at the specific call to use.
3. A markdown cell carrying the question, label bolded and matching `Tasks.md`
   exactly — `**Q8** What fraction of domains rely on a single DNS provider? …`
4. A markdown answer slot for the student to overwrite:

   ```markdown
   *Your answer for Q8:*

   Replace this line with your answer.
   ```

Every `Q` number in `Tasks.md` has exactly one question cell and one answer slot in
the notebook, and the wording matches in both places. Setup cells — imports,
credential loading, session creation, helper functions the task is not about — ship
complete and runnable, not stubbed.

## Execution environment

**Default to NRP's hosted JupyterHub.** The student uploads the notebook, works in
the browser, downloads the finished notebook, and pushes it. No local install
instructions, no `pyproject.toml`, no `requirements.txt`. Task 0 links to
[How to Access NRP](https://www.caida.org/projects/nids/how-to/nrp-access/).

**Ship a local path only if the assignment provides its own persistent database** —
the Postgres behind `nids-itdk`, the Neo4j behind `nids-iyp` — which the student
reaches over a tunnel from their own machine. In that case add a "Running Locally"
section to the README, at `###`, between Overview and Directory Structure. Offer both
installers, and ship the dependency files each one needs (`pyproject.toml` plus
`uv.lock`, and `requirements.txt`):

```bash
# Option A: uv
uv sync
uv run jupyter lab nids-itdk.ipynb
```

```bash
# Option B: pip + venv
python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt
jupyter lab nids-itdk.ipynb
```

An assignment whose data is read live from an API, an S3 object store, or a Spark
cluster does not qualify — those run on NRP.

## The private answer-key repository

`nids-<topic>-key`, private. Two things are required.

**1. An executed, answered copy of every notebook in the public repository.** Same
cell structure, but every `# YOUR CODE HERE` stub replaced with working code, every
answer slot filled in, and the whole notebook run top to bottom with no errors and
its outputs saved. This is the reference answer: if it does not run clean, it is not
finished.

**2. Everything needed to stand up the assignment's data resources.** Whatever an
instructor must run before students can start — loader scripts and notebooks,
container and Kubernetes manifests, schema exporters, credential templates,
cleanup scripts — plus a `README.md` that walks through them in order. Write it for
an instructor who has never set this assignment up: name the prerequisites, give the
commands, state which values are placeholders, and cover the failures that actually
happen. `nids-itdk-key/README.md` is the model — it takes an instructor from an empty
NRP namespace through deploying Postgres, opening a tunnel, loading the data,
creating the read-only student role, and handing credentials to students.

If the assignment reads its data live and needs no preparation, say so in the
`README.md` rather than leaving the question open.

Optional, if useful: a grading rubric, facilitation notes, an environment-check
notebook. No published assignment has these yet.

## Files that never ship

Keep these out of the public repository, and out of the key repository where noted:

- **Author scratch** — any file prefixed `z-` (`z-plan.md`, `z-notes.md`) and
  anything under `temp/`. These are working notes; they are not student-facing and
  they are not documentation.
- **Real credentials** — commit `<x>_credentials.env.example` with placeholder
  values; git-ignore the filled-in `<x>_credentials.env`. The same applies to any
  manifest that carries a real secret.
- **Large data files** — ship a `data/` directory with instructions for populating
  it, never the data itself.
- **Environments and caches** — `.venv/`, `__pycache__/`, `.ipynb_checkpoints/`.
- **`summary.md`** — the machine-readable assignment summary some authors generate
  is a workspace tool. It is optional, and it stays outside both repositories.
