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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
239 lines
35 KiB
JSON
239 lines
35 KiB
JSON
[
|
||
{ "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 `<script>`, 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 }
|
||
]
|