From f7691ddfd3753938cf19c47b8a43854313007146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morel=20Se=CC=81bastien?= Date: Tue, 13 Oct 2026 13:52:44 -0700 Subject: [PATCH] fix(skills): ignite discovery last and treat a failed ignition as blocking On 2026-10-13 a setup agent ran igniteDiscoApi before any shape existed, saw a complete task, re-ignited several times, and left the tenant's Discovery API answering 500 for ~2 hours. Ignition now goes last, after shapes with components and published content. A task that ends in error is read through info.traces instead of being retried unchanged, and a { __typename } probe against Discovery confirms the tenant is serving before success is reported. The query reference documents the backend fix landing alongside: a shapeless tenant has no browse field, and an unbuildable schema answers TENANT_SCHEMA_UNAVAILABLE. --- .../skills/mass-operations/SKILL.md | 5 +++++ .../skills/mutation/references/core-api.md | 4 +++- .../skills/query/references/discovery-api.md | 4 +++- .../skills/vector-ranking/SKILL.md | 5 ++++- .../references/vocabulary-authoring.md | 20 +++++++++++++++++-- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/use-crystallize/skills/mass-operations/SKILL.md b/use-crystallize/skills/mass-operations/SKILL.md index e4a0612..013307c 100644 --- a/use-crystallize/skills/mass-operations/SKILL.md +++ b/use-crystallize/skills/mass-operations/SKILL.md @@ -171,6 +171,11 @@ A schema violation or unparseable JSON marks the task `error` before any operati `bulkTask.info.error` reads only `Invalid Operation File` — the per-field issues go to the worker's own logs, not to you. Validate locally to see them. +**Seeding a tenant that Discovery will serve:** run `igniteDiscoApi` after the operations that create +the shapes and content have completed with clean `operationLogs`, never before or alongside them. Poll +the ignition task like any other bulk task, treat `error` as blocking, and probe Discovery with +`{ __typename }` before reporting success. See [[vector-ranking]] for the full ignition steps. + ## Rules that prevent most failures - **An item `upsert` with neither `itemId` nor `resourceIdentifier` always CREATES** — on every run. diff --git a/use-crystallize/skills/mutation/references/core-api.md b/use-crystallize/skills/mutation/references/core-api.md index 098f1d6..121b3ea 100644 --- a/use-crystallize/skills/mutation/references/core-api.md +++ b/use-crystallize/skills/mutation/references/core-api.md @@ -763,7 +763,9 @@ is not proof that the items are published yet — index right after it and the i versions. **Re-run `igniteDiscoApi` after every change to vocabularies or taste entries** — an unindexed change -has no effect and raises no error. Omitting `stacks: opensearch` likewise fails silently: the index +has no effect and raises no error. Run it **last**, once shapes and published content exist. A task +that ends in `error` is blocking: `bulkTask(id:) { ... on BulkTask { status info } }` carries the reason +in `info.traces`. Probe Discovery with `{ __typename }` before reporting success. Omitting `stacks: opensearch` likewise fails silently: the index rebuilds, but without vectors. Full guidance, including vocabulary design, positional weights and key validation, is in the [[vector-ranking]] skill. diff --git a/use-crystallize/skills/query/references/discovery-api.md b/use-crystallize/skills/query/references/discovery-api.md index 2600a11..febfcde 100644 --- a/use-crystallize/skills/query/references/discovery-api.md +++ b/use-crystallize/skills/query/references/discovery-api.md @@ -36,7 +36,9 @@ the tenant is re-indexed: **Introspect, do not assume.** An un-ignited tenant answers `{"success": false, "message": "There is no ignited Tenant for ."}` rather than serving a -schema at all. +schema at all. A tenant with no shapes has no `browse` field. A tenant whose schema cannot be built +answers HTTP 500 with `extensions.code: "TENANT_SCHEMA_UNAVAILABLE"`. Retrying will not help, so report +it with the tenant identifier. `{ __typename }` is the cheapest check that a tenant is serving. > **Note**: The Discovery API uses **lowercase** type names in inline fragments (`... on product`, > `... on category`) because types are derived from your shape identifiers. Interface fragments keep diff --git a/use-crystallize/skills/vector-ranking/SKILL.md b/use-crystallize/skills/vector-ranking/SKILL.md index 1bda66a..a6613ea 100644 --- a/use-crystallize/skills/vector-ranking/SKILL.md +++ b/use-crystallize/skills/vector-ranking/SKILL.md @@ -125,7 +125,8 @@ Two properties fall out of this and drive every design decision: Core upsertVocabulary once per vocabulary — FULL REPLACE, not a patch Core setItemTaste once per item, per vocabulary — writes the DRAFT Core publishItem per item and language — the step that is easy to miss -Core igniteDiscoApi(stacks: opensearch) poll bulkTask until "complete", then let it propagate +Core igniteDiscoApi(stacks: opensearch) LAST; poll bulkTask until "complete" ("error" is blocking) +Discovery { __typename } probe before reporting success Discovery search(rankBy:) your rules: margin, stock, velocity, recency Discovery search(context:) ranked for this shopper Discovery search(rankBy: + context:) your rules, plus this shopper @@ -173,6 +174,8 @@ Four of these produce **no error at all** — they are the reason this skill exi | Order unrelated to taste, no errors | Taste is on the draft only | `publishItem`, index again, retest | | Order unchanged after editing taste | No index run since the change | `igniteDiscoApi(stacks: opensearch)`, wait for `complete` | | Index rebuilt, still no vectors | `igniteDiscoApi` run without `stacks: opensearch` | Re-run with `stacks: opensearch` | +| Ignition task ends in `error` | e.g. ignited before any shape existed | Read `bulkTask.info.traces`, fix what it names, then ignite again. Never re-run it unchanged | +| `{ __typename }` fails after `complete` | Discovery cannot build the tenant's schema | Do not re-ignite in a loop. Report it with the tenant identifier and the response body | | Rankings subtly wrong, no errors | `magnitude` miscomputed client-side | Assert `sqrt(Σ w²)` against a known case | | `rankScore` comes back `null` | No rerank ran — no `rankBy`, or every term had `weight: 0` | Give at least one term a non-zero weight | | Vocabulary "does not exist in enum" | No index run since it was created | `igniteDiscoApi(stacks: opensearch)`, wait for `complete` | diff --git a/use-crystallize/skills/vector-ranking/references/vocabulary-authoring.md b/use-crystallize/skills/vector-ranking/references/vocabulary-authoring.md index f1a7dea..142d2f5 100644 --- a/use-crystallize/skills/vector-ranking/references/vocabulary-authoring.md +++ b/use-crystallize/skills/vector-ranking/references/vocabulary-authoring.md @@ -247,6 +247,10 @@ it just has no relation to taste. The check in step 6 is the only thing that cat `igniteDiscoApi` rebuilds the tenant's Discovery index and materializes the vectors. Run it after **any** change to vocabularies or taste entries, not only the first time. +**Ignite last.** Run it once the shapes exist, each with at least one component, and the content is +published, not as an early setup step. A tenant with no shapes that Discovery can index is refused: the +task ends in `error`. + **Pass `stacks: opensearch`.** The argument is optional in the schema but it selects which index stack is built, and vector ranking is only served from the `opensearch` stack — an ignition without it produces a working Discovery index with no vectors in it, and no error. @@ -284,12 +288,24 @@ query Task($id: ID!) { bulkTask(id: $id) { ... on BulkTask { id - status - } # pending, started, complete, error + status # pending, started, complete, error + info # on error, info.traces says why + } } } ``` +**`error` is blocking.** Read `info.traces`, fix what it names and only then ignite again. Re-running an +ignition that failed, unchanged, fails the same way. Before reporting success, probe Discovery itself: + +```graphql +{ + __typename +} +``` + +Anything but `{"data":{"__typename":"Query"}}` means the tenant is not serving, whatever the task said. + From then on the tenant's Discovery schema includes `context`, `rankBy` and `nearestTo`, and every vocabulary you created becomes a value of the `TenantVocabularyIdentifier` enum. **A vocabulary is only a valid enum value after the next index run** — until then, queries referencing it fail schema