fix(plugin): stop CI installing the jq the hooks no longer use (#4107)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 23s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 23s
Three loose ends from a49e7ed, all found by CI or by re-reading it.
TWO TESTS PINNED THE jq SYNTAX, not the word `jq`, so grepping the suite for
the tool name missed them: test_write_path_trigger asserted the literal filter
strings `(.note_ids // []) - (.sync_note_ids // [])` and `(.rule_ids // [])[]?`
appear in the hook. Re-spelled with the readers that replaced them. The claim
each makes is unchanged — that the reuse and sync channels keep their own
state file, their own query parameter and their own write-back.
CI STILL INSTALLED jq, TWICE. The "Install jq for hook execution tests" step
existed because those tests skipped rather than failed without it; the Plugin
hooks job installed it alongside shellcheck for the same reason. Removing a
dependency from the product and leaving CI to install it anyway means the
smoke tests never run under the condition they exist to assert. Both gone —
the hook tests now run on a bare image.
`awk 'END { print $0 }'` IS UNDEFINED IN POSIX. gawk retains the last record
in END and mawk does too, but it is not guaranteed, and reaching for a
non-portable idiom inside the change whose entire purpose is portability is
the same mistake one layer down. Now `{ last = $0 } END { if (NR) print last }`.
Verified it still selects the same start line on a real transcript.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
+13
-14
@@ -111,7 +111,7 @@ jobs:
|
|||||||
|
|
||||||
# Guards the one part of this repo that ships to users without a build step.
|
# Guards the one part of this repo that ships to users without a build step.
|
||||||
# See scripts/check_plugin.py for what it checks and, as importantly, what it
|
# See scripts/check_plugin.py for what it checks and, as importantly, what it
|
||||||
# can't check yet (shellcheck and jq are absent from ci-python).
|
# can't check yet (shellcheck is absent from ci-python).
|
||||||
plugin:
|
plugin:
|
||||||
name: Plugin hooks
|
name: Plugin hooks
|
||||||
if: github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
|
if: github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
|
||||||
@@ -133,12 +133,15 @@ jobs:
|
|||||||
# the only consumer today. Promotion into ci-python is filed as an issue
|
# the only consumer today. Promotion into ci-python is filed as an issue
|
||||||
# on CI-runner rather than assumed here.
|
# on CI-runner rather than assumed here.
|
||||||
#
|
#
|
||||||
# jq is not optional for the smoke test: every hook exits at line 1
|
# jq WAS installed here too, because every hook exited at line 1 without
|
||||||
# without it, so the check would pass while exercising nothing.
|
# it and the smoke test would have passed while exercising nothing. The
|
||||||
|
# hooks need no jq since #4107 — they use only what POSIX guarantees — so
|
||||||
|
# the smoke test now runs on a bare image, which is the condition it is
|
||||||
|
# actually meant to be asserting.
|
||||||
- name: Install shell tooling
|
- name: Install shell tooling
|
||||||
run: |
|
run: |
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get install -y -qq --no-install-recommends jq shellcheck
|
apt-get install -y -qq --no-install-recommends shellcheck
|
||||||
|
|
||||||
# On main the comparison would be against itself, so only the syntax and
|
# On main the comparison would be against itself, so only the syntax and
|
||||||
# pattern checks mean anything there.
|
# pattern checks mean anything there.
|
||||||
@@ -223,16 +226,12 @@ jobs:
|
|||||||
UV_PROJECT_ENVIRONMENT: /opt/venv
|
UV_PROJECT_ENVIRONMENT: /opt/venv
|
||||||
run: uv sync --locked --extra dev
|
run: uv sync --locked --extra dev
|
||||||
|
|
||||||
# The hook-EXECUTION tests (test_write_path_trigger's nudge pair) run the
|
# An "Install jq for hook execution tests" step stood here. The hook
|
||||||
# real bash hook, which exits silently without jq — and those tests skip
|
# EXECUTION tests run the real bash hook, which exited silently without
|
||||||
# rather than fail when it's absent, so without this step they would
|
# jq and skipped rather than failed, so the step existed to stop them
|
||||||
# quietly never be verified anywhere (ci-python ships without jq; same
|
# being silently unverified. Since #4107 the hooks need no jq, so the
|
||||||
# install the Plugin hooks job does).
|
# step is gone and those tests run against a bare image — and the point
|
||||||
- name: Install jq for hook execution tests
|
# of removing a dependency is lost if CI keeps installing it anyway.
|
||||||
run: |
|
|
||||||
apt-get update -qq
|
|
||||||
apt-get install -y -qq --no-install-recommends jq
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
# Integration tests (real Postgres) run in the `integration` job below.
|
# Integration tests (real Postgres) run in the `integration` job below.
|
||||||
run: /opt/venv/bin/python -m pytest tests/ -q -m "not integration"
|
run: /opt/venv/bin/python -m pytest tests/ -q -m "not integration"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "scribe",
|
"name": "scribe",
|
||||||
"description": "Scribe for Claude Code: connects the scribe MCP server, adds the hooks that deliver live project state and relevant records at the right moment, ships the shared client-neutral Scribe skills (using-scribe, writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code, shape-accounting), and syncs your saved Scribe Processes as skills (/scribe:sync).",
|
"description": "Scribe for Claude Code: connects the scribe MCP server, adds the hooks that deliver live project state and relevant records at the right moment, ships the shared client-neutral Scribe skills (using-scribe, writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code, shape-accounting), and syncs your saved Scribe Processes as skills (/scribe:sync).",
|
||||||
"version": "2026.09.20.1620",
|
"version": "2026.09.20.1623",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Bryan Van Deusen"
|
"name": "Bryan Van Deusen"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ turn_facts() { window | tail -n +"${1:-1}" | scribe_json_flat_lines \
|
|||||||
# slow way — correct, and slow, which is the right way round for a check that
|
# slow way — correct, and slow, which is the right way round for a check that
|
||||||
# can block a stop.
|
# can block a stop.
|
||||||
start=$(window | grep -n -F '"message":{"role":"user","content":"' 2>/dev/null \
|
start=$(window | grep -n -F '"message":{"role":"user","content":"' 2>/dev/null \
|
||||||
| cut -d: -f1 | awk 'END { if (NR) print $0 }')
|
| cut -d: -f1 | awk '{ last = $0 } END { if (NR) print last }')
|
||||||
case "$start" in ''|*[!0-9]*) start=1 ;; esac
|
case "$start" in ''|*[!0-9]*) start=1 ;; esac
|
||||||
|
|
||||||
facts=$(turn_facts "$start")
|
facts=$(turn_facts "$start")
|
||||||
|
|||||||
@@ -1091,8 +1091,9 @@ def test_hook_keeps_sync_and_reuse_dedup_apart():
|
|||||||
assert ".sync.ids" in src # its own state file
|
assert ".sync.ids" in src # its own state file
|
||||||
assert "exclude_sync_ids=" in src # its own query channel
|
assert "exclude_sync_ids=" in src # its own query channel
|
||||||
# The reuse file must NOT swallow sync ids — the write-back subtracts them.
|
# The reuse file must NOT swallow sync ids — the write-back subtracts them.
|
||||||
assert "(.note_ids // []) - (.sync_note_ids // [])" in src
|
# Spelled with the readers that replaced jq (#4107); the claim is unchanged.
|
||||||
assert "(.sync_note_ids // [])[]?" in src
|
assert "scribe_json_list_minus \"$body_flat\" '.note_ids' '.sync_note_ids'" in src
|
||||||
|
assert "scribe_json_list \"$body_flat\" '.sync_note_ids'" in src
|
||||||
|
|
||||||
|
|
||||||
def _hook_runtime_env():
|
def _hook_runtime_env():
|
||||||
@@ -1668,7 +1669,7 @@ def test_hook_keeps_the_rule_channel_apart_from_the_other_three():
|
|||||||
src = HOOK.read_text()
|
src = HOOK.read_text()
|
||||||
assert ".rules.ids" in src # its own state file
|
assert ".rules.ids" in src # its own state file
|
||||||
assert "exclude_rule_ids=" in src # its own query channel
|
assert "exclude_rule_ids=" in src # its own query channel
|
||||||
assert "(.rule_ids // [])[]?" in src # its own write-back
|
assert "scribe_json_list \"$body_flat\" '.rule_ids'" in src # its own write-back
|
||||||
# And it rides the same request as the rest, not a second round trip.
|
# And it rides the same request as the rest, not a second round trip.
|
||||||
assert "${rule_exclude_q}" in src
|
assert "${rule_exclude_q}" in src
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user