@design-ai/cli 4.56.0 → 4.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +109 -25
- package/CHANGELOG.md +68 -0
- package/README.ko.md +11 -28
- package/README.md +12 -25
- package/cli/bin/design-ai.mjs +1 -0
- package/cli/commands/help.mjs +7 -4
- package/cli/commands/index.mjs +292 -0
- package/cli/commands/learn-help.mjs +149 -0
- package/cli/commands/learn-print-profile.mjs +373 -0
- package/cli/commands/learn-print-restore.mjs +349 -0
- package/cli/commands/learn-print-signals.mjs +453 -0
- package/cli/commands/learn.mjs +60 -1281
- package/cli/commands/pack.mjs +7 -3
- package/cli/commands/prompt.mjs +7 -3
- package/cli/commands/route.mjs +13 -1
- package/cli/commands/search.mjs +94 -1
- package/cli/lib/dispatch.mjs +3 -0
- package/cli/lib/embedding-index.mjs +199 -0
- package/cli/lib/embedding-provider.mjs +121 -0
- package/cli/lib/embedding-rerank.mjs +52 -0
- package/cli/lib/learn-args.mjs +490 -0
- package/cli/lib/learn-backup.mjs +748 -0
- package/cli/lib/learn-curation.mjs +612 -0
- package/cli/lib/learn-eval.mjs +459 -0
- package/cli/lib/learn-profile.mjs +763 -0
- package/cli/lib/learn-select.mjs +223 -0
- package/cli/lib/learn-shared.mjs +158 -0
- package/cli/lib/learn-test-support.mjs +218 -0
- package/cli/lib/learn-usage.mjs +360 -0
- package/cli/lib/learn.mjs +83 -3694
- package/cli/lib/lexical.mjs +137 -0
- package/cli/lib/local-config.mjs +110 -0
- package/cli/lib/mcp-server.mjs +13 -3
- package/cli/lib/pack.mjs +31 -4
- package/cli/lib/prompt.mjs +42 -4
- package/cli/lib/recall.mjs +193 -0
- package/cli/lib/retrieval-index.mjs +0 -0
- package/cli/lib/route.mjs +62 -5
- package/cli/lib/search-ranked.mjs +202 -0
- package/cli/lib/search.mjs +11 -1
- package/cli/lib/signals-backlog-commands.mjs +673 -0
- package/cli/lib/signals-backlog.mjs +361 -0
- package/cli/lib/signals-eval.mjs +176 -0
- package/cli/lib/signals-readiness.mjs +247 -0
- package/cli/lib/signals-registry.mjs +377 -0
- package/cli/lib/signals-render.mjs +478 -0
- package/cli/lib/signals-shared.mjs +75 -0
- package/cli/lib/signals.mjs +16 -2337
- package/cli/lib/site-bundle-handoff-expected.mjs +173 -0
- package/cli/lib/site-bundle-handoff-runbook-action-summary.mjs +332 -0
- package/cli/lib/site-bundle-handoff-runbook-human-lines.mjs +167 -0
- package/cli/lib/site-bundle-handoff-runbook-maps.mjs +238 -0
- package/cli/lib/site-bundle-handoff-runbook-next-step.mjs +278 -0
- package/cli/lib/site-bundle-handoff-runbook.mjs +44 -931
- package/cli/lib/site-test-support.mjs +68 -0
- package/cli/lib/skill-proposals-apply-commands.mjs +135 -0
- package/cli/lib/skill-proposals-apply-contract.mjs +750 -0
- package/cli/lib/skill-proposals-apply-plan.mjs +118 -0
- package/cli/lib/skill-proposals-generate.mjs +298 -0
- package/cli/lib/skill-proposals-render.mjs +532 -0
- package/cli/lib/skill-proposals-review.mjs +262 -0
- package/cli/lib/skill-proposals.mjs +15 -2046
- package/cli/lib/workspace-args.mjs +83 -0
- package/cli/lib/workspace-git.mjs +169 -0
- package/cli/lib/workspace-learning.mjs +483 -0
- package/cli/lib/workspace-repo.mjs +139 -0
- package/cli/lib/workspace-report.mjs +283 -0
- package/cli/lib/workspace-test-support.mjs +99 -0
- package/cli/lib/workspace.mjs +30 -1056
- package/docs/AI-LEARNING-PHASE2.md +215 -0
- package/docs/DISTRIBUTION.ko.md +2 -2
- package/docs/DISTRIBUTION.md +2 -2
- package/docs/NEXT-SURFACE-DECISION.md +125 -0
- package/docs/PRODUCT-READINESS.md +3 -3
- package/docs/RELEASE-GATES.ko.md +35 -0
- package/docs/RELEASE-GATES.md +234 -0
- package/docs/ROADMAP.md +82 -8
- package/docs/external-status.md +9 -11
- package/docs/inspection-20260630.md +169 -0
- package/docs/integrations/design-ai-mcp-server.md +4 -4
- package/docs/reference/ant-design.md +413 -0
- package/docs/reference/awesome-design-md.md +439 -0
- package/docs/reference/mui.md +783 -0
- package/docs/reference/shadcn-ui.md +298 -0
- package/examples/component-accordion-actions.md +5 -5
- package/examples/component-accordion-details.md +5 -5
- package/examples/component-accordion-summary.md +5 -5
- package/examples/component-accordion.md +3 -3
- package/examples/component-affix.md +1 -1
- package/examples/component-alert-dialog.md +1 -1
- package/examples/component-alert-title.md +1 -1
- package/examples/component-alert.md +3 -3
- package/examples/component-anchor.md +1 -1
- package/examples/component-app-bar.md +1 -1
- package/examples/component-aspect-ratio.md +1 -1
- package/examples/component-auto-complete.md +2 -2
- package/examples/component-avatar-group.md +5 -5
- package/examples/component-avatar.md +3 -3
- package/examples/component-back-top.md +1 -1
- package/examples/component-backdrop.md +1 -1
- package/examples/component-badge.md +3 -3
- package/examples/component-border-beam.md +3 -3
- package/examples/component-bottom-navigation.md +1 -1
- package/examples/component-box.md +1 -1
- package/examples/component-breadcrumb.md +3 -3
- package/examples/component-button-base.md +3 -3
- package/examples/component-button-group.md +2 -2
- package/examples/component-button.md +3 -3
- package/examples/component-calendar.md +2 -2
- package/examples/component-card-actions.md +1 -1
- package/examples/component-card-content.md +1 -1
- package/examples/component-card-header.md +1 -1
- package/examples/component-card-media.md +1 -1
- package/examples/component-card.md +3 -3
- package/examples/component-carousel.md +2 -2
- package/examples/component-cascader.md +1 -1
- package/examples/component-chart.md +1 -1
- package/examples/component-checkbox.md +3 -3
- package/examples/component-click-away-listener.md +1 -1
- package/examples/component-code.md +1 -1
- package/examples/component-collapsible.md +1 -1
- package/examples/component-color-picker.md +1 -1
- package/examples/component-combobox.md +1 -1
- package/examples/component-command.md +1 -1
- package/examples/component-config-provider.md +3 -3
- package/examples/component-context-menu.md +1 -1
- package/examples/component-css-baseline.md +3 -3
- package/examples/component-date-picker.md +2 -2
- package/examples/component-descriptions.md +1 -1
- package/examples/component-dialog-actions.md +1 -1
- package/examples/component-dialog-content-text.md +1 -1
- package/examples/component-dialog-content.md +1 -1
- package/examples/component-dialog-title.md +1 -1
- package/examples/component-dialog.md +2 -2
- package/examples/component-divider.md +3 -3
- package/examples/component-drawer.md +3 -3
- package/examples/component-dropdown.md +3 -3
- package/examples/component-empty.md +2 -2
- package/examples/component-fade.md +1 -1
- package/examples/component-field.md +1 -1
- package/examples/component-filled-input.md +1 -1
- package/examples/component-flex.md +1 -1
- package/examples/component-float-button.md +2 -2
- package/examples/component-form-control-label.md +1 -1
- package/examples/component-form-control.md +1 -1
- package/examples/component-form-controls.md +1 -1
- package/examples/component-form-group.md +1 -1
- package/examples/component-form-helper-text.md +1 -1
- package/examples/component-form-label.md +1 -1
- package/examples/component-form.md +2 -2
- package/examples/component-grid.md +2 -2
- package/examples/component-grow.md +1 -1
- package/examples/component-hover-card.md +1 -1
- package/examples/component-icon-button.md +1 -1
- package/examples/component-icon.md +1 -1
- package/examples/component-image-list.md +1 -1
- package/examples/component-image.md +1 -1
- package/examples/component-input-adornment.md +1 -1
- package/examples/component-input-base.md +1 -1
- package/examples/component-input-number.md +1 -1
- package/examples/component-input-otp.md +2 -2
- package/examples/component-input.md +3 -3
- package/examples/component-item.md +1 -1
- package/examples/component-label.md +1 -1
- package/examples/component-layout.md +1 -1
- package/examples/component-link.md +1 -1
- package/examples/component-list-item-avatar.md +1 -1
- package/examples/component-list-item-button.md +1 -1
- package/examples/component-list-item-icon.md +1 -1
- package/examples/component-list-item-text.md +1 -1
- package/examples/component-list-item.md +1 -1
- package/examples/component-list-subheader.md +1 -1
- package/examples/component-list.md +2 -2
- package/examples/component-masonry.md +1 -1
- package/examples/component-mentions.md +1 -1
- package/examples/component-menu-item.md +1 -1
- package/examples/component-menu-list.md +1 -1
- package/examples/component-menu.md +1 -1
- package/examples/component-menubar.md +1 -1
- package/examples/component-message.md +1 -1
- package/examples/component-mobile-stepper.md +1 -1
- package/examples/component-modal.md +5 -5
- package/examples/component-navigation-menu.md +1 -1
- package/examples/component-notification.md +1 -1
- package/examples/component-outlined-input.md +1 -1
- package/examples/component-pagination.md +3 -3
- package/examples/component-paper.md +1 -1
- package/examples/component-popconfirm.md +1 -1
- package/examples/component-popover.md +3 -3
- package/examples/component-popper.md +1 -1
- package/examples/component-progress.md +2 -2
- package/examples/component-qr-code.md +1 -1
- package/examples/component-radio.md +3 -3
- package/examples/component-rate.md +2 -2
- package/examples/component-resizable.md +1 -1
- package/examples/component-result.md +1 -1
- package/examples/component-scroll-area.md +1 -1
- package/examples/component-segmented.md +3 -3
- package/examples/component-select.md +3 -3
- package/examples/component-separator.md +1 -1
- package/examples/component-sheet.md +1 -1
- package/examples/component-sidebar.md +1 -1
- package/examples/component-skeleton.md +3 -3
- package/examples/component-slide.md +1 -1
- package/examples/component-slider.md +3 -3
- package/examples/component-snackbar-content.md +1 -1
- package/examples/component-snackbar.md +1 -1
- package/examples/component-sonner.md +1 -1
- package/examples/component-space.md +1 -1
- package/examples/component-speed-dial-action.md +1 -1
- package/examples/component-speed-dial.md +1 -1
- package/examples/component-spin.md +2 -2
- package/examples/component-spinner.md +1 -1
- package/examples/component-splitter.md +2 -2
- package/examples/component-stack.md +1 -1
- package/examples/component-statistic.md +1 -1
- package/examples/component-step-button.md +4 -4
- package/examples/component-step-connector.md +4 -4
- package/examples/component-step-content.md +1 -1
- package/examples/component-step-icon.md +1 -1
- package/examples/component-step-label.md +1 -1
- package/examples/component-step.md +2 -2
- package/examples/component-steps.md +2 -2
- package/examples/component-swipeable-drawer.md +1 -1
- package/examples/component-switch.md +3 -3
- package/examples/component-tab-scroll-button.md +5 -5
- package/examples/component-tab.md +1 -1
- package/examples/component-table-body.md +1 -1
- package/examples/component-table-cell.md +1 -1
- package/examples/component-table-container.md +1 -1
- package/examples/component-table-footer.md +1 -1
- package/examples/component-table-head.md +1 -1
- package/examples/component-table-pagination.md +1 -1
- package/examples/component-table-row.md +1 -1
- package/examples/component-table-sort-label.md +1 -1
- package/examples/component-table.md +2 -2
- package/examples/component-tabs.md +3 -3
- package/examples/component-tag-badge.md +2 -2
- package/examples/component-tag.md +1 -1
- package/examples/component-textarea-autosize.md +1 -1
- package/examples/component-textarea.md +1 -1
- package/examples/component-time-picker.md +1 -1
- package/examples/component-timeline.md +1 -1
- package/examples/component-toast.md +4 -4
- package/examples/component-toggle-button.md +1 -1
- package/examples/component-toggle.md +1 -1
- package/examples/component-toolbar.md +1 -1
- package/examples/component-tooltip.md +3 -3
- package/examples/component-tour.md +1 -1
- package/examples/component-transfer.md +1 -1
- package/examples/component-tree-select.md +1 -1
- package/examples/component-tree.md +1 -1
- package/examples/component-typography.md +2 -2
- package/examples/component-upload.md +1 -1
- package/examples/component-watermark.md +1 -1
- package/examples/component-zoom.md +1 -1
- package/knowledge/COVERAGE.md +12 -9
- package/knowledge/components/INDEX.md +202 -202
- package/knowledge/i18n/korean-density-conventions.md +108 -0
- package/knowledge/i18n/korean-product-conventions.md +2 -0
- package/knowledge/patterns/async-control.md +233 -0
- package/knowledge/patterns/brand-references.md +72 -72
- package/knowledge/patterns/error-states.md +1 -0
- package/knowledge/patterns/form-design.md +2 -0
- package/package.json +1 -1
- package/tools/audit/local-ci.py +16 -1
- package/tools/audit/package-smoke.py +611 -9
- package/tools/audit/registry-smoke.py +537 -3
- package/tools/audit/release-metadata.py +47 -1
- package/tools/audit/smoke_assertions.py +918 -13
- package/tools/migrations/refs-links-to-reference-pages.py +179 -0
|
@@ -39,6 +39,8 @@ from smoke_assertions import (
|
|
|
39
39
|
EXPECTED_HELP_ALIASES,
|
|
40
40
|
EXPECTED_NUMERIC_VALUE_SMOKES,
|
|
41
41
|
EXPECTED_PACK_MAX_BYTES,
|
|
42
|
+
EXPECTED_RANKED_SEARCH_LIMIT,
|
|
43
|
+
EXPECTED_RANKED_SEARCH_NOT_BUILT_NOTICE,
|
|
42
44
|
EXPECTED_REPOSITORY_URL,
|
|
43
45
|
EXPECTED_ROUTE_BRIEF,
|
|
44
46
|
EXPECTED_ROUTE_ID,
|
|
@@ -61,6 +63,9 @@ from smoke_assertions import (
|
|
|
61
63
|
assert_force_overwrite_replaced,
|
|
62
64
|
assert_functional_alias_smokes,
|
|
63
65
|
assert_help_topic_output,
|
|
66
|
+
assert_index_build_json,
|
|
67
|
+
assert_index_status_json,
|
|
68
|
+
assert_index_verify_json,
|
|
64
69
|
assert_install_doctor_lifecycle_output,
|
|
65
70
|
assert_list_catalog_output,
|
|
66
71
|
assert_list_catalog_json,
|
|
@@ -72,6 +77,8 @@ from smoke_assertions import (
|
|
|
72
77
|
assert_pack_json_component_spec,
|
|
73
78
|
assert_pack_markdown_body_component_spec,
|
|
74
79
|
assert_pack_markdown_component_spec,
|
|
80
|
+
assert_ranked_search_determinism,
|
|
81
|
+
assert_ranked_search_json,
|
|
75
82
|
assert_site_repair_apply_report_payload,
|
|
76
83
|
assert_site_repair_guidance_report_contract,
|
|
77
84
|
assert_site_repair_preview_report_payload,
|
|
@@ -132,6 +139,10 @@ from smoke_assertions import (
|
|
|
132
139
|
parse_help_topics,
|
|
133
140
|
passing_doctor_report_json,
|
|
134
141
|
passing_check_artifact_content,
|
|
142
|
+
passing_index_build_json,
|
|
143
|
+
passing_index_status_json,
|
|
144
|
+
passing_index_verify_json,
|
|
145
|
+
passing_ranked_search_json,
|
|
135
146
|
passing_site_json,
|
|
136
147
|
passing_site_mcp_check_json,
|
|
137
148
|
passing_site_mcp_check_probes_human,
|
|
@@ -2205,6 +2216,102 @@ def assert_learning_redact_smoke(
|
|
|
2205
2216
|
)
|
|
2206
2217
|
|
|
2207
2218
|
|
|
2219
|
+
def assert_learning_recall_json(
|
|
2220
|
+
raw: str,
|
|
2221
|
+
*,
|
|
2222
|
+
context: str,
|
|
2223
|
+
cmd: list[str],
|
|
2224
|
+
) -> None:
|
|
2225
|
+
assert_no_ansi(raw, cmd)
|
|
2226
|
+
try:
|
|
2227
|
+
payload = json.loads(raw)
|
|
2228
|
+
except json.JSONDecodeError as error:
|
|
2229
|
+
raise SystemExit(f"{context}: failed to parse learn recall JSON") from error
|
|
2230
|
+
|
|
2231
|
+
require_registry_smoke(
|
|
2232
|
+
isinstance(payload, dict) and payload.get("query") == "korean mobile",
|
|
2233
|
+
context=context,
|
|
2234
|
+
cmd=cmd,
|
|
2235
|
+
message="learn recall JSON must echo the query",
|
|
2236
|
+
)
|
|
2237
|
+
corpus = payload.get("corpus")
|
|
2238
|
+
require_registry_smoke(
|
|
2239
|
+
isinstance(corpus, dict)
|
|
2240
|
+
and isinstance(corpus.get("candidateCount"), int)
|
|
2241
|
+
and corpus.get("candidateCount") > 0
|
|
2242
|
+
and isinstance(corpus.get("selectedCount"), int)
|
|
2243
|
+
and isinstance(corpus.get("selected"), list),
|
|
2244
|
+
context=context,
|
|
2245
|
+
cmd=cmd,
|
|
2246
|
+
message="learn recall corpus block shape changed",
|
|
2247
|
+
)
|
|
2248
|
+
learning = payload.get("learning")
|
|
2249
|
+
require_registry_smoke(
|
|
2250
|
+
isinstance(learning, dict)
|
|
2251
|
+
and learning.get("mode") == "brief-relevance"
|
|
2252
|
+
and learning.get("candidateCount") == 3
|
|
2253
|
+
and isinstance(learning.get("selected"), list),
|
|
2254
|
+
context=context,
|
|
2255
|
+
cmd=cmd,
|
|
2256
|
+
message="learn recall learning block shape changed",
|
|
2257
|
+
)
|
|
2258
|
+
selected = learning.get("selected")
|
|
2259
|
+
require_registry_smoke(
|
|
2260
|
+
len(selected) >= 1
|
|
2261
|
+
and isinstance(selected[0], dict)
|
|
2262
|
+
and selected[0].get("id") == "registry-korean"
|
|
2263
|
+
and selected[0].get("category") == "korean"
|
|
2264
|
+
and isinstance(selected[0].get("matchedTokens"), list),
|
|
2265
|
+
context=context,
|
|
2266
|
+
cmd=cmd,
|
|
2267
|
+
message="learn recall should rank the Korean learning entry for a Korean query",
|
|
2268
|
+
)
|
|
2269
|
+
|
|
2270
|
+
|
|
2271
|
+
def assert_learning_recall_smoke(
|
|
2272
|
+
command_factory,
|
|
2273
|
+
profile_path: Path,
|
|
2274
|
+
*,
|
|
2275
|
+
env: dict[str, str],
|
|
2276
|
+
cwd: Path | None = None,
|
|
2277
|
+
context: str,
|
|
2278
|
+
) -> None:
|
|
2279
|
+
write_learning_stats_fixture(profile_path)
|
|
2280
|
+
|
|
2281
|
+
json_cmd = command_factory(
|
|
2282
|
+
"learn",
|
|
2283
|
+
"--recall",
|
|
2284
|
+
"korean mobile",
|
|
2285
|
+
"--file",
|
|
2286
|
+
str(profile_path),
|
|
2287
|
+
"--json",
|
|
2288
|
+
)
|
|
2289
|
+
json_result = run_plain(json_cmd, cwd=cwd, env=env)
|
|
2290
|
+
assert_learning_recall_json(json_result.stdout, context=f"{context} JSON", cmd=json_cmd)
|
|
2291
|
+
|
|
2292
|
+
# Read-only: the profile file is unchanged after recall.
|
|
2293
|
+
before = write_learning_stats_fixture_snapshot(profile_path)
|
|
2294
|
+
human_cmd = command_factory("learn", "--recall", "korean mobile", "--file", str(profile_path))
|
|
2295
|
+
human_result = run_plain(human_cmd, cwd=cwd, env=env)
|
|
2296
|
+
require_registry_smoke(
|
|
2297
|
+
"Recall (read-only)" in human_result.stdout
|
|
2298
|
+
and "Privacy: recall is read-only" in human_result.stdout,
|
|
2299
|
+
context=f"{context} human",
|
|
2300
|
+
cmd=human_cmd,
|
|
2301
|
+
message="learn recall human output missing read-only markers",
|
|
2302
|
+
)
|
|
2303
|
+
require_registry_smoke(
|
|
2304
|
+
profile_path.read_text(encoding="utf-8") == before,
|
|
2305
|
+
context=f"{context} read-only",
|
|
2306
|
+
cmd=human_cmd,
|
|
2307
|
+
message="learn recall must not mutate the learning profile",
|
|
2308
|
+
)
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
def write_learning_stats_fixture_snapshot(profile_path: Path) -> str:
|
|
2312
|
+
return profile_path.read_text(encoding="utf-8")
|
|
2313
|
+
|
|
2314
|
+
|
|
2208
2315
|
def assert_learning_stats_json(
|
|
2209
2316
|
raw: str,
|
|
2210
2317
|
*,
|
|
@@ -4412,6 +4519,56 @@ def assert_pack_stdin_smoke(
|
|
|
4412
4519
|
)
|
|
4413
4520
|
|
|
4414
4521
|
|
|
4522
|
+
def assert_recall_context(payload: dict[str, object], *, context: str, cmd: list[str]) -> None:
|
|
4523
|
+
recall = payload.get("recall")
|
|
4524
|
+
require_registry_smoke(
|
|
4525
|
+
isinstance(recall, dict),
|
|
4526
|
+
context=context,
|
|
4527
|
+
cmd=cmd,
|
|
4528
|
+
message="recall should be present when --with-recall is used",
|
|
4529
|
+
)
|
|
4530
|
+
require_registry_smoke(
|
|
4531
|
+
recall.get("mode") == "lexical",
|
|
4532
|
+
context=context,
|
|
4533
|
+
cmd=cmd,
|
|
4534
|
+
message="recall should use the deterministic lexical scorer",
|
|
4535
|
+
)
|
|
4536
|
+
selected_count = recall.get("selectedCount")
|
|
4537
|
+
require_registry_smoke(
|
|
4538
|
+
isinstance(selected_count, int) and selected_count >= 1,
|
|
4539
|
+
context=context,
|
|
4540
|
+
cmd=cmd,
|
|
4541
|
+
message="recall should select at least one corpus file for the Button brief",
|
|
4542
|
+
)
|
|
4543
|
+
selected = recall.get("selected")
|
|
4544
|
+
require_registry_smoke(
|
|
4545
|
+
isinstance(selected, list) and len(selected) == selected_count and len(selected) >= 1,
|
|
4546
|
+
context=context,
|
|
4547
|
+
cmd=cmd,
|
|
4548
|
+
message="recall selected list should match the reported selected count",
|
|
4549
|
+
)
|
|
4550
|
+
top = selected[0]
|
|
4551
|
+
require_registry_smoke(
|
|
4552
|
+
isinstance(top, dict) and isinstance(top.get("id"), str) and top.get("id"),
|
|
4553
|
+
context=context,
|
|
4554
|
+
cmd=cmd,
|
|
4555
|
+
message="recall selection should cite the corpus relPath as its id",
|
|
4556
|
+
)
|
|
4557
|
+
require_registry_smoke(
|
|
4558
|
+
type(top.get("score")) in (int, float) and top.get("score") > 0,
|
|
4559
|
+
context=context,
|
|
4560
|
+
cmd=cmd,
|
|
4561
|
+
message="recall selection should include a positive relevance score",
|
|
4562
|
+
)
|
|
4563
|
+
markdown = recall.get("markdown")
|
|
4564
|
+
require_registry_smoke(
|
|
4565
|
+
isinstance(markdown, str) and "## Recalled design knowledge" in markdown and top.get("id") in markdown,
|
|
4566
|
+
context=context,
|
|
4567
|
+
cmd=cmd,
|
|
4568
|
+
message="recall markdown should carry the Recalled design knowledge section and cite the top file",
|
|
4569
|
+
)
|
|
4570
|
+
|
|
4571
|
+
|
|
4415
4572
|
def assert_learning_relevance_context(payload: dict[str, object], *, context: str, cmd: list[str]) -> None:
|
|
4416
4573
|
learning_context = payload.get("learningContext")
|
|
4417
4574
|
require_registry_smoke(
|
|
@@ -4628,7 +4785,7 @@ def assert_learning_query_human(raw: str, *, context: str, cmd: list[str]) -> No
|
|
|
4628
4785
|
"Limit: 2",
|
|
4629
4786
|
"Explain: selection score, matched tokens, and reason",
|
|
4630
4787
|
"[accessibility] Prioritize keyboard accessibility details for Button component API specs",
|
|
4631
|
-
"matched
|
|
4788
|
+
"matched accessibility, keyboard",
|
|
4632
4789
|
"reason brief-match",
|
|
4633
4790
|
):
|
|
4634
4791
|
require_registry_smoke(
|
|
@@ -4989,6 +5146,49 @@ def assert_learning_relevance_smoke(
|
|
|
4989
5146
|
require_registry_smoke(isinstance(plan, dict), context=f"{context} pack", cmd=pack_cmd, message="pack plan missing")
|
|
4990
5147
|
assert_learning_relevance_context(plan, context=f"{context} pack plan", cmd=pack_cmd)
|
|
4991
5148
|
|
|
5149
|
+
recall_prompt_cmd = command_factory(
|
|
5150
|
+
"prompt",
|
|
5151
|
+
EXPECTED_ROUTE_BRIEF,
|
|
5152
|
+
"--route",
|
|
5153
|
+
EXPECTED_ROUTE_ID,
|
|
5154
|
+
"--with-recall",
|
|
5155
|
+
"--recall-limit",
|
|
5156
|
+
"3",
|
|
5157
|
+
"--json",
|
|
5158
|
+
)
|
|
5159
|
+
recall_prompt_result = run_plain(recall_prompt_cmd, cwd=cwd, env=relevance_env)
|
|
5160
|
+
try:
|
|
5161
|
+
recall_prompt_payload = json.loads(recall_prompt_result.stdout)
|
|
5162
|
+
except json.JSONDecodeError as error:
|
|
5163
|
+
raise SystemExit(f"{context}: failed to parse prompt recall JSON") from error
|
|
5164
|
+
assert_recall_context(recall_prompt_payload, context=f"{context} prompt recall", cmd=recall_prompt_cmd)
|
|
5165
|
+
|
|
5166
|
+
recall_pack_cmd = command_factory(
|
|
5167
|
+
"pack",
|
|
5168
|
+
EXPECTED_ROUTE_BRIEF,
|
|
5169
|
+
"--route",
|
|
5170
|
+
EXPECTED_ROUTE_ID,
|
|
5171
|
+
"--with-recall",
|
|
5172
|
+
"--recall-limit",
|
|
5173
|
+
"3",
|
|
5174
|
+
"--max-bytes",
|
|
5175
|
+
str(EXPECTED_PACK_MAX_BYTES),
|
|
5176
|
+
"--json",
|
|
5177
|
+
)
|
|
5178
|
+
recall_pack_result = run_plain(recall_pack_cmd, cwd=cwd, env=relevance_env)
|
|
5179
|
+
try:
|
|
5180
|
+
recall_pack_payload = json.loads(recall_pack_result.stdout)
|
|
5181
|
+
except json.JSONDecodeError as error:
|
|
5182
|
+
raise SystemExit(f"{context}: failed to parse pack recall JSON") from error
|
|
5183
|
+
recall_plan = recall_pack_payload.get("plan")
|
|
5184
|
+
require_registry_smoke(
|
|
5185
|
+
isinstance(recall_plan, dict),
|
|
5186
|
+
context=f"{context} pack recall",
|
|
5187
|
+
cmd=recall_pack_cmd,
|
|
5188
|
+
message="pack recall plan missing",
|
|
5189
|
+
)
|
|
5190
|
+
assert_recall_context(recall_plan, context=f"{context} pack recall plan", cmd=recall_pack_cmd)
|
|
5191
|
+
|
|
4992
5192
|
eval_template_path = profile_path.with_name(f"{profile_path.stem}-eval-template.json")
|
|
4993
5193
|
eval_template_path.write_text("stale eval template output\n", encoding="utf-8")
|
|
4994
5194
|
eval_template_cmd = command_factory(
|
|
@@ -5055,6 +5255,166 @@ def assert_learning_relevance_smoke(
|
|
|
5055
5255
|
)
|
|
5056
5256
|
|
|
5057
5257
|
|
|
5258
|
+
def assert_index_roundtrip_smoke(
|
|
5259
|
+
command_factory,
|
|
5260
|
+
index_dir: Path,
|
|
5261
|
+
profile_path: Path,
|
|
5262
|
+
*,
|
|
5263
|
+
env: dict[str, str],
|
|
5264
|
+
cwd: Path | None = None,
|
|
5265
|
+
context: str,
|
|
5266
|
+
) -> None:
|
|
5267
|
+
"""`index --build` -> `index --status` -> `index --verify` round-trip against a
|
|
5268
|
+
temp index dir and learning profile, isolated from the ambient environment."""
|
|
5269
|
+
index_dir.mkdir(parents=True, exist_ok=True)
|
|
5270
|
+
write_learning_relevance_fixture(profile_path)
|
|
5271
|
+
index_env = env.copy()
|
|
5272
|
+
index_env["DESIGN_AI_INDEX_DIR"] = str(index_dir)
|
|
5273
|
+
index_env["DESIGN_AI_LEARNING_FILE"] = str(profile_path)
|
|
5274
|
+
|
|
5275
|
+
build_cmd = command_factory("index", "--build", "--json")
|
|
5276
|
+
build_result = run_plain(build_cmd, cwd=cwd, env=index_env)
|
|
5277
|
+
assert_index_build_json(
|
|
5278
|
+
build_result.stdout,
|
|
5279
|
+
index_dir=str(index_dir),
|
|
5280
|
+
context=f"{context} build",
|
|
5281
|
+
cmd=build_cmd,
|
|
5282
|
+
)
|
|
5283
|
+
|
|
5284
|
+
status_cmd = command_factory("index", "--status", "--json")
|
|
5285
|
+
status_result = run_plain(status_cmd, cwd=cwd, env=index_env)
|
|
5286
|
+
assert_index_status_json(
|
|
5287
|
+
status_result.stdout,
|
|
5288
|
+
index_dir=str(index_dir),
|
|
5289
|
+
context=f"{context} status",
|
|
5290
|
+
cmd=status_cmd,
|
|
5291
|
+
)
|
|
5292
|
+
|
|
5293
|
+
verify_cmd = command_factory("index", "--verify", "--json")
|
|
5294
|
+
verify_result = run_plain(verify_cmd, cwd=cwd, env=index_env)
|
|
5295
|
+
assert_index_verify_json(
|
|
5296
|
+
verify_result.stdout,
|
|
5297
|
+
index_dir=str(index_dir),
|
|
5298
|
+
context=f"{context} verify",
|
|
5299
|
+
cmd=verify_cmd,
|
|
5300
|
+
)
|
|
5301
|
+
|
|
5302
|
+
|
|
5303
|
+
def assert_ranked_search_determinism_smoke(
|
|
5304
|
+
command_factory,
|
|
5305
|
+
index_dir: Path,
|
|
5306
|
+
*,
|
|
5307
|
+
env: dict[str, str],
|
|
5308
|
+
cwd: Path | None = None,
|
|
5309
|
+
context: str,
|
|
5310
|
+
) -> None:
|
|
5311
|
+
"""Two identical `search --ranked --json` runs must produce byte-identical output."""
|
|
5312
|
+
index_dir.mkdir(parents=True, exist_ok=True)
|
|
5313
|
+
ranked_env = env.copy()
|
|
5314
|
+
ranked_env["DESIGN_AI_INDEX_DIR"] = str(index_dir)
|
|
5315
|
+
|
|
5316
|
+
ranked_cmd = command_factory(
|
|
5317
|
+
"search",
|
|
5318
|
+
EXPECTED_CORPUS_SEARCH_QUERY,
|
|
5319
|
+
"--dir",
|
|
5320
|
+
"knowledge",
|
|
5321
|
+
"--limit",
|
|
5322
|
+
str(EXPECTED_RANKED_SEARCH_LIMIT),
|
|
5323
|
+
"--ranked",
|
|
5324
|
+
"--json",
|
|
5325
|
+
)
|
|
5326
|
+
first_result = run_plain(ranked_cmd, cwd=cwd, env=ranked_env)
|
|
5327
|
+
second_result = run_plain(ranked_cmd, cwd=cwd, env=ranked_env)
|
|
5328
|
+
assert_ranked_search_json(
|
|
5329
|
+
first_result.stdout,
|
|
5330
|
+
context=f"{context} payload",
|
|
5331
|
+
cmd=ranked_cmd,
|
|
5332
|
+
expected_notice=EXPECTED_RANKED_SEARCH_NOT_BUILT_NOTICE,
|
|
5333
|
+
)
|
|
5334
|
+
assert_ranked_search_determinism(
|
|
5335
|
+
first_result.stdout,
|
|
5336
|
+
second_result.stdout,
|
|
5337
|
+
context=context,
|
|
5338
|
+
cmd=ranked_cmd,
|
|
5339
|
+
)
|
|
5340
|
+
|
|
5341
|
+
|
|
5342
|
+
def assert_embeddings_off_by_default_smoke(
|
|
5343
|
+
command_factory,
|
|
5344
|
+
index_dir: Path,
|
|
5345
|
+
profile_path: Path,
|
|
5346
|
+
*,
|
|
5347
|
+
env: dict[str, str],
|
|
5348
|
+
cwd: Path | None = None,
|
|
5349
|
+
context: str,
|
|
5350
|
+
) -> None:
|
|
5351
|
+
"""Phase B is opt-in: a plain `index --build` never touches embeddings, and
|
|
5352
|
+
`index --status` reports `embeddings: null` (the feature is simply unused)."""
|
|
5353
|
+
index_dir.mkdir(parents=True, exist_ok=True)
|
|
5354
|
+
write_learning_relevance_fixture(profile_path)
|
|
5355
|
+
index_env = env.copy()
|
|
5356
|
+
index_env["DESIGN_AI_INDEX_DIR"] = str(index_dir)
|
|
5357
|
+
index_env["DESIGN_AI_LEARNING_FILE"] = str(profile_path)
|
|
5358
|
+
# Point at a config file that is guaranteed not to exist, rather than relying on
|
|
5359
|
+
# the ambient environment lacking DESIGN_AI_CONFIG_FILE — a real ~/.design-ai/
|
|
5360
|
+
# config.json on the machine running this smoke must not leak into the test.
|
|
5361
|
+
index_env["DESIGN_AI_CONFIG_FILE"] = str(index_dir.parent / "no-config-here" / "config.json")
|
|
5362
|
+
|
|
5363
|
+
build_cmd = command_factory("index", "--build", "--json")
|
|
5364
|
+
build_result = run_plain(build_cmd, cwd=cwd, env=index_env)
|
|
5365
|
+
build_payload = json.loads(build_result.stdout)
|
|
5366
|
+
if "embeddings" in build_payload:
|
|
5367
|
+
raise SystemExit(f"index build JSON after {context} unexpectedly ran provider execution with plain --build")
|
|
5368
|
+
|
|
5369
|
+
status_cmd = command_factory("index", "--status", "--json")
|
|
5370
|
+
status_result = run_plain(status_cmd, cwd=cwd, env=index_env)
|
|
5371
|
+
assert_index_status_json(
|
|
5372
|
+
status_result.stdout,
|
|
5373
|
+
index_dir=str(index_dir),
|
|
5374
|
+
context=f"{context} status",
|
|
5375
|
+
cmd=status_cmd,
|
|
5376
|
+
expect_embeddings=False,
|
|
5377
|
+
)
|
|
5378
|
+
|
|
5379
|
+
|
|
5380
|
+
def assert_search_embeddings_no_provider_fallback_smoke(
|
|
5381
|
+
command_factory,
|
|
5382
|
+
*,
|
|
5383
|
+
env: dict[str, str],
|
|
5384
|
+
cwd: Path | None = None,
|
|
5385
|
+
context: str,
|
|
5386
|
+
config_file: Path,
|
|
5387
|
+
) -> None:
|
|
5388
|
+
"""`search --ranked --embeddings` with no provider configured (flag or config)
|
|
5389
|
+
degrades to the lexical backend with a notice and exit code 0."""
|
|
5390
|
+
fallback_env = env.copy()
|
|
5391
|
+
# Same isolation rationale as assert_embeddings_off_by_default_smoke: point at a
|
|
5392
|
+
# config path guaranteed not to exist rather than trusting the ambient environment.
|
|
5393
|
+
fallback_env["DESIGN_AI_CONFIG_FILE"] = str(config_file)
|
|
5394
|
+
|
|
5395
|
+
search_cmd = command_factory(
|
|
5396
|
+
"search",
|
|
5397
|
+
EXPECTED_CORPUS_SEARCH_QUERY,
|
|
5398
|
+
"--dir",
|
|
5399
|
+
"knowledge",
|
|
5400
|
+
"--limit",
|
|
5401
|
+
str(EXPECTED_RANKED_SEARCH_LIMIT),
|
|
5402
|
+
"--ranked",
|
|
5403
|
+
"--embeddings",
|
|
5404
|
+
"--json",
|
|
5405
|
+
)
|
|
5406
|
+
result = run_plain(search_cmd, cwd=cwd, env=fallback_env)
|
|
5407
|
+
assert_ranked_search_json(
|
|
5408
|
+
result.stdout,
|
|
5409
|
+
context=f"{context} payload",
|
|
5410
|
+
cmd=search_cmd,
|
|
5411
|
+
expected_backend="lexical",
|
|
5412
|
+
)
|
|
5413
|
+
payload = json.loads(result.stdout)
|
|
5414
|
+
if "embedding provider" not in payload.get("notice", "") and "no embedding provider configured" not in payload.get("notice", ""):
|
|
5415
|
+
raise SystemExit(f"search ranked JSON after {context} fallback notice does not mention the missing provider")
|
|
5416
|
+
|
|
5417
|
+
|
|
5058
5418
|
def wait_for_registry_package(
|
|
5059
5419
|
package_spec: str,
|
|
5060
5420
|
*,
|
|
@@ -6086,6 +6446,13 @@ def smoke_registry_package(package_spec: str, *, retries: int, delay: float) ->
|
|
|
6086
6446
|
env=env,
|
|
6087
6447
|
context="registry smoke npm exec learn stats",
|
|
6088
6448
|
)
|
|
6449
|
+
assert_learning_recall_smoke(
|
|
6450
|
+
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6451
|
+
npx_root / "registry-recall-learning.json",
|
|
6452
|
+
cwd=npx_root,
|
|
6453
|
+
env=env,
|
|
6454
|
+
context="registry smoke npm exec learn recall",
|
|
6455
|
+
)
|
|
6089
6456
|
assert_learning_audit_cleanup_smoke(
|
|
6090
6457
|
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6091
6458
|
npx_root / "registry-audit-learning.json",
|
|
@@ -6100,6 +6467,36 @@ def smoke_registry_package(package_spec: str, *, retries: int, delay: float) ->
|
|
|
6100
6467
|
env=env,
|
|
6101
6468
|
context="registry smoke npm exec learning relevance",
|
|
6102
6469
|
)
|
|
6470
|
+
assert_index_roundtrip_smoke(
|
|
6471
|
+
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6472
|
+
npx_root / "registry-index",
|
|
6473
|
+
npx_root / "registry-index-learning.json",
|
|
6474
|
+
cwd=npx_root,
|
|
6475
|
+
env=env,
|
|
6476
|
+
context="registry smoke npm exec index roundtrip",
|
|
6477
|
+
)
|
|
6478
|
+
assert_ranked_search_determinism_smoke(
|
|
6479
|
+
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6480
|
+
npx_root / "registry-ranked-search-index",
|
|
6481
|
+
cwd=npx_root,
|
|
6482
|
+
env=env,
|
|
6483
|
+
context="registry smoke npm exec ranked search determinism",
|
|
6484
|
+
)
|
|
6485
|
+
assert_embeddings_off_by_default_smoke(
|
|
6486
|
+
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6487
|
+
npx_root / "registry-embeddings-off-index",
|
|
6488
|
+
npx_root / "registry-embeddings-off-learning.json",
|
|
6489
|
+
cwd=npx_root,
|
|
6490
|
+
env=env,
|
|
6491
|
+
context="registry smoke npm exec embeddings off by default",
|
|
6492
|
+
)
|
|
6493
|
+
assert_search_embeddings_no_provider_fallback_smoke(
|
|
6494
|
+
lambda *args: npm_exec_cmd(package_spec, *args),
|
|
6495
|
+
cwd=npx_root,
|
|
6496
|
+
env=env,
|
|
6497
|
+
context="registry smoke npm exec search embeddings no provider fallback",
|
|
6498
|
+
config_file=npx_root / "registry-no-config-here" / "config.json",
|
|
6499
|
+
)
|
|
6103
6500
|
assert_update_dry_run_smoke(
|
|
6104
6501
|
npm_exec_cmd(package_spec, "update", "--dry-run"),
|
|
6105
6502
|
cwd=npx_root,
|
|
@@ -7981,7 +8378,7 @@ def run_self_test() -> None:
|
|
|
7981
8378
|
"",
|
|
7982
8379
|
"1. [accessibility] Prioritize keyboard accessibility details for Button component API specs",
|
|
7983
8380
|
" learn-relevant · 2026-05-22T00:00:01.000Z",
|
|
7984
|
-
" score
|
|
8381
|
+
" score 2.114533 · matched accessibility, keyboard · reason brief-match",
|
|
7985
8382
|
]),
|
|
7986
8383
|
context="registry smoke self-test",
|
|
7987
8384
|
cmd=learn_query_human_cmd,
|
|
@@ -7995,7 +8392,7 @@ def run_self_test() -> None:
|
|
|
7995
8392
|
"Limit: 2",
|
|
7996
8393
|
"Explain: selection score, matched tokens, and reason",
|
|
7997
8394
|
"[accessibility] Prioritize keyboard accessibility details for Button component API specs",
|
|
7998
|
-
"matched
|
|
8395
|
+
"matched accessibility, keyboard",
|
|
7999
8396
|
]),
|
|
8000
8397
|
context="registry smoke self-test",
|
|
8001
8398
|
cmd=learn_query_human_cmd,
|
|
@@ -8297,6 +8694,38 @@ def run_self_test() -> None:
|
|
|
8297
8694
|
scope="registry smoke",
|
|
8298
8695
|
)
|
|
8299
8696
|
|
|
8697
|
+
recall_payload = {
|
|
8698
|
+
"recall": {
|
|
8699
|
+
"query": EXPECTED_ROUTE_BRIEF,
|
|
8700
|
+
"mode": "lexical",
|
|
8701
|
+
"candidateCount": 42,
|
|
8702
|
+
"selectedCount": 1,
|
|
8703
|
+
"selected": [
|
|
8704
|
+
{
|
|
8705
|
+
"id": "knowledge/components/INDEX.md",
|
|
8706
|
+
"score": 9.5,
|
|
8707
|
+
"matchedTokens": ["button", "component"],
|
|
8708
|
+
},
|
|
8709
|
+
],
|
|
8710
|
+
"markdown": (
|
|
8711
|
+
"## Recalled design knowledge\n\n"
|
|
8712
|
+
"- knowledge/components/INDEX.md\n"
|
|
8713
|
+
" - Component index"
|
|
8714
|
+
),
|
|
8715
|
+
},
|
|
8716
|
+
}
|
|
8717
|
+
recall_cmd = ["design-ai", "prompt", EXPECTED_ROUTE_BRIEF, "--with-recall", "--json"]
|
|
8718
|
+
assert_recall_context(recall_payload, context="registry smoke self-test", cmd=recall_cmd)
|
|
8719
|
+
expect_self_test_failure(
|
|
8720
|
+
lambda: assert_recall_context(
|
|
8721
|
+
{**recall_payload, "recall": {**recall_payload["recall"], "selectedCount": 0, "selected": []}},
|
|
8722
|
+
context="registry smoke self-test",
|
|
8723
|
+
cmd=recall_cmd,
|
|
8724
|
+
),
|
|
8725
|
+
expected="recall should select at least one corpus file",
|
|
8726
|
+
scope="registry smoke",
|
|
8727
|
+
)
|
|
8728
|
+
|
|
8300
8729
|
learning_audit_path = tmp_root / "learning-audit.json"
|
|
8301
8730
|
duplicate_command_args = [
|
|
8302
8731
|
"design-ai",
|
|
@@ -8503,6 +8932,111 @@ def run_self_test() -> None:
|
|
|
8503
8932
|
scope="registry smoke",
|
|
8504
8933
|
)
|
|
8505
8934
|
|
|
8935
|
+
index_dir = str(tmp_root / "registry-index-self-test")
|
|
8936
|
+
index_build_cmd = ["design-ai", "index", "--build", "--json"]
|
|
8937
|
+
assert_index_build_json(
|
|
8938
|
+
passing_index_build_json(index_dir),
|
|
8939
|
+
index_dir=index_dir,
|
|
8940
|
+
context="registry smoke self-test",
|
|
8941
|
+
cmd=index_build_cmd,
|
|
8942
|
+
)
|
|
8943
|
+
expect_self_test_failure(
|
|
8944
|
+
lambda: assert_index_build_json(
|
|
8945
|
+
"{",
|
|
8946
|
+
index_dir=index_dir,
|
|
8947
|
+
context="registry smoke self-test",
|
|
8948
|
+
cmd=index_build_cmd,
|
|
8949
|
+
),
|
|
8950
|
+
expected="failed to parse index build JSON",
|
|
8951
|
+
scope="registry smoke",
|
|
8952
|
+
)
|
|
8953
|
+
|
|
8954
|
+
index_status_cmd = ["design-ai", "index", "--status", "--json"]
|
|
8955
|
+
assert_index_status_json(
|
|
8956
|
+
passing_index_status_json(index_dir),
|
|
8957
|
+
index_dir=index_dir,
|
|
8958
|
+
context="registry smoke self-test",
|
|
8959
|
+
cmd=index_status_cmd,
|
|
8960
|
+
)
|
|
8961
|
+
assert_index_status_json(
|
|
8962
|
+
passing_index_status_json(index_dir, with_embeddings=True),
|
|
8963
|
+
index_dir=index_dir,
|
|
8964
|
+
context="registry smoke self-test embeddings",
|
|
8965
|
+
cmd=index_status_cmd,
|
|
8966
|
+
expect_embeddings=True,
|
|
8967
|
+
)
|
|
8968
|
+
expect_self_test_failure(
|
|
8969
|
+
lambda: assert_index_status_json(
|
|
8970
|
+
passing_index_status_json(index_dir, with_embeddings=True),
|
|
8971
|
+
index_dir=index_dir,
|
|
8972
|
+
context="registry smoke self-test embeddings unexpected",
|
|
8973
|
+
cmd=index_status_cmd,
|
|
8974
|
+
expect_embeddings=False,
|
|
8975
|
+
),
|
|
8976
|
+
expected="embeddings is not null when embeddings were not built",
|
|
8977
|
+
scope="registry smoke",
|
|
8978
|
+
)
|
|
8979
|
+
|
|
8980
|
+
index_verify_cmd = ["design-ai", "index", "--verify", "--json"]
|
|
8981
|
+
assert_index_verify_json(
|
|
8982
|
+
passing_index_verify_json(index_dir),
|
|
8983
|
+
index_dir=index_dir,
|
|
8984
|
+
context="registry smoke self-test",
|
|
8985
|
+
cmd=index_verify_cmd,
|
|
8986
|
+
)
|
|
8987
|
+
expect_self_test_failure(
|
|
8988
|
+
lambda: assert_index_verify_json(
|
|
8989
|
+
json.dumps({**json.loads(passing_index_verify_json(index_dir)), "ok": False}),
|
|
8990
|
+
index_dir=index_dir,
|
|
8991
|
+
context="registry smoke self-test",
|
|
8992
|
+
cmd=index_verify_cmd,
|
|
8993
|
+
),
|
|
8994
|
+
expected="ok is not true",
|
|
8995
|
+
scope="registry smoke",
|
|
8996
|
+
)
|
|
8997
|
+
|
|
8998
|
+
ranked_search_cmd = ["design-ai", "search", EXPECTED_CORPUS_SEARCH_QUERY, "--ranked", "--json"]
|
|
8999
|
+
ranked_search_json = passing_ranked_search_json()
|
|
9000
|
+
assert_ranked_search_json(
|
|
9001
|
+
ranked_search_json,
|
|
9002
|
+
context="registry smoke self-test",
|
|
9003
|
+
cmd=ranked_search_cmd,
|
|
9004
|
+
)
|
|
9005
|
+
assert_ranked_search_determinism(
|
|
9006
|
+
ranked_search_json,
|
|
9007
|
+
ranked_search_json,
|
|
9008
|
+
context="registry smoke self-test",
|
|
9009
|
+
cmd=ranked_search_cmd,
|
|
9010
|
+
)
|
|
9011
|
+
expect_self_test_failure(
|
|
9012
|
+
lambda: assert_ranked_search_determinism(
|
|
9013
|
+
ranked_search_json,
|
|
9014
|
+
passing_ranked_search_json(backend="lexical"),
|
|
9015
|
+
context="registry smoke self-test",
|
|
9016
|
+
cmd=ranked_search_cmd,
|
|
9017
|
+
),
|
|
9018
|
+
expected="differs between identical runs",
|
|
9019
|
+
scope="registry smoke",
|
|
9020
|
+
)
|
|
9021
|
+
|
|
9022
|
+
ranked_search_fallback_json = passing_ranked_search_json(backend="lexical")
|
|
9023
|
+
assert_ranked_search_json(
|
|
9024
|
+
ranked_search_fallback_json,
|
|
9025
|
+
context="registry smoke self-test fallback",
|
|
9026
|
+
cmd=ranked_search_cmd,
|
|
9027
|
+
expected_backend="lexical",
|
|
9028
|
+
)
|
|
9029
|
+
expect_self_test_failure(
|
|
9030
|
+
lambda: assert_ranked_search_json(
|
|
9031
|
+
passing_ranked_search_json(backend="embeddings"),
|
|
9032
|
+
context="registry smoke self-test fallback mismatch",
|
|
9033
|
+
cmd=ranked_search_cmd,
|
|
9034
|
+
expected_backend="lexical",
|
|
9035
|
+
),
|
|
9036
|
+
expected="backend differs from expected backend",
|
|
9037
|
+
scope="registry smoke",
|
|
9038
|
+
)
|
|
9039
|
+
|
|
8506
9040
|
expect_self_test_failure(
|
|
8507
9041
|
lambda: smoke_registry_package("self-test-package", retries=0, delay=0),
|
|
8508
9042
|
expected="--retries must be at least 1",
|