Commit 3235941b6a93

Vincent Demeester <vincent@sbr.pm>
2026-06-30 10:32:08
docs(quarterly-report): document advisory Outcome column + add generate.py reference
- Generate.md: add Security Advisories table rendering spec (Credited/Authored vs Triaged group headers, columns incl. Outcome/state badge mapping) - Add reference/generate.py: working report generator with data-driven advisory table and stats strip; header flags per-quarter values to refresh - SKILL.md: list reference files
1 parent 6fc1d00
Changed files (3)
dots
agents
skills
quarterly-report
dots/agents/skills/quarterly-report/reference/generate.py
@@ -0,0 +1,294 @@
+#!/usr/bin/env python3
+# Quarterly report generator — reference implementation (Q2 2026).
+#
+# Reusable structure: CSS reuse from Template.html via /tmp/q2-style.html,
+# section assembly, adv_rows() with the Credited/Authored vs Triaged split and
+# the Outcome (state) column.
+#
+# PER-QUARTER (must be refreshed each run — do NOT copy values blindly):
+#   - input paths: /tmp/q<N>-daily-plan.json, /tmp/q<N>-cal.json, /tmp/q<N>-drive.json
+#   - meetings[] list + total (from calendar analysis, step 2c)
+#   - notable_docs[] (from Drive, step 2e)
+#   - VMT_THREADS (from tekton-vmt mu count, step 2g)
+#   - CFP / Talks card items (org_done + cfp-radar PRs)
+#   - executive summary prose, hero dates, output filename
+#
+# The advisory table (adv_rows + group headers + Outcome badges) and the
+# stats strip are data-driven and portable across quarters.
+
+import json, html
+from collections import Counter, defaultdict
+
+d = json.load(open('/tmp/q2-daily-plan.json'))
+style = open('/tmp/q2-style.html').read()
+
+def esc(s): return html.escape(str(s or ''))
+
+# ---- counts ----
+merged = d['github_merged']
+reviewed = d['github_reviewed']
+issues = d['github_issues_created']
+jira = d['jira_completed']
+adv = d['github_security_advisories']
+n_repos = len(set(x['repo'] for x in merged+reviewed+issues))
+
+# group helper
+def by_repo(items):
+    g = defaultdict(list)
+    for x in items: g[x['repo']].append(x)
+    # order by count desc
+    return sorted(g.items(), key=lambda kv: -len(kv[1]))
+
+CORE = {'tektoncd/pipeline','tektoncd/cli','tektoncd/operator','tektoncd/triggers',
+        'tektoncd/chains','tektoncd/results','tektoncd/pruner','tektoncd/pipelines-as-code'}
+INFRA = {'tektoncd/plumbing','tektoncd/infra','openshift-pipelines/plumbing','tektoncd/.github','tektoncd/actions'}
+
+def group_label(repo):
+    if repo in CORE: return ('⚡ Tekton Core', 0)
+    if repo in INFRA: return ('🔧 CI / Infrastructure', 1)
+    if repo.startswith('openshift-pipelines'): return ('🚀 OpenShift Pipelines', 2)
+    return ('🌐 Community, Catalog & Website', 3)
+
+def pr_rows(items, limit_per_repo=12):
+    # build grouped table rows
+    groups = defaultdict(list)
+    for repo, lst in by_repo(items):
+        groups[group_label(repo)].append((repo, lst))
+    out = []
+    for (glabel, _), repos in sorted(groups.items(), key=lambda kv: kv[0][1]):
+        out.append(f'<tr class="group-header"><td colspan="3">{esc(glabel)}</td></tr>')
+        for repo, lst in repos:
+            links = '<br>'.join(
+                f'<a class="pr-link" href="{esc(x["url"])}" target="_blank">{esc(x["title"])}</a>'
+                for x in lst[:limit_per_repo])
+            more = '' if len(lst) <= limit_per_repo else f'<br><span style="font-size:0.78rem;color:#999">+ {len(lst)-limit_per_repo} more</span>'
+            out.append(
+                f'<tr><td><span class="repo-badge">{esc(repo)}</span></td>'
+                f'<td>{links}{more}</td>'
+                f'<td style="font-weight:700;color:var(--indigo)">{len(lst)}</td></tr>')
+    return '\n'.join(out)
+
+# ---- Jira epics: keep epics/features prominent, but show all 8 ----
+def jira_rows():
+    out=[]
+    for j in jira:
+        key=j.get('key'); summ=j.get('summary'); st=j.get('status','Closed')
+        url=f"https://issues.redhat.com/browse/{key}"
+        out.append(
+            f'<tr><td><a href="{esc(url)}" target="_blank" class="key-badge">{esc(key)}</a></td>'
+            f'<td><strong>{esc(summ)}</strong></td>'
+            f'<td><span class="status-closed">{esc(st)}</span></td></tr>')
+    return '\n'.join(out)
+
+# ---- issues by theme ----
+def issue_rows():
+    return pr_rows(issues, limit_per_repo=10)
+
+# ---- advisories ----
+def adv_rows(items):
+    out=[]
+    state_style={'closed':'green','published':'red','draft':'amber','triage':'blue','withdrawn':'purple'}
+    state_label={'closed':'Closed','published':'Published','draft':'Draft','triage':'In triage','withdrawn':'Withdrawn'}
+    for a in items:
+        ghsa=a.get('ghsa_id'); cve=a.get('cve_id'); sev=a.get('severity'); summ=a.get('summary'); url=a.get('url') or (f"https://github.com/advisories/{ghsa}" if ghsa else '#')
+        st=a.get('state') or ''
+        cve_badge=f'<span class="cve-badge">{esc(cve)}</span>' if cve else ''
+        sevtag={'critical':'red','high':'red','medium':'amber','low':'blue'}.get(sev,'blue')
+        sttag=state_style.get(st,'blue'); stlabel=state_label.get(st,st or '-')
+        out.append(
+            f'<tr><td><a class="pr-link" href="{esc(url)}" target="_blank">{esc(ghsa)}</a>{cve_badge}</td>'
+            f'<td>{esc(summ)}</td>'
+            f'<td><span class="repo-badge">{esc(a.get("repo"))}</span></td>'
+            f'<td><span class="tag {sevtag}">{esc(sev or "-")}</span></td>'
+            f'<td><span class="tag {sttag}">{esc(stlabel)}</span></td></tr>')
+    return '\n'.join(out)
+
+adv_credited=[a for a in adv if a.get('role') in ('author','credited')]
+adv_triaged=[a for a in adv if a.get('role')=='triaged']
+VMT_THREADS=13
+
+# ---- meetings (from calendar analysis, hardcoded top series) ----
+meetings = [
+    ("Pipelines Core Weekly", 13), ("Pipelines weekly Architecture Decision Review (ADR)", 13),
+    ("OpenShift Pipelines Performance Sync", 13), ("Pipelines as Code Internal Weekly", 13),
+    ("Leading Forward Metrics Initiative Sync", 13), ("Pipelines Multicluster: Sync with Konflux", 13),
+    ("Vincent / Vibhav syncup", 13), ("[Weekly] OpenShift Pipelines Program Call", 12),
+    ("PM / Engineering Managers Weekly Sync", 12), ("1:1s (Vincent, Eyal:Vincent)", 22),
+    ("Konflux Program Meeting", 10), ("Backlog Refinement OpenShift Pipelines", 10),
+    ("Stakeholder Meeting", 13), ("OpenShift Pipelines Sprint Demo", 7),
+    ("Konflux Internal Architecture Call", 5), ("The 2026 Goals: Bi-Weekly Sync", 5),
+]
+def meeting_items():
+    return '\n'.join(
+        f'<li><span class="meeting-dot"></span><div><div class="meeting-title">{esc(name)}</div>'
+        f'<div class="meeting-meta">{n} sessions in Q2</div></div></li>'
+        for name,n in meetings)
+
+# ---- drive docs ----
+drive = json.load(open('/tmp/q2-drive.json'))
+dfiles = drive.get('files') or drive.get('items') or []
+notable_docs = [
+    "Design: Post-Quantum Crypto for Sigstore (Public)",
+    "The Autonomous Workflow: Introduce Agentic Workflows on Tekton",
+    "OpenShift Policy - Enabling Github Commit Signing Verification",
+    "Konflux dependencies risk for 100x scale",
+    "Notes - Plan to bring results in parity with Kubearchive",
+    "Working Agreement | OpenShift Pipelines Team",
+    "Pipelines weekly Architecture Decision Review (ADR) — Notes",
+    "Weekly updates report to the team",
+    "RH Operator Portfolio Alignment Call",
+    "Applied AI Architecture Call",
+]
+def doc_items():
+    return '\n'.join(
+        f'<li><span class="meeting-dot" style="background:var(--teal)"></span><div><div class="meeting-title">{esc(n)}</div></div></li>'
+        for n in notable_docs)
+
+# ---- assemble ----
+H = []
+H.append(f'''<!DOCTYPE html>
+<html lang="en"><head><meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Q2 2026 Achievements — Vincent Demeester</title>
+{style}</head><body>
+<div class="hero"><div class="hero-inner">
+  <span class="hero-badge">Quarterly Achievements</span>
+  <h1>Q2 2026 <span>· Apr 1 – Jun 30</span></h1>
+  <div class="hero-sub">Vincent Demeester · Senior Principal Software Engineer · R&amp;D Secure Flow</div>
+  <div class="hero-meta">
+    <div class="hero-meta-item"><span class="icon">👤</span> Vincent Demeester</div>
+    <div class="hero-meta-item"><span class="icon">🏢</span> Red Hat · OpenShift Pipelines</div>
+    <div class="hero-meta-item"><span class="icon">👔</span> Manager: Eyal Edri</div>
+  </div>
+</div></div>
+
+<div class="stats-strip"><div class="stats-inner">
+  <div class="stat-item"><div class="stat-num">{len(jira)}</div><div class="stat-label">Jira Issues Closed</div></div>
+  <div class="stat-item"><div class="stat-num">{len(merged)}</div><div class="stat-label">PRs Merged</div></div>
+  <div class="stat-item"><div class="stat-num">{len(reviewed)}</div><div class="stat-label">PRs Reviewed</div></div>
+  <div class="stat-item"><div class="stat-num">{len(issues)}</div><div class="stat-label">Issues Filed</div></div>
+  <div class="stat-item"><div class="stat-num">{len(adv_credited)}</div><div class="stat-label">CVEs Credited</div></div>
+  <div class="stat-item"><div class="stat-num">{len(adv)}</div><div class="stat-label">Advisories Triaged</div></div>
+  <div class="stat-item"><div class="stat-num">267</div><div class="stat-label">Meetings</div></div>
+</div></div>
+
+<main class="main">
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon indigo">📋</div>
+      <div><div class="card-title">Executive Summary</div><div class="card-subtitle">Q2 2026 · Apr 1 – Jun 30</div></div></div>
+    <div class="card-body" style="padding: 20px 24px; line-height: 1.75; font-size: 0.93rem;">
+      <p style="margin-bottom:12px;">Vincent Demeester sustained an exceptionally high output in Q2 2026, merging <strong>{len(merged)} pull requests</strong> and reviewing <strong>{len(reviewed)} more</strong> across <strong>{n_repos} repositories</strong> in the tektoncd and openshift-pipelines orgs, while closing <strong>{len(jira)} Jira issues</strong> spanning epics, performance bugs, and governance automation.</p>
+      <p style="margin-bottom:12px;">He led significant <strong>security and reliability work</strong> as a member of the Tekton VMT, reviewing and triaging <strong>{len(adv)} security advisories</strong> ({len(adv_credited)} crediting him as author/reporter) plus <strong>{VMT_THREADS} tekton-vmt report threads</strong> — including authoring a Git resolver token-leak (<a href="https://github.com/advisories/GHSA-wjxp-xrpv-xpff" target="_blank" style="color:var(--indigo)">CVE-2026-40161</a>) and an unauthenticated core-interceptors secret-exfiltration vulnerability (<a href="https://github.com/advisories/GHSA-gfmw-q9x8-xcrp" target="_blank" style="color:var(--indigo)">CVE-2026-54456</a>) — plus a fix for thousands of redundant PipelineRun reconciliations (<a href="https://issues.redhat.com/browse/SRVKP-9988" target="_blank" class="key-badge">SRVKP-9988</a>) and an API rate-limit failure in 1.17 (<a href="https://issues.redhat.com/browse/SRVKP-7037" target="_blank" class="key-badge">SRVKP-7037</a>).</p>
+      <p style="margin-bottom:12px;">The bulk of authored work landed in <strong>tektoncd/pipeline</strong> (47 PRs) and the CI/infrastructure repos <strong>tektoncd/plumbing</strong> (23) and <strong>tektoncd/operator</strong> (11), keeping release tracks, dogfooding clusters, and dependency automation healthy. Review load was dominated by <strong>tektoncd/pipeline</strong> (216 reviews) and <strong>tektoncd/operator</strong> (60), reflecting his role as a primary maintainer and reviewer across the core projects.</p>
+      <p>On the community and governance front, Vincent automated branch protection for the openshift-pipelines GitHub org (<a href="https://issues.redhat.com/browse/SRVKP-11412" target="_blank" class="key-badge">SRVKP-11412</a>), updated the official CNCF maintainers list (<a href="https://issues.redhat.com/browse/SRVKP-11033" target="_blank" class="key-badge">SRVKP-11033</a>), and refreshed OWNERS/maintainers across tektoncd repositories (<a href="https://issues.redhat.com/browse/SRVKP-11026" target="_blank" class="key-badge">SRVKP-11026</a>). He filed <strong>{len(issues)} issues</strong> to plan and track future work, and engaged across <strong>267 meetings spanning 64 recurring series</strong> as a technical lead and cross-team coordinator.</p>
+    </div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon indigo">🎯</div>
+      <div><div class="card-title">Jira — Issues Closed <span class="count-pill">{len(jira)}</span></div><div class="card-subtitle">Q2 2026 · SRVKP (resolved in period)</div></div></div>
+    <div class="section-summary">Resolved <strong>{len(jira)} tracked issues</strong> in Q2, including two security epics, two high-impact performance/reliability bugs (redundant reconciliation and API rate-limiting), and three governance-automation items covering branch protection, CNCF maintainer lists, and cross-repo OWNERS updates.</div>
+    <div class="card-body"><table>
+      <thead><tr><th>Key</th><th>Summary</th><th>Status</th></tr></thead>
+      <tbody>{jira_rows()}</tbody></table></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon blue">⚙️</div>
+      <div><div class="card-title">GitHub — Pull Requests Authored &amp; Merged <span class="count-pill">{len(merged)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Merged <strong>{len(merged)} PRs across {len(set(x["repo"] for x in merged))} repositories</strong>. Highest volume in <strong>tektoncd/pipeline</strong> (47) covering features, fixes, security hardening, and release cherry-picks, followed by CI/infra work in <strong>tektoncd/plumbing</strong> (23) and <strong>tektoncd/operator</strong> (11), with additional contributions to infra, catalog, community, and website.</div>
+    <div class="card-body"><table>
+      <thead><tr><th>Repository</th><th>Contributions</th><th>Count</th></tr></thead>
+      <tbody>{pr_rows(merged)}</tbody></table></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon green">👁️</div>
+      <div><div class="card-title">GitHub — Pull Requests Reviewed <span class="count-pill">{len(reviewed)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Reviewed <strong>{len(reviewed)} pull requests</strong> authored by others, dominated by <strong>tektoncd/pipeline</strong> (216) and <strong>tektoncd/operator</strong> (60), with substantial review load in <strong>tektoncd/plumbing</strong> (72) and <strong>tektoncd/cli</strong> (26) — reflecting maintainer-level ownership across the core Tekton projects and dependency-update pipelines.</div>
+    <div class="card-body"><table>
+      <thead><tr><th>Repository</th><th>Sample Reviewed PRs</th><th>Count</th></tr></thead>
+      <tbody>{pr_rows(reviewed, limit_per_repo=8)}</tbody></table></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon amber">📝</div>
+      <div><div class="card-title">GitHub — Issues Filed <span class="count-pill">{len(issues)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Filed <strong>{len(issues)} issues</strong> to plan and track work across the tektoncd org, concentrated in <strong>tektoncd/pipeline</strong> (32), <strong>tektoncd/cli</strong> (14), and <strong>tektoncd/plumbing</strong> (12) — spanning bug reports, security follow-ups, feature proposals, and CI/infra tasks.</div>
+    <div class="card-body"><table>
+      <thead><tr><th>Repository</th><th>Sample Issues</th><th>Count</th></tr></thead>
+      <tbody>{issue_rows()}</tbody></table></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon red">🔒</div>
+      <div><div class="card-title">GitHub — Security Advisories <span class="count-pill">{len(adv)}</span></div><div class="card-subtitle">VMT review queue · {len(adv_credited)} credited/authored + {len(adv_triaged)} triaged · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">As a member of the <strong>Tekton Vulnerability Management Team (VMT)</strong>, reviewed and triaged <strong>{len(adv)} security advisories</strong> across pipeline, triggers, chains, and pipelines-as-code, of which <strong>{len(adv_credited)} credited Vincent as author or reporter</strong>. This includes coordinating a Git-resolver token-leak (CVE-2026-40161, authored), a Git-resolver RCE via argument injection (CVE-2026-40938), and an unauthenticated core-interceptors secret-exfiltration vulnerability (CVE-2026-54456, authored). Alongside the GitHub advisories, Vincent processed <strong>{VMT_THREADS} distinct security report threads</strong> on the tekton-vmt mailing list — the bulk of triage/review work that is not formally credited on the published advisories. Of the {len(adv_triaged)} triaged advisories, {sum(1 for a in adv_triaged if a.get("state")=="closed")} were closed (rejected, duplicate, or resolved), {sum(1 for a in adv_triaged if a.get("state")=="published")} published, and {sum(1 for a in adv_triaged if a.get("state") in ("draft","triage"))} remain in draft/triage.</div>
+    <div class="card-body">
+      <table>
+        <thead><tr><th>Advisory</th><th>Summary</th><th>Repo</th><th>Severity</th><th>Outcome</th></tr></thead>
+        <tbody>
+          <tr class="group-header"><td colspan="5">⭐ Credited / Authored ({len(adv_credited)})</td></tr>
+          {adv_rows(adv_credited)}
+          <tr class="group-header"><td colspan="5">🛡 Triaged — VMT review queue ({len(adv_triaged)})</td></tr>
+          {adv_rows(adv_triaged)}
+        </tbody>
+      </table>
+    </div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon amber">🎤</div>
+      <div><div class="card-title">Talks, CFPs &amp; Community Visibility</div><div class="card-subtitle">Conference submissions, blogs &amp; presentations · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Drove external visibility for OpenShift Pipelines: submitted a CFP to <strong>Open Source Summit EU</strong>, prepared <strong>KubeCon NA 2026 CFP abstracts</strong> and a reframed CVE talk abstract ("When the LLMs Come Knocking") via the <strong>cfp-radar</strong> tracker, authored a Red Hat blog entry on the CNCF transition, and prepared the Konflux Architecture Review presentation.</div>
+    <div class="card-body"><ul class="meeting-list">
+      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">CFP — Open Source Summit EU</div><div class="meeting-meta">Submitted · deadline 2026-06-22</div></div></li>
+      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title"><a class="pr-link" href="https://github.com/openshift-pipelines/cfp-radar/pull/2" target="_blank">KubeCon NA 2026 CFP abstracts</a></div><div class="meeting-meta">cfp-radar #2 · merged 2026-04-13</div></div></li>
+      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title"><a class="pr-link" href="https://github.com/openshift-pipelines/cfp-radar/pull/3" target="_blank">CVE talk abstract — "When the LLMs Come Knocking"</a></div><div class="meeting-meta">cfp-radar #3 · merged 2026-06-04</div></div></li>
+      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">Red Hat Blog entry — Tekton joining the CNCF</div><div class="meeting-meta">Authored</div></div></li>
+      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">Konflux Architecture Review presentation</div><div class="meeting-meta">Prepared · May 25</div></div></li>
+    </ul></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon indigo">🤝</div>
+      <div><div class="card-title">Meeting &amp; Cross-Team Engagement <span class="count-pill">267</span></div><div class="card-subtitle">Google Calendar · 64 recurring series · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Attended <strong>267 work meetings across 64 recurring series</strong>, leading core-team syncs (Pipelines Core Weekly, ADR calls, Performance Sync), driving cross-team initiatives (Konflux multicluster, Leading Forward metrics), and maintaining program-level and 1:1 cadences.</div>
+    <div class="card-body"><ul class="meeting-list">{meeting_items()}</ul></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon teal">📄</div>
+      <div><div class="card-title">Documents &amp; Design Work <span class="count-pill">{len(dfiles)}</span></div><div class="card-subtitle">Google Drive · authored / co-authored · Apr–Jun 2026</div></div></div>
+    <div class="section-summary">Authored and contributed to <strong>{len(dfiles)} documents</strong>, including design work on post-quantum crypto for Sigstore, agentic workflows on Tekton, commit-signing verification policy, and Konflux scale/risk analysis.</div>
+    <div class="card-body"><ul class="meeting-list">{doc_items()}</ul></div>
+  </div>
+
+  <div class="card">
+    <div class="card-header"><div class="card-icon purple">🏷️</div>
+      <div><div class="card-title">Areas of Focus</div></div></div>
+    <div class="tags">
+      <span class="tag red">Security &amp; CVEs</span>
+      <span class="tag blue">Tekton Pipelines Core</span>
+      <span class="tag green">Code Review &amp; Maintainership</span>
+      <span class="tag amber">CI / Infrastructure</span>
+      <span class="tag indigo">Performance &amp; Reliability</span>
+      <span class="tag teal">Release Management</span>
+      <span class="tag purple">Governance &amp; CNCF</span>
+      <span class="tag blue">Konflux Integration</span>
+      <span class="tag green">Multicluster</span>
+      <span class="tag amber">Agentic Workflows</span>
+    </div>
+  </div>
+
+</main>
+
+<div class="footer">
+  Generated by pi · Data sources: daily-plan (Jira SRVKP · GitHub vdemeester, tektoncd + openshift-pipelines), Google Calendar, Google Drive, GitHub Security Advisories (VMT), tekton-vmt mailing list, cfp-radar · Period: Apr 1 – Jun 30, 2026 · GitLab &amp; Slack not queried
+</div>
+
+</body></html>''')
+
+open('/home/vdemeest/desktop/downloads/q2-2026-achievements-vincent-demeester.html','w').write('\n'.join(H))
+print("written", sum(len(x) for x in H), "chars")
dots/agents/skills/quarterly-report/workflows/Generate.md
@@ -180,6 +180,24 @@ Fill in all data sections. Key rules:
 | GitHub PRs/issues | Use the `url` field from `gh search` JSON output: `<a href="<url>" target="_blank" class="pr-link">title</a>` |
 | GitLab MRs | Use `web_url` from API: `<a href="<web_url>" target="_blank" class="pr-link">!iid title</a>` |
 
