Skip to content
Back to skills

Derive Physical Architecture

ASecurity

Stage 4 skill of /arch. Builds the runtime physical architecture by mapping every logical component to one or more physical components, inheriting system_ref grounding from the inventory, picking specific deployment targets and resources, wiring comms with retry/idempotency stance, and naming a delivery mechanism for every NFR target in the refined quality profile. Mapping cardinality (1:1, N:1, 1:N) is recorded per physical component with rationale for non-trivial cases.

  • 3 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 10, 2026
devopsgonodekubernetesawsgcpazureapidatabasefrontendci/cd

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add kapilvirenahuja/garura --skill derive-physical-architecture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Derive Physical Architecture?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Derive Physical Architecture
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kapilvirenahuja-derive-physical-architecture/badge)](https://www.skillsdirectory.com/skills/kapilvirenahuja-derive-physical-architecture)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: derive-physical-architecture
description: Stage 4 skill of /arch. Builds the runtime physical architecture by mapping every logical component to one or more physical components, inheriting system_ref grounding from the inventory, picking specific deployment targets and resources, wiring comms with retry/idempotency stance, and naming a delivery mechanism for every NFR target in the refined quality profile. Mapping cardinality (1:1, N:1, 1:N) is recorded per physical component with rationale for non-trivial cases.
version: 1.0.0
user-invocable: false
deprecated: true
deprecated_note: '#434 ProductOS realignment — superseded by the command model; retained for Phase E reference, not installed'
---

# derive-physical-architecture

> **Decision Surfacing Discipline:** This skill emits a `decision-manifest-derive-physical-architecture.yaml` alongside its primary artifact. Every inferred decision — cardinality choice, deployment_target pick, resource sizing, comms protocol, retry/idempotency stance, NFR mechanism — is recorded with tier, grounding source, recommendation, and alternatives. The orchestrator drives the tiered surfacing flow after this skill completes.

Called by `tech-architect` during `arch` Stage 4. Produces `physical-architecture.yaml` at `{product_base}architecture/physical-architecture.yaml` plus a decision manifest.

## Purpose

Build the runtime shape of the product. For every logical component, decide how it runs — where, on what resources, talking to whom, and with what mechanisms delivering the NFRs the refined quality profile describes. Physical components are NOT invented at physical-time; each is a runtime realization of an existing logical component and inherits its `system_ref` (and `sub_system_ref`) from the inventory grounding. The inventory-grounding chain — physical → logical → inventory — is the load-bearing trace that prevents architectural drift.

**Differences from the prior version (model change in #403):**
- `system_ref` now inherited from logical. Physical components NEVER invent systems.
- New `logical_ref_cardinality` field per physical component (`one-to-one | many-to-one | one-to-many`) with required rationale for non-trivial mappings.
- New `nfr_delivery[]` block per component — every refined-QP characteristic whose delivery falls in this component's scope appears here with mechanism. The prior separate `nfr-spec` artifact is gone; this block replaces it.
- `comms[]` now carries `retry` and `idempotency` stance per outbound edge.
- Cycle detection on the runtime graph: sync-only cycles forbidden, async edges break.
- `layer` on each physical component MUST equal the linked logical component's layer.

## Input

Receive from the `tech-architect` agent. All paths resolve against `{product_base}` and `{ltm_base}` supplied by the play via JSON contract.

- `logical_path` (path, required) — `{product_base}architecture/logical-architecture.yaml`. Stage 3 output.
- `refined_qp_path` (path, required) — `{product_base}architecture/quality-profile.yaml`. Stage 2 output.
- `inventory_dir` (path, required) — `{product_base}architecture/systems-inventory/`. Read for system Scale Profile and Tradeoffs to inform resource sizing and mechanism choice.
- `project_profile_path` (path, required) — `{product_base}user-provided/project-profile.yaml`. `grounded_tools.physical[]` pins are authoritative; `compliance[]` flags constrain region/residency.
- `kb_platforms_dir` (path, required) — `{ltm_base}components/memory/knowledge/arch/platforms/`. Cloud and on-prem platform candidates.
- `kb_data_dir` (path, required) — `{ltm_base}components/memory/knowledge/arch/data/`. Data store candidates.
- `kb_operations_dir` (path, required) — `{ltm_base}components/memory/knowledge/arch/operations/`. Observability, CI/CD, IaC, security infrastructure catalogs.
- `flows_dir` (path, optional) — `{product_base}experience/flows/`. Traffic context for resource sizing.
- `output_path` (string, required) — `{product_base}architecture/physical-architecture.yaml`.
- `decision_manifest_path` (string, required) — `{product_base}architecture/decision-manifest-derive-physical-architecture.yaml`.
- `grounding_questions_path` (string, required) — `{product_base}user-provided/grounding-questions.md`. Append-only for multi-candidate halts.

## Output

### Physical architecture

YAML at `{output_path}`.

```yaml
components:
  - id: order-orchestrator-fn               # kebab-case, unique within components[]
    logical_ref: order-orchestrator         # MUST match a logical component id
    logical_ref_cardinality: one-to-one | many-to-one | one-to-many
    cardinality_rationale: |                # REQUIRED when cardinality != one-to-one; cites driver
      {prose — e.g. "1:N for HA replication driven by refined QP reliability 99.9% target"}
    system_ref: shopify-functions           # inherited from the linked logical component; MUST match inventory
    sub_system_ref: null                    # inherited from logical when present
    layer: process                          # MUST equal the linked logical component's layer
    deployment_target:
      kind: cloud-service | on-prem-class | saas | hybrid
      name: AWS Lambda (Node.js 20 runtime, ARM64)   # SPECIFIC product, never a category
      region: us-east-1
      availability: multi-az | single-az | global-edge | on-prem-dc
      source_type: project_profile_pin | kb_catalog_single_candidate | kb_catalog_multi_candidate_user_approved | agent_default_with_user_approval
      source_citation: {pin slot | kb file path | grounding-question id | checkpoint id}
    resources:
      compute: { vcpu: 0.5, memory_mb: 512 }
      storage: { kind: ephemeral | persistent, size_gb: 0.5 }
      scaling:
        kind: autoscale | fixed | scheduled
        min: 0
        max: 200
        signal: concurrent-requests | cpu | rps | queue-depth | manual
        rationale: {one line — citing QP target}
    comms:
      - to: inventory-api-svc               # another physical component id
        protocol: HTTPS/1.1 | HTTPS/2 | gRPC | AMQP-0.9.1 | Kafka-protocol | S3-SigV4 | ...   # named specifically
        sync_mode: sync | async | hybrid    # inherited from logical edge by default
        retry:
          policy: none | linear | exponential-backoff | dead-letter-queue
          max_attempts: <int>
          backoff_ms: <int>                 # initial; doubles per attempt for exponential
        idempotency:
          stance: not-required | required | conditional
          key_header: {name when stance = required}
          rationale: {one line — citing QP target or QP characteristic}
    nfr_delivery:
      - nfr_characteristic: reliability     # MUST match a characteristic in refined QP
        target_reference: |                 # short citation of the refined QP target this mechanism delivers
          {quote or paraphrase of refined QP characteristic.target}
        mechanism: |                        # the specific mechanism — named, not abstract
          AWS Lambda multi-AZ with provisioned concurrency 10, dead-letter SQS,
          and async retry policy 3x exponential
        rationale: |                        # how this mechanism delivers the target
          {2-4 lines of prose}
        source_type: ...
        source_citation: ...
      - nfr_characteristic: security
        target_reference: "OWASP ASVS Level 2 per refined QP"
        mechanism: |
          IAM execution role with least-privilege policy; KMS-encrypted environment;
          ALB WAF with OWASP managed rule set; VPC-only invocation
        rationale: ...
```

**Validation rules baked into the schema:**
- Every component's `logical_ref` matches a component id in `logical-architecture.yaml`.
- Every component's `system_ref` matches the linked logical component's `system_ref` (and `sub_system_ref` if present).
- Every component's `layer` equals the linked logical component's `layer`.
- `logical_ref_cardinality` is one of the three values; `cardinality_rationale` is required when value is not `one-to-one`.
- `deployment_target.name` is not a category term (deny-list check).
- Every comms.to references a real physical component id.
- Every nfr_delivery.nfr_characteristic matches a characteristic in the refined QP.

### Decision manifest

One YAML file at `{decision_manifest_path}` with entries for every inferred decision. Decision types: `cardinality`, `deployment_target`, `resources`, `comms_protocol`, `retry_policy`, `idempotency_stance`, `nfr_mechanism`.

```yaml
manifest:
  skill: derive-physical-architecture
  written_at: {ISO 8601 timestamp}
  decisions:
    - decision_id: PA-001
      decision_type: cardinality | deployment_target | resources | comms_protocol | retry_policy | idempotency_stance | nfr_mechanism
      component_id: order-orchestrator-fn
      tier: high | mid | low
      grounding_source:
        kind: project_profile_pin | kb_catalog_single_candidate | kb_catalog_multi_candidate_user_approved | inventory_constraint | refined_qp_target | upstream_artifact | agent_default_with_user_approval
        citation: {pin slot | kb file path | inventory file path | refined QP characteristic | grounding-question id | checkpoint id}
      recommendation: {summarized decision}
      alternatives_considered:
        - option: {alt}
          why_rejected: {one line}
      agent_reasoning_summary: |
        {2-4 line prose}
      non_obvious: true | false
      user_response: accept | override | orbit | pending
      user_response_detail: {free text — null when pending}
```

## Process

### 1. Read inputs

- Parse `logical_path` → list of logical components with id, layer, system_ref, sub_system_ref, capability_ids, inbound_edges, outbound_edges (with sync_mode).
- Parse `refined_qp_path` → characteristics with targets and relevance.
- Glob `inventory_dir/*.md` → parse frontmatter for each referenced system; read Scale Profile and Tradeoffs sections for resource and mechanism context.
- Parse `project_profile_path` → `grounded_tools.physical[]`, `compliance[]`, `region_constraints[]`.
- Glob `kb_platforms_dir`, `kb_data_dir`, `kb_operations_dir` → KB candidate sets per slot type.

### 2. Validate pre-conditions

- `logical_path` exists and parses cleanly.
- `refined_qp_path` exists.
- Every logical component's `system_ref` resolves to an inventory file. If any does NOT, halt with `what_failed: logical_system_ref_unresolved` — Stage 3 must re-run.
- Required inputs exist OR documented stand-in exists.

### 3. Decide cardinality per logical component

For each logical component, decide how many physical components implement it:

- **one-to-one** by default. The simplest correct shape.
- **one-to-many** when a refined-QP target forces replication, sharding, or tiered placement. Examples:
  - Reliability target requires multi-region active-active → split into per-region physical components.
  - Performance target requires read-replica fanout → one writer + N readers.
  - Compliance requires data-residency partitioning → per-region physical components for the same logical role.
- **many-to-one** when multiple logical components collapse into a single deployed surface. Justified only when:
  - The logical components share transactional boundaries that span the collapse (a transactional commit must touch both).
  - Operational simplicity at a tier where the QP targets do NOT require independent failure domains.
  - A latency budget makes a network hop infeasible and the logical edge is sync.
  - The collapsing components all share the same `system_ref` (you cannot collapse components grounded in different systems — that's an inventory boundary).

Every cardinality decision is recorded in the manifest with `decision_type: cardinality`. When cardinality != one-to-one, `cardinality_rationale` MUST cite an architectural driver (refined-QP target, project-profile pin, or inventory constraint).

### 4. Pick deployment_target per physical component

For each physical component:

1. **Pin check.** If `project_profile.grounded_tools.physical[]` carries an entry for the system_ref OR for the logical_ref id, use the pinned deployment_target. Decision tier `high`, source_type `project_profile_pin`.
2. **KB candidate query.** Walk `kb_platforms_dir` and inventory's Scale Profile for candidates that fit the system_ref's hosting model (SaaS systems have only one deployment_target — the vendor's; self-hosted systems offer cloud / on-prem / hybrid choices).
3. **Resolve by candidate count:**
   - Single → use it, tier `high`, source_type `kb_catalog_single_candidate`.
   - Multiple → halt the slot per C20: append `Q-arch-NNN` to grounding-questions or surface at the Stage 4 checkpoint. user_response pending. tier `mid`, source_type `kb_catalog_multi_candidate_user_approved`.
   - Zero → enter agent-default mode, surface one-by-one per C19 LOW tier with explicit alternatives and rationale.

`deployment_target.name` MUST be a specific product or class (AWS Lambda, AWS ECS Fargate, GCP Cloud Run, Azure App Service, Kubernetes 1.29 on EKS, on-prem VMware vSphere cluster, Salesforce SaaS, Stripe SaaS, etc.). Category terms ("a relational database", "a serverless platform") are a structural violation enforced at Step 9.

### 5. Size resources

For each physical component, derive `resources.compute`, `resources.storage`, `resources.scaling`:

- Read refined QP performance characteristic targets (p95 latency, throughput RPS, concurrent users).
- Read inventory system's Scale Profile section for the sweet-spot ranges.
- Read flows (when available) for traffic shape.
- Propose:
  - Compute size aligned to per-instance throughput needed to meet the QP target at expected concurrency.
  - Storage kind: `ephemeral` for stateless compute; `persistent` for data-bearing roles.
  - Scaling: `autoscale` with signal aligned to the dominant load axis (rps, queue-depth, cpu) and bounds derived from QP scale target and budget pins.

Record one manifest entry per component with `decision_type: resources`. Tier:
- `high` when the QP target is quantified and the KB Scale Profile maps cleanly.
- `mid` when QP target requires interpretation (e.g., qualitative reliability without numbers).
- `low` when neither — agent default; user must approve.

### 6. Wire comms per logical edge

For each outbound edge from the linked logical component, create one entry in this physical component's `comms[]`:

1. `to` = the physical component id implementing the logical edge's target. (When the target logical component has cardinality one-to-many, the physical edge fans out to all targets unless flows indicate a single-target affinity.)
2. `protocol` — choose specifically. Inherit hints from the logical edge's sync_mode (sync → request-response protocols: HTTPS, gRPC; async → messaging or event protocols: AMQP, Kafka-protocol, SNS-SQS; hybrid → typically sync RPC + async event).
3. `sync_mode` — carry forward from the logical edge.
4. `retry`:
   - When QP reliability target demands resilience: `exponential-backoff`, max_attempts 3-5.
   - When the callee is idempotent and ops-cost matters: `dead-letter-queue` for failed messages.
   - When neither: `none`.
5. `idempotency.stance`:
   - `required` whenever retry is non-`none` AND the operation is mutating.
   - `conditional` when the operation is read-only or naturally idempotent (GETs, snapshot queries).
   - `not-required` when neither.

Record one manifest entry per comms decision (`decision_type: comms_protocol`, `retry_policy`, `idempotency_stance`).

### 7. Name NFR delivery mechanisms

For each characteristic in the refined QP with `relevance != not_applicable`:

1. Determine which physical component(s) own delivery of this characteristic. Heuristics:
   - **Performance** → entry-layer + process-layer components.
   - **Reliability** → every layer; mechanisms specific to component role.
   - **Security** → entry-layer (WAF, TLS termination, auth), process-layer (authz, input validation), data-layer (encryption-at-rest, KMS).
   - **Maintainability / observability** → every component (logs, metrics, traces).
   - **Compatibility / portability** → process-layer and integration boundaries.
2. For each owning component, add one entry to `nfr_delivery[]`:
   - `nfr_characteristic` matches the refined QP characteristic.
   - `target_reference` quotes or paraphrases the refined QP target.
   - `mechanism` names the specific architectural device delivering the target (e.g., "AWS Lambda multi-AZ with provisioned concurrency 10, dead-letter SQS, and async retry policy 3x exponential", NOT "use a resilient runtime").
   - `rationale` ties mechanism to target.

Every refined-QP characteristic with `relevance != not_applicable` MUST appear in at least one component's `nfr_delivery[]`. An unmapped target halts with `what_failed: nfr_target_unmapped`.

### 8. Cycle detection on the runtime graph

Build a directed graph from `comms[]`. Apply the same async-break rule as logical: a cycle that includes at least one edge with `sync_mode: async` is acceptable; a sync-only cycle is forbidden.

When a sync-only cycle is detected, halt with `what_failed: runtime_sync_cycle` and structured details (cycle path, candidate breaks).

### 9. Validate output

Before returning:
- Schema rules from the Output section all hold.
- Every component's `system_ref` matches the linked logical component's `system_ref` exactly. Mismatch → `what_failed: inventory_grounding_break`.
- Every component's `layer` equals the linked logical component's `layer`.
- `deployment_target.name` does NOT match the category-term deny-list (terms like "a database", "a queue", "an observability stack", "a frontend framework", "a CI system"). Hit → `what_failed: category_term_in_physical`.
- Every refined-QP characteristic with relevance != not_applicable appears in at least one `nfr_delivery[]`. Miss → `what_failed: nfr_target_unmapped`.
- Decision manifest complete with one entry per inferred decision.

## Output Contract

On success:

```json
{
  "status": "success",
  "skill": "derive-physical-architecture",
  "outputs": {
    "physical_path": "{product_base}architecture/physical-architecture.yaml",
    "decision_manifest_path": "{product_base}architecture/decision-manifest-derive-physical-architecture.yaml",
    "component_count": <int>,
    "comms_count": <int>,
    "nfr_delivery_count": <int>,
    "decisions_count": <int>,
    "halted_slots": [
      { "kind": "deployment_target | resources | comms_protocol | nfr_mechanism", "component_id": "...", "grounding_question_id": "Q-arch-NNN" }
    ]
  }
}
```

On failure:

```json
{
  "status": "failure",
  "skill": "derive-physical-architecture",
  "what_failed": "missing_input | logical_system_ref_unresolved | inventory_grounding_break | category_term_in_physical | runtime_sync_cycle | nfr_target_unmapped | cardinality_without_rationale | layer_mismatch | manifest_incomplete",
  "details": "..."
}
```

## Evals

| Eval | Failure Bound | Check |
|------|---------------|-------|
| PA-1 | F6 (physical missing fields / uses category) | Every component has logical_ref, system_ref, layer, deployment_target.kind, deployment_target.name; no name matches the category-term deny-list. |
| PA-2 | F23 (physical system_ref not in inventory) | Every physical component's system_ref matches the linked logical component's system_ref exactly AND resolves to an inventory file id. |
| PA-3 | F7 (cardinality without rationale or layer mismatch) | Every component with `logical_ref_cardinality != one-to-one` has a non-empty `cardinality_rationale`; every component's `layer` equals the linked logical component's `layer`. |
| PA-4 | F8 (NFR without delivery mechanism) | Every refined-QP characteristic with `relevance != not_applicable` appears in at least one component's `nfr_delivery[]` with mechanism and rationale. |
| PA-5 | F5 (runtime sync cycle) | The directed graph of `comms[]` edges, ignoring `sync_mode: async` edges, is acyclic. |
| PA-6 | F16 (manifest missing/malformed) | Decision manifest exists with one entry per inferred decision; every entry has decision_id, decision_type, component_id, tier, grounding_source, recommendation, alternatives_considered. |
| PA-7 | F13 (source_type discipline) | No decision has `grounding_source.kind: agent_default_unilateral`. |
| PA-8 | C16 (KB read-only) | The skill wrote NO file under `kb_platforms_dir`, `kb_data_dir`, or `kb_operations_dir`. |

## Constraints

- Writes ONLY to `{output_path}`, `{decision_manifest_path}`, and (for multi-candidate halts) appends to `{grounding_questions_path}`.
- Read-only on `logical_path`, `refined_qp_path`, `inventory_dir`, `project_profile_path`, every KB directory.
- NEVER invents a system. `system_ref` inherited from logical; mismatch is structural violation.
- NEVER changes the layer assigned in logical. Layer mismatch is structural violation.
- NEVER names a category term in `deployment_target.name`, `comms.protocol`, or `nfr_delivery.mechanism`. Specific products only.
- NEVER duplicates the refined-QP target text — references it via `target_reference` citation.
- Respects C18/C19 surfacing tiers and C20 multi-candidate halt.

## Failure modes

- `missing_input` — required input path absent and no stand-in.
- `logical_system_ref_unresolved` — a logical component's system_ref does not resolve to inventory. Stage 3 must re-run.
- `inventory_grounding_break` — a physical component's system_ref does not match the linked logical component's system_ref.
- `category_term_in_physical` — deployment_target name, comms protocol, or nfr_delivery mechanism uses a category term instead of a specific product.
- `runtime_sync_cycle` — directed comms graph (ignoring async edges) has a cycle.
- `nfr_target_unmapped` — a refined-QP characteristic with `relevance != not_applicable` has no mapped nfr_delivery entry.
- `cardinality_without_rationale` — a component with `logical_ref_cardinality != one-to-one` lacks `cardinality_rationale`.
- `layer_mismatch` — a physical component's layer differs from the linked logical component's layer.
- `manifest_incomplete` — decision manifest missing or any entry lacks required fields.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.