STACKTOIT · READING A REAL ASSESSMENT

How to read a real StackToIT migration assessment

An assessment folder holds well over a hundred files. You do not read them in order; you read five things: the summary, the class of each unit, one unit in full, one decision and the plan step it holds. This guide walks that path on the published AWS Retail Store run, so every figure below can be checked against the public example.

Start with the summary, then what is not established

The published AWS Retail Store run: 282 Terraform resources, 44 migration units. Left: the scan block of console.txt. Right: the validation matrix the run prints below it.

Scan summaryconsole.txt
StackToIT Assess
────────────────────────────────────────────
Source:                 terraform/ecs/default
Source files:           105
Resources scanned:      282  (0 in the root module · 282 inside 23 module calls)
  support resources:    34  (+12 Terraform helpers, out of scope; 34 + 12 = the 46 support nodes of summary.support.nodes in assessment.json)
Migration units:        44 known-present (44 instances) · 8 conditional  (+41 switched off — see Not in a wave)
Unit dependencies:      109
Modules:                23 module calls (13 external, 10 local): 23 loaded, 0 not downloaded, 0 invalid
  module.dependencies    ../../lib/dependencies  11 units (RECONFIGURE 7 · REPLATFORM 3 · REDESIGN 1) · 13 switched off · 77 resources (+10 nested calls)
  module.retail_app_ecs  ../../lib/ecs           30 known-present units (RECONFIGURE 24 · REPLATFORM 6) · 3 conditional · 3 switched off · 126 resources (+8 nested calls)
  module.tags            ../../lib/tags          0 units · 0 resources
  module.vpc             ../../lib/vpc           3 known-present units (RECONFIGURE 3) · 5 conditional · 25 switched off · 79 resources (+1 nested call)
Source checks:          Built-in source checks passed — OpenTofu validation of the source did not run (LOCK_FILE)
Source completeness:    RUNTIME_TOPOLOGY_PARTIAL — 8 unit(s) have a count/for_each that is not known statically; whether and how often they exist is decided at plan time

STACKIT mapping
────────────────────────────────────────────
DIRECT              0  
RECONFIGURE        34  ███████████████████████ 77%
REPLATFORM          9  ██████ 20%
CONTAINERIZE        0  
REDESIGN            1  █ 2%
MANUAL_REVIEW       0  
BLOCKED             0    (the mapping class BLOCKED, not the execution blockers, which Migration readiness counts)

Confidence  HIGH 0 · MEDIUM 35 · LOW 9
Validation matrixconsole.txt
Validation matrix (what has been established; nothing here approves the draft)
  Source completeness: PARTIAL (source status RUNTIME_TOPOLOGY_PARTIAL)
  Draft generation: GENERATED (the draft is in terraform/)
  StackToIT draft checks: PASSED (100 checks, none found a violation)
  Global invariants: PASSED (12 of 12 invariants PASS)
  OpenTofu validation: PASSED (tofu init -backend=false and tofu validate accepted the draft; tofu 1.13.1)
  Output schema validation: PASSED (verified at publish: every JSON file that has a schema is validated against it (see run_verification in manifest.json))
  STACKIT plan: NOT RUN (this build runs no plan against a STACKIT project)
  Architect approval: NOT PROVIDED (no review decision is recorded for this run)
  Semantic equivalence: NOT ASSESSED (this build has no measure for it)
  Safe to apply: NOT ASSERTED (StackToIT never asserts it)
  • Counts first

    The source has 282 resources and 44 units, 8 more units are decided only when OpenTofu plans, and the source status is RUNTIME_TOPOLOGY_PARTIAL. Read that before the table: it says the inventory is partial, and why.

  • A class is the work, not a verdict

    RECONFIGURE 34, REPLATFORM 9, REDESIGN 1, none BLOCKED. Confidence is MEDIUM for 35 units and LOW for 9, with none HIGH. The architect report gives the reason: the example ships no lock file, and until the provider version is pinned (commit .terraform.lock.hcl) its units are capped at MEDIUM.

  • The matrix says what the run did not do

    The STACKIT plan was not run, no architect approval is recorded, equivalence is not assessed and safe-to-apply is never asserted. A passing static validation of the draft is not approval, and the run labels it that way.

One unit in full: the DynamoDB table

The most instructive unit of the run is the one classed REDESIGN. Left: its record in assessment.json (id, class, confidence, target, reason and review). Right: the stackit_mongodbflex_instance block the run drafted for it, review comments left out.

StackToIT assessmentassessment.json
{
  "id": "module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this",
  "result": {
    "class": "REDESIGN",
    "confidence": "MEDIUM",
    "target": {
      "service": "STACKIT MongoDB Flex (alternative — data-model redesign; PostgreSQL Flex JSONB is the other option)",
      "resources": [
        "stackit_mongodbflex_instance"
      ]
    },
    "reason": "There is no DynamoDB-compatible service on STACKIT. The access layer is rewritten against a document store (MongoDB Flex) or relational JSONB (PostgreSQL Flex); key design, capacity modes and conditional writes do not carry over. The draft is an alternative, not an equivalent: one MongoDB Flex instance for the estate's tables, each table a collection with its keys and secondary indexes named as MongoDB indexes.",
    "review": [
      "Rewrite the data access layer against the MongoDB API (queries, conditional writes, transactions).",
      "Size the instance from the tables' data volume and request load; capacity units do not translate."
    ]
  }
}
STACKIT Terraform by StackToITterraform/data.tf
resource "stackit_mongodbflex_instance" "dynamodb_tables" {
  project_id = var.project_id
  name       = "dynamodb-tables"
  acl        = var.dynamodb_tables_allowed_cidrs
  version    = var.dynamodb_tables_version
  flavor = {
    cpu = var.dynamodb_tables_cpu
    ram = var.dynamodb_tables_ram
  }
  replicas = 3
  storage = {
    class = var.mongodbflex_storage_class
    size  = var.dynamodb_tables_storage_gb
  }
  backup_schedule = "0 2 * * *"
  options = {
    type                       = "Replica"
    point_in_time_window_hours = var.dynamodb_tables_pitr_hours
  }
}
  • The reason is the contract

    There is no DynamoDB-compatible service on STACKIT, so the draft is an alternative, not an equivalent. The reason names what does not carry over: key design, capacity modes and conditional writes.

  • Review items are your to-do list

    The two review lines are tasks: rewrite the data access layer, and size the instance, because capacity units do not translate.

  • Variables mark what only you know

    cpu, ram, storage and the access list are variables without a value. The run does not guess the size of your data.

One decision: from the register to the plan step

A question the code cannot answer becomes a record in decisions.json, a stub in review/decisions.yaml and a manual step in execution-plan.json. This is the NAT egress address, from the same run.

Decision registerdecisions.json
{
  "id": "DEC-NET-STACKITROUTE-NAT-FIXED-EGRESS-ADDRESS-LOST",
  "kind": "NAT_FIXED_EGRESS_ADDRESS_LOST",
  "status": "OPEN",
  "owner_role": "Network Architect",
  "required_by_phase": "BEFORE_PILOT",
  "options": [
    {
      "id": "accept-the-platform-egress-address",
      "execution_effect": "ACK_CURRENT_ARTIFACT"
    },
    {
      "id": "reserve-a-public-ip-per-server",
      "execution_effect": "REGENERATE_REQUIRED"
    }
  ]
}
Review templatereview/decisions.yaml
  # DEC-NET-STACKITROUTE-NAT-FIXED-EGRESS-ADDRESS-LOST
  # NAT_FIXED_EGRESS_ADDRESS_LOST (PLAN_DECISION, status OPEN, 1 member)
  # affects: module.vpc.module.vpc.aws_route_table.private
  # options (name one in chosen_option):
  #   accept-the-platform-egress-address: the draft already carries it out: a review frees the steps that wait for it
  #   reserve-a-public-ip-per-server: changes the draft, and no answer of this build writes it: change the source (or the draft by hand) and run again; a review frees nothing
  - id: DEC-NET-STACKITROUTE-NAT-FIXED-EGRESS-ADDRESS-LOST
    resolution: ""
    # An option above that changes the draft frees no step by a review alone: its line says how the draft comes to carry it. A review that names none of the options frees nothing either.
    # chosen_option: <one of the options above>
    rationale: ""
    evidence_refs: []
    reviewed_by: Network Architect
    reviewed_at: "<YYYY-MM-DD>"
    members_sha256: sha256:cbfcbf1e12e98cb3608485caffc5de82e33e3517a0845fc9ca14cbcf7e207d0e
    artifact_sha256: sha256:37a4992d7cb1b57ebe73b1567f6fec7b6f2f3de527370a9ba50c9d2e600bccea
