@kabran-tecnologia/kabran-config 1.7.0 → 1.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kabran-tecnologia/kabran-config",
3
- "version": "1.7.0",
3
+ "version": "1.9.0",
4
4
  "description": "Shared quality configurations, enforcement scripts, and CI/CD tooling for Kabran projects",
5
5
  "author": "Kabran",
6
6
  "license": "MIT",
@@ -11,7 +11,9 @@
11
11
  "bin": {
12
12
  "kabran-setup": "src/scripts/setup.mjs",
13
13
  "kabran-ci": "src/scripts/ci/ci-runner.sh",
14
- "kabran-pr-comment": "src/scripts/pr-quality-comment.mjs"
14
+ "kabran-pr-comment": "src/scripts/pr-quality-comment.mjs",
15
+ "kabran-traceability": "src/scripts/traceability/validate-traceability.sh",
16
+ "kabran-coverage": "src/scripts/traceability/coverage-report.sh"
15
17
  },
16
18
  "exports": {
17
19
  "./eslint": "./src/eslint.mjs",
@@ -29,6 +31,7 @@
29
31
  "./scripts/env-validator": "./src/scripts/env-validator.mjs",
30
32
  "./scripts/ci/*": "./src/scripts/ci/*",
31
33
  "./scripts/deploy/*": "./src/scripts/deploy/*",
34
+ "./scripts/traceability/*": "./src/scripts/traceability/*",
32
35
  "./scripts/setup": "./src/scripts/setup.mjs",
33
36
  "./scripts/quality-standard-validator": "./src/scripts/quality-standard-validator.mjs",
34
37
  "./scripts/generate-ci-result": "./src/scripts/generate-ci-result.mjs",
@@ -27,6 +27,8 @@ NC='\033[0m'
27
27
  declare -a ERRORS=()
28
28
  declare -a STEP_RESULTS=()
29
29
  CI_START_TIME=""
30
+ CI_TRACE_ID=""
31
+ CI_SPAN_ID=""
30
32
 
31
33
  # ==============================================================================
32
34
  # Logging Functions
@@ -58,6 +60,128 @@ log_debug() {
58
60
  fi
59
61
  }
60
62
 
63
+ # ==============================================================================
64
+ # Trace Context Functions (OpenTelemetry W3C Trace Context)
65
+ # ==============================================================================
66
+
67
+ # Generate a random hex string of specified length
68
+ # Usage: generate_hex_string 32
69
+ generate_hex_string() {
70
+ local length="${1:-32}"
71
+ # Try multiple methods for generating random hex
72
+ if command -v openssl &>/dev/null; then
73
+ openssl rand -hex "$((length / 2))" 2>/dev/null
74
+ elif [ -r /dev/urandom ]; then
75
+ head -c "$((length / 2))" /dev/urandom | od -An -tx1 | tr -d ' \n' | head -c "$length"
76
+ else
77
+ # Fallback: use date + process ID + random
78
+ local seed="$$$(date +%s%N 2>/dev/null || date +%s)"
79
+ echo "$seed" | md5sum 2>/dev/null | head -c "$length" || echo "$seed" | head -c "$length"
80
+ fi
81
+ }
82
+
83
+ # Generate a W3C trace ID (32 hex chars = 128 bits)
84
+ # Usage: generate_trace_id
85
+ generate_trace_id() {
86
+ generate_hex_string 32
87
+ }
88
+
89
+ # Generate a W3C span ID (16 hex chars = 64 bits)
90
+ # Usage: generate_span_id
91
+ generate_span_id() {
92
+ generate_hex_string 16
93
+ }
94
+
95
+ # Initialize trace context for the CI run
96
+ # Sets TRACEPARENT env var if not already set
97
+ # Format: 00-{trace_id}-{span_id}-{flags}
98
+ # Usage: setup_trace_context
99
+ setup_trace_context() {
100
+ # Check if trace context already exists from environment
101
+ if [ -n "${TRACEPARENT:-}" ]; then
102
+ log_debug "Using existing TRACEPARENT: $TRACEPARENT"
103
+ # Extract trace_id and span_id from existing TRACEPARENT
104
+ CI_TRACE_ID=$(echo "$TRACEPARENT" | cut -d'-' -f2)
105
+ CI_SPAN_ID=$(echo "$TRACEPARENT" | cut -d'-' -f3)
106
+ return 0
107
+ fi
108
+
109
+ # Check for direct trace ID from environment
110
+ if [ -n "${OTEL_TRACE_ID:-}" ]; then
111
+ log_debug "Using OTEL_TRACE_ID: $OTEL_TRACE_ID"
112
+ CI_TRACE_ID="$OTEL_TRACE_ID"
113
+ CI_SPAN_ID=$(generate_span_id)
114
+ TRACEPARENT="00-${CI_TRACE_ID}-${CI_SPAN_ID}-01"
115
+ export TRACEPARENT
116
+ return 0
117
+ fi
118
+
119
+ # Check for GitHub Actions run ID (use as fallback correlation)
120
+ if [ -n "${GITHUB_RUN_ID:-}" ]; then
121
+ log_debug "Using GitHub run ID for trace correlation"
122
+ # Create deterministic trace_id from GitHub run info
123
+ local gh_seed="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT:-1}"
124
+ CI_TRACE_ID=$(echo "$gh_seed" | md5sum | head -c 32)
125
+ CI_SPAN_ID=$(generate_span_id)
126
+ TRACEPARENT="00-${CI_TRACE_ID}-${CI_SPAN_ID}-01"
127
+ export TRACEPARENT
128
+ log_debug "Generated TRACEPARENT from GitHub: $TRACEPARENT"
129
+ return 0
130
+ fi
131
+
132
+ # Generate new trace context for local execution
133
+ log_debug "Generating new trace context for local CI run"
134
+ CI_TRACE_ID=$(generate_trace_id)
135
+ CI_SPAN_ID=$(generate_span_id)
136
+ TRACEPARENT="00-${CI_TRACE_ID}-${CI_SPAN_ID}-01"
137
+ export TRACEPARENT
138
+
139
+ log_info "Trace ID: ${CI_TRACE_ID:0:8}... (local)"
140
+ log_debug "Full TRACEPARENT: $TRACEPARENT"
141
+ return 0
142
+ }
143
+
144
+ # Get the current trace ID
145
+ # Usage: get_trace_id
146
+ get_trace_id() {
147
+ echo "${CI_TRACE_ID:-}"
148
+ }
149
+
150
+ # Get trace context info for metadata
151
+ # Usage: get_trace_context_json
152
+ get_trace_context_json() {
153
+ local trace_id="${CI_TRACE_ID:-}"
154
+ local span_id="${CI_SPAN_ID:-}"
155
+ local traceparent="${TRACEPARENT:-}"
156
+
157
+ if [ -z "$trace_id" ]; then
158
+ echo "null"
159
+ return
160
+ fi
161
+
162
+ # Determine source of trace context
163
+ local source="local"
164
+ if [ -n "${GITHUB_RUN_ID:-}" ]; then
165
+ source="github"
166
+ elif [ -n "${OTEL_TRACE_ID:-}" ]; then
167
+ source="otel_env"
168
+ elif [ -n "${TRACEPARENT:-}" ] && [ "${CI_TRACE_ID:-}" != "$(echo "$TRACEPARENT" | cut -d'-' -f2)" ]; then
169
+ source="external"
170
+ fi
171
+
172
+ jq -n \
173
+ --arg trace_id "$trace_id" \
174
+ --arg span_id "$span_id" \
175
+ --arg traceparent "$traceparent" \
176
+ --arg source "$source" \
177
+ '{
178
+ trace_id: $trace_id,
179
+ span_id: $span_id,
180
+ traceparent: $traceparent,
181
+ source: $source
182
+ }'
183
+ }
184
+
61
185
  # ==============================================================================
