NEC-169: Make the outstanding videos #237

Merged
nectenda-agent merged 19 commits from worktree-nec-169-make-the-outstanding-videos into main 2026-09-30 23:42:19 +01:00
Collaborator

Task: NEC-169 — https://projectron.nerchure.com/tasks/177

Makes every outstanding how-to video from NEC-169 (07 get started, 08 conflict copies and backups, 09 canvases together, 10 compare keys, 11 share links, 12 remove someone, 13 sync status) and the channel trailer (06), each recorded from real Obsidian with its claims checked as it is filmed, embedded in its guide, and ready to upload with its note. Puts the Nectenda logo in every video's step band and draws the lockup in the site header's proportions; 01-05 are re-rendered to match. Adds the canvas-together guide and embeds video 01 in share-a-folder. Filming video 12 found that a removed member kept receiving a folder's updates while connected: the server now sends a document's traffic only to subscribers still allowed into its folder (WIRE-065), including after removal from the whole organisation, and catches up a member added back on the same connection before acking their next push.

Spec: docs/changes/NEC-169-outstanding-videos/spec.md

Also fixes NEC-183: A removed member keeps receiving a folder's updates while connected
Also fixes NEC-184: The attachments guide still says canvases are attachments that do not merge

Changelog

A member removed from a shared folder, or from the organisation, now stops receiving its changes at once, even while their Obsidian stays open.

Task: NEC-169 — https://projectron.nerchure.com/tasks/177 Makes every outstanding how-to video from NEC-169 (07 get started, 08 conflict copies and backups, 09 canvases together, 10 compare keys, 11 share links, 12 remove someone, 13 sync status) and the channel trailer (06), each recorded from real Obsidian with its claims checked as it is filmed, embedded in its guide, and ready to upload with its note. Puts the Nectenda logo in every video's step band and draws the lockup in the site header's proportions; 01-05 are re-rendered to match. Adds the canvas-together guide and embeds video 01 in share-a-folder. Filming video 12 found that a removed member kept receiving a folder's updates while connected: the server now sends a document's traffic only to subscribers still allowed into its folder (WIRE-065), including after removal from the whole organisation, and catches up a member added back on the same connection before acking their next push. Spec: `docs/changes/NEC-169-outstanding-videos/spec.md` Also fixes NEC-183: A removed member keeps receiving a folder's updates while connected Also fixes NEC-184: The attachments guide still says canvases are attachments that do not merge ## Changelog A member removed from a shared folder, or from the organisation, now stops receiving its changes at once, even while their Obsidian stays open.
The lockup, mark and wordmark, leads the band in 16:9; a Short's band
is a third narrower and its captions nearly fill it, so there it is the
mark alone. A band may also carry no step count, for the trailer, which
is not a how-to. The band's markup moves into cards.mts so a unit test
can read it without a browser.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
A two-pane video can now show a recorded clip over its right-hand (in
9:16, lower) vault, leaving the other in view: the trailer puts a note
beside what the server holds of it. The terminal is sized to that box
and types a step's narrow form in it. A storyboard with steps: false
renders its band without "Step N of M".

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
06-trailer.mts is the storyboard. Tomás acts on the left and Priya watches
on the right, so each mark is seen by the person who receives it: named
carets and pointers, the arrow at the edge, jumping to someone, and on a
canvas every presence mark the plugin draws - the pointer and its edge pin,
a selection outline, the ghost of a card being moved or resized, a link
being drawn, and a caret and selection inside a card someone types in.
Each canvas shot waits for its mark on Priya's screen, so a take in which
one was not drawn fails. Then the server's copy of the note beside it.

choreo gains drag and clickAt: a canvas sends a gesture only while the
pointer is down, and click's scrollIntoView pans a canvas out from under
the other person's view. publish.mts copies a finished cut to where it
ships, with its thumbnails, poster and captions.

brand-videos.test.mjs now checks that the trailer is the featured video
and that every video a guide embeds has its file, captions and poster.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
06 is ready to upload: 16:9 and 9:16, 62.6 s, voiced, every narration
line heard as written. Its note carries the title, description, tags and
Short copy; youtube.md gains "The trailer", the steps to upload it and
make it the featured video for new visitors in place of 02. The 16:9 cut
plays on what-nectenda-is.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
The cards and the band copied assets/logo.svg, which draws the mark at
about half the wordmark's cap height. The design system's Logo guideline
sets it at 0.87x the cap with a gap of about 0.80x, and the site header
draws exactly that: a 26 px mark beside a 19 px wordmark, 12 px apart.
One lockup, built in cards.mts, now serves the start and end cards and
the band, in those proportions; cards.test.ts holds them there. The
trailer is re-rendered with it.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Two shots added at the user's request. In the note, Tomás drags across
two lines and Priya sees them highlighted in his colour. On the canvas,
Priya opens the card Tomás is typing in: her editor draws his caret and
selection inside it, and as she types, his draws hers. Each waits on the
mark itself on the receiving side. The cards are larger so two people's
words and carets fit, and both pointers leave the card once it is open.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Render-only, from the original takes: every cut has the same length and
the same subtitles as before, and only the picture changed. The site's
copies and every thumbnail move with them. youtube.md says what is still
the first cut on YouTube, and how to replace the uploads if the user
chooses to.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Removing a member dropped each socket's cached membership, and inbound
messages re-read it, but the fan-out never asked. A removed member whose
Obsidian stayed open and silent kept receiving every update written after
the removal, and presence, until it next sent something; the folder's key
is not rotated on removal, so they could read it. Found filming the
remove-someone video, where the owner's next line reached the removed
member's copy within seconds.

broadcast() and the presence relay now go only to subscribers still
allowed into the folder, by the same cached answer inbound messages get,
and unsubscribe any who are not. That covers deleting a user as well as
removing a member. WIRE-065 states it; member-removal.test.ts defends it,
mutation-checked both ways. security-model.md says when it changed.

Task: NEC-169
Also-fixes: NEC-183
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
What each person sees of the others on a canvas: pointers and the edge,
selections, cards moved, resized and linked as it happens, a card being
typed in, and two people in one card. How to go to someone, what happens
when two change the same thing, and that phones are not yet checked. Its
video follows.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
The attachments guide still listed .canvas files as attachments, synced
whole on the paid plans, with two people editing one canvas left with two
files. Since NEC-22 and NEC-23 a canvas is a structured document, merged
and bound live, and never goes through the attachment path. The guide now
says a canvas syncs like a note, and points to the canvas guide.

Task: NEC-169
Also-fixes: NEC-184
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
09 canvas together, 10 compare keys, 11 share links and 12 remove someone
are recorded, rendered, embedded in their guides and ready to upload,
each with its note. Video 01 is now also embedded in share-a-folder, whose
first two shots it is. The scripts for 07 get started, 08 conflict copies
and 13 sync status are here; their cuts follow.

Each shot checks the claim it films as it films it: the fingerprints on
both screens are the same string, the pasted link is the one copied, the
removed member's copy did not change. network.mts takes one vault off the
network with Chromium's own offline mode, holding the DevTools session open
for as long as it is off, since emulation ends with the session. A terminal
shot can now look at a vault, not only the server's copy. helpers.mts holds
what several storyboards share.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
07 installs Nectenda from Obsidian's own community plugin browser, the
store's release over the network, then signs in with an emailed code,
chooses a passphrase and saves the recovery key. Staged, and said so in
its script: the store's release is swapped off camera for the build about
to ship, pointed at the film's own sign-in service. 13 shows the icon
green, with someone in the note, its menu, offline and back, each waited
for by the icon's own state, and still offline at the end of the offline
shot. Both embedded in their guides, with their notes.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
The two cases the guide describes, as they happen: a note deleted while
Priya, offline, had unsent changes to it, which come back as a conflict
copy beside it for both of them; and a shared folder added over her own,
whose different note is written over only after hers is set aside in
.nectenda-backups, shown in a terminal because Obsidian hides the folder.
Both read back from disk as they are filmed. Embedded in its guide.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Review of the removal fix found two things it left open.

