From 7c8f0564474b8c5bf50eb9c1edaf2b9a7d961220 Mon Sep 17 00:00:00 2001 From: Lum1104 Date: Sat, 28 Mar 2026 18:50:29 +0800 Subject: [PATCH] feat(agents): add non-code pattern detection to architecture analyzer Add deployment topology detection (Dockerfile -> compose -> K8s), data pipeline detection (schema -> migration -> API -> client), documentation coverage analysis, and cross-category dependency analysis. Update layer hints for infrastructure, documentation, data, ci-cd, and configuration layers. Expand directory pattern matching with non-code patterns. Increase max layer count from 7 to 10 to accommodate non-code layers. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../architecture-analyzer-prompt.md | 223 ++++++++++++++++-- 1 file changed, 202 insertions(+), 21 deletions(-) diff --git a/understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md b/understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md index fb4dca4..66d61c3 100644 --- a/understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md +++ b/understand-anything-plugin/skills/understand/architecture-analyzer-prompt.md @@ -2,11 +2,11 @@ > Used by `/understand` Phase 4. Dispatch as a subagent with this full content as the prompt. -You are an expert software architect. Your job is to analyze a codebase's file structure, summaries, and import relationships to identify logical architectural layers and assign every file to exactly one layer. Your layer assignments must be well-reasoned and reflect the actual organization of the code. +You are an expert software architect. Your job is to analyze a codebase's file structure, summaries, and import relationships to identify logical architectural layers and assign every file to exactly one layer. Your layer assignments must be well-reasoned and reflect the actual organization of the code, including non-code files like configs, documentation, infrastructure, and data schemas. ## Task -Given a list of file nodes (with paths, summaries, tags) and import edges, identify 3-7 logical architecture layers and assign every file node to exactly one layer. You will accomplish this in two phases: first, write and execute a script that computes structural patterns from the import graph and file paths; second, use those structural insights to make semantic layer assignments. +Given a list of file nodes (with paths, summaries, tags, and node types) and import edges, identify 3-10 logical architecture layers and assign every file node to exactly one layer. You will accomplish this in two phases: first, write and execute a script that computes structural patterns from the import graph and file paths; second, use those structural insights to make semantic layer assignments. --- @@ -20,10 +20,18 @@ Write a Node.js script that analyzes the file paths and import edges to compute ```json { "fileNodes": [ - {"id": "file:src/routes/index.ts", "name": "index.ts", "filePath": "src/routes/index.ts", "summary": "...", "tags": ["api-handler"]} + {"id": "file:src/routes/index.ts", "type": "file", "name": "index.ts", "filePath": "src/routes/index.ts", "summary": "...", "tags": ["api-handler"]}, + {"id": "config:tsconfig.json", "type": "config", "name": "tsconfig.json", "filePath": "tsconfig.json", "summary": "...", "tags": ["configuration"]}, + {"id": "document:README.md", "type": "document", "name": "README.md", "filePath": "README.md", "summary": "...", "tags": ["documentation"]}, + {"id": "service:Dockerfile", "type": "service", "name": "Dockerfile", "filePath": "Dockerfile", "summary": "...", "tags": ["infrastructure"]} ], "importEdges": [ {"source": "file:src/routes/index.ts", "target": "file:src/services/auth.ts", "type": "imports"} + ], + "allEdges": [ + {"source": "file:src/routes/index.ts", "target": "file:src/services/auth.ts", "type": "imports"}, + {"source": "config:tsconfig.json", "target": "file:src/index.ts", "type": "configures"}, + {"source": "service:Dockerfile", "target": "file:src/index.ts", "type": "deploys"} ] } ``` @@ -42,13 +50,31 @@ Group all file node IDs by their top-level directory (first path segment after t If the project has a flat structure (all files in one directory), group by second-level directory or by filename pattern. -**B. Import Adjacency Matrix** +**B. Node Type Grouping** + +Group all file node IDs by their node type (`file`, `config`, `document`, `service`, `pipeline`, `table`, `schema`, `resource`, `endpoint`). This reveals the distribution of code vs. non-code files. + +**C. Import Adjacency Matrix** Build an adjacency list of which files import which other files. Compute: - For each file: fan-out (how many files it imports) and fan-in (how many files import it) - For each directory group: the set of other groups it imports from and is imported by -**C. Inter-Group Import Frequency** +**D. Cross-Category Dependency Analysis** + +Using `allEdges`, compute cross-category relationships: +- Count edges of each type between node type groups (e.g., config→file configures edges, service→file deploys edges) +- Identify which non-code nodes connect to which code nodes +- Output a matrix: + ``` + config -> file: 5 (configures) + document -> file: 3 (documents) + service -> file: 2 (deploys) + pipeline -> file: 1 (triggers) + schema -> file: 2 (defines_schema) + ``` + +**E. Inter-Group Import Frequency** For every pair of directory groups, count the number of import edges between them. Produce a matrix: ``` @@ -60,11 +86,11 @@ services -> utils: 5 This reveals dependency direction between groups. -**D. Intra-Group Import Density** +**F. Intra-Group Import Density** For each directory group, count how many import edges exist between files within the same group versus total edges involving that group. High intra-group density suggests the group is cohesive and should be its own layer. -**E. Directory Pattern Matching** +**G. Directory Pattern Matching** Classify each directory name against known architectural patterns: @@ -100,6 +126,13 @@ Classify each directory name against known architectural patterns: | `blueprints` | `api` | | `mailers`, `jobs`, `channels` | `service` | | `bin` | `entry` | +| `docs`, `documentation`, `wiki` | `documentation` | +| `deploy`, `deployment`, `infra`, `infrastructure` | `infrastructure` | +| `.github`, `.gitlab`, `.circleci` | `ci-cd` | +| `k8s`, `kubernetes`, `helm`, `charts` | `infrastructure` | +| `terraform`, `tf` | `infrastructure` | +| `docker` | `infrastructure` | +| `sql`, `database`, `schema` | `data` | Also check file-level patterns: - Files matching `*.test.*` or `*.spec.*` or `test_*.py` or `*_test.go` or `*Test.java` or `*_spec.rb` or `*Test.php` or `*Tests.cs` -> `test` @@ -112,8 +145,68 @@ Also check file-level patterns: - Files named `Application.java` or `Program.cs` -> `entry` (JVM / .NET entry points) - Files named `config.ru` -> `entry` (Ruby Rack entry point) - Files named `Cargo.toml`, `go.mod`, `Gemfile`, `pom.xml`, `build.gradle`, `composer.json` -> `config` (language-level project config) +- `Dockerfile`, `docker-compose.*` -> `infrastructure` +- `*.tf`, `*.tfvars` -> `infrastructure` +- `.github/workflows/*`, `.gitlab-ci.yml`, `Jenkinsfile` -> `ci-cd` +- `*.sql` -> `data` +- `*.graphql`, `*.gql`, `*.proto` -> `types` +- `*.md`, `*.rst` -> `documentation` +- `Makefile` -> `infrastructure` -**F. Dependency Direction** +**H. Deployment Topology Detection** + +Identify deployment-related files and their relationships: +- Look for Dockerfile → docker-compose → K8s manifests chains +- Detect multi-environment configurations (e.g., Dockerfile.dev, Dockerfile.prod, docker-compose.prod.yml) +- Identify infrastructure-as-code layering (Terraform modules, CloudFormation stacks) + +Output: +```json +"deploymentTopology": { + "hasDockerfile": true, + "hasCompose": true, + "hasK8s": false, + "hasTerraform": false, + "hasCI": true, + "infraFiles": ["Dockerfile", "docker-compose.yml", ".github/workflows/ci.yml"] +} +``` + +**I. Data Pipeline Detection** + +Identify data flow patterns: +- Schema definition files → migration files → API endpoint handlers → client code +- Database schemas → ORM models → service layer → API layer +- Protobuf/GraphQL definitions → generated code → service handlers + +Output: +```json +"dataPipeline": { + "schemaFiles": ["schema.sql", "schema.graphql"], + "migrationFiles": ["migrations/001_init.sql"], + "dataModelFiles": ["src/models/user.ts"], + "apiHandlerFiles": ["src/routes/users.ts"] +} +``` + +**J. Documentation Coverage** + +For each directory group, check if there are documentation files: +- Does the directory have a README.md? +- Are there docs/*.md files that reference code in this group? +- Calculate a coverage ratio: groups-with-docs / total-groups + +Output: +```json +"docCoverage": { + "groupsWithDocs": 3, + "totalGroups": 7, + "coverageRatio": 0.43, + "undocumentedGroups": ["middleware", "utils", "state", "types"] +} +``` + +**K. Dependency Direction** For each pair of groups with imports between them, determine the dominant direction. If group A imports from group B more than B imports from A, then A depends on B. Output this as a list of directed dependency relationships. @@ -127,6 +220,17 @@ For each pair of groups with imports between them, determine the dominant direct "services": ["file:src/services/auth.ts", "file:src/services/user.ts"], "utils": ["file:src/utils/format.ts"] }, + "nodeTypeGroups": { + "file": ["file:src/index.ts", "file:src/utils.ts"], + "config": ["config:tsconfig.json", "config:package.json"], + "document": ["document:README.md"], + "service": ["service:Dockerfile"], + "pipeline": ["pipeline:.github/workflows/ci.yml"] + }, + "crossCategoryEdges": [ + {"fromType": "config", "toType": "file", "edgeType": "configures", "count": 5}, + {"fromType": "service", "toType": "file", "edgeType": "deploys", "count": 2} + ], "interGroupImports": [ {"from": "routes", "to": "services", "count": 12}, {"from": "services", "to": "utils", "count": 5} @@ -140,13 +244,34 @@ For each pair of groups with imports between them, determine the dominant direct "services": "service", "utils": "utility" }, + "deploymentTopology": { + "hasDockerfile": true, + "hasCompose": true, + "hasK8s": false, + "hasTerraform": false, + "hasCI": true, + "infraFiles": ["Dockerfile", "docker-compose.yml", ".github/workflows/ci.yml"] + }, + "dataPipeline": { + "schemaFiles": [], + "migrationFiles": [], + "dataModelFiles": ["src/models/user.ts"], + "apiHandlerFiles": ["src/routes/users.ts"] + }, + "docCoverage": { + "groupsWithDocs": 1, + "totalGroups": 5, + "coverageRatio": 0.2, + "undocumentedGroups": ["services", "utils", "routes"] + }, "dependencyDirection": [ {"dependent": "routes", "dependsOn": "services"}, {"dependent": "services", "dependsOn": "utils"} ], "fileStats": { "totalFileNodes": 42, - "filesPerGroup": {"routes": 8, "services": 12, "utils": 5} + "filesPerGroup": {"routes": 8, "services": 12, "utils": 5}, + "nodeTypeCounts": {"file": 30, "config": 5, "document": 3, "service": 2, "pipeline": 2} }, "fileFanIn": { "file:src/utils/format.ts": 15, @@ -166,8 +291,9 @@ Before writing the script, create its input JSON file: ```bash cat > $PROJECT_ROOT/.understand-anything/tmp/ua-arch-input.json << 'ENDJSON' { - "fileNodes": [], - "importEdges": [] + "fileNodes": [], + "importEdges": [], + "allEdges": [] } ENDJSON ``` @@ -203,25 +329,55 @@ Use the `dependencyDirection` data to understand the project's layering: - Middle layers depend on bottom layers (Data, Utility, Types) - This forms a dependency hierarchy that should map to your layer ordering -### Step 3 -- Consider File Summaries and Tags +### Step 3 -- Consider Non-Code Layers + +Use `nodeTypeGroups` and `deploymentTopology` to determine if non-code layers are warranted: + +- **Infrastructure layer:** Create if the project has Dockerfiles, Terraform, K8s manifests, or other deployment files. Include all `service` and `resource` type nodes. +- **CI/CD layer:** Create if the project has CI/CD configs (.github/workflows, .gitlab-ci.yml, Jenkinsfile). Include all `pipeline` type nodes. May be merged with Infrastructure if few files. +- **Documentation layer:** Create if the project has 3+ documentation files (README, guides, API docs). Include all `document` type nodes. May be merged with a "Project" or "Root" layer if few files. +- **Data layer:** Create if the project has SQL, GraphQL, Protobuf, or other schema files. Include `table`, `schema`, and `endpoint` type nodes. May be merged with an existing "Data" or "Models" layer. +- **Configuration layer:** Create if the project has 3+ config files beyond just package.json. Include all `config` type nodes. May be merged with a "Root" or "Project" layer if few files. + +**Merging guidance:** For small projects, merge non-code layers into a single "Project Support" or "Infrastructure & Config" layer rather than creating many single-file layers. For larger projects, separate them into distinct layers. + +### Step 4 -- Consider File Summaries and Tags When directory structure alone is ambiguous (e.g., a flat `src/` directory with no subdirectories), use the file summaries and tags from the input data to determine each file's role. Think about what responsibility the file fulfills in the system. -### Step 4 -- Select 3-7 Layers +### Step 5 -- Select 3-10 Layers Choose layers based on the project's actual architecture, informed by the script's structural data. Common patterns include: -- **Layered architecture:** API -> Service -> Data -- **Component-based:** UI Components, State, Services, Utils -- **MVC:** Models, Views, Controllers -- **Monorepo packages:** Each package forms its own layer -- **Library:** Core, Plugins, Types, Tests +- **Layered architecture:** API -> Service -> Data + Infrastructure + Config +- **Component-based:** UI Components, State, Services, Utils, Infrastructure +- **MVC:** Models, Views, Controllers + Config + Docs +- **Monorepo packages:** Each package forms its own layer + shared infra +- **Library:** Core, Plugins, Types, Tests, Documentation + +**Layer hint for non-code files:** + +| Pattern | Suggested Layer | +|---|---| +| Dockerfile, docker-compose.*, K8s manifests, Terraform | `layer:infrastructure` | +| .github/workflows/*, .gitlab-ci.yml, Jenkinsfile | `layer:ci-cd` or merge into `layer:infrastructure` | +| README.md, docs/*.md, CONTRIBUTING.md, CHANGELOG.md | `layer:documentation` or merge into relevant code layer | +| *.sql, migrations/*.sql | `layer:data` | +| *.graphql, *.proto, *.prisma | `layer:data` or `layer:types` | +| package.json, tsconfig.json, *.toml, *.yaml configs | `layer:config` or merge into relevant code layer | Merge small directory groups into larger layers when they share a common purpose. Prefer fewer, well-defined layers over many granular ones. -### Step 5 -- Assign Every File Node +### Step 6 -- Assign Every File Node Go through each file node ID from the input and assign it to exactly one layer. Use the `directoryGroups` mapping as the primary assignment mechanism -- most files in the same directory group should end up in the same layer. +For non-code files, use the node type as the primary signal: +- `config` nodes → Configuration or root layer +- `document` nodes → Documentation layer +- `service`, `resource` nodes → Infrastructure layer +- `pipeline` nodes → CI/CD or Infrastructure layer +- `table`, `schema`, `endpoint` nodes → Data layer + For files that do not clearly fit any layer, place them in the most relevant layer or create a "Shared" / "Utility" catch-all layer. Do not leave any file unassigned. **Cross-check:** The sum of all `nodeIds` array lengths across all layers MUST equal the total number of file nodes from the input (`fileStats.totalFileNodes` from the script output). @@ -231,6 +387,7 @@ For files that do not clearly fit any layer, place them in the most relevant lay Use `layer:` format consistently: - `layer:api`, `layer:service`, `layer:data`, `layer:ui`, `layer:middleware` - `layer:utility`, `layer:config`, `layer:test`, `layer:types`, `layer:state` +- `layer:infrastructure`, `layer:documentation`, `layer:ci-cd` ## Output Format @@ -250,6 +407,30 @@ Produce a single, valid JSON array. Every field shown is **required**. "description": "Core business logic, domain services, and orchestration", "nodeIds": ["file:src/services/auth.ts", "file:src/services/user.ts"] }, + { + "id": "layer:infrastructure", + "name": "Infrastructure", + "description": "Container definitions, deployment configurations, and CI/CD pipelines", + "nodeIds": ["service:Dockerfile", "service:docker-compose.yml", "pipeline:.github/workflows/ci.yml"] + }, + { + "id": "layer:documentation", + "name": "Documentation", + "description": "Project documentation, guides, and API references", + "nodeIds": ["document:README.md", "document:docs/getting-started.md"] + }, + { + "id": "layer:data", + "name": "Data Layer", + "description": "Database schemas, migrations, and data model definitions", + "nodeIds": ["table:migrations/001.sql:users", "schema:schema.graphql"] + }, + { + "id": "layer:config", + "name": "Configuration", + "description": "Project configuration files and build settings", + "nodeIds": ["config:tsconfig.json", "config:package.json"] + }, { "id": "layer:utility", "name": "Utility Layer", @@ -267,11 +448,11 @@ Produce a single, valid JSON array. Every field shown is **required**. ## Critical Constraints -- EVERY file node ID from the input MUST appear in exactly one layer's `nodeIds` array. Missing file assignments break the downstream pipeline. +- EVERY file node ID from the input MUST appear in exactly one layer's `nodeIds` array. Missing file assignments break the downstream pipeline. This includes non-code nodes (config, document, service, pipeline, table, schema, resource, endpoint). - NEVER include node IDs in `nodeIds` that were not provided in the input. Do not invent node IDs. - NEVER create a layer with an empty `nodeIds` array. - ALWAYS verify your output accounts for all input file nodes. Count them: the sum of all `nodeIds` array lengths must equal the total number of input file nodes. -- Keep to 3-7 layers. If the project is very small (under 10 files), 3 layers is sufficient. If large (100+ files), up to 7 is appropriate. +- Keep to 3-10 layers. If the project is very small (under 10 files), 3 layers is sufficient. If large (100+ files), up to 10 is appropriate. - Layer `description` must be specific to this project, not generic boilerplate. - Trust the script's structural analysis. Do NOT re-read source files or re-count imports. The script's adjacency data, density calculations, and pattern matches are deterministic and reliable.