Rectify: Recipe-Level Feature Gate Enablement — Unified Visibility Axis#1859
Merged
Trecek merged 4 commits intoMay 5, 2026
Merged
Conversation
Fixes the asymmetry between pack gate (which has recipe-level override) and feature gate (which had no recipe-level input). Recipes can now declare requires_features: [planner] to ensure their skill-category features are enabled in init_session, matching the pattern used by requires_packs. Key changes: - Recipe schema: adds requires_features: list[str] field with FEATURE_REGISTRY validation - recipe/io.py: parses requires_features from YAML - recipe/_recipe_composition.py: union-merges requires_features from sub-recipes - recipe/_api.py: propagates requires_features into LoadRecipeResult - pipeline/context.py: adds active_recipe_features: frozenset[str] | None - tools_kitchen.py: sets/clears active_recipe_features on open/close - tools_execution.py: passes recipe_features to init_session - server/_lifespan.py: initializes active_recipe_features = frozenset() - workspace/session_skills.py: accepts recipe_features param, merges into session_features when feat not already set by user config (explicit user config wins over recipe-level defaults) - disabled_feature_tags now uses session_features instead of config.features for consistency with the merged state - recipe/rules/rules_features.py: adds undeclared-feature-requirement rule that flags recipes using feature-gated skills without requires_features - recipes/planner.yaml: adds requires_features: [planner] - Tests: 7 new tests in test_session_skills_features.py, 3 in test_schema.py, 2 in test_rules_features.py, 1 arch invariant in test_feature_registry.py
Both LoadRecipeResult and OpenKitchenResult now include requires_features, so both _FMT_LOAD_RECIPE_SUPPRESSED and _FMT_OPEN_KITCHEN_SUPPRESSED must declare it to satisfy the field coverage contract tests.
…on write site line number
Trecek
commented
May 5, 2026
Collaborator
Author
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit PR Review — Verdict: approved_with_comments
Trecek
commented
May 5, 2026
Collaborator
Author
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit review: warning-only findings detected. See inline comments — no blocking changes required.
…idation for requires_features - Replace `or []` coercion with `_rf_val if _rf_val is not None else []` so falsy non-None values (False, 0, "") raise via the isinstance guard instead of silently becoming [] - Add element-level check: non-string entries in requires_features_raw now raise ValueError before reaching Recipe.__post_init__ Addresses review comments 3185460963 and 3185460965.
Trecek
added a commit
that referenced
this pull request
May 8, 2026
…is (#1859) ## Summary The skill visibility system has two independent, uncoordinated gating axes: the **pack gate** (via `PACK_REGISTRY` + `_resolve_effective_disabled`) and the **feature gate** (via `FEATURE_REGISTRY` + `_is_skill_disabled`). The pack gate has a recipe-level override mechanism (`requires_packs` on `Recipe` flows through `ToolContext.active_recipe_packs` into `_resolve_effective_disabled` where it subtracts from the disabled set). The feature gate has no equivalent — `session_features` is derived exclusively from `config.features`, and recipes cannot declare feature requirements. This asymmetry means any `FEATURE_REGISTRY` entry with `default_enabled=False` and non-empty `skill_categories` silently suppresses its skills in all headless L1 sessions, even when the active recipe dispatches those skills. The planner is the first (and currently only) feature hitting this gap, but the architecture makes it inevitable for any future feature following the same pattern. The fix adds a `requires_features` field to the `Recipe` schema, flows it through the same path as `requires_packs`, and merges it into `session_features` in `init_session`. A new static validation rule catches recipes that reference feature-gated skills without declaring the corresponding feature requirement. An architecture test enforces the invariant that every feature with non-empty `skill_categories` has a tested recipe-level enablement path. Closes #1852 ## Implementation Plan Plan file: `/home/talon/projects/autoskillit-runs/remediation-20260504-163437-353221/.autoskillit/temp/rectify/rectify_planner_feature_gate_immunity_2026-05-04_163437.md` 🤖 Generated with [Claude Code](https://claude.com/claude-code) via AutoSkillit <!-- autoskillit:pipeline-signature steps=prepare_pr,run_arch_lenses,compose_pr,annotate_pr_diff,review_pr -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The skill visibility system has two independent, uncoordinated gating axes: the pack gate (via
PACK_REGISTRY+_resolve_effective_disabled) and the feature gate (viaFEATURE_REGISTRY+_is_skill_disabled). The pack gate has a recipe-level override mechanism (requires_packsonRecipeflows throughToolContext.active_recipe_packsinto_resolve_effective_disabledwhere it subtracts from the disabled set). The feature gate has no equivalent —session_featuresis derived exclusively fromconfig.features, and recipes cannot declare feature requirements.This asymmetry means any
FEATURE_REGISTRYentry withdefault_enabled=Falseand non-emptyskill_categoriessilently suppresses its skills in all headless L1 sessions, even when the active recipe dispatches those skills. The planner is the first (and currently only) feature hitting this gap, but the architecture makes it inevitable for any future feature following the same pattern.The fix adds a
requires_featuresfield to theRecipeschema, flows it through the same path asrequires_packs, and merges it intosession_featuresininit_session. A new static validation rule catches recipes that reference feature-gated skills without declaring the corresponding feature requirement. An architecture test enforces the invariant that every feature with non-emptyskill_categorieshas a tested recipe-level enablement path.Closes #1852
Implementation Plan
Plan file:
/home/talon/projects/autoskillit-runs/remediation-20260504-163437-353221/.autoskillit/temp/rectify/rectify_planner_feature_gate_immunity_2026-05-04_163437.md🤖 Generated with Claude Code via AutoSkillit