Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions case-studies/manlan-2019/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,36 @@ created metadata-only, and the file was attached in a later local import
repository** and must not enter the crate package until redistribution
rights are explicitly established.

## Layer-2 fabric semantics (2026-08-04 correction)

MAN LAN is a **Layer-2 exchange/fabric** operated by Internet2 for
research-and-education interconnection. For the purposes of this case
study:

- MAN LAN has **no ASN**;
- MAN LAN does **not** speak BGP, does not originate routes, and does
**not** appear as an AS-path hop;
- MAN LAN facilitates Layer-2 connectivity among attached networks
(reviewed attachments are listed in `case-study.json` →
`interconnection_context`, with ASN labels only where the reviewed
target research establishes them for 2019-08-21);
- **Layer-2 attachment is not BGP adjacency**: an attached network may
or may not have exchanged routes directly with other attachments;
- public BGP observes **exported route consequences** at public
collectors, never switch-fabric state.

The completed historical pilot is a **NORDUnet (AS2603) target-scoped
BGP analysis** of route observations during the operator-reported
Layer-2 incident. It is not MAN LAN BGP analysis, not a MAN LAN
routing-plane analysis, not evidence that MAN LAN announced or
withdrew routes, not a complete analysis of all connectors, and not
evidence that every attached network shared the same BGP topology.

Where reviewed records say "MAN LAN attachment predicate", read it as
the reviewed **proxy** for Internet2 R&E-plane transit presence
(AS11537-in-path) in NORDUnet paths — a modeling convenience, never a
MAN LAN ASN.

## What this directory contains

`case-study.json` — the single canonical reviewed data file (schema v1):
Expand Down
851 changes: 460 additions & 391 deletions case-studies/manlan-2019/case-study.json

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions docs/DOMAIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,20 @@ used for queue idempotency and run provenance. Staged artifact roots
are catalog-root-relative paths, never absolute. See
`docs/GLOSSARY.md` (Analysis job, Worker lease, Plan revision, Staging
artifact).

## Layer-2 interconnection context (reviewed, non-protocol)

A case study may carry **reviewed interconnection context** describing
the Layer-2 environment of an operator-reported incident (for example
an exchange fabric). The context names reviewed attachments and, where
the reviewed records establish them, their ASN labels with a validity
date. It is stored as reviewed interpretation in the case-study layer
(`interconnection_context`) and rendered as presentation.

The context is deliberately **not protocol evidence**: production
analysis never uses fabric attachment metadata in route predicates,
cohort selection, or findings. Layer-2 attachment is not BGP
adjacency; an exchange fabric is not automatically an AS-path hop;
public BGP observes exported route consequences, not switch-fabric
state. Observed AS paths are rendered from canonical route evidence
only (stream lifecycles and transitions), never from fabric context.
26 changes: 26 additions & 0 deletions docs/GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,29 @@ the source retrieval timestamp or another reviewed time); the result
is Provisional and states "observed through cutoff". A later source
refresh creates a new snapshot, plan revision, job, and run; the
provisional run is never mutated.

## Interconnection context and observed AS paths

- **Layer-2 fabric context** — reviewed physical / Layer-2
participation context of an incident (for example an exchange
fabric). A fabric for the purposes of a case study has no ASN, does
not speak BGP, does not originate routes, and does not appear as an
AS-path hop. Fabric context is reviewed interpretation; it is
presentation and case-study metadata, never protocol evidence.
- **Attached network** — an organization / network with a reviewed
Layer-2 attachment to the fabric. An attachment is reviewed physical
or Layer-2 participation context; it does **not** prove BGP
adjacency, exported route visibility, a commercial relationship,
traffic flow, or active state during the event. Attachment is never
rendered as a directional BGP edge.
- **Observed AS-path diagram** — a presentation of an observed AS path
at one public observer, rendered from canonical route evidence. A
solid arrow is observed AS-path order; arrow direction never labels
provider/customer/peer semantics unless separate reviewed
relationship evidence supports that exact label. The diagram is a
single-observer observation, not a topology map.
- **Reviewed unobserved relationship** — a reviewed relationship or
predicate (for example an adjacency) that the selected evidence did
not expose. It is rendered with a dashed edge and stated as "not
observed in the selected public baselines" — never as "the
relationship does not exist".
9 changes: 7 additions & 2 deletions docs/OBSERVABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,15 @@ missed detection; `no BGP change does not refute a Layer-2 incident`, and

## Historical predicate validation

A MAN LAN attachment predicate is a **candidate** until validated by
A candidate path predicate for the reviewed Internet2 transit presence in
NORDUnet paths (ContainsAny[11537]) is **candidate** until validated by
contemporaneous observation: the 2019-08-21 RouteViews RIB (Stage A
preflight) confirmed ContainsAny[11537] for AS2603 (33 streams), so the
pilot predicate is reviewed-by-observation rather than assumed. A
pilot predicate is reviewed-by-observation rather than assumed. The
predicate is a proxy for the reviewed R&E-plane transit presence in the
NORDUnet (AS2603) target's paths; it never represents MAN LAN itself
(MAN LAN is a Layer-2 exchange fabric with no ASN for the case study,
and does not appear as an AS-path hop). A
NotDirectlyVisible condition stays NotDirectlyObservable even when a pilot
run exists; a narrow pilot's absence of observations never refutes
non-BGP-visible conditions, and never extends beyond its own window.
Expand Down
29 changes: 29 additions & 0 deletions docs/UX.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,32 @@ factual progress, recent events, worker heartbeat, cancellation and
retry controls (write mode only), and the completed-run link. No
verbose parser logs on the first screen; execution details are
collapsed.

## AS-path and fabric diagrams (2026-08)

Case-study and run pages may render server-rendered SVG diagrams using
a familiar operational visual grammar (compact square-cornered ASN
nodes, monospaced ASN text, a short reviewed organization label,
directional or near-orthogonal edges, restrained grouping, strong
target highlight). The grammar is inspired by common AS-path tooling;
exact colors, layout, and product details are never copied.

Evidence semantics are encoded visually and repeated in text:

- **solid arrow** — observed AS-path order at one public observer;
- **dashed edge** — reviewed relationship or predicate not observed in
the selected evidence;
- **grey undirected line** — reviewed Layer-2 attachment context (never
a BGP adjacency claim).

Rules: arrow direction is never described as provider/customer/peer
without separate reviewed evidence; a Layer-2 fabric is never drawn as
an ASN node; a withdrawn route is an absence block, never an arrow to
a "withdrawn" node; repeated prepends render compactly (AS24489 ×4)
with the full sequence in the text equivalent; node position and
organization category never imply a relationship class; the diagram
states that it shows what one public BGP observer received, not a
complete topology map. All diagrams have a textual equivalent, an SVG
title and description, no color-only meaning, keyboard-accessible
links, bounded horizontal scrolling on mobile, and remain legible when
printed. No animation and no zoom/pan controls.
6 changes: 4 additions & 2 deletions docs/audits/2026-08-repository-truth-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ This audit verifies that every tracked file is classified, that every current st

## Summary

Tracked files: **457** · inventory entries: **457**
Tracked files: **459** · inventory entries: **459**

| Category | Files |
|---|---|
| Immutable or generated evidence | 148 |
| Production source | 104 |
| Production source | 106 |
| Normative current documentation | 42 |
| Historical decision record | 40 |
| Reviewed case-study interpretation | 28 |
Expand Down Expand Up @@ -403,10 +403,12 @@ Tracked files: **457** · inventory entries: **457**
| `src/catalog/target_research.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/tests.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/api.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/fabric_path_tests.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/handlers.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/job_handlers.rs` | Production source | developers | implementation | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/jobs_view.rs` | Production source | developers | implementation | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/mod.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/path_diagram.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/server.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/session_context.rs` | Production source | maintainers | implementation (behavioral authority) | no | current | implementation comments audited in this audit | none | reviewed in this audit |
| `src/catalog/web/templates/analysis.html` | Template or stylesheet | operators (NOC analysts) | workbench view model + domain model | no | current | user-visible text audited in this audit | none | reviewed in this audit |
Expand Down
16 changes: 16 additions & 0 deletions docs/audits/repository-inventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -3654,5 +3654,21 @@
"authoritative": "implementation",
"generated": false,
"current": true
},
{
"path": "src/catalog/web/path_diagram.rs",
"category": "Production source",
"audience": "maintainers",
"authoritative": "implementation (behavioral authority)",
"generated": false,
"current": true
},
{
"path": "src/catalog/web/fabric_path_tests.rs",
"category": "Production source",
"audience": "maintainers",
"authoritative": "implementation (behavioral authority)",
"generated": false,
"current": true
}
]
18 changes: 18 additions & 0 deletions docs/evaluation/facilitator/NOC-ALPHA-FACILITATOR-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,21 @@ occur.
4. Update the pilot registry
(`docs/evaluation/PILOT-REGISTRY.md`).
5. Do not implement feedback immediately without triage.

## Layer-2 fabric terminology (2026-08)

When an evaluator works the NORDUnet scenario, the facilitator holds
these reviewed truths and may clarify them without leading answers:

- MAN LAN is **Layer-2 fabric context**: it has no ASN for the case
study, does not speak BGP, does not originate routes, and does not
appear as an AS-path hop.
- **NORDUnet AS2603** is the analyzed BGP target — one attached
network. The completed pilot is NORDUnet-target-scoped public-BGP
analysis during the operator-reported Layer-2 incident; it is not
MAN LAN BGP analysis and not a complete analysis of all connectors.
- Observed AS paths in the diagrams are **public-collector evidence**
(what one observer received), never switch-fabric state.
- **Layer-2 attachment and AS-path adjacency are different evidence
classes**: attachment does not prove BGP adjacency, route export, a
commercial relationship, traffic flow, or active state.
3 changes: 2 additions & 1 deletion docs/reference/CATALOG-SCHEMA.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ catalog. It is not a column-by-column duplicate of the migrations.

## Migration policy

- `src/catalog/migrations.rs` holds ordered migrations `V1..V10`;
- `src/catalog/migrations.rs` holds ordered migrations `V1..V11`;
index `i` migrates `user_version i → i+1`.
- A fresh database applies all migrations in order; each migration runs
inside a transaction.
Expand All @@ -37,6 +37,7 @@ catalog. It is not a column-by-column duplicate of the migrations.
| V8 | — (ALTER) | `stream_lifecycle_summaries.first_change_utc`, `restoration_time_utc` |
| V9 | `observer_session_metadata` (+ `analysis_runs.classification`) | observed peer ASNs from baseline RIBs; run role classification |
| V10 | `analysis_jobs`, `analysis_job_events`, `worker_heartbeats` | durable job state machine, append-only job events, worker heartbeats |
| V11 | `case_studies.interconnection_context` | reviewed Layer-2 / interconnection context (presentation; never protocol evidence) |

## Important relationships (foreign keys)

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/SCHEMA-VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ version for them.

