diff --git a/.claude/skills/gitnexus/gitnexus-cli/SKILL.md b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md new file mode 100644 index 000000000..989c08277 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md @@ -0,0 +1,85 @@ +--- +name: gitnexus-cli +description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\"" +--- + +# GitNexus CLI Commands + +Commands below use `node .gitnexus/run.cjs ` — the project-local runner `gitnexus analyze` drops next to the index. It auto-selects an available runner at call time (global `gitnexus`, else `pnpm dlx`, else `npx`), so no package-manager assumption and no global install is required. + +> **Not analyzed yet, or `node .gitnexus/run.cjs` reports `Cannot find module`** (the gitignored runner is absent — e.g. a fresh clone or `git clean`)? (Re)generate it with `npx gitnexus analyze` from the project root. On **npm 11.x**, if `npx` crashes during install (`node.target is null`), install once with `npm i -g gitnexus` (then `gitnexus analyze`) or use `pnpm --allow-build=@ladybugdb/core --allow-build=gitnexus --allow-build=tree-sitter dlx gitnexus@latest analyze`. See [#1939](https://github.com/abhigyanpatwari/GitNexus/issues/1939). + +## Commands + +### analyze — Build or refresh the index + +```bash +node .gitnexus/run.cjs analyze +``` + +Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files. + +| Flag | Effect | +| -------------- | ---------------------------------------------------------------- | +| `--force` | Force full re-index even if up to date | +| `--embeddings` | Enable embedding generation for semantic search (off by default) | +| `--drop-embeddings` | Drop existing embeddings on rebuild. By default, an `analyze` without `--embeddings` preserves them. | + +**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook detects staleness after `git commit` and `git merge` and notifies the agent to run `analyze` — the hook does not run analyze itself, to avoid blocking the agent for up to 120s and risking KuzuDB corruption on timeout. + +### status — Check index freshness + +```bash +node .gitnexus/run.cjs status +``` + +Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed. + +### clean — Delete the index + +```bash +node .gitnexus/run.cjs clean +``` + +Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project. + +| Flag | Effect | +| --------- | ------------------------------------------------- | +| `--force` | Skip confirmation prompt | +| `--all` | Clean all indexed repos, not just the current one | + +### wiki — Generate documentation from the graph + +```bash +node .gitnexus/run.cjs wiki +``` + +Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use). + +| Flag | Effect | +| ------------------- | ----------------------------------------- | +| `--force` | Force full regeneration | +| `--model ` | LLM model (default: minimax/minimax-m2.5) | +| `--base-url ` | LLM API base URL | +| `--api-key ` | LLM API key | +| `--concurrency ` | Parallel LLM calls (default: 3) | +| `--gist` | Publish wiki as a public GitHub Gist | + +### list — Show all indexed repos + +```bash +node .gitnexus/run.cjs list +``` + +Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information. + +## After Indexing + +1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded +2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task + +## Troubleshooting + +- **"Not inside a git repository"**: Run from a directory inside a git repo +- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server +- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding diff --git a/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md new file mode 100644 index 000000000..4a33e589a --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md @@ -0,0 +1,101 @@ +--- +name: gitnexus-debugging +description: "Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: \"Why is X failing?\", \"Where does this error come from?\", \"Trace this bug\"" +--- + +# Debugging with GitNexus + +## When to Use + +- "Why is this function failing?" +- "Trace where this error comes from" +- "Who calls this method?" +- "This endpoint returns 500" +- Investigating bugs, errors, or unexpected behavior + +## Workflow + +``` +1. query({search_query: ""}) → Find related execution flows +2. context({name: ""}) → See callers/callees/processes +3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow +4. cypher({statement: "MATCH path..."}) → Custom traces if needed +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] Understand the symptom (error message, unexpected behavior) +- [ ] query for error text or related code +- [ ] Identify the suspect function from returned processes +- [ ] context to see callers and callees +- [ ] Trace execution flow via process resource if applicable +- [ ] cypher for custom call chain traces if needed +- [ ] Read source files to confirm root cause +``` + +## Debugging Patterns + +| Symptom | GitNexus Approach | +| -------------------- | ---------------------------------------------------------- | +| Error message | `query` for error text → `context` on throw sites | +| Wrong return value | `context` on the function → trace callees for data flow | +| Intermittent failure | `context` → look for external calls, async deps | +| Performance issue | `context` → find symbols with many callers (hot paths) | +| Recent regression | `detect_changes` to see what your changes affect | +| "How does A reach B?" | `trace` between the two symbols — shortest call chain in one call | + +## Tools + +**query** — find code related to error: + +``` +query({search_query: "payment validation error"}) +→ Processes: CheckoutFlow, ErrorHandling +→ Symbols: validatePayment, handlePaymentError, PaymentException +``` + +**context** — full context for a suspect: + +``` +context({name: "validatePayment"}) +→ Incoming calls: processCheckout, webhookHandler +→ Outgoing calls: verifyCard, fetchRates (external API!) +→ Processes: CheckoutFlow (step 3/7) +``` + +**cypher** — custom call chain traces: + +```cypher +MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"}) +RETURN [n IN nodes(path) | n.name] AS chain +``` + +**trace** — shortest call chain between two symbols ("how does A reach B?"), one call instead of chaining `context` hops: + +``` +trace({ from: "processCheckout", to: "fetchRates" }) +→ status: ok, hopCount: 3 +→ hops: processCheckout → validatePayment → verifyCard → fetchRates +→ edges: CALLS (1.0), CALLS (0.95), CALLS (1.0) +``` + +When no path exists, `trace` reports the furthest reachable node — exactly where the chain breaks (dynamic dispatch, reflection, or an external boundary). + +## Example: "Payment endpoint returns 500 intermittently" + +``` +1. query({search_query: "payment error handling"}) + → Processes: CheckoutFlow, ErrorHandling + → Symbols: validatePayment, handlePaymentError + +2. context({name: "validatePayment"}) + → Outgoing calls: verifyCard, fetchRates (external API!) + +3. READ gitnexus://repo/my-app/process/CheckoutFlow + → Step 3: validatePayment → calls fetchRates (external) + +4. Root cause: fetchRates calls external API without proper timeout +``` diff --git a/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md new file mode 100644 index 000000000..f483c2fd6 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md @@ -0,0 +1,78 @@ +--- +name: gitnexus-exploring +description: "Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: \"How does X work?\", \"What calls this function?\", \"Show me the auth flow\"" +--- + +# Exploring Codebases with GitNexus + +## When to Use + +- "How does authentication work?" +- "What's the project structure?" +- "Show me the main components" +- "Where is the database logic?" +- Understanding code you haven't seen before + +## Workflow + +``` +1. READ gitnexus://repos → Discover indexed repos +2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness +3. query({search_query: ""}) → Find related execution flows +4. context({name: ""}) → Deep dive on specific symbol +5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow +``` + +> If step 2 says "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] READ gitnexus://repo/{name}/context +- [ ] query for the concept you want to understand +- [ ] Review returned processes (execution flows) +- [ ] context on key symbols for callers/callees +- [ ] READ process resource for full execution traces +- [ ] Read source files for implementation details +``` + +## Resources + +| Resource | What you get | +| --------------------------------------- | ------------------------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) | +| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) | +| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) | + +## Tools + +**query** — find execution flows related to a concept: + +``` +query({search_query: "payment processing"}) +→ Processes: CheckoutFlow, RefundFlow, WebhookHandler +→ Symbols grouped by flow with file locations +``` + +**context** — 360-degree view of a symbol: + +``` +context({name: "validateUser"}) +→ Incoming calls: loginHandler, apiMiddleware +→ Outgoing calls: checkToken, getUserById +→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3) +``` + +## Example: "How does payment processing work?" + +``` +1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes +2. query({search_query: "payment processing"}) + → CheckoutFlow: processPayment → validateCard → chargeStripe + → RefundFlow: initiateRefund → calculateRefund → processRefund +3. context({name: "processPayment"}) + → Incoming: checkoutHandler, webhookHandler + → Outgoing: validateCard, chargeStripe, saveTransaction +4. Read src/payments/processor.ts for implementation details +``` diff --git a/.claude/skills/gitnexus/gitnexus-guide/SKILL.md b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md new file mode 100644 index 000000000..a5df5b665 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md @@ -0,0 +1,128 @@ +--- +name: gitnexus-guide +description: "Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: \"What GitNexus tools are available?\", \"How do I use GitNexus?\"" +--- + +# GitNexus Guide + +Quick reference for all GitNexus MCP tools, resources, and the knowledge graph schema. + +## Always Start Here + +For any task involving code understanding, debugging, impact analysis, or refactoring: + +1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness +2. **Match your task to a skill below** and **read that skill file** +3. **Follow the skill's workflow and checklist** + +> If step 1 warns the index is stale, run `node .gitnexus/run.cjs analyze` in the terminal first. + +## Skills + +| Task | Skill to read | +| -------------------------------------------- | ------------------- | +| Understand architecture / "How does X work?" | `gitnexus-exploring` | +| Blast radius / "What breaks if I change X?" | `gitnexus-impact-analysis` | +| Trace bugs / "Why is X failing?" | `gitnexus-debugging` | +| Rename / extract / split / refactor | `gitnexus-refactoring` | +| Tools, resources, schema reference | `gitnexus-guide` (this file) | +| Index, status, clean, wiki CLI commands | `gitnexus-cli` | + +## Tools Reference + +| Tool | What it gives you | +| ---------------- | ------------------------------------------------------------------------ | +| `query` | Process-grouped code intelligence — execution flows related to a concept | +| `context` | 360-degree symbol view — categorized refs, processes it participates in | +| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence | +| `trace` | Shortest path between two symbols — "how does A reach B?" in one call | +| `detect_changes` | Git-diff impact — what do your current changes affect | +| `rename` | Multi-file coordinated rename with confidence-tagged edits | +| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) | +| `explain` | Persisted taint findings — source→sink data flows (needs `analyze --pdg`) | +| `pdg_query` | Control/data dependence — what gates X (CDG) / where Y flows (REACHING_DEF); needs `analyze --pdg` | +| `check` | Check graph invariants such as circular imports | +| `list_repos` | Discover indexed repos (paginated — `limit`/`offset`) | + +### Paginating `list_repos` + +`list_repos` is paginated so a large registry is not truncated by MCP/LLM token limits. It takes optional `limit` (default **50**, max **200**) and `offset`, and returns: + +```jsonc +{ + "repositories": [ + { "name": "...", "path": "...", "indexedAt": "...", "lastCommit": "...", "stats": { } } + ], + "pagination": { + "total": 437, + "limit": 50, + "offset": 0, + "returned": 50, + "hasMore": true, + "nextOffset": 50 + } +} +``` + +To enumerate **every** repository, keep calling with `offset` set to `pagination.nextOffset` until `hasMore` is `false`: + +```text +list_repos {} → repos 1–50, nextOffset 50, hasMore true +list_repos { offset: 50 } → repos 51–100, nextOffset 100, hasMore true +… +list_repos { offset: 400 } → repos 401–437, hasMore false (done) +``` + +Notes: `offset` ≥ `total` returns an empty page (with `total` still reported). Out-of-range or malformed `limit`/`offset` (non-integer, `limit` outside `[1, 200]`, `offset < 0`) are rejected with a clear error — `limit` above the max is rejected, not silently capped. The order is deterministic (lower-cased name, then path), so paging never skips or duplicates an entry while the registry is unchanged. + +### Taint findings (`explain`) + +`explain` returns intra-procedural taint findings (`TAINTED` edges) recorded by `gitnexus analyze --pdg` — each with a sink category (command-injection, code-injection, path-traversal, sql-injection, xss), source/sink lines, and the ordered hop path with the variable carried on each hop. + +- `explain {}` — enumerate all findings for the repo (bounded by `limit`, deterministic order) +- `explain { target: "src/vuln.ts" }` — findings in a file (suffix path match accepted) +- `explain { target: "runUserCommand" }` — findings in a function (resolved like `context`; ambiguous names return ranked candidates) + +A repo indexed without `--pdg` returns a clear "no taint layer" note. Caveats: findings are intra-procedural only — cross-function, closure/callback, property/field, and implicit flows are not modeled, so the absence of a finding is **not** proof of safety. `SANITIZES` (sanitizer-kill) edges are queryable via `cypher`. + +### Control & data dependence (`pdg_query`) + +`pdg_query` reads the control/data-dependence layers `gitnexus analyze --pdg` records (CDG + REACHING_DEF, basic-block granular) — the control/data analog of `explain`. It is **always anchored** (a `target` file path or symbol, resolved like `context`) and has two modes: + +- `pdg_query { mode: "controls", target: "..." }` — CDG: "under what condition does X run?". Each edge is a controlling predicate block → dependent block with the branch sense (`'T'`/`'F'`) in `reason`; an edge into an early `return`/`throw` is flagged `guard: true` (guard-clause discovery — the sense depends on the predicate, so don't filter guards by a fixed label). +- `pdg_query { mode: "flows", target: "...", variable?: "..." }` — REACHING_DEF def→use edges within the function; pass `variable` to trace one binding. + +A repo indexed without `--pdg` returns a "no PDG layer" note (or "status unknown" when the layer can't be confirmed). Intra-procedural only — cross-function flow is taint's domain (`explain`). The raw CDG/REACHING_DEF edges are also queryable via `cypher`. See the `gitnexus-pdg-query` skill for the full query surface. + +### Shortest path between two symbols (`trace`) + +`trace` answers "how does A reach B?" in one call — the shortest directed path over `CALLS` (plus `HAS_METHOD`, so a class-rooted trace descends into its methods) instead of chaining 3–8 `context`/`impact` hops by hand. + +- `trace { from: "validateUser", to: "executeQuery" }` — shortest path between two symbols. +- Disambiguate common names with `from_uid`/`to_uid` (zero-ambiguity) or `from_file`/`to_file`; an ambiguous name returns ranked candidates. +- `maxDepth` (default 10, max 30) bounds the search; `includeTests` (default false) lets the traversal pass through test-file symbols. + +Returns ordered `hops` (each `{ name, filePath, startLine }`) and an aligned `edges[]` of `{ relType, confidence }`, so call hops and containment (`HAS_METHOD`) hops stay distinguishable. When no path exists it reports the **furthest** reachable node (where the chain breaks) and sets `truncated: true` if a traversal cap was hit first. Every result carries a `status`: `ok` / `no_path` / `ambiguous` / `not_found` / `error`. + +## Resources Reference + +Lightweight reads (~100-500 tokens) for navigation: + +| Resource | Content | +| ---------------------------------------------- | ----------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness check | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores | +| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members | +| `gitnexus://repo/{name}/processes` | All execution flows | +| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace | +| `gitnexus://repo/{name}/schema` | Graph schema for Cypher | + +## Graph Schema + +**Nodes:** File, Function, Class, Interface, Method, Community, Process +**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"}) +RETURN caller.name, caller.filePath +``` diff --git a/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md new file mode 100644 index 000000000..45eb7ce87 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md @@ -0,0 +1,97 @@ +--- +name: gitnexus-impact-analysis +description: "Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: \"Is it safe to change X?\", \"What depends on this?\", \"What will break?\"" +--- + +# Impact Analysis with GitNexus + +## When to Use + +- "Is it safe to change this function?" +- "What will break if I modify X?" +- "Show me the blast radius" +- "Who uses this code?" +- Before making non-trivial code changes +- Before committing — to understand what your changes affect + +## Workflow + +``` +1. impact({target: "X", direction: "upstream"}) → What depends on this +2. READ gitnexus://repo/{name}/processes → Check affected execution flows +3. detect_changes() → Map current git changes to affected flows +4. Assess risk and report to user +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklist + +``` +- [ ] impact({target, direction: "upstream"}) to find dependents +- [ ] Review d=1 items first (these WILL BREAK) +- [ ] Check high-confidence (>0.8) dependencies +- [ ] READ processes to check affected execution flows +- [ ] detect_changes() for pre-commit check +- [ ] Assess risk level and report to user +``` + +## Understanding Output + +| Depth | Risk Level | Meaning | +| ----- | ---------------- | ------------------------ | +| d=1 | **WILL BREAK** | Direct callers/importers | +| d=2 | LIKELY AFFECTED | Indirect dependencies | +| d=3 | MAY NEED TESTING | Transitive effects | + +## Risk Assessment + +| Affected | Risk | +| ------------------------------ | -------- | +| <5 symbols, few processes | LOW | +| 5-15 symbols, 2-5 processes | MEDIUM | +| >15 symbols or many processes | HIGH | +| Critical path (auth, payments) | CRITICAL | + +## Tools + +**impact** — the primary tool for symbol blast radius: + +``` +impact({ + target: "validateUser", + direction: "upstream", + minConfidence: 0.8, + maxDepth: 3 +}) + +→ d=1 (WILL BREAK): + - loginHandler (src/auth/login.ts:42) [CALLS, 100%] + - apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%] + +→ d=2 (LIKELY AFFECTED): + - authRouter (src/routes/auth.ts:22) [CALLS, 95%] +``` + +**detect_changes** — git-diff based impact analysis: + +``` +detect_changes({scope: "staged"}) + +→ Changed: 5 symbols in 3 files +→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline +→ Risk: MEDIUM +``` + +## Example: "What breaks if I change validateUser?" + +``` +1. impact({target: "validateUser", direction: "upstream"}) + → d=1: loginHandler, apiMiddleware (WILL BREAK) + → d=2: authRouter, sessionManager (LIKELY AFFECTED) + +2. READ gitnexus://repo/my-app/processes + → LoginFlow and TokenRefresh touch validateUser + +3. Risk: 2 direct callers, 2 processes = MEDIUM +``` diff --git a/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md new file mode 100644 index 000000000..90c8c324d --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md @@ -0,0 +1,121 @@ +--- +name: gitnexus-refactoring +description: "Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: \"Rename this function\", \"Extract this into a module\", \"Refactor this class\", \"Move this to a separate file\"" +--- + +# Refactoring with GitNexus + +## When to Use + +- "Rename this function safely" +- "Extract this into a module" +- "Split this service" +- "Move this to a new file" +- Any task involving renaming, extracting, splitting, or restructuring code + +## Workflow + +``` +1. impact({target: "X", direction: "upstream"}) → Map all dependents +2. query({search_query: "X"}) → Find execution flows involving X +3. context({name: "X"}) → See all incoming/outgoing refs +4. Plan update order: interfaces → implementations → callers → tests +``` + +> If "Index is stale" → run `node .gitnexus/run.cjs analyze` in terminal. + +## Checklists + +### Rename Symbol + +``` +- [ ] rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits +- [ ] Review graph edits (high confidence) and ast_search edits (review carefully) +- [ ] If satisfied: rename({..., dry_run: false}) — apply edits +- [ ] detect_changes() — verify only expected files changed +- [ ] Run tests for affected processes +``` + +### Extract Module + +``` +- [ ] context({name: target}) — see all incoming/outgoing refs +- [ ] impact({target, direction: "upstream"}) — find all external callers +- [ ] Define new module interface +- [ ] Extract code, update imports +- [ ] detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +### Split Function/Service + +``` +- [ ] context({name: target}) — understand all callees +- [ ] Group callees by responsibility +- [ ] impact({target, direction: "upstream"}) — map callers to update +- [ ] Create new functions/services +- [ ] Update callers +- [ ] detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +## Tools + +**rename** — automated multi-file rename: + +``` +rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) +→ 12 edits across 8 files +→ 10 graph edits (high confidence), 2 ast_search edits (review) +→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}] +``` + +**impact** — map all dependents first: + +``` +impact({target: "validateUser", direction: "upstream"}) +→ d=1: loginHandler, apiMiddleware, testUtils +→ Affected Processes: LoginFlow, TokenRefresh +``` + +**detect_changes** — verify your changes after refactoring: + +``` +detect_changes({scope: "all"}) +→ Changed: 8 files, 12 symbols +→ Affected processes: LoginFlow, TokenRefresh +→ Risk: MEDIUM +``` + +**cypher** — custom reference queries: + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"}) +RETURN caller.name, caller.filePath ORDER BY caller.filePath +``` + +## Risk Rules + +| Risk Factor | Mitigation | +| ------------------- | ----------------------------------------- | +| Many callers (>5) | Use rename for automated updates | +| Cross-area refs | Use detect_changes after to verify scope | +| String/dynamic refs | query to find them | +| External/public API | Version and deprecate properly | + +## Example: Rename `validateUser` to `authenticateUser` + +``` +1. rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) + → 12 edits: 10 graph (safe), 2 ast_search (review) + → Files: validator.ts, login.ts, middleware.ts, config.json... + +2. Review ast_search edits (config.json: dynamic reference!) + +3. rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false}) + → Applied 12 edits across 8 files + +4. detect_changes({scope: "all"}) + → Affected: LoginFlow, TokenRefresh + → Risk: MEDIUM — run tests for these flows +``` diff --git a/.claude/skills/repo-health/SKILL.md b/.claude/skills/repo-health/SKILL.md new file mode 100644 index 000000000..568a406fb --- /dev/null +++ b/.claude/skills/repo-health/SKILL.md @@ -0,0 +1,58 @@ +--- +name: repo-health +description: Use when the user wants to check or clean up the AI-BIM-governance repo's health — version/dependency drift across services, branch/worktree/temp cleanup, .claude asset hygiene, and doc/config sync. Scans read-only across four dimensions, reports, then fixes only what the user confirms. +argument-hint: "(選填)只想看某面向:version / cleanup / assets / docs" +--- + +# repo-health — AI-BIM repo 四面向健檢 + +對 `AI-BIM-governance` 跑唯讀健檢,回報問題,**只修使用者確認的項目**。 + +## 安全鐵則(不可違反) + +1. **掃描階段唯讀** — workflow 與本 skill 的掃描絕不修改任何檔案。 +2. **報告 → 確認 → 才修** — 任何修復都要先把報告給使用者、等使用者勾選後才動手。 +3. **risky 項一律明確確認** — 改版本檔、`.claude` agent 設定、文件內容、`.env.example`(只補 key 名、留空值,永不寫入任何 .env 值)都屬 risky。 +4. **優先複用既有腳本** — 清理用 `scripts/git-prune-merged-branches.ps1`、`scripts/log-retention/`;不要另寫新腳本(遵守 `scripts/SCRIPT_CONTRACT.md`)。 +5. **修完重驗** — 修復後對該項重新掃一次,確認真的閉合,如實回報。 + +## 面向 + +**4 個衛生面向(可修):** + +| 面向 | 抓什麼 | 修復安全性 | +|---|---|---| +| **版本漂移** | 同套件跨服務版本不一致(fastapi/uvicorn/pydantic/vitest/react…) | risky(改依賴檔) | +| **清理** | 已 merged 分支、過期 worktree、`.tmp`/`.pytest_cache`/舊 log | safe(純清理) | +| **.claude 資產** | 命名不一致、重複、孤兒 workflow、漏索引的 skill | risky(動 agent 設定) | +| **文件同步** | script-registry 落差、`.env.example` 缺 key、文件指向不存在的檔 | risky(動文件/設定) | + +**1 個進度面向(唯讀評估,不產可修項):** + +| 面向 | 抓什麼 | 性質 | +|---|---|---| +| **進度差異** | `docs/plans/開發軌跡與執行計畫.md` 的 A1–A10/M0–M8「計畫自報 vs 獨立查證」並列,標出計畫高估/低報 | 唯讀評估,**不納入「要修哪幾項」** | + +## 流程 + +1. **掃描** — 跑 workflow `repo-health-scan`(4 個 Explore agent 平行唯讀掃)。 + - 若使用者只要某一面向(arg = version/cleanup/assets/docs),仍跑全掃但報告時只聚焦該面向。 +2. **報告** — 套用 `repo-health` output-style,把回傳的 `dimensions` 畫成健康狀態表: + - 開頭一張總表(4 個衛生面向,每面向 ✅ 無問題 / ⚠️ warn / ❌ fail + 問題數)。 + - 各面向逐項列:標題、證據、建議修法、`[safe]`/`[risky]` 標記。 + - **進度差異獨立區塊** — 衛生面向之後另起「📊 進度差異」,把回傳的 `progress.items` 畫成小表:`目標 / 計畫說 / 實際 / 對齊 / 差距`;對齊用圖示(✅相符 / 🔴計畫高估 / 🟡計畫低報 / ❔查不出)。此區塊**純資訊,不列入可修項**。 +3. **問** — 結尾固定問:「**要修哪幾項?**」只列 4 個衛生面向的可修項(用編號),標清楚哪些 safe、哪些 risky。進度差異不在此問句範圍。 +4. **修** — 只對使用者勾選的項目動手: + - safe 項(清理):複用既有腳本執行。 + - risky 項(版本/資產/文件):先說明具體會改什麼,再以最小 diff 修改;版本對齊要讓使用者指定目標版本。 +5. **重驗** — 對已修項目重掃,回報 keep / 仍有問題;產出四項收尾(改了什麼 / 驗了什麼 / 沒做什麼+原因 / 已知風險)。 + +## 觸發 + +- 指令:`/repo-health`(薄指令,叫起本 skill)。 +- 或使用者直接說「跑 repo 健檢 / 檢查 repo 健康 / 清一下 repo」。 + +## 注意 + +- workflow 預設 `root` 為 `C:\Repos\active\iot\AI-BIM-governance`;在別處或 worktree 跑時用 args 帶入正確絕對路徑。 +- 掃描是 best-effort:某面向 agent 失敗(回 null)時如實標「該面向未完成」,不要假裝健康。 diff --git a/.claude/skills/spec-to-done/SKILL.md b/.claude/skills/spec-to-done/SKILL.md index 476fa45a4..4e1f75186 100644 --- a/.claude/skills/spec-to-done/SKILL.md +++ b/.claude/skills/spec-to-done/SKILL.md @@ -168,6 +168,7 @@ MUST 先從主工作區 root 跑本技能 helper 清掉佔住必要 host-native ``` powershell -NoProfile -ExecutionPolicy Bypass -File .claude\skills\spec-to-done\ensure-host-native-ports-free.ps1 +# 若 .codex 側或 user 級亦存在同名 helper,三份內容必須一致(.codex copy 定義了跨 host 優先序) ``` - **為什麼**:Kit 無 live reload / migration(docs/plans 鐵則 #4、D9——換 stage 只能 terminate+recreate)。殘留的 diff --git a/.claude/workflows/bim-frontend-redesign-plan.js b/.claude/workflows/bim-frontend-redesign-plan.js deleted file mode 100644 index ce9f86008..000000000 --- a/.claude/workflows/bim-frontend-redesign-plan.js +++ /dev/null @@ -1,224 +0,0 @@ -export const meta = { - name: 'bim-frontend-redesign-plan', - description: 'Readonly:收集 Claude/Anthropic 官方前端設計技能 + Kit primary/spectator 權威模型,據以規劃 5 項前端設計重構', - phases: [ - { title: 'Foundations', detail: '官方設計技能 + Kit 串流權限 + 設計參考 repo + 現況程式碼錨點' }, - { title: 'PlanItems', detail: '5 個項目各自規劃' }, - { title: 'Synthesize', detail: '彙整一致設計系統 + IA + 分期落地' }, - ], -} - -const GOV = 'C:/Repos/active/iot/AI-BIM-governance' -const DESIGN = 'C:/Repos/design/bim-desigin-arich/project' - -// ---------- Phase 1: Foundations ---------- -phase('Foundations') - -const F = await parallel([ - // F1 — 官方前端設計技能(web research) - () => agent( - `唯讀研究任務:找出 **Anthropic / Claude Code 官方推薦的「前端設計」技能/指南**,整理成一份可直接套用的「設計系統規範」。 -用 WebSearch + WebFetch 查這些方向(擇優取權威來源): -- Anthropic 官方 agent skills(GitHub: anthropics/skills、anthropics/claude-cookbooks)中與 frontend / web design / artifacts / web-design-guidelines 相關的 skill 內容 -- Claude 的「web aesthetic / design guidelines」官方說法(Anthropic 部落格或 docs) -- Claude Code 內建 'frontend-design' 實作型 skill 的設計原則 -產出一份**具體、可檢核**的設計規範(不要空泛口號),至少涵蓋: -1) 設計 token:色彩系統(語意色/狀態色)、字級階梯(type scale)、間距尺度(spacing)、圓角/陰影/邊框、密度(density) -2) 版面與資訊架構:layout grid、導航模式、面板/抽屜/overlay 的使用時機 -3) 元件狀態鐵律:default/hover/focus/active/disabled、loading/empty/error/skeleton -4) 無障礙(a11y):focus ring、aria-disabled vs pointer-events、鍵盤操作、對比 -5) 動效節制原則 -6) 針對「即時 3D 協作 / 會議主持(primary)與旁觀(spectator)」這種介面,官方設計原則會強調哪些(權限可視性、唯讀降級的誠實標示、狀態回饋) -明確標註每條來自哪個來源 URL。只研究、不改任何檔案。輸出 markdown。`, - { label: 'F1:official-design-skill', phase: 'Foundations', agentType: 'Explore' } - ), - - // F2 — Kit/Omniverse primary/spectator 權威模型 - () => agent( - `唯讀研究任務:整理 **NVIDIA Omniverse Kit App Streaming 的 primary(主持/操作) vs spectator(旁觀/唯讀) 權威模型**,作為前端權限設計的依據。 -用 Kit MCP 工具(透過 ToolSearch 載入 mcp__claude_ai_Kit_MCP__* 例如 search_kit_knowledge / search_kit_extensions / get_kit_instructions)與 WebSearch/WebFetch 查 NVIDIA 官方文件,釐清: -1) Kit App Streaming 的串流分享模型:單一 Kit instance 的 viewport 如何被多個 client 觀看(viewport streaming / viewport sharing) -2) 誰能操作相機/選取/編輯 —— "presenter/host" 與 "viewer/spectator" 的官方權限界線;spectator 是否只收結果(stage selection / camera) 而不能主動下指令 -3) follow mode / live session / presence 的官方概念與適用情境 -4) 對映到本專案:primary 經 DataChannel 主動下指令(open/focus/highlight/select),spectator 只接收 stageSelectionChanged 沿用 primary stage —— 這樣的設計是否對齊官方?官方建議的 spectator UX(唯讀標示、跟隨主持視角)有哪些? -列出「官方原則 → 對本專案 3D viewer 的具體要求」對照。標來源 URL。只研究、不改檔案。輸出 markdown。`, - { label: 'F2:kit-primary-spectator', phase: 'Foundations', agentType: 'Explore' } - ), - - // F3 — 設計參考 repo 萃取(Coordinator 控制台) - () => agent( - `唯讀分析任務:萃取設計參考 repo 的「Coordinator 控制台」頁面設計,作為項目4 移植(真實實作)的依據。讀: -${DESIGN}/coordinator/index.html -${DESIGN}/coordinator/console/app.jsx -${DESIGN}/coordinator/console/components.jsx -${DESIGN}/coordinator/console/data.jsx -${DESIGN}/coordinator/console/pages.jsx -${DESIGN}/coordinator/console/pages2.jsx -${DESIGN}/coordinator/console/tweaks-panel.jsx -也看 ${DESIGN}/README.md 了解設計意圖。 -產出: -1) Coordinator 控制台提供哪些頁面/區塊/卡片,各自功能與操作 -2) 視覺風格(色彩、排版、元件樣式、density)與互動模式 -3) 元件清單(可重用的 UI 元件)與資料結構(data.jsx 的 mock 形狀) -4) 哪些是「設計願景但後端要真實實作」的功能 —— 列出對應需要的後端能力 -注意:這是設計原型(mock 資料),目標是在 ${GOV} 真實實作。只讀不改。輸出 markdown。`, - { label: 'F3:design-ref-coordinator', phase: 'Foundations', agentType: 'Explore' } - ), - - // F4a — 現況:viewer 3D 互動與 primary/spectator 程式碼錨點 - () => agent( - `唯讀分析任務:建立「viewer 端 3D 互動 + primary/spectator」的程式碼錨點,供重構規劃使用。讀 ${GOV} 下: -web-viewer-sample/src/Window.tsx -web-viewer-sample/src/USDStage.tsx -web-viewer-sample/src/USDAsset.tsx -web-viewer-sample/src/StreamOnlyWindow.tsx -web-viewer-sample/src/AppStream.tsx -web-viewer-sample/src/clients/streamMessages.ts -web-viewer-sample/src/types/streamMessages.ts -web-viewer-sample/src/console/GovernanceOverlay.tsx -web-viewer-sample/src/console/governance/highlightBridge.ts -web-viewer-sample/src/console/governance/mappingCache.ts -web-viewer-sample/src/console/governance/windowOverlayGlue.ts -重點釐清(給出函式/檔案行號錨點): -1) 左側是否已有 USD prim 樹(USDStage)? 如何 getChildren/展開/選取? 目前選樹節點會不會聚焦相機? -2) DataChannel 指令: focusPrimRequest / selectPrimsRequest / getChildrenRequest / highlightPrimsRequest 的送出與回應流程 -3) primary vs spectator 目前如何判定(streamRole / viewport_sharing)、spectator 哪些操作被 gate -4) GovernanceOverlay 如何疊在 viewer、如何與 Window 溝通(windowOverlayGlue)、stage/artifact binding 目前有沒有 UI -5) 「選 prim path → 相機以該元件為中心」目前缺什麼 -列出可重用的 hook/函式與重構切入點。只讀不改。輸出 markdown。`, - { label: 'F4a:viewer-anchors', phase: 'Foundations', agentType: 'Explore' } - ), - - // F4b — 現況:console + coordinator serving + kit-manager + 轉檔 - () => agent( - `唯讀分析任務:建立「console / coordinator 服務層 / kit-manager / 轉檔」的程式碼錨點,供項目2/4/5 規劃使用。讀 ${GOV} 下: -web-viewer-sample/src/console/OperatorConsole.tsx -web-viewer-sample/src/console/EdgeConsole.tsx -web-viewer-sample/src/console/routing.ts -web-viewer-sample/src/console/pages.tsx -web-viewer-sample/src/console/IntakeSelectPage.tsx -web-viewer-sample/src/console/coordinatorClient.ts -apps/kit-manager-web/src/App.tsx -apps/kit-manager-web/src/components/KitManagerPage.tsx -apps/kit-manager-web/src/api/KitManagerClient.ts -apps/kit-manager-web/src/models.ts -然後用 Grep 在 bim-review-coordinator/src/app.ts 找:mountDevConsole、'/ui'、'/dev-console'、'/ui/open'、'/ui/console'、express.static、kit instance / kit-manager 相關 route、conversion/轉檔 相關 route(ifc-ready、external、conversions)。也看 bim-review-coordinator/src/public/dev-console.html 的功能區塊(不用逐行)。 -重點釐清(給檔案/行號錨點): -1) coordinator 實際服務哪些前端 route:/ui、/ui/open、/ui/console 是否存在? /ui 與 /ui/console 是否真的同頁(驗證使用者說法)? dev-console.html 提供哪些操作? -2) kit-manager-web 對 :8010 的哪些 endpoint? 轉檔(IFC→USDC)由誰觸發、走哪些 endpoint? -3) OperatorConsole 與 EdgeConsole 的關係與路由(/console vs #console)、IntakeSelectPage 現況 -4) 把 kit-manager + 轉檔 + dev-console 合併成單一頁,技術上要動哪些服務邊界(:8010 vs :8004)? -只讀不改。輸出 markdown。`, - { label: 'F4b:console-serving-anchors', phase: 'Foundations', agentType: 'Explore' } - ), -]) - -const FOUND = F.map((x) => x || '(此地基 agent 無輸出)') -const [DESIGN_SKILL, KIT_MODEL, DESIGN_REF, VIEWER_ANCHORS, CONSOLE_ANCHORS] = FOUND -log('Foundations 完成:5 份地基') - -const CONTEXT = ` -================ 地基 A:官方前端設計技能/規範 ================ -${DESIGN_SKILL} - -================ 地基 B:Kit primary/spectator 權威模型 ================ -${KIT_MODEL} - -================ 地基 C:設計參考 repo Coordinator 控制台 ================ -${DESIGN_REF} - -================ 地基 D:viewer 3D 互動程式碼錨點 ================ -${VIEWER_ANCHORS} - -================ 地基 E:console/serving/kit-manager 程式碼錨點 ================ -${CONSOLE_ANCHORS} -` - -// 共同規劃指引(注入每個 planner) -const RULES = ` -共同設計原則(務必貫穿): -- 套用「地基 A 官方前端設計規範」:一致的設計 token、元件狀態鐵律、a11y、動效節制。 -- primary/spectator 對齊「地基 B」官方模型:primary=會議主持可操作;spectator 唯讀只看結果,按鈕 disabled 並誠實標示(aria-disabled,非僅 pointer-events)。 -- 沿用本專案「誠實鐵律」:AS-BUILT/ARTIFACT/DEMO 標示、p1/p3/p4 disabled 不做假按鈕、無遙測標「未取得」不捏造。 -- 服務邊界:瀏覽器唯一可達面=coordinator :8004;不直連 :49101/:49102/:8010(kit-manager 例外但本次要合併,需經 coordinator proxy 化考量)。 -- 操作連貫性、風格一致、使用者友善:相同的「操作/觀測」語彙跨 A1/A2/A3。 -- 唯讀規劃:不要寫程式碼檔,只產出規劃(可含 TS/JSX 片段示意與檔案路徑、元件樹、狀態圖、API 草案、驗收條件、風險)。 -輸出格式:markdown,含「目標 / 現況落差 / 設計方案(IA+元件+互動+權限) / 觸及檔案與新增檔 / 後端/API 需求 / 驗收條件 / 風險與相依」。` - -// ---------- Phase 2: per-item planning ---------- -phase('PlanItems') - -const ITEMS = [ - { - label: 'P1:item1-3d-viewer', - title: '項目1 — 3D viewer 樹狀→prim 聚焦 + A1/A2/A3 操作觀測統一 + primary/spectator', - body: `規劃項目1: -- A1:左側欄樹狀呈現 IFC/BIM 語意(USD prim path 結構)。使用者點選某個 "usd prim path" → 3D viewer 相機切換到「以該元件為中心」顯示(focus/frame)。 -- A2、A3 採用相同的「邏輯/操作/觀測」三原則設計與重構(統一互動語彙、共用元件)。 -- primary 當會議主持有操作權限;spectator 只觀看結果(對齊 Kit 官方)。 -要點:以地基 D 的 USDStage/Window DataChannel(focusPrimRequest/selectPrimsRequest/getChildrenRequest)錨點為基礎,設計:樹元件、選取↔相機聚焦↔3D 選取的雙向同步、A1/A2/A3 共用的 viewer 互動抽象層(hook/component)、primary/spectator gating。給元件樹、狀態流、DataChannel 訊息對映、驗收條件。`, - }, - { - label: 'P2:item2-operator-console', - title: '項目2 — OperatorConsole (/console, #console/...) 依項目1 調整', - body: `規劃項目2:依項目1 的「樹狀→聚焦 + 操作/觀測 + primary/spectator」結果,調整 OperatorConsole 與 console 路由。 -釐清:OperatorConsole 與 viewer 目前互斥掛載(console 無 DataChannel) → 項目1 的 3D 互動要如何在 console 場景呈現(嵌入 viewer? 仍 disabled 標 p1? 還是 console 改為能開 primary/spectator viewer)? 路由(/console vs #console)如何配合。給出 IA 調整、頁面職責重劃、與項目1 元件的共用關係。`, - }, - { - label: 'P3:item3-stage-binding', - title: '項目3 — Stage/Artifact Binding overlay(主入口) + /console/intake(前置入口)', - body: `規劃項目3,兩個入口: -3.1 Primary viewer overlay 新增「Stage / Artifact Binding」區(在現有右側治理面板):選 1~N 個 ready USDC artifacts、指定 primary、調 load_order、套用、重載 stage。primary 可改、spectator disabled。這是 live review 中途動態綁定的主入口。 -3.2 /console/intake 擴充:現為從 /api/external/ifc-ready 選可審查模型;擴充成「建立新 review session 時選多個 artifact」。定位為進件/開場入口(非 live 中途切換)。 -給:overlay 元件設計、與 stage 重載(DataChannel openStageRequest / coordinator stream-config)的串接、artifact 多選/排序 UI、primary/spectator 權限、兩入口的職責分工與資料一致性、後端 binding API 需求、驗收條件。`, - }, - { - label: 'P4:item4-merge-page', - title: '項目4 — 合併 kit-manager-web + /ui 轉檔 成單一前端頁,並移植設計參考的 Coordinator 控制台(真實實作)', - body: `規劃項目4:把 apps/kit-manager-web 與 coordinator /ui(dev-console 的轉檔/IFC-ready/handoff 功能)合併成「一個」前端頁,並擴充移植地基 C 的「Coordinator 控制台」設計(全部要真實實作、非 mock)。 -釐清:服務邊界整併(kit-manager :8010 的 kit open/close 與 coordinator :8004 的轉檔/session) —— 合併頁如何同時操作兩個服務(是否把 :8010 經 coordinator proxy 化以維持「瀏覽器唯一可達面」原則)? 把地基 C 的哪些卡片/區塊落地、各需要哪些真實後端 endpoint。給:合併後頁面 IA、元件清單(對映地基 C)、API 對照(現有 vs 需新增)、資料流、風險、驗收條件。`, - }, - { - label: 'P5:item5-remove-ui-console', - title: '項目5 — 統一 /ui 與 /ui/console,項目4 完成後移除 /ui/console', - body: `規劃項目5:依地基 E 先確認 /8004/ui 與 /8004/ui/console 是否真為同頁同功能(若不是,據實修正前提)。規劃在項目4 合併頁完成後,安全移除 /ui/console:路由收斂、redirect(舊 URL→新頁)以免斷連、移除順序與回歸驗證、對既有 handoff(/ui/open) 的影響。給移除清單、相容性處理(301/302 或保留 alias 一段時間)、驗收條件、風險。`, - }, -] - -const PLANS = await parallel( - ITEMS.map((it) => () => - agent( - `你是資深前端架構師(熟 React/TS、3D viewer、Omniverse Kit 串流)。基於以下「地基」與「共同設計原則」,產出${it.title}的詳細設計規劃。\n${RULES}\n\n${it.body}\n\n${CONTEXT}`, - { label: it.label, phase: 'PlanItems' } - ) - ) -) -const validPlans = PLANS.map((p, i) => ({ item: ITEMS[i].title, plan: p || '(無輸出)' })) -log(`PlanItems 完成:${validPlans.filter((p) => p.plan !== '(無輸出)').length}/${ITEMS.length}`) - -// ---------- Phase 3: synthesis ---------- -phase('Synthesize') - -const FINAL = await agent( - `你是首席前端設計師暨技術主管。下面是(1)研究地基(官方設計技能 + Kit primary/spectator + 設計參考 + 程式碼錨點),(2)5 個項目的個別規劃。 -請整併成**一份連貫、可執行的前端設計與重構總規劃**(繁體中文台灣用語、markdown),要求: - -1. **統一設計系統**:根據地基 A 提煉本專案要採用的設計 token(色彩/字級/間距/狀態/density)、核心可重用元件清單(樹、面板、overlay、卡片、按鈕狀態、primary/spectator 徽章與唯讀降級樣式)。這是 5 個項目共用的基礎,先定義一次。 -2. **資訊架構(IA)總圖**:整併後的路由/頁面地圖(viewer / console / 合併後的 Coordinator 控制台),標出哪些保留、調整、新增、移除(含項目5 的 /ui/console 移除)。 -3. **5 個項目的整合計畫**:每項濃縮成 目標 / 設計方案 / 觸及與新增檔案 / 後端 API 需求 / 驗收條件;並標出**跨項目相依**(例如項目2 依項目1、項目5 依項目4)。 -4. **primary/spectator 一致性章節**:跨 A1/A2/A3/overlay/console 的權限與唯讀降級規則(對齊 Kit 官方),集中定義一次。 -5. **分期落地路線(Phase 1..N)**:依相依關係排序,每期可獨立驗證(含 browser E2E evidence 的期望),標示風險與 OpenSpec change 切分建議。 -6. **風險與未決問題**:服務邊界(:8010 proxy 化)、console 無 DataChannel、誠實降級、效能、相容性(舊 URL handoff)等。 -7. **UX 一致性檢查表**:操作連貫性與使用者友善的具體驗收點。 - -避免重複堆疊各 planner 原文;要消化、去衝突、給單一權威方案。若 planner 之間有矛盾,明確裁決並說明理由。輸出純 markdown。 - -================ 研究地基 ================ -${CONTEXT} - -================ 5 項個別規劃 ================ -${validPlans.map((p) => `\n#### ${p.item}\n${p.plan}`).join('\n')}`, - { label: 'synthesize:master-plan', phase: 'Synthesize' } -) - -return FINAL diff --git a/.claude/workflows/fe-redesign-alignment-audit.js b/.claude/workflows/fe-redesign-alignment-audit.js deleted file mode 100644 index a081d4ad2..000000000 --- a/.claude/workflows/fe-redesign-alignment-audit.js +++ /dev/null @@ -1,120 +0,0 @@ -export const meta = { - name: 'fe-redesign-alignment-audit', - description: '前端設計重構:以 582273a baseline 程式碼比對 frontend-redesign-ia-and-phases.html 六維度,對抗驗證後回結構化 差異/疑慮/矛盾', - phases: [ - { title: 'Audit', detail: '6 維度各一 auditor 讀碼比對設計文件' }, - { title: 'Verify', detail: '對抗驗證每維度的矛盾/疑慮/高風險差異' }, - ], -} - -const BASE = [ - '稽核基準:repo C:/Repos/active/iot/AI-BIM-governance,git main 已 fast-forward 到整合 baseline 582273a(= codex/runtime-orchestrator-phase-1 rebase 保 #187)。', - '前端在 web-viewer-sample/src/ 與 web-viewer-sample/src/console/;coordinator 後端在 bim-review-coordinator/(用 Grep/Glob 找)。設計文件全文在 frontend-redesign-ia-and-phases.html(可 Read 取脈絡)。', - '這是「靜態程式碼 vs 設計文件」稽核;可操作性/瀏覽器證據另由主流程用 gstack 收集,你聚焦:程式碼是否存在、設計 token 是否一致、結構是否對齊。', - '重要分類規則:設計文件是 2026-06-05 的「目標態藍圖」,內含明確未來項(★新增、A4–A10 disabled、CH-G URL 收斂未做)。', - ' - 文件標為未來、現未實作 → gaps 但 severity=planned。', - ' - 文件說「現況該有 / 已 asbuilt」但程式碼沒有或相反 → gaps(low/medium/high/critical)。', - ' - 文件自身或與既有鐵律(誠實降級、coordinator :8004 唯一可達面、前端不直連 _bim-control)互相打架 → contradictions。', - ' - 看不準、需執行期才能確認 → concerns。', - '每個發現附 file:line 證據。只輸出結構化資料,不要客套話。' -].join('\n') - -const FINDINGS_SCHEMA = { - type: 'object', additionalProperties: false, - properties: { - dimension: { type: 'string' }, - aligned: { type: 'array', items: { type:'object', additionalProperties:false, properties:{ item:{type:'string'}, evidence:{type:'string'} }, required:['item','evidence'] } }, - gaps: { type:'array', items:{ type:'object', additionalProperties:false, properties:{ item:{type:'string'}, doc_says:{type:'string'}, code_is:{type:'string'}, severity:{type:'string', enum:['planned','low','medium','high','critical']}, evidence:{type:'string'} }, required:['item','doc_says','code_is','severity','evidence'] } }, - concerns: { type:'array', items:{ type:'object', additionalProperties:false, properties:{ item:{type:'string'}, why:{type:'string'}, evidence:{type:'string'} }, required:['item','why','evidence'] } }, - contradictions: { type:'array', items:{ type:'object', additionalProperties:false, properties:{ item:{type:'string'}, doc_says:{type:'string'}, conflicts_with:{type:'string'}, evidence:{type:'string'} }, required:['item','doc_says','conflicts_with','evidence'] } }, - }, - required: ['dimension','aligned','gaps','concerns','contradictions'], -} - -const VERIFY_SCHEMA = { - type:'object', additionalProperties:false, - properties:{ dimension:{type:'string'}, verdicts:{ type:'array', items:{ type:'object', additionalProperties:false, properties:{ claim:{type:'string'}, kind:{type:'string', enum:['gap','concern','contradiction']}, verdict:{type:'string', enum:['confirmed','refuted','uncertain']}, note:{type:'string'} }, required:['claim','kind','verdict','note'] } } }, - required:['dimension','verdicts'], -} - -const DIMENSIONS = [ - { key:'ia', title:'IA / 可達面 / 路由', - spec:[ - '瀏覽器唯一可達面 = coordinator :8004。:8004/ui = UnifiedConsole(正規 console 入口,合併後・項目4/5)。', - 'Plane GOVERNANCE PLATFORM(零 GPU)路由:#/coordinator(控制台 移植・真實)、#/intake(Model Intake + 開模 + Binding)、#/runtime(Kit 綁定/串流觀測)、#/review(失敗構件派工 handoff)、#/kit(Kit 模型台,經 /api/kit proxy)。', - 'Plane GOVERNANCE A1–A10 路由:#/overview、#/issues、#/apps …;Review Room → primary viewer overlay 深連結。', - ':8004/ui/open?session=… = handoff 302 → viewer(逐字節凍結・CI guard)。', - 'coordinator 後端:coordinator REST(session/intake/runtime)、governanceProxy(A1–A3 → :49102)、kitProxy ★新增(/api/kit/* → :8010)。', - 'internal/loopback(瀏覽器不可達):governance-service :49102、kit-manager :8010→loopback(前端退役)、streaming-server(Signaling :1280、Media :1281)。' - ].join('\n'), - files:'web-viewer-sample/src/console/routing.ts、pages.tsx、main.tsx;coordinator 路由與 proxy:bim-review-coordinator/ 內 Grep "/api/kit"、"governanceProxy"、"/ui/open"、"302"、":49102"、":8010";compose.runtime-manager.yml、compose.host-kit.yml' }, - - { key:'tokens', title:'設計風格 / design tokens', - spec:[ - '設計尺規 = Anthropic 前端原則 + NVIDIA Kit primary/spectator。字型 JetBrains Mono + Noto Sans TC, monospace。', - 'body 背景 #020617、文字白。語意色:cyan #22d3ee(前端)、emerald #34d399(coordinator 後端)、amber #fbbf24(Kit/proxy)、violet #a78bfa(治理權威/DB)、rose #fb7185(handoff/critical)。NVIDIA green #76b900(強調/分期標)。', - 'card:背景 rgba(15,23,42,0.5)、border #1e293b、圓角;grid 背景線 #1e293b。' - ].join('\n'), - files:'web-viewer-sample/src/console/edge-console.css、components.tsx;web-viewer-sample/src/ 其他 *.css;比對上述 CSS 變數/顏色/字型是否一致、有無散落硬編碼或偏離 token' }, - - { key:'viewer', title:'viewer 元件結構(USDStage / ViewportLayer / GovernanceOverlay / BindingComposer)', - spec:[ - 'viewer 經 /ui/open 進場、WebRTC 連 streaming-server。', - ' 左側 USD 樹(項目1):點 prim path → 相機以該元件聚焦;viewport 點選 → 回灌樹 + 展開祖先;useViewerInteraction(A1/A2/A3 共用)。', - ' 16:10 WebRTC:primary 操作・spectator 唯讀跟隨;DataChannel: open/focus/select/highlight。', - ' 右側治理疊層: + (項目1,rule-run/issue/BCF); ★主入口(選 N 個 USDC・指定 primary・重載 stage,項目3);spectator → 全 aria-disabled + 誠實 banner。' - ].join('\n'), - files:'web-viewer-sample/src/ 的 App 進場與 viewer 元件;Grep USDStage、ViewportLayer、BindingComposer、OperationBar、ObservationPanel、useViewerInteraction;web-viewer-sample/src/console/GovernanceOverlay.tsx、console/viewer/' }, - - { key:'ps', title:'primary/spectator 一致性 + 誠實降級', - spec:[ - '單一判定來源:viewer 走 resolveGovPanelState,console 走 operatorOpsState。', - '三層縱深:UI disabled → send no-op → 後端 source_client_id(權威)。', - 'spectator 不隱藏按鈕:aria-disabled + 理由 banner(誠實鐵律)。', - '前端 gate 僅 UX,非授權邊界(文件須明示)。' - ].join('\n'), - files:'Grep resolveGovPanelState、operatorOpsState、source_client_id、aria-disabled、spectator、banner(web-viewer-sample/ 全域 + bim-review-coordinator/ 後端 source_client_id 驗證)' }, - - { key:'phases', title:'分期 CH-A→CH-G + 三條紅線 + 關鍵裁決', - spec:[ - '依賴鏈:CH-A(P0 設計token+共用元件骨架,低風險純前端) → CH-B(P1 viewer樹→聚焦,A1操作/觀測+gate,高風險改 Window.tsx) →(CH-C P1.5並行 streaming角色權威 source_client_id 驗證,跨sub-repo)→ CH-D(P2 kit /api/kit/* reverse-proxy,邊界風險先行PR) → CH-E(P3 console handoff+合併頁項2+4,高風險 bootstrap) → CH-F(P4 Binding主入口 overlay+intake,高風險雙寫一致) → CH-G(P5 URL收斂 移除舊別名,CRITICAL)。', - '項目→change:項目1→CH-B、項目2→CH-E、項目3→CH-F、項目4→CH-D+CH-E、項目5→CH-G;每期 done = browser E2E evidence。', - '三條紅線:RK6 CRITICAL(CH-G redirect 必精確列舉,禁 /ui/* 萬用 會吃掉 /ui/open + CI guard);RK5 HIGH(P1/P3/P4 都改 Window.tsx,動前 MUST gitnexus_impact,邏輯抽 hook);RK1 HIGH(kitProxy 只 forward,Kit 控制權威留 kit-manager)。', - '關鍵裁決:/ui/console 不存在 → 301 安全網收斂到 /ui;console 不長 WebRTC,3D 操作一律 handoff 跳 primary viewer;:8010 經 /api/kit/* proxy 化、改 loopback、前端退役;A1 先落地抽象,A2/A3 接同一 hook 列後續 change。' - ].join('\n'), - files:'Grep "/api/kit"、"/ui/console"、"301"、"/ui/*"、wildcard、Window.tsx、kitProxy、kit-manager;openspec/changes/ 下相關 change 與 specs/roadmap;git log --oneline -30;判斷 CH-A~CH-G 哪些已落地(582273a baseline)' }, - - { key:'a1a10', title:'A1–A10(A1–A3 asbuilt / A4–A10 disabled)', - spec:[ - 'Plane 2:A1–A3 asbuilt(真實資料、可操作),A4–A10 願景(disabled)。', - 'routing 認得 a1..a10;Review Room → primary viewer overlay 深連結。' - ].join('\n'), - files:'web-viewer-sample/src/console/routing.ts、pages.tsx、data.ts;Grep a1..a10 路由與渲染、A1/A2/A3 真實資料來源(governanceProxy/:49102)、A4–A10 disabled/vision 標記' }, -] - -const results = await pipeline( - DIMENSIONS, - d => agent( - BASE + '\n\n# 稽核維度:' + d.title + - '\n\n## 設計文件規格(節錄自 frontend-redesign-ia-and-phases.html)\n' + d.spec + - '\n\n## 應檢視的程式碼\n' + d.files + - '\n\n逐項比對規格與實際程式碼,輸出 aligned / gaps / concerns / contradictions(每項附 file:line 證據)。', - { label:'audit:'+d.key, phase:'Audit', schema: FINDINGS_SCHEMA } - ), - (audit, d) => { - const flags = [ - ...(audit.contradictions||[]).map(c => ({ kind:'contradiction', claim: c.item+' — 文件:'+c.doc_says+' ↔ 衝突:'+c.conflicts_with, evidence:c.evidence })), - ...(audit.concerns||[]).map(c => ({ kind:'concern', claim: c.item+' — '+c.why, evidence:c.evidence })), - ...(audit.gaps||[]).filter(g => g.severity==='high' || g.severity==='critical').map(g => ({ kind:'gap', claim: g.item+' — 文件:'+g.doc_says+' / 程式:'+g.code_is, evidence:g.evidence })), - ] - if (!flags.length) return { audit, verify: { dimension: d.title, verdicts: [] } } - return agent( - BASE + '\n\n# 對抗驗證:維度 ' + d.title + - '\n\n下列是 auditor 提出的矛盾/疑慮/高風險差異。逐項回到證據(file:line)親自查證,預設懷疑、試圖反駁。只有親讀證據確認屬實才標 confirmed;查無據/誤判標 refuted;無法確定標 uncertain,note 寫關鍵理由。\n\n待驗清單:\n' + - flags.map((f,i) => (i+1)+'. ['+f.kind+'] '+f.claim+'\n 證據:'+f.evidence).join('\n'), - { label:'verify:'+d.key, phase:'Verify', schema: VERIFY_SCHEMA } - ).then(v => ({ audit, verify: v })) - } -) - -return results \ No newline at end of file diff --git a/.claude/workflows/fu1-adversarial-verify.js b/.claude/workflows/fu1-adversarial-verify.js deleted file mode 100644 index 0281714d7..000000000 --- a/.claude/workflows/fu1-adversarial-verify.js +++ /dev/null @@ -1,89 +0,0 @@ -export const meta = { - name: 'fu1-adversarial-verify', - description: 'FU-1 修復對抗複驗:7 個 per-finding 懷疑者(refute-by-default)+ 1 整體誠實/regression critic', - phases: [{ title: 'Verify', detail: '每 finding 一懷疑者讀真 code 驗閉合 + 1 holistic critic' }], -} - -const ROOT = 'C:/Repos/active/iot/AI-BIM-governance/.worktrees/a1-rule-engine-honesty' - -const VERDICT_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['finding_id', 'truly_closed', 'introduced_new_issue', 'reason'], - properties: { - finding_id: { type: 'string' }, - truly_closed: { type: 'boolean' }, - introduced_new_issue: { type: 'boolean' }, - reason: { type: 'string' }, - }, -} - -const CRITIC_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['overall_safe', 'issues'], - properties: { - overall_safe: { type: 'boolean' }, - issues: { - type: 'array', - items: { - type: 'object', additionalProperties: false, - required: ['kind', 'file', 'detail'], - properties: { - kind: { type: 'string', enum: ['new-honesty', 'regression', 'spec-drift', 'other'] }, - file: { type: 'string' }, - detail: { type: 'string' }, - }, - }, - }, - }, -} - -const PRE = `你是 AI-BIM-governance A1 governance-service 的對抗式驗證者。worktree(已套用修復):${ROOT}。 -這是 BIM 治理平台 A1 rule-run(host py312、純 CPU ifcopenshell;誠實鐵律:無假數字、error/未取得不得偽裝成 pass)。 -用 Read/Grep 打開 ${ROOT}/governance-service/rule_engine/ 與 tests/ 的真實程式碼驗證。預設立場:修復「未真正閉合」,除非你在 code 找到確鑿證據證明已閉合。 -教訓:「測試綠」不代表問題消失——對著該 finding 宣稱的失效模式驗 fix 是否真閉合,並檢查是否引入新的誠實/正確性問題。` - -const FINDINGS = [ - { id: 'A1-RE-01', q: `engine.py run_rules 計分:分母原為 passed+failed(排除 errored),全 error 時 denom=0 → score=100 假滿分。驗:(a) 現在分母是否含 errored(全 error → score 0.0);(b) errored==0 時是否與舊式等價(真實模型 99.0 不變);(c) denom==0 僅在「無任何適用構件」時 → 100.0 是否合理。讀 engine.py 第 99-110 行附近。` }, - { id: 'A1-RE-04', q: `predicates.py eval_property_required:get_psets 注入合成 'id' key,property:id 規則會假性通過。驗:any-pset 與指定-pset 兩分支是否都排除合成 key(_SYNTHETIC_PSET_KEYS);指定-pset 時 pset_found 行為是否仍誠實。確認 property:id 不再假性 pass。` }, - { id: 'ids-001', q: `ids_runner.py run_ids:原以 spec.name 為 target_summary key,同名/未命名 spec 互相覆寫低報。驗:_spec_code 是否產生唯一 key(identifier 否則 name+index);同名兩 spec 是否得到兩個不同 key、計數不被覆寫。` }, - { id: 'ids-002', q: `ids_runner.py:prohibited applicability(spec.status False、零 requirement)原靜默丟棄 → 違規模型假 pass。驗:guard 是否在「無 result 產生 + spec.status is False + applicable 非空」時補逐構件 fail;guard 是否過度觸發(誤傷正常 spec)。誠實評估可達性。` }, - { id: 'ids-003', q: `ids_runner.py:errored 原硬寫 0。驗:errored 是否改為由結果推導 sum(status=='error'),且 IDS 計分分母與 YAML 一致。` }, - { id: 'A1-RE-03', q: `誠實文件:excel_export.py / engine.py docstring 與 default-governance.yaml description 原宣稱「BCF 未實作 / ifctester 未安裝 / IDS 為 p1」。驗:grep rule_engine/ 與 rules/ 是否仍殘留任何「未實作 / 未安裝 / p1 / p15 / 標後續」這類與已落地 bcf/、ids_runner、governance-service/CLAUDE.md 矛盾的過時敘述。` }, - { id: 'A1-RE-02', q: `test_rule_engine.py test_ifc4x3_type_alias_resolves_and_warns:驗測試是否真的建 IFC4X3 model + target IfcBuildingElement、真的走別名萃取到 IfcWall、斷言 warning 含「別名」「IfcBuiltElement」。確認是真迴歸守門而非空測試。` }, -] - -phase('Verify') -log(`FU-1:${FINDINGS.length} 個 per-finding 懷疑者 + 1 holistic critic`) - -const verdicts = await parallel([ - ...FINDINGS.map((f) => () => - agent(`${PRE} - -待驗 finding ${f.id}: -${f.q} - -回傳 StructuredOutput:finding_id=${f.id}、truly_closed(僅當你在 code 親見已真正閉合才 true)、introduced_new_issue(修復是否引入新誠實/正確性問題)、reason(引用你讀到的真實 code 片段與行號)。`, - { label: `verify:${f.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }) - ), - () => agent(`${PRE} - -任務(holistic critic):通讀本次 FU-1 全部 diff(${ROOT}/governance-service/rule_engine/{engine,predicates,ids_runner,excel_export}.py、rules/default-governance.yaml、tests/{test_rule_engine,test_ids}.py)。 -跑 \`git -C ${ROOT} diff HEAD\` 或直接讀檔。找:本次修改是否引入(a)新的誠實違規(假數字/把未取得當 pass)、(b)行為 regression(改壞既有 YAML/IDS 正常路徑)、(c)spec-drift(spec delta 與實作不符)。 -特別檢查:score 公式改動是否意外改變真實模型既有 99.0;prohibited guard 是否誤傷正常 IDS;_spec_code 索引後綴是否破壞既有 IDS 分類。 -回傳 StructuredOutput:overall_safe、issues[](每筆 kind/file/detail)。寧可多報疑慮。`, - { label: 'critic:holistic', phase: 'Verify', schema: CRITIC_SCHEMA }), -]) - -const fv = verdicts.slice(0, FINDINGS.length).filter(Boolean) -const critic = verdicts[FINDINGS.length] -const notClosed = fv.filter((v) => !v.truly_closed) -const newIssues = fv.filter((v) => v.introduced_new_issue) - -log(`閉合 ${fv.filter((v) => v.truly_closed).length}/${fv.length};未閉合 ${notClosed.length};報新問題 ${newIssues.length};critic overall_safe=${critic ? critic.overall_safe : 'null'}`) - -return { - verdicts: fv, - not_closed: notClosed, - new_issues: newIssues, - critic: critic || null, -} diff --git a/.claude/workflows/fu2-adversarial-verify.js b/.claude/workflows/fu2-adversarial-verify.js deleted file mode 100644 index d169db9bd..000000000 --- a/.claude/workflows/fu2-adversarial-verify.js +++ /dev/null @@ -1,75 +0,0 @@ -export const meta = { - name: 'fu2-adversarial-verify', - description: 'FU-2(Issues-DB + BCF)修復對抗複驗:7 per-finding 懷疑者(refute-by-default)+ 1 交易/誠實 critic', - phases: [{ title: 'Verify', detail: 'refute-by-default 讀真 code 驗閉合 + 交易正確性 critic' }], -} - -const ROOT = 'C:/Repos/active/iot/AI-BIM-governance/.worktrees/issue-bcf-integrity' - -const VERDICT_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['finding_id', 'truly_closed', 'introduced_new_issue', 'reason'], - properties: { - finding_id: { type: 'string' }, - truly_closed: { type: 'boolean' }, - introduced_new_issue: { type: 'boolean' }, - reason: { type: 'string' }, - }, -} -const CRITIC_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['overall_safe', 'issues'], - properties: { - overall_safe: { type: 'boolean' }, - issues: { type: 'array', items: { - type: 'object', additionalProperties: false, - required: ['kind', 'file', 'detail'], - properties: { kind: { type: 'string' }, file: { type: 'string' }, detail: { type: 'string' } }, - } }, - }, -} - -const PRE = `你是 AI-BIM-governance governance-service 的對抗式驗證者。worktree(已套用 FU-2 修復):${ROOT}。 -範圍:Issues-DB(issues/store.py, issues/api.py)+ BCF 匯出(bcf/bcf_writer.py)。誠實鐵律:model_version_id 綁定所有 issue;缺值不得以 Python None 字面外洩;BCF 2.1 schema 合規。 -用 Read/Grep 打開真實程式碼驗證;可用 host py312 跑 probe:「/c/Program Files/Python312/python.exe」。預設立場:修復未真正閉合,除非你在 code 找到確鑿證據。「測試綠」不代表閉合——對著 finding 宣稱的失效模式驗。` - -const FINDINGS = [ - { id: 'ISS-001', q: `issues/api.py issues_from_diff 原未傳 model_version_id(diff issue mv=NULL,違反「所有 issue 綁 model_version」鐵律,且斷裂 BCF 匯出過濾與 diff-impact)。驗:現在是否讀 diff_row 的 target_model_version_id 並傳入;DiffStore.get_diff 是否真有該欄位(讀 diff_engine/store.py schema)。` }, - { id: 'ISS-002', q: `issues/api.py from-rule-run / from-diff 原無冪等,重複呼叫產生重複 issue。驗:是否改用 create_issues_batch 且該方法對同 (source_type, source_ref) 跳過(讀 store.py);重複呼叫第二次 created==0/skipped>0。` }, - { id: 'ISS-003', q: `issues/store.py transition 原讀-改-寫跨兩連線(TOCTOU race / lost update)。驗:是否改為單一連線 BEGIN IMMEDIATE + 條件式 UPDATE WHERE id=? AND status=? + rowcount==0 偵測並發落空 raise。檢查 isolation_level/busy_timeout 設定是否正確、ROLLBACK 路徑是否完整、有無連線洩漏(finally close)。` }, - { id: 'ISS-004', q: `issues/api.py 批次建立原每筆獨立交易、中途失敗留部分寫入。驗:create_issues_batch 是否單一連線 BEGIN IMMEDIATE...COMMIT、except ROLLBACK 整批回滾;endpoint 是否改用它。` }, - { id: 'bcf-002', q: `bcf/bcf_writer.py build_bcfzip 原未驗 IfcGuid 22 字元,可產出違反 BCF 2.1 XSD 的 .bcfzip。驗:是否以 ^[0-9A-Za-z_$]{22}$ 過濾非法 guid(跳過不匯出);既有 22 字元測試 fixtures 是否仍通過。` }, - { id: 'bcf-003', q: `bcf/bcf_writer.py _iso 對 naive 時間戳用 astimezone 會吃系統本地偏移。驗:是否改為 tzinfo is None 時 replace(tzinfo=utc);用 probe 驗 _iso("2026-06-01T10:00:00") == "2026-06-01T10:00:00Z"。` }, - { id: 'bcf-005', q: `bcf/bcf_writer.py 原把 Python None 以字面 'None' 寫進 BCF comment。驗:缺值是否改輸出 'unbound'(或省略),不得出現字面 model_version=None;值有設時是否仍原樣(既有 model_version=mvB 測試相容)。` }, -] - -phase('Verify') -log(`FU-2:${FINDINGS.length} per-finding 懷疑者 + 1 critic`) - -const verdicts = await parallel([ - ...FINDINGS.map((f) => () => - agent(`${PRE} - -待驗 finding ${f.id}: -${f.q} - -回傳 StructuredOutput:finding_id=${f.id}、truly_closed(僅當 code 親見真閉合)、introduced_new_issue、reason(引用真實 code 片段 + 行號;可附 probe 結果)。`, - { label: `verify:${f.id}`, phase: 'Verify', schema: VERDICT_SCHEMA }) - ), - () => agent(`${PRE} - -任務(critic):通讀 FU-2 全 diff(issues/store.py, issues/api.py, bcf/bcf_writer.py, tests/test_issues.py, tests/test_bcf.py)。重點: -1. 交易正確性:transition 與 create_issues_batch 的 BEGIN IMMEDIATE / isolation_level=None / busy_timeout / COMMIT / ROLLBACK / conn.close 是否正確,有無在例外路徑漏 close 或留未結束交易;get_issue(另開連線)在 COMMIT 後呼叫是否安全。 -2. 既有行為相容:model_version 綁定是否破壞既有 test_issues_from_diff(mv 應為 'b'/'t'?讀 _seed_diff);create_issues_batch 是否正確處理 annotation(無 ifc_guid → kind=annotation);既有 transition 生命週期測試(created+3 transition=4 events)是否仍成立。 -3. 誠實:BCF 缺值是否真不洩漏 None;IfcGuid 過濾是否誠實(跳過而非捏造)。 -4. 新測試是否真守門(非空斷言)。 -回傳 StructuredOutput:overall_safe、issues[](kind/file/detail)。寧可多報疑慮。`, - { label: 'critic:fu2', phase: 'Verify', schema: CRITIC_SCHEMA }), -]) - -const fv = verdicts.slice(0, FINDINGS.length).filter(Boolean) -const critic = verdicts[FINDINGS.length] -const notClosed = fv.filter((v) => !v.truly_closed) -const newIssues = fv.filter((v) => v.introduced_new_issue) -log(`閉合 ${fv.filter((v) => v.truly_closed).length}/${fv.length};未閉合 ${notClosed.length};新問題 ${newIssues.length};critic safe=${critic ? critic.overall_safe : 'null'}`) -return { verdicts: fv, not_closed: notClosed, new_issues: newIssues, critic: critic || null } diff --git a/.claude/workflows/fu34-adversarial-verify.js b/.claude/workflows/fu34-adversarial-verify.js deleted file mode 100644 index 05f941077..000000000 --- a/.claude/workflows/fu34-adversarial-verify.js +++ /dev/null @@ -1,65 +0,0 @@ -export const meta = { - name: 'fu34-adversarial-verify', - description: 'FU-3 + FU-4 自包含對抗複驗:per-finding 懷疑者(refute-by-default)+ 每 FU 一 critic', - phases: [{ title: 'Verify', detail: 'FU-3 diff Tag + FU-4 federation TRS,refute-by-default' }], -} - -const FU3 = 'C:/Repos/active/iot/AI-BIM-governance/.worktrees/a2-diff-tag-typeguard' -const FU4 = 'C:/Repos/active/iot/AI-BIM-governance/.worktrees/a3-federation-trs-coords' - -const VS = { - type: 'object', additionalProperties: false, - required: ['finding_id', 'truly_closed', 'introduced_new_issue', 'reason'], - properties: { finding_id: { type: 'string' }, truly_closed: { type: 'boolean' }, introduced_new_issue: { type: 'boolean' }, reason: { type: 'string' } }, -} -const CS = { - type: 'object', additionalProperties: false, - required: ['overall_safe', 'issues'], - properties: { overall_safe: { type: 'boolean' }, issues: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['kind', 'file', 'detail'], properties: { kind: { type: 'string' }, file: { type: 'string' }, detail: { type: 'string' } } } } }, -} - -function pre(root) { - return `你是 AI-BIM-governance governance-service 的對抗式驗證者。worktree(已套用修復、未 commit):${root}。 -誠實鐵律:無假數字、未取得不得偽裝成 pass。USD 相關以 pxr 26.5 本體為 ground truth(可用 host py312 「/c/Program Files/Python312/python.exe」跑真 pxr probe)。 -**務必只讀 ${root} 內的檔案**(這是已修復的 worktree,不要去看 main 或別的 worktree)。用 Read/Grep 開真實 code 驗。預設立場:未真閉合,除非親見確鑿證據。對著 finding 宣稱的失效模式驗,「測試綠」不等於閉合。` -} - -const FINDINGS = [ - { root: FU3, fu: 'FU3', id: 'A2-001', q: `diff_engine/engine.py 第二級 Tag 對齊。驗:Tag map 是否以複合鍵 (e.is_a(), tag) 帶型別護欄(讀 _tagmap);用真 ifcopenshell probe:base IfcWall(Tag=999) + target IfcSlab(Tag=999, 不同 GlobalId) 是否正確得 removed+added(非 matched=1 吞變更)。` }, - { root: FU3, fu: 'FU3', id: 'A2-003', q: `diff_engine/engine.py 第三級同鍵簇 zip 配對。驗:配對前是否以穩定次鍵排序兩側;同鍵多構件 pset 不同時 property_changed 歸屬穩定可重現。` }, - { root: FU3, fu: 'FU3', id: 'A2-002', q: `tests/test_diff_engine.py 退階對齊測試。驗:是否真覆蓋 (a) 同型別同 Tag→tag 對齊 (b) type+name+loc 對齊 (c) 跨型別同 Tag→removed+added,非空實質斷言。` }, - { root: FU3, fu: 'FU3', id: 'A2-honesty', q: `grep diff_engine/ 是否仍殘留與已落地 geometry_changed(opt-in #162)矛盾的「p1 / MVP 不計算 / 未實作」過時敘述;仍正確的標示(issue-impact / 3D overlay p15)未被誤改。` }, - { root: FU4, fu: 'FU4', id: 'A3-1', q: `federation/builder.py per-member transform xformOp 順序。驗:是否 AddTranslateOp→AddRotateXYZOp→AddScaleOp(xformOpOrder=[translate,rotateXYZ,scale])。**用真實 pxr 開合成 stage 算世界座標**:scale=2+translate=(100,0,0) 下 local 原點↦世界(100,0,0)、(1,0,0)↦(102,0,0)。註解是否同步改正。` }, - { root: FU4, fu: 'FU4', id: 'A3-2', q: `tests/test_federation_builder.py 是否改用真實 pxr GetLocalTransformation().Transform() 數值世界座標斷言(非順序字面),且舊錯誤碼下會變紅。` }, - { root: FU4, fu: 'FU4', id: 'A3-3', q: `federation/builder.py build 是否依 member metersPerUnit 呼叫 UsdGeom.SetStageMetersPerUnit、回傳 dict 含 meters_per_unit;pxr probe:傳 0.001→stage 0.001、不傳→0.01。` }, - { root: FU4, fu: 'FU4', id: 'A3-4', q: `federation/api.py build 是否先跑 validate_coords、upAxis/mpu 不一致回 409+issues、一致時傳真實 upAxis(非硬編 Z)、不誤拒一致 member。` }, -] - -phase('Verify') -log('FU-3 + FU-4 自包含對抗複驗:8 per-finding + 2 critic') - -const all = await parallel([ - ...FINDINGS.map((f) => () => - agent(`${pre(f.root)} - -待驗 ${f.fu} finding ${f.id}: -${f.q} - -回傳 StructuredOutput:finding_id=${f.id}、truly_closed、introduced_new_issue、reason(引用 ${f.root} 內真實 code 行號 + probe 結果)。`, - { label: `v:${f.id}`, phase: 'Verify', schema: VS })), - () => agent(`${pre(FU3)} - -critic(FU-3 diff):通讀 ${FU3}/governance-service/diff_engine/{engine,keys,models}.py 與 tests/test_diff_engine.py。檢 Tag 複合鍵是否破壞第一級 GlobalId 或既有 matched 計數、同鍵排序是否改既有 property_changed 歸屬、誠實註解清理是否過頭、新測試是否空。回傳 overall_safe + issues[]。`, - { label: 'critic:FU3', phase: 'Verify', schema: CS }), - () => agent(`${pre(FU4)} - -critic(FU-4 federation):通讀 ${FU4}/governance-service/federation/{builder,api}.py 與 tests/test_federation_*.py。用真實 pxr 26.5 確認 per-member transform 世界座標正確、member usdc immutable、build 回傳向後相容、validate_coords 接線正確不誤拒。回傳 overall_safe + issues[]。`, - { label: 'critic:FU4', phase: 'Verify', schema: CS }), -]) - -const fv = all.slice(0, FINDINGS.length).filter(Boolean) -const critics = all.slice(FINDINGS.length).filter(Boolean) -const notClosed = fv.filter((v) => !v.truly_closed) -const newIssues = fv.filter((v) => v.introduced_new_issue) -log(`閉合 ${fv.filter((v) => v.truly_closed).length}/${fv.length};未閉合 ${notClosed.length};新問題 ${newIssues.length};critics safe=${critics.map((c) => c.overall_safe).join(',')}`) -return { verdicts: fv, not_closed: notClosed, new_issues: newIssues, critics } diff --git a/.claude/workflows/fullsystem-adversarial-verify.js b/.claude/workflows/fullsystem-adversarial-verify.js deleted file mode 100644 index 0c9d3ec8c..000000000 --- a/.claude/workflows/fullsystem-adversarial-verify.js +++ /dev/null @@ -1,194 +0,0 @@ -export const meta = { - name: 'fullsystem-adversarial-verify', - description: '全系統多 agent 交叉對抗驗證:A1/A2/A3 + coordinator + streaming + scripts + 安全 + 誠實鐵律;每個 finding 雙懷疑者 refute-by-default 驗證', - phases: [ - { title: 'Review', detail: '14 子系統 × lens 平行對抗審查' }, - { title: 'Verify', detail: '每 finding correctness+reachability 雙懷疑者對抗驗證' }, - ], -} - -const ROOT = 'C:/Repos/active/iot/AI-BIM-governance' - -const FINDINGS_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['subsystem', 'findings'], - properties: { - subsystem: { type: 'string' }, - findings: { - type: 'array', - items: { - type: 'object', additionalProperties: false, - required: ['id', 'title', 'severity', 'kind', 'file', 'evidence', 'why'], - properties: { - id: { type: 'string' }, - title: { type: 'string' }, - severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] }, - kind: { type: 'string', enum: ['bug', 'security', 'honesty', 'spec-mismatch', 'regression', 'hygiene', 'test-gap'] }, - file: { type: 'string' }, - line: { type: 'string' }, - evidence: { type: 'string' }, - why: { type: 'string' }, - proposed_fix: { type: 'string' }, - confidence: { type: 'string', enum: ['high', 'medium', 'low'] }, - }, - }, - }, - }, -} - -const VERDICT_SCHEMA = { - type: 'object', additionalProperties: false, - required: ['finding_id', 'real', 'reason'], - properties: { - finding_id: { type: 'string' }, - real: { type: 'boolean' }, - severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'not-a-bug'] }, - reason: { type: 'string' }, - fix_sound: { type: 'boolean' }, - }, -} - -const PREAMBLE = `你是 AI-BIM-governance 專案的對抗式 code reviewer。repo root: ${ROOT}。 -這是 BIM 治理平台:A1 治理規則檢核 / A2 模型版本差異 / A3 跨專業 USD federation。後端 governance-service(FastAPI :49102 loopback,host py312 ifcopenshell 純 CPU),coordinator(Node :8004,proxy 到 :49102),web-viewer-sample(React Edge Console,掛 /console)。 - -誠實鐵律(違反即 honesty finding): -- 無願景假數字;每個 UI/輸出元素標 provenance(asbuilt/artifact/demo/p1/p15)。 -- enum 用後端權威值;GPU/轉檔無遙測標「未取得」非 fail。 -- 瀏覽器只打 coordinator :8004(governance :49102 / streaming 49xxx 為內部 loopback)。 -- USD 非 source of truth;IFC GlobalId 為主鍵,model_version_id 綁定所有 issue。 -- mapping fake(mock / allow_fake_mapping / fake_mapping_count>0 / mapping_method=fake)嚴禁當真 pass。 - -任務:只審查指派範圍,用 Read/Grep(絕對路徑)讀真實程式碼,找真實、可證據化的問題。 -規則:寧缺勿濫——每個 finding 必須引用真實 code 片段(file + 行)。不要臆測、不要把「最佳實踐建議」當 bug。聚焦 correctness / security / honesty 違反 / spec 不符 / regression 風險 / 真實 test-gap。 -回傳 StructuredOutput(subsystem + findings[]);findings 可空陣列(代表該範圍乾淨)。` - -const REVIEWERS = [ - { key: 'a1-rule-engine', prompt: `${PREAMBLE} - -範圍:A1 治理規則引擎。檔案:${ROOT}/governance-service/rule_engine/(全部), ${ROOT}/governance-service/rules/*.yaml, ${ROOT}/governance-service/tests/test_rule_engine.py。 -Lens:correctness(規則評分 / pass-fail 邏輯、跨 schema 型別別名 IFC4X3 IfcBuildingElement→IfcBuiltElement)、honesty(is_fake_mapping 是否真擋假 mapping、score 是否可能被寫死或受 fake 汙染)、boundary。驗 score 計算與 failed 構件 ifc_guid 是否真從 ifcopenshell 萃取。` }, - - { key: 'a1-bcf-export', prompt: `${PREAMBLE} - -範圍:A1 BCF 匯出。檔案:${ROOT}/governance-service/bcf/(全部), ${ROOT}/governance-service/tests/test_bcf.py。 -Lens:BCF 2.1 spec 合規(markup / viewpoints / .bcfzip 結構)、純 stdlib 不依賴 GPLv3、issue→bcfzip 是否綁 model_version_id、audit。對照 BCF 原則:BCF 管協作非模型、issue 必綁 model_version、無 mapping 不得建正式 BCF issue。` }, - - { key: 'a1-ids-import', prompt: `${PREAMBLE} - -範圍:A1 buildingSMART IDS-XML 匯入(ifctester)。檔案:grep ${ROOT}/governance-service 內 ids / ifctester 相關, ${ROOT}/governance-service/tests/test_ids.py。 -Lens:IDS-XML 解析正確性、ifctester 缺席時誠實降級(health ifctester=false)、IDS spec 對應、輸入驗證。` }, - - { key: 'a2-diff', prompt: `${PREAMBLE} - -範圍:A2 模型版本差異。檔案:${ROOT}/governance-service/diff_engine/(全部), tests/test_diff_engine.py, test_diff_api.py, test_diff_geometry_impact.py。 -Lens:GlobalId 多級對齊(GlobalId→Tag→type+name+loc)、moved(placement 平移) / property_changed(pset hash) / geometry_changed(opt-in) 分類正確性、issue-impact 連動。注意過去 blocking:『真實版本對』勿為 identity(同 SHA1 檔當兩版本)。` }, - - { key: 'a3-federation', prompt: `${PREAMBLE} - -範圍:A3 跨專業 USD federation。檔案:${ROOT}/governance-service/federation/(全部), tests/test_federation_api.py, test_federation_builder.py。 -Lens:OpenUSD sublayer 疊合語義正確性、member usdc immutability、validate-coords(upAxis / metersPerUnit)、per-member transform。USD 對齊:pxr 26.5 為 ground truth;若對 USD composition 語義(sublayer 強弱 / LIVERPS)有疑慮以 pxr 官方為準——過去已修正『sublayer 為最弱 LIVERPS arc』是錯的(sublayer 不在 LIVERPS 七弧;subLayerPaths[0] 最強、opinion 在 Local 解析)。檢查 code / 註解 / spec 是否仍殘留錯誤論述。` }, - - { key: 'issues-db', prompt: `${PREAMBLE} - -範圍:Issue DB 生命週期。檔案:${ROOT}/governance-service/issues/(全部), ${ROOT}/governance-service/db.py, tests/test_issues.py。 -Lens:issue lifecycle(open/resolved/rejected/...)、audit log 完整性、A1/A2 來源綁定、BCF 對齊(model_version 綁定)、SQLite 並發 / race / atomicity。` }, - - { key: 'governance-app-api', prompt: `${PREAMBLE} - -範圍:governance-service API 邊界與誠實。檔案:${ROOT}/governance-service/app.py, conftest.py, tests/test_api.py。 -Lens:REST 端點正確性、health 誠實回報能力(ifctester / bcf)、501 p15 標示、錯誤路徑、loopback-only 綁定;重點安全:ifc_source_path / element_mapping_path 等檔案路徑輸入是否受控(path traversal / 任意檔讀取)。` }, - - { key: 'coordinator-proxy', prompt: `${PREAMBLE} - -範圍:coordinator governance proxy 與邊界。檔案:${ROOT}/bim-review-coordinator/src/routes/governanceProxy.ts, ${ROOT}/bim-review-coordinator/src/app.ts。 -Lens:誠實 502(governance 缺席)、只 proxy 白名單路徑、瀏覽器→:8004→:49102 邊界、header / 方法 / body 轉發正確、無 SSRF(GOVERNANCE_API_BASE 是否可被污染)。` }, - - { key: 'coordinator-security', prompt: `${PREAMBLE} - -範圍:coordinator 安全(對照 L4 backlog,須讀真 code 驗當前 main 是否仍存在)。檔案:grep ${ROOT}/bim-review-coordinator/src 內 viewer-log / structLog / internal / token / cors。 -Lens:#6 /api/internal/viewer-log 與 /structLog/health 是否明文無 token;internal 端點認證;CORS 設定;session / kit pool 安全。別照抄舊清單,以實際 code 為準。` }, - - { key: 'streaming-security', prompt: `${PREAMBLE} - -範圍:streaming-server / host-native conversion 安全。檔案:grep ${ROOT}/bim-streaming-server 內 token / 49101 / internal_conversion_token / bind / allowlist。 -Lens:#2 :49101 internal_conversion_token 預設 None 無驗證是否仍真、host allowlist、loopback 綁定、轉檔輸入驗證。讀真 code 驗,標明檔案行號。` }, - - { key: 'frontend-console', prompt: `${PREAMBLE} - -範圍:Edge Console 前端誠實 + 型別。檔案:${ROOT}/web-viewer-sample/src/console/(EdgeConsole.tsx, pages.tsx, components.tsx, data.ts, governanceClient.ts), ${ROOT}/web-viewer-sample/src/AppStream.tsx, ${ROOT}/web-viewer-sample/src/Window.tsx。 -已知 tsc --noEmit 錯誤(seed,請讀 code 確認並評估嚴重度):(a) EdgeConsole.tsx 第40/46行 provenance 值 'artifact' 不在型別 union 'asbuilt'|'demo'|'p1'|'p15' → 型別漏列(誠實鐵律要求 artifact 為合法 provenance);(b) AppStream.tsx 133/167 行 mediaPort number|null vs number|undefined;(c) 多個 unused React/var。 -Lens:provenance 誠實標示、無寫死假資料、enum 來自後端、型別正確性、僅打 :8004。` }, - - { key: 'scripts-deploy', prompt: `${PREAMBLE} - -範圍:deploy.ps1 與 scripts 衛生(對照 CH-5 backlog)。檔案:${ROOT}/scripts/deploy.ps1, ${ROOT}/scripts/lib/*.ps1。 -Lens:#22 Set-StrictMode -Version Latest 下未初始化變數 / 可能 null 取用 / 存取不存在的 property 會 throw 的點、#25 spectator port 上限常數是否仍硬寫散落、安全(env / token 處理)、preflight 邏輯正確性。實際讀 code 找 strict-mode 會炸或邏輯錯的點,標行號。` }, - - { key: 'honesty-audit', prompt: `${PREAMBLE} - -範圍:跨系統誠實鐵律稽核。手法:grep 全 repo(${ROOT}/governance-service, ${ROOT}/web-viewer-sample/src, ${ROOT}/bim-review-coordinator/src)找:寫死數字當遙測、fake/mock 資料外洩到正式路徑、provenance 缺漏或標錯、enum 前端硬寫非後端權威、瀏覽器直連內部 port(49xxx)、宣稱完成但實為 stub。每 finding 引真實 code(file+行)。` }, - - { key: 'bcf-usd-principle', prompt: `${PREAMBLE} - -範圍:BCF↔USD 開發原則對齊。檔案:${ROOT}/governance-service/bcf/, ${ROOT}/governance-service/issues/, ${ROOT}/governance-service/federation/, 及 mapping 相關。 -對照原則:USD/USDC 管場景幾何、BCF 管 issue/comment/viewpoint;model.usdc 應 immutable 不被 issue 污染;IFC GUID 主鍵 + usd_prim_path 執行期定位;所有 issue 綁 model_version;無 mapping 只能視覺標註不能正式 BCF issue。找違反這些原則的實作,引真實 code。` }, -] - -function refutePrompt(f, lens, subsystem) { - const lensInstr = lens === 'correctness' - ? '(correctness lens)該問題在程式邏輯上是否真實存在、reviewer 引用的 code 是否屬實、是否誤判 / 過時行號。' - : '(reachability lens)該問題是否真的可被觸發 / 可達 / 有實際影響,還是理論上不可達的死路或測試已涵蓋。' - return `你是對抗式驗證者(${lens} lens)。預設立場:這個 finding 是 FALSE(refuted),除非你讀真實程式碼找到確鑿證據證明它為真。repo root: ${ROOT}。 - -待驗 finding(來自 ${subsystem} reviewer): - id: ${f.id} - title: ${f.title} - file: ${f.file} line: ${f.line || '?'} - kind/severity: ${f.kind} / ${f.severity} - reviewer 宣稱證據: ${f.evidence} - why: ${f.why} - proposed_fix: ${f.proposed_fix || '(none)'} - -任務:用 Read/Grep 實際打開 ${f.file} 與相關檔確認: - ${lensInstr} -教訓:reviewer 給的行號 / 版本 / 簽章可能是幻覺——自己 grep 驗。「有改 + 測試綠」不代表問題消失;對著宣稱的失效模式驗。 -回傳 StructuredOutput:finding_id=${f.id}, real(true 僅當你親眼在 code 確認為真), severity(可下修或 not-a-bug), reason(引用你讀到的真實 code 片段), fix_sound(proposed_fix 是否正確可行)。` -} - -phase('Review') -log(`啟動 ${REVIEWERS.length} 個對抗 reviewer,各審一子系統`) - -const results = await pipeline( - REVIEWERS, - (r) => agent(r.prompt, { label: `review:${r.key}`, phase: 'Review', schema: FINDINGS_SCHEMA }), - (review, r) => { - const findings = (review && review.findings) ? review.findings : [] - if (!findings.length) return [] - return parallel(findings.map((f, fi) => () => - parallel([ - () => agent(refutePrompt(f, 'correctness', r.key), { label: `vc:${r.key}#${fi}`, phase: 'Verify', schema: VERDICT_SCHEMA }), - () => agent(refutePrompt(f, 'reachability', r.key), { label: `vr:${r.key}#${fi}`, phase: 'Verify', schema: VERDICT_SCHEMA }), - ]).then((vs) => ({ ...f, subsystem: r.key, verdicts: vs.filter(Boolean) })) - )) - } -) - -const flat = results.flat().filter(Boolean) -const confirmed = flat.filter((f) => { - const vs = f.verdicts || [] - const reals = vs.filter((v) => v && v.real).length - return reals >= 1 -}) -const strongConfirmed = flat.filter((f) => { - const vs = f.verdicts || [] - return vs.length >= 2 && vs.every((v) => v && v.real) -}) - -log(`Review 完成:${flat.length} findings;至少一懷疑者確認 ${confirmed.length};雙懷疑者皆確認 ${strongConfirmed.length}`) - -return { - total_findings: flat.length, - confirmed_count: confirmed.length, - strong_confirmed_count: strongConfirmed.length, - all: flat, -} diff --git a/.claude/workflows/plan-next-spec-to-done.js b/.claude/workflows/plan-next-spec-to-done.js deleted file mode 100644 index 2d0e74b79..000000000 --- a/.claude/workflows/plan-next-spec-to-done.js +++ /dev/null @@ -1,186 +0,0 @@ -export const meta = { - name: 'plan-next-spec-to-done', - description: 'Analyze docs/plans specs against current build state to recommend the next spec-to-done item', - phases: [ - { title: 'Understand', detail: 'parallel spec readers + repo build-state probes' }, - { title: 'Synthesize', detail: 'gap analysis -> ranked next-item candidates' }, - { title: 'Verify', detail: 'adversarially check top candidates against the real repo' }, - ], -} - -const SPEC_SCHEMA = { - type: 'object', - additionalProperties: false, - properties: { - source: { type: 'string' }, - items: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - id: { type: 'string' }, - kind: { type: 'string', description: 'milestone | a-item | interaction-card | decision | open-item | gap | standard | design' }, - title: { type: 'string' }, - scope: { type: 'string' }, - dod: { type: 'string', description: 'definition of done / acceptance criteria' }, - dependencies: { type: 'array', items: { type: 'string' } }, - measured_status: { type: 'string', description: 'working | partial | broken | not-built | unknown' }, - }, - required: ['id', 'kind', 'title'], - }, - }, - notes: { type: 'string' }, - }, - required: ['source', 'items'], -} - -const PROBE_SCHEMA = { - type: 'object', - additionalProperties: false, - properties: { - area: { type: 'string' }, - built: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - feature: { type: 'string' }, - evidence: { type: 'string', description: 'file:line or route' }, - status: { type: 'string', description: 'real | demo | stub | partial' }, - }, - required: ['feature', 'status'], - }, - }, - notBuilt: { type: 'array', items: { type: 'string' } }, - notes: { type: 'string' }, - }, - required: ['area', 'built'], -} - -const SYNTH_SCHEMA = { - type: 'object', - additionalProperties: false, - properties: { - currentState: { type: 'string', description: 'where the project sits on M0-M8 / A1-A10; what is the frontier' }, - candidates: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - rank: { type: 'number' }, - id: { type: 'string' }, - title: { type: 'string' }, - why: { type: 'string' }, - scope: { type: 'string' }, - dod: { type: 'string' }, - dependencies: { type: 'array', items: { type: 'string' } }, - dependenciesMet: { type: 'boolean' }, - risk: { type: 'string' }, - estimatedSize: { type: 'string', description: 'S | M | L' }, - }, - required: ['rank', 'id', 'title', 'why', 'scope', 'dod', 'dependenciesMet'], - }, - }, - recommendation: { type: 'string' }, - }, - required: ['currentState', 'candidates', 'recommendation'], -} - -const VERIFY_SCHEMA = { - type: 'object', - additionalProperties: false, - properties: { - candidateId: { type: 'string' }, - verdict: { type: 'string', description: 'confirmed-next | blocked-by-dependency | already-built | wrong-scope' }, - reasoning: { type: 'string' }, - blockingDependencies: { type: 'array', items: { type: 'string' } }, - alreadyBuiltEvidence: { type: 'string' }, - }, - required: ['candidateId', 'verdict', 'reasoning'], -} - -const REPO = 'C:/Repos/active/iot/AI-BIM-governance' -const PLANS = REPO + '/docs/plans' - -phase('Understand') -log('讀 3 份規格 + 探前端/後端現狀(5 路平行)') - -const reads = await parallel([ - () => agent( - `Read the file ${PLANS}/ai-bim-governance-開發軌跡與執行計畫.md IN FULL. This is the v3 trajectory — the AUTHORITATIVE IMPLEMENTATION-ORDER document for the AI-BIM-governance product. Extract a structured inventory:\n` + - `- Every milestone M0..M8: id, kind='milestone', title, scope, dod (its Definition of Done), dependencies (ids of milestones/items it gates on).\n` + - `- Every App API draft with its DoD (kind='a-item' if it maps to an A1..A10 item, else kind='milestone').\n` + - `- Decisions D1..D9 (kind='decision') and open items O1..O6 (kind='open-item').\n` + - `Be precise about the FIXED SEQUENCE (M0 地基 -> M1 A1 核心閉環 P0 純CPU -> M2 轉檔 -> M3 串流 -> M4 3D 連動 -> M5+) and which milestone gates which. Set measured_status='unknown' (this doc states the plan, not current build state). Analysis only; do NOT modify any file.`, - { label: 'spec:v3-trajectory', phase: 'Understand', schema: SPEC_SCHEMA, model: 'sonnet', effort: 'medium' } - ), - () => agent( - `Read the file ${PLANS}/ai-bim-governance-互動實作規格與標準對齊.md IN FULL. This is the HIGHEST-AUTHORITY behavior contract. Extract:\n` + - `- PART A 實測差距 (measured gaps vs the current build): each as kind='gap' with measured_status (working|partial|broken|not-built) and dod = what 'fixed' looks like. THESE ARE THE MOST CONCRETE next-work candidates — be exhaustive here.\n` + - `- PART B interaction cards IX-xx (state machine / API / acceptance): each as kind='interaction-card', dod = acceptance criteria.\n` + - `- PART C three-domain official-standard alignment (IfcOpenShell / Omniverse / NVIDIA): key binding constraints as kind='standard'.\n` + - `Return per schema. Analysis only; do NOT modify any file.`, - { label: 'spec:interaction-gaps', phase: 'Understand', schema: SPEC_SCHEMA, model: 'sonnet', effort: 'medium' } - ), - () => agent( - `Read the file ${PLANS}/ai-bim-governance-設計規格.md IN FULL (v2 design spec). Extract the A1..A10 interface analysis: for each A-item return id (A1..A10), kind='a-item', title, scope (what the feature does), dod (interface-level acceptance), dependencies. Also capture the MinIO three-tier storage structure and any cross-cutting Issue/BCF schema notes as kind='design'. Return per schema. Analysis only; do NOT modify any file.`, - { label: 'spec:design-a-items', phase: 'Understand', schema: SPEC_SCHEMA, model: 'sonnet', effort: 'medium' } - ), - () => agent( - `Audit the CURRENT BUILD STATE of the AI-BIM-governance FRONTEND in repo ${REPO}. The product shell is a React 18 + TypeScript "EdgeConsole" served by the coordinator at /ui (look for build:ui, a hash router, page components). Route contract (hash, NO slash): #home #a1 #a2 #viewer #conv #sessions #instances #minio #review, plus operator tools #kit #demo-control.\n` + - `For EACH route/feature decide: is it REALLY built and wired to a real backend, PARTIAL/DEMO (mock/DEMO-DATA/placeholder), or NOT built? Locate the EdgeConsole source first (find the route table + page components). Report built[] (feature, evidence=file:line or route, status=real|demo|stub|partial) and notBuilt[]. BE HONEST — flag any mock data, fake buttons, or DEMO-DATA markers. Read-only; do not modify anything.`, - { label: 'repo:frontend-routes', phase: 'Understand', schema: PROBE_SCHEMA, agentType: 'Explore', model: 'sonnet', effort: 'medium' } - ), - () => agent( - `Audit the CURRENT BUILD STATE of the AI-BIM-governance BACKEND in repo ${REPO}. Services: coordinator :8004 (session/instance lifecycle + /api/* + /api/governance/* proxy), governance-service :49102 (rules / Issue / BCF, CPU), conversion (host-native IFC->USD), Kit WebRTC streaming, MinIO / local_fs storage.\n` + - `Determine which backend capabilities are actually IMPLEMENTED vs STUBBED for: A1 rule-check + Issue + BCF closed loop; A2 version diff via ifcdiff (GlobalId-keyed JSON); conversion pipeline + mapping-coverage report (G_ prims); Kit session lifecycle (create/terminate/recreate, 1 GPU=1 stream, no live migration); MinIO intake + polling auto-intake; 3D viewer DataChannel (highlightPrimsRequest). Report built[] (feature, evidence=file:line, status=real|partial|stub) and notBuilt[]. Read-only; do not modify anything.`, - { label: 'repo:backend-capabilities', phase: 'Understand', schema: PROBE_SCHEMA, agentType: 'Explore', model: 'sonnet', effort: 'medium' } - ), -]) - -const specReads = [reads[0], reads[1], reads[2]].filter(Boolean) -const repoReads = [reads[3], reads[4]].filter(Boolean) -log(`規格抽取 ${specReads.length}/3、現狀探測 ${repoReads.length}/2 完成`) - -phase('Synthesize') -const synthesis = await agent( - `You are the lead architect selecting the NEXT single "spec-to-done" work item for the AI-BIM-governance repo.\n\n` + - `AUTHORITY ORDER (higher wins): 互動實作規格(behavior/standards) > v3 計畫(order/DoD) > v2 規格(interface) > html prototypes.\n` + - `FIXED IMPLEMENTATION ORDER: M0 地基 -> M1 A1 核心閉環 (P0, pure CPU, no 3D) -> M2 轉檔 -> M3 串流 -> M4 3D 連動 -> M5+.\n\n` + - `=== STRUCTURED SPEC EXTRACTION (3 docs) ===\n${JSON.stringify(specReads)}\n\n` + - `=== CURRENT REPO BUILD-STATE AUDIT (frontend + backend) ===\n${JSON.stringify(repoReads)}\n\n` + - `TASK:\n` + - `1) currentState: one tight paragraph — where the project actually sits on the M0-M8 / A1-A10 timeline, what is DONE, and what is the FRONTIER (the next unmet milestone DoD or measured gap).\n` + - `2) candidates: 2-3 ranked next-item options. Each MUST (a) respect the fixed milestone order, (b) have dependencies already met (set dependenciesMet), (c) be a coherent SINGLE spec-to-done scope (not a whole milestone). PREFER items that close a PART A measured gap or complete the current milestone's DoD over starting a brand-new milestone. Each candidate: rank, id, title, why, scope, dod, dependencies, dependenciesMet, risk, estimatedSize (S|M|L).\n` + - `3) recommendation: which candidate and why, in 2-3 sentences.\n` + - `Ground every claim in the provided data; if the audit and the spec disagree, say so. Analysis only; do not modify any file.`, - { label: 'synthesize:gap-analysis', phase: 'Synthesize', schema: SYNTH_SCHEMA, model: 'opus', effort: 'high' } -) - -phase('Verify') -const top = (synthesis && synthesis.candidates ? synthesis.candidates : []) - .slice() - .sort((a, b) => (a.rank || 99) - (b.rank || 99)) - .slice(0, 3) - -const verdicts = await parallel(top.map((c) => () => agent( - `Adversarially verify this PROPOSED next work item for AI-BIM-governance (repo ${REPO}). Default to skepticism.\n\n` + - `CANDIDATE:\n${JSON.stringify(c)}\n\n` + - `Check against the ACTUAL repository code (search for real evidence):\n` + - `1) Is it ALREADY built or partially built? Find file:line evidence.\n` + - `2) Is it BLOCKED by an unbuilt earlier-milestone dependency (per the M0->M5 order)?\n` + - `3) Is the scope right for ONE spec-to-done, or too big / too small?\n` + - `Verdict must be one of: confirmed-next | blocked-by-dependency | already-built | wrong-scope. Give reasoning with file:line evidence, list blockingDependencies if any, and alreadyBuiltEvidence if found. Read-only; do not modify anything.`, - { label: `verify:${c.id}`, phase: 'Verify', schema: VERIFY_SCHEMA, model: 'opus', effort: 'high' } -))) - -return { - currentState: synthesis ? synthesis.currentState : null, - recommendation: synthesis ? synthesis.recommendation : null, - candidates: synthesis ? synthesis.candidates : [], - verdicts: verdicts.filter(Boolean), - specCoverage: `${specReads.length}/3 specs, ${repoReads.length}/2 probes`, -} diff --git a/.claude/workflows/repo-wide-adversarial-round-1.js b/.claude/workflows/repo-wide-adversarial-round-1.js deleted file mode 100644 index 8ddc44685..000000000 --- a/.claude/workflows/repo-wide-adversarial-round-1.js +++ /dev/null @@ -1,57 +0,0 @@ -export const meta = { - name: 'repo-wide-adversarial-round-1', - description: 'merged main repo-wide 多 agent 對抗驗證(coordinator/governance/viewer/honest)→ 對抗確認真偽', - phases: [ - { title: 'Review', detail: '並行 4 lens:coordinator 安全/邊界、governance 正確/安全、viewer 狀態機/邊界、誠實降級全域' }, - { title: 'Verify', detail: 'high/blocker 對抗確認(預設懷疑)' }, - ], -} - -const FIND = { - type: "object", - properties: { - lens: { type: "string" }, - findings: { - type: "array", - items: { - type: "object", - properties: { - severity: { type: "string", enum: ["blocker", "high", "medium", "low"] }, - file: { type: "string" }, - title: { type: "string" }, - detail: { type: "string" }, - fix: { type: "string" }, - }, - required: ["severity", "file", "title", "detail", "fix"], - additionalProperties: false, - }, - }, - }, - required: ["lens", "findings"], - additionalProperties: false, -} - -const COMMON = `repo C:\\Repos\\active\\iot\\AI-BIM-governance(merged main,含 fe-redesign CH-0~H + 問題分頁)。只讀。 -回**真實會發生**的 findings(嚴格 severity:blocker=生產壞/安全洞,high=明確 bug/邊界違規/誠實違規,medium/low=次要)。無問題回空陣列、不硬湊。每筆給 file:line + 具體 detail + 可行 fix。` - -phase('Review') - -const reviews = await pipeline( - [ - { key: 'coord-security', prompt: `${COMMON}\n【lens: coordinator 安全/邊界】審 bim-review-coordinator/src(app.ts + routes/):dev 路由(/api/dev/*)授權(ENABLE_DEV_ROUTES/loopback)、/api/kit/* 變更型授權(x-dev-token)、ifc-file loopback-only、/api/dev/ifc-sources 不洩絕對路徑、/ui 服務(static/SPA fallback 不吞 /ui/open)、governance proxy for-session 的 session/guid 守門、ifc-ready intake webhook secret/IP allowlist、path traversal、secret 洩漏到回應。找真實安全/邊界洞。` }, - { key: 'gov-correctness', prompt: `${COMMON}\n【lens: governance-service 正確/安全】審 governance-service(app.py rule-run/diff/federation/element-semantics/spatial-tree + rule_engine/):任意 ifc_source_path open(path traversal;緩解=loopback+coordinator resolve?)、ifcopenshell 例外/奇異元素處理、JSON 序列化(enum/entity 值)、_spatial_subtree/_spatial_chain 迴圈終止、get_psets 合成 key、rule predicate 正確性、SQL/檔案注入。找真實正確/安全問題。` }, - { key: 'viewer-statemachine', prompt: `${COMMON}\n【lens: viewer 狀態機/邊界】審 web-viewer-sample/src(Window.tsx + AppStream + harness/ + console/viewer/):harness 旗標洩漏到 prod(harnessConfig)、viewerTab/MockViewport/GovernanceOverlay 分頁 gate 邏輯、spectator 三層權威(不送 mutating)、前端是否只打 :8004(各 fetch target)、WebRTC 生命週期/reconnect、_hasRemoteVideoFrame gate、競態(useEffect reqRef)。找真實 bug/邊界違規。` }, - { key: 'honest-degradation', prompt: `${COMMON}\n【lens: 誠實降級全域】跨 coordinator/governance/viewer 找違反誠實鐵律:捏造數值/假成功/靜默失敗/把 fake 當真/mock 覆蓋真資料/缺資料顯有把握值/disabled 按鈕假裝可用/coverage 自算誤導/未對映 usd_prim_path 捏造。重點查 fe-redesign 新碼 + mapping fake-vs-real 隔離。找真實誠實違規。` }, - ], - (d) => agent(d.prompt, { label: `review:${d.key}`, phase: 'Review', schema: FIND, model: 'opus' }), - (review, d) => parallel((review.findings || []).filter((f) => f.severity === 'blocker' || f.severity === 'high').map((f) => () => - agent(`${COMMON}\n對抗確認此 finding 真偽(預設懷疑,可能 false positive;讀實際碼+緩解機制確認):\n[${f.severity}] ${f.file} — ${f.title}\n${f.detail}\n建議修:${f.fix}\n回 {real:boolean, reason, severity_adjusted}。`, - { label: `verify:${d.key}`, phase: 'Verify', model: 'opus', - schema: { type: "object", properties: { real: { type: "boolean" }, reason: { type: "string" }, severity_adjusted: { type: "string" } }, required: ["real", "reason"], additionalProperties: false } }) - .then((v) => ({ ...f, lens: d.key, verdict: v })) - )), -) - -const flat = reviews.flat().filter(Boolean) -const confirmed = flat.filter((f) => f.verdict && f.verdict.real) -return { confirmedHighBlocker: confirmed, verifiedCount: flat.length } diff --git a/.claude/workflows/spec-to-done-design.js b/.claude/workflows/spec-to-done-design.js deleted file mode 100644 index 6653fa753..000000000 --- a/.claude/workflows/spec-to-done-design.js +++ /dev/null @@ -1,155 +0,0 @@ -export const meta = { - name: 'spec-to-done-design', - description: '深讀四套工具介面 → 3 視角設計 spec-to-done 工作流 → judge panel 評審', - phases: [ - { title: 'DeepRead', detail: '5 agents 平行深讀 superpowers / mattpocock / gitnexus / gstack / repo 治理' }, - { title: 'Design', detail: '3 個 Opus agents 以不同視角各產一份工作流設計', model: 'opus' }, - { title: 'Judge', detail: '3 個 Opus judges 以不同 lens 比較評分', model: 'opus' }, - ], -} - -phase('DeepRead') -log('深讀:superpowers / mattpocock / gitnexus / gstack / repo 治理規範') - -const READERS = [ - { - key: 'superpowers', - prompt: `你是工具介面研究員。深讀 Superpowers plugin 全部 14 個 skills,目錄: -C:/Users/IOT/.claude/plugins/cache/claude-plugins-official/superpowers/5.1.0/skills/ -子目錄:brainstorming, dispatching-parallel-agents, executing-plans, finishing-a-development-branch, receiving-code-review, requesting-code-review, subagent-driven-development, systematic-debugging, test-driven-development, using-git-worktrees, using-superpowers, verification-before-completion, writing-plans, writing-skills -每個讀其 SKILL.md(部分有 references/ 補充檔,關鍵的也讀)。 -回傳一份繁體中文「能力卡清單」,每個 skill 一張卡: -- skill 名 -- 觸發時機(什麼情境下用) -- 輸入(需要什麼前置產物,如 spec / plan 檔) -- 輸出(產生什麼,如 plan 檔路徑格式、worktree、PR) -- 流程要點(它內部的步驟與 gate,特別是哪些步驟要求「等使用者批准」) -- 與下一步的銜接(它結束時指示要 invoke 哪個 skill) -特別注意:writing-plans 的 plan 檔格式與存放路徑、subagent-driven-development 怎麼派 subagent 與兩階段 review、executing-plans 與 subagent-driven 的差異(何時選哪個)、verification-before-completion 的 done-gate 清單、finishing-a-development-branch 的收尾選項、using-git-worktrees 的隔離時機、dispatching-parallel-agents 的適用條件。 -最後給一段「在全自主(無人值守)模式下,哪些『等使用者批准』的點可以如何處理」的客觀觀察(只描述 skill 原文怎麼寫,不要自行放寬)。`, - }, - { - key: 'mattpocock', - prompt: `你是工具介面研究員。盤點 repo project-local skills 目錄 C:/Repos/active/iot/AI-BIM-governance/.claude/skills/ 下的 Matt Pocock 系列與其他輔助 skills(排除 gitnexus/ 子目錄與 generated/)。 -先 ls 全部子目錄,讀每個 SKILL.md 的 frontmatter(name + description),然後深讀這幾個與開發管線最相關的全文:tdd, review, triage, to-issues, to-prd, diagnose, design-an-interface, request-refactor-plan, prototype, qa, grill-me, zoom-out, ubiquitous-language。 -回傳繁體中文報告: -1. 全部 skills 的一行式清單(name — 一句話用途) -2. 上述深讀 skills 的能力卡(觸發時機/輸入/輸出/流程要點) -3. 重要脈絡:repo AGENTS.md 規定 Matt Pocock skills「僅 optional 輔助:issue / triage / domain-doc;不得當主線」。請標出哪些卡在「spec 已定、要精準實作到 merge」的流程中有實際輔助價值(例如 triage 處理 reviewer 發現、to-issues 把殘留工作開成 issue、diagnose 處理實作中遇到的 bug),哪些與主線重疊必須避免(例如 plan/build/ship/spec 類與 Superpowers 重疊)。`, - }, - { - key: 'gitnexus', - prompt: `你是工具介面研究員。深讀 GitNexus 在本 repo 的使用介面: -1. C:/Repos/active/iot/AI-BIM-governance/docs/agents/gitnexus-usage.md -2. C:/Repos/active/iot/AI-BIM-governance/.claude/skills/gitnexus/ 下全部子 skill 的 SKILL.md(exploring / impact-analysis / debugging / refactoring / guide / cli) -3. C:/Repos/active/iot/AI-BIM-governance/.claude/skills/gitnexus-blast-radius/SKILL.md -回傳繁體中文報告: -- MCP tools 清單與各自時機(query / context / impact / detect_changes / rename / cypher),含參數要點 -- 「改 symbol 前 impact、commit 前 detect_changes、HIGH/CRITICAL 先回報」的精確規範原文意涵 -- index stale 的偵測與處理(npx gitnexus analyze / status;LadybugDB crash 復原存在 agent memory) -- pre-change vs post-change 兩種模式(gitnexus-blast-radius) -- 在多 task 連續實作的流程中,建議的最小成本模式(例如:每個 task 改前 impact 一次 vs 整批;何時需要 re-analyze) -注意:你只讀文件與 skill,不需要實際跑 MCP tools。`, - }, - { - key: 'gstack-browser-evidence', - prompt: `你是工具可用性稽核員。任務:確認 gstack 與本 repo browser E2E evidence 的現實狀態,設計 fallback 鏈。 -1. 讀 C:/Users/IOT/.claude/skills/gstack/SKILL.md 全文(了解它提供哪些操作:navigate/screenshot/interact/diff 等與 CLI 形態) -2. 實測可用性(只跑無害指令):bash 下試 'ls C:/Users/IOT/.claude/skills/gstack/bin/' 看有哪些執行檔;試跑 gstack bin 的 --version 或 --help(若是 bun script 會失敗,記錄錯誤訊息);'bun --version' 確認 bun 是否存在。 -3. 盤點 repo 既有 browser E2E 慣例:ls C:/Repos/active/iot/AI-BIM-governance/web-viewer-sample/scripts/ 與 C:/Repos/active/iot/AI-BIM-governance/tests/e2e/(若存在),看用什麼引擎(Playwright? puppeteer? 自製?);看 C:/Repos/active/iot/AI-BIM-governance/artifacts/e2e/ 的檔名模式了解 evidence 慣例;grep web-viewer-sample/package.json 的 devDependencies 找 playwright/puppeteer。 -4. claude-in-chrome MCP tools 是另一個 fallback(本 session 有,headless/cron 可能沒有)。 -回傳繁體中文報告: -- gstack 目前可用性結論(可用/不可用+原因+啟用條件) -- repo 實際的 browser E2E 引擎與 evidence 慣例(指令、輸出路徑、截圖命名) -- 建議的 browser-evidence 引擎優先序 fallback 鏈(gstack → Playwright script → claude-in-chrome),每層的偵測指令與適用條件 -- AGENTS.md 說 gstack 是「user-facing 驗收唯一證據來源」但 product-operability 文件接受「Playwright / Chrome E2E 截圖或 trace」— 指出這個現實落差,工作流文件該怎麼寫才誠實`, - }, - { - key: 'governance-gates', - prompt: `你是流程治理研究員。深讀本 repo 對「從 spec 到 merge」全流程的硬性規範,輸出工作流必須內建的 gate 清單。 -讀: -1. C:/Repos/active/iot/AI-BIM-governance/AGENTS.md(§0.1 開發管線/四工具不平權/anti-patterns/誠實鐵律/完成標準) -2. C:/Repos/active/iot/AI-BIM-governance/docs/agents/github-workflow.md -3. C:/Repos/active/iot/AI-BIM-governance/docs/agents/product-operability-and-script-contract.md -4. C:/Repos/active/iot/AI-BIM-governance/.claude/workflows/ship-item.md(既有 buffered auto-merge ship-cycle 權威程序) -5. C:/Repos/active/iot/AI-BIM-governance/.claude/workflows/fu-adversarial-verify-generic.js(既有對抗驗證 workflow 模式) -6. C:/Repos/active/iot/AI-BIM-governance/CLAUDE.md -回傳繁體中文報告: -1. 「spec→plan→實作→驗收→PR→merge」每一段的 MUST gates(逐條,註明出處檔案) -2. 四工具不平權的精確分工與 4 條 anti-patterns 原文 -3. user-facing vs runtime/deploy vs 純 tooling/docs 三類變更的不同驗收表要求 -4. ship-item 工作流的輸入(args)、gate 與輸出 — 新工作流如何直接 compose 它 -5. 分支/worktree 紀律(不在 main 開發、worktree closeout 守衛) -6. 模型預算慣例(memory 提示:曾有「sonnet 讀 / opus 其餘」預算;本次使用者指定 Fable 5 max + Opus 4.8 max) -7. 既有 fu-adversarial-verify-generic.js 的可重用結構(它怎麼參數化、怎麼派 verifier)`, - }, -] - -const readings = await parallel(READERS.map(r => () => - agent(r.prompt, { label: `read:${r.key}`, phase: 'DeepRead' }) -)) -const readingDigest = READERS.map((r, i) => `\n\n===== [${r.key}] =====\n${readings[i] || '(讀取失敗)'}`).join('') -log(`深讀完成:${readings.filter(Boolean).length}/5 份報告`) - -phase('Design') -log('3 個 Opus 設計 agents 以不同視角產出工作流設計') - -const TASK_BRIEF = `# 任務:為 AI-BIM-governance repo 設計「spec-to-done」可重複使用工作流 - -## 使用者需求(原文意涵) -當使用者與 AI 完成頭腦風暴(superpowers:brainstorming)產出一份 spec 後,AI coding agent 能依照此工作流「自主執行」,在適當時機運用/搭配/組合/混合 repo 內四套工具 — Superpowers + gstack + GitNexus + Matt Pocock — 精準無誤地完成該 spec。模型配置:Fable 5(max effort)+ Opus 4.8(max effort)搭配使用。 - -## 硬性脈絡(不可違反) -- AGENTS.md 固定管線:spec/prototype → Superpowers 拆 plan → GitNexus impact → 實作 → gstack(browser E2E)驗收 → GitNexus detect_changes → branch → PR → Actions → merge -- 四工具不平權:Superpowers=主線 plan/execution governance;GitNexus=impact/detect_changes;gstack=browser QA evidence(user-facing 驗收);Matt Pocock=僅 issue/triage/domain-doc 輔助 -- 4 anti-patterns:Matt Pocock 不可取代 Superpowers plan;Superpowers 不可宣告 UI 完成而不跑 browser E2E;GitNexus 不可當產品設計依據;改 backend symbol 不可跳過 GitNexus impact -- 誠實鐵律:前端要真能操作;無 backend 處標 DEMO DATA / NOT BUILT / not observed;不偽裝 CI 綠;不 merge 真 P1/P2 -- user-facing 完成標準 = 前端 route 可操作 + 預設 fixture + loading/success/failure/retry + runtime ID + browser E2E 截圖 evidence -- 不在 main 上開發;ship 段已有權威 named workflow「ship-item」(commit→push→PR→CI watch→reviewer buffer→三來源查 reviewer 發現→carry-forward→buffered auto-merge→closeout),新工作流應 compose 它而非重造 -- HIGH/CRITICAL impact 規範要求「先回報再繼續」 -- gstack 目前 bun 缺失不可用 → 需 fallback 鏈(Playwright / Chrome E2E)且文件要誠實標註 -- 執行環境:Claude Code + Workflow tool(named workflows 放 .claude/workflows/*.js,skill 放 .claude/skills//SKILL.md);Workflow 內 subagent 無法問使用者;主對話可以問但 autonomous 模式應盡量不問 -- Workflow script 限制:純 JS、不可呼叫時間與亂數 API(會破壞 resume,需由 args 傳入時間戳)、agent() 可帶 schema/model('fable'|'opus'|'sonnet'|'haiku')/isolation:'worktree'/agentType、支援 workflow() compose(一層)、支援 resumeFromRunId 重入 - -## 你的交付物(繁體中文) -一份完整工作流設計,必含: -1. 形態與檔案結構(哪些 SKILL.md、哪些 .claude/workflows/*.js,各自職責) -2. 端到端階段圖:從「spec 檔已存在」到「merged + evidence + 回報」,每階段:用什麼工具/skill、誰執行(主對話 or workflow subagent)、模型(fable/opus)、gate 條件、失敗處理 -3. 四套工具各自的精確切入點(對照 anti-patterns 證明不犯規) -4. 自主性設計:哪些 gate 全自動、哪些必須停下回報使用者(HIGH/CRITICAL、merge carve-out、spec 矛盾)、停下時如何可重入(resume) -5. 參數化(args:spec 路徑、user-facing 與否、branch 名…)與可重複使用方式(下次怎麼一句話觸發) -6. 防錯設計:GitNexus stale、gstack 不可用、CI 異常(report generation failed 慣例)、plan 與 spec 偏離、subagent 失敗 -7. token/模型預算:何處 fable、何處 opus、何處可平行` - -const DESIGN_LENSES = [ - { key: 'sop-first', angle: '視角 A「SOP 文件主導」:以權威 SKILL.md 程序文件為核心(像 ship-item.md),主對話親自走每一步並在關鍵點派 subagent;Workflow scripts 只用於 fan-out 驗證(plan review、adversarial verify)。優先考慮:與 superpowers skills 原生流程的相容、人類可讀可維護、context 連續性。' }, - { key: 'phase-engines', angle: '視角 B「分階段引擎」:skill 入口文件 + 每個重階段一個 named workflow(如 plan-review、per-task implement、e2e-evidence、adversarial-review),主對話是指揮官,在 phase 之間做 gate 判斷與重入;ship 段 compose 既有 ship-item workflow。優先考慮:每段可獨立重跑(resume)、平行化收益最大化、失敗隔離。' }, - { key: 'max-autonomy', angle: '視角 C「極致自主」:單一 spec-to-done 大 workflow,args 給 spec 路徑一鍵跑到 merged;所有 gate 內建為自動判斷規則,僅在 repo 規範強制「先回報」處輸出 hold 狀態收尾。優先考慮:無人值守完成率、決定論編排、最少人工介面。' }, -] - -const designs = await parallel(DESIGN_LENSES.map(d => () => - agent(`${TASK_BRIEF}\n\n## 你的設計視角\n${d.angle}\n\n## 工具深讀情報(5 份)\n${readingDigest}\n\n請產出該視角下最強的完整設計。誠實面對視角弱點並給緩解。`, - { label: `design:${d.key}`, phase: 'Design', model: 'opus' }) -)) -log(`設計完成:${designs.filter(Boolean).length}/3 份`) - -phase('Judge') -const designDigest = DESIGN_LENSES.map((d, i) => `\n\n########## 設計方案 ${d.key} ##########\n${designs[i] || '(設計失敗)'}`).join('') - -const JUDGE_LENSES = [ - { key: 'compliance', lens: 'repo 規範一致性:逐條對照 AGENTS.md 管線、4 anti-patterns、誠實鐵律、ship-item 紀律、HIGH/CRITICAL 回報義務、worktree 守衛。任何犯規都是重大扣分。' }, - { key: 'autonomy-resilience', lens: '自主可執行性與失敗復原:無人值守能跑多遠?GitNexus stale、gstack 缺 bun、CI report-generation-failed、subagent 半途死亡、context 耗盡後 resume — 每個故障點是否有可行恢復路徑?gate 停下後使用者一句話能否重入?' }, - { key: 'precision-evidence', lens: '精準完成 spec 的保證力:spec→plan 的忠實度怎麼驗?per-task 驗證夠不夠小步?browser evidence 是否真實不可偽?adversarial review 的覆蓋與誠實標註?「精準無誤」的最終 done-gate 是否可被客觀檢查?' }, -] - -const verdicts = await parallel(JUDGE_LENSES.map(j => () => - agent(`你是嚴格的工作流設計評審。以下是同一任務的 3 份設計方案與任務脈絡。\n\n${TASK_BRIEF}\n\n${designDigest}\n\n## 你的評審 lens\n${j.lens}\n\n輸出(繁體中文,固定格式):\n1. 每方案逐一:【方案 key】SCORE: x/10 — 3-6 行理由(指出具體段落的優劣)\n2. RANKING: 第一名 key > 第二名 > 第三名\n3. 給最終綜合設計的 3-5 條「必須吸收的元素」與 2-3 條「必須避免的陷阱」(可跨方案擷取)`, - { label: `judge:${j.key}`, phase: 'Judge', model: 'opus' }) -)) -log(`評審完成:${verdicts.filter(Boolean).length}/3 份`) - -return { - readings: Object.fromEntries(READERS.map((r, i) => [r.key, readings[i] || null])), - designs: Object.fromEntries(DESIGN_LENSES.map((d, i) => [d.key, designs[i] || null])), - verdicts: Object.fromEntries(JUDGE_LENSES.map((j, i) => [j.key, verdicts[i] || null])), -} \ No newline at end of file diff --git a/.claude/workflows/ui-blueprint-a-vs-b-decision.js b/.claude/workflows/ui-blueprint-a-vs-b-decision.js deleted file mode 100644 index a44bf2c52..000000000 --- a/.claude/workflows/ui-blueprint-a-vs-b-decision.js +++ /dev/null @@ -1,81 +0,0 @@ -export const meta = { - name: 'ui-blueprint-A-vs-B-decision', - description: '評估兩套 /ui 設計藍圖二選一:Option A(frontend-redesign-ia-and-phases / OperatorConsole / 現 main) vs Option B(設計規格+prototype / EdgeConsole / stash WIP),5 維度 judge + 對抗驗證 → 推薦', - phases: [ - { title: 'Judge', detail: '5 維度各一評審讀實檔評 A/B 分數+勝者' }, - { title: 'Verify', detail: '逐維度對抗驗證評審結論是否站得住' }, - ], -} - -const BASE = [ - 'repo C:/Repos/active/iot/AI-BIM-governance。這是一個「兩套 /ui 前端設計藍圖二選一」的產品決策評估。', - '', - '【Option A】= frontend-redesign-ia-and-phases.html(repo 根目錄)。UnifiedConsole / OperatorConsole:coordinator :8004 為瀏覽器唯一可達面;2-plane(GOVERNANCE PLATFORM 零GPU #/coordinator #/intake #/runtime #/review #/kit + GOVERNANCE A1–A10);A1–A10 治理「疊在 primary viewer 的 GovernanceOverlay」;console 不長 WebRTC、3D 一律 /ui/open 302 handoff;slate #020617 + JetBrains Mono + cyan #22d3ee;primary/spectator + aria-disabled 誠實 banner。**這就是現在 main(582273a→1445c39) 已實作的方向**(web-viewer-sample/src/console/OperatorConsole.tsx 為掛載入口;A1–A3 asbuilt 真資料走 governanceProxy→:49102)。', - '', - '【Option B】= docs/plans/ai-bim-governance-設計規格.md + docs/plans/ai-bim-governance-prototype.html(1030 行可點原型)。EdgeConsole:三欄式(左 4 群導覽 / 中央工作區 / 右 Chat USD Agent);左欄群=工作台 + 核心治理 CORE(A1–A5 無 GPU 可先賣) + OMNIVERSE RUNTIME(GPU 加值 A6–A10+審查室) + SYSTEM + 落地端控制台(轉檔排程/Session/Kit·GPU 機隊/MinIO,對齊真實 MinIO 結構與 NVIDIA 官方 1-GPU-per-stream / no-migrate);per-app 引導式 stepper(A1 五步閉環);誠實四標記 已實作/實測/示範/待建(AS-BUILT/artifact/DEMO DATA/NOT BUILT);token #0c0f11 底 + #84c714 綠 + 15px 系統 sans(非 JetBrains Mono)。**這就是我先前 stash 的 WIP(product-governance-console-integration)方向,也是先前部署陳舊 dist-ui 照到的那套**。', - '', - '【已知 ground-truth(前面稽核已驗,可信)】', - '- 現 main 實作 = Option A 的 OperatorConsole(精簡 6 路由:coordinator/intake/runtime/review/kit/demo-control;#/overview #/issues #/apps #/a1-a10 不存在、fallback coordinator)。EdgeConsole 在現 main 是 dead code(tree-shaken)。', - '- Option B 的程式碼以未提交 stash 形式存在(11 檔、+575 行;pages.tsx +327、EdgeConsole.tsx +105…),pop 到現 main 只有 edge-console.css 真衝突、其餘多可 auto-merge(但 AGENTS/CLAUDE auto-merge 語意要人工檢查)。', - '- repo 剛確立「四套工具治理管線」契約(AGENTS.md §0.1):Superpowers(plan)→GitNexus(impact)→實作→gstack(UI/E2E 驗收唯一證據)→detect_changes→PR;誠實鐵律(無 backend 處 UI 標 DEMO DATA/NOT BUILT/not observed);OpenSpec 流程已退役。', - '- 邊界鐵律:前端只打 coordinator :8004、不直連 :49102/:8010/:49101;「不要把 Kit 包裝成 governance 賣點」;AI 只在 session layer 操作不改 source model。', - '- A1–A10 權威:05 BIM治理 為 10 大產品項、06 操作介面總覽 為 UX 北極星;A1–A3 已 asbuilt。', - '', - '請務實、有證據(file:line 或具體段落),不要客套。也評估「hybrid(取 A 的某面 + B 的某面)」是否更優,在 rationale 註明。', -].join('\n') - -const JUDGE_SCHEMA = { - type: 'object', additionalProperties: false, - properties: { - dimension: { type: 'string' }, - scoreA: { type: 'integer', minimum: 1, maximum: 5 }, - scoreB: { type: 'integer', minimum: 1, maximum: 5 }, - winner: { type: 'string', enum: ['A', 'B', 'tie'] }, - rationale: { type: 'string' }, - evidence: { type: 'array', items: { type: 'object', additionalProperties: false, properties: { point: { type: 'string' }, where: { type: 'string' } }, required: ['point', 'where'] } }, - hybridNote: { type: 'string' }, - risksOfWinner: { type: 'string' }, - }, - required: ['dimension', 'scoreA', 'scoreB', 'winner', 'rationale', 'evidence', 'hybridNote', 'risksOfWinner'], -} - -const VERIFY_SCHEMA = { - type: 'object', additionalProperties: false, - properties: { - dimension: { type: 'string' }, - challenge: { type: 'string' }, - verdict: { type: 'string', enum: ['holds', 'weakened', 'overturned'] }, - adjustedWinner: { type: 'string', enum: ['A', 'B', 'tie'] }, - note: { type: 'string' }, - }, - required: ['dimension', 'challenge', 'verdict', 'adjustedWinner', 'note'], -} - -const DIMS = [ - { key: 'arch', title: '架構與邊界對齊', - lens: 'coordinator :8004 唯一可達面、前端不直連內部服務、「不要把 Kit 包裝成 governance 賣點」、session-layer-only、primary/spectator。哪個藍圖更貼合 AGENTS.md 邊界與系統架構?B 的「落地端控制台(轉檔/Session/機隊)」與 A 的「console 不長 WebRTC、一律 handoff」各自如何符合或違反邊界?' }, - { key: 'honesty', title: '誠實降級鐵律 + 四工具契約相容', - lens: '誠實標記嚴謹度(A:aria-disabled+理由 banner+A4–A10 disabled;B:已實作/實測/示範/待建 四標記、port-has-listen≠frame)。哪個更貼合剛 merged 的四工具契約(gstack 為 UI 驗收唯一證據)與 DEMO DATA/NOT BUILT/not observed?哪個更不會「假裝完成」?' }, - { key: 'cost', title: '落地成本與現況程式碼距離', - lens: 'A = 現 main 已實作(OperatorConsole shipped、A1–A3 asbuilt)→ 採 A 幾乎零重做。B = stash WIP 部分 + 還缺三欄殼/落地端控制台/per-app stepper/新 token 系統 + 與現 main 衝突。逐項估「從現況到該藍圖」的工時/風險。讀 web-viewer-sample/src/console/OperatorConsole.tsx 與 EdgeConsole.tsx 對照。' }, - { key: 'product', title: '產品 / 商業敘事與 UX 北極星(06)', - lens: 'B 明確切 CORE(無 GPU 可先賣)/OMNIVERSE(GPU 加值)/落地端控制台(維運) + per-app 引導式 stepper + 三欄 Chat USD Agent;A 是精簡治理 console + viewer overlay。哪個對「賣點分層、新手 onboarding、對齊 05 BIM治理/06 操作介面北極星」更強?B 是否過度膨脹?' }, - { key: 'runtime', title: 'Kit/GPU runtime 現實、維運完整度與設計 token', - lens: 'B 引 NVIDIA 官方(1 GPU/stream、無 migrate API、terminate+recreate、shader cache) + 落地端控制台(機隊/Session 端點池/真實 MinIO 結構);A 的 handoff + endpoint pool。哪個對「多 GPU/多 session 維運」更完整且不誤導?另比較兩套 design token(#020617+JetBrains Mono vs #0c0f11+#84c714 15px sans) 與現 edge-console.css(#0b0d10) 的遷移成本與一致性。' }, -] - -const results = await pipeline( - DIMS, - d => agent( - BASE + '\n\n# 評審維度:' + d.title + '\n\n## 評估重點\n' + d.lens + - '\n\n## 必讀檔\n- Option A:frontend-redesign-ia-and-phases.html\n- Option B:docs/plans/ai-bim-governance-設計規格.md、docs/plans/ai-bim-governance-prototype.html\n- 契約/邊界:AGENTS.md(§0.1 開發管線)\n- 現況碼:web-viewer-sample/src/console/OperatorConsole.tsx、EdgeConsole.tsx(按需 Grep)\n\n給 scoreA/scoreB(1–5)、winner、rationale、evidence(附 where)、hybridNote(是否該混搭)、risksOfWinner。', - { label: 'judge:' + d.key, phase: 'Judge', schema: JUDGE_SCHEMA } - ), - (j, d) => agent( - BASE + '\n\n# 對抗驗證:維度「' + d.title + '」\n\n評審結論:winner=' + j.winner + '(A=' + j.scoreA + ' / B=' + j.scoreB + ')。rationale:' + j.rationale + - '\n\n請當 devil’s advocate:盡力反駁這個 winner(找反證、被忽略的成本/邊界/誠實風險、或證據是否站得住)。回到實檔查證。verdict=holds/weakened/overturned;adjustedWinner=你查證後的勝者;note 寫關鍵反證或為何結論仍成立。', - { label: 'verify:' + d.key, phase: 'Verify', schema: VERIFY_SCHEMA } - ).then(v => ({ judge: j, verify: v })) -) - -return results \ No newline at end of file diff --git a/.gitignore b/.gitignore index bf16e2c46..6803689d1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ Thumbs.db !.claude/skills/omniverse-cad-to-simready/ !.claude/skills/omniverse-realtime-viewer/ !.claude/skills/omniverse-usd-performance-tuning/ +# Tracked GitNexus CLI skills + repo-health(2026-07-02 治理審計:CLAUDE.md MUST 規則引用的檔案必須入版控) +!.claude/skills/gitnexus/ +!.claude/skills/repo-health/ # Tracked agent assets: workflows/commands/agents/settings (2026-06-10) !.claude/workflows/ !.claude/commands/ diff --git a/AGENTS.md b/AGENTS.md index 7a3a2ff10..aacefd532 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -55,19 +55,7 @@ → branch → PR → Actions → merge ``` -| 工具 | 唯一職責(單線,不可越界) | -|---|---| -| **Superpowers** | 主線 plan / execution governance:`writing-plans` 拆分期 plan → `subagent-driven-development` 執行 → `verification-before-completion` done-gate | -| **GitNexus** | code intelligence:改 symbol 前 `impact`(HIGH / CRITICAL 先回報)、commit 前 `detect_changes` 驗 scope | -| **gstack** | browser QA / screenshot / E2E evidence:user-facing 完成的**唯一驗收證據來源** | -| **Matt Pocock skills** | 僅 optional 輔助:issue / triage / domain-doc;**不得當主線** | - -禁止(anti-patterns): - -- ❌ 用 Matt Pocock skills 取代 Superpowers plan。 -- ❌ 用 Superpowers 宣告 UI 完成而不跑 gstack。 -- ❌ 用 GitNexus 當產品設計依據(設計來自 spec / prototype,非 call graph)。 -- ❌ 用 gstack 改 backend symbol 而跳過 GitNexus impact。 +四工具職責表與 anti-patterns 的完整定義見 `docs/agents/github-workflow.md`(單一權威版,避免雙表漂移);一句話分工:**Superpowers**=plan / execution 主線、**GitNexus**=impact / detect_changes、**gstack**=user-facing 驗收唯一證據、**Matt Pocock skills**=僅 issue / triage 輔助不得當主線。 誠實鐵律(repo contract:前端要真的能操作,不能只接 mock):某部分還沒 backend 時,UI 須誠實標 `DEMO DATA`/`NOT BUILT`/`not observed`,不得假裝 ready。完成標準與 frontend-operable rule 見上方「產品定位與完成標準」。 @@ -75,8 +63,8 @@ - 不在 `main` 上開發;plan / 設計文件預設繁體中文,API 路徑 / schema 欄位 / CLI flags / status enum / log / error / 外部產品名稱保留原文。 - `.claude/`、`.codex/`、`.agents/`、`.gitnexus/` 是本機 agent/tooling 產物,預設維持 ignored(含以 `skills` CLI 裝進 `.claude/skills/` 的技能)。 -- Repo-local `.codex/skills` SHALL 對齊 `.claude/skills` 作為本機 skill inventory;OpenSpec / opsx closed-loop skills 已退役,需求拆解與執行治理改由 Superpowers skills 負責。 -- 不提交 `.claude/skills/generated/`、`.codex/skills/` 或 GitNexus generated skill 檔,除非使用者明確要求改變 repo policy。 +- Repo-local `.codex/skills` SHALL 對齊 `.claude/skills` 作為本機 skill inventory(本機同步,非版控同步);OpenSpec / opsx closed-loop skills 已退役,需求拆解與執行治理改由 Superpowers skills 負責。 +- `.claude/` 版控白名單以 root `.gitignore` 的 `!.claude/...` 例外清單為準(2026-07-02 治理審計起含 `skills/gitnexus/`、`skills/repo-health/`——CLAUDE.md MUST 規則引用的檔案必須入版控);`.claude/skills/generated/` 與其餘未白名單技能不提交。`.codex/skills` 除既有 tracked 檔(`spec-to-done` adapter 等)外維持本機鏡像不入版控:`pr-review-agent` 對 `.codex/skills` 路徑的新增/修改一律 high blocker(`scripts/lib/pr-review-agent.ps1:343` hard-coded;連既有 tracked 的 `.codex/skills/spec-to-done/SKILL.md` 修改也會擋,屬已知張力,放寬須使用者拍板)。 完整 GitHub PR workflow 見 `docs/agents/github-workflow.md`。 diff --git a/CLAUDE.md b/CLAUDE.md index 64df5bbc6..f09c1953a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,12 +24,10 @@ installed skills / generated wiki / generated skills - 非平凡變更先列出假設、成功標準、最小改動面,再做最小可回復 diff。 - 非平凡 / 高風險任務先做 task tier 判斷、worker dispatch 或說明不派 worker 的理由,最終回覆區分 verified facts / inferences / unverified risks;完整規則見 `docs/agents/advanced-agent-reasoning-contract.md`。 - 不修改 secrets / private keys / `.env` 實際機密值;不新增 production dependency 不解釋。 -- 修改 function / class / method 前依 GitNexus 規範做 impact analysis;HIGH / CRITICAL 先回報。 - 非平凡功能用 superpowers `writing-plans` → `subagent-driven-development` → `verification-before-completion`;不在 `main` 上開發,走 branch → PR → Actions → merge。 -- A1–A10 是本 repo 主要產品項;user-facing feature 必須可從前端 route 操作並有 browser E2E evidence,backend-only done 不接受。 +- 需求效力序與 A1–A10 建成裁決依 `AGENTS.md` §0.1(docs-plans-README §1 > 互動實作規格 A.1.1 > 對齊矩陣 §4.4);前端改動前必讀後端凍結契約(前端對齊DS手冊 §1)。user-facing feature 必須可從前端 route 操作並有 browser E2E evidence,backend-only done 不接受。 - deploy / runtime / demo 行為必須回到 `scripts/deploy.ps1` golden path;新增 root-level start / smoke / check script 預設視為邊界風險。 -- 測試部署區重建口令固定執行 `.\scripts\dev\rebuild-test-deploy.ps1 -Build`;helper 必須從 freshly fetched `origin/main` 重建 `D:\Users\deploy\AI-bim-geo`,排除 agent/tooling 檔案與 root `docs/`、`openspec/`、`patches/` 後由部署區執行 `.\scripts\deploy.ps1 -Build`。禁止 `-DryRun`。 -- 已授權:若 `deploy.ps1 -Build` 被外部 `kit.exe` / conversion `python.exe` 等 host-native runtime blocker 佔用必要 ports 擋住,可停止該 blocking PID 並重跑同一條 `-Build`;不得改用 `-Force` / `-DryRun`。 +- 測試部署區重建口令固定執行 `.\scripts\dev\rebuild-test-deploy.ps1 -Build`(禁 `-DryRun`;helper 詳規、排除清單與 blocking PID 授權見 `docs/agents/product-operability-and-script-contract.md` §6 與 `AGENTS.md` §0.1)。 開發管線(四套工具不平權,固定「主流程 + 輔助」;完整版見 `AGENTS.md` §0.1): @@ -61,6 +59,7 @@ installed skills / generated wiki / generated skills | 跑 sub-repo 驗證(pytest / npm test / build / Cloud VM 啟動) | `docs/agents/sub-repo-verify-commands.md` | | 非平凡 / 高風險任務分級、worker dispatch、evidence labels、reviewer perspectives | `docs/agents/advanced-agent-reasoning-contract.md` | | 看舊 PR、了解退役服務與歷史 spec 脈絡 | `docs/agents/history-and-archive.md` | +| 查需求效力序、正典路由 A.1.1、A1–A10 建成裁決(§4.4)、後端凍結契約(§1) | `docs/plans/docs-plans-README.md`(跳板)→ 各 plans 檔 | 行數預算:本檔 ≤ 130 行(目標 ≤ 100);AGENTS.md ≤ 250 行(目標 ≤ 200)。預算規範見 spec `agent-doc-context-budget`。 @@ -76,7 +75,7 @@ python -m pytest tests -p no:cacheprovider ## 4. GitNexus 入口 -修改 code symbol 前 MUST 跑 `gitnexus_impact`;commit 前 MUST 跑 `gitnexus_detect_changes`;HIGH / CRITICAL risk 先回報再繼續。完整規範與 CLI skill 對應表見 `docs/agents/gitnexus-usage.md`。 +修改 code symbol 前 MUST 跑 `impact`;commit 前 MUST 跑 `detect_changes`;HIGH / CRITICAL risk 先回報再繼續。規範本文以下方自動維護區塊為準;stale 重建與 crash 復原見 `docs/agents/gitnexus-usage.md`。 # GitNexus — Code Intelligence diff --git a/bim-review-coordinator/AGENTS.md b/bim-review-coordinator/AGENTS.md index 0159b3840..764ca059f 100644 --- a/bim-review-coordinator/AGENTS.md +++ b/bim-review-coordinator/AGENTS.md @@ -4,9 +4,11 @@ ## Role -`bim-review-coordinator` 是外部 IFC-ready intake、metadata-only callback outbox 與 Session / Collaboration Control Plane。它負責建立 review session、協調 viewer 與 streaming server 的連線資訊、廣播多人協作事件,並保存最小 local shadow metadata。 +`bim-review-coordinator` 是外部 IFC-ready intake、metadata-only callback outbox 與 Session / Collaboration Control Plane。它負責建立 review session、協調 viewer 與 streaming server 的連線資訊、廣播 presence 等基本 session 事件,並保存最小 local shadow metadata。 -服務埠口:`127.0.0.1:8004` +服務埠口:`127.0.0.1:8004`(含 Socket.IO) + +> **退役狀態(2026-05-21,change `remove-conflict-review-from-fast-mvp`)**:`highlightRequest` / `selectionUpdate` / `annotationCreate` 等 collaboration Socket.IO event handlers 已自本 service 移除(`src/socket/reviewNamespace.ts`);`getReviewIssues` / `createAnnotation` / `/api/model-versions/:id/review-bootstrap` 也已刪。`/api/review-sessions/:id/events` 與 `/lifecycle-events` 仍保留;lifecycle endpoint 排除 collaboration event 的 wording 保留作 archive compatibility(舊 event log 仍可能含這些 type)——不要把這些已刪 handler 當 regression 加回來。 ## Owns @@ -32,8 +34,18 @@ - 本服務只協調 session、collaboration、intake 與 callback outbox,不取代外部公司雲端 control-plane 成為長期 metadata authority。 - 不得引入 Omniverse / `pxr` / `omni.*` dependency。 - 不得直接控制 Kit viewport、camera、material;runtime operation 屬於 `bim-streaming-server`。 +- 不直接保存大型模型檔案 byte。**例外 carve-out(2026-05-21,change `fast-ifc-link-demo-loop`)**:`POST /api/external/ifc-ready` 同步階段允許把外部 IFC 下載到本地 shared volume(`storage/ifc-cache//source.ifc`)作 dispatch 前臨時通道(實作 `src/services/ifcDownloader.ts`);coordinator 不因此成為 IFC bytes 權威。production 應設 `IFC_DOWNLOAD_STRICT=true` / `fallbackOnFetchError=false` 強制真實下載。 - User-facing flow 需要本服務參與時,API done 不等於 feature done;必須同步確認 `web-viewer-sample` 有可操作 route / button / E2E evidence。 +權威歸屬速查: + +| 行為 | 此 repo 角色 | +|---|---| +| review session state / presence broadcast / stream config / external IFC-ready intake / cloud callback outbox | **owner** | +| project / artifact metadata | reference only(owner 在外部公司雲端 control-plane) | +| file / conversion body | 不擁有(owner 在 `bim-streaming-server` / 外部 artifact store) | +| 3D runtime state | 不參與(owner 在 `bim-streaming-server`) | + ## Before Editing - 先讀 `README.md`、`src/`、`tests/`、`package.json` 與相關 contract。 diff --git a/bim-review-coordinator/CLAUDE.md b/bim-review-coordinator/CLAUDE.md index 0d0757977..f034844c2 100644 --- a/bim-review-coordinator/CLAUDE.md +++ b/bim-review-coordinator/CLAUDE.md @@ -1,56 +1,11 @@ -# bim-review-coordinator — Local Boundary Rules +# bim-review-coordinator — Claude Mirror Entry -本檔是 sibling [`AGENTS.md`](AGENTS.md) 的 Claude 鏡像入口;七段 schema(Role / Owns / Does Not Own / Required Boundaries / Before Editing / Verify / Done Criteria)以 sibling `AGENTS.md` 為準,本檔只列在此 repo 工作時必須遵守的最小規則。 +本檔是 sibling [`AGENTS.md`](AGENTS.md) 的 Claude 鏡像入口。完整規則(七段 schema、collaboration handler 退役狀態、ifc-cache carve-out、權威歸屬表)以 sibling `AGENTS.md` 為準;衝突時依根目錄 `CLAUDE.md` §1 優先序解析。 -> 完整跨 repo 邊界見根目錄 [`AGENTS.md`](../AGENTS.md) §1 與 [`docs/agents/repo-boundary-detail.md`](../docs/agents/repo-boundary-detail.md)。 -> 衝突時依根目錄 [`CLAUDE.md`](../CLAUDE.md) §1 優先序解析。 +重點:唯一對外 IFC-ready intake(`POST /api/external/ifc-ready`,Service auth + idempotency)+ Session Control Plane + metadata-only callback outbox(`localhost:8004` 含 Socket.IO)。不渲染 3D、不存大型模型 byte(`storage/ifc-cache/` 臨時通道除外)、不當 metadata 權威;governance 一律經 `/api/governance/*` proxy。完整跨 repo 邊界見根目錄 [`docs/agents/repo-boundary-detail.md`](../docs/agents/repo-boundary-detail.md) §3.4。 -## Role - -IFC-ready Intake / Callback Outbox / Session Control Plane — 唯一外部 IFC-ready intake;協調 browser client 與 Kit streaming server 的連線資訊;廣播 presence(`joinSession` / `leaveSession` / `presenceUpdated`)等基本 session 事件;將 streaming conversion 結果放入 metadata-only callback outbox。 - -> **退役狀態(2026-05-21,change `remove-conflict-review-from-fast-mvp`)**: -> `highlightRequest` / `selectionUpdate` / `annotationCreate` 等 collaboration -> Socket.IO event handlers 已從本 service 移除(`src/socket/reviewNamespace.ts`); -> `getReviewIssues` / `createAnnotation` / `/api/model-versions/:id/review-bootstrap` -> 也已刪。`/api/review-sessions/:id/events` 與 `/lifecycle-events` 仍保留; -> lifecycle endpoint 排除 collaboration event 的語意 wording 保留作 archive -> compatibility(舊 event log 仍可能含這些 type)。 - -埠口:`localhost:8004`(含 Socket.IO) - -## MUST - -- 外部 IFC-ready 只進 `POST /api/external/ifc-ready`;internal conversion result / callback outbox 端點必須使用 internal token。 -- Session lifecycle 事件(create / join / leave / dispose)必須由本服務集中管理。 -- API / Socket.IO event schema 變更必同步 `docs/contracts/` 下對應 contract,並更新 `tests/` fixture。 -- 提交前跑 `npm run verify`(= `npm run build && npm test`)。 - -## MUST NOT - -- ❌ 渲染 3D / 開啟 USD stage / 處理 GPU。 -- ❌ 直接保存大型模型檔案 byte(屬於 streaming/data-plane artifact storage)。 - > **例外 carve-out(2026-05-21,change `fast-ifc-link-demo-loop`)**:`POST /api/external/ifc-ready` 同步階段允許 coordinator 把外部 IFC 下載到本地 shared volume(`storage/ifc-cache//source.ifc`)作 dispatch 前臨時通道。coordinator 不視為該 IFC bytes 資料權威;`bim-streaming-server` 為 conversion authority,外部公司雲端為 control-plane 權威。實作:`src/services/ifcDownloader.ts` + `POST /api/external/ifc-ready` 內同步呼叫。production 應設 `IFC_DOWNLOAD_STRICT=true`/`fallbackOnFetchError=false` 強制真實下載。 -- ❌ 取代外部公司雲端 control-plane 成為 metadata 權威(本服務只保存最小 shadow metadata)。 -- ❌ 取代 `web-viewer-sample` 成為 UI(本服務不渲染畫面、不送 view-layer 樣式)。 -- ❌ 引入 Omniverse / `pxr` / `omni.*` 套件。 -- ❌ 直接控制 Kit 進程的 viewport / camera / material(runtime 操作必須透過 DataChannel 由 `web-viewer-sample` 發出,或由 streaming server 自治)。 - -## Verify 入口 +Verify: ```bash -npm run verify +npm run verify # = npm run build && npm test ``` - -## 權威歸屬 - -| 行為 | 此 repo 角色 | -|---|---| -| review session state | **owner** | -| presence / selection broadcast | **owner** | -| stream config 給 viewer | **owner** | -| external IFC-ready intake | **owner** | -| cloud callback outbox | **owner** | -| project / artifact metadata | **reference only**(owner 在外部公司雲端 control-plane) | -| file / conversion body | **不擁有**(owner 在 `bim-streaming-server` / 外部 artifact store) | -| 3D runtime state | 不參與(owner 在 `bim-streaming-server`) | diff --git a/bim-streaming-server/.gitignore b/bim-streaming-server/.gitignore index fde65c720..3d63a846f 100644 --- a/bim-streaming-server/.gitignore +++ b/bim-streaming-server/.gitignore @@ -61,7 +61,7 @@ logs/ # Local agent / browser automation artifacts /.claude/ /.playwright-mcp/ -/CLAUDE.md +# /CLAUDE.md un-ignored 2026-07-02(治理審計:薄鏡像入版控,PR review 可見) /current-stream-*.png /stream-validation-*.png /.codex diff --git a/bim-streaming-server/CLAUDE.md b/bim-streaming-server/CLAUDE.md new file mode 100644 index 000000000..0a25092ab --- /dev/null +++ b/bim-streaming-server/CLAUDE.md @@ -0,0 +1,13 @@ +# bim-streaming-server — Claude Mirror Entry + +本檔是 sibling [`AGENTS.md`](AGENTS.md) 的 Claude 鏡像入口。完整規則(七段 schema)以 sibling `AGENTS.md` 為準;衝突時依根目錄 `CLAUDE.md` §1 優先序解析。 + +重點:Omniverse Kit Runtime / GPU Streaming Server + B 方案 IFC→USDC conversion authority(WebRTC `127.0.0.1:49100`、conversion `:49101`)。runtime state 只代表當前 stream session——要成為正式審查資料必須經 `bim-review-coordinator` 或外部公司雲端 control-plane;metadata 查詢一律走 coordinator,本服務不管理 session lifecycle、不持久化 annotation / issue、不當檔案倉庫。DataChannel payload schema 變更必同步 `web-viewer-sample` 與 `docs/contracts/streaming-datachannel.md`。完整跨 repo 邊界見根目錄 [`docs/agents/repo-boundary-detail.md`](../docs/agents/repo-boundary-detail.md) §3.5。 + +Verify(低成本 smoke): + +```powershell +powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\tests\test-stage-loading-contract.ps1 +``` + +完整驗證:`.\repo.bat build` / `.\repo.bat test`;workspace 聚合:`scripts\verify-all.ps1 -StreamingOnly`。 diff --git a/docs/agents/github-workflow.md b/docs/agents/github-workflow.md index bac17c9d1..9bb38ab30 100644 --- a/docs/agents/github-workflow.md +++ b/docs/agents/github-workflow.md @@ -16,6 +16,22 @@ GitHub Actions = 自動驗證 Merge = 正式接受變更 ``` +四工具職責表(單一權威版;`AGENTS.md` §0.1 指向本表): + +| 工具 | 唯一職責(單線,不可越界) | +|---|---| +| **Superpowers** | 主線 plan / execution governance:`writing-plans` 拆分期 plan → `subagent-driven-development` 執行 → `verification-before-completion` done-gate | +| **GitNexus** | code intelligence:改 symbol 前 `impact`(HIGH / CRITICAL 先回報)、commit 前 `detect_changes` 驗 scope | +| **gstack** | browser QA / screenshot / E2E evidence:user-facing 完成的**唯一驗收證據來源** | +| **Matt Pocock skills** | 僅 optional 輔助:issue / triage / domain-doc;**不得當主線** | + +禁止(anti-patterns): + +- ❌ 用 Matt Pocock skills 取代 Superpowers plan。 +- ❌ 用 Superpowers 宣告 UI 完成而不跑 gstack。 +- ❌ 用 GitNexus 當產品設計依據(設計來自 spec / prototype,非 call graph)。 +- ❌ 用 gstack 改 backend symbol 而跳過 GitNexus impact。 + ## 開分支前 - 從最新 `main` 建立並切換到功能 branch(例:`feat/`、`fix/`、`chore/`)。 diff --git a/docs/agents/repo-boundary-detail.md b/docs/agents/repo-boundary-detail.md index be0253418..3ef1f7996 100644 --- a/docs/agents/repo-boundary-detail.md +++ b/docs/agents/repo-boundary-detail.md @@ -22,7 +22,10 @@ AI-BIM-governance/ AI-BIM-governance/ ├── bim-review-coordinator/ # 控制中心,localhost:8004 ├── bim-streaming-server/ # Kit streaming + IFC→USDC authority,WebRTC 49100 +├── governance-service/ # A1/A2/A3 governance authority,127.0.0.1:49102 loopback ├── web-viewer-sample/ # browser client,localhost:5173 +├── apps/kit-manager-web/ # Kit Manager operator UI +├── services/kit-manager-api/ # Kit Manager API,:8010 └── tests/ # external platform contracts + test-only fakes ``` @@ -30,15 +33,19 @@ AI-BIM-governance/ flowchart TD CO[bim-review-coordinator
Control Plane] KIT[bim-streaming-server
IFC→USDC Authority + Kit Runtime] + GOV[governance-service
A1/A2/A3 Governance Authority :49102] CLOUD[[external company-cloud bim-control
Control Plane]] EDGE[[external customer-edge IFC Worker]] WV[web-viewer-sample
Browser Client] + KM[kit-manager web + api :8010] EDGE -->|POST /api/external/ifc-ready| CO CO -->|start / check / reference process| KIT + CO -->|/api/governance/* proxy| GOV CO -->|metadata-only callback outbox| CLOUD WV -->|REST: create/join session| CO WV -->|WebRTC + DataChannel| KIT + KM -->|Kit fleet ops / telemetry| KIT ``` 其中: @@ -112,16 +119,20 @@ flowchart LR CLOUD["[外部] 公司雲端 bim-control"] CO["bim-review-coordinator\nExternal IFC-ready intake + Session / Control Plane"] KIT["bim-streaming-server\nIFC→USDC Authority\n+ Omniverse Kit Runtime"] + GOV["governance-service\nA1/A2/A3 Governance Authority\n127.0.0.1:49102 loopback"] WV["web-viewer-sample\nBrowser Client"] + KM["kit-manager web + api\n:8010"] EDGE -->|POST /api/external/ifc-ready| CO CO -->|internal conversion request| KIT + CO -->|/api/governance/* proxy| GOV CO -->|metadata-only callback outbox| CLOUD WV -->|REST: create / join session| CO WV -->|WebRTC video + DataChannel JSON| KIT WV -->|Socket.IO / WebSocket state events| CO CO -->|optional collaboration state| KIT WV -->|annotation / issue interaction| CO + KM -->|Kit fleet ops / telemetry| KIT ``` 一句話定位: @@ -131,7 +142,9 @@ flowchart LR [外部] IFC Worker = 客戶落地端 IFC 產出者(本 repo 不啟動) bim-review-coordinator = 唯一對外 IFC-ready intake + Session / 協作控制中心 bim-streaming-server = IFC→USDC conversion authority + Omniverse GPU / USD / WebRTC Runtime +governance-service = A1 rule-run / A2 diff / A3 federation / issue / BCF loopback authority(僅 coordinator proxy 可達) web-viewer-sample = Browser 操作端與串流觀看端 +kit-manager web + api = operator-facing Kit 機隊 UI / API(:8010) tests/fakes/contracts = 外部平台 test-only doubles,非 runtime profile ``` @@ -331,6 +344,24 @@ file / conversion access → _worker --- +## 3.7 `governance-service/` + +### 角色 + +A1「BIM 治理與模型檢核」與 A2 diff / A3 federation 的 core governance backend authority。落地端內部 Python/FastAPI 服務(`127.0.0.1:49102` loopback),對真實 IFC 跑宣告式規則集(`rules/*.yaml` DSL + `rule_engine/`),產出 governance score、failed elements、issue / BCF / diff / federation 等 CPU governance results。純 CPU host-native ifcopenshell,無 GPU / Kit 依賴。 + +### 邊界 + +- MUST 綁 `127.0.0.1`;瀏覽器 MUST NOT 直連,一律經 coordinator `/api/governance/*` proxy(缺席時 coordinator 誠實回 502)。 +- MUST 唯讀消費既有 `element_mapping.json`;不自行轉檔、不改寫 USDC(conversion 屬 `bim-streaming-server` :49101)。 +- 以 `ifc_guid` 為主鍵;`usd_prim_path` 未對映時為 `null`,不捏造;fake/smoke mapping 不得當真實覆蓋率。 +- 不擁有:對外控制面 / session / callback outbox(coordinator)、瀏覽器 UI(web-viewer-sample)、Kit runtime(streaming)。 +- 詳細規則見 `governance-service/AGENTS.md`(七段 schema)。 + +## 3.8 `apps/kit-manager-web/` 與 `services/kit-manager-api/` + +Operator-facing Kit 機隊管理:`kit-manager-api`(FastAPI `:8010`)掌 Kit instance 啟停 / 遙測;`kit-manager-web`(Vite)是 operator UI。不參與 IFC 轉檔、governance 判定與 review session lifecycle;詳細規則見各自 `AGENTS.md`。 + ## 4. 資料類型與歸屬 | 資料類型 | 權威 repo / folder | 說明 | diff --git a/docs/agents/sub-repo-verify-commands.md b/docs/agents/sub-repo-verify-commands.md index 26c2b6e3b..a659c8e22 100644 --- a/docs/agents/sub-repo-verify-commands.md +++ b/docs/agents/sub-repo-verify-commands.md @@ -87,6 +87,16 @@ python -m pytest tests/test_conversion_authority_api.py -q Kit 渲染需要 Windows host-native(NVIDIA driver);WSL2 / Docker 無 GPU graphics 通道,不可在容器跑 Kit runtime(見 agent memory `kit-gpu-render-needs-windows-native.md`)。 +## governance-service (Python host-native, port 49102) + +```powershell +cd governance-service +& "C:\Program Files\Python312\python.exe" -m pytest tests/ -v +& "C:\Program Files\Python312\python.exe" scripts/run_governance_evidence.py +``` + +須走 host-native `C:\Program Files\Python312\python.exe`(具 ifcopenshell 0.8.5 + ifctester);勿用 WSL / Docker(本服務 CPU-only,無 GPU 需求)。真實 IFC evidence 落 `docs/evidence/governance-rule-run-pass/`。 + ## web-viewer-sample (Vite, port 5173) ```powershell diff --git a/docs/superpowers/specs/2026-07-02-agent-governance-doc-alignment.md b/docs/superpowers/specs/2026-07-02-agent-governance-doc-alignment.md index 6b1a71434..eb2df56b3 100644 --- a/docs/superpowers/specs/2026-07-02-agent-governance-doc-alignment.md +++ b/docs/superpowers/specs/2026-07-02-agent-governance-doc-alignment.md @@ -37,4 +37,12 @@ ## 驗收 - 本地 `check-pr-body-evidence.ps1` 預跑通過;GitNexus `detect_changes` 無 code symbol 變更、risk low。 - CI 11 項 required checks 全綠。 -- P1 完成後 root CLAUDE.md ≤100 行、AGENTS.md ≤200 行;`diff -rq .claude/skills .codex/skills` 僅剩刻意設計的 adapter copy 差異。 +- P1 完成後 root CLAUDE.md 與 AGENTS.md 均低於硬預算(≤130 / ≤250)並向目標(≤100 / ≤200)收斂;「目標行數」的剩餘缺口為 GitNexus embedded block(工具自動維護、不可手動刪)與刻意的鏡像設計(CLAUDE.md 高頻規則本文化,避免每 session 追讀 AGENTS.md 反而多耗 token),屬已審酌的取捨。`diff -rq .claude/skills .codex/skills` 僅剩刻意設計的 adapter copy 差異。 + +## 執行紀錄 + +- P0:PR #274 merged(2026-07-02);首輪撞 missing_openspec,補本 spec 檔後綠。 +- CARC §2 補登:PR #276 merged(2026-07-02)。 +- P1:PR #275——首輪 pr-review-agent 抓出 `.codex/skills` 8 檔撞 `generated_tooling_path` hard blocker(`scripts/lib/pr-review-agent.ps1:343`)。依「不由 agent 自行放寬 review gate」原則縮範圍:`.codex` 側退出版控、維持本機鏡像(`git rm --cached` + 還原 `.gitignore` codex 白名單),`.claude` 側 7 檔納管照舊;AGENTS.md「本機 agent 產物」政策句同步明文化。`.codex/skills/spec-to-done` 的 stale 同步 diff 暫存本機,待使用者拍板規則調整後再入。 +- P1b(進行中):repo-boundary-detail 歷史敘事遷移 → history-and-archive(sonnet 起草 + 守恆/現行性雙 judge + 主對話審批,ultracode workflow)。 +- P2:worktree 殘骸與 generated 快照已由使用者手動清除(2026-07-02);`.codex` drift 7 檔本機同步完成;agent memory 整併完成;global Hermes 五件套與 23 個無關 skills 留使用者決定。 diff --git a/web-viewer-sample/.gitignore b/web-viewer-sample/.gitignore index d1efdc98a..634354552 100644 --- a/web-viewer-sample/.gitignore +++ b/web-viewer-sample/.gitignore @@ -30,7 +30,7 @@ yalc.lock # Local agent artifacts /.claude/ -/CLAUDE.md +# /CLAUDE.md un-ignored 2026-07-02(治理審計:薄鏡像入版控,PR review 可見) # Stray dir created when %SystemDrive% env var failed to expand under bash/MSYS /%SystemDrive%/ diff --git a/web-viewer-sample/AGENTS.md b/web-viewer-sample/AGENTS.md index bb55f44b4..dad9b959c 100644 --- a/web-viewer-sample/AGENTS.md +++ b/web-viewer-sample/AGENTS.md @@ -52,7 +52,7 @@ npm run verify 目前 `npm run verify` 等同: ```powershell -npm run build +npm run build && npm test && npm run test:struct-log ``` `npm run lint` 可手動使用,但既有 lint baseline 尚未清零,不能當作目前跨 repo hard gate。 diff --git a/web-viewer-sample/CLAUDE.md b/web-viewer-sample/CLAUDE.md new file mode 100644 index 000000000..e59e2805a --- /dev/null +++ b/web-viewer-sample/CLAUDE.md @@ -0,0 +1,11 @@ +# web-viewer-sample — Claude Mirror Entry + +本檔是 sibling [`AGENTS.md`](AGENTS.md) 的 Claude 鏡像入口。完整規則(七段 schema)以 sibling `AGENTS.md` 為準;衝突時依根目錄 `CLAUDE.md` §1 優先序解析。 + +重點:Browser Client / EdgeConsole UI(dev `127.0.0.1:5173`;正式產品入口是 coordinator `:8004/ui`)。session / metadata / file URL 一律經 `bim-review-coordinator`,不得讓瀏覽器直連 governance `:49102` 等 internal loopback;與 streaming server 的互動限 WebRTC video + DataChannel JSON command;不啟停 Kit、不轉檔、不在前端保存權威資料(顯示用 cache OK)。Codex 執行防呆:本 repo `.codex/config.toml` 為 project-level guardrail,sandbox 寫入限本 repo root。完整跨 repo 邊界見根目錄 [`docs/agents/repo-boundary-detail.md`](../docs/agents/repo-boundary-detail.md) §3.6。 + +Verify: + +```powershell +npm run verify # = npm run build && npm test && npm run test:struct-log +```