feat(bin): gstack-design-detect wrapper + design_detector config key

bin/gstack-design-detect.ts finds and runs an impeccable engine the user
installed; it never installs, downloads, or executes anything that could
download. `probe` reads only: config (design_detector off → DISABLED),
IMPECCABLE_BIN (absolute, realpath outside the repo and cwd), a PATH walk
(absolute entries outside the repo; a #! shim counts as launcher-present,
never READY), the ~/.impeccable/bin/<newest semver>/ cache, and the engine
installed beside a skill launcher (scripts/bin/<os>-<arch>/impeccable, the
layout a real install produced). It reports IMPECCABLE_SKILL, host-aware
IMPECCABLE_HOOK (+ HOOK_OTHER), the ignore lists from .impeccable/config*.json,
IMPECCABLE_ENGINE_UNTESTED for versions outside the fixture set, and a hint
only when a launcher exists without its engine. `scan` re-probes, refuses
URLs and anything outside the repo root or the design-report allow-list
(realpath, so symlinks cannot escape), derives `--changed <base>` targets
NUL-safely through git and lib/frontend-scope.ts, batches 100 absolute paths
per engine call with stdin ignored, a SIGKILL timeout, a 50 MB stdout cap, and
sanitized length-capped fields, then prints one normalized JSON document
(--format gstack) or the engine's bytes (--format raw); DETECT_TOP (fenced as
untrusted content), DETECT_SUMMARY, and DETECT_EXIT go to stderr; exit code
passes through with 1 over 2 over 0; exit 3 is a gstack bug. `rules` prints
the mapped set. Every run appends a content-free line to the local analytics
file.

lib/design-detect-contract.ts owns every sentinel string, the limits, and the
normalized-finding shape (pure module); test/design-detect-contract.test.ts
asserts every sentinel-shaped token the agent can read exists there.
lib/frontend-scope.ts mirrors gstack-diff-scope's frontend arm, pinned by a
parity test that runs the bash script. bin/gstack-config gains
design_detector (auto | off, default auto, invalid values rejected with the
file unchanged). test/fixtures/fake-impeccable.ts is the env-driven engine
stand-in; test/gstack-design-detect.test.ts covers READY/NOT_CACHED/
NOT_AVAILABLE/DISABLED, env trust (.env never loaded, in-repo IMPECCABLE_BIN
ignored), newest-semver cache, hook and ignore detection, refusals, exit
passthrough, raw byte-identity, normalization, the display cap, timeout,
parse errors, diagnostics, --changed, and analytics. The egress scanner test
records the wrapper as a documented non-sink.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-09-08 16:01:18 +00:00
co-authored by Claude Fable 5.1
parent 71505f8374
commit 3867dae355
10 changed files with 1572 additions and 2 deletions
+16 -2
View File
@@ -122,6 +122,13 @@ CONFIG_HEADER='# gstack configuration — edit freely, changes take effect on ne
# # /document-release skip the outside-voice step entirely.
# # An invalid value is REJECTED (existing value preserved) so
# # a typo cannot silently turn paid Codex calls on or off.
# design_detector: auto # Deterministic design pre-pass through a user-installed
# # impeccable engine (/design-review, /review, /ship,
# # /design-html). auto = use the engine when the probe
# # finds one (gstack never installs or downloads it);
# # off = no probe, no scan, no hint, no /impeccable
# # handoff lines. An invalid value is REJECTED (existing
# # value preserved) so a typo cannot silently disable it.
# gstack_contributor: false # true = file field reports when gstack misbehaves
# skip_eng_review: false # true = skip eng review gate in /ship (not recommended)
#
@@ -149,6 +156,7 @@ lookup_default() {
checkpoint_push) echo "false" ;;
explain_level) echo "default" ;;
codex_reviews) echo "enabled" ;;
design_detector) echo "auto" ;; # auto | off — impeccable engine pre-pass in the design skills
gstack_contributor) echo "false" ;;
skip_eng_review) echo "false" ;;
workspace_root) echo "$HOME/conductor/workspaces" ;;
@@ -416,6 +424,12 @@ case "${1:-}" in
echo "Error: codex_reviews '$VALUE' not recognized. Valid values: enabled, disabled. Existing value left unchanged." >&2
exit 1
fi
# design_detector gates a third-party binary the user installed. Reject a typo
# rather than coerce it: "of" must not silently re-enable or disable the scan.
if [ "$KEY" = "design_detector" ] && [ "$VALUE" != "auto" ] && [ "$VALUE" != "off" ]; then
echo "Error: design_detector '$VALUE' not recognized. Valid values: auto, off. Existing value left unchanged." >&2
exit 1
fi
# cross_project_learnings: empty get is the first-run prompt sentinel.
# Skills enable only on the literal "true". A typo must not persist — that
# keeps the feature off and suppresses the prompt. Reject, like
@@ -455,7 +469,7 @@ case "${1:-}" in
skill_prefix checkpoint_mode checkpoint_push explain_level \
codex_reviews gstack_contributor skip_eng_review workspace_root \
artifacts_sync_mode artifacts_sync_mode_prompted plan_tune_hooks \
timeline_stop_hook; do
timeline_stop_hook design_detector; do
VALUE=$(read_config_value "$KEY" || true)
SOURCE="default"
if [ -n "$VALUE" ]; then
@@ -472,7 +486,7 @@ case "${1:-}" in
skill_prefix checkpoint_mode checkpoint_push explain_level \
codex_reviews gstack_contributor skip_eng_review workspace_root \
artifacts_sync_mode artifacts_sync_mode_prompted plan_tune_hooks \
timeline_stop_hook; do
timeline_stop_hook design_detector; do
printf ' %-24s %s\n' "$KEY:" "$(lookup_default "$KEY")"
done
;;