#!/usr/bin/env bash set -euo pipefail # The JSON catalog is the only phase order/metadata authority. Check commands # remain in the marked functions below; devkit invokes this script, not copies. META_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" FOCUSED_MODE=run FOCUSED_PHASE="" FOCUSED_JSON=0 focused_usage() { echo "Usage: check-focused.sh [--phase ID] | --list-phases [--json]" echo "Without --phase, run every canonical phase in catalog order (fail fast)." } while [[ $# -gt 0 ]]; do case "$1" in --phase) if [[ "$FOCUSED_MODE" != run || -n "$FOCUSED_PHASE" || $# -lt 2 || -z "$2" || "$2" == --* ]]; then echo "check-focused: --phase requires one ID and cannot be combined with listing." >&2 exit 2 fi FOCUSED_PHASE="$2" shift 2 ;; --list-phases) if [[ "$FOCUSED_MODE" != run || -n "$FOCUSED_PHASE" ]]; then echo "check-focused: duplicate or incompatible phase selection." >&2 exit 2 fi FOCUSED_MODE=list shift ;; --json) if [[ "$FOCUSED_JSON" == 1 ]]; then echo "check-focused: duplicate --json." >&2 exit 2 fi FOCUSED_JSON=1 shift ;; --help|-h) focused_usage exit 0 ;; *) echo "check-focused: unknown argument: $1" >&2 focused_usage >&2 exit 2 ;; esac done if [[ "$FOCUSED_JSON" == 1 && "$FOCUSED_MODE" != list ]]; then echo "check-focused: --json is supported only with --list-phases." >&2 exit 2 fi # Metadata-only operations need standard Python, not an installed product venv, # Node, npm, a Core checkout, or any temporary/state directory. FOCUSED_METADATA_PYTHON="$(command -v python3)" || { echo "check-focused: Python 3 is required to read phase metadata." >&2 exit 127 } FOCUSED_SELECTION="$( PYTHONDONTWRITEBYTECODE=1 "$FOCUSED_METADATA_PYTHON" -I -S - \ "$META_ROOT/tools/checks/focused-phases.json" "$FOCUSED_MODE" "$FOCUSED_PHASE" "$FOCUSED_JSON" <<'PY' import json import os from pathlib import Path import re import stat import sys try: path = Path(sys.argv[1]) descriptor = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0)) with os.fdopen(descriptor, "rb") as handle: status = os.fstat(handle.fileno()) if not stat.S_ISREG(status.st_mode) or status.st_size > 1024 * 1024: raise ValueError("phase metadata must be a bounded regular file") encoded = handle.read(1024 * 1024 + 1) if len(encoded) > 1024 * 1024: raise ValueError("phase metadata exceeds its size bound") def unique(pairs): result = {} for key, value in pairs: if key in result: raise ValueError("duplicate phase metadata key") result[key] = value return result catalog = json.loads(encoded, object_pairs_hook=unique) if not isinstance(catalog, dict) or set(catalog) != {"schema_version", "phases"} or type(catalog["schema_version"]) is not int or catalog["schema_version"] != 1: raise ValueError("unsupported phase metadata schema") phases = catalog["phases"] if not isinstance(phases, list) or not 1 <= len(phases) <= 32: raise ValueError("phase catalog requires 1–32 definitions") seen = set() fields = {"id", "title", "cwd", "order_after", "depends_on", "resources", "outputs", "notes"} for phase in phases: if not isinstance(phase, dict) or set(phase) != fields: raise ValueError("invalid phase metadata fields") identity = phase["id"] if not isinstance(identity, str) or not re.fullmatch(r"[a-z][a-z0-9-]{0,63}", identity) or identity in seen: raise ValueError("invalid or duplicate phase ID") if not isinstance(phase["title"], str) or not phase["title"].strip() or len(phase["title"]) > 256 or any(ord(char) < 32 for char in phase["title"]): raise ValueError("invalid phase title") if phase["cwd"] not in {"core", "meta", "core-webui", "access-webui"}: raise ValueError("unsupported phase working directory") for field in ("order_after", "depends_on", "resources", "outputs", "notes"): values = phase[field] if not isinstance(values, list) or len(values) > 64 or any(not isinstance(value, str) or not value or len(value) > 4096 or "\0" in value for value in values): raise ValueError("invalid phase list: " + field) if len(set(values)) != len(values): raise ValueError("duplicate phase list value: " + field) if (set(phase["order_after"]) | set(phase["depends_on"])) - seen: raise ValueError("phase prerequisites must precede their consumer") seen.add(identity) mode, selected, as_json = sys.argv[2:] if selected and selected not in seen: raise ValueError("unknown phase: " + selected) if mode == "list": print(json.dumps(catalog, indent=2) if as_json == "1" else "\n".join(phase["id"] + "\t" + phase["title"] for phase in phases)) else: print("\n".join(phase["id"] for phase in phases if not selected or phase["id"] == selected)) except (OSError, ValueError, TypeError, RecursionError) as exc: print("check-focused: " + str(exc), file=sys.stderr) raise SystemExit(2) PY )" if [[ "$FOCUSED_MODE" == list ]]; then printf '%s\n' "$FOCUSED_SELECTION" exit 0 fi focused_setup() { WORKSPACE_ROOT="${GOVOPLAN_WORKSPACE_ROOT:-$(dirname "$META_ROOT")}" export GOVOPLAN_WORKSPACE_ROOT="$WORKSPACE_ROOT" ROOT="${GOVOPLAN_CORE_ROOT:-$WORKSPACE_ROOT/govoplan-core}" ROOT="$(cd "$ROOT" && pwd)" VENV_ROOT="${GOVOPLAN_VENV_ROOT:-$META_ROOT/.venv}" PYTHON="${PYTHON:-$VENV_ROOT/bin/python}" NODE="$(command -v "${NODE:-node}")" || { echo "check-focused: Node is unavailable; run ./devkit doctor." >&2; exit 127; } NPM="$(command -v "${NPM:-npm}")" || { echo "check-focused: npm is unavailable; run ./devkit doctor." >&2; exit 127; } NODE_BIN="$(dirname "$NODE")" WEBUI_BIN="$ROOT/webui/node_modules/.bin" NPM_USERCONFIG="$(mktemp "${TMPDIR:-/tmp}/govoplan-npmrc.XXXXXXXX")" trap 'rm -f "$NPM_USERCONFIG"' EXIT [ -x "$PYTHON" ] || { echo "check-focused: Python virtualenv not found at $PYTHON." >&2 echo "Run: cd $META_ROOT && python3 -m venv .venv && ./.venv/bin/python -m pip install --upgrade pip && ./.venv/bin/python -m pip install -r requirements-dev.txt" >&2 exit 127 } export PATH="$WEBUI_BIN:$NODE_BIN:$PATH" export NPM_CONFIG_USERCONFIG="$NPM_USERCONFIG" export GOVOPLAN_NPM_USERCONFIG="$NPM_USERCONFIG" unset npm_config_tmp NPM_CONFIG_TMP # Validate the current sibling checkouts even when a newly added module has not # yet been installed into an existing development virtualenv. SOURCE_PYTHONPATH="" for source_dir in "$WORKSPACE_ROOT"/govoplan*/src; do [ -d "$source_dir" ] || continue SOURCE_PYTHONPATH="${SOURCE_PYTHONPATH:+$SOURCE_PYTHONPATH:}$source_dir" done export PYTHONPATH="${SOURCE_PYTHONPATH}${PYTHONPATH:+:$PYTHONPATH}" } focused_phase_preflight() { # devkit-phase: preflight begin cd "$ROOT" GOVOPLAN_CORE_ROOT="$ROOT" PYTHON="$PYTHON" CHECK_TESTCLIENT_DEPRECATIONS=1 bash "$META_ROOT/tools/checks/check-dependency-hygiene.sh" "$PYTHON" "$META_ROOT/tools/checks/check-contracts.py" --no-impact PYTHONDONTWRITEBYTECODE=1 "$PYTHON" "$META_ROOT/tools/checks/check-manifest-shapes.py" --require-architecture PYTHONDONTWRITEBYTECODE=1 "$PYTHON" "$META_ROOT/tools/checks/check-dsar-coverage.py" "$NODE" "$META_ROOT/tests/test-jsx-value-imports.mjs" "$NODE" "$META_ROOT/tools/checks/check-jsx-value-imports.mjs" "$NODE" "$META_ROOT/tests/test-heading-help.mjs" "$NODE" "$META_ROOT/tools/checks/check-heading-help.mjs" "$NODE" --test "$META_ROOT/tests/test-devkit-display-labels.mjs" "$NODE" --test "$ROOT/webui/tests/component-test-runner.test.mjs" "$NODE" "$WORKSPACE_ROOT/govoplan-files/webui/scripts/test-archive-client.mjs" # devkit-phase: preflight end } focused_phase_tooling() { # devkit-phase: tooling begin cd "$META_ROOT" "$PYTHON" tools/inventory/platform-interface-inventory.py --workspace-root "$WORKSPACE_ROOT" --strict-declarations --strict-endpoints "$PYTHON" tools/repo/sync-module-package-workflows.py --check "$PYTHON" tools/release/generate-developer-meta-package.py --check "$PYTHON" tools/checks/check-webui-package-facades.py "$PYTHON" -m unittest tests.test_webui_package_facades "$PYTHON" -m pytest -q tests/test_ui_review_program.py "$META_ROOT"/tests/test_devkit_*.py "$PYTHON" -m pytest -q tests/test_focused_phases.py "$PYTHON" -m unittest tests.test_module_package_workflows tests.test_package_registry_release "$PYTHON" -m unittest tests.test_deployment_installer tests.test_webui_release_dependency_retries "$PYTHON" -m pytest -q tests/test_release_meta_source_tag.py tests/test_release_source_tag_batch.py tests/test_release_meta_preparation.py "$PYTHON" -m unittest tests.test_isolated_work_composition "$PYTHON" -m unittest tests.test_capability_fit_evidence "$PYTHON" -m unittest tests.test_capability_fit_generation tests.test_capability_fit_review "$PYTHON" tools/assessments/generate-capability-fit-report.py --check "$PYTHON" -m unittest tests.test_configuration_package_artifacts "$PYTHON" -m unittest tests.test_institutional_governance_journey "$PYTHON" -m unittest tests.test_institutional_service_journey # devkit-phase: tooling end } focused_phase_backend() { # devkit-phase: backend begin cd "$ROOT" "$PYTHON" - <<'PY' import ast import pathlib import os import sys repos_root = pathlib.Path(os.environ["GOVOPLAN_WORKSPACE_ROOT"]) roots = [ repo / "src" for repo in sorted(repos_root.glob("govoplan*")) if (repo / "src").is_dir() ] roots.extend( repo / "tests" for repo in sorted(repos_root.glob("govoplan*")) if (repo / "tests").is_dir() ) errors = [] count = 0 for root in roots: if not root.exists(): continue for path in root.rglob("*.py"): count += 1 try: ast.parse(path.read_text(), filename=str(path)) except SyntaxError as exc: errors.append(f"{path}:{exc.lineno}:{exc.offset}: {exc.msg}") if errors: print("\n".join(errors)) sys.exit(1) print(f"AST syntax check passed for {count} Python files") PY "$PYTHON" -c 'import govoplan_core.db.bootstrap; import govoplan_access.backend.admin.service; import govoplan_addresses.backend.manifest; import govoplan_files.backend.router; import govoplan_mail.backend.sending.imap; print("targeted backend imports passed")' "$META_ROOT/tools/checks/check_dependency_boundaries.py" "$PYTHON" "$META_ROOT/tools/checks/check-shared-webui-layouts.py" "$PYTHON" "$META_ROOT/tools/checks/check-shared-webui-primitives.py" "$PYTHON" "$META_ROOT/tools/checks/check-shared-webui-foundations.py" "$PYTHON" -m unittest tests.test_module_system "$PYTHON" -m unittest tests.test_bounded_process "$PYTHON" -m unittest tests.test_ownership_history_migration tests.test_ownership tests.test_ownership_api "$PYTHON" -m unittest tests.test_navigation_preferences tests.test_api_smoke.ApiSmokeTests.test_navigation_separator_layout_survives_system_tenant_and_personal_saves "$PYTHON" -m pytest -q \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_managed_archives.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archive_work.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archive_staging.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_upload_response_batching.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archive_performance.py" "$PYTHON" -m pytest -q \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archive_workers.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archive_inspection_bounds.py" \ "${WORKSPACE_ROOT}/govoplan-files/tests/test_archives.py" "$PYTHON" -m pytest -q "${WORKSPACE_ROOT}/govoplan-access/tests/test_external_function_mapping_migration.py" "$PYTHON" -m pytest -q "${WORKSPACE_ROOT}/govoplan-access/tests" "$PYTHON" -m pytest -q "${WORKSPACE_ROOT}/govoplan-templates/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-connectors/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-datasources/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-dataflow/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-workflow-engine/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-workflow/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-views/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-quick-access/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-dashboard/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-postbox/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-portal/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-payments/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-forms/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-forms-runtime/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-cases/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-committee/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-voting/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-approvals/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-identity-trust/tests" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-encryption/tests" "$PYTHON" -m pytest -q "${WORKSPACE_ROOT}/govoplan-wiki/tests" "$PYTHON" -m pytest -q \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_approval_gate.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_editor_state_security.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_mail_profile_boundary.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_independent_configuration_repairs.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_incremental_review_persistence.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_reviewed_build_mock.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_delivery_policy_settings.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_synchronous_delivery_policy.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_workerless_recovery.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_imap_batch_integration.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_testbed_claim_recovery.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_campaign_optimistic_concurrency.py" \ "${WORKSPACE_ROOT}/govoplan-campaign/tests/test_archive_encryption_governance.py" \ "${WORKSPACE_ROOT}/govoplan-policy/tests/test_campaign_archive_encryption.py" \ "${WORKSPACE_ROOT}/govoplan-policy/tests/test_archive_encryption_api.py" "$PYTHON" "$META_ROOT/tools/checks/check-datasource-composition.py" "$PYTHON" "$META_ROOT/tools/checks/check-sanctions-screening-composition.py" "$PYTHON" -m pytest -q "${WORKSPACE_ROOT}/govoplan-mail/tests/test_campaign_protocol_authorization.py" "${WORKSPACE_ROOT}/govoplan-mail/tests/test_campaign_imap_batch.py" "$PYTHON" -m unittest discover -s "${WORKSPACE_ROOT}/govoplan-mail/tests" "$PYTHON" -m unittest tests.test_api_smoke.ApiSmokeTests.test_mailbox_message_listing_reports_total_count "$PYTHON" -m unittest \ tests.test_api_smoke.ApiSmokeTests.test_managed_attachment_patterns_preview_build_and_mock_send \ tests.test_api_smoke.ApiSmokeTests.test_reports_and_job_review_are_scoped_to_the_selected_version \ tests.test_api_smoke.ApiSmokeTests.test_worker_loss_becomes_unknown_and_requires_reconciliation_before_retry # devkit-phase: backend end } focused_phase_core_ui() { # devkit-phase: core-ui begin cd "$ROOT/webui" "$NPM" run test:api-client-cache "$NPM" run test:auth-action-state "$NPM" run test:dependency-security "$NPM" run test:components -- layout-primitives page-layout data-grid-actions mail-components "$NODE" --test tests/breadcrumb-bar.test.mjs "$NPM" run test:module-capabilities # devkit-phase: core-ui end } focused_phase_module_builds() { # devkit-phase: module-builds begin cd "$ROOT/webui" "$NPM" run test:module-permutations # devkit-phase: module-builds end } focused_phase_browser() { # devkit-phase: browser begin cd "$ROOT/webui" "$NPM" run test:conformance # devkit-phase: browser end } focused_phase_module_ui() { # devkit-phase: module-ui begin cd "${WORKSPACE_ROOT}/govoplan-access/webui" "$NPM" run test:passwords "$WEBUI_BIN/tsc" -p "${WORKSPACE_ROOT}/govoplan-payments/webui/tsconfig.json" cd "${WORKSPACE_ROOT}/govoplan-payments/webui" "$NPM" run test:interface-pattern cd "${WORKSPACE_ROOT}/govoplan-dataflow/webui" "$NPM" run test:structure cd "${WORKSPACE_ROOT}/govoplan-datasources/webui" "$NPM" run typecheck cd "${WORKSPACE_ROOT}/govoplan-workflow/webui" "$NPM" run typecheck cd "${WORKSPACE_ROOT}/govoplan-dashboard/webui" "$NPM" run test:dashboard-layout cd "${WORKSPACE_ROOT}/govoplan-approvals/webui" "$NPM" run test:workspace-layout cd "${WORKSPACE_ROOT}/govoplan-postbox/webui" "$NPM" run test:ui-structure cd "${WORKSPACE_ROOT}/govoplan-mail/webui" "$NPM" run test:mail-ui cd "${WORKSPACE_ROOT}/govoplan-files/webui" "$NPM" run test:managed-archive cd "${WORKSPACE_ROOT}/govoplan-campaign/webui" "$NPM" run test:policy-ui "$NPM" run test:template-preview "$NPM" run test:review-workflow "$NPM" run test:accessibility-contract "$NPM" run test:campaign-collaboration "$NPM" run test:campaign-work cd "${WORKSPACE_ROOT}/govoplan-policy/webui" "$NPM" run test:archive-encryption cd "${WORKSPACE_ROOT}/govoplan-wiki/webui" "$NPM" run test:interface-pattern # devkit-phase: module-ui end } # Validate every selected implementation before setup can create a temp npmrc. while IFS= read -r phase_id; do if ! declare -F "focused_phase_${phase_id//-/_}" >/dev/null; then echo "check-focused: missing phase implementation: $phase_id" >&2 exit 2 fi done <<< "$FOCUSED_SELECTION" while IFS= read -r phase_id; do ( focused_setup "focused_phase_${phase_id//-/_}" ) done <<< "$FOCUSED_SELECTION"