shipwright-cli 3.1.0 → 3.3.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/.claude/agents/code-reviewer.md +2 -0
- package/.claude/agents/devops-engineer.md +2 -0
- package/.claude/agents/doc-fleet-agent.md +2 -0
- package/.claude/agents/pipeline-agent.md +2 -0
- package/.claude/agents/shell-script-specialist.md +2 -0
- package/.claude/agents/test-specialist.md +2 -0
- package/.claude/hooks/agent-crash-capture.sh +32 -0
- package/.claude/hooks/post-tool-use.sh +3 -2
- package/.claude/hooks/pre-tool-use.sh +35 -3
- package/README.md +22 -8
- package/claude-code/hooks/config-change.sh +18 -0
- package/claude-code/hooks/instructions-reloaded.sh +7 -0
- package/claude-code/hooks/worktree-create.sh +25 -0
- package/claude-code/hooks/worktree-remove.sh +20 -0
- package/config/code-constitution.json +130 -0
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +8 -6
- package/dashboard/public/styles.css +176 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +117 -25
- package/dashboard/services/config.ts +26 -0
- package/dashboard/services/db.ts +118 -0
- package/dashboard/src/canvas/pixel-agent.ts +298 -0
- package/dashboard/src/canvas/pixel-sprites.ts +440 -0
- package/dashboard/src/canvas/shipyard-effects.ts +367 -0
- package/dashboard/src/canvas/shipyard-scene.ts +616 -0
- package/dashboard/src/canvas/submarine-layout.ts +267 -0
- package/dashboard/src/components/header.ts +8 -7
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/core/router.ts +1 -0
- package/dashboard/src/design/submarine-theme.ts +253 -0
- package/dashboard/src/main.ts +2 -0
- package/dashboard/src/types/api.ts +12 -1
- package/dashboard/src/views/activity.ts +2 -1
- package/dashboard/src/views/metrics.ts +69 -1
- package/dashboard/src/views/shipyard.ts +39 -0
- package/dashboard/types/index.ts +166 -0
- package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
- package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
- package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
- package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
- package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
- package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
- package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
- package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
- package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
- package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
- package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
- package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
- package/docs/research/RESEARCH_INDEX.md +439 -0
- package/docs/research/RESEARCH_SOURCES.md +440 -0
- package/docs/research/RESEARCH_SUMMARY.txt +275 -0
- package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
- package/package.json +2 -2
- package/scripts/lib/adaptive-model.sh +427 -0
- package/scripts/lib/adaptive-timeout.sh +316 -0
- package/scripts/lib/audit-trail.sh +309 -0
- package/scripts/lib/auto-recovery.sh +471 -0
- package/scripts/lib/bandit-selector.sh +431 -0
- package/scripts/lib/bootstrap.sh +104 -2
- package/scripts/lib/causal-graph.sh +455 -0
- package/scripts/lib/compat.sh +126 -0
- package/scripts/lib/compound-audit.sh +337 -0
- package/scripts/lib/constitutional.sh +454 -0
- package/scripts/lib/context-budget.sh +359 -0
- package/scripts/lib/convergence.sh +594 -0
- package/scripts/lib/cost-optimizer.sh +634 -0
- package/scripts/lib/daemon-adaptive.sh +14 -2
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +25 -4
- package/scripts/lib/daemon-poll-github.sh +361 -0
- package/scripts/lib/daemon-poll-health.sh +299 -0
- package/scripts/lib/daemon-poll.sh +27 -611
- package/scripts/lib/daemon-state.sh +119 -66
- package/scripts/lib/daemon-triage.sh +10 -0
- package/scripts/lib/dod-scorecard.sh +442 -0
- package/scripts/lib/error-actionability.sh +300 -0
- package/scripts/lib/formal-spec.sh +461 -0
- package/scripts/lib/helpers.sh +180 -5
- package/scripts/lib/intent-analysis.sh +409 -0
- package/scripts/lib/loop-convergence.sh +350 -0
- package/scripts/lib/loop-iteration.sh +682 -0
- package/scripts/lib/loop-progress.sh +48 -0
- package/scripts/lib/loop-restart.sh +185 -0
- package/scripts/lib/memory-effectiveness.sh +506 -0
- package/scripts/lib/mutation-executor.sh +352 -0
- package/scripts/lib/outcome-feedback.sh +521 -0
- package/scripts/lib/pipeline-cli.sh +336 -0
- package/scripts/lib/pipeline-commands.sh +1216 -0
- package/scripts/lib/pipeline-detection.sh +101 -3
- package/scripts/lib/pipeline-execution.sh +897 -0
- package/scripts/lib/pipeline-github.sh +28 -3
- package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
- package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
- package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
- package/scripts/lib/pipeline-intelligence.sh +104 -1138
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -711
- package/scripts/lib/pipeline-quality-gates.sh +563 -0
- package/scripts/lib/pipeline-stages-build.sh +730 -0
- package/scripts/lib/pipeline-stages-delivery.sh +965 -0
- package/scripts/lib/pipeline-stages-intake.sh +1133 -0
- package/scripts/lib/pipeline-stages-monitor.sh +407 -0
- package/scripts/lib/pipeline-stages-review.sh +1022 -0
- package/scripts/lib/pipeline-stages.sh +161 -2901
- package/scripts/lib/pipeline-state.sh +36 -5
- package/scripts/lib/pipeline-util.sh +487 -0
- package/scripts/lib/policy-learner.sh +438 -0
- package/scripts/lib/process-reward.sh +493 -0
- package/scripts/lib/project-detect.sh +649 -0
- package/scripts/lib/quality-profile.sh +334 -0
- package/scripts/lib/recruit-commands.sh +885 -0
- package/scripts/lib/recruit-learning.sh +739 -0
- package/scripts/lib/recruit-roles.sh +648 -0
- package/scripts/lib/reward-aggregator.sh +458 -0
- package/scripts/lib/rl-optimizer.sh +362 -0
- package/scripts/lib/root-cause.sh +427 -0
- package/scripts/lib/scope-enforcement.sh +445 -0
- package/scripts/lib/session-restart.sh +493 -0
- package/scripts/lib/skill-memory.sh +300 -0
- package/scripts/lib/skill-registry.sh +775 -0
- package/scripts/lib/spec-driven.sh +476 -0
- package/scripts/lib/test-helpers.sh +18 -7
- package/scripts/lib/test-holdout.sh +429 -0
- package/scripts/lib/test-optimizer.sh +511 -0
- package/scripts/shipwright-file-suggest.sh +45 -0
- package/scripts/skills/adversarial-quality.md +61 -0
- package/scripts/skills/api-design.md +44 -0
- package/scripts/skills/architecture-design.md +50 -0
- package/scripts/skills/brainstorming.md +43 -0
- package/scripts/skills/data-pipeline.md +44 -0
- package/scripts/skills/deploy-safety.md +64 -0
- package/scripts/skills/documentation.md +38 -0
- package/scripts/skills/frontend-design.md +45 -0
- package/scripts/skills/generated/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
- package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
- package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
- package/scripts/skills/generated/cli-version-management.md +29 -0
- package/scripts/skills/generated/collection-system-validation.md +99 -0
- package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
- package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
- package/scripts/skills/generated/test-parallelization-detection.md +65 -0
- package/scripts/skills/observability.md +79 -0
- package/scripts/skills/performance.md +48 -0
- package/scripts/skills/pr-quality.md +49 -0
- package/scripts/skills/product-thinking.md +43 -0
- package/scripts/skills/security-audit.md +49 -0
- package/scripts/skills/systematic-debugging.md +40 -0
- package/scripts/skills/testing-strategy.md +47 -0
- package/scripts/skills/two-stage-review.md +52 -0
- package/scripts/skills/validation-thoroughness.md +55 -0
- package/scripts/sw +9 -3
- package/scripts/sw-activity.sh +9 -8
- package/scripts/sw-adaptive.sh +8 -7
- package/scripts/sw-adversarial.sh +2 -1
- package/scripts/sw-architecture-enforcer.sh +3 -1
- package/scripts/sw-auth.sh +12 -2
- package/scripts/sw-autonomous.sh +5 -1
- package/scripts/sw-changelog.sh +4 -1
- package/scripts/sw-checkpoint.sh +2 -1
- package/scripts/sw-ci.sh +15 -6
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +45 -20
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +107 -5
- package/scripts/sw-daemon.sh +71 -11
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +71 -20
- package/scripts/sw-decide.sh +8 -2
- package/scripts/sw-decompose.sh +360 -17
- package/scripts/sw-deps.sh +4 -1
- package/scripts/sw-developer-simulation.sh +4 -1
- package/scripts/sw-discovery.sh +378 -5
- package/scripts/sw-doc-fleet.sh +4 -1
- package/scripts/sw-docs-agent.sh +3 -1
- package/scripts/sw-docs.sh +2 -1
- package/scripts/sw-doctor.sh +453 -2
- package/scripts/sw-dora.sh +4 -1
- package/scripts/sw-durable.sh +12 -7
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +13 -4
- package/scripts/sw-evidence.sh +364 -12
- package/scripts/sw-feedback.sh +550 -9
- package/scripts/sw-fix.sh +20 -1
- package/scripts/sw-fleet-discover.sh +6 -2
- package/scripts/sw-fleet-viz.sh +9 -4
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +18 -4
- package/scripts/sw-github-checks.sh +3 -2
- package/scripts/sw-github-deploy.sh +3 -2
- package/scripts/sw-github-graphql.sh +18 -7
- package/scripts/sw-guild.sh +5 -1
- package/scripts/sw-heartbeat.sh +5 -30
- package/scripts/sw-hello.sh +67 -0
- package/scripts/sw-hygiene.sh +10 -3
- package/scripts/sw-incident.sh +273 -5
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +44 -7
- package/scripts/sw-jira.sh +5 -1
- package/scripts/sw-launchd.sh +2 -1
- package/scripts/sw-linear.sh +4 -1
- package/scripts/sw-logs.sh +4 -1
- package/scripts/sw-loop.sh +436 -1076
- package/scripts/sw-memory.sh +357 -3
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +483 -27
- package/scripts/sw-otel.sh +15 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +7 -1
- package/scripts/sw-pipeline-vitals.sh +12 -6
- package/scripts/sw-pipeline.sh +54 -2653
- package/scripts/sw-pm.sh +16 -8
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +17 -5
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +17 -4
- package/scripts/sw-quality.sh +14 -6
- package/scripts/sw-reaper.sh +8 -25
- package/scripts/sw-recruit.sh +156 -2303
- package/scripts/sw-regression.sh +19 -12
- package/scripts/sw-release-manager.sh +3 -1
- package/scripts/sw-release.sh +4 -1
- package/scripts/sw-remote.sh +3 -1
- package/scripts/sw-replay.sh +7 -1
- package/scripts/sw-retro.sh +158 -1
- package/scripts/sw-review-rerun.sh +3 -1
- package/scripts/sw-scale.sh +14 -5
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +173 -6
- package/scripts/sw-session.sh +9 -3
- package/scripts/sw-setup.sh +3 -1
- package/scripts/sw-stall-detector.sh +406 -0
- package/scripts/sw-standup.sh +15 -7
- package/scripts/sw-status.sh +3 -1
- package/scripts/sw-strategic.sh +14 -6
- package/scripts/sw-stream.sh +13 -4
- package/scripts/sw-swarm.sh +20 -7
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +7 -31
- package/scripts/sw-testgen.sh +17 -6
- package/scripts/sw-tmux-pipeline.sh +4 -1
- package/scripts/sw-tmux-role-color.sh +2 -0
- package/scripts/sw-tmux-status.sh +1 -1
- package/scripts/sw-tmux.sh +37 -1
- package/scripts/sw-trace.sh +3 -1
- package/scripts/sw-tracker-github.sh +3 -0
- package/scripts/sw-tracker-jira.sh +3 -0
- package/scripts/sw-tracker-linear.sh +3 -0
- package/scripts/sw-tracker.sh +3 -1
- package/scripts/sw-triage.sh +3 -2
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +5 -2
- package/scripts/sw-widgets.sh +9 -4
- package/scripts/sw-worktree.sh +15 -3
- package/scripts/test-skill-injection.sh +1233 -0
- package/templates/pipelines/autonomous.json +27 -3
- package/templates/pipelines/cost-aware.json +34 -8
- package/templates/pipelines/deployed.json +12 -0
- package/templates/pipelines/enterprise.json +12 -0
- package/templates/pipelines/fast.json +6 -0
- package/templates/pipelines/full.json +27 -3
- package/templates/pipelines/hotfix.json +6 -0
- package/templates/pipelines/standard.json +12 -0
- package/templates/pipelines/tdd.json +12 -0
package/scripts/sw-feedback.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -29,20 +29,25 @@ fi
|
|
|
29
29
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
30
|
emit_event() {
|
|
31
31
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
32
|
-
local payload
|
|
32
|
+
local payload
|
|
33
|
+
payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
34
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
35
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
36
|
}
|
|
36
37
|
fi
|
|
37
38
|
# ─── Storage Paths ──────────────────────────────────────────────────────────
|
|
38
39
|
INCIDENTS_FILE="${HOME}/.shipwright/incidents.jsonl"
|
|
40
|
+
MERGE_OUTCOMES_FILE="${HOME}/.shipwright/optimization/merge-outcomes.jsonl"
|
|
39
41
|
ERROR_THRESHOLD=5 # Create issue if error count >= threshold
|
|
42
|
+
# shellcheck disable=SC2034
|
|
40
43
|
ERROR_LOG_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
|
|
41
44
|
ARTIFACTS_DIR="${ARTIFACTS_DIR:-${REPO_DIR}/.claude/pipeline-artifacts}"
|
|
45
|
+
POST_MERGE_MONITORING_FILE="${ARTIFACTS_DIR}/post-merge-monitoring.json"
|
|
42
46
|
|
|
43
47
|
# ─── Initialize directories ────────────────────────────────────────────────
|
|
44
48
|
ensure_dirs() {
|
|
45
49
|
mkdir -p "${HOME}/.shipwright"
|
|
50
|
+
mkdir -p "${HOME}/.shipwright/optimization"
|
|
46
51
|
mkdir -p "$ARTIFACTS_DIR"
|
|
47
52
|
}
|
|
48
53
|
|
|
@@ -61,6 +66,7 @@ parse_error_patterns() {
|
|
|
61
66
|
local log_file="$1"
|
|
62
67
|
local error_count=0
|
|
63
68
|
local error_types=""
|
|
69
|
+
# shellcheck disable=SC2034
|
|
64
70
|
local stack_traces=""
|
|
65
71
|
|
|
66
72
|
if [[ ! -f "$log_file" ]]; then
|
|
@@ -72,24 +78,28 @@ parse_error_patterns() {
|
|
|
72
78
|
if [[ "$line" =~ (Error|Exception|panic|fatal).*: ]]; then
|
|
73
79
|
error_count=$((error_count + 1))
|
|
74
80
|
# Extract error message
|
|
75
|
-
local err_msg
|
|
81
|
+
local err_msg
|
|
82
|
+
err_msg=$(echo "$line" | sed -E 's/^.*\[.*\] //; s/:.*//')
|
|
76
83
|
error_types="${error_types}${err_msg};"
|
|
77
84
|
fi
|
|
78
85
|
done < "$log_file"
|
|
79
86
|
|
|
80
87
|
# Output CSV: count|types|first_stack_trace
|
|
81
|
-
local first_stack
|
|
88
|
+
local first_stack
|
|
89
|
+
first_stack=$(head -50 "$log_file" | tail -20)
|
|
82
90
|
echo "$error_count|$error_types|$first_stack"
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
# ─── Find commit that likely introduced regression ───────────────────────────
|
|
86
94
|
find_regression_commit() {
|
|
95
|
+
# shellcheck disable=SC2034
|
|
87
96
|
local error_pattern="$1"
|
|
88
97
|
local max_commits="${2:-20}"
|
|
89
98
|
|
|
90
99
|
# Search recent commits for changes that might have introduced the error
|
|
91
100
|
# Pattern: look for commits touching error-related code
|
|
92
101
|
local commit_hash
|
|
102
|
+
# shellcheck disable=SC2034
|
|
93
103
|
commit_hash=$(cd "$REPO_DIR" && git log --all -n "$max_commits" --pretty=format:"%H %s" | \
|
|
94
104
|
while read -r hash subject; do
|
|
95
105
|
# Simple heuristic: commits that touched multiple files or had large diffs
|
|
@@ -104,7 +114,505 @@ find_regression_commit() {
|
|
|
104
114
|
echo "${commit_hash:0:7}"
|
|
105
115
|
}
|
|
106
116
|
|
|
107
|
-
#
|
|
117
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
118
|
+
# POST-MERGE FEEDBACK FUNCTIONS
|
|
119
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
120
|
+
|
|
121
|
+
# ─── Monitor production after merge ─────────────────────────────────────────────
|
|
122
|
+
feedback_post_merge_monitor() {
|
|
123
|
+
local merge_sha="${1:-}"
|
|
124
|
+
local environment="${2:-production}"
|
|
125
|
+
local monitoring_window="${3:-1800}" # 30 minutes default
|
|
126
|
+
local poll_interval="${4:-60}" # 60 seconds
|
|
127
|
+
local owner_repo="${5:-}"
|
|
128
|
+
|
|
129
|
+
if [[ -z "$merge_sha" ]]; then
|
|
130
|
+
error "Usage: feedback_post_merge_monitor <merge_sha> [environment] [window_secs] [poll_interval]"
|
|
131
|
+
return 1
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
info "Starting post-merge production monitoring for: $merge_sha"
|
|
135
|
+
info "Environment: $environment | Window: $((monitoring_window / 60))m | Poll: ${poll_interval}s"
|
|
136
|
+
|
|
137
|
+
ensure_dirs
|
|
138
|
+
|
|
139
|
+
# Initialize monitoring data
|
|
140
|
+
local monitoring_data
|
|
141
|
+
local start_epoch
|
|
142
|
+
start_epoch=$(now_epoch)
|
|
143
|
+
monitoring_data=$(jq -n \
|
|
144
|
+
--arg ts "$(now_iso)" \
|
|
145
|
+
--arg merge_sha "$merge_sha" \
|
|
146
|
+
--arg env "$environment" \
|
|
147
|
+
--arg window "$monitoring_window" \
|
|
148
|
+
--arg start_ep "$start_epoch" \
|
|
149
|
+
'{
|
|
150
|
+
timestamp: $ts,
|
|
151
|
+
merge_sha: $merge_sha,
|
|
152
|
+
environment: $env,
|
|
153
|
+
monitoring_window_secs: ($window | tonumber),
|
|
154
|
+
start_epoch: ($start_ep | tonumber),
|
|
155
|
+
checks: [],
|
|
156
|
+
errors_detected: 0,
|
|
157
|
+
deployment_status: null,
|
|
158
|
+
monitoring_complete: false
|
|
159
|
+
}')
|
|
160
|
+
|
|
161
|
+
local start_time
|
|
162
|
+
start_time=$(now_epoch)
|
|
163
|
+
local elapsed=0
|
|
164
|
+
local iteration=0
|
|
165
|
+
|
|
166
|
+
# Poll for monitoring window duration
|
|
167
|
+
while [[ "$elapsed" -lt "$monitoring_window" ]]; do
|
|
168
|
+
iteration=$((iteration + 1))
|
|
169
|
+
local current_check
|
|
170
|
+
|
|
171
|
+
# Check GitHub deployment status (if NO_GITHUB not set)
|
|
172
|
+
local deploy_status="unknown"
|
|
173
|
+
local deploy_errors=0
|
|
174
|
+
if [[ "${NO_GITHUB:-}" != "true" && "${NO_GITHUB:-}" != "1" ]]; then
|
|
175
|
+
if [[ -z "$owner_repo" ]]; then
|
|
176
|
+
owner_repo=$(get_owner_repo) || true
|
|
177
|
+
fi
|
|
178
|
+
if [[ -n "$owner_repo" ]]; then
|
|
179
|
+
deploy_status=$(gh api "repos/${owner_repo}/deployments" \
|
|
180
|
+
--jq '.[] | select(.ref == "'$merge_sha'") | .statuses[0].state // "unknown"' \
|
|
181
|
+
2>/dev/null || echo "unknown")
|
|
182
|
+
fi
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# Simulate or check for error spikes (look at error log if available)
|
|
186
|
+
if [[ -f "${ARTIFACTS_DIR}/error-log.jsonl" ]]; then
|
|
187
|
+
deploy_errors=$(wc -l < "${ARTIFACTS_DIR}/error-log.jsonl" 2>/dev/null || echo "0")
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
current_check=$(jq -n \
|
|
191
|
+
--arg ts "$(now_iso)" \
|
|
192
|
+
--argjson iter "$iteration" \
|
|
193
|
+
--arg deploy_st "$deploy_status" \
|
|
194
|
+
--argjson err_count "$deploy_errors" \
|
|
195
|
+
'{
|
|
196
|
+
timestamp: $ts,
|
|
197
|
+
iteration: $iter,
|
|
198
|
+
deployment_status: $deploy_st,
|
|
199
|
+
error_count: $err_count
|
|
200
|
+
}')
|
|
201
|
+
|
|
202
|
+
monitoring_data=$(echo "$monitoring_data" | jq \
|
|
203
|
+
--argjson check "$current_check" \
|
|
204
|
+
--argjson err_count "$deploy_errors" \
|
|
205
|
+
'.checks += [$check] | .errors_detected += ($err_count | tonumber)')
|
|
206
|
+
|
|
207
|
+
# Check for immediate failure
|
|
208
|
+
if [[ "$deploy_status" == "failure" || "$deploy_status" == "error" ]]; then
|
|
209
|
+
warn "Deployment failed detected at iteration $iteration!"
|
|
210
|
+
monitoring_data=$(echo "$monitoring_data" | jq '.deployment_status = "failed"')
|
|
211
|
+
break
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
elapsed=$(($(now_epoch) - start_time))
|
|
215
|
+
if [[ "$elapsed" -lt "$monitoring_window" ]]; then
|
|
216
|
+
sleep "$poll_interval"
|
|
217
|
+
fi
|
|
218
|
+
done
|
|
219
|
+
|
|
220
|
+
# Mark monitoring complete
|
|
221
|
+
local end_epoch
|
|
222
|
+
end_epoch=$(now_epoch)
|
|
223
|
+
monitoring_data=$(echo "$monitoring_data" | jq \
|
|
224
|
+
--arg ts "$(now_iso)" \
|
|
225
|
+
--arg end_ep "$end_epoch" \
|
|
226
|
+
'.monitoring_complete = true | .end_timestamp = $ts | .end_epoch = ($end_ep | tonumber)')
|
|
227
|
+
|
|
228
|
+
# Write monitoring data atomically
|
|
229
|
+
local tmp_file
|
|
230
|
+
tmp_file=$(mktemp)
|
|
231
|
+
echo "$monitoring_data" > "$tmp_file"
|
|
232
|
+
mv "$tmp_file" "$POST_MERGE_MONITORING_FILE"
|
|
233
|
+
|
|
234
|
+
success "Post-merge monitoring complete: $POST_MERGE_MONITORING_FILE"
|
|
235
|
+
emit_event "feedback_post_merge_monitor" "merge_sha=$merge_sha" "environment=$environment" "errors=$( echo "$monitoring_data" | jq -r '.errors_detected')"
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# ─── Detect regressions from monitoring data ────────────────────────────────────
|
|
239
|
+
feedback_detect_regression() {
|
|
240
|
+
local monitoring_file="${1:-$POST_MERGE_MONITORING_FILE}"
|
|
241
|
+
|
|
242
|
+
if [[ ! -f "$monitoring_file" ]]; then
|
|
243
|
+
error "Monitoring file not found: $monitoring_file"
|
|
244
|
+
return 1
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
local merge_sha
|
|
248
|
+
merge_sha=$(jq -r '.merge_sha' "$monitoring_file")
|
|
249
|
+
local errors_detected
|
|
250
|
+
errors_detected=$(jq -r '.errors_detected // 0' "$monitoring_file")
|
|
251
|
+
local deploy_status
|
|
252
|
+
deploy_status=$(jq -r '.deployment_status // "unknown"' "$monitoring_file")
|
|
253
|
+
local error_count_threshold=5
|
|
254
|
+
|
|
255
|
+
local regression="false"
|
|
256
|
+
local regression_type="none"
|
|
257
|
+
local severity="P3"
|
|
258
|
+
local evidence=""
|
|
259
|
+
|
|
260
|
+
# P0: Deployment failed
|
|
261
|
+
if [[ "$deploy_status" == "failed" ]]; then
|
|
262
|
+
regression="true"
|
|
263
|
+
regression_type="deploy_failure"
|
|
264
|
+
severity="P0"
|
|
265
|
+
evidence="Deployment failed after merge"
|
|
266
|
+
# P1: Error spike
|
|
267
|
+
elif [[ "$errors_detected" -ge "$error_count_threshold" ]]; then
|
|
268
|
+
regression="true"
|
|
269
|
+
regression_type="error_spike"
|
|
270
|
+
severity="P1"
|
|
271
|
+
evidence="Error count: $errors_detected (threshold: $error_count_threshold)"
|
|
272
|
+
# P2: Minor errors (below threshold but present)
|
|
273
|
+
elif [[ "$errors_detected" -gt 0 ]]; then
|
|
274
|
+
regression="true"
|
|
275
|
+
regression_type="minor_errors"
|
|
276
|
+
severity="P2"
|
|
277
|
+
evidence="Error count: $errors_detected"
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
local regression_result
|
|
281
|
+
regression_result=$(jq -n \
|
|
282
|
+
--arg ts "$(now_iso)" \
|
|
283
|
+
--arg sha "$merge_sha" \
|
|
284
|
+
--arg regr "$regression" \
|
|
285
|
+
--arg type "$regression_type" \
|
|
286
|
+
--arg sev "$severity" \
|
|
287
|
+
--arg evid "$evidence" \
|
|
288
|
+
'{
|
|
289
|
+
timestamp: $ts,
|
|
290
|
+
merge_sha: $sha,
|
|
291
|
+
regression: ($regr == "true"),
|
|
292
|
+
type: $type,
|
|
293
|
+
severity: $sev,
|
|
294
|
+
evidence: $evid
|
|
295
|
+
}')
|
|
296
|
+
|
|
297
|
+
echo "$regression_result"
|
|
298
|
+
emit_event "feedback_detect_regression" "merge_sha=$merge_sha" "regression=$regression" "severity=$severity"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# ─── Correlate regressions with changed files ───────────────────────────────────
|
|
302
|
+
feedback_correlate_with_changes() {
|
|
303
|
+
local pr_number="${1:-}"
|
|
304
|
+
local regression_json="${2:-}"
|
|
305
|
+
|
|
306
|
+
if [[ -z "$pr_number" ]]; then
|
|
307
|
+
error "Usage: feedback_correlate_with_changes <pr_number> [regression_json]"
|
|
308
|
+
return 1
|
|
309
|
+
fi
|
|
310
|
+
|
|
311
|
+
# Get PR's changed files from git log (if available)
|
|
312
|
+
local changed_files=""
|
|
313
|
+
local culprit_files=""
|
|
314
|
+
local confidence=0
|
|
315
|
+
|
|
316
|
+
# Try to get files from recent commits
|
|
317
|
+
if [[ "${NO_GITHUB:-}" != "true" && "${NO_GITHUB:-}" != "1" ]]; then
|
|
318
|
+
changed_files=$(git log --oneline --all -n 50 --pretty=format:%B 2>/dev/null | \
|
|
319
|
+
grep -i "pr #$pr_number\|merge.*$pr_number" | head -1 || echo "")
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
# If no GitHub data, fall back to git history
|
|
323
|
+
if [[ -z "$changed_files" ]]; then
|
|
324
|
+
changed_files=$(cd "$REPO_DIR" && git diff HEAD~1..HEAD --name-only 2>/dev/null | head -10 || echo "")
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
# Score likelihood of files being culprits (common patterns)
|
|
328
|
+
if [[ -n "$changed_files" ]]; then
|
|
329
|
+
# Files commonly correlated with regressions
|
|
330
|
+
while IFS= read -r file; do
|
|
331
|
+
if [[ "$file" =~ (auth|login|session|permission|access) ]]; then
|
|
332
|
+
culprit_files="${culprit_files}${file}:auth "
|
|
333
|
+
confidence=$((confidence + 25))
|
|
334
|
+
elif [[ "$file" =~ (api|endpoint|route|handler|request) ]]; then
|
|
335
|
+
culprit_files="${culprit_files}${file}:api "
|
|
336
|
+
confidence=$((confidence + 20))
|
|
337
|
+
elif [[ "$file" =~ (database|migration|schema|sql) ]]; then
|
|
338
|
+
culprit_files="${culprit_files}${file}:db "
|
|
339
|
+
confidence=$((confidence + 20))
|
|
340
|
+
elif [[ "$file" =~ (util|helper|core|lib) ]]; then
|
|
341
|
+
culprit_files="${culprit_files}${file}:shared "
|
|
342
|
+
confidence=$((confidence + 15))
|
|
343
|
+
fi
|
|
344
|
+
done <<< "$changed_files"
|
|
345
|
+
fi
|
|
346
|
+
|
|
347
|
+
# Cap confidence at 100
|
|
348
|
+
if [[ "$confidence" -gt 100 ]]; then
|
|
349
|
+
confidence=100
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
local correlation_result
|
|
353
|
+
correlation_result=$(jq -n \
|
|
354
|
+
--arg pr "$pr_number" \
|
|
355
|
+
--arg files "$changed_files" \
|
|
356
|
+
--arg culprits "$culprit_files" \
|
|
357
|
+
--arg conf "$confidence" \
|
|
358
|
+
'{
|
|
359
|
+
pr_number: $pr,
|
|
360
|
+
changed_files: $files,
|
|
361
|
+
culprit_files: $culprits,
|
|
362
|
+
confidence_percent: ($conf | tonumber)
|
|
363
|
+
}')
|
|
364
|
+
|
|
365
|
+
echo "$correlation_result"
|
|
366
|
+
emit_event "feedback_correlate" "pr=$pr_number" "confidence=$confidence"
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
# ─── Auto-respond to regressions based on severity ──────────────────────────────
|
|
370
|
+
feedback_auto_respond() {
|
|
371
|
+
local regression_json="${1:-}"
|
|
372
|
+
local pr_number="${2:-}"
|
|
373
|
+
|
|
374
|
+
if [[ -z "$regression_json" ]]; then
|
|
375
|
+
error "Usage: feedback_auto_respond <regression_json> [pr_number]"
|
|
376
|
+
return 1
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
local severity
|
|
380
|
+
severity=$(echo "$regression_json" | jq -r '.severity // "P3"')
|
|
381
|
+
local regression_type
|
|
382
|
+
regression_type=$(echo "$regression_json" | jq -r '.type // "unknown"')
|
|
383
|
+
local evidence
|
|
384
|
+
evidence=$(echo "$regression_json" | jq -r '.evidence // ""')
|
|
385
|
+
|
|
386
|
+
info "Auto-responding to regression: $severity / $regression_type"
|
|
387
|
+
|
|
388
|
+
ensure_dirs
|
|
389
|
+
|
|
390
|
+
case "$severity" in
|
|
391
|
+
P0)
|
|
392
|
+
# Deploy failed: trigger rollback + create incident
|
|
393
|
+
info "P0 SEVERITY: Deployment failed — triggering rollback"
|
|
394
|
+
cmd_rollback "production" "Post-merge regression detected: $regression_type"
|
|
395
|
+
|
|
396
|
+
# Create incident issue if GitHub available
|
|
397
|
+
if [[ "${NO_GITHUB:-}" != "true" && "${NO_GITHUB:-}" != "1" ]]; then
|
|
398
|
+
local owner_repo
|
|
399
|
+
owner_repo=$(get_owner_repo) || true
|
|
400
|
+
if [[ -n "$owner_repo" && -n "$pr_number" ]]; then
|
|
401
|
+
if command -v gh >/dev/null 2>&1; then
|
|
402
|
+
gh issue create \
|
|
403
|
+
--repo "$owner_repo" \
|
|
404
|
+
--title "CRITICAL: Post-Merge Deployment Failed - PR #$pr_number" \
|
|
405
|
+
--body "**Severity**: P0 - CRITICAL
|
|
406
|
+
|
|
407
|
+
**Issue**: Deployment failed immediately after PR merge
|
|
408
|
+
|
|
409
|
+
**Type**: $regression_type
|
|
410
|
+
**Evidence**: $evidence
|
|
411
|
+
|
|
412
|
+
**Action Taken**: Rollback initiated
|
|
413
|
+
|
|
414
|
+
**Related PR**: #$pr_number
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
Auto-created by Shipwright Post-Merge Feedback System" \
|
|
418
|
+
--label "shipwright" \
|
|
419
|
+
--label "incident" \
|
|
420
|
+
--label "p0" \
|
|
421
|
+
2>&1 | grep -oE 'https://github.com/[^ ]+' | head -1 || true
|
|
422
|
+
fi
|
|
423
|
+
fi
|
|
424
|
+
fi
|
|
425
|
+
;;
|
|
426
|
+
P1)
|
|
427
|
+
# Error spike: create hotfix issue
|
|
428
|
+
info "P1 SEVERITY: Error spike detected — creating hotfix issue"
|
|
429
|
+
if [[ "${NO_GITHUB:-}" != "true" && "${NO_GITHUB:-}" != "1" ]]; then
|
|
430
|
+
local owner_repo
|
|
431
|
+
owner_repo=$(get_owner_repo) || true
|
|
432
|
+
if [[ -n "$owner_repo" && -n "$pr_number" ]]; then
|
|
433
|
+
if command -v gh >/dev/null 2>&1; then
|
|
434
|
+
gh issue create \
|
|
435
|
+
--repo "$owner_repo" \
|
|
436
|
+
--title "Hotfix Needed: Post-Merge Error Spike - PR #$pr_number" \
|
|
437
|
+
--body "**Severity**: P1 - HIGH
|
|
438
|
+
|
|
439
|
+
**Issue**: Error spike detected in production after PR merge
|
|
440
|
+
|
|
441
|
+
**Type**: $regression_type
|
|
442
|
+
**Evidence**: $evidence
|
|
443
|
+
|
|
444
|
+
**Action Required**: Investigate and create hotfix
|
|
445
|
+
|
|
446
|
+
**Related PR**: #$pr_number
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
Auto-created by Shipwright Post-Merge Feedback System" \
|
|
450
|
+
--label "shipwright" \
|
|
451
|
+
--label "hotfix" \
|
|
452
|
+
--label "p1" \
|
|
453
|
+
2>&1 | grep -oE 'https://github.com/[^ ]+' | head -1 || true
|
|
454
|
+
fi
|
|
455
|
+
fi
|
|
456
|
+
fi
|
|
457
|
+
;;
|
|
458
|
+
P2)
|
|
459
|
+
# Performance or minor regression: schedule for next sprint
|
|
460
|
+
info "P2 SEVERITY: Performance degradation — scheduling for next sprint"
|
|
461
|
+
;;
|
|
462
|
+
P3|*)
|
|
463
|
+
# Minor: just record in memory
|
|
464
|
+
info "P3 SEVERITY: Minor regression — recorded for awareness"
|
|
465
|
+
;;
|
|
466
|
+
esac
|
|
467
|
+
|
|
468
|
+
emit_event "feedback_auto_respond" "severity=$severity" "type=$regression_type"
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
# ─── Learn from post-merge outcomes ─────────────────────────────────────────────
|
|
472
|
+
feedback_learn_from_outcome() {
|
|
473
|
+
local pr_number="${1:-}"
|
|
474
|
+
local merge_result="${2:-success}"
|
|
475
|
+
local deploy_result="${3:-unknown}"
|
|
476
|
+
local regression="${4:-false}"
|
|
477
|
+
local regression_type="${5:-none}"
|
|
478
|
+
|
|
479
|
+
if [[ -z "$pr_number" ]]; then
|
|
480
|
+
error "Usage: feedback_learn_from_outcome <pr_number> [merge_result] [deploy_result] [regression] [type]"
|
|
481
|
+
return 1
|
|
482
|
+
fi
|
|
483
|
+
|
|
484
|
+
info "Recording merge outcome for learning: PR #$pr_number"
|
|
485
|
+
|
|
486
|
+
ensure_dirs
|
|
487
|
+
|
|
488
|
+
# Calculate time-to-detect (from merge timestamp if available)
|
|
489
|
+
local time_to_detect=0
|
|
490
|
+
if [[ -f "$POST_MERGE_MONITORING_FILE" ]]; then
|
|
491
|
+
local start_epoch
|
|
492
|
+
start_epoch=$(jq -r '.start_epoch // 0' "$POST_MERGE_MONITORING_FILE")
|
|
493
|
+
local end_epoch
|
|
494
|
+
end_epoch=$(jq -r '.end_epoch // 0' "$POST_MERGE_MONITORING_FILE")
|
|
495
|
+
if [[ "$end_epoch" -gt 0 && "$start_epoch" -gt 0 ]]; then
|
|
496
|
+
time_to_detect=$((end_epoch - start_epoch))
|
|
497
|
+
fi
|
|
498
|
+
fi
|
|
499
|
+
|
|
500
|
+
local outcome_entry
|
|
501
|
+
outcome_entry=$(jq -c -n \
|
|
502
|
+
--arg ts "$(now_iso)" \
|
|
503
|
+
--arg pr "$pr_number" \
|
|
504
|
+
--arg merge_res "$merge_result" \
|
|
505
|
+
--arg deploy_res "$deploy_result" \
|
|
506
|
+
--arg regr "$regression" \
|
|
507
|
+
--arg regr_type "$regression_type" \
|
|
508
|
+
--arg ttd "$time_to_detect" \
|
|
509
|
+
--arg repo "$(basename "$REPO_DIR")" \
|
|
510
|
+
'{
|
|
511
|
+
timestamp: $ts,
|
|
512
|
+
pr_number: $pr,
|
|
513
|
+
repository: $repo,
|
|
514
|
+
merge_result: $merge_res,
|
|
515
|
+
deploy_result: $deploy_res,
|
|
516
|
+
regression_detected: ($regr == "true"),
|
|
517
|
+
regression_type: $regr_type,
|
|
518
|
+
time_to_detect_secs: ($ttd | tonumber)
|
|
519
|
+
}')
|
|
520
|
+
|
|
521
|
+
# Atomic write
|
|
522
|
+
local tmp_file
|
|
523
|
+
tmp_file=$(mktemp)
|
|
524
|
+
echo "$outcome_entry" >> "$tmp_file"
|
|
525
|
+
cat "$MERGE_OUTCOMES_FILE" >> "$tmp_file" 2>/dev/null || true
|
|
526
|
+
mv "$tmp_file" "$MERGE_OUTCOMES_FILE"
|
|
527
|
+
|
|
528
|
+
success "Learned outcome: PR #$pr_number ($merge_result / $deploy_result / regression=$regression)"
|
|
529
|
+
emit_event "feedback_learn_from_outcome" "pr=$pr_number" "merge_result=$merge_result" "regression=$regression"
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
# ─── Generate post-merge health report ──────────────────────────────────────────
|
|
533
|
+
feedback_report() {
|
|
534
|
+
local days="${1:-30}"
|
|
535
|
+
|
|
536
|
+
info "Post-Merge Health Report (last $days days)"
|
|
537
|
+
echo ""
|
|
538
|
+
|
|
539
|
+
if [[ ! -f "$MERGE_OUTCOMES_FILE" ]]; then
|
|
540
|
+
warn "No merge outcomes recorded yet"
|
|
541
|
+
return 0
|
|
542
|
+
fi
|
|
543
|
+
|
|
544
|
+
# Calculate metrics
|
|
545
|
+
local total_merges=0
|
|
546
|
+
local successful_merges=0
|
|
547
|
+
local regressions=0
|
|
548
|
+
local p0_count=0
|
|
549
|
+
local p1_count=0
|
|
550
|
+
local p2_count=0
|
|
551
|
+
local total_detect_time=0
|
|
552
|
+
local avg_detect_time=0
|
|
553
|
+
local common_types=""
|
|
554
|
+
|
|
555
|
+
while IFS= read -r line; do
|
|
556
|
+
local merge_res
|
|
557
|
+
merge_res=$(echo "$line" | jq -r '.merge_result // "unknown"')
|
|
558
|
+
local regression
|
|
559
|
+
regression=$(echo "$line" | jq -r '.regression_detected // false')
|
|
560
|
+
local regr_type
|
|
561
|
+
regr_type=$(echo "$line" | jq -r '.regression_type // "none"')
|
|
562
|
+
local ttd
|
|
563
|
+
ttd=$(echo "$line" | jq -r '.time_to_detect_secs // 0')
|
|
564
|
+
|
|
565
|
+
total_merges=$((total_merges + 1))
|
|
566
|
+
[[ "$merge_res" == "success" ]] && successful_merges=$((successful_merges + 1))
|
|
567
|
+
[[ "$regression" == "true" ]] && regressions=$((regressions + 1))
|
|
568
|
+
|
|
569
|
+
total_detect_time=$((total_detect_time + ttd))
|
|
570
|
+
|
|
571
|
+
# Count severity (inferred from time-to-detect for now)
|
|
572
|
+
if [[ "$ttd" -lt 300 ]]; then
|
|
573
|
+
p0_count=$((p0_count + 1))
|
|
574
|
+
elif [[ "$ttd" -lt 900 ]]; then
|
|
575
|
+
p1_count=$((p1_count + 1))
|
|
576
|
+
else
|
|
577
|
+
p2_count=$((p2_count + 1))
|
|
578
|
+
fi
|
|
579
|
+
|
|
580
|
+
# Track common regression types
|
|
581
|
+
if [[ "$regr_type" != "none" ]]; then
|
|
582
|
+
common_types="${common_types}${regr_type};"
|
|
583
|
+
fi
|
|
584
|
+
done < "$MERGE_OUTCOMES_FILE"
|
|
585
|
+
|
|
586
|
+
if [[ "$total_merges" -gt 0 ]]; then
|
|
587
|
+
avg_detect_time=$((total_detect_time / total_merges))
|
|
588
|
+
fi
|
|
589
|
+
|
|
590
|
+
# Output report
|
|
591
|
+
echo " ${CYAN}Merge Statistics${RESET}"
|
|
592
|
+
echo " Total Merges: $total_merges"
|
|
593
|
+
echo " Success Rate: $((successful_merges * 100 / total_merges))% ($successful_merges/$total_merges)"
|
|
594
|
+
echo " Regressions: $regressions ($((regressions * 100 / total_merges))%)"
|
|
595
|
+
echo ""
|
|
596
|
+
echo " ${CYAN}Detection Metrics${RESET}"
|
|
597
|
+
echo " Avg Detection Time: ${avg_detect_time}s ($((avg_detect_time / 60))m)"
|
|
598
|
+
echo " P0 Incidents: $p0_count"
|
|
599
|
+
echo " P1 Issues: $p1_count"
|
|
600
|
+
echo " P2 Items: $p2_count"
|
|
601
|
+
echo ""
|
|
602
|
+
echo " ${CYAN}Common Regression Types${RESET}"
|
|
603
|
+
if [[ -n "$common_types" ]]; then
|
|
604
|
+
echo "$common_types" | tr ';' '\n' | sort | uniq -c | sort -rn | head -5 | while read -r count type; do
|
|
605
|
+
[[ -n "$type" ]] && echo " $type: $count occurrences"
|
|
606
|
+
done
|
|
607
|
+
else
|
|
608
|
+
echo " (None recorded)"
|
|
609
|
+
fi
|
|
610
|
+
echo ""
|
|
611
|
+
success "Report generated"
|
|
612
|
+
return 0
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
# ─── Collect errors from monitor stage output ────────────────────────────────────
|
|
108
616
|
cmd_collect() {
|
|
109
617
|
local log_path="${1:-.}"
|
|
110
618
|
|
|
@@ -127,6 +635,7 @@ cmd_collect() {
|
|
|
127
635
|
while IFS= read -r file; do
|
|
128
636
|
local result
|
|
129
637
|
result=$(parse_error_patterns "$file") || continue
|
|
638
|
+
# shellcheck disable=SC2034
|
|
130
639
|
IFS='|' read -r count types traces <<< "$result"
|
|
131
640
|
total_errors=$((total_errors + count))
|
|
132
641
|
error_summary="${error_summary}${types};"
|
|
@@ -398,20 +907,37 @@ ${BOLD}SUBCOMMANDS${RESET}
|
|
|
398
907
|
${CYAN}rollback${RESET} [env] [reason] Trigger rollback via Deployments API
|
|
399
908
|
${CYAN}learn${RESET} [cause] [fix] Capture incident in memory system
|
|
400
909
|
${CYAN}report${RESET} [days] Show recent incidents (default: 7 days)
|
|
910
|
+
|
|
911
|
+
${CYAN}post-merge${RESET} [sha] [env] Monitor production after merge
|
|
912
|
+
${CYAN}regressions${RESET} [file] Detect regressions from monitoring data
|
|
913
|
+
${CYAN}correlate${RESET} [pr] [json] Link regressions to changed files
|
|
914
|
+
${CYAN}outcomes${RESET} [pr] [...] Record merge outcome for learning
|
|
915
|
+
${CYAN}health${RESET} [days] Post-merge health report
|
|
916
|
+
|
|
401
917
|
${CYAN}help${RESET} Show this help message
|
|
402
918
|
|
|
403
919
|
${BOLD}EXAMPLES${RESET}
|
|
920
|
+
${DIM}# Traditional flow${RESET}
|
|
404
921
|
${DIM}shipwright feedback collect ./logs${RESET}
|
|
405
922
|
${DIM}shipwright feedback analyze${RESET}
|
|
406
923
|
${DIM}shipwright feedback create-issue${RESET}
|
|
407
924
|
${DIM}shipwright feedback rollback production "Hotfix v1.2.3 regression"${RESET}
|
|
408
|
-
${DIM}shipwright feedback learn "Off-by-one error
|
|
925
|
+
${DIM}shipwright feedback learn "Off-by-one error" "Fixed in PR #456"${RESET}
|
|
409
926
|
${DIM}shipwright feedback report 30${RESET}
|
|
410
927
|
|
|
928
|
+
${DIM}# Post-merge monitoring flow${RESET}
|
|
929
|
+
${DIM}shipwright feedback post-merge abc1234 production${RESET}
|
|
930
|
+
${DIM}shipwright feedback regressions${RESET}
|
|
931
|
+
${DIM}shipwright feedback correlate 42${RESET}
|
|
932
|
+
${DIM}shipwright feedback outcomes 42 success deployed true error_spike${RESET}
|
|
933
|
+
${DIM}shipwright feedback health 30${RESET}
|
|
934
|
+
|
|
411
935
|
${BOLD}STORAGE${RESET}
|
|
412
|
-
Incidents:
|
|
413
|
-
Errors:
|
|
414
|
-
Rollbacks:
|
|
936
|
+
Incidents: $INCIDENTS_FILE
|
|
937
|
+
Errors: ${ARTIFACTS_DIR}/errors-collected.json
|
|
938
|
+
Rollbacks: ${ARTIFACTS_DIR}/rollbacks.jsonl
|
|
939
|
+
Merge Outcomes: $MERGE_OUTCOMES_FILE
|
|
940
|
+
Monitoring: $POST_MERGE_MONITORING_FILE
|
|
415
941
|
|
|
416
942
|
${BOLD}VERSION${RESET}
|
|
417
943
|
$VERSION
|
|
@@ -442,6 +968,21 @@ main() {
|
|
|
442
968
|
report)
|
|
443
969
|
cmd_report "$@"
|
|
444
970
|
;;
|
|
971
|
+
post-merge)
|
|
972
|
+
feedback_post_merge_monitor "$@"
|
|
973
|
+
;;
|
|
974
|
+
regressions)
|
|
975
|
+
feedback_detect_regression "$@"
|
|
976
|
+
;;
|
|
977
|
+
correlate)
|
|
978
|
+
feedback_correlate_with_changes "$@"
|
|
979
|
+
;;
|
|
980
|
+
outcomes)
|
|
981
|
+
feedback_learn_from_outcome "$@"
|
|
982
|
+
;;
|
|
983
|
+
health)
|
|
984
|
+
feedback_report "$@"
|
|
985
|
+
;;
|
|
445
986
|
help|-h|--help)
|
|
446
987
|
show_help
|
|
447
988
|
;;
|