ROADMAP.md

This commit is contained in:
2026-01-10 01:46:21 +00:00
parent ae11af4267
commit 62e8870a6c
11 changed files with 145 additions and 5 deletions

View File

@@ -1,5 +1,7 @@
# ROADMAP
See docs/PROMPT.md
## North Star
Treat JSON config as a declarative control plane that compiles into scene, resource, and render graphs with strict validation, budget enforcement, and crash-resistant policies.

View File

@@ -311,7 +311,8 @@ void ServiceBasedApp::RegisterServices() {
registry_.GetService<services::IInputService>(),
registry_.GetService<services::IPhysicsService>(),
registry_.GetService<services::ISceneService>(),
registry_.GetService<services::IRenderCoordinatorService>());
registry_.GetService<services::IRenderCoordinatorService>(),
registry_.GetService<services::IValidationTourService>());
// Script bridge services
registry_.RegisterService<services::IMeshService, services::impl::MeshService>(

View File

@@ -14,6 +14,7 @@ FrameWorkflowService::FrameWorkflowService(std::shared_ptr<ILogger> logger,
std::shared_ptr<IPhysicsService> physicsService,
std::shared_ptr<ISceneService> sceneService,
std::shared_ptr<IRenderCoordinatorService> renderService,
std::shared_ptr<IValidationTourService> validationTourService,
const std::filesystem::path& templatePath)
: registry_(std::make_shared<WorkflowStepRegistry>()),
executor_(registry_, logger),
@@ -30,7 +31,8 @@ FrameWorkflowService::FrameWorkflowService(std::shared_ptr<ILogger> logger,
std::move(inputService),
std::move(physicsService),
std::move(sceneService),
std::move(renderService));
std::move(renderService),
std::move(validationTourService));
registrar.RegisterUsedSteps(workflow_, registry_);
}

View File

@@ -7,6 +7,7 @@
#include "../interfaces/i_physics_service.hpp"
#include "../interfaces/i_render_coordinator_service.hpp"
#include "../interfaces/i_scene_service.hpp"
#include "../interfaces/i_validation_tour_service.hpp"
#include "workflow_executor.hpp"
#include "workflow_definition_parser.hpp"
@@ -25,6 +26,7 @@ public:
std::shared_ptr<IPhysicsService> physicsService,
std::shared_ptr<ISceneService> sceneService,
std::shared_ptr<IRenderCoordinatorService> renderService,
std::shared_ptr<IValidationTourService> validationTourService,
const std::filesystem::path& templatePath = {});
void ExecuteFrame(float deltaTime, float elapsedTime) override;

View File

@@ -8,6 +8,7 @@
#include "workflow_frame_render_step.hpp"
#include "workflow_frame_scene_step.hpp"
#include "workflow_step_registry.hpp"
#include "workflow_validation_checkpoint_step.hpp"
#include <stdexcept>
#include <unordered_set>
@@ -19,13 +20,15 @@ FrameWorkflowStepRegistrar::FrameWorkflowStepRegistrar(std::shared_ptr<ILogger>
std::shared_ptr<IInputService> inputService,
std::shared_ptr<IPhysicsService> physicsService,
std::shared_ptr<ISceneService> sceneService,
std::shared_ptr<IRenderCoordinatorService> renderService)
std::shared_ptr<IRenderCoordinatorService> renderService,
std::shared_ptr<IValidationTourService> validationTourService)
: logger_(std::move(logger)),
audioService_(std::move(audioService)),
inputService_(std::move(inputService)),
physicsService_(std::move(physicsService)),
sceneService_(std::move(sceneService)),
renderService_(std::move(renderService)) {}
renderService_(std::move(renderService)),
validationTourService_(std::move(validationTourService)) {}
void FrameWorkflowStepRegistrar::RegisterUsedSteps(
const WorkflowDefinition& workflow,
@@ -59,6 +62,10 @@ void FrameWorkflowStepRegistrar::RegisterUsedSteps(
if (plugins.contains("frame.gui")) {
registry->RegisterStep(std::make_shared<WorkflowFrameGuiStep>(inputService_, logger_));
}
if (plugins.contains("validation.tour.checkpoint")) {
registry->RegisterStep(std::make_shared<WorkflowValidationCheckpointStep>(
validationTourService_, logger_));
}
}
} // namespace sdl3cpp::services::impl

View File

@@ -12,6 +12,7 @@ class IInputService;
class IPhysicsService;
class IRenderCoordinatorService;
class ISceneService;
class IValidationTourService;
}
namespace sdl3cpp::services::impl {
@@ -23,7 +24,8 @@ public:
std::shared_ptr<IInputService> inputService,
std::shared_ptr<IPhysicsService> physicsService,
std::shared_ptr<ISceneService> sceneService,
std::shared_ptr<IRenderCoordinatorService> renderService);
std::shared_ptr<IRenderCoordinatorService> renderService,
std::shared_ptr<IValidationTourService> validationTourService);
void RegisterUsedSteps(const WorkflowDefinition& workflow,
const std::shared_ptr<IWorkflowStepRegistry>& registry) const;
@@ -35,6 +37,7 @@ private:
std::shared_ptr<IPhysicsService> physicsService_;
std::shared_ptr<ISceneService> sceneService_;
std::shared_ptr<IRenderCoordinatorService> renderService_;
std::shared_ptr<IValidationTourService> validationTourService_;
};
} // namespace sdl3cpp::services::impl

View File

@@ -29,6 +29,14 @@ ValidationTourService::ValidationTourService(std::shared_ptr<IConfigService> con
if (configService) {
config_ = configService->GetValidationTourConfig();
}
checkpointIndexById_.clear();
for (size_t i = 0; i < config_.checkpoints.size(); ++i) {
const auto& checkpoint = config_.checkpoints[i];
if (checkpoint.id.empty()) {
continue;
}
checkpointIndexById_.emplace(checkpoint.id, i);
}
if (config_.enabled && config_.checkpoints.empty()) {
if (logger_) {
@@ -66,6 +74,43 @@ ValidationTourService::ValidationTourService(std::shared_ptr<IConfigService> con
AdvanceCheckpoint();
}
bool ValidationTourService::RequestCheckpoint(const std::string& checkpointId) {
if (!config_.enabled) {
if (logger_) {
logger_->Trace("ValidationTourService", "RequestCheckpoint",
"checkpoint=" + checkpointId,
"Validation tour disabled");
}
return true;
}
if (checkpointId.empty()) {
if (logger_) {
logger_->Error("ValidationTourService::RequestCheckpoint: checkpoint id is empty");
}
return false;
}
auto it = checkpointIndexById_.find(checkpointId);
if (it == checkpointIndexById_.end()) {
if (logger_) {
logger_->Error("ValidationTourService::RequestCheckpoint: checkpoint not found id=" + checkpointId);
}
return false;
}
checkpointIndex_ = it->second;
pendingCapture_.reset();
failed_ = false;
completed_ = false;
active_ = true;
AdvanceCheckpoint();
if (logger_) {
logger_->Trace("ValidationTourService", "RequestCheckpoint",
"checkpoint=" + checkpointId +
", index=" + std::to_string(checkpointIndex_),
"Checkpoint requested");
}
return true;
}
ValidationFramePlan ValidationTourService::BeginFrame(float aspect) {
ValidationFramePlan plan{};
if (!IsActive()) {

View File

@@ -6,6 +6,7 @@
#include "../interfaces/i_validation_tour_service.hpp"
#include <filesystem>
#include <optional>
#include <unordered_map>
namespace sdl3cpp::services::impl {
@@ -15,6 +16,7 @@ public:
std::shared_ptr<IProbeService> probeService,
std::shared_ptr<ILogger> logger);
bool RequestCheckpoint(const std::string& checkpointId) override;
ValidationFramePlan BeginFrame(float aspect) override;
ValidationFrameResult EndFrame() override;
bool IsActive() const override { return active_ && !completed_ && !failed_; }
@@ -47,6 +49,7 @@ private:
std::shared_ptr<IProbeService> probeService_;
std::shared_ptr<ILogger> logger_;
ValidationTourConfig config_{};
std::unordered_map<std::string, size_t> checkpointIndexById_{};
std::filesystem::path resolvedOutputDir_{};
size_t checkpointIndex_ = 0;
uint32_t warmupRemaining_ = 0;

View File

@@ -0,0 +1,42 @@
#include "workflow_validation_checkpoint_step.hpp"
#include "workflow_step_io_resolver.hpp"
#include <stdexcept>
namespace sdl3cpp::services::impl {
WorkflowValidationCheckpointStep::WorkflowValidationCheckpointStep(
std::shared_ptr<IValidationTourService> validationService,
std::shared_ptr<ILogger> logger)
: validationService_(std::move(validationService)),
logger_(std::move(logger)) {}
std::string WorkflowValidationCheckpointStep::GetPluginId() const {
return "validation.tour.checkpoint";
}
void WorkflowValidationCheckpointStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) {
if (!validationService_) {
throw std::runtime_error("validation.tour.checkpoint requires an IValidationTourService");
}
WorkflowStepIoResolver resolver;
const std::string checkpointKey = resolver.GetRequiredInputKey(step, "checkpoint");
const auto* checkpointValue = context.TryGet<std::string>(checkpointKey);
const std::string checkpointId = checkpointValue ? *checkpointValue : checkpointKey;
const bool fromContext = checkpointValue != nullptr;
if (checkpointId.empty()) {
throw std::runtime_error("validation.tour.checkpoint missing checkpoint id");
}
if (!validationService_->RequestCheckpoint(checkpointId)) {
throw std::runtime_error("validation.tour.checkpoint checkpoint not found: " + checkpointId);
}
if (logger_) {
logger_->Trace("WorkflowValidationCheckpointStep", "Execute",
"checkpoint=" + checkpointId +
", source=" + std::string(fromContext ? "context" : "literal") +
", active=" + std::string(validationService_->IsActive() ? "true" : "false"),
"Checkpoint scheduled");
}
}
} // namespace sdl3cpp::services::impl

View File

@@ -0,0 +1,25 @@
#pragma once
#include "../interfaces/i_logger.hpp"
#include "../interfaces/i_validation_tour_service.hpp"
#include "../interfaces/i_workflow_step.hpp"
#include <memory>
#include <string>
namespace sdl3cpp::services::impl {
class WorkflowValidationCheckpointStep final : public IWorkflowStep {
public:
WorkflowValidationCheckpointStep(std::shared_ptr<IValidationTourService> validationService,
std::shared_ptr<ILogger> logger);
std::string GetPluginId() const override;
void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override;
private:
std::shared_ptr<IValidationTourService> validationService_;
std::shared_ptr<ILogger> logger_;
};
} // namespace sdl3cpp::services::impl

View File

@@ -26,6 +26,14 @@ class IValidationTourService {
public:
virtual ~IValidationTourService() = default;
/**
* @brief Request a specific checkpoint by id.
*
* @param checkpointId Checkpoint identifier from validation_tour config
* @return true if the checkpoint was accepted or validation is disabled
*/
virtual bool RequestCheckpoint(const std::string& checkpointId) = 0;
/**
* @brief Prepare validation state for the upcoming frame.
*