thoughtleaders-cli 0.6.22__tar.gz → 0.6.24__tar.gz

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.
Files changed (91) hide show
  1. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/PKG-INFO +1 -1
  3. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/pyproject.toml +1 -1
  4. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl/references/postgres-schema.md +1 -0
  5. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/SKILL.md +17 -5
  6. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/topic_matcher.md +17 -1
  7. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/__init__.py +1 -1
  8. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/self_update.py +3 -2
  9. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/.claude-plugin/marketplace.json +0 -0
  10. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/.github/workflows/python-publish.yml +0 -0
  11. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/.gitignore +0 -0
  12. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/AGENTS.md +0 -0
  13. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/CLAUDE.md +0 -0
  14. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/LICENSE +0 -0
  15. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/README.md +0 -0
  16. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/agents/tl-analyst.md +0 -0
  17. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/commands/tl-balance.md +0 -0
  18. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/commands/tl-reports.md +0 -0
  19. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/commands/tl-sponsorships.md +0 -0
  20. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/commands/tl.md +0 -0
  21. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/docs/architecture.md +0 -0
  22. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/hooks/hooks.json +0 -0
  23. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/hooks/scripts/post-usage.sh +0 -0
  24. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/hooks/scripts/pre-check.sh +0 -0
  25. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl/SKILL.md +0 -0
  26. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl/references/business-glossary.md +0 -0
  27. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl/references/elasticsearch-schema.md +0 -0
  28. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl/references/firebolt-schema.md +0 -0
  29. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
  30. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/examples/golden_queries.md +0 -0
  31. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/columns_brands.md +0 -0
  32. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/columns_channels.md +0 -0
  33. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/columns_content.md +0 -0
  34. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
  35. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
  36. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
  37. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/report_glossary.md +0 -0
  38. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/sortable_columns.json +0 -0
  39. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
  40. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
  41. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/references/widgets.md +0 -0
  42. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/column_builder.md +0 -0
  43. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/database_query.md +0 -0
  44. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/keyword_research.md +0 -0
  45. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/name_resolver.md +0 -0
  46. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/sample_judge.md +0 -0
  47. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/similar_channels.md +0 -0
  48. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/skills/tl-report-builder/tools/widget_builder.md +0 -0
  49. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/_completions.py +0 -0
  50. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/auth/__init__.py +0 -0
  51. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/auth/commands.py +0 -0
  52. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/auth/login.py +0 -0
  53. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/auth/pkce.py +0 -0
  54. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/auth/token_store.py +0 -0
  55. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/client/__init__.py +0 -0
  56. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/client/errors.py +0 -0
  57. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/client/http.py +0 -0
  58. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/__init__.py +0 -0
  59. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/_comments_common.py +0 -0
  60. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/ask.py +0 -0
  61. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/balance.py +0 -0
  62. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/brands.py +0 -0
  63. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/changelog.py +0 -0
  64. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/channels.py +0 -0
  65. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/db.py +0 -0
  66. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/deals.py +0 -0
  67. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/describe.py +0 -0
  68. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/doctor.py +0 -0
  69. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/matches.py +0 -0
  70. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/proposals.py +0 -0
  71. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/recommender.py +0 -0
  72. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/reports.py +0 -0
  73. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/schema.py +0 -0
  74. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/setup.py +0 -0
  75. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/snapshots.py +0 -0
  76. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/sponsorships.py +0 -0
  77. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/uploads.py +0 -0
  78. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/commands/whoami.py +0 -0
  79. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/config.py +0 -0
  80. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/filters.py +0 -0
  81. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/hints.py +0 -0
  82. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/main.py +0 -0
  83. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/output/__init__.py +0 -0
  84. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/src/tl_cli/output/formatter.py +0 -0
  85. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/__init__.py +0 -0
  86. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/test_auth.py +0 -0
  87. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/test_filters.py +0 -0
  88. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/test_output.py +0 -0
  89. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/test_reports.py +0 -0
  90. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/tests/test_sponsorships.py +0 -0
  91. {thoughtleaders_cli-0.6.22 → thoughtleaders_cli-0.6.24}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.6.22",
3
+ "version": "0.6.24",
4
4
  "description": "ThoughtLeaders CLI — query sponsorship deals, channels, brands, uploads, and intelligence from the terminal",
