verify

GitHub

用于验证 BetterCmdTab 产品变更,通过构建应用并作为见证者捕获运行时证据,确认用户操作与预期结果的一致性。

.agents/skills/verify/SKILL.md rokartur/BetterCmdTab

Trigger Scenarios

需要验证代码变更的运行时行为 执行端到端的产品功能测试

Install

npx skills add rokartur/BetterCmdTab --skill verify -g -y
More Options

Non-standard path

npx skills add https://github.com/rokartur/BetterCmdTab/tree/main/.agents/skills/verify -g -y

Use without installing

npx skills use rokartur/BetterCmdTab@verify

指定 Agent (Claude Code)

npx skills add rokartur/BetterCmdTab --skill verify -a claude-code -g -y

安装 repo 全部 skill

npx skills add rokartur/BetterCmdTab --all -g -y

预览 repo 内 skill

npx skills add rokartur/BetterCmdTab --list

SKILL.md

Frontmatter
{
    "name": "verify",
    "description": "Witness BetterCmdTab product-source changes at the live macOS surface when a diff needs end-to-end runtime evidence."
}

Verify BetterCmdTab

A witness is a captured observation from the freshly built app after real user input crosses every changed seam. Build and test results are setup; the witness decides the verdict.

1. Bind the claim

Fix the scope as an explicit BASE..TARGET range or as the working tree. Inventory committed, staged, unstaged, and untracked files with the matching git diff --name-status commands plus git ls-files --others --exclude-standard. Map every changed product file to:

  1. the user action that reaches it; and
  2. the observable outcome that should change or remain unchanged.

Treat tests as specifications for what to drive. A diff with no runtime surface (docs, tests, or compile-time metadata only) is SKIP.

Complete when: the range is stated and every inventoried product file belongs to one runtime claim or has an explicit non-runtime reason.

2. Build and launch a witness process

Use the Debug lane by default. Use the Release lane for Liquid Glass/macOS 26, release-configuration, or performance claims. Signing, notarization, and updater installation are approval-gated release work outside this skill; return BLOCKED and ask before invoking release tooling. An ordinary Xcode Release build is not evidence for them.

VERIFY_ROOT="$PWD/build/verify"
SCHEME="BetterCmdTab Debug"
CONFIGURATION="Debug"
PRODUCT="BetterCmdTab Debug"
BUNDLE_ID="pro.bettercmdtab.BetterCmdTab.debug"

# Release lane:
# SCHEME="BetterCmdTab"; CONFIGURATION="Release"; PRODUCT="BetterCmdTab"
# BUNDLE_ID="pro.bettercmdtab.BetterCmdTab"

DERIVED_DATA="$VERIFY_ROOT/DerivedData-$CONFIGURATION"
mkdir -p "$VERIFY_ROOT"
if ! xcodebuild -project BetterCmdTab.xcodeproj \
  -scheme "$SCHEME" -configuration "$CONFIGURATION" \
  -derivedDataPath "$DERIVED_DATA" build \
  >"$VERIFY_ROOT/build.log" 2>&1; then
  tail -80 "$VERIFY_ROOT/build.log"
  exit 1
fi

APP="$DERIVED_DATA/Build/Products/$CONFIGURATION/$PRODUCT.app"
EXEC="$APP/Contents/MacOS/$PRODUCT"
test -x "$EXEC"

Every BetterCmdTab process installs global handlers. Before launch, identify all running BetterCmdTab processes. Gracefully clean up a recorded prior witness; if an installed copy is running, ask before quitting it, record its executable path and running state, and restore that exact copy afterward. A declined quit makes runtime verification BLOCKED.

Launch the bundle executable directly with isolated preferences and config. Keep its unique state for restarts and crash recovery. At the first launch of a verification session, an existing state-path means the prior run needs recovery. An intentional restart in the current session reuses the recorded state and skips this initializer.

test ! -e "$VERIFY_ROOT/state-path" || {
  echo "Recover the prior witness first: $VERIFY_ROOT/state-path" >&2
  exit 1
}
STATE="$(mktemp -d "$VERIFY_ROOT/state.XXXXXX")"
printf '%s\n' "$STATE" >"$VERIFY_ROOT/state-path"
printf '%s\n' "$EXEC" >"$VERIFY_ROOT/executable-path"
printf '%s\n' "$BUNDLE_ID" >"$VERIFY_ROOT/bundle-id"
mkdir -p "$STATE/home" "$STATE/xdg"

CFFIXED_USER_HOME="$STATE/home" \
XDG_CONFIG_HOME="$STATE/xdg" \
"$EXEC" -GitHubUpdater.checkInterval manual \
  >"$VERIFY_ROOT/app.stdout.log" 2>&1 &
echo $! >"$VERIFY_ROOT/app.pid"

Open Settings through the recorded process with:

osascript -e "tell application id \"$BUNDLE_ID\" to reopen"

The switcher becomes ready only after Accessibility trust. Panel appearance after the real chord is the readiness check. If macOS prompts for Accessibility or Automation, ask whether to grant it; the grant is persistent shared TCC state and belongs in the report. Without approval, return BLOCKED; preserve TCC as-is.

Complete when: the recorded PID resolves to EXEC and is the sole BetterCmdTab process, the intended surface is drivable, verification state is outside the user's defaults and XDG config, and any TCC change was approved.

3. Drive the changed seam

