Skip to content

fix(sdl): rename nested node-service and content-item references with their parent declaration #1573

Open

Description

@doublewhy

Gap Claim

rename_sdl_declaration refuses to rename a node when a nodes.<node>.services.<service> reference names it, and refuses to rename a content declaration when a content.<content>.items.<item> reference names it. Both renames return succeeded=False with artifact-transformation.target-invalid.

Cause: _rename_symbols in implementations/python/packages/raes/_transformation_rename.py starts from _identity_symbols, a symbol index built with an empty namespace. In implementations/python/packages/raes/_module_symbols.py, _nested_node_service_aliases and _nested_content_item_aliases skip every node or content entry whose rename-map target equals its own name, so the identity index holds no nested aliases. _rename_symbols then rewrites only existing alias targets that start with nodes.<old>., finds none, and leaves the nested reference unchanged. The candidate no longer validates, and the rename is refused.

Reproduction on dev a391904a. This scenario parses and validates:

name: rename-nested
nodes:
  lan: {type: switch}
  web:
    type: compute
    resources: {ram: 1 GiB, cpu: 1}
    services: [{port: 80, name: http}]
content:
  bundle: {type: dataset, target: web, items: [{name: report}]}
entities:
  red-team: {role: red}
agents:
  red-agent:
    affiliations: [red-team]
    actions: [probe]
action_contracts:
  probe:
    semantic_version: 1.0.0
    behavioral_granularity: atomic
    procedure_basis: probe the web service
    realization_profile: backend-declared
    fidelity_claim: records probe intent
    preconditions:
      - {precondition_id: in-scope, precondition_class: authority, description: the web service is in scope}
    effects:
      - {effect_id: observed, effect_class: observation_effect, description: probe observation, evidence_refs: [evidence.probe-output]}
    failure_classes: [unknown]
behavior_specifications:
  probe-behavior:
    semantic_version: 1.0.0
    lifecycle_state: active
    participant_refs: [red-agent]
    action_contract_refs: [probe]
    authority_scope_refs: [nodes.web.services.http, content.bundle.items.report]
Request Result
nodes.web -> frontend False ['artifact-transformation.target-invalid']
content.bundle -> kit False ['artifact-transformation.target-invalid']
agents.red-agent -> prober True []

With authority_scope_refs: [nodes.web, content.bundle] instead, both renames succeed, so the nested spelling alone causes the refusal. Module composition is not affected: an import namespace makes the rename map differ from the identity, so the nested aliases exist there.

This is not #1550, where an infrastructure key that is not a reference blocks a node rename.

Existing Surface Audit

  • rename_sdl_declaration and module composition share _rewrite_payload_with_symbols (raes/composition/_expand.py), so the rewrite of nested refs already works for imports.
  • nested_node_runtime_family_aliases (raes/_runtime_service_families.py, reached through nested_node_runtime_aliases) has the same skip (if prefixed_node == node_name: continue) for qualified runtime child refs. The fix covers it, or shows with a test that those refs are unaffected.
  • implementations/python/tests/test_artifact_transformations.py covers renames of plain and section-qualified references, not nested service or content-item refs.
  • Found while verifying Verify participant tool authoring across composition and compilation (DSL-117) #298 (PR fix(sdl): keep imported tool affordances bound to their own tool content #1440), which covers the tool and access-account rename paths.

Alternatives

  1. Build the nested aliases for the identity index too (old ref maps to itself), so _rename_symbols finds and rewrites them: selected.
  2. Special-case nested prefixes in _rename_symbols by string rewriting every reference that starts with nodes.<old>. or content.<old>.: rejected. It would rewrite strings that are not references and bypass the symbol index that composition uses.
  3. Document the limit: rejected. The rename contract says resolved references are updated, and these references resolve.

Chosen Architecture

Make the identity symbol index carry nodes.<node>.services.<service> and content.<content>.items.<item> aliases, plus qualified runtime child aliases if they show the same gap, each mapping to itself, so _rename_symbols rewrites them through its existing startswith(old_address + ".") branch. Composition output must not change.

The change is package code under implementations/python/packages, which the research-evidence digest covers, so both research captures are republished in the same pull request.

Verification Plan

  • Regression tests: the scenario above renames nodes.web to frontend and content.bundle to kit, and the output's authority_scope_refs read nodes.frontend.services.http and content.kit.items.report.
  • Composition tests for nested refs (test_sdl_module_registry.py, test_issue_298_tool_authoring.py) stay green.
  • Both evidence checkers, verify-fast-feedback, lint and make policy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions