guardian-framework 0.1.0
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/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +12958 -0
- package/dist/exports.js +12765 -0
- package/package.json +61 -0
- package/templates/languages/go-patterns.md +411 -0
- package/templates/languages/java-patterns.md +545 -0
- package/templates/languages/python-patterns.md +312 -0
- package/templates/languages/rust-patterns.md +232 -0
- package/templates/languages/typescript-patterns.md +313 -0
- package/templates/pi/INDEX.md +437 -0
- package/templates/pi/agent/AGENTS.md +166 -0
- package/templates/pi/agents/architecture-coordinator.md +40 -0
- package/templates/pi/agents/architecture-validator.md +36 -0
- package/templates/pi/agents/bootstrap-implementer.md +37 -0
- package/templates/pi/agents/issue-factory.md +31 -0
- package/templates/pi/agents/operations-validator.md +32 -0
- package/templates/pi/agents/security-validator.md +33 -0
- package/templates/pi/architecture/CHANGELOG.md +78 -0
- package/templates/pi/architecture/decisions/ADR-template.md +76 -0
- package/templates/pi/architecture/diagrams/system-overview.md +159 -0
- package/templates/pi/architecture/modules/module-template.md +152 -0
- package/templates/pi/context/checklists.md +91 -0
- package/templates/pi/context/domain-workflow.md +180 -0
- package/templates/pi/context/output-formats.md +135 -0
- package/templates/pi/context/patterns-base.md +47 -0
- package/templates/pi/context/patterns.md +38 -0
- package/templates/pi/context/project.md +88 -0
- package/templates/pi/domain/exploration.md +93 -0
- package/templates/pi/domain/ubiquitous-language.md +24 -0
- package/templates/pi/extensions/architect-lib/generators.ts +528 -0
- package/templates/pi/extensions/architect-lib/helpers.ts +344 -0
- package/templates/pi/extensions/architect-lib/types.ts +117 -0
- package/templates/pi/extensions/architect.ts +1425 -0
- package/templates/pi/extensions/ask-user-question.ts +579 -0
- package/templates/pi/extensions/bash-guard.ts +556 -0
- package/templates/pi/extensions/config-reload.ts +115 -0
- package/templates/pi/extensions/coordinator.ts +304 -0
- package/templates/pi/extensions/curator.ts +543 -0
- package/templates/pi/extensions/domain-explorer.ts +990 -0
- package/templates/pi/extensions/filechanges.ts +656 -0
- package/templates/pi/extensions/goal-loop.ts +717 -0
- package/templates/pi/extensions/hooks.ts +452 -0
- package/templates/pi/extensions/kanban.ts +547 -0
- package/templates/pi/extensions/pipeline.ts +1246 -0
- package/templates/pi/extensions/plan-mode.ts +209 -0
- package/templates/pi/extensions/project-scaffolder.ts +284 -0
- package/templates/pi/extensions/read-only-mode.ts +192 -0
- package/templates/pi/extensions/redaction.ts +128 -0
- package/templates/pi/extensions/session-persistence.ts +174 -0
- package/templates/pi/extensions/slash-commands.ts +229 -0
- package/templates/pi/extensions/snippets.ts +201 -0
- package/templates/pi/extensions/validation-runner.ts +100 -0
- package/templates/pi/github/agents/architecture-coordinator.agent.md +27 -0
- package/templates/pi/github/agents/architecture-validator.agent.md +20 -0
- package/templates/pi/github/agents/bootstrap-implementer.agent.md +20 -0
- package/templates/pi/github/agents/epic-planner.agent.md +70 -0
- package/templates/pi/github/agents/issue-factory.agent.md +20 -0
- package/templates/pi/github/agents/operations-validator.agent.md +20 -0
- package/templates/pi/github/agents/security-validator.agent.md +20 -0
- package/templates/pi/github/copilot/settings.json +16 -0
- package/templates/pi/github/copilot-instructions.md +155 -0
- package/templates/pi/github/instructions/architecture.instructions.md +71 -0
- package/templates/pi/github/instructions/validation.instructions.md +69 -0
- package/templates/pi/github/workflows/01-planning-workflow.md +75 -0
- package/templates/pi/github/workflows/02-issue-generation-workflow.md +69 -0
- package/templates/pi/github/workflows/03-implementation-workflow.md +80 -0
- package/templates/pi/github/workflows/04-validation-workflow.md +68 -0
- package/templates/pi/preflight_report.json +99 -0
- package/templates/pi/prompts/blueprint-update.md +262 -0
- package/templates/pi/prompts/blueprint-validate.md +218 -0
- package/templates/pi/prompts/bug-fix.md +50 -0
- package/templates/pi/prompts/ci-blueprint.md +131 -0
- package/templates/pi/prompts/context-refresh.md +258 -0
- package/templates/pi/prompts/epic-plan.md +356 -0
- package/templates/pi/prompts/epic-template.md +186 -0
- package/templates/pi/prompts/feature-development.md +131 -0
- package/templates/pi/prompts/git-issues.md +243 -0
- package/templates/pi/prompts/hotfix.md +71 -0
- package/templates/pi/prompts/issue-closeout.md +342 -0
- package/templates/pi/prompts/issue-draft.md +218 -0
- package/templates/pi/prompts/issue-implementation-series.md +173 -0
- package/templates/pi/prompts/issue-merge.md +372 -0
- package/templates/pi/prompts/issue-template-set.md +392 -0
- package/templates/pi/prompts/issue-template.md +207 -0
- package/templates/pi/prompts/pattern-extract.md +269 -0
- package/templates/pi/prompts/plan-to-issues.md +430 -0
- package/templates/pi/prompts/refactoring.md +82 -0
- package/templates/pi/prompts/scope-analyzer.md +254 -0
- package/templates/pi/prompts/sync-check.md +230 -0
- package/templates/pi/scripts/categorize-issues.sh +171 -0
- package/templates/pi/scripts/ci/check_architecture_conformance.sh +748 -0
- package/templates/pi/scripts/ci/check_planning_packet.py +228 -0
- package/templates/pi/scripts/ci/run_hardening_stages.sh +264 -0
- package/templates/pi/scripts/ci/run_preflight.sh +649 -0
- package/templates/pi/scripts/ci/run_stage.sh +193 -0
- package/templates/pi/scripts/ci/stage_docs_policy.sh +82 -0
- package/templates/pi/scripts/ci/stage_integration.sh +3 -0
- package/templates/pi/scripts/ci/stage_lint.sh +130 -0
- package/templates/pi/scripts/ci/stage_migration_verify.sh +3 -0
- package/templates/pi/scripts/ci/stage_package_build.sh +3 -0
- package/templates/pi/scripts/ci/stage_release_readiness.sh +3 -0
- package/templates/pi/scripts/ci/stage_remaining.sh +242 -0
- package/templates/pi/scripts/ci/stage_security.sh +3 -0
- package/templates/pi/scripts/ci/stage_static_analysis.sh +114 -0
- package/templates/pi/scripts/ci/stage_unit.sh +119 -0
- package/templates/pi/scripts/ci/validate_agent_output.py +181 -0
- package/templates/pi/scripts/ci/validate_agent_output.sh +243 -0
- package/templates/pi/scripts/create-feature-branch.sh +136 -0
- package/templates/pi/scripts/create-mr.sh +117 -0
- package/templates/pi/scripts/fetch-issues.sh +131 -0
- package/templates/pi/scripts/generate-architecture.sh +161 -0
- package/templates/pi/scripts/git/close-epic.sh +69 -0
- package/templates/pi/scripts/git/close-issue.sh +35 -0
- package/templates/pi/scripts/git/create-tracking-issue.sh +174 -0
- package/templates/pi/scripts/git/link-issue-to-epic.sh +51 -0
- package/templates/pi/scripts/git/update-tracking-issue.sh +66 -0
- package/templates/pi/scripts/languages/go/validate-architecture.sh +139 -0
- package/templates/pi/scripts/languages/go/validate-canonical.sh +129 -0
- package/templates/pi/scripts/languages/go/validate-ci.sh +132 -0
- package/templates/pi/scripts/languages/go/validate-integration.sh +156 -0
- package/templates/pi/scripts/languages/go/validate-operations.sh +146 -0
- package/templates/pi/scripts/languages/go/validate-security.sh +135 -0
- package/templates/pi/scripts/languages/go/validate-tests.sh +125 -0
- package/templates/pi/scripts/languages/java/validate-annotations.sh +185 -0
- package/templates/pi/scripts/languages/java/validate-architecture.sh +159 -0
- package/templates/pi/scripts/languages/java/validate-canonical.sh +114 -0
- package/templates/pi/scripts/languages/java/validate-ci.sh +269 -0
- package/templates/pi/scripts/languages/java/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/java/validate-operations.sh +142 -0
- package/templates/pi/scripts/languages/java/validate-security.sh +174 -0
- package/templates/pi/scripts/languages/java/validate-spring-architecture.sh +227 -0
- package/templates/pi/scripts/languages/java/validate-tests.sh +159 -0
- package/templates/pi/scripts/languages/python/validate-architecture.sh +99 -0
- package/templates/pi/scripts/languages/python/validate-canonical.sh +124 -0
- package/templates/pi/scripts/languages/python/validate-ci.sh +130 -0
- package/templates/pi/scripts/languages/python/validate-integration.sh +119 -0
- package/templates/pi/scripts/languages/python/validate-operations.sh +107 -0
- package/templates/pi/scripts/languages/python/validate-security.sh +68 -0
- package/templates/pi/scripts/languages/python/validate-tests.sh +102 -0
- package/templates/pi/scripts/languages/rust/validate-architecture.sh +188 -0
- package/templates/pi/scripts/languages/rust/validate-canonical.sh +146 -0
- package/templates/pi/scripts/languages/rust/validate-ci.sh +147 -0
- package/templates/pi/scripts/languages/rust/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/rust/validate-operations.sh +154 -0
- package/templates/pi/scripts/languages/rust/validate-security.sh +153 -0
- package/templates/pi/scripts/languages/rust/validate-tests.sh +150 -0
- package/templates/pi/scripts/languages/typescript/validate-architecture.sh +157 -0
- package/templates/pi/scripts/languages/typescript/validate-canonical.sh +135 -0
- package/templates/pi/scripts/languages/typescript/validate-ci.sh +244 -0
- package/templates/pi/scripts/languages/typescript/validate-integration.sh +166 -0
- package/templates/pi/scripts/languages/typescript/validate-operations.sh +162 -0
- package/templates/pi/scripts/languages/typescript/validate-security.sh +169 -0
- package/templates/pi/scripts/languages/typescript/validate-tests.sh +158 -0
- package/templates/pi/scripts/merge-mr.sh +95 -0
- package/templates/pi/scripts/mr-validation.sh +228 -0
- package/templates/pi/scripts/validate-architecture-readiness.sh +153 -0
- package/templates/pi/scripts/validate-architecture.sh +22 -0
- package/templates/pi/scripts/validate-canonical.sh +22 -0
- package/templates/pi/scripts/validate-ci.sh +37 -0
- package/templates/pi/scripts/validate-integration.sh +22 -0
- package/templates/pi/scripts/validate-operations.sh +22 -0
- package/templates/pi/scripts/validate-security.sh +22 -0
- package/templates/pi/scripts/validate-tests.sh +22 -0
- package/templates/pi/scripts/validate-ubiquitous-language.sh +291 -0
- package/templates/pi/scripts/validation-cache.sh +139 -0
- package/templates/pi/skills/agents/architecture-coordinator.md +178 -0
- package/templates/pi/skills/agents/architecture-generator.md +79 -0
- package/templates/pi/skills/agents/architecture-validator.md +74 -0
- package/templates/pi/skills/agents/ci-mr-validator.md +46 -0
- package/templates/pi/skills/agents/code-developer.md +76 -0
- package/templates/pi/skills/agents/commit.md +46 -0
- package/templates/pi/skills/agents/curator.md +71 -0
- package/templates/pi/skills/agents/debug.md +59 -0
- package/templates/pi/skills/agents/documentation-maintainer.md +36 -0
- package/templates/pi/skills/agents/goal-loop.md +125 -0
- package/templates/pi/skills/agents/hooks.md +122 -0
- package/templates/pi/skills/agents/integration-validator.md +35 -0
- package/templates/pi/skills/agents/issue-creator.md +75 -0
- package/templates/pi/skills/agents/issue-factory.md +143 -0
- package/templates/pi/skills/agents/kanban.md +85 -0
- package/templates/pi/skills/agents/land.md +59 -0
- package/templates/pi/skills/agents/operations-validator.md +43 -0
- package/templates/pi/skills/agents/pipeline.md +113 -0
- package/templates/pi/skills/agents/plan-mode.md +77 -0
- package/templates/pi/skills/agents/pull.md +40 -0
- package/templates/pi/skills/agents/push.md +41 -0
- package/templates/pi/skills/agents/security-validator.md +85 -0
- package/templates/pi/skills/agents/session-persistence.md +119 -0
- package/templates/pi/skills/agents/slash-commands.md +117 -0
- package/templates/pi/skills/agents/snippets.md +99 -0
- package/templates/pi/skills/agents/subagent-registry.md +78 -0
- package/templates/pi/skills/agents/test-validator.md +42 -0
- package/templates/pi/skills/validators/architecture-validator.md +43 -0
- package/templates/pi/skills/validators/ci-validator.md +27 -0
- package/templates/pi/skills/validators/context-compaction.md +73 -0
- package/templates/pi/skills/validators/integration-validator.md +38 -0
- package/templates/pi/skills/validators/model-registry.md +96 -0
- package/templates/pi/skills/validators/operations-validator.md +34 -0
- package/templates/pi/skills/validators/security-guards.md +72 -0
- package/templates/pi/skills/validators/security-validator.md +41 -0
- package/templates/pi/skills/validators/system-prompt-tiers.md +69 -0
- package/templates/pi/skills/validators/test-validator.md +33 -0
- package/templates/pi/types.ts +62 -0
- package/templates/pi/validators/README.md +93 -0
- package/templates/pi/validators/default.toml +209 -0
- package/templates/pi/validators/spring.toml +142 -0
- package/templates/pi/workpad.md +53 -0
- package/templates/project/java/Dockerfile +14 -0
- package/templates/project/java/README.md +40 -0
- package/templates/project/java/pom.xml +132 -0
- package/templates/project/typescript/Dockerfile +15 -0
- package/templates/project/typescript/README.md +29 -0
- package/templates/project/typescript/package.json +23 -0
- package/templates/project/typescript/tsconfig.json +21 -0
- package/templates/workflow.md +123 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stage 4: Static Analysis
|
|
3
|
+
#
|
|
4
|
+
# Verifies:
|
|
5
|
+
# - Type checking (mypy/tsc/cargo check/go vet)
|
|
6
|
+
# - Import boundary checks
|
|
7
|
+
# - Architecture sanity checks
|
|
8
|
+
# - Settings/env collision checks
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
FAIL=0
|
|
13
|
+
PASS=0
|
|
14
|
+
|
|
15
|
+
log_pass() { echo " ✓ PASS: $1"; ((PASS++)); }
|
|
16
|
+
log_fail() { echo " ✗ FAIL: $1 — $2"; ((FAIL++)); }
|
|
17
|
+
|
|
18
|
+
echo " Running static analysis..."
|
|
19
|
+
|
|
20
|
+
# Type checking
|
|
21
|
+
echo " Type checking..."
|
|
22
|
+
if command -v mypy &>/dev/null && [[ -d "app" ]]; then
|
|
23
|
+
if mypy app --ignore-missing-imports 2>/dev/null; then
|
|
24
|
+
log_pass "mypy type check"
|
|
25
|
+
else
|
|
26
|
+
log_fail "mypy type check" "Type errors found"
|
|
27
|
+
fi
|
|
28
|
+
elif command -v tsc &>/dev/null && [[ -f "tsconfig.json" ]]; then
|
|
29
|
+
if tsc --noEmit 2>/dev/null; then
|
|
30
|
+
log_pass "tsc type check"
|
|
31
|
+
else
|
|
32
|
+
log_fail "tsc type check" "Type errors found"
|
|
33
|
+
fi
|
|
34
|
+
elif command -v cargo &>/dev/null && [[ -f "Cargo.toml" ]]; then
|
|
35
|
+
if cargo check 2>/dev/null; then
|
|
36
|
+
log_pass "cargo check"
|
|
37
|
+
else
|
|
38
|
+
log_fail "cargo check" "Compilation errors"
|
|
39
|
+
fi
|
|
40
|
+
elif command -v go &>/dev/null && [[ -f "go.mod" ]]; then
|
|
41
|
+
if go vet ./... 2>/dev/null; then
|
|
42
|
+
log_pass "go vet"
|
|
43
|
+
else
|
|
44
|
+
log_fail "go vet" "Vet errors found"
|
|
45
|
+
fi
|
|
46
|
+
else
|
|
47
|
+
echo " No type checker found, skipping."
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Import boundary checks
|
|
51
|
+
echo " Checking import boundaries..."
|
|
52
|
+
if [[ -f ".pi/scripts/ci/check_import_boundaries.py" ]]; then
|
|
53
|
+
if python3 ".pi/scripts/ci/check_import_boundaries.py" 2>/dev/null; then
|
|
54
|
+
log_pass "import boundary check"
|
|
55
|
+
else
|
|
56
|
+
log_fail "import boundary check" "Boundary violations found"
|
|
57
|
+
fi
|
|
58
|
+
else
|
|
59
|
+
# Basic check: no domain→infrastructure imports
|
|
60
|
+
violations=0
|
|
61
|
+
if [[ -d "app/domain" ]]; then
|
|
62
|
+
while IFS= read -r file; do
|
|
63
|
+
if grep -qE "from.*infrastructure|from.*api|import.*infrastructure" "$file" 2>/dev/null; then
|
|
64
|
+
((violations++))
|
|
65
|
+
log_fail "import boundary" "$(basename "$file") imports from infrastructure/api"
|
|
66
|
+
fi
|
|
67
|
+
done < <(find app/domain -name "*.py" 2>/dev/null)
|
|
68
|
+
fi
|
|
69
|
+
if [[ $violations -eq 0 ]]; then
|
|
70
|
+
log_pass "import boundary check (no cross-layer violations)"
|
|
71
|
+
fi
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Architecture sanity
|
|
75
|
+
echo " Running architecture sanity checks..."
|
|
76
|
+
if [[ -f ".pi/scripts/ci/check_arch_sanity.py" ]]; then
|
|
77
|
+
if python3 ".pi/scripts/ci/check_arch_sanity.py" 2>/dev/null; then
|
|
78
|
+
log_pass "architecture sanity"
|
|
79
|
+
else
|
|
80
|
+
log_fail "architecture sanity" "Sanity checks failed"
|
|
81
|
+
fi
|
|
82
|
+
else
|
|
83
|
+
log_pass "architecture sanity (no script found, skipping)"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Settings/env collision
|
|
87
|
+
echo " Checking settings/env collision..."
|
|
88
|
+
if [[ -f ".env.example" && -f ".env" ]]; then
|
|
89
|
+
collisions=0
|
|
90
|
+
while IFS= read -r line; do
|
|
91
|
+
var_name=$(echo "$line" | cut -d= -f1)
|
|
92
|
+
if [[ -n "$var_name" && "$var_name" != \#* ]]; then
|
|
93
|
+
example_val=$(grep "^${var_name}=" ".env.example" 2>/dev/null | cut -d= -f2-)
|
|
94
|
+
actual_val=$(grep "^${var_name}=" ".env" 2>/dev/null | cut -d= -f2-)
|
|
95
|
+
if [[ "$example_val" == "$actual_val" && -n "$example_val" ]]; then
|
|
96
|
+
((collisions++))
|
|
97
|
+
log_fail "env collision" "${var_name} in .env matches .env.example value"
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
100
|
+
done < <(grep -v "^#" ".env.example" 2>/dev/null | grep "=" || true)
|
|
101
|
+
if [[ $collisions -eq 0 ]]; then
|
|
102
|
+
log_pass "settings/env collision check (no collisions)"
|
|
103
|
+
fi
|
|
104
|
+
else
|
|
105
|
+
log_pass "settings/env collision check (no .env files)"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [[ $FAIL -gt 0 ]]; then
|
|
109
|
+
echo " Static analysis FAILED (${FAIL} failure(s))"
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
echo " Static analysis passed (${PASS} check(s))"
|
|
114
|
+
exit 0
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stage 5: Unit Tests
|
|
3
|
+
#
|
|
4
|
+
# Verifies:
|
|
5
|
+
# - Domain tests
|
|
6
|
+
# - Application tests
|
|
7
|
+
# - Contract tests
|
|
8
|
+
# - Verification tests
|
|
9
|
+
# - Coverage threshold check
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
FAIL=0
|
|
14
|
+
PASS=0
|
|
15
|
+
COVERAGE_PCT=0
|
|
16
|
+
|
|
17
|
+
log_pass() { echo " ✓ PASS: $1"; ((PASS++)); }
|
|
18
|
+
log_fail() { echo " ✗ FAIL: $1 — $2"; ((FAIL++)); }
|
|
19
|
+
|
|
20
|
+
echo " Running unit tests..."
|
|
21
|
+
|
|
22
|
+
if command -v pytest &>/dev/null; then
|
|
23
|
+
# Domain tests
|
|
24
|
+
if [[ -d "tests/unit/domain" ]]; then
|
|
25
|
+
if pytest tests/unit/domain -v 2>/dev/null; then
|
|
26
|
+
log_pass "unit: domain tests"
|
|
27
|
+
else
|
|
28
|
+
log_fail "unit: domain tests" "Domain test failures"
|
|
29
|
+
fi
|
|
30
|
+
else
|
|
31
|
+
log_pass "unit: domain tests (no domain tests found)"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Application tests
|
|
35
|
+
if [[ -d "tests/unit/application" ]]; then
|
|
36
|
+
if pytest tests/unit/application -v 2>/dev/null; then
|
|
37
|
+
log_pass "unit: application tests"
|
|
38
|
+
else
|
|
39
|
+
log_fail "unit: application tests" "Application test failures"
|
|
40
|
+
fi
|
|
41
|
+
else
|
|
42
|
+
log_pass "unit: application tests (no application tests found)"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Contract tests
|
|
46
|
+
if [[ -d "tests/contract" ]]; then
|
|
47
|
+
if pytest tests/contract -v 2>/dev/null; then
|
|
48
|
+
log_pass "unit: contract tests"
|
|
49
|
+
else
|
|
50
|
+
log_fail "unit: contract tests" "Contract test failures"
|
|
51
|
+
fi
|
|
52
|
+
else
|
|
53
|
+
log_pass "unit: contract tests (no contract tests found)"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Verification tests
|
|
57
|
+
if [[ -d "tests/verification" ]]; then
|
|
58
|
+
if pytest tests/verification -v 2>/dev/null; then
|
|
59
|
+
log_pass "unit: verification tests"
|
|
60
|
+
else
|
|
61
|
+
log_fail "unit: verification tests" "Verification test failures"
|
|
62
|
+
fi
|
|
63
|
+
else
|
|
64
|
+
log_pass "unit: verification tests (no verification tests found)"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Coverage threshold check
|
|
68
|
+
echo " Checking coverage threshold..."
|
|
69
|
+
if [[ -f ".pi/scripts/ci/check_coverage_thresholds.py" ]]; then
|
|
70
|
+
if python3 ".pi/scripts/ci/check_coverage_thresholds.py" 2>/dev/null; then
|
|
71
|
+
log_pass "coverage threshold check"
|
|
72
|
+
else
|
|
73
|
+
log_fail "coverage threshold check" "Coverage below threshold"
|
|
74
|
+
fi
|
|
75
|
+
else
|
|
76
|
+
# Basic coverage check
|
|
77
|
+
coverage_file="coverage.xml"
|
|
78
|
+
if [[ -f "$coverage_file" ]]; then
|
|
79
|
+
COVERAGE_PCT=$(grep -oP 'line-rate="[^"]*"' "$coverage_file" 2>/dev/null | head -1 | cut -d'"' -f2 || echo "0")
|
|
80
|
+
threshold="${COVERAGE_THRESHOLD:-80}"
|
|
81
|
+
COVERAGE_INT=$(echo "$COVERAGE_PCT * 100" | bc 2>/dev/null || echo "0")
|
|
82
|
+
if [[ $COVERAGE_INT -ge $threshold ]]; then
|
|
83
|
+
log_pass "coverage threshold (${COVERAGE_PCT} >= ${threshold}%)"
|
|
84
|
+
else
|
|
85
|
+
log_fail "coverage threshold" "${COVERAGE_PCT} < ${threshold}%"
|
|
86
|
+
fi
|
|
87
|
+
else
|
|
88
|
+
log_pass "coverage threshold check (no coverage file found)"
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
elif command -v bun &>/dev/null && [[ -f "package.json" ]]; then
|
|
92
|
+
if bun test 2>/dev/null; then
|
|
93
|
+
log_pass "unit: all tests (bun)"
|
|
94
|
+
else
|
|
95
|
+
log_fail "unit: all tests (bun)" "Test failures"
|
|
96
|
+
fi
|
|
97
|
+
elif command -v cargo &>/dev/null && [[ -f "Cargo.toml" ]]; then
|
|
98
|
+
if cargo test 2>/dev/null; then
|
|
99
|
+
log_pass "unit: all tests (cargo)"
|
|
100
|
+
else
|
|
101
|
+
log_fail "unit: all tests (cargo)" "Test failures"
|
|
102
|
+
fi
|
|
103
|
+
elif command -v go &>/dev/null && [[ -f "go.mod" ]]; then
|
|
104
|
+
if go test ./... 2>/dev/null; then
|
|
105
|
+
log_pass "unit: all tests (go)"
|
|
106
|
+
else
|
|
107
|
+
log_fail "unit: all tests (go)" "Test failures"
|
|
108
|
+
fi
|
|
109
|
+
else
|
|
110
|
+
echo " No test runner found, skipping unit tests."
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ $FAIL -gt 0 ]]; then
|
|
114
|
+
echo " Unit test stage FAILED (${FAIL} failure(s))"
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
echo " Unit test stage passed (${PASS} check(s))"
|
|
119
|
+
exit 0
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate agent output schema compliance.
|
|
3
|
+
|
|
4
|
+
Validates that agent-generated outputs conform to expected schemas per agent role.
|
|
5
|
+
Checks required sections, contradiction patterns, and structural consistency.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python scripts/ci/validate_agent_output.py --input=output.md
|
|
9
|
+
python scripts/ci/validate_agent_output.py --input=output.md --schema=architecture-validator
|
|
10
|
+
python scripts/ci/validate_agent_output.py --input=output.md --json
|
|
11
|
+
|
|
12
|
+
Exit codes:
|
|
13
|
+
0 - Output is valid
|
|
14
|
+
1 - Validation errors found
|
|
15
|
+
2 - Script error
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
SCHEMAS: dict[str, dict] = {
|
|
28
|
+
"architecture-validator": {
|
|
29
|
+
"required_sections": [
|
|
30
|
+
"## Decision",
|
|
31
|
+
"## Blocking findings",
|
|
32
|
+
"## Non-blocking recommendations",
|
|
33
|
+
"## Section reference verification",
|
|
34
|
+
"## Acceptance criteria verification",
|
|
35
|
+
],
|
|
36
|
+
"contradiction_checks": [
|
|
37
|
+
{
|
|
38
|
+
"pattern1": r"## Decision\s*\n\s*-\s*`?pass`?",
|
|
39
|
+
"pattern2": r"## Non-blocking recommendations\s*\n\s*-",
|
|
40
|
+
"message": "Decision is 'pass' but recommendations exist (should be 'pass_with_recommendations')",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
"epic-plan": {
|
|
45
|
+
"required_sections": [
|
|
46
|
+
"## Stream classification",
|
|
47
|
+
"## Scope summary",
|
|
48
|
+
"## In scope",
|
|
49
|
+
"## Out of scope",
|
|
50
|
+
"## Impacted layers",
|
|
51
|
+
"## Risk classification",
|
|
52
|
+
"## Dependency graph",
|
|
53
|
+
"## Mandatory validators",
|
|
54
|
+
"## Mandatory CI gates",
|
|
55
|
+
"## Forbidden shortcuts",
|
|
56
|
+
"## First implementation issue recommendation",
|
|
57
|
+
],
|
|
58
|
+
"contradiction_checks": [],
|
|
59
|
+
},
|
|
60
|
+
"issue-draft": {
|
|
61
|
+
"required_sections": [
|
|
62
|
+
"## Why",
|
|
63
|
+
"## Scope",
|
|
64
|
+
"## In scope",
|
|
65
|
+
"## Out of scope",
|
|
66
|
+
"## Dependencies",
|
|
67
|
+
"## Acceptance criteria",
|
|
68
|
+
"## Verification",
|
|
69
|
+
"## Canonical references",
|
|
70
|
+
],
|
|
71
|
+
"contradiction_checks": [],
|
|
72
|
+
},
|
|
73
|
+
"implementation-report": {
|
|
74
|
+
"required_sections": [
|
|
75
|
+
"## Readiness check",
|
|
76
|
+
"## Acceptance criteria trace map",
|
|
77
|
+
"## Files changed",
|
|
78
|
+
"## Tests and CI impacts",
|
|
79
|
+
"## Toolchain validation",
|
|
80
|
+
"## Done / not done against acceptance criteria",
|
|
81
|
+
],
|
|
82
|
+
"contradiction_checks": [],
|
|
83
|
+
},
|
|
84
|
+
"generic": {
|
|
85
|
+
"required_sections": ["## Summary"],
|
|
86
|
+
"contradiction_checks": [],
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def extract_section(content: str, heading: str) -> str:
|
|
92
|
+
pattern = re.compile(rf"^{re.escape(heading)}\s*$", re.MULTILINE)
|
|
93
|
+
match = pattern.search(content)
|
|
94
|
+
if not match:
|
|
95
|
+
return ""
|
|
96
|
+
start = match.end()
|
|
97
|
+
next_heading = re.search(r"^##\s+", content[start:], re.MULTILINE)
|
|
98
|
+
end = start + next_heading.start() if next_heading else len(content)
|
|
99
|
+
return content[start:end].strip()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def check_contradictions(content: str, checks: list[dict]) -> list[dict]:
|
|
103
|
+
results: list[dict] = []
|
|
104
|
+
for check in checks:
|
|
105
|
+
has_p1 = bool(re.search(check["pattern1"], content, re.MULTILINE))
|
|
106
|
+
has_p2 = bool(re.search(check["pattern2"], content, re.MULTILINE))
|
|
107
|
+
if has_p1 and has_p2:
|
|
108
|
+
results.append({
|
|
109
|
+
"check": "contradiction",
|
|
110
|
+
"status": "fail",
|
|
111
|
+
"message": check["message"],
|
|
112
|
+
})
|
|
113
|
+
else:
|
|
114
|
+
results.append({
|
|
115
|
+
"check": f"contradiction: {check['message'][:40]}",
|
|
116
|
+
"status": "pass",
|
|
117
|
+
})
|
|
118
|
+
return results
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main() -> int:
|
|
122
|
+
parser = argparse.ArgumentParser(description="Validate agent output schema compliance")
|
|
123
|
+
parser.add_argument("--input", required=True, help="Path to agent output markdown")
|
|
124
|
+
parser.add_argument("--schema", default="generic", help="Schema to validate against")
|
|
125
|
+
parser.add_argument("--json", action="store_true", help="Emit JSON output")
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
input_path = Path(args.input)
|
|
129
|
+
if not input_path.exists():
|
|
130
|
+
print(f"Error: Input file not found: {args.input}", file=sys.stderr)
|
|
131
|
+
return 2
|
|
132
|
+
|
|
133
|
+
content = input_path.read_text(encoding="utf-8")
|
|
134
|
+
schema = SCHEMAS.get(args.schema, SCHEMAS["generic"])
|
|
135
|
+
all_checks: list[dict] = []
|
|
136
|
+
|
|
137
|
+
# Check required sections
|
|
138
|
+
for section in schema["required_sections"]:
|
|
139
|
+
if section in content:
|
|
140
|
+
all_checks.append({"check": f"section:{section}", "status": "pass"})
|
|
141
|
+
else:
|
|
142
|
+
all_checks.append({
|
|
143
|
+
"check": f"section:{section}",
|
|
144
|
+
"status": "fail",
|
|
145
|
+
"message": f"Missing required section: {section}",
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
# Check contradictions
|
|
149
|
+
contradiction_results = check_contradictions(content, schema["contradiction_checks"])
|
|
150
|
+
all_checks.extend(contradiction_results)
|
|
151
|
+
|
|
152
|
+
# Summary
|
|
153
|
+
passed = sum(1 for c in all_checks if c["status"] == "pass")
|
|
154
|
+
failed = sum(1 for c in all_checks if c["status"] == "fail")
|
|
155
|
+
|
|
156
|
+
if args.json:
|
|
157
|
+
output = {
|
|
158
|
+
"input": str(input_path),
|
|
159
|
+
"schema": args.schema,
|
|
160
|
+
"timestamp": __import__("datetime").datetime.utcnow().isoformat() + "Z",
|
|
161
|
+
"summary": {"total": len(all_checks), "passed": passed, "failed": failed},
|
|
162
|
+
"checks": all_checks,
|
|
163
|
+
"status": "pass" if failed == 0 else "fail",
|
|
164
|
+
}
|
|
165
|
+
print(json.dumps(output, indent=2))
|
|
166
|
+
else:
|
|
167
|
+
print(f"\nAgent Output Validation ({args.schema}): {args.input}")
|
|
168
|
+
print(f"{'='*50}")
|
|
169
|
+
for check in all_checks:
|
|
170
|
+
icon = "PASS" if check["status"] == "pass" else "FAIL"
|
|
171
|
+
print(f" [{icon}] {check['check']}")
|
|
172
|
+
if check["status"] == "fail" and "message" in check:
|
|
173
|
+
print(f" {check['message']}")
|
|
174
|
+
print(f"\nSummary: {passed} passed, {failed} failed, {len(all_checks)} total")
|
|
175
|
+
print(f"Result: {'VALID' if failed == 0 else 'INVALID'}")
|
|
176
|
+
|
|
177
|
+
return 0 if failed == 0 else 1
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
if __name__ == "__main__":
|
|
181
|
+
sys.exit(main())
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Guardian — Agent Output Validator
|
|
3
|
+
#
|
|
4
|
+
# Validates agent-generated output for schema compliance, consistency, and completeness.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# bash validate_agent_output.sh --input=output.md --schema=architecture-validator
|
|
8
|
+
# bash validate_agent_output.sh --input=output.md --json
|
|
9
|
+
# bash validate_agent_output.sh --input=output.md --no-coverage
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
INPUT=""
|
|
14
|
+
SCHEMA="generic"
|
|
15
|
+
JSON=false
|
|
16
|
+
NO_COVERAGE=false
|
|
17
|
+
|
|
18
|
+
# Colors
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
NC='\033[0m'
|
|
23
|
+
|
|
24
|
+
CHECKS_PASSED=0
|
|
25
|
+
CHECKS_FAILED=0
|
|
26
|
+
RESULTS=()
|
|
27
|
+
|
|
28
|
+
while [[ $# -gt 0 ]]; do
|
|
29
|
+
case $1 in
|
|
30
|
+
--input) INPUT="$2"; shift 2 ;;
|
|
31
|
+
--schema) SCHEMA="$2"; shift 2 ;;
|
|
32
|
+
--json) JSON=true; shift ;;
|
|
33
|
+
--no-coverage) NO_COVERAGE=true; shift ;;
|
|
34
|
+
*) shift ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [[ -z "$INPUT" || ! -f "$INPUT" ]]; then
|
|
39
|
+
echo "Error: --input <file> is required"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
CONTENT=$(cat "$INPUT")
|
|
44
|
+
|
|
45
|
+
# ── Validation Functions ──
|
|
46
|
+
|
|
47
|
+
check_section_present() {
|
|
48
|
+
local section="$1"
|
|
49
|
+
if echo "$CONTENT" | grep -qi "$section"; then
|
|
50
|
+
RESULTS+=("{\"check\": \"$section\", \"status\": \"pass\"}")
|
|
51
|
+
((CHECKS_PASSED++))
|
|
52
|
+
if [[ "$JSON" == "false" ]]; then
|
|
53
|
+
echo -e " ${GREEN}✓${NC} Section present: $section"
|
|
54
|
+
fi
|
|
55
|
+
else
|
|
56
|
+
RESULTS+=("{\"check\": \"$section\", \"status\": \"fail\", \"message\": \"Section '$section' not found\"}")
|
|
57
|
+
((CHECKS_FAILED++))
|
|
58
|
+
if [[ "$JSON" == "false" ]]; then
|
|
59
|
+
echo -e " ${RED}✗${NC} Missing section: $section"
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
check_no_contradictions() {
|
|
65
|
+
# Check for common contradiction patterns
|
|
66
|
+
local contradictions=0
|
|
67
|
+
|
|
68
|
+
# Check for "must not" followed by "must" about the same topic
|
|
69
|
+
while IFS= read -r line; do
|
|
70
|
+
topic=$(echo "$line" | grep -oP '^\s*[-*]\s+\*\*[^*]+\*\*' | head -1 || echo "")
|
|
71
|
+
if [[ -n "$topic" ]]; then
|
|
72
|
+
# Count must/must not for this topic
|
|
73
|
+
must_count=$(echo "$CONTENT" | grep -ci "${topic}.*must " || echo 0)
|
|
74
|
+
must_not_count=$(echo "$CONTENT" | grep -ci "${topic}.*must not\|${topic}.*must not " || echo 0)
|
|
75
|
+
if [[ $must_count -gt 0 && $must_not_count -gt 0 ]]; then
|
|
76
|
+
((contradictions++))
|
|
77
|
+
fi
|
|
78
|
+
fi
|
|
79
|
+
done < <(echo "$CONTENT" | grep -E "^\s*[-*]\s+\*\*" || true)
|
|
80
|
+
|
|
81
|
+
if [[ $contradictions -eq 0 ]]; then
|
|
82
|
+
RESULTS+=("{\"check\": \"no_contradictions\", \"status\": \"pass\"}")
|
|
83
|
+
((CHECKS_PASSED++))
|
|
84
|
+
if [[ "$JSON" == "false" ]]; then
|
|
85
|
+
echo -e " ${GREEN}✓${NC} No internal contradictions"
|
|
86
|
+
fi
|
|
87
|
+
else
|
|
88
|
+
RESULTS+=("{\"check\": \"no_contradictions\", \"status\": \"fail\", \"message\": \"Found $contradictions contradictions\"}")
|
|
89
|
+
((CHECKS_FAILED++))
|
|
90
|
+
if [[ "$JSON" == "false" ]]; then
|
|
91
|
+
echo -e " ${RED}✗${NC} Found $contradictions contradictions"
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
check_decision_consistency() {
|
|
97
|
+
# Check that all decisions have supporting evidence
|
|
98
|
+
local decisions=$(echo "$CONTENT" | grep -ci "decision\|recommendation\|conclusion" || echo 0)
|
|
99
|
+
local evidence=$(echo "$CONTENT" | grep -ci "evidence\|because\|reason\|rationale\|justification" || echo 0)
|
|
100
|
+
|
|
101
|
+
if [[ $decisions -eq 0 ]] || [[ $evidence -gt 0 ]]; then
|
|
102
|
+
RESULTS+=("{\"check\": \"decision_consistency\", \"status\": \"pass\"}")
|
|
103
|
+
((CHECKS_PASSED++))
|
|
104
|
+
if [[ "$JSON" == "false" ]]; then
|
|
105
|
+
echo -e " ${GREEN}✓${NC} Decision consistency"
|
|
106
|
+
fi
|
|
107
|
+
else
|
|
108
|
+
RESULTS+=("{\"check\": \"decision_consistency\", \"status\": \"fail\", \"message\": \"Decisions without supporting evidence\"}")
|
|
109
|
+
((CHECKS_FAILED++))
|
|
110
|
+
if [[ "$JSON" == "false" ]]; then
|
|
111
|
+
echo -e " ${RED}✗${NC} Decisions without supporting evidence"
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
check_acceptance_criteria() {
|
|
117
|
+
# Check that acceptance criteria are present and evaluable
|
|
118
|
+
local has_criteria=$(echo "$CONTENT" | grep -ci "acceptance criteria\|criteria\|must\|should\|required" || echo 0)
|
|
119
|
+
local has_checklist=$(echo "$CONTENT" | grep -c "\- \[ \]" || echo 0)
|
|
120
|
+
|
|
121
|
+
if [[ $has_criteria -gt 0 ]]; then
|
|
122
|
+
RESULTS+=("{\"check\": \"acceptance_criteria\", \"status\": \"pass\"}")
|
|
123
|
+
((CHECKS_PASSED++))
|
|
124
|
+
if [[ "$JSON" == "false" ]]; then
|
|
125
|
+
echo -e " ${GREEN}✓${NC} Acceptance criteria present"
|
|
126
|
+
fi
|
|
127
|
+
else
|
|
128
|
+
RESULTS+=("{\"check\": \"acceptance_criteria\", \"status\": \"fail\", \"message\": \"No acceptance criteria found\"}")
|
|
129
|
+
((CHECKS_FAILED++))
|
|
130
|
+
if [[ "$JSON" == "false" ]]; then
|
|
131
|
+
echo -e " ${RED}✗${NC} No acceptance criteria found"
|
|
132
|
+
fi
|
|
133
|
+
fi
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
check_canonical_references() {
|
|
137
|
+
local has_refs=$(echo "$CONTENT" | grep -c "Canonical Reference\|canonical.*reference\|\.pi/architecture" || echo 0)
|
|
138
|
+
|
|
139
|
+
if [[ $has_refs -gt 0 ]]; then
|
|
140
|
+
RESULTS+=("{\"check\": \"canonical_references\", \"status\": \"pass\"}")
|
|
141
|
+
((CHECKS_PASSED++))
|
|
142
|
+
if [[ "$JSON" == "false" ]]; then
|
|
143
|
+
echo -e " ${GREEN}✓${NC} Canonical references present"
|
|
144
|
+
fi
|
|
145
|
+
else
|
|
146
|
+
RESULTS+=("{\"check\": \"canonical_references\", \"status\": \"fail\", \"message\": \"No canonical references found\"}")
|
|
147
|
+
((CHECKS_FAILED++))
|
|
148
|
+
if [[ "$JSON" == "false" ]]; then
|
|
149
|
+
echo -e " ${RED}✗${NC} No canonical references found"
|
|
150
|
+
fi
|
|
151
|
+
fi
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
# ── Schema-Specific Checks ──
|
|
155
|
+
|
|
156
|
+
case "$SCHEMA" in
|
|
157
|
+
architecture-validator)
|
|
158
|
+
check_section_present "## Summary"
|
|
159
|
+
check_section_present "## Findings"
|
|
160
|
+
check_section_present "## Recommendations"
|
|
161
|
+
check_section_present "## Acceptance Criteria"
|
|
162
|
+
check_section_present "## Canonical References"
|
|
163
|
+
check_no_contradictions
|
|
164
|
+
check_decision_consistency
|
|
165
|
+
check_acceptance_criteria
|
|
166
|
+
check_canonical_references
|
|
167
|
+
;;
|
|
168
|
+
|
|
169
|
+
epic-plan)
|
|
170
|
+
check_section_present "## Why"
|
|
171
|
+
check_section_present "## Target Outcome"
|
|
172
|
+
check_section_present "## Scope"
|
|
173
|
+
check_section_present "## In Scope"
|
|
174
|
+
check_section_present "## Out of Scope"
|
|
175
|
+
check_section_present "## Impacted Layers"
|
|
176
|
+
check_section_present "## Architecture Constraints"
|
|
177
|
+
check_section_present "## Dependency Map"
|
|
178
|
+
check_section_present "## Canonical References"
|
|
179
|
+
check_acceptance_criteria
|
|
180
|
+
check_canonical_references
|
|
181
|
+
;;
|
|
182
|
+
|
|
183
|
+
issue-draft)
|
|
184
|
+
check_section_present "## Intent"
|
|
185
|
+
check_section_present "## Scope"
|
|
186
|
+
check_section_present "## In Scope"
|
|
187
|
+
check_section_present "## Out of Scope"
|
|
188
|
+
check_section_present "## Dependencies"
|
|
189
|
+
check_section_present "## Acceptance Criteria"
|
|
190
|
+
check_section_present "## Canonical References"
|
|
191
|
+
check_acceptance_criteria
|
|
192
|
+
check_canonical_references
|
|
193
|
+
;;
|
|
194
|
+
|
|
195
|
+
*)
|
|
196
|
+
# Generic validation
|
|
197
|
+
check_section_present "## Summary"
|
|
198
|
+
check_no_contradictions
|
|
199
|
+
check_decision_consistency
|
|
200
|
+
check_acceptance_criteria
|
|
201
|
+
;;
|
|
202
|
+
esac
|
|
203
|
+
|
|
204
|
+
# ── Summary ──
|
|
205
|
+
|
|
206
|
+
TOTAL=$((CHECKS_PASSED + CHECKS_FAILED))
|
|
207
|
+
|
|
208
|
+
if [[ "$JSON" == "true" ]]; then
|
|
209
|
+
RESULTS_JSON=$(printf '%s\n' "${RESULTS[@]}" | jq -s .)
|
|
210
|
+
cat << EOF
|
|
211
|
+
{
|
|
212
|
+
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
213
|
+
"input": "$INPUT",
|
|
214
|
+
"schema": "$SCHEMA",
|
|
215
|
+
"summary": {
|
|
216
|
+
"total": $TOTAL,
|
|
217
|
+
"passed": $CHECKS_PASSED,
|
|
218
|
+
"failed": $CHECKS_FAILED
|
|
219
|
+
},
|
|
220
|
+
"checks": ${RESULTS_JSON},
|
|
221
|
+
"status": "$([ $CHECKS_FAILED -gt 0 ] && echo "fail" || echo "pass")"
|
|
222
|
+
}
|
|
223
|
+
EOF
|
|
224
|
+
else
|
|
225
|
+
echo ""
|
|
226
|
+
echo "================================"
|
|
227
|
+
echo "AGENT OUTPUT VALIDATION SUMMARY"
|
|
228
|
+
echo "================================"
|
|
229
|
+
echo "Input: $INPUT"
|
|
230
|
+
echo "Schema: $SCHEMA"
|
|
231
|
+
echo "Total checks: $TOTAL"
|
|
232
|
+
echo -e "Passed: ${GREEN}${CHECKS_PASSED}${NC}"
|
|
233
|
+
echo -e "Failed: ${RED}${CHECKS_FAILED}${NC}"
|
|
234
|
+
echo "================================"
|
|
235
|
+
|
|
236
|
+
if [[ $CHECKS_FAILED -eq 0 ]]; then
|
|
237
|
+
echo -e "${GREEN}✅ Agent output validation passed${NC}"
|
|
238
|
+
else
|
|
239
|
+
echo -e "${RED}❌ Agent output validation failed (${CHECKS_FAILED} check(s))${NC}"
|
|
240
|
+
fi
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
exit $([ $CHECKS_FAILED -gt 0 ] && echo 1 || echo 0)
|