Appearance
Current architecture state — the single index
Read this first, and trust it over any other page. Maintained 2026-08-13. Purpose: one place that states what is decided, what is built, and what is open — so no document can silently become the source of truth for something it does not govern.
The reason this page exists: the three-user-category principle was verified on 2026-08-07 to exist in exactly five files and to have reached no ADR and no overview page 24 hours after being decided (QRS-384). Across 124 portal documents, per-document freshness is not achievable by discipline. A single authoritative index plus supersession banners is.
⚠ AND THIS PAGE GOES STALE TOO — check the date above against
git logbefore trusting a specific claim. On 2026-08-12 it still read "Maintained 2026-08-08" while 13 migrations had landed since, and it stated thatchatandmessages"are all absent" when both had shipped the previous day. That is this page's own thesis applied to itself, not an argument against it: one index drifting is far better than 124 pages drifting privately. The operating rule: read the Maintained date, then diff it againstgit logand the newestrelease.jsonchange records. Where they disagree, the migrations and the change records win, and updating this page is part of the change that outdated it.📏 A full ground-up re-measurement of Dev was taken on 2026-08-26 and lives at Admin Portal — backend readiness. It is newer than this page's Maintained date and every claim in it was read from the live project (55 tables · 45 policies · 69 functions · 10 Edge Functions · 0 views · zero table grants to
anon/authenticated). Where the two disagree, that page wins on backend facts — including three corrections to already-tracked rows (QRS-694 is closed in substance, QRS-643's symptom is fixed) and the headline finding that there is no platform-admin identity, no admin RPC, no admin policy, andaudit_loghas zero rows and no admin writer (its one writer isset_my_primary_context).🟢 Since 2026-08-13 the COUNTABLE half of that discipline is automated.
npm run check:claims(QRS-642) measures the repo on every push and fails ifCLAUDE.md's generated inventory disagrees — Edge Functions, migrations, real-vs-stub data seams, gates, workflows, ADRs, merchant features,@/uiprimitives, portal page counts, and the merchant-mobile screen ledger. So a stale number is now a failed push rather than something a reader has to notice. ⚠ A stale JUDGEMENT still is not — no gate can decide whether a decision recorded here is still the right one, so the date check above remains necessary. Arithmetic is automated; reasoning is not.Delta since the 2026-08-12 pass, all verified against Dev on 2026-08-13: the reminders backend is live · sign-in was BROKEN for five days on every surface and is fixed (QRS-636 — the auth-context read called an RPC that exists only in
_archive_pre_v2/) · slug claim was broken and is fixed (QRS-640), with thevalidate-user-inputEdge Function deleted and availability moved toresolve_setu_card_slug_status(text)· Google OAuth verified end-to-end ·provision_merchant_workspaceverified atomic by a rolled-back live probe. Still broken: email OTP (QRS-285, SMTP 535) and dark mode on the web export (QRS-639).
⭐ ADDED 2026-08-25 — this page is 12 days stale, and here is exactly where
A whole-product revalidation was run on 2026-08-25 and measured this page against the repo. Product & architecture revalidation is the result; it holds the commercial and prioritisation half. Six corrections belong here, so they are recorded here rather than left in a sibling section:
| This page says | 🧮 Measured 2026-08-25 |
|---|---|
| FACETS are "unsolved and retrofit-expensive" (the 2026-08-10 banner, QRS-498) | ✅ Solved. catalog_items.attributes jsonb with @> containment matching and jsonb_each_text facet counting. Multi-select buyer filters run on real data |
| "Not built: payouts … R2 media" | ✅ Both built. payout_accounts, payout_transfers and platform_settlements exist; R2 upload and card render were verified working (QRS-833) |
| The eleven primitives are listed as the closed set with no build status | ⚠ 3 of 11 have table substrate (Catalogue, Fulfilment, Location), 2 are partial (Recurrence is user-owned; Resource is stock-commitment only), and 6 have none. So the time and expertise archetypes have no substrate at all — full table |
| Card analytics "should be read as not working" (QRS-734) | ⚠ Still true, seven days on. The beacon in apps/web/src/tiers/public/features/setu-card/analyticsBeacon.ts still names track-card-event, which lives only in _archive_pre_v2/ and is not among the 10 live functions |
| The decision ledger cites ADR-0029 | ⚠ QRS-887 — ADR-0030 (tenant communication identity and prepaid credits) also exists and is not in the ledger |
| No row for the desktop console | ⚠ QRS-886 — 4 of 16 designed desktop merchant-console screens are built in DOM — a second implementation of the merchant product, against Accepted ADR-0011. Unreconciled; see desktop-journey-readiness and the challenge |
Two absences worth adding to §2's "not built" list, because nothing anywhere currently names them as blockers: 🧮 RBAC is 0% (no roles, permissions, user_roles, platform_admins, no is_admin(); workspace_members.role_key is text held to five values by an interim CHECK, owner · admin · manager · member · viewer (20260808210000_v2_production_hardening.sql:210-211), with no FK and no roles table) and 🧮 there is no scheduler at all (zero cron.schedule calls, and outbox is drained by nothing) — QRS-885.
🔎 The pattern, which is this page's own thesis one level up: check:claims now catches stale numbers on every push, so every item above is a stale claim — a decision that moved, an enumeration that got shorter, a gate asserted and never wired. Arithmetic is automated; judgement is not. That is the argument for revalidating on a trigger rather than on an intention.
1. Decision ledger — what governs what
| Area | Governing decision | Status |
|---|---|---|
| Source of truth | qr-setu-dev is greenfield. Prod is disposable and is never a design reference. The ..._baseline_schema_from_prod squash is retired | CLAUDE.md § "Second rule" · QRS-374 |
| User categories | Three — solo owner · enterprise · individual consumer — plus QRSETU staff. Six user types, four surfaces | user ecosystem · CLAUDE.md |
| Platform schema | Principal = user · workspace = business tenant · cards is its own public table · text keys | ADR-0020 |
| Feature control | 8 scopes × 3 axes · applicability derived from composition · grants sparse · source · on_exceed | ADR-0021 |
| Org sharing | Resolution over the org as a union, never duplication · per-type flags default off | ADR-0022 |
| Org hierarchy | Workspace tree + materialized path (depth 6) · seats license users · location ≠ business unit | ADR-0023 |
| Enterprise ops | Sharing down, oversight up · customer at the showroom · Asset primitive · divisions are tree nodes | ADR-0024 |
| Campaigns | Central, targeted, scheduled, measured · first-party offer ≠ inert promo_slot · scheduled purge | ADR-0025 |
| Industry scope | ~45 industries · 3 archetypes · 11 primitives · the ≥3-industry gate | industry scope |
| Setu Card render | One DOM renderer · manifest templates · palette axis · lossless switching | ADR-0019 |
| Public exposure | anon reads cards and nothing else · no policy grants by role alone | ADR-0014 + ADR-0020 D2/D4a |
| Communications | WhatsApp via Meta Cloud API direct, no BSP · one envelope, one dispatcher · consent fails closed · nothing built (2026-08-21) | ADR-0029 · communications |
⭐ ADDED 2026-08-18 — the commercial half of the index now exists
This page has always answered "what is decided, built and open" about the architecture. It has never answered the same question about the market, and until 2026-08-18 nothing in the portal did: ONDC, Justdial, WhatsApp Business, Khatabook, Dukaan and Vyapar appeared nowhere across the 139 pages that existed before it. Strategy: competitor analysis & market positioning is now the index for that half, and it carries its own revisit triggers.
Three of its findings change items on THIS page, so they are recorded here rather than left in a sibling section:
- ⚠ QRS-734: card analytics record NOTHING. The beacon posts to
track-card-event, which exists only in_archive_pre_v2/; a livelist_edge_functionsprobe on 2026-08-18 returns nine ACTIVE functions and it is not among them, andsendBeaconswallows the failure. This page's "Card analytics taxonomy + beacon (M11)" row should be read as not working, not merely as an unwired sink. - ✅ Two rows below are now out of date in the GOOD direction (both verified 2026-08-18):
setAnalyticsSinkis called, byapps/web's card beacon; andplace-public-orderhas client callers — the buyer order panel shipped ina45b21f/06c6880. Payments status's blocker 5 is closed. - ⚠ No reviews/ratings table exists anywhere, and reputation is not among the eleven primitives — argued as a genuine scope gap in product gaps G3.
The eleven primitives (the closed set — a new one needs ≥3 industries in writing): Catalogue · Party · Schedule · Recurrence · Fulfilment · Ledger · Balance · Location · Resource · Asset · Campaign.
2. What is actually BUILT — verified, not inferred
⭐ THE WAVE 1 BASELINE IS APPLIED ON DEV — 2026-08-08, verified not assumed
The owner ran v2_apply_all.sql. Measured on Dev afterwards: 26 tables · 16 functions · 22 policies · 11 triggers · 77 indexes · 15 migration rows, RLS on every table, versions matching filenames with no orphans, and zero tables directly readable by anon/authenticated. Seeds all present (753 reserved slugs, 11 primitives, 3 archetypes, 14 industries, 3 plans, 18 features, 8 scopes, 34 grants). The resolver was probed live and the dairy-vs-boutique applicability derivation holds with zero grant rows.
One defect found and fixed (QRS-420): touch_updated_at() shipped with EXECUTE granted to PUBLIC and a mutable search_path. Fixed by 20260808220000_v2_touch_updated_at_hardening.sql; check:sql's Rule 3a was widened to all functions (measured: zero new noise) so the class cannot recur.
Store is unblocked. The remaining work is application-side, not schema-side.
Everything in §1 except the last two rows is DESIGN. Do not read a decision as a feature.
| Built & running on Dev | Notes |
|---|---|
| Onboarding (mobile), Google sign-in | Email OTP is broken — SMTP 535, QRS-285/076 |
Public Setu Card route + manifest renderer (apps/web) | M14: a11y, layout-invariants, visual gates |
Catalog editor (M8) — manage-item EF, RPCs, mobile list/add/edit | On profile_items, which the baseline replaces |
| Capability gating (S1) | Superseded by ADR-0021; client contract useFeature() survives |
feature_flags (S0) + useFlag() | ⚠ Table dropped on Dev 2026-08-08 (QRS-412). Both consumers fail safe and all flags were seeded dark, so zero behaviour change — but the platform now has no revert lever until Wave 1's availability axis lands. Theoretical while nothing is in production; must be back before anything ships. |
setu_card_templates registry, palettes, check:setu-card-templates | ⚠ Registry table dropped on Dev 2026-08-08 (QRS-411). The card still renders — ADR-0019 kept content in the repo and only metadata in the DB. check:setu-card-templates is pure file validation and unaffected. |
| Card analytics taxonomy + beacon (M11) | setAnalyticsSink still never called — every track() is a no-op |
Not built, despite appearing in docs: payouts · CRM/leads · scheduling · admin panel · enterprise anything · campaigns · R2 media. (⚠ "cache invalidation on any write path (G1/G2)" was on this list and is now WRONG — see the 2026-08-12 banner below. It is wired into manage-item and manage-setu-card.)
⭐ ADDED 2026-08-12 — chat + reminders shipped to Dev, and cache invalidation is real
Built and DEPLOYED to qr-setu-dev since the 2026-08-10 banner below (Dev was 13 migrations behind and is now current, so orders/payments/chat are live there too, not merely written):
| Now built | Note |
|---|---|
chat + messages | Shipped 2026-08-11 (CR-26.0.1-22/23/24). ⚠ The banner below saying they "are all absent" is superseded — it was written before they landed. |
Reminders backend — reminders, reminder_occurrences, reminder_categories, get_reminders, get_reminder_categories, manage-reminder EF | Shipped and deployed 2026-08-12 (QRS-564, CR-26.0.1-27/28). remindersService is the 9th real packages/data service. Reminders are USER-owned, the only v2 feature that is — workspace_id is a nullable tag, because a category-3 consumer has zero workspaces and an employee's personal notes must stay outside the ADR-0023 oversight path. |
| Cache invalidation (G1) | _shared/cardCache.ts is called by manage-item and manage-setu-card, purging Cache-Tag: card-{slug}. ⚠ Two gaps remain, so G1/G2 is NOT closed: Cloudflare credentials are unset on Dev (QRS-306) so only the failure branch is ever exercised, and apps/web served no Cache-Tag at all until QRS-569. Both halves had to work and neither did. |
Four defects found on 2026-08-12, all previously invisible to every gate:
- QRS-568 —
apps/webdid not render at all; every SSR route 500'd on two React copies (Expo's exact 19.2.3 pin vs^19.2.7). Fixed byssr.noExternal: ['react-router'];resolve.dedupewas measured not to fix it. Root cause (two React versions) untouched — a dependency-policy decision. - QRS-569 — the public card served no
Cache-Controland noCache-Tag: React Router drops loader headers from a document response without aheadersexport. Edge caching and the whole ADR-0027 purge-by-tag design were both silently inert. - QRS-573 —
_sharedwas writing to droppedpublic_page_ops_*tables:logging.tson every log line in every EF (one spurious error per real line for four days) andcardCache.tson every card write. Both removed; stdout was always the real path. - QRS-570 — a
Docs-Impact:trailer waived the documentation debt of all 82 commits in a push, not just its own. Now scoped per commit.
⚠ QRS-572: never run npm audit fix --force here — it proposes expo → 53.0.27 and react-native → 0.72.17 (back four major SDK versions) to patch a build-time image-size that has no fix at any version. Triage Dependabot by manifest, not severity: of 43 alerts, ~14 were in retired legacy/ and exactly one reached a shipped artifact.
⭐ ADDED 2026-08-10 — the transactional layer started, and the CONSUMER side is now specified
Built since: orders/order_items/payments/payment_events + offline providers (QRS-480, QRS-484), 73 pgTAP assertions green. ⚠ payments is INERT until payout_accounts exists.
⚠ SUPERSEDED 2026-08-12 (see the banner above): chat and messages shipped 2026-08-11. As written on 2026-08-10 this said: Of the five consumer actions, only orders exists. Still absent: bookings, appointments, enquiries and parties are all absent, and notification transport is broken on every channel (push unbuilt, email 535) — which makes transport a hard prerequisite of the consumer surface, not an adjacent workstream (QRS-504).
Consumer Marketplace — approved design, nothing built (QRS-490…QRS-507), spec + send-ready prompts at Consumer Marketplace Spec:
- It lives IN the app (
apps/mobile, a third tier besideuser/admin), whichoverview/user-ecosystem.mdalready said. The public web directory is a separate, additional surface — acquisition and SEO, versus in-app engagement and retention. Not alternatives. - ⚠ The app must never render a vendor's card TEMPLATE. The manifest is a repo file, so the database cannot supply layout at all.
apps/webresolves a section list; native renders composition + brand and not per-block variants or ornament, with mandatory degradation plus "View full card" (QRS-501).check:parityR8 guards this. - Discovery mode is an INDUSTRY property, not an archetype one — archetype gives the action verb, and
expertisesplits (QRS-505). The unfiltered landing is category-first. - ⚠ Unsolved and retrofit-expensive: FACETS (QRS-498). Typed columns per facet is O(industries) which ADR-0020 forbids;
attributes jsonbis unfilterable which ADR-0010 forbids. Two standing rules point opposite ways. Decide before the item feed exists. - ⚠ No discovery read of any kind exists. Every public read is slug-keyed, so a marketplace is a new access class with a new scraping surface, and no policy may be widened to
TO authenticated(QRS-491). Location storage exists (locationshas pincode + coordinates) and is not publicly projected (QRS-492).
The rest of the consumer ecosystem is PARKED, deliberately, with its reasoning intact — see the tracker's "Upcoming features — the consumer ecosystem" section (QRS-528…QRS-533): consumer subscriptions and scheduled life, QR tools as an acquisition surface, create-and-share (biodata, invitations), a Shared hub, and targeted promotional placement. Highest priority for the phase after the Ganapati season; none of it is R1. ⚠ Do not read the parking as deferral by default: QRS-528 carries the flywheel argument (consumers → marketplace → vendor value → subscription adoption → enterprise leverage), and QRS-531 is supply-free and therefore the only consumer-acquisition channel that works before the marketplace has inventory.
Dev dropped to 37 tables on 2026-08-08 by the owner (QRS-410, QRS-411) — public_page_ops_*, the subscription tables, bio_pages, bio_links, setu_card_templates, feature_flags. All were on the baseline's drop list. One test breaks and is deliberately not patched: anon_least_privilege_test.sql asserts the bio tables exist; it is rewritten wholesale by the baseline, since ADR-0020 D2 makes that whole apparatus unnecessary rather than better-tested.
Orphaned as of 2026-08-08 (QRS-410): the four public_page_ops_* Edge Functions are deployed and referenced in supabase/config.toml but their tables were dropped on Dev by the owner. They are retired by the v2 baseline — the transactional outbox replaces the cache-ops mechanism — so they are removed rather than repaired. manage-reminder's quota lookup degrades to its default and is rewritten when plans/subscriptions land.
3. Decisions — resolved 2026-08-08, and what remains
The three blockers are settled (owner delegated 1 and 2, confirmed 3 on 2026-08-08):
| # | Decision | Resolution |
|---|---|---|
| 1 | Plan / tier vocabulary | free · pro · enterprise, plans.key text PK, with rank 0 / 100 / 300. ⚠ The rank gaps are the point — inserting a tier later (a business step between Pro and Enterprise for a multi-outlet dairy) is one row, with no renaming and no data migration. The three prior vocabularies are retired: none was in real use. plans.audience (solo | organization) keeps seat-based pricing out of a solo merchant's picker. |
| 2 | workspaces, not businesses | The tree contains nodes that are demonstrably not businesses — a region, a division ("Thane Sales"), a brand shell — so businesses would be actively wrong for those, and a schema should read like the domain it models. The UI still says "your business": that is presentation, and @qrsetu/i18n already mediates every string, so the table name and the label need not match. |
| 3 | Three archetypes | goods (a stocked item) · time (a slot) · expertise (an enquiry). ecommerce_cart and catalog_informational were compositions, not archetypes (QRS-392) — free to collapse only while greenfield. |
Still open, none of them blocking Wave 1:
| Decision | Blocks | Status |
|---|---|---|
| Launch date — 15 Aug is incompatible with the redesign | Release planning | 🟠 Assumed superseded; confirm |
| MLM / direct-selling vs the payment aggregator's restricted list | Whether that vertical can take payments | 🟡 Verify before payments |
| Cloudflare R2 provisioning (bucket, Images toggle, scoped token) | Store media only, not Wave 1 schema | 🟡 Owner-provisioned |
4. Pre-Store validation — the answer to "what must happen first"
⚠ The decisive finding: Store cannot meaningfully resume before the baseline
Every table the Store touches is being replaced. Resuming on today's schema means writing it twice:
| Store depends on | Today | After baseline |
|---|---|---|
| The item table | profile_items | catalog_items |
| The owner | profiles | workspaces |
| Gating | get_my_capabilities() | resolve_features() |
| Public render | get_public_profile_by_slug | cards |
| Media | (none) | media + R2 |
| Stock | a counter | per-period, location-aware |
M8's editor UI is largely salvageable; its data layer is not.
But Store does NOT block on the whole baseline — only ~60% of it
The primitives split cleanly. Store needs Wave 1; Party, Schedule, Recurrence, Fulfilment, Ledger, Balance, Asset and Campaign are Wave 2 and can follow.
| Wave 1 — required before Store | Why |
|---|---|
users · workspaces (+parent_id/path) · workspace_members | The owner of every catalogue row |
cards (+ card_links, card_hours) | Where the catalogue renders publicly |
industries · archetypes (+ composition) | Which Store features apply |
features · feature_grant_scopes · feature_grants + resolve_features() | Gating, with the axes separated |
catalog_items · catalog_categories · catalog_item_variants · catalog_item_media | The Store itself |
media (two-phase pending→ready) + R2 presign | Product images |
locations | Stock is per-location or the multi-outlet case breaks |
outbox (+ scheduled_for) | Cache invalidation — G1, else edits appear to do nothing |
RLS + (select auth.uid()) discipline + indexes | QRS-382 |
| Baseline-critical columns that are unfixable later | tax (QRS-387) · UoM + numeric qty (QRS-388) · ledger.unit (QRS-405) · analytics_events.campaign_id + source_campaign_id (QRS-403) |
Foundational gaps by the owner's own categories
| Category | Required before Store? | What |
|---|---|---|
| Client-side architecture | 🟡 Partial | useFeature() public API survives; its service and resolver are replaced. Screens repointed from profileService→workspace services |
| Navigation / feature gating | 🟡 | Action launcher + /create retirement (S6) is independent of the baseline — can proceed either side |
| Archetype / industry mapping | 🔴 Yes | Text keys, 3 archetypes, compositions per industry. Decision #3 |
| Feature entitlement infra | 🔴 Yes | features + feature_grants + resolver. Blocked on decision #1 |
| Enterprise / location hierarchy | 🟠 Structure yes, features no | parent_id/path/locations columns must exist (retrofitting is a rewrite); org sharing and oversight can follow |
| Database schema | 🔴 Yes | Wave 1 above |
| Edge Functions | 🔴 Yes | manage-item rewritten onto catalog_items + assertFeature; new manage-item-media |
| Storage / media | 🔴 Yes | R2 + presign + media two-phase + orphan sweeper. Owner must provision first |
| Permissions / RLS | 🔴 Yes | Relationship-scoped policies, consumer-isolation pgTAP, index discipline |
| Subscription / billing | 🟢 No | plans/billing_accounts/subscriptions/seats are Wave 2 — Store works ungated at first |
| Other | 🟠 | Sonar baseline bootstrap (QRS-256) before apps/web grows; release.json target paths (QRS-343) before G2 |
Recommended sequence
Settle decisions #1-#3— done 2026-08-08.- 🔴 OWNER ACTION: run
supabase/scripts/v2_reset_dev_schema.sqlin the Dashboard SQL Editor. The full audit (QRS-413) found zero of Dev's 37 tables should be kept, and a cascade drop is required because 37 functions would otherwise be orphaned (PL/pgSQL bodies are not dependency-tracked).drop schema public cascadeis refused by the auto-mode classifier, so this one step is yours. The script carries a project-confirmation pre-check and agen_random_uuid()post-check. Wave 1 baseline— AUTHORED 2026-08-08 (QRS-414): 11 migrations, 24 tables, 15 functions, a 36-assertion pgTAP suite (QRS-415),check:sqlandcheck:readmesboth EXIT=0. Not yet applied — it needs step 2 first. — archive the old series, author the new one, rebuild Dev, pgTAP both directions. ~8–9d.- Confirm the foundation — gates green, live probes on Dev, three-surface pass.
- Resume Store on the new schema — M8's UI adapted, full-field editor, media, location-aware stock. ~3d.
- Wave 2 as the roadmap demands — Party/Ledger/Balance for CRM and khata, Schedule/Fulfilment for services, Campaign for Enterprise.
Do not build Store first and migrate it. That is the position the repo is already in with profile_items, and it is what this whole review sequence exists to avoid repeating.
5. Documents superseded, and where the truth now lives
| Stale document | Superseded by |
|---|---|
overview/target-end-users.md "two audiences" | user ecosystem — banner added |
| ADR-0001 tenancy shape | ADR-0020 D1/D4 — banner added |
| ADR-0007 entitlement storage | ADR-0021 — banner added |
| ADR-0009 capability storage + "config not code" promise | ADR-0020/0021 + industry scope §A1 — banner added |
| ADR-0011 missing the 4th tier (org-admin portal) | Amendment owed — banner added |
ADR-0014 authenticated population | ADR-0020 D4a — banner added |
| ADR-0016 scope (platform recurrence, not reminders) | QRS-380 — banner added |
| ADR-0004 first-party vs third-party promo | ADR-0025 D1 |
architecture/database.md | REWRITTEN 2026-08-08 — now carries the real 26-table v2 ER diagram |
features/catalog.md | This page + ADR-0020 — banner added |
releases/26.0.1/* | Re-scoped once decision #4 lands |
The 2026-08-08 documentation audit (QRS-416)
The owner noticed stale BioLink references and asked for a broader audit rather than a single-page fix. That was the right call: the BioLink mentions were the smallest finding.
Rewritten from scratch (each had been describing the retired architecture as current): architecture/tiers.md · overview/platform.md · overview/glossary.md · index.md · architecture/database.md · overview/target-end-users.md (retired to a pointer). Extended: overview/user-ecosystem.md — five parser-validated diagrams mapping every user type to real tables. Corrected: overview/product-vision.md, both Claude Design prompts, guides/coding-standards.md. 18 supersession banners added, incl. ADR-0005/0006/0012.
Three findings worth carrying, because each says something this page did not:
architecture/tiers.mdhad no warning at all and was linked from the portal home as step 4 of "Start here". So an index is necessary but not sufficient — this page tells a reader where truth lives; it cannot stop a stale page from being recommended to them. Both are needed, and only one is enforceable.- A stale prompt is worse than a stale page.
design-system/pdpr-prompt.mddescribed BioLink as something to design for — and it is sent to Claude Design, so it does not merely mislead a reader, it manufactures designs for a deleted product. - Two overview pages contradicted each other about the flagship vertical.
overview/target-end-users.mdmade restaurants/cafés flagship Wave 1;overview/industry-scope.mdexcludes them, with a reason. Fixed by retiring the older page rather than reconciling two lists — two industry lists is the QRS-249/284/287 duplicate-source-of-truth defect applied to docs.
Now gated: npm run check:docs (QRS-417) — 12 retired-vocabulary groups, historical records and banner text exempt by design, ratchet baseline with a reason per file, in pre-commit and CI. Also found: one portal diagram that had never rendered (QRS-418).
Anything not listed here that contradicts §1 should be treated as stale and reported, not followed.