CUST-WP-0061-T03: the promotion transition (statehub promote-intake)
The mechanism named in canon/standards/work-record-types_v0.1.md:
"Promotion is a first-class transition... manual transcription of an
intake item into other kinds is a process defect." This is what AWQ-010
needed and didn't have -- a human/agent had to notice, transcribe, and
re-register it by hand. One call now does what that manual pass did.
scripts/promote_intake.py: intake.routed -> workplan | task | decision |
engagement.
- workplan: new ADR-001 file at workplans/{ID}-{slug}.md, registered
against the hub (repo+topic resolution, POST /workplans, frontmatter
id write-back)
- task: appended as a ```task``` block to an existing --workplan-file,
registered via POST /tasks, reuses the existing
_inject_task_id_into_block writeback helper
- decision: appended as a ```yaml``` block with a fresh
{PREFIX}-DEC-{YYYY}-{NNN} id to --target-file, registered the same
way C-32 registers decisions (reuses _inject_yaml_block_field)
- engagement: appended as a ```yaml``` block with a fresh
{PREFIX}-ENG-{YYYY}-{NNN} id -- file-only, no hub entity exists yet
(same honest deferral as C-32), reported not silently skipped
In every case the intake is closed with outcome=promoted and
promoted_to=<new canonical id>; the new record carries an
origin: "intake:<id>" back-link.
Wired as `statehub promote-intake <intake-id> --to <kind> --repo-slug
<slug> --repo-path <path> --domain <domain> [--target-file ...]
[--workplan-file ...]`, matching the CLI shape named in the workplan text.
17 tests: pure helpers (_slugify, _next_number, _append_yaml_block,
frontmatter injection) offline; full promote_intake() flow with the hub
API mocked.
Live-verified against the real running API/DB and a real repo
(binky-control), not just mocks -- and the live proof caught a real bug:
the first workplan-promotion run silently produced a false success (the
intake was closed outcome=promoted, but /workplans/ actually 422'd on a
missing repo_id that the code never resolved, so no workstream was ever
created). Fixed to resolve repo_id via /repos/{slug} and to raise loudly
on registration failure instead of writing a half-registered file
silently; locked in as two regression tests. Re-verified clean:
workplan promotion (CLI direct + through `statehub promote-intake`
itself) and decision promotion both proven end-to-end against the live
hub, with all scratch artefacts (files + hub rows) cleaned up afterward.
No regressions: full state-hub suite (271 tests across
test_promote_intake, test_intake, test_work_record_registration,
test_work_record_check, test_routers_core, test_consistency_check,
test_consistency_sweep, test_mcp_smoke, test_mcp_write_tools) green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aade470f4a
commit
3dbbc753bc
3 changed files with 694 additions and 0 deletions
|
|
@ -422,6 +422,30 @@ def cmd_fix_consistency(args: argparse.Namespace) -> None:
|
|||
sys.exit(exit_code)
|
||||
|
||||
|
||||
def cmd_promote_intake(args: argparse.Namespace) -> None:
|
||||
"""Promote a routed intake into a workplan, task, decision, or engagement."""
|
||||
script = STATE_HUB_DIR / "scripts" / "promote_intake.py"
|
||||
if not script.exists():
|
||||
print(f"ERROR: promote_intake.py not found at {script}")
|
||||
sys.exit(1)
|
||||
|
||||
cmd = [
|
||||
sys.executable, str(script), args.intake_id,
|
||||
"--to", args.to,
|
||||
"--repo-path", str(Path(args.repo_path).expanduser().resolve()),
|
||||
"--repo-slug", args.repo_slug,
|
||||
"--domain", args.domain,
|
||||
"--api-base", args.api_base,
|
||||
]
|
||||
if args.target_file:
|
||||
cmd.extend(["--target-file", args.target_file])
|
||||
if args.workplan_file:
|
||||
cmd.extend(["--workplan-file", args.workplan_file])
|
||||
|
||||
result = subprocess.run(cmd)
|
||||
sys.exit(result.returncode)
|
||||
|
||||
|
||||
def cmd_create_workstream(args: argparse.Namespace) -> None:
|
||||
"""Create a workstream under a domain's topic."""
|
||||
_api_get("/state/health")
|
||||
|
|
@ -684,6 +708,20 @@ def main() -> None:
|
|||
help="Preserve checker exit code 2 for warnings-only runs",
|
||||
)
|
||||
|
||||
# promote-intake
|
||||
promote = sub.add_parser(
|
||||
"promote-intake",
|
||||
help="Promote a routed intake into a workplan, task, decision, or engagement (CUST-WP-0061-T03)",
|
||||
)
|
||||
promote.add_argument("intake_id", help="UUID of the routed intake")
|
||||
promote.add_argument("--to", required=True, choices=["workplan", "task", "decision", "engagement"])
|
||||
promote.add_argument("--repo-path", default=os.getcwd(), help="Local checkout of the target repo")
|
||||
promote.add_argument("--repo-slug", required=True, help="Registered repo slug")
|
||||
promote.add_argument("--domain", required=True, help="Market domain slug, e.g. infotech")
|
||||
promote.add_argument("--target-file", default=None, help="Repo-relative path (required for decision/engagement)")
|
||||
promote.add_argument("--workplan-file", default=None, help="Repo-relative workplan file path (required for task)")
|
||||
promote.add_argument("--api-base", default=API_BASE, help="State Hub API base URL")
|
||||
|
||||
# create-workstream
|
||||
cws = sub.add_parser("create-workstream", help="Create a workstream under a domain topic")
|
||||
cws.add_argument("--domain", required=True, help="Domain slug to create the workstream under")
|
||||
|
|
@ -767,6 +805,8 @@ def main() -> None:
|
|||
cmd_ingest_sbom(args)
|
||||
elif args.command == "fix-consistency":
|
||||
cmd_fix_consistency(args)
|
||||
elif args.command == "promote-intake":
|
||||
cmd_promote_intake(args)
|
||||
elif args.command == "create-workstream":
|
||||
cmd_create_workstream(args)
|
||||
elif args.command == "create-task":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue