Merged
Conversation
Adds a CI guard that fails immediately if a PR targets production from any branch other than main. Combined with the branch protection rule (requiring CI to pass) this prevents the production/main drift that required manual reconciliation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…b-shadowban-check (#1706) Root causes: - snapshot-retention: used WIKI_SERVER_API_KEY (project-scoped) to call DELETE endpoints that require `content` scope — resulting in 403 errors. Fixed by using LONGTERMWIKI_CONTENT_KEY (content-scoped) with fallback to LONGTERMWIKI_SERVER_API_KEY (legacy superkey that grants all scopes). - github-shadowban-check: hardcoded "quri-bot" which does not exist on GitHub. Every run returned 404 → interpreted as "banned" → success: false. Fixed by defaulting to empty usernames and reading from TASK_GITHUB_SHADOWBAN_CHECK_USERNAMES env var (comma-separated). Closes #1616 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
#1703) The integrity check in fetchIntegritySummary() was counting edit_logs and citation_quotes with page_id_int IS NULL as dangling references. But records from before the Phase D / Phase 4a migration have page_id_old (text) populated and page_id_int NULL — these are migration artifacts, not data corruption. Fix: only flag records where BOTH page_id_old AND page_id_int are NULL (truly orphaned). This eliminates ~54 false positives from the System Health dashboard (E927), restoring trust in its integrity counts. Closes #1615 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1708) The citation dot overlays were completely dark in production because buildCitationQuotesBundle() still read from the old citationQuotes table while all new data is written to statement_citations/statementPageReferences. - Add GET /api/statements/citation-dots/all endpoint that joins statementPageReferences → statements → statementCitations → resources and returns data grouped by page slug, mapping statement verdicts to AccuracyVerdict values (verified→accurate, disputed→inaccurate, etc.) - Add buildStatementCitationDots() in build-data.mjs that fetches from the new endpoint and stores results as database.statementCitationDots - Add statementCitationDots field to DatabaseShape and getStatementCitationDots() getter in data/index.ts - Add getStatementCitationQuotes(pageId, referenceMap) in citation-data.ts that bridges footnoteResourceId strings to numeric footnote numbers via the referenceMap produced by renderMdxPage() - Merge statement quotes with legacy quotes in page.tsx; statement data takes precedence for any footnote it covers, legacy fills the rest Closes #1598 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntion (#1711) Adds both a _ignoreCommandNote JSON key and an inline bash comment to explain that Vercel's ignoreCommand uses inverted exit codes (exit 1 = BUILD, exit 0 = SKIP), which is the opposite of Unix convention. This was gotten wrong 4 times across PRs #1586, #1611, #1630. Closes #1659 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#1697) - Add `.finite()` to all numeric fields in CreateStatementBody, PatchStatementBody, BatchScoreBody, CoverageScoreBody, and QualityDimensionsSchema — rejects Infinity/-Infinity (NaN was already rejected by Zod's number type) - Add `.min(1)` to all optional nullish string fields in CreateStatementBody and PatchStatementBody — rejects empty strings (`""`) that would store junk data in the DB - Add `.min(1)` to ListQuery entityId/propertyId filter params to prevent empty-string filter queries - Export CreateStatementBody and PatchStatementBody for unit testing - Add 40 new tests in statements-boundary-validation.test.ts covering all three failure modes from issue #1647 Root cause fix for the 5-PR junk-data chain (#1606, #1607, #1608, #1620, #1623): Infinity values and empty strings could previously be stored in the statements table because the Zod schemas lacked `.finite()` and `.min(1)` constraints on optional fields. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…y fixed (#1713) * docs: add comments to Vercel ignoreCommand explaining exit code convention Adds both a _ignoreCommandNote JSON key and an inline bash comment to explain that Vercel's ignoreCommand uses inverted exit codes (exit 1 = BUILD, exit 0 = SKIP), which is the opposite of Unix convention. This was gotten wrong 4 times across PRs #1586, #1611, #1630. Closes #1659 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(sessions): add fix-chain tracking to link fix PRs to the PRs they fixed Implements GitHub issue #1669. Agents can now record when a PR is fixing regressions from a previous PR, enabling fix rate computation and traceability. **Database changes:** - Add `pr_outcome` column to `agent_sessions` (merged | merged_with_revisions | reverted | closed_without_merge) - Add `fixes_pr_url` column to `agent_sessions` to store the URL of the PR being fixed **API changes (wiki-server):** - Export `PR_OUTCOMES` constant and `PrOutcome` type from `api-types.ts` - Update `UpdateAgentSessionSchema` to accept `prOutcome` and `fixesPrUrl` - Update PATCH /:id route to handle the new fields - Add GET /stats endpoint returning `{ total, fixSessions, fixRate }` **CLI changes (crux):** - `crux issues done <N> --fixes-pr=<URL>` records the fix-chain relationship - `crux issues done <N> --outcome=<outcome>` records PR outcome - When `--fixes-pr` is used, posts a comment on the original PR noting the fix - Session is updated with `fixesPrUrl` and `prOutcome` via wiki-server **Dashboard changes:** - Agent Sessions table shows "Fixes" column (orange link to the PR being fixed) - Agent Sessions table shows "Outcome" column with color-coded badges - Dashboard header shows fix session count and fix rate when > 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1712) Addresses the silent CI failure mode observed March 2-4, 2026: when main branch CI stops producing results entirely (e.g. YAML syntax errors), the existing checkActions() doesn't alert because it only checks the most-recent completed run — if there are no runs, nothing fires. New check (crux health --check=ci-main): - Queries GitHub API for ci.yml runs on main branch in last 24h - Alerts if: 0 runs triggered (workflow may be broken or no pushes) - Alerts if: runs exist but 0 succeeded (all failed/cancelled) - Passes if: at least one successful run or a run is in-progress - Integrated into the twice-daily wellness-check.yml workflow via the existing --report --auto-issue pipeline, which creates/updates/ closes GitHub issues automatically Also fixes a gap where health/**/*.ts and health/**/*.test.ts were not included in crux/tsconfig.json or crux/vitest.config.ts, meaning the existing pr-quality.test.ts and wellness-report.test.ts were also being skipped by the test runner. Closes #1651 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ws (#1707) Replaces the monolithic wellness-check.yml with three focused workflow files: - server-api-health.yml: Server & DB health + API smoke tests - frontend-data-health.yml: Frontend availability + data freshness - ci-pr-health.yml: GitHub Actions health + job queue + PR quality + label cleanup Each workflow runs independently, uses the same twice-daily schedule, and manages the wellness GitHub issue via --auto-issue. All 7 checks from the original are preserved with identical logic (no changes to crux/health/). Updates .claude/audits.yaml to reference the new workflow file names. Updates comments in crux/health/ and crux/commands/ to reference new files. Closes #1667 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(statements): add property upsert endpoint and seed-properties command
- POST /properties/upsert: batch create/update properties in wiki-server
- crux statements seed-properties: seeds 25 properties for 5 missing
categories (governance, technical, research, products, people)
- These categories are defined as coverage targets but had zero properties,
causing the improve pipeline to generate nothing for them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(json-parsing): handle JSON arrays in LLM response parsing
parseJsonFromLlm looked for the first `{` brace, finding the first
object inside an array and returning only that single object. This
broke the improve pipeline which expects a JSON array.
Now checks for `[` first — if the array bracket comes before any
object brace, it extracts the complete array. This fixes the improve
pipeline generating 0 statements despite valid LLM output.
Also improved batch insert error messages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#1699) * feat: add session-sweep groundskeeper task to auto-expire stale agent sessions Adds a new `session-sweep` task to the groundskeeper that runs every 4 hours and automatically marks stale active sessions (not updated in 4+ hours) as completed. Also removes the `claude-working` label from any closed GitHub issues that were linked to swept sessions, fixing phantom active sessions and stale labels (#1664). Changes: - apps/groundskeeper/src/tasks/session-sweep.ts: new task calling POST /api/agent-sessions/sweep and cleaning up claude-working labels - apps/groundskeeper/src/config.ts: adds sessionSweep task config with TASK_SESSION_SWEEP_ENABLED and TASK_SESSION_SWEEP_SCHEDULE env vars - apps/groundskeeper/src/index.ts: registers session-sweep task on startup - apps/wiki-server/src/routes/agent-sessions.ts: sweep endpoint now returns issueNumber so groundskeeper can clean up labels - Test files: update Config mocks in all existing tests to include sessionSweep - apps/groundskeeper/src/tasks/session-sweep.test.ts: 10 unit tests covering sweep endpoint call, label cleanup, deduplication, error handling Closes #1664 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: resolve E1007 numericId conflict between statement dashboards statement-quality-dashboard and statement-scores-dashboard both had numericId E1007, causing build-data to fail with a conflict error. Reassign statement-quality-dashboard to E1008 (the next unused ID). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove stale computeDiffHash tests after hash check was removed The c4ebc2e commit removed the diff-hash feature from validate-review-marker.ts but left the test file importing the now-non-existent computeDiffHash function. Remove the stale describe block to fix the TypeScript compilation error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sessions): add numeric costCents and durationMinutes fields for aggregation Closes #1666 - Add DB migration 0060 adding cost_cents (INTEGER) and duration_minutes (REAL) to sessions table - Add costCents and durationMinutes fields to CreateSessionSchema Zod validation - Add parseCostCents() and parseDurationMinutes() exported functions to sessions route that parse free-text strings like "~$2.50" → 250 and "~45 minutes" → 45.0 - Auto-parse numeric values on write if not explicitly provided; explicit values take precedence over auto-parsed - Update sessionValues(), mapSessionRow(), and sessionConflictSet to handle new fields - Add 24 new tests: 10 parser unit tests, 14 integration tests - Update agent-sessions dashboard to show aggregate cost when data available - Existing free-text cost/duration fields unchanged for backwards compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: extract shared fetchAllPaginated helper for API pagination Replace 4 duplicate pagination implementations with a single shared helper in apps/web/src/lib/fetch-paginated.ts. Key improvements: - Fails on intermediate page errors instead of silently returning partial data - Fetches remaining pages in parallel after first page determines total - Configurable page size, deadline, timeout, and extra query params - Console warning when multi-page fetching triggers Refactored consumers: - statements-content.tsx (internal dashboard) - property-explorer-content.tsx (internal dashboard) - statements/page.tsx (statements explorer) - claims-data.ts (claims pages) Closes #1650 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…aggregation (#1715) * feat(sessions): add numeric costCents and durationMinutes fields for aggregation Closes #1666 - Add DB migration 0060 adding cost_cents (INTEGER) and duration_minutes (REAL) to sessions table - Add costCents and durationMinutes fields to CreateSessionSchema Zod validation - Add parseCostCents() and parseDurationMinutes() exported functions to sessions route that parse free-text strings like "~$2.50" → 250 and "~45 minutes" → 45.0 - Auto-parse numeric values on write if not explicitly provided; explicit values take precedence over auto-parsed - Update sessionValues(), mapSessionRow(), and sessionConflictSet to handle new fields - Add 24 new tests: 10 parser unit tests, 14 integration tests - Update agent-sessions dashboard to show aggregate cost when data available - Existing free-text cost/duration fields unchanged for backwards compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(sessions): correct migration 0062 journal timestamp to be strictly increasing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ents (#1716) * feat(statements): add property upsert endpoint and seed-properties command - POST /properties/upsert: batch create/update properties in wiki-server - crux statements seed-properties: seeds 25 properties for 5 missing categories (governance, technical, research, products, people) - These categories are defined as coverage targets but had zero properties, causing the improve pipeline to generate nothing for them Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(json-parsing): handle JSON arrays in LLM response parsing parseJsonFromLlm looked for the first `{` brace, finding the first object inside an array and returning only that single object. This broke the improve pipeline which expects a JSON array. Now checks for `[` first — if the array bracket comes before any object brace, it extracts the complete array. This fixes the improve pipeline generating 0 statements despite valid LLM output. Also improved batch insert error messages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(statements): resolve quality mode bugs found during testing - Fix by-entity response format: use [...structured, ...attributed] instead of .statements (quality mode crashed immediately) - Re-export analyzeGaps() from gaps.ts (lost during main merge) - Add normalizeValueDate() to convert partial dates (2024, 2024-06) to valid ISO dates — PostgreSQL date columns reject partial strings - Validate propertyId against property vocabulary before insert (FK constraint rejects IDs the LLM invents) - Include actual API error message in quality mode rejection reasons Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(statements): add classify mode and propertyId PATCH support - Add --mode=classify to improve pipeline: batch-classifies uncategorized statements by assigning propertyId via LLM (uses Haiku, ~$0.008/entity) - Add propertyId to PATCH endpoint schema (PatchStatementBody + handler) - Add propertyId to PatchStatementInput client type - Update CLI help to show --mode=quality|classify Tested on Anthropic entity: classified 36/36 uncategorized statements, structure dimension score improved 0.560 → 0.683. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add classify mode to statements help text Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(statements): show 0 instead of ? for empty classify remaining count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(statements): score active-only, validate entity, expand property vocab - Score command now filters to active statements with non-empty text, fixing inflated counts and artificially low quality scores - Improve pipeline now validates entity exists before spending LLM budget - Classify rejection messages now distinguish null (no match) from invalid property IDs (vocabulary gap) - Added 6 new properties: executive-compensation, operating-expenses, net-income, net-assets, risk-assessment, award Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(statements): move coverage-scores routes before /:id wildcard The GET /:id wildcard route was intercepting /coverage-scores and /coverage-scores/all requests, causing "Statement ID must be a positive integer" errors. Moved these routes before the wildcard so they match first. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(statements): auto-classify before gap-filling in improve pipeline When runSinglePass detects uncategorized statements, it automatically runs classify (cheap Haiku call) before analyzing gaps. This ensures accurate coverage numbers and prevents wasting Sonnet budget on categories that are already covered after classification. Tested on redwood-research: 15 uncategorized statements classified, coverage went from 0.330 → 1.000 in 2 passes (was 7+ without classify). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ol (#1719) * feat: add structured JSONL logging and periodic reflection to PR Patrol - Log every PR fix result and cycle summary to ~/.cache/pr-patrol/runs.jsonl with structured fields (pr_num, issues, result, elapsed, cycle_number) - Every 10 cycles, spawn a Claude reflection session that analyzes the last 100 log entries for recurring patterns and optionally files a GitHub issue - Reflection results logged separately to ~/.cache/pr-patrol/reflections.jsonl - Fix summary truncation bug (tail -c 1500 | head -c 500 took a random middle slice, now uses tail -c 500 for the actual last 500 chars) - Configurable via PR_PATROL_REFLECTION_INTERVAL env var (default: 10) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review feedback - Validate REFLECTION_INTERVAL is a positive integer to prevent modulo-by-zero arithmetic errors in the reflection loop - Filter empty strings from jq split(",") to avoid spurious [""] in JSONL logs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…rds (#1624) * feat(security): add SafeExternalLink component to centralize URL safety guards - Create apps/web/src/lib/url-utils.ts with isSafeUrl() utility - Create apps/web/src/components/ui/safe-external-link.tsx wrapping isSafeUrl validation + target=_blank rel=noopener noreferrer in one component - Migrate all 4 files using the duplicated isSafeUrl+<a> pattern: CitationOverlay, FootnoteTooltip, InlineCitationCards, citation-detail - Remove 3 copy-pasted isSafeUrl definitions and 1 getDomain duplicate - Re-export isSafeUrl from CitationOverlay for backward compatibility - Update citation-data.test.ts to import from url-utils directly Closes #1621 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: remove dead isSafeUrl re-export, consolidate getDomain in citation-detail - Remove dead re-export of isSafeUrl from CitationOverlay (no consumers remain) - Replace local getDomain copy in citation-detail.tsx with import from resource-utils Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove duplicate isSafeUrl/getDomain imports in FootnoteTooltip Leftover stale import line from merge caused TS2300 duplicate identifier errors. Remove the redundant `import { getDomain, isSafeUrl } from "./resource-utils"` since both are already imported individually above. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: show clear warning when AUTOMATION_PAUSED skips workflows
All 15 workflows that check AUTOMATION_PAUSED now:
- Show [PAUSED] in the GitHub Actions run name
- Run a paused-notice job with a ::warning annotation explaining
how to resume
Also adds CLI commands:
- `pnpm crux ci pause-automation` — set AUTOMATION_PAUSED
- `pnpm crux ci unpause-automation` — delete AUTOMATION_PAUSED
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract paused-notice job into reusable workflow
Replace the 7-line inline paused-notice job block duplicated across
15 workflow files with a single reusable workflow (_paused-notice.yml).
Each workflow now calls it with a 2-line `uses:` reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* rename: pause-automation → pause-actions, unpause → resume-actions
Use GitHub's own terminology ("Actions") and more natural "resume"
instead of "unpause".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…1696) * feat: add data quality assertions to statements extraction pipeline Adds a new `validate-quality.ts` module with three core exports: - `validateExtractedStatements()` — checks post-LLM extraction output - `validateCreateStatementBatch()` — checks pre-DB-write batch - `printQualityReport()` — color-coded CLI reporter Assertion checks: - ZERO_STATEMENTS: no statements from a page with ≥2 sections - EMPTY_STATEMENT_TEXT: blank statement text strings - NON_FINITE_NUMERIC: NaN or Infinity in numeric values - ALL_ZERO_NUMERIC: all-zero batch when ≥3 numeric values (suggests extraction failure) In dry-run mode, violations are warnings (logged but not blocking). In apply mode (--apply flag), violations abort before any DB writes. Integration points: - `extract.ts`: validates after FK sanitization, before dry-run/apply split - `improve.ts`: validates accepted statements before `createStatementBatch()` Closes #1653 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: restore E1008 numericId for statement-quality-dashboard (conflict with E1007) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review feedback on data quality assertions - Add validateCreateStatementBatch call in runQualityPass (improve.ts) before createStatementBatch to close the quality gate bypass - Add DUPLICATE_TUPLE detection in validateCreateStatementBatch for items with the same (subjectEntityId, propertyId, valueDate) key - Add tests for printQualityReport dry-run and apply-mode CLI branches - Add tests for DUPLICATE_TUPLE detection and non-duplicate cases Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents agents from creating new bash scripts when TypeScript in crux/ is the better choice. Exceptions: git hooks, Claude Code hooks, and CI glue where Node.js isn't available. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(statements): add property upsert endpoint and seed-properties command
- POST /properties/upsert: batch create/update properties in wiki-server
- crux statements seed-properties: seeds 25 properties for 5 missing
categories (governance, technical, research, products, people)
- These categories are defined as coverage targets but had zero properties,
causing the improve pipeline to generate nothing for them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(json-parsing): handle JSON arrays in LLM response parsing
parseJsonFromLlm looked for the first `{` brace, finding the first
object inside an array and returning only that single object. This
broke the improve pipeline which expects a JSON array.
Now checks for `[` first — if the array bracket comes before any
object brace, it extracts the complete array. This fixes the improve
pipeline generating 0 statements despite valid LLM output.
Also improved batch insert error messages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(statements): resolve quality mode bugs found during testing
- Fix by-entity response format: use [...structured, ...attributed]
instead of .statements (quality mode crashed immediately)
- Re-export analyzeGaps() from gaps.ts (lost during main merge)
- Add normalizeValueDate() to convert partial dates (2024, 2024-06)
to valid ISO dates — PostgreSQL date columns reject partial strings
- Validate propertyId against property vocabulary before insert
(FK constraint rejects IDs the LLM invents)
- Include actual API error message in quality mode rejection reasons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(statements): add classify mode and propertyId PATCH support
- Add --mode=classify to improve pipeline: batch-classifies uncategorized
statements by assigning propertyId via LLM (uses Haiku, ~$0.008/entity)
- Add propertyId to PATCH endpoint schema (PatchStatementBody + handler)
- Add propertyId to PatchStatementInput client type
- Update CLI help to show --mode=quality|classify
Tested on Anthropic entity: classified 36/36 uncategorized statements,
structure dimension score improved 0.560 → 0.683.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: add classify mode to statements help text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(statements): show 0 instead of ? for empty classify remaining count
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(statements): score active-only, validate entity, expand property vocab
- Score command now filters to active statements with non-empty text,
fixing inflated counts and artificially low quality scores
- Improve pipeline now validates entity exists before spending LLM budget
- Classify rejection messages now distinguish null (no match) from
invalid property IDs (vocabulary gap)
- Added 6 new properties: executive-compensation, operating-expenses,
net-income, net-assets, risk-assessment, award
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(statements): move coverage-scores routes before /:id wildcard
The GET /:id wildcard route was intercepting /coverage-scores and
/coverage-scores/all requests, causing "Statement ID must be a
positive integer" errors. Moved these routes before the wildcard
so they match first.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(statements): auto-classify before gap-filling in improve pipeline
When runSinglePass detects uncategorized statements, it automatically
runs classify (cheap Haiku call) before analyzing gaps. This ensures
accurate coverage numbers and prevents wasting Sonnet budget on
categories that are already covered after classification.
Tested on redwood-research: 15 uncategorized statements classified,
coverage went from 0.330 → 1.000 in 2 passes (was 7+ without classify).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(statements): add entity ideation + ontology skills + statement reassignment
Add `crux statements ideate` command for analyzing entity statements and
suggesting sub-entity splits via LLM. Add `subjectEntityId` to PATCH
endpoint to enable statement reassignment between entities. Add
`includeChildren` query parameter for roll-up queries across related entities.
Create three Claude Code skills for deep ontology reasoning:
- /ontology-review — analyze entity structure and suggest splits
- /entity-deep-dive — comprehensive single-entity quality review
- /knowledge-gap — identify missing topics in the knowledge base
Applied to Anthropic: created claude entity, moved 16 statements to it,
reassigned 14 statements to constitutional-ai, responsible-scaling-policies,
sleeper-agents, deceptive-alignment, and long-term-benefit-trust. Updated
Anthropic's relatedEntries with 7 missing relationships.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: use valid relationship types in Anthropic relatedEntries
Replace policy-of, product-of, governance with valid enum values
(composed-of, related) to pass schema validation gate check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(statements): add coverage targets for approach, concept, policy, risk, project types
Enable the improve pipeline to work on non-organization entity types.
Previously only organization, person, and model had coverage targets.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…test (#1730) - crux/statements/improve.ts: duplicate function declaration of normalizeValueDate was introduced in #1723 causing esbuild transform failure; remove the second copy (identical to the first) - crux/statements/coverage-targets.test.ts: 'concept' was added to TARGETS in #1723; update the "unknown entity type" tests to use 'widget' which truly has no coverage targets Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: increase auto-update timeout and align scheduled count default The auto-update job has been hitting the 60-minute job timeout for 3 consecutive days (run IDs 22705771773, 22660285330, 22618059745). Root cause: each page improvement takes ~10-12 minutes, setup/install/ build-data takes ~18 minutes, so 5 pages * 12 min + 18 min overhead = ~78 minutes — well over the 60-minute limit. Two changes: 1. Increase `timeout-minutes` from 60 to 120 to give the job enough headroom to complete all pages. 2. Align the scheduled run default count (`|| '5'`) with the `workflow_dispatch` UI default (which was already '3'). This reduces the scheduled wall time to ~54 min (3 pages * 12 min + 18 min), comfortably within the new 120-minute limit. Closes #1725 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use >| (force-overwrite) for /tmp writes to prevent zsh noclobber stale reads In push-and-ensure-green.md, Option B showed `cat > /tmp/pr-body.md` which silently fails under zsh noclobber if the file already exists, causing the agent to read stale file content. Replace with `cat >| /tmp/pr-body.md` and add a warning comment. pr-review-guidelines.md already correctly documents this issue as "BAD" pattern. Closes #1701 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1729) The auto-update job has been hitting the 60-minute job timeout for 3 consecutive days (run IDs 22705771773, 22660285330, 22618059745). Root cause: each page improvement takes ~10-12 minutes, setup/install/ build-data takes ~18 minutes, so 5 pages * 12 min + 18 min overhead = ~78 minutes — well over the 60-minute limit. Two changes: 1. Increase `timeout-minutes` from 60 to 120 to give the job enough headroom to complete all pages. 2. Align the scheduled run default count (`|| '5'`) with the `workflow_dispatch` UI default (which was already '3'). This reduces the scheduled wall time to ~54 min (3 pages * 12 min + 18 min), comfortably within the new 120-minute limit. Closes #1725 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: allow merge commits to not invalidate review-done marker Add onlyMergeCommitsSince() helper to validate-review-marker.ts that uses --first-parent git log to check whether all commits between the reviewed SHA and HEAD are merge commits. If they are, the marker is still considered valid — merging main into a feature branch to resolve conflicts should not require a re-review. Non-merge commits (new code authored on the branch) still invalidate the marker as before. Also handles the edge case where the marker SHA is not an ancestor of HEAD (rebase/force-push) by failing closed. Closes #1695 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: update tests to call onlyMergeCommitsSince() directly and add cwd param - Add optional `cwd` parameter to onlyMergeCommitsSince() so tests can inject a temp repo directory instead of always running against PROJECT_ROOT - Rewrite onlyMergeCommitsSince tests to import and call the function directly, asserting its return value (true/false) rather than testing raw git commands separately - Fix tautological expect(sha).toBe(sha) assertion — now calls the function with sha === sha to verify the early-exit path returns true - Add a new test case: returns false when markerSha is not an ancestor of headSha (rebase/force-push scenario) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1705) - Replace hard-coded /api/statements?limit=500 in statements-content.tsx with a paginating fetchAllStatementsPaginated() helper that fetches all pages (each up to 500 rows) — prevents dashboard table truncation and wrong entity-count stats when total exceeds 500 - Replace hard-coded /api/statements?limit=200 in property-explorer-content.tsx with the same paginating approach — prevents wrong entity-to-property coverage counts when total exceeds 200 - Raise /insights endpoint in sessions.ts from hard-coded .limit(500) to INSIGHTS_LIMIT=5000 with a console.warn when the limit is hit — prevents silent insight truncation; a warning flags when pagination is needed Both web fixes log a console.warn when multi-page fetching is required so operators can see when data volumes are growing. Closes #1650 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Detailed analysis of Anthropic statements pages identifying 32 issues across data quality, UX, missing features, and architecture. Includes design mockups and a prioritized 5-phase fix roadmap. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Snapshot component: - Replace alarming "conflicting properties" with "multiple open values" - Remove amber background highlighting and warning triangle icons - Change "(also: $14B)" to "(prev: $14B [2026-02])" with dates - Sort previous values by date descending - Improve qualifier label formatting (strip prefix, replace hyphens) PATCH endpoint: - Add qualifierKey to PatchStatementBody schema and handler - Previously PATCH silently ignored qualifierKey updates Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add actionlint gate check for GitHub Actions workflow YAML Closes #1646 - Add crux/validate/validate-actions-yaml.ts: runs actionlint on all .github/workflows/*.yml files, gracefully skips when actionlint is not installed (local dev), blocking when installed. - Register the check in validate-gate.ts as a blocking parallel step. - Add Install actionlint + actionlint blocking step to .github/workflows/ci.yml. - Fix pre-existing injection risk in ci.yml (github.head_ref used directly in shell — actionlint [expression] finding). Replaced with env var HEAD_REF. - shellcheck style/info suggestions (SC*:info, SC*:style) are excluded via -shellcheck= flag so only real actionlint structural errors block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use official download-actionlint script to fix gzip install failure The previous install command used /releases/latest/download/ redirect URLs piped directly to tar, which fails with "gzip: stdin: not in gzip format" because GitHub's redirect responses are not handled correctly in piped curl. Replace with the official download-actionlint script which handles platform detection and the redirect properly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use gh release download for actionlint install (curl URL returns 404) The download-actionlint script URL returned a 404 page and the /releases/latest/download/ redirect returned non-gzip HTML. Using `gh release download` which handles GitHub API auth and redirects reliably. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use import.meta.url for main script detection in validate-actions-yaml Replace process.argv[1]?.includes('validate-actions-yaml') with the more robust ESM-idiomatic check process.argv[1] === fileURLToPath(import.meta.url). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the full standalone /statements/entity/[entityId] page with a redirect to /wiki/[numericId]/statements, consolidating two different views of the same data into a single canonical URL (the wiki tab). This addresses discussion #1736 item 2.1. Old links and internal references to /statements/entity/... will transparently redirect. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Record verification results for post-merge items and ongoing audits: - PR #1630: Vercel production-only builds — verified - PR #1637: Audits system end-to-end — verified - Ongoing: ci-gate-catches-regressions, audits-system-adoption, vercel-production-only — all passing Also reviewed PR #1707 (wellness-check split), #1710 (AUTOMATION_PAUSED), #1708 (citation dots), #1704 (issue-responder disabled), #1712 (CI alerting) — all confirmed working in production. https://claude.ai/code/session_012gfpYecbR2ZdkHAiobzBj3 Co-authored-by: Claude <noreply@anthropic.com>
- Standalone page: replace misleading "Total" (included retracted) with "Active"; rename labels to "Structured"/"Attributed"; "With Citations" now counts only active statements - Wiki tab: replace redundant "Active Cited" with "Retracted" count; rename "Active Structured/Attributed" to "Structured/Attributed" - Add brief intro text on both pages explaining what structured vs attributed statements are - Add "rose" color option to StatCard component Addresses discussion #1736 items 2.7 and 2.10. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
) The internal Statements dashboard (E1002) and Property Explorer dashboard (E1004) were redundant with the richer public pages at /statements and /statements/properties. The public pages have better filtering, navigation, and visual design. - Sidebar now links directly to /statements and /statements/properties - Internal redirects updated to point to public pages - Removed unused content components, table components, and MDX stubs - Cleaned up mdx-components.tsx registrations - Updated wiki-nav test to reflect new linking pattern https://claude.ai/code/session_014ajohoZ9vfQ7zskBvScfpR Co-authored-by: Claude <noreply@anthropic.com>
…ic (#1751) - Both server and client csvEscape now quote cells starting with =, +, -, @, \t, \r to defend against CSV injection attacks in Excel/Google Sheets - Sanitize entityId in Content-Disposition headers to prevent header injection - Client statementToFlatValue now handles valueNumeric (matching server formatValue) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: improve statements page UX (discussion #1736) - Extract formatPeriod to shared statement-display.ts with human-readable dates (Mar 2026 instead of 2026-03) - Hide Verdict column when >90% of statements are unverified - Hide inactive/retracted statements by default on standalone entity page - Hide empty categories, collapse uncategorized by default - Fix qualifier display leaking raw text into values (suppress non-prefix qualifiers like "per-share-tender") - Show qualifier context in Property column as "(qualifier)" - Add qualifierKey to PATCH schema (from PR #1737) - Soften conflict display: "prev:" with dates instead of "also:" with amber warnings - Label sidebar category counts as "(all entities)" Closes #1736 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove duplicate qualifierKey field in PatchStatementBody schema Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ead of rejecting batch (#1760) The facts sync endpoint rejected the entire batch of 144 facts when any subject value (like "industry-average") didn't match a real entity. This has been blocking the Sync Entities & Facts workflow since the subject validation was added in b40dbf9. Now warns and nulls out unresolved subjects so the rest of the batch syncs successfully. Closes #1759 https://claude.ai/code/session_01GxwyPf2Q2xcCFuka8rGpR2 Co-authored-by: Claude <noreply@anthropic.com>
…c.) (#1753) Extends PR Patrol to surface unresolved bot review comments as actionable issues, using the existing single GraphQL call (no extra API request). Changes: - Extend PR_QUERY to fetch reviewThreads (resolved/outdated status, path, line, comment body/author) alongside status checks - Add extractBotComments() — filters to unresolved, non-outdated threads from known bot logins (coderabbitai, dependabot, renovate, github-actions) - Add two new PrIssueType values: bot-review-major (score 55) and bot-review-nitpick (score 15), classified by ACTIONABLE_SEVERITY_RE - Inject bot comment bodies into the fix prompt with file/line context, truncated at 2000 chars each to keep prompts manageable - Update pr-patrol.md skill doc to reflect the new issue type Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create shared CommandOptions type in crux/lib/command-types.ts and update 14 command files to use it instead of duplicated declarations - Centralize wiki-server timeout constants in crux/lib/config.ts, replacing duplicated values in client.ts and sync-common.ts - Fix crux/README.md: remove duplicate edit-log entry, add 27 missing domain references, update page count from ~625 to ~660 - Fix --no-limit flag in issues create (kebab-case wasn't recognized after crux.mjs converts to camelCase) Closes #1754 Closes #1756 Closes #1757 https://claude.ai/code/session_01RK5QvhtkMzMqoxFNEHLE1j Co-authored-by: Claude <noreply@anthropic.com>
Resolves conflicts between main and origin/production to fix PR #1763. Conflict resolutions: - .github/workflows/ci.yml: kept HEAD (env var approach for shell safety) - apps/web/vercel.json: kept HEAD (includes github.enabled:false from #1739) - apps/wiki-server/src/routes/statements.ts: kept HEAD (qualifierKey schema, /export endpoint); removed duplicate qualifierKey line (merge artifact) - Deleted property-explorer-content.tsx + statements-content.tsx (consolidated in #1749) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ft (#1782) * fix: derive test mock types from Drizzle schema to prevent column name drift 5 wiki-server test files had hardcoded column name strings in their in-memory store type definitions. Every schema migration that renames a column broke these mocks, causing cascading CI failures (PR #1609 had 30+ failures from this exact problem). Fix: replace hardcoded field definitions with TypeScript types derived from the Drizzle schema using \`typeof table.\$inferSelect\`. TypeScript now catches column renames at compile time — if a migration renames a field, the type error surfaces immediately rather than as a runtime test failure. Key changes per file: - hallucination-risk.test.ts: HrsRow = typeof hallucinationRiskSnapshots.\$inferSelect - edit-logs.test.ts: EditLogRow = typeof editLogs.\$inferSelect - citations.test.ts: QuoteRow/SnapshotRow/ContentRow from respective schema tables - auto-update-runs.test.ts: RunRow/ResultRow from autoUpdateRuns/autoUpdateResults - auto-update-news.test.ts: RunRow/NewsRow from autoUpdateRuns/autoUpdateNewsItems All stores now use camelCase Drizzle field names (matching \$inferSelect) with toSqlRow() helpers to produce the snake_case objects the dispatch functions need to return for the mock SQL layer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): remove unused rest variable in auto-update-news dispatch The destructured `rest` variable was never used after the PR migration to camelCase stores. The `newsToSqlRow()` call now directly receives `r` instead of `{ ...r }` (same result), and the redundant destructuring is removed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude was hitting the 30-turn limit during daily maintenance sweeps, causing `claude-code-action` to fail with `error_max_turns`. Observed in runs 22649707498 (2026-03-04) and 22708103847 (2026-03-05). Raise --max-turns 30 → 60 and timeout-minutes 30 → 60 to give the maintenance sweep enough budget to complete daily tasks. Root cause investigation for issue #1745: - server-health-monitor.yml: historical push-triggered failures from when YAML had syntax errors (fixed in #1587). No scheduled runs exist yet because the weekly Monday schedule hasn't fired since the YAML was last fixed (2026-03-05, next Monday is 2026-03-09). - auto-update.yml: timeout-minutes: 60 caused 60-min cancellations. Already fixed in main via PR #1728 (timeout-minutes: 120). - scheduled-maintenance.yml: max-turns: 30 too low, fixed here. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… drift detection (#1781) * feat(ci): add PR size warning (non-test additions) and Drizzle schema drift detection PR size warning (#1685): - Update pr-size-check.yml to filter out test files, wiki content, snapshots, and lockfiles before counting additions - Now checks non-test infrastructure additions (threshold: 500) instead of total additions+deletions, matching the issue's intent - Adds git checkout step with fetch-depth: 0 to enable per-file diff - Comment now shows both non-test and total additions for context Drizzle schema drift detection (#1686): - Add crux/validate/validate-schema-drift.ts with two modes: - PR mode (BASE_SHA/HEAD_SHA): warns if schema.ts changed without a new migration file being added or modified - Local/structural mode: runs drizzle-kit check to compare schema.ts against migration journal snapshots (no DB required) - Add "Drizzle schema drift detection (advisory)" step to ci.yml, runs on pull_request events with continue-on-error: true - Catches the class of bug from PR #1570 (migration 0052 journal desync) Both checks use ::warning:: annotations — advisory only, never blocking. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): fix shallow-clone false-negative in schema drift check and remove dead pr API call Three bugs found during code review: 1. **False-negative in schema drift detection (ci.yml)**: The default checkout is shallow (depth=1). `git diff BASE...HEAD` (3-dot) requires finding the merge-base of both SHAs via ancestor traversal, which fails silently with a shallow clone. The `getChangedFiles()` try/catch was returning `[]` on error, so the check reported "schema.ts not modified" (false-negative) for most real PRs where the base branch had advanced since branching. Fix: `git fetch --unshallow` before the validator step so the merge-base is always reachable. Falls back to `--depth=100` if already unshallow (e.g., already fetched with depth=0 earlier in the job). 2. **Silent git failure → misleading message**: `getChangedFiles()` returned `[]` on error, which led runPrDriftCheck to print "schema.ts not modified in this PR" even when git had failed entirely. Fix: Return `null` on error (distinct from `[]` = no files changed) and emit a `::warning::` annotation explaining that the check was skipped. 3. **Dead API call in pr-size-check.yml**: The `const { data: pr }` GitHub API fetch was left over from the old implementation (which used `pr.additions`, `pr.deletions`, `pr.changed_files`). The new code computes all those values from `git diff --numstat` and never reads `pr`. Removed the unnecessary API round-trip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…on (#1786) * fix(ci): increase scheduled-maintenance max-turns and timeout Previous run (2026-03-05T07:59:11Z) failed with error_max_turns after 31 turns — Claude ran out with max-turns=30 on a weekly sweep. Also increase timeout-minutes from 30 to 60 to give sufficient wall-clock headroom for weekly/monthly cadences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(pr-patrol): add main branch CI monitoring and PR overlap detection - Add check_main_branch() that runs at the top of each cycle with highest priority — if main CI is red, it dispatches Claude to diagnose and fix before processing any PRs - Add detect_pr_overlaps() that compares changed files across open PRs and posts warning comments when PRs touch the same files - Remove claude-assistant.yml (effectively dead — 0 successful runs in visible history, all triggers skip) - Remove ci-autofix.yml (reliably fails with 10-turn limit, redundant with pr-patrol's existing CI failure handling with 40 turns) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(pr-patrol): port main branch CI + overlap detection to TypeScript, delete bash script Replaces the bash implementation with TypeScript in crux/pr-patrol/index.ts: - checkMainBranch(): queries GitHub CI workflow runs on main, returns red/green - fixMainBranch(): spawns Claude to diagnose and fix main branch CI failures - detectPrOverlaps(): fetches changed files for open PRs, posts overlap warnings - Generalized cooldown functions to accept string keys (for 'main-branch', 'overlap-A-B') - Integrated both features into runCheckCycle() with main branch as step 0 - Deleted scripts/pr-patrol.sh (1028 lines) — TS version is now canonical - Updated CLAUDE.md to remove "pending migration to TS" note - Updated .claude/commands/pr-patrol.md daemon mode references Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
#1784) * feat(statements): add CRUD CLI commands and markdown-based ontology draft workflow Phase 0b: CRUD commands for statements management: - `crux statements list <entity>` — formatted table with property/value/date - `crux statements create <entity>` — auto-validates property, generates text - `crux statements update <id>` — PATCH any field (property, status, text, date) - `crux statements retract <id>` — single or batch retract with --all flag - `crux statements properties` — list all properties grouped by category Phase 1: Ontology review workflow: - `crux statements draft <entity>` — generates .claude/ontology-drafts/<entity>.md with coverage tables, gap analysis, unclassified statements, and action items - `crux statements apply-draft <entity>` — parses checked actions (RETRACT, CLASSIFY, NEW_PROPERTY, CREATE) and executes them against wiki-server Also expands PatchStatementInput to match server's full PATCH schema (variety, statementText, qualifierKey, validStart/End, attributedTo). Epic: #1765 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: prefix unused parseDraft parameter with underscore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…dings (#1780) * feat(ci): add CodeRabbit security gate to block merges on critical findings Adds a new GitHub Actions workflow that checks for unresolved Critical or Major CodeRabbit review threads before a PR can merge. If any blocking findings exist, the check fails until either: - The thread is resolved in the GitHub review interface, OR - A human adds the `coderabbit-security-ok` label after acknowledging The gate prevents bots and claude-* actors from self-bypassing via label. Addresses issue #1649, which identified 3 unresolved security findings from CodeRabbit (XSS, global delete risk, missing schema validation) that were self-merged without human review. All 3 bugs were already fixed: - XSS (PR #1613): StatementSourcesTable.tsx uses isSafeUrl() at line 111 - Global delete (PR #1623): cleanup endpoint uses z.string().min(1) for entityId - Schema validation (PR #1634): QualityDimensionsSchema with .strict() exists Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security-gate): harden bot actor detection and add GraphQL pagination Two security fixes for the CodeRabbit security gate: 1. **Broaden bot actor detection in isDisallowedActor** - Previous: only blocked `github-actions[bot]`, `dependabot[bot]`, and `claude-*` - Any other bot (renovate[bot], snyk-bot, GitHub Apps, coderabbitai[bot]) could self-apply the `coderabbit-security-ok` label to bypass the gate - Fix: accept the full actor object and check `actor.type === 'Bot'` first (GitHub sets this for ALL bot accounts and GitHub Apps), with a belt-and-suspenders `[bot]` suffix check and the explicit list as final fallbacks - Call site updated to pass `mostRecent.actor` instead of just `.actor.login` 2. **Paginate GraphQL reviewThreads query** - Previous: `reviewThreads(first: 100)` with no pagination - PRs with >100 review threads would silently miss findings in threads 101+ - Fix: add `pageInfo { hasNextPage endCursor }` and loop with cursor pagination - Collects all threads before filtering for blocking severity Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security-gate): accept both coderabbitai and coderabbitai[bot] logins CodeRabbit may appear as either login depending on whether the GraphQL or REST API is used. Accept both to prevent the gate silently passing when the login format doesn't match. Addresses CodeRabbit Critical finding on PR #1780. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): increase scheduled-maintenance max-turns and timeout Previous run (2026-03-05T07:59:11Z) failed with error_max_turns after 31 turns — Claude ran out with max-turns=30 on a weekly sweep. Also increase timeout-minutes from 30 to 60 to give sufficient wall-clock headroom for weekly/monthly cadences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ci): integrate Reviewdog for inline PR annotations Add Reviewdog to CI pipeline to post inline annotations on PR diffs for validation findings. This makes it much faster to locate issues vs digging through CI logs. Changes: - Add crux validate to-rdjsonl converter (crux → Reviewdog rdjsonl format) - Add reviewdog setup + crux validation annotations step (70+ rules) - Add actionlint reviewdog annotations step - Both annotation steps are advisory (continue-on-error, filter-mode=added) - Add job permissions for Checks API (checks: write) - 5 tests for the converter covering severity mapping, paths, edge cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: add post-merge audit for reviewdog annotations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use null check for line 0, update audit PR number Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): add pipefail to reviewdog steps, remove stderr suppression Surfaces broken annotation plumbing as a visible (orange) step failure instead of silently producing no annotations. continue-on-error keeps it advisory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1771) * feat(ci): test Drizzle migrations against throwaway Postgres in CI Adds a migrate-test job that spins up a throwaway Postgres 16 container and runs all Drizzle migrations against it on every PR. Catches broken migrations before they reach production. Previously, migration failures were only discovered after deploying to production. The job is independent (no needs: dependency) so it runs in parallel with the main CI job. Closes #1652 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): add timeout-minutes to migrate-test job Without a timeout, the job defaults to the GitHub Actions maximum of 6 hours. A stuck migration (e.g., waiting for a DDL lock that never arrives) would block the CI queue for the full 6 hours. 15 minutes is well above the expected runtime (~2–3 min for 63 migrations on a fresh container) but provides a safety net. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(migration): remove FK to wiki_pages(integer_id) — column added via manual migration only integer_id on wiki_pages was applied via phase4a-manual-migration.sql (outside Drizzle), so it does not exist in a fresh CI database. The migrate-test CI job was failing with 'column integer_id does not exist'. Store page_id_int as plain INTEGER with a comment. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): increase scheduled-maintenance max-turns and timeout Previous run (2026-03-05T07:59:11Z) failed with error_max_turns after 31 turns — Claude ran out with max-turns=30 on a weekly sweep. Also increase timeout-minutes from 30 to 60 to give sufficient wall-clock headroom for weekly/monthly cadences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(pr-patrol): add auto-merge for PRs labeled ready-to-merge Extend PR Patrol's detect-score-fix cycle with a merge phase that automatically squash-merges PRs labeled `ready-to-merge` when clean: CI green, no conflicts, no unresolved threads, no unchecked items. Key changes: - Refactor detectAllPrIssues into fetchOpenPrs + detectAllPrIssuesFromNodes so both fix and merge phases share a single GraphQL fetch - Add checkMergeEligibility (pure, exported) and findMergeCandidates - Merge at most 1 PR per cycle (lets CI re-run on updated main) - Add `crux pr-patrol merge-status` subcommand for live status - 23 unit tests covering eligibility checks and edge cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pr-patrol): also block merge on CANCELLED CI conclusion Caught during code review — a CheckRun with conclusion: 'CANCELLED' was not detected by either the failure or pending checks, allowing a PR with a cancelled CI check to be auto-merged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…1790) Salvages valuable content from closed PR #1764: - Add 15 Claude model entities (E1027-E1041) to data/entities/ai-models.yaml - Simplify current-snapshot.tsx: always show verdict column, amber conflict text - Add 'part-of' and 'created-by' to schema relationship enum Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add language identifiers to unlabeled code fences in command docs - Fix qualifier parsing to preserve segments after first colon - Filter includeChildren to only composed-of relationships (not all related) - Move budget check after LLM analysis (was always 0 before) - Combine JSON output into single object in --json --apply mode Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
* fix(ci): increase scheduled-maintenance max-turns and timeout Previous run (2026-03-05T07:59:11Z) failed with error_max_turns after 31 turns — Claude ran out with max-turns=30 on a weekly sweep. Also increase timeout-minutes from 30 to 60 to give sufficient wall-clock headroom for weekly/monthly cadences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(release): prevent squash merges on production branch Squash-merging release PRs (main → production) creates orphan commits that cause conflicts on every subsequent release. Added: - GitHub branch ruleset enforcing merge commits only for production - CI notice reminding to use merge commits on release PRs - CLI warning in `crux release create` output Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): increase scheduled-maintenance max-turns and timeout Previous run (2026-03-05T07:59:11Z) failed with error_max_turns after 31 turns — Claude ran out with max-turns=30 on a weekly sweep. Also increase timeout-minutes from 30 to 60 to give sufficient wall-clock headroom for weekly/monthly cadences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(pr): draft PRs by default, auto-undraft in pr-patrol - `crux pr create` now creates draft PRs by default (use --no-draft to override) - New `crux pr ready` command validates eligibility (CI green, no conflicts, no unresolved threads, no unchecked items) before converting draft to ready - PR Patrol auto-undrafts draft PRs labeled `ready-to-merge` when all other eligibility checks pass, then merges in the same cycle - PR Patrol skips draft PRs from the fix queue (no point fixing drafts) - Added `isDraft` to GraphQL PR query and `GqlPrNode` interface - `is-draft` added as a new `MergeBlockReason` - 4 new tests covering draft eligibility checks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address review findings — is-draft self-block, REST fallback, failed undraft tracking - Filter out 'is-draft' from block reasons in `crux pr ready` (it's the whole point of the command, not a blocker) - Replace REST-then-GraphQL fallback with direct GraphQL for undrafting (REST API doesn't support undrafting, so the REST call always fails) - Track which PRs were successfully undrafted before attempting merge (prevents merge attempts on PRs where undraft API call failed) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(pr): address CodeRabbit review feedback - Validate --pr option: return error on malformed values instead of silently falling back to branch autodetection - Keep ci-pending as a blocker for `crux pr ready` to match PR Patrol auto-undraft behavior (only is-draft is filtered out) - Simulate undraft in dry-run mode so merge phase also reports what would happen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Open
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 2026-03-06
54 commits since last release.
Warning
Production has 1 commits not on main (hotfixes or merge commits).
Review carefully to ensure these won't be overwritten.
Features
Fixes
Refactoring
Documentation
Infrastructure
Other
Full diff