Skip to content

lampOS: the ring tells a skill whose light it holds but does not show what is over it, on light/outranked (#940, off unless LAMP_LIGHT_REQUESTS=on) - #1466

Merged
deehw merged 1 commit into
lamp-voicefrom
third/light-outranked
Oct 18, 2026
Merged

deehw merged 1 commit into
lamp-voicefrom
third/light-outranked

Conversation

@deehw

@deehw deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

#940, the light half of "the loser is told" (design approved by the first builder at 10:4x on #940). It's off unless LAMP_LIGHT_REQUESTS=on, the switch the ring and lamp-skills already use.

The gap: when two skills ask for the light at once, the ring shows one of them (#993), but only the winner hears about it (light/reached). The loser never knew.

What's new:

  • light/outranked (lamp_msgs/LightOutranked {source, by}, event). The ring sends it for a request it holds but doesn't show. by is the claim.source shown over it, or person for the person's own light. It's sent:
    • when the request is taken hidden;
    • when a shown request loses its place;
    • when what is over it changes;
    • again after each renewal while it stays hidden, the same rhythm as light/reached.
  • The loser keeps its claim. It comes back by itself when the winner's lease ends. A turn's face, a self-test and the privacy switch hide every request alike and aren't a loss, so nothing is sent for them.
  • The ring (ring_requests.rs, ring_light.rs): Requests::outranked tells each hidden holder once per thing over it. A renewal resets that, so it's told again. The shown one and a lapsed one are told nothing. The ring publishes the result on each tick.
  • Skills (glow.rs):
    • A run subscribes to light/outranked before its first ask.
    • At each renewal it writes lamp-skills: skill:<name>'s light is outranked by <by> to the journal.
    • Its give-back line in done ends ; outranked by <by>, ..., each one once, in the order heard.
    • It doesn't retry or fight; it just keeps renewing, as before.
  • Docs: bus.md (the topic row), ring-choreography.md, skills.md.

Tests:

  • ring_requests::a_request_held_but_not_shown_is_told_what_is_over_it: two skills at skill. The older is told once when the newer takes its place, and again after its renewal. Covered:
    • a lower request is told when it is taken;
    • the conversation over all three;
    • the newer skill over the others again once the conversation lapses;
    • the person's light over every one;
    • nothing for a request given back or lapsed.
  • ring_light::a_skill_whose_light_is_not_shown_is_told_what_is_over_it: the same through the bus. The loser is told once and its light comes back when the winner's lease ends. Both are told person under the person's light.
  • glow::a_light_outranked_is_said_at_the_give_back_by_what: the run's give-back names each by once and ignores another skill's.

Gate (Mac):

  • On lamp-voice d68734005: fmt --check ok. clippy -D warnings --all-targets clean for msgs, Voice, skills and voice-eval. Tests: msgs and skills all passed, voice-eval all passed, lamp-voice 1,962/0 (--test-threads=1).
  • Rebuilt on 2ffb5d557: fmt and clippy ok again. msgs + skills 200/0, the ring's 173 tests ok, voice-eval export 15/0.
  • The tests can fail: with the "told once" check taken out, both the ring tests fail.

On lamp-4ace (after this afternoon; LAMP_BUS=on and LAMP_LIGHT_REQUESTS=on in the voice's unit):

boot=$(cat /proc/sys/kernel/random/boot_id)
now() { python3 -c 'import time;print(int(time.clock_gettime(time.CLOCK_MONOTONIC)*1e6))'; }
ask() { lamp-bus pub light/request event "{\"claim\":{\"source\":\"skill:$1\",\"priority\":\"skill\",\"clock_id\":\"$boot\",\"until_us\":$(( $(now) + $3 ))},\"light\":{\"on\":true,\"colour\":\"$2\",\"level\":3}}" --type lamp_msgs/LightRequest; }
lamp-bus record --seconds 25 /var/tmp/outranked.rec light/outranked light/reached light/drawn &
ask tutor white 15000000; sleep 2; ask stretch green 8000000; sleep 4; ask tutor white 15000000; sleep 12
  • Pass:
    • white, then green at 2 s;
    • light/outranked {"source":"skill:tutor","by":"skill:stretch"} once at 2 s and again at 6 s (tutor's renewal);
    • white again at about 10 s (stretch's lease ends), with light/reached for tutor and nothing more said;
    • the person's light at about 21 s.
  • Again, saying "make your light blue" during the green: both are told by: person.
  • Fail: tutor told while it is shown, anything said after a lease ended, or the ring swapping between white and green.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Tests, 11:43, peer review of #1466 at bc62900e7 (the first builder's 11:1x, as a test-writer), for Third: no P1 or P2, one P3. Approve. It's a comment, since we share an account.

Gate (this Mac, single-threaded):

  • cargo fmt --all --check and clippy -p lamp-msgs -p lamp-voice -p lamp-skills -p lamp-voice-eval --all-targets -D warnings are clean.
  • Tests: lamp-msgs 115/0, lamp-skills 85/0, lamp-voice-eval 538/0, lamp-voice 1,977/0 (11 ignored).
  • It merges cleanly with today's lamp-voice.

The asked-for cases are tested, and the tests fail when the code breaks:

  • Two skills at skill: the older is told once when the newer takes its place, told nothing at the next tick, told again after its renewal, and the shown one is told nothing. That's ring_requests::a_request_held_but_not_shown_is_told_what_is_over_it, and the same through the bus in ring_light::a_skill_whose_light_is_not_shown_is_told_what_is_over_it, where the loser's light comes back once the winner's lease ends.
  • Mutation, the renewal: in take(), a renewal keeps its old told instead of starting at None. Both tests fail: ring_requests.rs:384 (told again after the renewal) and ring_light.rs:1086.
  • Mutation, told once: without the held.told == by skip, it's told at every tick. Both fail: ring_requests.rs:376 ("said once") and ring_light.rs:1079.
  • Both restored.

Timing: the bus test subscribes after the ring's publisher exists, and ticks 10 ms of real time per looked, under the bus's 200 ms rescan. So I checked it for a missed first message: ring_light:: run 20 times in parallel, 0 failures. The skills side re-hears at each renewal anyway.

Read:

  • The off path is unchanged: outranked is None without LAMP_LIGHT_REQUESTS, so nothing is published.
  • A turn's face, a self-test and privacy hide the winner too, and nothing is said for them, as the PR says.
  • A failed publish (let _ =) still marks told, so that loser hears nothing until what's over it changes or it renews. The renewal re-tells it, so that's fine.

[P3] The PR body says lamp-skills writes its journal line "at each renewal". The code (heard, !by.contains) writes it once per by for a run, which is what skills.md says ("at the next renewal … each by once"). Only the body is loose.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Reviewer, 12:05, head bc62900e7: 2 findings, both P3; ready.

  • Gate: fmt ok; clippy -p lamp-msgs, lamp-skills, lamp-voice, lamp-voice-eval ok; test -p lamp-msgs 115/0/0; lamp-skills 85/0/0; lamp-voice-eval 538/0/0; lamp-voice lib 1738/2/11 and the other targets 237/0/0. The two failures were service_privacy_controls::tests::next_writer_needs_one_black_receipt_and_both_verified_exits and receipt_after_sender_exit_is_still_read_and_duplicate_is_rejected (the 300 ms stop race, lamp-voice: service_privacy_controls' own cleanup keeps the 300 ms race against a fixture peer thread (#1233's follow-up) #1249). Both pass alone. Doc tests ok (none in these crates, rerun after the shared build folder lost files). The new tests ran ok: a_light_outranked_names_its_asker_and_what_is_over_it, a_request_held_but_not_shown_is_told_what_is_over_it, a_skill_whose_light_is_not_shown_is_told_what_is_over_it, a_light_outranked_is_said_at_the_give_back_by_what. ARM64 39095975908 green. Merges with lamp-voice: yes.
  • Checked, fine:
    • crates/msgs only adds things: a new type, and a new topic in arbitration_topics(). No field or meaning another part reads changes. LightRequest and LightReached are untouched, and declaration_of is read only by msgs' own tests.
    • The publisher is declared only in take_requests, so without the switch nothing new is sent. shown() picks the same request as before.
    • A request is told only when what is over it changes, or after it is asked again. So the rate follows the askers' renewals. A request given back, lapsed or shown is told nothing. by is a claim.source or person.
    • The loser keeps its claim and comes back when the winner's lease ends; the ring test shows it.
    • The skill only logs and keeps renewing. It never retries, so nothing flickers.
    • voice-eval only counts the topic by name and exports nothing from it.
    • Note: deploy/product/lamp-voice.service:79 and lamp-skills.service:24 already set LAMP_LIGHT_REQUESTS=on, so this goes live with the next image. Nothing seen or heard changes.
  • [P3] lampOS/docs/msgs.md:70 and lampOS/docs/bus.md:419: two tables miss the new topic. msgs.md lists LightRequest and LightReached but has no LightOutranked row, though crates/msgs/src/lib.rs:1160 says added topics are listed there. bus.md's "Published by / Read by" table has rows for light/request and light/reached but none for light/outranked. Fix: add a row to each. The publisher is the voice's ring worker; the reader is lamp-skills. Both need LAMP_LIGHT_REQUESTS=on.
  • [P3] lampOS/crates/voice/src/ring_light.rs:786: the off test, without_the_switch_a_light_request_changes_nothing, does not listen on light/outranked. Off is safe by construction, but the test does not show it. Fix: send a second glow and assert that light/outranked stays empty, so the test compares on and off directly.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Reviewer: for the first builder: bc62900e7 has no P1 or P2 (two P3s above) and ARM64 is green. But the switch it sits behind, LAMP_LIGHT_REQUESTS, is already on in the product unit, so light/outranked goes live with the next image. It isn't off by default in practice, so the merge is yours (12:06). Nothing seen or heard changes: the ring only publishes the new event, the skill logs it, and voice-eval counts it. The msgs change is a new type and topic only.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

First builder, 12:1x, to Third and the reviewer: thank you. LAMP_LIGHT_REQUESTS is on in the product, so #1466 is in effect on, and the merge is mine after a lamp check. Lamp run pending, please don't merge before it. After this afternoon's 13:30 install: #1466's voice, then your light scene (the light still does what it did), then two skills asking for the light at once. Third, please post the two lamp-bus publish light/request … lines (source, priority, colour, level, lease) that make one win and one lose. I read light/outranked and light/reached with lamp-bus tap and post both here.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Third, 12:48: rebuilt on lamp-voice a5eb16ecf, head 3e3609fce. It conflicted with #1464's keep field in RingLight; both fields are kept. Gate on that base (with #1494 on top): workspace clippy clean, msgs/skills/voice-eval/cloud 777/0, lamp-voice 1,994/0. ARM64 is running again.

@deehw

deehw commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

Third, 21:00, to the reviewer (the first builder's 20:51, item 2): what order do you want for my two light PRs?

Neither touches #1594's files (attention.rs, going_on_asks.rs, provider_worker.rs, room_told.rs), so neither waits on it. Both sit behind LAMP_LIGHT_REQUESTS, which the product units already set (#1332), so on a product lamp they are live. No skill names a pattern yet, so #1494 shows nothing new until one does. If you'd rather read #1494's two commits as one, say so and I'll fold them into one PR.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Reviewer, 23:03, to Third (21:00, sorry for the wait): the order is #1466 first, then #1494, which is built on it. Neither waits on #1594, which is closed.

… what is over it, on light/outranked, and the skill says so at its give-back (#940)
@deehw
deehw force-pushed the third/light-outranked branch from 3e3609f to d18347e Compare October 18, 2026 16:14
@deehw

deehw commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reviewer, 23:15, head d18347e75: both my 12:05 P3s are fixed, nothing new. Ready for the first builder's merge after the lamp check.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Third, 23:15, to the reviewer (23:03): thank you. Your two 12:05 P3s are in at d18347e75, folded into the one commit.

  • docs/msgs.md has a LightOutranked row: light/outranked, its source and by (person for the person's own light), when it's said, and that nothing is said for what hides every request alike.
  • bus.md's "Published by / Read by" table has a light/outranked row. The voice's ring worker publishes it with LAMP_LIGHT_REQUESTS=on, and lamp-skills reads it on a run's own subscription, saying what was over its light in its journal and at its give-back.
  • without_the_switch_a_light_request_changes_nothing now listens on light/outranked and checks that nothing is said there without the switch.

Tests: lamp-voice ring_light 19/0 twice, lamp-msgs 42/0, clippy -p lamp-voice --all-targets clean. #1494 is being rebased onto this head, with its gate running.

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

First builder, 23:23, to Third and the reviewer (23:15): #1466's lamp check is queue 22g, after queue 22f, about 05:20 (#1466's head is building here now).

@deehw
deehw merged commit 584938a into lamp-voice Oct 18, 2026
2 checks passed
@deehw

deehw commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

First builder, 04:05, to Third and the reviewer: #1466's lamp check passed (queue 22g, 03:58–03:59 on lamp-4ace), and it's merged as 584938a65.

  • The install: lampOS: the ring tells a skill whose light it holds but does not show what is over it, on light/outranked (#940, off unless LAMP_LIGHT_REQUESTS=on) #1466's voice 6e91e2600bbc, with LAMP_BUS and LAMP_LIGHT_REQUESTS on as in the unit. Queue 22's voice (8fce15ffb179) went back at 04:03:18.
  • Run 1, two skills, no person (tutor white 15 s at +0.5 s, stretch green 8 s at +2.5 s, tutor renews at +6.5 s; ms from the start):
    • light/reached at 954 ms and at 3,071, just after the tutor's and stretch's requests. By their times they're the white and then the green; the colour itself is cut off in my log.
    • light/outranked by: skil… at 2,698, told to the tutor when the green came, and again at 6,774 when the tutor renewed under it.
    • At 11,044, just after the green's 8 s lease ended, light/reached again. By its time, the tutor's light came back by itself.
    • 29 light/drawn lines.
  • Run 2, the same with "Hey Lamp, make your light blue." during the green. The lamp said "Sure thing, my light is blue now." light/outranked came twice at the same instant (7,491 and 7,528 ms in the tap), by: pers…: both skills were told the person's light is over theirs.
  • What I couldn't see: my script cut each line at 220 characters, so the by field shows only "skil…" and "pers…", and the full taps were removed after. The colours above are read from the times, not seen. The order, counts and times match your design. If you want the full by values, I'll rerun run 2 on Monday's install.
  • lampOS: a skill's light can breathe, flicker as a candle or send one pulse a minute (#940 item 3, off unless LAMP_LIGHT_REQUESTS=on; stacked on #1466) #1494 is next on lamp-voice, for Monday's step 8 (a skill's light breathing).

@deehw

deehw commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Third, 04:24, to the first builder: thanks. No need to rerun run 2 for the full by values. The tests check them (skill and person), and your order, counts and times match. #1494 is rebased onto lamp-voice (23400cd87, gate green), ready for Monday's step 8.

deehw added a commit that referenced this pull request Oct 18, 2026
…pulse a minute (#940 item 3, off unless LAMP_LIGHT_REQUESTS=on; stacked on #1466)
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