@phosphorco/bb-identity 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/EDITING.md ADDED
@@ -0,0 +1,131 @@
1
+ # Opt-in shared work-product editing
2
+
3
+ `@phosphorco/bb-identity/editing` uses the production state controller and binding
4
+ lifetime with an explicit `bb-identity.editing/v1` protocol. Legacy `/state`
5
+ consumers retain their existing outcomes, codecs, auto-dispatch and blocked edit
6
+ behavior. This entry adds no mandatory SDK or React runtime dependency.
7
+
8
+ | Feature owns | Package owns | UI owns |
9
+ | --- | --- | --- |
10
+ | Shared storage, document targets and schema | Session and controller lifetime fences | Text controls and conflict choices |
11
+ | Atomic admission, immutable request receipts and retention | Desired generation, exact flight, acknowledged base | Explicit publication and checkpoint/export actions |
12
+ | Protocol advertisement and selected v1 transport | Versioned codecs and receipt/request validation | Separate publication and backup presentation |
13
+ | Real map epoch, monotone admission ordinal, opaque revision | Bounded reconnect and recovery | Feature diagnostics and labels |
14
+ | Draft adapter and conditional checkpoint revisions | Shared Provider retirement coordination | Explicit recovery candidate selection |
15
+
16
+ A shared map has no personal owner. `draftAddress.owner` is the actual actor
17
+ whose editing work is retained. `target` selects the shared feature document.
18
+ Do not send this editing scope to legacy personal-state server routes or
19
+ register a fake personal state owner for the shared document. The feature
20
+ adapter loads shared content into an actor's editing scope and supplies real
21
+ version metadata. Epoch changes on reset/recreation; sequence increases inside
22
+ the admission transaction. Keep opaque revision identity in the feature value
23
+ when the feature command needs it. Do not derive sequence from time, UUID or hash.
24
+
25
+ ## Controller and binding
26
+
27
+ Construct `createIdentityEditingState({draftAddress,target,targetCodec,expected,
28
+ ownerSession,definition,transport,drafts?,scheduler?,onConflict,initializeEmpty,
29
+ currentSession})`. `currentSession` observes the live client, never a captured
30
+ initial session. The transport must be explicitly negotiated with the feature's
31
+ v1 endpoint before construction; the protocol literal and a successful local
32
+ codec do not prove remote capability or durable storage.
33
+
34
+ Prefer `useIdentityEditingBinding({resourceKey,target,targetCodec,create,
35
+ onUnpersistedDraft?})` and `useIdentityEditingSnapshot(binding)` from `/react`
36
+ under the continuously mounted `BbIdentity.Provider` and `BbIdentity.Context`.
37
+ `create({session,subject,ownerSession})` returns the controller; `subject` is the
38
+ actual actor. The hook acquires resources only after commit. Use a stable
39
+ `resourceKey` describing the feature/schema/draft record. Semantic encoded
40
+ Target changes replace the owner; object and callback recreation alone do not.
41
+ Callback changes are visible only after commit. A manually owned resource may
42
+ use `bindIdentityEditingState({...options,client,view})` from `/editing`.
43
+
44
+ The shared binding fences delayed recovery/conflict/checkpoint commands with
45
+ `currentOwnerSession()` before and after awaits. A1 → B2 → A3 creates distinct
46
+ controller incarnations even when actor A returns. A detached controller cannot
47
+ be revived; new work requires a new controller and explicit recovery. The
48
+ controller's borrowed `draftStorage` identity lets the Provider wait for an old
49
+ write before enumerating replacement recovery candidates. The Provider never
50
+ owns or disposes feature storage.
51
+
52
+ ## Publication and backup are separate
53
+
54
+ `edit(B)` changes desired value and generation. Loaded active same-owner drafts
55
+ remain editable through conflict, unknown save, definitive rejection and failed
56
+ checkpoint. Session/owner change, detach/dispose, migration and load failure
57
+ fence editing. An authoritative successful reload can resolve a load failure;
58
+ returning to an old identity cannot revive a retired controller.
59
+
60
+ Edits never publish automatically. `flush()` captures an immutable request
61
+ before the first checkpoint or transport await. With pending A, one explicit
62
+ flush reconciles A only. It never follows reconciliation by sending newer B.
63
+ A successful `Result<void>` can mean A was acknowledged while B remains dirty;
64
+ always render the snapshot's desired/acknowledged/publication/backup facets.
65
+ A rejected receipt returns a failed Result, retires A without changing base,
66
+ and retains B plus structured diagnostics. After correction, a later explicit
67
+ flush submits a new operation. Retrying a checkpoint or reading unchanged data
68
+ cannot resolve rejection or an unknown save. Conflict is also a failed explicit
69
+ publication; decisions capture a token that changes immediately when typing B.
70
+
71
+ `checkpoint()` serializes desired B, acknowledged base, exact pending A and
72
+ last definitive rejection. `snapshot.draft` remains exportable when it fails.
73
+ `checkpoint.status` is disabled, local-only, writing, backed-up or failed;
74
+ `generation` and `revision` identify the last committed checkpoint. A generation
75
+ alone cannot prove backup: receipt/pending/base/rejection metadata must also
76
+ match. Without DraftStorage there is no browser-death recovery guarantee.
77
+
78
+ On retirement failure, `useIdentityEditingPreservationFailures()` retains the
79
+ full EditingDraft, including Target, without a fresh identity RPC. Its bounded
80
+ Provider presentation records have exact generation tokens.
81
+ `useAcknowledgeIdentityEditingPreservationFailure()(generation)` only dismisses
82
+ that record; it neither retries storage nor proves backup or publication.
83
+
84
+ ## Exact request finality and recovery
85
+
86
+ An `EditingRequest` binds protocol, Target and the full immutable StateMutation,
87
+ including actual actor/session, ownerSession, expected version, local generation,
88
+ schema, operation ID and submitted value. Every final receipt echoes this exact
89
+ request. The feature must reserve/check its canonical request fingerprint before
90
+ CAS and atomically retain the original outcome, including rejected diagnostics.
91
+ Changed payload with the same ID is invalid-operation. The package validates the
92
+ full echoed request; matching operation ID alone cannot authorize retirement.
93
+ Bounds are exported as `EDITING_LIMITS`; codecs reject malformed versions,
94
+ diagnostics, recovery data and mismatched resource metadata.
95
+
96
+ `reconcile(originalRequest)` uses the current authenticated invocation to inspect
97
+ the original request, even when its actor's server session has since changed.
98
+ Never rewrite the original request's expected session or ownerSession. A final
99
+ saved outcome contains the admitted A snapshot, even if remote current is C.
100
+ Load C afterwards and review divergence against A's acknowledged base. A final
101
+ conflict likewise carries the original captured remote snapshot. Pending,
102
+ unknown, expired and ordinary transport errors retain A. Even absent-final does
103
+ not cause automatic or implicit replay in this manual v1 controller. No new
104
+ operation is created while A is unresolved.
105
+
106
+ Draft discovery is bounded to 20 candidates by full actor/draft address/Target.
107
+ Selection is explicit; codecs preserve B and A independently across controller
108
+ sessions. `remove({target,draftKey},revision)` must conditionally delete only that
109
+ exact checkpoint. A newer checkpoint cannot be erased by stale recovery UI.
110
+
111
+ Source/controller/binding tests and local packed-consumer tests establish only
112
+ the exercised source/artifact contracts. Actual feature negotiation, durable
113
+ atomic receipt storage, registry adoption and live runtime coverage require
114
+ separate evidence.
115
+
116
+ Protocol metadata is validated through typed normalization too: encoders retain
117
+ supplied protocol fields so an unsupported outer or nested version cannot be
118
+ rewritten into v1. Recovered rejection evidence must match the draft's schema
119
+ and cannot come from a future local generation or the same still-pending
120
+ operation. Historical actor session and ownerSession remain unchanged; a new
121
+ active session may recover and reconcile that exact historical request.
122
+
123
+ Use `editingCodecs(valueCodec,targetCodec).scope` at the feature's v1 load and
124
+ subscription wire boundary. It encodes/decodes the actual `EditingScope`:
125
+ `{draftAddress,schemaVersion,target,expected}`. Public ID and identity codecs
126
+ validate the draft owner and exact opaque session; draft owner must equal the
127
+ expected actual actor, while Target remains feature data. The codec rejects
128
+ unknown input keys and unsafe schema integers, preserves typed Target wire
129
+ conversion, and shares `EDITING_LIMITS.bytes`. A load scope contains no invented
130
+ operation, revision, submitted value or mutation. Protocol negotiation still
131
+ belongs to the selected v1 endpoint and transport.
@@ -0,0 +1,222 @@
1
+ # Native source evidence — 0.4.0 candidate
2
+
3
+ `@phosphorco/bb-identity/native` normalizes bounded, retained public SDK
4
+ snapshots into `NativeSourceEvidence`. It preserves native source facts without
5
+ manufacturing a Contribution, successful history lookup, attempt, person, or
6
+ agent identity. Existing Contribution/ExecutionProvenance APIs are unchanged.
7
+
8
+ | Caller owns | Package owns | Host/public SDK owns |
9
+ | --- | --- | --- |
10
+ | Reading and freezing snapshots; retention/rewrite fences | Bounds and validation | Retained events and visible timeline projection |
11
+ | Cursors, discovery, budgets, persistence and wake/recovery | Exact request/turn and projection/item joins | Native attribution fields when recorded |
12
+ | Product text selection and semantic support | Independent evidence coverage | Genuine Contribution/ExecutionProvenance history |
13
+ | Rendering and product acceptance | Optional bounded history read composition | Native producer semantics |
14
+
15
+ No registry, RPC, timers, scanner, subscription, storage, or background owner is
16
+ introduced. This is request-scoped normalization; the caller owns any durable
17
+ work resumed after restart. A wake is never source evidence.
18
+
19
+ ## Public API
20
+
21
+ ```ts
22
+ import { createNativeSourceAdapter } from '@phosphorco/bb-identity/native';
23
+
24
+ const adapter = createNativeSourceAdapter({ history: binding.server.history });
25
+ // These are actual public SDK return values captured by the caller's history reader.
26
+ const events = await bb.sdk.threads.events.list({ threadId, order: 'asc', limit: '200' });
27
+ const timeline = await bb.sdk.threads.timeline({
28
+ threadId, includeNestedRows: 'true', deferContent: 'false',
29
+ summaryOnly: 'false', segmentLimit: '200',
30
+ });
31
+ // The caller must freeze/fence matching retained snapshots before admission.
32
+ const result = adapter.resolve({
33
+ source: {
34
+ kind: 'assistant-terminal', threadId, terminalEventId,
35
+ scope: { turnId },
36
+ },
37
+ events, timeline,
38
+ });
39
+ if (result.ok) {
40
+ const nativeEvidence = result.value;
41
+ // Optional: actual existing history reads, retaining their exact outcomes.
42
+ const enriched = await adapter.enrich(nativeEvidence, { signal });
43
+ }
44
+ ```
45
+
46
+ The example targets the inspected fork SDK
47
+ `0.6.52+phosphor.975e38f02f1a.sdk.12eb78c20820`. Timeline flags such as
48
+ `deferContent` are host-specific; the public registry SDK 0.6.31 does not
49
+ declare that flag. Its baseline witness calls `threads.timeline({threadId})`
50
+ using its own public contract. Do not add undeclared flags to a consumer.
51
+ The example illustrates public calls, not an atomic snapshot transaction.
52
+ Concurrent rewrites, history pagination, and changed projection snapshots need a
53
+ caller-owned fence. The adapter cannot authenticate the origin or revision of
54
+ injected snapshots. Do not combine an old event page and a new timeline page and
55
+ claim they describe one frozen retained history.
56
+
57
+ References are opaque native IDs:
58
+
59
+ - `request-group`: threadId, eventId, requestId, groupIndex (zero based).
60
+ - `event`: threadId, eventId; currently normalizes `client/turn/requested`.
61
+ Multiple groups require an explicit `request-group`; other event types yield
62
+ unsupported source coverage.
63
+ - `assistant-item`: threadId, itemId, terminalEventId, scope.turnId.
64
+ - `assistant-terminal`: threadId, terminalEventId, scope.turnId.
65
+
66
+ Terminal references contain no attemptId. A terminal event must be
67
+ `turn/completed` with the exact scope.turnId. Its status remains completed,
68
+ failed, or interrupted. Two terminals in one turn remain distinct sources.
69
+ An attempt ID appears only inside an actual optional history response.
70
+
71
+ ## Source and identity semantics
72
+
73
+ A request group uses its exact `inputGroups[groupIndex]`, falling back to the
74
+ single native input only when groups were not recorded. Authors and editors
75
+ are accepted only from group-aligned native arrays. Missing/misaligned arrays
76
+ are explicit unknown coverage; the adapter never borrows another group's author.
77
+ Text includes visible text parts in order, separated by newlines. Non-text
78
+ attachments are not expanded, and agent-only text is excluded with an explicit
79
+ coverage reason. Request-wide native mentioned targets retain their structured
80
+ provider source and are never converted to per-group authorship.
81
+
82
+ `origin` preserves native dispatch initiator user/agent/system. `user` means the
83
+ native initiator value; it does not assert a person. Native structured author,
84
+ latest editor, mentions, and dispatch senderThreadId are independent. A machine
85
+ author can accompany a user initiator. No text envelope, participant roster,
86
+ first/latest author, display name, or parent thread supplies missing identity.
87
+
88
+ Assistant output has origin assistant, author/editor null, and no inherited
89
+ mentions. Its accepted inputs identify execution causes, never output authors.
90
+ `turn/input/accepted.data.clientRequestId` must join exactly one preceding
91
+ request event to the accepted event's scope.turnId. For a selected request
92
+ source, that exact event must be the unique preceding candidate; a later event
93
+ reusing its request ID cannot inherit an earlier event's acceptance. Many requests and groups
94
+ can share a turn. Supplied windows cannot prove all input causes were retained,
95
+ so execution coverage remains partial even when every included join succeeds.
96
+
97
+ The native source contract does not establish initiating person, carried person,
98
+ agentId, or personal delegation. Those fields remain explicitly unknown/null.
99
+ Optional genuine history may contain an integration assertion or execution
100
+ correlation; that assertion retains its original basis and does not silently
101
+ populate stronger native lineage fields.
102
+
103
+ ## Recorded external people
104
+
105
+ `NativeEvent`, `NativeActor` and `NativeMention` retain their actual public SDK
106
+ meanings. `NativeSourceActor = NativeActor | ExternalPersonSnapshotV1` is a
107
+ separate package-owned recorded-source capability. `NativeSourceEvent` derives
108
+ all event fields from the SDK and overlays only the request's optional,
109
+ group-parallel `p6rAuthors`/`p6rEditors` arrays with that actor type. Ordinary SDK
110
+ event arrays remain assignable to `NativeSourceSnapshot.events`.
111
+
112
+ The adapter validates recorded external people through the existing public
113
+ `externalPersonSnapshotCodec`. It preserves `evidence: 'integration-asserted'`,
114
+ identity and presentation; it never promotes that evidence to provider-verified.
115
+ Author and latest editor remain independently indexed by group. Invalid asserted
116
+ people return invalid-input; missing or misaligned arrays remain unknown.
117
+
118
+ For typed recorded input, decode the actor with that codec and use the successful
119
+ value in an event satisfying `NativeSourceEvent`. This explicit source input is
120
+ not an augmentation of the SDK. The inspected fork's host source admits such
121
+ assertions, while its consumed SDK version still excludes them; assigning the
122
+ richer event to that stale `NativeEvent` is a type error. Public SDK 0.6.31 lacks
123
+ the attribution properties entirely. The package seam does not establish that
124
+ any baseline or live producer records them. Actual producer and adopter evidence
125
+ remain separate gates. Assistant authorship and personal lineage remain unchanged.
126
+
127
+ ## Retained terminal output join
128
+
129
+ The adapter uses the supported public `threads.timeline` projection. It does
130
+ not reconstruct visible text by concatenating transient deltas, nor select only
131
+ completed items. It accepts assistant conversation rows with the exact native
132
+ thread and turn and a source range wholly through the selected terminal.
133
+ Both range endpoints must join supplied text-bearing agentMessage delta or
134
+ completed agentMessage events with the same native item ID, recorded parentToolCallId,
135
+ and turn. IDs, nonempty endpoint text and optional commentary/final_answer phase
136
+ are validated before use. Omitted/nonstring request text and invalid visibility
137
+ are rejected rather than coerced. Missing/invalid row IDs withhold those rows.
138
+ Every returned text row preserves its recorded parentToolCallId; null means the
139
+ public field was absent, not recovered root delegation. An assistant-item selector
140
+ matching several recorded parent instances is ambiguous and supplies no text. The
141
+ projection's row ID is retained, never parsed for hidden identity. Per-text
142
+ source IDs, sequence range, item ID, and available completed-item phase survive.
143
+ Deltas without recorded phase keep phase null.
144
+
145
+ This permits retained visible commentary and final output, including text flushed
146
+ at failed/interrupted terminals without item/completed. Public timeline text is
147
+ the authority; the adapter does not invent projection behavior. Empty text and
148
+ non-assistant/tool rows contribute no text. Cross-terminal ranges, missing
149
+ endpoints, or different item IDs cannot supply text. Plan/reasoning rows are not
150
+ accepted as agentMessage output. Missing/deferred nested rows and incomplete
151
+ pages disclose coverage gaps. A bounded empty page never proves a turn had no
152
+ retained assistant text. The caller decides whether retained text is substantive.
153
+
154
+ Sequence endpoints prove the structural join within supplied matching snapshots.
155
+ They do not prove producer stability, identical revisions across independent
156
+ reads, or that this package observed a real interrupted producer.
157
+
158
+ ## Independent coverage and optional history
159
+
160
+ `coverage.source` describes admitted text and the selected source within the
161
+ snapshot. It is separate from attribution, execution and personalLineage.
162
+ `known` source coverage does not imply complete thread traversal or identity.
163
+ Native facts do not change `binding.server.history` outcomes.
164
+
165
+ `enrich` optionally calls the existing history reader using native-event queries
166
+ for request sources or assistant input requests. It retains each exact Result,
167
+ including pending, unavailable, errors, partial pages and continuation cursors.
168
+ Attempts are queried only via genuinely returned same-thread Contribution refs.
169
+ Responses stay under `history` with their query basis; they are not relabeled as
170
+ source authors or resolved assistant executions. In particular, a returned
171
+ attempt with a different correlation turn is not an execution of this assistant
172
+ source. Consumers must match genuine correlation.threadId/turnId and contribution
173
+ causes before using optional attempts. No pages are silently followed, unknown
174
+ results retried, or history coverage upgraded. Existing readers may throw
175
+ programmer errors according to the existing Result contract.
176
+
177
+ `NATIVE_SOURCE_LIMITS` publishes 2000 events, 2000 nested projection rows, 2 MiB
178
+ UTF-8 serialized input, 8 nested levels, 16 total enrichment calls and 256-character
179
+ native identifiers, plus 64 levels for the complete plain-data representation.
180
+ A bounded stable copy reads own data descriptors, including non-enumerable data,
181
+ and rejects accessors, callable serialization hooks, cycles and exotic prototypes.
182
+ It bounds consumed UTF-8 data with structural overhead, then the UTF-8 JSON
183
+ serialization of that same copied representation (including escape expansion).
184
+ Normalization consumes only the checked copy; no original getters/toJSON run.
185
+ Oversized/malformed input returns invalid-input. Reads are
186
+ cancellable between operations and use the reader's supplied cancellation
187
+ semantics. No feature work is launched after return.
188
+
189
+ ## Compatibility and proof
190
+
191
+ The new entry imports SDK types only; its emitted runtime imports no SDK or
192
+ React. Existing root, model, client, server and other exports/peer ranges retain
193
+ their previous contract. The current declaration witness uses installed SDK
194
+ `0.6.52+phosphor.975e38f02f1a.sdk.12eb78c20820`, including optional native
195
+ p6rAuthors/p6rEditors/p6rMentionedTargets. NativeActor and NativeMention derive
196
+ conditionally from the SDK's public optional properties; when absent (as in public
197
+ SDK 0.6.31), their member types are never. Snapshots without recorded attribution
198
+ retain null authors/editors and empty mentions; user dispatch never supplies a person.
199
+ No fork property or protocol is copied to emulate a missing capability. Public
200
+ 0.6.31 all-entry declarations and its minimal native calls are a separate actual-peer
201
+ conformance job, without skipLibCheck; missing upstream declaration dependencies
202
+ are resolved by that fixture separately. Existing peers and default exports
203
+ remain unchanged. Older hosts can keep existing entries;
204
+ using `/native` requires the public snapshot types/capabilities exercised by the
205
+ adopter. Missing optional attribution on a host stays unknown.
206
+
207
+ `@phosphorco/bb-identity/native/testing` exports
208
+ `defineNativeSourceConformance({test, resolve, cases})`. Pass the adopter's actual
209
+ source path and independently authored semantic oracles. The kit refuses empty
210
+ case lists; it does not substitute a fake adapter or assert live coverage.
211
+
212
+ Package source fixtures cover human/machine/agent dispatch, author/editor/mention
213
+ separation, multiple requests/groups sharing a turn, commentary/final and
214
+ failed/interrupted delta projections, exact joins and refusals, missing lineage,
215
+ bounds, and actual optional reader outcomes. These are synthetic SDK and recorded-source snapshots, including codec-validated
216
+ external assertions; none establishes a live producer fact.
217
+ Public declarations, emitted entries and a scratch packed consumer are separate
218
+ package proofs. Registry publication, exact-version consumer adoption,
219
+ producer/live fixtures, rewrite/outage/restart and host acceptance remain
220
+ separate gates. Source version 0.4.0 is a candidate; installed org consumers on
221
+ 0.3.1 do not gain this API until a separately authorized registry release and
222
+ exact-version adoption.
package/README.md CHANGED
@@ -106,6 +106,20 @@ Notifications as a third consumer. Offline fixtures establish specific safety
106
106
  properties but do not replace those migrations or the master plan's
107
107
  upstream → fork → upstream → fork authored-session compatibility proof.
108
108
 
109
+ ## Native source evidence (0.4.0 candidate)
110
+
111
+ The additive `/native` entry normalizes retained public SDK event/group/item/terminal
112
+ snapshots into evidence distinct from Contribution history. It preserves independent
113
+ source, attribution, execution and lineage coverage. See [NATIVE-SOURCES.md](NATIVE-SOURCES.md)
114
+ for API, ownership, public joins, bounds and proof limits; `/native/testing` supplies
115
+ the caller-driven semantic conformance kit. This source candidate is not evidence
116
+ of registry publication or installed consumer adoption.
117
+
118
+ The combined 0.4.0 source candidate also adds opt-in `/editing` and explicit React
119
+ hooks for continued local typing across unknown publication, conflicts and backup
120
+ failures. See [EDITING.md](EDITING.md) for the independent editing/v1 contract and
121
+ proof limits; existing state protocol and default behavior remain unchanged.
122
+
109
123
  ## Entry points
110
124
 
111
125
  | Import suffix | Runtime/declaration status | Responsibility |