mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 04:07:04 +00:00
fix(projects): keep the model's Project name when a promotion carries a source
A promotion with `source` (clone or attach) registers the Project row in its off-loop half, before the worker-side named create. `create_project` returns an existing row untouched, so the display name given by the model was dropped and the Project was named by its id. For a non-Latin name that id is `proj_<digest>`, which then showed in the sidebar, the card footer and the System rows. The display name now reaches the first create. A title over the registry limit is withheld there instead of refusing a finished clone, which keeps today's outcome for that case.
This commit is contained in:
parent
ac1f236709
commit
db927715c2
4 changed files with 64 additions and 5 deletions
|
|
@ -15,7 +15,7 @@ def _source_project_id(source: str, is_git: bool) -> str:
|
|||
|
||||
|
||||
def resolve_promote_source(
|
||||
ctx: Any, source: str, project_id: str,
|
||||
ctx: Any, source: str, project_id: str, *, project_name: str = "",
|
||||
) -> Tuple[str, str, str, str, bool]:
|
||||
"""Attach/clone only after the supervisor has admitted an executor.
|
||||
|
||||
|
|
@ -27,7 +27,10 @@ def resolve_promote_source(
|
|||
the project row — the promote continuation carries it so the one
|
||||
workers-side ``project_started`` announce still fires for a creation that
|
||||
happened in this off-loop half (owner 2=A: it is the same agent-initiated
|
||||
promote flow).
|
||||
promote flow). ``project_name`` is the display name the model gave: this
|
||||
half registers the row FIRST, and a later named ``create_project`` returns
|
||||
the existing row untouched, so a name withheld here is lost for good and
|
||||
the Project shows its id (``proj_<digest>`` for a non-Latin name).
|
||||
"""
|
||||
from ouroboros.config import DATA_DIR
|
||||
from ouroboros.project_sources import clone_project_repo, valid_git_url, validate_attach_path
|
||||
|
|
@ -88,11 +91,14 @@ def resolve_promote_source(
|
|||
if prior_wd == folder and str((existing or {}).get("provenance") or "").strip() not in ("", "none"):
|
||||
return folder, note, "", pid, False
|
||||
try:
|
||||
from ouroboros.projects_registry import create_project, update_project
|
||||
from ouroboros.projects_registry import PROJECT_NAME_MAX, create_project, update_project
|
||||
from ouroboros.utils import utc_now_iso
|
||||
|
||||
name = str(project_name or "").strip()
|
||||
if len(name) > PROJECT_NAME_MAX:
|
||||
name = "" # never refuse a finished clone over a long title; the row keeps its id
|
||||
created = bool(create_project(
|
||||
drive_root, pid, origin="promote_chat_to_task",
|
||||
drive_root, pid, name=name, origin="promote_chat_to_task",
|
||||
).get("created"))
|
||||
update_project(
|
||||
drive_root,
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ def _prepare_promote_source_off_loop(evt: Dict[str, Any], ctx: Any) -> None:
|
|||
ctx,
|
||||
str(evt.get("source") or ""),
|
||||
str(evt.get("project_id") or ""),
|
||||
project_name=str(evt.get("project_name") or ""),
|
||||
)
|
||||
continuation["project_id"] = project_id
|
||||
continuation["_source_note"] = note
|
||||
|
|
|
|||
|
|
@ -914,7 +914,10 @@ def test_source_resolution_runs_off_supervisor_loop_and_continues_once(
|
|||
release = threading.Event()
|
||||
continuation_bus = thread_queue.Queue()
|
||||
|
||||
def slow_resolve(_ctx, _source, project_id):
|
||||
seen_names = []
|
||||
|
||||
def slow_resolve(_ctx, _source, project_id, *, project_name=""):
|
||||
seen_names.append(project_name)
|
||||
started.set()
|
||||
assert release.wait(2)
|
||||
return "", "source checked", "", project_id, False
|
||||
|
|
@ -946,6 +949,7 @@ def test_source_resolution_runs_off_supervisor_loop_and_continues_once(
|
|||
"routing_token": "source-token",
|
||||
"objective": "Inspect source",
|
||||
"source": "https://github.com/example/project.git",
|
||||
"project_name": "Исходники проекта",
|
||||
"chat_id": 1,
|
||||
}
|
||||
|
||||
|
|
@ -965,3 +969,6 @@ def test_source_resolution_runs_off_supervisor_loop_and_continues_once(
|
|||
assert load_task_result(tmp_path, "source-task")["promotion_admission"][
|
||||
"routing_token"
|
||||
] == "source-token"
|
||||
# The off-loop half registers the Project row first, so the model's display
|
||||
# name has to reach it: the later named create finds the row and changes nothing.
|
||||
assert seen_names == ["Исходники проекта"]
|
||||
|
|
|
|||
|
|
@ -463,3 +463,48 @@ def test_promote_source_registers_derived_project_and_mirrors_conflict(tmp_path,
|
|||
)
|
||||
ws4, _, err4, _, _ = resolve_promote_source(ctx, "https://example.com/myrepo.git", "myrepo")
|
||||
assert ws4 == "" and "conflict" in err4
|
||||
|
||||
|
||||
def test_promote_with_a_source_keeps_the_display_name_the_model_gave(tmp_path, monkeypatch):
|
||||
"""A sourced promotion registers the row in its off-loop half, BEFORE the named create.
|
||||
|
||||
``create_project`` returns an existing row untouched, so the name must reach the first
|
||||
call: withheld, a non-Latin name (whose id is ``proj_<digest>``) showed the id everywhere.
|
||||
"""
|
||||
from types import SimpleNamespace
|
||||
|
||||
import ouroboros.config as config
|
||||
from ouroboros.project_facts import project_id_from_display_name
|
||||
from ouroboros.projects_registry import PROJECT_NAME_MAX, create_project, get_project
|
||||
from ouroboros.promotion_source import resolve_promote_source
|
||||
|
||||
data = tmp_path / "data"
|
||||
data.mkdir()
|
||||
monkeypatch.setattr(config, "DATA_DIR", data)
|
||||
ctx = SimpleNamespace(repo_dir=str(tmp_path / "repo"))
|
||||
name = "Переключатели субагентов"
|
||||
pid = project_id_from_display_name(name)
|
||||
assert pid.startswith("proj_") # no Latin slug: the id is a digest, the NAME is what people read
|
||||
folder = tmp_path / "work"
|
||||
folder.mkdir()
|
||||
|
||||
_, _, err, got, created = resolve_promote_source(ctx, str(folder), pid, project_name=name)
|
||||
assert err == "" and got == pid and created is True
|
||||
assert get_project(data, pid)["name"] == name
|
||||
# The worker-side named create that follows finds the row and changes nothing.
|
||||
assert create_project(data, pid, name=name, origin="promote_chat_to_task")["created"] is False
|
||||
assert get_project(data, pid)["name"] == name
|
||||
|
||||
# No name given stays what it was: the row is named by its id.
|
||||
plain = tmp_path / "plain"
|
||||
plain.mkdir()
|
||||
_, _, err2, pid2, _ = resolve_promote_source(ctx, str(plain), "plain-project")
|
||||
assert err2 == "" and get_project(data, pid2)["name"] == "plain-project"
|
||||
|
||||
# A title over the registry limit never turns a finished clone/attach into a refusal.
|
||||
longer = tmp_path / "longer"
|
||||
longer.mkdir()
|
||||
_, _, err3, pid3, created3 = resolve_promote_source(
|
||||
ctx, str(longer), "long-title", project_name="x" * (PROJECT_NAME_MAX + 1))
|
||||
assert err3 == "" and created3 is True and get_project(data, pid3)["name"] == "long-title"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue