Skip to content

Write down the mechanics that are easy to get wrong - #102

Merged
QuiteYellow merged 5 commits into
mainfrom
docs/agents-file
Sep 20, 2026
Merged

QuiteYellow merged 5 commits into
mainfrom
docs/agents-file

Conversation

@QuiteYellow

@QuiteYellow QuiteYellow commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Four things lived only in my head, and each one has cost time to rediscover:

  • docs/api.md is generated. tests/test_public_api_contract.py fails when it is stale, so the symptom is a test failure with no obvious connection to the docstring that caused it.
  • The public surface is an allowlist in tools/api_contract.py, so a new exported name needs a deliberate edit there. I hit this adding PeerInitiatedHandshakeError.
  • tools/check_share_safety.py gates identifiers in CI as the "Share safety" job, and a value that is already public belongs in its SAFE_UUIDS set with the reason.
  • A local virtualenv matches neither the Python matrix nor the dependency floor. CI runs 3.11 through 3.14 plus a floor job installing minimum pinned versions with --no-deps, and the file gives the uv run incantation for pinning an interpreter when output depends on one.

The judgement calls stay where they already are. docs/use-of-ai.md carries the rules about evidence and appliance safety, docs/firmware-families.md carries how to tell which stack a claim may cite, and this file links both, since a duplicated rule is a second place to update.

The three reference stacks get a table with their public upstream and the pin used here, so a reader can fetch their own copy. None is checked into this repository, and none is a substitute for hardware.

AGENTS.md over CLAUDE.md for the filename: it is the cross-tool convention, and .gitignore excludes .claude/ anyway.

One section deliberately duplicates: appliance safety. An assistant reading only the root file should not have to follow a link before it learns it can brick hardware.


Two commits added after the first review pass.

Driving the library by hand. Reads and writes against a real appliance, outside the bridge, have preconditions that are invisible until one is missed: the bridge holds the appliance's one DTLS session, Docker bridge NAT drops the replies these devices send from an ephemeral port, and a session with no reader thread times out every exchange after a clean handshake. Each of those reads as a dead device rather than a harness fault, and each has cost a session to rediscover.

The reference table pointed at the wrong tree. It named upstream iotivity 1.2.1 as the pin used here, two lines under the rule that a mechanism claim has to cite the stack an appliance actually runs. These appliances run Samsung's fork of it, vendored in TizenRT, and ca_adapter_net_ssl.c differs between the two by 1295 lines — enough that an upstream line number lands somewhere unrelated in the fork. As written the table sent a reader to the tree that produced the published 5684 error. The fork is now the first row with its pin and a sparse-checkout command, upstream is kept and labelled contrast only, and mbedTLS is added: the build links TizenRT's own 2.7.8, not the 2.4.0 the iotivity extlib's prep.sh pins, and the DTLS behaviour these appliances show is only legible across both trees.

#103 and #104 depend on this one: both cite the pin this table now carries.

Four things lived only in one maintainer's head: docs/api.md is
generated and a test fails when it is stale, the public surface is an
allowlist in tools/api_contract.py, check_share_safety.py gates
identifiers in CI, and a local virtualenv matches neither the Python
matrix nor the dependency floor.

Judgement calls stay in docs/use-of-ai.md and docs/firmware-families.md,
which this links rather than restates. The three reference stacks are
named by their public upstream and pin so a reader can fetch their own;
none is checked in here, and none substitutes for hardware.
Reads and writes against a real appliance, outside the bridge, have a
handful of preconditions that are invisible until one is missed: the
bridge holds the appliance's one DTLS session, Docker bridge NAT drops
replies from the ephemeral port these devices answer on, and a session
with no reader thread times out every exchange after a clean handshake.

Each of those has cost a debugging session, and each reads as a dead
device rather than a harness fault. Writing them down beside the session
lifecycle turns a stall into something checkable.
The table named upstream iotivity 1.2.1 as the pin used here, two lines
under a rule that a mechanism claim has to cite the stack the appliance
actually runs. These appliances run Samsung's fork of it, vendored in
TizenRT, and ca_adapter_net_ssl.c differs between the two by 1295 lines
— enough that an upstream line number lands somewhere unrelated in the
fork. As written the table sent a reader to the tree that produced the
published 5684 error.

The fork is now the first row with its pin and sparse-checkout command,
upstream is kept and labelled contrast only, and mbedTLS is added: the
build links TizenRT's own 2.7.8 rather than the 2.4.0 the iotivity
extlib's prep.sh pins, and the DTLS behaviour these appliances show is
only legible across both trees.
QuiteYellow added a commit that referenced this pull request Sep 19, 2026
The peerId citation pointed at the pin table in AGENTS.md, which arrives
with #102 and is not on main yet. test_links_between_markdown_files_
resolve maps a blob/main URL back to a local path, so the link failed
the suite on this branch and would have coupled two independent changes
in the merge order.

The line names the fork and gives both trees' line numbers itself,
which is what a reader needs at that point anyway.
The lifecycle bullet pointed at local-tools/probe_paths.py, which is
gitignored, so it named a file no contributor can open. The bullet
already states the lifecycle it was illustrating.

The safety section said an appliance wedges "once its session table
fills". That is the RFC 6347 section 4.2.8 eviction mechanism, and the
audit of the stack these appliances run found no peer cap, no idle
timeout and no LRU anywhere in it. The silence is measured; that cause
is not. It now says what was seen, which is minutes of silence after
repeated handshakes in quick succession.

The line count between fork and upstream does not reproduce at the pin
the table gives. At e590f30ab against 1.2.1 it is 1371 changed lines,
or 1205 ignoring whitespace; the 1295 in the text matches neither, and
most likely came from the master checkout the tree held before it was
re-pinned. The point survives without a figure.
The reference table led its first row with "IoTivity classic, Samsung's
fork". Read quickly, that is a family name, and the family name sends a
reader to upstream.

Upstream is the wrong tree for these appliances. It sets VERIFY_REQUIRED
and carries no ECDHE-ECDSA-AES128-GCM-SHA256, yet the appliances
complete a session on an empty client certificate using exactly that
suite. So the row is now TizenRT's iotivity_1.2-rel fork, its path runs
down to that directory, and the sentence below states what a reader
loses by following the family label: a tree that answers this question
differently.
@QuiteYellow
QuiteYellow merged commit 8348a80 into main Sep 20, 2026
8 checks passed
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