Initial skills documentation — 25 categories, all SKILL.md + references + scripts

This commit is contained in:
root
2026-07-15 17:42:20 -04:00
commit 1b4fcd4427
976 changed files with 188344 additions and 0 deletions
@@ -0,0 +1,152 @@
# Extracting Content from Angular SPAs (Government / Statute Sites)
Many government websites — including the Texas Legislature Online — are built as **Angular Single-Page Applications (SPAs)**. The initial HTML page is a shell containing only CSS/JS bundles, navigation tree metadata, and skeleton markup. The actual content (statute text, bill text, search results) is loaded asynchronously via undocumented backend API calls.
## Identifying an Angular SPA Shell
Signs that you've hit an SPA shell, not the real content:
1. **Huge HTML file, tiny meaningful text**: The entire page is 200K250K bytes but contains fewer than 100 meaningful text lines (e.g., just navigation tree labels).
2. **`<app-root>` or `<app-home>` custom element**: Angular mounts the app on a custom element — the static HTML contains no content inside it.
3. **`ng-state` JSON script tag**: Contains Angular server-side state, but close inspection shows it only holds navigation metadata (code lists, tree nodes), not the actual document text.
4. **All real content is inside `<app-doc-viewer>`**: The document viewer component is empty in the static HTML — content loads via API after JavaScript executes.
5. **Known backend API routes return 404**: The Angular app may call an API like `api/Statutes/Chapter?code=FI&chp=392` that doesn't exist at the static URL level (the Angular router intercepts it).
## Telltale Pattern: TX Legislature Online
The Texas statutes site (`https://statutes.capitol.texas.gov/Docs/FI/htm/FI.392.htm`) follows this pattern:
| Check | Result |
|-------|--------|
| Total HTML size | ~250 KB |
| Meaningful text lines | ~84 (all navigation tree labels) |
| `ng-state` content | Only `StatuteCode` lists (code names like "Finance Code") — no statute text |
| `<app-doc-viewer>` | Empty `<!---->` in static HTML |
| Backend API (`api/Statutes/Chapter`) | 404 |
| Download links (DOCX, PDF) | Return 200 but serve HTML (bot wall/redirect) |
## Techniques to Try (in priority order)
### 1. Look for non-JavaScript versions or plain-text mirrors
Government sites often have alternate views or legacy versions:
```bash
# Try the "print" or "show all" parameter
curl -sL "https://statutes.capitol.texas.gov/GetStatute.aspx?Code=FI&Value=392&ShowAll=true" -o /tmp/page.html
# Try query parameters the old site might have used
curl -sL "https://statutes.capitol.texas.gov/StatutesByCode.aspx?Code=FI&Value=392" -o /tmp/page.html
# Try different encoding paths
curl -sL "https://statutes.capitol.texas.gov/Docs/FI/word/FI.392.docx" -o /tmp/doc.docx
curl -sL "https://statutes.capitol.texas.gov/Download.aspx?Code=FI&Value=IV.392&type=pdf" -o /tmp/doc.pdf
```
**⚠️ Pitfall**: Some "download" links return HTTP 200 but serve the Angular shell HTML (not the actual DOCX/PDF). Check the file's magic bytes: `head -c 100 /tmp/doc.docx` should start with `PK` (ZIP/DOCX), not `<!DOCTYPE html>`.
### 2. Try third-party legal databases
When the official site is locked behind an SPA, third-party aggregators may have the content in readable form:
| Source | Typical Format | Notes |
|--------|---------------|-------|
| **Justia** (`law.justia.com/codes/texas/...`) | HTML | May have Cloudflare challenge/bot protection |
| **Cornell LII** (`www.law.cornell.edu/statutes/texas/...`) | HTML | URL structure may differ — try searching the site |
| **FindLaw** | HTML | Generally permissive |
| **Casetext** | HTML | May require registration |
| **Hackers & Founders / GitHub** | Plain text / markdown | Community-maintained; may be stale |
```bash
# Fetch a known URL pattern
curl -sL "https://law.justia.com/codes/texas/finance-code/title-4/subtitle-b/chapter-392/" -o /tmp/justia.html
# If blocked by Cloudflare/challenge, check the first 500 bytes:
head -c 500 /tmp/justia.html
# "Just a moment..." = Cloudflare challenge — capture the page and report it
```
### 3. Search for any `<script>` data payloads
Even in an Angular SPA, some content may be embedded in script tags or JSON:
```bash
# Check ng-state (Angular Universal SSR)
grep -oP 'id="ng-state"[^>]*>\K.*?(?=</script>)' /tmp/page.html | python3 -c "
import sys, json
data = json.load(sys.stdin)
for k, v in data.items():
if isinstance(v, dict) and 'b' in v:
for bk, bv in v['b'].items():
# Print first 300 chars of each value
print(f'{bk}: {str(bv)[:300]}')
"
# Check for __NEXT_DATA__ (Next.js, not Angular but worth checking)
grep -oP '__NEXT_DATA__[^>]*>\K.*?(?=</script>)' /tmp/page.html | head -c 2000
# Check for any JSON-like objects with content
grep -oP '\{[^}]{100,}Chapter[^}]*\}' /tmp/page.html | head -5
# Check window.__INITIAL_STATE__
grep -oP 'window\.__INITIAL_STATE__\s*=\s*\K.*?(?=;</script>)' /tmp/page.html | head -c 2000
```
### 4. Probe the backend API
Angular apps often call a REST or JSON API. The backend may still work even if the Angular frontend doesn't render:
```bash
# Common pattern for TX statutes
curl -sL "https://statutes.capitol.texas.gov/api/Statutes/Chapter?code=FI&chp=392" \
-H "Accept: application/json" -o /tmp/api.json
# Try with Referer header (anti-hotlinking)
curl -sL "https://statutes.capitol.texas.gov/api/Statutes/Chapter?code=FI&chp=392" \
-H "Accept: application/json" \
-H "Referer: https://statutes.capitol.texas.gov/Docs/FI/htm/FI.392.htm" \
-o /tmp/api.json
```
If API returns 404, the route may not exist at that path — look for the actual API base URL in the JavaScript bundles (`chunk-*.js`):
```bash
# Search for API paths in JS bundles
grep -oP 'https?://[^"'"'"' ]*api[^"'"'"' ]*' /tmp/page.html | sort -u
grep -oP '/api/[^"'"'"' ]+' /tmp/page.html | sort -u
```
### 5. Render with a headless browser (last resort)
If none of the above works and the content is critical, you need a headless browser (Puppeteer, Playwright) to render the JavaScript and capture the DOM after Angular loads:
```bash
# Not available via curl alone — this is a "requires browser" signal
```
## When to Give Up and Report
Document the blocker honestly rather than fabricating content. Use this template:
> **Data gap**: The [source] is an Angular SPA that loads statute content via an undocumented backend API. The following approaches were attempted and failed:
> - Direct HTML fetch: Only navigation shell, no content (~250KB of CSS/JS, ~84 lines of navigation text)
> - `ng-state` JSON: Contained only metadata (code lists), not statute text
> - Backend API probing: `/api/Statutes/Chapter?code=FI&chp=392` returned 404
> - DOCX/PDF download links: Returned HTTP 200 but served the Angular HTML shell (bot wall)
> - Third-party mirrors: [Justia/Cornell/etc.] had bot protection (Cloudflare challenge)
>
> **Impact**: Statute dates, specific section numbers, and exact wording of [key provisions] could not be independently verified against the live source.
## Summary Decision Tree
```
Is the site an Angular SPA (ng-state, <app-root>, huge HTML + little text)?
├─ YES → Try 1: Legacy/alternate URL patterns (GetStatute.aspx?ShowAll=true)
│ Try 2: Third-party legal aggregators (Justia, Cornell, FindLaw)
│ Try 3: Script data payloads (ng-state, __NEXT_DATA__)
│ Try 4: Backend API probing (look for /api/ paths in JS)
│ Try 5: Report blocker — do NOT fabricate content
└─ NO → Use standard HTML extraction (web-research-fallback core technique)
```