@ccoalm/ccl-skills 0.18.5 → 0.18.7
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/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-policy.md +5 -4
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +11 -9
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/host-input.py +135 -11
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/remind-review-covers-head.sh +34 -9
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh +14 -3
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-loading.py +39 -2
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_host_input.py +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_proposed_next.py +180 -3
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_remind_review_covers_head.sh +19 -3
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_skill_loading.py +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/development-completion.md +4 -3
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +11 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +65 -11
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +4 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_cli_review_wrappers.sh +158 -6
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +39 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +48 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +5 -5
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-review-gate-mechanics.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +4 -3
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/review-reception.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/firing-point-placement.md +1 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +2 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-size-budget.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-sync-pointers.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +11 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_body_compliance_grading.sh +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +4 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_register_pending_exclusion.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_route_drift.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_size_budget.sh +4 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_source_register_lifecycle.sh +9 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_sync_pointers.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_grader_diagnostics.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_resolution.sh +32 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_surface_binding.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_prose_target.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_dateless_host.sh +3 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_verdict_differential.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_round_attribution.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_self_adjudication.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_source_refuted.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_locale_independent_gates.sh +264 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_resolution.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_delivery_contract.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_loading_budget.sh +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +2 -0
- package/dist/assets/release.json +61 -56
- package/package.json +1 -1
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
# Oracle: an always-refuse candidate fails on the pins; an always-accept
|
|
37
37
|
# candidate fails on the baseline-red case. Both arms are exercised.
|
|
38
38
|
set -euo pipefail
|
|
39
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
40
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
39
41
|
|
|
40
42
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
41
43
|
CANDIDATE_GATE="$SCRIPT_DIR/impact-chain-gate.rb"
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
# mistake were observed while writing this file. Do not "fix" a leg by relaxing
|
|
36
36
|
# its assertion.
|
|
37
37
|
set -euo pipefail
|
|
38
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
39
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
38
40
|
|
|
39
41
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
40
42
|
# REVERSE DIFFERENTIAL. Each leg below states which gate behavior it pins, and a
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# 期望红的用例都必须点名 WHICH refusal:rc 单独是弱 oracle,为无关原因(fixture 缺陷、
|
|
15
15
|
# 锚点断掉)红同样是 rc=1,会把「形态已关闭」读成绿。
|
|
16
16
|
set -u
|
|
17
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
18
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
17
19
|
ROOT="$(cd "$(dirname "$0")/../../.." && pwd -P)"
|
|
18
20
|
GATE="$ROOT/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb"
|
|
19
21
|
LEDGER_REL="skills/skill-extraction-workflow/references/source-register.md"
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
#
|
|
8
8
|
# 全部确定性,不调模型。每用例一条分支,互不影响本地未提交改动。
|
|
9
9
|
set -u
|
|
10
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
11
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
10
12
|
ROOT="$(cd "$(dirname "$0")/../../.." && pwd -P)"
|
|
11
13
|
GATE="$ROOT/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb"
|
|
12
14
|
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT INT TERM
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Regression: the repository gates must not depend on the caller's locale.
|
|
3
|
+
# Under a POSIX/unset locale Ruby defaults to US-ASCII, so a gate that reads the
|
|
4
|
+
# UTF-8 skill text (or runs a `ruby -e` program with UTF-8 literals) crashed with
|
|
5
|
+
# "invalid byte sequence in US-ASCII" before checking anything, while CI (which
|
|
6
|
+
# runs C.UTF-8) stayed green. Each ruby-invoking script pins `RUBYOPT=-Ku`.
|
|
7
|
+
# (1) every tracked live shell script (skills/, hooks/, scripts/) and every
|
|
8
|
+
# Makefile target that invokes ruby carries the pin, and no other literal RUBYOPT mention drops it; the
|
|
9
|
+
# classifier is held by pinned bypass and near-miss rows; frozen evidence
|
|
10
|
+
# under specs/ and eval/ is exempt;
|
|
11
|
+
# (2) validate-skill.sh passes on a UTF-8 fixture under LC_ALL=C;
|
|
12
|
+
# (3) the same run with the pin deleted goes red for the encoding reason, which
|
|
13
|
+
# shows the pin is what makes leg (2) pass; on a host whose C locale already
|
|
14
|
+
# reads UTF-8 the pin is not load-bearing and leg (3) reports unevaluated.
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
17
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
20
|
+
ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd -P)"
|
|
21
|
+
PIN='case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac'
|
|
22
|
+
fail() { printf 'FAIL: %b\n' "$*" >&2; exit 1; }
|
|
23
|
+
|
|
24
|
+
# Closed contract over the idiom this repo owns: a RUBYOPT mention keeps the pin
|
|
25
|
+
# only as the pin line itself, the keep idiom RUBYOPT="${RUBYOPT:+$RUBYOPT }..."
|
|
26
|
+
# whose suffix holds only `-r<lib>` requires or variables, or an empty RUBYOPT=
|
|
27
|
+
# before `bash "$script"` (that script pins itself). Any other literal mention -
|
|
28
|
+
# replacing, clearing, unset, env -u, any other Ruby option - drops the pin.
|
|
29
|
+
# Ruby's option names are not this repo's to enumerate, so the suffix is
|
|
30
|
+
# allowlisted, never denylisted. Returns 0 when allowed.
|
|
31
|
+
KEEP_TOKEN='(-r[^[:space:]"\\]+|[$][{]?[A-Za-z_0-9]+[}]?)'
|
|
32
|
+
pin_kept() {
|
|
33
|
+
local line="$1" rest
|
|
34
|
+
[ "$line" = "$PIN" ] && return 0
|
|
35
|
+
# An attribute builtin on the variable can unexport or rescope it even when
|
|
36
|
+
# the value is the keep idiom.
|
|
37
|
+
if printf '%s\n' "$line" | grep -qE '(^|[[:space:];&|({])(declare|typeset|local|readonly|export[[:space:]]+-n)([[:space:]]|$)[^;|&]*RUBYOPT'; then
|
|
38
|
+
return 1
|
|
39
|
+
fi
|
|
40
|
+
rest="$(printf '%s\n' "$line" | sed -E \
|
|
41
|
+
-e "s/^([^\"'\\\\]*)[[:space:]]#.*\$/\\1/" \
|
|
42
|
+
-e "s/RUBYOPT=\"[\$][{]RUBYOPT:[+][\$]RUBYOPT [}](${KEEP_TOKEN}([[:space:]]+${KEEP_TOKEN})*)?\"//g" \
|
|
43
|
+
-e 's/(^|[[:space:]])RUBYOPT=[[:space:]]+bash[[:space:]]+"[$][A-Za-z_{][^"]*"/\1/g')"
|
|
44
|
+
case "$rest" in *RUBYOPT*) return 1 ;; esac
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Every RUBYOPT line of one file that drops the pin, as "N:line". Whole-line
|
|
49
|
+
# comments are skipped; nothing else is pre-filtered, so a line that merely
|
|
50
|
+
# contains the pin text is still classified.
|
|
51
|
+
pin_drops() {
|
|
52
|
+
local hit
|
|
53
|
+
while IFS= read -r hit; do
|
|
54
|
+
pin_kept "${hit#*:}" || printf '%s\n' "$hit"
|
|
55
|
+
done < <(grep -nE 'RUBYOPT' "$1" | grep -vE '^[0-9]+:[[:space:]]*#' || true)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# (1a) The classifier itself: every bypass row must be flagged and every
|
|
59
|
+
# near-miss row must stay allowed, so a broken classifier cannot pass on a
|
|
60
|
+
# corpus that happens to hold only allowed shapes.
|
|
61
|
+
while IFS= read -r row; do
|
|
62
|
+
[ -n "$row" ] || continue
|
|
63
|
+
if pin_kept "$row"; then fail "classifier allowed a pin-dropping line: $row"; fi
|
|
64
|
+
done <<'ROWS'
|
|
65
|
+
RUBYOPT="-r$SHIM" ruby x.rb
|
|
66
|
+
RUBYOPT= ruby -e "p 1"
|
|
67
|
+
unset RUBYOPT
|
|
68
|
+
env -u RUBYOPT ruby -e 1
|
|
69
|
+
RUBYOPT="$RUBYOPT_EXTRA -rfoo" ruby -e 1
|
|
70
|
+
export RUBYOPT=
|
|
71
|
+
RUBYOPT=
|
|
72
|
+
RUBYOPT= LC_ALL=C ruby -e 1
|
|
73
|
+
LC_ALL=C RUBYOPT= LANG=C ruby -e 1
|
|
74
|
+
RUBYOPT= exec ruby -e 1
|
|
75
|
+
RUBYOPT= "${RUBY:-ruby}" -e 1
|
|
76
|
+
RUBYOPT= bash -c "ruby -e 1"
|
|
77
|
+
unset -v RUBYOPT
|
|
78
|
+
unset LANG RUBYOPT
|
|
79
|
+
env --unset=RUBYOPT ruby -e 1
|
|
80
|
+
env -uRUBYOPT ruby -e 1
|
|
81
|
+
RUBYOPT=-W0 ruby -e 1 "$RUBYOPT"
|
|
82
|
+
RUBYOPT="${RUBYOPT#-Ku}" ruby -e 1
|
|
83
|
+
RUBYOPT="" bash x.sh
|
|
84
|
+
export RUBYOPT=-W0
|
|
85
|
+
echo "a #b"; RUBYOPT=-Kn ruby -e 1
|
|
86
|
+
printf ' #' ; unset RUBYOPT
|
|
87
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac; unset RUBYOPT
|
|
88
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }-Kn" ruby x.rb
|
|
89
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }-E ASCII" ruby x.rb
|
|
90
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }--internal-encoding=US-ASCII" ruby x.rb
|
|
91
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }--disable=rubyopt" ruby x.rb
|
|
92
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }-r\" -Kn" ruby x.rb
|
|
93
|
+
export -n RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate"
|
|
94
|
+
declare +x RUBYOPT="${RUBYOPT:+$RUBYOPT }"
|
|
95
|
+
local RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate"
|
|
96
|
+
readonly RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate"
|
|
97
|
+
typeset -x RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate"
|
|
98
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT_EXTRA }" ruby x.rb
|
|
99
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT}-Kn" ruby x.rb
|
|
100
|
+
x=$#; unset RUBYOPT
|
|
101
|
+
echo a\ #b; unset RUBYOPT
|
|
102
|
+
local RUBYOPT
|
|
103
|
+
declare -x RUBYOPT=
|
|
104
|
+
ROWS
|
|
105
|
+
while IFS= read -r row; do
|
|
106
|
+
[ -n "$row" ] || continue
|
|
107
|
+
pin_kept "$row" || fail "classifier flagged an allowed line: $row"
|
|
108
|
+
done <<'ROWS'
|
|
109
|
+
out="$(RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate" ruby x.rb)"
|
|
110
|
+
env -u X LC_ALL=C RUBYOPT= bash "$SIZE_SCRIPT" "$REPO"
|
|
111
|
+
f() { # takes a RUBYOPT value
|
|
112
|
+
RUBYOPT= bash "$x"; ruby -e 1
|
|
113
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }-r$SHIM -rdate" ruby x.rb
|
|
114
|
+
RUBYOPT="${RUBYOPT:+$RUBYOPT }$2" ruby "$1"
|
|
115
|
+
run_gate() { # <gate-path> <RUBYOPT value or empty>
|
|
116
|
+
locale=C RUBYOPT= bash "$x"
|
|
117
|
+
dir=/usr/local RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate" ruby x.rb
|
|
118
|
+
declared=1 RUBYOPT= bash "$s"
|
|
119
|
+
ROWS
|
|
120
|
+
|
|
121
|
+
# (1b) Static coverage over tracked live shell scripts.
|
|
122
|
+
tracked="$(git -C "$ROOT" ls-files -- 'skills/*.sh' 'hooks/*.sh' 'scripts/*.sh')" \
|
|
123
|
+
|| fail "cannot list tracked scripts (not a git checkout?); leg 1 needs git ls-files"
|
|
124
|
+
[ -n "$tracked" ] || fail "git ls-files listed no tracked scripts under $ROOT; leg 1 would pass vacuously"
|
|
125
|
+
missing=""
|
|
126
|
+
dropped=""
|
|
127
|
+
while IFS= read -r rel; do
|
|
128
|
+
# A bare `ruby` word: catches `ruby -e`, `ruby<<`, `ruby;`, `${RUBY:-ruby}`;
|
|
129
|
+
# leaves `rubygems` / `ruby-build` alone. Over-matching only over-requires the pin.
|
|
130
|
+
grep -qE '(^|[^a-z_])ruby([^a-z0-9_.-]|$)' "$ROOT/$rel" || continue
|
|
131
|
+
grep -qxF "$PIN" "$ROOT/$rel" || missing="$missing\n $rel"
|
|
132
|
+
# This file names RUBYOPT in its own patterns and rows, so only its pin is checked.
|
|
133
|
+
[ "$rel" = "skills/skill-extraction-workflow/scripts/test_locale_independent_gates.sh" ] && continue
|
|
134
|
+
while IFS= read -r hit; do
|
|
135
|
+
[ -n "$hit" ] && dropped="$dropped\n $rel: $hit"
|
|
136
|
+
done < <(pin_drops "$ROOT/$rel")
|
|
137
|
+
done <<<"$tracked"
|
|
138
|
+
# Makefile targets that run ruby in a recipe must be on the target-specific
|
|
139
|
+
# RUBYOPT pin line. A rule line names every target before its first colon
|
|
140
|
+
# (`a b: deps`); `X := y` assignments and the pin line itself are not rules.
|
|
141
|
+
mk_pinned_of() { sed -nE 's/^([^#:]*):[[:space:]]*override RUBYOPT :=.*-Ku.*$/\1/p' "$1"; }
|
|
142
|
+
mk_ruby_of() {
|
|
143
|
+
awk '
|
|
144
|
+
/^\t/ { if ($0 ~ /(^|[^a-z_])ruby([^a-z0-9_.-]|$)/) for (i in cur) print cur[i]; next }
|
|
145
|
+
/^[^#[:space:]]/ {
|
|
146
|
+
c = index($0, ":"); if (c == 0) next
|
|
147
|
+
head = substr($0, 1, c - 1)
|
|
148
|
+
if (substr($0, c + 1, 1) == "=" || head ~ /=/) next
|
|
149
|
+
if ($0 ~ /RUBYOPT :=/) next
|
|
150
|
+
split("", cur); n = split(head, names, /[[:space:]]+/)
|
|
151
|
+
for (i = 1; i <= n; i++) if (names[i] != "") cur[i] = names[i]
|
|
152
|
+
}' "$1" | sort -u
|
|
153
|
+
}
|
|
154
|
+
mk_missing_of() { # <Makefile>: ruby-running targets absent from the pin line
|
|
155
|
+
local pinned t
|
|
156
|
+
grep -qxF 'export RUBYOPT' "$1" || { echo "(RUBYOPT is not exported)"; return; }
|
|
157
|
+
pinned="$(mk_pinned_of "$1")"
|
|
158
|
+
[ -n "$pinned" ] || { echo "(no target-specific RUBYOPT -Ku pin line)"; return; }
|
|
159
|
+
for t in $(mk_ruby_of "$1"); do
|
|
160
|
+
case " $pinned " in *" $t "*) ;; *) echo "$t" ;; esac
|
|
161
|
+
done
|
|
162
|
+
}
|
|
163
|
+
[ -n "$(mk_ruby_of "$ROOT/Makefile")" ] || fail "found no Makefile recipe that runs ruby; the Makefile check would pass vacuously"
|
|
164
|
+
for t in $(mk_missing_of "$ROOT/Makefile"); do missing="$missing\n Makefile target $t"; done
|
|
165
|
+
# The tracker itself, on a fixture: a multi-target ruby rule after a pinned one
|
|
166
|
+
# must be reported under its own names, and an assignment line must not reset it.
|
|
167
|
+
mk_fx="$(mktemp "${TMPDIR:-/tmp}/locale-mk.XXXXXX")"
|
|
168
|
+
printf 'X := 1\nexport RUBYOPT\np1 p2: override RUBYOPT := -Ku\np1:\n\truby a.rb\nnew-a new-b: dep\n\t@ruby b.rb\nY := 2\n\techo no\n' >"$mk_fx"
|
|
169
|
+
mk_fx_out="$(mk_missing_of "$mk_fx" | tr '\n' ' ')"
|
|
170
|
+
rm -f "$mk_fx"
|
|
171
|
+
[ "$mk_fx_out" = "new-a new-b " ] || fail "Makefile tracker must report exactly new-a new-b on its fixture, got: $mk_fx_out"
|
|
172
|
+
[ -z "$missing" ] || fail "ruby-invoking scripts without the RUBYOPT UTF-8 pin:$missing"
|
|
173
|
+
[ -z "$dropped" ] || fail "RUBYOPT mentions that drop the UTF-8 pin (use the keep idiom):$dropped"
|
|
174
|
+
|
|
175
|
+
TMP="$(mktemp -d "${TMPDIR:-/tmp}/locale-gates.XXXXXX")"
|
|
176
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
177
|
+
|
|
178
|
+
# Exercise the actual Makefile declarations using inert recipes. In particular,
|
|
179
|
+
# command-line RUBYOPT must not override the UTF-8 pin. Replacing just the recipes
|
|
180
|
+
# keeps live evals offline and preserves Make's assignment/export semantics.
|
|
181
|
+
make_targets="$(mk_ruby_of "$ROOT/Makefile" | tr '\n' ' ')"
|
|
182
|
+
printf '%s:\n' "$make_targets" >"$TMP/probe.mk"
|
|
183
|
+
printf '\t@ruby -e '\''abort "make recipe lost UTF-8" unless Encoding.default_external == Encoding::UTF_8; abort "make recipe lost caller option" if ENV["CCL_MAKE_CALLER_OPTION"] == "yes" && !ENV.fetch("RUBYOPT").split.include?("-W0")'\''\n' >>"$TMP/probe.mk"
|
|
184
|
+
run_make_pin() {
|
|
185
|
+
local makefile="$1"
|
|
186
|
+
shift
|
|
187
|
+
env -u LANGUAGE -u RUBYOPT LC_ALL=C LANG=C make --no-print-directory \
|
|
188
|
+
-f "$makefile" -f "$TMP/probe.mk" "$@" $make_targets
|
|
189
|
+
}
|
|
190
|
+
if ! make_out="$(run_make_pin "$ROOT/Makefile" RUBYOPT=-W0 CCL_MAKE_CALLER_OPTION=yes 2>&1)"; then
|
|
191
|
+
fail "Makefile Ruby targets failed under LC_ALL=C with CLI RUBYOPT:\n$make_out"
|
|
192
|
+
fi
|
|
193
|
+
if ! make_out="$(run_make_pin "$ROOT/Makefile" 2>&1)"; then
|
|
194
|
+
fail "Makefile Ruby targets failed with RUBYOPT absent:\n$make_out"
|
|
195
|
+
fi
|
|
196
|
+
# Applied mutations prove both declarations matter at runtime, as well as in
|
|
197
|
+
# the static tracker. CLI variables are auto-exported by Make, so the export
|
|
198
|
+
# mutation must run without the CLI override to avoid masking a missing export.
|
|
199
|
+
sed 's/: override RUBYOPT :=/: RUBYOPT :=/' "$ROOT/Makefile" >"$TMP/no-override.mk"
|
|
200
|
+
sed '/^export RUBYOPT$/d' "$ROOT/Makefile" >"$TMP/no-export.mk"
|
|
201
|
+
for mutant in no-override no-export; do
|
|
202
|
+
cmp -s "$ROOT/Makefile" "$TMP/$mutant.mk" && fail "$mutant mutation was not applied"
|
|
203
|
+
[ -n "$(mk_missing_of "$TMP/$mutant.mk")" ] || fail "Makefile tracker accepted $mutant mutation"
|
|
204
|
+
make_args=()
|
|
205
|
+
[ "$mutant" != no-override ] || make_args=(RUBYOPT=-W0)
|
|
206
|
+
# Bash 3.2 treats an empty array as unset under nounset.
|
|
207
|
+
if make_out="$(run_make_pin "$TMP/$mutant.mk" ${make_args[@]+"${make_args[@]}"} 2>&1)"; then
|
|
208
|
+
fail "Makefile $mutant mutation still passed the UTF-8 assertion"
|
|
209
|
+
fi
|
|
210
|
+
case "$make_out" in *'make recipe lost UTF-8'*) : ;; *) fail "$mutant failed for an unrelated reason:\n$make_out" ;; esac
|
|
211
|
+
done
|
|
212
|
+
|
|
213
|
+
# (1c) The scan as a whole, on a fixture file: only a line that drops the pin is
|
|
214
|
+
# reported, including one that also contains the pin text.
|
|
215
|
+
{
|
|
216
|
+
printf '%s\n' "$PIN"
|
|
217
|
+
printf '%s; unset RUBYOPT\n' "$PIN"
|
|
218
|
+
printf '# unset RUBYOPT in a comment\n'
|
|
219
|
+
printf 'out="$(RUBYOPT="${RUBYOPT:+$RUBYOPT }-rdate" ruby x.rb)"\n'
|
|
220
|
+
} >"$TMP/scan-fixture.sh"
|
|
221
|
+
scan_out="$(pin_drops "$TMP/scan-fixture.sh")"
|
|
222
|
+
[ "${scan_out%%:*}" = "2" ] && [ "$(printf '%s\n' "$scan_out" | grep -c .)" = "1" ] \
|
|
223
|
+
|| fail "pin_drops must report only line 2 of the scan fixture, got:\n$scan_out"
|
|
224
|
+
mkdir -p "$TMP/skill/references"
|
|
225
|
+
cat >"$TMP/skill/SKILL.md" <<'EOF'
|
|
226
|
+
---
|
|
227
|
+
name: locale-fixture
|
|
228
|
+
description: 合成夹具 — synthetic fixture for locale independence.
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
# 夹具
|
|
232
|
+
|
|
233
|
+
见 `references/detail.md`。
|
|
234
|
+
EOF
|
|
235
|
+
printf '# 细节\n\n中文正文。\n' >"$TMP/skill/references/detail.md"
|
|
236
|
+
|
|
237
|
+
run_c_locale() { env -u LANGUAGE LC_ALL=C LANG=C RUBYOPT= bash "$1" "$TMP/skill"; }
|
|
238
|
+
|
|
239
|
+
# (2) The shipped gate passes under the C locale.
|
|
240
|
+
if ! out="$(run_c_locale "$SCRIPT_DIR/validate-skill.sh" 2>&1)"; then
|
|
241
|
+
fail "validate-skill.sh failed under LC_ALL=C:\n$out"
|
|
242
|
+
fi
|
|
243
|
+
case "$out" in *markdown_references_ok*) : ;; *) fail "validate-skill.sh did not reach the reference check under LC_ALL=C:\n$out" ;; esac
|
|
244
|
+
|
|
245
|
+
# (3) Applied mutation: the same script without the pin reds for the encoding reason.
|
|
246
|
+
cp -R "$SCRIPT_DIR" "$TMP/scripts"
|
|
247
|
+
grep -vxF "$PIN" "$SCRIPT_DIR/validate-skill.sh" >"$TMP/scripts/validate-skill.sh"
|
|
248
|
+
if mout="$(run_c_locale "$TMP/scripts/validate-skill.sh" 2>&1)"; then
|
|
249
|
+
# Unevaluated only when the host itself explains the pass: Ruby already reads
|
|
250
|
+
# UTF-8 under the C locale, so the pin is not load-bearing here. Any other
|
|
251
|
+
# reason the unpinned run passed means leg 2 may be vacuous.
|
|
252
|
+
if ! env -u LANGUAGE LC_ALL=C LANG=C ruby -e 'exit(Encoding.find("locale") == Encoding::UTF_8 ? 0 : 1)'; then
|
|
253
|
+
fail "pin removed, yet validate-skill.sh still passed under LC_ALL=C on a host whose Ruby reads US-ASCII there, so leg 2 proves nothing:\n$mout"
|
|
254
|
+
fi
|
|
255
|
+
echo "test_locale_independent_gates_leg3_unevaluated: this host's Ruby reads UTF-8 under LC_ALL=C, so removing the pin cannot be shown to matter here" >&2
|
|
256
|
+
echo "test_locale_independent_gates: ok (legs 1-2; leg 3 unevaluated on this host)"
|
|
257
|
+
exit 0
|
|
258
|
+
fi
|
|
259
|
+
case "$mout" in
|
|
260
|
+
*"invalid byte sequence"*|*"invalid multibyte char"*) : ;;
|
|
261
|
+
*) fail "pin removed: run failed, but not for the encoding reason:\n$mout" ;;
|
|
262
|
+
esac
|
|
263
|
+
|
|
264
|
+
echo "test_locale_independent_gates: ok"
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
# locator. A test that only ever asserts "clean stays clean" would pass with the
|
|
14
14
|
# whole detection deleted, so every RED case here has a paired GREEN control.
|
|
15
15
|
set -euo pipefail
|
|
16
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
17
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
16
18
|
|
|
17
19
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
18
20
|
GATE="$SCRIPT_DIR/register-firing-path-resolution.rb"
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
# ALIAS_AUDIT_CMD=true stands in for a passing private R0 audit so the assertion
|
|
12
12
|
# isolates firing-path enforcement from the separate R0 interim path.
|
|
13
13
|
set -euo pipefail
|
|
14
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
15
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
14
16
|
|
|
15
17
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
16
18
|
CHECK_SCRIPT="$SCRIPT_DIR/check-ccl-skills.sh"
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
# The canonical reference owns the protocol; each participating skill keeps
|
|
4
4
|
# only its local responsibility and a pointer to that reference.
|
|
5
5
|
set -euo pipefail
|
|
6
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
7
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
6
8
|
|
|
7
9
|
ROOT="${UIUX_CONTRACT_ROOT:-$(cd "$(dirname "$0")/../../.." && pwd -P)}"
|
|
8
10
|
CONTRACT="$ROOT/skills/product-ui-ux-design/references/delivery-contract.md"
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
# entry and every routed reference local and resolvable. Real provider load,
|
|
8
8
|
# token, latency, correction, and task-quality claims still require task trials.
|
|
9
9
|
set -euo pipefail
|
|
10
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
11
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
10
12
|
|
|
11
13
|
ROOT="${UIUX_LOADING_ROOT:-$(cd "$(dirname "$0")/../../.." && pwd -P)}"
|
|
12
14
|
DEFAULT_BASE_REF="e322db47abe5736e6e1fdf0e73e2ed3eb32c006b"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
|
+
# Ruby takes its encoding from the locale; under a POSIX/unset locale it reads the UTF-8 skill text as US-ASCII and crashes. Pin UTF-8, as CI runs.
|
|
4
|
+
case " ${RUBYOPT:-} " in *" -Ku "*) ;; *) export RUBYOPT="-Ku${RUBYOPT:+ $RUBYOPT}" ;; esac
|
|
3
5
|
|
|
4
6
|
target="${1:-.}"
|
|
5
7
|
|