llm-wb 0.1.0-beta.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.
Files changed (170) hide show
  1. package/.agentic/00.chat/README.md +78 -0
  2. package/.agentic/00.chat/checklists/before-commit.md +195 -0
  3. package/.agentic/00.chat/checklists/llm-workbench-public-beta.md +94 -0
  4. package/.agentic/00.chat/commands/README.md +108 -0
  5. package/.agentic/00.chat/migration-plan.md +132 -0
  6. package/.agentic/00.chat/skills/session-summary.md +48 -0
  7. package/.agentic/00.chat/standards/llm-workbench-public-beta-contract.md +216 -0
  8. package/.agentic/00.chat/standards/main-refresh-conflict-types.md +358 -0
  9. package/.agentic/00.chat/workflows/README.md +40 -0
  10. package/.agentic/00.chat/workflows/bootstrap-chat-workbench-repo.md +212 -0
  11. package/.agentic/00.chat/workflows/chat-cleanup.md +102 -0
  12. package/.agentic/00.chat/workflows/chat-commit.md +56 -0
  13. package/.agentic/00.chat/workflows/chat-promote-to-main.md +169 -0
  14. package/.agentic/00.chat/workflows/chat-refresh-from-main.md +242 -0
  15. package/.agentic/00.chat/workflows/chat-reporting.md +69 -0
  16. package/.agentic/00.chat/workflows/chat-start.md +173 -0
  17. package/.agentic/00.chat/workflows/chat-upstream-reusable-lesson.md +123 -0
  18. package/.agentic/shared/standards/README.md +32 -0
  19. package/.agentic/shared/standards/upstream-repo-bootstrap.md +131 -0
  20. package/.agentic/shared/workflows/README.md +35 -0
  21. package/.agentic/shared/workflows/capability-resolution-workflow.md +189 -0
  22. package/.agentic/shared/workflows/change-shared-process.md +92 -0
  23. package/.cursor/rules/llm-workbench.mdc +17 -0
  24. package/.github/copilot-instructions.md +16 -0
  25. package/AGENTS.md +63 -0
  26. package/CLAUDE.md +16 -0
  27. package/CONTRIBUTING.md +57 -0
  28. package/LICENSE +21 -0
  29. package/LLM_WORKBENCH.md +17 -0
  30. package/README.md +98 -0
  31. package/SECURITY.md +44 -0
  32. package/bin/llm-workbench.js +672 -0
  33. package/docs/00.chat/README.md +47 -0
  34. package/docs/00.chat/llm-workbench-acceptance-matrix.md +55 -0
  35. package/docs/00.chat/script-layout.md +107 -0
  36. package/docs/adapting-to-your-repo.md +29 -0
  37. package/docs/concepts.md +38 -0
  38. package/docs/install.md +114 -0
  39. package/docs/public-beta-contract.md +45 -0
  40. package/docs/workflows.md +103 -0
  41. package/examples/minimal-repo/README.md +13 -0
  42. package/package.json +93 -0
  43. package/scripts/00.chat/README.md +46 -0
  44. package/scripts/00.chat/bootstrap/README.md +35 -0
  45. package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/README.md +39 -0
  46. package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/script.sh +213 -0
  47. package/scripts/00.chat/closeout/README.md +30 -0
  48. package/scripts/00.chat/closeout/build-closeout-prompt/README.md +35 -0
  49. package/scripts/00.chat/closeout/build-closeout-prompt/script.sh +124 -0
  50. package/scripts/00.chat/command/README.md +31 -0
  51. package/scripts/00.chat/command/close/README.md +30 -0
  52. package/scripts/00.chat/command/close/script.sh +25 -0
  53. package/scripts/00.chat/command/dispatcher/README.md +46 -0
  54. package/scripts/00.chat/command/dispatcher/script.sh +91 -0
  55. package/scripts/00.chat/command/dispatcher/smoke-test.sh +168 -0
  56. package/scripts/00.chat/command/new/README.md +32 -0
  57. package/scripts/00.chat/command/new/script.sh +28 -0
  58. package/scripts/00.chat/command/open-window/README.md +38 -0
  59. package/scripts/00.chat/command/open-window/script.sh +25 -0
  60. package/scripts/00.chat/command/package-scripts/README.md +34 -0
  61. package/scripts/00.chat/command/package-scripts/smoke-test.sh +113 -0
  62. package/scripts/00.chat/git/README.md +30 -0
  63. package/scripts/00.chat/git/cleanup-empty-chat-branches/README.md +36 -0
  64. package/scripts/00.chat/git/cleanup-empty-chat-branches/script.sh +243 -0
  65. package/scripts/00.chat/git/cleanup-empty-chat-branches/smoke-test.sh +136 -0
  66. package/scripts/00.chat/local-merge/README.md +30 -0
  67. package/scripts/00.chat/local-merge/list-active-chat-branches/README.md +29 -0
  68. package/scripts/00.chat/local-merge/list-active-chat-branches/script.sh +109 -0
  69. package/scripts/00.chat/local-merge/report-chat-branch-overlaps/README.md +29 -0
  70. package/scripts/00.chat/local-merge/report-chat-branch-overlaps/script.sh +142 -0
  71. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/README.md +33 -0
  72. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/script.sh +345 -0
  73. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/smoke-test.sh +244 -0
  74. package/scripts/00.chat/main-refresh/README.md +39 -0
  75. package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/README.md +32 -0
  76. package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/script.sh +198 -0
  77. package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/README.md +30 -0
  78. package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/script.sh +121 -0
  79. package/scripts/00.chat/main-refresh/classify-conflict/README.md +39 -0
  80. package/scripts/00.chat/main-refresh/classify-conflict/script.sh +169 -0
  81. package/scripts/00.chat/main-refresh/classify-conflict/smoke-test.sh +137 -0
  82. package/scripts/00.chat/main-refresh/classify-refresh-readiness/README.md +35 -0
  83. package/scripts/00.chat/main-refresh/classify-refresh-readiness/script.sh +171 -0
  84. package/scripts/00.chat/main-refresh/classify-refresh-readiness/smoke-test.sh +132 -0
  85. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/README.md +34 -0
  86. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/script.sh +124 -0
  87. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/smoke-test.sh +257 -0
  88. package/scripts/00.chat/main-refresh/show-main-update-status/README.md +31 -0
  89. package/scripts/00.chat/main-refresh/show-main-update-status/script.sh +73 -0
  90. package/scripts/00.chat/main-refresh/verify-conflict-audit/README.md +37 -0
  91. package/scripts/00.chat/main-refresh/verify-conflict-audit/script.sh +154 -0
  92. package/scripts/00.chat/main-refresh/verify-conflict-audit/smoke-test.sh +99 -0
  93. package/scripts/00.chat/metrics/README.md +35 -0
  94. package/scripts/00.chat/metrics/data/chat-pricing.json +107 -0
  95. package/scripts/00.chat/metrics/data/chat-pricing.schema.json +63 -0
  96. package/scripts/00.chat/metrics/estimate-chat-cost/README.md +40 -0
  97. package/scripts/00.chat/metrics/estimate-chat-cost/script.js +130 -0
  98. package/scripts/00.chat/migration/README.md +30 -0
  99. package/scripts/00.chat/migration/audit-chat-layer-migration/README.md +33 -0
  100. package/scripts/00.chat/migration/audit-chat-layer-migration/script.sh +127 -0
  101. package/scripts/00.chat/recovery/README.md +30 -0
  102. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/README.md +76 -0
  103. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/script.sh +212 -0
  104. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/smoke-test.sh +162 -0
  105. package/scripts/00.chat/reporting/README.md +30 -0
  106. package/scripts/00.chat/reporting/generate-commit-log-summary/README.md +35 -0
  107. package/scripts/00.chat/reporting/generate-commit-log-summary/script.sh +299 -0
  108. package/scripts/00.chat/reporting/generate-commit-log-summary/smoke-test.sh +93 -0
  109. package/scripts/00.chat/reporting/report-chat-workspaces/README.md +32 -0
  110. package/scripts/00.chat/reporting/report-chat-workspaces/script.sh +82 -0
  111. package/scripts/00.chat/session-log/README.md +33 -0
  112. package/scripts/00.chat/session-log/check-commit-prerequisites/README.md +89 -0
  113. package/scripts/00.chat/session-log/check-commit-prerequisites/script.sh +121 -0
  114. package/scripts/00.chat/session-log/check-commit-prerequisites/smoke-test.sh +119 -0
  115. package/scripts/00.chat/session-log/check-commitlog-deletions/README.md +90 -0
  116. package/scripts/00.chat/session-log/check-commitlog-deletions/script.sh +131 -0
  117. package/scripts/00.chat/session-log/check-commitlog-deletions/smoke-test.sh +123 -0
  118. package/scripts/00.chat/session-log/checkpoint-chat-session-log/README.md +98 -0
  119. package/scripts/00.chat/session-log/checkpoint-chat-session-log/script.sh +126 -0
  120. package/scripts/00.chat/session-log/paths/README.md +38 -0
  121. package/scripts/00.chat/session-log/paths/lib.sh +133 -0
  122. package/scripts/00.chat/session-log/prepare-chat-session-before-commit/README.md +90 -0
  123. package/scripts/00.chat/session-log/prepare-chat-session-before-commit/script.sh +145 -0
  124. package/scripts/00.chat/session-log/read-current-chat-log/README.md +44 -0
  125. package/scripts/00.chat/session-log/read-current-chat-log/script.sh +92 -0
  126. package/scripts/00.chat/session-log/read-current-chat-log/smoke-test.sh +127 -0
  127. package/scripts/00.chat/session-log/record-chat-commit/README.md +133 -0
  128. package/scripts/00.chat/session-log/record-chat-commit/script.sh +394 -0
  129. package/scripts/00.chat/session-log/record-chat-commit/smoke-test.sh +227 -0
  130. package/scripts/00.chat/session-log/record-main-refresh-conflict/README.md +34 -0
  131. package/scripts/00.chat/session-log/record-main-refresh-conflict/script.sh +239 -0
  132. package/scripts/00.chat/session-log/rename-current-chat-log-folder/README.md +32 -0
  133. package/scripts/00.chat/session-log/rename-current-chat-log-folder/script.sh +112 -0
  134. package/scripts/00.chat/session-log/update-chat-log/README.md +32 -0
  135. package/scripts/00.chat/session-log/update-chat-log/script.sh +294 -0
  136. package/scripts/00.chat/startup/README.md +37 -0
  137. package/scripts/00.chat/startup/auto-start-missing-session/README.md +113 -0
  138. package/scripts/00.chat/startup/auto-start-missing-session/script.sh +54 -0
  139. package/scripts/00.chat/startup/resolve-current-chat-session/README.md +57 -0
  140. package/scripts/00.chat/startup/resolve-current-chat-session/script.sh +47 -0
  141. package/scripts/00.chat/startup/resolve-current-chat-session/smoke-test.sh +130 -0
  142. package/scripts/00.chat/startup/start-chat-session/README.md +197 -0
  143. package/scripts/00.chat/startup/start-chat-session/script.sh +330 -0
  144. package/scripts/00.chat/startup/start-chat-session/smoke-test.sh +182 -0
  145. package/scripts/00.chat/startup/start-new-chat/README.md +31 -0
  146. package/scripts/00.chat/startup/start-new-chat/script.sh +29 -0
  147. package/scripts/00.chat/transcript/README.md +36 -0
  148. package/scripts/00.chat/transcript/discover-codex-session-log/README.md +32 -0
  149. package/scripts/00.chat/transcript/discover-codex-session-log/script.sh +106 -0
  150. package/scripts/00.chat/transcript/register-codex-session-log/README.md +32 -0
  151. package/scripts/00.chat/transcript/register-codex-session-log/script.sh +115 -0
  152. package/scripts/00.chat/worktree/README.md +32 -0
  153. package/scripts/00.chat/worktree/check-write-location/README.md +87 -0
  154. package/scripts/00.chat/worktree/check-write-location/script.sh +95 -0
  155. package/scripts/00.chat/worktree/dirty-worktree-check/README.md +77 -0
  156. package/scripts/00.chat/worktree/dirty-worktree-check/script.sh +93 -0
  157. package/scripts/00.chat/worktree/ensure-chat-worktree/README.md +33 -0
  158. package/scripts/00.chat/worktree/ensure-chat-worktree/script.sh +132 -0
  159. package/scripts/00.chat/worktree/open-window/README.md +34 -0
  160. package/scripts/00.chat/worktree/open-window/script.sh +131 -0
  161. package/scripts/00.chat/worktree/paths/README.md +32 -0
  162. package/scripts/00.chat/worktree/paths/lib.sh +71 -0
  163. package/scripts/01.harness/artifact-metadata/check-headers/script.sh +522 -0
  164. package/scripts/01.harness/artifact-metadata/check-headers/smoke-test.sh +48 -0
  165. package/scripts/01.harness/check-deterministic-process-drift.sh +416 -0
  166. package/scripts/01.harness/check-governed-script-command-drift.sh +184 -0
  167. package/scripts/01.harness/run-governed-script.sh +178 -0
  168. package/scripts/install.sh +503 -0
  169. package/scripts/uninstall.sh +199 -0
  170. package/tests/smoke-test-install.sh +70 -0
