The index was created without number_of_replicas, so OpenSearch's default
of 1 left an unassignable replica on single-node clusters: the alias was
yellow and quick_search.opensearch reported DEGRADED.
- New config indexReplicas (default null = automatic:
min(maxAutoReplicas, data nodes - 1)) and maxAutoReplicas (default 1).
Zero config gives 0 replicas on one node and 1 on larger clusters.
- New physical indexes get the target; at startup existing indexes are
reconciled with PUT /<index>/_settings when the value differs
(idempotent, logged, failure tolerant, never blocks startup). Indexes
with auto_expand_replicas and OpenSearch Serverless are left alone.
- Status snapshot and quick_search.opensearch health details gain
unassignedReplicaShards, targetReplicas and replicaSettingsFailed.
Yellow on a single node with every primary active is UP with a note;
yellow with an inactive primary or on multiple nodes stays DEGRADED,
red stays DOWN.
- Unit tests (stub server), health/status tests and a Testcontainers
integration test; OpenAPI fragment regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
primeConfig created QSystemUserSession() before QContext.init, so
on a thread without a context (startup on [main]) the session had no
instance and no all-access keys, and kof22 logged "QInstance was not
supplied" once per pod. DiagnosticEventRecorder did the same.
Both now pass the instance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QRun-IO/.github#2 adds a tag-and-release job that signs vX with the
QRUN_TAG_SIGNING_KEY secret after Maven Central confirms the artifact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v1.1.0-RC.11 tag points at 6028a66, but the RC.11 artifact on Maven
Central was built from 2e2501d (#61 only). Cluster caches (#62) first ship
in 1.1.0-RC.12.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register the runtime config cache (config store snapshot and settings,
per-table enabled flags) with QQQ ClusterCaches as
qbit-quick-search.config. invalidateConfig() now clears locally and
publishes a cluster invalidation, so a config edit on one node reaches
every node at once; the existing TTLs stay as the safety net. The
warn-once table set in QuickSearchFieldRules is registered node-local.
Builds against QQQ 4.1.0-SNAPSHOT (qqq.snapshot.version) until the QQQ
RC with ClusterCaches is published; a release must pin that RC.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regenerated against UI API 1.6.0: every operation has an operationId and
the standard error responses (BasicErrorResponseV1: error, code, message,
fieldErrors, traceId); the extension's own error schema is kept but
deprecated; hand-written error bodies go through QJavalinUtils so they carry
code/message/traceId. Extension MINOR bumped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Basepull, full reindex and real-time indexing update runtime state on the
quick_search_index row (status, lastBasepullTime, documentCount, last run,
realTimeErrorCount), and every startup re-records the priming outcome on the
settings row. Each of those writes produced a FIELD audit ("Record was Edited
during process: Update search index"), about 2,800 audit rows in 6 hours on
kof22 production. These writes now set omitDmlAudit; admin edits to the
index, field and settings tables keep their audits. Tests prove both sides.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On release branches the bundle's version and the producer's differed, so the
bundle test that asserts they match failed, and released bundles recorded
SNAPSHOT as their provenance. help/*.yaml is now filtered:
version: ${project.version}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Host-neutral help (deployment-specific facts removed), registered with
HelpBundles, gated by HelpBundleAssertions. QQQ 4.1.0-RC.7.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds help/quick-search.yaml (QQQ help bundle) applied by QuickSearchHelp, a
tables guardrail test, and a seeded-defaults test proving the primer fills
the config tables on a fresh backend.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /qqq/v1/qbit/quick-search/suggest: prefix matches grouped per table with label and subtitle, reusing the permission-, lock- and PHI-aware QuickSearchAction.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Resolve the record-search provider (keep score/highlight/total hits and the failure diagnostics), CHANGELOG and README; requires QQQ 4.1.0-RC.4+ (develop is on RC.6).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Secured-data spec section 15: Quick Search must never put classified
values in the shared search index, snippets or results.
QuickSearchFieldRules decides it in one place on QQQ 4.1.0-RC.6:
isProtected is true for fields classified PII or PHI (field, else the
table's classification), fields with a field security lock, sensitive
fields and masked/password types. Such fields are never indexable;
explicit configs drop them with a warning (never the value); a table
whose primary key is protected (for example a PHI table) is not indexed
at all. Record labels built from protected fields fall back, the
version field is skipped when protected, and results from tables with
protected fields are rebuilt from allowed values only, so documents
indexed before this change cannot leak through labels or snippets.
Tables with only harmless non-indexable fields (booleans, blobs) keep
their labels and are not result-filtered.
A canary test proves a PHI and a PII marker never reach a captured
index request, result or snippet. RC.7 follow-up: also honour core
ClassifiedValues.isClassified (qqq#1182) and FieldAccessHelper lock
tiers (qqq#1172).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
realTimeErrorCount was only ever written as 0, so the status screen,
diagnostics and the status API always said there were no real-time
errors. When the change listener records failed events it now adds
their number to the table's count (after commit, serialized in the JVM,
never failing the user's write). A successful basepull or full reindex
resets it; the field's help text says so.
Fixes#53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves qqq-orb@0.6.8 to qqq-orb@0.6.9, which passes --update-snapshots so cached SNAPSHOT dependencies are re-checked on every build (QRun-IO/qqq-orb#22).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enforce the qbit-bom#10 guardrails (G1, G3, G4, G7) and run tests in
strict raw-route mode (G2). All pass on the released QQQ 4.1.0-RC.6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hosts no longer need QuickSearchOpenSearchClient or a copy of this qbit's
diagnostics. The new public api package holds:
- QuickSearchStatus, an immutable snapshot: overall state, cluster
reachability, per-table index counts, backlog, last sync, last error
and checkedAt;
- QuickSearchStatusService.get(), bounded and cached for five seconds,
built on the existing diagnostics;
- QuickSearchApi, with the app name and home href, so hosts link to the
Quick Search home instead of duplicating it.
The same data is served as UI API extension operation
GET /qqq/v1/qbit/quick-search/status (getQuickSearchStatus), gated by the
admin permission. The fragment is committed and checked by a contract
test. The core baseline becomes 4.1.0-RC.6.
Closes#50 (architecture review QRun-IO/qqq#1150, finding F10).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>