fix: refuse to scaffold prj- repos from statehub register
STATE-WP-0080-T01: detect project flavor from classification, GOAL.md, or a prj- slug, then exit pointing at rmgr scaffold. Durable-repo write path is unchanged. Rebind 0080 hub IDs to the live workstream and open T02 now that RMGR-WP-0004-T03 has landed.
This commit is contained in:
parent
131b824dd3
commit
f564e99a14
4 changed files with 216 additions and 12 deletions
|
|
@ -49,6 +49,7 @@
|
||||||
| workplan | STATE-WP-0077 | finished | — | workplans/STATE-WP-0077-dox-assessment-recording-and-soft-visibility.md |
|
| workplan | STATE-WP-0077 | finished | — | workplans/STATE-WP-0077-dox-assessment-recording-and-soft-visibility.md |
|
||||||
| workplan | STATE-WP-0078 | finished | — | workplans/STATE-WP-0078-ops-run-read-projection.md |
|
| workplan | STATE-WP-0078 | finished | — | workplans/STATE-WP-0078-ops-run-read-projection.md |
|
||||||
| workplan | STATE-WP-0079 | proposed | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
| workplan | STATE-WP-0079 | proposed | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
||||||
|
| workplan | STATE-WP-0080 | active | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
| task | ADHOC-2026-06-04-T01 | done | — | workplans/ADHOC-2026-06-04.md |
|
| task | ADHOC-2026-06-04-T01 | done | — | workplans/ADHOC-2026-06-04.md |
|
||||||
| task | ADHOC-2026-07-01-T01 | done | — | workplans/ADHOC-2026-07-01.md |
|
| task | ADHOC-2026-07-01-T01 | done | — | workplans/ADHOC-2026-07-01.md |
|
||||||
| task | ADHOC-2026-07-01-T02 | done | — | workplans/ADHOC-2026-07-01.md |
|
| task | ADHOC-2026-07-01-T02 | done | — | workplans/ADHOC-2026-07-01.md |
|
||||||
|
|
@ -279,3 +280,11 @@
|
||||||
| task | STATE-WP-0079-T04 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
| task | STATE-WP-0079-T04 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
||||||
| task | STATE-WP-0079-T05 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
| task | STATE-WP-0079-T05 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
||||||
| task | STATE-WP-0079-T06 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
| task | STATE-WP-0079-T06 | todo | — | workplans/STATE-WP-0079-retirement-strangler.md |
|
||||||
|
| task | STATE-WP-0080-T01 | done | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T02 | todo | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T03 | wait | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T04 | wait | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T05 | cancel | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T06 | cancel | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T07 | cancel | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
| task | STATE-WP-0080-T08 | cancel | — | workplans/STATE-WP-0080-register-project-flavor-awareness.md |
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,18 @@ from datetime import date
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
STATE_HUB_DIR = Path(__file__).resolve().parent
|
STATE_HUB_DIR = Path(__file__).resolve().parent
|
||||||
API_BASE = os.environ.get("API_BASE", "http://127.0.0.1:8000")
|
API_BASE = os.environ.get("API_BASE", "http://127.0.0.1:8000")
|
||||||
RULES_TEMPLATES_DIR = STATE_HUB_DIR / "scripts" / "project_rules"
|
RULES_TEMPLATES_DIR = STATE_HUB_DIR / "scripts" / "project_rules"
|
||||||
|
|
||||||
|
from api.classification import ( # noqa: E402
|
||||||
|
CLASSIFICATION_FILENAME,
|
||||||
|
extract_classification_block,
|
||||||
|
load_classification_document,
|
||||||
|
)
|
||||||
from scripts.ensure_gitignore_claude_rules import ensure_claude_gitignore # noqa: E402
|
from scripts.ensure_gitignore_claude_rules import ensure_claude_gitignore # noqa: E402
|
||||||
|
|
||||||
KEY_CONTEXT_FILES = [
|
KEY_CONTEXT_FILES = [
|
||||||
|
|
@ -60,12 +67,87 @@ class RegisterInference:
|
||||||
current_state: str | None = None
|
current_state: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
_FRONTMATTER_RE = re.compile(r"\A---\s*\n(.*?)\n---", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
|
def detect_project_flavor_signal(
|
||||||
|
project_path: Path,
|
||||||
|
repo_slug: str | None = None,
|
||||||
|
) -> str | None:
|
||||||
|
"""Return the first project-flavor signal, or None for durable repos.
|
||||||
|
|
||||||
|
Precedence matches repo-manager: classification category, GOAL.md
|
||||||
|
``repo_flavor``, then a ``prj-`` slug prefix. Any match is enough to
|
||||||
|
refuse scaffolding here (STATE-WP-0080-T01).
|
||||||
|
"""
|
||||||
|
category = _classification_category(project_path)
|
||||||
|
if category == "project":
|
||||||
|
return f"{CLASSIFICATION_FILENAME} category=project"
|
||||||
|
|
||||||
|
goal_flavor = _goal_repo_flavor(project_path)
|
||||||
|
if goal_flavor == "project":
|
||||||
|
return "GOAL.md repo_flavor=project"
|
||||||
|
|
||||||
|
for candidate in (repo_slug, project_path.name):
|
||||||
|
if not candidate:
|
||||||
|
continue
|
||||||
|
slug = _slugify(candidate)
|
||||||
|
if slug.startswith("prj-"):
|
||||||
|
return f"slug prefix prj- ({slug})"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def refuse_project_flavor_scaffold(
|
||||||
|
project_path: Path,
|
||||||
|
repo_slug: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Exit before writing INTENT.md / PRJ-WP- files into a project repo."""
|
||||||
|
signal = detect_project_flavor_signal(project_path, repo_slug)
|
||||||
|
if signal is None:
|
||||||
|
return
|
||||||
|
raise SystemExit(
|
||||||
|
"ERROR: statehub register refuses to scaffold a project-flavor repository.\n"
|
||||||
|
f" Detected via: {signal}\n"
|
||||||
|
" Durable-repo registration is unchanged. Scaffold project repos with Repo Manager:\n"
|
||||||
|
f" rmgr scaffold --path {project_path} --flavor project --wp-prefix <PREFIX>-WP\n"
|
||||||
|
" Choose --wp-prefix from the project identity, never PRJ-WP-."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _classification_category(project_path: Path) -> str | None:
|
||||||
|
doc = load_classification_document(project_path / CLASSIFICATION_FILENAME)
|
||||||
|
block = extract_classification_block(doc)
|
||||||
|
if not block:
|
||||||
|
return None
|
||||||
|
raw = block.get("category")
|
||||||
|
return str(raw).strip().lower() if raw else None
|
||||||
|
|
||||||
|
|
||||||
|
def _goal_repo_flavor(project_path: Path) -> str | None:
|
||||||
|
path = project_path / "GOAL.md"
|
||||||
|
if not path.is_file():
|
||||||
|
return None
|
||||||
|
match = _FRONTMATTER_RE.match(_read_limited(path, 4000))
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
frontmatter = yaml.safe_load(match.group(1)) or {}
|
||||||
|
except yaml.YAMLError:
|
||||||
|
return None
|
||||||
|
if not isinstance(frontmatter, dict):
|
||||||
|
return None
|
||||||
|
raw = frontmatter.get("repo_flavor")
|
||||||
|
return str(raw).strip().lower() if raw else None
|
||||||
|
|
||||||
|
|
||||||
def run_register(args: argparse.Namespace) -> None:
|
def run_register(args: argparse.Namespace) -> None:
|
||||||
project_path = Path(args.path).expanduser().resolve()
|
project_path = Path(args.path).expanduser().resolve()
|
||||||
if not project_path.is_dir():
|
if not project_path.is_dir():
|
||||||
print(f"ERROR: {project_path} is not a directory.")
|
print(f"ERROR: {project_path} is not a directory.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
refuse_project_flavor_scaffold(project_path, args.repo_slug)
|
||||||
|
|
||||||
snapshot = collect_repo_snapshot(project_path)
|
snapshot = collect_repo_snapshot(project_path)
|
||||||
print(f"==> Inspecting repo at {snapshot.path}")
|
print(f"==> Inspecting repo at {snapshot.path}")
|
||||||
|
|
||||||
|
|
@ -75,6 +157,7 @@ def run_register(args: argparse.Namespace) -> None:
|
||||||
|
|
||||||
inference = infer_registration(snapshot, args, domain_slugs)
|
inference = infer_registration(snapshot, args, domain_slugs)
|
||||||
repo_slug = args.repo_slug or inference.repo_slug or _slugify(snapshot.project_name)
|
repo_slug = args.repo_slug or inference.repo_slug or _slugify(snapshot.project_name)
|
||||||
|
refuse_project_flavor_scaffold(project_path, repo_slug)
|
||||||
wp_prefix = args.wp_prefix or inference.workplan_prefix or _default_wp_prefix(repo_slug)
|
wp_prefix = args.wp_prefix or inference.workplan_prefix or _default_wp_prefix(repo_slug)
|
||||||
domain = args.domain or inference.domain_slug or _detect_domain_from_files(snapshot)
|
domain = args.domain or inference.domain_slug or _detect_domain_from_files(snapshot)
|
||||||
project_description = (
|
project_description = (
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ import custodian_cli
|
||||||
from custodian_cli import cmd_fix_consistency
|
from custodian_cli import cmd_fix_consistency
|
||||||
from statehub_register import (
|
from statehub_register import (
|
||||||
RegisterInference,
|
RegisterInference,
|
||||||
|
detect_project_flavor_signal,
|
||||||
|
refuse_project_flavor_scaffold,
|
||||||
|
run_register,
|
||||||
_invoke_llm,
|
_invoke_llm,
|
||||||
_normalise_inference,
|
_normalise_inference,
|
||||||
_parse_json_object,
|
_parse_json_object,
|
||||||
|
|
@ -101,6 +104,107 @@ def test_write_registration_files_primes_codex_repo(tmp_path: Path):
|
||||||
assert "statehub fix-consistency" in workplan
|
assert "statehub fix-consistency" in workplan
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_project_flavor_from_classification(tmp_path: Path):
|
||||||
|
(tmp_path / ".repo-classification.yaml").write_text(
|
||||||
|
"repo_classification:\n category: project\n domain: infotech\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(tmp_path) == (
|
||||||
|
".repo-classification.yaml category=project"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_project_flavor_from_goal_md(tmp_path: Path):
|
||||||
|
(tmp_path / "GOAL.md").write_text(
|
||||||
|
"---\nrepo_flavor: project\n---\n\n# Project goal\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(tmp_path) == "GOAL.md repo_flavor=project"
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_project_flavor_from_prj_directory_name(tmp_path: Path):
|
||||||
|
repo = tmp_path / "prj-example"
|
||||||
|
repo.mkdir()
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(repo) == "slug prefix prj- (prj-example)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_detect_project_flavor_from_repo_slug_argument(tmp_path: Path):
|
||||||
|
repo = tmp_path / "example"
|
||||||
|
repo.mkdir()
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(repo) is None
|
||||||
|
assert detect_project_flavor_signal(repo, "prj-example") == (
|
||||||
|
"slug prefix prj- (prj-example)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_classification_project_takes_precedence_over_slug(tmp_path: Path):
|
||||||
|
repo = tmp_path / "prj-example"
|
||||||
|
repo.mkdir()
|
||||||
|
(repo / ".repo-classification.yaml").write_text(
|
||||||
|
"repo_classification:\n category: project\n domain: infotech\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(repo) == (
|
||||||
|
".repo-classification.yaml category=project"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_durable_repo_is_not_project_flavor(tmp_path: Path):
|
||||||
|
(tmp_path / ".repo-classification.yaml").write_text(
|
||||||
|
"repo_classification:\n category: tooling\n domain: infotech\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert detect_project_flavor_signal(tmp_path, "demo-service") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_refuse_project_flavor_scaffold_points_at_rmgr(tmp_path: Path):
|
||||||
|
repo = tmp_path / "prj-example"
|
||||||
|
repo.mkdir()
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit, match="rmgr scaffold") as exc:
|
||||||
|
refuse_project_flavor_scaffold(repo)
|
||||||
|
|
||||||
|
message = str(exc.value)
|
||||||
|
assert "refuses to scaffold a project-flavor repository" in message
|
||||||
|
assert "never PRJ-WP-" in message
|
||||||
|
assert str(repo) in message
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_register_refuses_prj_repo_without_writing_or_calling_api(
|
||||||
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||||
|
):
|
||||||
|
repo = tmp_path / "prj-example"
|
||||||
|
repo.mkdir()
|
||||||
|
(repo / ".repo-classification.yaml").write_text(
|
||||||
|
"repo_classification:\n category: project\n domain: infotech\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
called: list[str] = []
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"statehub_register._check_api",
|
||||||
|
lambda *_args, **_kwargs: called.append("api"),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"statehub_register.write_registration_files",
|
||||||
|
lambda **_kwargs: called.append("write") or [],
|
||||||
|
)
|
||||||
|
|
||||||
|
args = argparse.Namespace(path=str(repo), repo_slug=None)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit, match="rmgr scaffold"):
|
||||||
|
run_register(args)
|
||||||
|
|
||||||
|
assert called == []
|
||||||
|
assert not (repo / "INTENT.md").exists()
|
||||||
|
assert not (repo / "workplans").exists()
|
||||||
|
|
||||||
|
|
||||||
def test_write_registration_files_is_idempotent_without_force(tmp_path: Path):
|
def test_write_registration_files_is_idempotent_without_force(tmp_path: Path):
|
||||||
inference = RegisterInference()
|
inference = RegisterInference()
|
||||||
kwargs = {
|
kwargs = {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ status: active
|
||||||
owner: codex
|
owner: codex
|
||||||
topic_slug: infotech
|
topic_slug: infotech
|
||||||
created: "2026-08-16"
|
created: "2026-08-16"
|
||||||
updated: "2026-08-16"
|
updated: "2026-08-18"
|
||||||
parent_project: prj-state-hub-retirement
|
parent_project: prj-state-hub-retirement
|
||||||
parent_workplan: SHR-WP-0001
|
parent_workplan: SHR-WP-0001
|
||||||
related:
|
related:
|
||||||
|
|
@ -16,7 +16,7 @@ related:
|
||||||
- STATE-WP-0079
|
- STATE-WP-0079
|
||||||
- CFED-WP-0001
|
- CFED-WP-0001
|
||||||
- SHR-WP-0001
|
- SHR-WP-0001
|
||||||
state_hub_workstream_id: "bbfce36a-0b19-462f-af78-167f9eb89b86"
|
state_hub_workstream_id: "03f38314-7d2c-42ee-bd1e-b0cc555dc06b"
|
||||||
---
|
---
|
||||||
|
|
||||||
# statehub register: stop repo scaffolding, hand off to repo-manager
|
# statehub register: stop repo scaffolding, hand off to repo-manager
|
||||||
|
|
@ -70,9 +70,9 @@ manual deletion after registration.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: STATE-WP-0080-T01
|
id: STATE-WP-0080-T01
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "6b01a939-7d60-4a0c-90db-af8e31c45359"
|
state_hub_task_id: "65c52600-15fe-45bd-82b1-dfeff54698af"
|
||||||
```
|
```
|
||||||
|
|
||||||
Add a minimal flavor guard to the register path — detect project flavor from
|
Add a minimal flavor guard to the register path — detect project flavor from
|
||||||
|
|
@ -85,13 +85,18 @@ path here would become a second source of truth competing with `RMGR-WP-0004`.
|
||||||
|
|
||||||
Durable-repo behaviour is untouched.
|
Durable-repo behaviour is untouched.
|
||||||
|
|
||||||
|
**Result (2026-08-18):** `statehub register` exits before writing files when any
|
||||||
|
of those three signals match. Message points at
|
||||||
|
`rmgr scaffold --path <repo> --flavor project --wp-prefix <PREFIX>-WP`.
|
||||||
|
Durable path (`write_registration_files`) is unchanged.
|
||||||
|
|
||||||
## Delegate registration scaffolding
|
## Delegate registration scaffolding
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: STATE-WP-0080-T02
|
id: STATE-WP-0080-T02
|
||||||
status: wait
|
status: todo
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "bd6a9069-b455-4f5e-b1a5-4a87d014e8f6"
|
state_hub_task_id: "ab1e079c-b36f-4bfc-a9fd-fb43f7f93924"
|
||||||
```
|
```
|
||||||
|
|
||||||
Once `RMGR-WP-0004-T03` lands, route scaffolding through Repo Manager instead of
|
Once `RMGR-WP-0004-T03` lands, route scaffolding through Repo Manager instead of
|
||||||
|
|
@ -101,13 +106,16 @@ does: record the repo, its identity, and its host path.
|
||||||
|
|
||||||
Coordinate the cutover point with `RMGR-WP-0004-T05`.
|
Coordinate the cutover point with `RMGR-WP-0004-T05`.
|
||||||
|
|
||||||
|
**Opened (2026-08-18):** T01 guard is live and `RMGR-WP-0004-T03` (`rmgr scaffold`)
|
||||||
|
has landed. Ready to replace the refusal with a delegated scaffold call.
|
||||||
|
|
||||||
## Correct the inventory disposition
|
## Correct the inventory disposition
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: STATE-WP-0080-T03
|
id: STATE-WP-0080-T03
|
||||||
status: wait
|
status: wait
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "b141b378-10d0-4865-a67b-159806bcf037"
|
state_hub_task_id: "91cb1a33-7748-4d65-bfbc-bad21234e364"
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm the register/scaffolding capability is dispositioned `move` →
|
Confirm the register/scaffolding capability is dispositioned `move` →
|
||||||
|
|
@ -122,7 +130,7 @@ the boundary violation during cutover.
|
||||||
id: STATE-WP-0080-T04
|
id: STATE-WP-0080-T04
|
||||||
status: wait
|
status: wait
|
||||||
priority: low
|
priority: low
|
||||||
state_hub_task_id: "d933ae91-ad40-4a88-9ce3-90872cd1f3d7"
|
state_hub_task_id: "342aa5e8-96d0-4832-be60-f48815a86f71"
|
||||||
```
|
```
|
||||||
|
|
||||||
After delegation is live and `RMGR-WP-0004-T06` compatibility tests pass, delete
|
After delegation is live and `RMGR-WP-0004-T06` compatibility tests pass, delete
|
||||||
|
|
@ -139,7 +147,7 @@ retirement rather than as an isolated breaking change.
|
||||||
id: STATE-WP-0080-T05
|
id: STATE-WP-0080-T05
|
||||||
status: cancel
|
status: cancel
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "9eb5ddb5-28d9-4244-8a4f-8fe2a50b5d27"
|
state_hub_task_id: "03224fa5-56f1-4e32-bc2e-40457dceb9cc"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cancelled — moved to **`RMGR-WP-0004-T04`** by decision `747011c6`.
|
Cancelled — moved to **`RMGR-WP-0004-T04`** by decision `747011c6`.
|
||||||
|
|
@ -155,7 +163,7 @@ registration, and it must not be lost in the handoff.
|
||||||
id: STATE-WP-0080-T06
|
id: STATE-WP-0080-T06
|
||||||
status: cancel
|
status: cancel
|
||||||
priority: low
|
priority: low
|
||||||
state_hub_task_id: "3467ae11-1301-46ab-9e7e-75c4f55f53fe"
|
state_hub_task_id: "47adb8e3-2a03-45b9-9647-fc4e42c58cd1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cancelled — moved to **`RMGR-WP-0004-T02`** by decision `747011c6`.
|
Cancelled — moved to **`RMGR-WP-0004-T02`** by decision `747011c6`.
|
||||||
|
|
@ -171,7 +179,7 @@ the result rather than computing it.
|
||||||
id: STATE-WP-0080-T07
|
id: STATE-WP-0080-T07
|
||||||
status: cancel
|
status: cancel
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "126ddd07-df9d-4b65-a651-fff0ad2d4074"
|
state_hub_task_id: "c056b8fd-d91b-4cf0-973c-d74d8e718dd1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cancelled — moved to **`RMGR-WP-0004-T06`** by decision `747011c6`.
|
Cancelled — moved to **`RMGR-WP-0004-T06`** by decision `747011c6`.
|
||||||
|
|
@ -185,7 +193,7 @@ the handoff must not change what ordinary repositories receive.
|
||||||
id: STATE-WP-0080-T08
|
id: STATE-WP-0080-T08
|
||||||
status: cancel
|
status: cancel
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "405526b7-b133-4746-aab5-6301c1a0b72e"
|
state_hub_task_id: "15eca52e-7c3b-40a7-b2a8-38b0313f57a8"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cancelled — superseded by decision `747011c6`, which answered this task's open
|
Cancelled — superseded by decision `747011c6`, which answered this task's open
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue