feat(project-create): v0.3.0 — путь создания репо = выбор оператора (шаг 2, Hard rule 2: не регистрировать до репо) [agensyn-урок 2026-08-29]
This commit is contained in:
@@ -1,13 +1,15 @@
|
|||||||
---
|
---
|
||||||
name: project-create
|
name: project-create
|
||||||
author: ours
|
author: ours
|
||||||
version: 0.2.0
|
version: 0.3.0
|
||||||
description: >
|
description: >
|
||||||
Mappa-side cycle of creating a new project: ask the operator for the hosting
|
Mappa-side cycle of creating a new project: ask the operator for the hosting
|
||||||
address (platform + user/org) FIRST — never derive it from neighbouring
|
address (platform + user/org) FIRST — never derive it from neighbouring
|
||||||
projects — then pre-flight checks (free in mappa AND in gitea), then create
|
projects — then pre-flight checks (free in mappa AND in gitea), then ASK the
|
||||||
mappa registration and the gitea repo SIMULTANEOUSLY (repo via .admin: task
|
operator HOW to create the repo (via .admin task+letter / server flow
|
||||||
+ covering letter, priority P0, no paired review for ops), then ask where on
|
projects_create_repo / manual) — the path is the operator's call, never
|
||||||
|
assumed — then create the repo and register in mappa (in the right order,
|
||||||
|
see Hard rule 2026-08-29), then ask where on
|
||||||
disk the project folder goes and what it's named, create the folder, write
|
disk the project folder goes and what it's named, create the folder, write
|
||||||
the `.mappa` marker (wiki:3340), and hand over to project-bootstrap (general
|
the `.mappa` marker (wiki:3340), and hand over to project-bootstrap (general
|
||||||
skill). Triggers (bilingual):
|
skill). Triggers (bilingual):
|
||||||
@@ -37,23 +39,33 @@ Before any `projects_register` / gitea repo creation for a **new** project.
|
|||||||
- Re-hosting / renaming an existing project → read what's there first, no creation.
|
- Re-hosting / renaming an existing project → read what's there first, no creation.
|
||||||
- A project that already exists in mappa registry or gitea → verify with the operator, don't create a duplicate.
|
- A project that already exists in mappa registry or gitea → verify with the operator, don't create a duplicate.
|
||||||
|
|
||||||
## Hard rule (the original lesson)
|
## Hard rules
|
||||||
|
|
||||||
|
### Hard rule 1 (original lesson)
|
||||||
|
|
||||||
**The hosting address (platform + user/org) is the operator's decision. ASK, never derive.** Do not copy the owner from a neighbouring project (the live failure: `victor/tg-digest` was assumed by analogy with `victor/yt-digest` — wrong, the operator had to correct it). Options to offer: platform (Gitea git.kzntsv.site / GitHub), and for Gitea — the known users/orgs from the registry (e.g. `victor` personal apps, `OpeItcLoc03` infra/meta, `cancel_music` music modules). The registry `mcp__mappa__projects_list` shows the existing `qualified` names — use it to propose options, but the choice is the operator's.
|
**The hosting address (platform + user/org) is the operator's decision. ASK, never derive.** Do not copy the owner from a neighbouring project (the live failure: `victor/tg-digest` was assumed by analogy with `victor/yt-digest` — wrong, the operator had to correct it). Options to offer: platform (Gitea git.kzntsv.site / GitHub), and for Gitea — the known users/orgs from the registry (e.g. `victor` personal apps, `OpeItcLoc03` infra/meta, `cancel_music` music modules). The registry `mcp__mappa__projects_list` shows the existing `qualified` names — use it to propose options, but the choice is the operator's.
|
||||||
|
|
||||||
|
### Hard rule 2 (2026-08-29, live failure agensyn)
|
||||||
|
|
||||||
|
**The repo-creation PATH is the operator's decision — ASK, never assume the default.** Offer: (a) via `.admin` (task + letter — the legacy canon, secrets live there), (b) server flow `mcp__mappa__projects_create_repo` (creates the repo on the provider AND registers in mappa itself, `source=auto`), (c) manual. The operator overrides the default; delegating to `.admin` before they choose is not revocable (the task lands on the board, `.admin` reacts instantly — the agensyn case).
|
||||||
|
|
||||||
|
**NEVER register the project in mappa (`projects_register`) BEFORE the repo exists.** A pre-existing registry entry makes the server flow `projects_create_repo` return 409 `already registered` (resolveStrict), and there is no delete channel for registry entries. Order that works: operator picks the path → repo is created → registration (the server flow registers itself; the `.admin` path registers AFTER the repo exists, with the known qualified).
|
||||||
|
|
||||||
## Steps (the pattern)
|
## Steps (the pattern)
|
||||||
|
|
||||||
1. **Ask the hosting address.** Platform (Gitea/GitHub) + user/org. One question, offer the registry-derived options, wait for the answer. Do NOT register anything yet.
|
1. **Ask the hosting address.** Platform (Gitea/GitHub) + user/org. One question, offer the registry-derived options, wait for the answer. Do NOT register anything yet.
|
||||||
2. **Pre-flight checks** — can we create in BOTH places:
|
2. **Ask the repo-creation path** (Hard rule 2): via `.admin` / server flow `projects_create_repo` / manual. Do NOT delegate or register yet — this is the operator's call.
|
||||||
- mappa: the project name is not in the registry (`projects_list` / `projects_resolve`).
|
3. **Pre-flight checks** — can we create:
|
||||||
- gitea: repo name is free, the user/org exists, we have rights (the .admin owns the tokens — it checks on its side).
|
- mappa: the project name is not in the registry (`projects_list` / `projects_resolve`) — and do NOT create it here.
|
||||||
3. **Create SIMULTANEOUSLY** (not one before the other):
|
- gitea: repo name is free, the user/org exists, we have rights (`.admin` path: `.admin` owns the tokens and checks on its side; server flow: the mappa server holds provider creds).
|
||||||
- `mcp__mappa__projects_register` — mappa registration (id returned).
|
4. **Create the repo + register, per the chosen path:**
|
||||||
- repo via `.admin` — `task_create` in `.admin` (**priority P0** — it blocks the project chain) + covering letter via `inbox_send` (a task on the board doesn't ping a live session). The repo task is an **ops task → NO paired review** (mappa-delegation: skip review for ops). Acceptance: repo created private, answer letter with clone URLs + which token is needed for push.
|
- **server flow** (`projects_create_repo`) — single call creates the repo AND registers (`source=auto`, `qualified` from the provider response). Nothing else to register.
|
||||||
4. **Ask the operator: where on disk the project folder goes and what it's named** (location AND folder name — both are the operator's call) — do not guess the path or the name.
|
- **via `.admin`** — `task_create` in `.admin` (**priority P0** — it blocks the project chain) + covering letter via `inbox_send` (a task on the board doesn't ping a live session). The repo task is an **ops task → NO paired review** (mappa-delegation: skip review for ops). Acceptance: repo created private, answer letter with clone URLs + which token is needed for push. AFTER the repo exists (qualified known) → `projects_register`.
|
||||||
5. **Create the folder** on the agent's local filesystem (the operator's workstation, not a remote host).
|
- **manual** — the operator creates the repo themselves; register after they confirm.
|
||||||
6. **Write the `.mappa` marker** — see Step 5.5 below. Right after the folder exists, the marker values are known from this cycle; no manual generator run.
|
5. **Ask the operator: where on disk the project folder goes and what it's named** (location AND folder name — both are the operator's call) — do not guess the path or the name.
|
||||||
7. **Hand over to bootstrap** — `project-bootstrap` (general skill) does git init, .gitignore, README, AGENTS.md, remote connect, push. Separate step, after the repo exists.
|
6. **Create the folder** on the agent's local filesystem (the operator's workstation, not a remote host).
|
||||||
|
7. **Write the `.mappa` marker** — see Step 5.5 below. Right after the folder exists, the marker values are known from this cycle; no manual generator run.
|
||||||
|
8. **Hand over to bootstrap** — `project-bootstrap` (general skill) does git init, .gitignore, README, AGENTS.md, remote connect, push. Separate step, after the repo exists.
|
||||||
|
|
||||||
## Step 5.5 — `.mappa` маркер (контракт wiki:3340)
|
## Step 5.5 — `.mappa` маркер (контракт wiki:3340)
|
||||||
|
|
||||||
@@ -61,11 +73,11 @@ Before any `projects_register` / gitea repo creation for a **new** project.
|
|||||||
«без маркера папка не участвует в mappa-операциях», task:1546). Значения уже
|
«без маркера папка не участвует в mappa-операциях», task:1546). Значения уже
|
||||||
известны из этого цикла — ручной прогон генератора не нужен (task:1583):
|
известны из этого цикла — ручной прогон генератора не нужен (task:1583):
|
||||||
|
|
||||||
- `project` — канон (имя папки, выбрано оператором в шаге 4);
|
- `project` — канон (имя папки, выбрано оператором в шаге 5);
|
||||||
- `tenant` — `MAPPA_TENANT` (по умолчанию `vitya`);
|
- `tenant` — `MAPPA_TENANT` (по умолчанию `vitya`);
|
||||||
- `url` — `MAPPA_CORE_URL` (без trailing slash);
|
- `url` — `MAPPA_CORE_URL` (без trailing slash);
|
||||||
- `git_provider` — платформа из шага 1 (gitea/github/…);
|
- `git_provider` — платформа из шага 1 (gitea/github/…);
|
||||||
- `git` — qualified (owner/repo) из ответа `.admin` (шаг 3, clone URL).
|
- `git` — qualified (owner/repo) из ответа `.admin` / `projects_create_repo` (шаг 4, clone URL).
|
||||||
|
|
||||||
Запись — детерминированный рендер по контракту. Канон-скрипт — ассет
|
Запись — детерминированный рендер по контракту. Канон-скрипт — ассет
|
||||||
`project-bootstrap` (в репо: `skills/project-bootstrap/assets/dot_mappa_marker.py`;
|
`project-bootstrap` (в репо: `skills/project-bootstrap/assets/dot_mappa_marker.py`;
|
||||||
@@ -79,24 +91,30 @@ python <skills-repo>/skills/project-bootstrap/assets/dot_mappa_marker.py write \
|
|||||||
|
|
||||||
Верифицировать: `python .../dot_mappa_marker.py check --dir "$FOLDER_PATH"`
|
Верифицировать: `python .../dot_mappa_marker.py check --dir "$FOLDER_PATH"`
|
||||||
→ exit 0. Маркер без секретов, коммитится. Если project-bootstrap не
|
→ exit 0. Маркер без секретов, коммитится. Если project-bootstrap не
|
||||||
установлен — маркер всё равно появится на хэндовере (шаг 7 → bootstrap 5.8).
|
установлен — маркер всё равно появится на хэндовере (шаг 8 → bootstrap 5.8).
|
||||||
|
|
||||||
## Why the repo goes through `.admin`
|
## Why the repo usually goes through `.admin` (and when it doesn't)
|
||||||
|
|
||||||
Gitea tokens are secrets — they live only with `.admin` (zone rule: secrets stay out of other agents). Precedent: yt-digest (inbox:2305) and tg-digest (inbox:2463) — `.admin` creates the repo via `POST /user/repos` → transfer to the target owner (the admin endpoint refuses without write:admin), then answers with the clone URLs and the push token (`pass show gitea/admin-token` for OpeItcLoc03, or a user token with repo:write for the target owner).
|
Gitea tokens are secrets — they live only with `.admin` (zone rule: secrets stay out of other agents). Precedent: yt-digest (inbox:2305) and tg-digest (inbox:2463) — `.admin` creates the repo via `POST /user/repos` → transfer to the target owner (the admin endpoint refuses without write:admin), then answers with the clone URLs and the push token (`pass show gitea/admin-token` for OpeItcLoc03, or a user token with repo:write for the target owner).
|
||||||
|
|
||||||
|
**The alternative:** `projects_create_repo` (task:1542) — the mappa server holds provider creds and creates the repo itself, registering the project in the same call. The operator chooses which path; do not hard-default to `.admin` (Hard rule 2, agensyn 2026-08-29).
|
||||||
|
|
||||||
## Failure modes
|
## Failure modes
|
||||||
|
|
||||||
- The operator hasn't chosen the address → abort, don't create. The address is the operator's call.
|
- The operator hasn't chosen the address → abort, don't create. The address is the operator's call.
|
||||||
|
- The operator hasn't chosen the repo-creation path → ask, don't default to `.admin` (Hard rule 2).
|
||||||
- mappa name taken → suggest a rename, don't overwrite.
|
- mappa name taken → suggest a rename, don't overwrite.
|
||||||
- gitea name taken / user missing → report, suggest a rename.
|
- gitea name taken / user missing → report, suggest a rename.
|
||||||
|
- `projects_create_repo` → 409 `already registered` → you registered before the repo (Hard rule 2) — there is no delete channel; report to the operator, don't work around it by hand.
|
||||||
- `.admin` repo task failed → report, don't register the project alone (mappa and gitea are created as a pair).
|
- `.admin` repo task failed → report, don't register the project alone (mappa and gitea are created as a pair).
|
||||||
- `task_create` in `.admin` → 422 secret-detected on the token scope string (`write:repository` is flagged) → rephrase ("токен с правами на запись в репозиторий"), don't include raw token strings.
|
- `task_create` in `.admin` → 422 secret-detected on the token scope string (`write:repository` is flagged) → rephrase ("токен с правами на запись в репозиторий"), don't include raw token strings.
|
||||||
- The operator answers the on-disk path only after the repo is created → that's the normal order, fine.
|
- The operator answers the on-disk path only after the repo is created → that's the normal order, fine.
|
||||||
|
|
||||||
## What NOT to do
|
## What NOT to do
|
||||||
|
|
||||||
- Don't assume the hosting owner from a neighbouring project — ask (the hard rule).
|
- Don't assume the hosting owner from a neighbouring project — ask (Hard rule 1).
|
||||||
|
- Don't assume the repo-creation path — ask (Hard rule 2); a `.admin` delegation already sent is not revocable.
|
||||||
|
- Don't register the project in mappa before the repo exists (breaks the server flow with 409; no delete channel).
|
||||||
- Don't create mappa registration alone without the repo (they're a pair).
|
- Don't create mappa registration alone without the repo (they're a pair).
|
||||||
- Don't create the repo alone without the mappa registration.
|
- Don't create the repo alone without the mappa registration.
|
||||||
- Don't create the on-disk folder in a guessed location — ask.
|
- Don't create the on-disk folder in a guessed location — ask.
|
||||||
|
|||||||
Reference in New Issue
Block a user