5
5
  "author": {
6
6
  "name": "ThoughtLeaders",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thoughtleaders-cli
3
- Version: 0.6.22
3
+ Version: 0.6.24
4
4
  Summary: ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence
5
5
  Project-URL: Homepage, https://thoughtleaders.io
6
6
  Project-URL: Repository, https://github.com/ThoughtLeaders-io/thoughtleaders-cli
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "thoughtleaders-cli"
7
- version = "0.6.22"
7
+ version = "0.6.24"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -270,6 +270,7 @@ Common hallucinations the agent has tried in real runs (each wasted a round-trip
270
270
  Cited regression markers from real runs:
271
271
  - AI/marketing channels run: tried `thoughtleaders_topic` (singular — table doesn't exist), then `WHERE is_active = TRUE`. Three round-trips before consulting `information_schema`.
272
272
  - Travel/digital-nomad run: tried `SELECT id, name, type, parent_id FROM thoughtleaders_topics WHERE name ILIKE ANY(...)`.
273
+ - **Name-pattern WHERE-clause loop (general pattern)**: when the user's niche has no obvious curated topic, agents have run progressively broader name-pattern `WHERE` queries against this table — typically two or three rounds of `WHERE name ILIKE '%<term1>%' OR name ILIKE '%<term2>%' OR ...`, sometimes interleaved with an `information_schema.columns` inspection between them — each returning zero rows. The correct path is one canonical fetch (above) + the matcher's `summary.no_match: true` verdict for the off-taxonomy case. **A zero-row canonical fetch (no WHERE clause) is a data-plane failure, NOT off-taxonomy** — surface the failure rather than silently falling through to keyword_research.
273
274
 
274
275
  If a query against this table errors with *"column '\<X\>' does not exist"*, that's the regression marker — go back to the verbatim fetch above.
275
276
 
@@ -321,11 +321,16 @@ USER_QUERY
321
321
  │ • Type-8: count_sponsorships, sum_price (axis branches on │
322
322
  │ publish_status — send_date for proposals, purchase_date for sold)│
323
323
  │ • histogram_bucket_size set per date range │
324
+ │ • Generate report_title + report_description from final config │
325
+ │ (must happen BEFORE validation — both fields are mandatory │
326
+ │ on save and the validation step below checks for them) │
324
327
  │ • PERFORM FINAL JSON-SHAPE VALIDATION of the campaign config: │
325
328
  │ – All Phase 2 + Phase 3 + Phase 4 outputs compose validly │
326
329
  │ – API-contract pre-check (type=2 DYNAMIC, valid report_type, │
327
- │ non-empty columns, sort references an emitted column)
328
- Generate report_title + report_description from final config
330
+ │ non-empty columns, sort references an emitted column,
331
+ report_title ≤60 chars non-empty, report_description
332
+ │ 1–3 sentences non-empty — both mandatory on save; CLI │
333
+ │ rejects with HTTP 400 if either is missing) │
329
334
  │ • Compose key takeaway insights │
330
335
  │ │
331
336
  │ ↘ FOLLOW-UP TRIGGERS: │
@@ -474,7 +479,13 @@ Each tool fires only when its criteria are explicitly met (no automatic / specul
474
479
  ### T1 — `tools/topic_matcher.md`
475
480
  **Fires when**: `ReportType ∈ {1, 2, 3}` AND USER_QUERY mentions a topic concept that could plausibly map to a curated topic in `thoughtleaders_topics`.
476
481
  **Skipped when**: `ReportType == 8` (sponsorships don't use topic matching at the SQL level) OR USER_QUERY is purely an entity-name lookup ("emails for these channels").
477
- **How to fetch the live topics**: see the `tl-cli:tl` skill's Postgres-schema reference [`tl/references/postgres-schema.md` → `thoughtleaders_topics`](../tl/references/postgres-schema.md#thoughtleaders_topics-curated-topic-taxonomy). That's the canonical home for the fetch query, column list, and "do not guess" regression markers. Don't restate the SQL here.
482
+ **How to fetch the live topics**: use the canonical fetch SQL documented at [`tl/references/postgres-schema.md` → `thoughtleaders_topics` → Fetch query](../tl/references/postgres-schema.md#fetch-query-canonical--use-verbatim). Single query, no `WHERE` clause; table has <20 rows so client-side filtering after the full fetch is free.
483
+
484
+ **Agent-behaviour rules** (encoded in [`tools/topic_matcher.md`](tools/topic_matcher.md); regression markers catalogued in the schema reference's "Cited regression markers" list):
485
+
486
+ - Don't push name-pattern `WHERE` clauses into the fetch query — agents have burnt credits + round-trips on this in multiple real runs.
487
+ - Don't run `information_schema.columns` to inspect the table.
488
+ - **Empty fetch ≠ off-taxonomy.** A zero-row result from the canonical (no-`WHERE`) fetch is a data-plane failure — surface it rather than silently falling through to T2. Off-taxonomy is when the fetch returns rows but the matcher emits `summary.no_match: true`.
478
489
  **Output**: per-topic verdicts (strong/weak/none) + summary. If `summary.strong_matches` non-empty, the topic's curated `keywords[]` array drives the FilterSet's `keywords` field (with per-position `content_fields` set via `keyword_content_fields_map` when a keyword targets a non-default match surface). Phase 2 may also emit the matched topic IDs directly via the FilterSet's `topics` field — both paths are valid; pick by intent.
479
490
 
480
491
  **Narrow-first FilterSet assembly (mandatory — applies to topic-strong + keyword_research paths both)**: Phase 2c MUST assemble the FilterSet with the **narrowest viable shape first**, then validate. Expand only if the count is below the type's narrow threshold. The two narrowing levers, **ranked by impact on noisy-niche / multilingual runs**:
@@ -1468,7 +1479,9 @@ Phase 4 is the terminal phase. It picks widgets, performs FINAL JSON-shape valid
1468
1479
  ### Process
1469
1480
 
1470
1481
  1. **Pick widgets via `tools/widget_builder.md`.** Inject `REPORT_TYPE`, `FILTERSET`, `COLUMNS`, `ROUTING_METADATA`, and the matching widget schema (`references/intelligence_widget_schema.json` for types 1/2/3; `references/sponsorship_widget_schema.json` for type 8). The builder emits `{ widgets, histogram_bucket_size, _widget_metadata }`. **The selection rule is: emit only widgets that add value to the user's original prompt.** A widget earns its slot if it answers a question the user implicitly cares about (intent), surfaces a metric tied to a filter the user named (niche), or shows a trend over the date scope they specified. Don't pad to hit 6 — emit fewer (down to 4) if the extras don't answer something. The builder handles type-8 axis branching and intent-driven swaps per the schema's `_tl_intent_overrides`.
1471
- 2. **FINAL JSON-shape validation pass.** Verify the composed config:
1482
+ 2. **Generate `report_title` and `report_description`** from the FilterSet + the user's original NL request. Title ≤ 60 chars; description 1–3 sentences summarizing intent + key filters. **Do this BEFORE step 3's validation pass** both fields are mandatory on save, so the validation in step 3 needs to see them populated.
1483
+ 3. **FINAL JSON-shape validation pass.** Verify the composed config:
1484
+ - **`report_title` is a non-empty string ≤ 60 chars AND `report_description` is a non-empty 1–3 sentences.** Both fields are **MANDATORY** on `tl reports create` — the CLI rejects with HTTP 400 `Missing required field: report_title` (or `report_description`) if either is missing. If step 2 (title/description generation) hasn't run yet, run it FIRST, then come back to this check. Verbatim regression marker (real run, LATAM cooking 2026-05-11): saved config omitted `report_title`; first `tl reports create --config-file <path> --yes` returned `Error (400): Missing required field: report_title` and the agent had to edit the transport file and retry. **Fail closed at this validation step rather than discovering the missing field at save time** — a save-side 400 wastes a CLI round-trip and a credit charge.
1472
1485
  - Every field in `filterset` exists in the schema and matches its declared type.
1473
1486
  - Every column in `columns` is in the type's column file.
1474
1487
  - Every aggregator in `widgets` is in the matching catalog (intelligence for 1/2/3, sponsorship for 8).
@@ -1477,7 +1490,6 @@ Phase 4 is the terminal phase. It picks widgets, performs FINAL JSON-shape valid
1477
1490
  - When `cross_references` is present, `report_type ∈ {1, 3}`.
1478
1491
  - When `filters_json.similar_to_channels` is present, no overlapping `keywords` / `topics` fields.
1479
1492
  - `type = 2` (DYNAMIC) and `report_type ∈ {1, 2, 3, 8}` — Campaign-model contract for the API endpoint.
1480
- 3. **Generate `report_title` and `report_description`** from the FilterSet + the user's original NL request. Title ≤ 60 chars; description 1–3 sentences summarizing intent + key filters.
1481
1493
  4. **Compose key takeaway insights** — see "Takeaway-composition rules" below. These are the headline observations the user reads in the Phase 4 message. The `_validation` block from Phase 2 carries through here — narrow-result notes, sample_judge reasoning, and validation_concerns are all surfaced as takeaways.
1482
1494
  5. **Emit the final deliverable.**
1483
1495
 
@@ -26,7 +26,23 @@ The orchestration injects two values:
26
26
 
27
27
  ### How to fetch the topics
28
28
 
29
- The fetch query, the column list, and the negative-column regression markers all live in the canonical Postgres-schema reference in the `tl-cli:tl` skill: **[`tl/references/postgres-schema.md` → `thoughtleaders_topics`](../../tl/references/postgres-schema.md#thoughtleaders_topics-curated-topic-taxonomy)**. Schema-shaped facts belong in that reference, not in tool text. Use the verbatim fetch query documented there. **Do not restate or paraphrase the schema here.** If you find yourself about to type `SELECT … FROM thoughtleaders_topics …` from memory, stop and consult the reference file instead. This tool's job is to score topics against the user query; the schema reference's job is to say what the underlying table looks like.
29
+ Use the canonical fetch SQL from the schema reference: **[`tl/references/postgres-schema.md` → `thoughtleaders_topics` → Fetch query](../../tl/references/postgres-schema.md#fetch-query-canonical--use-verbatim)**. The table has fewer than 20 rows; client-side filtering after the full fetch is free **filter the results in your head, not in SQL.** Column catalogue and "do not exist" markers live in the same reference; consult it when you need column-level facts.
30
+
31
+ **Agent-behaviour rules** (these are agent-side, not schema-shaped — the failure modes pinned here are catalogued in the schema reference's "Cited regression markers" list):
32
+
33
+ - ❌ Don't push a name-pattern `WHERE` clause into the query (e.g. `WHERE name ILIKE '%crypto%' OR name ILIKE '%web3%' OR ...`). Whatever the user said, the right path is fetch-all → match in your head.
34
+ - ❌ Don't run `information_schema.columns` to inspect the table. If you need column names, read the schema reference linked above.
35
+ - ❌ Don't retry the canonical fetch with broader patterns or different fields when the matcher reads the fetched rows and emits `summary.no_match: true` — that's off-taxonomy. Fall through to keyword_research (T2).
36
+
37
+ **Interpreting the fetch result:**
38
+
39
+ | Fetch result | Meaning | Next step |
40
+ |---|---|---|
41
+ | Non-empty, matcher emits ≥1 `strong` / `weak` verdict | Curated match found | Use the matched topic's `keywords[]` array in the FilterSet (topic-strong path) |
42
+ | Non-empty, matcher emits all `none` verdicts (`summary.no_match: true`) | **Off-taxonomy** — niche has no curated topic | Fall through to keyword_research (T2) |
43
+ | **Empty (zero rows returned)** | **Data-plane failure or empty taxonomy — NOT off-taxonomy.** The canonical fetch has no `WHERE` clause; an empty result means either the table is empty, the database returned an error, or the request was truncated. | Surface the failure rather than silently falling through to T2. If a re-fetch also returns empty, escalate to the user — silently bypassing curated topic matching on a real data-plane failure would mask the bug. |
44
+
45
+ The "Cited regression markers" section in the schema reference catalogues the anti-pattern shapes that have occurred in practice. Read it when you recognise the failure-mode shape in your own output.
30
46
 
31
47
  ---
32
48
 
@@ -1,3 +1,3 @@
1
1
  """ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence."""
2
2
 
3
- __version__ = "0.6.22"
3
+ __version__ = "0.6.24"
@@ -34,9 +34,10 @@ def _detect_install_method() -> str | None:
34
34
 
35
35
  Both the new distribution name (`thoughtleaders-cli`) and the legacy one
36
36
  (`tl-cli`) are matched so users who installed before the rename keep
37
- auto-updating.
37
+ auto-updating. `Path.as_posix()` normalises Windows backslashes so the
38
+ same substring checks work on every platform.
38
39
  """
39
- exe = sys.executable
40
+ exe = Path(sys.executable).as_posix()
40
41
  for dist_name in ("thoughtleaders-cli", "tl-cli"):
41
42
  if f"/pipx/venvs/{dist_name}/" in exe:
42
43
  return "pipx"