Skip to content

feat(visibility): demote-on-downgrade + /verify-brand use resolver (#4159 Stage 1.2) - #4301

Merged
bokelley merged 2 commits into
mainfrom
bokelley/4159-stage1-2-visibility-enforcement
May 9, 2026
Merged

feat(visibility): demote-on-downgrade + /verify-brand use resolver (#4159 Stage 1.2)#4301
bokelley merged 2 commits into
mainfrom
bokelley/4159-stage1-2-visibility-enforcement

Conversation

@bokelley

@bokelley bokelley commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Stage 1.2 of #4159. Two more read sites migrated to getBrandPrimaryDomain(orgId):

  1. demotePublicAgentsOnTierDowngrade (server/src/services/agent-visibility-enforcement.ts) — the visibility-demote path that fires when an org's tier loses API access. Drops primary_brand_domain from the FOR-UPDATE SELECT; brand.json manifest cleanup now reads the brand-primary via the resolver after commit.

  2. /verify-brand (server/src/routes/member-profiles.ts) — the brand-claim verifier endpoint. Same swap.

Lock-release reasoning (same as Stage 1.1)

The FOR UPDATE on member_profiles is load-bearing for the agents JSONB read/write. Brand-primary ownership is enforced at write time elsewhere (member self-service PUT verifies membership; brand-claim verify proves DNS control). A concurrent setPrimaryDomain (Stage 3) racing this read lands old-or-new — both states the org legitimately controls.

Tests

  • Unit test agent-visibility-enforcement.test.ts updated to mock the resolver. Tests that depend on a brand domain set the mock per-case.
  • 60 tests pass across the 4 affected files: visibility-enforcement (10), visibility-e2e (14), member-agents-api (25), brand-domain-resolver (11).

What's left

Site Reads Notes
member-profiles.ts GET-resolution paths (lines ~695, ~748, ~1995) 5 Response-shape sites; deferred to Stage 2 with the column drop
http.ts 11 Dashboard/list views — natural fit for batched resolver
services/brand-property-parse.ts 4 Brand-property crawler
services/brand-identity.ts 6 Mostly write-side; minimal reads to migrate
services/announcement-drafter.ts 1 Addie announcements
routes/brand-feeds.ts 4 Public brand registry feeds
Other addie/MCP/jobs ~6 Profile-completion-nudge, announcement-trigger, member-tools, brand-property-tools, registry-api, si-chat, referrals

Next PR will likely target dashboard reads in http.ts (good fit for the batched resolver shipped in PR #4299).

🤖 Generated with Claude Code

bokelley and others added 2 commits May 9, 2026 13:19
…4159 Stage 1.2)

Migrates two more read sites:
- agent-visibility-enforcement.ts: drop primary_brand_domain from the
  FOR-UPDATE SELECT, read via resolver after commit. The brand.json
  manifest cleanup still runs against the resolved domain — no
  behavior change.
- member-profiles.ts /verify-brand: replace profile.primary_brand_domain
  with getBrandPrimaryDomain. Profile read still validates existence
  (404 path); brand-domain check moves to the resolver.

Same lock-release reasoning as Stage 1.1 (PR #4300): the FOR UPDATE on
member_profiles is load-bearing for the agents JSONB read; brand-primary
ownership is enforced at write time elsewhere.

Unit tests for visibility-enforcement updated to mock the resolver.
60 tests pass across visibility-enforcement (10), visibility-e2e (14),
member-agents-api (25), brand-domain-resolver (11).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Comment in /verify-brand explaining why the existence check is still
  separate from brand-primary lookup (404 vs 400 distinction).
- TODO in agent-visibility-enforcement referencing #4159 Stage 3: when
  setPrimaryDomain writer lands, it should own old-primary-manifest
  cleanup rather than depending on a tier-downgrade race.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley
bokelley merged commit fdf824f into main May 9, 2026
13 checks passed
@bokelley
bokelley deleted the bokelley/4159-stage1-2-visibility-enforcement branch May 9, 2026 17:31
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.

1 participant