Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ab57221
docs: integrate recovered MyOpenCommunity protocol knowledge
Oct 2, 2026
9ff7804
docs: reassess archived MyOpenCommunity sources and close coverage gaps
Oct 2, 2026
b926384
docs: record successful private archive source validation
Oct 2, 2026
490d81a
docs: extend MyOpenCommunity integration with bounded coverage audit
Oct 2, 2026
a1593db
docs: complete MyOpenCommunity deleted-source review
Oct 3, 2026
7a75fc0
docs: integrate WHO 8 intermediate history findings
Oct 3, 2026
084a65a
docs: qualify archived transport and addressing behavior
Oct 3, 2026
ec58772
docs: qualify energy and PIC history behavior
Oct 3, 2026
5aaeb55
docs: qualify HVAC and thermoregulation history behavior
Oct 4, 2026
df4387d
docs: qualify WHO 5 alarm feedback and event filtering
Oct 4, 2026
c7b79c3
docs: integrate MyOpenCommunity lighting and automation history
Oct 4, 2026
1d61c78
docs: integrate scenario and condition history findings
Oct 4, 2026
3efe8ea
docs: integrate WHO 9 auxiliary status and condition evidence
Oct 4, 2026
a603ce3
docs: qualify CEN and WHO 25 historical client behavior
Oct 4, 2026
5b19a7c
docs: integrate historical sound client behavior and evidence
Oct 4, 2026
ca8c30d
docs: document historical alarm-clock control and scheduling
Oct 4, 2026
6deef8b
Document equalizer controls and custom preset model mismatch
Oct 4, 2026
a1566fb
docs: document SCS configurator labels and product-specific modes
Oct 5, 2026
85cdc04
knowledge: trace archived implementation evidence and extract reviewe…
Oct 5, 2026
4c1f2b3
Merge main into docs/myopencommunity-integration
Oct 9, 2026
fb5f54c
docs: document archived local playback failure handling
Oct 10, 2026
f26c688
docs: document archived asynchronous media and browser lifecycle
Oct 10, 2026
af601f0
Document archived video routing and native Qt runtime behavior
Oct 10, 2026
73b1511
docs: document archived call audio and state arbitration
Oct 10, 2026
262466a
docs: trace audio consumers and historical call behavior
Oct 10, 2026
04a9efa
docs: close bounded MyOpenCommunity integration
Oct 10, 2026
ad9d0e5
fix: validate KB compatibility and exact-commit source integrity
Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/encyclopedia-compliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ on:

permissions:
contents: read
statuses: read

jobs:
mechanical-compliance:
Expand Down Expand Up @@ -78,16 +79,21 @@ jobs:
- name: Verify external artifact manifest
run: python project/review/checks/check_artifact_manifest.py

- name: Verify canonical sources
run: |
python project/review/checks/audit_source_coverage.py | tee source-audit.json
- name: Require exact-commit canonical-source and catalogue validation
env:
GH_TOKEN: ${{ github.token }}
CATALOGUE_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
run: python devices/tools/catalogue_ci_status.py verify --commit "$CATALOGUE_COMMIT" --output source-audit-status.json

- name: Test fail-closed source-status verification
run: python -m unittest discover -s devices/tools/tests -p test_ci_catalogue.py -v

- name: Preserve source audit
if: always()
uses: actions/upload-artifact@v4
with:
name: source-integrity-audit
path: source-audit.json
path: source-audit-status.json
if-no-files-found: ignore

epistemic-review:
Expand Down
29 changes: 20 additions & 9 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
from render_references import REFERENCE_FILES, reference_records # noqa: E402
from render_claims import claim_coverage_metrics, claim_records # noqa: E402
from serialization import json_bytes, jsonl_bytes, write_bytes # noqa: E402
from evidence_reviews import load_reviews, join_claim_evidence
from id_lifecycle import emitted_ids, validate_lifecycle # noqa: E402
from validate_schema import validate_registry # noqa: E402
from validate_schema import validate_record, validate_registry # noqa: E402
from validate_text_hygiene import validate_generated_text # noqa: E402
from device_units import validate_device_units # noqa: E402

GENERATOR_VERSION = "ownkb-build-0.8.2"
SCHEMA_COMPATIBILITY_VERSION = "0.1.0"
GENERATOR_VERSION = "ownkb-build-0.9.0"
SCHEMA_COMPATIBILITY_VERSION = "2.0.0"
MANIFEST_FORMAT_VERSION = "0.1.0"
CHUNK_IDENTITIES = ROOT / "knowledge/inputs/chunk-identities.json"

Expand All @@ -32,7 +33,11 @@ def sha256_bytes(content: bytes) -> str:


