Skip to Content

← All archived runs

Run: catalogue-services-skills-alignment

run.md

Run: catalogue-services-skills-alignment

  • branch: claude/catalogue-services-skills-alignment-6ylzdz
  • pr: #618

00_intake/stub.md

Stub: Tighten services & skills to real taxonomy fields

  • feature-slug: catalogue-services-skills-alignment
  • epic: onboarding-blueprint-alignment
  • personas: Admin, Vendor
  • initiative: Build the Bridge / objective: Q2-2026 O1 — Establish Product-Market Fit with Vendor Partners
  • depends-on: remove-categories-section
  • sequence: 5 of 6

Problem

The services and skills sections can draft datapoints that don't exist on the real taxonomy models (the demo reference carried fields like priceBand, duration, level, linkedServices that have no home). Real service and skill are thin taxonomy models: service = {name, description, productKeys[]}; skill = {name, serviceKey, description}. Junk fields confuse the review panel and never commit.

Proposed change

Constrain the services and skills blueprint sections to their real taxonomy fields and cross-references only: service data = name / description + productKeys (links to drafted product items); skill data = name / description + serviceKey (exactly one drafted service). Align contract, prompt, review-panel editable fields, and commit so no non-existent fields are drafted and the cross-refs resolve correctly.

Acceptance criteria (rough)

  • Services draft only name, description and productKeys cross-refs; no invented fields.
  • Skills draft only name, description and a single serviceKey cross-ref; no invented fields.
  • Cross-refs resolve at commit (service → product, skill → service), with clear handling when a ref is missing.
  • The review panel exposes only the real editable fields for services / skills.
  • Committing writes valid services / skills rows with the correct links.

Out of scope (this feature)

  • The products section (confirmed correct, untouched — it is the upstream parent of these cross-refs).
  • Changes to the service / skill taxonomy models or their admin CRUD.

Notes for Define

  • Services + skills are coupled (skill.serviceKey → service; service.productKeys → product), so they are aligned together as the catalogue tail; products stay as-is upstream.
  • touches: packages/services/src/ai/onboarding/{contract.ts,prompt.ts,analyse-source.ts}, packages/services/src/db/services/onboarding-blueprint/commit.ts (the services + skills branches, including productKeys / serviceKey resolution), apps/web/components/onboarding/types.ts (services / skills SECTION_META); reference the taxonomy models packages/services/src/db/models/{service,skill,taxonomy}.ts.

01_define/output/spec.md

Spec: Tighten services & skills blueprint to real taxonomy fields

  • slug: catalogue-services-skills-alignment
  • personas: Admin, Vendor
  • touches: packages/services/src/ai/onboarding/{contract.ts, prompt.ts, analyse-source.ts}, packages/services/src/db/services/onboarding-blueprint/commit.ts, apps/web/components/onboarding/types.ts
  • complexity: standard

Problem

The AI onboarding concierge drafts a per-tenant blueprint, but the services and skills sections can invent datapoints that have no home on the real taxonomy models. Those models are deliberately thin: service = { name, description } with product links held many-to-many via product_service_link; skill = { name, description, services[] } linking to at least one service. Today the extraction contract's data is a free-form record (its description still name-drops "pricing, tiers, locations"), and neither the analysis prompt nor the conversational prompt tells the model which fields to draft or to populate the cross-references. So a draft can carry junk fields like priceBand / duration / level / linkedServices that confuse the review panel and never commit, and it can omit the productKeys / serviceKey cross-refs the commit needs — leaving services unlinked or aborting the commit. This is the catalogue tail of the onboarding-blueprint-alignment epic (Build the Bridge / Q2-2026 O1 — establish product-market fit with vendor partners); a blueprint that mirrors the real platform is what lets a vendor onboard cleanly onto a paid tier.

Proposed change

