- capi: oakengine_node_output_connection_at/_at_ex returned the source
node as the connection destination; the actual destination is
conn.second.node(). Out-edge enumeration was useless, so the node
view could only draw in-edges and randomly lost whichever edges
needed the out-edge path (random per context build order).
Regression test in oakengine_node_test
- project teardown: Project::clear() pre-notifies node removal while
nodes are fully constructed (observers used to crash on
half-destroyed nodes); childEvent suppresses the removal dance while
clearing; Node::disconnect_all/disconnect_edge get a silent mode for
teardown so no invalidation/events touch dying members
(is_being_cleared); ClipBlock marker disconnect guarded against
dead viewer/markers; ProjectCopier and PreviewAutoCacher drop
project references on Project::destroyed instead of disconnecting
dead objects at shutdown
- preview: add oakengine_preview_request_get_audio_sample_count; the
viewer queried sample count by passing nullptr to get_audio_samples
which rejects it, so all playback audio was silently dropped
- app: fix unterminated input-id memcpy in ResolveGroupInput
(nodeparamviewitem, widgetbridge) that corrupted every parameter id
- app: unsubscribe raw C-API event subscriptions in destructors of
NodeParamViewKeyframeControl, NodeParamViewConnectedLabel and
ExportDialog; playhead events used to fire into dead widgets
(crash when dragging the playhead)
- tests: preview request roundtrip (video frame + audio range) and
free-while-active teardown coverage; env-gated OAK_DEBUG_EDGES /
OAK_DEBUG_INVALID_INPUT diagnostics
- docs: investigation notes in docs/zh/