Reach the behavior through its real boundary: CGEvent/Carbon input, an AppKit control, a watched file, or an Accessibility window action. Calling an internal Swift function is a test, not a witness.

Changed area Drive Witness
App/, System/ Fresh launch, reopen, menu action, or relevant permission transition Window/menu/lifecycle state and filtered unified-log lines
Input/, Switcher/ Hold and send the actual configured chord with System Events; use a real password field for Secure Event Input and ask the user for a real trackpad gesture Cropped panel capture plus the selected/cancelled app or window outcome
Settings/, Preferences Reopen Settings, operate the control, restart with the same isolated state, then exercise its downstream behavior Restored control state and the changed live behavior
Catalog/, Windows/ Prepare named real apps/windows, open the switcher, then select or act on one Visible rows and resulting frontmost app/window state
ConfigFile, import/export Seed $STATE/xdg/bettercmdtab/config.json or use the real import/export UI File contents and the live setting/behavior after reload
updater/About Use the manual UI action against a safe target UI result and relevant unified-log lines
hot-path performance Use separate clean base/target worktrees and SHA-specific Release build/state roots; drive identical seeded scenarios under Instruments with Log.reveal Equal sample counts and median/p95 latency, CPU, or allocation numbers

For each independent claim, drive the claimed path and one adjacent probe: cancel, repeat, stale state, empty input, rapid input, or the neighboring error case. Inspect visual captures for clipping, stale/blank frames, focus, and contrast. A changed macOS 13 fallback requires a real macOS 13 host/VM; otherwise that claim is BLOCKED.

Destructive actions use a temporary target or dry run. Publishing, notarizing, installing an update, deleting user data, or changing shared system state requires approval before the action.

Complete when: every runtime claim has an observed expected outcome and its own adjacent probe has an observed outcome at the same surface.

4. Preserve evidence and restore the machine

Capture the smallest useful window/region with screencapture; read every image before using it as evidence. Capture nonvisual outcomes from app state or Unified Logging filtered to the witness process. Keep the relevant output inline; a local path alone is not evidence for a remote reader.

Request a graceful AppKit quit for the exact recorded PID, then wait for it to disappear:

VERIFY_ROOT="$PWD/build/verify"
ROOT_REAL="$(realpath "$VERIFY_ROOT")"
test "$ROOT_REAL" = "$(realpath "$PWD")/build/verify"
PID="$(cat "$VERIFY_ROOT/app.pid")"
EXEC="$(realpath "$(cat "$VERIFY_ROOT/executable-path")")"
case "$EXEC" in "$ROOT_REAL"/*) ;; *) exit 1 ;; esac
swift -e 'import AppKit
import Darwin
import Foundation
func normalized(_ url: URL) -> String {
  url.resolvingSymlinksInPath().standardizedFileURL.path
}
let pid = pid_t(CommandLine.arguments[1])!
let executable = URL(fileURLWithPath: CommandLine.arguments[2])
let bundle = executable.deletingLastPathComponent()
  .deletingLastPathComponent().deletingLastPathComponent()
guard let app = NSRunningApplication(processIdentifier: pid),
      let actualBundle = app.bundleURL,
      normalized(actualBundle) == normalized(bundle) else {
  fatalError("Recorded PID no longer belongs to the witness")
}
guard app.terminate() else { fatalError("AppKit termination request failed") }
let deadline = Date().addingTimeInterval(5)
while !app.isTerminated && Date() < deadline {
  RunLoop.current.run(until: Date().addingTimeInterval(0.1))
}
exit(app.isTerminated ? 0 : 1)
' "$PID" "$EXEC"

Signals bypass in-process symbolic-hotkey restoration. If AppKit quit fails or the process vanished abnormally, follow RECOVERY.md before removing state. After a clean quit, use the validated cleanup block in recovery step 3, then restore the approved installed app path.

Complete when: each reported step has reviewed evidence, the witness PID is gone after AppKit quit or recovery, state metadata is removed, native ⌘Tab works, and the installed app has its original running/stopped state.

5. Report the verdict

## Verification: <one-line claim>

**Verdict:** PASS | FAIL | BLOCKED | SKIP
**Build:** <scheme/configuration, ref, executable path>
**Claim:** <expected user-visible behavior>

### Claim 1: <expected behavior>
1. ✅ <real action> → <observation and evidence>
2. 🔍 <adjacent probe> → <observation and evidence>

<Repeat per independent claim.>

**Witness:** <attached screenshots or inline state/log excerpts>
**Findings:** <runtime surprises, friction, or “none”>
  • PASS: every claim was witnessed and the probe held.
  • FAIL: the running app contradicted a claim, regressed adjacent behavior, or produced ambiguous evidence.
  • BLOCKED: the surface could not be reached; include the exact build, permission, automation, or environment failure.
  • SKIP: no runtime surface exists; give the reason in one line.

Complete when: the verdict follows these definitions, every claim from step 1 is accounted for, and the evidence reaches the reader.

Version History

  • 7d5fa2e Current 2026-08-02 23:43

Same Skill Collection

.agents/skills/add-preference/SKILL.md
.agents/skills/localize-strings/SKILL.md
.agents/skills/release-changelog/SKILL.md
.agents/skills/release/SKILL.md

Metadata

Files
0
Version
7d5fa2e
Hash
dc2c6943
Indexed
2026-08-02 23:43

Главная - Вики-сайт
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-03 10:43
浙ICP备14020137号-1 $Гость$