[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71JG2FQSVC6YKBKPS62F4EC":3,"skill-same:01M71JG2FQSVC6YKBKPS62F4EC":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":6,"updatedAt":57,"install":58,"resources":71},"01M71JG2FQSVC6YKBKPS62F4EC","generate-allure-report",null,"Generate Allure-ready reports from bigpowers YAML metadata. Reads execution-status.yaml, release-plan.yaml, epic capsules, task YAMLs, cycle-times.yaml, and bug registry to produce allure-results\u002Fjunit-results.xml, categories.json, and executor.json. Use when preparing progress dashboards, integrating with Allure TestOps, or generating CI reports.","danielvm-git\u002Fbigpowers","danielvm-git","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1020864?v=4","01M71H1N1CTQ529S0KN7KETVG6","Daniel V M","01M71H1N218Y3S8WHCJ58NPRSW",289,"MIT","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fgenerate-allure-report\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"generate","generate allure report","report","allure","dashboards","sonnet","registry","status","bug","release","progress","plan","reports","when","ci","cycle","executor","junit","ready","categories","2026-11-10 10:12:30",false,"---\nname: generate-allure-report\nmodel: sonnet\ndescription: \"Generate Allure-ready reports from bigpowers YAML metadata. Reads execution-status.yaml, release-plan.yaml, epic capsules, task YAMLs, cycle-times.yaml, and bug registry to produce allure-results\u002Fjunit-results.xml, categories.json, and executor.json. Use when preparing progress dashboards, integrating with Allure TestOps, or generating CI reports.\"\n---\n\n# Generate Allure Report\n\nGenerate Allure TestOps-compatible reports from bigpowers project metadata. Produces JUnit XML for story-level test results, custom categories for filtering, and executor metadata — all in the `allure-results\u002F` directory.\n\n## Quick Start\n\n```bash\nbash scripts\u002Fgenerate-allure-report.sh\n```\n\n## What It Produces\n\nThree files in `allure-results\u002F`:\n\n| File | Description |\n|------|-------------|\n| `junit-results.xml` | One `\u003Ctestcase>` per story with `\u003Cproperties>` for risk, security, WSJF, tier, wave, and status. Incomplete stories get a `\u003Cfailure>` element. |\n| `categories.json` | Custom Allure categories for filtering by epic, risk level (P0), and security reviews. |\n| `executor.json` | Build metadata — name, type, version from release-plan.yaml, build order. |\n\n## Data Sources\n\nSee [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fgenerate-allure-report\u002FREFERENCE.md)\n\n## Verify\n\n```bash\ntest -f allure-results\u002Fjunit-results.xml && test -f allure-results\u002Fcategories.json && test -f allure-results\u002Fexecutor.json\n```\n\n## Handoff\n\n- next_skill: null (terminal skill — no downstream workflow step)\n\n---\n\n# generate-allure-report — Reference\n\n## Data Sources\n\nThe script reads five YAML sources from the project:\n\n| Source | Path | Fields Used |\n|--------|------|-------------|\n| Execution status | `specs\u002Fexecution-status.yaml` | `epics`, `stories`, `development_status` |\n| Release plan | `specs\u002Frelease-plan.yaml` | `release.version`, `release.status`, `bugs` summary |\n| Epic capsules | `specs\u002Fepics\u002F**\u002Fepic.yaml` + `-tasks.yaml` | Epic metadata, task pass\u002Ffail counts |\n| Cycle times | `specs\u002Fmetrics\u002Fcycle-times.yaml` | Story-level `cycle_minutes`, `bcp_per_hour`, `source` |\n| Bug registry | `specs\u002Fbugs\u002Fregistry.yaml` | Bug counts by status and severity |\n\n## Script Body\n\n`scripts\u002Fgenerate-allure-report.sh`:\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\nset -euo pipefail\nsource \"$(dirname \"${BASH_SOURCE[0]}\")\u002Flib\u002Fpython-env.sh\"\nROOT=\"$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull)\" || ROOT=\"$(dirname \"${BASH_SOURCE[0]}\")\u002F..\"\n\nmkdir -p \"$ROOT\u002Fallure-results\"\n\n$PYTHON - \"$ROOT\" \u003C\u003C'PY'\nimport json\nimport sys\nimport xml.etree.ElementTree as ET\nfrom pathlib import Path\n\nroot = Path(sys.argv[1])\nout = root \u002F \"allure-results\"\n\n# 1. Read execution-status.yaml\nexec_status_file = root \u002F \"specs\" \u002F \"execution-status.yaml\"\nrelease_plan_file = root \u002F \"specs\" \u002F \"release-plan.yaml\"\ncycle_times_file = root \u002F \"specs\" \u002F \"metrics\" \u002F \"cycle-times.yaml\"\nbugs_registry_file = root \u002F \"specs\" \u002F \"bugs\" \u002F \"registry.yaml\"\n\nsys.path.insert(0, str(root \u002F \"scripts\" \u002F \"lib\"))\nfrom simple_yaml import parse_simple_yaml\n\nexec_status = parse_simple_yaml(exec_status_file.read_text()) if exec_status_file.exists() else {}\nrelease_plan = parse_simple_yaml(release_plan_file.read_text()) if release_plan_file.exists() else {}\ncycle_times = parse_simple_yaml(cycle_times_file.read_text()) if cycle_times_file.exists() else {\"stories\": []}\nbugs_registry = parse_simple_yaml(bugs_registry_file.read_text()) if bugs_registry_file.exists() else {\"bugs\": []}\n\n# Build cycle-times lookup\nct_lookup = {}\nfor ct in cycle_times.get(\"stories\", []):\n    if isinstance(ct, dict):\n        ct_lookup[ct.get(\"id\", \"\")] = ct\n\n# 2. Build JUnit XML\nstories = exec_status.get(\"stories\", {})\n\n# Counts for testsuite attributes\ntotal_stories = len(stories)\nincomplete = sum(1 for s in stories.values() if isinstance(s, dict) and s.get(\"status\") != \"done\")\n\ntestsuite = ET.Element(\"testsuite\", {\n    \"name\": \"bigpowers-epic-progress\",\n    \"tests\": str(total_stories),\n    \"failures\": str(incomplete),\n    \"errors\": \"0\",\n    \"skipped\": \"0\",\n})\n\nfor story_id in sorted(stories.keys()):\n    story = stories[story_id]\n    if not isinstance(story, dict):\n        continue\n\n    epic_id = story.get(\"epic\", \"unknown\")\n    title = story.get(\"title\", story_id)\n    bcps = story.get(\"bcps\", 0)\n    status = story.get(\"status\", \"backlog\")\n    risk_max = story.get(\"risk_max\", \"none\")\n    security_max = story.get(\"security_max\", \"none\")\n\n    # Enrich with cycle-times data\n    ct_data = ct_lookup.get(story_id, {})\n    cycle_minutes = ct_data.get(\"cycle_minutes\", 0)\n    bcp_per_hour = ct_data.get(\"bcp_per_hour\", 0)\n\n    # Time: cycle_minutes * 60 for seconds in Allure display\n    time_seconds = cycle_minutes * 60.0 if cycle_minutes else 0.0\n\n    testcase = ET.SubElement(testsuite, \"testcase\", {\n        \"classname\": epic_id,\n        \"name\": f\"{story_id}: {title}\",\n        \"time\": str(round(time_seconds, 3)),\n    })\n\n    props = ET.SubElement(testcase, \"properties\")\n    ET.SubElement(props, \"property\", {\"name\": \"risk\", \"value\": risk_max})\n    ET.SubElement(props, \"property\", {\"name\": \"security\", \"value\": security_max})\n    ET.SubElement(props, \"property\", {\"name\": \"bcps\", \"value\": str(bcps)})\n    ET.SubElement(props, \"property\", {\"name\": \"status\", \"value\": status})\n    ET.SubElement(props, \"property\", {\"name\": \"bcp_per_hour\", \"value\": str(bcp_per_hour)})\n    ET.SubElement(props, \"property\", {\"name\": \"lead_time_minutes\", \"value\": str(cycle_minutes)})\n\n    if status != \"done\":\n        ET.SubElement(testcase, \"failure\", {\n            \"message\": f\"Story {story_id} is {status} [risk={risk_max}, security={security_max}]\",\n            \"type\": \"StoryIncomplete\"\n        })\n\ntree = ET.ElementTree(testsuite)\nET.indent(tree, space=\"  \")\ntree.write(str(out \u002F \"junit-results.xml\"), encoding=\"utf-8\", xml_declaration=True)\n\n# 3. Build categories.json\nepics = exec_status.get(\"epics\", {})\ncategories = []\n\nfor epic_id in sorted(epics.keys()):\n    epic = epics[epic_id]\n    if isinstance(epic, dict) and epic.get(\"status\") != \"done\":\n        categories.append({\n            \"name\": f\"Epic: {epic.get('title', epic_id)}\",\n            \"matchedStatuses\": [\"failed\"],\n            \"messageRegex\": f\".*{epic_id}:.*\"\n        })\n\ncategories.append({\n    \"name\": \"P0 Risk\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*risk.*P0.*\"\n})\ncategories.append({\n    \"name\": \"Security Review\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*security.*(?:medium|high).*\"\n})\n\n# Add bug-based categories\nbug_list = bugs_registry.get(\"bugs\", [])\nbug_count = len(bug_list) if isinstance(bug_list, list) else 0\nopen_bugs = sum(1 for b in bug_list if isinstance(b, dict) and b.get(\"status\") not in (\"fixed\", \"closed\", None))\nif open_bugs > 0:\n    categories.append({\n        \"name\": \"Open Bugs\",\n        \"matchedStatuses\": [\"failed\"],\n        \"messageRegex\": \".*Bug.*\"\n    })\n\n(out \u002F \"categories.json\").write_text(json.dumps(categories, indent=2))\n\n# 4. Build executor.json\nrl = release_plan.get(\"release\", {}) if isinstance(release_plan.get(\"release\"), dict) else {}\nexecutor = {\n    \"name\": \"bigpowers\",\n    \"type\": \"bigpowers\",\n    \"buildName\": rl.get(\"version\", \"unknown\") if isinstance(rl, dict) else \"unknown\",\n    \"buildOrder\": len(exec_status.get(\"development_status\", {})),\n}\n(out \u002F \"executor.json\").write_text(json.dumps(executor, indent=2))\n\n# Summary\nepic_count = len([e for e in epics.values() if isinstance(e, dict) and e.get(\"status\") == \"done\"])\ntotal_epics = len(epics)\nprint(f\"generate-allure-report: {total_stories} stories, {epic_count}\u002F{total_epics} epics done, {bug_count} bugs\")\nprint(f\"  -> {out}\u002Fjunit-results.xml\")\nprint(f\"  -> {out}\u002Fcategories.json\")\nprint(f\"  -> {out}\u002Fexecutor.json\")\nPY\n```\n\n## JUnit XML Schema\n\n```xml\n\u003C?xml version=\"1.0\" encoding=\"utf-8\"?>\n\u003Ctestsuite name=\"bigpowers-epic-progress\" tests=\"N\" failures=\"F\" errors=\"0\" skipped=\"0\">\n  \u003Ctestcase classname=\"e01\" name=\"e01s01: Security slopcheck tags\" time=\"0.75\">\n    \u003Cproperties>\n      \u003Cproperty name=\"risk\" value=\"none\"\u002F>\n      \u003Cproperty name=\"security\" value=\"none\"\u002F>\n      \u003Cproperty name=\"bcps\" value=\"1\"\u002F>\n      \u003Cproperty name=\"status\" value=\"done\"\u002F>\n      \u003Cproperty name=\"bcp_per_hour\" value=\"1.3\"\u002F>\n      \u003Cproperty name=\"lead_time_minutes\" value=\"45\"\u002F>\n    \u003C\u002Fproperties>\n  \u003C\u002Ftestcase>\n  \u003Ctestcase classname=\"e01\" name=\"e01s99: Some incomplete story\" time=\"0.0\">\n    \u003Cproperties>...\u003C\u002Fproperties>\n    \u003Cfailure message=\"Story e01s99 is backlog [risk=P0, security=high]\" type=\"StoryIncomplete\"\u002F>\n  \u003C\u002Ftestcase>\n\u003C\u002Ftestsuite>\n```\n\n## Categories JSON Schema\n\n```json\n[\n  {\n    \"name\": \"Epic: Quality Core - Skill Hardening\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*e45:.*\"\n  },\n  {\n    \"name\": \"P0 Risk\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*risk.*P0.*\"\n  },\n  {\n    \"name\": \"Security Review\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*security.*(?:medium|high).*\"\n  }\n]\n```\n\n## Executor JSON Schema\n\n```json\n{\n  \"name\": \"bigpowers\",\n  \"type\": \"bigpowers\",\n  \"buildName\": \"2.76.2\",\n  \"buildOrder\": 400\n}\n```\n\n## Example Usage\n\n```bash\n# Generate reports\nbash scripts\u002Fgenerate-allure-report.sh\n\n# Verify output\ntest -f allure-results\u002Fjunit-results.xml && echo \"JUnit OK\"\ntest -f allure-results\u002Fcategories.json && echo \"Categories OK\"\ntest -f allure-results\u002Fexecutor.json && echo \"Executor OK\"\n\n# Serve with Allure\nallure serve allure-results\u002F\n\n# Or open the Allure TestOps UI\nallure open allure-results\u002F\n```\n","# Generate Allure Report\n\nGenerate Allure TestOps-compatible reports from bigpowers project metadata. Produces JUnit XML for story-level test results, custom categories for filtering, and executor metadata — all in the `allure-results\u002F` directory.\n\n## Quick Start\n\n```bash\nbash scripts\u002Fgenerate-allure-report.sh\n```\n\n## What It Produces\n\nThree files in `allure-results\u002F`:\n\n| File | Description |\n|------|-------------|\n| `junit-results.xml` | One `\u003Ctestcase>` per story with `\u003Cproperties>` for risk, security, WSJF, tier, wave, and status. Incomplete stories get a `\u003Cfailure>` element. |\n| `categories.json` | Custom Allure categories for filtering by epic, risk level (P0), and security reviews. |\n| `executor.json` | Build metadata — name, type, version from release-plan.yaml, build order. |\n\n## Data Sources\n\nSee [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fgenerate-allure-report\u002FREFERENCE.md)\n\n## Verify\n\n```bash\ntest -f allure-results\u002Fjunit-results.xml && test -f allure-results\u002Fcategories.json && test -f allure-results\u002Fexecutor.json\n```\n\n## Handoff\n\n- next_skill: null (terminal skill — no downstream workflow step)\n\n---\n\n# generate-allure-report — Reference\n\n## Data Sources\n\nThe script reads five YAML sources from the project:\n\n| Source | Path | Fields Used |\n|--------|------|-------------|\n| Execution status | `specs\u002Fexecution-status.yaml` | `epics`, `stories`, `development_status` |\n| Release plan | `specs\u002Frelease-plan.yaml` | `release.version`, `release.status`, `bugs` summary |\n| Epic capsules | `specs\u002Fepics\u002F**\u002Fepic.yaml` + `-tasks.yaml` | Epic metadata, task pass\u002Ffail counts |\n| Cycle times | `specs\u002Fmetrics\u002Fcycle-times.yaml` | Story-level `cycle_minutes`, `bcp_per_hour`, `source` |\n| Bug registry | `specs\u002Fbugs\u002Fregistry.yaml` | Bug counts by status and severity |\n\n## Script Body\n\n`scripts\u002Fgenerate-allure-report.sh`:\n\n```bash\n#!\u002Fusr\u002Fbin\u002Fenv bash\nset -euo pipefail\nsource \"$(dirname \"${BASH_SOURCE[0]}\")\u002Flib\u002Fpython-env.sh\"\nROOT=\"$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull)\" || ROOT=\"$(dirname \"${BASH_SOURCE[0]}\")\u002F..\"\n\nmkdir -p \"$ROOT\u002Fallure-results\"\n\n$PYTHON - \"$ROOT\" \u003C\u003C'PY'\nimport json\nimport sys\nimport xml.etree.ElementTree as ET\nfrom pathlib import Path\n\nroot = Path(sys.argv[1])\nout = root \u002F \"allure-results\"\n\n# 1. Read execution-status.yaml\nexec_status_file = root \u002F \"specs\" \u002F \"execution-status.yaml\"\nrelease_plan_file = root \u002F \"specs\" \u002F \"release-plan.yaml\"\ncycle_times_file = root \u002F \"specs\" \u002F \"metrics\" \u002F \"cycle-times.yaml\"\nbugs_registry_file = root \u002F \"specs\" \u002F \"bugs\" \u002F \"registry.yaml\"\n\nsys.path.insert(0, str(root \u002F \"scripts\" \u002F \"lib\"))\nfrom simple_yaml import parse_simple_yaml\n\nexec_status = parse_simple_yaml(exec_status_file.read_text()) if exec_status_file.exists() else {}\nrelease_plan = parse_simple_yaml(release_plan_file.read_text()) if release_plan_file.exists() else {}\ncycle_times = parse_simple_yaml(cycle_times_file.read_text()) if cycle_times_file.exists() else {\"stories\": []}\nbugs_registry = parse_simple_yaml(bugs_registry_file.read_text()) if bugs_registry_file.exists() else {\"bugs\": []}\n\n# Build cycle-times lookup\nct_lookup = {}\nfor ct in cycle_times.get(\"stories\", []):\n    if isinstance(ct, dict):\n        ct_lookup[ct.get(\"id\", \"\")] = ct\n\n# 2. Build JUnit XML\nstories = exec_status.get(\"stories\", {})\n\n# Counts for testsuite attributes\ntotal_stories = len(stories)\nincomplete = sum(1 for s in stories.values() if isinstance(s, dict) and s.get(\"status\") != \"done\")\n\ntestsuite = ET.Element(\"testsuite\", {\n    \"name\": \"bigpowers-epic-progress\",\n    \"tests\": str(total_stories),\n    \"failures\": str(incomplete),\n    \"errors\": \"0\",\n    \"skipped\": \"0\",\n})\n\nfor story_id in sorted(stories.keys()):\n    story = stories[story_id]\n    if not isinstance(story, dict):\n        continue\n\n    epic_id = story.get(\"epic\", \"unknown\")\n    title = story.get(\"title\", story_id)\n    bcps = story.get(\"bcps\", 0)\n    status = story.get(\"status\", \"backlog\")\n    risk_max = story.get(\"risk_max\", \"none\")\n    security_max = story.get(\"security_max\", \"none\")\n\n    # Enrich with cycle-times data\n    ct_data = ct_lookup.get(story_id, {})\n    cycle_minutes = ct_data.get(\"cycle_minutes\", 0)\n    bcp_per_hour = ct_data.get(\"bcp_per_hour\", 0)\n\n    # Time: cycle_minutes * 60 for seconds in Allure display\n    time_seconds = cycle_minutes * 60.0 if cycle_minutes else 0.0\n\n    testcase = ET.SubElement(testsuite, \"testcase\", {\n        \"classname\": epic_id,\n        \"name\": f\"{story_id}: {title}\",\n        \"time\": str(round(time_seconds, 3)),\n    })\n\n    props = ET.SubElement(testcase, \"properties\")\n    ET.SubElement(props, \"property\", {\"name\": \"risk\", \"value\": risk_max})\n    ET.SubElement(props, \"property\", {\"name\": \"security\", \"value\": security_max})\n    ET.SubElement(props, \"property\", {\"name\": \"bcps\", \"value\": str(bcps)})\n    ET.SubElement(props, \"property\", {\"name\": \"status\", \"value\": status})\n    ET.SubElement(props, \"property\", {\"name\": \"bcp_per_hour\", \"value\": str(bcp_per_hour)})\n    ET.SubElement(props, \"property\", {\"name\": \"lead_time_minutes\", \"value\": str(cycle_minutes)})\n\n    if status != \"done\":\n        ET.SubElement(testcase, \"failure\", {\n            \"message\": f\"Story {story_id} is {status} [risk={risk_max}, security={security_max}]\",\n            \"type\": \"StoryIncomplete\"\n        })\n\ntree = ET.ElementTree(testsuite)\nET.indent(tree, space=\"  \")\ntree.write(str(out \u002F \"junit-results.xml\"), encoding=\"utf-8\", xml_declaration=True)\n\n# 3. Build categories.json\nepics = exec_status.get(\"epics\", {})\ncategories = []\n\nfor epic_id in sorted(epics.keys()):\n    epic = epics[epic_id]\n    if isinstance(epic, dict) and epic.get(\"status\") != \"done\":\n        categories.append({\n            \"name\": f\"Epic: {epic.get('title', epic_id)}\",\n            \"matchedStatuses\": [\"failed\"],\n            \"messageRegex\": f\".*{epic_id}:.*\"\n        })\n\ncategories.append({\n    \"name\": \"P0 Risk\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*risk.*P0.*\"\n})\ncategories.append({\n    \"name\": \"Security Review\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*security.*(?:medium|high).*\"\n})\n\n# Add bug-based categories\nbug_list = bugs_registry.get(\"bugs\", [])\nbug_count = len(bug_list) if isinstance(bug_list, list) else 0\nopen_bugs = sum(1 for b in bug_list if isinstance(b, dict) and b.get(\"status\") not in (\"fixed\", \"closed\", None))\nif open_bugs > 0:\n    categories.append({\n        \"name\": \"Open Bugs\",\n        \"matchedStatuses\": [\"failed\"],\n        \"messageRegex\": \".*Bug.*\"\n    })\n\n(out \u002F \"categories.json\").write_text(json.dumps(categories, indent=2))\n\n# 4. Build executor.json\nrl = release_plan.get(\"release\", {}) if isinstance(release_plan.get(\"release\"), dict) else {}\nexecutor = {\n    \"name\": \"bigpowers\",\n    \"type\": \"bigpowers\",\n    \"buildName\": rl.get(\"version\", \"unknown\") if isinstance(rl, dict) else \"unknown\",\n    \"buildOrder\": len(exec_status.get(\"development_status\", {})),\n}\n(out \u002F \"executor.json\").write_text(json.dumps(executor, indent=2))\n\n# Summary\nepic_count = len([e for e in epics.values() if isinstance(e, dict) and e.get(\"status\") == \"done\"])\ntotal_epics = len(epics)\nprint(f\"generate-allure-report: {total_stories} stories, {epic_count}\u002F{total_epics} epics done, {bug_count} bugs\")\nprint(f\"  -> {out}\u002Fjunit-results.xml\")\nprint(f\"  -> {out}\u002Fcategories.json\")\nprint(f\"  -> {out}\u002Fexecutor.json\")\nPY\n```\n\n## JUnit XML Schema\n\n```xml\n\u003C?xml version=\"1.0\" encoding=\"utf-8\"?>\n\u003Ctestsuite name=\"bigpowers-epic-progress\" tests=\"N\" failures=\"F\" errors=\"0\" skipped=\"0\">\n  \u003Ctestcase classname=\"e01\" name=\"e01s01: Security slopcheck tags\" time=\"0.75\">\n    \u003Cproperties>\n      \u003Cproperty name=\"risk\" value=\"none\"\u002F>\n      \u003Cproperty name=\"security\" value=\"none\"\u002F>\n      \u003Cproperty name=\"bcps\" value=\"1\"\u002F>\n      \u003Cproperty name=\"status\" value=\"done\"\u002F>\n      \u003Cproperty name=\"bcp_per_hour\" value=\"1.3\"\u002F>\n      \u003Cproperty name=\"lead_time_minutes\" value=\"45\"\u002F>\n    \u003C\u002Fproperties>\n  \u003C\u002Ftestcase>\n  \u003Ctestcase classname=\"e01\" name=\"e01s99: Some incomplete story\" time=\"0.0\">\n    \u003Cproperties>...\u003C\u002Fproperties>\n    \u003Cfailure message=\"Story e01s99 is backlog [risk=P0, security=high]\" type=\"StoryIncomplete\"\u002F>\n  \u003C\u002Ftestcase>\n\u003C\u002Ftestsuite>\n```\n\n## Categories JSON Schema\n\n```json\n[\n  {\n    \"name\": \"Epic: Quality Core - Skill Hardening\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*e45:.*\"\n  },\n  {\n    \"name\": \"P0 Risk\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*risk.*P0.*\"\n  },\n  {\n    \"name\": \"Security Review\",\n    \"matchedStatuses\": [\"failed\"],\n    \"messageRegex\": \".*security.*(?:medium|high).*\"\n  }\n]\n```\n\n## Executor JSON Schema\n\n```json\n{\n  \"name\": \"bigpowers\",\n  \"type\": \"bigpowers\",\n  \"buildName\": \"2.76.2\",\n  \"buildOrder\": 400\n}\n```\n\n## Example Usage\n\n```bash\n# Generate reports\nbash scripts\u002Fgenerate-allure-report.sh\n\n# Verify output\ntest -f allure-results\u002Fjunit-results.xml && echo \"JUnit OK\"\ntest -f allure-results\u002Fcategories.json && echo \"Categories OK\"\ntest -f allure-results\u002Fexecutor.json && echo \"Executor OK\"\n\n# Serve with Allure\nallure serve allure-results\u002F\n\n# Or open the Allure TestOps UI\nallure open allure-results\u002F\n```\n",{"name":5,"model":29,"description":7},"main","72f5e4c8b43f60cf86b37078ad8cd7e22daf67aa",".pi\u002Fskills\u002Fgenerate-allure-report",24,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers","https:\u002F\u002Fdanielvm-git.github.io\u002Fbigpowers\u002F","https:\u002F\u002Fgithub.com\u002Fdanielvm-git","danielvm.net","2026-11-10 01:18:54",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add danielvm-git\u002Fbigpowers --skill generate-allure-report",{"tool":64,"command":65},"bunx","bunx skills add danielvm-git\u002Fbigpowers --skill generate-allure-report",{"tool":67,"command":68},"pnpm","pnpm dlx skills add danielvm-git\u002Fbigpowers --skill generate-allure-report","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fgenerate-allure-report\u002FSKILL.md",true,[72],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"REFERENCE.md","REFERENCE","参考文档",7887,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fgenerate-allure-report\u002FREFERENCE.md",[79,100,107,135,158,178],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":90,"publishedAt":44},"01M71KBG9F8X644MJB16H4V8M7","skill-verify-fail-open-fixture","Negative-path fixture for run-skill-verify.sh — must never PASS.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fspecs\u002Fverifications\u002Ffixtures\u002Fskill-verify-fail-open\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[91,92,93,94,95,96,97,98,99],"fixture","open","verify","skill verify fail open fixture","skill verify","path","run","for","never",{"skillNo":101,"name":102,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":44},"01M71KBE3BKEMKNE0C5DGVDWZH","negative-path","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fspecs\u002Fverifications\u002Ffixtures\u002Fnegative-path\u002FSKILL.md",[],[106,96],"negative path",{"skillNo":108,"name":109,"nameZh":6,"description":110,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":116,"publishedAt":44},"01M71KBBGF7Y4EB4AMHBZ8CJFC","write-document","Write, organize, and sync high-integrity technical documents using the BMAD methodology. Ensures every document is Bold, Minimal, Actionable, and Durable. Use when creating architectural docs, technical guides, or organizing the specs\u002F directory.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwrite-document\u002FSKILL.md",[113],{"categoryNo":114,"categoryName":115,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000002","文档处理",[117,118,119,120,121,122,123,124,125,126,127,37,128,129,29,130,131,132,133,134],"write","write document","document","documents","actionable","technical","methodology","high","bmad","standard","use","minimal","bold","integrity","organize","sync","directory","guides",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":44},"01M71KB8TM089JJD5AY5KAFSDM","wire-observability","Add structured JSON logging, observability commands, and idempotent setup scripts to a project. Use when a project needs production-readiness instrumentation, when user wants structured logging, or as a production-readiness gate at any phase of development.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwire-observability\u002FSKILL.md",[],[142,143,144,126,145,127,146,147,148,149,29,150,151,152,153,154,155,37,156,157],"observability","wire observability","readiness","commands","development","as","logging","add","instrumentation","at","structured logging","production-readiness","idempotent","phase","project","scripts",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":164,"publishedAt":44},"01M71KB6CNRANP449DQA3NJZ96","wire-ci","CI pipeline setup with bundled, forge-neutral templates and local validation. Detects the forge from the git remote, generates workflows for supported forges, and skips honestly for the rest. The CI equivalent of wire-observability.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwire-ci\u002FSKILL.md",[],[165,38,166,167,168,169,170,171,172,173,174,126,175,98,142,29,176,177],"wire ci","remote","local","pipeline","forge","validation","setup","templates","REST","with","ci pipeline setup","git","workflows",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":193,"publishedAt":44},"01M71KB2ZV98P03X88QR8MT9F1","visual-dashboard","Start a browser-based dashboard that visualizes architecture, implementation plans, and project status. Persists artifacts in .bigpowers\u002Fdashboard\u002F. Reads specs\u002Fstate.yaml, release-plan.yaml, epics, and planning-status via HTTP API or opencode panel.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-dashboard\u002FSKILL.md",[184,187,190],{"categoryNo":185,"categoryName":186,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":188,"categoryName":189,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师",{"categoryNo":191,"categoryName":192,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000033","数据分析师",[194,195,196,31,197,198,199,200,201,29,202,33,203,35,204,205,206,156,207,208],"dashboard","visual","visual dashboard","artifacts","http","plans","planning","panel","start","opencode","browser","api","architecture","project status","http api"]