@evoclock/pi-agentic-driver 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +736 -0
- package/PROVENANCE.md +69 -0
- package/README.md +325 -0
- package/config/herdr-worker-repositories.v1.json +9 -0
- package/extensions/aidr.ts +5 -0
- package/extensions/code-phage.js +144 -0
- package/extensions/herdr-communication.ts +7 -0
- package/extensions/herdr-lifecycle.ts +7 -0
- package/extensions/linux-microvm.ts +10 -0
- package/lib/adapters/diff-scope.mjs +148 -0
- package/lib/adapters/evidence.mjs +151 -0
- package/lib/adapters/narrative.mjs +171 -0
- package/lib/adapters/review-feedback.mjs +77 -0
- package/lib/adapters/visualization.mjs +176 -0
- package/lib/code-phage-core.mjs +882 -0
- package/lib/python_ast_metrics.py +378 -0
- package/lib/typescript_ast_metrics.mjs +441 -0
- package/package.json +50 -0
- package/scripts/aidr_writing_review.js +468 -0
- package/scripts/enforcement/herdr_communication_pi.js +1198 -0
- package/scripts/enforcement/herdr_lifecycle_pi.js +902 -0
- package/scripts/enforcement/linux_microvm_cutover_pi.js +328 -0
- package/scripts/enforcement/linux_microvm_remote_fixture.sh +366 -0
- package/scripts/enforcement/native_tui_context.js +11 -0
- package/templates/AGENTS.md +72 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
phase=setup
|
|
5
|
+
if [ "$#" -ne 2 ]; then
|
|
6
|
+
printf 'microvm failure phase=identity code=2 detail=fixture id and script hash are required\n' >&2
|
|
7
|
+
exit 2
|
|
8
|
+
fi
|
|
9
|
+
fixture_id=$1
|
|
10
|
+
script_hash=$2
|
|
11
|
+
fixture_fail() {
|
|
12
|
+
local code=$1
|
|
13
|
+
shift
|
|
14
|
+
printf 'microvm failure phase=%s code=%s detail=%s\n' "$phase" "$code" "$*" >&2
|
|
15
|
+
exit "$code"
|
|
16
|
+
}
|
|
17
|
+
case "$fixture_id" in
|
|
18
|
+
""|*[!A-Za-z0-9._-]*) fixture_fail 2 'unsafe fixture id' ;;
|
|
19
|
+
esac
|
|
20
|
+
if [ "${#script_hash}" -ne 64 ]; then fixture_fail 2 'invalid fixture script hash'; fi
|
|
21
|
+
case "$script_hash" in
|
|
22
|
+
""|*[!0-9a-f]*) fixture_fail 2 'invalid fixture script hash' ;;
|
|
23
|
+
esac
|
|
24
|
+
|
|
25
|
+
state_root="$HOME/agentic-driver-state/cutover-fixtures/microvm"
|
|
26
|
+
fixture_root="$state_root/$fixture_id"
|
|
27
|
+
domain="agentic-driver-$fixture_id"
|
|
28
|
+
kernel="/boot/vmlinuz-$(uname -r)"
|
|
29
|
+
marker="AGENTIC_MICROVM_PROBE:$fixture_id"
|
|
30
|
+
acl_backup="$fixture_root/home.acl.before"
|
|
31
|
+
acl_after="$fixture_root/home.acl.after"
|
|
32
|
+
initramfs="$fixture_root/initramfs.cpio.gz"
|
|
33
|
+
initramfs_acl_after="$fixture_root/initramfs.acl.after"
|
|
34
|
+
initramfs_build_log="$fixture_root/initramfs.build.log"
|
|
35
|
+
console_error="$fixture_root/console.stderr"
|
|
36
|
+
receipt_schema="agentic-driver.linux-microvm-cutover.v1"
|
|
37
|
+
|
|
38
|
+
mkdir -p "$state_root" || fixture_fail 3 'fixture state root could not be created'
|
|
39
|
+
if ! mkdir "$fixture_root"; then
|
|
40
|
+
fixture_fail 3 'fixture already exists'
|
|
41
|
+
fi
|
|
42
|
+
if ! getfacl -p "$HOME" >"$acl_backup"; then
|
|
43
|
+
fixture_fail 3 'home ACL snapshot could not be captured'
|
|
44
|
+
fi
|
|
45
|
+
home_acl_applied=false
|
|
46
|
+
initramfs_acl_applied=false
|
|
47
|
+
domain_started=false
|
|
48
|
+
domain_destroy_requested=false
|
|
49
|
+
recorder_pid=""
|
|
50
|
+
acl_restored=false
|
|
51
|
+
domain_absent=false
|
|
52
|
+
|
|
53
|
+
if ! home_acl_before_sha=$(sha256sum "$acl_backup" | awk '{print $1}'); then
|
|
54
|
+
fixture_fail 3 'home ACL snapshot digest could not be computed'
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
cleanup_failed=false
|
|
58
|
+
cleanup_error_count=0
|
|
59
|
+
cleanup_error() {
|
|
60
|
+
cleanup_failed=true
|
|
61
|
+
cleanup_error_count=$((cleanup_error_count + 1))
|
|
62
|
+
local detail=${1:-'unspecified cleanup failure'}
|
|
63
|
+
detail=$(printf '%s' "$detail" | tr '\r\n' ' ' | cut -c1-400)
|
|
64
|
+
printf 'microvm cleanup failure code=cleanup-failed detail=%s\n' "$detail" >&2
|
|
65
|
+
}
|
|
66
|
+
run_cleanup() {
|
|
67
|
+
local label=$1
|
|
68
|
+
shift
|
|
69
|
+
local output status
|
|
70
|
+
output=$("$@" 2>&1)
|
|
71
|
+
status=$?
|
|
72
|
+
if [ "$status" -ne 0 ]; then
|
|
73
|
+
cleanup_error "$label exit=$status ${output:-no diagnostic}"
|
|
74
|
+
fi
|
|
75
|
+
return "$status"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
domain_state() {
|
|
79
|
+
local names
|
|
80
|
+
if virsh dominfo "$domain" >/dev/null 2>&1; then
|
|
81
|
+
printf 'present'
|
|
82
|
+
return 0
|
|
83
|
+
fi
|
|
84
|
+
if ! names=$(virsh list --all --name 2>&1); then
|
|
85
|
+
printf 'domain absence query failed: %s\n' "${names:-no diagnostic}" >&2
|
|
86
|
+
return 2
|
|
87
|
+
fi
|
|
88
|
+
if grep -F -x -- "$domain" <<<"$names" >/dev/null; then
|
|
89
|
+
printf 'present'
|
|
90
|
+
else
|
|
91
|
+
local match_status=$?
|
|
92
|
+
if [ "$match_status" -eq 1 ]; then
|
|
93
|
+
printf 'absent'
|
|
94
|
+
else
|
|
95
|
+
printf 'domain name absence query failed\n' >&2
|
|
96
|
+
return 2
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
assert_domain_absent() {
|
|
102
|
+
local state
|
|
103
|
+
if ! state=$(domain_state); then return 2; fi
|
|
104
|
+
if [ "$state" != absent ]; then return 1; fi
|
|
105
|
+
return 0
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
verify_initramfs_acl_removed() {
|
|
109
|
+
if ! getfacl -p "$initramfs" >"$initramfs_acl_after"; then return 1; fi
|
|
110
|
+
if grep -F 'user:libvirt-qemu:' "$initramfs_acl_after" >/dev/null; then
|
|
111
|
+
return 1
|
|
112
|
+
else
|
|
113
|
+
local match_status=$?
|
|
114
|
+
if [ "$match_status" -eq 1 ]; then return 0; fi
|
|
115
|
+
return 2
|
|
116
|
+
fi
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
cleanup_recorder() {
|
|
120
|
+
if [ -z "$recorder_pid" ]; then
|
|
121
|
+
printf 'microvm cleanup recorder=no-op\n' >&2
|
|
122
|
+
return
|
|
123
|
+
fi
|
|
124
|
+
if kill -0 "$recorder_pid" 2>/dev/null; then
|
|
125
|
+
if run_cleanup 'stop console recorder' kill "$recorder_pid"; then
|
|
126
|
+
printf 'microvm cleanup recorder=terminated\n' >&2
|
|
127
|
+
fi
|
|
128
|
+
else
|
|
129
|
+
printf 'microvm cleanup recorder=no-op\n' >&2
|
|
130
|
+
fi
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
cleanup_domain() {
|
|
134
|
+
local state
|
|
135
|
+
if [ "$domain_started" != true ]; then
|
|
136
|
+
printf 'microvm cleanup domain=no-op\n' >&2
|
|
137
|
+
return
|
|
138
|
+
fi
|
|
139
|
+
if state=$(domain_state); then
|
|
140
|
+
if [ "$state" = present ]; then
|
|
141
|
+
domain_destroy_requested=true
|
|
142
|
+
run_cleanup "destroy domain $domain" virsh destroy "$domain"
|
|
143
|
+
fi
|
|
144
|
+
else
|
|
145
|
+
cleanup_error 'domain absence query failed during cleanup'
|
|
146
|
+
fi
|
|
147
|
+
if state=$(domain_state); then
|
|
148
|
+
if [ "$state" = absent ]; then
|
|
149
|
+
printf 'microvm cleanup domain=checked-absent\n' >&2
|
|
150
|
+
else
|
|
151
|
+
cleanup_error "domain $domain remains present after cleanup"
|
|
152
|
+
fi
|
|
153
|
+
else
|
|
154
|
+
cleanup_error 'final domain absence query failed during cleanup'
|
|
155
|
+
fi
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
cleanup_acl() {
|
|
159
|
+
if [ "$initramfs_acl_applied" = true ]; then
|
|
160
|
+
if [ -e "$initramfs" ]; then
|
|
161
|
+
run_cleanup 'remove initramfs ACL' setfacl -x u:libvirt-qemu "$initramfs"
|
|
162
|
+
if verify_initramfs_acl_removed; then
|
|
163
|
+
initramfs_acl_applied=false
|
|
164
|
+
else
|
|
165
|
+
cleanup_error 'initramfs ACL removal could not be verified'
|
|
166
|
+
fi
|
|
167
|
+
else
|
|
168
|
+
printf 'microvm cleanup initramfs_acl=no-op-target-absent\n' >&2
|
|
169
|
+
initramfs_acl_applied=false
|
|
170
|
+
fi
|
|
171
|
+
else
|
|
172
|
+
printf 'microvm cleanup initramfs_acl=no-op\n' >&2
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
if [ "$home_acl_applied" = true ]; then
|
|
176
|
+
run_cleanup 'restore home ACL' setfacl --restore="$acl_backup"
|
|
177
|
+
if getfacl -p "$HOME" >"$acl_after"; then
|
|
178
|
+
if cmp -s "$acl_backup" "$acl_after"; then
|
|
179
|
+
if home_acl_after_sha=$(sha256sum "$acl_after" | awk '{print $1}'); then
|
|
180
|
+
home_acl_applied=false
|
|
181
|
+
acl_restored=true
|
|
182
|
+
else
|
|
183
|
+
cleanup_error 'restored home ACL digest could not be computed'
|
|
184
|
+
fi
|
|
185
|
+
else
|
|
186
|
+
cleanup_error 'restored home ACL differs from home.acl.before'
|
|
187
|
+
fi
|
|
188
|
+
else
|
|
189
|
+
cleanup_error 'restored home ACL could not be captured'
|
|
190
|
+
fi
|
|
191
|
+
else
|
|
192
|
+
printf 'microvm cleanup home_acl=no-op\n' >&2
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
cleanup_on_exit() {
|
|
197
|
+
local original_status=$?
|
|
198
|
+
trap - EXIT INT TERM HUP
|
|
199
|
+
set +e
|
|
200
|
+
cleanup_recorder
|
|
201
|
+
cleanup_domain
|
|
202
|
+
cleanup_acl
|
|
203
|
+
if [ "$cleanup_failed" = true ]; then
|
|
204
|
+
printf 'microvm cleanup summary=failed errors=%s\n' "$cleanup_error_count" >&2
|
|
205
|
+
exit 70
|
|
206
|
+
fi
|
|
207
|
+
printf 'microvm cleanup summary=clean\n' >&2
|
|
208
|
+
exit "$original_status"
|
|
209
|
+
}
|
|
210
|
+
trap cleanup_on_exit EXIT INT TERM HUP
|
|
211
|
+
|
|
212
|
+
phase=preflight
|
|
213
|
+
for tool in /usr/bin/qemu-system-x86_64 /usr/bin/busybox /usr/bin/cpio /usr/bin/gzip /usr/bin/setfacl /usr/bin/getfacl; do
|
|
214
|
+
if ! test -x "$tool"; then fixture_fail 4 "required tool unavailable: $tool"; fi
|
|
215
|
+
done
|
|
216
|
+
if ! test -r /dev/kvm -a -w /dev/kvm; then fixture_fail 4 '/dev/kvm is unavailable'; fi
|
|
217
|
+
if ! test -e "$kernel"; then fixture_fail 4 "kernel unavailable: $kernel"; fi
|
|
218
|
+
if state=$(domain_state); then
|
|
219
|
+
if [ "$state" != absent ]; then fixture_fail 5 'fixture domain already exists'; fi
|
|
220
|
+
else
|
|
221
|
+
fixture_fail 5 'fixture domain absence could not be established'
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
phase=build
|
|
225
|
+
root="$fixture_root/root"
|
|
226
|
+
if ! mkdir -p "$root/bin" "$root/proc" "$root/sys" "$root/dev"; then fixture_fail 6 'guest root could not be created'; fi
|
|
227
|
+
if ! cp /usr/bin/busybox "$root/bin/busybox"; then fixture_fail 6 'BusyBox could not be copied'; fi
|
|
228
|
+
for name in sh mount poweroff uname; do
|
|
229
|
+
if ! ln -s busybox "$root/bin/$name"; then fixture_fail 6 "BusyBox link could not be created: $name"; fi
|
|
230
|
+
done
|
|
231
|
+
if ! cat >"$root/init" <<EOF
|
|
232
|
+
#!/bin/busybox sh
|
|
233
|
+
/bin/mount -t proc proc /proc
|
|
234
|
+
/bin/mount -t sysfs sysfs /sys
|
|
235
|
+
/bin/mount -t devtmpfs devtmpfs /dev
|
|
236
|
+
echo '$marker'
|
|
237
|
+
echo "guest-kernel=\$(/bin/uname -r)"
|
|
238
|
+
echo 'network=absent disk=absent host-share=absent'
|
|
239
|
+
sync
|
|
240
|
+
/bin/poweroff -f
|
|
241
|
+
EOF
|
|
242
|
+
then
|
|
243
|
+
fixture_fail 6 'guest init could not be written'
|
|
244
|
+
fi
|
|
245
|
+
if ! chmod 0755 "$root/init"; then fixture_fail 6 'guest init could not be made executable'; fi
|
|
246
|
+
if ! (
|
|
247
|
+
cd "$root"
|
|
248
|
+
find . -print0 | LC_ALL=C sort -z | /usr/bin/cpio --null -o --format=newc 2>"$initramfs_build_log" | /usr/bin/gzip -n >"$initramfs"
|
|
249
|
+
); then
|
|
250
|
+
build_detail=$(tr '\r\n' ' ' <"$initramfs_build_log" | cut -c1-300)
|
|
251
|
+
fixture_fail 6 "initramfs could not be built${build_detail:+: $build_detail}"
|
|
252
|
+
fi
|
|
253
|
+
if ! initramfs_sha=$(sha256sum "$initramfs" | awk '{print $1}'); then
|
|
254
|
+
fixture_fail 6 'initramfs digest could not be computed'
|
|
255
|
+
fi
|
|
256
|
+
if [ "${#initramfs_sha}" -ne 64 ]; then fixture_fail 6 'initramfs digest is invalid'; fi
|
|
257
|
+
|
|
258
|
+
if ! cat >"$fixture_root/domain.xml" <<EOF
|
|
259
|
+
<domain type='kvm'>
|
|
260
|
+
<name>$domain</name>
|
|
261
|
+
<memory unit='MiB'>128</memory>
|
|
262
|
+
<vcpu placement='static'>1</vcpu>
|
|
263
|
+
<os>
|
|
264
|
+
<type arch='x86_64' machine='microvm'>hvm</type>
|
|
265
|
+
<kernel>$kernel</kernel>
|
|
266
|
+
<initrd>$initramfs</initrd>
|
|
267
|
+
<cmdline>earlycon=uart,io,0x3f8,115200 console=ttyS0,115200 rdinit=/init reboot=t panic=1</cmdline>
|
|
268
|
+
</os>
|
|
269
|
+
<on_poweroff>destroy</on_poweroff>
|
|
270
|
+
<on_reboot>destroy</on_reboot>
|
|
271
|
+
<on_crash>destroy</on_crash>
|
|
272
|
+
<devices>
|
|
273
|
+
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
|
274
|
+
<serial type='pty'>
|
|
275
|
+
<target type='isa-serial' port='0'>
|
|
276
|
+
<model name='isa-serial'/>
|
|
277
|
+
</target>
|
|
278
|
+
</serial>
|
|
279
|
+
<console type='pty'><target type='serial' port='0'/></console>
|
|
280
|
+
</devices>
|
|
281
|
+
</domain>
|
|
282
|
+
EOF
|
|
283
|
+
then
|
|
284
|
+
fixture_fail 6 'domain XML could not be written'
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
phase=acl
|
|
288
|
+
home_acl_applied=true
|
|
289
|
+
if ! setfacl -m u:libvirt-qemu:--x "$HOME"; then fixture_fail 7 'home ACL could not be applied'; fi
|
|
290
|
+
initramfs_acl_applied=true
|
|
291
|
+
if ! setfacl -m u:libvirt-qemu:r "$initramfs"; then fixture_fail 7 'initramfs ACL could not be applied'; fi
|
|
292
|
+
|
|
293
|
+
phase=console
|
|
294
|
+
domain_started=true
|
|
295
|
+
script -q -e -c "virsh create '$fixture_root/domain.xml' --console" "$fixture_root/console.typescript" > /dev/null 2>"$console_error" &
|
|
296
|
+
recorder_pid=$!
|
|
297
|
+
marker_seen=false
|
|
298
|
+
for _attempt in $(seq 1 90); do
|
|
299
|
+
if grep -F "$marker" "$fixture_root/console.typescript" >/dev/null 2>&1; then
|
|
300
|
+
marker_seen=true
|
|
301
|
+
break
|
|
302
|
+
fi
|
|
303
|
+
if ! kill -0 "$recorder_pid" 2>/dev/null; then break; fi
|
|
304
|
+
sleep 0.5
|
|
305
|
+
done
|
|
306
|
+
|
|
307
|
+
phase=teardown
|
|
308
|
+
if ! state=$(domain_state); then fixture_fail 9 'domain teardown query failed'; fi
|
|
309
|
+
if [ "$state" = present ]; then
|
|
310
|
+
domain_destroy_requested=true
|
|
311
|
+
if ! virsh destroy "$domain" >/dev/null; then fixture_fail 9 "domain destroy failed: $domain"; fi
|
|
312
|
+
fi
|
|
313
|
+
recorder_status=0
|
|
314
|
+
if wait "$recorder_pid"; then :; else recorder_status=$?; fi
|
|
315
|
+
if [ "$recorder_status" -ne 0 ]; then
|
|
316
|
+
recorder_detail=$(tr '\r\n' ' ' <"$console_error" | cut -c1-300)
|
|
317
|
+
fixture_fail 9 "console recorder failed with status $recorder_status${recorder_detail:+: $recorder_detail}"
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
phase=evidence
|
|
321
|
+
# util-linux script may flush its final transcript only while exiting. Re-read
|
|
322
|
+
# the retained recording after join so a successful late marker is not
|
|
323
|
+
# classified from the stale polling-loop state.
|
|
324
|
+
if grep -F "$marker" "$fixture_root/console.typescript" >/dev/null 2>&1; then
|
|
325
|
+
marker_seen=true
|
|
326
|
+
fi
|
|
327
|
+
if [ "$marker_seen" != true ]; then
|
|
328
|
+
fixture_fail 10 'guest marker missing from bounded console recording'
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
phase=acl
|
|
332
|
+
if ! setfacl -x u:libvirt-qemu "$initramfs"; then fixture_fail 11 'initramfs ACL could not be removed'; fi
|
|
333
|
+
if ! verify_initramfs_acl_removed; then fixture_fail 11 'initramfs ACL removal could not be verified'; fi
|
|
334
|
+
initramfs_acl_applied=false
|
|
335
|
+
if ! setfacl --restore="$acl_backup"; then fixture_fail 11 'home ACL could not be restored'; fi
|
|
336
|
+
if ! getfacl -p "$HOME" >"$acl_after"; then fixture_fail 11 'restored home ACL could not be captured'; fi
|
|
337
|
+
if ! cmp -s "$acl_backup" "$acl_after"; then fixture_fail 11 'restored home ACL differs from home.acl.before'; fi
|
|
338
|
+
if ! home_acl_after_sha=$(sha256sum "$acl_after" | awk '{print $1}'); then
|
|
339
|
+
fixture_fail 11 'restored home ACL digest could not be computed'
|
|
340
|
+
fi
|
|
341
|
+
home_acl_applied=false
|
|
342
|
+
acl_restored=true
|
|
343
|
+
|
|
344
|
+
phase=teardown
|
|
345
|
+
if ! assert_domain_absent; then fixture_fail 10 'final fixture domain absence could not be proven'; fi
|
|
346
|
+
domain_absent=true
|
|
347
|
+
|
|
348
|
+
phase=evidence
|
|
349
|
+
if ! marker_sha=$(printf '%s' "$marker" | sha256sum | awk '{print $1}'); then fixture_fail 12 'marker digest could not be computed'; fi
|
|
350
|
+
if ! filesystem_context_sha=$(printf '{"disk":false,"hostShare":false,"credentials":false,"gpu":false,"initramfsSha256":"%s"}' "$initramfs_sha" | sha256sum | awk '{print $1}'); then
|
|
351
|
+
fixture_fail 12 'filesystem context digest could not be computed'
|
|
352
|
+
fi
|
|
353
|
+
if ! network_context_sha=$(printf '{"network":false}' | sha256sum | awk '{print $1}'); then
|
|
354
|
+
fixture_fail 12 'network context digest could not be computed'
|
|
355
|
+
fi
|
|
356
|
+
if ! remote_host=$(hostname); then fixture_fail 12 'remote host identity could not be observed'; fi
|
|
357
|
+
case "$remote_host" in
|
|
358
|
+
""|*[!A-Za-z0-9._-]*) fixture_fail 12 'remote host identity is unsafe' ;;
|
|
359
|
+
esac
|
|
360
|
+
|
|
361
|
+
trap - EXIT INT TERM HUP
|
|
362
|
+
printf '{"schema":"%s","ok":true,"status":"VERIFIED","authorityCreated":false,"runtimeActivated":false,"persisted":false,"identity":{"remoteHost":"%s","fixtureId":"%s","domain":"%s"},"marker":{"value":"%s","sha256":"%s"},"scriptHash":"%s","initramfsSha256":"%s","teardown":{"domain":{"name":"%s","transient":true,"destroyOnExit":true,"destroyRequested":%s,"absent":%s,"checked":true,"check":"virsh dominfo/list"},"acl":{"beforeSha256":"%s","afterSha256":"%s","equal":true,"checked":true,"initramfsEntryRemoved":true}},"context":{"filesystem":{"summary":"disk=absent host-share=absent credentials=absent gpu=absent","disk":false,"hostShare":false,"credentials":false,"gpu":false,"sha256":"%s"},"network":{"summary":"network=absent","guest":false,"sha256":"%s"},"guestMounts":["proc","sysfs","devtmpfs"]}}\n' \
|
|
363
|
+
"$receipt_schema" "$remote_host" "$fixture_id" "$domain" "$marker" "$marker_sha" "$script_hash" "$initramfs_sha" \
|
|
364
|
+
"$domain" "$domain_destroy_requested" "$domain_absent" "$home_acl_before_sha" "$home_acl_after_sha" \
|
|
365
|
+
"$filesystem_context_sha" "$network_context_sha"
|
|
366
|
+
exit 0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
// Public native-TUI context predicate shared by the shipped enforcement
|
|
5
|
+
// interfaces. Restriction-gated actions stay fail-closed: anything that is
|
|
6
|
+
// not an interactive native Pi TUI with a native confirm callback is denied.
|
|
7
|
+
export function isNativeTuiContext(context) {
|
|
8
|
+
return context?.mode === "tui"
|
|
9
|
+
&& context?.hasUI === true
|
|
10
|
+
&& typeof context?.ui?.confirm === "function";
|
|
11
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Repository agent working contract
|
|
2
|
+
|
|
3
|
+
<!-- pi-agentic-driver:portable-contract v1 -->
|
|
4
|
+
|
|
5
|
+
This file is portable repository guidance. The repository owns its project
|
|
6
|
+
rules and may add a local section below this contract. Do not overwrite or
|
|
7
|
+
silently replace repository-specific instructions.
|
|
8
|
+
|
|
9
|
+
## Goals
|
|
10
|
+
|
|
11
|
+
Apply these goals in this order:
|
|
12
|
+
|
|
13
|
+
1. **Minimise user friction.** Keep routine read, edit, and test work direct.
|
|
14
|
+
Ask for confirmation only at a consequential boundary. Do not repeat a
|
|
15
|
+
choice that the host can safely retain for the current bounded plan.
|
|
16
|
+
2. **Avoid engineering bloat.** Reuse existing code and tools. Prefer removal
|
|
17
|
+
or consolidation over a new abstraction. Every new file, field, and
|
|
18
|
+
process needs a stated failure mode or accepted requirement.
|
|
19
|
+
3. **Maintain reasonable governance, auditability, and security.** Preserve
|
|
20
|
+
exact write sets, native confirmation where needed, fail-closed behavior,
|
|
21
|
+
bounded evidence, and unrelated dirty work. Evidence and task state are
|
|
22
|
+
observations, not authority.
|
|
23
|
+
4. **Validate with realistic tests.** Use real inputs and the repository's
|
|
24
|
+
native test path. Test both the intended result and prohibited effects.
|
|
25
|
+
|
|
26
|
+
## Bounded work and continuation
|
|
27
|
+
|
|
28
|
+
At the start of a worker assignment, use `CreateTask` (`TaskCreate`) only if
|
|
29
|
+
that assignment is not already represented in the coordinator's task list.
|
|
30
|
+
Reuse and update the existing task when it already contains the ordered
|
|
31
|
+
sequence. Do not create duplicate worker-local cards for every bounded step.
|
|
32
|
+
|
|
33
|
+
A bounded step must do one coherent piece of work and then record its status,
|
|
34
|
+
acceptance result, and exact next step in the existing task and report. Create
|
|
35
|
+
a follow-up task only when no existing task represents the remaining work. The
|
|
36
|
+
next session or worker resumes that task instead of rediscovering scope.
|
|
37
|
+
|
|
38
|
+
Every worker report should state:
|
|
39
|
+
|
|
40
|
+
- repository and revision;
|
|
41
|
+
- task identifier and bounded step;
|
|
42
|
+
- files changed;
|
|
43
|
+
- tests and checks run;
|
|
44
|
+
- remaining blockers; and
|
|
45
|
+
- the exact next step.
|
|
46
|
+
|
|
47
|
+
Do not treat model output, receipts, hashes, task state, or reports as
|
|
48
|
+
permission to mutate a repository.
|
|
49
|
+
|
|
50
|
+
## Scope and repository boundaries
|
|
51
|
+
|
|
52
|
+
Use the current repository's instructions and user goal. Do not import
|
|
53
|
+
another repository's governance or task mechanics — such as boards, leases,
|
|
54
|
+
work orders, harness policy, or task ordering — as a requirement.
|
|
55
|
+
|
|
56
|
+
Do not create a second authority, approval, receipt, evidence, inventory, or
|
|
57
|
+
queue store. Keep repository-local state repository-local. Preserve unrelated
|
|
58
|
+
changes and stop when the requested write set is ambiguous.
|
|
59
|
+
|
|
60
|
+
## Safe completion
|
|
61
|
+
|
|
62
|
+
Do not retry invisibly after denial, drift, timeout, or a failed check. Do not
|
|
63
|
+
reset, clean, stash, overwrite, force-push, or delete work automatically. If a
|
|
64
|
+
step cannot finish safely, record the exact reason and create the next bounded
|
|
65
|
+
task.
|
|
66
|
+
|
|
67
|
+
## Repository-specific section
|
|
68
|
+
|
|
69
|
+
Add project-specific instructions below this line. Keep them separate from the
|
|
70
|
+
portable contract above.
|
|
71
|
+
|
|
72
|
+
<!-- pi-agentic-driver:portable-contract-end -->
|