Skip to content

fix: binding を持たない manifest で SessionStart の通知が無音になる問題を修正(v0.77.1) - #168

Merged
okash1n merged 2 commits into
mainfrom
fix/check-pending-legacy-manifest-binding
Aug 31, 2026
Merged

fix: binding を持たない manifest で SessionStart の通知が無音になる問題を修正(v0.77.1)#168
okash1n merged 2 commits into
mainfrom
fix/check-pending-legacy-manifest-binding

Conversation

@loadbalance-sudachi-kun

Copy link
Copy Markdown
Contributor

Fixes #166

概要

check-pending.sh_load_manifest_binding が、runtime binding を持たない manifest を「不正な manifest」と判定していた。結果として _resolve_kit_repo が失敗し、新機能・新プラグインの SessionStart 通知が何の表示もなく抑止されていた

対象は ~/.claude/.starter-kit-manifest.json が存在し、かつ kit_repo / config_file を持たないインストール。write_manifest は MDM 環境で policy_sha256 形式を出力するため MDM 管理下の環境が該当し、binding 導入前の古い manifest も同様。

原因

binding="$(jq -cse '... else null end ... else error("invalid manifest") end' "$manifest" 2>/dev/null)" || {
  _MANIFEST_BINDING_STATE="invalid"
  return 0
}

[[ "$binding" != "null" ]] || return 0

「binding なし」を表すセンチネルは null。しかし jq -e最後の出力が null または false のとき終了コード 1 を返す。したがって binding を持たない manifest では常に || 分岐に落ち、_MANIFEST_BINDING_STATElegacy ではなく invalid になる。直後の null 判定はこの経路では到達しない。

同関数のコメントは意図をこう述べており、実装は逆の動作をしていた。

Older and MDM-managed manifests do not carry a runtime binding. Preserve their legacy config/default-checkout lookup, but fail closed when a binding is present only partially or is otherwise malformed.

影響

invalid は下流で次のように効く(同ファイル :168)。

[[ "$_MANIFEST_BINDING_STATE" != "invalid" ]] || return 1

_resolve_kit_repo が 1 を返して KIT_REPO が解決されず、FEATURE_CATALOG / PLUGIN_CATALOG が空のまま hook が exit 0 で終了する。失敗が利用者にも管理者にも見えない。 ~/.claude-starter-kit.conf に有効な KIT_REPO があっても、既定のチェックアウトが存在しても使われない。

修正

-e を外す。null は正常なセンチネルであって失敗ではない。

部分的な binding と壊れた manifest は引き続き error() 経由で非ゼロ終了するため、fail-closed の挙動は変わらない。同じフィルタを持つ姉妹実装 wizard/runtime-binding.sh:19 は元から jq -cs-e なし)で、そちらが意図した形。commands/update-kit.md:31-e を残す代わりにセンチネルを truthy な [] にしている。check-pending.sh だけが -enull を組み合わせていた。

実測

同一の HOME・pending ファイル・カタログで manifest だけを差し替えた結果。

manifest 修正前 修正後
なし 通知あり 通知あり
{"version":2,"mdm_managed":true,"policy_sha256":"abc"} (空) 通知あり
{"version":1,"files":[]} (空) 通知あり
{"version":2,"kit_repo":"/tmp/incomplete"}(部分的) (空) (空)
壊れた JSON (空) (空)

テスト

tests/unit/test-check-pending.sh に 3 件追加した。

  • MDM 形式 manifest(binding なし)で通知が出ること
  • 旧 v1 manifest(binding なし)で通知が出ること
  • 壊れた manifest では引き続き通知が出ないこと(fail-closed の逆方向の退行防止)

既存のテストは「manifest を作らない経路」「完全な binding」「部分的な binding」しか通っておらず、「manifest はあるが binding が無い」ケースが一度も実行されていなかった。これが本不具合が検出されなかった理由。

修正前のコードでは新規 3 件のうち 2 件が失敗する(Total: 32 Pass: 30 Fail: 2)。修正後は 32/32 通過。

実行した検証

  • shellcheck -S warning features/feature-recommendation/scripts/check-pending.sh tests/unit/test-check-pending.sh — いずれもクリーン
  • tests/unit/test-check-pending.sh — 32/32 通過(修正前 30/32)

アップグレード経路

ENABLE_* フラグ、profile 既定値、生成ファイル、settings キー、manifest 形式のいずれも変更していない。変更は hook スクリプト 1 ファイルの判定に閉じている。

