fix(collaboration): harden awareness runtime contracts - #167
Draft
seonghobae wants to merge 54 commits into
Draft
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #208.
Closes #297.
Closes #305.
Closes #309.
Closes #370.
Buyer-visible boundary
Inkspan publishes local collaboration identity/presence into Yjs awareness and publicly exports collaboration presentation helpers. This Draft hardens that finite local boundary without acquiring provider transport, room authorization, tenancy, persistence, credentials, network, model, database, deployment, retention, durable-audit, or Yjs document authority. Remote awareness remains untrusted presentation data and never authorization evidence.
Current exact boundary
Protected shipped truth is independently resolved as
main@3b38ead2d00f44eb578d0689087b9293b3dabe1e. Current exact Draft head isd8407c5fc65027233c880cae2d1f2d14d5261d91onfix/collaboration-awareness-bounds-20260811. GitHub reports the Draft mechanically mergeable.Fresh exact comparison from protected main reports this long-lived branch as diverged, 54 ahead / 29 behind, with merge base
50ac98cfa0ad9e8dd75f93ca437a5679fed4d804and 19 awareness/docs/test paths. The 29 protected-main commits after that merge base include release/control-plane authority this branch does not own. Do not merge, force-push, destructively rebase, or treat this branch tree as current protected-main authority while #118 owns the release boundary. Reconciliation must remain non-destructive and source-owner aware after that boundary permits it.Implemented
Array.from(...)materialization;trim()normalization while preserving the normalized in-bound identifier contract;userId,displayName, andcursorColorsource strings above 1,024 UTF-16 code units before normalization and validates their runtime types;undefined -> Collaboration readyand the four declared connection states while invalid runtime status tokens fail closed;contrastingTextColor()accepts exactly six-digit hexadecimal CSS colors and rejects malformed runtime values before channel parsing;user/idmetadata and contains failures from host-ownedawareness.clientIDandawareness.getStates(), returning the safe zero-presence fallback rather than leaking a caller/private exception;nameandcolor, source-bounds remote cursor names, and restricts colors to the existing six-digit grammar plus safe fallback;provider.awarenessor awareness members cannot escape configuration/scoped-provider operations;on(...)commits local wrapper state only after host registration succeeds, redacts host registration failures, and permits a clean retry instead of recording a false-success registration;off(...)redacts host removal failures and retains local wrapper state after a rejected host removal so callers can retry without losing cleanup authority;off(...)call throws, clears local wrapper state, stays idempotent, and does not leak the private teardown failure through React cleanup; andTest-first lineage
Earlier hosted lineage in this PR established RED→GREEN for display-name bounds, invalid remote identity counting, allocation-free Unicode bounds, invalid connection-status behavior, local collaboration-user runtime field validation, public contrast-color validation, the #309 remote source ceiling, descriptor-safe remote presentation, and the 1,024-code-unit remote cursor-name source preflight.
For provider-capability acquisition, test-only predecessor
7209a86d45908ab9bd9118591445ac6cf666cf49introduced a provider whose firstawarenessread is valid and whose second read throws a private sentinel. Its hosted workflows were superseded/cancelled by the immediate source repair, so no hosted RED is claimed. Source repaireda95121085bfd42c14756002b7c531b88b008aecentralizes provider awareness acquisition and structural compatibility reads inreadCompatibleCollaborationAwareness(), normalizing failures to the stable module-owned provider-capability error. Later regressionde6f54b44fa9b7f771784c9f6635a451374b3029covers a structuralclientIDgetter failure.The count-path defect was found on predecessor head
4b74b65cb52becc4e18f72ad480fe9d9c206ddfb:countRemoteCollaborators()directly read host-ownedawareness.clientIDand invokedawareness.getStates(), so either capability could throw a private value through the public helper. Test-only successorf07819b4252a0735cbe41619ef3c9117d5b7dc44adds two realistic failure-containment regressions; source repair6a01457ad7a044405a100a5b563f1b718fe3d220wraps that host-owned count operation while retaining descriptor-safe remote identity rules.The disposal defect was isolated on
6a01457ad7a044405a100a5b563f1b718fe3d220:dispose()called host-ownedsource.off(...)directly inside the nested cleanup loop, so one private teardown exception aborted all later detachments and escaped the component cleanup boundary despite the scoped-provider contract. Test-only REDd14dcd5aa935e21a3e7d10c12797f5ee8863b1b4requires one throwingchangedetachment not to preventupdatedetachment, not to leak the sentinel, and to remain idempotent. The predecessor deterministically fails that contract; the immediate source repair superseded hosted RED generation, so no hosted RED is claimed. GREENa03c7d04a11f7d7c7274e466247b38057fc19bb7isolates each host detachment, continues cleanup, and clears local wrappers regardless of host failure.The latest listener-operation defect remained after that cleanup repair: direct scoped
on(...)inserted its wrapper before calling the host, so a rejected host registration both leaked the private host exception and poisoned the local map into a false-success retry; direct scopedoff(...)also leaked a private host removal exception. Test-only commitsbe5e0a1a1d87a297160a259d3df24cca90c0ca47and3694bfaafc96501c0e164668a43870568ee74ce9require stable payload-redacted registration/removal failures plus real retry semantics. Their workflow generations were superseded/cancelled by the immediate narrow source repair, so no hosted RED is claimed. Current GREENd8407c5fc65027233c880cae2d1f2d14d5261d91moves registration-state commit after successful hoston(...), retains state after rejected hostoff(...), and normalizes both host failures to module-owned errors.Exact-current-head evidence
For unchanged exact head
d8407c5fc65027233c880cae2d1f2d14d5261d91at the latest commit-bound refetch:32221759117: completed / success, including exact 100% root test coverage, package consumers, demo build, Office Python 3.11–3.14, and the Playwright 1.62.0 cross-engine clipboard job;32221759122: completed / success;32221759109: completed / success;Repository exact-head technical success is not qualifying independent approval and does not replace separately applicable central workflows or live governance. Pending/queued/in-progress/skipped/cancelled/absent/stale/predecessor/status-only/model-only evidence remains non-passing.
Canonical consistency
docs/collaboration.md, protected PRD/TRD/contracts and architecture continue to state the intended authority accurately: remote awareness is ephemeral untrusted presentation data, not authorization evidence, and host/provider lifecycle authority remains outside Inkspan. These repairs narrow execution/resource/error-containment behavior within that existing boundary; they do not change provider, host, persistence, transport, model, or public semantic authority.Draft #228 separately owns direct
CollaborativeCwlEditor.tsxcomponent interactions with host awareness. Its component-local getter/listener containment is complementary to this awareness-module lane and is not duplicated here.Integration boundary
Release issue #118 owns exact protected
v0.6.0tag/publication/provenance from protected main. Keep this PR Draft and unmerged while that release boundary remains frozen and live governance is unsatisfied. After #118 permits integration work, refetch live main/head/ancestry/writers and reconcile this diverged branch non-destructively without reviving stale protected-control files or racing overlapping owners; then reacquire every exact-head/live-base repository/central workflow plus qualifying independent approval before any Ready/merge decision. Never transfer predecessor evidence, self-approve, weaken gates, or fabricate tag/release identity.