Files
digital-psychology/scripts/ess-slice-scaffold.py
T
jackyu66gitandCursor 32ac559385 feat(ECR-024): OpsCMS Banner 只读并 Closed
运营横幅目录(ops_banners + admin /cms),锁定 024–040 全队列。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 03:05:55 +08:00

173 lines
5.0 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Scaffold ESS thin-slice artifacts for Ops Loop (docs only)."""
import argparse
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def write(path: Path, text: str):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text.strip() + "\n", encoding="utf-8")
print("wrote", path.relative_to(ROOT))
def main():
p = argparse.ArgumentParser()
p.add_argument("--ecr", required=True) # 024
p.add_argument("--slug", required=True) # banner
p.add_argument("--title", required=True)
p.add_argument("--capability", required=True)
p.add_argument("--bc", required=True)
p.add_argument("--concept", required=True)
p.add_argument("--predecessor", required=True) # ECR-023
p.add_argument("--migration", required=True) # 000025
p.add_argument("--perm", required=True)
p.add_argument("--apis", required=True, help="comma paths like GET /admin/cms/banners|GET /admin/cms/banners/{id}")
p.add_argument("--non-goals", required=True)
p.add_argument("--seed", default="")
p.add_argument("--new-perm", action="store_true")
args = p.parse_args()
ecr = f"ECR-{args.ecr}"
bd = f"BD-2026-{args.ecr}"
spec = f"ops-{args.slug}.md"
apis = [a.strip() for a in args.apis.split("|")]
write(ROOT / f".ai/product/feature-spec/{spec}", f"""
# Feature Spec: {args.capability} · {args.concept}Ops · {ecr}
> Status: `Active`Loop continuous · **{ecr}**
> Parent: WAVE0-FROZEN · Predecessor: {args.predecessor} Closed
> Capability: `{args.capability}` · BC: `{args.bc}`
> 授权:`docs/WAVE0/LOOP_AUTHORIZATION.md`
## Non-goals
{args.non_goals}
## L2 Domain
| 概念 | 语义 |
|------|------|
| `{args.concept}` | 本切片只读目录;code 唯一(若适用) |
## L3 API
| Method | Path | 权限 | 语义 |
|--------|------|------|------|
""" + "\n".join(
f"| {a.split()[0]} | `{a.split()[1]}` | `{args.perm}` | 只读 |"
for a in apis
) + f"""
## Migration
`{args.migration}`:表 + 种子(若有){' + 授予 ' + args.perm if args.new_perm else '(权限复用)'}
## L4 AC
| ID | Then |
|----|------|
| AC-F-01 | list 含种子或空列表合法 |
| AC-F-02 | 已知 id get 200 |
| AC-F-03 | 未知 id → 404 |
| AC-S-01 | 无 Admin → 401 |
| AC-S-02 | 无权限 → 403 |
| AC-P-01 | list &lt; 500ms |
| AC-O-01 | N/A 只读 |
contract_diff: `docs/CONTRACT_DIFF/{ecr}.yaml`
""")
write(ROOT / f"docs/ECR/{ecr}-{args.slug}.md", f"""
# {ecr}
**Title:** {args.title}
**Status:** **Approved**Coding authorized · Loop continuous
**Parent:** WAVE0-FROZEN · **Predecessor:** {args.predecessor} Closed
**Change Level:** L2
## Change
{args.concept} 只读 · `{args.migration}` · `{args.perm}`
## Forbidden
{args.non_goals}
## Linked
Spec `{spec}` · {bd} · CONTRACT_DIFF/{ecr}.yaml
""")
write(ROOT / f"docs/BACKEND_DESIGN/{bd}-{args.slug}.md", f"""
# Backend Design: {ecr} {args.concept}
| ID | {bd} |
| Status | Approved |
| Coding | Loop authorized |
| Level | L2 |
| Migration | YES {args.migration} |
## Backend Change Boundary
```text
Domain: {args.concept} (read)
App: AdminHandler → admin.Service → AdminRepo
API: {'; '.join(apis)}
Permission: {args.perm}
Migration: {args.migration}
```
## Out of boundary
{args.non_goals}
Rollback: down migration + remove routes/UI
""")
api_yaml = "\n".join(
f" - method: {a.split()[0]}\n path: /api/v1{a.split()[1]}\n change: added"
for a in apis
)
perm_line = f" - code: {args.perm}\n change: {'added' if args.new_perm else 'unchanged'}"
write(ROOT / f"docs/CONTRACT_DIFF/{ecr}.yaml", f"""
ecr: {ecr}
capability: {args.capability}
bounded_context: {args.bc}
parent: WAVE0-FROZEN
predecessor: {args.predecessor}
change:
type: additive
breaking_change: false
migration_required: true
compatibility_notes: >
Adds {args.concept} read catalog. Forbidden: UGC / real payment.
apis:
{api_yaml}
perms:
{perm_line}
""")
write(ROOT / f"docs/PRODUCT_SPEC/{ecr}-{args.slug}.md", f"# PRODUCT_SPEC — {ecr}\n\n对齐 {spec} · Approved · Loop · L2 · {args.concept} 只读")
write(ROOT / f"docs/ENGINEERING_SPEC/{ecr}-{args.slug}.md", f"# ENGINEERING_SPEC — {ecr}\n\n1. migration {args.migration}\n2. AdminRepo/Service/Handler\n3. OpenAPI + admin-h5\n4. Integration · Closed")
write(ROOT / f"docs/HANDOFF/{ecr}-architect-to-engineer.md", f"# HANDOFF — {ecr} Architect → Engineer\n\nLoop continuous · Approved + Coding. Migration {args.migration}. Forbidden: UGC/真支付.")
write(ROOT / f"docs/STATE/{ecr}.md", f"# STATE — {ecr}\n\n| Status | **Approved** · Coding |\n| Phase | coding |\n| Spec | {spec} |\n| Updated | 2026-08-08 |")
write(ROOT / f"docs/TASKS/TASK-{args.ecr}-{ecr.replace('-','')}.yaml", f"""
id: TASK-{args.ecr}-{ecr.replace('-','')}
ecr: {ecr}
title: {args.title}
role: engineer
status: active
change_level: L2
parent: WAVE0-FROZEN
predecessor: {args.predecessor}
acceptance:
- Spec AC mapped
- {args.concept} read only
- No UGC / payment
""")
if __name__ == "__main__":
main()