| Format | Current version | Implementation authority | Compatibility policy | Producer | Consumer | Tracked examples | Generated or authored |
|---|---|---|---|---|---|---|---|
| Catalog database | v10 | `src/catalog/migrations.rs` (`CATALOG_SCHEMA_VERSION`) | ordered migrations; future schema rejected at open | `catalog init`, `demo init` | web, CLI, worker | none (runtime) | generated at runtime |
| Catalog database | v11 | `src/catalog/migrations.rs` (`CATALOG_SCHEMA_VERSION`) | ordered migrations; future schema rejected at open | `catalog init`, `demo init` | web, CLI, worker | none (runtime) | generated at runtime |
| Manifest (analysis plan input) | v2 | `src/schema.rs` (`MANIFEST_SCHEMA_VERSION`) | v1 rejected with `LegacyManifestRequiresMigration`; offline `migrate-manifest` | authored | `plan`, `analyze`, catalog import | `manifests/*.json` | authored |
| RIB derived cache | v2 | `src/schema.rs` (`RIB_CACHE_SCHEMA_VERSION`) | mismatch → invalidated and rebuilt atomically | orchestrator | preflight/execution | none (runtime) | generated at runtime |
| UPDATE derived cache | v2 | `src/schema.rs` (`UPDATE_CACHE_SCHEMA_VERSION`) | mismatch → invalidated and rebuilt atomically | orchestrator | execution | none (runtime) | generated at runtime |
Expand Down
7 changes: 7 additions & 0 deletions evaluation/generated/answer-key.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
"the exact-baseline restoration timestamps per prefix (lifecycle.json)",
"the RRC15 cooldown transitions (report.json transitions.cooldown = 11)"
],
"incident_context": {
"attachment_vs_adjacency": "Layer-2 attachment and AS-path adjacency are different evidence classes: attachment does not prove BGP adjacency, route export, a commercial relationship, traffic flow, or active state during the event.",
"path_evidence": "observed AS paths are public-collector evidence (route-views2 peer 64.57.28.241 and RIS observers); they show what the collector received, never switch-fabric state.",
"reference": "case-studies/manlan-2019/case-study.json",
"target": "NORDUnet AS2603 is the analyzed BGP target (one attached network); the completed pilot is NORDUnet-target-scoped, not MAN LAN BGP analysis.",
"text": "MAN LAN is a Layer-2 exchange/fabric: it has no ASN for this case study, does not speak BGP, does not originate routes, and does not appear as an AS-path hop."
},
"likely_confusions": [
"exact baseline returned (17:02:03Z) versus final route state",
"one observer's result (route-views2) versus all observers",
Expand Down
8 changes: 8 additions & 0 deletions evaluation/generated/answer-key.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ is authoritative and the contradiction is a P0 defect.
- **Source event**: MAN LAN 2019-08-21 (multi-ticket operator incident)
- **Target**: NORDUnet (AS2603)
- **Reviewed relationship**: NORDUnet (AS2603) routes via the Internet2 R&E plane (AS11537)

### Incident context (Layer-2 fabric)

- **text**: MAN LAN is a Layer-2 exchange/fabric: it has no ASN for this case study, does not speak BGP, does not originate routes, and does not appear as an AS-path hop.
- **target**: NORDUnet AS2603 is the analyzed BGP target (one attached network); the completed pilot is NORDUnet-target-scoped, not MAN LAN BGP analysis.
- **path_evidence**: observed AS paths are public-collector evidence (route-views2 peer 64.57.28.241 and RIS observers); they show what the collector received, never switch-fabric state.
- **attachment_vs_adjacency**: Layer-2 attachment and AS-path adjacency are different evidence classes: attachment does not prove BGP adjacency, route export, a commercial relationship, traffic flow, or active state during the event.
- **reference**: `case-studies/manlan-2019/case-study.json`
- **Artifact**: `case-studies/manlan-2019/pilot/cross-observer-matrix.json`

### Route state answers
Expand Down
16 changes: 16 additions & 0 deletions scripts/build-evaluation-answer-key.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ def iso_parse(s: str):
"predicate": "origin AS2603 AND baseline AS path contains AS11537",
"reference": path_as_ref("case-studies/manlan-2019/pilot/cross-observer-matrix.json"),
},
"incident_context": {
"text": "MAN LAN is a Layer-2 exchange/fabric: it has no ASN for this case study, does not speak BGP, does not originate routes, and does not appear as an AS-path hop.",
"target": "NORDUnet AS2603 is the analyzed BGP target (one attached network); the completed pilot is NORDUnet-target-scoped, not MAN LAN BGP analysis.",
"path_evidence": "observed AS paths are public-collector evidence (route-views2 peer 64.57.28.241 and RIS observers); they show what the collector received, never switch-fabric state.",
"attachment_vs_adjacency": "Layer-2 attachment and AS-path adjacency are different evidence classes: attachment does not prove BGP adjacency, route export, a commercial relationship, traffic flow, or active state during the event.",
"reference": path_as_ref("case-studies/manlan-2019/case-study.json"),
},
"analysis_window_utc": pilot["window_start_utc"] + " .. " + pilot["window_end_utc"],
"observers": [
{
Expand Down Expand Up @@ -755,6 +762,15 @@ def render_markdown(doc: dict) -> str:
lines.append(f"- **Source event**: {s['source_event']['id']}")
lines.append(f"- **Target**: {s['target']['name']}")
lines.append(f"- **Reviewed relationship**: {s['reviewed_relationship']['text']}")
if "incident_context" in s:
ic = s["incident_context"]
lines.append("")
lines.append("### Incident context (Layer-2 fabric)")
lines.append("")
for k, v in ic.items():
if k != "reference":
lines.append(f"- **{k}**: {v}")
lines.append(f"- **reference**: `{ic.get('reference', '')}`")
lines.append(f"- **Artifact**: `{s['reviewed_relationship'].get('reference', '')}`")
lines.append("")
lines.append("### Route state answers")
Expand Down
4 changes: 3 additions & 1 deletion src/catalog/archive_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ pub fn list_targets(conn: &Connection, case_study_id: i64) -> Result<Vec<CaseStu
pub fn find_case_study(conn: &Connection, slug: &str) -> Option<CaseStudy> {
conn.query_row(
"SELECT id, slug, title, summary, start_utc, end_utc, status, content_sha256,
created_utc, updated_utc
created_utc, updated_utc, interconnection_context
FROM case_studies WHERE slug = ?1",
[slug],
|r| {
Expand All @@ -658,6 +658,7 @@ pub fn find_case_study(conn: &Connection, slug: &str) -> Option<CaseStudy> {
content_sha256: r.get(7)?,
created_utc: r.get(8)?,
updated_utc: r.get(9)?,
interconnection_context: r.get(10)?,
})
},
)
Expand Down Expand Up @@ -688,6 +689,7 @@ mod tests {
content_sha256: "abc".to_string(),
created_utc: "2019-09-01T00:00:00Z".to_string(),
updated_utc: "2019-09-01T00:00:00Z".to_string(),
interconnection_context: None,
}
}

Expand Down
Loading