Constrain the services and skills blueprint sections to their real taxonomy fields plus their cross-references only, and align every layer that touches them so no non-existent field is drafted and the cross-refs resolve at commit:

  • Contract (contract.ts) — validate the services and skills sections against a constrained item shape so only real fields survive: service data = name, description, productKeys[] (slugs of drafted product items); skill data = name, description, serviceKey (slug of exactly one drafted service). Any other field is stripped/rejected at the contract boundary and never persisted. The other sections keep their current free-form payload. Remove the stale "pricing, tiers, locations" hint from the generic data description.
  • Prompts (analyse-source.ts system prompt, prompt.ts interview instructions) — tell the model exactly which fields to draft for services and skills, and to populate the cross-refs by referencing the key of a drafted product (for a service's productKeys) or a drafted service (for a skill's serviceKey), so a normal draft yields resolvable references.
  • Commit (commit.ts) — keep the existing product → service → skill resolution: a service's productKeys resolve into product_service_link rows (many-to-many); a skill's serviceKey resolves to a single service and writes serviceIds: [serviceId]. A missing or unresolvable required cross-ref (a skill with no/absent service, or a productKey/serviceKey naming an item not being committed) aborts the whole commit atomically with a clear, item-specific message — no partial writes. Confirm the service/skill branches match the constrained field set (drop any reliance on invented fields).
  • Review panel (apps/web/components/onboarding/types.ts SECTION_META) — services and skills expose only name and description as editable fields; no invented field is surfaced or editable. The structural cross-refs (productKeys / serviceKey) stay non-editable so editing can't break the commit.

Products stay untouched — they are the upstream parent these cross-refs point at.

Acceptance criteria

  • The services section persists only name, description, and a productKeys[] cross-ref; any other field the model emits (e.g. priceBand, duration, linkedServices) is dropped at validation and never reaches the stored blueprint.
  • The skills section persists only name, description, and a single serviceKey cross-ref; any other field (e.g. level) is dropped at validation and never reaches the stored blueprint.
  • The analysis prompt and the conversational interview prompt instruct the model to draft those exact fields and to populate productKeys / serviceKey by referencing drafted item keys, so a normal end-to-end draft produces cross-refs that resolve.
  • At commit, a service's productKeys resolve into product_service_link rows and a skill's serviceKey resolves into serviceIds: [serviceId]; a missing or unresolvable required cross-ref aborts the entire commit atomically with a clear, item-specific message and writes nothing.
  • The review panel exposes only name and description as editable fields for services and skills, and surfaces no invented field.
  • A successful commit writes valid service rows (linked to their products) and skill rows (each linked to ≥1 service) that satisfy the real taxonomy model validation.

Out of scope

  • The products section — confirmed correct; left untouched (it is the upstream parent of these cross-refs).
  • Changes to the service / skill taxonomy models themselves, or their admin CRUD.
  • Drafting multiple services per skill — the model permits services[], but the blueprint draws exactly one serviceKey; multi-service skills are a possible follow-up.
  • Skip-and-continue commit behaviour — a bad cross-ref aborts atomically (decided), it does not commit a partial catalogue.
  • Read-only display of the resolved cross-refs in the review panel beyond today's behaviour.
  • The other blueprint sections (profile, SLA, settings) and the conversational progressive flow — their own epic stubs.

Open questions

None — the missing-cross-ref behaviour is settled as atomic abort with a clear per-item message.

02_build/output/notes.md

Build notes: catalogue-services-skills-alignment

  • commits: feat: catalogue-services-skills-alignment — constrain services & skills to real taxonomy fields

What changed

  • packages/services/src/ai/onboarding/contract.ts: added a single-source-of-truth whitelist (CONSTRAINED_SECTION_FIELDS) and sanitiseSectionData(section, data) that drops any field outside a section's real taxonomy shape. Services → name / description / productKeys; skills → name / description / serviceKey. Removed the stale "pricing, tiers, locations" hint from the generic data description. The extraction schema stays a plain object; the whitelist is enforced at the persistence boundary on both write paths (see below), so the schema the model is generated against needs no transform.
  • packages/services/src/ai/onboarding/analyse-source.ts + blueprint-tools.ts: both write paths route each item's data through sanitiseSectionData(section, …) before persisting — the analysis path in toItemInput, the conversational draft_section tool inline — so a service/skill can never persist an invented field, whichever path drafts it. One whitelist, applied uniformly.
  • packages/services/src/ai/onboarding/prompt.ts: the interview instructions tell the concierge exactly which fields to draft for services (name, description, productKeys) and skills (name, description, serviceKey), and to set the cross-refs to the key values of the drafted products/services so links resolve on commit.
  • packages/services/src/ai/onboarding/analyse-source.ts: the source-analysis system prompt got the same field- and cross-ref guidance for services and skills.

Acceptance criteria status

  • Services persist only name, description, productKeys — enforced on both write paths by sanitiseSectionData("services", …) (analysis in toItemInput, interview in draft_section); invented fields (priceBand, duration, linkedServices) are dropped before persistence.
  • Skills persist only name, description, a single serviceKey — same enforcement; level and any other field are dropped before persistence.
  • Analysis prompt + interview prompt instruct the model to draft those exact fields and populate productKeys / serviceKey from drafted item keys so cross-refs resolve.
  • Commit resolves a service's productKeys into product_service_link rows and a skill's serviceKey into serviceIds: [serviceId]; a missing/unresolvable required ref aborts the whole transaction with a clear, item-specific message and writes nothing — already implemented in commit.ts (verified, unchanged), and now matches the constrained field set exactly.
  • Review panel exposes only name + description as editable for services/skills, and no invented field — already the case in apps/web/components/onboarding/types.ts SECTION_META (verified, unchanged); cross-refs stay deliberately non-editable.
  • A successful commit writes valid service rows (linked to products via product_service_link) and skill rows (serviceIds with ≥1 service) that satisfy the taxonomy model validation.

Verify result

  • mechanical checks (format · lint · typecheck · build) run in CI + the Vercel preview, not here. No check is expected to fail. The change is enforcement-and-prompt only; the commit switch and review panel already matched the real models, so commit.ts and types.ts were verified rather than edited.

Notes for review

  • Enforcement is a shared whitelist applied on both AI write paths (schema transform + the draft_section tool). The spec's touches under-listed blueprint-tools.ts — the conversational path needed the same guard to satisfy "never reaches the stored blueprint", so it's included.
  • commit.ts and types.ts are intentionally unchanged: they already read/expose exactly the real fields, so editing them would be churn. Look closely if you'd prefer a redundant server-side guard in onboarding-blueprint/upsertSection as belt-and-suspenders — I kept enforcement at the two AI entry points per the spec's scope.
  • The skill model permits multiple services (services: ObjectId[]); the blueprint deliberately drafts exactly one serviceKey (committed as serviceIds: [one]). Multi-service drafting is out of scope.

03_release/output/changelog.md


title: Cleaner services and skills in your onboarding setup date: 2026-07-08T14:30:00Z personas: [admin, vendor] slug: catalogue-services-skills-alignment pr: https://github.com/sustentus/sustentus/pull/618

Cleaner services and skills in your onboarding setup

When you set up a new workspace, the setup assistant now drafts your services and skills using only the details that actually apply — a name, a short description, and the links between them.

  • No more invented fields: services and skills only carry information your workspace can use, so there's less to review before you launch.
  • Every service is linked to the products it delivers, and every skill to the service it supports, so your catalogue is connected from the start.
  • What you approve commits cleanly into your workspace, with the links resolved for you.

03_release/output/investor-update.md

New vendors' onboarding now drafts a clean, commit-ready catalogue

Who it's for: Vendors onboarding, and the admins supporting them What shipped: The setup concierge now drafts services and skills using only real fields and links, dropping invented data. Why it matters: Cleaner, reliable vendor setup — advancing product-market fit with vendor partners (Build the Bridge).

Every drafted service and skill commits with correct links.

Dig deeper: <merged-PR URL> · <changelog entry URL>

03_release/output/release.md

Release: catalogue-services-skills-alignment

  • pr: #618 · merged: no (pending Ready-to-merge tick + green CI)
  • CI: green at Build (Quality Project — format/lint/typecheck/build — passed)
  • technical docs: no technical docs impact — technical/packages/services describes the onboarding concierge as "a shared Zod extraction contract"; still accurate (the contract now constrains services/skills, same architecture)
  • business docs: no business docs impact — a correctness tightening of what the concierge drafts, not a new/changed capability the feature-role-matrix or service-journey documents
  • release notes: both — changelog entry (apps/help) + investor draft in this PR
  • deploy: pending (post-merge poll)
  • sent: pending green deploy

Review summary

  • /code-review medium on the branch diff (4 code files + changelog + run docs). No correctness findings. One simplification landed on the branch before merge: enforcement was split (schema transform for the analysis path, explicit call for the conversational path). Unified both to call sanitiseSectionData at the persistence boundary and removed the schema transform — one whitelist applied identically on both paths, and the extraction schema stays a plain object the model is generated against (no reliance on nested-transform handling in generateObject).
  • No technical/business docs impact (recorded above); changelog + investor drafts reviewed in-PR.

Acceptance check (vs spec)

  • Services persist only name/description/productKeys — schema transform + draft_section sanitiser
  • Skills persist only name/description/serviceKey — same enforcement on both write paths
  • Analysis + interview prompts instruct the exact fields and cross-ref population
  • Commit resolves cross-refs and aborts atomically with a clear per-item message on a missing ref (verified in commit.ts, unchanged)
  • Review panel exposes only name/description editable for services/skills (verified in types.ts, unchanged)
  • Successful commit writes valid service/skill rows with correct links