def artifact(path: str, kind: str, content: bytes, record_count: int | None = None) -> dict[str, object]:
result: dict[str, object] = {"format_version": SCHEMA_COMPATIBILITY_VERSION, "kind": kind,
updated_schemas = {"common.schema.json", "record.schema.json", "retrieval-chunks.schema.json",
"manifest.schema.json", "evidence-reviews.schema.json", "id-registry.schema.json"}
unchanged_format = kind == "id_registry" or (kind == "schema" and path.rsplit("/", 1)[-1] not in updated_schemas)
version = "0.1.0" if unchanged_format else SCHEMA_COMPATIBILITY_VERSION
result: dict[str, object] = {"format_version": version, "kind": kind,
"path": path, "sha256": sha256_bytes(content)}
if record_count is not None:
result["record_count"] = record_count
Expand Down Expand Up @@ -78,7 +83,7 @@ def coverage(ir: dict[str, object], chunk_metrics: dict[str, int], reference_cou

def manifest(ir: dict[str, object], output_root: Path, root: Path, chunk_metrics: dict[str, int],
reference_records_by_kind: dict[str, list[dict[str, object]]], claims: list[dict],
claim_metrics: dict, lifecycle: dict) -> dict[str, object]:
claim_metrics: dict, lifecycle: dict, reviews: dict) -> dict[str, object]:
ir_digest = dict(ir)
ir_digest.pop("identities", None)
documents = ir["documents"]
Expand All @@ -91,7 +96,7 @@ def manifest(ir: dict[str, object], output_root: Path, root: Path, chunk_metrics
"format_version": MANIFEST_FORMAT_VERSION,
"generator_version": GENERATOR_VERSION,
"input_content_sha256": sha256_bytes(json_bytes({"ir": ir_digest, "references": reference_records_by_kind,
"claims": claims, "id_lifecycle": lifecycle})),
"claims": claims, "id_lifecycle": lifecycle, "evidence_reviews": reviews})),
"schema_compatibility_version": SCHEMA_COMPATIBILITY_VERSION,
}

Expand All @@ -100,6 +105,11 @@ def build(root: Path, output_root: Path) -> Path:
ir = build_ir(root, root / "knowledge/inputs/canonical-sources.jsonl", root / "knowledge/inputs/identities.json")
references, section_references = reference_records(ir, root / "knowledge/inputs/reference-records.json")
claims = claim_records(ir, references, root / "knowledge/inputs/claim-records.json")
reviews = load_reviews(root, ir, references, {c["id"] for c in claims})
join_claim_evidence(claims, reviews, references)
for claim in claims:
if claim["id"] in reviews["claims"]:
validate_record(claim)
validate_device_units(ir, claims, root / "knowledge/inputs/device-unit-review.json")
claim_metrics = claim_coverage_metrics(ir, claims, root / "knowledge/inputs/claim-coverage.json")
namespace_ids = {}
Expand All @@ -110,7 +120,8 @@ def build(root: Path, output_root: Path) -> Path:
"ownkb:namespace:device-model" if document["namespace_context"]["area"] == "device-model" else
"ownkb:namespace:openwebnet")
identities = load_chunk_identities(root / "knowledge/inputs/chunk-identities.json")
records, metrics = chunk_records(ir, identities, section_references, namespace_ids)
records, metrics = chunk_records(ir, identities, section_references, namespace_ids, reviews["sections"],
{r["id"]: r for r in references["source"]})
expected_sections = {section["id"] for document in ir["documents"] for section in document["sections"] if section["blocks"]}
if set(identities) != expected_sections:
raise ValueError("curated retrieval chunk identity mapping is stale or incomplete")
Expand All @@ -121,13 +132,13 @@ def build(root: Path, output_root: Path) -> Path:
write_bytes(output_root / "knowledge/id-registry.json", json_bytes(lifecycle))
target_corpus = output_root / "knowledge/llm/llm-corpus.md"
target_chunks = output_root / "knowledge/retrieval/chunks.jsonl"
write_bytes(target_corpus, corpus(ir))
write_bytes(target_corpus, corpus(ir, reviews["sections"], {r["id"]: r for r in references["source"]}))
write_bytes(target_chunks, jsonl_bytes(records))
write_bytes(output_root / "knowledge/claims/claims.jsonl", jsonl_bytes(claims))
for kind, filename in REFERENCE_FILES.items():
write_bytes(output_root / "knowledge/reference" / filename, jsonl_bytes(references[kind]))
target_manifest = output_root / "knowledge/manifest.json"
manifest_value = manifest(ir, output_root, root, metrics, references, claims, claim_metrics, lifecycle)
manifest_value = manifest(ir, output_root, root, metrics, references, claims, claim_metrics, lifecycle, reviews)
write_bytes(target_manifest, json_bytes(manifest_value))
validate_generated_text(output_root, manifest_value)
return target_manifest
Expand Down
3 changes: 2 additions & 1 deletion check.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def validate_manifest(path: Path) -> dict:

def validate_chunks(path: Path) -> list[dict]:
schema = load_json(ROOT / "knowledge/schema/retrieval-chunks.schema.json")
common = load_json(ROOT / "knowledge/schema/common.schema.json")
privacy = load_json(ROOT / "knowledge/schema/privacy-metadata.schema.json")
registry = Registry().with_resources((item["$id"], Resource.from_contents(item)) for item in (schema, privacy))
registry = Registry().with_resources((item["$id"], Resource.from_contents(item)) for item in (schema, privacy, common))
validator = Draft202012Validator(schema, registry=registry)
content = path.read_bytes()
if content.startswith(b"\xef\xbb\xbf") or (content and not content.endswith(b"\n")):
Expand Down
1 change: 1 addition & 0 deletions device-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Firmware is an implementation layer between the product model and its exposed Mo
| Logical functions and Object identity | [Objects](objects.md) |
| Configurable Module templates and permitted Objects | [Virgin Objects](virgin-objects.md) |
| Configuration definitions, values, constraints, and protocol representation | [Configuration](configuration.md) |
| Physical plug labels, socket meanings, PUL and software counterparts | [SCS Configurator Labels](configurators.md) |

## Canonical model

Expand Down
26 changes: 26 additions & 0 deletions device-model/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ A complete configuration UI may combine both scopes.

The canonical catalogue represents configuration mode and physical configurator semantics separately.

For the literal meanings and functions of `PUL`, `SLA`, `O/I`, collective-address plugs, arrows and system-specific positions, see [SCS Configurator Labels](configurators.md). A plug label's established meaning is distinct from its product-specific legal positions, numerical encoding and runtime behavior.

`EN_CONFIG_MODE` contains distinct records for Virtual Configuration, Advanced Configuration, Physical configuration, and Product Programming. `AS_FIRMWARE_CONFIG_MODE` records which modes a firmware supports. A firmware can support both Virtual and Advanced configuration, so neither label should be used as an umbrella synonym for all non-physical configuration.

Mode support is a catalogue capability. It does not establish which mode configured an installed Device or which MyHOME Suite UI label was active for a particular operation.
Expand Down Expand Up @@ -283,6 +285,30 @@ For example, a preset position or load-dependent minimum level can have a value

A mapping between a UI field, catalogue definition, and protocol value requires compatible UI behavior, catalogue scope and index data, protocol `slot`/value evidence and, where available, the resulting runtime behavior. Numeric equality alone is insufficient.

## Historical touchscreen application configuration

BtExperience at `TS10_1_0_23` imports XML into its own client Objects. These application identifiers and persistence rules are separate from catalogue Object IDs, Device programming and MyHOME Suite project export.

| Input / mechanism | Client meaning |
| --- | --- |
| `conf.xml` | Local setup, including source and amplifier addresses; literal `-1` becomes an empty address |
| `archive.xml` | Function definitions in `obj` elements and instances in `ist` elements |
| String attributes | Instance values override definition defaults; absent attributes use those defaults |
| `uii` | Application instance reference; duplicate registered values are fatal in this revision |
| Amplifier-group `link` | Resolves an already-created, correctly typed amplifier; an unresolved reference asserts in assertion-enabled builds and is skipped otherwise |

The importer processes definitions in document order, so amplifier members must precede groups that reference them. It retains repeated member references; group operations can therefore call a member more than once. A configured monochannel/multichannel function selects client behavior, without proving the deployed product's capabilities. See [Virtual and composite amplifier controllers](../functional/who-22-sound-diffusion/#virtual-and-composite-amplifier-controllers) for the distinct library controller model.

Configuration documents are cached after loading. Saving marks the cached document as modified and restarts a single-shot ten-second save timer. Flushing attempts each modified write and then clears the pending set, including failed writes; this path provides no automatic retry or read-back confirmation. These are local XML persistence rules, not an acknowledgement of Device programming. See [Configuration closure evidence](../project/review/myopencommunity-closure-review.md#findings-and-canonical-placement).

## F411 simulator configuration

The VDK 2.0 F411 model stores `A`, `PL`, and group separately for each simulated output, with Device mode and bus selection outside those output records. A simulated local click emits `WHO 1` using the output's concatenated `A`/`PL` address. Point, area, group, and general addressing are handled against the configured outputs.

In its `PUL` mode, the model suppresses general/area commands and status responses while still handling point/group targets. These are executable simulator choices; the source does not establish a complete physical F411 configuration or prove equivalence between its output records and MyHOME Suite Modules. Its simplified decoder treats any command other than `WHAT 1` as OFF, which must not be adopted as a protocol rule. See [Simulator evidence](../project/review/myopencommunity-integration.md#simulator-models).

Manufacturer F411-family sheets independently establish PUL exclusion of Room and General commands. The simulator's group handling and collective status suppression do not establish physical behavior; Suite help and an older manufacturer guide differ explicitly on PUL group commands. See [PUL collective commands and status](configurators.md#collective-commands-and-status) for the source scopes. PUL on a lighting command is an established momentary function, while actuator/local-control modes must be read separately.

## Sources

Primary configuration evidence comes from [`MHCatalogue.db`](../sources/myhome-suite/3.5.38/databases/), with protocol structure from [`OPEN.db`](../sources/myhome-suite/3.5.38/databases/) and [`OpenQuery.txt`](../sources/myhome-suite/3.5.38/support/). [`rules.db3`](../sources/myhome-suite/3.5.38/databases/) adds selected Temperature Control dependencies. ScenarioDevices and the public protocol documents describe adjacent runtime layers rather than catalogue configuration identity.
Expand Down
Loading
Loading