Skip to content

D229 — A map contract can change after creation

Decision. map_update changes the lint contract of an existing map — require_index_entry, required_fields, required_fields_by_type, machine_path_allow_prefixes — and nothing else in its descriptor. A dead link in a map's index.md is a broken_link finding whether or not the map opted in to require_index_entry; completeness (index_incomplete) stays opt-in.

Why. The contract could be set only by map_create, and _map.md is reserved from artifact_write and concept_write. A map created before its contract existed could therefore never opt in, so concept_move never maintained its index and lint never looked at it: after 21 concepts moved out of three such maps, every index still linked the old IDs and lint reported nothing (#320). A broken link is broken regardless of a promise of completeness; tying its detection to the contract hid exactly the maps that had drifted the longest.

Alternatives rejected. Letting artifact_write or concept_write edit _map.md: it would open the descriptor's structural keys (kind, ontology_mode, concept_types) to a free-form write the server cannot validate as a contract. Rewriting every [[id]] in every map index on concept_move, contract or not: index maintenance was made opt-in by D160 on purpose, since a curated document is the operator's prose; reporting the dead link is enough to make the drift visible. Classifying map_update as an advanced tool: the agent that tidies a map's index is the caller that needs it, and map_create/map_delete are agent-visible for the same reason.

Consequences. Absent keys are left as they are and an empty value removes the key, so a descriptor updated to a contract reads exactly as if map_create had written it. A legacy _archive.md is refused, not rewritten (D77 keeps that form read-only). A map index missing altogether is still not a finding for a map without the contract.