WGS Tools
WGS ships seven Python command-line tools under tools/. Five are declared as validators in WGS.manifest.toml; migrate_entity_manifests.py and normalize_entity_manifests.py are one-time/repeatable migration helpers referenced by the migration notes. All of them default to dry-run or read-only behavior where mutation is possible, per the WGS agent-safety rules.
city_hall_audit.py
Entity-aware validator that audits City Hall standard directories for SFDS/WGS documentation shape, and — when given --workspace-root — also audits the governed development workspace: root files, portfolio manifests, physical-versus-registered children, project/group required files, manifest path and parent consistency, canonical standard-link resolution, placeholder detection, and holding-area exclusion. Produces a Markdown findings table and returns a nonzero exit code on any failure. This is the tool behind the City Hall Standards Audit and both Workspace Governance Audit examples.
#!/usr/bin/env python3
"""Audit City Hall standard directories for SFDS/WGS documentation shape."""
from __future__ import annotations
import argparse
import json
import sys
import tomllib
from dataclasses import dataclass
from pathlib import Path
IGNORED_DIRS = {".git", ".idea", ".vscode", "__pycache__"}
WORKSPACE_PORTFOLIOS = ["WDS", "BASIC", "CTS", "DATA", "DRS"]
REQUIRED_TOP_LEVEL = [
"README.md",
"Adoption-Guide.md",
"Validation-Checklist.md",
"CHANGELOG.md",
]
@dataclass
class Finding:
standard: str
level: str
message: str
def load_manifest(path: Path) -> tuple[dict, str | None]:
try:
with path.open("rb") as handle:
return tomllib.load(handle), None
except Exception as exc: # pragma: no cover - diagnostic path
return {}, f"manifest parse failed: {exc}"
def version_in_changelog(changelog: Path, version: str) -> bool:
if not changelog.exists() or not version:
return False
text = changelog.read_text(encoding="utf-8", errors="replace")
return f"## {version}" in text or f"## [{version}]" in text
def audit_standard(directory: Path) -> list[Finding]:
findings: list[Finding] = []
name = directory.name
manifest_path = directory / f"{name}.manifest.toml"
if not manifest_path.exists():
findings.append(Finding(name, "FAIL", f"missing entity-named manifest {manifest_path.name}"))
return findings
manifest, manifest_error = load_manifest(manifest_path)
if manifest_error:
findings.append(Finding(name, "FAIL", manifest_error))
return findings
for rel_path in REQUIRED_TOP_LEVEL:
if not (directory / rel_path).exists():
findings.append(Finding(name, "FAIL", f"missing {rel_path}"))
artifacts = manifest.get("artifacts", {})
spec_rel = artifacts.get("specification", "")
if not spec_rel:
findings.append(Finding(name, "FAIL", "manifest does not declare artifacts.specification"))
elif not (directory / spec_rel).exists():
findings.append(Finding(name, "FAIL", f"declared specification is missing: {spec_rel}"))
examples_rel = artifacts.get("examples", "examples")
if examples_rel:
examples_dir = directory / examples_rel
if not examples_dir.exists():
findings.append(Finding(name, "WARN", f"examples directory is missing: {examples_rel}"))
elif not any(item.is_file() for item in examples_dir.rglob("*")):
findings.append(Finding(name, "WARN", f"examples directory has no files: {examples_rel}"))
templates_rel = artifacts.get("templates", "")
if templates_rel:
templates_dir = directory / templates_rel
if not templates_dir.exists():
findings.append(Finding(name, "WARN", f"templates directory is declared but missing: {templates_rel}"))
schema_rel = artifacts.get("schema", "")
if schema_rel:
schema_path = directory / schema_rel
if not schema_path.exists():
findings.append(Finding(name, "FAIL", f"declared schema is missing: {schema_rel}"))
elif schema_path.suffix == ".json":
try:
json.loads(schema_path.read_text(encoding="utf-8"))
except Exception as exc:
findings.append(Finding(name, "FAIL", f"declared JSON schema does not parse: {schema_rel}: {exc}"))
for rel_path in artifacts.get("validators", []):
if rel_path and not (directory / rel_path).exists():
findings.append(Finding(name, "WARN", f"declared validator is missing: {rel_path}"))
for key in ["adoption_guide", "validation_checklist", "changelog"]:
rel_path = artifacts.get(key, "")
if rel_path and not (directory / rel_path).exists():
findings.append(Finding(name, "FAIL", f"declared {key} is missing: {rel_path}"))
for rel_path in artifacts.get("reference_examples", []):
if rel_path and not (directory / rel_path).exists():
findings.append(Finding(name, "WARN", f"declared reference example is missing: {rel_path}"))
for rel_path in artifacts.get("governance_notes", []):
if rel_path and not (directory / rel_path).exists():
findings.append(Finding(name, "WARN", f"declared governance note is missing: {rel_path}"))
adopter_artifacts = manifest.get("adopter_artifacts", {})
for key in ["schemas", "manifest_templates", "document_templates"]:
for rel_path in adopter_artifacts.get(key, []):
if rel_path and not (directory / rel_path).exists():
findings.append(Finding(name, "WARN", f"declared adopter {key[:-1]} is missing: {rel_path}"))
version = str(manifest.get("standard", {}).get("version", ""))
changelog = directory / str(artifacts.get("changelog", "CHANGELOG.md"))
if version and not version_in_changelog(changelog, version):
findings.append(Finding(name, "FAIL", f"manifest version {version} is not recorded in changelog"))
return findings
def standard_directories(root: Path) -> list[Path]:
directories = []
for item in root.iterdir():
if item.is_dir() and item.name not in IGNORED_DIRS and (item / f"{item.name}.manifest.toml").exists():
directories.append(item)
return sorted(directories, key=lambda path: path.name.lower())
def render_markdown(root: Path, findings_by_standard: dict[str, list[Finding]]) -> str:
lines = [
"# City Hall Standards Audit",
"",
f"- Root: `{root}`",
f"- Audit scopes inspected: {len(findings_by_standard)}",
"",
"| Scope | Status | Findings |",
"| --- | --- | --- |",
]
for standard, findings in findings_by_standard.items():
if not findings:
lines.append(f"| {standard} | pass | None |")
continue
status = "fail" if any(f.level == "FAIL" for f in findings) else "warn"
message = "<br>".join(f"{f.level}: {f.message}" for f in findings)
lines.append(f"| {standard} | {status} | {message} |")
lines.append("")
return "\n".join(lines)
def windows_path(value: str) -> Path:
"""Resolve a manifest's absolute Windows path without changing its meaning."""
return Path(value)
def placeholder_values(value: object, location: str = "") -> list[str]:
findings: list[str] = []
if isinstance(value, dict):
for key, child in value.items():
findings.extend(placeholder_values(child, f"{location}.{key}" if location else str(key)))
elif isinstance(value, list):
for index, child in enumerate(value):
findings.extend(placeholder_values(child, f"{location}[{index}]"))
elif isinstance(value, str):
lowered = value.lower()
tokens = ["yyyy-mm-dd", "example-project", "example-directory", "000-example", "replace with"]
if any(token in lowered for token in tokens):
findings.append(f"placeholder value at {location}: {value}")
return findings
def audit_governance_links(scope: str, manifest: dict) -> list[Finding]:
findings: list[Finding] = []
governance = manifest.get("governance", {})
declared = [governance.get("primary_standard_path", "")]
declared.extend(governance.get("additional_standard_paths", []))
release_path = governance.get("release_standard_path", "")
if release_path:
declared.append(release_path)
for value in declared:
if not value:
findings.append(Finding(scope, "FAIL", "empty canonical standard path"))
elif not windows_path(str(value)).exists():
findings.append(Finding(scope, "FAIL", f"canonical standard link does not resolve: {value}"))
return findings
def entity_manifest_path(directory: Path) -> Path:
return directory / f"{directory.name}.manifest.toml"
def canonical_entity_manifests(directory: Path) -> list[Path]:
records: list[Path] = []
for path in directory.glob("*.manifest.toml"):
manifest, error = load_manifest(path)
if error:
continue
if manifest.get("manifest", {}).get("manifest_type") in {"directory", "project"}:
records.append(path)
return records
def audit_local_authority(directory: Path, scope: str) -> list[Finding]:
findings: list[Finding] = []
expected = entity_manifest_path(directory)
if not expected.is_file():
findings.append(Finding(scope, "FAIL", f"missing entity-named manifest {expected.name}"))
fixed = [directory / "directory.manifest.toml", directory / "project.manifest.toml"]
for path in fixed:
if path.exists() and path != expected:
findings.append(Finding(scope, "FAIL", f"superseded fixed-name manifest remains: {path.name}"))
authorities = canonical_entity_manifests(directory)
if len(authorities) > 1:
findings.append(Finding(scope, "FAIL", "multiple local entity authorities: " + ", ".join(path.name for path in authorities)))
return findings
def same_path(left: str, right: Path) -> bool:
try:
return windows_path(str(left)).resolve() == right.resolve()
except Exception:
return False
def audit_manifest_common(directory: Path, manifest: dict, expected_parent: Path) -> list[Finding]:
scope = str(directory)
findings = audit_local_authority(directory, scope)
expected_name = entity_manifest_path(directory).name
if manifest.get("manifest", {}).get("canonical_name") != expected_name:
findings.append(Finding(scope, "FAIL", f"canonical_name is not {expected_name}"))
domain = manifest.get("directory") or manifest.get("paths", {})
recorded = domain.get("path") if "directory" in manifest else domain.get("root")
if not recorded or not same_path(str(recorded), directory):
findings.append(Finding(scope, "FAIL", f"manifest path does not match physical path: {recorded}"))
parent = manifest.get("relationships", {}).get("parent", "")
if not parent or not same_path(str(parent), expected_parent):
findings.append(Finding(scope, "FAIL", f"manifest parent does not match: {parent}"))
findings.extend(audit_governance_links(scope, manifest))
for message in placeholder_values(manifest):
findings.append(Finding(scope, "FAIL", message))
return findings
def audit_project(project_dir: Path, expected_parent: Path) -> list[Finding]:
scope = str(project_dir)
findings: list[Finding] = []
manifest_path = entity_manifest_path(project_dir)
for filename in ["AGENTS.md", manifest_path.name, "Project-README.md"]:
if not (project_dir / filename).is_file():
findings.append(Finding(scope, "FAIL", f"missing {filename}"))
if not manifest_path.exists():
return findings + audit_local_authority(project_dir, scope)
manifest, error = load_manifest(manifest_path)
if error:
return findings + [Finding(scope, "FAIL", error)]
findings.extend(audit_manifest_common(project_dir, manifest, expected_parent))
project = manifest.get("project", {})
entity = manifest.get("entity", {})
if project.get("version") in {None, "", "unverified", "0.0.0"}:
findings.append(Finding(scope, "FAIL", f"unreconciled project version: {project.get('version')}"))
if project.get("stage") == "existing-unverified" or entity.get("status") == "unverified":
findings.append(Finding(scope, "FAIL", "unreconciled lifecycle classification"))
verification = manifest.get("verification", {})
if not verification:
findings.append(Finding(scope, "FAIL", "missing verification boundary"))
if entity.get("status") == "release-ready" and not all(
verification.get(field) for field in ["build_verified", "tests_verified", "artifact_verified", "release_verified"]
):
findings.append(Finding(scope, "FAIL", "release-ready status is not supported by complete verification"))
for child_name in manifest.get("relationships", {}).get("child_projects", []):
child = project_dir / str(child_name)
if not child.is_dir():
findings.append(Finding(scope, "FAIL", f"registered child project is missing: {child_name}"))
else:
findings.extend(audit_project(child, project_dir))
for child_name in manifest.get("relationships", {}).get("child_containers", []):
child = project_dir / str(child_name)
findings.extend(audit_directory_entity(child, project_dir, compare_children=False))
return findings
def audit_directory_entity(directory: Path, expected_parent: Path, compare_children: bool = True) -> list[Finding]:
scope = str(directory)
findings: list[Finding] = []
manifest_path = entity_manifest_path(directory)
for filename in ["AGENTS.md", manifest_path.name]:
if not (directory / filename).is_file():
findings.append(Finding(scope, "FAIL", f"missing {filename}"))
if not manifest_path.exists():
return findings + audit_local_authority(directory, scope)
manifest, error = load_manifest(manifest_path)
if error:
return findings + [Finding(scope, "FAIL", error)]
findings.extend(audit_manifest_common(directory, manifest, expected_parent))
if compare_children:
registered = set(manifest.get("structure", {}).get("children", []))
physical = {item.name for item in directory.iterdir() if item.is_dir() and item.name not in IGNORED_DIRS}
for child in sorted(registered - physical, key=str.lower):
findings.append(Finding(scope, "FAIL", f"registered child is missing: {child}"))
for child in sorted(physical - registered, key=str.lower):
findings.append(Finding(scope, "FAIL", f"physical child is not registered: {child}"))
return findings
def audit_holding(directory: Path, expected_parent: Path) -> list[Finding]:
findings = audit_directory_entity(directory, expected_parent, compare_children=True)
manifest_path = entity_manifest_path(directory)
if manifest_path.exists():
manifest, error = load_manifest(manifest_path)
if not error and not manifest.get("policy", {}).get("exclude_from_active_reporting", False):
findings.append(Finding(str(directory), "FAIL", "holding is not excluded from active reporting"))
return findings
def audit_portfolio(workspace_root: Path, portfolio_name: str) -> list[Finding]:
directory = workspace_root / portfolio_name
findings: list[Finding] = []
if not directory.is_dir():
return [Finding(portfolio_name, "FAIL", f"portfolio directory is missing: {directory}")]
manifest_path = entity_manifest_path(directory)
findings.extend(audit_directory_entity(directory, workspace_root, compare_children=True))
if not manifest_path.exists():
return findings
manifest, error = load_manifest(manifest_path)
if error:
return findings
registered = set(manifest.get("structure", {}).get("children", []))
classification = manifest.get("classification", {})
classified: dict[str, str] = {}
for class_name, names in classification.items():
if class_name in {"artifacts", "root_artifacts"}:
continue
for child in names:
child = str(child)
if child in classified:
findings.append(Finding(portfolio_name, "FAIL", f"child has multiple classifications: {child}"))
classified[child] = class_name
for child in sorted(registered - set(classified), key=str.lower):
findings.append(Finding(portfolio_name, "FAIL", f"registered child lacks classification: {child}"))
for child in sorted(set(classified) - registered, key=str.lower):
findings.append(Finding(portfolio_name, "FAIL", f"classified child is not registered: {child}"))
for child, class_name in sorted(classified.items(), key=lambda item: item[0].lower()):
child_dir = directory / child
if class_name in {"projects", "project_groups", "datasets"}:
findings.extend(audit_project(child_dir, directory))
elif class_name in {"external_sources", "containers", "services", "caches", "runtimes"}:
findings.extend(audit_directory_entity(child_dir, directory, compare_children=False))
elif class_name == "archives":
findings.extend(audit_holding(child_dir, directory))
governance_shortcuts = sorted(path.name for path in directory.glob("*.lnk"))
if governance_shortcuts:
findings.append(Finding(portfolio_name, "FAIL", "portfolio-root Windows shortcuts are forbidden: " + ", ".join(governance_shortcuts)))
return findings
def audit_workspace(workspace_root: Path) -> dict[str, list[Finding]]:
findings: dict[str, list[Finding]] = {}
root_findings: list[Finding] = []
for filename in ["AGENTS.md", "INDEX.md", "Development.manifest.toml"]:
if not (workspace_root / filename).is_file():
root_findings.append(Finding("workspace", "FAIL", f"missing root file {filename}"))
development_path = workspace_root / "Development.manifest.toml"
development: dict = {}
if development_path.exists():
development, error = load_manifest(development_path)
if error:
root_findings.append(Finding("workspace", "FAIL", error))
else:
if development.get("manifest", {}).get("canonical_name") != "Development.manifest.toml":
root_findings.append(Finding("workspace", "FAIL", "drive manifest canonical_name is incorrect"))
for message in placeholder_values(development):
root_findings.append(Finding("workspace", "FAIL", message))
for root in development.get("roots", []):
path = windows_path(str(root.get("path", "")))
manifest = windows_path(str(root.get("manifest", "")))
if not path.exists():
root_findings.append(Finding("workspace", "FAIL", f"registered root is missing: {path}"))
if not manifest.exists():
root_findings.append(Finding("workspace", "FAIL", f"registered root manifest is missing: {manifest}"))
findings["workspace:root"] = root_findings
for portfolio in WORKSPACE_PORTFOLIOS:
findings[f"portfolio:{portfolio}"] = audit_portfolio(workspace_root, portfolio)
for root in development.get("roots", []):
path = windows_path(str(root.get("path", "")))
if root.get("kind") in {"shared-infrastructure", "reference-library", "shared-runtime"} and path.exists():
findings[f"foundation:{path.name}"] = audit_directory_entity(path, workspace_root, compare_children=True)
manifest, error = load_manifest(entity_manifest_path(path))
if not error:
classification = manifest.get("classification", {})
for names in classification.values():
for child_name in names:
child = path / str(child_name)
if entity_manifest_path(child).exists():
findings[f"foundation:{path.name}"].extend(audit_directory_entity(child, path, compare_children=False))
return findings
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, default=Path.cwd(), help="City Hall workspace root.")
parser.add_argument("--workspace-root", type=Path, help="Also audit the governed development workspace and portfolios.")
parser.add_argument("--entity-root", type=Path, action="append", default=[], help="Audit an additional project or directory entity root.")
args = parser.parse_args()
root = args.root.resolve()
if not root.exists():
print(f"Root does not exist: {root}", file=sys.stderr)
return 2
findings_by_standard = {
directory.name: audit_standard(directory)
for directory in standard_directories(root)
}
if args.workspace_root:
workspace_root = args.workspace_root.resolve()
if not workspace_root.exists():
print(f"Workspace root does not exist: {workspace_root}", file=sys.stderr)
return 2
findings_by_standard.update(audit_workspace(workspace_root))
for entity_root in args.entity_root:
directory = entity_root.resolve()
manifest_path = entity_manifest_path(directory)
manifest, error = load_manifest(manifest_path) if manifest_path.exists() else ({}, "manifest missing")
if error:
findings_by_standard[f"entity:{directory}"] = [Finding(str(directory), "FAIL", error)]
elif manifest.get("manifest", {}).get("manifest_type") == "project":
findings_by_standard[f"entity:{directory}"] = audit_project(directory, directory.parent)
else:
findings_by_standard[f"entity:{directory}"] = audit_directory_entity(directory, directory.parent, compare_children=True)
print(render_markdown(root, findings_by_standard))
has_failures = any(
finding.level == "FAIL"
for findings in findings_by_standard.values()
for finding in findings
)
return 1 if has_failures else 0
if __name__ == "__main__":
raise SystemExit(main())
workspace_inventory.py
Read-only report of registration/filesystem drift. Compares Development.manifest.toml's registered roots and their declared children against what's physically on disk, and checks that each governed directory has exactly one local entity-manifest authority. Never rewrites files; returns nonzero when any root shows drift. Powers the Workspace Inventory page's repeatable commands.
#!/usr/bin/env python3
"""Report workspace registration and filesystem drift without rewriting files."""
from __future__ import annotations
import argparse
import json
import tomllib
from pathlib import Path
IGNORED = {".git", ".idea", ".vscode", "__pycache__", "node_modules"}
def load(path: Path) -> dict:
with path.open("rb") as handle:
return tomllib.load(handle)
def inspect_root(path: Path, manifest_path: Path) -> dict:
result = {"path": str(path), "manifest": str(manifest_path), "status": "pass", "findings": []}
if not path.is_dir():
result["status"] = "fail"; result["findings"].append("root missing"); return result
if not manifest_path.is_file():
result["status"] = "fail"; result["findings"].append("manifest missing"); return result
try:
manifest = load(manifest_path)
except Exception as exc:
result["status"] = "fail"; result["findings"].append(f"manifest parse failed: {exc}"); return result
registered = set(manifest.get("structure", {}).get("children", []))
physical = {item.name for item in path.iterdir() if item.is_dir() and item.name not in IGNORED}
missing = sorted(registered - physical, key=str.lower)
extra = sorted(physical - registered, key=str.lower)
if missing:
result["findings"].append("registered but missing: " + ", ".join(missing))
if extra:
result["findings"].append("physical but unregistered: " + ", ".join(extra))
authorities = []
for candidate in path.glob("*.manifest.toml"):
try:
data = load(candidate)
if data.get("manifest", {}).get("manifest_type") in {"directory", "project"}:
authorities.append(candidate.name)
except Exception:
pass
if len(authorities) != 1:
result["findings"].append("local entity authorities: " + (", ".join(authorities) or "none"))
if result["findings"]:
result["status"] = "drift"
result["registered_children"] = len(registered)
result["physical_children"] = len(physical)
return result
def markdown(results: list[dict]) -> str:
lines = ["# Workspace Inventory Report", "", "| Root | Status | Registered | Physical | Findings |", "| --- | --- | ---: | ---: | --- |"]
for item in results:
lines.append(
f"| `{item['path']}` | {item['status']} | {item.get('registered_children', 0)} | "
f"{item.get('physical_children', 0)} | {'; '.join(item['findings']) or 'None'} |"
)
lines.append("")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace-root", type=Path, default=Path("D:/"))
parser.add_argument("--format", choices=["markdown", "json"], default="markdown")
args = parser.parse_args()
workspace = args.workspace_root.resolve()
development = load(workspace / "Development.manifest.toml")
results = [
inspect_root(Path(root["path"]), Path(root["manifest"]))
for root in development.get("roots", [])
if root.get("kind") != "standards-registry"
]
print(json.dumps(results, indent=2) if args.format == "json" else markdown(results))
return 1 if any(item["status"] != "pass" for item in results) else 0
if __name__ == "__main__":
raise SystemExit(main())
governance_scaffold.py
Dry-run-first tool that scaffolds a new entity-named governed child (project, project-group, dataset, reference, container, or archive) and registers it with its parent's entity manifest. Refuses to overwrite existing targets. Requires --apply to actually create files; without it, prints exactly what it would create. This is the tool that produced ExampleProject inside the test fixtures, as referenced by the 2026-07-08 audit example.
#!/usr/bin/env python3
"""Scaffold and register an entity-named governed child.
Dry-run is the default. --apply creates the child and updates the parent's
entity manifest. Existing targets are never overwritten.
"""
from __future__ import annotations
import argparse
import re
import tomllib
from datetime import date
from pathlib import Path
import tomli_w
CLASSIFICATION = {
"project": "projects",
"project-group": "project_groups",
"dataset": "datasets",
"reference": "external_sources",
"container": "containers",
"archive": "archives",
}
PROJECT_KINDS = {"project", "project-group", "dataset"}
STANDARD_PATHS = {
name: f"D:\\.city_hall\\{name}\\README.md"
for name in ["WGS", "PPS", "CTS", "DRS", "WDS", "DDS", "SIS"]
}
def load(path: Path) -> dict:
with path.open("rb") as handle:
return tomllib.load(handle)
def write_toml(path: Path, value: dict) -> None:
path.write_bytes(tomli_w.dumps(value, multiline_strings=True).encode("utf-8"))
def entity_manifest(directory: Path) -> Path:
return directory / f"{directory.name}.manifest.toml"
def slug(value: str) -> str:
return re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
def project_manifest(target: Path, parent: Path, kind: str, standard: str, description: str) -> dict:
today = date.today().isoformat()
return {
"manifest": {
"schema": "APTlantis Entity Manifest", "schema_version": "2.4",
"manifest_type": "project", "canonical_name": entity_manifest(target).name,
"last_updated": today, "maintainer": "Herb",
},
"entity": {
"id": slug(target.name), "title": target.name, "kind": "dataset" if kind == "dataset" else "project",
"class": kind, "status": "experimental", "description": description, "tags": [],
},
"project": {
"type": kind, "portfolio_class": kind, "stage": "concept", "version": "not-versioned",
},
"governance": {
"primary_standard": standard, "primary_standard_path": STANDARD_PATHS[standard],
"additional_standards": ["WGS", "PPS"],
"additional_standard_paths": [STANDARD_PATHS["WGS"], STANDARD_PATHS["PPS"]],
"inherits_from": f"..\\{entity_manifest(parent).name}",
},
"lifecycle": {"state": "experimental", "created": today, "last_reviewed": today, "maintainer": "Herb"},
"paths": {"root": str(target)},
"documentation": {"project_readme": "Project-README.md", "readme": "README.md"},
"relationships": {"parent": str(parent), "child_projects": []},
"state": {
"stability": "experimental", "active_development": False,
"known_gaps": ["Implementation, build, test, artifact, and release evidence have not been established."],
},
"migration": {"archived_manifests": []},
"agent": {
"read_first": ["AGENTS.md", entity_manifest(target).name, "Project-README.md"],
"authoritative_docs": [entity_manifest(target).name, "Project-README.md", "AGENTS.md"],
"safe_to_modify": True, "notes": "Concept scaffold; verify evidence before changing lifecycle claims.",
},
"structure": {"required_files": ["AGENTS.md", entity_manifest(target).name, "Project-README.md"]},
"verification": {
"level": "scaffold-only", "evidence": "operator-supplied scaffold metadata", "reviewed": today,
"build_verified": False, "tests_verified": False, "artifact_verified": False, "release_verified": False,
},
}
def directory_manifest(target: Path, parent: Path, kind: str, standard: str, description: str) -> dict:
today = date.today().isoformat()
status = "archived" if kind == "archive" else "planned"
return {
"manifest": {
"schema": "APTlantis Entity Manifest", "schema_version": "2.4",
"manifest_type": "directory", "canonical_name": entity_manifest(target).name,
"last_updated": today, "maintainer": "Herb",
},
"entity": {
"id": slug(target.name), "title": target.name, "kind": "directory", "class": kind,
"status": status, "description": description, "tags": [],
},
"directory": {
"path": str(target), "role": description, "portfolio_class": "container",
"health": "unreviewed", "allows_project_groups": kind == "container",
},
"governance": {
"primary_standard": standard, "primary_standard_path": STANDARD_PATHS[standard],
"additional_standards": ["WGS"], "additional_standard_paths": [STANDARD_PATHS["WGS"]],
"inherits_from": f"..\\{entity_manifest(parent).name}", "requires_child_manifests": True,
"allowed_child_types": ["project", "project-group", "container"],
},
"lifecycle": {"state": status, "created": today, "last_reviewed": today, "maintainer": "Herb"},
"structure": {"required_files": ["AGENTS.md", entity_manifest(target).name], "children": [], "reserved_directories": []},
"classification": {"projects": [], "project_groups": [], "containers": [], "archives": []},
"relationships": {"parent": str(parent)},
"policy": {
"allow_project_creation": kind == "container", "allow_agent_scaffolding": kind == "container",
"requires_manual_review_for_moves": True, "exclude_from_active_reporting": kind == "archive",
},
"migration": {"archived_manifests": [], "known_gaps": ["Child topology and operating policy require review."]},
"agent": {
"read_first": ["AGENTS.md", entity_manifest(target).name],
"authoritative_docs": [entity_manifest(target).name, "AGENTS.md"],
"safe_to_modify": kind != "archive", "notes": "New governed directory scaffold.",
},
}
def update_parent(parent_manifest: dict, name: str, kind: str) -> None:
structure = parent_manifest.setdefault("structure", {})
children = structure.setdefault("children", [])
if name in children:
raise ValueError(f"parent already registers child: {name}")
children.append(name)
children.sort(key=str.lower)
classification = parent_manifest.setdefault("classification", {})
bucket = classification.setdefault(CLASSIFICATION[kind], [])
bucket.append(name)
bucket.sort(key=str.lower)
parent_manifest.setdefault("manifest", {})["last_updated"] = date.today().isoformat()
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--parent", type=Path, required=True)
parser.add_argument("--name", required=True)
parser.add_argument("--kind", choices=sorted(CLASSIFICATION), required=True)
parser.add_argument("--standard", choices=sorted(STANDARD_PATHS), default="WGS")
parser.add_argument("--description", required=True)
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
parent = args.parent.resolve()
parent_manifest_path = entity_manifest(parent)
if not parent_manifest_path.is_file():
raise SystemExit(f"Parent entity manifest is missing: {parent_manifest_path}")
if any(part in {".", ".."} for part in Path(args.name).parts) or Path(args.name).name != args.name:
raise SystemExit("--name must be one directory name")
target = parent / args.name
if target.exists():
raise SystemExit(f"Target already exists: {target}")
parent_manifest = load(parent_manifest_path)
update_parent(parent_manifest, args.name, args.kind)
manifest = (
project_manifest(target, parent, args.kind, args.standard, args.description)
if args.kind in PROJECT_KINDS
else directory_manifest(target, parent, args.kind, args.standard, args.description)
)
files = ["AGENTS.md", entity_manifest(target).name]
if args.kind in PROJECT_KINDS:
files.append("Project-README.md")
print(f"{'CREATE' if args.apply else 'WOULD CREATE'} {target}")
print("Files: " + ", ".join(files))
print(f"{'UPDATE' if args.apply else 'WOULD UPDATE'} {parent_manifest_path}")
if not args.apply:
return 0
target.mkdir(parents=False)
write_toml(entity_manifest(target), manifest)
standard_link = STANDARD_PATHS[args.standard].replace("\\", "/")
(target / "AGENTS.md").write_text(
f"# {args.name} Instructions\n\nInherit `{parent / 'AGENTS.md'}` and `D:\\AGENTS.md`.\n\n"
f"Read `{entity_manifest(target).name}` first. Canonical standard: [{args.standard}]({standard_link}).\n",
encoding="utf-8", newline="\n",
)
if args.kind in PROJECT_KINDS:
(target / "Project-README.md").write_text(
f"# {args.name}\n\n## Purpose\n\n{args.description}\n\n## Governance\n\n"
f"- [{entity_manifest(target).name}]({entity_manifest(target).name})\n"
f"- [AGENTS.md](AGENTS.md)\n\n## Current state\n\n"
"Concept scaffold only. Build, tests, artifacts, and release posture are unverified.\n",
encoding="utf-8", newline="\n",
)
write_toml(parent_manifest_path, parent_manifest)
return 0
if __name__ == "__main__":
raise SystemExit(main())
snapshot_root_governance.py
Backs up the three drive-root governance files (AGENTS.md, Development.manifest.toml, INDEX.md) into the version-controlled City Hall repo as a non-authoritative recovery copy. Without --apply it only compares SHA-256 hashes and reports current or refresh-needed; --apply copies the current files and rewrites SNAPSHOT.toml. See Workspace Root Snapshot for the snapshot this tool produces.
#!/usr/bin/env python3
"""Back up root governance records inside the version-controlled City Hall repo.
The snapshot is explicitly non-authoritative. Run without --apply to compare
hashes; --apply refreshes the controlled backup and its SHA-256 inventory.
"""
from __future__ import annotations
import argparse
import hashlib
import shutil
from datetime import datetime, timezone
from pathlib import Path
import tomli_w
FILES = ("AGENTS.md", "Development.manifest.toml", "INDEX.md")
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for block in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace-root", type=Path, default=Path("D:/"))
parser.add_argument("--snapshot-root", type=Path, default=Path("D:/.city_hall/WGS/workspace-root-snapshot"))
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
workspace = args.workspace_root.resolve()
snapshot = args.snapshot_root.resolve()
records = []
changed = False
for name in FILES:
source = workspace / name
target = snapshot / name
if not source.is_file():
raise SystemExit(f"Missing root governance file: {source}")
source_hash = sha256(source)
target_hash = sha256(target) if target.exists() else ""
state = "current" if source_hash == target_hash else "refresh-needed"
print(f"{name}: {state}")
changed |= state != "current"
records.append({"name": name, "source": str(source), "sha256": source_hash, "size_bytes": source.stat().st_size})
if args.apply and state != "current":
snapshot.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, target)
if args.apply:
metadata = {
"snapshot": {
"authoritative": False,
"purpose": "Version-controlled recovery copy of D drive root governance records.",
"source_root": str(workspace),
"refreshed_utc": datetime.now(timezone.utc).isoformat(),
"files": records,
}
}
snapshot.mkdir(parents=True, exist_ok=True)
(snapshot / "SNAPSHOT.toml").write_bytes(tomli_w.dumps(metadata).encode("utf-8"))
(snapshot / "README.md").write_text(
"# Workspace Root Governance Snapshot\n\n"
"This directory is a version-controlled recovery copy of `D:\\AGENTS.md`, "
"`D:\\Development.manifest.toml`, and `D:\\INDEX.md`. The files at the drive root "
"remain authoritative. Refresh this snapshot with `snapshot_root_governance.py --apply`; "
"do not edit snapshot copies directly.\n",
encoding="utf-8", newline="\n",
)
return 1 if changed and not args.apply else 0
if __name__ == "__main__":
raise SystemExit(main())
migrate_entity_manifests.py
The one-time migration tool that promoted the workspace from fixed-name (directory.manifest.toml / project.manifest.toml) to entity-named canonical manifests on 2026-07-08. It archives conflicting legacy manifests into a dated City Hall archive before promotion, reconciles project lifecycle/version fields from a hard-coded table of explicit local evidence (TRUTH), and updates AGENTS.md/Project-README.md references mechanically. Run without --apply for a dry run. See Entity-Named Live Migration for the resulting migration note.
#!/usr/bin/env python3
"""Promote fixed-name workspace manifests to entity-named canonical records.
The migration is deliberately conservative:
- conflicting entity-named and other legacy manifests are moved to a dated
City Hall archive before promotion;
- one canonical manifest remains in each governed directory;
- project lifecycle/version fields are reconciled from explicit local evidence;
- AGENTS.md and Project-README.md references are updated mechanically.
Run without --apply for a dry run.
"""
from __future__ import annotations
import argparse
import json
import os
import re
import shutil
import tomllib
from dataclasses import dataclass
from pathlib import Path
import tomli_w
PORTFOLIOS = ("WDS", "BASIC", "CTS", "DATA", "DRS")
PRUNE = {
".git", ".idea", ".vscode", "node_modules", "target", "bin", "obj",
"dist", "build", ".next", "__pycache__", "vendor",
}
FIXED_NAMES = ("directory.manifest.toml", "project.manifest.toml")
@dataclass(frozen=True)
class ProjectTruth:
version: str
status: str
stage: str
stability: str
active: bool
evidence: str
# TRUTH maps each governed project's workspace-relative path to hand-verified
# version, lifecycle, and evidence facts collected before the migration ran.
# See the source file for the full ~50-entry table (WDS/, BASIC/, CTS/, DATA/,
# and DRS/ project paths); omitted here for length.
TRUTH: dict[str, ProjectTruth] = {
"WDS/aptlantis-one": ProjectTruth("0.1.0", "active", "active", "experimental", True, "package.json"),
# ... additional entries for every governed project under WDS, BASIC, CTS, DATA, DRS
}
def load(path: Path) -> dict:
with path.open("rb") as handle:
return tomllib.load(handle)
def dump(path: Path, data: dict) -> None:
path.write_bytes(tomli_w.dumps(data, multiline_strings=True).encode("utf-8"))
def relative_key(workspace: Path, directory: Path) -> str:
return directory.relative_to(workspace).as_posix()
def governed_directories(workspace: Path) -> list[tuple[Path, Path]]:
found: list[tuple[Path, Path]] = []
for portfolio in PORTFOLIOS:
root = workspace / portfolio
for current, dirs, files in os.walk(root):
dirs[:] = [name for name in dirs if name not in PRUNE]
fixed = next((name for name in FIXED_NAMES if name in files), None)
if fixed:
found.append((Path(current), Path(current) / fixed))
return sorted(found, key=lambda item: (len(item[0].parts), str(item[0]).lower()))
def archive_path(archive_root: Path, workspace: Path, source: Path) -> Path:
return archive_root / source.relative_to(workspace)
def replace_doc_references(directory: Path, old_name: str, new_name: str, apply: bool) -> None:
for doc_name in ("AGENTS.md", "Project-README.md"):
path = directory / doc_name
if not path.exists():
continue
text = path.read_text(encoding="utf-8", errors="replace")
updated = text.replace(old_name, new_name)
if updated != text:
print(f"UPDATE {path}: {old_name} -> {new_name}")
if apply:
path.write_text(updated, encoding="utf-8", newline="\n")
def reconcile_manifest(
workspace: Path,
directory: Path,
manifest: dict,
canonical_name: str,
archived: list[Path],
) -> dict:
manifest.setdefault("manifest", {})["canonical_name"] = canonical_name
manifest["manifest"]["last_updated"] = "2026-07-08"
key = relative_key(workspace, directory)
entity = manifest.setdefault("entity", {})
entity["id"] = re.sub(r"[^a-z0-9]+", "-", directory.name.lower()).strip("-")
if canonical_name != f"{directory.name}.manifest.toml":
raise ValueError(f"unexpected canonical filename for {directory}")
structure = manifest.setdefault("structure", {})
required = structure.get("required_files", [])
structure["required_files"] = [
canonical_name if item in FIXED_NAMES or item == "DIRECTORY.manifest.toml" else item
for item in required
]
structure["required_child_project_files"] = [
"AGENTS.md", "[EntityName].manifest.toml", "Project-README.md"
] if "required_child_project_files" in structure else structure.get("required_child_project_files", [])
agent = manifest.setdefault("agent", {})
for field in ("read_first", "authoritative_docs"):
values = agent.get(field, [])
agent[field] = [
canonical_name if item in FIXED_NAMES or item == "DIRECTORY.manifest.toml" else item
for item in values
]
migration = manifest.setdefault("migration", {})
migration["archived_manifests"] = [str(path) for path in archived]
migration.pop("legacy_manifests", None)
if "project" in manifest:
truth = TRUTH.get(key)
if not truth:
raise ValueError(f"missing ProjectTruth entry for {key}")
entity["status"] = truth.status
manifest["project"]["stage"] = truth.stage
manifest["project"]["version"] = truth.version
lifecycle = manifest.setdefault("lifecycle", {})
lifecycle["state"] = truth.status
lifecycle["last_reviewed"] = "2026-07-08"
state = manifest.setdefault("state", {})
state["stability"] = truth.stability
state["active_development"] = truth.active
state["known_gaps"] = [
"Current build, test, artifact, and release posture were not executed during the governance migration."
]
manifest["verification"] = {
"level": "metadata-reconciled",
"evidence": truth.evidence,
"reviewed": "2026-07-08",
"build_verified": False,
"tests_verified": False,
"artifact_verified": False,
"release_verified": False,
}
else:
manifest.setdefault("lifecycle", {})["last_reviewed"] = "2026-07-08"
return manifest
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace-root", type=Path, default=Path("D:/"))
parser.add_argument(
"--archive-root",
type=Path,
default=Path("D:/.city_hall/WGS/migration-notes/Legacy-Live-Manifests-20260708"),
)
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
workspace = args.workspace_root.resolve()
archive_root = args.archive_root.resolve()
mode = "APPLY" if args.apply else "DRY-RUN"
print(f"Mode: {mode}")
operations = 0
for directory, fixed in governed_directories(workspace):
canonical_name = f"{directory.name}.manifest.toml"
canonical = directory / canonical_name
to_archive = [
path for path in directory.glob("*.manifest.toml")
if path.name not in {fixed.name, canonical_name}
]
if canonical.exists() and canonical != fixed:
to_archive.append(canonical)
to_archive = sorted(set(to_archive), key=lambda path: path.name.lower())
archived_records: list[Path] = []
for source in to_archive:
destination = archive_path(archive_root, workspace, source)
print(f"ARCHIVE {source} -> {destination}")
archived_records.append(destination)
operations += 1
if args.apply:
destination.parent.mkdir(parents=True, exist_ok=True)
if destination.exists():
raise FileExistsError(destination)
shutil.move(str(source), str(destination))
print(f"PROMOTE {fixed} -> {canonical}")
operations += 1
if args.apply:
if canonical.exists() and canonical != fixed:
raise FileExistsError(canonical)
shutil.move(str(fixed), str(canonical))
manifest = reconcile_manifest(
workspace,
directory,
load(canonical),
canonical_name,
archived_records,
)
dump(canonical, manifest)
replace_doc_references(directory, fixed.name, canonical_name, args.apply)
print(f"Operations: {operations}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
:::note Abridged listing
The TRUTH dictionary in the actual script has roughly 50 entries, one per governed project under WDS/, BASIC/, CTS/, DATA/, and DRS/, each recording a hand-verified version, lifecycle status, stage, stability, active-development flag, and evidence string. It is abridged above (with a comment marker) to keep this page a reasonable length — the full table is source-controlled at D:\.city_hall\WGS\tools\migrate_entity_manifests.py.
:::
normalize_entity_manifests.py
Repeatable normalizer (as opposed to migrate_entity_manifests.py's one-time promotion) that keeps already-entity-named manifests internally consistent: fixes canonical_name, corrects the recorded directory/project path, recomputes inherits_from based on actual filesystem parentage, and normalizes any leftover fixed-name references inside required_files or agent tables. Only touches manifests whose filename already matches their containing directory name.
#!/usr/bin/env python3
"""Normalize canonical entity-manifest filenames, paths, and inheritance.
This tool only rewrites manifests whose filename exactly matches the containing
directory name plus `.manifest.toml`. Run without --apply for a dry run.
"""
from __future__ import annotations
import argparse
import os
import re
import tomllib
from pathlib import Path
import tomli_w
PRUNE = {
".git", ".idea", ".vscode", "node_modules", "target", "bin", "obj",
"dist", "build", ".next", "__pycache__", "vendor", "$RECYCLE.BIN",
"System Volume Information", "migration-notes",
}
PORTFOLIOS = {"WDS", "BASIC", "CTS", "DATA", "DRS"}
def load(path: Path) -> dict:
with path.open("rb") as handle:
return tomllib.load(handle)
def dump(path: Path, value: dict) -> None:
path.write_bytes(tomli_w.dumps(value, multiline_strings=True).encode("utf-8"))
def normalize_string(value: str) -> str:
if re.match(r"^[A-Za-z]:\\", value):
while "\\\\" in value:
value = value.replace("\\\\", "\\")
return value
def normalize_values(value: object) -> object:
if isinstance(value, dict):
return {key: normalize_values(child) for key, child in value.items()}
if isinstance(value, list):
return [normalize_values(child) for child in value]
if isinstance(value, str):
return normalize_string(value)
return value
def entity_manifests(workspace: Path) -> list[Path]:
manifests: list[Path] = []
for root_name in PORTFOLIOS:
root = workspace / root_name
for current, dirs, files in os.walk(root):
dirs[:] = [
name for name in dirs
if name not in PRUNE and not name.endswith("_holding")
]
directory = Path(current)
expected = f"{directory.name}.manifest.toml"
if expected in files:
manifests.append(directory / expected)
return sorted(manifests, key=lambda path: str(path).lower())
def expected_parent_reference(workspace: Path, directory: Path) -> str:
if directory.parent == workspace:
return "D:\\Development.manifest.toml"
return f"..\\{directory.parent.name}.manifest.toml"
def normalize_manifest(workspace: Path, path: Path) -> tuple[dict, list[str]]:
original = load(path)
manifest = normalize_values(original)
changes: list[str] = []
canonical = path.name
if manifest.setdefault("manifest", {}).get("canonical_name") != canonical:
manifest["manifest"]["canonical_name"] = canonical
changes.append("canonical_name")
manifest["manifest"]["last_updated"] = "2026-07-08"
directory = path.parent
domain = manifest.get("directory") or manifest.get("paths")
path_key = "path" if "directory" in manifest else "root"
expected_path = str(directory)
if domain is not None and domain.get(path_key) != expected_path:
domain[path_key] = expected_path
changes.append(path_key)
governance = manifest.setdefault("governance", {})
expected_inheritance = expected_parent_reference(workspace, directory)
if governance.get("inherits_from") != expected_inheritance:
governance["inherits_from"] = expected_inheritance
changes.append("inherits_from")
structure = manifest.setdefault("structure", {})
required = structure.get("required_files", [])
normalized_required = [
canonical if item in {"directory.manifest.toml", "project.manifest.toml", "DIRECTORY.manifest.toml"} else item
for item in required
]
if normalized_required != required:
structure["required_files"] = normalized_required
changes.append("required_files")
if "required_child_project_files" in structure:
desired = ["AGENTS.md", "[EntityName].manifest.toml", "Project-README.md"]
if structure["required_child_project_files"] != desired:
structure["required_child_project_files"] = desired
changes.append("required_child_project_files")
agent = manifest.setdefault("agent", {})
for field in ("read_first", "authoritative_docs"):
values = agent.get(field, [])
updated = [
canonical if item in {"directory.manifest.toml", "project.manifest.toml", "DIRECTORY.manifest.toml"} else item
for item in values
]
if updated != values:
agent[field] = updated
changes.append(f"agent.{field}")
if manifest != original and not changes:
changes.append("path-separator normalization")
return manifest, changes
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace-root", type=Path, default=Path("D:/"))
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
workspace = args.workspace_root.resolve()
changed = 0
for path in entity_manifests(workspace):
manifest, changes = normalize_manifest(workspace, path)
if changes:
changed += 1
print(f"{'UPDATE' if args.apply else 'WOULD UPDATE'} {path}: {', '.join(changes)}")
if args.apply:
dump(path, manifest)
print(f"Manifests changed: {changed}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
reconcile_project_readmes.py
Replaces boilerplate rollout-placeholder sentences in Project-README.md files with a manifest-backed verification statement (version, lifecycle, stage, evidence, and an explicit "not a release-readiness claim" disclaimer), generated per-project from that project's own entity manifest.
#!/usr/bin/env python3
"""Replace rollout-placeholder state text with manifest-backed verification text."""
from __future__ import annotations
import argparse
import os
import tomllib
from pathlib import Path
PORTFOLIOS = ("WDS", "BASIC", "CTS", "DATA", "DRS")
PRUNE = {".git", ".idea", ".vscode", "node_modules", "target", "bin", "obj", "dist", "build", ".next", "__pycache__", "vendor"}
PLACEHOLDERS = (
"The project predates the July 2026 fixed-name governance rollout. Its physical source and existing documents are present, but build, version, lifecycle, and release claims have not yet been fully reconciled into the canonical manifest.",
"The project predates the July 2026 governance rollout. Source material is present, but its current version, build state, and release posture still require project-specific reconciliation.",
"The current version, lifecycle, environment, and output integrity require project-specific reconciliation.",
)
def project_manifests(workspace: Path) -> list[Path]:
result: list[Path] = []
for portfolio in PORTFOLIOS:
for current, dirs, files in os.walk(workspace / portfolio):
dirs[:] = [name for name in dirs if name not in PRUNE and not name.endswith("_holding")]
directory = Path(current)
expected = f"{directory.name}.manifest.toml"
if expected in files:
path = directory / expected
try:
with path.open("rb") as handle:
manifest = tomllib.load(handle)
if "project" in manifest:
result.append(path)
except Exception:
pass
return sorted(result, key=lambda path: str(path).lower())
def statement(manifest: dict) -> str:
project = manifest.get("project", {})
entity = manifest.get("entity", {})
verification = manifest.get("verification", {})
version = project.get("version", "not-versioned")
status = entity.get("status", "unreviewed")
stage = project.get("stage", "unreviewed")
evidence = verification.get("evidence", "local source and documentation")
reviewed = verification.get("reviewed", "2026-07-08")
return (
f"Governance metadata was reconciled on {reviewed}: version `{version}`, "
f"lifecycle `{status}`, stage `{stage}`. Evidence reviewed: {evidence}. "
"The build, tests, shipping artifact, and release posture were not executed "
"during this metadata pass, so this classification is not a release-readiness claim."
)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace-root", type=Path, default=Path("D:/"))
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
changed = 0
for manifest_path in project_manifests(args.workspace_root.resolve()):
readme = manifest_path.parent / "Project-README.md"
if not readme.exists():
continue
with manifest_path.open("rb") as handle:
manifest = tomllib.load(handle)
text = readme.read_text(encoding="utf-8", errors="replace")
updated = text
for placeholder in PLACEHOLDERS:
updated = updated.replace(placeholder, statement(manifest))
if updated != text:
changed += 1
print(f"{'UPDATE' if args.apply else 'WOULD UPDATE'} {readme}")
if args.apply:
readme.write_text(updated, encoding="utf-8", newline="\n")
print(f"Project READMEs changed: {changed}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Test fixtures
tests/fixtures/TEST/ is a fixture-only portfolio used to exercise governance_scaffold.py and city_hall_audit.py without touching the live workspace. It is not a real project — it is the harness for the 2026-07-08 audit example's scaffold-acceptance step.
TEST/AGENTS.md
# Scaffold Test Portfolio Instructions
Fixture-only parent for validating entity-aware scaffolding and auditing.
TEST/TEST.manifest.toml — the fixture parent directory manifest, classifying ExampleProject as a registered child project:
[manifest]
schema = "APTlantis Entity Manifest"
schema_version = "2.4"
manifest_type = "directory"
canonical_name = "TEST.manifest.toml"
last_updated = "2026-07-08"
maintainer = "Herb"
[entity]
id = "test"
title = "Scaffold Test Portfolio"
kind = "directory"
class = "container"
status = "active"
description = "Fixture-only parent for scaffold validation."
tags = ["fixture"]
[directory]
path = "D:\\.city_hall\\WGS\\tests\\fixtures\\TEST"
role = "Exercise scaffold registration and entity auditing."
portfolio_class = "container"
health = "test-fixture"
allows_project_groups = true
[governance]
primary_standard = "WGS"
primary_standard_path = "D:\\.city_hall\\WGS\\README.md"
additional_standards = []
additional_standard_paths = []
inherits_from = "D:\\.city_hall\\WGS\\WGS.manifest.toml"
requires_child_manifests = true
allowed_child_types = ["project"]
[lifecycle]
state = "active"
created = "2026-07-08"
last_reviewed = "2026-07-08"
maintainer = "Herb"
[structure]
required_files = ["AGENTS.md", "TEST.manifest.toml"]
children = ["ExampleProject"]
reserved_directories = []
[classification]
projects = ["ExampleProject"]
project_groups = []
containers = []
archives = []
[relationships]
parent = "D:\\.city_hall\\WGS\\tests\\fixtures"
[policy]
allow_project_creation = true
allow_agent_scaffolding = true
requires_manual_review_for_moves = true
[agent]
read_first = ["AGENTS.md", "TEST.manifest.toml"]
authoritative_docs = ["TEST.manifest.toml", "AGENTS.md"]
safe_to_modify = true
notes = "Fixture only."
TEST/ExampleProject/ — the scaffold's generated output: AGENTS.md, ExampleProject.manifest.toml, and Project-README.md, produced by governance_scaffold.py --apply and shown here as the concrete result of that tool.
# ExampleProject Instructions
Inherit `D:\.city_hall\WGS\tests\fixtures\TEST\AGENTS.md` and `D:\AGENTS.md`.
Read `ExampleProject.manifest.toml` first. Canonical standard: [CTS](D:/.city_hall/CTS/README.md).
[manifest]
schema = "APTlantis Entity Manifest"
schema_version = "2.4"
manifest_type = "project"
canonical_name = "ExampleProject.manifest.toml"
last_updated = "2026-07-08"
maintainer = "Herb"
[entity]
id = "exampleproject"
title = "ExampleProject"
kind = "project"
class = "project"
status = "experimental"
description = "Fixture project used to prove scaffold and audit compatibility."
tags = []
[project]
type = "project"
portfolio_class = "project"
stage = "concept"
version = "not-versioned"
[governance]
primary_standard = "CTS"
primary_standard_path = "D:\\.city_hall\\CTS\\README.md"
additional_standards = ["WGS", "PPS"]
additional_standard_paths = ["D:\\.city_hall\\WGS\\README.md", "D:\\.city_hall\\PPS\\README.md"]
inherits_from = "..\\TEST.manifest.toml"
[lifecycle]
state = "experimental"
created = "2026-07-08"
last_reviewed = "2026-07-08"
maintainer = "Herb"
[paths]
root = "D:\\.city_hall\\WGS\\tests\\fixtures\\TEST\\ExampleProject"
[documentation]
project_readme = "Project-README.md"
readme = "README.md"
[relationships]
parent = "D:\\.city_hall\\WGS\\tests\\fixtures\\TEST"
child_projects = []
[state]
stability = "experimental"
active_development = false
known_gaps = ["Implementation, build, test, artifact, and release evidence have not been established."]
[migration]
archived_manifests = []
[agent]
read_first = ["AGENTS.md", "ExampleProject.manifest.toml", "Project-README.md"]
authoritative_docs = ["ExampleProject.manifest.toml", "Project-README.md", "AGENTS.md"]
safe_to_modify = true
notes = "Concept scaffold; verify evidence before changing lifecycle claims."
[structure]
required_files = ["AGENTS.md", "ExampleProject.manifest.toml", "Project-README.md"]
[verification]
level = "scaffold-only"
evidence = "operator-supplied scaffold metadata"
reviewed = "2026-07-08"
build_verified = false
tests_verified = false
artifact_verified = false
release_verified = false
# ExampleProject
## Purpose
Fixture project used to prove scaffold and audit compatibility.
## Governance
- [ExampleProject.manifest.toml](ExampleProject.manifest.toml)
- [AGENTS.md](AGENTS.md)
## Current state
Concept scaffold only. Build, tests, artifacts, and release posture are unverified.