From 96dfaa1cc9aea8e17e86d9cbf0c8d7d257f5eacf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:02:29 +0200
Subject: [PATCH 01/26] Fix links to renamed repositories and venues
The approach pages pointed at repositories that were renamed or merged into
ardoco/ardoco and ardoco/lissa, three replication packages carry a new name,
and the SE venue moved to fb-swt.gi.de.
Co-Authored-By: Claude Opus 5.5
---
src/content/approaches/arcotl.md | 2 +-
src/content/approaches/ardocode.md | 2 +-
src/content/approaches/exarch.md | 2 +-
src/content/approaches/inconsistency-detection.md | 2 +-
src/content/approaches/lissa.md | 2 +-
src/content/approaches/swattr.md | 2 +-
src/content/approaches/transarc.md | 2 +-
src/content/conferences/icsa25.md | 2 +-
src/content/conferences/icse25.md | 2 +-
src/content/conferences/refsq25.md | 2 +-
src/data/venues.yml | 2 +-
11 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/content/approaches/arcotl.md b/src/content/approaches/arcotl.md
index d2c0510a..f23ad627 100644
--- a/src/content/approaches/arcotl.md
+++ b/src/content/approaches/arcotl.md
@@ -8,7 +8,7 @@ figure:
plate: true
repositories:
- name: Implementation
- url: https://github.com/ardoco/tlr
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ICSE 2024)
url: https://github.com/ardoco/Replication-Package-ICSE24_Recovering-Trace-Links-Between-Software-Documentation-And-Code
---
diff --git a/src/content/approaches/ardocode.md b/src/content/approaches/ardocode.md
index 8847a2c3..ec971f33 100644
--- a/src/content/approaches/ardocode.md
+++ b/src/content/approaches/ardocode.md
@@ -8,7 +8,7 @@ figure:
plate: false
repositories:
- name: Implementation
- url: https://github.com/ardoco/tlr
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ICSE 2024)
url: https://github.com/ardoco/Replication-Package-ICSE24_Recovering-Trace-Links-Between-Software-Documentation-And-Code
---
diff --git a/src/content/approaches/exarch.md b/src/content/approaches/exarch.md
index 99d3c03f..f133d9ba 100644
--- a/src/content/approaches/exarch.md
+++ b/src/content/approaches/exarch.md
@@ -8,7 +8,7 @@ figure:
plate: true
repositories:
- name: Implementation
- url: https://github.com/ardoco/tlr
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ICSA 2025)
url: https://github.com/ardoco/Replication-Package-ICSA25_Enabling-Arch-Traceability-by-LLM-based-Arch-Component-Name-Extraction
---
diff --git a/src/content/approaches/inconsistency-detection.md b/src/content/approaches/inconsistency-detection.md
index fceb724b..25009eea 100644
--- a/src/content/approaches/inconsistency-detection.md
+++ b/src/content/approaches/inconsistency-detection.md
@@ -8,7 +8,7 @@ figure:
plate: true
repositories:
- name: Implementation
- url: https://github.com/ardoco/inconsistency-detection
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ICSA 2023)
url: https://github.com/ardoco/DetectingInconsistenciesInSoftwareArchitectureDocumentationUsingTraceabilityLinkRecovery
---
diff --git a/src/content/approaches/lissa.md b/src/content/approaches/lissa.md
index 7ce6dace..242481a2 100644
--- a/src/content/approaches/lissa.md
+++ b/src/content/approaches/lissa.md
@@ -8,7 +8,7 @@ figure:
plate: true
repositories:
- name: Implementation
- url: https://github.com/ardoco/lissa-ratlr
+ url: https://github.com/ardoco/lissa
- name: Replication Package (ICSE 2025)
url: https://github.com/ardoco/Replication-Package-ICSE25_LiSSA-Toward-Generic-Traceability-Link-Recovery-through-RAG
- name: Replication Package (REFSQ 2025)
diff --git a/src/content/approaches/swattr.md b/src/content/approaches/swattr.md
index 39fa35bb..cbc9c904 100644
--- a/src/content/approaches/swattr.md
+++ b/src/content/approaches/swattr.md
@@ -8,7 +8,7 @@ figure:
plate: false
repositories:
- name: Implementation
- url: https://github.com/ardoco/tlr
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ECSA 2021)
url: https://github.com/ardoco/SWATTR
---
diff --git a/src/content/approaches/transarc.md b/src/content/approaches/transarc.md
index 0366eb7c..db0cdc0f 100644
--- a/src/content/approaches/transarc.md
+++ b/src/content/approaches/transarc.md
@@ -8,7 +8,7 @@ figure:
plate: true
repositories:
- name: Implementation
- url: https://github.com/ardoco/tlr
+ url: https://github.com/ardoco/ardoco
- name: Replication Package (ICSE 2024)
url: https://github.com/ardoco/Replication-Package-ICSE24_Recovering-Trace-Links-Between-Software-Documentation-And-Code
- name: Replication Package (ICSA 2025)
diff --git a/src/content/conferences/icsa25.md b/src/content/conferences/icsa25.md
index edc11b65..cbd552eb 100644
--- a/src/content/conferences/icsa25.md
+++ b/src/content/conferences/icsa25.md
@@ -34,7 +34,7 @@ links:
kitopen: https://publikationen.bibliothek.kit.edu/1000179830
replication:
zenodo: https://doi.org/10.5281/zenodo.14506935
- repo: https://github.com/ardoco/ReplicationPackage-EnablingArchitectureTraceabilitybyLLM-basedArchitectureComponentNameExtraction
+ repo: https://github.com/ardoco/Replication-Package-ICSA25_Enabling-Arch-Traceability-by-LLM-based-Arch-Component-Name-Extraction
slides:
pptx: /assets/pdf/presentation_icsa25.pptx
pdf: /assets/pdf/presentation_icsa25.pdf
diff --git a/src/content/conferences/icse25.md b/src/content/conferences/icse25.md
index 0ef8fe01..6c13f6b0 100644
--- a/src/content/conferences/icse25.md
+++ b/src/content/conferences/icse25.md
@@ -32,7 +32,7 @@ links:
kitopen: https://publikationen.bibliothek.kit.edu/1000179816
replication:
zenodo: https://doi.org/10.5281/zenodo.14714706
- repo: https://github.com/ardoco/ReplicationPackage-ICSE25_LiSSA-Toward-Generic-Traceability-Link-Recovery-through-RAG/tree/main
+ repo: https://github.com/ardoco/Replication-Package-ICSE25_LiSSA-Toward-Generic-Traceability-Link-Recovery-through-RAG/tree/main
slides:
pptx: /assets/pdf/presentation_icse25.pptx
pdf: /assets/pdf/presentation_icse25.pdf
diff --git a/src/content/conferences/refsq25.md b/src/content/conferences/refsq25.md
index 2e9e955d..078b77ea 100644
--- a/src/content/conferences/refsq25.md
+++ b/src/content/conferences/refsq25.md
@@ -25,7 +25,7 @@ links:
springer: https://doi.org/10.1007/978-3-031-88531-0_27
replication:
zenodo: https://doi.org/10.5281/zenodo.14779457
- repo: https://github.com/ardoco/ReplicationPackage-REFSQ25_Requirements-TLR-via-RAG
+ repo: https://github.com/ardoco/Replication-Package-REFSQ25_Requirements-TLR-via-RAG
---
## Abstract
diff --git a/src/data/venues.yml b/src/data/venues.yml
index 31ed6a83..bee15f0f 100644
--- a/src/data/venues.yml
+++ b/src/data/venues.yml
@@ -26,5 +26,5 @@ ASE:
# badges rendered grey and unlabelled on the old site.
SE:
name: Software Engineering (GI)
- url: https://fachgruppe-se.gi.de/
+ url: https://fb-swt.gi.de/
color: '#5b5bd6'
From 5907174b3ae83fc902be5843e18fa49d6f81be22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:03:05 +0200
Subject: [PATCH 02/26] Pin draw.io SVGs to a light colour scheme
The ECSA 2021 and ICSE 2024 exports carry color-scheme: light dark, so on the
dark site they drew black boxes onto the white plate. Pin them to light and put
both on the plate; the alt text of the ArDoCode figure said ArCoTL.
Co-Authored-By: Claude Opus 5.5
---
public/assets/img/approaches/ecsa21-swattr.svg | 2 +-
public/assets/img/approaches/icse24-ardocode.svg | 2 +-
src/components/Figure.astro | 4 ++--
src/content.config.ts | 9 +++++++--
src/content/approaches/ardocode.md | 4 ++--
src/content/approaches/swattr.md | 2 +-
src/content/conferences/ecsa21.md | 2 +-
verification/asset-sha256.txt | 4 ++--
8 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/public/assets/img/approaches/ecsa21-swattr.svg b/public/assets/img/approaches/ecsa21-swattr.svg
index 22483a5b..73c883b2 100644
--- a/public/assets/img/approaches/ecsa21-swattr.svg
+++ b/public/assets/img/approaches/ecsa21-swattr.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/approaches/icse24-ardocode.svg b/public/assets/img/approaches/icse24-ardocode.svg
index 937ceaf3..ef2cd8b1 100644
--- a/public/assets/img/approaches/icse24-ardocode.svg
+++ b/public/assets/img/approaches/icse24-ardocode.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/components/Figure.astro b/src/components/Figure.astro
index c63a000b..a97ac0e1 100644
--- a/src/components/Figure.astro
+++ b/src/components/Figure.astro
@@ -43,8 +43,8 @@ const maxWidth = isVector ? 'var(--measure)' : `${width}px`;
/*
* The approach diagrams are dark line art on a transparent background, drawn
* for a white page. On a near-black one they are all but invisible, so they
- * sit on a light plate — except the two that were authored with their own
- * background already baked in.
+ * sit on a light plate. Screenshots, which bring their own background, opt
+ * out with `plate: false`.
*/
.has-plate img {
background: #fff;
diff --git a/src/content.config.ts b/src/content.config.ts
index 37332553..79f65a0f 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -80,8 +80,13 @@ const figure = z.object({
alt: z.string(),
/**
* The approach diagrams are dark-on-transparent SVGs drawn for a white page.
- * On a near-black background they need a light plate behind them — except
- * the two that were authored without one.
+ * On a near-black background they need a light plate behind them. Only
+ * screenshots, which bring their own background, turn it off.
+ *
+ * The draw.io exports (ecsa21-swattr.svg, icse24-ardocode.svg) carry
+ * `color-scheme: light dark` and light-dark() fills, so on this dark site
+ * they drew black boxes onto the white plate. Their root style is pinned
+ * to `color-scheme: light`; a fresh export needs the same edit.
*/
plate: z.boolean().default(true),
});
diff --git a/src/content/approaches/ardocode.md b/src/content/approaches/ardocode.md
index ec971f33..1b0836d4 100644
--- a/src/content/approaches/ardocode.md
+++ b/src/content/approaches/ardocode.md
@@ -4,8 +4,8 @@ description: ArDoCode – TLR between Software Architecture Documentation and Co
importance: 5
figure:
src: /assets/img/approaches/icse24-ardocode.svg
- alt: ArCoTL Overview
- plate: false
+ alt: ArDoCode Overview
+ plate: true
repositories:
- name: Implementation
url: https://github.com/ardoco/ardoco
diff --git a/src/content/approaches/swattr.md b/src/content/approaches/swattr.md
index cbc9c904..9f4d019a 100644
--- a/src/content/approaches/swattr.md
+++ b/src/content/approaches/swattr.md
@@ -5,7 +5,7 @@ importance: 1
figure:
src: /assets/img/approaches/ecsa21-swattr.svg
alt: SWATTR Overview
- plate: false
+ plate: true
repositories:
- name: Implementation
url: https://github.com/ardoco/ardoco
diff --git a/src/content/conferences/ecsa21.md b/src/content/conferences/ecsa21.md
index a4342e98..866e8754 100644
--- a/src/content/conferences/ecsa21.md
+++ b/src/content/conferences/ecsa21.md
@@ -20,7 +20,7 @@ conferenceUrl: https://conf.researchr.org/home/ecsa-2021
figure:
src: /assets/img/approaches/ecsa21-swattr.svg
alt: SWATTR Overview
- plate: false
+ plate: true
links:
paper:
springer: https://doi.org/10.1007/978-3-030-86044-8_7
diff --git a/verification/asset-sha256.txt b/verification/asset-sha256.txt
index 3fb50bfc..c013a51b 100644
--- a/verification/asset-sha256.txt
+++ b/verification/asset-sha256.txt
@@ -9,13 +9,13 @@
# Regenerate with: node scripts/generate-asset-baseline.mjs
44a2a583fa2f46d8e2e7bcaae2105aab9d61adbeb74a5a46b28bca2991092eba assets/img/approaches/aire25-aire.svg
-a2e7dae134928e7631cbc70894aa9be646191d6d74a2ecf74b83c1b699c8efaa assets/img/approaches/ecsa21-swattr.svg
+6954b6f6a29fb93d86588abb9f9c250d83324a8b1004a3325bc2efd3bd75b02c assets/img/approaches/ecsa21-swattr.svg
b12be95af68108a34d1538afa842e606471f0073b7fa770a768a29cc07a5fc39 assets/img/approaches/fgarch24-titleslide.png
4f154c230bd2e2192ef4994c50415f0d78444e03ccd4b6fddbe2827fafcc5a11 assets/img/approaches/icsa2019-poster.png
0738cad487eafbc432d7c58d949edaa6fdfeb4572dd58e950da4667fee9cb242 assets/img/approaches/icsa23-inconsistency.svg
e6025dc3eedc594dbf693e3442792f019b91610d82239afb596d358419cd3cb4 assets/img/approaches/icsa25-transarc.svg
d3224cf1cf0833acbb788cdfaf11b4809168f8ddcfd8b0c93f5773058b4756ab assets/img/approaches/icsa26-archguard.svg
-4b3041302a281a92e4555cab23fafdbfb26b46334116b869034cf9b60c971350 assets/img/approaches/icse24-ardocode.svg
+48d8faed4ec20678777396e1f060b738e465f4e62607941fbc7e6e5a06601e99 assets/img/approaches/icse24-ardocode.svg
5b182296e53933f645620fb9949d2524f49dd8c3cabd731761ab7b0e76b4c348 assets/img/approaches/icse24-transarc.svg
0d644debfd32492225acdeb67d5c392585d7bffe4f50c27ec972265b824e1094 assets/img/approaches/icse25-lissa.svg
213ead2badd11009d31894ef63c95b1719856ac070fb7296c919fef83a8d7b60 assets/img/approaches/refsq25-refsq.svg
From 884c2566fc2c0d3eaa31065bf42b7c8811758436 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:03:05 +0200
Subject: [PATCH 03/26] Add TAAS, REFSQ and AIRE venue badges
Three papers had no abbr, so they rendered without a badge. Colours are chosen
apart from the existing venues and readable on the dark background.
Co-Authored-By: Claude Opus 5.5
---
src/content.config.ts | 2 +-
src/data/papers.bib | 3 +++
src/data/venues.yml | 17 +++++++++++++++++
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/content.config.ts b/src/content.config.ts
index 79f65a0f..28fde1dc 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -51,7 +51,7 @@ const publications = defineCollection({
authors: z.array(z.object({ first: z.string(), last: z.string() })).min(1),
year: z.number().int(),
month: z.number().int().min(1).max(12).optional(),
- // An abbr with no venues.yml entry fails the build. Five entries carry no
+ // An abbr with no venues.yml entry fails the build. Two entries carry no
// abbr at all, which is fine — they render without a badge.
abbr: reference('venues').optional(),
booktitle: z.string().optional(),
diff --git a/src/data/papers.bib b/src/data/papers.bib
index 18bc2fa6..a71000e2 100644
--- a/src/data/papers.bib
+++ b/src/data/papers.bib
@@ -148,6 +148,7 @@ @inproceedings{fuchss_lissa_2025
@inproceedings{hey_requirements_2025,
title = {{Requirements} {Traceability} {Link} {Recovery} via {Retrieval}-{Augmented} {Generation}},
author = {Hey, Tobias and Fuch{\ss}, Dominik and Keim, Jan and Koziolek, Anne},
+ abbr = {REFSQ},
address = {Cham},
booktitle = {Lecture Notes in Computer Science},
doi = {10.1007/978-3-031-88531-0\_27},
@@ -165,6 +166,7 @@ @inproceedings{hey_requirements_2025
@inproceedings{fuchss_beyond_2025,
title = {{Beyond} {Retrieval}: {A} {Study} of {Using} {LLM} {Ensembles} for {Candidate} {Filtering} in {Requirements} {Traceability}},
author = {Fuch{\ss}, Dominik and Schwedt, Stefan and Keim, Jan and Hey, Tobias},
+ abbr = {AIRE},
booktitle = {2025 IEEE 33rd International Requirements Engineering Conference Workshops (REW)},
doi = {10.1109/rew66121.2025.00006},
html = {/c/aire25},
@@ -229,6 +231,7 @@ @inproceedings{liu_architecture_2026
@article{fuchss_whos_2026,
author = {Fuch{\ss}, Dominik and Liu, Haoyu and Corallo, Sophie and Hey, Tobias and Keim, Jan and von Geisau, Johannes and Koziolek, Anne},
title = {Who's Who? LLM-assisted Software Traceability with Architecture Entity Recognition},
+ abbr = {TAAS},
year = {2026},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
diff --git a/src/data/venues.yml b/src/data/venues.yml
index bee15f0f..572ef879 100644
--- a/src/data/venues.yml
+++ b/src/data/venues.yml
@@ -28,3 +28,20 @@ SE:
name: Software Engineering (GI)
url: https://fb-swt.gi.de/
color: '#5b5bd6'
+
+# Colours are chosen apart from the five above (blue, amber, magenta, teal,
+# violet) and light enough for the badge's dark-site background.
+TAAS:
+ name: ACM Transactions on Autonomous and Adaptive Systems
+ url: https://dl.acm.org/journal/taas
+ color: '#e4572e'
+
+REFSQ:
+ name: 'International Working Conference on Requirements Engineering: Foundation for Software Quality'
+ url: https://refsq.org/
+ color: '#7cb518'
+
+AIRE:
+ name: International Workshop on Artificial Intelligence and Requirements Engineering
+ url: https://aire-ws.github.io/aire25/
+ color: '#e86a92'
From f8d1f140652ec79fa29c0bb11e304498618ede9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:03:56 +0200
Subject: [PATCH 04/26] Fold /conferences/ into /publications/
/publications/ already links every /c/ page, and "conferences" was a misnomer
for a list that includes journal papers. The URL stays as a redirect stub; the
nav, sitemap and copy lose the section, and its violet accent now belongs to
the home page's publication section only.
Co-Authored-By: Claude Opus 5.5
---
README.md | 25 ++---
scripts/audit-features.mjs | 11 +++
src/components/Nav.astro | 5 -
src/consts.ts | 2 +-
src/content.config.ts | 7 +-
src/content/pages/404.md | 1 -
src/content/pages/conferences.md | 7 --
src/content/pages/publications.md | 2 +-
src/content/pages/site/nav.md | 1 -
src/content/pages/site/publication.md | 6 +-
src/lib/conferences.ts | 4 +-
src/lib/redirect.ts | 10 +-
src/pages/c/[slug].astro | 4 +-
src/pages/conferences/index.astro | 127 ++------------------------
src/pages/index.astro | 2 +-
src/pages/sitemap.xml.ts | 1 -
src/styles/tokens.css | 5 +-
17 files changed, 53 insertions(+), 167 deletions(-)
delete mode 100644 src/content/pages/conferences.md
diff --git a/README.md b/README.md
index 6b2d8350..8ad8c98c 100644
--- a/README.md
+++ b/README.md
@@ -74,14 +74,14 @@ The `.astro` files hold layout and code. Every word a reader sees that is not co
`` and description, its lede, the labels on its chips and buttons, the nav and footer rows,
the home page's introduction — is in `src/content/pages/`, one Markdown file per page:
-| File | Holds |
-| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
-| `site/site.md` | the site `title`, the `tagline` and the default `description` |
-| `site/nav.md` | each section's nav item |
-| `site/footer.md` | the copyright holder and link row; the body is the affiliation |
-| `site/publication.md` | words shared by a publication entry and a conference page, and `linkLabels` |
-| `home.md`, `home/affiliation.md`, `home/poster.md`, `home/links.md` | the home page: buttons and labels; the body is the introduction; one block per fragment |
-| `404.md`, `approaches.md`, `conferences.md`, `people.md`, `publications.md` | one page each; the body, where there is one, is the lede |
+| File | Holds |
+| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
+| `site/site.md` | the site `title`, the `tagline` and the default `description` |
+| `site/nav.md` | each section's nav item |
+| `site/footer.md` | the copyright holder and link row; the body is the affiliation |
+| `site/publication.md` | words shared by a publication entry and a conference page, and `linkLabels` |
+| `home.md`, `home/affiliation.md`, `home/poster.md`, `home/links.md` | the home page: buttons and labels; the body is the introduction; one block per fragment |
+| `404.md`, `approaches.md`, `people.md`, `publications.md` | one page each; the body, where there is one, is the lede |
**Front matter holds short plain strings, the body holds anything with a link or emphasis in it.**
`labels` are short words, `intros` the sentence under a section heading, `plurals` a
@@ -115,7 +115,7 @@ Two shapes, both inherited from the Jekyll site and both still served:
| `/` | `src/pages/index.astro` |
| `/approaches/` | `src/pages/approaches/index.astro` |
| `/approaches//` | `src/pages/approaches/[slug]/` |
-| `/conferences/` | `src/pages/conferences/index.astro` |
+| `/conferences/` | redirect stub to `/publications/` |
| **`/c/`** | `src/pages/c/[slug].astro` → `.html` |
| `/publications/` | `src/pages/publications/index.astro` |
| `/people/` | `src/pages/people/index.astro` |
@@ -133,6 +133,9 @@ is the _file_ path, so canonical links and sitemap entries go through `canonical
(`se24`, `se25`, `se26-exarch`, `se26-lissa`, `taas26`) redirect to the page that superseded them and
stay that way.
+**`/conferences/`** was published, so it stays as a redirect stub to `/publications/`: that page links every
+`/c/` page, so the list was a duplicate.
+
**`public/assets/**`** — served byte-for-byte at URLs that have been live for years. Never rename,
move, or run them through an optimiser. Pinned by SHA-256 in `verification/asset-sha256.txt`; if you
genuinely add or replace one, rerun `node scripts/generate-asset-baseline.mjs`.
@@ -145,7 +148,7 @@ makes them easy to lose.
**`public/CNAME`** — the deploy replaces the `gh-pages` branch wholesale, so if this file stops being
emitted, `ardoco.de` stops resolving.
-`npm run verify` asserts all four, and the deploy workflow runs it before publishing. It also checks
+`npm run verify` asserts the redirect stubs (the five `/c/` ones and `/conferences/`), the asset hashes, the two comments and `CNAME`, and the deploy workflow runs it before publishing. It also checks
WCAG contrast, that every internal link and `#fragment` resolves, that images carry intrinsic
dimensions, that no text runs into a link, that no email address appears in the served bytes, and
that `www.youtube.com` (the two screencasts) is still the only third-party origin.
@@ -160,7 +163,7 @@ that `www.youtube.com` (the two screencasts) is still the only third-party origi
| Add an approach | new `.md` in `src/content/approaches/`; `importance` sets its place in the list |
| Link a paper to approaches | `approaches: [lissa, exarch]` in its front matter — bad slugs fail the build |
| Add a person | new entry in `src/data/people.yml`; the key becomes the `/people/#anchor` |
-| Reorder the nav | `navOrder` on a conference entry; it drives the nav and the front-page list alike |
+| Reorder the home list | `navOrder` on a conference entry; it orders the home-page list and the feed |
| Add an image | drop it in `public/assets/img/`, then rerun `scripts/generate-asset-baseline.mjs` |
| Change a page's words | its file in `src/content/pages/`; the nav and footer rows are in `site/` |
| Check bib against Crossref | `python3 scripts/update_bib.py` (stdlib only; `--write` applies the safe fields) |
diff --git a/scripts/audit-features.mjs b/scripts/audit-features.mjs
index 632abf62..19220629 100644
--- a/scripts/audit-features.mjs
+++ b/scripts/audit-features.mjs
@@ -69,6 +69,17 @@ const PUB_COUNT = (readFileSync(join(SRC, 'data/papers.bib'), 'utf8').match(/^@/
`conferences: all ${stubs.length} legacy redirect stubs refresh and are noindex`,
);
+ // The folded-away page: a published URL that now only points onward.
+ for (const [file, to] of [
+ ['conferences/index.html', '/publications/'],
+ ]) {
+ const html = has(file) ? read(file) : '';
+ check(
+ html.includes(` {
const fm = frontmatter(join(SRC, 'content/conferences', f));
if (!/^publication:/m.test(fm)) return false;
diff --git a/src/components/Nav.astro b/src/components/Nav.astro
index 48465f51..773ad6d7 100644
--- a/src/components/Nav.astro
+++ b/src/components/Nav.astro
@@ -98,11 +98,6 @@ const { title } = await siteText();
color: var(--azure);
border-color: var(--azure-line);
}
- ul a[data-section='conferences']:hover,
- ul a[data-section='conferences'][aria-current='page'] {
- color: var(--violet);
- border-color: var(--violet-line);
- }
ul a[data-section='publications']:hover,
ul a[data-section='publications'][aria-current='page'] {
color: var(--green);
diff --git a/src/consts.ts b/src/consts.ts
index a22dad06..19f15d4f 100644
--- a/src/consts.ts
+++ b/src/consts.ts
@@ -21,5 +21,5 @@ export const SITE = {
* A list rather than a bare union so the nav rows in
* src/content/pages/site/nav.md are validated against it.
*/
-export const SECTIONS = ['home', 'approaches', 'conferences', 'publications', 'people'] as const;
+export const SECTIONS = ['home', 'approaches', 'publications', 'people'] as const;
export type Section = (typeof SECTIONS)[number];
diff --git a/src/content.config.ts b/src/content.config.ts
index 28fde1dc..5c6b3092 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -137,10 +137,9 @@ const conferences = defineCollection({
inPress: z.boolean().default(false),
/**
- * Navbar label and ordering, previously the `children:` array in
- * _pages/conferences.md. That one list drove both the dropdown and the
- * front-page publication order, so it had to be edited in lockstep with
- * this directory; now each entry carries its own position.
+ * Label and ordering of the home page's publication list (and the feed),
+ * previously the `children:` array in _pages/conferences.md, which also
+ * drove a navbar dropdown. Each entry now carries its own position.
*/
navLabel: z.string().optional(),
navOrder: z.number().int().optional(),
diff --git a/src/content/pages/404.md b/src/content/pages/404.md
index 67bdf153..720c649e 100644
--- a/src/content/pages/404.md
+++ b/src/content/pages/404.md
@@ -7,6 +7,5 @@ lede: 'The address you followed does not exist here. It may have been a paper pa
links:
- '[Home](/)'
- '[Approaches](/approaches/)'
- - '[Conferences](/conferences/)'
- '[Publications](/publications/)'
---
diff --git a/src/content/pages/conferences.md b/src/content/pages/conferences.md
deleted file mode 100644
index c9be7319..00000000
--- a/src/content/pages/conferences.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-# /conferences/, the list of paper pages. Each page's own words are its file in
-# src/content/conferences/, the shared ones site/publication.md.
-title: 'conferences'
-description: 'Paper pages for ARDoCo publications: abstracts, slides, replication packages and the approaches each one builds on.'
-lede: 'One page per publication, with the abstract, the approaches it builds on, and links to the paper, slides and replication package.'
----
diff --git a/src/content/pages/publications.md b/src/content/pages/publications.md
index ce661b5c..c33000bc 100644
--- a/src/content/pages/publications.md
+++ b/src/content/pages/publications.md
@@ -9,4 +9,4 @@ labels:
noResults: 'No publications match that filter.'
---
-Entries with a **Details** link have a page of their own with the abstract, slides and replication package.
+Entries with a **Details** link have a paper page of their own with the abstract, slides and replication package.
diff --git a/src/content/pages/site/nav.md b/src/content/pages/site/nav.md
index 342b614e..8b16aac4 100644
--- a/src/content/pages/site/nav.md
+++ b/src/content/pages/site/nav.md
@@ -4,7 +4,6 @@
sections:
home: '[about](/)'
approaches: '[approaches](/approaches/)'
- conferences: '[conferences](/conferences/)'
publications: '[publications](/publications/)'
people: '[people](/people/)'
---
diff --git a/src/content/pages/site/publication.md b/src/content/pages/site/publication.md
index 75f95837..8c685260 100644
--- a/src/content/pages/site/publication.md
+++ b/src/content/pages/site/publication.md
@@ -1,6 +1,6 @@
---
-# Words shared by a publication entry (/publications/), the conference list
-# (/conferences/) and a conference page (/c/).
+# Words shared by a publication entry (/publications/, via PubEntry) and a
+# conference page (/c/). The home page does not load this file.
labels:
# the chips on an entry; `details` is followed by an arrow
details: 'Details'
@@ -8,8 +8,6 @@ labels:
# the entry's `url`, shown when it has no DOI
link: 'Link'
bibtex: 'BibTeX'
- # the status in the conference list
- toAppear: 'to appear'
# before the `conferenceName` on a conference page
publishedAt: 'Published at'
toBePublishedAt: 'To be published at'
diff --git a/src/lib/conferences.ts b/src/lib/conferences.ts
index 8d3f1cba..a4d16c9f 100644
--- a/src/lib/conferences.ts
+++ b/src/lib/conferences.ts
@@ -6,10 +6,10 @@ type Conference = CollectionEntry<'conferences'>;
const isPage = (c: Conference): boolean => c.data.redirectTo === undefined;
/**
- * Navbar and front-page order.
+ * Home-page and feed order.
*
* `navOrder` came from the `children:` array in _pages/conferences.md, which
- * was the single list driving both. Entries without one (the redirect stubs)
+ * once drove a navbar dropdown as well. Entries without one (the redirect stubs)
* are not listed anywhere.
*/
function byNavOrder(a: Conference, b: Conference): number {
diff --git a/src/lib/redirect.ts b/src/lib/redirect.ts
index 759fa98b..7d467857 100644
--- a/src/lib/redirect.ts
+++ b/src/lib/redirect.ts
@@ -10,11 +10,11 @@ const escapeHtml = (s: string): string =>
* A bare meta-refresh page.
*
* Used for the five /c/ URLs that outlived the papers they pointed at
- * (se24, se25, se26-exarch, se26-lissa, taas26). Returned as a Response from
- * the route rather than rendered as markup, because rendering it through the
- * page component would make Astro inject that page's stylesheet into the
- * stub's — several KB of CSS on a page whose whole job is to be left
- * immediately.
+ * (se24, se25, se26-exarch, se26-lissa, taas26) and for /conferences/, folded
+ * into /publications/. Returned as a Response from the route rather than
+ * rendered as markup, because rendering it through the page component would
+ * make Astro inject that page's stylesheet into the stub's — several KB
+ * of CSS on a page whose whole job is to be left immediately.
*
* Lives in a .ts module rather than inline in the .astro frontmatter: raw
* closing tags inside a template literal confuse the frontmatter parser
diff --git a/src/pages/c/[slug].astro b/src/pages/c/[slug].astro
index 940d1a8d..a22d52d4 100644
--- a/src/pages/c/[slug].astro
+++ b/src/pages/c/[slug].astro
@@ -62,7 +62,7 @@ const linkRows = sections
.filter((s) => s.items.length > 0);
---
-
+
{pub && (
@@ -79,7 +79,7 @@ const linkRows = sections
Both sides of the separator need an explicit space: Astro strips the
newline between an element and the next. */}
diff --git a/src/pages/conferences/index.astro b/src/pages/conferences/index.astro
index cf5c7321..ac177249 100644
--- a/src/pages/conferences/index.astro
+++ b/src/pages/conferences/index.astro
@@ -1,126 +1,13 @@
---
-import { getCollection, getEntry } from 'astro:content';
-import Base from '../../layouts/Base.astro';
-import VenueBadge from '../../components/pub/VenueBadge.astro';
-import { listed } from '../../lib/conferences';
-import { conferencePath } from '../../lib/urls';
+import { redirectResponse } from '../../lib/redirect';
import { getPage, need } from '../../lib/pages';
/*
- * This page is new. The old site had no conferences index: the eleven paper
- * pages were reachable only from a navbar dropdown, and the page that defined
- * that dropdown had no permalink, so Jekyll published it at the accidental
- * address /_pages/conferences/ (which now redirects here).
+ * /conferences/ listed the paper pages, but /publications/ already links each
+ * one (title and "Details" chip) and "conferences" was a misnomer for a list
+ * that includes journal papers. The list is folded into /publications/; this
+ * stub keeps the URL, which has been published since the Astro migration.
*/
-const all = listed(await getCollection('conferences'));
-const entries = await Promise.all(
- all.map(async (c) => ({
- c,
- pub: c.data.publication ? await getEntry(c.data.publication) : undefined,
- })),
-);
-
-/* The words: src/content/pages/conferences.md, and site/publication.md for a row. */
-const page = await getPage('conferences');
-const words = await getPage('site/publication');
+const page = await getPage('publications');
+return redirectResponse('/publications/', need(page.data.title, 'publications.title'));
---
-
-
-
diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts
index 5352a599..53787b7b 100644
--- a/src/pages/sitemap.xml.ts
+++ b/src/pages/sitemap.xml.ts
@@ -23,7 +23,6 @@ export async function GET() {
const urls = [
'/',
'/approaches/',
- '/conferences/',
'/publications/',
'/people/',
...standalone.map((entry) => `/${entry.id}/`),
diff --git a/src/styles/tokens.css b/src/styles/tokens.css
index aad13dcc..b9f197be 100644
--- a/src/styles/tokens.css
+++ b/src/styles/tokens.css
@@ -109,7 +109,10 @@
--sec-dim: var(--azure-dim);
--sec-glow: var(--azure-glow);
}
-[data-section='conferences'] {
+/* Violet: only the home page's "Relevant and recent publications" section
+ (data-section="papers") uses it; the nav and /c/ pages are green, as
+ publications. */
+[data-section='papers'] {
--sec: var(--violet);
--sec-strong: var(--violet-strong);
--sec-line: var(--violet-line);
From e4d80ff90af95813f8c6a2b51dfbcca7985fff1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:04:25 +0200
Subject: [PATCH 05/26] Group approaches and tag the artifacts they link
Approaches get a required group (tlr, consistency, tools) and the pairs of
artifact they link. importance now only orders within a group, so the pages
sort through ordered() instead of a bare importance sort. tv.md gets its group
here and is replaced by the tools page later in the series.
Co-Authored-By: Claude Opus 5.5
---
src/components/Artifacts.astro | 61 +++++++++++++++++++
src/consts.ts | 19 ++++++
src/content.config.ts | 16 ++++-
src/content/approaches/arcotl.md | 2 +
src/content/approaches/ardocode.md | 4 +-
src/content/approaches/exarch.md | 4 +-
.../approaches/inconsistency-detection.md | 2 +
src/content/approaches/lissa.md | 8 ++-
src/content/approaches/swattr.md | 2 +
src/content/approaches/transarc.md | 2 +
src/content/approaches/tv.md | 1 +
src/lib/approaches.ts | 20 ++++++
src/pages/approaches/[slug]/index.astro | 5 ++
src/pages/approaches/index.astro | 5 +-
src/pages/index.astro | 5 +-
15 files changed, 145 insertions(+), 11 deletions(-)
create mode 100644 src/components/Artifacts.astro
create mode 100644 src/lib/approaches.ts
diff --git a/src/components/Artifacts.astro b/src/components/Artifacts.astro
new file mode 100644
index 00000000..ca0aae41
--- /dev/null
+++ b/src/components/Artifacts.astro
@@ -0,0 +1,61 @@
+---
+/**
+ * The pairs of artifact an approach links — `artifacts` in its front matter,
+ * e.g. SAD ↔ SAM — as a row of tags. Used on the approach's card on
+ * /approaches/ and under the lede on its own page. Most approaches link one
+ * pair; a generic one like LiSSA lists several.
+ */
+interface Props {
+ pairs: [string, string][];
+}
+const { pairs } = Astro.props;
+---
+
+
+ {pairs.map(([from, to]) => (
+
+ {from}{' '}
+ {/* The arrow says "linked with". A glyph, so it lives here rather than
+ in the content; a screen reader gets the words instead. The explicit
+ spaces keep the words from running into the tags in the accessible
+ text ("SADlinked withSAM"): Astro strips the whitespace between
+ elements, so none would survive otherwise. */}
+
+ ↔
+
+ {' '}linked with{' '}
+ {to}
+
+ ))}
+
+
+
diff --git a/src/consts.ts b/src/consts.ts
index 19f15d4f..2d18cac8 100644
--- a/src/consts.ts
+++ b/src/consts.ts
@@ -23,3 +23,22 @@ export const SITE = {
*/
export const SECTIONS = ['home', 'approaches', 'publications', 'people'] as const;
export type Section = (typeof SECTIONS)[number];
+
+/**
+ * The four kinds of artifact an approach can link, as the short tags the site
+ * shows: `SAD` is architecture documentation, `SAM` an architecture model. A
+ * list rather than a bare union so `artifacts` in the approaches schema can
+ * validate against it.
+ */
+export const ARTIFACTS = ['Requirements', 'SAD', 'SAM', 'Code'] as const;
+export type Artifact = (typeof ARTIFACTS)[number];
+
+/**
+ * The groups /approaches/ is divided into, in the order the page shows them:
+ * traceability link recovery, consistency analysis, then the tools built on
+ * both. Each approach names its group in front matter (`group`); its
+ * `importance` orders it within that group. A list rather than a bare union so
+ * the schema can validate against it and the page can iterate it.
+ */
+export const APPROACH_GROUPS = ['tlr', 'consistency', 'tools'] as const;
+export type ApproachGroup = (typeof APPROACH_GROUPS)[number];
diff --git a/src/content.config.ts b/src/content.config.ts
index 5c6b3092..bd7942d8 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -2,7 +2,7 @@ import { defineCollection, reference } from 'astro:content';
import { z } from 'zod';
import { file, glob } from 'astro/loaders';
import { bibtexLoader } from './loaders/bibtex';
-import { SECTIONS } from './consts';
+import { APPROACH_GROUPS, ARTIFACTS, SECTIONS } from './consts';
/** Conference brand colours for the publication badges, keyed by BibTeX `abbr`. */
const venues = defineCollection({
@@ -96,8 +96,20 @@ const approaches = defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
- /** Sort key for /approaches/, roughly the order the work was published. */
+ /** The section of /approaches/ the card sits in; see APPROACH_GROUPS. */
+ group: z.enum(APPROACH_GROUPS),
+ /** Order within the group, lowest first: roughly the order the work was published. */
importance: z.number().int(),
+ /**
+ * The pairs of artifact the approach links, each as two short tags: `SAD`
+ * (architecture documentation), `SAM` (architecture model), `Code`,
+ * `Requirements`. A list of pairs rather than one list of tags, because a
+ * generic approach like LiSSA links several pairs, and a flat list would
+ * read as one chain (Requirements ↔ SAD ↔ Code ↔ …). Shown as tags on the
+ * card and under the page's lede.
+ */
+ artifacts: z.array(z.tuple([z.enum(ARTIFACTS), z.enum(ARTIFACTS)])).default([]),
+ repositories: z.array(z.object({ name: z.string(), url: z.url() })).default([]),
repositories: z.array(z.object({ name: z.string(), url: z.url() })).default([]),
figure: figure.optional(),
}),
diff --git a/src/content/approaches/arcotl.md b/src/content/approaches/arcotl.md
index f23ad627..47f45c8e 100644
--- a/src/content/approaches/arcotl.md
+++ b/src/content/approaches/arcotl.md
@@ -2,6 +2,8 @@
title: ArCoTL
description: ArCoTL – TLR between Software Architecture Models and Code.
importance: 2
+group: tlr
+artifacts: [['SAM', 'Code']]
figure:
src: /assets/img/approaches/icse24-transarc.svg
alt: ArCoTL Overview
diff --git a/src/content/approaches/ardocode.md b/src/content/approaches/ardocode.md
index 1b0836d4..c3df4a72 100644
--- a/src/content/approaches/ardocode.md
+++ b/src/content/approaches/ardocode.md
@@ -1,7 +1,9 @@
---
title: ArDoCode
description: ArDoCode – TLR between Software Architecture Documentation and Code.
-importance: 5
+importance: 4
+group: tlr
+artifacts: [['SAD', 'Code']]
figure:
src: /assets/img/approaches/icse24-ardocode.svg
alt: ArDoCode Overview
diff --git a/src/content/approaches/exarch.md b/src/content/approaches/exarch.md
index f133d9ba..e665a853 100644
--- a/src/content/approaches/exarch.md
+++ b/src/content/approaches/exarch.md
@@ -1,7 +1,9 @@
---
title: ExArch
description: ExArch – LLM-based Architecture Component Name Extraction for TLR between Software Architecture Documentation and Code.
-importance: 4
+importance: 5
+group: tlr
+artifacts: [['SAD', 'Code']]
figure:
src: /assets/img/approaches/icsa25-transarc.svg
alt: ExArch Overview
diff --git a/src/content/approaches/inconsistency-detection.md b/src/content/approaches/inconsistency-detection.md
index 25009eea..04e17147 100644
--- a/src/content/approaches/inconsistency-detection.md
+++ b/src/content/approaches/inconsistency-detection.md
@@ -2,6 +2,8 @@
title: Inconsistency Detection
description: Documentation-Model-Inconsistency-Analysis pipeline.
importance: 8
+group: consistency
+artifacts: [['SAD', 'SAM']]
figure:
src: /assets/img/approaches/icsa23-inconsistency.svg
alt: Approach Overview
diff --git a/src/content/approaches/lissa.md b/src/content/approaches/lissa.md
index 242481a2..fb23313b 100644
--- a/src/content/approaches/lissa.md
+++ b/src/content/approaches/lissa.md
@@ -1,7 +1,13 @@
---
title: LiSSA
description: LiSSA – LLM/RAG-based TLR.
-importance: 6
+importance: 7
+group: tlr
+artifacts:
+ - ['Requirements', 'Code']
+ - ['Requirements', 'Requirements']
+ - ['SAD', 'Code']
+ - ['SAD', 'SAM']
figure:
src: /assets/img/approaches/icse25-lissa.svg
alt: LiSSA Overview
diff --git a/src/content/approaches/swattr.md b/src/content/approaches/swattr.md
index 9f4d019a..bf247a78 100644
--- a/src/content/approaches/swattr.md
+++ b/src/content/approaches/swattr.md
@@ -2,6 +2,8 @@
title: SWATTR
description: SWATTR – TLR between Software Architecture Documentation and Software Architecture Models.
importance: 1
+group: tlr
+artifacts: [['SAD', 'SAM']]
figure:
src: /assets/img/approaches/ecsa21-swattr.svg
alt: SWATTR Overview
diff --git a/src/content/approaches/transarc.md b/src/content/approaches/transarc.md
index db0cdc0f..a2c1cdc4 100644
--- a/src/content/approaches/transarc.md
+++ b/src/content/approaches/transarc.md
@@ -2,6 +2,8 @@
title: TransArC
description: TransArC – TLR between Software Architecture Documentation, Models, and Code.
importance: 3
+group: tlr
+artifacts: [['SAD', 'Code']]
figure:
src: /assets/img/approaches/icse24-transarc.svg
alt: TransArC Overview
diff --git a/src/content/approaches/tv.md b/src/content/approaches/tv.md
index 62da5051..1c0c1612 100644
--- a/src/content/approaches/tv.md
+++ b/src/content/approaches/tv.md
@@ -2,6 +2,7 @@
title: ARDoCo-TV
description: 'Trace View: a viewer for trace links.'
importance: 9
+group: tools
repositories:
- name: Implementation (v2)
url: https://github.com/ardoco/traceview-v2
diff --git a/src/lib/approaches.ts b/src/lib/approaches.ts
new file mode 100644
index 00000000..ca3b6667
--- /dev/null
+++ b/src/lib/approaches.ts
@@ -0,0 +1,20 @@
+import type { CollectionEntry } from 'astro:content';
+import { APPROACH_GROUPS } from '../consts';
+
+type Approach = CollectionEntry<'approaches'>;
+
+/**
+ * Page order: by group in APPROACH_GROUPS order, then by `importance` within
+ * the group. `importance` used to be one global sequence; since the groups
+ * came in it only means something inside a group, so a bare sort on it would
+ * interleave them. The title breaks a tie, so two equal numbers do not
+ * reshuffle between builds.
+ */
+export function ordered(all: Approach[]): Approach[] {
+ return [...all].sort(
+ (a, b) =>
+ APPROACH_GROUPS.indexOf(a.data.group) - APPROACH_GROUPS.indexOf(b.data.group) ||
+ a.data.importance - b.data.importance ||
+ a.data.title.localeCompare(b.data.title),
+ );
+}
diff --git a/src/pages/approaches/[slug]/index.astro b/src/pages/approaches/[slug]/index.astro
index 1f9ae402..6576123c 100644
--- a/src/pages/approaches/[slug]/index.astro
+++ b/src/pages/approaches/[slug]/index.astro
@@ -3,6 +3,7 @@ import { getCollection, getEntry, render } from 'astro:content';
import Base from '../../../layouts/Base.astro';
import Prose from '../../../components/Prose.astro';
import Figure from '../../../components/Figure.astro';
+import Artifacts from '../../../components/Artifacts.astro';
import VenueBadge from '../../../components/pub/VenueBadge.astro';
import { conferencePath } from '../../../lib/urls';
@@ -43,6 +44,7 @@ const related = await Promise.all(
{d.title}
{d.description}
+ {d.artifacts.length > 0 && }
{d.figure && }
@@ -100,6 +102,9 @@ const related = await Promise.all(
color: var(--text-muted);
margin: 0;
}
+ header :global(.artifacts) {
+ margin-top: 0.9rem;
+ }
.block {
margin-top: 2.5rem;
diff --git a/src/pages/approaches/index.astro b/src/pages/approaches/index.astro
index de3e1226..714d9e53 100644
--- a/src/pages/approaches/index.astro
+++ b/src/pages/approaches/index.astro
@@ -2,11 +2,10 @@
import { getCollection } from 'astro:content';
import Base from '../../layouts/Base.astro';
import { approachPath } from '../../lib/urls';
+import { ordered } from '../../lib/approaches';
import { getPage, need } from '../../lib/pages';
-const approaches = (await getCollection('approaches')).sort(
- (a, b) => a.data.importance - b.data.importance,
-);
+const approaches = ordered(await getCollection('approaches'));
/* The words: src/content/pages/approaches.md. */
const page = await getPage('approaches');
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 47df9818..62391c5a 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -2,14 +2,13 @@
import { getCollection, getEntry } from 'astro:content';
import Base from '../layouts/Base.astro';
import { featured } from '../lib/conferences';
+import { ordered } from '../lib/approaches';
import { approachPath, conferencePath } from '../lib/urls';
import { SITE } from '../consts';
import Email from '../components/Email.astro';
import { getPage, siteText } from '../lib/pages';
-const approaches = (await getCollection('approaches')).sort(
- (a, b) => a.data.importance - b.data.importance,
-);
+const approaches = ordered(await getCollection('approaches'));
const conferences = featured(await getCollection('conferences'));
const highlights = await Promise.all(
From d8725dc810959510da9dc85e7099b75fb04bc330 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:04:45 +0200
Subject: [PATCH 06/26] List an approach's journal papers on its page
relatedPublications() merges the conference pages that name an approach with
the BibTeX keys in its own publications field, for papers that only exist as a
redirect stub (the TAAS extension of ExArch). The card badges come from
relatedVenues(), one per venue.
Co-Authored-By: Claude Opus 5.5
---
src/components/pub/VenueBadge.astro | 3 +-
src/content.config.ts | 10 +++
src/content/approaches/exarch.md | 1 +
src/lib/approaches.ts | 93 ++++++++++++++++++++++++-
src/lib/publications.ts | 19 +++++
src/pages/approaches/[slug]/index.astro | 33 +++------
6 files changed, 133 insertions(+), 26 deletions(-)
diff --git a/src/components/pub/VenueBadge.astro b/src/components/pub/VenueBadge.astro
index c1e08360..f0c9137d 100644
--- a/src/components/pub/VenueBadge.astro
+++ b/src/components/pub/VenueBadge.astro
@@ -1,9 +1,10 @@
---
import { getEntry } from 'astro:content';
import type { DataEntryMap } from 'astro:content';
+import type { VenueRef } from '../../lib/publications';
interface Props {
- abbr: { collection: 'venues'; id: string } | undefined;
+ abbr: VenueRef | undefined;
}
const { abbr } = Astro.props;
diff --git a/src/content.config.ts b/src/content.config.ts
index bd7942d8..eee9c087 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -111,6 +111,16 @@ const approaches = defineCollection({
artifacts: z.array(z.tuple([z.enum(ARTIFACTS), z.enum(ARTIFACTS)])).default([]),
repositories: z.array(z.object({ name: z.string(), url: z.url() })).default([]),
repositories: z.array(z.object({ name: z.string(), url: z.url() })).default([]),
+ /**
+ * Papers about the approach that have no conference page of their own, as
+ * references to BibTeX entries (the id is the BibTeX key). Most papers
+ * reach an approach the other way round, through a conference page's
+ * `approaches:`; this is for the ones that only exist as a redirect stub,
+ * like a journal extension, whose stub would otherwise attach the
+ * approach to the paper it redirects to. Merged with the conference
+ * pages by relatedPublications() in lib/approaches.ts.
+ */
+ publications: z.array(reference('publications')).default([]),
figure: figure.optional(),
}),
});
diff --git a/src/content/approaches/exarch.md b/src/content/approaches/exarch.md
index e665a853..c904a7d2 100644
--- a/src/content/approaches/exarch.md
+++ b/src/content/approaches/exarch.md
@@ -8,6 +8,7 @@ figure:
src: /assets/img/approaches/icsa25-transarc.svg
alt: ExArch Overview
plate: true
+publications: [fuchss_whos_2026]
repositories:
- name: Implementation
url: https://github.com/ardoco/ardoco
diff --git a/src/lib/approaches.ts b/src/lib/approaches.ts
index ca3b6667..b2c205a7 100644
--- a/src/lib/approaches.ts
+++ b/src/lib/approaches.ts
@@ -1,5 +1,7 @@
-import type { CollectionEntry } from 'astro:content';
+import { getCollection, getEntry, type CollectionEntry } from 'astro:content';
import { APPROACH_GROUPS } from '../consts';
+import { conferencePath } from './urls';
+import { doiOrUrl, type VenueRef } from './publications';
type Approach = CollectionEntry<'approaches'>;
@@ -18,3 +20,92 @@ export function ordered(all: Approach[]): Approach[] {
a.data.title.localeCompare(b.data.title),
);
}
+
+/** What both approach pages render for one related paper. */
+export interface RelatedPublication {
+ title: string;
+ /** Site path for a conference page, absolute URL for a paper elsewhere. */
+ href: string;
+ /** The short label line under the title. */
+ venue: string | undefined;
+ /** For the venue badge; absent when the BibTeX entry has no `abbr`. */
+ abbr: VenueRef | undefined;
+ year: number;
+ month: number;
+}
+
+/**
+ * Every paper that belongs to this approach, newest first: the conference
+ * pages that name it, plus the papers the approach lists itself in
+ * `publications`.
+ *
+ * The Jekyll version compared `conf.approaches` against `page.title` as
+ * strings, so a renamed approach quietly emptied this list. The collection
+ * stores references, so the join is by id and the build fails instead.
+ *
+ * Redirect stubs are left out of the conference side: they stand in for a
+ * page that superseded them, which is listed in its own right. That is also
+ * why direct publications exist — a paper whose only page is such a stub
+ * (the TAAS journal extension) cannot be reached through `approaches:` on a
+ * conference page without showing the paper it redirects to.
+ *
+ * A paper reachable both ways is listed once, as its conference page: that
+ * page carries the abstract and links, which a bare DOI does not.
+ */
+export async function relatedPublications(approach: Approach): Promise {
+ const conferences = (await getCollection('conferences'))
+ .filter((c) => c.data.redirectTo === undefined)
+ .filter((c) => c.data.approaches.some((ref) => ref.id === approach.id));
+
+ const found = new Map();
+ const withoutPub: RelatedPublication[] = [];
+
+ for (const c of conferences) {
+ const pub = c.data.publication ? await getEntry(c.data.publication) : undefined;
+ const item: RelatedPublication = {
+ title: c.data.title,
+ href: conferencePath(c.id),
+ venue: c.data.pubShortName ?? c.data.conferenceName,
+ abbr: pub?.data.abbr,
+ year: pub?.data.year ?? c.data.year ?? 0,
+ month: pub?.data.month ?? 0,
+ };
+ if (pub) found.set(pub.id, item);
+ else withoutPub.push(item);
+ }
+
+ for (const ref of approach.data.publications) {
+ if (found.has(ref.id)) continue;
+ const pub = await getEntry(ref);
+ // The entry's `html` slug is no use here: for these papers it names a
+ // redirect stub, which would bounce to a different paper.
+ const href = doiOrUrl(pub);
+ if (!href)
+ throw new Error(`approaches/${approach.id}: publication ${pub.id} has no DOI or url`);
+ const where = pub.data.abbr?.id ?? pub.data.journal ?? pub.data.booktitle;
+ found.set(pub.id, {
+ title: pub.data.title,
+ href,
+ venue: where ? `${where} ${pub.data.year}` : String(pub.data.year),
+ abbr: pub.data.abbr,
+ year: pub.data.year,
+ month: pub.data.month ?? 0,
+ });
+ }
+
+ return [...found.values(), ...withoutPub].sort(
+ (a, b) => b.year - a.year || b.month - a.month || a.title.localeCompare(b.title),
+ );
+}
+
+/**
+ * One badge per venue, newest paper first: two papers at the same conference
+ * would otherwise print its badge twice on the approach's card.
+ */
+export async function relatedVenues(approach: Approach): Promise {
+ const venues = new Map();
+ for (const { abbr } of await relatedPublications(approach)) {
+ if (abbr && !venues.has(abbr.id)) venues.set(abbr.id, abbr);
+ }
+ return [...venues.values()];
+}
diff --git a/src/lib/publications.ts b/src/lib/publications.ts
index 12f7e149..c36c3777 100644
--- a/src/lib/publications.ts
+++ b/src/lib/publications.ts
@@ -1,7 +1,11 @@
import type { CollectionEntry } from 'astro:content';
+import { conferencePath } from './urls';
type Pub = CollectionEntry<'publications'>;
+/** A reference to a venues.yml entry, as `abbr` on a publication. */
+export type VenueRef = NonNullable;
+
/**
* Newest first, fully deterministic.
*
@@ -32,3 +36,18 @@ export function byYear(pubs: Pub[]): { year: number; pubs: Pub[] }[] {
.sort((a, b) => b[0] - a[0])
.map(([year, list]) => ({ year, pubs: list.sort(byNewest) }));
}
+
+/** The paper's DOI as a link, else its `url`; undefined when it has neither. */
+export function doiOrUrl(pub: Pub): string | undefined {
+ return pub.data.doi ? `https://doi.org/${pub.data.doi}` : pub.data.url;
+}
+
+/**
+ * Where a link "to the paper" goes: its own page under /c/ when it has one —
+ * that page carries the abstract, slides and every other link — otherwise
+ * straight to the DOI, otherwise to its `url`. Undefined when there is none.
+ */
+export function paperHref(pub: Pub): string | undefined {
+ if (pub.data.infoSlug) return conferencePath(pub.data.infoSlug);
+ return doiOrUrl(pub);
+}
diff --git a/src/pages/approaches/[slug]/index.astro b/src/pages/approaches/[slug]/index.astro
index 6576123c..16cdf6d6 100644
--- a/src/pages/approaches/[slug]/index.astro
+++ b/src/pages/approaches/[slug]/index.astro
@@ -1,11 +1,11 @@
---
-import { getCollection, getEntry, render } from 'astro:content';
+import { getCollection, render } from 'astro:content';
import Base from '../../../layouts/Base.astro';
import Prose from '../../../components/Prose.astro';
import Figure from '../../../components/Figure.astro';
import Artifacts from '../../../components/Artifacts.astro';
import VenueBadge from '../../../components/pub/VenueBadge.astro';
-import { conferencePath } from '../../../lib/urls';
+import { relatedPublications } from '../../../lib/approaches';
export async function getStaticPaths() {
const all = await getCollection('approaches');
@@ -16,24 +16,9 @@ const { entry } = Astro.props;
const d = entry.data;
const { Content } = await render(entry);
-/*
- * Reverse index: every conference page that names this approach.
- *
- * The Jekyll version compared `conf.approaches` against `page.title` as
- * strings, so a renamed approach quietly emptied this list. The collection
- * stores references, so the join is by id and the build fails instead.
- */
-const conferences = (await getCollection('conferences'))
- .filter((c) => c.data.redirectTo === undefined)
- .filter((c) => c.data.approaches.some((ref) => ref.id === entry.id))
- .sort((a, b) => (b.data.year ?? 0) - (a.data.year ?? 0));
-
-const related = await Promise.all(
- conferences.map(async (c) => ({
- conference: c,
- pub: c.data.publication ? await getEntry(c.data.publication) : undefined,
- })),
-);
+/* Every conference page that names this approach, plus its own
+ `publications` — see relatedPublications(). */
+const related = await relatedPublications(entry);
---
@@ -72,12 +57,12 @@ const related = await Promise.all(
))}
From 3d3bf60e98dc6178b451adb61e88f5fc01fe416c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:04:51 +0200
Subject: [PATCH 07/26] Add gallery figures to approach pages
A gallery list in front matter shows extra images after the page text, with an
optional caption (Markdown images cannot carry width and height, which the
audit requires). The light plate colour becomes a token. LiSSA gets its AIRE
2025 figure.
Co-Authored-By: Claude Opus 5.5
---
src/components/Figure.astro | 17 +++++++++--
src/content.config.ts | 39 ++++++++++++++++++-------
src/content/approaches/lissa.md | 5 ++++
src/pages/approaches/[slug]/index.astro | 14 +++++++++
src/styles/tokens.css | 2 ++
5 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/src/components/Figure.astro b/src/components/Figure.astro
index a97ac0e1..5e67b4aa 100644
--- a/src/components/Figure.astro
+++ b/src/components/Figure.astro
@@ -5,15 +5,18 @@ interface Props {
src: string;
alt: string;
plate?: boolean;
+ /** Plain text under the image. The approach figure has none; a gallery image may. */
+ caption?: string;
}
-const { src, alt, plate = true } = Astro.props;
+const { src, alt, plate = true, caption } = Astro.props;
const { width, height } = intrinsic(src);
/*
* How wide the figure is allowed to get.
*
- * The approach diagrams are small and wide (icsa25-transarc.svg is 337x110).
+ * The approach diagrams are small and wide (icsa25-transarc.svg is 337x110;
+ * despite its name it depicts ExArch).
* Stretched across the full 1120px column they dominate the page and dwarf the
* text they illustrate, so vectors are capped at roughly the prose measure.
*
@@ -26,6 +29,7 @@ const maxWidth = isVector ? 'var(--measure)' : `${width}px`;
+ {caption && {caption}}
diff --git a/src/content.config.ts b/src/content.config.ts
index eee9c087..29401ce8 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -75,22 +75,38 @@ const publications = defineCollection({
}),
});
-const figure = z.object({
+/**
+ * An image under public/, as every figure and gallery picture is given.
+ *
+ * The approach diagrams are dark-on-transparent SVGs drawn for a white page.
+ * On a near-black background they need a light plate behind them. Only
+ * screenshots, which bring their own background, turn it off.
+ *
+ * The draw.io exports (ecsa21-swattr.svg, icse24-ardocode.svg) carry
+ * `color-scheme: light dark` and light-dark() fills, so on this dark site
+ * they drew black boxes onto the white plate. Their root style is pinned
+ * to `color-scheme: light`; a fresh export needs the same edit.
+ */
+const image = z.object({
src: z.string(),
alt: z.string(),
- /**
- * The approach diagrams are dark-on-transparent SVGs drawn for a white page.
- * On a near-black background they need a light plate behind them. Only
- * screenshots, which bring their own background, turn it off.
- *
- * The draw.io exports (ecsa21-swattr.svg, icse24-ardocode.svg) carry
- * `color-scheme: light dark` and light-dark() fills, so on this dark site
- * they drew black boxes onto the white plate. Their root style is pinned
- * to `color-scheme: light`; a fresh export needs the same edit.
- */
plate: z.boolean().default(true),
});
+const figure = image;
+
+/**
+ * One extra image on an approach page, after its text. Front matter rather
+ * than a Markdown image in the body: Markdown cannot carry width and height,
+ * and scripts/audit-site.mjs fails any without them.
+ */
+const galleryImage = image
+ .extend({
+ /** Shown under the image; plain text. */
+ caption: z.string().optional(),
+ })
+ .strict();
+
const approaches = defineCollection({
loader: glob({ base: 'src/content/approaches', pattern: '**/*.md' }),
schema: z.object({
@@ -122,6 +138,7 @@ const approaches = defineCollection({
*/
publications: z.array(reference('publications')).default([]),
figure: figure.optional(),
+ gallery: z.array(galleryImage).default([]),
}),
});
diff --git a/src/content/approaches/lissa.md b/src/content/approaches/lissa.md
index fb23313b..d9ef6432 100644
--- a/src/content/approaches/lissa.md
+++ b/src/content/approaches/lissa.md
@@ -12,6 +12,11 @@ figure:
src: /assets/img/approaches/icse25-lissa.svg
alt: LiSSA Overview
plate: true
+gallery:
+ - src: /assets/img/approaches/aire25-aire.svg
+ alt: AIRE 2025 Overview
+ caption: 'Beyond Retrieval: A Study of Using LLM Ensembles for Candidate Filtering in Requirements Traceability (AIRE 2025)'
+ plate: true
repositories:
- name: Implementation
url: https://github.com/ardoco/lissa
diff --git a/src/pages/approaches/[slug]/index.astro b/src/pages/approaches/[slug]/index.astro
index 16cdf6d6..8bcd28eb 100644
--- a/src/pages/approaches/[slug]/index.astro
+++ b/src/pages/approaches/[slug]/index.astro
@@ -38,6 +38,16 @@ const related = await relatedPublications(entry);
+ {/* Extra figures from front matter (`gallery`), after the text they
+ illustrate; see the schema for why they are not Markdown images. */}
+ {d.gallery.length > 0 && (
+
+ {d.gallery.map((g) => (
+
+ ))}
+
+ )}
+
{d.repositories.length > 0 && (
Code
@@ -91,6 +101,10 @@ const related = await relatedPublications(entry);
margin-top: 0.9rem;
}
+ .gallery {
+ margin-top: 2.25rem;
+ }
+
.block {
margin-top: 2.5rem;
}
diff --git a/src/styles/tokens.css b/src/styles/tokens.css
index b9f197be..fc264470 100644
--- a/src/styles/tokens.css
+++ b/src/styles/tokens.css
@@ -21,6 +21,8 @@
--bg-1: #111620;
--bg-2: #171d28;
--bg-3: #1e2633;
+ /* The light plate behind dark line-art diagrams (Figure, approach cards). */
+ --plate: #fff;
--border: rgb(255 255 255 / 9%);
--border-strong: rgb(255 255 255 / 17%);
From 5c414dd781ed0f38925acbed3c057c94e38e6006 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:04:58 +0200
Subject: [PATCH 08/26] Draw ArCoTL's own figure
ArCoTL showed the TransArC diagram. The new figure is the heuristic
computation graph from the ICSE 2024 paper.
Co-Authored-By: Claude Opus 5.5
---
.../assets/img/approaches/icse24-arcotl.svg | 781 ++++++++++++++++++
src/content/approaches/arcotl.md | 4 +-
verification/asset-sha256.txt | 1 +
3 files changed, 784 insertions(+), 2 deletions(-)
create mode 100644 public/assets/img/approaches/icse24-arcotl.svg
diff --git a/public/assets/img/approaches/icse24-arcotl.svg b/public/assets/img/approaches/icse24-arcotl.svg
new file mode 100644
index 00000000..e677a846
--- /dev/null
+++ b/public/assets/img/approaches/icse24-arcotl.svg
@@ -0,0 +1,781 @@
+
+
diff --git a/src/content/approaches/arcotl.md b/src/content/approaches/arcotl.md
index 47f45c8e..8e135a60 100644
--- a/src/content/approaches/arcotl.md
+++ b/src/content/approaches/arcotl.md
@@ -5,8 +5,8 @@ importance: 2
group: tlr
artifacts: [['SAM', 'Code']]
figure:
- src: /assets/img/approaches/icse24-transarc.svg
- alt: ArCoTL Overview
+ src: /assets/img/approaches/icse24-arcotl.svg
+ alt: ArCoTL heuristic computation graph
plate: true
repositories:
- name: Implementation
diff --git a/verification/asset-sha256.txt b/verification/asset-sha256.txt
index c013a51b..7c570fb0 100644
--- a/verification/asset-sha256.txt
+++ b/verification/asset-sha256.txt
@@ -15,6 +15,7 @@ b12be95af68108a34d1538afa842e606471f0073b7fa770a768a29cc07a5fc39 assets/img/app
0738cad487eafbc432d7c58d949edaa6fdfeb4572dd58e950da4667fee9cb242 assets/img/approaches/icsa23-inconsistency.svg
e6025dc3eedc594dbf693e3442792f019b91610d82239afb596d358419cd3cb4 assets/img/approaches/icsa25-transarc.svg
d3224cf1cf0833acbb788cdfaf11b4809168f8ddcfd8b0c93f5773058b4756ab assets/img/approaches/icsa26-archguard.svg
+bab179d5a965fa0a4b30e681a3b9311d696724e4d13e37a7f7a025d55fe96fe7 assets/img/approaches/icse24-arcotl.svg
48d8faed4ec20678777396e1f060b738e465f4e62607941fbc7e6e5a06601e99 assets/img/approaches/icse24-ardocode.svg
5b182296e53933f645620fb9949d2524f49dd8c3cabd731761ab7b0e76b4c348 assets/img/approaches/icse24-transarc.svg
0d644debfd32492225acdeb67d5c392585d7bffe4f50c27ec972265b824e1094 assets/img/approaches/icse25-lissa.svg
From 16917761955102c506dabe8063285eafa72a7da4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:05:08 +0200
Subject: [PATCH 09/26] Add ArTEMiS, the TAAS extension of ExArch
ArTEMiS recognises architecture entities with an LLM for documentation to model
links. ExArch points to it as its journal extension; the paper reaches both
pages through their publications field.
Co-Authored-By: Claude Opus 5.5
---
.../assets/img/approaches/taas26-artemis.svg | 361 ++++++++++++++++++
src/content/approaches/artemis.md | 28 ++
src/content/approaches/exarch.md | 1 +
verification/asset-sha256.txt | 1 +
4 files changed, 391 insertions(+)
create mode 100644 public/assets/img/approaches/taas26-artemis.svg
create mode 100644 src/content/approaches/artemis.md
diff --git a/public/assets/img/approaches/taas26-artemis.svg b/public/assets/img/approaches/taas26-artemis.svg
new file mode 100644
index 00000000..70d006f1
--- /dev/null
+++ b/public/assets/img/approaches/taas26-artemis.svg
@@ -0,0 +1,361 @@
+
+
diff --git a/src/content/approaches/artemis.md b/src/content/approaches/artemis.md
new file mode 100644
index 00000000..7532ac59
--- /dev/null
+++ b/src/content/approaches/artemis.md
@@ -0,0 +1,28 @@
+---
+title: ArTEMiS
+description: ArTEMiS – LLM-based Architecture Entity Recognition for TLR between Software Architecture Documentation and Models.
+importance: 6
+group: tlr
+artifacts: [['SAD', 'SAM']]
+figure:
+ src: /assets/img/approaches/taas26-artemis.svg
+ alt: ArTEMiS Overview
+ plate: true
+publications: [fuchss_whos_2026]
+repositories:
+ - name: Implementation
+ url: https://github.com/ardoco/ardoco
+ - name: Named Architecture Entity Recognition library
+ url: https://github.com/ardoco/named-architecture-entity-recognition
+ - name: Replication Package (TAAS)
+ url: https://github.com/ardoco/Replication-Package-TAAS25_LLM-assisted-Software-Traceability-with-Architecture-Entity-Recognition
+---
+
+ArTEMiS (Architecture Traceability with Entity Matching via Semantic inference) links software architecture documentation (SAD) to software architecture models (SAM) using an LLM.
+A specialized, LLM-based named entity recognition finds the architecture entities mentioned in the SAD, including coreferences and alternative names, and matches them to the elements of the SAM.
+It replaces the text stages of [SWATTR](/approaches/swattr/) through the NER connection generator and is built on the Named Architecture Entity Recognition (NAER) library.
+ArTEMiS was introduced in the TAAS journal extension of the [ExArch](/approaches/exarch/) paper, "Who's Who? LLM-assisted Software Traceability with Architecture Entity Recognition".
+
+- How it works: A first prompt asks the LLM to name the architecturally relevant components in the SAD, with their alternative names and the lines that mention them. The names of the SAM elements are given as positive examples. A second prompt converts this output to JSON. The identified entities are then matched to the SAM elements by string similarity and embedding similarity.
+- Hybrids: ArTEMiS can also stand in for SWATTR in larger pipelines that link the SAD to code. ArTEMiS in ExArch uses an LLM-generated SAM, and ArTEMiS in TransArC uses a manual SAM.
+- Results: With GPT-5, ArTEMiS achieved an average F1 of 0.81 for SAD-SAM links, slightly above SWATTR (0.80), and a higher average recall (0.85 vs. 0.77). Integrated into TransArC, it raised the average F1 for SAD-code links from 0.80 to 0.85 and the average recall from 0.77 to 0.87. TransArC with ExArch (GPT-4o) and ArTEMiS (GPT-5) reached a weighted average F1 of 0.87, the best of the approaches that need no manual SAM (ArDoCode: 0.62).
diff --git a/src/content/approaches/exarch.md b/src/content/approaches/exarch.md
index c904a7d2..a585845a 100644
--- a/src/content/approaches/exarch.md
+++ b/src/content/approaches/exarch.md
@@ -24,3 +24,4 @@ The goal is to bridge the SAD–code gap without manual modeling.
- How it works: Given the software architecture text and the codebase, the system asks the LLM to list likely component names. That list of names forms a "Simple Software Architecture Model" (SSAM). Finally, code elements with matching names or descriptions are linked to the documentation. This pipeline avoids needing an explicit UML model.
- Effectiveness: ExArch achieved very competitive results. Using GPT-4o, it obtained a weighted F1 of about 0.86, nearly as good as the original TransArC with a hand-made model (F1 0.87). It also substantially outperformed the ArDoCode baseline (which scored ~0.62). This shows that LLMs can automatically infer the key architectural components.
+- Extension: The TAAS journal extension, "Who's Who? LLM-assisted Software Traceability with Architecture Entity Recognition", adds [ArTEMiS](/approaches/artemis/).
diff --git a/verification/asset-sha256.txt b/verification/asset-sha256.txt
index 7c570fb0..c9a3c3c0 100644
--- a/verification/asset-sha256.txt
+++ b/verification/asset-sha256.txt
@@ -20,6 +20,7 @@ bab179d5a965fa0a4b30e681a3b9311d696724e4d13e37a7f7a025d55fe96fe7 assets/img/app
5b182296e53933f645620fb9949d2524f49dd8c3cabd731761ab7b0e76b4c348 assets/img/approaches/icse24-transarc.svg
0d644debfd32492225acdeb67d5c392585d7bffe4f50c27ec972265b824e1094 assets/img/approaches/icse25-lissa.svg
213ead2badd11009d31894ef63c95b1719856ac070fb7296c919fef83a8d7b60 assets/img/approaches/refsq25-refsq.svg
+d7c3801a5b894dd48be0c342f0e663f600f3880268ba79dffdf597d4037bd55f assets/img/approaches/taas26-artemis.svg
0fa8fabec3f0ffda868474ca9269f1f38dfed653d76355d79943825b76b2f605 assets/img/logo.png
42c57bbb2265601135acb9abd028a9635df5c093661e56a2b9a4e7687c3fbef0 assets/img/people/corallo_sophie.jpg
211a0df859ad6cf8205e4051ca68e59ea1eb3cc0a867523cc672aae64aa27738 assets/img/people/fuchss_dominik.jpg
From 48577bdeaebd8417ed99ba4c38e88c0f0bd0441e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Fuch=C3=9F?=
Date: Thu, 8 Oct 2026 17:05:16 +0200
Subject: [PATCH 10/26] Turn ARDoCo-TV into the tools page
The page described one viewer; it now covers the REST API, TraceView and
TraceViz with their screenshots and the ASE 2026 landscape figure, and the
conference page links it. /approaches/tv/ stays as a redirect stub.
Co-Authored-By: Claude Opus 5.5
---
README.md | 7 +-
.../assets/img/approaches/ase26-landscape.svg | 427 ++++++++++++++++++
.../assets/img/approaches/ase26-traceview.png | Bin 0 -> 315306 bytes
.../assets/img/approaches/ase26-traceviz.png | Bin 0 -> 653824 bytes
scripts/audit-features.mjs | 3 +-
src/content/approaches/tools.md | 39 ++
src/content/approaches/tv.md | 15 -
src/content/conferences/ase26-tools.md | 6 +
src/lib/redirect.ts | 11 +-
src/pages/approaches/tv/index.astro | 14 +
verification/asset-sha256.txt | 3 +
11 files changed, 503 insertions(+), 22 deletions(-)
create mode 100644 public/assets/img/approaches/ase26-landscape.svg
create mode 100644 public/assets/img/approaches/ase26-traceview.png
create mode 100644 public/assets/img/approaches/ase26-traceviz.png
create mode 100644 src/content/approaches/tools.md
delete mode 100644 src/content/approaches/tv.md
create mode 100644 src/pages/approaches/tv/index.astro
diff --git a/README.md b/README.md
index 8ad8c98c..160deea6 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,7 @@ is the _file_ path, so canonical links and sitemap entries go through `canonical
stay that way.
**`/conferences/`** was published, so it stays as a redirect stub to `/publications/`: that page links every
+| `/approaches/tv/` | redirect stub to `/approaches/tools/` |
`/c/` page, so the list was a duplicate.
**`public/assets/**`** — served byte-for-byte at URLs that have been live for years. Never rename,
@@ -148,13 +149,17 @@ makes them easy to lose.
**`public/CNAME`** — the deploy replaces the `gh-pages` branch wholesale, so if this file stops being
emitted, `ardoco.de` stops resolving.
-`npm run verify` asserts the redirect stubs (the five `/c/` ones and `/conferences/`), the asset hashes, the two comments and `CNAME`, and the deploy workflow runs it before publishing. It also checks
+`npm run verify` asserts the redirect stubs (the five `/c/` ones, `/conferences/` and
+`/approaches/tv/`), the asset hashes, the two comments and `CNAME`, and the deploy workflow runs it before publishing. It also checks
WCAG contrast, that every internal link and `#fragment` resolves, that images carry intrinsic
dimensions, that no text runs into a link, that no email address appears in the served bytes, and
that `www.youtube.com` (the two screencasts) is still the only third-party origin.
## Content tasks
+**`/approaches/tv/`** was the page for ARDoCo-TV alone, which grew into the tools page, so it stays as a
+redirect stub to `/approaches/tools/`.
+
| Task | How |
| -------------------------- | --------------------------------------------------------------------------------- |
| Add a publication | append to `src/data/papers.bib`; `html = {/c/}` links it to its page |
diff --git a/public/assets/img/approaches/ase26-landscape.svg b/public/assets/img/approaches/ase26-landscape.svg
new file mode 100644
index 00000000..bade42e5
--- /dev/null
+++ b/public/assets/img/approaches/ase26-landscape.svg
@@ -0,0 +1,427 @@
+
+
diff --git a/public/assets/img/approaches/ase26-traceview.png b/public/assets/img/approaches/ase26-traceview.png
new file mode 100644
index 0000000000000000000000000000000000000000..d2b82eba7115f48323cd8373967c1c306e0b483d
GIT binary patch
literal 315306
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