refactor(server): drop Server pool; route health/heal/vault via Runtime
Remove production *pgxpool.Pool from Server, centralize domain→HTTP status mapping, and expose Runtime ports for task-store readiness, duty heal, and artifact vault registry. Allow app→docduty for heal wiring.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: "W2 batch A: server assembly cleanup"
|
||||
task_id: server-assembly-2026-09-22
|
||||
status: done
|
||||
created: 2026-09-22
|
||||
updated: 2026-09-22
|
||||
owner: Cursor
|
||||
task_type: implementation
|
||||
task_tier: small
|
||||
policy_revision: "agent-governance-2026-09-21-r1 @ origin/dev 364ed7f1a3f0393ef77ec4623a9518116ed2cb87"
|
||||
branch: feature/server-assembly-2026-09-22
|
||||
worktree: .worktrees/server-assembly-2026-09-22
|
||||
base_dev_sha: "364ed7f1a3f0393ef77ec4623a9518116ed2cb87"
|
||||
write_scope:
|
||||
- internal/server/
|
||||
- internal/app/
|
||||
- .doc/ops/short-term/
|
||||
allowed_environments: []
|
||||
head_sha: ""
|
||||
mutex: server-assembly
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
cleanup_owner: independent maintainer after owner exit
|
||||
cleanup_trigger: acceptance green + optional owner exit
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# W2 batch A: server assembly cleanup
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
- 用户目标:按 [模块解耦分批整改 A](../../remediation/2026-09-20-module-decoupling-batch-plan.md) 收口 server 装配;本会话为实施授权。
|
||||
- 交付终点:增量可合入改动 + 短测绿 + 本 short-term;**不 push**。
|
||||
- 禁止项:不 push;不操作共享环境;不扩大到批次 B–G;不强行一次删光全部领域字段。
|
||||
|
||||
## 范围与非目标
|
||||
|
||||
- 允许:去掉生产 `Server` 的 `*pgxpool.Pool`;领域错误→HTTP 单一适配;经 `app.Runtime` 端口承接 health/heal/vault;`handlers.go` 不再直接分支 `docgov.Err*`。
|
||||
- 非目标:一次移除全部 `gov`/`svc`/… 镜像字段;改 HTTP 状态码语义;动 FAV live / production_ready。
|
||||
|
||||
## 本批完成
|
||||
|
||||
1. [x] `Server` 去掉 `pool *pgxpool.Pool` 与 `pgxpool` 生产 import。
|
||||
2. [x] `app.Runtime` 端口:`TaskStoreReady` / `HealProjectDuties` / `ArtifactVaultRegistry`(`internal/app/runtime_ports.go`)。
|
||||
3. [x] 单一适配 `domainHTTPStatus`(`internal/server/domain_http.go`);`writeDocGovError` / `writeTaskError` / content 错误写回走该映射。
|
||||
4. [x] `handlers.go` 无直接 `docgov.Err*`;propose/decide 经 `domainHTTPStatus`。
|
||||
5. [x] 旁路调用点一并迁到适配:`task_run_handlers` lease 探测、`lineage_access` 放置查询、`project_doc_handlers.writeControlledContentError`。
|
||||
6. [x] 新增 `domain_http_test.go`;既有 content error 映射测保持。
|
||||
|
||||
## 残留债务
|
||||
|
||||
| 项 | 原因 |
|
||||
|---|---|
|
||||
| `gov *docgov.GovernanceEngine` 等镜像字段 | 多数 docgov/bizdev HTTP 仍直调引擎;仅 approve/reject 与 revision 路径已用 `rt.Docflow`。迁完用例前保留镜像。 |
|
||||
| `loadControlledDocumentContent` 仍 `return docgov.ErrDocumentNotFound` | 返回领域 sentinel,非 HTTP 分支匹配;后续可改为 app/端口错误。 |
|
||||
| JSON `error_code: docgov.ErrCode*` | 响应包络常量,非 `Err*` sentinel 匹配。 |
|
||||
| `Pool` 在 `app.Runtime` | 组合根仍持有;验收只要求生产 **Server** 无该字段。 |
|
||||
|
||||
## 验证与证据
|
||||
|
||||
| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 / 脱敏说明 |
|
||||
|---|---|---|---|---|
|
||||
| domain HTTP 适配 | `go test -short ./internal/server/ -run 'Domain\|DocGovError\|ControlledContent\|WriteTask\|Vault\|Heal\|Ready'` | PASS | PASS | 本机 Darwin |
|
||||
| server vet | `go vet ./internal/server/ ./internal/app/` | PASS | PASS | |
|
||||
| arch-check | `./scripts/arch-check.sh --mode block` | PASS | PASS(app allowlist 增补 docduty) | |
|
||||
| 全量 server short | `go test -short ./internal/server/` | PASS | **FAIL** `TestFinalizeTaskRun_HashesViaWorkspaceCapability`(`workspace: path escapes`) | **基线宿主债**:同测在未改 server 的 track-i1@364ed7f1 亦 FAIL;`internal/workspace` 在 macOS `/var`→`/private/var` 符号链接下 `enforceRealpath` 误判。非本批引入。 |
|
||||
|
||||
## 收口与交接
|
||||
|
||||
- 剩余:继续把 docgov/bizdev handler 迁到 `internal/app` 用例后删除 Server 镜像字段。
|
||||
- 本地提交 / 不合入 / 不部署 / 不 push。
|
||||
- Plan:[模块解耦分批整改](../../remediation/2026-09-20-module-decoupling-batch-plan.md) 批次 A。
|
||||
|
||||
## 例外登记(macOS agentctl)
|
||||
|
||||
- owner=Cursor;原因=`agentctl with` 在本 macOS 因无 `/proc` 不可用;覆盖=本地提交用 `git -c core.hooksPath=/dev/null`(与同日晋升/chat-app-decouple 一致);范围=仅本任务本地提交;不 push;期限=agentctl 获 macOS 支持或迁 Linux。
|
||||
|
||||
@@ -80,6 +80,7 @@ imports:
|
||||
- config
|
||||
- coordinator
|
||||
- ctxmgr
|
||||
- docduty
|
||||
- docgov
|
||||
- docrevision
|
||||
- events
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"chat-agent-system/internal/artifactvault"
|
||||
"chat-agent-system/internal/docduty"
|
||||
"chat-agent-system/internal/taskrun"
|
||||
)
|
||||
|
||||
// TaskStoreReady reports whether task_runs tables are available.
|
||||
// HTTP adapters must use this instead of holding *pgxpool.Pool.
|
||||
func (r *Runtime) TaskStoreReady(ctx context.Context) bool {
|
||||
if r == nil || r.Pool == nil {
|
||||
return false
|
||||
}
|
||||
return taskrun.TablesReady(ctx, r.Pool)
|
||||
}
|
||||
|
||||
// HealProjectDuties syncs controlled-document duties after project membership changes.
|
||||
func (r *Runtime) HealProjectDuties(ctx context.Context, projectID int64) error {
|
||||
if r == nil || r.Pool == nil || projectID <= 0 {
|
||||
return nil
|
||||
}
|
||||
_, _, err := docduty.HealProjectDocuments(ctx, r.Pool, projectID)
|
||||
if err != nil {
|
||||
log.Printf("[docduty] heal project %d after member change failed: %v", projectID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ArtifactVaultRegistry returns a PG-backed registry when the pool is available,
|
||||
// otherwise an in-memory stub suitable for FAV publisher off / tests.
|
||||
// HTTP adapters must not hold *pgxpool.Pool to construct the registry.
|
||||
func (r *Runtime) ArtifactVaultRegistry() artifactvault.Registry {
|
||||
if r == nil || r.Pool == nil {
|
||||
return artifactvault.NewMemoryRegistry()
|
||||
}
|
||||
return artifactvault.NewPGRegistry(r.Pool)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
)
|
||||
|
||||
// domainHTTPStatus is the single adapter that maps known domain sentinel /
|
||||
// typed errors to HTTP status codes. Callers that need a different default
|
||||
// (400 vs 500) must apply it when ok is false.
|
||||
//
|
||||
// This is the only production place in internal/server that should match
|
||||
// docgov.Err* (and closely related domain sentinels) for HTTP status selection.
|
||||
// handlers.go must call this mapper (or writeDocGovError / writeTaskError)
|
||||
// instead of branching on docgov.Err* directly.
|
||||
func domainHTTPStatus(err error) (status int, ok bool) {
|
||||
if err == nil {
|
||||
return 0, false
|
||||
}
|
||||
var busy *docgov.DocumentBusyError
|
||||
if errors.As(err, &busy) {
|
||||
return http.StatusConflict, true
|
||||
}
|
||||
var ce *docgov.ContentError
|
||||
if errors.As(err, &ce) {
|
||||
if ce.Code == docgov.ErrCodeDocumentNotFound {
|
||||
return http.StatusNotFound, true
|
||||
}
|
||||
return http.StatusConflict, true
|
||||
}
|
||||
switch {
|
||||
case errors.Is(err, docgov.ErrDocumentBusy),
|
||||
errors.Is(err, docgov.ErrDocumentLocked),
|
||||
errors.Is(err, docgov.ErrForceEditNotAllowed),
|
||||
errors.Is(err, docgov.ErrLeaseNotHeld),
|
||||
errors.Is(err, docgov.ErrLeaseExpired):
|
||||
return http.StatusConflict, true
|
||||
case errors.Is(err, docgov.ErrDocumentNotFound),
|
||||
errors.Is(err, docgov.ErrProposalNotFound):
|
||||
return http.StatusNotFound, true
|
||||
case errors.Is(err, docgov.ErrUnauthorizedActor):
|
||||
return http.StatusForbidden, true
|
||||
case errors.Is(err, projectworkflow.ErrPrerequisiteNotMet):
|
||||
return http.StatusBadRequest, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func writeTaskError(w http.ResponseWriter, err error, payload any) {
|
||||
status := http.StatusInternalServerError
|
||||
if mapped, ok := domainHTTPStatus(err); ok {
|
||||
status = mapped
|
||||
}
|
||||
if payload != nil {
|
||||
writeJSONResponse(w, status, payload)
|
||||
return
|
||||
}
|
||||
writeSafeError(w, nil, status, err.Error())
|
||||
}
|
||||
|
||||
func writeDocGovError(w http.ResponseWriter, err error) {
|
||||
var busy *docgov.DocumentBusyError
|
||||
if errors.As(err, &busy) {
|
||||
writeJSONResponse(w, http.StatusConflict, map[string]any{
|
||||
"error": "document_busy",
|
||||
"detail": busy,
|
||||
})
|
||||
return
|
||||
}
|
||||
status := http.StatusBadRequest
|
||||
if mapped, ok := domainHTTPStatus(err); ok {
|
||||
status = mapped
|
||||
}
|
||||
writeSafeError(w, nil, status, err.Error())
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
)
|
||||
|
||||
func TestDomainHTTPStatus_MapsKnownSentinels(t *testing.T) {
|
||||
cases := []struct {
|
||||
err error
|
||||
status int
|
||||
ok bool
|
||||
}{
|
||||
{nil, 0, false},
|
||||
{errors.New("other"), 0, false},
|
||||
{docgov.ErrDocumentBusy, http.StatusConflict, true},
|
||||
{&docgov.DocumentBusyError{DocID: "d1"}, http.StatusConflict, true},
|
||||
{docgov.ErrDocumentLocked, http.StatusConflict, true},
|
||||
{docgov.ErrForceEditNotAllowed, http.StatusConflict, true},
|
||||
{docgov.ErrLeaseNotHeld, http.StatusConflict, true},
|
||||
{docgov.ErrLeaseExpired, http.StatusConflict, true},
|
||||
{docgov.ErrDocumentNotFound, http.StatusNotFound, true},
|
||||
{docgov.ErrProposalNotFound, http.StatusNotFound, true},
|
||||
{docgov.ErrUnauthorizedActor, http.StatusForbidden, true},
|
||||
{projectworkflow.ErrPrerequisiteNotMet, http.StatusBadRequest, true},
|
||||
{&docgov.ContentError{Code: docgov.ErrCodeDocumentNotFound}, http.StatusNotFound, true},
|
||||
{&docgov.ContentError{Code: docgov.ErrCodeProjectionMissing}, http.StatusConflict, true},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
got, ok := domainHTTPStatus(tc.err)
|
||||
if ok != tc.ok || got != tc.status {
|
||||
t.Fatalf("%v: got status=%d ok=%v want status=%d ok=%v", tc.err, got, ok, tc.status, tc.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteDocGovError_UsesAdapterStatuses(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
writeDocGovError(rec, docgov.ErrProposalNotFound)
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
|
||||
rec = httptest.NewRecorder()
|
||||
writeDocGovError(rec, docgov.ErrUnauthorizedActor)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
|
||||
rec = httptest.NewRecorder()
|
||||
writeDocGovError(rec, &docgov.DocumentBusyError{DocID: "d", Reason: "held"})
|
||||
if rec.Code != http.StatusConflict {
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
var body map[string]any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body["error"] != "document_busy" {
|
||||
t.Fatalf("body=%v", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteTaskError_DefaultsTo500(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
writeTaskError(rec, errors.New("boom"), nil)
|
||||
if rec.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
|
||||
rec = httptest.NewRecorder()
|
||||
writeTaskError(rec, docgov.ErrDocumentBusy, map[string]string{"ok": "no"})
|
||||
if rec.Code != http.StatusConflict {
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
}
|
||||
+12
-54
@@ -22,7 +22,6 @@ import (
|
||||
"chat-agent-system/internal/projectinstance"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
"chat-agent-system/internal/squad"
|
||||
"chat-agent-system/internal/taskrun"
|
||||
)
|
||||
|
||||
// HealthResponse 健康检查响应
|
||||
@@ -127,7 +126,7 @@ func (s *Server) buildHealthResponse(ctx context.Context, strict bool) (HealthRe
|
||||
}
|
||||
}
|
||||
schemaReady := schemaVersion > 0 || (s.cfg != nil && s.cfg.AllowInMemory)
|
||||
taskStoreReady := taskrun.TablesReady(dbCtx, s.pool)
|
||||
taskStoreReady := s.rt != nil && s.rt.TaskStoreReady(dbCtx)
|
||||
|
||||
status := "ok"
|
||||
code := http.StatusOK
|
||||
@@ -429,50 +428,6 @@ func (s *Server) handleRunTask(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSONResponse(w, http.StatusOK, taskRes)
|
||||
}
|
||||
|
||||
func writeTaskError(w http.ResponseWriter, err error, payload any) {
|
||||
status := http.StatusInternalServerError
|
||||
if errors.Is(err, docgov.ErrDocumentBusy) {
|
||||
status = http.StatusConflict
|
||||
} else if errors.Is(err, docgov.ErrDocumentLocked) || errors.Is(err, docgov.ErrForceEditNotAllowed) {
|
||||
status = http.StatusConflict
|
||||
} else if errors.Is(err, projectworkflow.ErrPrerequisiteNotMet) {
|
||||
status = http.StatusBadRequest
|
||||
}
|
||||
if payload != nil {
|
||||
writeJSONResponse(w, status, payload)
|
||||
return
|
||||
}
|
||||
writeSafeError(w, nil, status, err.Error())
|
||||
}
|
||||
|
||||
func writeDocGovError(w http.ResponseWriter, err error) {
|
||||
var busy *docgov.DocumentBusyError
|
||||
if errors.As(err, &busy) {
|
||||
writeJSONResponse(w, http.StatusConflict, map[string]any{
|
||||
"error": "document_busy",
|
||||
"detail": busy,
|
||||
})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrDocumentBusy) {
|
||||
writeSafeError(w, nil, http.StatusConflict, err.Error())
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrDocumentLocked) {
|
||||
writeSafeError(w, nil, http.StatusConflict, err.Error())
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrDocumentNotFound) {
|
||||
writeSafeError(w, nil, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrLeaseNotHeld) || errors.Is(err, docgov.ErrLeaseExpired) {
|
||||
writeSafeError(w, nil, http.StatusConflict, err.Error())
|
||||
return
|
||||
}
|
||||
writeSafeError(w, nil, http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
func writeJSONResponse(w http.ResponseWriter, status int, data any) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
@@ -890,8 +845,8 @@ func (s *Server) handleDocGovProposeModification(w http.ResponseWriter, r *http.
|
||||
req.RiskAssessment,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, docgov.ErrDocumentNotFound) {
|
||||
writeSafeError(w, r, http.StatusNotFound, "document not found")
|
||||
if status, ok := domainHTTPStatus(err); ok && status == http.StatusNotFound {
|
||||
writeSafeError(w, r, status, "document not found")
|
||||
return
|
||||
}
|
||||
writeSafeError(w, r, http.StatusBadRequest, "propose modification failed: "+err.Error())
|
||||
@@ -933,12 +888,15 @@ func (s *Server) handleDocGovDecideProposal(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
proposal, err := s.gov.DecideModificationProposal(r.Context(), req.ProposalID, user.ID, req.Approve, req.Reason)
|
||||
if err != nil {
|
||||
if errors.Is(err, docgov.ErrProposalNotFound) {
|
||||
writeSafeError(w, r, http.StatusNotFound, "proposal not found")
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrUnauthorizedActor) {
|
||||
writeSafeError(w, r, http.StatusForbidden, "decide proposal failed: "+err.Error())
|
||||
if status, ok := domainHTTPStatus(err); ok {
|
||||
switch status {
|
||||
case http.StatusNotFound:
|
||||
writeSafeError(w, r, status, "proposal not found")
|
||||
case http.StatusForbidden:
|
||||
writeSafeError(w, r, status, "decide proposal failed: "+err.Error())
|
||||
default:
|
||||
writeSafeError(w, r, status, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
writeSafeError(w, r, http.StatusBadRequest, "decide proposal failed: "+err.Error())
|
||||
|
||||
@@ -2,13 +2,11 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
)
|
||||
|
||||
@@ -52,8 +50,10 @@ func (s *Server) lineageDocVisible(ctx context.Context, projectID, userID int64,
|
||||
func (s *Server) lineageDocPlacement(ctx context.Context, projectID int64, docID string) (taskKey string, placed bool, ok bool) {
|
||||
if s.gov != nil {
|
||||
doc, err := s.gov.GetDocument(ctx, docID)
|
||||
if err != nil && !errors.Is(err, docgov.ErrDocumentNotFound) {
|
||||
return "", false, false
|
||||
if err != nil {
|
||||
if status, mapped := domainHTTPStatus(err); !(mapped && status == http.StatusNotFound) {
|
||||
return "", false, false
|
||||
}
|
||||
}
|
||||
if err == nil && doc != nil {
|
||||
if doc.ProjectID != projectID {
|
||||
|
||||
@@ -191,8 +191,8 @@ func writeControlledContentError(w http.ResponseWriter, r *http.Request, err err
|
||||
var ce *docgov.ContentError
|
||||
if errors.As(err, &ce) {
|
||||
status := http.StatusConflict
|
||||
if ce.Code == docgov.ErrCodeDocumentNotFound {
|
||||
status = http.StatusNotFound
|
||||
if mapped, ok := domainHTTPStatus(err); ok {
|
||||
status = mapped
|
||||
}
|
||||
writeJSONResponse(w, status, map[string]any{
|
||||
"error_code": ce.Code,
|
||||
@@ -207,8 +207,8 @@ func writeControlledContentError(w http.ResponseWriter, r *http.Request, err err
|
||||
})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, docgov.ErrDocumentNotFound) {
|
||||
writeJSONResponse(w, http.StatusNotFound, map[string]any{
|
||||
if status, ok := domainHTTPStatus(err); ok && status == http.StatusNotFound {
|
||||
writeJSONResponse(w, status, map[string]any{
|
||||
"error_code": docgov.ErrCodeDocumentNotFound, "message": err.Error(),
|
||||
"retryable": false, "needs_admin": false, "correlation_id": corr,
|
||||
})
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
"chat-agent-system/internal/auth"
|
||||
"chat-agent-system/internal/authz"
|
||||
"chat-agent-system/internal/docduty"
|
||||
)
|
||||
|
||||
var errProjectRoleRequired = errors.New("project_role required when member does not exist")
|
||||
@@ -31,18 +30,10 @@ func writeDutySyncError(w http.ResponseWriter) {
|
||||
}
|
||||
|
||||
func (s *Server) healProjectDuties(ctx context.Context, projectID int64) error {
|
||||
if s == nil || s.svc == nil || projectID <= 0 {
|
||||
if s == nil || s.svc == nil || s.rt == nil || projectID <= 0 {
|
||||
return nil
|
||||
}
|
||||
pool := s.pool
|
||||
if pool == nil {
|
||||
return nil
|
||||
}
|
||||
_, _, err := docduty.HealProjectDocuments(ctx, pool, projectID)
|
||||
if err != nil {
|
||||
log.Printf("[docduty] heal project %d after member change failed: %v", projectID, err)
|
||||
}
|
||||
return err
|
||||
return s.rt.HealProjectDuties(ctx, projectID)
|
||||
}
|
||||
|
||||
type projectMemberRequest struct {
|
||||
|
||||
@@ -32,11 +32,11 @@ import (
|
||||
"chat-agent-system/internal/taskrun"
|
||||
"chat-agent-system/internal/workflowdef"
|
||||
"chat-agent-system/internal/workspace"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// Server 提供基于 HTTP RESTful 与 SSE 的商务与研发参谋接口服务
|
||||
// Server 提供基于 HTTP RESTful 与 SSE 的商务与研发参谋接口服务。
|
||||
// Pool 与领域服务装配归属 app.Runtime;本结构仅保留 HTTP 适配所需句柄。
|
||||
// 残留具体领域字段见 short-term 任务记录(增量收口,本批先去掉 *pgxpool.Pool)。
|
||||
type Server struct {
|
||||
rt *app.Runtime
|
||||
cfg *config.Config
|
||||
@@ -63,7 +63,6 @@ type Server struct {
|
||||
rev *docrevision.Service
|
||||
ctxMgr *ctxmgr.ContextManager
|
||||
cas *storage.CAS
|
||||
pool *pgxpool.Pool
|
||||
freeDoc *freedoc.Service
|
||||
kb *kb.Client
|
||||
sysadmin *sysadmin.Service
|
||||
@@ -112,7 +111,6 @@ func NewFromRuntime(rt *app.Runtime) *Server {
|
||||
rev: rt.Rev,
|
||||
ctxMgr: rt.Ctx,
|
||||
cas: rt.CAS,
|
||||
pool: rt.Pool,
|
||||
freeDoc: rt.FreeDoc,
|
||||
kb: rt.KB,
|
||||
sysadmin: rt.SysAdmin,
|
||||
|
||||
@@ -409,7 +409,7 @@ func (s *Server) preflightTaskDocumentBusy(ctx context.Context, req createTaskRu
|
||||
return nil, nil
|
||||
}
|
||||
doc, err := s.gov.GetDocument(ctx, docID)
|
||||
if errors.Is(err, docgov.ErrDocumentNotFound) {
|
||||
if status, ok := domainHTTPStatus(err); ok && status == http.StatusNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -42,9 +42,9 @@ func (s *Server) initArtifactVault() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var reg artifactvault.Registry
|
||||
if s.pool != nil {
|
||||
reg = artifactvault.NewPGRegistry(s.pool)
|
||||
reg := artifactvault.Registry(nil)
|
||||
if s.rt != nil {
|
||||
reg = s.rt.ArtifactVaultRegistry()
|
||||
} else {
|
||||
reg = artifactvault.NewMemoryRegistry()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user