keyspace-debug
Skill2 starsChanged 6 months agoMITView on GitHub
Guides debugging of pydita key space construction and key resolution failures. Use this skill when keys are not resolving, keyscoped references return None, duplicate key warnings appear, or you need to inspect the key space tree structure built by KeyspaceManager from a resolved DITA map.
In this repository18 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- context-setupSkill
- dita-best-practicesSkill
- ditaval-helperSkill
- error-handlingSkill
- generate-bookmapSkill
- generate-ditamapSkill
- generate-dita-topicSkill
- generate-keyrefsSkill
- map-resolveSkill
- pdf-to-ditaSkill
- refactor-dita-contentSkill
- review-dita-guideSkill
- validate-bookmapSkill
- validate-ditamapSkill
- validate-dita-topicSkill
- visitor-extendSkill
- xslt-dita-helperSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 97
Check the key name is spelled correctly (case-sensitive).
- Very specific: line 98
Verify the <keydef> element exists in the resolved map:
- Very specific: line 104
Check the <keydef> was not excluded by the DITAVAL filter (it won't appear in the resolved map if filtered out).
- Very specific: line 105
If the key is in a submap with @keyscope, you must look it up in the child key space, not the root.
- Very specific: line 128
If a <keydef> uses @keyref that eventually points back to itself, pydita will detect it and record an error.
- Distinctive: line 139
If you suspect a bug in construction, enable debug:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Overview
pydita implements the DITA 1.3 key space algorithm in pydita.keyspace and pydita.keyspacemgr. A key space is a tree of KeySpace nodes, each containing KeyDefinition children — one per key name. The root key space is built from the resolved map; child key spaces are created for every @keyscope boundary.
Key classes
| Class | Module | Role |
KeyspaceManager | keyspacemgr | Top-level manager; builds and indexes all key spaces |
KeySpace | keyspace | One key space (one @keyscope scope); contains KeyDefinition children |
KeyDefinition | keyspace | One key name → one or more key-defining elements (priority order) |
Inspecting the key space tree
Print the full tree
from anytree import RenderTree
from pydita.keyspacemgr import KeyspaceManager
ksm = KeyspaceManager(resolvedMap=resolved_map, errors=errors)
root_ks = ksm.getRootKeyspace()
for pre, _, node in RenderTree(root_ks):
print(f"{pre}{node.label}")Output example:
KeySpace: #annonymous
├── KeyDef: product-name
├── KeyDef: version
└── KeySpace: enterprise-scope
├── KeyDef: product-name ← overrides parent
└── KeyDef: ent-featureUse the built-in text reporter
from pydita.keyspacevisitors import KeyspaceReportingVisitor
reporter = KeyspaceReportingVisitor()
print(reporter.reportKeySpace(ksm.getRootKeyspace()))Looking up keys
Context-free lookup (root key space)
root_ks = ksm.getRootKeyspace()
key_def = root_ks.resolveKey("product-name")
if key_def is None:
print("Key not defined in root scope")
else:
# getKeyDefiners() returns key-defining elements in priority order
first_elem = key_def.getKeyDefiners()[0]
href = first_elem.get("href")
print(f"Key 'product-name' -> href={href}")Keyscoped lookup
# Get child key spaces by scope name (returns a list — scope names need not be unique)
scoped_spaces = ksm.getRootKeyspace().getKeyspacesByScopeName("enterprise-scope")
if scoped_spaces:
key_def = scoped_spaces[0].resolveKey("product-name")Lookup by map URI
ks = ksm.getKeyspaceByMapUri("/abs/path/to/submap.ditamap")Common problems and how to diagnose them
Key resolves to None
- Check the key name is spelled correctly (case-sensitive).
- Verify the
<keydef>element exists in the resolved map:keydefs = resolved_map.xpath("//*[@keys]") for kd in keydefs: print(kd.get("keys"), kd.get("href")) - Check the
<keydef>was not excluded by the DITAVAL filter (it won't appear in the resolved map if filtered out). - If the key is in a submap with
@keyscope, you must look it up in the child key space, not the root.
Key space not built for a submap
Submaps become child key spaces only when they carry a @keyscope attribute. A submap without @keyscope contributes its key definitions directly to the parent scope.
# Check which key spaces exist
for ks_uri, ks in ksm.keyspacesByMapUri.items():
print(ks_uri, "->", ks.label)Duplicate key warning
The first definition wins (DITA 1.3 §2.4.4.2). Subsequent definitions are stored in key_def.keydefElems at lower priority indexes. Use the reporter to see all definitions:
reporter = KeyspaceReportingVisitor()
print(reporter.reportKeySpace(ksm.getRootKeyspace()))Recursive key definition
If a <keydef> uses @keyref that eventually points back to itself, pydita will detect it and record an error. Check errors for entries containing "recursive".
Key space construction algorithm
The construction runs in two phases after resolveMap():
- Pull-up (
PullUpVisitor): walks the resolved map and createsKeyDefinitionnodes. Keys defined in a keyscoped submap are placed in a childKeySpace. - Push-down (
PushDownVisitor): propagates parent-scope key definitions down to child scopes so child scopes can fall back to parent definitions.
If you suspect a bug in construction, enable debug:
ksm = KeyspaceManager(resolvedMap=resolved_map, errors=errors, debug=True)See also
context-setup— full pipeline setup including KeyspaceManager initialisationmap-resolve— ensure the resolved map is correct before building key spaces
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

