Step 568: integrate phase 31a memory reflection workflow
This commit is contained in:
@@ -3991,4 +3991,13 @@ target_link_libraries(step567_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step568_test tests/step568_test.cpp)
|
||||
target_include_directories(step568_test PRIVATE src)
|
||||
target_link_libraries(step568_test PRIVATE
|
||||
nlohmann_json::nlohmann_json
|
||||
unofficial::tree-sitter::tree-sitter
|
||||
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)
|
||||
|
||||
156
editor/src/Phase31aIntegration.h
Normal file
156
editor/src/Phase31aIntegration.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#pragma once
|
||||
// Step 568: Phase 31a Integration
|
||||
|
||||
#include "AllocationOwnershipTraceHooks.h"
|
||||
#include "CallStackFrameInspector.h"
|
||||
#include "DebugSessionModel.h"
|
||||
#include "LeakCorruptionSignalBridge.h"
|
||||
#include "MemoryInspectorUiModel.h"
|
||||
#include "MemorySnapshotModel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct Phase31aInput {
|
||||
std::string sessionId = "session-31a";
|
||||
std::string snapshotId = "snapshot-31a";
|
||||
std::string threadId = "thread-main";
|
||||
std::string targetId = "target-main";
|
||||
std::string bufferId = "buffer-main";
|
||||
std::string executablePath = "/tmp/whetstone-app";
|
||||
|
||||
std::string stackRegionId = "stack-region";
|
||||
std::string heapRegionId = "heap-region";
|
||||
std::string pointerText = "0x2008";
|
||||
|
||||
std::string allocationId = "alloc-main";
|
||||
std::string signalAllocationId = "";
|
||||
std::string initialOwner = "runtime";
|
||||
std::string transferredOwner = "inspector";
|
||||
|
||||
std::string frameFunction = "run";
|
||||
std::string frameFile = "src/main.ws";
|
||||
int frameLine = 42;
|
||||
bool emitCorruptionSignal = false;
|
||||
bool omitSignalMessage = false;
|
||||
};
|
||||
|
||||
struct Phase31aResult {
|
||||
bool snapshotReady = false;
|
||||
bool inspectorReady = false;
|
||||
bool traceReady = false;
|
||||
bool signalBridgeReady = false;
|
||||
bool stackCorrelationReady = false;
|
||||
bool phase31aPass = false;
|
||||
MemorySignalSeverity maxSeverity = MemorySignalSeverity::Info;
|
||||
std::vector<std::string> notes;
|
||||
};
|
||||
|
||||
class Phase31aIntegration {
|
||||
public:
|
||||
static Phase31aResult run(const Phase31aInput& input) {
|
||||
Phase31aResult result;
|
||||
MemorySnapshot snapshot;
|
||||
std::string error;
|
||||
|
||||
DebugSessionModel debugSession;
|
||||
if (!debugSession.start(input.targetId, input.bufferId, input.executablePath)) {
|
||||
result.notes.push_back("fail:debug_session_start");
|
||||
return finalize(result);
|
||||
}
|
||||
|
||||
if (!MemorySnapshotModel::createSnapshot(input.snapshotId,
|
||||
input.sessionId,
|
||||
input.threadId,
|
||||
1,
|
||||
&snapshot,
|
||||
&error)) {
|
||||
result.notes.push_back("fail:snapshot_create");
|
||||
return finalize(result);
|
||||
}
|
||||
if (!MemorySnapshotModel::addRegion(&snapshot, {input.stackRegionId, MemoryRegionKind::Stack, 0x1000, 0x100, false}, &error) ||
|
||||
!MemorySnapshotModel::addRegion(&snapshot, {input.heapRegionId, MemoryRegionKind::Heap, 0x2000, 0x100, false}, &error) ||
|
||||
!MemorySnapshotModel::addReference(&snapshot, {0x1010, 0x2008, "stack_ptr"}, &error)) {
|
||||
result.notes.push_back("fail:snapshot_content");
|
||||
return finalize(result);
|
||||
}
|
||||
result.snapshotReady = true;
|
||||
|
||||
MemoryValueNode root;
|
||||
MemoryValueNode pointerNode;
|
||||
if (!MemoryInspectorUiModel::createComposite("root", "Memory", MemoryValueKind::Struct, &root, &error) ||
|
||||
!MemoryInspectorUiModel::createLeaf("ptr", "head", MemoryValueKind::Pointer, input.pointerText, &pointerNode, &error) ||
|
||||
!MemoryInspectorUiModel::appendChild(&root, pointerNode, &error)) {
|
||||
result.notes.push_back("fail:inspector_node_build");
|
||||
return finalize(result);
|
||||
}
|
||||
const auto rows = MemoryInspectorUiModel::collectVisibleRows(root, 8);
|
||||
const MemoryRegionRecord* pointerRegion = nullptr;
|
||||
if (rows.size() < 2 ||
|
||||
!MemoryInspectorUiModel::resolvePointerRegion(snapshot, pointerNode, &pointerRegion, &error) ||
|
||||
!pointerRegion) {
|
||||
result.notes.push_back("fail:inspector_pointer_resolve");
|
||||
return finalize(result);
|
||||
}
|
||||
result.inspectorReady = true;
|
||||
|
||||
AllocationOwnershipTraceHooks hooks;
|
||||
if (!hooks.recordAllocation(input.sessionId, input.allocationId, 0x2008, 64, input.initialOwner, 10, &error) ||
|
||||
!hooks.transferOwnership(input.sessionId, input.allocationId, input.transferredOwner, 20, &error)) {
|
||||
result.notes.push_back("fail:allocation_trace");
|
||||
return finalize(result);
|
||||
}
|
||||
result.traceReady = hooks.ownerFor(input.allocationId) == input.transferredOwner;
|
||||
if (!result.traceReady) {
|
||||
result.notes.push_back("fail:allocation_owner_mismatch");
|
||||
return finalize(result);
|
||||
}
|
||||
|
||||
LeakCorruptionSignalBridge bridge;
|
||||
const std::string signalAllocId = input.signalAllocationId.empty() ? input.allocationId : input.signalAllocationId;
|
||||
const std::string leakMessage = input.omitSignalMessage ? "" : "Potential leak near allocation";
|
||||
if (!bridge.ingestSignal({"sig-1", input.sessionId, signalAllocId, MemorySignalType::LeakSuspected,
|
||||
leakMessage, 30}, &error)) {
|
||||
result.notes.push_back("fail:signal_bridge_ingest");
|
||||
return finalize(result);
|
||||
}
|
||||
if (input.emitCorruptionSignal &&
|
||||
!bridge.ingestSignal({"sig-2", input.sessionId, signalAllocId, MemorySignalType::CorruptionConfirmed,
|
||||
"Corruption confirmed near allocation", 31}, &error)) {
|
||||
result.notes.push_back("fail:signal_bridge_corruption_ingest");
|
||||
return finalize(result);
|
||||
}
|
||||
result.signalBridgeReady = !bridge.diagnosticsForSession(input.sessionId).empty();
|
||||
result.maxSeverity = bridge.highestSeverityForSession(input.sessionId);
|
||||
|
||||
FrameScope frame;
|
||||
frame.frameIndex = 0;
|
||||
frame.functionName = input.frameFunction;
|
||||
frame.filePath = input.frameFile;
|
||||
frame.line = input.frameLine;
|
||||
frame.variables["ptr"] = input.pointerText;
|
||||
const auto frameResult = CallStackFrameInspector::inspect({frame}, 0);
|
||||
const auto vars = CallStackFrameInspector::variableNames(frame);
|
||||
const bool hasPointerVar = std::find(vars.begin(), vars.end(), "ptr") != vars.end();
|
||||
result.stackCorrelationReady = frameResult.ok && hasPointerVar && debugSession.hasTargetForBuffer(input.bufferId);
|
||||
if (!result.stackCorrelationReady) {
|
||||
result.notes.push_back("fail:stack_correlation");
|
||||
return finalize(result);
|
||||
}
|
||||
|
||||
result.notes.push_back("phase31a:memory_reflection_cycle_ready");
|
||||
return finalize(result);
|
||||
}
|
||||
|
||||
private:
|
||||
static Phase31aResult finalize(Phase31aResult result) {
|
||||
result.phase31aPass = result.snapshotReady &&
|
||||
result.inspectorReady &&
|
||||
result.traceReady &&
|
||||
result.signalBridgeReady &&
|
||||
result.stackCorrelationReady;
|
||||
if (!result.phase31aPass) result.notes.push_back("phase31a:blocked");
|
||||
return result;
|
||||
}
|
||||
};
|
||||
116
editor/tests/step568_test.cpp
Normal file
116
editor/tests/step568_test.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// Step 568: Phase 31a Integration (8 tests)
|
||||
|
||||
#include "Phase31aIntegration.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static int passed = 0, failed = 0;
|
||||
#define TEST(name) { std::cout << " " << #name << "... "; }
|
||||
#define PASS() { std::cout << "PASS\n"; ++passed; }
|
||||
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
|
||||
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
|
||||
|
||||
static bool hasNote(const Phase31aResult& result, const std::string& note) {
|
||||
for (const auto& n : result.notes) if (n == note) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void test_full_cycle_passes() {
|
||||
TEST(full_cycle_passes);
|
||||
Phase31aInput input;
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(result.phase31aPass, "phase should pass");
|
||||
CHECK(result.snapshotReady, "snapshot should be ready");
|
||||
CHECK(result.inspectorReady, "inspector should be ready");
|
||||
CHECK(result.traceReady, "trace should be ready");
|
||||
CHECK(result.signalBridgeReady, "signal bridge should be ready");
|
||||
CHECK(result.stackCorrelationReady, "stack correlation should be ready");
|
||||
CHECK(hasNote(result, "phase31a:memory_reflection_cycle_ready"), "success note missing");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_debug_session_start_failure_blocks_phase() {
|
||||
TEST(debug_session_start_failure_blocks_phase);
|
||||
Phase31aInput input;
|
||||
input.targetId.clear();
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:debug_session_start"), "expected debug start failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_snapshot_creation_failure_blocks_phase() {
|
||||
TEST(snapshot_creation_failure_blocks_phase);
|
||||
Phase31aInput input;
|
||||
input.snapshotId.clear();
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:snapshot_create"), "expected snapshot creation failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_invalid_pointer_text_blocks_inspector_resolution() {
|
||||
TEST(invalid_pointer_text_blocks_inspector_resolution);
|
||||
Phase31aInput input;
|
||||
input.pointerText = "invalid-pointer";
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:inspector_pointer_resolve"), "expected pointer resolve failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_invalid_transfer_owner_blocks_trace() {
|
||||
TEST(invalid_transfer_owner_blocks_trace);
|
||||
Phase31aInput input;
|
||||
input.transferredOwner.clear();
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:allocation_trace"), "expected allocation trace failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_signal_bridge_failure_blocks_phase() {
|
||||
TEST(signal_bridge_failure_blocks_phase);
|
||||
Phase31aInput input;
|
||||
input.omitSignalMessage = true;
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:signal_bridge_ingest"), "expected signal bridge failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_invalid_stack_frame_blocks_correlation() {
|
||||
TEST(invalid_stack_frame_blocks_correlation);
|
||||
Phase31aInput input;
|
||||
input.frameLine = 0;
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(!result.phase31aPass, "phase should fail");
|
||||
CHECK(hasNote(result, "fail:stack_correlation"), "expected stack correlation failure");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_corruption_signal_raises_max_severity() {
|
||||
TEST(corruption_signal_raises_max_severity);
|
||||
Phase31aInput input;
|
||||
input.emitCorruptionSignal = true;
|
||||
const auto result = Phase31aIntegration::run(input);
|
||||
CHECK(result.phase31aPass, "phase should pass");
|
||||
CHECK(result.maxSeverity == MemorySignalSeverity::Critical, "max severity should be critical");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 568: Phase 31a Integration\n";
|
||||
|
||||
test_full_cycle_passes(); // 1
|
||||
test_debug_session_start_failure_blocks_phase(); // 2
|
||||
test_snapshot_creation_failure_blocks_phase(); // 3
|
||||
test_invalid_pointer_text_blocks_inspector_resolution();// 4
|
||||
test_invalid_transfer_owner_blocks_trace(); // 5
|
||||
test_signal_bridge_failure_blocks_phase(); // 6
|
||||
test_invalid_stack_frame_blocks_correlation(); // 7
|
||||
test_corruption_signal_raises_max_severity(); // 8
|
||||
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
42
progress.md
42
progress.md
@@ -10294,3 +10294,45 @@ session-scoped diagnostics and pane routing for memory debug surfaces.
|
||||
- `editor/src/LeakCorruptionSignalBridge.h` within header-size limit (`154` <= `600`)
|
||||
- `editor/tests/step567_test.cpp` within test-file size guidance (`176` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
### Step 568: Phase 31a Integration
|
||||
**Status:** PASS (8/8 tests)
|
||||
|
||||
Integrates Steps 564-567 into one memory-reflection control flow that validates
|
||||
snapshot capture, UI inspection, allocation tracing, signal diagnostics, and
|
||||
stack/debug correlation gating.
|
||||
|
||||
**Files added:**
|
||||
- `editor/src/Phase31aIntegration.h` - Phase 31a integration module:
|
||||
- end-to-end memory reflection cycle orchestration
|
||||
- debug session + snapshot bootstrap and region/reference population
|
||||
- inspector node/row build and pointer-region resolution
|
||||
- allocation/ownership trace lifecycle validation
|
||||
- leak/corruption signal bridge ingestion and severity capture
|
||||
- stack frame correlation checks against active debug context
|
||||
- `editor/tests/step568_test.cpp` - 8 tests covering:
|
||||
- full happy-path cycle behavior
|
||||
- debug start/snapshot failure handling
|
||||
- pointer resolution failure handling
|
||||
- allocation transfer failure handling
|
||||
- signal bridge failure handling
|
||||
- stack correlation failure handling
|
||||
- corruption severity escalation behavior
|
||||
|
||||
**Files modified:**
|
||||
- `editor/CMakeLists.txt` - `step568_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `cmake -S editor -B editor/build-native` - PASS
|
||||
- `cmake --build editor/build-native --target step568_test step567_test` - PASS
|
||||
- `./editor/build-native/step568_test` - PASS (8/8)
|
||||
- `./editor/build-native/step567_test` - PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/Phase31aIntegration.h` within header-size limit (`156` <= `600`)
|
||||
- `editor/tests/step568_test.cpp` within test-file size guidance (`116` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
**Phase 31a totals (564-568):**
|
||||
- **Steps completed:** 5
|
||||
- **New tests in this phase plan:** 56/56 passing
|
||||
|
||||
Reference in New Issue
Block a user