Skip to content

Commit 3a8e3d7

Browse files
committed
refactor: prune historical data, consolidate reporting scripts, and improve CI/CD infrastructure
1 parent 8a7179a commit 3a8e3d7

68 files changed

Lines changed: 330 additions & 43803 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/deploy-pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- uses: actions/checkout@v4
3030
- uses: actions/setup-node@v4
3131
with:
32-
node-version: "20"
32+
node-version: "22"
3333
cache: "npm"
3434
cache-dependency-path: web/package-lock.json
3535
- run: npm ci

.github/workflows/pr-checks.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: PR checks
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
web-build:
13+
runs-on: ubuntu-latest
14+
defaults:
15+
run:
16+
working-directory: web
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: actions/setup-node@v4
20+
with:
21+
node-version: "22"
22+
cache: "npm"
23+
cache-dependency-path: web/package-lock.json
24+
- run: npm ci
25+
- run: npm run build
26+
27+
python-syntax:
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v4
31+
- uses: actions/setup-python@v5
32+
with:
33+
python-version: "3.12"
34+
- name: Compile all track scripts
35+
run: python -m compileall -q tracks/*/scripts
36+
37+
shellcheck:
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: actions/checkout@v4
41+
- name: Run shellcheck
42+
run: |
43+
shopt -s nullglob globstar
44+
files=(scripts/*.sh tracks/*/scripts/*.sh)
45+
if [ ${#files[@]} -eq 0 ]; then
46+
echo "No shell scripts found"
47+
exit 0
48+
fi
49+
shellcheck "${files[@]}"

scripts/prune.sh

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,71 @@
11
#!/usr/bin/env bash
2-
# Keep only the latest entry under each track artifact directory.
2+
# Trim track artifacts to the canonical retention policy:
3+
# - reports/{daily,weekly}/ : keep latest 1 file
4+
# - data/snapshots/, data/raw/ : keep latest 1 entry
5+
# - data/normalized/<prefix>-<YYYY-MM-DD>.json : keep latest 7 per prefix
6+
# (weekly reports may need recent dated history; non-dated files are left alone)
37
# Usage: bash scripts/prune.sh <track-dir>
48
set -euo pipefail
9+
shopt -s nullglob
510

611
TRACK_DIR="${1:?track directory required (e.g. tracks/ietf-wimse)}"
712

813
prune_keep_latest() {
914
local dir="$1"
1015
local keep="${2:-1}"
1116
[ -d "$dir" ] || return 0
12-
local total
13-
total=$(ls -1 "$dir" 2>/dev/null | wc -l | tr -d ' ')
17+
local entries=()
18+
local entry
19+
for entry in "$dir"/*; do
20+
entries+=("$(basename "$entry")")
21+
done
22+
local total=${#entries[@]}
1423
if [ "$total" -le "$keep" ]; then
1524
return 0
1625
fi
1726
local drop=$((total - keep))
18-
ls -1 "$dir" | sort | head -n "$drop" | while read -r entry; do
19-
rm -rf "$dir/$entry"
27+
IFS=$'\n' read -r -d '' -a sorted < <(printf '%s\n' "${entries[@]}" | sort && printf '\0')
28+
local i
29+
for ((i = 0; i < drop; i++)); do
30+
rm -rf "${dir:?}/${sorted[i]}"
2031
done
2132
echo "pruned $drop from $dir"
2233
}
2334

35+
# For files like <prefix>-<YYYY-MM-DD>.json under a directory, keep the latest N per prefix.
36+
prune_dated_normalized() {
37+
local dir="$1"
38+
local keep="${2:-7}"
39+
[ -d "$dir" ] || return 0
40+
local file base prefix
41+
local raw_prefixes=()
42+
for file in "$dir"/*-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].json; do
43+
base=$(basename "$file")
44+
prefix=${base%-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].json}
45+
raw_prefixes+=("$prefix")
46+
done
47+
[ ${#raw_prefixes[@]} -eq 0 ] && return 0
48+
local prefixes=()
49+
IFS=$'\n' read -r -d '' -a prefixes < <(printf '%s\n' "${raw_prefixes[@]}" | sort -u && printf '\0')
50+
for prefix in "${prefixes[@]}"; do
51+
local matches=()
52+
for file in "$dir"/"$prefix"-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].json; do
53+
matches+=("$(basename "$file")")
54+
done
55+
local total=${#matches[@]}
56+
if [ "$total" -le "$keep" ]; then continue; fi
57+
local drop=$((total - keep))
58+
IFS=$'\n' read -r -d '' -a sorted < <(printf '%s\n' "${matches[@]}" | sort && printf '\0')
59+
local i
60+
for ((i = 0; i < drop; i++)); do
61+
rm -f "${dir:?}/${sorted[i]}"
62+
done
63+
echo "pruned $drop ${prefix}-* files from $dir"
64+
done
65+
}
66+
2467
prune_keep_latest "$TRACK_DIR/reports/daily" 1
2568
prune_keep_latest "$TRACK_DIR/reports/weekly" 1
2669
prune_keep_latest "$TRACK_DIR/data/snapshots" 1
2770
prune_keep_latest "$TRACK_DIR/data/raw" 1
71+
prune_dated_normalized "$TRACK_DIR/data/normalized" 7

templates/new-track/README.md

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,47 @@
22

33
Automated monitoring and deep-dive workspace for **&lt;Track Name&gt;**.
44

5-
## Goals
5+
## Purpose
66

7-
- Continuously collect the latest signals from primary sources.
8-
- Detect meaningful changes (draft revisions, new specs, repo activity, mailing-list trends).
7+
- Continuously collect signals from primary sources.
8+
- Detect meaningful changes (draft revisions, repo activity, mailing-list trends).
99
- Prioritize deep-dive candidates with reproducible scoring.
10-
- Maintain a hands-on backlog tied to real working-group movement.
10+
- Generate daily and weekly Markdown reports.
1111

12-
## Data Sources
12+
## Sources
1313

14-
- &lt;!-- Add your sources here --&gt;
14+
Configured in `config/sources.yaml`. Add the upstream URLs and tracked repositories you want to watch.
1515

16-
All source endpoints and tracked repositories are configured in `config/sources.yaml`.
16+
## Layout
1717

18-
## Repository Layout
19-
20-
- `config/`: Source and scoring configuration.
21-
- `data/raw/<YYYY-MM-DD>/<source>.json`: Raw fetch artifacts.
22-
- `data/normalized/`: Merged state and scoring output.
23-
- `reports/daily/<YYYY-MM-DD>.md` and `reports/weekly/<YYYY>-W<NN>.md`: Generated reports.
24-
- `backlog/candidate-queue.md`: Scored deep-dive candidate queue.
25-
- `deep-dives/`: Investigation notes (scaffold from `../../templates/deep-dive/`).
26-
- `scripts/`: `_common.py` helpers + `collect.py` / `normalize.py` / `score.py` / `report.py`.
18+
```text
19+
config/ sources.yaml + scoring.yaml
20+
data/raw/<YYYY-MM-DD>/ Raw fetch artifacts (latest only — pruned)
21+
data/normalized/ Merged state + scoring output
22+
reports/daily/<YYYY-MM-DD>.md Latest daily report (older pruned)
23+
reports/weekly/<YYYY>-W<NN>.md Latest weekly digest (older pruned)
24+
deep-dives/_backlog.md Scored deep-dive candidate queue
25+
deep-dives/<topic>/ Investigation notes (scaffold from templates/deep-dive/)
26+
scripts/ _common.py + collect.py / normalize.py / score.py / report.py
27+
```
2728

28-
## Local Usage
29+
## Usage
2930

3031
```bash
3132
python3 -m venv .venv
3233
source .venv/bin/activate
3334
make install
34-
make update # collect + normalize + score + report-daily
35-
make weekly # collect + normalize + score + report-weekly
35+
make update # collect + normalize + score + report-daily + prune
36+
make weekly # collect + normalize + score + report-weekly + prune
3637
```
3738

38-
Individual stages: `make collect`, `make normalize`, `make score`, `make report-daily`, `make report-weekly`.
39+
Individual stages: `make collect`, `make normalize`, `make score`, `make report-daily`, `make report-weekly`, `make prune`.
3940

4041
## Automation
4142

42-
The repo-root `.github/workflows/{daily-update,weekly-digest}.yml` files use a `matrix.track` list. Add this track's directory name to that list to wire it into CI.
43+
The repo-root `.github/workflows/{daily-update,weekly-digest}.yml` files run `make update` / `make weekly` per track via a `matrix.track` list. Add this track's directory name to that list to wire it into CI.
44+
45+
## Notes
46+
47+
- Retention policy: `make prune` (auto-invoked by `update` / `weekly`) keeps only the latest report and snapshot per category. Use git history for older state.
48+
- Set `GITHUB_TOKEN` (or `GH_TOKEN`) to avoid rate limits on GitHub fetches.

templates/new-track/scripts/score.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def main() -> None:
5454
else:
5555
for i, c in enumerate(ranked, start=1):
5656
lines.append(f"| {i} | {c['score']} | {c['title']} |")
57-
write_text(ROOT / "backlog" / "candidate-queue.md", "\n".join(lines) + "\n")
57+
write_text(ROOT / "deep-dives" / "_backlog.md", "\n".join(lines) + "\n")
5858
print(f"score: candidates={len(ranked)} threshold={threshold}")
5959

6060

tracks/ietf-wimse/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ score:
1717
$(PYTHON) scripts/score.py
1818

1919
report-daily:
20-
$(PYTHON) scripts/render_reports.py --mode daily
20+
$(PYTHON) scripts/report.py --mode daily
2121

2222
report-weekly:
23-
$(PYTHON) scripts/render_reports.py --mode weekly
23+
$(PYTHON) scripts/report.py --mode weekly
2424

2525
prune:
2626
bash ../../scripts/prune.sh .

tracks/ietf-wimse/README.md

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,53 @@
11
# IETF WIMSE Deep Dive
22

3-
Automated monitoring and deep-dive workspace for the IETF WIMSE working group.
3+
Continuous monitoring and deep-dive workspace for the IETF WIMSE working group (Workload Identity in Multi-System Environments).
44

5-
## Goals
5+
## Purpose
66

7-
- Continuously collect the latest WIMSE signals from primary sources.
8-
- Detect meaningful changes (draft revisions, new related drafts, meeting artifacts, mailing-list trends).
9-
- Prioritize deep-dive candidates with reproducible scoring.
10-
- Maintain a hands-on lab backlog tied to real WG movement.
7+
- Track WIMSE drafts, related specifications, and working-group activity.
8+
- Surface deep-dive candidates ranked by lifecycle state, recency, and mailing-list signal.
9+
- Generate daily and weekly Markdown reports for review.
1110

12-
## Data Sources
11+
## Sources
1312

14-
- Datatracker WG pages: documents, meetings, history.
15-
- IETF mail archive (`wimse` list).
16-
- GitHub repositories under `ietf-wg-wimse`.
13+
Configured in `config/sources.yaml`:
1714

18-
All source endpoints and tracked repositories are configured in `config/sources.yaml`.
15+
- IETF Datatracker (WG documents, meetings, history) — HTML scrape
16+
- IETF Mail Archive (`mailarchive.ietf.org/arch/browse/wimse/`) — HTML scrape
17+
- GitHub repos under `ietf-wg-wimse/` — REST API
1918

20-
## Repository Layout
19+
## Layout
2120

22-
- `config/`: source and scoring configuration.
23-
- `data/raw/`: raw fetch artifacts by date.
24-
- `data/normalized/`: latest normalized source outputs and merged state.
25-
- `data/snapshots/`: daily state snapshots.
26-
- `reports/daily/`: generated daily markdown reports.
27-
- `reports/weekly/`: generated weekly markdown reports.
28-
- `backlog/candidate-queue.md`: scored deep-dive candidate queue.
29-
- `deep-dives/`: manually curated deep-dive notes (scaffold from `../../templates/deep-dive/`).
30-
- `scripts/`: data collection, normalization, scoring, and report generation.
21+
```text
22+
config/ sources.yaml + scoring.yaml
23+
data/raw/<YYYY-MM-DD>/ Per-source audit JSON (latest only — pruned)
24+
data/normalized/ datatracker.json / mailarchive.json / github.json /
25+
wimse_state.json / candidates.json
26+
data/snapshots/<YYYY-MM-DD>/ Snapshot of normalized state
27+
reports/daily/<YYYY-MM-DD>.md Latest daily report
28+
reports/weekly/<YYYY>-W<NN>.md Latest weekly digest
29+
deep-dives/_backlog.md Scored deep-dive candidate queue
30+
deep-dives/<topic>/ Investigation notes
31+
scripts/ _common.py + collect_*.py / normalize.py / score.py / report.py
32+
```
3133

32-
## Local Usage
34+
## Usage
3335

3436
```bash
3537
python3 -m venv .venv
3638
source .venv/bin/activate
3739
make install
38-
make update
40+
make update # collect + normalize + score + report-daily + prune
41+
make weekly # collect + normalize + score + report-weekly + prune
3942
```
4043

41-
`make update` runs:
42-
43-
1. Source collectors
44-
2. State normalization
45-
3. Candidate scoring
46-
4. Daily report rendering
47-
48-
Useful targets:
49-
50-
- `make collect`
51-
- `make normalize`
52-
- `make score`
53-
- `make report-daily`
54-
- `make report-weekly`
55-
- `make weekly`
44+
Set `GITHUB_TOKEN` (or `GH_TOKEN`) to avoid GitHub API rate limits.
5645

5746
## Automation
5847

59-
Driven from the repo-root `.github/workflows/{daily-update,weekly-digest}.yml`. Both workflows commit generated outputs when changed.
48+
Driven by repo-root `.github/workflows/{daily-update,weekly-digest}.yml` (matrix over all tracks).
6049

6150
## Notes
6251

63-
- Generated files are intentionally committed for historical traceability.
64-
- Scoring logic is intentionally simple and transparent; tune weights in `config/scoring.yaml`.
52+
- Scoring weights live in `config/scoring.yaml` (`recency_days`, `weights`, `priority_keywords`).
53+
- Retention: `make prune` keeps only the latest report and snapshot. For older state use git history.

tracks/ietf-wimse/backlog/candidate-queue.md

Lines changed: 0 additions & 12 deletions
This file was deleted.

tracks/ietf-wimse/scripts/_common.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import datetime as dt
44
import json
5+
import os
56
import re
67
from pathlib import Path
78
from typing import Any
9+
from urllib.parse import urlparse
810

911
import requests
1012
import yaml
@@ -51,15 +53,25 @@ def write_text(path: Path, text: str) -> None:
5153
path.write_text(text, encoding="utf-8")
5254

5355

56+
def _build_headers(url: str) -> dict[str, str]:
57+
headers = dict(DEFAULT_HEADERS)
58+
host = urlparse(url).hostname or ""
59+
if host.endswith("api.github.com"):
60+
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
61+
if token:
62+
headers["Authorization"] = f"Bearer {token}"
63+
return headers
64+
65+
5466
def fetch_text(url: str, timeout: int = 30) -> str:
55-
resp = requests.get(url, headers=DEFAULT_HEADERS, timeout=timeout)
67+
resp = requests.get(url, headers=_build_headers(url), timeout=timeout)
5668
resp.raise_for_status()
5769
resp.encoding = resp.encoding or "utf-8"
5870
return resp.text
5971

6072

6173
def fetch_json(url: str, timeout: int = 30) -> Any:
62-
resp = requests.get(url, headers=DEFAULT_HEADERS, timeout=timeout)
74+
resp = requests.get(url, headers=_build_headers(url), timeout=timeout)
6375
resp.raise_for_status()
6476
return resp.json()
6577

File renamed without changes.

0 commit comments

Comments
 (0)