Skip to content

feat: title Property entities by name and refuse a rename on update - #226

Merged
LukasGold merged 3 commits into
stagefrom
feat/property-entity-title
Nov 13, 2026
Merged

LukasGold merged 3 commits into
stagefrom
feat/property-entity-title

Conversation

@LukasGold

@LukasGold LukasGold commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Create SMW properties through the generic entity path: an entity of a Category:Property subclass is stored at Property:<name> instead of Property:OSW<uuid>.

Changes

  • pyproject.toml, uv.lock: reference opensemantic v0.2.5
  • src/osw/core.py:
    • New OSW._check_property_title_unchanged, called in store_entity before the page is loaded or edited, for the Property namespace and not offline. It queries [[HasUuid::<uuid>]]. If a Property: page with this uuid exists under a different title, the write is refused with a ValueError. The message names the uuid and both titles. It suggests moving the old page to the new title if a replacement is intended, or keeping the original name. Titles are compared after MediaWiki normalization (underscore equals space, first letter upper case).
    • delete_entity uses get_title instead of its own copy of the title rule.
  • src/osw/service/errors.py, src/osw/service/ops/entities.py: create_or_update_entity converts StoreEntityPartialError into the new StoreFailed error. Its message lists each failed title with its reason, so CLI and MCP callers see the refusal text. The MCP error type stays StoreEntityPartialError and the CLI exit code stays 1. This applies to every failed store, not only the refusal. Docstring updated.
  • Tests: tests/test_property_title.py (new) and one CLI test in tests/test_cli.py.

Behavior to note

  • An update that changes name of a property is refused, because it would create a second page with the same uuid.
  • Existing pages titled Property:OSW<uuid> whose name differs from that title are also refused on update. On wiki-dev a title search finds 40 pages titled Property:OSW...; the two checked (HasDirectoryTree, HasComponentRole) have a name and no meta. The owner moves the page to Property:<name> once. Moving a page through the CLI or MCP is tracked in Move a wiki page through the CLI and MCP, with a skill for renaming entities #227.
  • delete_entity targets Property:<name> for a Property without meta.wiki_page.title. It no longer reaches an old Property:OSW<uuid> page. osw entity delete <title> still deletes by title.
  • The SMW index can lag, so a page written seconds before may not be found and the refusal can be missed.

Live test on wiki-dev.open-semantic-lab.org

  • Create of an AnnotationProperty through osw entity put wrote Property:HasOswPyTitleTest1 with the jsondata, header and footer slots. Has_type was set from property_type.
  • An update by uuid with the same name updated that page.
  • An update with a changed name exited with code 1 and the full error text. No second page was created.
  • Classes of the OSW-id subcategories Category:OSW1b15ddcf042c4599bd9d431cbfdf3430 and Category:OSW2607ff65b0574f60996d41434d0e4fa4 give Property:<name> (no write).
  • OSW.delete_entity deleted the test page. SMW locked the page with smw-change-propagation-protection for about 27 minutes after the update, so the deletion succeeded only after retries.
  • Not verified: whether the redirect left by a page move keeps HasUuid. If it does, the check refuses the update after the suggested move.

Required before the merge

PyPI rejects a release whose metadata contains a direct URL dependency, so this PR stays a draft until these are done.

- reference opensemantic PR #5 (664da4a), get_title uses name for Property
- store_entity refuses a write when the uuid is on another Property: page
- delete_entity uses get_title
- create_or_update_entity reports the reason of a failed store
@LukasGold LukasGold self-assigned this Nov 13, 2026
@LukasGold LukasGold added bug Something isn't working enhancement New feature or request labels Nov 13, 2026
@LukasGold
LukasGold marked this pull request as ready for review November 13, 2026 13:17
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Release preview

Merging this PR would release v2.10.0 (current: v2.9.1).

Changelog preview (truncated)
## v2.10.0 (2026-11-13)

### Bug Fixes

- A wiki file finds its session without a URL
  ([`f3f1080`](https://github.com/OpenSemanticLab/osw-python/commit/f3f1080106c0c4f8c18386bceb9d9eafac098182))

- Botfilter for user sync
  ([`4d6f440`](https://github.com/OpenSemanticLab/osw-python/commit/4d6f4401c63a148c924bef89963b8f18bc8d4b0c))

- Follow properties and items when collecting category templates
  ([#220](https://github.com/OpenSemanticLab/osw-python/pull/220),
  [`55e500e`](https://github.com/OpenSemanticLab/osw-python/commit/55e500efb896f0a3d6bde98409b3a6f43a652bdc))

- Keep the stored jsonschema when store_entity regenerates it
  ([`9b76a8f`](https://github.com/OpenSemanticLab/osw-python/commit/9b76a8fbeb813b34c4881b54d329e9e837b08f95))

- One session per host and credential, named by host alone
  ([`f199283`](https://github.com/OpenSemanticLab/osw-python/commit/f1992832fa20969fc5a63d0a215ba59a9e796245))

- Path is a field again, in step with local_path
  ([`4ecbc7c`](https://github.com/OpenSemanticLab/osw-python/commit/4ecbc7caddb1558ac765ba38f654f37d55e1e58c))

- Select category templates from the schema allOf like the wiki
  ([#220](https://github.com/OpenSemanticLab/osw-python/pull/220),
  [`9f606f4`](https://github.com/OpenSemanticLab/osw-python/commit/9f606f48fefd640cca48e6718f1a92eca118da6b))

- **core**: Address follow-up issues in the overwrite policy
  ([`10808a0`](https://github.com/OpenSemanticLab/osw-python/commit/10808a05d1c27c5cf4053e79169d39ceeac16f99))

- **core**: Do not warn when a registered subclass was set aside
  ([`c116199`](https://github.com/OpenSemanticLab/osw-python/commit/c1161990e1ef6ebed6372c814ba2133c80258f5c))

- **core**: Drop skipped pages from StoreEntityPartialError.stored
  ([`cf78de9`](https://github.com/OpenSemanticLab/osw-python/commit/cf78de9f253700a92b8b44761dd4baa75050695e))

- **core**: Guard the registry conflict check against a non-class
  ([`0017ef0`](https://github.com/OpenSemanticLab/osw-python/commit/0017ef094e009dd3fe04096f11eea880bd2a4142))

- **core**: Ignore registered subclasses of the canonical model class
  ([`4ee1e09`](https://github.com/OpenSemanticLab/osw-python/commit/4ee1e09ee54f39258fb4f03d4b74f11de4a4c451))

- **core**: Prefer a registered class over a generated one
  ([`90fa310`](https://github.com/OpenSemanticLab/osw-python/commit/90fa310a8e8f71b8ce58d95c0a575e4e6607a1dd))

- **core**: Restore the page cache state once per fetch_schema call
  ([`f09dcf6`](https://github.com/OpenSemanticLab/osw-python/commit/f09dcf6b9d0e0bf3baf04107d9e1acf56e755c8d))

- **core**: Skip a page whose category has no usable schema
  ([`3c9278d`](https://github.com/OpenSemanticLab/osw-python/commit/3c9278d24baadce753f868ff39cbddccf9418494))

- **core**: Skip non-class attributes when choosing a category class
  ([`0ea247c`](https://github.com/OpenSemanticLab/osw-python/commit/0ea247c3452b207942fe08a23b596ec6e2d52f96))

- **core**: Use the current class after fetch_schema reloads the module
  ([`e39a857`](https://github.com/OpenSemanticLab/osw-python/commit/e39a857a20604718ee5dd7d1ed300b509baa7f8c))

- **package**: Write packages.json pages in a deterministic order
  ([`467d11c`](https://github.com/OpenSemanticLab/osw-python/commit/467d11cc26a0a94f3a31936124740f33c31692c0))

- **user-sync**: Actually remove pruned fields via empty relations and remove_empty
  ([`87cf85b`](https://github.com/OpenSemanticLab/osw-python/commit/87cf85b31cbfec6b80e2e30b92852c359586133c))

- **user-sync**: Align with stage and the tools docs
  ([`bc6b0d6`](https://github.com/OpenSemanticLab/osw-python/commit/bc6b0d642f5697ca8048b4be05fd26c9ad2162f6))

- **user-sync**: Count and redirect only stored items
  ([#224](https://github.com/OpenSemanticLab/osw-python/pull/224),
  [`0b8dc97`](https://github.com/OpenSemanticLab/osw-python/commit/0b8dc974e972e8adaa7a2bb03bd3ae4396589f40))

- **user-sync**: Drop python-dotenv, use default accounts.pwd.yaml
  ([`02570c8`](https://github.com/OpenSemanticLab/osw-python/commit/02570c8f88d6d27c58e1e595bc8bb13e90354fd4))

- **user-sync**: Prune a single-valued key stored with an empty value
  ([`ebda514`](https://github.com/OpenSemanticLab/osw-python/commit/ebda514c731718ab20a084b93288491b3b944627))

- **user-sync**: Prune by field type and decide from stored jsondata
  ([`9b36e4e`](https://github.com/OpenSemanticLab/osw-python/commit/9b36e4ef8417b8847ba304535a95c0eedaf628b9))

### Build System

Preview via python-semantic-release and conventional commits.

@LukasGold
LukasGold changed the base branch from main to stage November 13, 2026 13:21
@LukasGold
LukasGold merged commit 723a11b into stage Nov 13, 2026
12 checks passed
@LukasGold
LukasGold deleted the feat/property-entity-title branch November 13, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant