Skip to content

Align stubs with documented and kernel behavior - #78

Merged
paresy merged 1 commit into
masterfrom
fix/doc-and-kernel-alignment
Oct 17, 2026
Merged

paresy merged 1 commit into
masterfrom
fix/doc-and-kernel-alignment

Conversation

@paresy

@paresy paresy commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Compared the stubs against the official docs (https://www.symcon.de/de/llms.txt) and the kernel source, then fixed bugs in the existing stubs and added the input checks the real kernel performs. Error messages are copied from the kernel, so tests fail with the same text a module would see in production.

Bug fixes

  • New objects were never added to root's ChildrenIDs (typo ChildrendIDs), so IPS_GetChildrenIDs(0) was always empty and ident uniqueness below root was not checked.
  • IPS_GetObjectIDByName / IPS_Get*IDByName threw a TypeError on success. They now return the ID, or emit a warning and return false if nothing is found.
  • IPS_RunScriptWait / IPS_RunScriptTextWait called methods that don't exist.
  • IPS_GetScriptFile returned nothing.
  • The ident regex was not anchored, so any ident was accepted.
  • The instance status during creation was 100 (IS_SBASE) instead of IS_CREATING (101). Like the kernel, the instance now becomes IS_ACTIVE after the first ApplyChanges has finished.
  • GetTimerInterval now returns the configured interval, as in the kernel (IPSModule.cpp). Before, it returned the remaining time, which went negative for interval 0.
  • IPSModuleStrict::ReceiveData threw a TypeError when the module did not override it.
  • IPS_GetVariablePresentation now falls back to the system presentation.
  • Float associations are sorted correctly. IPS_GetVariableProfileListByType returns names.
  • Fixed the argument count of IPS_UpdateFormField. Added UnregisterOAuth (strict).
  • The validator accepts module type 6 (visualization).

Input checks matching the kernel

  • Objects: the parent must exist; reject cycles, assigning self as parent, ident collisions and icons with spaces. Deleting an object that has children fails before any state is changed. Object type ranges are checked on create.
  • Variables:
    • typed SetValue*/GetValue* check the variable type
    • SetValue converts values like the kernel does ('5' → 5, 1.7 → 2, true → 'True')
    • reject NaN/INF, strings over 1024 kB and invalid UTF-8
    • custom profiles must exist and match the variable type
    • custom action scripts must exist
    • presentations need a known PRESENTATION GUID
  • Read-only: variables of IPSModuleStrict modules are read-only. Only $this->SetValue can change them.
  • Profiles: name rules, no duplicates, ~ system profiles are read-only, min/max/step/digit ranges, boolean associations cannot be deleted, deleting a missing association fails.
  • Connections: IPS_ConnectInstance checks the module-type rules, dataflow compatibility (implemented vs. requirements), an existing parent, connecting to itself and loops. IPS_DisconnectInstance requires a parent.
  • Data flow: packets must be a JSON object with a string DataID, and the parent must implement that DataID. Children that don't implement the DataID are skipped.
  • IPSModule:
    • IPS_SetProperty/IPS_SetConfiguration convert values to the property type and reject unknown properties and non-scalar values
    • default values are converted to the property type
    • properties, attributes and timers can only be registered in Create, and only once
    • negative timer intervals are rejected
    • SetStatus accepts only 102/104/106/≥200
    • LogMessage rejects KL_SUCCESS and KL_CUSTOM
    • an empty value removes a buffer; buffer size limits are applied
  • Where the stubs were stricter than the kernel:
    • EnableAction/DisableAction on an unknown ident return false instead of throwing a TypeError
    • RegisterVariable on an ident used by another object type bails out instead of throwing
    • strict RegisterVariable*, MaintainVariable and UnregisterVariable report whether the variable was actually created or removed

⚠️ Can break downstream module tests

These changes are intended, but modules that relied on the looser behavior will now fail:

  • Timers: tests that relied on GetTimerInterval returning the remaining time.
  • Late registration: modules that register properties, attributes or timers outside Create.
  • Configurations: test configurations that contain unknown properties or array values.
  • Module setup: module.json files whose dataflow GUIDs don't match. IPS_ConnectInstance and the data flow now check them, and ConnectParent and RequireParent use IPS_ConnectInstance.
  • Strict variables: tests of IPSModuleStrict modules that call the global SetValue on the module's variables.

Tests

  • Added 71 tests in tests/KernelSanitizationTest.php and tests/ModuleSanitizationTest.php, with fixture modules in tests/SanitizationStubs. 66 of them fail on the old stubs.
  • The full suite passes (91 tests), including the IPS 7.4 emulation. php-cs-fixer with .style and the JSON check are clean.

🤖 Generated with Claude Code

Fix outright bugs:
- Register new objects in root's ChildrenIDs (typo ChildrendIDs)
- IPS_GetObjectIDByName returned an int from an array function
- IPS_RunScriptWait/IPS_RunScriptTextWait called missing methods
- IPS_GetScriptFile did not return anything
- Anchor the ident regex so invalid idents are rejected
- Use IS_CREATING (101) during creation and switch to IS_ACTIVE after the first ApplyChanges, like the kernel
- GetTimerInterval returns the configured interval
- IPSModuleStrict::ReceiveData returns '' when not overridden
- IPS_GetVariablePresentation falls back to the system presentation
- Sort float associations correctly, return profile names by type
- Fix IPS_UpdateFormField argument count, add UnregisterOAuth
- Allow module type 6 (visualization) in the validator

Reject the same invalid input as the kernel:
- Objects: parent existence, cycles, ident collisions, icon spaces, deleting objects with children, object type ranges
- Variables: type checks on read/write, kernel value conversion for SetValue, NaN/INF, 1024kB and UTF-8 limits, read-only variables of IPSModuleStrict, profile/action/presentation checks
- Profiles: name rules, duplicates, read-only system profiles, value/digit ranges, boolean association deletion
- Instances: connection rules for module types and dataflow, data flow packet and DataID checks
- Modules: property conversion and unknown properties in configurations, registration only in Create, duplicate registrations, timer intervals, status codes, log message types, buffer limits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@paresy
paresy merged commit 03c39ee into master Oct 17, 2026
4 checks passed
@paresy
paresy deleted the fix/doc-and-kernel-alignment branch October 17, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant