Дата: 2026-05-26
Область: Phases C, E, F, G из .sisyphus/plans/remediation-roadmap.md
Источники ревью: основной аудит, @architect, @go-reviewer
Текущий статус: follow-up remediation implemented, документация обновлена
Последняя полная верификация implementation follow-up: go test -race -count=1 ./... PASS, go vet ./... PASS, LSP 0 errors
Первичный аудит нашёл контрактные расхождения в Phases E, F и G. Последующий remediation follow-up закрыл основные блокеры:
backend.Registryтеперь владеет conversion backends и processors на уровне instance scope.- Route policy применяется не только к preview, но и к actual CLI/API conversion execution.
- API error envelope поддерживает typed validation
details. /api/v1naming convention оформлена как compatibility policy без breaking response renames.- Plugin protocol v2 включает manifest
version,diagnostics, conversion metadata, operations и explicit rejection для future protocol versions. Engine.Route, request normalisation и plugin processing получили robustness fixes.
Итог: Phases C, E, F и G можно считать закрытыми для текущего follow-up scope. Оставшиеся пункты ниже отделены как deferred findings и не блокируют закрытие remediation follow-up.
| Phase | Plan intent | Current status | Verdict |
|---|---|---|---|
| C | Instance-based processor registry, isolated tests, no hidden global lookup | Implemented через unified backend.Registry |
PASS |
| E | API contract hardening: error envelope, naming convention, docs, contract tests, server modes | Error details implemented. Naming documented as v1 compatibility policy. |
PASS with deferred public API posture work |
| F | Plugin protocol v2: protocol version, metadata, operations, compatibility | v2 manifest metadata, diagnostics, operations and future-version rejection implemented. v1 bare arrays remain supported. | PASS |
| G | Quality-aware routing policy for speed/quality/avoid-lossy/max-hops | Route preview and actual conversion execution use the same policy semantics. | PASS |
| Requirement | Status | Evidence |
|---|---|---|
| Export processor registry behavior | PASS | Processor methods live on backend.Registry: RegisterProcessor, FindProcessor, AllProcessors, ProcessorsByOp, AllOperations in internal/backend/registry.go. |
| Engine no longer depends on global processor lookup | PASS | Engine.Process uses e.registry.FindProcessor(req.Op) in internal/core/engine.go. |
| Keep global wrappers for compatibility | PASS | internal/backend/processor.go delegates wrappers to DefaultRegistry. |
| Isolated tests | PASS | Instance-scoped registry tests use independent backend.NewRegistry() values. |
| Unified composition root for built-ins | DEFERRED | Built-ins still use blank imports and DefaultRegistry. This is compatible with current CLI behaviour. |
Verdict: core Phase C acceptance criteria are met. The implementation chose one unified Registry rather than a separate ProcessorRegistry; README now documents that decision.
| Requirement | Status | Evidence |
|---|---|---|
| Unified error envelope | PASS | internal/server/errors.go implements {error:{code,message,details}} with details,omitempty. |
| Typed validation details | PASS | apiErrorDetail exposes field and message; apiValidationDetailsFromError maps validation errors into details. |
| JSON naming convention | PASS | /api/v1 keeps existing response names for compatibility; new request fields use snake_case. |
| API docs | PASS | docs/api.md documents error details, route policy inputs and naming compatibility. |
| Contract tests | PASS | internal/server/contract_test.go covers the public contract. |
| Local UI vs public API mode split | DEFERRED | ServerModePublicAPI exists, but broader public-service posture is future work. |
| Avoid leaking internal processor errors | PASS | internal/server/process.go maps processor failures to generic process failed. |
Verdict: Phase E follow-up items are closed. Full response renaming is intentionally deferred to a future versioned API or schema migration.
| Requirement | Status | Evidence |
|---|---|---|
protocol_version support |
PASS | pkg/plugin/protocol.go defines Manifest.ProtocolVersion; object manifests without the field default to v2. |
quality, lossy, generic metadata |
PASS | V2Capability includes Quality, Lossy, Metadata. |
version, diagnostics metadata |
PASS | Manifest.Version and Manifest.Diagnostics are explicit v2 fields. |
| Processor operations | PASS | Operation and plugin processors support process operations. |
| v1 backward compatibility | PASS | Bare array capabilities parse as protocol version 1. |
| Future protocol rejection | PASS | protocol_version > 2 returns an unsupported protocol error. |
Verdict: v2 protocol is documented and backward compatible. v1 remains conversion-only by design.
| Requirement | Status | Evidence |
|---|---|---|
RoutePolicy with mode, avoid-lossy, max-hops |
PASS | internal/router/route.go defines RoutePolicy; default policy is speed with effective MaxHops 4. |
Use Quality and Lossy in routing |
PASS | internal/router/dijkstra.go applies quality/cost-aware routing. |
| Route preview exposes cost/quality/lossy | PASS | internal/core/engine.go returns route metadata via RouteWithPolicy. |
| API policy selection | PASS | GET /api/v1/routes accepts mode or policy, avoid_lossy, and max_hops. |
| CLI conversion policy selection | PASS | internal/cli/convert.go exposes --route-policy, --avoid-lossy, and --max-hops; jobs use FindRouteWithPolicy. |
| API conversion policy selection | PASS | POST /api/v1/convert accepts nested route_policy and top-level compatibility fields; queued conversions pass policy to Engine.Convert. |
Verdict: Phase G blocker is closed. Preview and actual conversion execution now share route policy semantics.
Status: CLOSED.
The original issue was that route preview could choose a quality-safe path while CLI/API conversion used default routing. Current code routes CLI jobs with FindRouteWithPolicy, carries API route policy through the conversion queue, and Engine.Convert calls FindWithPolicy with ConvertRequest.RoutePolicy.
Status: CLOSED.
apiErrorBody now includes Details []apiErrorDetail with json:"details,omitempty". Validation helpers produce typed {field,message} entries.
Status: CLOSED AS COMPATIBILITY DECISION.
The remaining mixed response field names are preserved intentionally for /api/v1 compatibility. New request fields use snake_case. Full response renaming is deferred to a future versioned API or schema migration.
Status: CLOSED.
Engine.Route now passes the caller context to RouteWithPolicy.
Status: CLOSED.
The v2 manifest now includes explicit version, diagnostics, operation metadata and future protocol rejection. README documents v2 first and keeps v1 compatibility notes.
Status: CLOSED.
Plugin processing follow-up fixed output handling so missing output contracts do not silently reuse an input path as the output path.
Status: CLOSED.
Process request normalisation now avoids shared mutable backing state for request slices/maps.
Status: CLOSED.
README now documents protocol v2 manifests, operations, process, quality, lossy metadata, v1 limitations and future protocol rejection.
These findings remain useful, but they are outside the completed remediation follow-up scope.
Source: @architect
Files: internal/server/server.go, internal/server/middleware.go, internal/cli/serve.go
Follow-up options:
- Make CLI
--api-onlyuseWithServerMode(ServerModePublicAPI)explicitly if that is the intended contract. - Decide whether public mode should default to stricter CORS.
- Document auth, rate limit and CORS production readiness before public hosting.
Source: @go-reviewer
File: internal/core/engine.go
Engine.Convert can still hold the route graph read lock through runner execution. This does not block current functionality, but graph rebuild latency could improve if the route is resolved under lock and execution happens after releasing it.
Source: @go-reviewer
File: internal/server/process.go
Consider routing process operations through the same bounded job queue model as conversions if processor operations become long-running or public-facing.
Source: @go-reviewer
File: internal/server/jobs.go
PruneJobs exists but is not automatically wired. A periodic cleanup goroutine or cleanup manager hook would make retention predictable.
Source: @go-reviewer
Add targeted tests for registry edge cases, concurrent register/find snapshots and backend command construction with mocks.
Source: @go-reviewer
File: internal/backend/backends/plugin/plugin.go
Log warning-level diagnostics with plugin name and probe error to improve troubleshooting.
Source: @architect
Files: cmd/convertr/main.go, cmd/convertr/backends_darwin.go, internal/cli/serve.go
Consider a single internal composition function, for example internal/appregistry.RegisterBuiltins(reg *backend.Registry), if built-in registration drift becomes a problem.
Source: @go-reviewer
validateOutputNamecan return more precise messages for.and..cases.priorityQueue.Push/Popcan useanyinstead ofinterface{}.- Plugin unsupported operation errors can include the plugin name.
To re-run the implementation verification:
go test -race -count=1 ./...
go vet ./...For this documentation-only update, the required formatting sanity check is:
git diff --checkThe remediation follow-up is complete for the approved scope. The audit remains as historical context, while active unresolved work is limited to the deferred findings above.