@@ -0,0 +1,416 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # agentic-artifact:
5
+ # schema: agentic-artifact/v2
6
+ # id: harness.script.check-deterministic-process-drift
7
+ # version: 1
8
+ # status: active
9
+ # layer: 01.harness
10
+ # domain: governance
11
+ # disciplines:
12
+ # - agentic
13
+ # kind: script
14
+ # purpose: Flag process prose that should likely be represented as deterministic scripts
15
+ # or gates.
16
+ # portability:
17
+ # class: required
18
+ # targets:
19
+ # - llm-workbench
20
+ # used_by:
21
+ # - id: chat.checklists.before-commit
22
+ # path: .agentic/00.chat/checklists/before-commit.md
23
+ # - id: shared.workflows.change-shared-process
24
+ # path: .agentic/shared/workflows/change-shared-process.md
25
+ # effects:
26
+ # - read-only
27
+
28
+ MODE=""
29
+ COMMIT_SHA=""
30
+ PATH_ARGS=()
31
+
32
+ usage() {
33
+ cat <<'EOF'
34
+ Usage:
35
+ check-deterministic-process-drift.sh --staged
36
+ check-deterministic-process-drift.sh --commit <sha>
37
+ check-deterministic-process-drift.sh --paths <path> [path...]
38
+ check-deterministic-process-drift.sh --all
39
+
40
+ Flags harness process prose that looks like it could be represented by a
41
+ deterministic script or gate. The check suggests changes only; it never rewrites
42
+ files.
43
+
44
+ Allow intentional governance prose with:
45
+ <!-- deterministic-check: allow reason="requires human approval judgment" -->
46
+ EOF
47
+ }
48
+
49
+ while [ $# -gt 0 ]; do
50
+ case "$1" in
51
+ --staged|--all)
52
+ if [ -n "$MODE" ]; then
53
+ echo "ERROR: choose exactly one mode." >&2
54
+ exit 2
55
+ fi
56
+ MODE="${1#--}"
57
+ shift
58
+ ;;
59
+ --commit)
60
+ if [ -n "$MODE" ]; then
61
+ echo "ERROR: choose exactly one mode." >&2
62
+ exit 2
63
+ fi
64
+ if [ $# -lt 2 ] || [ -z "${2:-}" ]; then
65
+ echo "ERROR: --commit requires a commit sha." >&2
66
+ exit 2
67
+ fi
68
+ MODE="commit"
69
+ COMMIT_SHA="$2"
70
+ shift 2
71
+ ;;
72
+ --paths)
73
+ if [ -n "$MODE" ]; then
74
+ echo "ERROR: choose exactly one mode." >&2
75
+ exit 2
76
+ fi
77
+ MODE="paths"
78
+ shift
79
+ if [ $# -eq 0 ]; then
80
+ echo "ERROR: --paths requires at least one path." >&2
81
+ exit 2
82
+ fi
83
+ while [ $# -gt 0 ]; do
84
+ PATH_ARGS+=("$1")
85
+ shift
86
+ done
87
+ ;;
88
+ --help|-h)
89
+ usage
90
+ exit 0
91
+ ;;
92
+ *)
93
+ echo "ERROR: unknown argument: $1" >&2
94
+ usage >&2
95
+ exit 2
96
+ ;;
97
+ esac
98
+ done
99
+
100
+ if [ -z "$MODE" ]; then
101
+ usage >&2
102
+ exit 2
103
+ fi
104
+
105
+ is_scannable_path() {
106
+ local path="$1"
107
+
108
+ case "$path" in
109
+ docs/harness/architecture/adrs/*.md)
110
+ return 1
111
+ ;;
112
+ AGENTS.md|.agentic/*.md|.agentic/**/*.md|docs/harness/*.md|docs/harness/**/*.md)
113
+ return 0
114
+ ;;
115
+ *)
116
+ return 1
117
+ ;;
118
+ esac
119
+ }
120
+
121
+ collect_all_paths() {
122
+ {
123
+ [ -f AGENTS.md ] && printf '%s\n' AGENTS.md
124
+ [ -d .agentic ] && find .agentic -type f
125
+ [ -d docs/harness ] && find docs/harness -type f
126
+ } | sort -u
127
+ }
128
+
129
+ collect_paths_from_args() {
130
+ local path
131
+
132
+ for path in "${PATH_ARGS[@]}"; do
133
+ if [ -d "$path" ]; then
134
+ find "$path" -type f
135
+ elif [ -f "$path" ]; then
136
+ printf '%s\n' "$path"
137
+ else
138
+ echo "WARN: path does not exist, skipping: $path" >&2
139
+ fi
140
+ done | sort -u
141
+ }
142
+
143
+ scan_file_content() {
144
+ local source_path="$1"
145
+ local content_file="$2"
146
+
147
+ awk -v source="$source_path" '
148
+ function finding(type, text) {
149
+ printf "%s:%d\n", source, NR
150
+ printf " Type: %s\n", type
151
+ printf " Text: %s\n", text
152
+ printf " Suggestion: Move deterministic checks into a script or gate, or add an allow marker with a reason when the prose is intentionally human-governed.\n\n"
153
+ findings++
154
+ }
155
+
156
+ /```/ {
157
+ in_code = !in_code
158
+ next
159
+ }
160
+
161
+ /deterministic-check: allow/ {
162
+ if ($0 !~ /reason="[^"]+"/) {
163
+ finding("allow-marker-missing-reason", $0)
164
+ }
165
+ allow_until = NR + 8
166
+ next
167
+ }
168
+
169
+ in_code {
170
+ next
171
+ }
172
+
173
+ NR <= allow_until {
174
+ next
175
+ }
176
+
177
+ {
178
+ line = $0
179
+ lower = tolower(line)
180
+ }
181
+
182
+ lower ~ /(check|verify|ensure|confirm) that / {
183
+ finding("scriptable-check", line)
184
+ next
185
+ }
186
+
187
+ lower ~ /(current branch contains|file exists|files exist|path exists|if .*missing|if .*dirty|if .*exists|when .*missing|must contain)/ {
188
+ finding("scriptable-condition", line)
189
+ next
190
+ }
191
+
192
+ lower ~ /(run .*(and|then).*(inspect|check|verify|confirm)|rerun .*(checklist|gate|script))/ {
193
+ finding("scriptable-sequence", line)
194
+ next
195
+ }
196
+
197
+ lower ~ /^[-0-9. ]+(check|verify|ensure|confirm|inspect) / {
198
+ procedural_bullets++
199
+ if (procedural_bullets == 3) {
200
+ finding("scriptable-enumeration", "Three or more nearby checklist items begin with deterministic process verbs.")
201
+ }
202
+ next
203
+ }
204
+
205
+ line !~ /^[-0-9. ]/ {
206
+ procedural_bullets = 0
207
+ }
208
+
209
+ END {
210
+ exit findings > 0 ? 1 : 0
211
+ }
212
+ ' "$content_file"
213
+ }
214
+
215
+ scan_worktree_file() {
216
+ local path="$1"
217
+ local result
218
+
219
+ if ! is_scannable_path "$path"; then
220
+ return 0
221
+ fi
222
+
223
+ set +e
224
+ scan_file_content "$path" "$path"
225
+ result=$?
226
+ set -e
227
+ return "$result"
228
+ }
229
+
230
+ scan_git_blob() {
231
+ local ref="$1"
232
+ local path="$2"
233
+ local tmp
234
+
235
+ if ! is_scannable_path "$path"; then
236
+ return 0
237
+ fi
238
+
239
+ tmp="$(mktemp)"
240
+ if ! git show "${ref}:${path}" > "$tmp" 2>/dev/null; then
241
+ rm -f "$tmp"
242
+ return 0
243
+ fi
244
+
245
+ set +e
246
+ scan_file_content "$path" "$tmp"
247
+ local result=$?
248
+ set -e
249
+ rm -f "$tmp"
250
+ return "$result"
251
+ }
252
+
253
+ scan_diff_added_lines() {
254
+ local source_path="$1"
255
+ local diff_file="$2"
256
+
257
+ if ! is_scannable_path "$source_path"; then
258
+ return 0
259
+ fi
260
+
261
+ awk -v source="$source_path" '
262
+ function finding(type, text) {
263
+ printf "%s:%d\n", source, line_no
264
+ printf " Type: %s\n", type
265
+ printf " Text: %s\n", text
266
+ printf " Suggestion: Move deterministic checks into a script or gate, or add an allow marker with a reason when the prose is intentionally human-governed.\n\n"
267
+ findings++
268
+ }
269
+
270
+ function scan_added_line(text, lower) {
271
+ if (text ~ /```/) {
272
+ in_code = !in_code
273
+ return
274
+ }
275
+
276
+ if (text ~ /deterministic-check: allow/) {
277
+ if (text !~ /reason="[^"]+"/) {
278
+ finding("allow-marker-missing-reason", text)
279
+ }
280
+ allow_until = line_no + 8
281
+ return
282
+ }
283
+
284
+ if (in_code || line_no <= allow_until) {
285
+ return
286
+ }
287
+
288
+ lower = tolower(text)
289
+
290
+ if (lower ~ /(check|verify|ensure|confirm) that /) {
291
+ finding("scriptable-check", text)
292
+ return
293
+ }
294
+
295
+ if (lower ~ /(current branch contains|file exists|files exist|path exists|if .*missing|if .*dirty|if .*exists|when .*missing|must contain)/) {
296
+ finding("scriptable-condition", text)
297
+ return
298
+ }
299
+
300
+ if (lower ~ /(run .*(and|then).*(inspect|check|verify|confirm)|rerun .*(checklist|gate|script))/) {
301
+ finding("scriptable-sequence", text)
302
+ return
303
+ }
304
+
305
+ if (lower ~ /^[-0-9. ]+(check|verify|ensure|confirm|inspect) /) {
306
+ procedural_bullets++
307
+ if (procedural_bullets == 3) {
308
+ finding("scriptable-enumeration", "Three or more nearby added checklist items begin with deterministic process verbs.")
309
+ }
310
+ return
311
+ }
312
+
313
+ if (text !~ /^[-0-9. ]/) {
314
+ procedural_bullets = 0
315
+ }
316
+ }
317
+
318
+ /^@@ / {
319
+ hunk = $0
320
+ sub(/^.* \+/, "", hunk)
321
+ sub(/ .*/, "", hunk)
322
+ split(hunk, parts, ",")
323
+ line_no = parts[1] - 1
324
+ next
325
+ }
326
+
327
+ /^\+\+\+ / {
328
+ next
329
+ }
330
+
331
+ /^\+/ {
332
+ line_no++
333
+ scan_added_line(substr($0, 2))
334
+ next
335
+ }
336
+
337
+ /^ / {
338
+ line_no++
339
+ next
340
+ }
341
+
342
+ END {
343
+ exit findings > 0 ? 1 : 0
344
+ }
345
+ ' "$diff_file"
346
+ }
347
+
348
+ TOTAL_FINDINGS=0
349
+
350
+ scan_path_list() {
351
+ local path
352
+
353
+ while IFS= read -r path; do
354
+ if [ -z "${path// }" ]; then
355
+ continue
356
+ fi
357
+
358
+ if ! scan_worktree_file "$path"; then
359
+ TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
360
+ fi
361
+ done
362
+ }
363
+
364
+ case "$MODE" in
365
+ staged)
366
+ while IFS= read -r path; do
367
+ if [ -z "${path// }" ]; then
368
+ continue
369
+ fi
370
+
371
+ tmp="$(mktemp)"
372
+ git diff --cached -U0 --no-ext-diff -- "$path" > "$tmp"
373
+ if ! scan_diff_added_lines "$path" "$tmp"; then
374
+ TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
375
+ fi
376
+ rm -f "$tmp"
377
+ done < <(git diff --cached --name-only --diff-filter=ACMR)
378
+ ;;
379
+ commit)
380
+ if ! git rev-parse --verify --quiet "$COMMIT_SHA" >/dev/null; then
381
+ echo "ERROR: commit does not exist: $COMMIT_SHA" >&2
382
+ exit 2
383
+ fi
384
+
385
+ while IFS= read -r path; do
386
+ if [ -z "${path// }" ]; then
387
+ continue
388
+ fi
389
+
390
+ tmp="$(mktemp)"
391
+ git show --format= --unified=0 --no-ext-diff "$COMMIT_SHA" -- "$path" > "$tmp"
392
+ if ! scan_diff_added_lines "$path" "$tmp"; then
393
+ TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
394
+ fi
395
+ rm -f "$tmp"
396
+ done < <(git diff-tree --no-commit-id --name-only -r "$COMMIT_SHA")
397
+ ;;
398
+ paths)
399
+ scan_path_list < <(collect_paths_from_args)
400
+ ;;
401
+ all)
402
+ scan_path_list < <(collect_all_paths)
403
+ ;;
404
+ *)
405
+ echo "ERROR: unsupported mode: $MODE" >&2
406
+ exit 2
407
+ ;;
408
+ esac
409
+
410
+ if [ "$TOTAL_FINDINGS" -gt 0 ]; then
411
+ echo "ERROR: deterministic process drift found." >&2
412
+ echo "Review the suggestions, then either move deterministic procedure into a script/gate or add an allow marker with a reason." >&2
413
+ exit 1
414
+ fi
415
+
416
+ echo "No deterministic process drift found."
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # agentic-artifact:
5
+ # schema: agentic-artifact/v2
6
+ # id: harness.script.check-governed-script-command-drift
7
+ # version: 1
8
+ # status: active
9
+ # layer: 01.harness
10
+ # domain: governance
11
+ # disciplines:
12
+ # - agentic
13
+ # kind: script
14
+ # purpose: Flag approval-sensitive governed script references that bypass the governed
15
+ # runner.
16
+ # portability:
17
+ # class: required
18
+ # targets:
19
+ # - llm-workbench
20
+ # used_by:
21
+ # - id: chat.script.session-log.prepare-chat-session-before-commit
22
+ # path: scripts/00.chat/session-log/prepare-chat-session-before-commit/script.sh
23
+ # - id: harness.standards.governed-script-permissions
24
+ # effects:
25
+ # - read-only
26
+
27
+ usage() {
28
+ cat <<'EOF'
29
+ Usage:
30
+ check-governed-script-command-drift.sh [--paths <path>...]
31
+
32
+ Flags active agent-facing artifacts that show approval-sensitive governed
33
+ scripts without routing through the governed runner.
34
+ EOF
35
+ }
36
+
37
+ PATH_ARGS=()
38
+
39
+ while [ $# -gt 0 ]; do
40
+ case "$1" in
41
+ --paths)
42
+ shift
43
+ if [ $# -eq 0 ]; then
44
+ echo "ERROR: --paths requires at least one path." >&2
45
+ exit 2
46
+ fi
47
+ while [ $# -gt 0 ]; do
48
+ PATH_ARGS+=("$1")
49
+ shift
50
+ done
51
+ ;;
52
+ -h|--help)
53
+ usage
54
+ exit 0
55
+ ;;
56
+ *)
57
+ echo "ERROR: unknown argument: $1" >&2
58
+ usage >&2
59
+ exit 2
60
+ ;;
61
+ esac
62
+ done
63
+
64
+ collect_default_paths() {
65
+ {
66
+ if [ -f AGENTS.md ]; then
67
+ printf '%s\n' AGENTS.md
68
+ fi
69
+ if [ -d .agentic ]; then
70
+ find .agentic -type f
71
+ fi
72
+ if [ -d docs/harness ]; then
73
+ find docs/harness -type f
74
+ fi
75
+ } | sort -u
76
+ }
77
+
78
+ collect_paths_from_args() {
79
+ local path
80
+
81
+ for path in "${PATH_ARGS[@]}"; do
82
+ if [ -d "$path" ]; then
83
+ find "$path" -type f
84
+ elif [ -f "$path" ]; then
85
+ printf '%s\n' "$path"
86
+ else
87
+ echo "WARN: path does not exist, skipping: $path" >&2
88
+ fi
89
+ done | sort -u
90
+ }
91
+
92
+ is_scannable_path() {
93
+ local path="$1"
94
+
95
+ case "$path" in
96
+ docs/harness/architecture/adrs/*.md)
97
+ return 1
98
+ ;;
99
+ AGENTS.md|.agentic/*.md|.agentic/**/*.md|docs/harness/*.md|docs/harness/**/*.md)
100
+ return 0
101
+ ;;
102
+ *)
103
+ return 1
104
+ ;;
105
+ esac
106
+ }
107
+
108
+ APPROVED_SCRIPTS="$(bash scripts/01.harness/run-governed-script.sh --list \
109
+ | awk '$1 == "approved" { print $2 }')"
110
+
111
+ if [ -z "${APPROVED_SCRIPTS// }" ]; then
112
+ echo "ERROR: governed runner returned no approved scripts." >&2
113
+ exit 1
114
+ fi
115
+
116
+ if [ "${#PATH_ARGS[@]}" -gt 0 ]; then
117
+ PATHS="$(collect_paths_from_args)"
118
+ else
119
+ PATHS="$(collect_default_paths)"
120
+ fi
121
+
122
+ FINDINGS=0
123
+
124
+ scan_file() {
125
+ local path="$1"
126
+ local script
127
+ local line_no
128
+ local text
129
+ local previous_text=""
130
+
131
+ is_scannable_path "$path" || return 0
132
+
133
+ while IFS=: read -r line_no text; do
134
+ [ -n "$line_no" ] || continue
135
+ for script in $APPROVED_SCRIPTS; do
136
+ case "$text" in
137
+ *"$script"*)
138
+ case "$text" in
139
+ *"bash $script"*)
140
+ ;;
141
+ *)
142
+ continue
143
+ ;;
144
+ esac
145
+ case "$text" in
146
+ *"bash scripts/01.harness/run-governed-script.sh --approved-action $script"*)
147
+ ;;
148
+ *)
149
+ case "$path:$text" in
150
+ scripts/shared/*:*"exec bash $script"*)
151
+ continue
152
+ ;;
153
+ esac
154
+ case "$previous_text" in
155
+ *"bash scripts/01.harness/run-governed-script.sh --approved-action \\"*)
156
+ continue
157
+ ;;
158
+ esac
159
+ printf '%s:%s\n' "$path" "$line_no"
160
+ printf ' Type: direct-approved-governed-script\n'
161
+ printf ' Text: %s\n' "$text"
162
+ printf ' Suggestion: Use bash scripts/01.harness/run-governed-script.sh --approved-action %s\n\n' "$script"
163
+ FINDINGS=$((FINDINGS + 1))
164
+ break
165
+ ;;
166
+ esac
167
+ ;;
168
+ esac
169
+ done
170
+ previous_text="$text"
171
+ done < <(grep -n 'scripts/' "$path" || true)
172
+ }
173
+
174
+ while IFS= read -r path; do
175
+ [ -n "$path" ] || continue
176
+ scan_file "$path"
177
+ done <<< "$PATHS"
178
+
179
+ if [ "$FINDINGS" -gt 0 ]; then
180
+ echo "Governed script command drift found: $FINDINGS finding(s)." >&2
181
+ exit 1
182
+ fi
183
+
184
+ echo "No governed script command drift found."