Keeps develop's scheduling section and applies its cron rules (cron-capable
scheduler, valid Quartz expression, time zone ID) to validationCronExpression
through one shared check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds diagnostic tools so every QQQ app using the QBit can validate its
search and debug it from the admin UI. All are table or record actions
(processes with a tableName, never added to the app nav), gated by
permissions, rate-limited per user and tool, recorded as diagnostic events,
and read-only except Reindex in Search.
- Search Playground (Quick Search Index): runs a term as the current user
the way the global search does; per-table path and reason (OpenSearch
provider, core database search, not searched), the provider's request
timed, the global search results, the production query's scores,
highlights and matched clauses, readable / shown flags, query DSL and raw
response (unreadable hits redacted), term tokens, explain for a hit.
The form loops back so a user can search again.
- Validate Search Index (Quick Search Index; schedulable with
validationCronExpression): cluster and index health, alias, leftover
physical indexes, live mapping and analysis settings, per-table counts,
sampled missing / stale documents and orphaned documents, index row status
and failed events. Reports kept in the new quickSearchValidationRun table.
- Test Search Analyzer: _analyze with the index's analyzers, and whether a
term's tokens are among a text's indexed tokens.
- Inspect Search Document and Reindex in Search on every indexed table and
on quickSearchFailedEvent rows: database vs index diff, and why a record
does or does not match a term (token-level reasons, explain, rank).
- Search failure diagnostics: provider and QuickSearchAction failures are
recorded as SEARCH_FAILED events (never the term, only its length), with
runtime counters; the Search Diagnostics widget shows provider state,
recent failures from every server and the latest validation.
- New settings: enableDiagnosticTools, enableRecordDiagnosticActions,
validationCronExpression, validationCronTimeZoneId, validationSampleSize,
diagnosticRunsPerMinute, debugPermissionRules (quickSearchDebug).
- History purge covers the two new tables.
Tests: unit (metadata incl. QInstanceValidator, offline tool behaviour
against a closed port, the playground loop through RunProcessAction) and a
Testcontainers OpenSearch integration test for every tool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(#29): validate cron zone, warn when basepull is off, document schedulers
A reconcileCronExpression without reconcileCronTimeZoneId passed the
QBit's validation, then QQQ's QInstanceValidator rejected the reconcile
process schedule at startup ("a cron schedule must specify a
cronTimeZoneId"); QQQ has no default zone. validate() now applies the
same checks QQQ does (Quartz CronExpression.validateExpression, a zone
from TimeZone.getAvailableIDs) and requires the zone, naming both
fields. It also rejects a cron on a scheduler in the instance that does
not support cron: QQQ's SimpleScheduler runs fixed intervals only and
fails when the schedule manager starts.
Config-driven tables without their basepull timestamp field now log the
same startup warning as annotated tables, once per table, through one
shared helper. A field set to null is an opt-out and stays quiet.
README and MIGRATION-1.0 document that schedules run only when the host
starts through QApplicationLauncher (qqq-middleware-javalin), and that a
reconcile cron needs a Quartz scheduler and a time zone ID.
Closes#29
* docs(producer): keep develop's hidden-and-password Javadoc after the merge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* docs(#26): fix migration guide and README gaps
The migration guide now names the permissions a host must grant and has
a schema section for the 0.x to 1.0 table changes, including the new
quickSearchFailedEvent table and the status value lengths. The
plaintext credentials setter is spelled withAllowPlaintextCredentials,
and the README and PRD point at 1.0.0-RC.2 as the current release.
Closes#26
* docs(#26): name each table in the migration schema step
The schema step now says which table each STRING to TEXT change belongs
to and includes the required, unique quickSearchIndex.tableName, matching
the schema section.
Refs #26
* docs(readme): name 1.1.0-RC.1 as the current release candidate
Maven Central's newest is 1.1.0-RC.1 (develop is the 1.1 line). Keep the
1.0 line's 1.0.0-RC.2 for hosts that stay on 1.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Implements QQQ core's RecordSearchProviderInterface so the Next UI global
search (POST /qqq/v1/search) is served from the Quick Search index for the
tables this QBit indexes. The provider returns record ids only; core re-reads
them through QueryAction, so table permissions, record security locks and
labels stay core's job. One bounded _msearch per call, with a short backoff
after a failure during which core falls back to its own LIKE search.
Builds against the released QQQ 4.1.0-RC.2, the first release that carries
the SPI (replaces the 4.1.0-SNAPSHOT pin from PR #32).
Re-signed from PR #32 (originally 75dc2b3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Real-time INSERT events were indexed from the event's own records, which
carry raw values only, so a foreign key was indexed as its id and the
record label as "2 - email" until the next basepull. Inserts now take the
same path as updates: the listener re-reads the written records inside
the write's transaction with display values and possible-value labels.
A failed re-read is handled as for updates (#13): logged at once, then
recorded in quickSearchFailedEvent after commit for basepull replay,
never failing the host's insert, and nothing recorded on rollback.
Tests: listener unit tests for the PVS label and record label of a
just-inserted record, and for a failed insert re-read (commit and
rollback); an OpenSearch Testcontainers test that a just-inserted
record is searchable by its possible-value label and carries it in
fieldValues and the record label.
Closes#28
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: add 1.0 PRD, deep-dive audit, plan, and session state
* build: target qqq 4.1.0-RC.1, opensearch-java 3.10.0, wrapper 3.9.11, real JaCoCo gate
* feat: add 1.0 config surface, instance-scoped runtime, and deprecated static facade
* feat: implement the 4.1 QBit contract with a record-change listener and failed-event capture
* feat: opensearch client with auth modes, TLS, timeouts, mapping v2, aliases, versioned bulk writes
* feat: trustworthy indexing steps and permission-aware bounded search
* docs: rewrite README for 1.0, add CHANGELOG and migration guide
* feat: table picker and result screens for the maintenance processes; close out 1.0 planning docs
* docs: add AGENTS.md so Codex shares the CLAUDE.md guidance
* fix: keep the live index after an alias swap, atomic legacy upgrade, exact paging under record locks
From the PR #10 review: never delete the new physical index once the alias points at it, upgrade a legacy concrete index in one aliases request, base hasMore on raw hits so filtered pages stay reachable, and deduplicate requested table names.
* docs: explain the hasMore trade-off under record locks
* docs: session state for the RC.1 hand-off
- Add FullReindexStepTest with 7 tests
- Add BasepullIndexStepTest with 8 tests
- Add QuickSearchQBitProducerTest with 12 tests
- Update CLAUDE.md with project status
- Add docs/TODO.md and docs/SESSION-STATE.md