settings-registry-alignmentrun.md00_intake/stub.mdThe settings section invents arbitrary key/value datapoints that don't correspond to real platform
settings. The platform has a fixed set of 12 known settings defined in SETTINGS_REGISTRY (keys,
categories, types, defaults) — the blueprint should only ever propose those, not made-up settings.
Constrain the settings blueprint to the canonical settings registry: draft only the registry's known
keys, each with its correct category, type and default, seeded from tenant-defaults, with the AI
adjusting values from the source where meaningful and the operator confirming. Contract, prompt,
review-panel editable fields, and commit all reflect the registry (commit already targets
tenant_settings).
SETTINGS_REGISTRY (no invented settings).key, category, value (typed to the entry's
type) and description.tenant_settings rows (unique per key) that pass the key pattern and type.packages/services/src/db/services/tenant-setting/registry.ts
(12 keys across general / sla / matching / escalation / commercial / coverage / marketSignals). Seed
wiring in db/seed/tenant-defaults.ts. The model is db/models/tenant-setting.ts
(key / category / value / description).packages/services/src/ai/onboarding/{contract.ts,prompt.ts,analyse-source.ts},
packages/services/src/db/services/onboarding-blueprint/commit.ts (the settings branch),
apps/web/components/onboarding/types.ts (settings SECTION_META); reference
tenant-setting/registry.ts.01_define/output/spec.mdThe AI onboarding concierge drafts a per-tenant blueprint across six sections, but its settings
section invents arbitrary key/value datapoints with no home in the platform. The platform already has
a canonical registry — SETTINGS_REGISTRY in tenant-setting/registry.ts (12 keys, each with a
category, type and default) — that every domain read and the tenant seed resolve against. The
blueprint ignores it: the extraction contract's settings items are free-form, the prompts invite
made-up keys, the commit falls back to an invented category: "onboarding" and an untyped value,
and the review panel edits every setting through a single plain-text box. This is stub 4 of the
onboarding-blueprint-alignment epic (initiative Build the Bridge, objective Q2-2026 O1 —
Establish Product-Market Fit with Vendor Partners): the blueprint must configure a vendor tenant
into the platform's real shapes, so a smooth, trustworthy setup gets vendors onto paid tiers.
Constrain the settings section to a curated, onboarding-relevant subset of the canonical registry, so the blueprint only ever proposes registry keys in their registry-correct shape.
default_currency, timezone
(general), sla_business_days_only (sla), escalation.defaultEnabled (escalation),
commercial.vendorRevenuePercent, commercial.pricingRulesSet (commercial). The internal SDM
analytics thresholds — matching.minFitScore, all coverage.*, and marketSignals.bandMarginPct —
are excluded from onboarding: they keep their seeded registry defaults and are tuned later in the
admin Settings tab. The subset is a single explicit allow-list (derived from the registry, not a
re-typed copy) so adding/removing a key is one edit.commercial.vendorRevenuePercent has no registry default — it appears for the operator to optionally
supply a value and is committed only if a valid number is given.settings items carry the
registry key, its category, a value typed to the entry's type, and the registry
description; keys outside the curated subset are rejected/dropped. The concierge prompt and the
analyse-source system prompt describe settings as this fixed key list (with categories and types),
instructing the model to adjust values, never to invent keys.commit.ts writes each item with the registry
key, category and description, and a value coerced to the registry type. It upserts by
(tenantId, key) rather than blind-creating, so a commit is idempotent and never collides with a
tenant whose defaults were already seeded. The category: "onboarding" fallback is removed.type — a text input for string, a number input for number, and a new boolean
control (switch/checkbox) for boolean — instead of the single plain-text box. This adds a
"boolean" variant to EditableField and its renderer in blueprint-item.tsx.default_currency,
timezone, sla_business_days_only, escalation.defaultEnabled, commercial.vendorRevenuePercent,
commercial.pricingRulesSet) — no invented settings and no excluded SDM-threshold keys.key, category, a value typed to the
entry's registry type, and the registry description.tenant_settings rows — one per key, unique on (tenantId, key), with a
registry-typed value that passes the key pattern — upserting so an already-seeded tenant does not
collide. commercial.vendorRevenuePercent commits only when a valid number is supplied.string, number input for number, and a boolean toggle for boolean.SETTINGS_REGISTRY itself.matching.minFitScore, coverage.*, marketSignals.*) — kept
at their seeded registry defaults and managed in the admin Settings tab, not surfaced at onboarding.conversational-progressive-flow).02_build/output/notes.mdpackages/services/src/db/services/tenant-setting/registry.ts: added the curated onboarding
allow-list (ONBOARDING_SETTING_KEYS, onboardingSettings(), isOnboardingSettingKey,
onboardingSettingLabel) and a shared coerceSettingValue(value, type) typing helper. The curated
six are the operator-facing operating defaults; the internal SDM thresholds (matching.*,
coverage.*, marketSignals.*) are excluded. Registry entries themselves are untouched.packages/services/src/ai/onboarding/contract.ts: settings now use a registry-constrained
DraftSettingsItemSchema — key is a z.enum of the curated keys, value a string|number|boolean
matching the key's type. DraftBlueprintSchema.settings uses it (the satisfies guard is relaxed to
z.ZodTypeAny so it still fails to compile if a section key is missing). category/description are
not the model's to set.packages/services/src/ai/onboarding/analyse-source.ts: the system prompt lists the fixed known
settings (key/type/description) and forbids invented keys. New buildSettingsItems seeds every
curated setting at its registry default and overlays a type-coerced model value where the source
supports one — each item's data carries the registry key/category/value/description. The
section is always written (seed-then-adjust); seeded defaults don't count toward the thin/empty signal.packages/services/src/ai/onboarding/prompt.ts: the concierge's settings section is described as the
fixed known list (seeded at defaults, adjust-only), so the chat path can't invent settings either.packages/services/src/db/services/onboarding-blueprint/commit.ts: the settings branch now resolves
each item against the registry, coerces the value to the registry type, skips off-registry keys and
unset values (so an unset commercial.vendorRevenuePercent never commits as 0), and upserts by
(tenantId, key) via the model — idempotent, and no unique-index collision on an already-seeded
tenant. The invented category: "onboarding" fallback is gone.apps/web/components/onboarding/types.ts: EditableField gains a "boolean" control type; added a
client-safe ONBOARDING_SETTING_TYPES map and settingsEditableFields(item) that resolves a settings
item's control from its registry key.apps/web/components/onboarding/blueprint-item.tsx: settings items resolve their edit fields per item
(heterogeneous types); added a Switch control for boolean, with matching save-time coercion.DraftSettingsItemSchema / DraftSettingsItem from ai/onboarding.z.enum),
buildSettingsItems, the concierge prompt, and as a commit backstop (isOnboardingSettingKey).key/category/typed value/description — stamped from the
registry in buildSettingsItems and written from the registry at commit.buildSettingsItems
seeds+overlays; review panel edits per type; only approved/edited items commit.tenant_settings rows, unique per key, upserting; vendorRevenuePercent
commits only with a valid number — findOneAndUpdate upsert + coerceSettingValue null-skip.Switch) resolved from the
item's registry key.ONBOARDING_SETTING_TYPES) because the onboarding client components must not import the server
(Mongoose) barrel — same pattern as the existing client-safe mirrors in types.ts. It must stay in
lockstep with ONBOARDING_SETTING_KEYS / SETTINGS_REGISTRY.analyse-source (website/description path). A pure-chat onboarding
(no source analysed) relies on the concierge prompt to draft the curated settings; the commit is the
hard guarantee that only registry-shaped rows land regardless of path.SECTION_META.settings.editableFields is now a fallback only — blueprint-item overrides it per item
for settings — so it was left as-is to keep the diff focused.03_release/output/changelog.mdLive entry: apps/help/app/changelog/2026-07-08-settings-registry-alignment/page.mdx
title: Workspace setup now proposes your real settings, ready to confirm personas: [admin, vendor]
When you set up a new workspace, the settings step no longer invents made-up options. It now offers the platform's real operating settings, pre-filled with sensible defaults for you to confirm or adjust.
03_release/output/investor-update.mdWho it's for: Admins and vendors setting up a new workspace What shipped: The onboarding assistant's settings step now proposes only the platform's real, correctly-typed settings, seeded from defaults for the operator to confirm — not invented ones. Why it matters: A trustworthy setup helps get vendors onto paid subscription tiers (Build the Bridge · Q2 objective: establish product-market fit with vendor partners).
Confirmed settings now commit as valid workspace configuration.
Dig deeper: <merged-PR URL> · <changelog entry URL>
03_release/output/release.mdtechnical/packages/services describes the onboarding concierge at the blueprint-section level; the described architecture (Zod extraction contract → onboarding-blueprint service → commit into the real workspace) is unchanged, this change only constrains the settings section's shape within it.platform-overview describes the blueprint's settings section generically and roles already states tenant settings are "backed by a canonical registry"; this change aligns onboarding to that already-documented registry without altering any documented route or flow.apps/help/app/changelog/2026-07-08-settings-registry-alignment/page.mdx) + investor draft in this PRRan /code-review medium (complexity: standard) over this run's diff — ENABLE_CLAUDE_REVIEW is off, so the review ran inline. Correctness pass found no bugs: seeded false, unset null (vendor revenue share), and 0 all round-trip correctly through seed → review → commit, with only genuinely-unset null dropped. Cleanup pass found no CONVENTIONS.md violations and three maintainability notes, all accepted (not actioned) with rationale:
ONBOARDING_SETTING_TYPES map (types.ts) is Record<string, …>, so a future 7th onboarding setting added server-side wouldn't fail the client build — accepted. The suggested fix (stamp type into item.data and drop the map) would regress the concierge-drafted path (its items don't carry a stamped type, so booleans would render as a text control); the map resolves the right control for both the analyse-source and concierge paths, and commit-side coercion is the safety net either way. The lockstep requirement is documented in a comment + build notes.analyse-source seeds the settings baseline before the itemCount === 0 guard, so a thin source still writes the settings section while returning empty — accepted; deliberate (settings seed regardless of source richness; empty only signals the catalogue was thin so the concierge interviews).SECTION_META.settings.editableFields is now a fallback that BlueprintItem overrides per item for settings — accepted; the Record<OnboardingSectionKey, …> type requires the entry to exist, and it's harmless.z.enum(ONBOARDING_SETTING_KEYS) in the extraction contract, buildSettingsItems emits only onboardingSettings(), the concierge prompt lists the fixed set, and the commit skips off-registry keys (isOnboardingSettingKey).buildSettingsItems; the commit writes registry category/description and a type-coerced value.buildSettingsItems seeds defaults and overlays coerced source values; review panel edits per type; only approved/edited items commit.tenant_settings rows, upserting; vendorRevenuePercent only with a valid number — findOneAndUpdate upsert on (tenantId, key) + coerceSettingValue null-skip.Switch, resolved per item from its registry key.