Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

239 lines
35 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[
{ "id": "T001", "featureIds": ["F001", "F003"], "description": "Migration up creates `app_search_index` table with exactly the columns and types listed in PRD §9.1", "implemented": true },
{ "id": "T002", "featureIds": ["F003"], "description": "Primary key is `(tenant, object_type, object_id)` and `tenant` is NOT NULL", "implemented": true },
{ "id": "T003", "featureIds": ["F002"], "description": "Migration is idempotent on `pg_trgm`: re-running CREATE EXTENSION IF NOT EXISTS does not fail", "implemented": true },
{ "id": "T004", "featureIds": ["F004"], "description": "Under Citus, `pg_dist_partition` shows `app_search_index` distributed by `tenant`", "implemented": true },
{ "id": "T005", "featureIds": ["F004"], "description": "Without Citus extension, migration completes without invoking `create_distributed_table`", "implemented": true },
{ "id": "T006", "featureIds": ["F005"], "description": "GIN index on `search_vector` is present and is selected by EXPLAIN for an `@@` query", "implemented": true },
{ "id": "T007", "featureIds": ["F006"], "description": "GIN trgm index on `title` is selected by EXPLAIN for `title %% 'abc'`", "implemented": true },
{ "id": "T008", "featureIds": ["F006"], "description": "GIN trgm index on `subtitle` is selected by EXPLAIN for `subtitle %% 'abc'`", "implemented": true },
{ "id": "T009", "featureIds": ["F007"], "description": "btree indexes on `(tenant, source_updated_at DESC)` and `(tenant, object_type)` exist", "implemented": true },
{ "id": "T010", "featureIds": ["F008"], "description": "Migration down drops the table; re-running up succeeds afterwards", "implemented": true },
{ "id": "T011", "featureIds": ["F009"], "description": "All 27 entity types compile-time exhaustive-check via a switch over `SearchObjectType`", "implemented": true },
{ "id": "T012", "featureIds": ["F010", "F011"], "description": "SearchDoc / AclMetadata interfaces require ACL fields when the entity has non-trivial ACL (compile-time)", "implemented": true },
{ "id": "T013", "featureIds": ["F012"], "description": "`flattenBlockNote` extracts visible text from a real document's BlockNote JSON fixture", "implemented": true },
{ "id": "T014", "featureIds": ["F012"], "description": "`flattenBlockNote` drops image data URI payloads (no `data:image/...` substring in output)", "implemented": true },
{ "id": "T015", "featureIds": ["F012"], "description": "`flattenBlockNote` handles deeply nested lists and inline marks without throwing", "implemented": true },
{ "id": "T016", "featureIds": ["F013"], "description": "`flattenMarkdown` strips headings, lists, link syntax, bold/italic markers, code fences, leaves plain text", "implemented": true },
{ "id": "T017", "featureIds": ["F014"], "description": "`flattenJsonbPayload` concatenates string leaves and skips keys matching the secret regex (`password|secret|token|api_key|authorization`)", "implemented": true },
{ "id": "T018", "featureIds": ["F014"], "description": "`flattenJsonbPayload` returns an empty string for non-object/non-array inputs", "implemented": true },
{ "id": "T019", "featureIds": ["F015"], "description": "`truncateForIndex` enforces ≤ max bytes on a UTF-8 multibyte string without splitting a code point", "implemented": true },
{ "id": "T020", "featureIds": ["F015"], "description": "`truncateForIndex` is a no-op when input is already under the limit", "implemented": true },
{ "id": "T021", "featureIds": ["F016"], "description": "`buildTsvectorSql` produces SQL containing `process_large_lexemes(`, weight 'A' for title, 'B' for subtitle, 'C' for body", "implemented": true },
{ "id": "T022", "featureIds": ["F017", "F018"], "description": "Registry exposes exactly 27 indexers via `allIndexers()`; `getIndexer('client')` returns the client indexer", "implemented": true },
{ "id": "T023", "featureIds": ["F019"], "description": "`upsertSearchDoc` inserts a new row when none exists for (tenant, type, id)", "implemented": true },
{ "id": "T024", "featureIds": ["F019"], "description": "`upsertSearchDoc` updates an existing row, refreshing `search_vector` and `indexed_at`", "implemented": true },
{ "id": "T025", "featureIds": ["F020"], "description": "`deleteSearchDoc` removes the row and is a no-op when none exists", "implemented": true },
{ "id": "T026", "featureIds": ["F019"], "description": "Concurrent `upsertSearchDoc` calls for the same (tenant, type, id) end up with one row (last write wins)", "implemented": true },
{ "id": "T027", "featureIds": ["F022"], "description": "Client indexer loadOne returns a SearchDoc with title=client_name and required_permission='client:read'", "implemented": true },
{ "id": "T028", "featureIds": ["F022"], "description": "Backfilling client indexer for a seeded tenant produces an index row for every client in that tenant", "implemented": true },
{ "id": "T029", "featureIds": ["F023"], "description": "Contact indexer subtitle includes email and phone", "implemented": true },
{ "id": "T030", "featureIds": ["F024"], "description": "User indexer excludes users with `user_type='client'`", "implemented": true },
{ "id": "T031", "featureIds": ["F025"], "description": "Ticket indexer denormalizes client_name into subtitle and exposes ticket_number in metadata.identifier", "implemented": true },
{ "id": "T032", "featureIds": ["F026"], "description": "Ticket-comment indexer sets is_internal_only=true when source `comments.is_internal` is true", "implemented": true },
{ "id": "T033", "featureIds": ["F026"], "description": "Ticket-comment indexer url ends with `#comment-{comment_id}`", "implemented": true },
{ "id": "T034", "featureIds": ["F027"], "description": "Project indexer sets `client_scope_id` to the project's client_id", "implemented": true },
{ "id": "T035", "featureIds": ["F028", "F029"], "description": "Project phase/task indexers inherit ACL fields from their parent project", "implemented": true },
{ "id": "T036", "featureIds": ["F030"], "description": "Project-task-comment indexer prefers markdown_content over BlockNote content when both are present", "implemented": true },
{ "id": "T037", "featureIds": ["F030"], "description": "Project-task-comment indexer falls back to `flattenBlockNote(note)` when markdown_content is null", "implemented": true },
{ "id": "T038", "featureIds": ["F031"], "description": "Asset indexer's body contains flattened jsonb attribute string values but never key names like `password`", "implemented": true },
{ "id": "T039", "featureIds": ["F031"], "description": "Asset indexer metadata.identifier equals asset_tag", "implemented": true },
{ "id": "T040", "featureIds": ["F032"], "description": "Invoice indexer denormalizes client_name in subtitle and metadata.identifier equals invoice_number", "implemented": true },
{ "id": "T041", "featureIds": ["F033", "F034"], "description": "Invoice-item and annotation indexers inherit invoice client_scope_id and required_permission", "implemented": true },
{ "id": "T042", "featureIds": ["F035"], "description": "Contract indexer with `contracts.status='draft'` sets subtitle to 'Quote'", "implemented": true },
{ "id": "T043", "featureIds": ["F035"], "description": "Contract indexer with `contracts.status='active'` sets subtitle to 'Contract'", "implemented": true },
{ "id": "T044", "featureIds": ["F037"], "description": "Document indexer body length is ≤ 65536 bytes even when source content is multi-MB", "implemented": true },
{ "id": "T045", "featureIds": ["F037"], "description": "Document indexer sets `client_scope_id` from `documents.client_id` when non-null; leaves `is_private` and `visible_to_user_ids` at defaults (false / empty)", "implemented": true },
{ "id": "T046", "featureIds": ["F038"], "description": "KB article indexer pulls content via the FK join to documents", "implemented": true },
{ "id": "T047", "featureIds": ["F039"], "description": "Service catalog indexer includes flattened `attributes` jsonb string values in body", "implemented": true },
{ "id": "T048", "featureIds": ["F040"], "description": "Service-request-submission indexer flattens submitted_payload string fields but excludes secret-like keys", "implemented": true },
{ "id": "T049", "featureIds": ["F041"], "description": "Service-request-definition indexer requires admin permission via required_permission column", "implemented": true },
{ "id": "T050", "featureIds": ["F042"], "description": "Workflow-task indexer populates visible_to_user_ids with all assignee user_ids", "implemented": true },
{ "id": "T051", "featureIds": ["F044"], "description": "Schedule-entry indexer populates visible_to_user_ids with the owner", "implemented": true },
{ "id": "T052", "featureIds": ["F045"], "description": "Time-entry indexer SKIPS rows where notes is NULL or empty string (no index row produced)", "implemented": true },
{ "id": "T053", "featureIds": ["F045"], "description": "Time-entry indexer produces a row when notes is any non-empty string (even a single character)", "implemented": true },
{ "id": "T054", "featureIds": ["F046", "F047", "F048"], "description": "Board, Category, Tag indexers produce rows with only required_permission='ticket:read'", "implemented": true },
{ "id": "T055", "featureIds": ["F049"], "description": "Creating a client publishes `CLIENT_CREATED` event with tenant + client_id", "implemented": true },
{ "id": "T056", "featureIds": ["F049"], "description": "Updating a client publishes `CLIENT_UPDATED`", "implemented": true },
{ "id": "T057", "featureIds": ["F049"], "description": "Deleting a client publishes `CLIENT_DELETED`", "implemented": true },
{ "id": "T058", "featureIds": ["F050"], "description": "Contact CRUD emits CONTACT_* events", "implemented": true },
{ "id": "T059", "featureIds": ["F051"], "description": "User CRUD and role-change emit corresponding events", "implemented": true },
{ "id": "T060", "featureIds": ["F052"], "description": "Project CRUD and child entity CRUD emit project-family events", "implemented": true },
{ "id": "T061", "featureIds": ["F053"], "description": "Asset CRUD emits ASSET_* events", "implemented": true },
{ "id": "T062", "featureIds": ["F054"], "description": "Invoice CRUD (header, items, annotations) emits invoice-family events", "implemented": true },
{ "id": "T063", "featureIds": ["F055"], "description": "Contract / client-contract CRUD emits contract-family events", "implemented": true },
{ "id": "T064", "featureIds": ["F056"], "description": "Document content-change AND share-list-change both emit DOCUMENT_UPDATED", "implemented": true },
{ "id": "T065", "featureIds": ["F057"], "description": "Service catalog CRUD emits SERVICE_CATALOG_* events", "implemented": true },
{ "id": "T066", "featureIds": ["F058"], "description": "Service-request submission / definition CRUD emits corresponding events", "implemented": true },
{ "id": "T067", "featureIds": ["F059"], "description": "Workflow task CRUD + assignment-change emit corresponding events", "implemented": true },
{ "id": "T068", "featureIds": ["F060", "F061", "F062"], "description": "Interaction, schedule, time-entry, board/category/tag CRUD emit corresponding events", "implemented": true },
{ "id": "T069", "featureIds": ["F063", "F064"], "description": "Subscriber starts subscribed to every `sourceEvents` set returned by registered indexers (union of events)", "implemented": true },
{ "id": "T070", "featureIds": ["F065"], "description": "A `CLIENT_CREATED` event causes an upsert into `app_search_index` with object_type='client'", "implemented": true },
{ "id": "T071", "featureIds": ["F066"], "description": "A `CLIENT_DELETED` event causes the index row to be deleted", "implemented": true },
{ "id": "T072", "featureIds": ["F067"], "description": "With `SEARCH_INDEX_LIVE=false`, events are received but `app_search_index` is not written to", "implemented": true },
{ "id": "T073", "featureIds": ["F067"], "description": "Flipping `SEARCH_INDEX_LIVE=true` without restart picks up live writes (or is documented to require a restart)", "implemented": true },
{ "id": "T074", "featureIds": ["F065"], "description": "Subscriber handles a missing source row (race: row deleted before loadOne resolves) by deleting the index row instead of erroring", "implemented": true },
{ "id": "T075", "featureIds": ["F068"], "description": "TICKET_UPDATED triggers a cascade re-index of all of the ticket's comments (their denormalized parent title updates)", "implemented": true },
{ "id": "T076", "featureIds": ["F069"], "description": "INVOICE_UPDATED triggers cascade re-index of items and annotations", "implemented": true },
{ "id": "T077", "featureIds": ["F070"], "description": "PROJECT_UPDATED triggers a paged async re-index covering all phases/tasks/task-comments", "implemented": true },
{ "id": "T078", "featureIds": ["F071"], "description": "Inserting a `document_associations` row tying a document to a different client triggers re-index of the document row with updated `client_scope_id`", "implemented": true },
{ "id": "T079", "featureIds": ["F072"], "description": "User role change kicks off background re-index of rows where the user appears in `visible_to_user_ids`", "implemented": true },
{ "id": "T080", "featureIds": ["F073", "F074", "F075"], "description": "`npm run search:backfill -- --tenant=<uuid> --type=client` indexes all clients for that tenant", "implemented": true },
{ "id": "T081", "featureIds": ["F076"], "description": "Backfill processes a 10k-row table in batches of 500 without OOM", "implemented": true },
{ "id": "T082", "featureIds": ["F077"], "description": "Running backfill twice produces identical row content (idempotent)", "implemented": true },
{ "id": "T083", "featureIds": ["F074"], "description": "Backfill without --tenant flag iterates all tenants discovered via tenant catalog", "implemented": true },
{ "id": "T084", "featureIds": ["F078"], "description": "`npm run search:backfill` is wired in root package.json", "implemented": true },
{ "id": "T085", "featureIds": ["F079", "F080"], "description": "Reconciliation re-indexes a row whose `source_updated_at` advanced after the last index update", "implemented": true },
{ "id": "T086", "featureIds": ["F081"], "description": "Reconciliation deletes an index row whose source row was deleted directly via SQL (event missed)", "implemented": true },
{ "id": "T087", "featureIds": ["F082"], "description": "Reconciliation re-creates an index row that was manually deleted while source still exists", "implemented": true },
{ "id": "T088", "featureIds": ["F083"], "description": "Reconciliation job is registered with pg-boss at startup with a daily cron schedule", "implemented": true },
{ "id": "T089", "featureIds": ["F084"], "description": "parseQuery rejects queries > 200 chars with a typed error", "implemented": true },
{ "id": "T090", "featureIds": ["F084"], "description": "parseQuery accepts and normalizes whitespace and casing", "implemented": true },
{ "id": "T091", "featureIds": ["F085"], "description": "FTS branch returns matches via `search_vector @@ websearch_to_tsquery(...)`", "implemented": true },
{ "id": "T092", "featureIds": ["F085"], "description": "FTS results ordered by `ts_rank_cd` desc", "implemented": true },
{ "id": "T093", "featureIds": ["F086"], "description": "pg_trgm fallback returns results when FTS finds nothing but title is a similar string (`exhcange` → `Exchange`)", "implemented": true },
{ "id": "T094", "featureIds": ["F086"], "description": "pg_trgm similarity is included in the composite score when present", "implemented": true },
{ "id": "T095", "featureIds": ["F087"], "description": "Query `TIC-1023` pins the matching ticket as result #1 via metadata identifier match", "implemented": true },
{ "id": "T096", "featureIds": ["F087"], "description": "Asset-tag style query (e.g., `LAP-0042`) pins the matching asset", "implemented": true },
{ "id": "T097", "featureIds": ["F088"], "description": "All else equal, newer rows rank higher than older rows by ~time-decay factor", "implemented": true },
{ "id": "T098", "featureIds": ["F088"], "description": "Time decay multiplier never drops below 0.05 (floor)", "implemented": true },
{ "id": "T099", "featureIds": ["F089"], "description": "Cursor encoding round-trip is stable; decoded cursor reproduces page boundary correctly", "implemented": true },
{ "id": "T100", "featureIds": ["F089"], "description": "Pagination is stable across two pages: row appearing on page 1 does not reappear on page 2", "implemented": true },
{ "id": "T101", "featureIds": ["F090"], "description": "ts_headline output contains the configured sentinel tokens around matched terms in the body", "implemented": true },
{ "id": "T102", "featureIds": ["F091"], "description": "Sanitizer rebuild produces output containing ONLY `<mark>` tags around match segments; given source body with literal `<script>` text, output contains escaped `&lt;script&gt;`, no executable HTML", "implemented": true },
{ "id": "T103", "featureIds": ["F091"], "description": "Sanitizer is robust to unpaired sentinels (malformed ts_headline output) — falls back to fully escaped output instead of throwing", "implemented": true },
{ "id": "T104", "featureIds": ["F092"], "description": "Typeahead action SQL does NOT include ts_headline (verified via captured query string or telemetry)", "implemented": true },
{ "id": "T105", "featureIds": ["F093"], "description": "acl_predicate excludes rows whose `required_permission` is not in the user's permission set", "implemented": true },
{ "id": "T106", "featureIds": ["F094"], "description": "User permission set is resolved exactly once per action call (not per-row)", "implemented": true },
{ "id": "T107", "featureIds": ["F095"], "description": "Row with non-empty `visible_to_user_ids` is excluded for users not in the array", "implemented": true },
{ "id": "T108", "featureIds": ["F095"], "description": "Row with empty `visible_to_user_ids` is visible to all users with the required permission", "implemented": true },
{ "id": "T109", "featureIds": ["F096"], "description": "`is_internal_only=true` row hidden from a client-type user", "implemented": true },
{ "id": "T110", "featureIds": ["F096"], "description": "Synthetic row with `is_private=true` and non-empty `visible_to_user_ids` is hidden from users not in the array (validates the column is wired, even though no v1 entity sets it)", "implemented": true },
{ "id": "T111", "featureIds": ["F096"], "description": "`client_scope_id` filters out rows for clients the user has no access to", "implemented": true },
{ "id": "T112", "featureIds": ["F097", "F098"], "description": "verifyResultVisibility drops rows that the SQL filter let through but the record-level helper rejects", "implemented": true },
{ "id": "T113", "featureIds": ["F099"], "description": "`search.acl_drift` telemetry counter increments when a discrepancy occurs", "implemented": true },
{ "id": "T114", "featureIds": ["F097"], "description": "verifyResultVisibility is a no-op when SQL filter and record-level checks agree (zero drift)", "implemented": true },
{ "id": "T115", "featureIds": ["F100"], "description": "searchAppAction returns SearchAppResult with grouped counts per object_type", "implemented": true },
{ "id": "T116", "featureIds": ["F100"], "description": "searchAppAction throws when called unauthenticated (via withAuth)", "implemented": true },
{ "id": "T117", "featureIds": ["F100"], "description": "searchAppAction enforces tenant isolation: a row from tenant B is never returned to a user in tenant A across 10k seeded queries", "implemented": true },
{ "id": "T118", "featureIds": ["F101"], "description": "searchAppTypeaheadAction returns ≤5 results, title-only, no snippet field", "implemented": true },
{ "id": "T119", "featureIds": ["F101"], "description": "searchAppTypeaheadAction p50 latency < 100ms against a seeded medium tenant", "implemented": true },
{ "id": "T120", "featureIds": ["F102"], "description": "Zod input rejects empty query, > 200 chars, types not in the union, limit > 100", "implemented": true },
{ "id": "T121", "featureIds": ["F103"], "description": "Result rows include a non-empty `url` for every entity type", "implemented": true },
{ "id": "T122", "featureIds": ["F104", "F108"], "description": "SearchPalette renders at the top of the MSP sidebar", "implemented": true },
{ "id": "T123", "featureIds": ["F105"], "description": "Cmd+K (mac) and Ctrl+K (Windows/Linux) open the SearchPalette and focus the input", "implemented": true },
{ "id": "T124", "featureIds": ["F106"], "description": "Typeahead shows up to 5 rows; each row is a native `<a>` with non-empty `href`", "implemented": true },
{ "id": "T125", "featureIds": ["F106"], "description": "Cmd/Ctrl+click on a typeahead row opens the result in a new tab without closing the palette", "implemented": true },
{ "id": "T126", "featureIds": ["F107"], "description": "Last typeahead row reads `See all N results` (i18n) and links to `/msp/search?q={query}`", "implemented": true },
{ "id": "T127", "featureIds": ["F106"], "description": "Typeahead does NOT render before query length ≥ 2", "implemented": true },
{ "id": "T128", "featureIds": ["F109"], "description": "GET /msp/search?q=foo renders server-side with results in the initial HTML", "implemented": true },
{ "id": "T129", "featureIds": ["F110"], "description": "Typing in the results-page input updates the URL via router.replace, debounced 200ms", "implemented": true },
{ "id": "T130", "featureIds": ["F110"], "description": "Opening a deep-linked /msp/search?q=foo&type=ticket&cursor=...&sort=recent restores the same state", "implemented": true },
{ "id": "T131", "featureIds": ["F111"], "description": "Filter chips render with count badges that match `groups` from the action response", "implemented": true },
{ "id": "T132", "featureIds": ["F112"], "description": "type=All renders grouped sections with max 10 rows per group", "implemented": true },
{ "id": "T133", "featureIds": ["F113"], "description": "type=ticket renders a flat paginated list of tickets only", "implemented": true },
{ "id": "T134", "featureIds": ["F114"], "description": "Next/prev cursor pagination moves forward and back without duplicating rows", "implemented": true },
{ "id": "T135", "featureIds": ["F115"], "description": "Empty state echoes the query back and suggests removing the type filter", "implemented": true },
{ "id": "T136", "featureIds": ["F115"], "description": "Loading skeleton renders on first input change and disappears when results arrive", "implemented": true },
{ "id": "T137", "featureIds": ["F116"], "description": "Every results-page row is a native `<a href>`; Cmd/Ctrl+click opens in new tab", "implemented": true },
{ "id": "T138", "featureIds": ["F117"], "description": "sort=recent orders results by source_updated_at DESC, ignoring relevance score", "implemented": true },
{ "id": "T139", "featureIds": ["F118"], "description": "Sidebar input exposes ARIA combobox role, aria-expanded reflects open state, aria-activedescendant updates on arrow keys", "implemented": true },
{ "id": "T140", "featureIds": ["F119"], "description": "Down-arrow on the sidebar input moves focus into typeahead; up-arrow at top wraps back to input", "implemented": true },
{ "id": "T141", "featureIds": ["F119"], "description": "Esc closes typeahead and restores focus to the input", "implemented": true },
{ "id": "T142", "featureIds": ["F119"], "description": "Enter on input (no row focused) navigates to /msp/search?q=...", "implemented": true },
{ "id": "T143", "featureIds": ["F119"], "description": "Enter on a focused row navigates to that row's url", "implemented": true },
{ "id": "T144", "featureIds": ["F120"], "description": "Stable id `app-search-input` is present on the sidebar input", "implemented": true },
{ "id": "T145", "featureIds": ["F120"], "description": "Every result row has id matching `app-search-result-row-{type}-{id}` (kebab-case)", "implemented": true },
{ "id": "T146", "featureIds": ["F120"], "description": "Every filter chip on the results page has id matching `app-search-filter-chip-{type}`", "implemented": true },
{ "id": "T147", "featureIds": ["F121"], "description": "`server/public/locales/en/msp/core.json` includes all required `search.*` keys (placeholder, helper, group labels, empty state, error, see-all-results)", "implemented": true },
{ "id": "T148", "featureIds": ["F122"], "description": "Lang-pack validation script reports zero missing keys across all locales for the `search` namespace", "implemented": true },
{ "id": "T149", "featureIds": ["F123"], "description": "Sidebar and results page contain zero hardcoded English strings (verified by grep guard test)", "implemented": true },
{ "id": "T150", "featureIds": ["F121", "F122"], "description": "Pseudo locale (`xx`) renders accented characters for every search UI string (no untranslated leaks)", "implemented": true },
{ "id": "T151", "featureIds": ["F124"], "description": "Env reference doc lists `SEARCH_INDEX_LIVE` with default and effect described", "implemented": true },
{ "id": "T152", "featureIds": ["F125"], "description": "Deploy runbook walks through migrate → deploy → backfill → flip env → enable UI", "implemented": true },
{ "id": "T153", "featureIds": ["F126"], "description": "Each search action call increments `search.query.count` and records `search.query.latency_ms`", "implemented": true },
{ "id": "T154", "featureIds": ["F126"], "description": "Queries returning zero results increment `search.query.empty`", "implemented": true },
{ "id": "T155", "featureIds": ["F127"], "description": "Rate limit on typeahead action returns a 429-equivalent error after 30 calls/sec from one user", "implemented": true },
{ "id": "T156", "featureIds": ["F127"], "description": "Rate limit on full search returns a 429-equivalent error after 10 calls/sec from one user", "implemented": true },
{ "id": "T157", "featureIds": ["F128"], "description": "Navigating to `/msp/tickets/{id}#comment-{cid}` scrolls the comment into view and applies a `.search-highlight` class for ~2s", "implemented": true },
{ "id": "T158", "featureIds": ["F129"], "description": "`/msp/invoices/{id}#item-{iid}` and `#annotation-{aid}` scroll and highlight correctly", "implemented": true },
{ "id": "T159", "featureIds": ["F130"], "description": "`/msp/projects/{pid}/tasks/{tid}#comment-{cid}` scrolls and highlights correctly", "implemented": true },
{ "id": "T160", "featureIds": ["F100", "F022", "F025"], "description": "End-to-end: seed a tenant with clients + tickets; search 'acme' as the technician → ACME Corp is top result (Acceptance #1)", "implemented": true },
{ "id": "T161", "featureIds": ["F100", "F109"], "description": "End-to-end: pressing Enter on the sidebar input lands on `/msp/search?q={query}` (Acceptance #2)", "implemented": true },
{ "id": "T162", "featureIds": ["F116"], "description": "End-to-end: Cmd/Ctrl+click on a result opens in a new tab and original tab keeps its state (Acceptance #3)", "implemented": true },
{ "id": "T163", "featureIds": ["F087"], "description": "End-to-end: 'TIC-1023' and 'tic-10' both find the right ticket (Acceptance #4)", "implemented": true },
{ "id": "T164", "featureIds": ["F026", "F128"], "description": "End-to-end: searching a phrase that appears only in one ticket comment lands on the ticket page with the comment scrolled+highlighted (Acceptance #5)", "implemented": true },
{ "id": "T165", "featureIds": ["F026", "F109"], "description": "End-to-end: an internal user sees an internal-comment hit in results (Acceptance #6)", "implemented": true },
{ "id": "T166", "featureIds": ["F026", "F096"], "description": "End-to-end: a non-internal user DOES NOT see the same internal-comment hit (Acceptance #7)", "implemented": true },
{ "id": "T167", "featureIds": ["F027", "F093"], "description": "End-to-end: user A searches for project they don't have permission for; project does NOT appear (Acceptance #8)", "implemented": true },
{ "id": "T168", "featureIds": ["F037", "F096"], "description": "End-to-end: client-scoped user A searches for a document whose `documents.client_id = X` where A has no access to X; document does NOT appear (Acceptance #9)", "implemented": true },
{ "id": "T169", "featureIds": ["F086"], "description": "End-to-end: 'exhcange' returns 'Exchange' as a top result via pg_trgm (Acceptance #10)", "implemented": true },
{ "id": "T170", "featureIds": ["F063", "F065"], "description": "End-to-end: creating a ticket through the UI causes it to appear in search within 5 seconds (Acceptance #11)", "implemented": true },
{ "id": "T171", "featureIds": ["F066"], "description": "End-to-end: deleting a ticket causes it to disappear from search within 5 seconds (Acceptance #12)", "implemented": true },
{ "id": "T172", "featureIds": ["F073", "F074", "F075"], "description": "End-to-end: fresh DB + backfill across all 27 entity types — a sampled record from each type is findable in search (Acceptance #13)", "implemented": true },
{ "id": "T173", "featureIds": ["F079", "F082"], "description": "End-to-end: manually DELETE a single index row then run reconciliation → the row is restored (Acceptance #14)", "implemented": true },
{ "id": "T174", "featureIds": ["F100"], "description": "Load test: 1M random-tenant queries across a 50-tenant seed; zero cross-tenant leaks (Acceptance #15)", "implemented": true },
{ "id": "T175", "featureIds": ["F122"], "description": "Pseudo locale renders all search UI strings (Acceptance #16)", "implemented": true },
{ "id": "T176", "featureIds": ["F118", "F119"], "description": "Keyboard-only flow can: open palette, type, navigate, choose, open results page, paginate, filter, exit — without using mouse (Acceptance #17)", "implemented": true },
{ "id": "T177", "featureIds": ["F110"], "description": "Deep-linked URL `/msp/search?q=...&type=...&cursor=...&sort=...` reproduces the same results when opened cold (Acceptance #18)", "implemented": true },
{ "id": "T178", "featureIds": ["F003", "F004"], "description": "Cross-shard query: searching across a tenant with 10M index rows uses GIN index (EXPLAIN ANALYZE shows no seq scan)", "implemented": true },
{ "id": "T179", "featureIds": ["F019"], "description": "upsertSearchDoc co-locates writes by tenant under Citus (no inter-shard write fanout for a single doc)", "implemented": true },
{ "id": "T180", "featureIds": ["F100"], "description": "Search query SQL always includes `tenant = ?` predicate (verified by SQL log capture)", "implemented": true },
{ "id": "T181", "featureIds": ["F012", "F037"], "description": "Document indexer fixture: 10MB BlockNote JSON with embedded image data URI → indexed body ≤ 64KB and contains zero `data:image` substrings", "implemented": true },
{ "id": "T182", "featureIds": ["F014", "F040"], "description": "Service-request submission fixture with a 'password' key in submitted_payload → that value is NOT present in the indexed body", "implemented": true },
{ "id": "T183", "featureIds": ["F016"], "description": "`process_large_lexemes` is invoked in the SQL path that computes search_vector (verified via SQL log capture)", "implemented": true },
{ "id": "T184", "featureIds": ["F067", "F125"], "description": "Smoke test runs backfill against a seed tenant and then flips SEARCH_INDEX_LIVE=true and confirms incremental updates land", "implemented": true },
{ "id": "T185", "featureIds": ["F063", "F068"], "description": "Stress test: 100 ticket updates/sec for 60s causes < 30s indexing lag p99 (subscriber keeps up)", "implemented": true },
{ "id": "T186", "featureIds": ["F100", "F087"], "description": "Identifier query containing both an entity ID and a free-text term ranks the exact-id row #1 and free-text matches after it", "implemented": true },
{ "id": "T187", "featureIds": ["F100"], "description": "Search action result includes only entity types the user has permission to read (types union pre-filtered)", "implemented": true },
{ "id": "T188", "featureIds": ["F102"], "description": "Action rejects malformed cursor with a typed error (no 500)", "implemented": true },
{ "id": "T189", "featureIds": ["F068"], "description": "Renaming a ticket title triggers comment row re-index — comment row subtitle reflects new ticket title", "implemented": true },
{ "id": "T190", "featureIds": ["F072"], "description": "Removing a user from a document share-list triggers the document row's `visible_to_user_ids` to update within 10 minutes", "implemented": true },
{ "id": "T191", "featureIds": ["F104", "F118"], "description": "Axe-core accessibility scan on SearchPalette reports zero serious/critical violations", "implemented": true },
{ "id": "T192", "featureIds": ["F109", "F118"], "description": "Axe-core scan on /msp/search reports zero serious/critical violations", "implemented": true },
{ "id": "T193", "featureIds": ["F126"], "description": "search.query.latency_ms histogram has p95 < 500ms on a seeded medium tenant", "implemented": true },
{ "id": "T194", "featureIds": ["F099"], "description": "search.acl_drift counter is zero across the entire integration test suite (no SQL/record-level mismatch)", "implemented": true },
{ "id": "T195", "featureIds": ["F083"], "description": "Reconciliation job emits a per-run summary log: rows added, rows re-indexed, rows deleted per (tenant, type)", "implemented": true },
{ "id": "T196", "featureIds": ["F036"], "description": "Client-contract indexer joins `clients` and `contracts`; produces title `{client_name} {contract_name}` and sets `client_scope_id = client_id`", "implemented": true },
{ "id": "T197", "featureIds": ["F043"], "description": "Interaction indexer on a row with BlockNote JSON in `notes` produces a body containing the flattened text from text leaves (e.g., 'Added Sciton Tribrid Laser') and contains no JSON syntax characters", "implemented": true },
{ "id": "T198", "featureIds": ["F042"], "description": "Workflow-task indexer correctly upserts and reads rows when `workflow_tasks.task_id` is the only PK column; queries always include `tenant` in WHERE clause", "implemented": true },
{ "id": "T199", "featureIds": ["F042"], "description": "Workflow-task indexer parses `assigned_users` JSONB into a uuid[] and writes it into `visible_to_user_ids`", "implemented": true },
{ "id": "T200", "featureIds": ["F018", "F131"], "description": "CE build: `eeIndexers` resolves to `[]` and `allIndexers().length === ceIndexers.length` (== 27 at v1)", "implemented": true },
{ "id": "T201", "featureIds": ["F018"], "description": "Adding a synthetic indexer via direct `ceIndexers` array, `allIndexers()` includes it; `getIndexer('synthetic')` returns it", "implemented": true },
{ "id": "T202", "featureIds": ["F132"], "description": "Inserting a synthetic row with `object_type='ee_chat_history'` directly via SQL and querying as a CE build (no indexer registered for that type) → row is NOT returned (filtered by `registeredObjectTypes()`)", "implemented": true },
{ "id": "T203", "featureIds": ["F133"], "description": "Results page filter chips render exactly one chip per type in `registeredObjectTypes()` plus an `All` chip; no hard-coded chip list survives a registry change", "implemented": true },
{ "id": "T204", "featureIds": ["F133"], "description": "When a registered object_type has no i18n key for its label, the chip falls back to a humanized form of the object_type (e.g., `service_request_submission` → `Service request submission`)", "implemented": true },
{ "id": "T205", "featureIds": ["F134"], "description": "Reconciliation: inserting a synthetic `app_search_index` row with `object_type='ee_chat_history'` does NOT cause the CE reconciliation job to error or attempt to load a source row for that type; the row remains untouched", "implemented": true }
]