Plan stepexecution-plan.json
{
  "id": "DEC/routing/stackitroute:module.vpc.module.vpc.aws_route_table.private:NAT_FIXED_EGRESS_ADDRESS_LOST",
  "mode": "MANUAL",
  "phase": "PREPARE",
  "capability": "decision",
  "operation": {
    "manual": {
      "owner_role": "Network Architect",
      "when": "BEFORE_PILOT",
      "success_condition": "the decision DEC-NET-STACKITROUTE-NAT-FIXED-EGRESS-ADDRESS-LOST is answered (accepted or rejected, with its evidence) in the inputs of the run and is no longer open when the run is repeated"
    }
  },
  "runs_as_written": false
}
  • Three files, one id

    The decision id DEC-NET-STACKITROUTE-NAT-FIXED-EGRESS-ADDRESS-LOST appears in all three, so an answer can be traced from the register to the review and to the step that waits for it.

  • Options say what they change

    accept-the-platform-egress-address is carried out by the draft as written, so a review frees the steps that wait for it. reserve-a-public-ip-per-server changes the draft and needs a rerun; a review alone frees nothing.

  • Inputs and reviews are different

    A design answer goes to the inputs file and regenerates the draft. A review records that an architect looked and decided. The next run reads both; a review alone rewrites no Terraform.

Where to look, in order

StepFileWhat you take from it
1 · Summaryindex.html, console.txtSource completeness, class distribution, package state, first blocker
2 · Unitsassessment.jsonClass, confidence, target, reason, review per unit, with the source line
3 · Draftterraform/The STACKIT Terraform, with NOT CARRIED comments per setting
4 · Decisionsdecisions.json, review/Open questions with options, owner role and phase
5 · Planexecution-plan.json, execution/Ordered steps, who does them, what each waits for
6 · Datamigration/data-movement.mdStateful units and the open data questions
7 · Integritymanifest.jsonThe files of the run and their checksums for stacktoit verify

File names as the published run writes them.

Reading rules that save arguments

  • Zero can run as written

    The Retail run says 48 of 57 automated steps are free of decisions, yet 0 can run as written because they wait for values such as project_id. Free of decisions is not ready to apply.

  • A default is not an answer

    Two records rest on a draft default: public endpoint and size derived from the source. Until someone confirms or changes them, they are open.

  • Not carried means said

    Every setting the draft leaves out is named in the file with the reason. The run reports 404 source properties checked on generated units, 204 carried or explained and 200 not carried, with none unaccounted.

  • Verify before you rely on a folder

    stacktoit verify checks the files against the manifest. For the published run it reports 145 files matching, 7 of 7 checks passing.

  • Nothing is applied

    The run reads code and writes files. It creates nothing in any cloud.

Questions reviewers ask

Why are there no HIGH confidence units in the run?

The source provider is unpinned: the Retail example ships no lock file. Confidence is capped at MEDIUM until the exact provider version is pinned.

Does a REPLATFORM class mean the move is easy?

It means the workload moves to a different platform model. Read the review items and the NOT CARRIED comments to size the effort.

Where do I put my answers?

Copy inputs-template.yaml and decisions-template.yaml outside the run folder, fill the requested fields without changing their identifiers, and pass them with --inputs and --decisions on the next run.

Can I trust the Terraform as it is?

It is a draft for review. The run validated it statically, and no plan was run against a STACKIT project.

Sources

Your next move: STACKIT.

Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.