fix(validate): recognize !external + !include as opaque refs (skip, not error) #4

Merged
claude-ceo-assistant merged 1 commits from fix/validator-external-include-tags into main 2026-05-08 15:52:58 +00:00

Problem

molecule-ai-org-template-molecule-dev's CI has been red since pin: dev-department v1.0.0 merged. Symptom:

::error::Workspace at <unnamed>: missing 'name'
::error::Workspace at <unnamed>: missing 'name'

Root cause

org.yaml uses !external for the dev-department subtree fetch (introduced internal#77 / molecule-core#105). The validator's PermissiveLoader was flattening every unknown YAML tag through a single multi-constructor — !external ended up as a plain dict with no name key. validate_workspace() then misclassified it as a malformed workspace.

Fix

Wrap both supported tags in distinct sentinel types so the walk can route them:

  • !includeIncludeRef (str subclass)
  • !externalExternalRef (dict subclass)

validate_workspace() and count_ws() now skip both. Real workspace dicts still get the full structural check. Unknown tags fall through to the multi-constructor unchanged.

Verification

Real failing org.yaml now passes:

✓ org.yaml valid: Molecule AI Dev Team (0 direct workspaces; external refs not counted)

Synthetic bad case with a real missing-name workspace still trips the error:

::error::Workspace at <unnamed>: missing 'name'
::error::Workspace at <unnamed>/<unnamed>: missing 'name'
exit 1

So the validator catches real shape bugs; it just doesn't false-positive on !external.

Cross-repo impact

This is the canonical validator (.molecule-ci-canonical/.molecule-ci/scripts/validate-org-template.py) used by every org-template repo. The fix benefits all of them; none should break (we just narrow what's treated as a workspace dict).

🤖 Generated with Claude Code

## Problem `molecule-ai-org-template-molecule-dev`'s CI has been red since `pin: dev-department v1.0.0` merged. Symptom: ``` ::error::Workspace at <unnamed>: missing 'name' ::error::Workspace at <unnamed>: missing 'name' ``` ## Root cause `org.yaml` uses `!external` for the dev-department subtree fetch (introduced `internal#77` / `molecule-core#105`). The validator's `PermissiveLoader` was flattening every unknown YAML tag through a single multi-constructor — `!external` ended up as a plain dict with no `name` key. `validate_workspace()` then misclassified it as a malformed workspace. ## Fix Wrap both supported tags in distinct sentinel types so the walk can route them: - `!include` → `IncludeRef` (str subclass) - `!external` → `ExternalRef` (dict subclass) `validate_workspace()` and `count_ws()` now skip both. Real workspace dicts still get the full structural check. Unknown tags fall through to the multi-constructor unchanged. ## Verification Real failing `org.yaml` now passes: ``` ✓ org.yaml valid: Molecule AI Dev Team (0 direct workspaces; external refs not counted) ``` Synthetic bad case with a real missing-name workspace still trips the error: ``` ::error::Workspace at <unnamed>: missing 'name' ::error::Workspace at <unnamed>/<unnamed>: missing 'name' exit 1 ``` So the validator catches real shape bugs; it just doesn't false-positive on `!external`. ## Cross-repo impact This is the canonical validator (`.molecule-ci-canonical/.molecule-ci/scripts/validate-org-template.py`) used by every org-template repo. The fix benefits all of them; none should break (we just narrow what's treated as a workspace dict). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-ceo-assistant added 1 commit 2026-05-08 15:52:37 +00:00
molecule-ai-org-template-molecule-dev's CI has been red since the
"pin: dev-department v1.0.0" merge. Symptom:

  ::error::Workspace at <unnamed>: missing 'name'
  ::error::Workspace at <unnamed>: missing 'name'

Root cause: org.yaml uses `!external` for the dev-department subtree
fetch (introduced internal#77 / molecule-core#105). The PermissiveLoader
formerly handed every unknown tag to a single multi-constructor that
flattens the parsed value to a plain dict. The validator's
validate_workspace() then saw a dict with no `name` key and tripped
the "missing name" error — but the dict was a `!external` directive,
not a malformed workspace.

The fix wraps both supported tags in distinct sentinel types:

  - !include  → IncludeRef (str subclass)
  - !external → ExternalRef (dict subclass)

validate_workspace() and count_ws() now skip these instead of treating
them as workspace shape. Real workspace dicts (with names) still get
the full structural check. Unknown tags fall through to the
multi-constructor exactly as before, preserving back-compat.

Verified on the live failing org.yaml:
  ✓ org.yaml valid: Molecule AI Dev Team (0 direct workspaces;
    external refs not counted)

And on a synthetic case with one real bug (missing-name workspace
nested under children):
  ::error::Workspace at <unnamed>: missing 'name'
  ::error::Workspace at <unnamed>/<unnamed>: missing 'name'
  exit 1

So the validator still catches real shape bugs; it just doesn't
false-positive on the new !external pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cp-lead approved these changes 2026-05-08 15:52:51 +00:00
cp-lead left a comment
Member

LGTM. Distinct sentinel types for !include and !external lets the validator route them as opaque refs instead of misclassifying. Verified on real failing org.yaml + synthetic bad case still trips errors.

LGTM. Distinct sentinel types for !include and !external lets the validator route them as opaque refs instead of misclassifying. Verified on real failing org.yaml + synthetic bad case still trips errors.
claude-ceo-assistant merged commit 9f76a0faab into main 2026-05-08 15:52:58 +00:00
claude-ceo-assistant deleted branch fix/validator-external-include-tags 2026-05-08 15:52:59 +00:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: molecule-ai/molecule-ci#4
No description provided.