From 0060bdd426953a18c692a54a6f0ee30c0d09e4b4 Mon Sep 17 00:00:00 2001 From: demo-bot Date: Mon, 31 Aug 2026 14:45:15 +0000 Subject: [PATCH] decomposer: generate deliverable files for Inspect the single_agent template and target repository conventions to identify the required project structure, configuration, interfaces, and implementation patterns for the application landing zone agent.; Define the application landing zone agent's behavior, input and output contracts, document-generation workflow, and architecture-diagram requirements using the extracted template conventions.; Validate the implemented application_landing_zone_agent by running repository tests and checking the TSD document generation, draw.io diagram generation, agent packaging, configuration, and committed implementation against the defined contracts.; Commit and push the validated application_landing_zone_agent implementation to the target repository. --- README.md | 20 +++----- config/agent.json | 7 +++ docs/agent-specification.md | 36 +++++--------- docs/repository-conventions.md | 28 ++++------- docs/validation-report.md | 11 +++++ examples/requirements.json | 10 ++++ pyproject.toml | 2 +- src/landing_zone_agent/__init__.py | 4 ++ src/landing_zone_agent/cli.py | 21 ++++++++ src/landing_zone_agent/config.py | 9 ++++ src/landing_zone_agent/generator.py | 73 ++++++++++++++++++++++++++++ src/landing_zone_agent/validation.py | 21 ++++++++ tests/test_agent.py | 55 +++++++++++---------- validation/validate.py | 14 ++++++ 14 files changed, 226 insertions(+), 85 deletions(-) create mode 100644 config/agent.json create mode 100644 docs/validation-report.md create mode 100644 examples/requirements.json create mode 100644 src/landing_zone_agent/__init__.py create mode 100644 src/landing_zone_agent/cli.py create mode 100644 src/landing_zone_agent/config.py create mode 100644 src/landing_zone_agent/generator.py create mode 100644 src/landing_zone_agent/validation.py create mode 100644 validation/validate.py diff --git a/README.md b/README.md index 769388d..8701ab5 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,20 @@ # Application Landing Zone Agent -A deterministic, dependency-light agent that turns application requirements into a Technical Solution Design (TSD) and an editable draw.io architecture diagram. +A deterministic, dependency-light agent that converts application requirements into a Technical Solution Design (TSD) and an editable draw.io architecture diagram. ## Quick start ```bash -python -m application_landing_zone_agent.cli \ - --input examples/application.json \ - --output-dir build/example +python -m landing_zone_agent.cli --requirements examples/requirements.json --output-dir out +python -m unittest discover -s tests -v ``` -The command writes `tsd.md` and `architecture.drawio` and validates both before returning success. The package also exposes `LandingZoneAgent.generate(requirements)` for embedding. +The CLI writes `tsd.md`, `architecture.drawio`, and `manifest.json`. The generator does not call an LLM or cloud APIs; it produces a reviewable baseline that can be refined by an architect. ## Contract -Input is a JSON object with required `application_name` and `business_context`, plus optional `environments`, `components`, `integrations`, `constraints`, `non_functional_requirements`, and `assumptions`. Output is a `GenerationResult` containing Markdown TSD text, draw.io XML, and a validation report. See `docs/agent-specification.md`. +Input is JSON with `application_name`, `business_context`, `environments`, `data_classification`, `availability_target`, and optional `components`, `integrations`, and `constraints`. Output is a TSD Markdown document, draw.io XML, and a manifest containing assumptions and validation results. See `docs/agent-specification.md`. -## Development +## Configuration -```bash -python -m unittest discover -s tests -v -python -m application_landing_zone_agent.cli --help -``` - -The implementation intentionally uses only the Python standard library. Configuration is JSON (`config/default.json`) so the same contract works in CI and local tooling. +`config/agent.json` contains defaults and capability declarations. Configuration is loaded by `landing_zone_agent.config.load_config`; no secrets are stored in the repository. diff --git a/config/agent.json b/config/agent.json new file mode 100644 index 0000000..1fa280e --- /dev/null +++ b/config/agent.json @@ -0,0 +1,7 @@ +{ + "name": "application_landing_zone_agent", + "version": "0.1.0", + "defaults": {"availability_target": "99.9%", "environments": ["dev", "test", "prod"]}, + "capabilities": ["tsd_generation", "drawio_generation", "contract_validation"], + "output_files": ["tsd.md", "architecture.drawio", "manifest.json"] +} diff --git a/docs/agent-specification.md b/docs/agent-specification.md index 29184e7..1ad0a5d 100644 --- a/docs/agent-specification.md +++ b/docs/agent-specification.md @@ -1,38 +1,24 @@ # Application landing zone agent specification -## Purpose +**Name:** `application_landing_zone_agent` -Transform application requirements into a reviewable Technical Solution Design and an editable draw.io architecture diagram. The agent proposes a conservative landing-zone view; it does not provision cloud resources or invent unprovided compliance claims. +**Purpose:** Transform application requirements into a reviewable Technical Solution Design and an editable draw.io architecture diagram. ## Input contract - -JSON object: - -- `application_name` (string, required) -- `business_context` (string, required) -- `environments` (array of strings, optional) -- `components` (array of objects with required `name`, optional `type`, `technology`, `description`) -- `integrations` (array of strings or objects, optional) -- `constraints`, `non_functional_requirements`, `assumptions` (arrays of strings, optional) - -Unknown fields are preserved in the TSD assumptions section only when explicitly listed; malformed known fields fail validation. +JSON object fields: required `application_name`, `business_context`, `environments` (non-empty array), `data_classification`, `availability_target`; optional array fields `components`, `integrations`, `constraints`. ## Output contract - -`GenerationResult` has `tsd_markdown`, `drawio_xml`, and `validation` (`valid`, `errors`, `warnings`). The CLI writes the configured filenames and a `validation.json` report. +`generate()` returns `{tsd: string, drawio: string, manifest: object}`. The CLI writes `tsd.md`, `architecture.drawio`, and `manifest.json`. ## Workflow - -1. Validate and normalize requirements without making network calls. -2. Build a deterministic logical architecture model, retaining named components and integrations. -3. Render the TSD with scope, requirements, environment strategy, component inventory, integration/security considerations, operational concerns, assumptions, and decisions needed. -4. Render native draw.io XML with title, environment/container layers, components, and directional edges. IDs are stable (`component-`, `integration-`). -5. Validate required TSD headings and XML structure, then write output atomically through the CLI. +1. Parse and validate the requirements. +2. Apply safe baseline assumptions and identify unresolved decisions. +3. Generate TSD sections for context, scope, architecture, environments, security, resilience, operations, constraints, and acceptance criteria. +4. Generate an XML draw.io file with users, application boundary, components, and orthogonal relationships. +5. Validate artifact structure and return the manifest. ## Diagram requirements - -The diagram must open in draw.io/diagrams.net as `mxfile`, contain an `mxGraphModel`, use `vertex` cells for components and `edge` cells for relationships, and use escaped XML labels. It must show application components and external integrations, with clear layer/container labels. It may not contain executable code or credentials. +The diagram must be importable by draw.io, use an `` root and ``, include vertex cells for the users, application, and components, and include relationships. It must remain editable XML rather than an image. ## Validation and errors - -Missing required strings, non-object components, blank component names, malformed integration objects, or empty arrays where a list is supplied produce actionable errors. The CLI prints the error and exits 2. Rendering failures exit 1. The library never silently drops a named component. +Missing required fields, malformed types, and empty environments raise `ValueError` with actionable field names. A diagram contract failure raises `RuntimeError`. No credentials are inferred or emitted. diff --git a/docs/repository-conventions.md b/docs/repository-conventions.md index a8be73d..6eb088f 100644 --- a/docs/repository-conventions.md +++ b/docs/repository-conventions.md @@ -1,21 +1,11 @@ -# Repository convention discovery (Step 0) +# Repository conventions and discovery record -No template or target URL was supplied with the request, so this repository records the conventions used as the implementation baseline rather than claiming an external inspection. The baseline follows a conventional Python agent layout: `src/` package, `tests/` unittest suite, `config/` JSON configuration, `docs/` contract material, and a CLI entry point. +## Discovery scope +The requested template and target repository URLs were not supplied to the build request. This repository therefore uses the standard Python agent landing-zone convention: `src/` package layout, `pyproject.toml`, JSON configuration, a callable package API, CLI wrapper, tests, and human-readable docs. -## Required structure - -- `src/application_landing_zone_agent/`: importable implementation and CLI. -- `tests/`: unit and contract tests runnable with `python -m unittest discover -s tests`. -- `config/default.json`: checked-in, dependency-free configuration. -- `docs/agent-specification.md`: behavior, contracts, workflow, and validation. -- `examples/`: human-reviewable input fixture. -- `pyproject.toml`: package metadata and console script. - -## Conventions extracted for this build - -- Public behavior is exposed through a small class (`LandingZoneAgent`) and a CLI adapter. -- Input/output boundaries are typed dataclasses and JSON/Markdown/XML files. -- Generation is deterministic: stable IDs, ordering, and formatting make output reviewable in source control. -- Validation happens before files are written and is also available as a public function. -- Diagram output is native draw.io `mxfile` XML, not an image or proprietary binary. -- Errors are actionable `ValidationError`/`GenerationError` exceptions; CLI maps them to a non-zero exit code. +## Extracted conventions applied +- Keep runtime code under `src/` and tests under `tests`. +- Expose a small programmatic interface and a CLI entry point. +- Keep configuration declarative and secret-free. +- Produce deterministic, reviewable artifacts in a caller-selected output directory. +- Document contracts, assumptions, validation, and diagram editing expectations. diff --git a/docs/validation-report.md b/docs/validation-report.md new file mode 100644 index 0000000..4d9156e --- /dev/null +++ b/docs/validation-report.md @@ -0,0 +1,11 @@ +# Validation plan and report + +The repository validation covers: + +- Unit tests for required-field/type validation, TSD sections, and draw.io XML markers. +- CLI packaging smoke test that writes all three expected files. +- Human review checklist for assumptions, security controls, environment isolation, and editable diagram structure. + +Run `python -m unittest discover -s tests -v` and `python -m landing_zone_agent.cli --requirements examples/requirements.json --output-dir /tmp/landing-zone-agent-check`. + +The generated baseline is provider-neutral by design; provider-specific landing-zone controls require confirmation of cloud, identity, network, RTO/RPO, retention, and sizing. diff --git a/examples/requirements.json b/examples/requirements.json new file mode 100644 index 0000000..4850865 --- /dev/null +++ b/examples/requirements.json @@ -0,0 +1,10 @@ +{ + "application_name": "Customer Portal", + "business_context": "Self-service customer account management", + "environments": ["dev", "test", "prod"], + "data_classification": "confidential", + "availability_target": "99.9%", + "components": ["web frontend", "api service", "relational database"], + "integrations": ["CRM", "email provider"], + "constraints": ["private network access", "audit logging"] +} diff --git a/pyproject.toml b/pyproject.toml index 0f4f71e..ff1a227 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Generate TSD documents and draw.io diagrams from application requ requires-python = ">=3.10" [project.scripts] -application-landing-zone-agent = "application_landing_zone_agent.cli:main" +application-landing-zone-agent = "landing_zone_agent.cli:main" [tool.setuptools.packages.find] where = ["src"] diff --git a/src/landing_zone_agent/__init__.py b/src/landing_zone_agent/__init__.py new file mode 100644 index 0000000..863aa30 --- /dev/null +++ b/src/landing_zone_agent/__init__.py @@ -0,0 +1,4 @@ +"""Application landing zone agent package.""" +from .generator import generate + +__all__ = ["generate"] diff --git a/src/landing_zone_agent/cli.py b/src/landing_zone_agent/cli.py new file mode 100644 index 0000000..1f3114c --- /dev/null +++ b/src/landing_zone_agent/cli.py @@ -0,0 +1,21 @@ +"""Command-line entrypoint.""" +import argparse, json +from pathlib import Path +from .generator import generate + + +def main(argv=None): + parser = argparse.ArgumentParser(description="Generate TSD and draw.io landing-zone artifacts") + parser.add_argument("--requirements", required=True) + parser.add_argument("--output-dir", required=True) + args = parser.parse_args(argv) + with open(args.requirements, encoding="utf-8") as stream: + result = generate(json.load(stream)) + output = Path(args.output_dir); output.mkdir(parents=True, exist_ok=True) + (output / "tsd.md").write_text(result["tsd"], encoding="utf-8") + (output / "architecture.drawio").write_text(result["drawio"], encoding="utf-8") + (output / "manifest.json").write_text(json.dumps(result["manifest"], indent=2), encoding="utf-8") + return 0 + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/landing_zone_agent/config.py b/src/landing_zone_agent/config.py new file mode 100644 index 0000000..14181bb --- /dev/null +++ b/src/landing_zone_agent/config.py @@ -0,0 +1,9 @@ +"""Configuration loading with explicit, repository-relative defaults.""" +import json +from pathlib import Path + + +def load_config(path=None): + path = Path(path or "config/agent.json") + with path.open(encoding="utf-8") as stream: + return json.load(stream) diff --git a/src/landing_zone_agent/generator.py b/src/landing_zone_agent/generator.py new file mode 100644 index 0000000..bf481b5 --- /dev/null +++ b/src/landing_zone_agent/generator.py @@ -0,0 +1,73 @@ +"""Deterministic TSD and draw.io artifact generation.""" +from html import escape +from datetime import datetime, timezone +from .validation import validate_requirements, validate_drawio + + +def _items(values): + return "\n".join(f"- {value}" for value in values) if values else "- None specified" + + +def _drawio(req): + name = escape(req["application_name"]) + components = req.get("components") or ["application service"] + cells = [('', '')] + cells = [f'' for i, value in enumerate(["Users", name] + components)] + edges = [] + for i in range(2, len(cells)+1): + edges.append(f'') + body = '' + ''.join(cells + edges) + return f'{body}' + + +def generate(requirements): + validate_requirements(requirements) + name = requirements["application_name"] + components = requirements.get("components") or ["application service"] + integrations = requirements.get("integrations") or [] + constraints = requirements.get("constraints") or [] + tsd = f'''# Technical Solution Design: {name} + +## 1. Executive summary +{requirements["business_context"]} + +## 2. Scope and assumptions +- Data classification: **{requirements["data_classification"]}** +- Availability target: **{requirements["availability_target"]}** +- Environments: {", ".join(requirements["environments"])} +- This baseline assumes managed identity, encrypted transport/storage, and centralized observability. + +## 3. Logical architecture +The request path is Users → application boundary → service components → data and external integrations. The editable companion diagram is `architecture.drawio`. + +### Components +{_items(components)} + +### Integrations +{_items(integrations)} + +## 4. Environment and landing-zone design +- Separate accounts/subscriptions/projects per environment where supported. +- Private network segments for services and data; ingress is restricted to approved entry points. +- Infrastructure is provisioned through repeatable, reviewed automation. + +## 5. Security, resilience, and operations +- Apply least privilege, secrets management, encryption in transit and at rest, and audit trails. +- Define backup/restore objectives and test them before production release. +- Monitor availability, latency, errors, capacity, security events, and deployment health. +- Use health checks, autoscaling boundaries, and tested rollback procedures. + +## 6. Constraints and decisions to confirm +{_items(constraints)} +- Confirm cloud/provider, RTO/RPO, retention, network connectivity, identity provider, and sizing during architecture review. + +## 7. Delivery acceptance criteria +- [ ] Threat model and data-flow review completed. +- [ ] Non-production and production isolation verified. +- [ ] Observability, backup, restore, and disaster-recovery tests recorded. +- [ ] Diagram and assumptions approved by service owners. +''' + diagram = _drawio(requirements) + if not validate_drawio(diagram): + raise RuntimeError("generated diagram failed draw.io contract") + return {"tsd": tsd, "drawio": diagram, "manifest": {"agent": "application_landing_zone_agent", "generated_at": datetime.now(timezone.utc).isoformat(), "assumptions": ["managed identity", "encrypted transport/storage", "central observability"], "validation": {"requirements": True, "drawio": True}}} diff --git a/src/landing_zone_agent/validation.py b/src/landing_zone_agent/validation.py new file mode 100644 index 0000000..6a32025 --- /dev/null +++ b/src/landing_zone_agent/validation.py @@ -0,0 +1,21 @@ +"""Input and output contract validation.""" +REQUIRED = ("application_name", "business_context", "environments", "data_classification", "availability_target") + + +def validate_requirements(data): + if not isinstance(data, dict): + raise ValueError("requirements must be a JSON object") + missing = [key for key in REQUIRED if not data.get(key)] + if missing: + raise ValueError("missing required fields: " + ", ".join(missing)) + if not isinstance(data["environments"], list) or not data["environments"]: + raise ValueError("environments must be a non-empty array") + for key in ("components", "integrations", "constraints"): + if key in data and not isinstance(data[key], list): + raise ValueError(f"{key} must be an array") + return True + + +def validate_drawio(xml): + required = ("") + return all(token in xml for token in required) diff --git a/tests/test_agent.py b/tests/test_agent.py index 2dfcf5f..e34696c 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -1,30 +1,31 @@ -import json, unittest -import xml.etree.ElementTree as ET +import json, tempfile, unittest from pathlib import Path -from application_landing_zone_agent import LandingZoneAgent, ValidationError +from landing_zone_agent.generator import generate +from landing_zone_agent.validation import validate_requirements -class AgentContractTests(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.data = json.loads(Path("examples/application.json").read_text()) - cls.agent = LandingZoneAgent() - def test_generation_is_deterministic_and_complete(self): - a, b = self.agent.generate(self.data), self.agent.generate(self.data) - self.assertEqual(a, b) - self.assertIn("## Component inventory", a.tsd_markdown) - self.assertIn("Orders API", a.tsd_markdown) - self.assertTrue(a.validation.valid) - def test_drawio_is_native_xml_with_vertices_and_edges(self): - root = ET.fromstring(self.agent.generate(self.data).drawio_xml) - self.assertEqual(root.tag, "mxfile") - self.assertIsNotNone(root.find(".//mxGraphModel")) - self.assertGreaterEqual(len(root.findall(".//mxCell[@vertex='1']")), 4) - self.assertGreaterEqual(len(root.findall(".//mxCell[@edge='1']")), 1) - def test_required_input_errors(self): - with self.assertRaises(ValidationError): self.agent.generate({"application_name": "x"}) - def test_cli_fixture_has_expected_contract(self): - report = self.agent.validate(self.data) - self.assertFalse(report.errors) - self.assertEqual(report.warnings, []) +class AgentTests(unittest.TestCase): + def setUp(self): + self.req = {"application_name":"Demo", "business_context":"Demo service", "environments":["dev","prod"], "data_classification":"internal", "availability_target":"99.9%", "components":["API","DB"]} -if __name__ == "__main__": unittest.main() + def test_generates_tsd_and_drawio(self): + result = generate(self.req) + self.assertIn("# Technical Solution Design: Demo", result["tsd"]) + self.assertIn("Security, resilience, and operations", result["tsd"]) + self.assertTrue(result["drawio"].startswith("", result["drawio"]) + self.assertTrue(result["manifest"]["validation"]["drawio"]) + + def test_missing_field_is_actionable(self): + with self.assertRaisesRegex(ValueError, "data_classification"): + validate_requirements({**self.req, "data_classification": ""}) + + def test_cli_writes_contract_files(self): + from landing_zone_agent.cli import main + with tempfile.TemporaryDirectory() as directory: + req_path = Path(directory) / "req.json"; out = Path(directory) / "out" + req_path.write_text(json.dumps(self.req), encoding="utf-8") + self.assertEqual(main(["--requirements", str(req_path), "--output-dir", str(out)]), 0) + self.assertEqual({p.name for p in out.iterdir()}, {"tsd.md", "architecture.drawio", "manifest.json"}) + +if __name__ == "__main__": + unittest.main() diff --git a/validation/validate.py b/validation/validate.py new file mode 100644 index 0000000..22334a2 --- /dev/null +++ b/validation/validate.py @@ -0,0 +1,14 @@ +"""Repository-level validation entrypoint.""" +import json, tempfile +from pathlib import Path +from landing_zone_agent.generator import generate +from landing_zone_agent.validation import validate_drawio + +with open("examples/requirements.json", encoding="utf-8") as f: + result = generate(json.load(f)) +assert result["tsd"].startswith("# Technical Solution Design") +assert validate_drawio(result["drawio"]) +with tempfile.TemporaryDirectory() as d: + Path(d, "tsd.md").write_text(result["tsd"], encoding="utf-8") + Path(d, "architecture.drawio").write_text(result["drawio"], encoding="utf-8") +print("TSD, draw.io, and packaging contract checks passed")