Fix mobile topic buttons layout (#219)

* Fix mobile topic buttons layout Move topic discovery off the crowded mobile surfaces, route readers to the Topics page, and populate /topics/ with active topic/category listings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(squad): log Ralph round 1 — #217 #216 agent work - Archived 27 decisions (>= 7 days old) - Merged 17 inbox entries into decisions.md - Updated Fry and Amy history with team round work - Created orchestration logs (ignored paths) - Created session log (ignored paths) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(squad): log Ralph round 2 — Leela PR reviews - Archive 863 lines of decisions older than 7 days - Merge leela-pr-review.md from inbox to active decisions - Reduce decisions.md from 55,132 to 14,288 bytes - Update Leela and Scribe history with session notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use front matter description and correct heading hierarchy Addresses PR #219 review feedback: - Use .Description from front matter instead of hard-coded text - Use h3 for card titles under h2 section headings (accessibility) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Juan Manuel Servera committed Jun 1, 2026 at 12:48 UTC fb965b46748fe5c46eb401e56e03a55a4d8e65f1
26 files changed +1454 -1321
.squad/agents/amy/history.md
+9
@@ -20,3 +20,12 @@
20 - 2026-05-25 Weekly press context uses canonical `## Where Industry Meets Code`; wrapping it in a Hugo partial preserves clean heading flow while giving it complementary landmark styling.
21 - 2026-05-25 Phase 5 cost transparency lives in the About page via `{{< cost-dashboard >}}`; keep the shortcode as a thin wrapper over `layouts/partials/cost-dashboard.html` so direct `/dashboard/` links can reuse it.
22 - 2026-05-25 PR #199 follow-up: cost dashboard metric lists live in `assets/css/common/cost-dashboard.css`; strengthen `.post-content .cost-dashboard__metrics` specificity so global `.md-content dl/dt/dd` flex rules cannot override dashboard grid layout in article content.
23 +- 2026-06-01 Issue #216: remove the header/home topic chip strips, keep desktop topic discovery in the homepage rail, and send mobile users to `/topics/` so topic navigation stops crowding small screens.
24 +- 2026-06-01 The live `/topics/` route is driven by `layouts/topics/terms.html` because Hugo treats `topics` as a taxonomy landing page; fixes for an empty Topics page belong there, not only in `content/topics/_index.md`.
25 +
26 +## Round 2026-06-01T12:19
27 +
28 +### Issue #216: Mobile Topic Buttons
29 +- PR #219 opened with clean Hugo build
30 +- Mobile UX improved for topics navigation
31 +- Responsive design verified on small screens
.squad/agents/fry/history.md
+7
@@ -8,3 +8,10 @@
8 - The PaperMod theme in this repo needs Hugo `v0.146.0+`, so build validation must use a sufficiently new Hugo binary.
9 - End-to-end checks matter more than isolated unit confidence when artifacts move across crawl, analyze, and publish stages.
10 - Raw crawl output can be publishable with curation, but trend filters still need skepticism about exploit noise and weak momentum data.
11 +
12 +## Round 2026-06-01T12:19
13 +
14 +### Issue #217: Quality Gates
15 +- PR #218 opened with all tests passing
16 +- Fallback mechanism now includes GitHub Models support
17 +- Copilot prompt validation hardened
.squad/agents/leela/history.md
+3
@@ -10,3 +10,6 @@
10 - Copilot CLI agent selection uses the registered agent name, not the path to the agent file.
11 - Documentation and orchestration updates should land in the permanent record quickly so the rest of the squad sees the current operating model.
12 - Cleanup pattern: distinguish team-member agent directories (`agents/{squad-member}/`) from orphaned agent definitions (`.github/agents/*.agent.md`). Archive before deleting if historical value is uncertain; delete confidently once verified dead (unused in workflows).
13 +- 2026-06-01 review note: PR #218 looked structurally sound and its targeted analysis tests passed locally after dependency setup; the fix closes prompt placeholder leakage and restores the GitHub Models fallback path.
14 +- 2026-06-01 review note: PR #219 stayed within presentation scope and diff-check was clean, but local Hugo validation remained blocked by the repo's existing toolchain baseline rather than the PR itself.
15 +- 2026-06-01 governance note: GitHub will not let this account approve its own PRs, so branches opened as `jmservera` still need an independent reviewer before Leela can treat approval gating as satisfied.
.squad/agents/scribe/history.md
+6
@@ -6,3 +6,9 @@
6 ## Learnings
7 - Documentation should preserve durable outcomes and discard transient coordination chatter.
8 - When a team-wide operating pattern stabilizes, it belongs in `.squad/skills/` rather than repeated across multiple history files.
9 +
10 +## 2026-06-01 Decisions Archive & Inbox Processing
11 +- Archived 863 lines (entries older than 7 days) from decisions.md to decisions-archive.md
12 +- Merged leela-pr-review.md from inbox into Active Decisions section
13 +- decisions.md reduced from 55,132 bytes to 14,288 bytes (archive triggered by >= 51,200 threshold)
14 +- All inbox files cleaned up; decisions.md now contains only active decisions (2026-05-25 and later)
.squad/decisions-archive.md new
+1179
@@ -0,0 +1,1179 @@
1 +# Squad Decisions Archive
2 +
3 +## Archived Decisions (older than 7 days)
4 +
5 +## Analysis Output Specification (2026-05-18)
6 +
7 +**Issue:** #9 — Define weekly analysis contract between crawler output and site generator
8 +**Author:** Farnsworth (Analyst)
9 +**Status:** Approved for Phase 2 implementation
10 +**Date:** 2026-05-18T12:07:20.778+02:00
11 +
12 +## Analyze Job Integration & Quality Gate (2026-05-18)
13 +
14 +**Issue:** #10 — Integrate Actions analyze job with Copilot path and reviewer gate
15 +**Author:** Bender (Crawler agent)
16 +**Status:** Approved for Phase 2 implementation
17 +**Date:** 2026-05-18T13:05:53.678+02:00
18 +
19 +## Architecture Decision: CI Analysis Interface & Fallback Architecture
20 +
21 +**Date:** 2026-05-18T10:25:12.565+02:00
22 +**Author:** Leela (Lead/Architect)
23 +**Status:** Approved
24 +**Issue:** #2 — Decide CI analysis interface and fallback architecture
25 +**Depends on:** #1 (Copilot CLI investigation — completed by Bender)
26 +
27 +## Crawler Cache & Artifact Handoff Decision (2026-05-18)
28 +
29 +**Issue:** #8 — Create weekly Actions crawl job with artifact handoff
30 +**Author:** Bender (Crawler agent)
31 +**Status:** Approved for implementation
32 +**Date:** 2026-05-18T12:07:20.778+02:00
33 +
34 +## Crawler Hardening Decision (2026-05-18)
35 +
36 +**Issue:** #6 — Harden crawler for production readiness
37 +**Author:** Bender (Crawler agent)
38 +**Status:** Approved — implemented in crawler
39 +**Date:** 2026-05-18T10:59:10.800+02:00
40 +
41 +## Dry-Run Validation Findings (2026-05-18)
42 +
43 +**Issue:** #7 — Validate dry-run execution of full pipeline
44 +**Author:** Fry (Validator)
45 +**Status:** Findings archived for Phase 2 planning
46 +**Date:** 2026-05-18T10:59:10.800+02:00
47 +
48 +## Generate & Deploy Workflow (2026-05-18)
49 +
50 +**Issue:** #11 — Implement generate-and-deploy workflow for GitHub Pages
51 +**Author:** Amy (Generator agent)
52 +**Status:** Approved for Phase 2 implementation
53 +**Date:** 2026-05-18T13:20:07.067+02:00
54 +
55 +## Reskill Retrospective & Learning State (2026-05-18)
56 +
57 +**Issue:** #14 — Reskill retrospective, learned-state injection, and quality trend tracking
58 +**Author:** Farnsworth (Analyst)
59 +**Status:** Approved for Phase 2 implementation
60 +**Date:** 2026-05-18T15:22:25.067+02:00
61 +
62 +## Run Counter & Reskill Trigger (2026-05-18)
63 +
64 +**Issue:** #15 — Add run counter persistence and every-fifth-run reskill trigger
65 +**Author:** Bender (Crawler agent)
66 +**Status:** Approved for Phase 1B implementation
67 +**Date:** 2026-05-18T15:22:25.067+02:00
68 +
69 +## Topic-Specific News Channels Architecture (2026-05-18)
70 +
71 +**Issue:** #16 — Topic-specific news channels architecture
72 +**Author:** Leela (Lead/Architect)
73 +**Status:** Proposed
74 +**PRD:** docs/PRD-topic-channels.md
75 +**PR:** #39
76 +**Date:** 2026-05-18T13:20:07.067+02:00
77 +
78 +### Architecture Decision: SquadScope Foundation
79 +
80 +**Date:** 2026-05-18
81 +**Author:** Leela (Lead/Architect)
82 +**Status:** Proposed — awaiting stakeholder approval
83 +**Context:** PRD for greenfield SquadScope project
84 +
85 +**Decisions Proposed:**
86 +
87 +1. **Static Site Generator: Hugo (recommended)**
88 + - Why: Fastest builds (critical as archive grows to hundreds of pages), native RSS, single binary (no Node in CI), mature taxonomy support.
89 + - Alternative: Astro — better component model but heavier toolchain. Migrate later if interactive features needed.
90 + - Awaiting: jmservera preference confirmation.
91 +
92 +2. **Search: Pagefind**
93 + - Why: Fully static (no server), tiny JS bundle, build-time indexing, free, supports metadata filters.
94 + - Trade-off: Index grows with content, but estimated 5+ years before any concern.
95 +
96 +3. **Notifications MVP: RSS + GitHub Releases**
97 + - Why: Zero external dependencies, no accounts to manage, built into GitHub ecosystem.
98 + - Phase 2: Add GitHub Discussions, webhook support.
99 + - Not yet: Email newsletters (evaluate if demand exceeds RSS reach).
100 +
101 +4. **Pipeline Architecture: Crawl → Analyze → Generate → Notify**
102 + - Why: Clean separation of concerns, each stage testable independently, artifacts stored between stages.
103 + - Key constraint: Copilot invocation in CI is an open question. May need fallback strategy.
104 +
105 +5. **Reskill Cycle: Every 5th run**
106 + - Mechanism: Integer counter in `.squad/run-counter.txt`, modulo check.
107 + - Why simple counter: Avoids complex state management, easy to audit and reset.
108 +
109 +6. **Content Immutability: Weekly pages never modified after publication**
110 + - Why: Historical integrity, reproducible archive, no merge conflicts on old content.
111 +
112 +7. **Crawler Plugin Architecture (future-facing)**
113 + - Why: Design for extensibility now so adding HN/Reddit/etc. doesn't require pipeline rewrite.
114 + - Pattern: `DataSource` protocol with `crawl()`, `get_name()`, `get_rate_limits()` interface.
115 +
116 +**Risks Acknowledged:**
117 +- Copilot API availability in CI (Medium probability, High impact)
118 +- Analysis quality without human review (mitigated by reviewer agent gate + reskill)
119 +- GitHub API rate limits (mitigated by auth tokens + backoff)
120 +
121 +**Open Questions Requiring Input:**
122 +- OQ1/OQ3: Copilot in Actions — how? (blocks Phase 2)
123 +- OQ2: Hugo vs Astro final call
124 +- OQ4: Star threshold (50 proposed)
125 +- OQ8: Copilot usage limits in automation
126 +
127 +## 2026-05-19: Milestone-based workflow adopted
128 +
129 +- **Owner:** jmservera (via Copilot)
130 +- **Date:** 2026-05-19
131 +- **Decision:** All future work organized into versioned milestones (v0.5, v0.6, etc.). PRDs are decomposed into issues, assigned to milestones, then moved to docs/processed/. This enables progress tracking and versioning.
132 +- **Why:** User directive — makes work easier to follow and enables versioning.
133 +
134 +## 2026-05-19: Press Context Dual-Mode Rendering
135 +
136 +- **Owner:** Farnsworth
137 +- **Date:** 2026-05-19T20:50:22+02:00
138 +- **Status:** Implemented
139 +- **Decision:** Implement dual-mode rendering in `render_press_context.py` to serve AI prompts (full data + instructions) and reader-facing fallback (clean narrative) separately via `reader_mode` parameter and post-processing.
140 +- **Why:** The press context serves two audiences. AI prompts need full data and model instructions; reader-facing pages should not expose AI directives or 100+ repo lists.
141 +- **Changes:**
142 + - `render_press_context(reader_mode=False)` — new kwarg. When True, limits correlations to top 10, strips `### Instructions` block, and passes reader_mode to `format_divergences()`
143 + - `format_correlations_list(top_n=None)` — new kwarg. Truncates display and appends "…and N more repos"
144 + - `format_divergences(reader_mode=False)` — new kwarg. Replaces instruction bullets with reader-friendly narrative
145 + - `analyze_fallback._strip_ai_instructions(content)` — new helper. Applied in no-AI path to post-process rendered content
146 +- **Consequences:** AI prompt path unchanged (full instructions + list continue to model); no-AI fallback now produces clean reader output. 16 new tests cover truncation, sorting, instruction stripping, narrative injection. All 498 tests passing. PR #135 merged.
147 +
148 +## 2026-05-19: TechCrunch RSS as Enrichment Signal (PR #55)
149 +
150 +- **Owner:** Bender
151 +- **Date:** 2026-05-19
152 +- **Decision:** TechCrunch RSS integration is an enrichment signal (not primary source) with explicit low-expectation framing (5–15% correlation hit rate). Feature degrades to zero noise when no correlations found.
153 +- **Why:** Correlation between press articles and repos is inherently low. Value lies in the delta (hype vs traction), not article summarization. Enrichment positioning allows silent failure without degrading digest.
154 +- **Implications:** All future `DataSource` plugins must declare "primary" or "enrichment" status. Enrichment sources require explicit failure/removal criteria. Farnsworth's analysis treats correlation data as optional context, never required input.
155 +
156 +## Constraints Respected
157 +
158 +- `reader_mode=False` output is unchanged — AI prompt consumers still receive full raw data.
159 +- README fetching only happens in reader_mode=True paths (no side effects in CI pre-rendering).
160 +- Article title lookup reuses the already-loaded `tc_data["articles"]` list — no new I/O for the article side.
161 +- All new functions are covered by unit tests; 513 tests pass.
162 +
163 +---
164 +
165 +# Decision: CI Self-Learning Pipeline Architecture
166 +
167 +**Date:** 2026-05-19T22:57:55+02:00
168 +**Author:** Leela (Lead/Architect)
169 +**Status:** Proposed
170 +**Scope:** Analysis and reskill CI jobs — self-learning loop
171 +
172 +## Cost Estimation & Budget Controls (2026-05-19)
173 +
174 +**Issue:** #17 — Cost estimation framework for SquadScope
175 +**Author:** Leela (Lead/Architect)
176 +**Status:** Proposed
177 +**PRD:** docs/PRD-cost-estimation.md
178 +**Date:** 2026-05-19T05:17:53.102+02:00
179 +
180 +## Directive: Always test the whole publishing cycle before considering work done (2026-05-19)
181 +
182 +**By:** jmservera (via Copilot)
183 +**Date:** 2026-05-19T19:37:45+02:00
184 +
185 +User directive — captured for team memory. Always test the whole publishing cycle before considering work done.
186 +
187 +---
188 +
189 +## Directive: Never bypass branch protection rulesets (2026-05-19)
190 +
191 +**By:** jmservera (via Squad)
192 +**Date:** 2026-05-19T18:05:10Z
193 +
194 +CI workflows must not push directly to protected branches. Use PR-based commits instead. Never add bypass actors to rulesets to work around branch protection.
195 +
196 +**Why:** Branch protection exists to ensure code review on every change. Bypassing it for convenience undermines the safety net.
197 +
198 +---
199 +
200 +
201 +# Decision: Divergence Section Uses Narrative Prose in Reader Mode
202 +
203 +**Date:** 2026-05-19T21:24:54+02:00
204 +**Author:** Farnsworth (Analyst)
205 +**Status:** Implemented
206 +**Affects:** `scripts/render_press_context.py`, `tests/test_render_press_context.py`
207 +
208 +## Files Changed
209 +
210 +- `scripts/analyze_fallback.py` — `_render_press_section_no_ai()` (lines 346–370)
211 +
212 +---
213 +
214 +# Decision: Correlation Summary — Narrative Prose in reader_mode
215 +
216 +**Date:** 2026-05-19T22:34:57+02:00
217 +**Author:** Farnsworth (Analyst)
218 +**PR:** #138
219 +**Status:** Merged
220 +
221 +## Implications
222 +
223 +- Any future changes to reader-mode divergence prose go into the two helper functions.
224 +- If the data schema adds new fields (e.g., `growth_rate`), the helpers can incorporate them without touching AI-mode output.
225 +- Tests updated: `test_reader_mode_has_narrative` and `test_reader_mode_has_repo_links` replace the old phrase-matching assertions. 499 tests pass.
226 +
227 +---
228 +
229 +# Decision: No-AI Fallback Must Re-render from Raw Data for Reader Mode
230 +
231 +**Date:** 2026-05-19T21:54:14+02:00
232 +**Author:** Farnsworth
233 +**Status:** Implemented (PR #137, merged)
234 +
235 +## TechCrunch RSS as First Non-GitHub Data Source (2026-05-19)
236 +
237 +**Issue:** TechCrunch integration as first non-GitHub crawler plugin
238 +**Author:** Farnsworth (Analyst)
239 +**Status:** Proposed
240 +**PRD:** docs/PRD-techcrunch-integration.md
241 +**Date:** 2026-05-19T11:48:44.543Z
242 +
243 +## Implementation
244 +
245 +- Removed `--model claude-sonnet-4` from Copilot CLI invocations
246 +- Removed workflow pinned preflight model, switched to generic `copilot-default` rate profile
247 +- Promoted `GITHUB_MODELS_MODEL` to workflow-level env with `openai/gpt-4o` default
248 +
249 +**Files:** `.github/workflows/crawl-and-publish.yml`, `scripts/preflight_cost_check.py`, `scripts/track_token_usage.py`
250 +
251 +---
252 +
253 +# Decision: Prevent Copilot stdout from Leaking into Published Markdown
254 +
255 +**Date:** 2026-05-20T22:14:02+02:00
256 +**Owner:** Farnsworth
257 +**Status:** Proposed
258 +
259 +## Weekly Analysis Article Restructure
260 +
261 +**Date:** 2026-05-20T19:15:53.942+02:00
262 +**Author:** Leela (Lead/Architect) — Proposed; Farnsworth (Analyst) — Implemented
263 +**Status:** Implemented
264 +**Requested by:** jmservera
265 +
266 +### Implementation
267 +
268 +**Files Changed:** `prompts/analyze-weekly.md`, `docs/analysis-spec.md`, `scripts/analysis_gate.py`, `scripts/analyze_fallback.py`, `scripts/generate_rollups.py`, 5 test files.
269 +
270 +**Backward Compatibility:** `generate_rollups.py` tries new heading names first and falls back to old names. All frontmatter fields, repo link format, quality_score gate, and body word count rules unchanged.
271 +
272 +**Outcome:** All 519 tests pass with new structure.
273 +
274 +---
275 +
276 +# Decision: Model Resilience for Weekly CI
277 +
278 +**Date:** 2026-05-20T20:09:26+02:00
279 +**Owner:** Farnsworth
280 +**Status:** Proposed
281 +
282 +## Impact
283 +
284 +- All charters now under 1.5 KB target
285 +- Oversized histories condensed
286 +- 3 new skills extracted (minimal-agent-charter, agent-history-hygiene, weekly-learning-loop)
287 +- 1 existing skill upgraded (branch-protection-pr-workflow)
288 +- **Net savings: 68.4% reduction** (39,568 → 12,521 bytes)
289 +
290 +---
291 +
292 +# Decision: Farnsworth Weekly Headline Review
293 +
294 +**Date:** 2026-05-21T12:33:16.507+02:00
295 +**Author:** Farnsworth (Analyst)
296 +**Status:** Implemented
297 +
298 +## Implementation
299 +
300 +- Changed Copilot CLI redirects from output markdown to `/dev/null`
301 +- Added `scripts/sanitize_agent_output.py` to strip leaked lines (`✅ Farnsworth is done`, `Editorial thesis:`, etc.)
302 +- Reinforced `prompts/analyze-weekly.md` so agent writes only publication-ready markdown
303 +
304 +**Files:** `.github/workflows/crawl-and-publish.yml`, `prompts/analyze-weekly.md`, `scripts/sanitize_agent_output.py`, `tests/test_sanitize_agent_output.py`
305 +
306 +---
307 +
308 +# Decision: Squad Agent Documentation Restructure
309 +
310 +**Date:** 2026-05-21T09:23:40+02:00
311 +**Author:** Farnsworth (Analyst)
312 +**Status:** Implemented
313 +
314 +
315 +## Archived from 2026-06-01 sweep (entries older than 7 days)
316 +
317 +## Copilot CLI in GitHub Actions (2026-05-18)
318 +
319 +**Requestor:** jmservera
320 +**Source:** Bender investigation
321 +**Status:** Approved for implementation
322 +
323 +- **Action:** Use standalone **GitHub Copilot CLI** (not deprecated `gh copilot` extension)
324 +- **Auth:** Fine-grained PAT with **Account → Copilot Requests** permission, passed as `COPILOT_GITHUB_TOKEN`
325 +- **Invocation:** Programmatic via `copilot -p "..." -s --no-ask-user --allow-tool=...`
326 +- **Output:** JSON (--output-format=json, JSONL) or markdown (--share=PATH)
327 +- **Fallback:** GitHub Models API with `GITHUB_TOKEN` (permissions: models: read)
328 +- **Next spike:** Test whether `copilot-requests: write` on workflow token replaces PAT (community action shows promise)
329 +
330 +## PRD Decomposition into GitHub Issues (2026-05-18)
331 +
332 +**Decision:** Decompose docs/PRD.md into 24 issues across Phase 0 (blocker investigations) + Phases 1-4.
333 +
334 +**Phase 0 gating condition:** Resolves OQ1/OQ3 — Copilot invocation in GitHub Actions.
335 +
336 +**Why:** Isolates largest delivery risk; ensures crawler, analyzer, and generator teams can work independently; makes reviewer gates explicit.
337 +
338 +**Implications:**
339 +- Phase 2 analyzer work blocked until Phase 0 closure
340 +- Phase 1 (site foundation + crawler) can proceed in parallel
341 +- QA and documentation are first-class issues
342 +
343 +## MCP Tools for Multi-Site Crawling (2026-05-18)
344 +
345 +**Directive:** MCP tools may crawl sites beyond GitHub; remote calls require allowlist in Copilot agent settings (GitHub repo settings).
346 +
347 +**Impact:** Affects crawler extensibility design (HackerNews, Reddit, etc.) and GitHub Actions Copilot token model.
348 +
349 +### Context
350 +
351 +SquadScope's pipeline requires AI-powered analysis of crawled GitHub data inside GitHub Actions. Bender's investigation (docs/investigation-copilot-cli.md) confirmed that the standalone `copilot` CLI can run in CI with a fine-grained PAT, and identified GitHub Models API as a credible fallback. This decision formalizes the approved architecture.
352 +
353 +### Decision 1: Primary Analysis Path — Standalone Copilot CLI
354 +
355 +**Approved.** The primary CI analysis engine is the standalone `copilot` CLI (`@github/copilot`).
356 +
357 +**Rationale:**
358 +- Officially documented by GitHub for Actions automation
359 +- Real-world precedent (microsoft/BCApps)
360 +- Repo-aware agent behavior: can read/write files, use tools (grep, glob, read, write)
361 +- Supports structured output (`--output-format=json`) and transcript export (`--share=PATH`)
362 +- Programmatic mode (`-p`, `--no-ask-user`) is CI-safe
363 +
364 +**Invocation Contract:**
365 +
366 +```bash
367 +copilot -p "<prompt>" \
368 + -s \
369 + --no-ask-user \
370 + --allow-tool=read \
371 + --allow-tool=write \
372 + --allow-tool=glob \
373 + --allow-tool=grep \
374 + --output-format=json \
375 + --share=./copilot-session.md
376 +```
377 +
378 +**Token Strategy:**
379 +
380 +| Item | Value |
381 +|------|-------|
382 +| Secret name | `COPILOT_GH_TOKEN` |
383 +| Token type | Fine-grained PAT (`github_pat_...`) |
384 +| Permission | Account → Copilot Requests |
385 +| Env variable | `COPILOT_GITHUB_TOKEN` |
386 +| Resource owner | Personal account (jmservera) |
387 +| Classic PAT | **Not supported** — do not use `ghp_` tokens |
388 +
389 +Wire in workflow:
390 +```yaml
391 +env:
392 + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GH_TOKEN }}
393 +```
394 +
395 +### Decision 2: Fallback Path — GitHub Models API
396 +
397 +**Approved.** If Copilot CLI is unavailable, rate-limited, or proves too brittle in CI, the fallback is the GitHub Models API.
398 +
399 +**Rationale:**
400 +- Works with built-in `GITHUB_TOKEN` (no PAT needed)
401 +- Simple REST interface, easy to test and mock
402 +- Supports structured JSON responses
403 +- Less agentic, but sufficient for summarization tasks
404 +
405 +**Invocation Contract:**
406 +
407 +```yaml
408 +permissions:
409 + models: read
410 +
411 +steps:
412 + - name: Analyze via GitHub Models
413 + env:
414 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
415 + run: |
416 + curl "https://models.github.ai/inference/chat/completions" \
417 + -H "Content-Type: application/json" \
418 + -H "Authorization: Bearer $GITHUB_TOKEN" \
419 + -d @data/prompts/analyze-week.json
420 +```
421 +
422 +**Trigger conditions for fallback:**
423 +- Copilot CLI auth failure (token expired, permission revoked)
424 +- Copilot CLI rate-limit / quota exhaustion
425 +- Copilot CLI install failure (npm registry issue, Node version mismatch)
426 +- Repeated non-deterministic failures (3+ retries fail)
427 +
428 +### Decision 3: Pipeline Stage Contracts
429 +
430 +**Stage boundaries and data flow:**
431 +
432 +```
433 +┌─────────┐ JSON ┌──────────┐ Markdown ┌──────────┐ HTML ┌────────┐
434 +│ Crawl │ ──────────► │ Analyze │ ───────────► │ Generate │ ────────► │ Deploy │
435 +└─────────┘ data/raw/ └──────────┘ data/analyzed └──────────┘ public/ └────────┘
436 +```
437 +
438 +**Crawl → Analyze:**
439 +
440 +| Property | Specification |
441 +|----------|---------------|
442 +| Location | `data/raw/` |
443 +| Format | JSON (one file per crawl run) |
444 +| Naming | `YYYY-WNN.json` (e.g., `2026-W21.json`) |
445 +| Schema | Array of repo objects: `{name, url, description, stars, stars_gained, language, topics, created_at}` |
446 +| Contract | Analyzer MUST NOT modify files in `data/raw/` |
447 +
448 +**Analyze → Generate:**
449 +
450 +| Property | Specification |
451 +|----------|---------------|
452 +| Location | `data/analyzed/` |
453 +| Format | Markdown with YAML frontmatter |
454 +| Naming | `YYYY-WNN-summary.md` |
455 +| Frontmatter | `title`, `date`, `week`, `year`, `categories`, `quality_score` |
456 +| Sections | Signal (important), Noise (overhyped), Gaps (missing from conversation) |
457 +| Contract | Must include `quality_score` (0-100) for reviewer gate |
458 +
459 +**Generate → Deploy:**
460 +
461 +| Property | Specification |
462 +|----------|---------------|
463 +| Location | `public/` (Hugo build output) |
464 +| Format | Static HTML/CSS/JS |
465 +| Contract | Hugo builds from `content/` which is populated from `data/analyzed/` |
466 +
467 +### Decision 4: Reviewer Gate
468 +
469 +Analysis output in `data/analyzed/` MUST pass a quality check before the Generate stage runs.
470 +
471 +**Gate criteria:**
472 +- `quality_score` in frontmatter is ≥ 60
473 +- All three required sections present (Signal, Noise, Gaps)
474 +- Word count ≥ 200 (guards against empty/stub output)
475 +- No raw JSON or error messages in body
476 +
477 +**On failure:**
478 +- Block publish
479 +- Log failure reason to workflow summary
480 +- Open an issue tagged `quality-gate-failure` for human review
481 +- Do NOT retry analysis automatically (preserves Copilot request budget)
482 +
483 +### Decision 5: MCP Tools Strategy
484 +
485 +**Directive:** MCP tools are authorized for multi-site crawling extensibility.
486 +
487 +**Constraints:**
488 +- Remote MCP calls MUST be allowlisted in GitHub Copilot agent settings (repo-level)
489 +- MCP tool definitions live in `.github/copilot/mcp.json`
490 +- Only crawl-stage tools may make external HTTP calls
491 +- Analysis-stage tools are local-only (read, write, glob, grep)
492 +
493 +**Future extensibility:**
494 +- Each new data source (HN, Reddit, etc.) is an MCP tool with a `crawl()` method
495 +- Tools registered in allowlist before activation
496 +- Rate limits per-source defined in tool config
497 +
498 +### Decision 6: Nap & Reskill Interface
499 +
500 +Every 5th pipeline run triggers a reskill cycle. The reskill workflow invokes Copilot CLI to review squad state and propose improvements.
501 +
502 +**Mechanism:**
503 +
504 +```bash
505 +# Counter check
506 +COUNTER=$(cat .squad/run-counter.txt)
507 +if [ $((COUNTER % 5)) -eq 0 ]; then
508 + # Reskill invocation
509 + copilot -p "Read .squad/agents/*/history.md and .squad/decisions.md. \
510 + Assess: What patterns are working? What should change? \
511 + Write recommendations to .squad/reskill/YYYY-WNN.md" \
512 + --no-ask-user \
513 + --allow-tool=read \
514 + --allow-tool=write \
515 + --allow-tool=glob \
516 + --share=./reskill-session.md
517 +fi
518 +```
519 +
520 +**Input context for reskill:**
521 +- `.squad/agents/*/history.md` — all agent learnings
522 +- `.squad/decisions.md` — current decision log
523 +- `data/analyzed/` — recent analysis outputs (quality trend)
524 +- `.squad/run-counter.txt` — run history
525 +
526 +### Decision 7: Weekly Analysis Fail-Fast Policy
527 +
528 +Weekly article generation must only publish Copilot-authored analysis. The workflow now fails immediately if Copilot CLI is unavailable or the analysis call fails; it does not fall back to GitHub Models or no-AI summaries.
529 +
530 +**Enforcement:**
531 +- `scripts/analysis_gate.py` rejects any analysis source other than `copilot-cli`
532 +- The article title must be a journalistic headline, not the generic `Week NN, YYYY Analysis` template
533 +- If Copilot cannot run, the workflow is expected to be rerun later rather than publishing stale content
534 +
535 +**Goal:** prevent generic or stale weekly articles from being published when the preferred analysis agent is unavailable.
536 +
537 +**Output:**
538 +- `.squad/reskill/YYYY-WNN.md` — improvement recommendations
539 +- Optional: PR with proposed changes to agent prompts or pipeline config
540 +
541 +### Decision 7: Future Validation Spike — GITHUB_TOKEN + copilot-requests: write
542 +
543 +**Status:** Noted for future spike (not yet approved for production use).
544 +
545 +The community action `austenstone/copilot-cli` demonstrates that `GITHUB_TOKEN` with `permissions: copilot-requests: write` may eliminate the PAT requirement entirely. GitHub's official docs do not yet confirm this path.
546 +
547 +**Spike criteria:**
548 +- Create a test workflow with `copilot-requests: write`
549 +- Validate auth succeeds without PAT
550 +- Confirm quota/billing behaves identically
551 +- If successful: migrate from PAT to workflow token (simpler, no secret rotation)
552 +
553 +### Risks & Mitigations
554 +
555 +| Risk | Probability | Impact | Mitigation |
556 +|------|------------|--------|------------|
557 +| Copilot CLI quota exhaustion | Medium | High | Coarse-grained prompts; fallback to Models API |
558 +| PAT expiration in CI | Medium | Medium | GitHub secret expiry alerts; spike on workflow token |
559 +| Analysis quality drift | Low | High | Reviewer gate + reskill cycle |
560 +| MCP allowlist misconfiguration | Low | Medium | CI test that validates mcp.json against live config |
561 +| Node 22 unavailability in runner | Very Low | Low | Pin `actions/setup-node@v4` with explicit version |
562 +
563 +### Summary
564 +
565 +The SquadScope CI analysis pipeline uses a two-tier approach: Copilot CLI (primary, agentic, repo-aware) with GitHub Models API (fallback, simpler, REST-based). Data flows through well-defined stage boundaries with JSON → Markdown → HTML transformations. A quality gate ensures no low-quality analysis reaches publication. The architecture is designed for extensibility via MCP tools and self-improvement via the reskill cycle.
566 +
567 +### Decision: Cache Restoration from Prior Workflow Runs
568 +
569 +The weekly crawl workflow (`crawl-and-publish.yml`) MUST restore `data/cache/` from the latest successful run before executing `scripts/crawl.py`.
570 +
571 +**Rationale:**
572 +- Reuses the crawler's on-disk GitHub API cache across weekly runs
573 +- Lowers repeated README/search calls on warm runs
574 +- Keeps the crawl stage self-contained until downstream jobs arrive in later issues
575 +
576 +**Implementation Details:**
577 +- Workflow needs `actions: read` permission to discover prior successful runs
578 +- Download the `crawl-cache` artifact before running the crawler
579 +- Upload new cache artifact after successful crawl
580 +- Preserve crawler state through GitHub Actions artifact storage
581 +
582 +**Implications:**
583 +- Reduces GitHub API rate limit consumption across runs
584 +- Enables faster weekly crawls as cache grows
585 +- Supports Phase 1 crawl-only deliverables
586 +
587 +---
588 +
589 +### Decision: Degradable README Signals & Bounded Retry Strategy
590 +
591 +Treat README lookups as a degradable signal instead of a hard-stop path. The crawler now:
592 +- Caches API responses to reduce repeated calls
593 +- Saves weekly star snapshots under `data/snapshots/`
594 +- Logs rate-limit state for observability
595 +- Caps README retry delays to ensure partial failures don't block weekly crawls
596 +
597 +**Rationale:**
598 +- Search queries are cheap, but hundreds of README checks can trigger secondary GitHub API throttling
599 +- Bounded retries plus persistent cache keep Phase 1 crawls finishable
600 +- Partial failures recorded in metadata preserve data integrity even when GitHub responses are incomplete
601 +
602 +**Outcomes:**
603 +- Phase 1 crawls remain finishable even during GitHub API congestion
604 +- Farnsworth (analyzer) receives usable JSON data even when README metadata is partial
605 +- Better observability into rate-limit behavior across runs
606 +
607 +---
608 +
609 +### Key Findings
610 +
611 +1. **Hugo Version Pinning Required**
612 + - Local environment defaulted to `hugo v0.123.7`
613 + - Repository theme requires `v0.146.0+`
614 + - Dry-run only succeeded with `hugo v0.161.1`
615 + - **Action:** Pin Hugo version in CI/validation workflows
616 +
617 +2. **Trending Analysis Requires Historical Data**
618 + - `data/raw/2026-W21.json` contains no usable `stars_gained` values in `trending_repos`
619 + - Current output is popularity-biased rather than momentum-based
620 + - **Action:** Implement multi-week aggregation in analyzer for trend detection
621 +
622 +3. **Content Filtering Needs Refinement**
623 + - Sample week contains exploit, bypass, cheat, and game-mod repositories in "new" ranking
624 + - Current filtering logic insufficient for curated editorial quality
625 + - **Action:** Implement stricter content filtering or human quality gate in Phase 2
626 +
627 +4. **Analyzer-Generator Contract Needs Specification**
628 + - PRD weekly page shape and approved analyzer contract are close but not identical
629 + - Generator step needs explicit mapping from analyzed markdown to publishable Hugo content
630 + - **Action:** Formalize analyzer output schema and generator input contract (Phase 2)
631 +
632 +---
633 +
634 +### Decision
635 +
636 +Extend `.github/workflows/crawl-and-publish.yml` with an `analyze` job that runs after `crawl` and enforces an automated quality gate before downstream publish steps.
637 +
638 +**Stage handoff artifacts:**
639 +- `raw-data` for crawl → analyze
640 +- `analyzed-data` for analyze → generate
641 +
642 +**Analysis paths:**
643 +1. Primary: Standalone Copilot CLI with `permissions.copilot-requests: write` and `COPILOT_GH_TOKEN`
644 +2. Fallback: `scripts/analyze_fallback.py` using GitHub Models API with `permissions.models: read`
645 +
646 +**Quality Gate Contract** — workflow must fail if any of the following are false:
647 +- YAML frontmatter exists with exact required keys
648 +- `quality_score` is an integer ≥ 60
649 +- Required H2/H3 sections appear in documented order
650 +- Body word count ≥ 200
651 +- Output does not leak raw JSON, traceback, or placeholder content
652 +
653 +**Implications:**
654 +- Generate jobs can safely consume `analyzed-data` without inspecting raw crawl artifacts
655 +- Copilot failures do not block immediately; GitHub Models fallback preserves publishability
656 +- Reviewer-gate failures stop low-quality summaries before downstream stages
657 +
658 +---
659 +
660 +### Decisions
661 +
662 +1. **Analyzer output frontmatter is a superset contract.**
663 + - Required fields: `title`, `date`, `week`, `year`, `tags`, `categories`, `repos_featured`, `stars_tracked`, `top_repo`, `quality_score`, `summary`
664 +
665 +2. **Reader-facing structure: five stable H2 sections** (in order):
666 + - `Notable New Repositories`
667 + - `Trending This Week (Stars Gained)`
668 + - `Trend Analysis` (with required `### Signal` and `### Noise` subsections)
669 + - `What's Missing` (with required `### Gaps` subsection)
670 + - `Conclusion`
671 +
672 +3. **Trending must degrade honestly when momentum data is incomplete.**
673 + - If `stars_gained` is absent or null, summary must say the section is directional, not a true momentum leaderboard
674 +
675 +4. **Analyzer input schema: strict on core fields, tolerant on metadata.**
676 + - Required: week slug, crawl timestamp, new/trending repo arrays, top topics
677 + - Optional: `partial_failures`, `filter_summary`, `snapshot_path`
678 +
679 +---
680 +
681 +### Decision
682 +
683 +Keep `.github/workflows/deploy-site.yml` for push-to-main deployments. Weekly automation lives in `.github/workflows/crawl-and-publish.yml` end-to-end (crawl → analyze → generate → deploy).
684 +
685 +**Generate stage:**
686 +1. Read `data/analyzed/YYYY-WNN-summary.md`
687 +2. Write Hugo page to `content/weekly/YYYY/WNN.md` with archetype-compatible frontmatter
688 +3. Commit back to default branch before Pages build so future archive builds retain previously published content
689 +
690 +**Deploy:**
691 +- Build with Hugo 0.161.1 + Pagefind
692 +- Deploy with `actions/deploy-pages@v4` under `github-pages` environment
693 +
694 +---
695 +
696 +### Decisions
697 +
698 +1. **Create `.squad/run-counter.txt`** initialized to `0`
699 +2. **Increment counter** in `crawl` job's git commit step after syncing default branch, then commit `.squad/run-counter.txt` with `data/raw/` and `data/snapshots/`
700 +3. **Add `reskill-check` job** that reads persisted counter and exposes `should_reskill` for downstream jobs
701 +4. **Add placeholder `reskill` job** that logs the trigger and scaffolds `.squad/skills/` and `.squad/reskill/` until Issue #14 adds full retrospective implementation
702 +
703 +**Why:** Reading the counter only after syncing `origin/main` keeps the increment tied to latest persisted state. Committing together ensures survival between weekly runs. Splitting `reskill-check` from `reskill` keeps trigger logic auditable.
704 +
705 +---
706 +
707 +### Decisions
708 +
709 +1. **Reskill context** from latest analyzer evidence, not generic squad history:
710 + - Inputs: last ~5 `data/analyzed/*-summary.md` files, `data/snapshots/` hindsight, `wisdom.md`, learned skills, quality trend report
711 + - Why: gives retrospective concrete calibration points and closes gap findings
712 +
713 +2. **Learned state flows back** into weekly analyzer prompt:
714 + - Inject `.squad/identity/wisdom.md` into `{{WISDOM}}` placeholder
715 + - Inject concatenated markdown from `.squad/skills/` into `{{SKILLS}}` placeholder
716 + - Why: without prompt injection, learning artifacts exist but never influence future analysis
717 +
718 +3. **Quality trend tracking** is first-class reskill input:
719 + - `scripts/track_quality.py` reads `quality_score` from analyzed summaries, produces markdown trend report
720 + - Why: squad needs lightweight longitudinal measure of editorial quality improvement
721 +
722 +4. **Reskill outputs in persistent squad state:**
723 + - `.squad/reskill/` for weekly retrospective reports
724 + - `.squad/skills/` for extracted reusable patterns
725 + - Both committed to git (not ephemeral workflow output)
726 +
727 +---
728 +
729 +### Summary
730 +
731 +Current SquadScope cost under token-based billing: ~$0.30/week (~$16/year), well within Copilot Pro's 300 credits/month allowance. However, proactive monitoring and budget controls needed before context growth or model upgrades change the picture.
732 +
733 +### Decisions
734 +
735 +1. **Accept current cost profile as sustainable** — $16/year is economically trivial; no immediate model downgrade required
736 +2. **Implement token usage tracking (Phase A)** — Add `scripts/track_token_usage.py` and `data/metrics/token-usage.jsonl` to establish baselines before optimizing
737 +3. **Set budget alert thresholds:**
738 + - Warn at $0.50/run
739 + - Fail at $1.00/run
740 + - Email alert at $5/month cumulative
741 + - Auto-switch to cheaper model at $10/month cumulative
742 +4. **Defer raw JSON pre-processing** — 40-60% savings significant but adds pipeline complexity; implement only if costs grow beyond $30/year
743 +5. **Wisdom.md cap at 5 KB** — Reskill should retire obsolete heuristics, not only append
744 +
745 +**Rationale:** Dominant cost driver (raw JSON at 86K tokens) is stable and bounded by crawl scope. Growth comes from wisdom/skills/history accumulation, which is slow. Premature optimization would add complexity without meaningful savings at current scale.
746 +
747 +**Risks:**
748 +- OQ5/OQ6: Billing mechanics for Copilot CLI vs Models API may differ in ways not yet visible
749 +- Credit exhaustion mid-month would disrupt weekly pipeline if no degradation path exists
750 +
751 +---
752 +
753 +### Key Architectural Decisions
754 +
755 +**Feature First, Not Platform:** Generalize SquadScope into topic channels by adding topic namespace to existing pipeline. No new platform, no new repo structure. Same codebase, configured differently.
756 +
757 +**Multi-Instance Single-Topic (v1):** One fork/config per topic with isolated learning, own `squadscope.topic.yml`, own Actions schedule, own GitHub Pages site. Multi-topic single-instance is v2.
758 +
759 +**Topic Config as Single Source of Truth:** `squadscope.topic.yml` controls:
760 +- Crawler queries
761 +- Scoring weights and thresholds
762 +- Analysis tone and audience
763 +- Learning state paths
764 +- Quality criteria
765 +
766 +**Scoring Pipeline (New Stage):** GitHub topic search is noisy. New `scripts/score_repos.py` between crawl and analyze, scoring repos 0-100 on relevance/momentum/language/noise/recency. Only repos ≥40 reach analysis.
767 +
768 +**Per-Topic Learning Isolation:**
769 +- `topics/{id}/wisdom.md` — domain-specific heuristics
770 +- `topics/{id}/skills/` — extracted patterns
771 +- `topics/{id}/predictions.jsonl` — prediction ledger
772 +- `topics/{id}/scorecards/` — hindsight validation results
773 +- No cross-topic contamination
774 +
775 +**Prediction Ledger with Hindsight Validation:** Every analysis appends machine-readable predictions to `predictions.jsonl`. Four weeks later, `scripts/validate_predictions.py` scores them against actual outcomes (star deltas, fork growth). Scorecards feed into reskill.
776 +
777 +**Topic Quality Criteria:**
778 +- Minimum N repos/week passing filters
779 +- Maximum false positive rate
780 +- Minimum genuinely significant repos per issue
781 +
782 +### Implications
783 +
784 +- Crawler must read config instead of hardcoded queries
785 +- Analysis prompt becomes a template with injection points
786 +- Hugo gains topic taxonomy and per-topic RSS
787 +- All data paths gain `{topic_id}/` prefix
788 +- Reskill reads per-topic state
789 +
790 +### Open for Discussion
791 +
792 +- Should enrichment signals (forks, contributors) be in v1 scorer or deferred?
793 +- Prediction confidence: fixed initial values or prompt-generated?
794 +- Topic config in root vs `topics/` directory?
795 +
796 +---
797 +
798 +### Decision
799 +
800 +Add TechCrunch RSS (`https://techcrunch.com/feed/`) as SquadScope's first non-GitHub data source, implementing Decision #7's crawler plugin architecture.
801 +
802 +**Rationale:**
803 +1. Cross-source correlation enables hype detection (press-driven vs. organic growth)
804 +2. Near-zero cost and complexity (public RSS, no auth, no rate limits)
805 +3. Directly implements the `DataSource` plugin pattern already approved
806 +4. Enriches editorial judgment without changing SquadScope's voice or pipeline structure
807 +
808 +**Impact:**
809 +- **Bender:** Implements `TechCrunchSource` crawler plugin
810 +- **Farnsworth:** Analyzer prompt gains press-context block; labels repos as press-correlated or organic
811 +- **Amy:** Optional correlation badge in Hugo templates
812 +- **Leela:** No architectural changes needed; plugin arch already designed for this
813 +
814 +### Open for Team Input
815 +
816 +- Should we start with full feed or category-specific feeds?
817 +- Correlation annotations: reader-visible or internal-only?
818 +
819 +---
820 +
821 +## Decision: Use `publish` branch for automated data commits (2026-05-19)
822 +
823 +**Author:** Bender (Crawler)
824 +**Status:** Implemented (PR #129)
825 +**Fixes:** Issue #128
826 +
827 +### Context
828 +
829 +The crawl-and-publish workflow failed because:
830 +1. The repo setting "Allow GitHub Actions to create or approve pull requests" is disabled
831 +2. `gh pr create` with `GITHUB_TOKEN` is blocked by this setting
832 +3. Even if enabled, the `copilot_code_review` rule + `required_review_thread_resolution` on main could block auto-merge unpredictably
833 +
834 +### Decision
835 +
836 +Replace PR-based commits with direct push to an unprotected `publish` branch.
837 +
838 +- The main branch ruleset only protects `refs/heads/main`
839 +- The `publish` branch accepts direct pushes from workflow `GITHUB_TOKEN`
840 +- Inter-job data flow uses artifacts (unchanged)
841 +- Deploy job downloads all artifacts directly (no dependency on branch state)
842 +- `reskill-check` reads `run-counter.txt` from `publish` branch with fallback to main
843 +
844 +### Consequences
845 +
846 +- Automated data no longer lands on `main` automatically — it accumulates on `publish`
847 +- A separate manual or scheduled merge from `publish` → `main` can sync when desired
848 +- Main branch protection remains fully intact (no bypasses)
849 +- Pipeline reliability is decoupled from PR permission settings
850 +
851 +### Alternatives Considered
852 +
853 +1. Enable "Allow GitHub Actions to create PRs" — requires repo admin action, doesn't solve auto-merge reliability
854 +2. Use a PAT/GitHub App token — adds secret management complexity
855 +3. `--admin` flag on merge — bypasses protection, violates team decision
856 +
857 +---
858 +
859 +## Decision: Manual W21 content regeneration (2026-05-19)
860 +
861 +**Author:** Bender
862 +**Status:** Executed
863 +
864 +### Context
865 +
866 +The crawl-and-publish workflow (run #26109935234) generated W21 analysis but failed to commit it because the commit step tried to push directly to `main`, which requires PRs (branch protection). PR #123 fixed the workflow to use PR-based commits, but it merged after the failed run.
867 +
868 +### Decision
869 +
870 +Regenerated W21 content manually and created PR #125 to update the page. No workflow code changes needed — the root cause (direct push) was already fixed by PR #123.
871 +
872 +### Impact
873 +
874 +- `content/weekly/2026/W21.md` updated from stale manual dry-run to full analysis
875 +- Monthly/yearly rollups refreshed
876 +- Once PR #125 merges, deploy-site will publish the updated page
877 +- Future scheduled runs will use the PR-based approach and should not hit this again
878 +
879 +---
880 +
881 +## Decision: PR #126 Security Review — Clear (2026-05-19)
882 +
883 +**Author:** Hermes (Security)
884 +**PR:** #126 — "feat: wire TechCrunch RSS into CI pipeline and add API retry backoff"
885 +
886 +### Decision
887 +
888 +PR #126 is **security-clear**. No blocking vulnerabilities found.
889 +
890 +### Key Findings
891 +
892 +- No SSRF risk (hardcoded feed URL)
893 +- Retry logic properly bounded (3 retries, exponential backoff + jitter)
894 +- No secrets leaked in logs
895 +- feedparser dependency is well-maintained, no CVEs
896 +- Workflow permissions unchanged
897 +
898 +### Non-blocking Recommendation
899 +
900 +RSS content fed into AI prompts has a theoretical indirect prompt injection surface. Mitigated by HTML stripping and content truncation. Recommend adding control character sanitization in a future PR for defense-in-depth.
901 +
902 +### Impact
903 +
904 +Team can merge PR #126 without security holds.
905 +
906 +---
907 +
908 +## Decision
909 +
910 +The divergence section in `format_divergences()` now renders as narrative prose when `reader_mode=True`, replacing the prior bullet list format. AI-prompt mode (`reader_mode=False`) is unchanged.
911 +
912 +## Rationale
913 +
914 +Raw topic-and-repo bullet lists communicate data but not meaning. Readers gain more from a paragraph that groups activity, links to repos by short name, and closes with an interpretive sentence. The AI model still needs the full structured data — so the dual-mode architecture cleanly separates the two use cases.
915 +
916 +## Format Decisions
917 +
918 +1. **Repo links:** `[repo-name](https://github.com/owner/repo-name)` — repo name only (after `/`), never `owner/repo (⭐N)`.
919 +2. **Article links:** `[title](url)` — standard markdown.
920 +3. **Topic capping:** Top 6 topics by aggregate star count for "Dev Activity Without Press Coverage"; top 5 for "Tech Trends Without Dev Activity".
921 +4. **Structure:** Two named helpers — `_format_unpublicized_narrative()` and `_format_uncovered_narrative()` — keep the logic isolated and independently testable.
922 +
923 +## Context
924 +
925 +The CI pipeline falls to the no-AI path when the AI API is unavailable. In that path, `_render_press_section_no_ai()` was reading the pre-rendered `data/analyzed/{WEEK}-press-context.md` and stripping AI instructions to produce reader output.
926 +
927 +The problem: that file is generated in AI-prompt mode (`reader_mode=False`). The narrative divergence format introduced in PR #136 is only produced when `reader_mode=True`. So the no-AI path always showed the old bullet-list format regardless of code changes in the reader-mode rendering path.
928 +
929 +## Decision
930 +
931 +**Re-render from raw JSON data in the no-AI path.** Specifically:
932 +
933 +1. Extract the week identifier from the `press_context_path` filename stem.
934 +2. Load `data/raw/{WEEK}-techcrunch.json` and `data/analyzed/{WEEK}-correlations.json`.
935 +3. Call `render_press_context(tc_data, corr_data, week, reader_mode=True)`.
936 +4. If raw files are absent, fall back to the existing strip-based approach.
937 +
938 +## Rationale
939 +
940 +- The pre-rendered press-context.md is an AI prompt artifact, not a reader artifact. It must not be the source of truth for reader-facing output.
941 +- Raw JSON files are always present when the CI pipeline runs (they are produced earlier in the same pipeline run).
942 +- The fallback ensures backward compatibility for edge cases (manual script invocations against older data).
943 +
944 +## Impact
945 +
946 +- The no-AI CI path now uses identical rendering logic to the AI path's fallback output.
947 +- Any future changes to `render_press_context(..., reader_mode=True)` automatically apply to the no-AI path without further changes.
948 +- The W21 page will show the correct narrative format on the next pipeline run.
949 +
950 +## Context
951 +
952 +The Correlation Summary section was showing a raw bullet list of repo names, confidence scores, and match types — useful for AI prompt consumption but meaningless to human readers. The Divergence section had already been upgraded to narrative prose (PR #131). This decision extends that pattern to correlations.
953 +
954 +## Decision
955 +
956 +When `reader_mode=True`, `format_correlations_list()` delegates to `_format_correlations_narrative()` which:
957 +
958 +1. **Groups correlations by org** (first path segment of owner/repo). This is the natural unit of press coverage — TechCrunch writes about organizations, not individual repos.
959 +2. **Ranks groups by aggregate confidence score** (sum of correlation_confidence across all repos in the group).
960 +3. **Fetches README snippets** (first 500 chars) for the top 2 repos per group, up to 6 total, using `urllib.request` with a 5-second timeout and graceful failure. This enables project descriptions in the narrative (e.g., "Guava is a set of core Java libraries from Google").
961 +4. **Produces 1–3 paragraphs** with inline links to repos (short name, e.g., `[codex](https://github.com/openai/codex)`) and matched TechCrunch articles (full title as link text).
962 +
963 +## Alternative Considered
964 +
965 +**No README fetching — use only repo names**: simpler and fully deterministic, but produces flat prose with no editorial context about what the repos actually do. The README fetch adds signal at low cost (max 6 network requests, fails gracefully).
966 +
967 +## Context
968 +
969 +The CI pipeline runs AI analysis (Copilot CLI) and reskill (GitHub Models API) but neither job leverages the squad agent system. The analysis agent has no identity, cannot read its own history/skills, and has no mechanism to write learnings back. The reskill job bypasses Copilot CLI entirely and uses a model (`openai/gpt-4.1`) that returns 403.
970 +
971 +## Decisions
972 +
973 +### 1. Dedicated Farnsworth Agent File (`.github/agents/farnsworth.agent.md`)
974 +
975 +A standalone agent file gives the Copilot CLI the full Farnsworth identity — charter, history reading instructions, post-analysis learning format, and write permissions to `.squad/`.
976 +
977 +**Rationale:** The `--agent` flag loads an agent markdown file with YAML frontmatter and instructions. A dedicated file allows CI-specific directives (learning output format, file write permissions) without polluting the interactive Squad coordinator agent.
978 +
979 +### 2. `--agent` Flag in Copilot CLI Invocations
980 +
981 +Both the analysis and reskill jobs now use:
982 +```bash
983 +copilot --agent .github/agents/farnsworth.agent.md ...
984 +```
985 +
986 +**Rationale:** This loads Farnsworth's identity, making the CLI aware of the agent's history, wisdom, skills, and learning expectations.
987 +
988 +### 3. Learning Commit Strategy: Same Branch, Same Job
989 +
990 +After analysis, `.squad/` changes (history, skills) are committed alongside `data/analyzed/` to the `publish` data branch in a single atomic commit.
991 +
992 +**Rationale:** No additional branch/PR overhead. The data branch is unprotected and already receives CI commits. Learnings are part of the analysis artifact — they should be co-located temporally. The reskill job already commits `.squad/` state via the same pattern.
993 +
994 +### 4. Model Fallback: `openai/gpt-4o` Replaces `openai/gpt-4.1`
995 +
996 +The default model for GitHub Models API fallback is changed from `openai/gpt-4.1` (which returns 403) to `openai/gpt-4o` (widely accessible).
997 +
998 +**Rationale:** `gpt-4.1` is not accessible via the GitHub Models API for this repository's token. `gpt-4o` is the current generally available model. The env var `GITHUB_MODELS_MODEL` still allows override.
999 +
1000 +### 5. Reskill Primary Path: Copilot CLI with Agent
1001 +
1002 +The reskill job now tries Copilot CLI first (with agent identity), falling back to GitHub Models API if CLI is unavailable. This gives reskill the same agent-aware capabilities as analysis: read wisdom/skills/history, write updated wisdom and learnings back.
1003 +
1004 +**Rationale:** The reskill cycle is the primary mechanism for reinforcing the learning loop. With agent identity, it can directly update `wisdom.md` and `history.md` based on retrospective findings — the core of self-improvement.
1005 +
1006 +### 6. Prompt Template Unchanged
1007 +
1008 +The existing prompt templates (`prompts/analyze-weekly.md`, `prompts/reskill.md`) already inject wisdom and skills via `{{WISDOM}}` and `{{SKILLS}}` placeholders. The agent file complements this by providing identity context and learning output instructions that the templates alone cannot express.
1009 +
1010 +## Risks
1011 +
1012 +| Risk | Mitigation |
1013 +|------|-----------|
1014 +| Agent writes bad content to `.squad/` files | Quality gate still runs on analysis output; .squad changes are append-only learnings |
1015 +| Copilot CLI doesn't support `--agent` as expected | Fallback path (GitHub Models via reskill.py) still works without agent identity |
1016 +| Learning state diverges between publish branch and main | Periodic sync PRs already exist; learnings on publish are forward-compatible |
1017 +
1018 +## Implementation
1019 +
1020 +- [x] `.github/agents/farnsworth.agent.md` — agent identity file
1021 +- [x] `.github/workflows/crawl-and-publish.yml` — `--agent` flag, learning commits, model fix
1022 +- [x] `scripts/reskill.py` — model default updated to `openai/gpt-4o`
1023 +- [x] `scripts/analyze_fallback.py` — model default updated to `openai/gpt-4o`
1024 +
1025 +---
1026 +
1027 +## Governance
1028 +
1029 +- All meaningful changes require team consensus
1030 +- Document architectural decisions here
1031 +- Keep history focused on work, decisions focused on direction
1032 +
1033 +### Context
1034 +
1035 +The weekly analysis output was structured like a repo-listing document (Notable New Repositories, Trending This Week, etc.). User requested a restructure to read like a Gartner/McKinsey-style trend insight brief.
1036 +
1037 +### Decision
1038 +
1039 +Replace the six-section repo-listing structure with a six-section editorial structure:
1040 +
1041 +| Old Section | New Section |
1042 +|---|---|
1043 +| `## Notable New Repositories` | (moved to `### Notable Projects` under Key References) |
1044 +| `## Trending This Week` | (rolled into `## This Week's Trends`) |
1045 +| `## Industry & Press Correlation` | `## Where Industry Meets Code` |
1046 +| `## Trend Analysis` / `### Signal` / `### Noise` | `## Signal & Noise` (integrated prose, no sub-headings) |
1047 +| `## What's Missing` / `### Gaps` | `## Blind Spots` |
1048 +| `## Conclusion` | `## The Week Ahead` |
1049 +| _(new)_ | `## Key References` / `### Notable Projects` / `### Press & Industry` |
1050 +
1051 +### Rationale
1052 +
1053 +1. Lead with synthesis, not inventory.
1054 +2. Comparative press analysis gets its own section.
1055 +3. Signal & Noise integrated (no mandatory sub-headings).
1056 +4. Key References at the end (scannable).
1057 +5. Forward-looking close ("The Week Ahead").
1058 +
1059 +## Context
1060 +
1061 +Copilot CLI model IDs can disappear from the platform, causing silent degradation to fallback paths.
1062 +
1063 +## Decision
1064 +
1065 +The `crawl-and-publish.yml` workflow should never pass a version-pinned `--model` flag. Analysis and reskill rely on the CLI's platform default, while GitHub Models fallback uses `openai/gpt-4o` (configurable via `GITHUB_MODELS_MODEL`).
1066 +
1067 +## Rationale
1068 +
1069 +Pinned model IDs can silently disappear; letting the CLI choose its default keeps the primary path available without manual model churn.
1070 +
1071 +## Context
1072 +
1073 +Published week 21 article leaked agent status text because shell appended Copilot CLI stdout to the markdown file after Farnsworth had already written the real article.
1074 +
1075 +## Decision
1076 +
1077 +In `crawl-and-publish.yml`, Copilot CLI stdout must never redirect to the same markdown file the agent writes. Analysis and reskill invocations send stdout to `/dev/null`, rely on `--share` or workflow logs for transcripts, and run a post-write sanitizer for defense in depth.
1078 +
1079 +## Rationale
1080 +
1081 +Separates channels (fixes root cause) and reduces blast radius if CLI emits metadata again.
1082 +
1083 +## Context
1084 +
1085 +Audit found repeated charter scaffolding, duplicated rollout updates in histories, and mature workflow knowledge scattered across multiple agent files.
1086 +
1087 +## Decision
1088 +
1089 +Squad agent docs follow a shared minimal-charter and history-hygiene model. Shared operating patterns move into `.squad/skills/`, while charters keep only: identity, ownership, working style, boundaries, and model preference.
1090 +
1091 +## Rationale
1092 +
1093 +- Eliminates redundant documentation
1094 +- Preserves workflow knowledge as reusable skills
1095 +- Reduces agent charter bloat
1096 +
1097 +## Context
1098 +
1099 +Week 21 analysis requires both editorial quality and automation compliance. The title and press-fallback handling must satisfy both reader expectations and the analyzer contract.
1100 +
1101 +## Decision
1102 +
1103 +Week 21 analysis should use a journalistic title, not a generic week label, and must keep the no-press fallback explicit when press data is absent.
1104 +
1105 +## Rationale
1106 +
1107 +The published analysis needs to read like an editorial artifact and satisfy the analyzer contract at the same time. A headline plus explicit press fallback keeps the page useful to readers and safe for automation.
1108 +
1109 +## Context
1110 +
1111 +When rebuilding data for a previous week, the workflow must NOT re-run the crawl. Re-crawling pollutes prior weeks' data (overwrites the high-quality version with a fresh, possibly worse snapshot). User repeatedly lost high-quality W21 analysis because re-runs re-crawled and re-analyzed, regenerating inferior versions.
1112 +
1113 +## Directive
1114 +
1115 +For previous-week rebuilds:
1116 +1. Hydrate from `publish` (canonical source for analyzed content)
1117 +2. Re-run analysis/generation only as needed
1118 +3. **Never crawl again** for previous weeks
1119 +
1120 +This restores/regenerates from existing data without polluting the archive.
1121 +
1122 +## Implementation Status
1123 +
1124 +- Captured in PR #164 (bender-3): deploy-site.yml now hydrates content/data from publish before hugo build
1125 +- Schedule event guard fixed: `!inputs.rebuild_week` instead of `== ''` ensures cron doesn't skip
1126 +- Format validation added for YYYY-WNN rebuild_week parameter
1127 +- Architectural fix prevents main/publish divergence
1128 +
1129 +**Files affected:** `.github/workflows/deploy-site.yml`, `.github/workflows/crawl-and-publish.yml`
1130 +
1131 +### 2026-05-18T16:22:40Z: User directive
1132 +**By:** jmservera (via Copilot)
1133 +**What:** When the Hugo deployment fails, automatically create a GitHub issue so the squad can decide to fix it or dismiss it as transient. The squad should think thoroughly about whether an issue truly needs a human before escalating.
1134 +**Why:** User request — ensures deploy failures don't go unnoticed and the team self-triages problems.
1135 +
1136 +### 2026-05-18T12:57:06Z: User directive
1137 +**By:** jmservera (via Copilot)
1138 +**What:** To merge a PR, all review conversations must be fixed AND resolved first. Agents must resolve each conversation thread (not just push fixes) before a PR can be merged.
1139 +**Why:** User request — reinforcement of PR review workflow. GitHub blocks merge when conversations are unresolved.
1140 +# Decision Inbox: Learning System Audit Findings
1141 +
1142 +**Author:** Leela (Lead/Architect)
1143 +**Date:** 2026-05-18T13:20:07.067+02:00
1144 +**Type:** Audit findings requiring team action
1145 +**Related:** Issues #14, #15; docs/learning-audit.md
1146 +
1147 +## Summary
1148 +
1149 +Comprehensive audit of the learning system reveals that SquadScope's main differentiator — learning over time — is currently design-only. Zero implementation exists. The full gap analysis is in `docs/learning-audit.md`.
1150 +
1151 +## Decisions Needed
1152 +
1153 +### 1. Prompt Feedback Loop (New Issue Required)
1154 +
1155 +**Problem:** `prompts/analyze-weekly.md` has no mechanism to inject learned wisdom or skills. Even if reskill produces insights, they never reach the analyzer.
1156 +
1157 +**Proposed fix:** Add `{{WISDOM_CONTENT}}` and `{{SKILLS_CONTENT}}` template variables; update `scripts/analyze_fallback.py` to read and inject `.squad/identity/wisdom.md` and `.squad/skills/` content.
1158 +
1159 +**Impact:** Without this, learning has literally no effect on analysis quality.
1160 +
1161 +### 2. Reskill Output Governance
1162 +
1163 +**Question:** Should reskill commit directly to main, or produce a PR for human review?
1164 +
1165 +**Leela's recommendation:** PR-based for prompt/spec changes; direct commit for `.squad/reskill/` reports and `run-counter.txt`.
1166 +
1167 +### 3. New Issues to Create
1168 +
1169 +Three gaps require issues beyond #14 and #15:
1170 +- Prompt feedback loop (G7)
1171 +- Hindsight validation script (G8)
1172 +- Prediction registry format (G9)
1173 +
1174 +**Assignee recommendation:** Farnsworth for all three (owns analysis and reskill domain).
1175 +
1176 +## Action Items for Existing Issues
1177 +
1178 +- **Issue #15 (Bender):** Must include counter initialization, increment in commit step, and `.squad/run-counter.txt` in git add paths.
1179 +- **Issue #14 (Farnsworth):** Must create `.squad/skills/`, `.squad/reskill/`, seed `wisdom.md`, write structured `prompts/reskill.md`, and add `.squad/` commit step to workflow.
\ No newline at end of file
.squad/decisions.md
+177 -1012
@@ -1,55 +1,25 @@
1 # Squad Decisions
2
3 -## Active Decisions
4 -
5 -### Architecture Decision: SquadScope Foundation
6 -
7 -**Date:** 2026-05-18
8 -**Author:** Leela (Lead/Architect)
9 -**Status:** Proposed — awaiting stakeholder approval
10 -**Context:** PRD for greenfield SquadScope project
11 -
12 -**Decisions Proposed:**
13 -
14 -1. **Static Site Generator: Hugo (recommended)**
15 - - Why: Fastest builds (critical as archive grows to hundreds of pages), native RSS, single binary (no Node in CI), mature taxonomy support.
16 - - Alternative: Astro — better component model but heavier toolchain. Migrate later if interactive features needed.
17 - - Awaiting: jmservera preference confirmation.
18 -
19 -2. **Search: Pagefind**
20 - - Why: Fully static (no server), tiny JS bundle, build-time indexing, free, supports metadata filters.
21 - - Trade-off: Index grows with content, but estimated 5+ years before any concern.
3 +## Impact
4
23 -3. **Notifications MVP: RSS + GitHub Releases**
24 - - Why: Zero external dependencies, no accounts to manage, built into GitHub ecosystem.
25 - - Phase 2: Add GitHub Discussions, webhook support.
26 - - Not yet: Email newsletters (evaluate if demand exceeds RSS reach).
5 +Applies to future weekly summaries and any generator work that consumes `data/analyzed/*-summary.md`.
6
28 -4. **Pipeline Architecture: Crawl → Analyze → Generate → Notify**
29 - - Why: Clean separation of concerns, each stage testable independently, artifacts stored between stages.
30 - - Key constraint: Copilot invocation in CI is an open question. May need fallback strategy.
7 +---
8
32 -5. **Reskill Cycle: Every 5th run**
33 - - Mechanism: Integer counter in `.squad/run-counter.txt`, modulo check.
34 - - Why simple counter: Avoids complex state management, easy to audit and reset.
9 +# Directive: Prevent Recrawl on Previous-Week Rebuilds
10
36 -6. **Content Immutability: Weekly pages never modified after publication**
37 - - Why: Historical integrity, reproducible archive, no merge conflicts on old content.
11 +**Date:** 2026-05-25T15:55:00+02:00
12 +**Source:** User directive (jmservera via Copilot)
13 +**Status:** Active
14
39 -7. **Crawler Plugin Architecture (future-facing)**
40 - - Why: Design for extensibility now so adding HN/Reddit/etc. doesn't require pipeline rewrite.
41 - - Pattern: `DataSource` protocol with `crawl()`, `get_name()`, `get_rate_limits()` interface.
15 +## Active Decisions
16
43 -**Risks Acknowledged:**
44 -- Copilot API availability in CI (Medium probability, High impact)
45 -- Analysis quality without human review (mitigated by reviewer agent gate + reskill)
46 -- GitHub API rate limits (mitigated by auth tokens + backoff)
17 +# Leela — PR review gate follow-up
18
48 -**Open Questions Requiring Input:**
49 -- OQ1/OQ3: Copilot in Actions — how? (blocks Phase 2)
50 -- OQ2: Hugo vs Astro final call
51 -- OQ4: Star threshold (50 proposed)
52 -- OQ8: Copilot usage limits in automation
19 +- Date: 2026-06-01
20 +- Context: Round review of PR #218 and PR #219 showed both branches were opened by `jmservera`, which means the current GitHub identity cannot submit an approving review on them.
21 +- Decision: Do not bypass the review gate on self-authored pull requests. Treat independent approval as still required before merging branches opened by the same account Leela is operating under.
22 +- Why: GitHub blocks self-approval, and preserving the review gate matters more than forcing a merge from the lead seat.
23
24 ## Cost Transparency Placement (2026-05-25)
25
@@ -57,1100 +27,295 @@
27
28 **Rationale:** Cost reporting is operational transparency, not a primary navigation destination or product dashboard. Keeping it on About matches the editorial-restrained redesign while preserving the old URL for references.
29
60 -## Copilot CLI in GitHub Actions (2026-05-18)
61 -
62 -**Requestor:** jmservera
63 -**Source:** Bender investigation
64 -**Status:** Approved for implementation
65 -
66 -- **Action:** Use standalone **GitHub Copilot CLI** (not deprecated `gh copilot` extension)
67 -- **Auth:** Fine-grained PAT with **Account → Copilot Requests** permission, passed as `COPILOT_GITHUB_TOKEN`
68 -- **Invocation:** Programmatic via `copilot -p "..." -s --no-ask-user --allow-tool=...`
69 -- **Output:** JSON (--output-format=json, JSONL) or markdown (--share=PATH)
70 -- **Fallback:** GitHub Models API with `GITHUB_TOKEN` (permissions: models: read)
71 -- **Next spike:** Test whether `copilot-requests: write` on workflow token replaces PAT (community action shows promise)
72 -
73 -## PRD Decomposition into GitHub Issues (2026-05-18)
74 -
75 -**Decision:** Decompose docs/PRD.md into 24 issues across Phase 0 (blocker investigations) + Phases 1-4.
76 -
77 -**Phase 0 gating condition:** Resolves OQ1/OQ3 — Copilot invocation in GitHub Actions.
78 -
79 -**Why:** Isolates largest delivery risk; ensures crawler, analyzer, and generator teams can work independently; makes reviewer gates explicit.
80 -
81 -**Implications:**
82 -- Phase 2 analyzer work blocked until Phase 0 closure
83 -- Phase 1 (site foundation + crawler) can proceed in parallel
84 -- QA and documentation are first-class issues
85 -
86 -## MCP Tools for Multi-Site Crawling (2026-05-18)
30 +## Nibbler Review Gate for External-Facing Artifacts (2026-05-25)
31
88 -**Directive:** MCP tools may crawl sites beyond GitHub; remote calls require allowlist in Copilot agent settings (GitHub repo settings).
32 +**Source:** Nibbler audit recommendation
33 +**Adopted by:** Leela
34 +**Status:** Adopted
35
90 -**Impact:** Affects crawler extensibility design (HackerNews, Reddit, etc.) and GitHub Actions Copilot token model.
36 +External-facing launch and announcement artifacts require Nibbler review before publication or merge. This includes Hacker News posts, LinkedIn announcements, Bluesky threads, Reddit posts, launch blogs, press copy, launch graphics, and similar materials that will appear outside this repository.
37
92 -## Architecture Decision: CI Analysis Interface & Fallback Architecture
38 +PRs that ship this copy or graphics must tag `@squad:nibbler` for RAI sign-off and use the [Responsible AI checklist](skills/responsible-ai-review/SKILL.md) (`.squad/skills/responsible-ai-review/SKILL.md`) before merge.
39
94 -**Date:** 2026-05-18T10:25:12.565+02:00
95 -**Author:** Leela (Lead/Architect)
96 -**Status:** Approved
97 -**Issue:** #2 — Decide CI analysis interface and fallback architecture
98 -**Depends on:** #1 (Copilot CLI investigation — completed by Bender)
40 +**Rationale:** Distribution copy can create reputational, safety, accessibility, or policy risk even when the underlying code is unchanged. Nibbler provides the hostile-reader and responsible-AI perspective before users encounter the material.
41
100 -### Context
42
102 -SquadScope's pipeline requires AI-powered analysis of crawled GitHub data inside GitHub Actions. Bender's investigation (docs/investigation-copilot-cli.md) confirmed that the standalone `copilot` CLI can run in CI with a fine-grained PAT, and identified GitHub Models API as a credible fallback. This decision formalizes the approved architecture.
43 +# AI Disclosure Pattern
44
104 -### Decision 1: Primary Analysis Path — Standalone Copilot CLI
45 +**Date:** 2026-05-25
46 +**Author:** Amy
47 +**Status:** Proposed
48
106 -**Approved.** The primary CI analysis engine is the standalone `copilot` CLI (`@github/copilot`).
49 +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.
50
108 -**Rationale:**
109 -- Officially documented by GitHub for Actions automation
110 -- Real-world precedent (microsoft/BCApps)
111 -- Repo-aware agent behavior: can read/write files, use tools (grep, glob, read, write)
112 -- Supports structured output (`--output-format=json`) and transcript export (`--share=PATH`)
113 -- Programmatic mode (`-p`, `--no-ask-user`) is CI-safe
51 +# Amy — Cookie Consent vendoring
52
115 -**Invocation Contract:**
53 +Date: 2026-05-25
54
117 -```bash
118 -copilot -p "<prompt>" \
119 - -s \
120 - --no-ask-user \
121 - --allow-tool=read \
122 - --allow-tool=write \
123 - --allow-tool=glob \
124 - --allow-tool=grep \
125 - --output-format=json \
126 - --share=./copilot-session.md
127 -```
55 +Decision: vendor Cookie Consent v3 directly in `static/vendor/cookieconsent/` and pin it to upstream version `v3.0.1`.
56
129 -**Token Strategy:**
57 +Rationale:
58 +- Cookie consent must run before optional analytics scripts are activated.
59 +- Vendoring avoids relying on the jsDelivr CDN at runtime.
60 +- The pinned files are the published `dist` CSS and UMD bundle from `orestbida/cookieconsent@v3.0.1`.
61
131 -| Item | Value |
132 -|------|-------|
133 -| Secret name | `COPILOT_GH_TOKEN` |
134 -| Token type | Fine-grained PAT (`github_pat_...`) |
135 -| Permission | Account → Copilot Requests |
136 -| Env variable | `COPILOT_GITHUB_TOKEN` |
137 -| Resource owner | Personal account (jmservera) |
138 -| Classic PAT | **Not supported** — do not use `ghp_` tokens |
62 +Checksums:
63 +- `cookieconsent.css`: `sha256 ca046b8b1b1094107205988e7096a687b241c8ef5f3fefe5e543ed28d26646c1`
64 +- `cookieconsent.umd.js`: `sha256 1267fd33fcf3ab4043a7cc62cc9259a2c66f839f695216f7737ed37b7b3e62e6`
65
140 -Wire in workflow:
141 -```yaml
142 -env:
143 - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GH_TOKEN }}
144 -```
66 +# Article errata schema
67
146 -### Decision 2: Fallback Path — GitHub Models API
68 +**Date:** 2026-05-25
69 +**Author:** Amy
70 +**Status:** Proposed
71
148 -**Approved.** If Copilot CLI is unavailable, rate-limited, or proves too brittle in CI, the fallback is the GitHub Models API.
72 +## Decision
73
150 -**Rationale:**
151 -- Works with built-in `GITHUB_TOKEN` (no PAT needed)
152 -- Simple REST interface, easy to test and mock
153 -- Supports structured JSON responses
154 -- Less agentic, but sufficient for summarization tasks
74 +Articles declare corrections in front-matter using `errata: [{date, note}]`; the article footer renders those entries at the end of the article.
75
156 -**Invocation Contract:**
76 +## Schema example
77
78 ```yaml
159 -permissions:
160 - models: read
161 -
162 -steps:
163 - - name: Analyze via GitHub Models
164 - env:
165 - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
166 - run: |
167 - curl "https://models.github.ai/inference/chat/completions" \
168 - -H "Content-Type: application/json" \
169 - -H "Authorization: Bearer $GITHUB_TOKEN" \
170 - -d @data/prompts/analyze-week.json
171 -```
172 -
173 -**Trigger conditions for fallback:**
174 -- Copilot CLI auth failure (token expired, permission revoked)
175 -- Copilot CLI rate-limit / quota exhaustion
176 -- Copilot CLI install failure (npm registry issue, Node version mismatch)
177 -- Repeated non-deterministic failures (3+ retries fail)
178 -
179 -### Decision 3: Pipeline Stage Contracts
180 -
181 -**Stage boundaries and data flow:**
182 -
183 -```
184 -┌─────────┐ JSON ┌──────────┐ Markdown ┌──────────┐ HTML ┌────────┐
185 -│ Crawl │ ──────────► │ Analyze │ ───────────► │ Generate │ ────────► │ Deploy │
186 -└─────────┘ data/raw/ └──────────┘ data/analyzed └──────────┘ public/ └────────┘
79 +errata:
80 + - date: 2026-05-26
81 + note: "Corrected the company name in the EU AI Act section (was 'Mistral.ai', now 'Mistral AI')."
82 ```
83
189 -**Crawl → Analyze:**
190 -
191 -| Property | Specification |
192 -|----------|---------------|
193 -| Location | `data/raw/` |
194 -| Format | JSON (one file per crawl run) |
195 -| Naming | `YYYY-WNN.json` (e.g., `2026-W21.json`) |
196 -| Schema | Array of repo objects: `{name, url, description, stars, stars_gained, language, topics, created_at}` |
197 -| Contract | Analyzer MUST NOT modify files in `data/raw/` |
198 -
199 -**Analyze → Generate:**
200 -
201 -| Property | Specification |
202 -|----------|---------------|
203 -| Location | `data/analyzed/` |
204 -| Format | Markdown with YAML frontmatter |
205 -| Naming | `YYYY-WNN-summary.md` |
206 -| Frontmatter | `title`, `date`, `week`, `year`, `categories`, `quality_score` |
207 -| Sections | Signal (important), Noise (overhyped), Gaps (missing from conversation) |
208 -| Contract | Must include `quality_score` (0-100) for reviewer gate |
209 -
210 -**Generate → Deploy:**
211 -
212 -| Property | Specification |
213 -|----------|---------------|
214 -| Location | `public/` (Hugo build output) |
215 -| Format | Static HTML/CSS/JS |
216 -| Contract | Hugo builds from `content/` which is populated from `data/analyzed/` |
217 -
218 -### Decision 4: Reviewer Gate
219 -
220 -Analysis output in `data/analyzed/` MUST pass a quality check before the Generate stage runs.
221 -
222 -**Gate criteria:**
223 -- `quality_score` in frontmatter is ≥ 60
224 -- All three required sections present (Signal, Noise, Gaps)
225 -- Word count ≥ 200 (guards against empty/stub output)
226 -- No raw JSON or error messages in body
227 -
228 -**On failure:**
229 -- Block publish
230 -- Log failure reason to workflow summary
231 -- Open an issue tagged `quality-gate-failure` for human review
232 -- Do NOT retry analysis automatically (preserves Copilot request budget)
233 -
234 -### Decision 5: MCP Tools Strategy
235 -
236 -**Directive:** MCP tools are authorized for multi-site crawling extensibility.
237 -
238 -**Constraints:**
239 -- Remote MCP calls MUST be allowlisted in GitHub Copilot agent settings (repo-level)
240 -- MCP tool definitions live in `.github/copilot/mcp.json`
241 -- Only crawl-stage tools may make external HTTP calls
242 -- Analysis-stage tools are local-only (read, write, glob, grep)
243 -
244 -**Future extensibility:**
245 -- Each new data source (HN, Reddit, etc.) is an MCP tool with a `crawl()` method
246 -- Tools registered in allowlist before activation
247 -- Rate limits per-source defined in tool config
248 -
249 -### Decision 6: Nap & Reskill Interface
250 -
251 -Every 5th pipeline run triggers a reskill cycle. The reskill workflow invokes Copilot CLI to review squad state and propose improvements.
252 -
253 -**Mechanism:**
254 -
255 -```bash
256 -# Counter check
257 -COUNTER=$(cat .squad/run-counter.txt)
258 -if [ $((COUNTER % 5)) -eq 0 ]; then
259 - # Reskill invocation
260 - copilot -p "Read .squad/agents/*/history.md and .squad/decisions.md. \
261 - Assess: What patterns are working? What should change? \
262 - Write recommendations to .squad/reskill/YYYY-WNN.md" \
263 - --no-ask-user \
264 - --allow-tool=read \
265 - --allow-tool=write \
266 - --allow-tool=glob \
267 - --share=./reskill-session.md
268 -fi
269 -```
270 -
271 -**Input context for reskill:**
272 -- `.squad/agents/*/history.md` — all agent learnings
273 -- `.squad/decisions.md` — current decision log
274 -- `data/analyzed/` — recent analysis outputs (quality trend)
275 -- `.squad/run-counter.txt` — run history
276 -
277 -### Decision 7: Weekly Analysis Fail-Fast Policy
278 -
279 -Weekly article generation must only publish Copilot-authored analysis. The workflow now fails immediately if Copilot CLI is unavailable or the analysis call fails; it does not fall back to GitHub Models or no-AI summaries.
280 -
281 -**Enforcement:**
282 -- `scripts/analysis_gate.py` rejects any analysis source other than `copilot-cli`
283 -- The article title must be a journalistic headline, not the generic `Week NN, YYYY Analysis` template
284 -- If Copilot cannot run, the workflow is expected to be rerun later rather than publishing stale content
285 -
286 -**Goal:** prevent generic or stale weekly articles from being published when the preferred analysis agent is unavailable.
287 -
288 -**Output:**
289 -- `.squad/reskill/YYYY-WNN.md` — improvement recommendations
290 -- Optional: PR with proposed changes to agent prompts or pipeline config
291 -
292 -### Decision 7: Future Validation Spike — GITHUB_TOKEN + copilot-requests: write
293 -
294 -**Status:** Noted for future spike (not yet approved for production use).
295 -
296 -The community action `austenstone/copilot-cli` demonstrates that `GITHUB_TOKEN` with `permissions: copilot-requests: write` may eliminate the PAT requirement entirely. GitHub's official docs do not yet confirm this path.
297 -
298 -**Spike criteria:**
299 -- Create a test workflow with `copilot-requests: write`
300 -- Validate auth succeeds without PAT
301 -- Confirm quota/billing behaves identically
302 -- If successful: migrate from PAT to workflow token (simpler, no secret rotation)
303 -
304 -### Risks & Mitigations
305 -
306 -| Risk | Probability | Impact | Mitigation |
307 -|------|------------|--------|------------|
308 -| Copilot CLI quota exhaustion | Medium | High | Coarse-grained prompts; fallback to Models API |
309 -| PAT expiration in CI | Medium | Medium | GitHub secret expiry alerts; spike on workflow token |
310 -| Analysis quality drift | Low | High | Reviewer gate + reskill cycle |
311 -| MCP allowlist misconfiguration | Low | Medium | CI test that validates mcp.json against live config |
312 -| Node 22 unavailability in runner | Very Low | Low | Pin `actions/setup-node@v4` with explicit version |
313 -
314 -### Summary
315 -
316 -The SquadScope CI analysis pipeline uses a two-tier approach: Copilot CLI (primary, agentic, repo-aware) with GitHub Models API (fallback, simpler, REST-based). Data flows through well-defined stage boundaries with JSON → Markdown → HTML transformations. A quality gate ensures no low-quality analysis reaches publication. The architecture is designed for extensibility via MCP tools and self-improvement via the reskill cycle.
317 -
318 -## Crawler Cache & Artifact Handoff Decision (2026-05-18)
319 -
320 -**Issue:** #8 — Create weekly Actions crawl job with artifact handoff
321 -**Author:** Bender (Crawler agent)
322 -**Status:** Approved for implementation
323 -**Date:** 2026-05-18T12:07:20.778+02:00
324 -
325 -### Decision: Cache Restoration from Prior Workflow Runs
326 -
327 -The weekly crawl workflow (`crawl-and-publish.yml`) MUST restore `data/cache/` from the latest successful run before executing `scripts/crawl.py`.
328 -
329 -**Rationale:**
330 -- Reuses the crawler's on-disk GitHub API cache across weekly runs
331 -- Lowers repeated README/search calls on warm runs
332 -- Keeps the crawl stage self-contained until downstream jobs arrive in later issues
333 -
334 -**Implementation Details:**
335 -- Workflow needs `actions: read` permission to discover prior successful runs
336 -- Download the `crawl-cache` artifact before running the crawler
337 -- Upload new cache artifact after successful crawl
338 -- Preserve crawler state through GitHub Actions artifact storage
339 -
340 -**Implications:**
341 -- Reduces GitHub API rate limit consumption across runs
342 -- Enables faster weekly crawls as cache grows
343 -- Supports Phase 1 crawl-only deliverables
344 -
345 ----
346 -
347 -## Crawler Hardening Decision (2026-05-18)
348 -
349 -**Issue:** #6 — Harden crawler for production readiness
350 -**Author:** Bender (Crawler agent)
351 -**Status:** Approved — implemented in crawler
352 -**Date:** 2026-05-18T10:59:10.800+02:00
353 -
354 -### Decision: Degradable README Signals & Bounded Retry Strategy
355 -
356 -Treat README lookups as a degradable signal instead of a hard-stop path. The crawler now:
357 -- Caches API responses to reduce repeated calls
358 -- Saves weekly star snapshots under `data/snapshots/`
359 -- Logs rate-limit state for observability
360 -- Caps README retry delays to ensure partial failures don't block weekly crawls
361 -
362 -**Rationale:**
363 -- Search queries are cheap, but hundreds of README checks can trigger secondary GitHub API throttling
364 -- Bounded retries plus persistent cache keep Phase 1 crawls finishable
365 -- Partial failures recorded in metadata preserve data integrity even when GitHub responses are incomplete
366 -
367 -**Outcomes:**
368 -- Phase 1 crawls remain finishable even during GitHub API congestion
369 -- Farnsworth (analyzer) receives usable JSON data even when README metadata is partial
370 -- Better observability into rate-limit behavior across runs
371 -
372 ----
373 -
374 -## Dry-Run Validation Findings (2026-05-18)
375 -
376 -**Issue:** #7 — Validate dry-run execution of full pipeline
377 -**Author:** Fry (Validator)
378 -**Status:** Findings archived for Phase 2 planning
379 -**Date:** 2026-05-18T10:59:10.800+02:00
380 -
381 -### Key Findings
382 -
383 -1. **Hugo Version Pinning Required**
384 - - Local environment defaulted to `hugo v0.123.7`
385 - - Repository theme requires `v0.146.0+`
386 - - Dry-run only succeeded with `hugo v0.161.1`
387 - - **Action:** Pin Hugo version in CI/validation workflows
388 -
389 -2. **Trending Analysis Requires Historical Data**
390 - - `data/raw/2026-W21.json` contains no usable `stars_gained` values in `trending_repos`
391 - - Current output is popularity-biased rather than momentum-based
392 - - **Action:** Implement multi-week aggregation in analyzer for trend detection
393 -
394 -3. **Content Filtering Needs Refinement**
395 - - Sample week contains exploit, bypass, cheat, and game-mod repositories in "new" ranking
396 - - Current filtering logic insufficient for curated editorial quality
397 - - **Action:** Implement stricter content filtering or human quality gate in Phase 2
398 -
399 -4. **Analyzer-Generator Contract Needs Specification**
400 - - PRD weekly page shape and approved analyzer contract are close but not identical
401 - - Generator step needs explicit mapping from analyzed markdown to publishable Hugo content
402 - - **Action:** Formalize analyzer output schema and generator input contract (Phase 2)
403 -
404 ----
405 -
406 -## Analyze Job Integration & Quality Gate (2026-05-18)
407 -
408 -**Issue:** #10 — Integrate Actions analyze job with Copilot path and reviewer gate
409 -**Author:** Bender (Crawler agent)
410 -**Status:** Approved for Phase 2 implementation
411 -**Date:** 2026-05-18T13:05:53.678+02:00
412 -
413 -### Decision
414 -
415 -Extend `.github/workflows/crawl-and-publish.yml` with an `analyze` job that runs after `crawl` and enforces an automated quality gate before downstream publish steps.
416 -
417 -**Stage handoff artifacts:**
418 -- `raw-data` for crawl → analyze
419 -- `analyzed-data` for analyze → generate
420 -
421 -**Analysis paths:**
422 -1. Primary: Standalone Copilot CLI with `permissions.copilot-requests: write` and `COPILOT_GH_TOKEN`
423 -2. Fallback: `scripts/analyze_fallback.py` using GitHub Models API with `permissions.models: read`
424 -
425 -**Quality Gate Contract** — workflow must fail if any of the following are false:
426 -- YAML frontmatter exists with exact required keys
427 -- `quality_score` is an integer ≥ 60
428 -- Required H2/H3 sections appear in documented order
429 -- Body word count ≥ 200
430 -- Output does not leak raw JSON, traceback, or placeholder content
431 -
432 -**Implications:**
433 -- Generate jobs can safely consume `analyzed-data` without inspecting raw crawl artifacts
434 -- Copilot failures do not block immediately; GitHub Models fallback preserves publishability
435 -- Reviewer-gate failures stop low-quality summaries before downstream stages
436 -
437 ----
438 -
439 -## Analysis Output Specification (2026-05-18)
440 -
441 -**Issue:** #9 — Define weekly analysis contract between crawler output and site generator
442 -**Author:** Farnsworth (Analyst)
443 -**Status:** Approved for Phase 2 implementation
444 -**Date:** 2026-05-18T12:07:20.778+02:00
445 -
446 -### Decisions
447 -
448 -1. **Analyzer output frontmatter is a superset contract.**
449 - - Required fields: `title`, `date`, `week`, `year`, `tags`, `categories`, `repos_featured`, `stars_tracked`, `top_repo`, `quality_score`, `summary`
450 -
451 -2. **Reader-facing structure: five stable H2 sections** (in order):
452 - - `Notable New Repositories`
453 - - `Trending This Week (Stars Gained)`
454 - - `Trend Analysis` (with required `### Signal` and `### Noise` subsections)
455 - - `What's Missing` (with required `### Gaps` subsection)
456 - - `Conclusion`
457 -
458 -3. **Trending must degrade honestly when momentum data is incomplete.**
459 - - If `stars_gained` is absent or null, summary must say the section is directional, not a true momentum leaderboard
460 -
461 -4. **Analyzer input schema: strict on core fields, tolerant on metadata.**
462 - - Required: week slug, crawl timestamp, new/trending repo arrays, top topics
463 - - Optional: `partial_failures`, `filter_summary`, `snapshot_path`
464 -
465 ----
466 -
467 -## Generate & Deploy Workflow (2026-05-18)
468 -
469 -**Issue:** #11 — Implement generate-and-deploy workflow for GitHub Pages
470 -**Author:** Amy (Generator agent)
471 -**Status:** Approved for Phase 2 implementation
472 -**Date:** 2026-05-18T13:20:07.067+02:00
473 -
474 -### Decision
475 -
476 -Keep `.github/workflows/deploy-site.yml` for push-to-main deployments. Weekly automation lives in `.github/workflows/crawl-and-publish.yml` end-to-end (crawl → analyze → generate → deploy).
477 -
478 -**Generate stage:**
479 -1. Read `data/analyzed/YYYY-WNN-summary.md`
480 -2. Write Hugo page to `content/weekly/YYYY/WNN.md` with archetype-compatible frontmatter
481 -3. Commit back to default branch before Pages build so future archive builds retain previously published content
482 -
483 -**Deploy:**
484 -- Build with Hugo 0.161.1 + Pagefind
485 -- Deploy with `actions/deploy-pages@v4` under `github-pages` environment
486 -
487 ----
488 -
489 -## Run Counter & Reskill Trigger (2026-05-18)
490 -
491 -**Issue:** #15 — Add run counter persistence and every-fifth-run reskill trigger
492 -**Author:** Bender (Crawler agent)
493 -**Status:** Approved for Phase 1B implementation
494 -**Date:** 2026-05-18T15:22:25.067+02:00
495 -
496 -### Decisions
497 -
498 -1. **Create `.squad/run-counter.txt`** initialized to `0`
499 -2. **Increment counter** in `crawl` job's git commit step after syncing default branch, then commit `.squad/run-counter.txt` with `data/raw/` and `data/snapshots/`
500 -3. **Add `reskill-check` job** that reads persisted counter and exposes `should_reskill` for downstream jobs
501 -4. **Add placeholder `reskill` job** that logs the trigger and scaffolds `.squad/skills/` and `.squad/reskill/` until Issue #14 adds full retrospective implementation
502 -
503 -**Why:** Reading the counter only after syncing `origin/main` keeps the increment tied to latest persisted state. Committing together ensures survival between weekly runs. Splitting `reskill-check` from `reskill` keeps trigger logic auditable.
504 -
505 ----
506 -
507 -## Reskill Retrospective & Learning State (2026-05-18)
508 -
509 -**Issue:** #14 — Reskill retrospective, learned-state injection, and quality trend tracking
510 -**Author:** Farnsworth (Analyst)
511 -**Status:** Approved for Phase 2 implementation
512 -**Date:** 2026-05-18T15:22:25.067+02:00
513 -
514 -### Decisions
515 -
516 -1. **Reskill context** from latest analyzer evidence, not generic squad history:
517 - - Inputs: last ~5 `data/analyzed/*-summary.md` files, `data/snapshots/` hindsight, `wisdom.md`, learned skills, quality trend report
518 - - Why: gives retrospective concrete calibration points and closes gap findings
519 -
520 -2. **Learned state flows back** into weekly analyzer prompt:
521 - - Inject `.squad/identity/wisdom.md` into `{{WISDOM}}` placeholder
522 - - Inject concatenated markdown from `.squad/skills/` into `{{SKILLS}}` placeholder
523 - - Why: without prompt injection, learning artifacts exist but never influence future analysis
524 -
525 -3. **Quality trend tracking** is first-class reskill input:
526 - - `scripts/track_quality.py` reads `quality_score` from analyzed summaries, produces markdown trend report
527 - - Why: squad needs lightweight longitudinal measure of editorial quality improvement
528 -
529 -4. **Reskill outputs in persistent squad state:**
530 - - `.squad/reskill/` for weekly retrospective reports
531 - - `.squad/skills/` for extracted reusable patterns
532 - - Both committed to git (not ephemeral workflow output)
533 -
534 ----
535 -
536 -## Cost Estimation & Budget Controls (2026-05-19)
537 -
538 -**Issue:** #17 — Cost estimation framework for SquadScope
539 -**Author:** Leela (Lead/Architect)
540 -**Status:** Proposed
541 -**PRD:** docs/PRD-cost-estimation.md
542 -**Date:** 2026-05-19T05:17:53.102+02:00
543 -
544 -### Summary
545 -
546 -Current SquadScope cost under token-based billing: ~$0.30/week (~$16/year), well within Copilot Pro's 300 credits/month allowance. However, proactive monitoring and budget controls needed before context growth or model upgrades change the picture.
547 -
548 -### Decisions
549 -
550 -1. **Accept current cost profile as sustainable** — $16/year is economically trivial; no immediate model downgrade required
551 -2. **Implement token usage tracking (Phase A)** — Add `scripts/track_token_usage.py` and `data/metrics/token-usage.jsonl` to establish baselines before optimizing
552 -3. **Set budget alert thresholds:**
553 - - Warn at $0.50/run
554 - - Fail at $1.00/run
555 - - Email alert at $5/month cumulative
556 - - Auto-switch to cheaper model at $10/month cumulative
557 -4. **Defer raw JSON pre-processing** — 40-60% savings significant but adds pipeline complexity; implement only if costs grow beyond $30/year
558 -5. **Wisdom.md cap at 5 KB** — Reskill should retire obsolete heuristics, not only append
559 -
560 -**Rationale:** Dominant cost driver (raw JSON at 86K tokens) is stable and bounded by crawl scope. Growth comes from wisdom/skills/history accumulation, which is slow. Premature optimization would add complexity without meaningful savings at current scale.
561 -
562 -**Risks:**
563 -- OQ5/OQ6: Billing mechanics for Copilot CLI vs Models API may differ in ways not yet visible
564 -- Credit exhaustion mid-month would disrupt weekly pipeline if no degradation path exists
565 -
566 ----
567 -
568 -## Topic-Specific News Channels Architecture (2026-05-18)
569 -
570 -**Issue:** #16 — Topic-specific news channels architecture
571 -**Author:** Leela (Lead/Architect)
572 -**Status:** Proposed
573 -**PRD:** docs/PRD-topic-channels.md
574 -**PR:** #39
575 -**Date:** 2026-05-18T13:20:07.067+02:00
576 -
577 -### Key Architectural Decisions
578 -
579 -**Feature First, Not Platform:** Generalize SquadScope into topic channels by adding topic namespace to existing pipeline. No new platform, no new repo structure. Same codebase, configured differently.
580 -
581 -**Multi-Instance Single-Topic (v1):** One fork/config per topic with isolated learning, own `squadscope.topic.yml`, own Actions schedule, own GitHub Pages site. Multi-topic single-instance is v2.
582 -
583 -**Topic Config as Single Source of Truth:** `squadscope.topic.yml` controls:
584 -- Crawler queries
585 -- Scoring weights and thresholds
586 -- Analysis tone and audience
587 -- Learning state paths
588 -- Quality criteria
589 -
590 -**Scoring Pipeline (New Stage):** GitHub topic search is noisy. New `scripts/score_repos.py` between crawl and analyze, scoring repos 0-100 on relevance/momentum/language/noise/recency. Only repos ≥40 reach analysis.
591 -
592 -**Per-Topic Learning Isolation:**
593 -- `topics/{id}/wisdom.md` — domain-specific heuristics
594 -- `topics/{id}/skills/` — extracted patterns
595 -- `topics/{id}/predictions.jsonl` — prediction ledger
596 -- `topics/{id}/scorecards/` — hindsight validation results
597 -- No cross-topic contamination
598 -
599 -**Prediction Ledger with Hindsight Validation:** Every analysis appends machine-readable predictions to `predictions.jsonl`. Four weeks later, `scripts/validate_predictions.py` scores them against actual outcomes (star deltas, fork growth). Scorecards feed into reskill.
600 -
601 -**Topic Quality Criteria:**
602 -- Minimum N repos/week passing filters
603 -- Maximum false positive rate
604 -- Minimum genuinely significant repos per issue
605 -
606 -### Implications
607 -
608 -- Crawler must read config instead of hardcoded queries
609 -- Analysis prompt becomes a template with injection points
610 -- Hugo gains topic taxonomy and per-topic RSS
611 -- All data paths gain `{topic_id}/` prefix
612 -- Reskill reads per-topic state
613 -
614 -### Open for Discussion
615 -
616 -- Should enrichment signals (forks, contributors) be in v1 scorer or deferred?
617 -- Prediction confidence: fixed initial values or prompt-generated?
618 -- Topic config in root vs `topics/` directory?
619 -
620 ----
621 -
622 -## TechCrunch RSS as First Non-GitHub Data Source (2026-05-19)
623 -
624 -**Issue:** TechCrunch integration as first non-GitHub crawler plugin
625 -**Author:** Farnsworth (Analyst)
626 -**Status:** Proposed
627 -**PRD:** docs/PRD-techcrunch-integration.md
628 -**Date:** 2026-05-19T11:48:44.543Z
629 -
630 -### Decision
631 -
632 -Add TechCrunch RSS (`https://techcrunch.com/feed/`) as SquadScope's first non-GitHub data source, implementing Decision #7's crawler plugin architecture.
633 -
634 -**Rationale:**
635 -1. Cross-source correlation enables hype detection (press-driven vs. organic growth)
636 -2. Near-zero cost and complexity (public RSS, no auth, no rate limits)
637 -3. Directly implements the `DataSource` plugin pattern already approved
638 -4. Enriches editorial judgment without changing SquadScope's voice or pipeline structure
639 -
640 -**Impact:**
641 -- **Bender:** Implements `TechCrunchSource` crawler plugin
642 -- **Farnsworth:** Analyzer prompt gains press-context block; labels repos as press-correlated or organic
643 -- **Amy:** Optional correlation badge in Hugo templates
644 -- **Leela:** No architectural changes needed; plugin arch already designed for this
645 -
646 -### Open for Team Input
647 -
648 -- Should we start with full feed or category-specific feeds?
649 -- Correlation annotations: reader-visible or internal-only?
650 -
651 ----
652 -
653 -## Decision: Use `publish` branch for automated data commits (2026-05-19)
654 -
655 -**Author:** Bender (Crawler)
656 -**Status:** Implemented (PR #129)
657 -**Fixes:** Issue #128
658 -
659 -### Context
660 -
661 -The crawl-and-publish workflow failed because:
662 -1. The repo setting "Allow GitHub Actions to create or approve pull requests" is disabled
663 -2. `gh pr create` with `GITHUB_TOKEN` is blocked by this setting
664 -3. Even if enabled, the `copilot_code_review` rule + `required_review_thread_resolution` on main could block auto-merge unpredictably
665 -
666 -### Decision
667 -
668 -Replace PR-based commits with direct push to an unprotected `publish` branch.
669 -
670 -- The main branch ruleset only protects `refs/heads/main`
671 -- The `publish` branch accepts direct pushes from workflow `GITHUB_TOKEN`
672 -- Inter-job data flow uses artifacts (unchanged)
673 -- Deploy job downloads all artifacts directly (no dependency on branch state)
674 -- `reskill-check` reads `run-counter.txt` from `publish` branch with fallback to main
675 -
676 -### Consequences
677 -
678 -- Automated data no longer lands on `main` automatically — it accumulates on `publish`
679 -- A separate manual or scheduled merge from `publish` → `main` can sync when desired
680 -- Main branch protection remains fully intact (no bypasses)
681 -- Pipeline reliability is decoupled from PR permission settings
682 -
683 -### Alternatives Considered
684 -
685 -1. Enable "Allow GitHub Actions to create PRs" — requires repo admin action, doesn't solve auto-merge reliability
686 -2. Use a PAT/GitHub App token — adds secret management complexity
687 -3. `--admin` flag on merge — bypasses protection, violates team decision
688 -
689 ----
690 -
691 -## Decision: Manual W21 content regeneration (2026-05-19)
692 -
693 -**Author:** Bender
694 -**Status:** Executed
695 -
696 -### Context
697 -
698 -The crawl-and-publish workflow (run #26109935234) generated W21 analysis but failed to commit it because the commit step tried to push directly to `main`, which requires PRs (branch protection). PR #123 fixed the workflow to use PR-based commits, but it merged after the failed run.
699 -
700 -### Decision
701 -
702 -Regenerated W21 content manually and created PR #125 to update the page. No workflow code changes needed — the root cause (direct push) was already fixed by PR #123.
703 -
704 -### Impact
705 -
706 -- `content/weekly/2026/W21.md` updated from stale manual dry-run to full analysis
707 -- Monthly/yearly rollups refreshed
708 -- Once PR #125 merges, deploy-site will publish the updated page
709 -- Future scheduled runs will use the PR-based approach and should not hit this again
710 -
711 ----
712 -
713 -## Directive: Always test the whole publishing cycle before considering work done (2026-05-19)
714 -
715 -**By:** jmservera (via Copilot)
716 -**Date:** 2026-05-19T19:37:45+02:00
717 -
718 -User directive — captured for team memory. Always test the whole publishing cycle before considering work done.
719 -
720 ----
721 -
722 -## Decision: PR #126 Security Review — Clear (2026-05-19)
723 -
724 -**Author:** Hermes (Security)
725 -**PR:** #126 — "feat: wire TechCrunch RSS into CI pipeline and add API retry backoff"
726 -
727 -### Decision
728 -
729 -PR #126 is **security-clear**. No blocking vulnerabilities found.
730 -
731 -### Key Findings
732 -
733 -- No SSRF risk (hardcoded feed URL)
734 -- Retry logic properly bounded (3 retries, exponential backoff + jitter)
735 -- No secrets leaked in logs
736 -- feedparser dependency is well-maintained, no CVEs
737 -- Workflow permissions unchanged
84 +## Rationale
85
739 -### Non-blocking Recommendation
86 +Keeping corrections in front-matter makes the article-level errata path data-driven, reviewable in Git, and visible to readers without requiring silent edits to published analysis.
87
741 -RSS content fed into AI prompts has a theoretical indirect prompt injection surface. Mitigated by HTML stripping and content truncation. Recommend adding control character sanitization in a future PR for defense-in-depth.
88 +# Home hero restructure
89
743 -### Impact
90 +**Date:** 2026-05-25
91 +**Author:** Amy (Frontend Engineer)
92 +**Status:** Proposed
93
745 -Team can merge PR #126 without security holds.
94 +## Decision
95
747 ----
96 +Home page is a publication front page — the latest weekly analysis IS the hero. Explainer lives at `/about/`.
97
749 -## Directive: Never bypass branch protection rulesets (2026-05-19)
98 +# Amy Phase 1 Design Foundation Implementation
99
751 -**By:** jmservera (via Squad)
752 -**Date:** 2026-05-19T18:05:10Z
100 +**Date:** 2026-05-25
101 +**Author:** Amy (Frontend Developer)
102 +**Status:** Implemented
103
754 -CI workflows must not push directly to protected branches. Use PR-based commits instead. Never add bypass actors to rulesets to work around branch protection.
104 +## Decision
105
756 -**Why:** Branch protection exists to ensure code review on every change. Bypassing it for convenience undermines the safety net.
106 +Phase 1 tokens and typography are implemented as a Hugo asset-pipeline foundation without changing page layouts.
107
758 ----
108 +## File locations
109
110 +- `assets/css/tokens.css` is the design-system entry point for color, type, spacing, radius, shadow, and line-height tokens.
111 +- `layouts/partials/head.html` loads Inter and JetBrains Mono from Google Fonts using preload + stylesheet links, then includes `tokens.css` before the PaperMod-compatible CSS bundle.
112 +- `assets/css/core/theme-vars.css` maps PaperMod legacy variables to SquadScope tokens so existing templates continue to render.
113 +- `assets/css/core/reset.css` applies the base reset, body typography, heading scale, and monospace stack.
114 +- `assets/css/common/*.css`, `assets/css/extended/squadscope.css`, and `assets/css/badges.css` consume the token aliases while preserving existing layouts.
115
761 -# Decision: Divergence Section Uses Narrative Prose in Reader Mode
116 +## How to extend
117
763 -**Date:** 2026-05-19T21:24:54+02:00
764 -**Author:** Farnsworth (Analyst)
765 -**Status:** Implemented
766 -**Affects:** `scripts/render_press_context.py`, `tests/test_render_press_context.py`
118 +Future phases should add new tokens to `assets/css/tokens.css` first, then consume them through component or layout CSS. Keep semantic tokens stable (`--color-*`, `--text-*`, `--space-*`) and add component-specific variables only when a pattern repeats across multiple publishing surfaces.
119
768 -## Decision
120 +## Gotchas
121
770 -The divergence section in `format_divergences()` now renders as narrative prose when `reader_mode=True`, replacing the prior bullet list format. AI-prompt mode (`reader_mode=False`) is unchanged.
122 +PaperMod lives as a submodule, so theme CSS changes should be copied into root-level `assets/css/` overrides rather than editing `themes/PaperMod` directly. Hugo resolves these project assets through the existing asset pipeline while leaving the third-party theme clean.
123
772 -## Rationale
124 +# Amy Phase 2 Implementation Notes
125
774 -Raw topic-and-repo bullet lists communicate data but not meaning. Readers gain more from a paragraph that groups activity, links to repos by short name, and closes with an interpretive sentence. The AI model still needs the full structured data — so the dual-mode architecture cleanly separates the two use cases.
126 +Date: 2026-05-25
127 +Author: Amy
128 +Status: Implemented in PR branch
129
776 -## Format Decisions
130 +## Decisions
131
778 -1. **Repo links:** `[repo-name](https://github.com/owner/repo-name)` — repo name only (after `/`), never `owner/repo (⭐N)`.
779 -2. **Article links:** `[title](url)` — standard markdown.
780 -3. **Topic capping:** Top 6 topics by aggregate star count for "Dev Activity Without Press Coverage"; top 5 for "Tech Trends Without Dev Activity".
781 -4. **Structure:** Two named helpers — `_format_unpublicized_narrative()` and `_format_uncovered_narrative()` — keep the logic isolated and independently testable.
132 +- Override PaperMod chrome at the project layer (`layouts/partials/header.html`, `layouts/partials/footer.html`) rather than editing the theme submodule.
133 +- Add `layouts/_default/baseof.html` solely to place the skip-to-content link before the cached header and give the main landmark `id="main-content"`.
134 +- Keep the primary nav intentionally scoped to Weekly, Monthly, Yearly, and About for Phase 2; archive/search/taxonomy links remain in the page body and footer where already present.
135 +- Use a native `<details>` disclosure for mobile navigation so the collapsed menu remains keyboard reachable without adding new JavaScript.
136
137 ## Implications
138
785 -- Any future changes to reader-mode divergence prose go into the two helper functions.
786 -- If the data schema adds new fields (e.g., `growth_rate`), the helpers can incorporate them without touching AI-mode output.
787 -- Tests updated: `test_reader_mode_has_narrative` and `test_reader_mode_has_repo_links` replace the old phrase-matching assertions. 499 tests pass.
139 +Future chrome work should continue to extend root layouts and tokenized CSS. If PaperMod changes its base template, compare against this override before upgrading the theme.
140
789 ----
141 +# Amy — Topic buttons follow-up
142
791 -# Decision: No-AI Fallback Must Re-render from Raw Data for Reader Mode
143 +- Date: 2026-06-01
144 +- Context: Issue #216 mobile topic buttons regression
145 +- Proposal: Keep topic discovery centered on `/topics/`, remove the global header topic shortcut strip, and hide per-report topic chips on screens up to 768px while leaving desktop topic browsing available through the homepage rail and Topics page.
146 +- Why: The repeated chip rows were consuming too much vertical space on mobile and duplicated navigation that already exists in the primary menu.
147
793 -**Date:** 2026-05-19T21:54:14+02:00
794 -**Author:** Farnsworth
795 -**Status:** Implemented (PR #137, merged)
148 +# Decision: GA4 fork-safe secret injection
149
797 -## Context
150 +**Date:** 2026-05-25T22:30:00+02:00
151 +**Author:** Bender (Crawler/CI)
152 +**Status:** Proposed
153
799 -The CI pipeline falls to the no-AI path when the AI API is unavailable. In that path, `_render_press_section_no_ai()` was reading the pre-rendered `data/analyzed/{WEEK}-press-context.md` and stripping AI instructions to produce reader output.
154 +## Context
155
801 -The problem: that file is generated in AI-prompt mode (`reader_mode=False`). The narrative divergence format introduced in PR #136 is only produced when `reader_mode=True`. So the no-AI path always showed the old bullet-list format regardless of code changes in the reader-mode rendering path.
156 +SquadScope needs GA4 analytics for the upstream site, but forks must not silently report traffic to the maintainer's GA property. Repository secrets are not inherited by forks, so analytics must depend on an explicitly provided secret and render nothing when absent.
157
158 ## Decision
159
805 -**Re-render from raw JSON data in the no-AI path.** Specifically:
806 -
807 -1. Extract the week identifier from the `press_context_path` filename stem.
808 -2. Load `data/raw/{WEEK}-techcrunch.json` and `data/analyzed/{WEEK}-correlations.json`.
809 -3. Call `render_press_context(tc_data, corr_data, week, reader_mode=True)`.
810 -4. If raw files are absent, fall back to the existing strip-based approach.
160 +Use a secret-default-empty pattern: Hugo config defines `params.ga_measurement_id = ""`, while the Pages deploy workflow injects `${{ secrets.GA_MEASUREMENT_ID }}` through `HUGO_PARAMS_GA_MEASUREMENT_ID`. Hugo maps that environment key to `params.ga.measurement.id`, and the analytics partial renders GA4 only when either config path is non-empty. The rendered scripts are marked with `data-cc-category="analytics"` so Cookie Consent v3 can load them only after analytics consent.
161
162 ## Rationale
163
814 -- The pre-rendered press-context.md is an AI prompt artifact, not a reader artifact. It must not be the source of truth for reader-facing output.
815 -- Raw JSON files are always present when the CI pipeline runs (they are produced earlier in the same pipeline run).
816 -- The fallback ensures backward compatibility for edge cases (manual script invocations against older data).
164 +The empty config default is safe for forks and local builds. The environment override keeps the maintainer measurement ID out of source control while still enabling analytics in the upstream deployment. Consent-category script tagging keeps analytics dormant until the consent integration activates the analytics category.
165
166 ## Impact
167
820 -- The no-AI CI path now uses identical rendering logic to the AI path's fallback output.
821 -- Any future changes to `render_press_context(..., reader_mode=True)` automatically apply to the no-AI path without further changes.
822 -- The W21 page will show the correct narrative format on the next pipeline run.
168 +- Upstream deploys can enable GA4 by setting `GA_MEASUREMENT_ID`.
169 +- Forks build without analytics by default.
170 +- Maintainers can opt out by deleting the secret.
171 +- Cookie consent integration can activate the tagged scripts without changing the GA4 partial.
172
824 -## Files Changed
173 +# Decision: Journalistic shell baseline
174
826 -- `scripts/analyze_fallback.py` — `_render_press_section_no_ai()` (lines 346–370)
827 -
828 ----
829 -
830 -# Decision: Correlation Summary — Narrative Prose in reader_mode
831 -
832 -**Date:** 2026-05-19T22:34:57+02:00
833 -**Author:** Farnsworth (Analyst)
834 -**PR:** #138
835 -**Status:** Merged
836 -
837 -## Context
838 -
839 -The Correlation Summary section was showing a raw bullet list of repo names, confidence scores, and match types — useful for AI prompt consumption but meaningless to human readers. The Divergence section had already been upgraded to narrative prose (PR #131). This decision extends that pattern to correlations.
175 +**Date:** 2026-05-25T23:31:03+02:00
176 +**Owner:** Calculon
177 +**Status:** Proposed
178
179 ## Decision
180
843 -When `reader_mode=True`, `format_correlations_list()` delegates to `_format_correlations_narrative()` which:
844 -
845 -1. **Groups correlations by org** (first path segment of owner/repo). This is the natural unit of press coverage — TechCrunch writes about organizations, not individual repos.
846 -2. **Ranks groups by aggregate confidence score** (sum of correlation_confidence across all repos in the group).
847 -3. **Fetches README snippets** (first 500 chars) for the top 2 repos per group, up to 6 total, using `urllib.request` with a 5-second timeout and graceful failure. This enables project descriptions in the narrative (e.g., "Guava is a set of core Java libraries from Google").
848 -4. **Produces 1–3 paragraphs** with inline links to repos (short name, e.g., `[codex](https://github.com/openai/codex)`) and matched TechCrunch articles (full title as link text).
849 -
850 -## Alternative Considered
181 +The journalistic shell is a non-negotiable baseline for SquadScope. Navigation density, search, weekly archive access, and topic shortcuts must remain present in future home-page cleanups.
182
852 -**No README fetching — use only repo names**: simpler and fully deterministic, but produces flat prose with no editorial context about what the repos actually do. The README fetch adds signal at low cost (max 6 network requests, fails gracefully).
183 +## Rationale
184
854 -## Constraints Respected
185 +jmservera rejected the PR #205 revision because it over-pruned the publication shell. Future cleanups may relocate explanatory body content, but they must not remove the publication affordances that make the site feel like an editorial front page.
186
856 -- `reader_mode=False` output is unchanged — AI prompt consumers still receive full raw data.
857 -- README fetching only happens in reader_mode=True paths (no side effects in CI pre-rendering).
858 -- Article title lookup reuses the already-loaded `tc_data["articles"]` list — no new I/O for the article side.
859 -- All new functions are covered by unit tests; 513 tests pass.
187 +## Implications
188
861 ----
189 +- Keep top-level access to all weeks, topics, and search.
190 +- Keep a home-page rail or equivalent surfacing active topics and recent issues.
191 +- Preserve `/about/` as the home for the explainer and transparency dashboard.
192
863 -# Decision: CI Self-Learning Pipeline Architecture
193 +# Design Direction: Editorial Trend Report
194
865 -**Date:** 2026-05-19T22:57:55+02:00
866 -**Author:** Leela (Lead/Architect)
195 +**Date:** 2026-05-25
196 +**Author:** Calculon (Designer)
197 **Status:** Proposed
868 -**Scope:** Analysis and reskill CI jobs — self-learning loop
869 -
870 -## Context
871 -
872 -The CI pipeline runs AI analysis (Copilot CLI) and reskill (GitHub Models API) but neither job leverages the squad agent system. The analysis agent has no identity, cannot read its own history/skills, and has no mechanism to write learnings back. The reskill job bypasses Copilot CLI entirely and uses a model (`openai/gpt-4.1`) that returns 403.
873 -
874 -## Decisions
875 -
876 -### 1. Dedicated Farnsworth Agent File (`.github/agents/farnsworth.agent.md`)
877 -
878 -A standalone agent file gives the Copilot CLI the full Farnsworth identity — charter, history reading instructions, post-analysis learning format, and write permissions to `.squad/`.
879 -
880 -**Rationale:** The `--agent` flag loads an agent markdown file with YAML frontmatter and instructions. A dedicated file allows CI-specific directives (learning output format, file write permissions) without polluting the interactive Squad coordinator agent.
881 -
882 -### 2. `--agent` Flag in Copilot CLI Invocations
883 -
884 -Both the analysis and reskill jobs now use:
885 -```bash
886 -copilot --agent .github/agents/farnsworth.agent.md ...
887 -```
888 -
889 -**Rationale:** This loads Farnsworth's identity, making the CLI aware of the agent's history, wisdom, skills, and learning expectations.
890 -
891 -### 3. Learning Commit Strategy: Same Branch, Same Job
892 -
893 -After analysis, `.squad/` changes (history, skills) are committed alongside `data/analyzed/` to the `publish` data branch in a single atomic commit.
894 -
895 -**Rationale:** No additional branch/PR overhead. The data branch is unprotected and already receives CI commits. Learnings are part of the analysis artifact — they should be co-located temporally. The reskill job already commits `.squad/` state via the same pattern.
896 -
897 -### 4. Model Fallback: `openai/gpt-4o` Replaces `openai/gpt-4.1`
898 -
899 -The default model for GitHub Models API fallback is changed from `openai/gpt-4.1` (which returns 403) to `openai/gpt-4o` (widely accessible).
198
901 -**Rationale:** `gpt-4.1` is not accessible via the GitHub Models API for this repository's token. `gpt-4o` is the current generally available model. The env var `GITHUB_MODELS_MODEL` still allows override.
902 -
903 -### 5. Reskill Primary Path: Copilot CLI with Agent
904 -
905 -The reskill job now tries Copilot CLI first (with agent identity), falling back to GitHub Models API if CLI is unavailable. This gives reskill the same agent-aware capabilities as analysis: read wisdom/skills/history, write updated wisdom and learnings back.
906 -
907 -**Rationale:** The reskill cycle is the primary mechanism for reinforcing the learning loop. With agent identity, it can directly update `wisdom.md` and `history.md` based on retrospective findings — the core of self-improvement.
908 -
909 -### 6. Prompt Template Unchanged
910 -
911 -The existing prompt templates (`prompts/analyze-weekly.md`, `prompts/reskill.md`) already inject wisdom and skills via `{{WISDOM}}` and `{{SKILLS}}` placeholders. The agent file complements this by providing identity context and learning output instructions that the templates alone cannot express.
912 -
913 -## Risks
914 -
915 -| Risk | Mitigation |
916 -|------|-----------|
917 -| Agent writes bad content to `.squad/` files | Quality gate still runs on analysis output; .squad changes are append-only learnings |
918 -| Copilot CLI doesn't support `--agent` as expected | Fallback path (GitHub Models via reskill.py) still works without agent identity |
919 -| Learning state diverges between publish branch and main | Periodic sync PRs already exist; learnings on publish are forward-compatible |
920 -
921 -## Implementation
922 -
923 -- [x] `.github/agents/farnsworth.agent.md` — agent identity file
924 -- [x] `.github/workflows/crawl-and-publish.yml` — `--agent` flag, learning commits, model fix
925 -- [x] `scripts/reskill.py` — model default updated to `openai/gpt-4o`
926 -- [x] `scripts/analyze_fallback.py` — model default updated to `openai/gpt-4o`
927 -
928 ----
929 -
930 -## Governance
931 -
932 -- All meaningful changes require team consensus
933 -- Document architectural decisions here
934 -- Keep history focused on work, decisions focused on direction
199 +## Decision
200
936 -## Weekly Analysis Article Restructure
201 +**Visual Direction:** Editorial Trend Report — Dense but Quiet
202
938 -**Date:** 2026-05-20T19:15:53.942+02:00
939 -**Author:** Leela (Lead/Architect) — Proposed; Farnsworth (Analyst) — Implemented
940 -**Status:** Implemented
941 -**Requested by:** jmservera
203 +This positions SquadScope as a credible, opinionated weekly briefing rather than a generic blog or SaaS dashboard. Typography carries the design; images and color accents are supporting actors.
204
943 -### Context
205 +## Rationale
206
945 -The weekly analysis output was structured like a repo-listing document (Notable New Repositories, Trending This Week, etc.). User requested a restructure to read like a Gartner/McKinsey-style trend insight brief.
207 +After studying GitHub Pulse, TechCrunch, Wired, and The Verge:
208 +- GitHub Pulse is too dashboard-like for editorial content
209 +- TechCrunch provides good headline hierarchy but is too news-feed
210 +- Wired is too image-dependent for text-first analysis
211 +- The Verge shows density can work if hierarchy is clear
212
947 -### Decision
213 +SquadScope is closer to a weekly briefing document than any of these. The design borrows TechCrunch's reading rhythm, GitHub Pulse's monochrome discipline, and The Verge's willingness to be dense — while avoiding their weaknesses.
214
949 -Replace the six-section repo-listing structure with a six-section editorial structure:
215 +## Token Summary
216
951 -| Old Section | New Section |
952 -|---|---|
953 -| `## Notable New Repositories` | (moved to `### Notable Projects` under Key References) |
954 -| `## Trending This Week` | (rolled into `## This Week's Trends`) |
955 -| `## Industry & Press Correlation` | `## Where Industry Meets Code` |
956 -| `## Trend Analysis` / `### Signal` / `### Noise` | `## Signal & Noise` (integrated prose, no sub-headings) |
957 -| `## What's Missing` / `### Gaps` | `## Blind Spots` |
958 -| `## Conclusion` | `## The Week Ahead` |
959 -| _(new)_ | `## Key References` / `### Notable Projects` / `### Press & Industry` |
217 +**Palette:** Monochrome foundation with single accent (#0066CC light, #4DA3FF dark). All combinations WCAG AA verified.
218
961 -### Rationale
219 +**Typography:** Inter system stack for headlines and body. JetBrains Mono for code. Type scale from 0.75rem (tiny) to 2.25rem (h1). Optimal prose measure 68ch.
220
963 -1. Lead with synthesis, not inventory.
964 -2. Comparative press analysis gets its own section.
965 -3. Signal & Noise integrated (no mandatory sub-headings).
966 -4. Key References at the end (scannable).
967 -5. Forward-looking close ("The Week Ahead").
221 +## Phase Plan
222
969 -### Implementation
223 +1. Tokens + Typography Foundation
224 +2. Header + Footer + Navigation
225 +3. Home Page Layout
226 +4. Article Layout + Components
227 +5. Cost Dashboard Refresh
228 +6. Icon + Favicon + Social Images
229
971 -**Files Changed:** `prompts/analyze-weekly.md`, `docs/analysis-spec.md`, `scripts/analysis_gate.py`, `scripts/analyze_fallback.py`, `scripts/generate_rollups.py`, 5 test files.
230 +Each phase ships independently. Tokens must land first; other phases have light dependencies.
231
973 -**Backward Compatibility:** `generate_rollups.py` tries new heading names first and falls back to old names. All frontmatter fields, repo link format, quality_score gate, and body word count rules unchanged.
232 +## Icon
233
975 -**Outcome:** All 519 tests pass with new structure.
234 +Radar sweep concept — concentric circles with sweep line and signal blip. Represents continuous scanning. Hand-coded SVG, no external fonts, under 2KB. Uses currentColor for automatic mode adaptation.
235
977 ----
236 +## References
237
979 -# Decision: Model Resilience for Weekly CI
238 +- `docs/design/redesign-proposal-2026-05.md`
239 +- `docs/design/icon-spec.md`
240 +- Issues #170-#177
241
981 -**Date:** 2026-05-20T20:09:26+02:00
982 -**Owner:** Farnsworth
983 -**Status:** Proposed
242
985 -## Context
243 +# Source-selection methodology disclosure
244
987 -Copilot CLI model IDs can disappear from the platform, causing silent degradation to fallback paths.
245 +- **Date:** 2026-05-25
246 +- **Owner:** Farnsworth
247 +- **Status:** Proposed for merge
248
249 ## Decision
250
991 -The `crawl-and-publish.yml` workflow should never pass a version-pinned `--model` flag. Analysis and reskill rely on the CLI's platform default, while GitHub Models fallback uses `openai/gpt-4o` (configurable via `GITHUB_MODELS_MODEL`).
992 -
993 -## Rationale
994 -
995 -Pinned model IDs can silently disappear; letting the CLI choose its default keeps the primary path available without manual model churn.
996 -
997 -## Implementation
998 -
999 -- Removed `--model claude-sonnet-4` from Copilot CLI invocations
1000 -- Removed workflow pinned preflight model, switched to generic `copilot-default` rate profile
1001 -- Promoted `GITHUB_MODELS_MODEL` to workflow-level env with `openai/gpt-4o` default
1002 -
1003 -**Files:** `.github/workflows/crawl-and-publish.yml`, `scripts/preflight_cost_check.py`, `scripts/track_token_usage.py`
1004 -
1005 ----
1006 -
1007 -# Decision: Prevent Copilot stdout from Leaking into Published Markdown
1008 -
1009 -**Date:** 2026-05-20T22:14:02+02:00
1010 -**Owner:** Farnsworth
1011 -**Status:** Proposed
251 +Source-selection biases are publicly disclosed at `/methodology/`; updates to scoring, source ingestion, crawl thresholds, or press coverage should be reflected there.
252
253 ## Context
254
1015 -Published week 21 article leaked agent status text because shell appended Copilot CLI stdout to the markdown file after Farnsworth had already written the real article.
1016 -
1017 -## Decision
1018 -
1019 -In `crawl-and-publish.yml`, Copilot CLI stdout must never redirect to the same markdown file the agent writes. Analysis and reskill invocations send stdout to `/dev/null`, rely on `--share` or workflow logs for transcripts, and run a post-write sanitizer for defense in depth.
1020 -
1021 -## Rationale
1022 -
1023 -Separates channels (fixes root cause) and reduces blast radius if CLI emits metadata again.
255 +Nibbler's second responsible-AI sweep identified source-selection bias disclosure as a high-severity fairness and transparency gap. The methodology page gives readers a plain-English explanation of source inputs, ranking logic, and interpretation limits.
256
1025 -## Implementation
257 +## Consequences
258
1027 -- Changed Copilot CLI redirects from output markdown to `/dev/null`
1028 -- Added `scripts/sanitize_agent_output.py` to strip leaked lines (`✅ Farnsworth is done`, `Editorial thesis:`, etc.)
1029 -- Reinforced `prompts/analyze-weekly.md` so agent writes only publication-ready markdown
259 +- Pipeline changes that alter source mix or scoring should include a reader-facing methodology update.
260 +- Future bias metrics can link back to `/methodology/` as the stable disclosure surface.
261
1031 -**Files:** `.github/workflows/crawl-and-publish.yml`, `prompts/analyze-weekly.md`, `scripts/sanitize_agent_output.py`, `tests/test_sanitize_agent_output.py`
262 +# BaseURL-aware links in data files
263
1033 ----
1034 -
1035 -# Decision: Squad Agent Documentation Restructure
1036 -
1037 -**Date:** 2026-05-21T09:23:40+02:00
1038 -**Author:** Farnsworth (Analyst)
1039 -**Status:** Implemented
1040 -
1041 -## Context
1042 -
1043 -Audit found repeated charter scaffolding, duplicated rollout updates in histories, and mature workflow knowledge scattered across multiple agent files.
264 +Date: 2026-05-25
265 +Owner: Hermes
266
267 ## Decision
268
1047 -Squad agent docs follow a shared minimal-charter and history-hygiene model. Shared operating patterns move into `.squad/skills/`, while charters keep only: identity, ownership, working style, boundaries, and model preference.
269 +Links inside `data/*.json` files must use `__TOKEN__` placeholders substituted by partials with Hugo URL helpers; never hardcode `/path/` prefixes inside data files.
270
271 ## Rationale
272
1051 -- Eliminates redundant documentation
1052 -- Preserves workflow knowledge as reusable skills
1053 -- Reduces agent charter bloat
1054 -
1055 -## Impact
1056 -
1057 -- All charters now under 1.5 KB target
1058 -- Oversized histories condensed
1059 -- 3 new skills extracted (minimal-agent-charter, agent-history-hygiene, weekly-learning-loop)
1060 -- 1 existing skill upgraded (branch-protection-pr-workflow)
1061 -- **Net savings: 68.4% reduction** (39,568 → 12,521 bytes)
273 +SquadScope is currently deployed on GitHub project Pages under `/SquadScope/`, so root-relative links such as `/privacy/` resolve outside the site and can 404. If the site later moves to an apex/custom domain, Hugo URL helpers will render the same logical route correctly without changing legal-copy JSON.
274
1063 ----
275 +## Implementation note
276
1065 -# Decision: Farnsworth Weekly Headline Review
277 +For cookie-consent copy, `data/cookieconsent.json` uses `__PRIVACY_URL__`, and `layouts/partials/cookie-consent.html` replaces it with `"privacy/" | relURL` before initializing Cookie Consent.
278
1067 -**Date:** 2026-05-21T12:33:16.507+02:00
1068 -**Author:** Farnsworth (Analyst)
1069 -**Status:** Implemented
279 +# Hermes Privacy Policy v1
280
1071 -## Context
1072 -
1073 -Week 21 analysis requires both editorial quality and automation compliance. The title and press-fallback handling must satisfy both reader expectations and the analyzer contract.
281 +Date: 2026-05-25
282 +Author: Hermes (Security & Legal)
283 +Status: Proposed
284
285 ## Decision
286
1077 -Week 21 analysis should use a journalistic title, not a generic week label, and must keep the no-press fallback explicit when press data is absent.
1078 -
1079 -## Rationale
1080 -
1081 -The published analysis needs to read like an editorial artifact and satisfy the analyzer contract at the same time. A headline plus explicit press fallback keeps the page useful to readers and safe for automation.
1082 -
1083 -## Impact
1084 -
1085 -Applies to future weekly summaries and any generator work that consumes `data/analyzed/*-summary.md`.
1086 -
1087 ----
1088 -
1089 -# Directive: Prevent Recrawl on Previous-Week Rebuilds
1090 -
1091 -**Date:** 2026-05-25T15:55:00+02:00
1092 -**Source:** User directive (jmservera via Copilot)
1093 -**Status:** Active
287 +GA4 is our ONLY analytics; no first-party tracking.
288
289 ## Context
290
1097 -When rebuilding data for a previous week, the workflow must NOT re-run the crawl. Re-crawling pollutes prior weeks' data (overwrites the high-quality version with a fresh, possibly worse snapshot). User repeatedly lost high-quality W21 analysis because re-runs re-crawled and re-analyzed, regenerating inferior versions.
1098 -
1099 -## Directive
291 +SquadScope is a static editorial trend-analysis site with no accounts, signup, comments, contact form, or newsletter. The site is hosted on GitHub Pages and uses a cookie consent banner before analytics can run.
292
1101 -For previous-week rebuilds:
1102 -1. Hydrate from `publish` (canonical source for analyzed content)
1103 -2. Re-run analysis/generation only as needed
1104 -3. **Never crawl again** for previous weeks
293 +## Consequences
294
1106 -This restores/regenerates from existing data without polluting the archive.
295 +- SquadScope must not add first-party visitor profiling, server-side personal-data storage, or additional analytics tools without a new privacy review.
296 +- GA4 must remain consent-gated behind the analytics cookie category.
297 +- Privacy disclosures should continue to identify GitHub Pages hosting logs, GA4, Google Fonts if used, and the essential consent cookie.
298
1108 -## Implementation Status
299 +# Prompt Injection Hardening for Analysis Prompts
300
1110 -- Captured in PR #164 (bender-3): deploy-site.yml now hydrates content/data from publish before hugo build
1111 -- Schedule event guard fixed: `!inputs.rebuild_week` instead of `== ''` ensures cron doesn't skip
1112 -- Format validation added for YYYY-WNN rebuild_week parameter
1113 -- Architectural fix prevents main/publish divergence
1114 -
1115 -**Files affected:** `.github/workflows/deploy-site.yml`, `.github/workflows/crawl-and-publish.yml`
1116 -
1117 -## 2026-05-19: TechCrunch RSS as Enrichment Signal (PR #55)
1118 -
1119 -- **Owner:** Bender
1120 -- **Date:** 2026-05-19
1121 -- **Decision:** TechCrunch RSS integration is an enrichment signal (not primary source) with explicit low-expectation framing (5–15% correlation hit rate). Feature degrades to zero noise when no correlations found.
1122 -- **Why:** Correlation between press articles and repos is inherently low. Value lies in the delta (hype vs traction), not article summarization. Enrichment positioning allows silent failure without degrading digest.
1123 -- **Implications:** All future `DataSource` plugins must declare "primary" or "enrichment" status. Enrichment sources require explicit failure/removal criteria. Farnsworth's analysis treats correlation data as optional context, never required input.
1124 -
1125 -## 2026-05-19: Milestone-based workflow adopted
301 +**Date:** 2026-05-25
302 +**Author:** Hermes
303 +**Status:** Proposed
304
1127 -- **Owner:** jmservera (via Copilot)
1128 -- **Date:** 2026-05-19
1129 -- **Decision:** All future work organized into versioned milestones (v0.5, v0.6, etc.). PRDs are decomposed into issues, assigned to milestones, then moved to docs/processed/. This enables progress tracking and versioning.
1130 -- **Why:** User directive — makes work easier to follow and enables versioning.
305 +## Context
306
1132 -## 2026-05-19: Press Context Dual-Mode Rendering
307 +Nibbler's RAI audit identified user-controlled GitHub repository descriptions entering the weekly analysis prompt through `{{RAW_JSON_CONTENT}}`. A malicious repo description can contain prompt-injection text that attempts to override Farnsworth's editorial instructions.
308
1134 -- **Owner:** Farnsworth
1135 -- **Date:** 2026-05-19T20:50:22+02:00
1136 -- **Status:** Implemented
1137 -- **Decision:** Implement dual-mode rendering in `render_press_context.py` to serve AI prompts (full data + instructions) and reader-facing fallback (clean narrative) separately via `reader_mode` parameter and post-processing.
1138 -- **Why:** The press context serves two audiences. AI prompts need full data and model instructions; reader-facing pages should not expose AI directives or 100+ repo lists.
1139 -- **Changes:**
1140 - - `render_press_context(reader_mode=False)` — new kwarg. When True, limits correlations to top 10, strips `### Instructions` block, and passes reader_mode to `format_divergences()`
1141 - - `format_correlations_list(top_n=None)` — new kwarg. Truncates display and appends "…and N more repos"
1142 - - `format_divergences(reader_mode=False)` — new kwarg. Replaces instruction bullets with reader-friendly narrative
1143 - - `analyze_fallback._strip_ai_instructions(content)` — new helper. Applied in no-AI path to post-process rendered content
1144 -- **Consequences:** AI prompt path unchanged (full instructions + list continue to model); no-AI fallback now produces clean reader output. 16 new tests cover truncation, sorting, instruction stripping, narrative injection. All 498 tests passing. PR #135 merged.
309 +## Decision
310
1146 -## Nibbler Review Gate for External-Facing Artifacts (2026-05-25)
311 +Apply a layered OWASP LLM01 defense for analyzer prompt rendering:
312
1148 -**Source:** Nibbler audit recommendation
1149 -**Adopted by:** Leela
1150 -**Status:** Adopted
313 +1. Mark raw crawl JSON as untrusted data with explicit `<untrusted-content>` boundaries.
314 +2. Sanitize repository descriptions before prompt rendering by stripping leading whitespace, escaping boundary-closing tags, truncating long text, and warning on common prompt-injection phrases.
315 +3. Add output guardrails telling the analyst to stop on unsupported claims and avoid verbatim descriptions containing meta-instructions.
316 +4. Repeat the editorial mission after the untrusted content so late prompt text reinforces trusted instructions.
317
1152 -External-facing launch and announcement artifacts require Nibbler review before publication or merge. This includes Hacker News posts, LinkedIn announcements, Bluesky threads, Reddit posts, launch blogs, press copy, launch graphics, and similar materials that will appear outside this repository.
318 +## Consequences
319
1154 -PRs that ship this copy or graphics must tag `@squad:nibbler` for RAI sign-off and use the [Responsible AI checklist](skills/responsible-ai-review/SKILL.md) (`.squad/skills/responsible-ai-review/SKILL.md`) before merge.
320 +The analyzer keeps using the same editorial structure, but prompt provenance is clearer and repository descriptions have bounded influence. Suspicious descriptions are logged and truncated rather than blocked to avoid false positives disrupting publication.
321
1156 -**Rationale:** Distribution copy can create reputational, safety, accessibility, or policy risk even when the underlying code is unchanged. Nibbler provides the hostile-reader and responsible-AI perspective before users encounter the material.
.squad/decisions/inbox/amy-ai-disclosure-pattern.md deleted
-7
@@ -1,7 +0,0 @@
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/decisions/inbox/amy-cookie-consent-vendoring.md deleted
-14
@@ -1,14 +0,0 @@
1 -# Amy — Cookie Consent vendoring
2 -
3 -Date: 2026-05-25
4 -
5 -Decision: vendor Cookie Consent v3 directly in `static/vendor/cookieconsent/` and pin it to upstream version `v3.0.1`.
6 -
7 -Rationale:
8 -- Cookie consent must run before optional analytics scripts are activated.
9 -- Vendoring avoids relying on the jsDelivr CDN at runtime.
10 -- The pinned files are the published `dist` CSS and UMD bundle from `orestbida/cookieconsent@v3.0.1`.
11 -
12 -Checksums:
13 -- `cookieconsent.css`: `sha256 ca046b8b1b1094107205988e7096a687b241c8ef5f3fefe5e543ed28d26646c1`
14 -- `cookieconsent.umd.js`: `sha256 1267fd33fcf3ab4043a7cc62cc9259a2c66f839f695216f7737ed37b7b3e62e6`
.squad/decisions/inbox/amy-errata-schema.md deleted
-21
@@ -1,21 +0,0 @@
1 -# Article errata schema
2 -
3 -**Date:** 2026-05-25
4 -**Author:** Amy
5 -**Status:** Proposed
6 -
7 -## Decision
8 -
9 -Articles declare corrections in front-matter using `errata: [{date, note}]`; the article footer renders those entries at the end of the article.
10 -
11 -## Schema example
12 -
13 -```yaml
14 -errata:
15 - - date: 2026-05-26
16 - note: "Corrected the company name in the EU AI Act section (was 'Mistral.ai', now 'Mistral AI')."
17 -```
18 -
19 -## Rationale
20 -
21 -Keeping corrections in front-matter makes the article-level errata path data-driven, reviewable in Git, and visible to readers without requiring silent edits to published analysis.
.squad/decisions/inbox/amy-home-hero-restructure.md deleted
-9
@@ -1,9 +0,0 @@
1 -# Home hero restructure
2 -
3 -**Date:** 2026-05-25
4 -**Author:** Amy (Frontend Engineer)
5 -**Status:** Proposed
6 -
7 -## Decision
8 -
9 -Home page is a publication front page — the latest weekly analysis IS the hero. Explainer lives at `/about/`.
.squad/decisions/inbox/amy-phase1-implementation.md deleted
-25
@@ -1,25 +0,0 @@
1 -# Amy Phase 1 Design Foundation Implementation
2 -
3 -**Date:** 2026-05-25
4 -**Author:** Amy (Frontend Developer)
5 -**Status:** Implemented
6 -
7 -## Decision
8 -
9 -Phase 1 tokens and typography are implemented as a Hugo asset-pipeline foundation without changing page layouts.
10 -
11 -## File locations
12 -
13 -- `assets/css/tokens.css` is the design-system entry point for color, type, spacing, radius, shadow, and line-height tokens.
14 -- `layouts/partials/head.html` loads Inter and JetBrains Mono from Google Fonts using preload + stylesheet links, then includes `tokens.css` before the PaperMod-compatible CSS bundle.
15 -- `assets/css/core/theme-vars.css` maps PaperMod legacy variables to SquadScope tokens so existing templates continue to render.
16 -- `assets/css/core/reset.css` applies the base reset, body typography, heading scale, and monospace stack.
17 -- `assets/css/common/*.css`, `assets/css/extended/squadscope.css`, and `assets/css/badges.css` consume the token aliases while preserving existing layouts.
18 -
19 -## How to extend
20 -
21 -Future phases should add new tokens to `assets/css/tokens.css` first, then consume them through component or layout CSS. Keep semantic tokens stable (`--color-*`, `--text-*`, `--space-*`) and add component-specific variables only when a pattern repeats across multiple publishing surfaces.
22 -
23 -## Gotchas
24 -
25 -PaperMod lives as a submodule, so theme CSS changes should be copied into root-level `assets/css/` overrides rather than editing `themes/PaperMod` directly. Hugo resolves these project assets through the existing asset pipeline while leaving the third-party theme clean.
.squad/decisions/inbox/amy-phase2-implementation.md deleted
-16
@@ -1,16 +0,0 @@
1 -# Amy Phase 2 Implementation Notes
2 -
3 -Date: 2026-05-25
4 -Author: Amy
5 -Status: Implemented in PR branch
6 -
7 -## Decisions
8 -
9 -- Override PaperMod chrome at the project layer (`layouts/partials/header.html`, `layouts/partials/footer.html`) rather than editing the theme submodule.
10 -- Add `layouts/_default/baseof.html` solely to place the skip-to-content link before the cached header and give the main landmark `id="main-content"`.
11 -- Keep the primary nav intentionally scoped to Weekly, Monthly, Yearly, and About for Phase 2; archive/search/taxonomy links remain in the page body and footer where already present.
12 -- Use a native `<details>` disclosure for mobile navigation so the collapsed menu remains keyboard reachable without adding new JavaScript.
13 -
14 -## Implications
15 -
16 -Future chrome work should continue to extend root layouts and tokenized CSS. If PaperMod changes its base template, compare against this override before upgrading the theme.
.squad/decisions/inbox/bender-ga4-fork-safety.md deleted
-24
@@ -1,24 +0,0 @@
1 -# Decision: GA4 fork-safe secret injection
2 -
3 -**Date:** 2026-05-25T22:30:00+02:00
4 -**Author:** Bender (Crawler/CI)
5 -**Status:** Proposed
6 -
7 -## Context
8 -
9 -SquadScope needs GA4 analytics for the upstream site, but forks must not silently report traffic to the maintainer's GA property. Repository secrets are not inherited by forks, so analytics must depend on an explicitly provided secret and render nothing when absent.
10 -
11 -## Decision
12 -
13 -Use a secret-default-empty pattern: Hugo config defines `params.ga_measurement_id = ""`, while the Pages deploy workflow injects `${{ secrets.GA_MEASUREMENT_ID }}` through `HUGO_PARAMS_GA_MEASUREMENT_ID`. Hugo maps that environment key to `params.ga.measurement.id`, and the analytics partial renders GA4 only when either config path is non-empty. The rendered scripts are marked with `data-cc-category="analytics"` so Cookie Consent v3 can load them only after analytics consent.
14 -
15 -## Rationale
16 -
17 -The empty config default is safe for forks and local builds. The environment override keeps the maintainer measurement ID out of source control while still enabling analytics in the upstream deployment. Consent-category script tagging keeps analytics dormant until the consent integration activates the analytics category.
18 -
19 -## Impact
20 -
21 -- Upstream deploys can enable GA4 by setting `GA_MEASUREMENT_ID`.
22 -- Forks build without analytics by default.
23 -- Maintainers can opt out by deleting the secret.
24 -- Cookie consent integration can activate the tagged scripts without changing the GA4 partial.
.squad/decisions/inbox/calculon-journalistic-shell-baseline.md deleted
-19
@@ -1,19 +0,0 @@
1 -# Decision: Journalistic shell baseline
2 -
3 -**Date:** 2026-05-25T23:31:03+02:00
4 -**Owner:** Calculon
5 -**Status:** Proposed
6 -
7 -## Decision
8 -
9 -The journalistic shell is a non-negotiable baseline for SquadScope. Navigation density, search, weekly archive access, and topic shortcuts must remain present in future home-page cleanups.
10 -
11 -## Rationale
12 -
13 -jmservera rejected the PR #205 revision because it over-pruned the publication shell. Future cleanups may relocate explanatory body content, but they must not remove the publication affordances that make the site feel like an editorial front page.
14 -
15 -## Implications
16 -
17 -- Keep top-level access to all weeks, topics, and search.
18 -- Keep a home-page rail or equivalent surfacing active topics and recent issues.
19 -- Preserve `/about/` as the home for the explainer and transparency dashboard.
.squad/decisions/inbox/calculon-redesign-direction.md deleted
-48
@@ -1,48 +0,0 @@
1 -# Design Direction: Editorial Trend Report
2 -
3 -**Date:** 2026-05-25
4 -**Author:** Calculon (Designer)
5 -**Status:** Proposed
6 -
7 -## Decision
8 -
9 -**Visual Direction:** Editorial Trend Report — Dense but Quiet
10 -
11 -This positions SquadScope as a credible, opinionated weekly briefing rather than a generic blog or SaaS dashboard. Typography carries the design; images and color accents are supporting actors.
12 -
13 -## Rationale
14 -
15 -After studying GitHub Pulse, TechCrunch, Wired, and The Verge:
16 -- GitHub Pulse is too dashboard-like for editorial content
17 -- TechCrunch provides good headline hierarchy but is too news-feed
18 -- Wired is too image-dependent for text-first analysis
19 -- The Verge shows density can work if hierarchy is clear
20 -
21 -SquadScope is closer to a weekly briefing document than any of these. The design borrows TechCrunch's reading rhythm, GitHub Pulse's monochrome discipline, and The Verge's willingness to be dense — while avoiding their weaknesses.
22 -
23 -## Token Summary
24 -
25 -**Palette:** Monochrome foundation with single accent (#0066CC light, #4DA3FF dark). All combinations WCAG AA verified.
26 -
27 -**Typography:** Inter system stack for headlines and body. JetBrains Mono for code. Type scale from 0.75rem (tiny) to 2.25rem (h1). Optimal prose measure 68ch.
28 -
29 -## Phase Plan
30 -
31 -1. Tokens + Typography Foundation
32 -2. Header + Footer + Navigation
33 -3. Home Page Layout
34 -4. Article Layout + Components
35 -5. Cost Dashboard Refresh
36 -6. Icon + Favicon + Social Images
37 -
38 -Each phase ships independently. Tokens must land first; other phases have light dependencies.
39 -
40 -## Icon
41 -
42 -Radar sweep concept — concentric circles with sweep line and signal blip. Represents continuous scanning. Hand-coded SVG, no external fonts, under 2KB. Uses currentColor for automatic mode adaptation.
43 -
44 -## References
45 -
46 -- `docs/design/redesign-proposal-2026-05.md`
47 -- `docs/design/icon-spec.md`
48 -- Issues #170-#177
.squad/decisions/inbox/farnsworth-methodology-disclosure.md deleted
-18
@@ -1,18 +0,0 @@
1 -# Source-selection methodology disclosure
2 -
3 -- **Date:** 2026-05-25
4 -- **Owner:** Farnsworth
5 -- **Status:** Proposed for merge
6 -
7 -## Decision
8 -
9 -Source-selection biases are publicly disclosed at `/methodology/`; updates to scoring, source ingestion, crawl thresholds, or press coverage should be reflected there.
10 -
11 -## Context
12 -
13 -Nibbler's second responsible-AI sweep identified source-selection bias disclosure as a high-severity fairness and transparency gap. The methodology page gives readers a plain-English explanation of source inputs, ranking logic, and interpretation limits.
14 -
15 -## Consequences
16 -
17 -- Pipeline changes that alter source mix or scoring should include a reader-facing methodology update.
18 -- Future bias metrics can link back to `/methodology/` as the stable disclosure surface.
.squad/decisions/inbox/hermes-baseurl-aware-data-links.md deleted
-16
@@ -1,16 +0,0 @@
1 -# BaseURL-aware links in data files
2 -
3 -Date: 2026-05-25
4 -Owner: Hermes
5 -
6 -## Decision
7 -
8 -Links inside `data/*.json` files must use `__TOKEN__` placeholders substituted by partials with Hugo URL helpers; never hardcode `/path/` prefixes inside data files.
9 -
10 -## Rationale
11 -
12 -SquadScope is currently deployed on GitHub project Pages under `/SquadScope/`, so root-relative links such as `/privacy/` resolve outside the site and can 404. If the site later moves to an apex/custom domain, Hugo URL helpers will render the same logical route correctly without changing legal-copy JSON.
13 -
14 -## Implementation note
15 -
16 -For cookie-consent copy, `data/cookieconsent.json` uses `__PRIVACY_URL__`, and `layouts/partials/cookie-consent.html` replaces it with `"privacy/" | relURL` before initializing Cookie Consent.
.squad/decisions/inbox/hermes-privacy-policy-v1.md deleted
-19
@@ -1,19 +0,0 @@
1 -# Hermes Privacy Policy v1
2 -
3 -Date: 2026-05-25
4 -Author: Hermes (Security & Legal)
5 -Status: Proposed
6 -
7 -## Decision
8 -
9 -GA4 is our ONLY analytics; no first-party tracking.
10 -
11 -## Context
12 -
13 -SquadScope is a static editorial trend-analysis site with no accounts, signup, comments, contact form, or newsletter. The site is hosted on GitHub Pages and uses a cookie consent banner before analytics can run.
14 -
15 -## Consequences
16 -
17 -- SquadScope must not add first-party visitor profiling, server-side personal-data storage, or additional analytics tools without a new privacy review.
18 -- GA4 must remain consent-gated behind the analytics cookie category.
19 -- Privacy disclosures should continue to identify GitHub Pages hosting logs, GA4, Google Fonts if used, and the essential consent cookie.
.squad/decisions/inbox/hermes-prompt-injection.md deleted
-22
@@ -1,22 +0,0 @@
1 -# Prompt Injection Hardening for Analysis Prompts
2 -
3 -**Date:** 2026-05-25
4 -**Author:** Hermes
5 -**Status:** Proposed
6 -
7 -## Context
8 -
9 -Nibbler's RAI audit identified user-controlled GitHub repository descriptions entering the weekly analysis prompt through `{{RAW_JSON_CONTENT}}`. A malicious repo description can contain prompt-injection text that attempts to override Farnsworth's editorial instructions.
10 -
11 -## Decision
12 -
13 -Apply a layered OWASP LLM01 defense for analyzer prompt rendering:
14 -
15 -1. Mark raw crawl JSON as untrusted data with explicit `<untrusted-content>` boundaries.
16 -2. Sanitize repository descriptions before prompt rendering by stripping leading whitespace, escaping boundary-closing tags, truncating long text, and warning on common prompt-injection phrases.
17 -3. Add output guardrails telling the analyst to stop on unsupported claims and avoid verbatim descriptions containing meta-instructions.
18 -4. Repeat the editorial mission after the untrusted content so late prompt text reinforces trusted instructions.
19 -
20 -## Consequences
21 -
22 -The analyzer keeps using the same editorial structure, but prompt provenance is clearer and repository descriptions have bounded influence. Suspicious descriptions are logged and truncated rather than blocked to avoid false positives disrupting publication.
assets/css/extended/squadscope.css
+5
@@ -392,6 +392,11 @@ summary:focus-visible,
392 width: 100%;
393 }
394
395 + .home-topic-rail,
396 + .post-tags__topic {
397 + display: none;
398 + }
399 +
400 .table-scroll table {
401 min-width: 30rem;
402 }
layouts/_default/single.html
+2 -2
@@ -34,10 +34,10 @@
34 {{- $categories := .Language.Params.Taxonomies.category | default "categories" }}
35 <ul class="post-tags">
36 {{- range ($.GetTerms $categories) }}
37 - <li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
37 + <li class="post-tags__category"><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
38 {{- end }}
39 {{- range ($.GetTerms $tags) }}
40 - <li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
40 + <li class="post-tags__topic"><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
41 {{- end }}
42 </ul>
43 {{- if (.Param "ShowPostNavLinks") }}
layouts/index.html
+1 -11
@@ -32,16 +32,6 @@
32 </section>
33 {{- end -}}
34
35 - {{- if $topTags -}}
36 - <nav class="home-tag-strip" aria-label="Active topic shortcuts">
37 - <span class="home-tag-label">Active topics</span>
38 - {{- range $topTags }}
39 - <a href="{{ printf "tags/%s/" (.Name | urlize) | absLangURL }}">{{ .Name }}</a>
40 - {{- end }}
41 - <a href="{{ `topics/` | absLangURL }}">All topics</a>
42 - </nav>
43 - {{- end -}}
44 -
35 <div class="home-content-grid">
36 {{- if gt (len $weeklyPages) 0 -}}
37 <section class="home-recent" aria-labelledby="recent-reports-heading">
@@ -78,7 +68,7 @@
68 <div class="home-topic-list">
69 {{- range $topTags -}}
70 <a class="home-topic-card" href="{{ printf "tags/%s/" (.Name | urlize) | absLangURL }}">
81 - <span>{{ .Name }}</span>
71 + <span>{{ .Name | humanize }}</span>
72 <small>{{ .Count }} issue{{ if ne .Count 1 }}s{{ end }}</small>
73 </a>
74 {{- end -}}
layouts/partials/article-footer.html
+2 -2
@@ -5,10 +5,10 @@
5 <div class="article-footer__taxonomies" aria-label="Report taxonomy">
6 <ul class="post-tags">
7 {{- range ($page.GetTerms $categories) }}
8 - <li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
8 + <li class="post-tags__category"><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
9 {{- end }}
10 {{- range ($page.GetTerms $tags) }}
11 - <li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
11 + <li class="post-tags__topic"><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
12 {{- end }}
13 </ul>
14 </div>
layouts/partials/header.html
-12
@@ -80,16 +80,4 @@
80 </div>
81 </div>
82 </nav>
83 -
84 - {{- $featuredTags := first 5 site.Taxonomies.tags.ByCount }}
85 - {{- if $featuredTags }}
86 - <nav class="topic-shortcuts" aria-label="Topic shortcuts">
87 - <span class="topic-shortcuts__label">Topics</span>
88 - {{- range $featuredTags }}
89 - <a href="{{ printf "tags/%s/" (.Name | urlize) | absLangURL }}">{{ .Name }}</a>
90 - {{- end }}
91 - <a class="topic-shortcuts__utility" href="{{ `weekly/` | absLangURL }}">All weeks</a>
92 - <a class="topic-shortcuts__utility" href="{{ `search/` | absLangURL }}">Search</a>
93 - </nav>
94 - {{- end }}
83 </header>
layouts/partials/report-shortcuts.html
+2 -2
@@ -2,7 +2,7 @@
2 {{- $archiveURL := "archive/" | absURL -}}
3 {{- $rssURL := "index.xml" | absURL -}}
4 {{- $searchURL := "search/" | absURL -}}
5 -{{- $tagsURL := "tags/" | absURL -}}
5 +{{- $topicsURL := "topics/" | absURL -}}
6 {{- $categoriesURL := "categories/" | absURL -}}
7 {{- $isWeekly := eq $page.Type "weekly" -}}
8 {{- $monthlyURL := "monthly/" | absURL -}}
@@ -21,7 +21,7 @@
21 <a href="{{ $monthlyURL }}">Monthly</a>
22 <a href="{{ $yearlyURL }}">Yearly</a>
23 {{- end }}
24 - <a href="{{ $tagsURL }}">Tags</a>
24 + <a href="{{ $topicsURL }}">Topics</a>
25 <a href="{{ $categoriesURL }}">Categories</a>
26 <a href="{{ $searchURL }}">Search</a>
27 <a href="{{ $rssURL }}">RSS</a>
layouts/topics/terms.html
+61 -22
@@ -1,32 +1,71 @@
1 {{- define "main" -}}
2 +{{- $tagTerms := site.Taxonomies.tags.ByCount -}}
3 +{{- $categoryTerms := site.Taxonomies.categories.Alphabetical -}}
4 <header class="page-header">
5 {{- partial "breadcrumbs.html" . }}
6 <h1>{{ .Title }}</h1>
5 - {{- with (.Description | default .Params.summary) }}
6 - <div class="post-description">{{ . }}</div>
7 - {{- end }}
7 + <div class="post-description">{{ .Description | default "Browse weekly issues by topic area, then jump across weekly, monthly, and yearly report categories." }}</div>
8 </header>
9
10 -{{- if .Content }}
11 -<div class="post-content md-content">
12 - {{ .Content }}
13 -</div>
14 -{{- end }}
15 -
16 -<section class="taxonomy-grid" aria-label="{{ .Title }} terms">
17 - {{- range .Data.Terms.Alphabetical }}
18 - {{- $term := .Name -}}
19 - {{- $count := .Count -}}
20 - {{- with site.GetPage (printf "/topics/%s" $term) }}
21 - <article class="home-report-card taxonomy-card">
22 - <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
23 - <p>{{ .Params.summary | default (printf "Browse %d weekly issue%s." $count (cond (eq $count 1) "" "s")) }}</p>
24 - <div class="home-report-meta">
25 - <span>{{ $count }} issue{{ if ne $count 1 }}s{{ end }}</span>
26 - <a href="{{ .RelPermalink }}index.xml" title="RSS feed for {{ .LinkTitle }}">RSS</a>
10 +<section aria-labelledby="topics-directory-heading">
11 + <div class="section-heading-row">
12 + <div>
13 + <div class="section-topline">Browse by theme</div>
14 + <h2 id="topics-directory-heading">Active topics</h2>
15 </div>
28 - </article>
29 - {{- end }}
16 + <a href="{{ `categories/` | absLangURL }}">Browse categories</a>
17 + </div>
18 +
19 + {{- if $tagTerms }}
20 + <div class="taxonomy-grid">
21 + {{- range $tagTerms }}
22 + {{- $term := .Name -}}
23 + {{- $count := .Count -}}
24 + {{- with site.GetPage (printf "/tags/%s" $term) }}
25 + <article class="home-report-card taxonomy-card">
26 + <h3><a href="{{ .RelPermalink }}">{{ $term | humanize }}</a></h3>
27 + <p>Browse {{ $count }} weekly issue{{ if ne $count 1 }}s{{ end }} touching {{ $term | humanize | lower }}.</p>
28 + <div class="home-report-meta">
29 + <span>{{ $count }} issue{{ if ne $count 1 }}s{{ end }}</span>
30 + <span>Topic</span>
31 + </div>
32 + </article>
33 + {{- end }}
34 + {{- end }}
35 + </div>
36 + {{- else }}
37 + <section class="home-empty-state">
38 + <h2>No topics published yet</h2>
39 + <p>Topic cards will appear here as soon as weekly issues ship with topic tags.</p>
40 + </section>
41 {{- end }}
42 </section>
43 +
44 +{{- if $categoryTerms }}
45 +<section aria-labelledby="categories-directory-heading">
46 + <div class="section-heading-row">
47 + <div>
48 + <div class="section-topline">Browse by cadence</div>
49 + <h2 id="categories-directory-heading">Report categories</h2>
50 + </div>
51 + <a href="{{ `categories/` | absLangURL }}">Open categories page</a>
52 + </div>
53 + <div class="taxonomy-grid">
54 + {{- range $categoryTerms }}
55 + {{- $term := .Name -}}
56 + {{- $count := .Count -}}
57 + {{- with site.GetPage (printf "/categories/%s" $term) }}
58 + <article class="home-report-card taxonomy-card">
59 + <h3><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h3>
60 + <p>{{ .Params.summary | default (printf "Browse %d report%s filed under %s." $count (cond (eq $count 1) "" "s") ($term | humanize | lower)) }}</p>
61 + <div class="home-report-meta">
62 + <span>{{ $count }} report{{ if ne $count 1 }}s{{ end }}</span>
63 + <span>Category</span>
64 + </div>
65 + </article>
66 + {{- end }}
67 + {{- end }}
68 + </div>
69 +</section>
70 +{{- end }}
71 {{- end -}}