62
186
  # Version Compatibility Check
63
187
  # ==============================================================================
@@ -432,6 +556,10 @@ export_ci_data() {
432
556
  # Get scope
433
557
  local scope="${CI_SCOPE:-all}"
434
558
 
559
+ # Get trace context
560
+ local trace_context
561
+ trace_context=$(get_trace_context_json)
562
+
435
563
  # Generate intermediate data file for Node.js generator
436
564
  jq -n \
437
565
  --argjson steps "$steps_json" \
@@ -441,6 +569,7 @@ export_ci_data() {
441
569
  --arg finished_at "$now" \
442
570
  --arg project_name "$project_name" \
443
571
  --arg scope "$scope" \
572
+ --argjson trace_context "$trace_context" \
444
573
  '{
445
574
  steps: $steps,
446
575
  errors: $errors,
@@ -454,7 +583,8 @@ export_ci_data() {
454
583
  },
455
584
  metadata: {
456
585
  scope: $scope
457
- }
586
+ },
587
+ trace_context: $trace_context
458
588
  }' > "$output_file"
459
589
 
460
590
  log_debug "CI data exported to: $output_file"
@@ -171,6 +171,9 @@ if [ "$CI_SCOPE" != "all" ]; then
171
171
  fi
172
172
  echo ""
173
173
 
174
+ # Setup trace context (generates trace_id if not provided externally)
175
+ setup_trace_context
176
+
174
177
  # Start timing
175
178
  ci_start
176
179
 
@@ -177,8 +177,9 @@ export function generateCiResult(input) {
177
177
  // Determine exit code
178
178
  const exitCode = executionStats.steps_failed > 0 ? 1 : 0
179
179
 
180
- // Get trace ID if available
181
- const traceId = getTraceId()
180
+ // Get trace ID - prefer trace_context from input (shell-generated) over env vars
181
+ const traceContext = input.trace_context || {}
182
+ const traceId = traceContext.trace_id || getTraceId()
182
183
 
183
184
  // Build meta object
184
185
  const meta = {
@@ -198,7 +199,19 @@ export function generateCiResult(input) {
198
199
  // Build extensions with telemetry if trace_id exists
199
200
  const extensions = { ...(metadata.extensions || {}) }
200
201
  if (traceId) {
201
- extensions.telemetry = buildTelemetryExtension(traceId)
202
+ // Count errors from failed steps
203
+ const errorsRecorded = executionStats.steps_failed || 0
204
+
205
+ extensions.telemetry = buildTelemetryExtension(traceId, {
206
+ errorsRecorded,
207
+ // spans_exported remains 0 until we implement actual OTel export (GAP-004/Q12)
208
+ spansExported: 0,
209
+ })
210
+
211
+ // Add trace source info if available
212
+ if (traceContext.source) {
213
+ extensions.telemetry.trace_source = traceContext.source
214
+ }
202
215
  }
203
216
 
204
217
  // Build result object
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env bash
2
+ # ==============================================================================
3
+ # Kabran Traceability Coverage Report
4
+ # Part of @kabran-owner/kabran-config
5
+ # Implements PROP-006: JSDoc Traceability Tags
6
+ #
7
+ # Generates a report of spec coverage in the codebase.
8
+ # Shows which specs have code implementing them and which ACs are covered.
9
+ # ==============================================================================
10
+
11
+ set -euo pipefail
12
+
13
+ # Source core functions
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ # shellcheck source=traceability-core.sh
16
+ source "$SCRIPT_DIR/traceability-core.sh"
17
+
18
+ # ==============================================================================
19
+ # Configuration
20
+ # ==============================================================================
21
+
22
+ SEARCH_PATH="${1:-.}"
23
+ SPEC_FILTER="${2:-}"
24
+ OUTPUT_FORMAT="${OUTPUT_FORMAT:-text}"
25
+
26
+ # ==============================================================================
27
+ # Report Functions
28
+ # ==============================================================================
29
+
30
+ # Generate report for a specific spec
31
+ report_spec() {
32
+ local spec="$1"
33
+ local files
34
+
35
+ files=$(grep -rl "@spec $spec" --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null || true)
36
+
37
+ if [ -z "$files" ]; then
38
+ return
39
+ fi
40
+
41
+ echo ""
42
+ echo "=== $spec ==="
43
+ echo ""
44
+ echo "Files:"
45
+ echo "$files" | while read -r file; do
46
+ [ -n "$file" ] && echo " - $file"
47
+ done
48
+
49
+ echo ""
50
+ echo "ACs Implemented:"
51
+ echo "$files" | while read -r file; do
52
+ [ -n "$file" ] && extract_implements "$file"
53
+ done | sort -u | while read -r ac; do
54
+ [ -n "$ac" ] && echo " - $ac"
55
+ done
56
+ }
57
+
58
+ # Generate summary report
59
+ report_summary() {
60
+ log_section "Traceability Coverage Report v${TRACEABILITY_VERSION}"
61
+ log_info "Search path: $SEARCH_PATH"
62
+ echo ""
63
+
64
+ local total_files
65
+ local tagged_files
66
+ local specs
67
+
68
+ total_files=$(count_total_files "$SEARCH_PATH")
69
+ tagged_files=$(count_tagged_files "$SEARCH_PATH")
70
+
71
+ echo "## Overview"
72
+ echo ""
73
+ echo "| Metric | Value |"
74
+ echo "|--------|-------|"
75
+ echo "| Total TypeScript files | $total_files |"
76
+ echo "| Files with @spec | $tagged_files |"
77
+
78
+ if [ "$total_files" -gt 0 ]; then
79
+ local coverage=$((tagged_files * 100 / total_files))
80
+ echo "| Coverage | $coverage% |"
81
+ fi
82
+
83
+ echo ""
84
+ echo "## Specs Found"
85
+ echo ""
86
+
87
+ # Find all unique specs
88
+ specs=$(grep -roh '@spec S[0-9]*' --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null | sed 's/@spec //' | sort -u || true)
89
+
90
+ if [ -z "$specs" ]; then
91
+ echo "No @spec tags found in codebase."
92
+ return
93
+ fi
94
+
95
+ echo "$specs" | while read -r spec; do
96
+ if [ -n "$spec" ]; then
97
+ local file_count
98
+ file_count=$(grep -rl "@spec $spec" --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null | wc -l)
99
+ echo "- **$spec**: $file_count files"
100
+ fi
101
+ done
102
+ }
103
+
104
+ # Generate detailed report for all specs
105
+ report_detailed() {
106
+ report_summary
107
+
108
+ echo ""
109
+ echo "## Detailed Coverage"
110
+
111
+ local specs
112
+ specs=$(grep -roh '@spec S[0-9]*' --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null | sed 's/@spec //' | sort -u || true)
113
+
114
+ if [ -n "$specs" ]; then
115
+ echo "$specs" | while read -r spec; do
116
+ [ -n "$spec" ] && report_spec "$spec"
117
+ done
118
+ fi
119
+ }
120
+
121
+ # Generate JSON report
122
+ report_json() {
123
+ local total_files
124
+ local tagged_files
125
+ local specs
126
+
127
+ total_files=$(count_total_files "$SEARCH_PATH")
128
+ tagged_files=$(count_tagged_files "$SEARCH_PATH")
129
+ specs=$(grep -roh '@spec S[0-9]*' --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null | sed 's/@spec //' | sort -u || true)
130
+
131
+ local coverage=0
132
+ if [ "$total_files" -gt 0 ]; then
133
+ coverage=$((tagged_files * 100 / total_files))
134
+ fi
135
+
136
+ echo "{"
137
+ echo " \"version\": \"${TRACEABILITY_VERSION}\","
138
+ echo " \"searchPath\": \"$SEARCH_PATH\","
139
+ echo " \"totalFiles\": $total_files,"
140
+ echo " \"taggedFiles\": $tagged_files,"
141
+ echo " \"coverage\": $coverage,"
142
+ echo " \"specs\": ["
143
+
144
+ local first=true
145
+ if [ -n "$specs" ]; then
146
+ echo "$specs" | while read -r spec; do
147
+ if [ -n "$spec" ]; then
148
+ local file_count
149
+ file_count=$(grep -rl "@spec $spec" --include="*.ts" --include="*.tsx" "$SEARCH_PATH" 2>/dev/null | wc -l)
150
+ if [ "$first" = true ]; then
151
+ first=false
152
+ else
153
+ echo ","
154
+ fi
155
+ echo -n " { \"id\": \"$spec\", \"files\": $file_count }"
156
+ fi
157
+ done
158
+ fi
159
+
160
+ echo ""
161
+ echo " ]"
162
+ echo "}"
163
+ }
164
+
165
+ # ==============================================================================
166
+ # Help
167
+ # ==============================================================================
168
+
169
+ show_help() {
170
+ cat << EOF
171
+ Kabran Traceability Coverage Report v${TRACEABILITY_VERSION}
172
+
173
+ Usage: coverage-report.sh [path] [spec] [options]
174
+
175
+ Arguments:
176
+ path Directory to scan (default: current directory)
177
+ spec Filter by specific spec ID (e.g., S25)
178
+
179
+ Environment Variables:
180
+ OUTPUT_FORMAT Output format: text, detailed, json (default: text)
181
+
182
+ Examples:
183
+ coverage-report.sh ./src
184
+ coverage-report.sh ./src S25
185
+ OUTPUT_FORMAT=json coverage-report.sh ./src
186
+ OUTPUT_FORMAT=detailed coverage-report.sh ./src
187
+
188
+ Output Formats:
189
+ text Summary with spec counts
190
+ detailed Full breakdown with files and ACs per spec
191
+ json Machine-readable JSON output
192
+
193
+ EOF
194
+ }
195
+
196
+ # ==============================================================================
197
+ # Entry Point
198
+ # ==============================================================================
199
+
200
+ if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
201
+ show_help
202
+ exit 0
203
+ fi
204
+
205
+ # Handle specific spec filter
206
+ if [ -n "$SPEC_FILTER" ]; then
207
+ report_spec "$SPEC_FILTER"
208
+ exit 0
209
+ fi
210
+
211
+ # Generate report based on format
212
+ case "$OUTPUT_FORMAT" in
213
+ json)
214
+ report_json
215
+ ;;
216
+ detailed)
217
+ report_detailed
218
+ ;;
219
+ *)
220
+ report_summary
221
+ ;;
222
+ esac
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bash
2
+ # ==============================================================================
3
+ # Kabran Traceability Core - Shared Functions
4
+ # Part of @kabran-owner/kabran-config
5
+ # Implements PROP-006: JSDoc Traceability Tags
6
+ # ==============================================================================
7
+
8
+ # Version - Dynamically resolve from package.json
9
+ _SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ _PKG_JSON="$_SCRIPT_DIR/../../../package.json"
11
+ if [ -f "$_PKG_JSON" ]; then
12
+ TRACEABILITY_VERSION=$(grep '"version":' "$_PKG_JSON" | head -1 | sed -E 's/.*"version": "([^"]+)".*/\1/')
13
+ else
14
+ TRACEABILITY_VERSION="unknown"
15
+ fi
16
+
17
+ # Colors
18
+ RED='\033[0;31m'
19
+ GREEN='\033[0;32m'
20
+ YELLOW='\033[1;33m'
21
+ BLUE='\033[0;34m'
22
+ GRAY='\033[0;90m'
23
+ NC='\033[0m'
24
+
25
+ # ==============================================================================
26
+ # Logging Functions
27
+ # ==============================================================================
28
+
29
+ log_info() {
30
+ echo -e "${BLUE}[INFO]${NC} $1"
31
+ }
32
+
33
+ log_success() {
34
+ echo -e "${GREEN}[PASS]${NC} $1"
35
+ }
36
+
37
+ log_error() {
38
+ echo -e "${RED}[FAIL]${NC} $1"
39
+ }
40
+
41
+ log_warn() {
42
+ echo -e "${YELLOW}[WARN]${NC} $1"
43
+ }
44
+
45
+ log_section() {
46
+ echo -e "\n${BLUE}====${NC} $1 ${BLUE}====${NC}"
47
+ }
48
+
49
+ # ==============================================================================
50
+ # Tag Patterns (PROP-006 Standard)
51
+ # ==============================================================================
52
+
53
+ # Valid @spec format: @spec SXX (ID only, not full name)
54
+ PATTERN_SPEC_VALID='@spec S[0-9]+'
55
+ PATTERN_SPEC_INVALID='@spec S[0-9]+-'
56
+
57
+ # Valid @implements format: @implements AC-XX or @implements SXX:AC-XX
58
+ PATTERN_IMPLEMENTS='@implements'
59
+
60
+ # Valid @task format: @task XXX-NNN
61
+ PATTERN_TASK='@task [A-Z]+-[0-9]+'
62
+
63
+ # Valid @prd format: @prd RF-XXX or @prd RNF-XXX
64
+ PATTERN_PRD='@prd R(N)?F-[0-9]+'
65
+
66
+ # ==============================================================================
67
+ # Validation Functions
68
+ # ==============================================================================
69
+
70
+ # Check if a file has @implements without @spec (integrity error)
71
+ # Usage: check_orphan_implements "path/to/file.ts"
72
+ # Returns: 0 if valid, 1 if orphan found
73
+ check_orphan_implements() {
74
+ local file="$1"
75
+
76
+ if grep -qE "$PATTERN_IMPLEMENTS" "$file" 2>/dev/null; then
77
+ if ! grep -qE "$PATTERN_SPEC_VALID" "$file" 2>/dev/null; then
78
+ return 1 # Orphan found
79
+ fi
80
+ fi
81
+ return 0 # Valid
82
+ }
83
+
84
+ # Check if a file uses invalid @spec format (full name instead of ID)
85
+ # Usage: check_spec_format "path/to/file.ts"
86
+ # Returns: 0 if valid, 1 if invalid format found
87
+ check_spec_format() {
88
+ local file="$1"
89
+
90
+ if grep -qE "$PATTERN_SPEC_INVALID" "$file" 2>/dev/null; then
91
+ return 1 # Invalid format
92
+ fi
93
+ return 0 # Valid
94
+ }
95
+
96
+ # Extract all @spec tags from a file
97
+ # Usage: extract_specs "path/to/file.ts"
98
+ extract_specs() {
99
+ local file="$1"
100
+ grep -oE '@spec S[0-9]+' "$file" 2>/dev/null | sed 's/@spec //' | sort -u
101
+ }
102
+
103
+ # Extract all @implements tags from a file
104
+ # Usage: extract_implements "path/to/file.ts"
105
+ extract_implements() {
106
+ local file="$1"
107
+ grep -oE '@implements [^*]+' "$file" 2>/dev/null | sed 's/@implements //' | tr ',' '\n' | sed 's/^ *//' | sort -u
108
+ }
109
+
110
+ # Count files with traceability tags
111
+ # Usage: count_tagged_files "path/to/search"
112
+ count_tagged_files() {
113
+ local search_path="${1:-.}"
114
+ grep -rl "@spec" --include="*.ts" --include="*.tsx" "$search_path" 2>/dev/null | wc -l
115
+ }
116
+
117
+ # Count total TypeScript files
118
+ # Usage: count_total_files "path/to/search"
119
+ count_total_files() {
120
+ local search_path="${1:-.}"
121
+ find "$search_path" -type f \( -name "*.ts" -o -name "*.tsx" \) 2>/dev/null | wc -l
122
+ }
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env bash
2
+ # ==============================================================================
3
+ # Kabran Traceability Validator
4
+ # Part of @kabran-owner/kabran-config
5
+ # Implements PROP-006: JSDoc Traceability Tags
6
+ #
7
+ # Validates FORMAT of traceability tags (not presence).
8
+ # Tags are optional - this script only checks:
9
+ # 1. @implements without @spec (integrity error)
10
+ # 2. @spec with full name instead of ID (format warning)
11
+ # ==============================================================================
12
+
13
+ set -uo pipefail
14
+
15
+ # Source core functions
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ # shellcheck source=traceability-core.sh
18
+ source "$SCRIPT_DIR/traceability-core.sh"
19
+
20
+ # ==============================================================================
21
+ # Configuration
22
+ # ==============================================================================
23
+
24
+ SEARCH_PATH="${1:-.}"
25
+ STRICT_MODE="${STRICT_MODE:-false}"
26
+ EXIT_CODE=0
27
+
28
+ # ==============================================================================
29
+ # Main Validation
30
+ # ==============================================================================
31
+
32
+ main() {
33
+ log_section "Traceability Validation v${TRACEABILITY_VERSION}"
34
+ log_info "Search path: $SEARCH_PATH"
35
+ log_info "Strict mode: $STRICT_MODE"
36
+
37
+ local orphan_count=0
38
+ local format_count=0
39
+ local files_checked=0
40
+
41
+ # Find all TypeScript files
42
+ local files
43
+ files=$(find "$SEARCH_PATH" -type f \( -name "*.ts" -o -name "*.tsx" \) 2>/dev/null || true)
44
+
45
+ if [ -z "$files" ]; then
46
+ log_info "No TypeScript files found"
47
+ return 0
48
+ fi
49
+
50
+ while IFS= read -r file; do
51
+ [ -z "$file" ] && continue
52
+ files_checked=$((files_checked + 1))
53
+
54
+ # Check for orphan @implements (ERROR)
55
+ if ! check_orphan_implements "$file"; then
56
+ log_error "Orphan @implements (no @spec): $file"
57
+ orphan_count=$((orphan_count + 1))
58
+ fi
59
+
60
+ # Check for invalid @spec format (WARNING)
61
+ if ! check_spec_format "$file"; then
62
+ log_warn "Invalid @spec format (use ID only): $file"
63
+ format_count=$((format_count + 1))
64
+ fi
65
+
66
+ done <<< "$files"
67
+
68
+ # Summary
69
+ log_section "Validation Summary"
70
+ log_info "Files checked: $files_checked"
71
+
72
+ if [ "$orphan_count" -gt 0 ]; then
73
+ log_error "Orphan @implements found: $orphan_count"
74
+ EXIT_CODE=1
75
+ else
76
+ log_success "No orphan @implements found"
77
+ fi
78
+
79
+ if [ "$format_count" -gt 0 ]; then
80
+ log_warn "Invalid @spec format: $format_count"
81
+ if [ "$STRICT_MODE" = "true" ]; then
82
+ EXIT_CODE=1
83
+ fi
84
+ else
85
+ log_success "All @spec tags use correct format"
86
+ fi
87
+
88
+ # Coverage stats (informational)
89
+ local tagged_files
90
+ local total_files
91
+ tagged_files=$(count_tagged_files "$SEARCH_PATH")
92
+ total_files=$(count_total_files "$SEARCH_PATH")
93
+
94
+ if [ "$total_files" -gt 0 ]; then
95
+ local coverage=$((tagged_files * 100 / total_files))
96
+ log_info "Traceability coverage: $tagged_files/$total_files files ($coverage%)"
97
+ fi
98
+
99
+ return $EXIT_CODE
100
+ }
101
+
102
+ # ==============================================================================
103
+ # Help
104
+ # ==============================================================================
105
+
106
+ show_help() {
107
+ cat << EOF
108
+ Kabran Traceability Validator v${TRACEABILITY_VERSION}
109
+
110
+ Usage: validate-traceability.sh [path] [options]
111
+
112
+ Arguments:
113
+ path Directory to validate (default: current directory)
114
+
115
+ Environment Variables:
116
+ STRICT_MODE If "true", format warnings become errors (default: false)
117
+
118
+ Exit Codes:
119
+ 0 Validation passed
120
+ 1 Validation failed (orphan @implements or strict mode violations)
121
+
122
+ Examples:
123
+ validate-traceability.sh ./src
124
+ STRICT_MODE=true validate-traceability.sh ./src
125
+
126
+ Tags Validated (PROP-006):
127
+ @spec S25 Link to spec (ID only, not full name)
128
+ @implements AC-01 Acceptance criteria implemented
129
+ @task AGT-123 Link to Linear task
130
+ @prd RF-007 Link to PRD requirement
131
+
132
+ Rules:
133
+ - All tags are OPTIONAL
134
+ - @implements WITHOUT @spec is an ERROR
135
+ - @spec with full name (S25-name) is a WARNING
136
+
137
+ EOF
138
+ }
139
+
140
+ # ==============================================================================
141
+ # Entry Point
142
+ # ==============================================================================
143
+
144
+ if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
145
+ show_help
146
+ exit 0
147
+ fi
148
+
149
+ main
150
+ exit $EXIT_CODE
@@ -0,0 +1,407 @@
1
+ # @kabran-tecnologia/kabran-config/telemetry
2
+
3
+ Unified telemetry package for Kabran projects using OpenTelemetry.
4
+
5
+ ## Features
6
+
7
+ - **Multi-runtime support**: Node.js, Frontend (Browser), Edge/Serverless
8
+ - **OpenTelemetry integration**: W3C Trace Context, OTLP export
9
+ - **Zero-config defaults**: Works out of the box with sensible defaults
10
+ - **Structured logging**: Logger with automatic trace correlation
11
+ - **Tree-shakeable**: Import only what you need
12
+
13
+ ## Installation
14
+
15
+ The telemetry modules are included in `@kabran-tecnologia/kabran-config`. Install the package and the required OpenTelemetry peer dependencies:
16
+
17
+ ```bash
18
+ # Install kabran-config
19
+ npm install @kabran-tecnologia/kabran-config
20
+
21
+ # Install required peer dependencies (pick based on your runtime)
22
+
23
+ # For Node.js:
24
+ npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions
25
+
26
+ # For Frontend:
27
+ npm install @opentelemetry/api @opentelemetry/sdk-trace-web @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/instrumentation-fetch @opentelemetry/instrumentation-document-load @opentelemetry/instrumentation-user-interaction
28
+
29
+ # For Edge/Serverless:
30
+ npm install @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ### Node.js (Express/Fastify)
36
+
37
+ ```javascript
38
+ // instrumentation.js - Import this FIRST in your app
39
+ import { initTelemetry, telemetryMiddleware, shutdownTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/node'
40
+
41
+ // Initialize telemetry
42
+ initTelemetry({
43
+ serviceName: 'my-api',
44
+ serviceVersion: '1.0.0',
45
+ })
46
+
47
+ // In your Express app
48
+ import express from 'express'
49
+ const app = express()
50
+
51
+ // Add telemetry middleware (creates spans for each request)
52
+ app.use(telemetryMiddleware())
53
+
54
+ app.get('/api/users', (req, res) => {
55
+ // Your handler - automatically traced
56
+ res.json({ users: [] })
57
+ })
58
+
59
+ // Graceful shutdown
60
+ process.on('SIGTERM', async () => {
61
+ await shutdownTelemetry()
62
+ process.exit(0)
63
+ })
64
+ ```
65
+
66
+ ### Frontend (React/Vite)
67
+
68
+ ```typescript
69
+ // main.tsx
70
+ import { initTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/frontend'
71
+
72
+ // Initialize before rendering
73
+ initTelemetry({
74
+ serviceName: 'my-frontend',
75
+ serviceVersion: '1.0.0',
76
+ // Optional: customize which events to trace
77
+ instrumentation: {
78
+ userInteractionEvents: ['click', 'submit'],
79
+ },
80
+ })
81
+
82
+ // Your React app renders normally
83
+ import { createRoot } from 'react-dom/client'
84
+ import App from './App'
85
+
86
+ createRoot(document.getElementById('root')!).render(<App />)
87
+ ```
88
+
89
+ ### Edge/Serverless (Supabase Functions)
90
+
91
+ ```typescript
92
+ // supabase/functions/my-function/index.ts
93
+ import { withTelemetry, traceSupabaseQuery } from '@kabran-tecnologia/kabran-config/telemetry/edge'
94
+ import { createClient } from '@supabase/supabase-js'
95
+
96
+ const supabase = createClient(
97
+ Deno.env.get('SUPABASE_URL')!,
98
+ Deno.env.get('SUPABASE_ANON_KEY')!
99
+ )
100
+
101
+ // Wrap your handler with telemetry
102
+ Deno.serve(withTelemetry(
103
+ {
104
+ serviceName: 'my-edge-function',
105
+ serviceVersion: '1.0.0',
106
+ },
107
+ async (req) => {
108
+ // Trace Supabase queries
109
+ const { data, error } = await traceSupabaseQuery(
110
+ 'select-users',
111
+ () => supabase.from('users').select('*')
112
+ )
113
+
114
+ return new Response(JSON.stringify({ data, error }), {
115
+ headers: { 'Content-Type': 'application/json' },
116
+ })
117
+ }
118
+ ))
119
+ ```
120
+
121
+ ## Structured Logging
122
+
123
+ The logger automatically includes trace context in log output:
124
+
125
+ ```javascript
126
+ import { createLogger } from '@kabran-tecnologia/kabran-config/telemetry/logger'
127
+
128
+ const log = createLogger()
129
+
130
+ log.info('User logged in', { userId: '123' })
131
+ // Output (JSON in production):
132
+ // {"level":"info","message":"User logged in","userId":"123","trace_id":"abc123...","span_id":"def456...","timestamp":"2024-01-13T..."}
133
+
134
+ // Output (pretty in development):
135
+ // 2024-01-13T12:00:00.000Z [INFO] User logged in [trace:abc123...] {"userId":"123"}
136
+ ```
137
+
138
+ ### Span-bound Logger
139
+
140
+ ```javascript
141
+ import { trace } from '@opentelemetry/api'
142
+ import { createSpanLogger } from '@kabran-tecnologia/kabran-config/telemetry/logger'
143
+
144
+ const span = trace.getActiveSpan()
145
+ const log = createSpanLogger(span)
146
+
147
+ log.info('Processing order', { orderId: '456' })
148
+ // Logs are also added as span events for visibility in traces
149
+ ```
150
+
151
+ ## Configuration
152
+
153
+ ### Environment Variables
154
+
155
+ All configuration can be set via environment variables:
156
+
157
+ ```bash
158
+ # Core
159
+ SERVICE_NAME=my-service # Required: Your service name
160
+ SERVICE_VERSION=1.0.0 # Service version (default: 1.0.0)
161
+ ENVIRONMENT=production # Environment name (default: from NODE_ENV)
162
+ OTEL_NAMESPACE=kabran # Service namespace (default: kabran)
163
+
164
+ # OTLP Exporter
165
+ OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.kabran.com.br # Collector endpoint
166
+ OTEL_EXPORTER_OTLP_TIMEOUT=10000 # Export timeout in ms (default: 10000)
167
+
168
+ # Sampling
169
+ OTEL_SAMPLE_RATE=0.1 # Sampling rate 0.0-1.0 (default: 0.1 = 10%)
170
+
171
+ # Enable/Disable
172
+ OTEL_ENABLED=true # Enable telemetry (default: true in production)
173
+
174
+ # Logger
175
+ OTEL_LOG_TRACE_ID_LENGTH=8 # Trace ID length in logs (default: 8)
176
+ NO_COLOR=1 # Disable ANSI colors in logs
177
+ ```
178
+
179
+ ### Programmatic Configuration
180
+
181
+ ```javascript
182
+ import { initTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/node'
183
+
184
+ initTelemetry({
185
+ // Required
186
+ serviceName: 'my-service',
187
+
188
+ // Optional (all have sensible defaults)
189
+ serviceVersion: '1.0.0',
190
+ environment: 'production',
191
+ endpoint: 'https://otel.kabran.com.br',
192
+ sampleRate: 0.1,
193
+ enabled: true,
194
+
195
+ // Resource attributes (added to all spans)
196
+ resourceAttributes: {
197
+ 'deployment.environment': 'production',
198
+ 'service.instance.id': process.env.POD_NAME,
199
+ },
200
+
201
+ // Batch processor settings (Node.js only)
202
+ batchProcessor: {
203
+ maxQueueSize: 2048,
204
+ maxExportBatchSize: 512,
205
+ scheduledDelayMillis: 5000,
206
+ },
207
+ })
208
+ ```
209
+
210
+ ## Module Reference
211
+
212
+ ### `telemetry/node`
213
+
214
+ For Node.js servers and long-running processes.
215
+
216
+ ```javascript
217
+ import {
218
+ initTelemetry, // Initialize the tracer
219
+ shutdownTelemetry, // Graceful shutdown
220
+ telemetryMiddleware,// Express/Fastify middleware
221
+ isInitialized, // Check if initialized
222
+ getTracer, // Get the tracer instance
223
+ getConfig, // Get resolved config
224
+ } from '@kabran-tecnologia/kabran-config/telemetry/node'
225
+ ```
226
+
227
+ ### `telemetry/frontend`
228
+
229
+ For browser applications (React, Vue, vanilla JS).
230
+
231
+ ```javascript
232
+ import {
233
+ initTelemetry, // Initialize the tracer
234
+ shutdownTelemetry, // Flush pending spans
235
+ isInitialized, // Check if initialized
236
+ getTracer, // Get the tracer instance
237
+ getConfig, // Get resolved config
238
+ } from '@kabran-tecnologia/kabran-config/telemetry/frontend'
239
+ ```
240
+
241
+ ### `telemetry/edge`
242
+
243
+ For Edge Functions and serverless (Supabase, Deno Deploy, Cloudflare Workers).
244
+
245
+ ```javascript
246
+ import {
247
+ withTelemetry, // Handler wrapper with auto-tracing
248
+ traceSupabaseQuery, // Trace Supabase queries
249
+ shutdownTelemetry, // Flush pending spans
250
+ isInitialized, // Check if initialized
251
+ getConfig, // Get resolved config
252
+ } from '@kabran-tecnologia/kabran-config/telemetry/edge'
253
+ ```
254
+
255
+ ### `telemetry/logger`
256
+
257
+ Structured logger with trace correlation.
258
+
259
+ ```javascript
260
+ import {
261
+ createLogger, // Create a logger instance
262
+ createSpanLogger, // Create a span-bound logger
263
+ log, // Default logger instance
264
+ getTraceContext, // Get current trace context
265
+ } from '@kabran-tecnologia/kabran-config/telemetry/logger'
266
+ ```
267
+
268
+ ### `telemetry/config`
269
+
270
+ Configuration utilities.
271
+
272
+ ```javascript
273
+ import {
274
+ defineTelemetryConfig, // Create a type-safe config
275
+ resolveConfig, // Resolve config with defaults and env vars
276
+ validateConfig, // Validate config object
277
+ detectEnabled, // Check if telemetry should be enabled
278
+ } from '@kabran-tecnologia/kabran-config/telemetry/config'
279
+ ```
280
+
281
+ ### `telemetry/shared`
282
+
283
+ Shared utilities and types.
284
+
285
+ ```javascript
286
+ import {
287
+ setAttributes, // Set multiple span attributes
288
+ formatDuration, // Format milliseconds to human-readable
289
+ generateInvocationId, // Generate unique invocation ID
290
+ safeWarn, // Safe console.warn
291
+ safeLog, // Safe console.log
292
+ } from '@kabran-tecnologia/kabran-config/telemetry/shared'
293
+ ```
294
+
295
+ ## Integration with Kosmos Observability
296
+
297
+ This package is designed to work with the Kosmos observability stack:
298
+
299
+ - **Traces** → Grafana Tempo
300
+ - **Logs** → Grafana Loki (via stdout/Promtail or direct export)
301
+ - **Metrics** → Prometheus (planned, see [GAP-006])
302
+
303
+ Default endpoint: `https://otel.kabran.com.br`
304
+
305
+ ### Viewing Traces
306
+
307
+ 1. Open Grafana at your Kosmos instance
308
+ 2. Go to Explore → Select Tempo
309
+ 3. Search by service name or trace ID
310
+
311
+ ## Best Practices
312
+
313
+ ### 1. Initialize Early
314
+
315
+ Initialize telemetry as early as possible in your application:
316
+
317
+ ```javascript
318
+ // This should be the FIRST import
319
+ import './instrumentation.js'
320
+
321
+ // Then your app code
322
+ import express from 'express'
323
+ ```
324
+
325
+ ### 2. Use Meaningful Span Names
326
+
327
+ ```javascript
328
+ // Good
329
+ span.updateName('user.create')
330
+ span.updateName('order.process')
331
+
332
+ // Bad
333
+ span.updateName('handler')
334
+ span.updateName('function1')
335
+ ```
336
+
337
+ ### 3. Add Relevant Attributes
338
+
339
+ ```javascript
340
+ import { trace } from '@opentelemetry/api'
341
+
342
+ const span = trace.getActiveSpan()
343
+ span?.setAttributes({
344
+ 'user.id': userId,
345
+ 'order.id': orderId,
346
+ 'order.total': total,
347
+ })
348
+ ```
349
+
350
+ ### 4. Handle Errors Properly
351
+
352
+ ```javascript
353
+ import { trace, SpanStatusCode } from '@opentelemetry/api'
354
+
355
+ try {
356
+ // Your code
357
+ } catch (error) {
358
+ const span = trace.getActiveSpan()
359
+ span?.recordException(error)
360
+ span?.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
361
+ throw error
362
+ }
363
+ ```
364
+
365
+ ### 5. Graceful Shutdown
366
+
367
+ Always flush pending spans before shutdown:
368
+
369
+ ```javascript
370
+ process.on('SIGTERM', async () => {
371
+ await shutdownTelemetry()
372
+ process.exit(0)
373
+ })
374
+ ```
375
+
376
+ ## Troubleshooting
377
+
378
+ ### Traces not appearing
379
+
380
+ 1. Check `OTEL_ENABLED` is not set to `false`
381
+ 2. Verify `SERVICE_NAME` is set
382
+ 3. Check network connectivity to the collector endpoint
383
+ 4. Verify sampling rate (default is 10%)
384
+
385
+ ### Missing trace correlation in logs
386
+
387
+ 1. Ensure telemetry is initialized before logging
388
+ 2. Check that you're within an active span context
389
+
390
+ ### High memory usage
391
+
392
+ Reduce batch processor queue size:
393
+
394
+ ```javascript
395
+ initTelemetry({
396
+ serviceName: 'my-service',
397
+ batchProcessor: {
398
+ maxQueueSize: 512, // Lower from default 2048
399
+ },
400
+ })
401
+ ```
402
+
403
+ ## Related Documentation
404
+
405
+ - [OpenTelemetry JavaScript](https://opentelemetry.io/docs/languages/js/)
406
+ - [W3C Trace Context](https://www.w3.org/TR/trace-context/)
407
+ - [Kosmos Observability Stack](https://github.com/kabran-owner/kosmos/tree/main/services/observability)