このスクリプトは deploy_hook_scripts() / _update_hook_scripts() により ~/.claude/hooks/feature-recommendation/ へ配布されるため、既存インストールは次回の更新で修正版を受け取る。manifest の書き換えや利用者側の操作は不要。

ドキュメント

  • CHANGELOG.md — 更新済み(## [0.77.1]
  • README.md / README.en.md / docs/ — 変更不要。この内部判定と失敗時の挙動はどこにも記載されていない
  • MDM — mdm/render-expected.pylib/features.sh / profiles/*.conf / i18n/*/CLAUDE.md.base / feature partials のみを読む。スクリプト本文の変更は expected state の再生成を要さない。ただし本修正はMDM 管理下の環境で通知が出るようになる変更であり、MDM で ENABLE_FEATURE_RECOMMENDATION を有効にしている場合は挙動が変わる(これまで抑止されていた通知が出る)

補足

バージョンは 0.77.1 とした。#161(0.76.1)、#162(0.76.2)、#163(0.77.0)が先にマージされる前提。順序が変わる場合は付け替える。

🤖 Generated with Claude Code

Fixes #166

check-pending.sh の _load_manifest_binding は、runtime binding の有無を
jq -cse の結果で判定していた。

  binding="$(jq -cse '... else null end ...' "$manifest" 2>/dev/null)" || {
    _MANIFEST_BINDING_STATE="invalid"
    return 0
  }
  [[ "$binding" != "null" ]] || return 0

「binding なし」を表すセンチネルは null だが、jq -e は最後の出力が null または
false のとき終了コード 1 を返す。このため binding を持たない manifest では常に
|| 分岐に落ち、_MANIFEST_BINDING_STATE が legacy ではなく invalid になっていた。
直後の null 判定はこの経路では到達しない。

同関数のコメントは「旧形式と MDM manifest は binding を持たないので legacy の
探索を維持する」と述べており、実装は逆の動作をしていた。

影響:

  invalid は下流で [[ "$_MANIFEST_BINDING_STATE" != "invalid" ]] || return 1 と
  して効くため、_resolve_kit_repo が失敗して KIT_REPO が解決されない。カタログが
  空のまま hook が exit 0 で終了するので、新機能・新プラグインの通知が何の表示も
  なく抑止される。~/.claude-starter-kit.conf に有効な KIT_REPO があっても、既定の
  チェックアウトが存在しても使われない。

  対象は manifest が存在し kit_repo / config_file を持たないインストール。
  write_manifest は MDM 環境で policy_sha256 形式を出力するため MDM 管理下の環境が
  該当し、binding 導入前の古い manifest も同様。

修正:

  -e を外した。null は正常なセンチネルであって失敗ではない。部分的な binding と
  壊れた manifest は引き続き error() 経由で非ゼロ終了するため fail-closed の挙動は
  変わらない。同じフィルタを持つ wizard/runtime-binding.sh は元から -e なしで、
  そちらが意図した形だった。

実測(同一の HOME・pending ファイル・カタログで manifest だけを変えたもの):

  manifest                                    修正前    修正後
  なし                                        通知あり  通知あり
  {"version":2,"mdm_managed":true,...}        (空)    通知あり
  {"version":1,"files":[]}                    (空)    通知あり
  {"version":2,"kit_repo":"/tmp/incomplete"}  (空)    (空)
  壊れた JSON                                 (空)    (空)

回帰テストを 3 件追加した。既存のテストは manifest を作らない経路と、完全な
binding・部分的な binding しか通っておらず、「manifest はあるが binding が無い」
ケースが未検査だった。

検証:
- shellcheck -S warning: check-pending.sh / test-check-pending.sh ともにクリーン
- tests/unit/test-check-pending.sh: 32/32 通過(修正前は 30/32)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T08:46:54.207665Z edcf5e1 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc4af9d756

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md

The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).

## [0.77.1] - 2026-08-31

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the next patch version in the changelog

When this commit is applied to its recorded parent (554e455), the latest release is 0.76.0 and neither 0.76.1/0.76.2 nor 0.77.0 exists, so publishing this heading would skip directly to 0.77.1 and associate this patch fix with a nonexistent release lineage. Change it to 0.76.1, or rebase the commit only after the prerequisite releases have actually landed.

AGENTS.md reference: AGENTS.md:L221-L224

Useful? React with 👍 / 👎.

…acy-manifest-binding

# Conflicts:
#	CHANGELOG.md
@okash1n
okash1n merged commit e3a0dd3 into main Aug 31, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants