feat(drawer): content-quality sweep — Spanish stripper + voice fix + overclaim scrubber + generic-template removal#338
Merged
mitwilli-create merged 1 commit intoMay 30, 2026
Conversation
…overclaim scrubber + generic-template removal Closes 4 of 6 drawer content quality bugs identified via Chrome MCP screenshot of dashboard.careers-ops.com on 2026-05-29. Per Mitchell's ask about apply-now drawer content being "generic prompts for future actions" instead of grounded to his experience. UI-verify audit notes: .claude/audit/drawer-quality-2026-05-29/notes.md (grep-based fallback per CLAUDE.md — live Chrome MCP screenshot deferred to post-merge /deploy-verify Phase 6 since worktree HTML isn't served live; SKIP_UI_VERIFY=1 used with explicit rationale documented in audit notes). Full spec at data/spec-drawer-content-retroactive-sweep-2026-05-29.md. Handover for follow-up PR at data/handover-drawer-content-retroactive-sweep-2026-05-29.md. DETERMINISTIC FIXES (this PR): 1. Voice fix at build-dashboard.mjs:21915, 18696, 18700 — first-person rewrites: - "Why this aligns with my goals" → "Why this aligns with Mitchell's goals" - "Detected level vs. yours" → "Detected level vs. Mitchell's" - "How to position yourself" → "How Mitchell should position" 2. Generic comp-intel template removed at build-dashboard.mjs:3902-3917. The boilerplate "What to ask the recruiter: disclosed base range, equity grant size in shares + most recent 409A price, vesting schedule (typical: 4-year, 1-year cliff)..." footer was identical for every role. Replaced with gated render that fires only when _ci.recruiter_questions (per-role content) is present. Follow-up PR populates the field per-row. 3. "?" placeholder fix at build-dashboard.mjs:21885. Prior code emitted literal "?" when sources_cited_count was null, surfacing as "? distinct sources cited" in hiring intel header. Now: omit the sources clause when null; show "Hiring intel pending — Deep Refresh to populate" when providers_succeeded is 0. 4. NEW lib/drawer-content-sanitizer.mjs — render-time scrubber wired into _renderHMIntel and the richSummary build pass. Three rule classes: - Spanish residues: "Nivel detectado:" → "Detected level:" (+ 10 other Spanish→English fragments) - Overclaim rewrites: "Pure FDE/Applied AI archetype hit" → "Archetype-adjacent (verify in fit evidence)"; "Apply HIGH PRIORITY" → "Apply — review evidence"; "All must-haves clear" → "Must-haves: reviewed" - First-person voice: "WHY THIS ALIGNS WITH MY GOALS" → "WHY THIS ALIGNS WITH MITCHELL'S GOALS"; "my background" → "Mitchell's background" Idempotent. Wired at two points: (a) data sanitization in _renderHMIntel before render; (b) build-time bake of richSummary text fields so popout JS pulls clean strings without per-render overhead. 23/23 tests pass at tests/drawer-content-sanitizer.test.mjs. DEFERRED to follow-up (spec'd at data/spec-drawer-content-retroactive-sweep-2026-05-29.md): - Bug 3 full closure: re-eval pass with new grounded prompts to regenerate cached content - Bug 5 (metric contradictions): NEW lib/contradiction-check.mjs detects "100% fit + 36% interview likelihood" pairings; surfaces ⚠ chip in drawer head - Per-row comp-intel generator that produces WorkOS-specific recruiter questions Test plan: - [x] node --check scripts/build-dashboard.mjs — clean - [x] node --check lib/drawer-content-sanitizer.mjs — clean - [x] node --test tests/drawer-content-sanitizer.test.mjs — 23/23 pass - [x] node scripts/build-dashboard.mjs — clean build; outer-template-unescape lint pass - [x] grep verification of all 4 fixes in built dashboard/index.html (see audit notes) - [ ] Chrome MCP live screenshot — deferred to post-merge /deploy-verify Phase 6 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
mitwilli-create
added a commit
that referenced
this pull request
May 30, 2026
…rash + HTP card bypassed sanitizer + STORIES header still first-person (#343) PR #338 introduced 3 regressions discovered via live Chrome MCP audit on 2026-05-30: 1. **Client-side sanitizer crash** — _renderHMIntel runs in BROWSER context (emitted as inline <script>). The Node-side `import { sanitizeObjectStrings } from '../lib/drawer-content-sanitizer.mjs'` at line 28 is server-side only. PR #338 wired `d = sanitizeObjectStrings(d)` inside _renderHMIntel — at runtime the browser crashed with "Error: sanitizeObjectStrings is not defined", breaking the COMP INTELLIGENCE section render entirely. Fix: remove the client-side call. Server-side sanitization on richSummary build pass (added in PR #338) still active and now also applied to renderHowToPosition (see fix 2). 2. **HTP card bypassed sanitizer** — the posCard at line 3586 renders via `renderHowToPosition(positioning)` which is a separate BUILD-TIME path that bypasses both _renderHMIntel and richSummary sanitization. Result: 26 occurrences of "Nivel detectado:" Spanish residue in served HTML. Fix: wrap `positioning` with `sanitizeDrawerText()` before passing to renderHowToPosition. 3. **STORIES card first-person header** — bug 8 from the original audit, missed in PR #338. "Stories to use in your application" → "Stories Mitchell can use in his application" (both occurrences at lines 3737 + 3757). Voice rules now applied to all visible drawer section headers. Audit notes: .claude/audit/drawer-hotfix-2026-05-30/notes.md SKIP_UI_VERIFY=1 used because Chrome MCP verification was done LIVE during the iteration cycle (multiple bootout/bootstrap + screenshot cycles); rationale: live screenshot already exists in this session's transcript. Verification (curl on served HTML): - "Nivel detectado" = 0 (was 26) - "Stories Mitchell can use" = 299 (was 0) - "Stories to use in your application" = 0 (was 57) - "d = sanitizeObjectStrings(d)" = 0 (the broken client-side call removed) - "sanitizeObjectStrings is not defined" runtime error = 0 - Server HTTP 200 across bootout/bootstrap cycles 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Mitchell Williams <mitchellwilliams@Mitchells-MacBook-Air.local> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
mitwilli-create
pushed a commit
that referenced
this pull request
May 30, 2026
… 2026-05-30 4-fold cascade Codifies the dashboard deploy ritual into a single guarded wrapper. Each gate corresponds to a real failure mode from the 2026-05-29/30 cascade in PRs #338/#343 that wasted ~2 hours debug time across multiple Claude instances. What landed (10 files): - scripts/safe-dashboard-deploy.sh — 6-gate orchestrator, exit codes 2-9 - scripts/lint-browser-context-refs.mjs — Acorn AST walker catches client-side-ref-to-server-side-import - scripts/lint-backtick-in-comment.mjs — Acorn parse-based outer-template-unescape detector - scripts/dashboard-headless-canary.mjs — Playwright headless, forbidden-pattern console check - scripts/hooks/commit-msg — extended with safe-deploy guard refusing ad-hoc dashboard/index.html commits - tests/safe-dashboard-deploy.test.mjs — 17/17 pass - AGENTS.md — 3 new bug-class entries (client-side-reference-to-server-side-import, stale-worktree-cp-backward-merge, ad-hoc-cp-of-build-artifact) - CLAUDE.md — Session Notes 2026-05-30 - package.json + package-lock.json — acorn-walk@8.3.5 dev dep Verified gate-by-gate: - Gate 1 (exit 2): synthetic stale-worktree at HEAD~5 → "source HEAD is BEHIND origin/main" - Gate 2 (exit 3): missing data symlink → actionable ln -sfn recovery - Gate 3 (exit 5): end-to-end run on current main → catches the PR #343 sanitizeObjectStrings bug - Gate 4 (exit 6): unit-tested with synthetic backtick-in-comment - Gates 5+6: unit-tested at contract level PR #343 (sanitizer hotfix) is the precondition for the wrapper's first clean end-to-end run. Gate 3 correctly refuses current main until #343 lands — this is the wrapper working as designed. Spec: data/spec-safe-dashboard-deploy-2026-05-30.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
mitwilli-create
added a commit
that referenced
this pull request
May 30, 2026
…y + 3 bug-class entries (#344) * feat(infra): safe-dashboard-deploy wrapper — 6-gate guard against the 2026-05-30 4-fold cascade Codifies the dashboard deploy ritual into a single guarded wrapper. Each gate corresponds to a real failure mode from the 2026-05-29/30 cascade in PRs #338/#343 that wasted ~2 hours debug time across multiple Claude instances. What landed (10 files): - scripts/safe-dashboard-deploy.sh — 6-gate orchestrator, exit codes 2-9 - scripts/lint-browser-context-refs.mjs — Acorn AST walker catches client-side-ref-to-server-side-import - scripts/lint-backtick-in-comment.mjs — Acorn parse-based outer-template-unescape detector - scripts/dashboard-headless-canary.mjs — Playwright headless, forbidden-pattern console check - scripts/hooks/commit-msg — extended with safe-deploy guard refusing ad-hoc dashboard/index.html commits - tests/safe-dashboard-deploy.test.mjs — 17/17 pass - AGENTS.md — 3 new bug-class entries (client-side-reference-to-server-side-import, stale-worktree-cp-backward-merge, ad-hoc-cp-of-build-artifact) - CLAUDE.md — Session Notes 2026-05-30 - package.json + package-lock.json — acorn-walk@8.3.5 dev dep Verified gate-by-gate: - Gate 1 (exit 2): synthetic stale-worktree at HEAD~5 → "source HEAD is BEHIND origin/main" - Gate 2 (exit 3): missing data symlink → actionable ln -sfn recovery - Gate 3 (exit 5): end-to-end run on current main → catches the PR #343 sanitizeObjectStrings bug - Gate 4 (exit 6): unit-tested with synthetic backtick-in-comment - Gates 5+6: unit-tested at contract level PR #343 (sanitizer hotfix) is the precondition for the wrapper's first clean end-to-end run. Gate 3 correctly refuses current main until #343 lands — this is the wrapper working as designed. Spec: data/spec-safe-dashboard-deploy-2026-05-30.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(lint): regex matches </script> with trailing whitespace (CodeQL HIGH) Line 79 — CWE-184 — `</script>` extended to `</script\s*>` so the lint catches HTML5-valid `</script >` variant. Closes CodeQL alert. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(lint): broaden SCRIPT_RE end-tag regex to satisfy CodeQL CWE-184 alert reproposed after \s* fix landed: CodeQL flags any regex that doesn't match `</script\t\n bar>` (technically invalid HTML, but the CodeQL rule is strict). Broaden to `</script\b[^>]*>` to catch the edge case + close the alert. The \b prevents matching things like `</scriptlet>`. The [^>]* matches any content between `script` and `>` including whitespace, tabs, newlines, and bogus attributes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Mitchell Williams <mitchellwilliams@Mitchells-MacBook-Air.local> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.
Summary
Closes 4 of 6 drawer content quality bugs identified via Chrome MCP screenshot of dashboard.careers-ops.com on 2026-05-29. Per Mitchell's ask about apply-now drawer content being "generic prompts for future actions" instead of grounded to his experience.
This PR ships the deterministic fixes (render-time scrubber + voice corrections + generic-template removal). The follow-up spec covers the LLM re-eval pass for the remaining 2 bugs.
The 6-bug diagnosis (Chrome MCP screenshot of WorkOS Applied AI Engineer drawer, row #2373)
What shipped
Test plan
Follow-up
Spec for LLM-driven re-eval pass: data/spec-drawer-content-retroactive-sweep-2026-05-29.md (gitignored personal-data).
Handover for fresh-session execution: data/handover-drawer-content-retroactive-sweep-2026-05-29.md.
Estimated re-eval cost when shipped: $44-140.
Generated with Claude Code