feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133
feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133
Conversation
… templates, commands, and scripts - Add strategy field validation in PresetManifest._validate() - Add VALID_PRESET_STRATEGIES and VALID_SCRIPT_STRATEGIES constants - Add PresetResolver.resolve_content() for composed content resolution - Add PresetResolver._collect_all_layers() for full priority stack - Update _register_commands() to compose before writing - Update CLI preset resolve command to show composition chain - Add resolve_template_content() to bash common.sh - Add Resolve-TemplateContent to PowerShell common.ps1 - Update scaffold preset.yml with strategy documentation - Update presets/README.md and ARCHITECTURE.md - Add 26 unit tests covering validation, composition, and chaining Agent-Logs-Url: https://github.com/github/spec-kit/sessions/c285c51b-f00b-480a-9eb2-ae70e3cbcb72 Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
…, improve default strategy test Agent-Logs-Url: https://github.com/github/spec-kit/sessions/c285c51b-f00b-480a-9eb2-ae70e3cbcb72 Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Address code-quality review: explain why PresetValidationError is intentionally caught and ignored (falls back to default 'replace' strategy so layer resolution continues).
00edba1 to
fa04828
Compare
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of always fully replacing them.
Changes:
- Introduces
strategyvalidation in preset manifests and a new Python composition resolver (_collect_all_layers()+resolve_content()). - Updates command registration to attempt composing command content before writing into agent directories.
- Adds shell (bash/PowerShell) “resolve composed content” helpers plus docs and extensive new tests for strategy behavior.
Show a summary per file
| File | Description |
|---|---|
| tests/test_presets.py | Adds strategy validation + composition resolver unit tests (including multi-preset chaining). |
| src/specify_cli/presets.py | Adds strategy constants/validation, command composition during registration, and composition-aware resolution APIs. |
| src/specify_cli/init.py | Enhances specify preset resolve output to show the composition chain when applicable. |
| scripts/powershell/common.ps1 | Adds Resolve-TemplateContent to compose template layers using strategies. |
| scripts/bash/common.sh | Adds resolve_template_content to compose template layers using strategies. |
| presets/scaffold/preset.yml | Documents the new strategy field and shows composition examples. |
| presets/README.md | Documents strategy semantics, supported combinations, and chaining behavior. |
| presets/ARCHITECTURE.md | Documents strategy table and where composition resolution is implemented across runtimes. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 8
- Fix bash newline handling: use printf instead of literal \n\n in prepend/append string concatenation (common.sh) - Fix PowerShell wrap: use .Replace() instead of -replace to avoid $ capture-group interpolation in replacement strings (common.ps1) - Fix layer collection to use manifest file path when available, falling back to convention-based path (presets.py, common.sh, common.ps1) - Fix install ordering: pre-register preset before command/skill registration so resolve_content() sees it in the priority stack - Fix skills divergence: use composed content from .composed/ dir when available instead of original command file for skill generation - Add fallback directory scan in bash resolve_template_content when python3/registry is unavailable, matching resolve_template() behavior - Clarify doc examples: note that file field can differ from convention path (scaffold/preset.yml, presets/README.md)
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of always fully replacing them.
Changes:
- Introduces
strategyvalidation in preset manifests and adds Python composition resolution across the full priority stack. - Updates command registration to write composed command content before registering with agent directories; adds CLI output to display a composition chain.
- Adds bash/PowerShell template-content composition helpers, documentation updates, and a large set of new tests.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Adds strategy validation, layer collection, composed content resolver, and command registration changes to use composed content. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to display a composition chain. |
scripts/bash/common.sh |
Adds resolve_template_content() to compose template content in bash using the same strategy concepts. |
scripts/powershell/common.ps1 |
Adds Resolve-TemplateContent to compose template content in PowerShell. |
presets/scaffold/preset.yml |
Documents the new strategy field and provides composition examples. |
presets/README.md |
Documents composition strategies and supported combinations; updates future-considerations list. |
presets/ARCHITECTURE.md |
Adds strategy table and references to the new composition resolution functions. |
tests/test_presets.py |
Adds extensive coverage for strategy validation, composition behavior, chaining, and layer collection ordering. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 3
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, with matching CLI output, shell parity, and expanded test coverage.
Changes:
- Introduces
strategyvalidation in preset manifests and implements bottom-up composition viaPresetResolver.collect_all_layers()+PresetResolver.resolve_content(). - Updates command registration to write composed command content into agent directories and reconciles agent outputs on install/remove.
- Extends Bash/PowerShell resolvers plus preset docs and scaffolding; adds extensive unit tests for strategy behavior and chaining.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Adds strategy validation, layer collection, content composition, and command reconciliation logic. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to show composition chains. |
scripts/bash/common.sh |
Adds resolve_template_content() and filters out disabled presets in registry traversal. |
scripts/powershell/common.ps1 |
Adds YAML-strategy parsing (via Python) and Resolve-TemplateContent; filters disabled presets. |
tests/test_presets.py |
Adds strategy validation and composition behavior tests (templates/commands/scripts + chaining + reconciliation). |
presets/scaffold/preset.yml |
Documents strategy usage and provides composition examples. |
presets/README.md |
Documents composition strategies and supported combinations. |
presets/ARCHITECTURE.md |
Documents strategy semantics and references resolution functions across implementations. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
scripts/bash/common.sh:540
layer_content=$(cat "$path")uses command substitution, which strips trailing newlines from the file content. That means composed output can differ from the underlying files (and from the Python resolver) in subtle ways. If exact content preservation matters, read/compose in a way that preserves trailing newlines or explicitly normalize behavior across implementations.
layer_content=$(cat "$path")
- Files reviewed: 8/8 changed files
- Comments generated: 4
- Persist normalized strategy: write lowercase value back to tmpl dict
so downstream composition logic always sees lowercase
- Normalize strategy in PowerShell: .ToLowerInvariant() after parsing
- Fix bash tab parsing: use IFS+read instead of parameter expansion to
avoid trailing newline in manifest_file; normalize with ${strategy,,}
- Gate CLI composition message: only show 'Final output is composed...'
when the top layer is non-replace (top replace wins outright)
There was a problem hiding this comment.
Pull request overview
Adds preset “composition strategies” so higher-priority presets can augment lower-priority templates/commands/scripts (prepend/append/wrap) rather than only fully replacing them, with consistent resolution across Python + shell helpers and updated CLI/docs/tests.
Changes:
- Add
strategyvalidation to preset manifests and implement multi-layer composition viaPresetResolver.collect_all_layers()+resolve_content(). - Update command registration to register composed command content (and reconcile after install/remove so priority stack, not install order, determines active agent command files).
- Add shell helpers + CLI output + documentation + tests for the strategy behaviors.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Implements strategy validation, layered resolution + composition, and command registration/reconciliation behavior. |
tests/test_presets.py |
Adds validation + resolver tests for strategies, chaining, ordering, and removal reconciliation. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to show composition chain when applicable. |
scripts/bash/common.sh |
Adds template content composition resolver in Bash + skips disabled presets from registry. |
scripts/powershell/common.ps1 |
Adds template content composition resolver in PowerShell + skips disabled presets from registry. |
presets/scaffold/preset.yml |
Documents the new strategy field and provides composition examples. |
presets/README.md |
Documents composition strategies and supported combinations; updates future considerations. |
presets/ARCHITECTURE.md |
Documents strategy semantics and points to the new resolution functions. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 5
- Add frontmatter composition test: verify core+preset command layers with frontmatter produce only one frontmatter block in composed output - Defer resolve_with_source: only call when collect_all_layers returns empty, avoiding redundant filesystem walk - Reuse CommandRegistrar.parse_frontmatter: replace local _strip_frontmatter helper with _split_frontmatter that delegates to the shared parse_frontmatter method - Fix removed_cmd_names collection: gather ALL command names before filtering out skill agents so reconciliation covers all affected commands including those only registered for skill-based agents - Preserve trailing newlines in bash: use sentinel character technique (cat + printf x + strip) to avoid command substitution stripping
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to preset-provided templates/commands/scripts so higher-priority presets can augment (prepend/append/wrap) lower-priority content instead of only replacing it, updating resolvers across Python + shell implementations and documenting the behavior.
Changes:
- Add
strategyvalidation topreset.ymlentries and implement bottom-up composition inPresetResolver.resolve_content()(with multi-layer chaining and command frontmatter handling). - Update command registration to materialize composed command content to disk and reconcile command/skill outputs after install/remove so results don’t depend on operation order.
- Add shell helpers (bash/pwsh) for composed template resolution, expand docs, and add extensive test coverage for strategy behavior.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Core implementation: strategy validation, layer collection, composition resolver, and command/skill reconciliation logic. |
tests/test_presets.py |
Adds validation + resolver + chaining + reconciliation tests for the new strategies. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to show composition chain when relevant. |
scripts/bash/common.sh |
Adds composed template resolver and filters disabled presets in registry iteration. |
scripts/powershell/common.ps1 |
Adds composed template resolver, Python discovery, and filters disabled presets in registry iteration. |
presets/scaffold/preset.yml |
Documents the new strategy field and provides usage examples in scaffold preset. |
presets/README.md |
Documents composition strategies and updates “future enhancements” section accordingly. |
presets/ARCHITECTURE.md |
Describes strategy semantics and points to implementation entrypoints across languages. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Extract stable source_id from display label in reconciliation: parse
'extension:foo v1.0' to 'foo' instead of passing the human-facing
display string as source_id
- Fix bash lowercase to be POSIX-compatible: use tr instead of ${,,}
which requires Bash 4+ and fails on macOS default Bash 3.2
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset resolution system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, and updates CLI/docs/tests and shell resolvers accordingly.
Changes:
- Introduces
strategyvalidation inpreset.ymland bottom-up multi-layer composition viaPresetResolver.collect_all_layers()/resolve_content(). - Updates command registration to write composed command content into agent directories and reconciles command files after install/remove.
- Extends CLI
specify preset resolveoutput, adds Bash/PowerShell template-content composition helpers, and documents the new feature with extensive tests.
Show a summary per file
| File | Description |
|---|---|
| tests/test_presets.py | Adds coverage for strategy validation, composition behavior, chaining, ordering, and reconciliation scenarios. |
| src/specify_cli/presets.py | Implements strategy validation, layer collection, content composition, command registration composition, and reconciliation logic. |
| src/specify_cli/init.py | Enhances preset resolve to display layer stack and composition chain. |
| scripts/bash/common.sh | Adds resolve_template_content() and updates preset sorting to ignore disabled presets. |
| scripts/powershell/common.ps1 | Adds Resolve-TemplateContent and updates preset sorting to ignore disabled presets; adds Python 3 discovery helper. |
| presets/scaffold/preset.yml | Documents strategy field and provides composition examples in the scaffold preset. |
| presets/README.md | Documents composition strategies and supported combinations; updates future considerations. |
| presets/ARCHITECTURE.md | Documents composition strategies and references the new resolution functions across implementations. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 4
- Warn on missing PyYAML in bash/PS1: emit stderr warning when manifest contains strategy: but YAML parsing failed, so users know composition strategies may be silently ignored - Fix composition chain base labeling: only mark the lowest layer as 'base', keep 'replace' label for non-effective replace layers above it - Clear frontmatter on replace layers: replace strategy resets top_frontmatter_text (even to None) since it replaces the whole command including metadata, preventing lower-layer frontmatter from leaking
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset resolution stack so presets can augment lower-priority templates/commands/scripts (instead of only replacing), and updates CLI/docs/tests to support and explain the new behavior.
Changes:
- Introduces
strategyvalidation in preset manifests and bottom-up composition inPresetResolver.resolve_content()/collect_all_layers(). - Updates command registration to materialize composed command content and reconciles command/skill outputs after install/remove.
- Adds shell-side template composition helpers plus extensive test coverage and documentation updates.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Implements strategy validation, layer collection + composition, and command reconciliation/registration changes. |
tests/test_presets.py |
Adds validation + composition + reconciliation test suite for the new strategy behavior. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to show composition chain details. |
scripts/bash/common.sh |
Adds composed template content resolver and filters disabled presets in registry scanning. |
scripts/powershell/common.ps1 |
Adds composed template content resolver (with Python 3 discovery) and filters disabled presets. |
presets/scaffold/preset.yml |
Documents strategy field and provides composition examples. |
presets/README.md |
Documents composition strategies and updates future-considerations section. |
presets/ARCHITECTURE.md |
Adds strategy table and links to resolver functions across Python/Bash/PowerShell. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 3
- Remove dead has_composition branch in resolve_content: after the top-replace early return, the top layer is guaranteed non-replace so the any() check was always true - Fix CLI composition chain base labeling: compute effective base index using same logic as resolve_content (last consecutive replace from bottom before first non-replace) instead of always labeling i==0 - Support extension manifest file paths in collect_all_layers: when convention lookup fails for commands, parse extension.yml to find the actual file path, enabling composition onto extension commands that use non-convention filenames
Replace broad 'except Exception: pass' with specific exception types (ExtValidationError, yaml.YAMLError) and add explanatory comment for the intentional fallback to convention-based lookup.
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset/template resolution system so presets can augment lower-priority content (prepend/append/wrap) instead of only replacing, and updates CLI/docs/tests accordingly.
Changes:
- Introduces
strategyvalidation in preset manifests and implements layered composition viaPresetResolver.collect_all_layers()+resolve_content(). - Updates command registration to pre-compose command content (and reconcile after install/remove) so agent command files reflect the effective priority stack.
- Adds shell equivalents for composed template resolution, expands documentation, and adds extensive test coverage for the new behaviors.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Adds strategy validation, layer collection + content composition, and command registration/reconciliation updates. |
src/specify_cli/__init__.py |
Enhances specify preset resolve output to display composition chain details. |
scripts/bash/common.sh |
Adds resolve_template_content() and filters disabled presets when reading registry. |
scripts/powershell/common.ps1 |
Adds Resolve-TemplateContent, a Python3 locator helper, and filters disabled presets when reading registry. |
tests/test_presets.py |
Adds new tests for strategy validation, composition behaviors, layer ordering, and remove-time reconciliation. |
presets/scaffold/preset.yml |
Documents the new strategy field and provides examples. |
presets/README.md |
Adds a “Composition Strategies” section and updates future considerations. |
presets/ARCHITECTURE.md |
Documents supported strategies and points to the new composition resolvers. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 8/8 changed files
- Comments generated: 3
- Add public register_commands_for_non_skill_agents() on CommandRegistrar: reconciliation no longer accesses private _ensure_configs() or iterates AGENT_CONFIGS directly - Cache parsed preset manifests in PresetResolver: _get_manifest() caches by pack_dir to avoid re-parsing YAML on each collect_all_layers() call - Fix frontmatter detection for empty dicts: detect based on --- fence presence rather than parsed dict truthiness, so empty frontmatter blocks are properly stripped during command composition
There was a problem hiding this comment.
Pull request overview
Adds composition strategies to the preset system so higher-priority presets can augment lower-priority layers (instead of always replacing), spanning Python resolution, shell helpers, CLI output, docs, and tests.
Changes:
- Introduces
strategyvalidation in preset manifests and implements bottom-up composition (replace/prepend/append/wrap) viaPresetResolver.collect_all_layers()+resolve_content(). - Updates command registration to register composed command content and adds post-install/remove reconciliation so agent command files reflect the current priority stack.
- Extends bash/powershell helpers, CLI
preset resolveoutput, scaffold/docs, and adds extensive tests for composition behavior.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/presets.py |
Core implementation: strategy validation, layer collection, composition, and command reconciliation/registration updates. |
src/specify_cli/agents.py |
Adds a registrar helper to register commands while skipping SKILL.md-based agents. |
src/specify_cli/__init__.py |
Enhances specify preset resolve to show composition chain using the new layer collector. |
scripts/bash/common.sh |
Adds resolve_template_content() and filters disabled presets from registry traversal. |
scripts/powershell/common.ps1 |
Adds YAML-aware Resolve-TemplateContent, Python 3 detection, and filters disabled presets. |
tests/test_presets.py |
Adds a large new test suite covering validation, composition behavior, ordering, and removal reconciliation. |
presets/scaffold/preset.yml |
Documents the new strategy field and provides composition examples. |
presets/README.md |
Adds a Composition Strategies section and updates “future considerations”. |
presets/ARCHITECTURE.md |
Documents strategy semantics and points to new resolution/composition functions. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 9/9 changed files
- Comments generated: 3
| def register_commands_for_non_skill_agents( | ||
| self, | ||
| commands: List[Dict[str, Any]], | ||
| source_id: str, | ||
| source_dir: Path, | ||
| project_root: Path, | ||
| ) -> Dict[str, List[str]]: | ||
| """Register commands for all non-skill agents in the project. | ||
| Like register_commands_for_all_agents but skips skill-based agents | ||
| (those with extension '/SKILL.md'). Used by reconciliation to avoid | ||
| overwriting properly formatted SKILL.md files. | ||
| Args: | ||
| commands: List of command info dicts | ||
| source_id: Identifier of the source | ||
| source_dir: Directory containing command source files | ||
| project_root: Path to project root | ||
| Returns: | ||
| Dictionary mapping agent names to list of registered commands | ||
| """ | ||
| results = {} | ||
| self._ensure_configs() | ||
| for agent_name, agent_config in self.AGENT_CONFIGS.items(): | ||
| if agent_config.get("extension") == "/SKILL.md": | ||
| continue | ||
| agent_dir = project_root / agent_config["dir"] | ||
| if agent_dir.exists(): | ||
| try: | ||
| registered = self.register_commands( | ||
| agent_name, commands, source_id, | ||
| source_dir, project_root, | ||
| ) | ||
| if registered: | ||
| results[agent_name] = registered | ||
| except ValueError: | ||
| continue | ||
| return results |
| layers = resolver.collect_all_layers(template_name) | ||
|
|
||
| if layers: | ||
| # Use the highest-priority layer for display because the final output | ||
| # may be composed and may not map to resolve_with_source()'s single path. | ||
| display_layer = layers[0] | ||
| console.print(f" [bold]{template_name}[/bold]: {display_layer['path']}") | ||
| console.print(f" [dim](top layer from: {display_layer['source']})[/dim]") | ||
|
|
||
| has_composition = ( | ||
| layers[0]["strategy"] != "replace" | ||
| and any(layer["strategy"] != "replace" for layer in layers) | ||
| ) | ||
| if has_composition: | ||
| console.print(" [dim]Final output is composed from multiple preset layers; the path above is the highest-priority contributing layer.[/dim]") | ||
| console.print("\n [bold]Composition chain:[/bold]") | ||
| # Compute the effective base: the last consecutive replace layer | ||
| # from the bottom before the first non-replace (same logic as | ||
| # PresetResolver.resolve_content). | ||
| reversed_display = list(reversed(layers)) | ||
| effective_base_idx = 0 | ||
| for idx, lyr in enumerate(reversed_display): | ||
| if lyr["strategy"] == "replace": | ||
| effective_base_idx = idx | ||
| else: | ||
| break | ||
| for i, layer in enumerate(reversed_display): | ||
| strategy_label = layer["strategy"] | ||
| if strategy_label == "replace" and i == effective_base_idx: | ||
| strategy_label = "base" | ||
| console.print(f" {i + 1}. [{strategy_label}] {layer['source']} → {layer['path']}") |
| def _register_for_non_skill_agents( | ||
| self, | ||
| registrar: Any, | ||
| commands: List[Dict[str, Any]], | ||
| source_id: str, | ||
| source_dir: Path, | ||
| ) -> None: | ||
| """Register commands for all non-skill agents. | ||
|
|
||
| Used during reconciliation to avoid overwriting properly formatted | ||
| SKILL.md files that were written by _register_skills(). | ||
| """ | ||
| registrar.register_commands_for_non_skill_agents( | ||
| commands, source_id, source_dir, self.project_root | ||
| ) |
- Keep non-skill agent reconciliation: reconciliation uses register_commands_for_non_skill_agents to avoid overwriting formatted SKILL.md content; _unregister_skills restores core/extension skills and _reconcile_skills handles lower-priority preset skills - Show composition error in CLI resolve: when has_composition is true, call resolve_content() and warn if composition cannot produce output (no base layer) instead of showing a misleading 'resolved' path
Presets can now augment lower-priority templates instead of only fully replacing them. A new optional
strategyfield inpreset.ymlcontrols how content is composed across the priority stack.replaceprependappendwrap{CORE_TEMPLATE}/$CORE_SCRIPTplaceholder substitutionMultiple composing presets chain recursively (e.g. security
prepend+ complianceappend→ header + core + footer).Python resolver (
src/specify_cli/presets.py)VALID_PRESET_STRATEGIES/VALID_SCRIPT_STRATEGIESconstants; validation in_validate()rejectsprepend/appendfor scriptsPresetResolver._collect_all_layers()— walks full priority stack, reads strategy from each preset manifestPresetResolver.resolve_content()— bottom-up composition across layersPresetManager._register_commands()— composes command content before writing to agent directoriesShell resolvers
resolve_template_content()inscripts/bash/common.shResolve-TemplateContentinscripts/powershell/common.ps1CLI
specify preset resolveshows composition chain when non-replace strategies are presentDocumentation
presets/scaffold/preset.yml— strategy field docs and composition examplespresets/README.md— composition strategies section; moved implemented items out of future considerationspresets/ARCHITECTURE.md— strategy table and content resolution function referencesTests
resolve_content()for each strategy × type, multi-preset chaining, override precedence, separator behavior,_collect_all_layers()ordering