Docs: CSP nonce + strict-dynamic strategy (#158) + v4.9 PLANDOC entry - docs/01-PRODUCT.md: new §3.2 CSP Strategy — current state, target state, transition plan (3-phase), implementation note for nonce sharing - docs/05-PLAN.md: v4.9 CSP nonce + strict-dynamic entry Co-Authored-By: Claude Code deepseek-v4-pro <noreply@taotoken.net>
fix: --status query excludes NOT_FOUND entries from emoji counts Failed enhancements are now cached as status='not_found' to prevent retries. The --status count query must filter status='found' to avoid counting failures as completed enhancements. Co-Authored-By: Claude <noreply@taotoken.net>
fix: cache NOT_FOUND on LLM failure to prevent repeated retries Pages that fail enhancement (LLM returns empty) were not cached, causing them to be retried every batch run, wasting consecutive failure quota and killing processes prematurely. Now failed pages are cached as status='not_found', so the next run's annotation check correctly skips them. Use --rebuild to force retry cached failures. Co-Authored-By: Claude <noreply@taotoken.net>
fix: preg_match_all called before empty() check in splitHtmlIntoSections The heading regex was defined but preg_match_all was placed AFTER the first empty($matches) guard, so $matches was always undefined and the function always returned a single chunk. Also fixed stale variable references ($tag → $headingText, $positions → $matches). Co-Authored-By: Claude <noreply@taotoken.net>
fix: man page heading detection in splitHtmlIntoSections Man pages use <a id="section-NAME"><b>SECTION</b> anchors, not <h1> tags. Previous regex required only ALL_CAPS <b> content, producing 378 false positives. Fixed to require <a id="section-" or <a id="sub-" prefix. Also wired chunked path into batch-enhance.php HTML phase. Co-Authored-By: Claude <noreply@taotoken.net>
fix: wire chunked enhancement into batch-enhance.php HTML path batch-enhance.php called callLLM() directly with full raw HTML, bypassing enhanceManPageChunked(). Now pages > PHPMAN_ENHANCE_CHUNK_THRESHOLD (200KB) are automatically split and enhanced in chunks. Co-Authored-By: Claude <noreply@taotoken.net>
feat: chunked LLM enhancement for large man pages (>200KB) Pages exceeding PHPMAN_ENHANCE_CHUNK_THRESHOLD (default 200KB) are automatically split into sections at h1/h2 heading boundaries, each chunk independently enhanced via callLLM(), then reassembled. Split strategy (failsafe cascade): 1. h1 section boundaries (NAME, SYNOPSIS, DESCRIPTION, etc.) 2. h2 sub-section boundaries within oversized sections 3. Paragraph/block boundaries (</p>, <br>, </li>, </dd>, etc.) 4. Sentence boundaries ($. + ' ') — last resort, never mid-sentence Key guarantees: - Never splits inside <pre>, <table>, <dl> blocks - Parent heading preserved in every chunk for LLM context - Failed chunks fall back to original HTML (graceful degradation) - Each chunk capped at PHPMAN_ENHANCE_MAX_CHARS (32KB) Co-Authored-By: Claude <noreply@taotoken.net>
docs: add architectural paradox — data sources are already CLI tools The man/perldoc/info/ri/pydoc3 data sources already have CLI interfaces. phpMan's web layer (HTML rendering, format negotiation, emoji enhance) is redundant for LLM Agent use cases. The only irreplaceable value: TLDR cheatsheets + cross-mode FTS5 search. Co-Authored-By: Claude <noreply@taotoken.net>
docs: strategic review — phpMan value in the LLM era (GEO/MCP/SEO analysis) Key findings from production access log: - AI bots prefer MCP/markdown over HTML (78-86% structured format choice) - MCP is GPTBot's #1 format (437 > markdown 413 > html 297) - Traditional SEO failed — Googlebot only 23 phpMan requests - LLM emoji enhancement cost: ~¥2,170 total (), marginal value - phpMan's strategic value shifted: human web viewer → AI agent API Co-Authored-By: Claude <noreply@taotoken.net>
fix: deterministic PID file naming for multi-mode parallel batch-enhance Problem: restarting a batch process didn't clean up the old one because PID file paths weren't derived from the same option combination. Manual 'rm pidfile && nohup ...' bypassed the startup guard, creating duplicate processes for the same mode. Changes: - buildPidFilePath(mode, format) — canonical path for any option combo - 15 unique PID files: 5 modes × 3 formats (both/html/md) - --force flag: auto-kills existing process with same PID file - --yes also enables auto-cleanup (batch/cron friendly) - --restart + --mode=man auto-finds /tmp/bm.pid (no need --pid-file) - Old error message now suggests --force as an option PID file naming: --mode=man → /tmp/bm.pid --mode=man --format=html → /tmp/bm_html.pid --mode=ri --format=md → /tmp/br_md.pid --pid-file=/custom.pid → /custom.pid (explicit wins) Co-Authored-By: Claude <noreply@taotoken.net>