Removing someone from the whole organisation deletes their user row, and
their folder memberships go by cascade without naming a folder, so no
socket's cached membership was dropped and they went on being sent every
folder they had been in. Deleting a user now clears that user's cached
memberships on every socket (invalidateUser), and the fan-out re-reads.

And the fix itself opened a gap: a member dropped for losing access and
added back on the same connection re-registers with their next push, and
its ack would move them past every update written while they were out,
which they would never ask for again, and which a later snapshot of theirs
could compact away. A socket now remembers where it was dropped from, and
is caught up from there before that push is acked.

A failed membership read inside the fan-out sends as before rather than
throwing out of the push's ack or the presence timer.

member-removal.test.ts covers both, each mutation-checked, and its second
case now keeps both folders on one socket, as the plugin does.

Task: NEC-169
Also-fixes: NEC-183
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
12 now counts Tomás's line on the server before checking it did not reach
Priya, so a line that never left his vault cannot pass; 13 checks the line
typed offline has not reached Priya before the vault comes back, so the
catching up it films is the catching up. network.mts says what offline
mode does not cut. The spec records what review added to NEC-183.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
12's positive control reads the shard's own name for the rota: the index
already returns it with the folder prefix. Both takes pass their checks in
both directions, and replace the earlier cuts.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
Re-film 07 and 11 on the plugin as main has it now
Some checks failed
Release note / release-note (pull_request) Successful in 15s
CI / build (pull_request) Failing after 2m27s
CI / promote (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
7854c5c1b2
main moved the sign-in code box onto a row of its own and loads the share
link row once the organisation page is showing, both on screens these two
videos film. Recorded again from the rebased build, so neither shows a
layout that has since changed.

Task: NEC-169
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9N4NcSRo4fTamGGez188X
cruelacid force-pushed worktree-nec-169-make-the-outstanding-videos from 7854c5c1b2
Some checks failed
Release note / release-note (pull_request) Successful in 15s
CI / build (pull_request) Failing after 2m27s
CI / promote (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
to e97a8460d0
Some checks failed
CI / e2e (pull_request) Failing after 6s
CI / build (pull_request) Failing after 6s
Release note / release-note (pull_request) Failing after 6s
CI / promote (pull_request) Has been skipped
2026-09-30 23:17:13 +01:00
Compare
cruelacid force-pushed worktree-nec-169-make-the-outstanding-videos from e97a8460d0
Some checks failed
CI / e2e (pull_request) Failing after 6s
CI / build (pull_request) Failing after 6s
Release note / release-note (pull_request) Failing after 6s
CI / promote (pull_request) Has been skipped
to dc30b81ee6
Some checks failed
Release note / release-note (pull_request) Successful in 13s
CI / build (pull_request) Failing after 2m30s
CI / e2e (pull_request) Successful in 6m50s
CI / promote (pull_request) Has been skipped
2026-09-30 23:19:33 +01:00
Compare
cruelacid force-pushed worktree-nec-169-make-the-outstanding-videos from dc30b81ee6
Some checks failed
Release note / release-note (pull_request) Successful in 13s
CI / build (pull_request) Failing after 2m30s
CI / e2e (pull_request) Successful in 6m50s
CI / promote (pull_request) Has been skipped
to ffb9565462
All checks were successful
Release note / release-note (pull_request) Successful in 14s
CI / build (pull_request) Successful in 4m58s
CI / e2e (pull_request) Successful in 6m53s
CI / promote (pull_request) Has been skipped
Deploy site / deploy (push) Successful in 1m1s
CI / build (push) Successful in 5m20s
CI / e2e (push) Successful in 6m56s
CI / promote (push) Successful in 31s
2026-09-30 23:34:28 +01:00
Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda!237
No description provided.