Commit Graph
20024 Commits
Author SHA1 Message Date
Magne Sjaastad 7de74f1092 #14717 Fix spdlog silently dropping debug-level log messages
spdlog::logger objects have their own internal severity filter
(defaulting to info) independent of RiaLogging's own level checks.
Without explicitly setting the spdlog logger's level to debug, .debug()
calls were silently discarded regardless of RiaLogging's configured
level, making debug-level logging invisible in the log file.
2026-09-10 08:22:29 -04:00
Magne Sjaastad 4b0e03d7fc #14717 Forward cvf logging to RiaLogging
cvf loggers default to LL_WARNING on a console destination and are never
wired to RiaLogging, so cvf's own diagnostics never reach the log file. A
rendering failure is therefore silent, with no artefact a user can send us.

Add RiaToCvfLoggingBridge (cvf::LogDestination) and RiaCvfLoggingManager,
mirroring RiaToCafLoggingBridge, to forward cvf log events into RiaLogging.
Wire initialize/shutdown into RiaApplication.

cee.cvf, cee.cvf.OpenGL and cee.cvf.qt follow the application log level:
LL_INFO normally, LL_DEBUG only when the application itself is set to debug,
so normal runs stay quiet.
2026-09-10 08:22:29 -04:00
Jørgen Herje c49f298a7d [ri-cloud-api]: Add grid data from sumo using api (#14653)
Add grid data from Sumo using ri-cloud-api

Load Eclipse grid data (roff) from Sumo as RimReservoirGridEnsemble, one case per realization, with async fetch of grid properties per timestep.

- New: RiaSumoGrid (transport), RifReaderSumoGridProperty (lazy property reader), RimReservoirGridEnsembleSumo, RimRoffCaseSumo, and a "Create Reservoir Grid Ensemble" command.
- Shared grid: IJK dimensions compared before download; one RigMainGrid is reused across the ensemble when they match, each realization still parses its own ACTNUM before releasing geometry.
- Rename folders: Summary/Sumo -> Summary/Cloud, RimSumoDataSource -> Cloud/ (PDM keywords unchanged, old project files still load).
- UI: cloud data sources also shown in the 3D window's Data Sources dock.
- Fix: realizations no longer lost on project reload; realizations missing data are now reported instead of silently skipped.
2026-09-10 10:33:58 +02:00
Kristian Bendiksen 71c5b5a97d #14612 Simulator Events: Remove Orion project naming 2026-09-09 13:01:26 +02:00
Magne Sjaastad 1fc5e424e4 #14539 Schedule tree updates and release user defined axis ranges for all plot types
Axis range and auto-zoom setters now schedule the editor update instead of
performing it immediately. Every immediate update rebuilds the tags of the whole
project tree, and zoom-all releases the range and re-enables auto zoom for every
axis of every subplot. Scheduling also avoids deleting the tag whose clicked
signal is still being emitted from onPinnedTagClicked().

Remove the m_isAutoZoom branches in fieldChangedByUi(). The field is not part of
any UI ordering, and both orderings end with skipRemainingFields(), so the
branches were unreachable. Comments referring to a "Set Range Automatically"
checkbox are updated accordingly.

The pinned tag no longer reuses pinned.svg, which is also the Quick Access dock
icon and must keep following the widget palette. The gray tag variant lives in
PinnedAxisRange.svg.

Zoom All is an explicit request for automatic ranges, but only summary plots
released the user defined range. Histogram, grid cross, VFP and analysis plots
share RimPlotAxisProperties and set the range as user defined when a min or max
is typed, so Zoom All left them with a stale pinned tag and permanently blocked
enableAutoValueMinMax().

Release the range for every axis owned by the window in RimViewWindow instead,
which makes the summary specific overrides redundant.
2026-09-09 12:08:10 +02:00
Magne Sjaastad 3284fd200a #14539 Add shared-axis, pinned-range indicators and Auto Zoom command for axis objects
Replace the chain/padlock icon with a simple two-headed-arrow icon
(SharedAxis.svg) for linked time/property axes.

Add a pinned-range project-tree tag shown when an axis range is
user-defined, using the standard gray pinned.svg icon. The tag
refreshes immediately regardless of the code path that changes the
range/auto-zoom state (Zoom All, data source changes, axis linking,
UI edits), and clicking the tag releases the user-defined range so
the axis auto-zooms again.

Add RicToggleAxisAutoZoomFeature, a checkable context-menu command
on Y-axis and time-axis objects that toggles auto-zoom and keeps the
pinned/user-defined-range tag in sync in both directions.

Move axis-specific context-menu entries out of RimContextCommandBuilder
into appendMenuItems() overrides on RimPlotAxisProperties and
RimSummaryTimeAxisProperties, per the project convention of keeping
object-specific menu logic in the object.

Fix RimSummaryPlot::timeAxisSettingsChanged() to actually re-apply
auto-scale to the plot widget when auto-zoom is re-enabled on the
time axis; previously only the property was updated, and no
recompute of the plotted range was triggered.
2026-09-09 12:08:10 +02:00
Magne Sjaastad 110bdbe0c7 #14539 Summary Plot: Preserve user defined axis ranges when the data source changes
An axis range defined by the user is now kept when a summary case or ensemble is added, reloaded or replaced. The range is marked as user defined when the user edits the min/max values, unchecks "Set Range Automatically" or zooms interactively in the plot.

The user defined range is released by "Zoom All", by double click in a plot, by checking "Set Range Automatically" or by changing the Y axis range aggregation of a summary multi plot.
2026-09-09 12:08:10 +02:00
Kristian Bendiksen f38332b2e6 #14648 Reduce the risk of changed behaviour for text values in lists
A quote or an opening bracket is only given special meaning when it is the first character of a value. Brackets and parentheses are treated as ordinary characters for text based values, as nested containers are not possible for these types. Text values are then parsed as before, also when they contain unbalanced brackets, parentheses or quotes.

Items in a tuple are not quoted by the Python client, as the tuple parser does not support quoted strings.

Add unit tests for text values containing separator characters, white space, file paths, numbers, nested containers and 3D vectors.
2026-09-09 11:19:44 +02:00
Kristian Bendiksen 5ed45b8f19 #14648 Python: Support strings containing commas in list arguments
Lists sent from Python over gRPC are serialized as text, and the list parser split on every comma, also commas inside a string. A category name like "Coal,Calcite" was therefore split in two, and set_discrete_property_category_names() failed with "CategoryValues and CategoryNames must have matching sizes".

The list parser is now quote-aware, and ignores commas inside quoted strings and inside nested brackets and parentheses. A quoted item is parsed as a quoted string also when the surrounding text is unquoted, as is the case for text coming from Python. The Python client quotes and escapes strings in lists and tuples when they contain separator characters.

Add unit tests for the field serialization and a Python test for the category names.
2026-09-09 11:19:44 +02:00
Magne Sjaastad b02d95bf95 #14698 Add regression tests for NaN/Inf/overflow guard in parameter correlations
Add RimSummaryEnsemble-Test.cpp with tests verifying that:
- a realization whose calculated summary vector value is NaN or Inf
  at the selected timestep is excluded from the Pearson correlation
  result instead of corrupting it
- extremely large but finite parameter/result magnitudes, which
  overflow the sum-of-squares in RigStatisticsTools::pearsonCorrelation()
  and RigEnsembleParameter::stdDeviation(), do not surface a NaN/Inf
  correlation value and are not silently dropped from the result

Add RigStatisticsTools.OverflowProducesNan reproducing the pearsonCorrelation()
overflow directly.

Verified each new test fails without its corresponding production fix
and passes with it.
2026-09-09 10:47:54 +02:00
Magne Sjaastad aee80deb30 #14698 Guard against NaN/Inf in ensemble parameter correlation
Realizations whose calculated summary vector value is NaN or Inf at
the selected timestep are now excluded from the Pearson correlation
computation instead of propagating NaN through the whole result,
which corrupted the correlation tornado plot. Also guard the final
correlation value against NaN, since the previous check only compared
against +Infinity.

RigEnsembleParameter::stdDeviation() sums squared parameter values,
which can overflow to +Inf for extreme (but finite) magnitudes,
turning normalizedStdDeviation() into NaN. Since NaN compares false
against the variation epsilon, such parameters were silently treated
as having no variation and dropped from parameterCorrelations(),
producing an empty tornado plot for that parameter and calculated
vector combination. Fall back to a range-based variation estimate
when the standard deviation calculation overflows, so the parameter
is retained and the Pearson correlation guard above can take over
instead.
2026-09-09 10:47:54 +02:00
Kristian Bendiksen d81e1e69f4 #14345 Route ensemble data filters to ensemble views
Use the ensemble data filter collection as the source for views owned by a reservoir grid ensemble. Apply the source for newly inserted views, case changes, and project-load initialization while preserving case-level sources for ordinary case views.

Add a regression test verifying that an ensemble view switches from its case collection to the ensemble collection.
2026-09-09 10:14:41 +02:00
Kristian Bendiksen d332a9bfdc #14345 Update ensemble data filter case after file-set refresh
Rebind the ensemble data filter collection after file-set cases are recreated. This ensures the collection uses the new main case and clears its source when no replacement cases are found.
2026-09-09 10:14:41 +02:00
Kristian Bendiksen 7ae3543e76 #14345 Refresh the owning object when data filters are added or removed
The data filter collection node is hidden in the project tree while the
collection is empty, and the owner must be refreshed to re-run its tree
ordering when the first filter appears. The refresh targeted the source
case, which for a grid ensemble collection is the main case of the
ensemble, not the ensemble owning the tree node. Newly created ensemble
data filters were therefore not visible in the tree.

Refresh the PDM parent object instead, which is the case or the grid
ensemble. Also refresh from the programmatic removeFilter path.
2026-09-09 10:14:41 +02:00
Kristian Bendiksen ab43e67f0f #14345 Add Data Filters to grid ensembles
Add a data filter collection to RimReservoirGridEnsemble, so filters can be defined once for the ensemble. The filters are bound to the main case of the ensemble for configuration.

Expose filter creation commands from a Data Filters submenu on the ensemble node, and hide the collection node while empty, matching the case-level behavior. Grid calculation integration is intentionally left for the dependent calculation-filtering change.
2026-09-09 10:14:41 +02:00
Kristian Bendiksen 2f2f0fd4e8 #14345 Add polygon filter creation to the Data Filters menu
RicNewPolygonFilterFeature already supports adding polygon filters to
the case-level data filter collection, but the collection menu did not
offer it. Add the polygon filter entries to the menu, matching the cell
filter collection menu in a view. The polygon filter computes its cells
lazily from the collection's source case, so no view is required.
2026-09-09 10:14:41 +02:00
Magne Sjaastad dd28b595ea Fix crash in RimSeismicSection::wellPathToSectionPoints when points is empty
Guard against calling points.back() on an empty vector when all well
path points are filtered out (e.g. due to the zmin check), which
previously caused undefined behavior/crash.
2026-09-08 15:10:58 +02:00
Magne Sjaastad 561bb35bd5 #14704 Guard against zero time-step count in findOrLoadKnownScalarResultForTimeStep
The bounds check on timeStepIndex was only applied when timeStepCount
was greater than zero. When a DYNAMIC_NATIVE result has zero known
time steps for a case, the check was skipped entirely and the
function still returned scalarResultIndex as valid, even though
m_cellScalarResults for it was never resized. Callers such as
RigSoilResultCalculator::calculate then indexed it out of bounds via
a CAF_ASSERT-only check (a no-op in Release builds), causing a
segfault.
2026-09-08 13:14:24 +02:00
Magne Sjaastad 6b4620715c #14699 Guard against null-pointer derefs during view/dock teardown 2026-09-08 11:18:33 +02:00
Magne Sjaastad 18e8b5545d #14699 Add unit tests for PdmUiTreeViewEditor 2026-09-08 11:18:33 +02:00
Magne Sjaastad de3996ee9e Fix four crashes found via automated stacktrace triage (#14702)
* Fail gracefully when exportSnapshots command has no main window
* Guard against unopened plot panels in selection change handler
* Guard ecl_rsthead_alloc against missing INTEHEAD_KW
* Guard against detached flow diag solution in solverInterface
* Never rewrite all crash-triage reports when updating registry
2026-09-08 11:16:38 +02:00
Kristian Bendiksen 15fe3a3656 #14680 Contour map: Restore property filter creation 2026-09-08 08:20:38 +02:00
Kristian Bendiksen 2462170647 #14683 Share OPM parser for keyword lookups 2026-09-07 18:58:05 +02:00
Kristian Bendiksen 275b120688 #14683 Python: Generalize gRPC resource limit error 2026-09-07 18:58:05 +02:00
Kristian Bendiksen 2e5a3a3d17 #14683 Python: Preserve positional heartbeat callback 2026-09-07 18:58:05 +02:00
Kristian Bendiksen 35614d160e #14683 Serve liveness requests on the gRPC server thread
Requests are queued by the completion queue thread and processed from the main
thread. A long running request, or an open progress dialog in the GUI, therefore
left every request unanswered for as long as that operation lasted, including
the liveness checks a client uses to decide whether ResInsight is still there.

Let a callback declare that it touches no application state, and serve those
directly on the completion queue thread instead of queueing them. GetVersion is
the only such callback, since it reads compile-time constants only. Everything
that touches the project or the data model is still processed on the main
thread, so no request can observe or modify the data model while another one is
running.

The allocated callback list is now used from both threads and is guarded by a
mutex. Shutdown takes a lock before flagging that it is in progress, so that it
waits for any dispatch already running on the completion queue thread and no new
request handler can be registered on a queue that is about to be shut down.

During a blocking call of 3.25 s, 65 pings were answered with a maximum latency
of 6.2 ms. Before this change none of them were answered until the call
completed.
2026-09-07 18:58:05 +02:00
Kristian Bendiksen 32f97bd862 #14683 Raise the gRPC message size limit for large payloads
A schedule generated from a full production history, or a large raw text block
imported into the event timeline, easily exceeds the gRPC default limit of 4 MB.
Such a call failed with "Received message larger than max (5119402 vs 4194304)"
even though both sides were healthy.

Raise the limit to 128 MB on the server and use a matching limit for the client
channels. A schedule of 19.5 MB is now returned without error.
2026-09-07 18:58:05 +02:00
Kristian Bendiksen 16ad832689 #14683 Python: Add context to connection and message size errors
A call that failed because the connection went away surfaced the raw gRPC text,
typically "Channel closed!", which says nothing about what happened. Translate
such failures through a single helper that explains that the connection to
ResInsight was lost while the call was running, and that names the message size
limit when that is the cause. The gRPC code and details are still carried on the
RipsError for callers that branch on them.
2026-09-07 18:58:05 +02:00
Kristian Bendiksen b0496f82d6 #14683 Python: Do not treat a busy ResInsight as a dead one
ResInsight serves gRPC requests from its main thread, so a long running call
leaves the heartbeat pings unanswered for as long as that call runs. The
heartbeat counted those timeouts as connection failures and closed the channel,
which aborted the very call the user was waiting for. The client reported
"RipsError: Channel closed!" while the ResInsight process was alive and well.

Classify a ping that fails with DEADLINE_EXCEEDED or RESOURCE_EXHAUSTED as a
busy server and never count it towards the failure threshold. Only failures
that indicate a broken connection declare the connection lost. A new
busy_warning_sec argument controls when a warning is logged for a server that
has been unresponsive for a while, so long operations are visible without being
killed.

Keep the process handle from Instance.launch so the heartbeat can check whether
ResInsight actually exited. A dead process is now detected immediately and
reported with its exit code instead of a bare channel error, and check_alive()
repeats that diagnosis.
2026-09-07 18:58:05 +02:00
Kristian Bendiksen 30254df9e9 #14683 Avoid building an Opm::Parser per keyword in schedule generation
Constructing an Opm::Parser populates the complete keyword database (2774
keywords, measured at 2.4 ms per construction) and this was done once per
keyword event in RifEventKeywordFormatter::buildKeyword, and twice more per
keyword in the column-aligned serialisation in RimKeywordFactory. Schedule
generation was therefore completely dominated by parser construction and grew
directly with the number of events on the timeline. Use a single shared parser
instance instead, since the parser is stateless once constructed.

Also compute the events for a date once in generateDateSection and pass them to
the per-well helpers, instead of calling RimWellEventTimeline::getEventsAtDate
four times per well and date, which scaled as dates x wells x events.

Generating a schedule for a production data set with 1737 events over 490 dates
goes from 4.2 s to 0.1 s, and 21000 events over 14 wells now complete in 0.5 s.
2026-09-07 18:58:05 +02:00
Jon Jenssen 51a4fa74bf Fix missing picker updates in ensemble reservoir views 2026-09-07 15:38:12 +02:00
Kristian Bendiksen 4e0abb456f Fix crash when deleting a sub plot of a multi plot in console mode
RimMultiPlot::recreatePlotWidgets() dereferenced the viewer unconditionally. The viewer does not exist in console mode, so deleting a summary plot from Python through the generic PdmObject delete() crashed ResInsight in onChildDeleted(). Return early when there is no viewer, matching the other viewer accesses in RimMultiPlot.

Add Python regression tests for deleting a single summary plot inside a multi plot and for deleting a whole multi plot, and an example showing how project tree objects are removed with delete().
2026-09-07 14:11:02 +02:00
Kristian Bendiksen e85137db6e #14345 Recompute calculated results when data for a time step has been released
The grid calculator releases result data per time step to reduce memory
usage when calculating for many cases. If only some time steps are
released, findOrLoadKnownScalarResult() returned early because data was
present for other time steps, leaving the released time steps empty.
Results computed by ResInsight, like riOILVOLUME, then appeared as
undefined in the 3d view after running a calculation for a selected
time step.

Recompute results computed by ResInsight when data is missing for any
time step. Skip the delegation from the single time step variant when
the requested time step already has data, to avoid repeated
recomputation while the calculator releases other time steps.
2026-09-07 11:18:09 +02:00
Kristian Bendiksen 4c143482bb #14345 Compute ResInsight-calculated results when loading a single time step
findOrLoadKnownScalarResultForTimeStep() tried to read ResInsight-
calculated results like riOILVOLUME from the restart file. For lazily
loaded grid case group members these results are never computed, so
every cell ended up undefined and the grid calculator produced zero
sums for all additional cases.

Delegate to findOrLoadKnownScalarResult(), which dispatches to the
result calculators, for results flagged as must-be-calculated and for
the ri* volume results. Already computed data is not computed again.
2026-09-07 11:18:09 +02:00
Magne Sjaastad c2f19344d4 #1044 Contour maps in 3d views: fix tree selection, empty name and add source navigation
Three related fixes found while reviewing the feature:
- Clicking the contour map surface inside a regular 3d view selected the internal RimContourMapProjection in the project tree instead of the RimContourMapInView object. Resolve the actual view from the pick event rather than climbing the projection's own ancestor chain, which pointed to a hidden internal contour map view, and select the owning RimContourMapInView when found.
- RimContourMapInView::name() returned only the raw custom name of the underlying contour map view. RimStatisticsContourMapView leaves its custom name empty and builds the displayed name entirely from generated tags, so the name shown for a statistics contour map in a 3d view was empty. Use the view's auto-generated name instead.
- RimContourMapInView is a presentation wrapper around a hidden RimEclipseContourMapView (or RimStatisticsContourMapView) that owns the actual contour map data. Add a Go to Contour Map button, following the existing pattern used by RimPolygonInView and RimDataFilterInView, so the underlying source object can be quickly selected in the project tree.
2026-09-07 09:32:04 +02:00
Magne Sjaastad c8023e8803 #1044 Contour maps in 3d views: wire the contour map collection into Eclipse and GeoMech 3d views
Give RimGridView a RimContourMapInViewCollection and let RimEclipseView and RimGeoMechView build their 3d model from it. A dedicated contour map view (RimEclipseContourMapView/RimStatisticsContourMapView) shows its own contour map and returns no collection of its own, so it is unaffected. Adjust RimSurfaceInViewCollection so surfaces and contour maps coexist in the same 3d view without z-fighting.
2026-09-07 09:32:04 +02:00
Magne Sjaastad d6c5774da9 #1044 Contour maps in 3d views: add RimContourMapInView and RimContourMapInViewCollection
Add the data model for showing contour maps inside a regular 3d view. RimContourMapInView is a presentation wrapper that decides where a contour map is placed vertically in the 3d scene and what parts of it are drawn; the contour map itself, including the result, the aggregation and the computed geometry, remains owned by the contour map view it points at. RimContourMapInViewCollection owns the set of contour maps available in a 3d view. Add a CONTOUR_MAP entry to RiaDefines::ItemIn3dView so the project tree can be refreshed for just the contour map items.
2026-09-07 09:32:04 +02:00
Magne Sjaastad b22fb02aa5 #1044 Contour maps in 3d views: extend part manager to drape map surface and lines on 3d geometry
Add RivContourMapElevationProvider and extend RivContourMapProjectionPartMgr so the contour map surface and contour lines can be projected onto the terrain/grid geometry of the 3d view instead of only being drawn as a flat map.
2026-09-07 09:32:04 +02:00
Magne Sjaastad 4587ad4c98 #1044 Contour maps in 3d views: add topography sampling for draped rendering
Add RigContourMapTopography, a raster of the terrain/grid elevation a contour map is draped onto when shown inside a regular 3d view.
2026-09-07 09:32:04 +02:00
Kristian Bendiksen f4a3361303 Python: Avoid crash when creating summary plot for ensemble without address
RicNewSummaryEnsembleCurveSetFeature::createPlotForCurveSetsAndUpdate() always
called RiaGuiApplication::instance(), which is null when running as a console
application. Calling new_summary_plot() with an ensemble and no address string
from Python did therefore terminate ResInsight. Only access the plot main
window when the GUI is running.
2026-09-04 15:32:09 +02:00
Kristian Bendiksen e2dc024854 Python: Create ensemble curve sets when creating summary plot for ensemble
new_summary_plot() with an ensemble and an address string created an empty
plot. The address filters were applied to an empty list of summary cases, and
no curve sets were created. Use the summary cases of the ensemble, and make
sure the summary addresses are created before the address filters are applied.

Add example script showing how to create summary plots for an ensemble.
2026-09-04 15:32:09 +02:00
Magne Sjaastad d575ae504b #14669 Fix O(N^2) scaling in RimEnsembleCurveFilter::applyFilter
* Add performance unit test for RimEnsembleCurveFilter::applyFilter
* Fix O(N^2) scaling in RimEnsembleCurveFilter::applyFilter

RimEnsembleCurveSet::objectiveFunctionTimeConfig() was called once per
summary case inside the applyFilter() loop, for both the OBJECTIVE_FUNCTION
and SUMMARY_VALUE filter modes. Internally it calls allAvailableTimeSteps(),
which scans the full time series of every case in the ensemble, so
recomputing it per case turned applyFilter() into an O(caseCount^2) operation.

* Avoid redundant allAvailableTimeSteps() calls in fullTimeStepRange()

fullTimeStepRange() called allAvailableTimeSteps() three times (once for the
empty check, once for min, once for max), each re-scanning the full time
series of every case in the ensemble. Compute it once and reuse the result.

Also simplify allAvailableTimeSteps() to insert time steps directly into the
result set instead of collecting them into an intermediate vector first.
2026-09-03 15:12:34 +02:00
Magne Sjaastad e8f02fd7b0 Increase Windows buildcache size limit to 1.5 GiB
A full Windows build writes ~550 MB of buildcache entries, so the shared 500 MB limit was exceeded before the build finished. buildcache then evicted entries the same build still needed, and the cache never converged: rebuilding an unchanged tree against a cache written by that very tree hit only 44%, leaving the Windows leg at ~70 minutes while Linux, whose objects are half the size, finished in 83 seconds.

Move the limit into the matrix so Windows gets 1.5 GiB and Linux keeps 500 MB.
2026-09-03 14:32:50 +02:00
Magne Sjaastad 6a7301e004 Only add PendingRelease label when issue is closed as completed 2026-09-03 11:51:16 +02:00
Magne Sjaastad 052c1eb550 Fix crash in RimWellIADataAccess::interpolatedResultValue for out-of-grid positions 2026-09-03 11:36:57 +02:00
Kristian Bendiksen 7867205468 #14639 Orion Events: Allow signed operand in date arithmetic
A term operand had to be an unsigned integer or a DURATION variable, so
"DATE STARTUP = 2026-08-28 + -2" was rejected as a malformed declaration
instead of subtracting two days.

Accept an optional sign on the operand in date and duration expressions, and
share one pattern between the terms of a date expression and the UNTIL terms
of INSERT_DATE so the two cannot drift apart.

Fractional day offsets are still unsupported.
2026-09-01 11:56:59 +02:00
Kristian Bendiksen 98e39bc02f #14636 Orion Events: List COMMENT as valid item name
COMMENT is accepted on all keywords and is stored on the event instead of
being passed as keyword data, so it is not part of the item names reported
by opm-common. The validation error listed only the opm-common items, giving
no hint that COMMENT is allowed when a user mistyped it as COMMENTS.

Append COMMENT to the list of valid item names in the error message. Only the
diagnostic is affected, COMMENT is still handled as event metadata.
2026-09-01 11:56:59 +02:00
Kristian Bendiksen 1336eba81d #14635 Orion Events: Use well name alias for generic keywords 2026-09-01 11:56:59 +02:00
Kristian Bendiksen c08323c65e #14630 Orion Events: Merge aligned keyword records 2026-09-01 11:56:59 +02:00
Kristian Bendiksen 96c2304606 #14630 Tests: Reproduce split aligned keyword records 2026-09-01 11:56:59 +02:00