Skip to content

Feature Proposal: "What-If" Architecture Check API #6

@qiuethan

Description

@qiuethan

Summary

Archctl currently evaluates the architecture of an existing project by analyzing files, dependencies, contexts, layers, and capabilities. However, there is no way to ask:

"If I add this import or this code to a file, will it violate any rules?"

This proposal introduces a "what-if" API that allows tools (and developers) to query Archctl about hypothetical changes before they are committed. This is particularly useful for integration with AI coding assistants, IDEs, and automated refactoring tools, but it remains architecture-style agnostic and purely static.


Problem

As projects adopt stricter architectural rules (layers, contexts, capabilities), it becomes risky to:

  • Add new imports
  • Move files between contexts or layers
  • Introduce new usage of capabilities (e.g., network, database, filesystem)

Without a "what-if" API:

  • AI agents and tooling cannot reliably know if a suggested change will be valid
  • Developers must run Archctl after making changes, then undo or adjust when violations appear
  • Automated refactoring tools cannot test architecture compliance before applying transformations

There is a missing bridge between intention ("I want to call this module") and validation ("is that allowed?").


Goal

Provide a programmatic and CLI-accessible way to ask Archctl:

  1. "If I add this dependency edge (from file A to file B), will it violate any rules?"
  2. Optionally: "If I insert this snippet into file A, will it violate any rules (dependencies or capabilities)?"

This must be:

  • Deterministic and purely static (no runtime execution)
  • Architecture-style agnostic
  • Reusable by editors, AIs, and other tools

Scope

Initial version should focus on a dependency-centric "what-if":

  • Input: fromFile, toFile (hypothetical import or dependency)
  • Output: list of RuleViolations that would be triggered if this dependency existed

A later version can extend this to full snippet analysis (capabilities + imports) if needed.


Proposed Solution

1. Core API Shape

Introduce a new function in the Archctl service layer, for example:

interface WhatIfDependencyRequest {
  fromFile: string;
  toFile: string;
}

interface WhatIfResult {
  allowed: boolean;
  violations: RuleViolation[];
}

function checkWhatIfDependency(
  graph: ProjectGraph,
  rules: BaseRule[],
  archConfig: ArchConfig,
  request: WhatIfDependencyRequest
): WhatIfResult;

Behavior:

  1. Take the current ProjectGraph and RuleContext.
  2. Temporarily add a synthetic dependency edge fromFile → toFile.
  3. Run all rules that depend on dependencies (e.g., layer rules, context rules, cycles).
  4. Return any violations that arise because of this hypothetical edge.

This enables:

  • "Is it safe to add import X from 'Y' here?"
  • "Will this new dependency introduce a cycle, cross-context breach, or layer violation?"

2. CLI Command

Expose the API via a new CLI command, for example:

archctl what-if dependency   --from src/orders/internal/useCase.ts   --to src/billing/api/calcTax.ts   --format json

Output (JSON):

{
  "allowed": false,
  "violations": [
    {
      "ruleId": "context-visibility",
      "severity": "error",
      "message": "Context 'orders' is not allowed to depend on non-public files in context 'billing'.",
      "metadata": {
        "fromContext": "orders",
        "toContext": "billing",
        "fromFile": "src/orders/internal/useCase.ts",
        "toFile": "src/billing/api/calcTax.ts"
      }
    }
  ]
}

This makes it easy to pipe into editors, scripts, and AI tools.


3. Rule Integration

To support the "what-if" dependency check cleanly:

  • The existing rule engine already consumes a RuleContext that includes:
    • files
    • dependencies
    • config (layers, contexts, capabilities)
  • The what-if function should:
    • Clone or extend the dependency list with a synthetic edge
    • Build a RuleContext that includes this edge
    • Run all rules that depend on dependencies (BaseRules that read ctx.dependencies)
    • Return only the violations involving the hypothetical edge

This allows reuse of all existing rules, including:

  • Layer dependency rules
  • Context visibility rules
  • Cycle detection rules (file-level and context-level)
  • Any future rules that rely on dependency edges

4. Future Extension: Snippet-Level "What-If"

A second phase could support a richer API:

interface WhatIfSnippetRequest {
  filePath: string;
  snippet: string;
}

function checkWhatIfSnippet(
  graph: ProjectGraph,
  rules: BaseRule[],
  archConfig: ArchConfig,
  request: WhatIfSnippetRequest
): WhatIfResult;

This would require:

  1. Parsing the snippet as if it was inserted into filePath.
  2. Extracting hypothetical imports (new dependency edges).
  3. Running capability detection on the snippet.
  4. Merging these into a temporary RuleContext.
  5. Returning rule violations.

This is more complex and can be deferred to a later milestone.


Configuration

No additional user-facing configuration is required to support a dependency-based "what-if" API.

Optionally, a configuration option could allow enabling or disabling the CLI surface:

{
  "features": {
    "whatIfApi": true
  }
}

But this is not strictly necessary if the API is exposed programmatically only.


Implementation Outline

  1. Service function

    • Add checkWhatIfDependency(...) to the rule or graph service layer.
    • Ensure it can reuse existing rule registration and context building.
  2. RuleContext handling

    • Provide a helper to build a RuleContext with an additional synthetic dependency edge.
  3. CLI command

    • Add archctl what-if dependency subcommand.
    • Arguments: --from, --to, --format (json, text).
    • Wire the command to checkWhatIfDependency(...).
  4. Output format

    • Define a minimal JSON schema for WhatIfResult that is stable for tooling.
    • Optionally add a human-readable output mode.
  5. Documentation

    • Add a section on the "what-if" API in README / setup docs.
    • Provide usage examples for CLI and programmatic integration.
    • Explain how this can be used by editors and AI assistants.

Benefits

  • Allows editors and AI assistants to query architecture rules ahead of time.
  • Reduces trial-and-error when adding imports across layers or contexts.
  • Encourages usage of Archctl as an architecture oracle, not only a linter.
  • Remains architecture-style agnostic and purely static.

Open Questions

  • Should we limit which rules participate in what-if checks (e.g., only dependency-based rules)?
  • Do we need an explicit API for snippet-based capability checks, or is dependency-only sufficient for first release?
  • Should the CLI output include suggested fixes (if rules provide suggestions), or only raw violations?

These can be refined as a follow-up once the initial implementation is in place.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions