Skip to content

Add dating app shadowban FAQ#86

Open
mikepsinn wants to merge 3 commits into
mainfrom
feature/love-shadowban-faq
Open

Add dating app shadowban FAQ#86
mikepsinn wants to merge 3 commits into
mainfrom
feature/love-shadowban-faq

Conversation

@mikepsinn
Copy link
Copy Markdown
Owner

@mikepsinn mikepsinn commented May 19, 2026

Summary

Adds the missing /love FAQ entry warning users not to copy-paste the same dating-app message or mass-like people, because shadowbanning would defeat the campaign distribution goal.

Validation

  • pnpm --dir packages/web exec eslint --fix --no-warn-ignored src/app/love/page.tsx
  • pnpm --filter @optimitron/web typecheck:fast
  • pnpm --filter @optimitron/web copy:preview -- --routes=/love
  • pnpm --filter @optimitron/web run e2e -- visual --grep love --project default --project visual-mobile --workers=1 --reporter=list
  • pnpm --filter @optimitron/web run visual:review

Local screenshot review was regenerated and inspected for /love desktop and mobile.

Summary by CodeRabbit

  • New Features

    • Added comprehensive developers documentation page with MCP integration guides and API reference.
  • Bug Fixes

    • Improved admin authorization for task management.
    • Enhanced OAuth consent scope handling.
  • Documentation

    • Updated Love page FAQ with guidance on avoiding shadowbans on dating platforms.
  • Chores

    • Updated grant task identifiers and IAM organization management.
    • Added automated enforcement policies for autoplan submissions.

Review Change Stack

Copilot AI review requested due to automatic review settings May 19, 2026 04:21
@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
optimitron-web Ready Ready Preview, Comment May 19, 2026 11:48pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR introduces autoplan enforcement hooks for plan validation and feature checks, refactors MCP admin authorization to gate on user status rather than OAuth scope, migrates grant task identifiers to a new IC2EWD prefix, flags Mike Sinn as an admin in managed IAM, and updates user documentation including shadow-ban risk guidance on the dating page.

Changes

Autoplan Enforcement Hooks

Layer / File(s) Summary
Cost-Benefit Analysis enforcement hook
.claude/hooks/enforce-cba-table-on-plan-files.mjs
Pre-tool hook scans plan files for required Cost-Benefit Matrix signals (heading, effort, opportunity cost, decision cues) and emits advisories with templates when signals are missing; always exits successfully (non-blocking).
Feature-preexistence detection hook
.claude/hooks/enforce-feature-preexistence-check-on-autoplan.mjs
Pre-tool hook extracts candidate feature nouns from args and branch, searches app directories, routes.ts, and recent commits for evidence of preexistence, and emits findings to stderr; always exits successfully (non-blocking).
Hook wiring and autoplan policy documentation
.claude/settings.json, TODO.md
Hooks registered in Skill matchers with configured timeouts; TODO documents enforced autoplan policies requiring Cost-Benefit Matrix placement and feature-preexistence acknowledgment.

MCP Admin Authorization Refactor

Layer / File(s) Summary
Consent scope constant refactor
packages/web/src/lib/mcp-scopes.ts, packages/web/src/lib/mcp-server.ts, packages/web/src/app/mcp/authorize/page.tsx
DEFAULT_SCOPES renamed to DEFAULT_CONSENT_SCOPES to clarify that the OAuth UI preselects these scopes but filters by allowedMcpScopesForUser. Authorization page uses new constant as fallback.
Admin task write access authorization
packages/web/src/lib/mcp-server.ts
hasAdminTaskWriteAccess now gates solely on isAdmin, discarding scope requirements. createTask, updateTask, and deleteTask permit admin callers to modify public tasks and others' tasks; dependency validation and error messages updated accordingly.
Authorization regression test coverage
packages/web/src/lib/__tests__/mcp-server.test.ts
New test cases for updateTask and deleteTask cover non-admin rejection, admin scope gating legacy behavior, admin writers modifying unowned tasks, and public task handling by admin users.

Grant Task Seeding and IAM Updates

Layer / File(s) Summary
IC2EWD grant task constants and seeding
packages/db/src/managed-data/managed-seed-data.ts
Foundation grant tasks updated to use new IC2EWD-scoped constants for task key prefix, task id stem, interestTags, and methodologyKey instead of legacy campaign naming.
Grant task key prefix migration
packages/db/src/__tests__/seed.integration.test.ts, packages/web/scripts/soft-delete-funding-tasks.ts
Test and script updated to generate and filter grant task keys using new ic2ewd:grant: prefix constant instead of legacy prefix construction.
Mike Sinn managed IAM admin flag
packages/db/src/managed-data/managed-iam-organization.ts, packages/db/src/managed-data/managed-iam-organization.test.ts
syncManagedIamOrganization now sets isAdmin: true on Mike Sinn user upsert (create and update branches); test assertion updated to expect admin flag.

User-Facing Content and Project Documentation

Layer / File(s) Summary
Love page shadowbanning FAQ
packages/web/src/app/love/page.tsx, packages/web/src/app/love/page.logged-out.md
FAQ item updated and new logged-out section address shadowbanning risks from repeated messaging; guidance includes varying wording, limiting activity frequency, spacing messages, and targeting specific individuals. Extraneous footer text removed from page component.
Developers logged-out documentation
packages/web/src/app/developers/page.logged-out.md
New documentation page for logged-out developers explains OPTIMITRON MCP integration, tool categories, setup instructions for multiple MCP clients, OAuth scope guidance, and API reference for endpoint, tool catalog, and discovery.
Sprint and project planning updates
TODO.md
2026-05-19 active review section added with cost/benefit matrix; P0 Conversion and Email Safety priorities defined; follow-up work for /poster and apocalypse phrasing estimated; email ownership and template selection clarified; org admin surface constraints, plaintiff-registration priority downgrade, and dating-registry deferral documented.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

  • mikepsinn/optimitron#38: MCP server task authorization changes in packages/web/src/lib/mcp-server.ts directly address task visibility and permission handling across write operations.
  • mikepsinn/optimitron#59: Autoplan hook implementations and MCP server refactoring touch tooling and MCP authorization areas referenced in daily drift audits.

Poem

🐰 A rabbit hops through admin gates,
Where scopes no longer seal our fates,
Plans now checked for cost and care,
Features found or new and rare,
Love and code dance hand in hand. 🌙

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title describes only a minor /love FAQ addition, but the changeset includes substantial unrelated changes: MCP server admin authorization refactoring, managed IAM Mike user fixes, new autoplan enforcement hooks, campaign-wide seed data/nomenclature updates (icewad→ic2ewd), and developers page documentation. Retitle to reflect the primary changes, such as 'Refactor MCP admin task write access and add autoplan hooks' or split into multiple focused PRs with one per objective.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/love-shadowban-faq

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/web/scripts/soft-delete-funding-tasks.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///packages/web/.eslintrc.json?mtime=1779234286162" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32

packages/web/src/app/love/page.tsx

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///packages/web/.eslintrc.json?mtime=1779234286162" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32

packages/web/src/app/mcp/authorize/page.tsx

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///packages/web/.eslintrc.json?mtime=1779234286162" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32

  • 3 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mikepsinn mikepsinn force-pushed the feature/love-shadowban-faq branch from 9e62a07 to e474445 Compare May 19, 2026 04:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new FAQ entry to the /love landing page advising users to avoid dating-app “shadowban” behaviors (copy/paste messaging, mass-liking) so the campaign distribution strategy remains effective.

Changes:

  • Added a new FAQ item to the /love page content in page.tsx.
  • Updated the corresponding logged-out markdown snapshot to match the rendered content.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/web/src/app/love/page.tsx Adds a new FAQ question/answer warning against copy-paste messaging and mass-liking to avoid reduced visibility.
packages/web/src/app/love/page.logged-out.md Updates the logged-out snapshot content to include the new FAQ entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@claude
Copy link
Copy Markdown

claude Bot commented May 19, 2026

Code review

Two issues found.


1. Wishonia voice violation + hardcoded numbers

File: packages/web/src/app/love/page.tsx lines 143-147

Run-on sentence. After the opener, all advice collapses into a single 107-word colon-delimited sentence. CLAUDE.md requires short, punchy declaratives: "Write like Kurt Vonnegut. Plain declaratives." and "Short sentences — punchy. Declarative." The adjacent FAQ answers are each 1–3 short sentences. Break the tips into separate declarative sentences.

Hardcoded numeric ranges. 10-15 likes and 3-5 messages per day are plain string literals. Per CLAUDE.md: "<ParameterValue> for every user-facing number. Grep packages/data/src/parameters/parameters-calculations-citations.ts for a matching parameter before typing a number." If no matching parameters exist, add them and update the answer field to accept ReactNode so it can render <ParameterValue> components.


2. Missing todo-skipped commit marker

The commit message Add dating app shadowban FAQ has no body and is missing the required marker. Per CLAUDE.md: "Commit message must include todo-touched: <item> (work closed a TODO line) or todo-skipped: <reason> (net-new work or out-of-scope)". Since this is new FAQ content, the commit body should include todo-skipped: net-new.


@claude
Copy link
Copy Markdown

claude Bot commented May 19, 2026

Code review

Two issues found. Checked for bugs (none) and CLAUDE.md compliance.


1. Wishonia voice violations — page.tsx line 146

Three rules broken in the FAQ answer. CLAUDE.md reference.

Not data-first. Opens with qualitative "Yes, you will." — numbers (10–15 likes, 3–5 messages/day) buried three sentences in. Rule: "Data-first — lead with specific numbers, costs, percentages, or ROI ratios. Numbers beat adjectives."

Run-on sentence. "To avoid this: vary your wording … send something specific" chains four instructions across ~60 words in a single sentence. Rule: "Short sentences — punchy. Declarative. Then a devastating follow-up."

Startup-bro close. "Be a human, not a bot, even if your goal is to reach as many humans as possible." Rule: "If a sentence could appear unchanged in a Stripe keynote, rewrite."

Suggested replacement for

answer:
'Yes, you will. Dating apps detect copy-paste messages and mass-liking and will quietly make you invisible to everyone. This defeats the entire purpose. To avoid this: vary your wording each time you send the profile improvement message, limit yourself to 10-15 likes and 3-5 messages per day, space your activity throughout the day rather than doing it all at once, and for people you\'re actually interested in, send something specific to their profile instead of the campaign message. The algorithm rewards selectivity. Be a human, not a bot, even if your goal is to reach as many humans as possible.',
},
:

    answer:
      'Yes. Apps detect copy-paste messages and mass-liking. The penalty: silent invisibility — you\'ll never be told. Cap yourself at 10–15 likes and 3–5 messages per day. Vary your wording each time. Space it out. For genuine matches, skip the campaign message entirely. The algorithm rewards selectivity.',

2. Missing todo-skipped: commit marker

Commit e474445 (Add dating app shadowban FAQ) has no todo-touched: or todo-skipped: annotation. CLAUDE.md:

Commit message must include todo-touched: <item> (work closed a TODO line) or todo-skipped: <reason> (net-new work or out-of-scope) — verify-ui-changes.mjs advisory-flags missing markers.

Since this is net-new content with no pre-existing TODO line, add to the commit body:

todo-skipped: net-new /love FAQ entry, no pre-existing TODO line

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

PR review packet

Start here

  • 🖼️ Visual review
  • 🚀 Preview deployment
  • ☝️ Cmd/Ctrl-click review links to keep this PR open.
  • 🔑 ?login=demo signs in as the demo user; ?logout=1 clears the session.
  • 💬 For a visual problem, use the comment button in latest.html or reply here with @claude and the checklist item.

Review checklist

  • 🖼️ Love - logged-out 2 changed screenshots - open page
  • 🚀 /love - logged-out preview - app/love/page.tsx
  • 🚀 /mcp/authorize - demo logged-in preview - app/mcp/authorize/page.tsx
Changed files considered
  • .claude/hooks/enforce-cba-table-on-plan-files.mjs
  • .claude/hooks/enforce-feature-preexistence-check-on-autoplan.mjs
  • .claude/settings.json
  • TODO.md
  • packages/db/src/__tests__/seed.integration.test.ts
  • packages/db/src/managed-data/managed-iam-organization.test.ts
  • packages/db/src/managed-data/managed-iam-organization.ts
  • packages/db/src/managed-data/managed-seed-data.ts
  • packages/web/scripts/soft-delete-funding-tasks.ts
  • packages/web/src/app/developers/page.logged-out.md
  • packages/web/src/app/love/page.logged-out.md
  • packages/web/src/app/love/page.tsx
  • packages/web/src/app/mcp/authorize/page.tsx
  • packages/web/src/lib/__tests__/mcp-server.test.ts
  • packages/web/src/lib/mcp-scopes.ts
  • packages/web/src/lib/mcp-server.ts

Updated automatically when this PR's preview or visual review reruns.

mikepsinn and others added 2 commits May 19, 2026 18:42
…hooks

MCP server: hasAdminTaskWriteAccess now returns isAdmin alone (option B).
Admin role IS the gate; TASKS_ADMIN scope is documentation/UX, not a
security gate. Reversible to multi-admin posture by tightening one line
in mcp-server.ts:198.

Mike's User row now gets isAdmin: true via managed-iam-organization sync,
unblocking the ic2ewd-grant updateTask Forbidden bug after deploy.

DEFAULT_SCOPES renamed to DEFAULT_CONSENT_SCOPES with comment explaining
what the constant actually controls (consent-UI preselection, filtered
by allowedMcpScopesForUser).

189 lines of mcp-server.test.ts coverage including explicit regression
tests for the ic2ewd-grant update + delete failure modes.

/love source: removed "Hey Google, set a timer for one minute" leftover
from prior dictation pass.

Autoplan hooks: enforce-feature-preexistence-check warns when /autoplan
references feature nouns that already exist as routes/branches/commits.
enforce-cba-table-on-plan-files warns when plan files lack a structured
Cost-Benefit Matrix. Both fix structural gaps in the 2026-05-19 autoplan
failure that proposed a feature already shipped.

TODO.md sweep: audited against actual code state, 207 lines of shipped
items removed (login spam fix, wishonia smirk-to-happy avatar, email
12px-to-14px, grandma headshot crop, direct-reports-to-employees,
humanity-manager-status panel, forward-to-better-fit mailto, dynamic
approved-org + court/HvG sitemaps). Added dating registry deferred
section + autoplan process rules.

todo-touched: login-spam, wishonia-avatar, email-12px, grandma-headshot,
direct-reports-rename, humanity-manager-status, forward-to-better-fit,
dynamic-sitemaps

qa-passed: option-B admin MCP simplification + ic2ewd-grant regression
tests, copy:preview snapshots, mcp-server tests (123 passed), tsc clean,
managed-iam-organization tests passed, /love smoke clean, dev-log scan clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finishes a prior naming decision that didn't propagate to every surface.
Live source/test scope now has zero 'icewad' / 'ICEWAD' hits; only ignored
generated paths (.next/cache, packages/web/output/tmp-*) and historical
plan files retain the old name.

Renamed seed task keys: icewad-grant-* → ic2ewd-grant-*, icewad:grant:*
→ ic2ewd:grant:*, plus methodology key and interest tag.

Production data risk surfaced by audit: 10 old icewad:grant:* rows exist
(7 not soft-deleted). Audit found 0 active comments, 0 task communications,
0 sent/received communications, 0 email logs on the old rows. After deploy
+ managed-data sync, new ic2ewd-grant-* rows will be created; old rows
remain orphaned but carry no user state.

Files: packages/db/src/__tests__/seed.integration.test.ts (+3/-3),
packages/db/src/managed-data/managed-seed-data.ts (+8/-8),
packages/web/scripts/soft-delete-funding-tasks.ts (+4/-4),
packages/web/src/lib/__tests__/mcp-server.test.ts (+2/-2 — comment refs
updated to ic2ewd-grant for consistency with the rename).

Verification: pnpm copy:preview passed, web tests + db tests + tsc clean.

todo-skipped: rename completed a prior intent not tracked in TODO.md.

qa-passed: source rename complete, focused tests + typecheck clean,
no live-source icewad hits remain

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/lib/mcp-server.ts (1)

6728-6756: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

blockedTaskIds still rejects admin task management.

This block now exempts admins from the private-dependency visibility check, but forbiddenBlockedTaskIds still errors on any target task not created by userId. Admins therefore still cannot create a new prerequisite that blocks an existing public or other-owned task.

Allow the same admin override here
               const forbiddenBlockedTaskIds = dependencyTasks
                 .filter(
                   (task) =>
                     blockedTaskIds.includes(task.id) &&
-                    task.createdByUserId !== userId,
+                    task.createdByUserId !== userId &&
+                    !hasAdminTaskWriteAccess(scopes, isAdmin),
                 )
                 .map((task) => task.id);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/lib/mcp-server.ts` around lines 6728 - 6756, The
forbiddenBlockedTaskIds check incorrectly blocks admins; update the filter that
builds forbiddenBlockedTaskIds (which iterates dependencyTasks and uses
blockedTaskIds and task.createdByUserId !== userId) to also exempt admins by
checking hasAdminTaskWriteAccess(scopes, isAdmin) — i.e., only mark a blocked
task as forbidden if task.createdByUserId !== userId AND the caller does not
have admin task write access (use hasAdminTaskWriteAccess(scopes, isAdmin)) so
admins can create prerequisites that block other users' tasks.
🧹 Nitpick comments (4)
packages/web/src/app/developers/page.logged-out.md (2)

7-7: ⚡ Quick win

Canonical metadata appears unset; verify source metadata export.

Line 7 shows Canonical: [missing]. If this reflects actual route metadata, it can create avoidable SEO ambiguity for /developers.

Please verify packages/web/src/app/developers/page.tsx (or shared metadata generator) defines a canonical URL for this route.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/app/developers/page.logged-out.md` at line 7, The page's
metadata is missing a canonical URL; open the route's metadata export in
packages/web/src/app/developers/page.tsx (look for export const metadata or
export async function generateMetadata) and add a canonical link (e.g.,
metadata.openGraph.url or metadata.alternates.canonical) pointing to the
absolute URL for /developers; if you use a shared helper (e.g., getCanonicalUrl
or buildMetadata), update that generator to return a canonical property using
your SITE_URL/appConfig so the canonical is always populated for this route.

57-57: ⚡ Quick win

Remove internal mechanism wording from user-facing copy.

“delivery envelopes stay internal” reads like implementation detail and distracts from the user action.

Suggested rewrite
-- The agent posts task comments for status updates, questions, and next steps. Comment posting handles comment notifications; delivery envelopes stay internal.
+- The agent posts task comments for status updates, questions, and next steps. Comment posting handles notifications automatically.

As per coding guidelines, “Do not leak implementation or planning terms into user copy.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/app/developers/page.logged-out.md` at line 57, The
user-facing sentence in packages/web/src/app/developers/page.logged-out.md
contains an implementation detail—specifically the phrase "delivery envelopes
stay internal"—which should be removed; update the sentence that currently reads
"The agent posts task comments for status updates, questions, and next steps.
Comment posting handles comment notifications; delivery envelopes stay
internal." to a concise user-focused line (e.g., keep that the agent posts
comments and notifications are handled) that omits any internal mechanism
wording and ensures clarity for users rather than developers.
packages/db/src/__tests__/seed.integration.test.ts (1)

157-157: ⚡ Quick win

Add a regression check that legacy icewad:grant: tasks are absent.

This test currently proves new keys exist, but not that old keys are gone. A negative assertion will catch duplicate-seed regressions.

✅ Suggested assertion
   expect(grantTasks).toHaveLength(foundationSlugs.length);
@@
   expect(grantTasks[0]?.description).toContain("Suggested grant: $1.");
+
+  const legacyGrantTaskCount = await prisma.task.count({
+    where: { deletedAt: null, taskKey: { startsWith: "icewad:grant:" } },
+  });
+  expect(legacyGrantTaskCount).toBe(0);

Also applies to: 161-161, 186-186

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/src/__tests__/seed.integration.test.ts` at line 157, Add a
negative regression check to ensure legacy "icewad:grant:" task keys are not
present: when verifying grant tasks (reference the grantTaskKeyPrefix variable
and the test assertions around it), add an assertion that no keys start with or
equal "icewad:grant:" (e.g., use the test framework's negative
containment/assertion method) so the test fails if old legacy keys remain; apply
the same negative check to the other similar spots noted (the checks around
lines referencing grantTaskKeyPrefix at the other two locations).
packages/web/src/lib/mcp-server.ts (1)

3770-3774: ⚡ Quick win

Align the MCP descriptions with the new admin contract.

updateTask/deleteTask now allow admins to operate on public and non-owned tasks, but the schema text in this file still says “Update a private task...” and “Delete one of your own tasks...”. Schema-guided MCP clients will keep avoiding those paths unless the tool descriptions are updated too. While you are here, the createTask.visibility docs should also state that the default PUBLIC behavior for organization-assigned tasks is admin-only.

Also applies to: 7902-7935, 8185-8194

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/lib/mcp-server.ts` around lines 3770 - 3774, The schema
documentation strings for createTask.visibility, updateTask and deleteTask are
out of date: update the createTask.visibility description to explicitly state
that the default PUBLIC behavior for tasks assigned to an organization is
allowed only for admin callers, and update the updateTask and deleteTask
descriptions to say that admins may operate on PUBLIC and non-owned tasks
(rather than “a private task” / “one of your own tasks”); locate the doc strings
attached to the createTask visibility option and the updateTask/deleteTask
operation descriptions (search for "create a task. Visibility defaults to",
"Update a private task", and "Delete one of your own tasks") and revise their
text accordingly, and mirror the same wording changes in the other duplicated
schema-description locations where those strings appear.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/hooks/enforce-feature-preexistence-check-on-autoplan.mjs:
- Around line 237-245: searchRecentCommits currently runs safeExec(`git log
main..HEAD ...`) per candidate and hardcodes "main", which can timeout and
misses repos not using main; instead, run a single git log once, detect the
correct base branch dynamically (e.g., resolve origin/HEAD or use git merge-base
to find a common ancestor) and cache that output for reuse. Refactor by
extracting a collector (e.g., collectRecentCommits or precomputeRecentCommits)
that calls safeExec a single time (no hardcoded "main"), stores the raw log, and
change searchRecentCommits to accept or query that cached log and then filter by
candidate; update callers that previously invoked searchRecentCommits repeatedly
so they use the precomputed log.

In `@packages/db/src/managed-data/managed-seed-data.ts`:
- Around line 1347-1350: The seeded constants IC2EWD_CAMPAIGN_KEY_STEM,
IC2EWD_GRANT_TASK_ID_PREFIX, IC2EWD_GRANT_TASK_KEY_PREFIX and
IC2EWD_GRANT_METHODOLOGY_KEY introduce new deterministic IDs/keys and can create
duplicate grant task rows if legacy "icewad" rows remain; before inserting the
new seeded rows in managed-seed-data.ts, detect any existing rows that use the
old stems (e.g. "icewad" prefix) and either migrate them to the new values
(update id/taskKey to the new IC2EWD_* values) or perform an idempotent upsert
that updates existing rows instead of inserting duplicates, and apply the same
fix for the other renamed constants around the 1414–1416 region so seeding is
migration-safe.

In `@packages/web/src/app/developers/page.logged-out.md`:
- Around line 87-88: The markdown contains an incomplete setup step: the line
"MCP Server URL for step 2:" is missing the actual URL or placeholder before the
next heading ("#### HEADS-UP: DEEP RESEARCH MODE"); update the content in
packages/web/src/app/developers/page.logged-out.md to include the correct MCP
Server URL (or a clear placeholder like "<MCP_SERVER_URL>") immediately after
"MCP Server URL for step 2:" so the ChatGPT setup step is actionable, and ensure
the value is shown before any follow-up instruction or heading.

In `@packages/web/src/lib/mcp-server.ts`:
- Around line 7910-7924: The admin fallback that sets existingTask from
adminVisibleTask returns only a partial record, which lets resolveTaskEconomics
fall back to defaults and causes attachDirectTaskImpactEstimate to overwrite
true economics; update the admin fallback (the prisma.task.findFirst that
assigns adminVisibleTask and the existingTask assignment) to either: 1) select
and load the full set of economics-related fields used by
resolveTaskEconomics/attachDirectTaskImpactEstimate (e.g., cash_cost, hours,
p_success, EV/probability/time-to-impact inputs), or 2) if those fields are not
present, fail closed by leaving existingTask undefined so the admin path does
not write new estimates; ensure you modify the query and the assignment logic
around existingTask/adminVisibleTask so complete economics inputs are available
before allowing admin-only updates.

---

Outside diff comments:
In `@packages/web/src/lib/mcp-server.ts`:
- Around line 6728-6756: The forbiddenBlockedTaskIds check incorrectly blocks
admins; update the filter that builds forbiddenBlockedTaskIds (which iterates
dependencyTasks and uses blockedTaskIds and task.createdByUserId !== userId) to
also exempt admins by checking hasAdminTaskWriteAccess(scopes, isAdmin) — i.e.,
only mark a blocked task as forbidden if task.createdByUserId !== userId AND the
caller does not have admin task write access (use
hasAdminTaskWriteAccess(scopes, isAdmin)) so admins can create prerequisites
that block other users' tasks.

---

Nitpick comments:
In `@packages/db/src/__tests__/seed.integration.test.ts`:
- Line 157: Add a negative regression check to ensure legacy "icewad:grant:"
task keys are not present: when verifying grant tasks (reference the
grantTaskKeyPrefix variable and the test assertions around it), add an assertion
that no keys start with or equal "icewad:grant:" (e.g., use the test framework's
negative containment/assertion method) so the test fails if old legacy keys
remain; apply the same negative check to the other similar spots noted (the
checks around lines referencing grantTaskKeyPrefix at the other two locations).

In `@packages/web/src/app/developers/page.logged-out.md`:
- Line 7: The page's metadata is missing a canonical URL; open the route's
metadata export in packages/web/src/app/developers/page.tsx (look for export
const metadata or export async function generateMetadata) and add a canonical
link (e.g., metadata.openGraph.url or metadata.alternates.canonical) pointing to
the absolute URL for /developers; if you use a shared helper (e.g.,
getCanonicalUrl or buildMetadata), update that generator to return a canonical
property using your SITE_URL/appConfig so the canonical is always populated for
this route.
- Line 57: The user-facing sentence in
packages/web/src/app/developers/page.logged-out.md contains an implementation
detail—specifically the phrase "delivery envelopes stay internal"—which should
be removed; update the sentence that currently reads "The agent posts task
comments for status updates, questions, and next steps. Comment posting handles
comment notifications; delivery envelopes stay internal." to a concise
user-focused line (e.g., keep that the agent posts comments and notifications
are handled) that omits any internal mechanism wording and ensures clarity for
users rather than developers.

In `@packages/web/src/lib/mcp-server.ts`:
- Around line 3770-3774: The schema documentation strings for
createTask.visibility, updateTask and deleteTask are out of date: update the
createTask.visibility description to explicitly state that the default PUBLIC
behavior for tasks assigned to an organization is allowed only for admin
callers, and update the updateTask and deleteTask descriptions to say that
admins may operate on PUBLIC and non-owned tasks (rather than “a private task” /
“one of your own tasks”); locate the doc strings attached to the createTask
visibility option and the updateTask/deleteTask operation descriptions (search
for "create a task. Visibility defaults to", "Update a private task", and
"Delete one of your own tasks") and revise their text accordingly, and mirror
the same wording changes in the other duplicated schema-description locations
where those strings appear.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a75f65ee-1234-4f9f-bfc0-9a8a2a0f20cc

📥 Commits

Reviewing files that changed from the base of the PR and between e277b7e and a070dd5.

📒 Files selected for processing (16)
  • .claude/hooks/enforce-cba-table-on-plan-files.mjs
  • .claude/hooks/enforce-feature-preexistence-check-on-autoplan.mjs
  • .claude/settings.json
  • TODO.md
  • packages/db/src/__tests__/seed.integration.test.ts
  • packages/db/src/managed-data/managed-iam-organization.test.ts
  • packages/db/src/managed-data/managed-iam-organization.ts
  • packages/db/src/managed-data/managed-seed-data.ts
  • packages/web/scripts/soft-delete-funding-tasks.ts
  • packages/web/src/app/developers/page.logged-out.md
  • packages/web/src/app/love/page.logged-out.md
  • packages/web/src/app/love/page.tsx
  • packages/web/src/app/mcp/authorize/page.tsx
  • packages/web/src/lib/__tests__/mcp-server.test.ts
  • packages/web/src/lib/mcp-scopes.ts
  • packages/web/src/lib/mcp-server.ts

Comment on lines +237 to +245
function searchRecentCommits(candidate) {
const log = safeExec(`git log main..HEAD --oneline --format=%h%x09%s`);
if (!log) return [];
const needle = candidate.toLowerCase();
return log
.split(/\r?\n/)
.filter((line) => line.toLowerCase().includes(needle))
.slice(0, 5);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid per-candidate git log main..HEAD; this can timeout and miss evidence.

Line 238 hardcodes main, and Line 274 calls this scan once per candidate. With a 4s command timeout and a 6s hook timeout, just a couple slow invocations can kill detection; repos not using main also return no commit hits.

💡 Proposed fix
 function searchRecentCommits(candidate) {
-  const log = safeExec(`git log main..HEAD --oneline --format=%h%x09%s`);
+  const log = safeExec(`git log ${BASE_REF}..HEAD --oneline --format=%h%x09%s`);
   if (!log) return [];
   const needle = candidate.toLowerCase();
   return log
@@
 }
 
 try {
@@
   const args = String(hookData?.tool_input?.args || "");
   if (args.includes("ACKNOWLEDGED-PREEXISTENCE")) process.exit(0);
+
+  const remoteHead = safeExec("git symbolic-ref --short refs/remotes/origin/HEAD").trim();
+  const BASE_REF = (remoteHead.replace(/^origin\//, "") || "main");
+  const commitLog = safeExec(`git log ${BASE_REF}..HEAD --oneline --format=%h%x09%s`);
@@
   for (const candidate of candidates) {
@@
-    const commitHits = searchRecentCommits(candidate);
+    const commitHits = (function searchRecentCommitsFromLog() {
+      if (!commitLog) return [];
+      const needle = candidate.toLowerCase();
+      return commitLog
+        .split(/\r?\n/)
+        .filter((line) => line.toLowerCase().includes(needle))
+        .slice(0, 5);
+    })();

Also applies to: 271-275

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/hooks/enforce-feature-preexistence-check-on-autoplan.mjs around
lines 237 - 245, searchRecentCommits currently runs safeExec(`git log main..HEAD
...`) per candidate and hardcodes "main", which can timeout and misses repos not
using main; instead, run a single git log once, detect the correct base branch
dynamically (e.g., resolve origin/HEAD or use git merge-base to find a common
ancestor) and cache that output for reuse. Refactor by extracting a collector
(e.g., collectRecentCommits or precomputeRecentCommits) that calls safeExec a
single time (no hardcoded "main"), stores the raw log, and change
searchRecentCommits to accept or query that cached log and then filter by
candidate; update callers that previously invoked searchRecentCommits repeatedly
so they use the precomputed log.

Comment on lines +1347 to +1350
const IC2EWD_CAMPAIGN_KEY_STEM = "ic2ewd";
const IC2EWD_GRANT_TASK_ID_PREFIX = `${IC2EWD_CAMPAIGN_KEY_STEM}-grant`;
const IC2EWD_GRANT_TASK_KEY_PREFIX = `${IC2EWD_CAMPAIGN_KEY_STEM}:grant`;
const IC2EWD_GRANT_METHODOLOGY_KEY = `${IC2EWD_CAMPAIGN_KEY_STEM}-one-dollar-grant`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent duplicate grant tasks when renaming seeded IDs/keys.

Switching to new deterministic id/taskKey values without migrating legacy rows means re-seeding existing environments can leave old icewad rows active and create new ic2ewd rows in parallel.

💡 Suggested migration-safe pattern
   for (const [index, foundation] of foundationGrantOrganizations.entries()) {
     const slug = slugify(foundation.name);
@@
+    const existingGrantTask = await prisma.task.findFirst({
+      where: {
+        deletedAt: null,
+        parentTaskId: TREATY_PARENT_TASK_ID,
+        assigneeOrganizationId: organization.id,
+        OR: [
+          { taskKey: `${IC2EWD_GRANT_TASK_KEY_PREFIX}:${slug}` },
+          { taskKey: `icewad:grant:${slug}` },
+        ],
+      },
+      select: { id: true },
+    });
+    const grantTaskId =
+      existingGrantTask?.id ?? `${IC2EWD_GRANT_TASK_ID_PREFIX}-${slug}`;
+
     await createTaskWithImpact({
       task: {
-        id: `${IC2EWD_GRANT_TASK_ID_PREFIX}-${slug}`,
+        id: grantTaskId,
         taskKey: `${IC2EWD_GRANT_TASK_KEY_PREFIX}:${slug}`,

Also applies to: 1414-1416

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/src/managed-data/managed-seed-data.ts` around lines 1347 - 1350,
The seeded constants IC2EWD_CAMPAIGN_KEY_STEM, IC2EWD_GRANT_TASK_ID_PREFIX,
IC2EWD_GRANT_TASK_KEY_PREFIX and IC2EWD_GRANT_METHODOLOGY_KEY introduce new
deterministic IDs/keys and can create duplicate grant task rows if legacy
"icewad" rows remain; before inserting the new seeded rows in
managed-seed-data.ts, detect any existing rows that use the old stems (e.g.
"icewad" prefix) and either migrate them to the new values (update id/taskKey to
the new IC2EWD_* values) or perform an idempotent upsert that updates existing
rows instead of inserting duplicates, and apply the same fix for the other
renamed constants around the 1414–1416 region so seeding is migration-safe.

Comment on lines +87 to +88
- MCP Server URL for step 2:
#### HEADS-UP: DEEP RESEARCH MODE
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing server URL in ChatGPT setup step blocks completion.

Line 87 introduces “MCP Server URL for step 2:” but no URL follows before the next heading on Line 88. This leaves the setup flow incomplete.

Suggested patch
 - MCP Server URL for step 2:
+- http://localhost:3001/api/mcp
 #### HEADS-UP: DEEP RESEARCH MODE

As per coding guidelines, “Make the action obvious, then show the value to them for doing it.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- MCP Server URL for step 2:
#### HEADS-UP: DEEP RESEARCH MODE
- MCP Server URL for step 2:
- http://localhost:3001/api/mcp
#### HEADS-UP: DEEP RESEARCH MODE
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/app/developers/page.logged-out.md` around lines 87 - 88, The
markdown contains an incomplete setup step: the line "MCP Server URL for step
2:" is missing the actual URL or placeholder before the next heading ("####
HEADS-UP: DEEP RESEARCH MODE"); update the content in
packages/web/src/app/developers/page.logged-out.md to include the correct MCP
Server URL (or a clear placeholder like "<MCP_SERVER_URL>") immediately after
"MCP Server URL for step 2:" so the ChatGPT setup step is actionable, and ensure
the value is shown before any follow-up instruction or heading.

Comment on lines +7910 to +7924
if (!existingTask && isAdminWriter) {
const adminVisibleTask = await prisma.task.findFirst({
where: { deletedAt: null, id: a.taskId as string },
select: {
contextJson: true,
createdByUserId: true,
deadlinePolicy: true,
estimatedEffortHours: true,
id: true,
isPublic: true,
},
});
existingTask = adminVisibleTask
? (adminVisibleTask as PersonalQueueTaskRecord)
: undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't let admin-only updates clobber existing economics.

When getTaskDetailData() cannot load the task, the admin fallback only fetches a partial record. resolveTaskEconomics() then falls back missing economics inputs to defaults, and attachDirectTaskImpactEstimate() writes a new current estimate from those defaults. An admin changing only cash_cost, hours, or p_success on someone else’s task can silently overwrite the existing EV/probability/time-to-impact data.

Fail closed until the admin path loads the full economics inputs
             const economicsPatch = hasEconomicsPatch(a);
+            if (economicsPatch && !existingDetail && isAdminWriter) {
+              return err(
+                "Admin economics updates require a full task detail payload before recomputing impact estimates.",
+              );
+            }
             const economics = resolveTaskEconomics(a, existingTask);

Also applies to: 7981-7982, 8134-8144

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/lib/mcp-server.ts` around lines 7910 - 7924, The admin
fallback that sets existingTask from adminVisibleTask returns only a partial
record, which lets resolveTaskEconomics fall back to defaults and causes
attachDirectTaskImpactEstimate to overwrite true economics; update the admin
fallback (the prisma.task.findFirst that assigns adminVisibleTask and the
existingTask assignment) to either: 1) select and load the full set of
economics-related fields used by
resolveTaskEconomics/attachDirectTaskImpactEstimate (e.g., cash_cost, hours,
p_success, EV/probability/time-to-impact inputs), or 2) if those fields are not
present, fail closed by leaving existingTask undefined so the admin path does
not write new estimates; ensure you modify the query and the assignment logic
around existingTask/adminVisibleTask so complete economics inputs are available
before allowing admin-only updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants