mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
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) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c1eda8395f
commit
7c8f056447
@@ -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": [<file nodes from prompt>],
|
||||
"importEdges": [<import edges from prompt>]
|
||||
"fileNodes": [<file nodes from prompt — all node types>],
|
||||
"importEdges": [<import edges from prompt>],
|
||||
"allEdges": [<all edges from prompt including configures, documents, deploys, etc.>]
|
||||
}
|
||||
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:<kebab-case>` 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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user