feat(rai): disclose AI-generated content (#207)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Juan Manuel Servera committed
May 25, 2026 at 23:23 UTC
a819e1aecd6064de1ac65b8d3531d8e045f7ff36
9 files changed
+141
-4
.squad/decisions/inbox/amy-ai-disclosure-pattern.md
new
+7
@@ -0,0 +1,7 @@
1
+# AI Disclosure Pattern
2
+
3
+**Date:** 2026-05-25
4
+**Author:** Amy
5
+**Status:** Proposed
6
+
7
+Every page renders an AI-disclosure footer partial; article pages additionally show a prominent AI-generated badge in the meta block. Single partial = single source of truth.
.squad/skills/ai-content-disclosure/SKILL.md
new
+32
@@ -0,0 +1,32 @@
1
+---
2
+name: "ai-content-disclosure"
3
+description: "Reusable pattern for visibly disclosing AI-generated editorial content across the Hugo site."
4
+domain: "responsible-ai, frontend, hugo, accessibility"
5
+confidence: "medium"
6
+source: "Amy AI disclosure implementation — 2026-05-25"
7
+owner: "Amy"
8
+---
9
+
10
+## Pattern
11
+
12
+Use one global Hugo partial for baseline disclosure on every page, then add a stronger badge in article metadata for generated analysis pages.
13
+
14
+## Requirements
15
+
16
+- Keep visible disclosure text in the normal reading flow; do not rely only on metadata, tooltips, or ARIA.
17
+- Use generic language such as "AI models" rather than vendor-specific names.
18
+- Name accountability: editorial structure and source curation are owned by the SquadScope maintainer.
19
+- Provide an error-reporting path to GitHub issues.
20
+- Keep the footer partial as the single source of truth so new pages inherit disclosure automatically.
21
+- Ensure print styles preserve the disclosure.
22
+
23
+## Hugo Implementation
24
+
25
+1. Render `layouts/partials/ai-disclosure.html` from `layouts/partials/footer.html`.
26
+2. Add `<meta name="ai-generated" content="true">` in `layouts/partials/head.html`.
27
+3. Add `data-ai-generated="true"` to the `<body>` in `layouts/_default/baseof.html`.
28
+4. Add an `AI-generated analysis` badge in `layouts/partials/article-meta.html` for weekly/topic analysis pages.
29
+
30
+## Verification
31
+
32
+Build the site, inspect rendered HTML for the meta and body attributes, and visually check the footer disclosure plus article badge in light/dark and mobile/desktop viewports.
assets/css/common/footer.css
+60
@@ -36,6 +36,66 @@
36
gap: var(--space-3);
37
}
38
39
+.ai-disclosure {
40
+ display: grid;
41
+ grid-template-columns: auto 1fr;
42
+ gap: var(--space-3);
43
+ max-width: var(--prose-measure);
44
+ margin: 0 auto;
45
+ padding: var(--space-3);
46
+ border: var(--size-border-thin) solid var(--color-border);
47
+ border-radius: var(--radius-lg);
48
+ background: color-mix(in srgb, var(--color-accent-muted) 55%, var(--color-surface));
49
+ text-align: left;
50
+}
51
+
52
+.ai-disclosure__icon {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: var(--space-5);
57
+ height: var(--space-5);
58
+ border-radius: var(--radius-full);
59
+ background: var(--color-surface);
60
+ box-shadow: var(--shadow-sm);
61
+}
62
+
63
+.ai-disclosure__title,
64
+.ai-disclosure p {
65
+ margin: 0;
66
+}
67
+
68
+.ai-disclosure__body {
69
+ display: grid;
70
+ gap: var(--space-2);
71
+}
72
+
73
+.ai-disclosure__title {
74
+ color: var(--color-text);
75
+ font-size: var(--text-sm);
76
+ line-height: var(--leading-tight);
77
+}
78
+
79
+@media (max-width: 640px) {
80
+ .ai-disclosure {
81
+ grid-template-columns: 1fr;
82
+ text-align: center;
83
+ }
84
+
85
+ .ai-disclosure__icon {
86
+ margin: 0 auto;
87
+ }
88
+}
89
+
90
+@media print {
91
+ .ai-disclosure {
92
+ break-inside: avoid;
93
+ border-color: currentColor;
94
+ background: transparent;
95
+ color: #000;
96
+ }
97
+}
98
+
99
.site-footer a,
100
.site-footer__link {
101
color: var(--color-text-muted);
assets/css/extended/squadscope.css
+13
@@ -516,6 +516,19 @@ summary:focus-visible,
516
line-height: var(--leading-normal);
517
}
518
519
+.article-ai-badge {
520
+ display: inline-flex;
521
+ align-items: center;
522
+ gap: var(--space-1);
523
+ padding: 0.15rem var(--space-2);
524
+ border: var(--size-border-thin) solid var(--color-border);
525
+ border-radius: var(--radius-full);
526
+ background: var(--color-accent-muted);
527
+ color: var(--color-text);
528
+ font-weight: 600;
529
+ white-space: nowrap;
530
+}
531
+
532
.squad-article .report-metrics,
533
.article-jump-nav,
534
.article-featured-repos,
layouts/_default/baseof.html
+2
-2
@@ -17,9 +17,9 @@
17
</head>
18
19
{{- if (or (ne .Kind `page` ) (eq .Layout `archives`) (eq .Layout `search`)) }}
20
-<body class="list" id="top">
20
+<body class="list" id="top" data-ai-generated="true">
21
{{- else }}
22
-<body id="top">
22
+<body id="top" data-ai-generated="true">
23
{{- end }}
24
<a class="skip-link" href="#main-content">Skip to content</a>
25
{{ partialCached "header.html" . .Page -}}
layouts/partials/ai-disclosure.html
new
+14
@@ -0,0 +1,14 @@
1
+<section class="ai-disclosure" aria-labelledby="ai-disclosure-title">
2
+ <span class="ai-disclosure__icon" aria-hidden="true">✨</span>
3
+ <div class="ai-disclosure__body">
4
+ <h2 id="ai-disclosure-title" class="ai-disclosure__title">AI-generated content disclosure</h2>
5
+ <p>
6
+ Editorial content on SquadScope is generated by AI models, with human curation of sources and editorial structure by the
7
+ <a href="https://github.com/jmservera/SquadScope" target="_blank" rel="noopener">SquadScope maintainer</a>.
8
+ Read more about <a href="{{ "about/" | absLangURL }}">how we work</a>.
9
+ </p>
10
+ <p>
11
+ Spot an error? <a href="https://github.com/jmservera/SquadScope/issues/new" target="_blank" rel="noopener">Open an issue on GitHub</a>.
12
+ </p>
13
+ </div>
14
+</section>
layouts/partials/article-meta.html
+11
-2
@@ -15,6 +15,15 @@
15
{{- with $page.Params.top_repo -}}
16
{{- $meta = $meta | append (printf "Top repo: %s" .) -}}
17
{{- end -}}
18
-{{- if gt (len $meta) 0 -}}
19
-<p class="article-meta" aria-label="Report metadata">{{ delimit $meta " <span aria-hidden=\"true\">·</span> " | safeHTML }}</p>
18
+{{- $showAIBadge := or (eq $page.Section "weekly") (eq $page.Section "topics") -}}
19
+{{- if or (gt (len $meta) 0) $showAIBadge -}}
20
+<p class="article-meta" aria-label="Report metadata">
21
+ {{- if gt (len $meta) 0 -}}
22
+ {{ delimit $meta " <span aria-hidden=\"true\">·</span> " | safeHTML }}
23
+ {{- end -}}
24
+ {{- if and (gt (len $meta) 0) $showAIBadge }} <span aria-hidden="true">·</span> {{ end -}}
25
+ {{- if $showAIBadge -}}
26
+ <span class="article-ai-badge" title="This analysis was written by an AI model using public GitHub + press data. Editorial structure and source curation by the SquadScope maintainer." aria-label="AI-generated analysis. This analysis was written by an AI model using public GitHub and press data. Editorial structure and source curation by the SquadScope maintainer.">✨ AI-generated analysis</span>
27
+ {{- end -}}
28
+</p>
29
{{- end -}}
layouts/partials/footer.html
+1
@@ -2,6 +2,7 @@
2
<footer class="footer site-footer" aria-label="Site footer">
3
<div class="site-footer__inner">
4
<p class="site-footer__tagline"><strong>SquadScope</strong> — Weekly tech signal from GitHub.</p>
5
+ {{ partial "ai-disclosure.html" . }}
6
<nav class="site-footer__nav" aria-label="Footer">
7
<a href="{{ "privacy/" | absLangURL }}">Privacy</a>
8
<button type="button" class="site-footer__link" onclick="CookieConsent.showPreferences()">Manage cookies</button>
layouts/partials/head.html
+1
@@ -6,6 +6,7 @@
6
{{- else }}
7
<meta name="robots" content="noindex, nofollow">
8
{{- end }}
9
+<meta name="ai-generated" content="true">
10
11
{{- partial "seo.html" . -}}
12