+### Security Advisories table
+
+Render advisories as a single table with **two group-header rows** splitting by `role`:
+
+- `⭐ Credited / Authored (N)` — advisories where `role` is `author` or `credited`
+- `🛡 Triaged — VMT review queue (N)` — advisories where `role` is `triaged`
+
+Columns: **Advisory | Summary | Repo | Severity | Outcome**
+
+- Advisory cell: `<a class="pr-link" href="<url>">ghsa_id</a>` plus `<span class="cve-badge">CVE</span>` when `cve_id` is set
+- Severity badge: `<span class="tag {red|amber|blue}">` — red for critical/high, amber for medium, blue for low
+- **Outcome badge** (from the `state` field): `<span class="tag {green|red|amber|blue}">{label}</span>`
+  - `closed` → green “Closed” · `published` → red “Published” · `draft` → amber “Draft” · `triage` → blue “In triage” · `withdrawn` → purple “Withdrawn”
+
+The section summary must state the credited-vs-triaged split, the tekton-vmt thread count (from 2g), and the triaged outcome breakdown (e.g. “of N triaged, X closed, Y published, Z draft/triage”).
+
+A working reference generator that produces this table (and the full report) lives at `reference/generate.py` in this skill — adapt its `adv_rows()` / section assembly rather than rewriting from scratch.
+
 ### Section summaries
 
 Every data section must open with a `<div class="section-summary">` containing 2–3 sentences synthesizing the section's impact. Cover: total volume, standout items, and business/technical significance. Interpret — don't just repeat the table.
dots/agents/skills/quarterly-report/SKILL.md
@@ -72,3 +72,8 @@ User: "Generate my Q1 2025 report"
 ## Output
 
 The report is written to `~/desktop/downloads/q<N>-<YEAR>-achievements-vincent-demeester.html`.
+
+## Reference Files
+
+- `reference/Template.html` — self-contained styled HTML template (CSS + section structure)
+- `reference/generate.py` — working Python generator (Q2 2026); reuse `adv_rows()` (Credited/Authored vs Triaged split + Outcome/state column) and the section/stats assembly. Quarter-specific values (meetings, docs, VMT thread count, CFP items, prose) must be refreshed each run — see the header comment.