agentic-dev 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -54
- package/bin/agentic-dev.mjs +162 -11
- package/lib/github.mjs +246 -0
- package/lib/orchestration-assets.mjs +249 -0
- package/lib/scaffold.mjs +89 -0
- package/package.json +8 -19
- package/.dockerignore +0 -8
- package/.env.example +0 -50
- package/.gitignore +0 -16
- package/AGENTS.md +0 -86
- package/SDD_SKILL.md +0 -589
- package/compose.yml +0 -206
- package/infra/compose/.env.dev.example +0 -28
- package/infra/compose/.env.prod.example +0 -29
- package/infra/compose/README.md +0 -35
- package/infra/compose/dev.yml +0 -125
- package/infra/compose/prod.yml +0 -126
- package/infra/terraform/README.md +0 -34
- package/infra/terraform/aws/data/.terraform.lock.hcl +0 -25
- package/infra/terraform/aws/data/README.md +0 -18
- package/infra/terraform/aws/data/main.tf +0 -147
- package/infra/terraform/aws/data/outputs.tf +0 -14
- package/infra/terraform/aws/data/variables.tf +0 -57
- package/infra/terraform/aws/data/versions.tf +0 -10
- package/infra/terraform/aws/domain/.terraform.lock.hcl +0 -25
- package/infra/terraform/aws/domain/README.md +0 -20
- package/infra/terraform/aws/domain/env/dev.tfvars.example +0 -6
- package/infra/terraform/aws/domain/env/prod.tfvars.example +0 -7
- package/infra/terraform/aws/domain/main.tf +0 -149
- package/infra/terraform/aws/domain/outputs.tf +0 -29
- package/infra/terraform/aws/domain/variables.tf +0 -58
- package/infra/terraform/aws/domain/versions.tf +0 -10
- package/infra/terraform/openstack/README.md +0 -38
- package/infra/terraform/openstack/dev/.terraform.lock.hcl +0 -24
- package/infra/terraform/openstack/dev/README.md +0 -18
- package/infra/terraform/openstack/dev/main.tf +0 -49
- package/infra/terraform/openstack/dev/providers.tf +0 -15
- package/infra/terraform/openstack/dev/terraform.tfvars.example +0 -54
- package/infra/terraform/openstack/dev/variables.tf +0 -210
- package/infra/terraform/openstack/dev/versions.tf +0 -10
- package/infra/terraform/openstack/modules/environment_host/main.tf +0 -143
- package/infra/terraform/openstack/modules/environment_host/outputs.tf +0 -25
- package/infra/terraform/openstack/modules/environment_host/templates/docker-host-user-data.sh.tftpl +0 -40
- package/infra/terraform/openstack/modules/environment_host/variables.tf +0 -145
- package/infra/terraform/openstack/modules/environment_host/versions.tf +0 -7
- package/infra/terraform/openstack/prod/.terraform.lock.hcl +0 -24
- package/infra/terraform/openstack/prod/README.md +0 -18
- package/infra/terraform/openstack/prod/main.tf +0 -49
- package/infra/terraform/openstack/prod/providers.tf +0 -15
- package/infra/terraform/openstack/prod/terraform.tfvars.example +0 -55
- package/infra/terraform/openstack/prod/variables.tf +0 -210
- package/infra/terraform/openstack/prod/versions.tf +0 -10
- package/infra/terraform/openstack/server/.terraform.lock.hcl +0 -45
- package/infra/terraform/openstack/server/README.md +0 -47
- package/infra/terraform/openstack/server/main.tf +0 -161
- package/infra/terraform/openstack/server/outputs.tf +0 -30
- package/infra/terraform/openstack/server/providers.tf +0 -30
- package/infra/terraform/openstack/server/templates/server-user-data.sh.tftpl +0 -50
- package/infra/terraform/openstack/server/variables.tf +0 -233
- package/infra/terraform/openstack/server/zz_aspace.auto.tfvars.example.json +0 -29
- package/pnpm-workspace.yaml +0 -2
- package/scripts/dev/audit_sdd_build_ast.py +0 -277
- package/sdd/01_planning/01_feature/INDEX.md +0 -16
- package/sdd/01_planning/01_feature/README.md +0 -76
- package/sdd/01_planning/01_feature/alerts_feature_spec.md +0 -55
- package/sdd/01_planning/01_feature/auth_feature_spec.md +0 -57
- package/sdd/01_planning/01_feature/catalog_feature_spec.md +0 -61
- package/sdd/01_planning/01_feature/fulfillment_feature_spec.md +0 -58
- package/sdd/01_planning/01_feature/health_feature_spec.md +0 -52
- package/sdd/01_planning/01_feature/inventory_feature_spec.md +0 -60
- package/sdd/01_planning/01_feature/order_feature_spec.md +0 -63
- package/sdd/01_planning/01_feature/shipping_feature_spec.md +0 -55
- package/sdd/01_planning/01_feature/support_feature_spec.md +0 -53
- package/sdd/01_planning/01_feature/user_feature_spec.md +0 -54
- package/sdd/01_planning/02_screen/INDEX.md +0 -13
- package/sdd/01_planning/02_screen/README.md +0 -41
- package/sdd/01_planning/02_screen/admin_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/assets/README.md +0 -16
- package/sdd/01_planning/02_screen/assets/example/README.md +0 -13
- package/sdd/01_planning/02_screen/landing_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/mobile_screen_spec.pdf +0 -0
- package/sdd/01_planning/02_screen/web_screen_spec.pdf +0 -0
- package/sdd/01_planning/03_architecture/INDEX.md +0 -9
- package/sdd/01_planning/03_architecture/README.md +0 -25
- package/sdd/01_planning/03_architecture/architecture_document_structure.md +0 -77
- package/sdd/01_planning/03_architecture/backend/README.md +0 -10
- package/sdd/01_planning/03_architecture/frontend/README.md +0 -12
- package/sdd/01_planning/03_architecture/infra/README.md +0 -10
- package/sdd/01_planning/03_architecture/tech-research/README.md +0 -4
- package/sdd/01_planning/03_architecture/templates_system_architecture.md +0 -84
- package/sdd/01_planning/04_data/INDEX.md +0 -4
- package/sdd/01_planning/04_data/README.md +0 -10
- package/sdd/01_planning/04_data/templates_data_modeling.md +0 -119
- package/sdd/01_planning/05_api/README.md +0 -12
- package/sdd/01_planning/05_api/templates_api_contract.md +0 -90
- package/sdd/01_planning/06_iac/README.md +0 -11
- package/sdd/01_planning/06_iac/templates_runtime_and_cicd_baseline.md +0 -46
- package/sdd/01_planning/07_integration/README.md +0 -11
- package/sdd/01_planning/07_integration/templates_frontend_api_integration.md +0 -46
- package/sdd/01_planning/08_nonfunctional/README.md +0 -7
- package/sdd/01_planning/09_security/README.md +0 -7
- package/sdd/01_planning/10_test/README.md +0 -12
- package/sdd/01_planning/10_test/templates_test_strategy.md +0 -60
- package/sdd/01_planning/INDEX.md +0 -19
- package/sdd/01_planning/README.md +0 -17
- package/sdd/02_plan/01_feature/README.md +0 -34
- package/sdd/02_plan/01_feature/_feature_todo_template.md +0 -29
- package/sdd/02_plan/02_screen/INDEX.md +0 -19
- package/sdd/02_plan/02_screen/README.md +0 -39
- package/sdd/02_plan/02_screen/_screen_todo_template.md +0 -60
- package/sdd/02_plan/03_architecture/README.md +0 -23
- package/sdd/02_plan/03_architecture/architecture_document_governance.md +0 -40
- package/sdd/02_plan/03_architecture/build_ast_runtime_tree_governance.md +0 -53
- package/sdd/02_plan/03_architecture/repository_governance.md +0 -39
- package/sdd/02_plan/03_architecture/runtime_and_structure_governance.md +0 -38
- package/sdd/02_plan/03_architecture/templates-hexagonal-template-architecture.md +0 -9
- package/sdd/02_plan/03_architecture/toolchain_governance.md +0 -98
- package/sdd/02_plan/04_data/README.md +0 -5
- package/sdd/02_plan/05_api/README.md +0 -5
- package/sdd/02_plan/06_iac/README.md +0 -11
- package/sdd/02_plan/06_iac/dev_runtime_delivery.md +0 -36
- package/sdd/02_plan/06_iac/template_runtime_delivery.md +0 -50
- package/sdd/02_plan/07_integration/README.md +0 -5
- package/sdd/02_plan/07_integration/frontend_live_integration.md +0 -31
- package/sdd/02_plan/08_nonfunctional/README.md +0 -5
- package/sdd/02_plan/08_nonfunctional/repository_hygiene.md +0 -26
- package/sdd/02_plan/09_security/README.md +0 -5
- package/sdd/02_plan/10_test/README.md +0 -11
- package/sdd/02_plan/10_test/regression_verification.md +0 -39
- package/sdd/02_plan/10_test/templates/README.md +0 -8
- package/sdd/02_plan/10_test/templates/ui_parity_web_contract.template.yaml +0 -23
- package/sdd/02_plan/10_test/verification_strategy.md +0 -43
- package/sdd/02_plan/99_generated/from_planning/ui_parity/.gitkeep +0 -1
- package/sdd/02_plan/README.md +0 -40
- package/sdd/03_build/01_feature/README.md +0 -20
- package/sdd/03_build/01_feature/domain/README.md +0 -3
- package/sdd/03_build/01_feature/domain/account_and_access.md +0 -20
- package/sdd/03_build/01_feature/domain/catalog_and_inventory.md +0 -20
- package/sdd/03_build/01_feature/domain/ordering_and_fulfillment.md +0 -21
- package/sdd/03_build/01_feature/domain/support_and_observability.md +0 -21
- package/sdd/03_build/01_feature/domain_surfaces.md +0 -28
- package/sdd/03_build/01_feature/service/README.md +0 -3
- package/sdd/03_build/01_feature/service/admin_surface.md +0 -15
- package/sdd/03_build/01_feature/service/landing_surface.md +0 -13
- package/sdd/03_build/01_feature/service/mobile_surface.md +0 -14
- package/sdd/03_build/01_feature/service/web_surface.md +0 -14
- package/sdd/03_build/02_screen/README.md +0 -25
- package/sdd/03_build/02_screen/_screen_build_template.md +0 -26
- package/sdd/03_build/02_screen/admin/README.md +0 -5
- package/sdd/03_build/02_screen/landing/README.md +0 -5
- package/sdd/03_build/02_screen/mobile/README.md +0 -5
- package/sdd/03_build/02_screen/web/README.md +0 -5
- package/sdd/03_build/03_architecture/README.md +0 -10
- package/sdd/03_build/03_architecture/architecture_document_governance.md +0 -30
- package/sdd/03_build/03_architecture/build_ast_runtime_tree_governance.md +0 -24
- package/sdd/03_build/03_architecture/repository_governance.md +0 -18
- package/sdd/03_build/03_architecture/toolchain_governance.md +0 -36
- package/sdd/03_build/06_iac/README.md +0 -3
- package/sdd/03_build/06_iac/dev_runtime_delivery.md +0 -10
- package/sdd/03_build/06_iac/template_runtime_delivery.md +0 -49
- package/sdd/03_build/07_integration/README.md +0 -3
- package/sdd/03_build/07_integration/frontend_live_integration.md +0 -11
- package/sdd/03_build/08_nonfunctional/README.md +0 -3
- package/sdd/03_build/08_nonfunctional/repository_hygiene.md +0 -10
- package/sdd/03_build/10_test/README.md +0 -9
- package/sdd/03_build/10_test/regression_verification.md +0 -16
- package/sdd/03_build/10_test/verification_harness.md +0 -11
- package/sdd/03_build/README.md +0 -35
- package/sdd/03_verify/01_feature/README.md +0 -5
- package/sdd/03_verify/01_feature/domain_verification.md +0 -14
- package/sdd/03_verify/01_feature/service_verification.md +0 -22
- package/sdd/03_verify/02_screen/README.md +0 -6
- package/sdd/03_verify/02_screen/_screen_verify_template.md +0 -20
- package/sdd/03_verify/02_screen/admin/README.md +0 -4
- package/sdd/03_verify/02_screen/landing/README.md +0 -4
- package/sdd/03_verify/02_screen/mobile/README.md +0 -4
- package/sdd/03_verify/02_screen/web/README.md +0 -4
- package/sdd/03_verify/03_architecture/README.md +0 -10
- package/sdd/03_verify/03_architecture/architecture_document_governance.md +0 -15
- package/sdd/03_verify/03_architecture/build_ast_runtime_tree_governance.md +0 -28
- package/sdd/03_verify/03_architecture/repository_governance.md +0 -16
- package/sdd/03_verify/03_architecture/toolchain_governance.md +0 -58
- package/sdd/03_verify/06_iac/README.md +0 -3
- package/sdd/03_verify/06_iac/dev_runtime_delivery.md +0 -10
- package/sdd/03_verify/06_iac/template_runtime_delivery.md +0 -42
- package/sdd/03_verify/07_integration/README.md +0 -3
- package/sdd/03_verify/07_integration/frontend_live_integration.md +0 -16
- package/sdd/03_verify/08_nonfunctional/README.md +0 -3
- package/sdd/03_verify/08_nonfunctional/repository_hygiene.md +0 -14
- package/sdd/03_verify/10_test/README.md +0 -9
- package/sdd/03_verify/10_test/regression_verification.md +0 -16
- package/sdd/03_verify/10_test/ui_parity/README.md +0 -4
- package/sdd/03_verify/10_test/ui_parity/loop_runs/.gitkeep +0 -0
- package/sdd/03_verify/10_test/ui_parity/reference/.gitkeep +0 -0
- package/sdd/03_verify/10_test/ui_parity/staged_runs/.gitkeep +0 -0
- package/sdd/03_verify/10_test/verification_harness.md +0 -17
- package/sdd/03_verify/README.md +0 -22
- package/sdd/05_operate/01_runbooks/.gitkeep +0 -1
- package/sdd/05_operate/01_runbooks/README.md +0 -4
- package/sdd/05_operate/02_delivery_status/README.md +0 -4
- package/sdd/05_operate/02_delivery_status/service_status.md +0 -16
- package/sdd/05_operate/README.md +0 -12
- package/sdd/99_toolchain/01_automation/.gitkeep +0 -1
- package/sdd/99_toolchain/01_automation/README.md +0 -76
- package/sdd/99_toolchain/01_automation/agentic-dev/analyze_proof_results.py +0 -132
- package/sdd/99_toolchain/01_automation/agentic-dev/analyze_route_gap.py +0 -85
- package/sdd/99_toolchain/01_automation/agentic-dev/assets/repo-contract.template.json +0 -75
- package/sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh +0 -84
- package/sdd/99_toolchain/01_automation/agentic-dev/init_frontend_parity.sh +0 -33
- package/sdd/99_toolchain/01_automation/agentic-dev/init_repo_contract.sh +0 -51
- package/sdd/99_toolchain/01_automation/agentic-dev/repo-contract.json +0 -76
- package/sdd/99_toolchain/01_automation/agentic-dev/resolve_frontend_target.py +0 -52
- package/sdd/99_toolchain/01_automation/agentic-dev/resolve_repo_contract.py +0 -56
- package/sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh +0 -100
- package/sdd/99_toolchain/01_automation/agentic-dev/run_repo_phase.sh +0 -140
- package/sdd/99_toolchain/01_automation/agentic-dev/validate_json_schema.py +0 -39
- package/sdd/99_toolchain/01_automation/agentic-parity-harness-design.md +0 -291
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/queue.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/admin_screen_capture/support.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/home.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/landing_screen_capture/workspace.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/fulfillment.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/mobile_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/dashboard.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/login.png +0 -0
- package/sdd/99_toolchain/01_automation/assets/web_screen_capture/orders.png +0 -0
- package/sdd/99_toolchain/01_automation/build_asset_recipes.py +0 -10
- package/sdd/99_toolchain/01_automation/build_screen_spec_pdf.py +0 -427
- package/sdd/99_toolchain/01_automation/capture_screen_assets.mjs +0 -148
- package/sdd/99_toolchain/01_automation/harness-layout.md +0 -34
- package/sdd/99_toolchain/01_automation/parity-execution-tooling-design.md +0 -319
- package/sdd/99_toolchain/01_automation/playwright_exactness_manifest.py +0 -21
- package/sdd/99_toolchain/01_automation/run_playwright_exactness.py +0 -87
- package/sdd/99_toolchain/01_automation/screen_spec_manifest.py +0 -321
- package/sdd/99_toolchain/01_automation/spec_asset_builder.py +0 -274
- package/sdd/99_toolchain/01_automation/ui-contract-projection.md +0 -79
- package/sdd/99_toolchain/01_automation/ui-parity/README.md +0 -60
- package/sdd/99_toolchain/01_automation/ui-parity/cli/extract-reference-pages.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/cli/materialize-reference-assets.mjs +0 -58
- package/sdd/99_toolchain/01_automation/ui-parity/cli/normalize-reference-assets.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/cli/route-gap-report.mjs +0 -187
- package/sdd/99_toolchain/01_automation/ui-parity/cli/run-proof.mjs +0 -50
- package/sdd/99_toolchain/01_automation/ui-parity/cli/scaffold-contract.mjs +0 -62
- package/sdd/99_toolchain/01_automation/ui-parity/cli/upload-parity1.mjs +0 -2
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/collector-metadata.schema.json +0 -33
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/proof-result.schema.json +0 -76
- package/sdd/99_toolchain/01_automation/ui-parity/contracts/route-gap-report.schema.json +0 -95
- package/sdd/99_toolchain/01_automation/ui-parity/core/capture-runner.mjs +0 -55
- package/sdd/99_toolchain/01_automation/ui-parity/core/load-adapter.mjs +0 -25
- package/sdd/99_toolchain/01_automation/ui-parity/core/load-contract.mjs +0 -81
- package/sdd/99_toolchain/01_automation/ui-parity/core/paths.mjs +0 -23
- package/sdd/99_toolchain/01_automation/ui-parity/core/proof-runner.mjs +0 -255
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-artifact-layout.md +0 -23
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-proof-interface.md +0 -60
- package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-route-gap-interface.md +0 -82
- package/sdd/99_toolchain/01_automation/ui-parity/runtime/playwright-runtime.mjs +0 -16
- package/sdd/99_toolchain/01_automation/ui-parity/runtime/static-runtime.mjs +0 -6
- package/sdd/99_toolchain/02_policies/.gitkeep +0 -1
- package/sdd/99_toolchain/02_policies/build-ast-governance-policy.md +0 -22
- package/sdd/99_toolchain/02_policies/compose-runtime-baseline-policy.md +0 -24
- package/sdd/99_toolchain/02_policies/convention-storage-policy.md +0 -26
- package/sdd/99_toolchain/02_policies/main-push-before-dev-deploy-policy.md +0 -27
- package/sdd/99_toolchain/02_policies/regression-verification-policy.md +0 -22
- package/sdd/99_toolchain/03_templates/.gitkeep +0 -1
- package/sdd/99_toolchain/03_templates/asset_recipe_manifest.example.py +0 -38
- package/sdd/99_toolchain/03_templates/generated_assets/README.md +0 -11
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-lockup.svg +0 -3
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-mark.svg +0 -3
- package/sdd/99_toolchain/03_templates/generated_assets/example-brand-wordmark.svg +0 -3
- package/sdd/99_toolchain/03_templates/playwright_exactness_manifest.example.py +0 -21
- package/sdd/99_toolchain/README.md +0 -23
- package/sdd/README.md +0 -21
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import { ensureDirectory } from "./paths.mjs";
|
|
4
|
-
|
|
5
|
-
export function sanitizeFileName(raw) {
|
|
6
|
-
return String(raw || "screen")
|
|
7
|
-
.replace(/[^a-zA-Z0-9._-]/g, "_")
|
|
8
|
-
.replace(/_+/g, "_")
|
|
9
|
-
.replace(/^_+|_+$/g, "")
|
|
10
|
-
.slice(0, 120);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function captureScreen({
|
|
14
|
-
browser,
|
|
15
|
-
screen,
|
|
16
|
-
adapter,
|
|
17
|
-
outputPath,
|
|
18
|
-
baseUrl,
|
|
19
|
-
viewport,
|
|
20
|
-
}) {
|
|
21
|
-
ensureDirectory(path.dirname(outputPath));
|
|
22
|
-
const page = await browser.newPage({ viewport });
|
|
23
|
-
try {
|
|
24
|
-
if (typeof adapter.preparePage === "function") {
|
|
25
|
-
await adapter.preparePage(page, { route: screen.route, screen, baseUrl, viewport });
|
|
26
|
-
}
|
|
27
|
-
if (typeof adapter.beforeNavigate === "function") {
|
|
28
|
-
await adapter.beforeNavigate(page, { route: screen.route, screen, baseUrl, viewport });
|
|
29
|
-
}
|
|
30
|
-
const targetUrl = new URL(screen.route, baseUrl).toString();
|
|
31
|
-
await page.goto(targetUrl, { waitUntil: "networkidle" });
|
|
32
|
-
if (screen.readySelector) {
|
|
33
|
-
await page.waitForSelector(screen.readySelector, {
|
|
34
|
-
timeout: Number.isFinite(Number(screen.readyTimeoutMs)) ? Number(screen.readyTimeoutMs) : 10000,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
if (typeof adapter.waitForReady === "function") {
|
|
38
|
-
await adapter.waitForReady(page, { route: screen.route, screen, baseUrl, viewport });
|
|
39
|
-
}
|
|
40
|
-
if (typeof adapter.afterPageReady === "function") {
|
|
41
|
-
await adapter.afterPageReady(page, { route: screen.route, screen, baseUrl, viewport });
|
|
42
|
-
}
|
|
43
|
-
await page.screenshot({
|
|
44
|
-
path: outputPath,
|
|
45
|
-
fullPage: Boolean(screen.captureFullPage ?? false),
|
|
46
|
-
});
|
|
47
|
-
return {
|
|
48
|
-
targetUrl,
|
|
49
|
-
status: "captured",
|
|
50
|
-
detail: "capture_ok",
|
|
51
|
-
};
|
|
52
|
-
} finally {
|
|
53
|
-
await page.close();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { pathToFileURL } from "node:url";
|
|
3
|
-
|
|
4
|
-
export async function loadAdapter(adapterPath) {
|
|
5
|
-
const resolvedPath = path.resolve(adapterPath);
|
|
6
|
-
const moduleUrl = pathToFileURL(resolvedPath).href;
|
|
7
|
-
const loaded = await import(moduleUrl);
|
|
8
|
-
const adapter = loaded.default ?? loaded.adapter ?? loaded;
|
|
9
|
-
if (!adapter || typeof adapter !== "object") {
|
|
10
|
-
throw new Error(`Invalid adapter module: ${resolvedPath}`);
|
|
11
|
-
}
|
|
12
|
-
if (typeof adapter.service !== "string" || !adapter.service.trim()) {
|
|
13
|
-
throw new Error(`Adapter is missing required string field: service (${resolvedPath})`);
|
|
14
|
-
}
|
|
15
|
-
if (typeof adapter.targetBaseUrl !== "string" || !adapter.targetBaseUrl.trim()) {
|
|
16
|
-
throw new Error(`Adapter is missing required string field: targetBaseUrl (${resolvedPath})`);
|
|
17
|
-
}
|
|
18
|
-
if (!Array.isArray(adapter.screens) || adapter.screens.length === 0) {
|
|
19
|
-
throw new Error(`Adapter must expose a non-empty screens array (${resolvedPath})`);
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
resolvedPath,
|
|
23
|
-
adapter,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
function normalizeBoolean(value, fallback = false) {
|
|
5
|
-
if (typeof value === "boolean") return value;
|
|
6
|
-
if (value == null) return fallback;
|
|
7
|
-
const normalized = String(value).trim().toLowerCase();
|
|
8
|
-
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
9
|
-
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
10
|
-
return fallback;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function normalizeNumber(value, fallback = 0) {
|
|
14
|
-
const parsed = Number(value);
|
|
15
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function parseViewport(value) {
|
|
19
|
-
if (!value || typeof value !== "object") return null;
|
|
20
|
-
const width = normalizeNumber(value.width, NaN);
|
|
21
|
-
const height = normalizeNumber(value.height, NaN);
|
|
22
|
-
if (![width, height].every(Number.isFinite) || width <= 0 || height <= 0) return null;
|
|
23
|
-
return { width, height };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function parseRect(value) {
|
|
27
|
-
if (!value || typeof value !== "object") return null;
|
|
28
|
-
const x = normalizeNumber(value.x, NaN);
|
|
29
|
-
const y = normalizeNumber(value.y, NaN);
|
|
30
|
-
const width = normalizeNumber(value.width, NaN);
|
|
31
|
-
const height = normalizeNumber(value.height, NaN);
|
|
32
|
-
if (![x, y, width, height].every(Number.isFinite) || width <= 0 || height <= 0) return null;
|
|
33
|
-
return { x, y, width, height };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function parseRectList(value) {
|
|
37
|
-
if (!Array.isArray(value)) return [];
|
|
38
|
-
return value.map(parseRect).filter(Boolean);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function inferRepoRoot(contractPath) {
|
|
42
|
-
const parts = path.resolve(contractPath).split(path.sep);
|
|
43
|
-
const sddIndex = parts.lastIndexOf("sdd");
|
|
44
|
-
if (sddIndex <= 0) {
|
|
45
|
-
return path.dirname(path.resolve(contractPath));
|
|
46
|
-
}
|
|
47
|
-
const rootParts = parts.slice(0, sddIndex);
|
|
48
|
-
return rootParts.length === 0 ? path.sep : rootParts.join(path.sep) || path.sep;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function loadContract(contractPath, loadYaml) {
|
|
52
|
-
const resolvedPath = path.resolve(contractPath);
|
|
53
|
-
const raw = fs.readFileSync(resolvedPath, "utf8");
|
|
54
|
-
const parsed = loadYaml(raw) ?? {};
|
|
55
|
-
const screens = Array.isArray(parsed.screens)
|
|
56
|
-
? parsed.screens.map((screen) => ({
|
|
57
|
-
id: screen.id,
|
|
58
|
-
route: screen.route,
|
|
59
|
-
referenceImage: screen.reference_image ?? screen.referenceImage ?? null,
|
|
60
|
-
captureFullPage: screen.capture_full_page ?? screen.captureFullPage ?? false,
|
|
61
|
-
allowResize: normalizeBoolean(screen.allow_resize, false),
|
|
62
|
-
pixelmatchThreshold: normalizeNumber(screen.pixelmatch_threshold, 0.1),
|
|
63
|
-
includeAA: normalizeBoolean(screen.include_aa, true),
|
|
64
|
-
viewport: parseViewport(screen.viewport),
|
|
65
|
-
maskRects: parseRectList(screen.mask_rects),
|
|
66
|
-
maxDiffRatio: Number.isFinite(Number(screen.max_diff_ratio))
|
|
67
|
-
? Number(screen.max_diff_ratio)
|
|
68
|
-
: 0,
|
|
69
|
-
}))
|
|
70
|
-
: [];
|
|
71
|
-
const targetBaseUrl = parsed?.spec?.target_base_url ?? parsed?.target_base_url ?? "";
|
|
72
|
-
return {
|
|
73
|
-
resolvedPath,
|
|
74
|
-
contract: {
|
|
75
|
-
...parsed,
|
|
76
|
-
screens,
|
|
77
|
-
targetBaseUrl,
|
|
78
|
-
repoRoot: inferRepoRoot(resolvedPath),
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
export function ensureDirectory(dirPath) {
|
|
5
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function timestampUtc(now = new Date()) {
|
|
9
|
-
const parts = [
|
|
10
|
-
now.getUTCFullYear(),
|
|
11
|
-
String(now.getUTCMonth() + 1).padStart(2, "0"),
|
|
12
|
-
String(now.getUTCDate()).padStart(2, "0"),
|
|
13
|
-
String(now.getUTCHours()).padStart(2, "0"),
|
|
14
|
-
String(now.getUTCMinutes()).padStart(2, "0"),
|
|
15
|
-
String(now.getUTCSeconds()).padStart(2, "0"),
|
|
16
|
-
];
|
|
17
|
-
return `${parts[0]}${parts[1]}${parts[2]}${parts[3]}${parts[4]}${parts[5]}`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function writeJson(filePath, payload) {
|
|
21
|
-
ensureDirectory(path.dirname(filePath));
|
|
22
|
-
fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
23
|
-
}
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { ensureDirectory, timestampUtc, writeJson } from "./paths.mjs";
|
|
5
|
-
import { captureScreen, sanitizeFileName } from "./capture-runner.mjs";
|
|
6
|
-
|
|
7
|
-
function loadPng(filePath) {
|
|
8
|
-
const { PNG } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
9
|
-
return PNG.sync.read(fs.readFileSync(filePath));
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function clonePng(png) {
|
|
13
|
-
const { PNG } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
14
|
-
const next = new PNG({ width: png.width, height: png.height });
|
|
15
|
-
png.data.copy(next.data);
|
|
16
|
-
return next;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function writePng(filePath, png) {
|
|
20
|
-
const { PNG } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
21
|
-
ensureDirectory(path.dirname(filePath));
|
|
22
|
-
fs.writeFileSync(filePath, PNG.sync.write(png));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function createBlankDiff(width, height) {
|
|
26
|
-
const { PNG } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
27
|
-
return new PNG({ width, height });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function applyMaskRects(png, rects) {
|
|
31
|
-
if (!Array.isArray(rects) || rects.length === 0) return png;
|
|
32
|
-
const masked = clonePng(png);
|
|
33
|
-
for (const rect of rects) {
|
|
34
|
-
const xStart = Math.max(0, Math.floor(rect.x));
|
|
35
|
-
const yStart = Math.max(0, Math.floor(rect.y));
|
|
36
|
-
const xEnd = Math.min(masked.width, xStart + Math.floor(rect.width));
|
|
37
|
-
const yEnd = Math.min(masked.height, yStart + Math.floor(rect.height));
|
|
38
|
-
for (let y = yStart; y < yEnd; y += 1) {
|
|
39
|
-
for (let x = xStart; x < xEnd; x += 1) {
|
|
40
|
-
const index = (masked.width * y + x) * 4;
|
|
41
|
-
masked.data[index] = 255;
|
|
42
|
-
masked.data[index + 1] = 255;
|
|
43
|
-
masked.data[index + 2] = 255;
|
|
44
|
-
masked.data[index + 3] = 255;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return masked;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function resizeNearestNeighbor(source, targetWidth, targetHeight) {
|
|
52
|
-
const { PNG } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
53
|
-
const resized = new PNG({ width: targetWidth, height: targetHeight });
|
|
54
|
-
for (let y = 0; y < targetHeight; y += 1) {
|
|
55
|
-
for (let x = 0; x < targetWidth; x += 1) {
|
|
56
|
-
const srcX = Math.min(source.width - 1, Math.floor((x / targetWidth) * source.width));
|
|
57
|
-
const srcY = Math.min(source.height - 1, Math.floor((y / targetHeight) * source.height));
|
|
58
|
-
const srcIndex = (source.width * srcY + srcX) * 4;
|
|
59
|
-
const dstIndex = (targetWidth * y + x) * 4;
|
|
60
|
-
resized.data[dstIndex] = source.data[srcIndex];
|
|
61
|
-
resized.data[dstIndex + 1] = source.data[srcIndex + 1];
|
|
62
|
-
resized.data[dstIndex + 2] = source.data[srcIndex + 2];
|
|
63
|
-
resized.data[dstIndex + 3] = source.data[srcIndex + 3];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return resized;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function compareImages(referencePath, actualPath, diffPath, options = {}) {
|
|
70
|
-
const { pixelmatch } = globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
71
|
-
let reference = loadPng(referencePath);
|
|
72
|
-
let actual = loadPng(actualPath);
|
|
73
|
-
reference = applyMaskRects(reference, options.maskRects);
|
|
74
|
-
actual = applyMaskRects(actual, options.maskRects);
|
|
75
|
-
if (reference.width !== actual.width || reference.height !== actual.height) {
|
|
76
|
-
if (options.allowResize) {
|
|
77
|
-
actual = resizeNearestNeighbor(actual, reference.width, reference.height);
|
|
78
|
-
} else {
|
|
79
|
-
return {
|
|
80
|
-
diffRatio: 1,
|
|
81
|
-
status: "size_mismatch",
|
|
82
|
-
detail: `reference=${reference.width}x${reference.height} actual=${actual.width}x${actual.height}`,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (reference.width !== actual.width || reference.height !== actual.height) {
|
|
88
|
-
return {
|
|
89
|
-
diffRatio: 1,
|
|
90
|
-
status: "size_mismatch",
|
|
91
|
-
detail: `reference=${reference.width}x${reference.height} actual=${actual.width}x${actual.height}`,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const diff = createBlankDiff(reference.width, reference.height);
|
|
96
|
-
const diffPixels = pixelmatch(
|
|
97
|
-
reference.data,
|
|
98
|
-
actual.data,
|
|
99
|
-
diff.data,
|
|
100
|
-
reference.width,
|
|
101
|
-
reference.height,
|
|
102
|
-
{
|
|
103
|
-
threshold: options.pixelmatchThreshold ?? 0.1,
|
|
104
|
-
includeAA: options.includeAA ?? true,
|
|
105
|
-
},
|
|
106
|
-
);
|
|
107
|
-
writePng(diffPath, diff);
|
|
108
|
-
return {
|
|
109
|
-
diffRatio: diffPixels / (reference.width * reference.height),
|
|
110
|
-
status: diffPixels === 0 ? "passed" : "failed",
|
|
111
|
-
detail: `reference=${reference.width}x${reference.height} actual=${actual.width}x${actual.height} diff_pixels=${diffPixels}`,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export async function runProof({
|
|
116
|
-
adapterPath,
|
|
117
|
-
contractPath,
|
|
118
|
-
outPath,
|
|
119
|
-
adapter,
|
|
120
|
-
contract,
|
|
121
|
-
browser,
|
|
122
|
-
requireFromAdapter,
|
|
123
|
-
}) {
|
|
124
|
-
const pixelmatchModule = await import(pathToFileURL(requireFromAdapter.resolve("pixelmatch")).href);
|
|
125
|
-
const { PNG } = requireFromAdapter("pngjs");
|
|
126
|
-
globalThis.__TEMPLATE_UI_PARITY_DEPS__ = {
|
|
127
|
-
pixelmatch: pixelmatchModule.default ?? pixelmatchModule,
|
|
128
|
-
PNG,
|
|
129
|
-
};
|
|
130
|
-
const evidenceRoot = path.dirname(path.resolve(outPath));
|
|
131
|
-
const timestamp = timestampUtc();
|
|
132
|
-
const timestampRoot = path.join(evidenceRoot, timestamp);
|
|
133
|
-
const actualRoot = path.join(timestampRoot, "actual");
|
|
134
|
-
const diffRoot = path.join(timestampRoot, "diff");
|
|
135
|
-
ensureDirectory(actualRoot);
|
|
136
|
-
ensureDirectory(diffRoot);
|
|
137
|
-
|
|
138
|
-
const configuredScreens = Array.isArray(contract?.screens) && contract.screens.length > 0 ? contract.screens : adapter.screens ?? [];
|
|
139
|
-
const baseUrl = adapter.targetBaseUrl ?? contract?.targetBaseUrl ?? "http://127.0.0.1:4301";
|
|
140
|
-
const defaultViewport = adapter.viewport ?? { width: 1440, height: 1024 };
|
|
141
|
-
const repoRoot = contract?.repoRoot ?? process.cwd();
|
|
142
|
-
|
|
143
|
-
const results = [];
|
|
144
|
-
for (const configuredScreen of configuredScreens) {
|
|
145
|
-
const screen = {
|
|
146
|
-
...configuredScreen,
|
|
147
|
-
referenceImage:
|
|
148
|
-
configuredScreen.referenceImage ??
|
|
149
|
-
configuredScreen.reference_image ??
|
|
150
|
-
`sdd/03_verify/10_test/ui_parity/reference/${configuredScreen.id}.png`,
|
|
151
|
-
};
|
|
152
|
-
const stem = sanitizeFileName(screen.id || screen.route);
|
|
153
|
-
const actualPath = path.join(actualRoot, `${stem}.png`);
|
|
154
|
-
const diffPath = path.join(diffRoot, `${stem}.png`);
|
|
155
|
-
const referencePath = screen.referenceImage ? path.resolve(screen.referenceImage) : null;
|
|
156
|
-
const resolvedReferencePath =
|
|
157
|
-
screen.referenceImage && !path.isAbsolute(screen.referenceImage)
|
|
158
|
-
? path.resolve(repoRoot, screen.referenceImage)
|
|
159
|
-
: referencePath;
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const capture = await captureScreen({
|
|
163
|
-
browser,
|
|
164
|
-
screen,
|
|
165
|
-
adapter,
|
|
166
|
-
outputPath: actualPath,
|
|
167
|
-
baseUrl,
|
|
168
|
-
viewport: screen.viewport ?? defaultViewport,
|
|
169
|
-
});
|
|
170
|
-
const actualRelative = path.relative(path.dirname(outPath), actualPath).split(path.sep).join("/");
|
|
171
|
-
|
|
172
|
-
if (!resolvedReferencePath || !fs.existsSync(resolvedReferencePath)) {
|
|
173
|
-
results.push({
|
|
174
|
-
id: screen.id,
|
|
175
|
-
title: screen.title ?? null,
|
|
176
|
-
route: screen.route,
|
|
177
|
-
tags: Array.isArray(screen.tags) ? screen.tags : [],
|
|
178
|
-
status: "missing_reference",
|
|
179
|
-
diff_ratio: 1,
|
|
180
|
-
reference_image: screen.referenceImage ?? null,
|
|
181
|
-
actual_image: actualRelative,
|
|
182
|
-
diff_image: null,
|
|
183
|
-
detail: "Reference image is missing. Capture succeeded but comparison was skipped.",
|
|
184
|
-
target_url: capture.targetUrl,
|
|
185
|
-
});
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const compared = compareImages(resolvedReferencePath, actualPath, diffPath, {
|
|
190
|
-
allowResize: Boolean(screen.allowResize),
|
|
191
|
-
pixelmatchThreshold: screen.pixelmatchThreshold,
|
|
192
|
-
includeAA: screen.includeAA,
|
|
193
|
-
maskRects:
|
|
194
|
-
typeof adapter.resolveMaskRects === "function"
|
|
195
|
-
? await adapter.resolveMaskRects({ screen, baseUrl, defaultViewport })
|
|
196
|
-
: screen.maskRects,
|
|
197
|
-
});
|
|
198
|
-
const threshold = Number.isFinite(Number(screen.maxDiffRatio)) ? Number(screen.maxDiffRatio) : 0;
|
|
199
|
-
const withinThreshold = compared.diffRatio <= threshold;
|
|
200
|
-
results.push({
|
|
201
|
-
id: screen.id,
|
|
202
|
-
title: screen.title ?? null,
|
|
203
|
-
route: screen.route,
|
|
204
|
-
tags: Array.isArray(screen.tags) ? screen.tags : [],
|
|
205
|
-
status: compared.status === "size_mismatch" ? compared.status : withinThreshold ? "passed" : "failed",
|
|
206
|
-
diff_ratio: compared.diffRatio,
|
|
207
|
-
max_diff_ratio: threshold,
|
|
208
|
-
reference_image: screen.referenceImage,
|
|
209
|
-
actual_image: actualRelative,
|
|
210
|
-
diff_image: path.relative(path.dirname(outPath), diffPath).split(path.sep).join("/"),
|
|
211
|
-
detail: compared.detail,
|
|
212
|
-
target_url: capture.targetUrl,
|
|
213
|
-
});
|
|
214
|
-
} catch (error) {
|
|
215
|
-
results.push({
|
|
216
|
-
id: screen.id,
|
|
217
|
-
title: screen.title ?? null,
|
|
218
|
-
route: screen.route,
|
|
219
|
-
tags: Array.isArray(screen.tags) ? screen.tags : [],
|
|
220
|
-
status: "capture_error",
|
|
221
|
-
diff_ratio: 1,
|
|
222
|
-
max_diff_ratio: Number.isFinite(Number(screen.maxDiffRatio)) ? Number(screen.maxDiffRatio) : 0,
|
|
223
|
-
reference_image: screen.referenceImage ?? null,
|
|
224
|
-
actual_image: null,
|
|
225
|
-
diff_image: null,
|
|
226
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
227
|
-
target_url: new URL(screen.route, baseUrl).toString(),
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const summary = {
|
|
233
|
-
total: results.length,
|
|
234
|
-
passed: results.filter((screen) => screen.status === "passed").length,
|
|
235
|
-
failed: results.filter((screen) => screen.status === "failed" || screen.status === "size_mismatch").length,
|
|
236
|
-
missing_reference: results.filter((screen) => screen.status === "missing_reference").length,
|
|
237
|
-
capture_error: results.filter((screen) => screen.status === "capture_error").length,
|
|
238
|
-
matched: results.filter((screen) => screen.status === "passed").length === results.length && results.length > 0,
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const payload = {
|
|
242
|
-
generated_at: new Date().toISOString(),
|
|
243
|
-
service: adapter.service ?? "replace-service-name",
|
|
244
|
-
adapter_path: adapterPath,
|
|
245
|
-
contract_path: contractPath,
|
|
246
|
-
target_base_url: baseUrl,
|
|
247
|
-
default_viewport: defaultViewport,
|
|
248
|
-
screens: results,
|
|
249
|
-
summary,
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
writeJson(outPath, payload);
|
|
253
|
-
delete globalThis.__TEMPLATE_UI_PARITY_DEPS__;
|
|
254
|
-
return payload;
|
|
255
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# UI Parity Artifact Layout
|
|
2
|
-
|
|
3
|
-
권장 루트:
|
|
4
|
-
|
|
5
|
-
- `sdd/03_verify/10_test/ui_parity/`
|
|
6
|
-
|
|
7
|
-
필수 파일:
|
|
8
|
-
|
|
9
|
-
- latest proof json
|
|
10
|
-
- 예: `templates_web_agentic_dev_latest.json`
|
|
11
|
-
|
|
12
|
-
권장 하위 구조:
|
|
13
|
-
|
|
14
|
-
- `reference/`
|
|
15
|
-
- `<timestamp>/actual/`
|
|
16
|
-
- `<timestamp>/diff/`
|
|
17
|
-
- `loop_runs/`
|
|
18
|
-
- `staged_runs/`
|
|
19
|
-
|
|
20
|
-
정책:
|
|
21
|
-
|
|
22
|
-
- latest proof json은 항상 고정 경로를 사용한다.
|
|
23
|
-
- timestamp run directory는 회차별 evidence 보존용이다.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# UI Parity Proof Interface
|
|
2
|
-
|
|
3
|
-
입력:
|
|
4
|
-
|
|
5
|
-
- `--adapter`
|
|
6
|
-
- app adapter module path
|
|
7
|
-
- `--contract`
|
|
8
|
-
- parity contract yaml path
|
|
9
|
-
- `--out`
|
|
10
|
-
- latest proof json output path
|
|
11
|
-
|
|
12
|
-
adapter contract:
|
|
13
|
-
|
|
14
|
-
- `service`
|
|
15
|
-
- `targetBaseUrl`
|
|
16
|
-
- optional `viewport`
|
|
17
|
-
- optional `preparePage(page, context)`
|
|
18
|
-
- optional `beforeNavigate(page, context)`
|
|
19
|
-
- optional `waitForReady(page, context)`
|
|
20
|
-
- optional `afterPageReady(page, context)`
|
|
21
|
-
- optional `resolveMaskRects(context)`
|
|
22
|
-
- `screens[]`
|
|
23
|
-
- `id`
|
|
24
|
-
- optional `title`
|
|
25
|
-
- `route`
|
|
26
|
-
- optional `referenceImage`
|
|
27
|
-
- optional `maxDiffRatio`
|
|
28
|
-
- optional `viewport`
|
|
29
|
-
- optional `allowResize`
|
|
30
|
-
- optional `pixelmatchThreshold`
|
|
31
|
-
- optional `includeAA`
|
|
32
|
-
- optional `maskRects`
|
|
33
|
-
- optional `readySelector`
|
|
34
|
-
- optional `readyTimeoutMs`
|
|
35
|
-
- optional `tags`
|
|
36
|
-
|
|
37
|
-
출력 JSON:
|
|
38
|
-
|
|
39
|
-
- `generated_at`
|
|
40
|
-
- `service`
|
|
41
|
-
- `adapter_path`
|
|
42
|
-
- `contract_path`
|
|
43
|
-
- `target_base_url`
|
|
44
|
-
- `default_viewport`
|
|
45
|
-
- `screens[]`
|
|
46
|
-
- `id`
|
|
47
|
-
- optional `title`
|
|
48
|
-
- `route`
|
|
49
|
-
- optional `tags`
|
|
50
|
-
- `status`
|
|
51
|
-
- `diff_ratio`
|
|
52
|
-
- optional `max_diff_ratio`
|
|
53
|
-
- optional `reference_image`
|
|
54
|
-
- `summary`
|
|
55
|
-
- `total`
|
|
56
|
-
- `passed`
|
|
57
|
-
- `failed`
|
|
58
|
-
- `missing_reference`
|
|
59
|
-
- `capture_error`
|
|
60
|
-
- `matched`
|
package/sdd/99_toolchain/01_automation/ui-parity/interfaces/ui-parity-route-gap-interface.md
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# UI Parity Route Gap Interface
|
|
2
|
-
|
|
3
|
-
입력:
|
|
4
|
-
|
|
5
|
-
- `--service`
|
|
6
|
-
- 화면 카탈로그를 소유하는 프론트 디렉터리 또는 서비스 이름
|
|
7
|
-
- `--screens`
|
|
8
|
-
- spec screen catalog json path
|
|
9
|
-
- `--routes`
|
|
10
|
-
- route catalog json path
|
|
11
|
-
- `--out`
|
|
12
|
-
- route gap json output path
|
|
13
|
-
- `--markdown-out`
|
|
14
|
-
- optional markdown summary output path
|
|
15
|
-
|
|
16
|
-
분류 규칙:
|
|
17
|
-
|
|
18
|
-
- `direct`
|
|
19
|
-
- route가 1:1로 연결된 화면
|
|
20
|
-
- `shared`
|
|
21
|
-
- 여러 screen id가 같은 route를 공유하거나 route entry가 `binding=shared`
|
|
22
|
-
- `stateful`
|
|
23
|
-
- direct route 대신 상태 전이에 의존하거나 `binding=stateful`
|
|
24
|
-
- `missing`
|
|
25
|
-
- route entry가 없거나 `binding=missing`
|
|
26
|
-
|
|
27
|
-
planning evidence 필드:
|
|
28
|
-
|
|
29
|
-
- `binding_source`
|
|
30
|
-
- `explicit` 또는 `inferred`
|
|
31
|
-
- `coverage_state`
|
|
32
|
-
- `route_bound`, `shared_route`, `state_transition`, `unmapped`
|
|
33
|
-
- `evidence_level`
|
|
34
|
-
- `strong`, `medium`, `weak`, `missing`
|
|
35
|
-
- `duplicate_route_groups`
|
|
36
|
-
- 같은 route를 여러 screen id가 공유하는 그룹
|
|
37
|
-
|
|
38
|
-
출력 JSON:
|
|
39
|
-
|
|
40
|
-
- `generated_at`
|
|
41
|
-
- `service`
|
|
42
|
-
- `screens_path`
|
|
43
|
-
- `routes_path`
|
|
44
|
-
- `summary`
|
|
45
|
-
- `total`
|
|
46
|
-
- `direct`
|
|
47
|
-
- `shared`
|
|
48
|
-
- `stateful`
|
|
49
|
-
- `missing`
|
|
50
|
-
- `coverage_ratio`
|
|
51
|
-
- `explicit_bindings`
|
|
52
|
-
- `strong_evidence`
|
|
53
|
-
- `medium_evidence`
|
|
54
|
-
- `weak_evidence`
|
|
55
|
-
- `with_notes`
|
|
56
|
-
- `with_tags`
|
|
57
|
-
- `duplicate_route_groups`
|
|
58
|
-
- `duplicate_route_groups[]`
|
|
59
|
-
- `route`
|
|
60
|
-
- `screen_ids[]`
|
|
61
|
-
- `screens[]`
|
|
62
|
-
- `id`
|
|
63
|
-
- `title`
|
|
64
|
-
- `route`
|
|
65
|
-
- `binding`
|
|
66
|
-
- `binding_source`
|
|
67
|
-
- `coverage_state`
|
|
68
|
-
- `evidence_level`
|
|
69
|
-
- `route_defined`
|
|
70
|
-
- `has_notes`
|
|
71
|
-
- `has_tags`
|
|
72
|
-
- `duplicate_route_ids[]`
|
|
73
|
-
- `tags[]`
|
|
74
|
-
- `status`
|
|
75
|
-
- `notes[]`
|
|
76
|
-
|
|
77
|
-
주요 생성 경로 예시:
|
|
78
|
-
|
|
79
|
-
- `sdd/02_plan/99_generated/from_planning/ui_parity/ui_parity_web_route_gap_report.json`
|
|
80
|
-
- `sdd/02_plan/99_generated/from_planning/ui_parity/ui_parity_web_route_gap_report.md`
|
|
81
|
-
- `sdd/02_plan/99_generated/from_planning/ui_parity/mobile.route_gap_report.json`
|
|
82
|
-
- `sdd/02_plan/99_generated/from_planning/ui_parity/mobile.route_gap_report.md`
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export async function createPlaywrightRuntime(requireFromAdapter) {
|
|
2
|
-
const playwright = requireFromAdapter("@playwright/test");
|
|
3
|
-
const chromium = playwright.chromium ?? playwright.default?.chromium;
|
|
4
|
-
if (!chromium) {
|
|
5
|
-
throw new Error("Failed to load Playwright chromium runtime from the app workspace.");
|
|
6
|
-
}
|
|
7
|
-
const browser = await chromium.launch({
|
|
8
|
-
headless: true,
|
|
9
|
-
});
|
|
10
|
-
return {
|
|
11
|
-
browser,
|
|
12
|
-
async dispose() {
|
|
13
|
-
await browser.close();
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Build AST Governance Policy
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
`sdd/03_build`를 implementation history가 아니라 runtime assembly current-state 문서로 고정한다.
|
|
6
|
-
|
|
7
|
-
## Rules
|
|
8
|
-
|
|
9
|
-
- service build summary는 실제 entrypoint부터 읽혀야 한다.
|
|
10
|
-
- 기본 설명 순서는 `entry -> provider/router -> auth/session gate -> shell -> route leaf -> backend contract leaf`다.
|
|
11
|
-
- shared shell, auth/session, data contract, transport split은 route leaf 이후 cross-cutting link로 연결한다.
|
|
12
|
-
- `sdd/03_build`에는 dated memo, Ralph iteration narrative, run id, turn-specific 회고를 남기지 않는다.
|
|
13
|
-
- 구조 current-state 적합성은 `scripts/dev/audit_sdd_build_ast.py`로 검증하고 결과는 `sdd/03_verify/03_architecture`에 유지한다.
|
|
14
|
-
- downstream 저장소는 이 정책과 audit script를 함께 복제해야 한다.
|
|
15
|
-
|
|
16
|
-
## Canonical References
|
|
17
|
-
|
|
18
|
-
- `AGENTS.md`
|
|
19
|
-
- `scripts/dev/audit_sdd_build_ast.py`
|
|
20
|
-
- `sdd/02_plan/03_architecture/build_ast_runtime_tree_governance.md`
|
|
21
|
-
- `sdd/03_build/03_architecture/build_ast_runtime_tree_governance.md`
|
|
22
|
-
- `sdd/03_verify/03_architecture/build_ast_runtime_tree_governance.md`
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Compose Runtime Baseline Policy
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
템플릿 저장소의 compose/runtime 기준선을 root compose 중심 current-state로 고정하고, dedicated host overlay와 provider-first delivery split의 역할을 분리한다.
|
|
6
|
-
|
|
7
|
-
## Rules
|
|
8
|
-
|
|
9
|
-
- 루트 `compose.yml`은 템플릿 저장소의 canonical dev-focused runtime baseline이다.
|
|
10
|
-
- root compose는 4개 frontend surface, `server`, 기본 `postgres`, optional DB profile(`mysql`, `mariadb`, `mongo`)을 한 graph로 유지한다.
|
|
11
|
-
- `infra/compose/dev.yml`, `infra/compose/prod.yml`은 dedicated DEV(개발계)/PROD host나 분리된 runtime stack이 필요할 때 사용하는 overlay/example set이다.
|
|
12
|
-
- compose 문서는 root compose baseline과 dedicated overlay를 혼동하지 않고 current-state 역할로만 설명한다.
|
|
13
|
-
- browser-facing 환경 변수(`VITE_API_BASE_URL` 등)는 컨테이너 내부 DNS가 아니라 실제 브라우저가 도달 가능한 URL을 사용한다.
|
|
14
|
-
- remote delivery topology는 `AWS edge/domain -> OpenStack backend compute -> AWS data plane` current split을 기준으로 설명한다.
|
|
15
|
-
- compose baseline이나 topology가 바뀌면 `README.md`, `infra/compose/README.md`, `sdd/02_plan/06_iac`, `sdd/03_build/06_iac`, `sdd/03_verify/06_iac`를 같은 변경 단위로 동기화한다.
|
|
16
|
-
|
|
17
|
-
## Canonical References
|
|
18
|
-
|
|
19
|
-
- `README.md`
|
|
20
|
-
- `infra/compose/README.md`
|
|
21
|
-
- `infra/terraform/README.md`
|
|
22
|
-
- `sdd/02_plan/06_iac/template_runtime_delivery.md`
|
|
23
|
-
- `sdd/03_build/06_iac/template_runtime_delivery.md`
|
|
24
|
-
- `sdd/03_verify/06_iac/template_runtime_delivery.md`
|