@phosphorco/bb-cross-references 0.1.1 → 0.3.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/CONTRACT.md CHANGED
@@ -107,3 +107,161 @@ so the conformance kit uses the same production module instance. Do not commit
107
107
  Package self-tests, adopter source conformance, UI/host proof and live composition
108
108
  are separate evidence levels. Rendering, dependency locks, publication and live
109
109
  proof are owned by the coordinating lane.
110
+
111
+ ## Recognition identity adapter (package 0.2.0; wire v1 unchanged)
112
+
113
+ Ownership: the recognition supplier owns its provider/id grammar; this package
114
+ owns the pure `recognitionIdentity` codec; the consumer owns existing-thread
115
+ verification, source eligibility, authored locators, persistence and scheduling.
116
+ `bb.thread` requires an explicit verified existing `{id,projectId,deletedAt?}`
117
+ and maps to existing `bb` project/thread keys. `bb.url` must pass safe canonical
118
+ HTTP(S) URL policy, including credential/sensitive-parameter rejection. Other
119
+ identities map to `recognition` keys `{provider,identity}`, where identity is
120
+ SHA-256 of recognition `canonicalJson([provider,id])`. `kind` is advisory and
121
+ excluded. This hashes, rather than truncates, recognition's bounded opaque id.
122
+ `recognitionIdentityRecord` preserves the complete provider/id in at most
123
+ 16,384 UTF-8 bytes for a consumer-owned mapping. Authored href/span/URL remain
124
+ separate; no alias/redirect/host equivalence is inferred.
125
+
126
+ No v1 input, output, projection duplicate rule or resource-containment meaning
127
+ changes. Package 0.2.0 adds no evidence RPC, storage or lifecycle code. Source
128
+ codec tests import the emitted public entry; they do not prove live adoption.
129
+
130
+ ### Verified file identity codec (unreleased 0.2.0)
131
+
132
+ `recognitionIdentity` requires `bb.file` callers to use `verifiedFileIdentity`
133
+ with a consumer-verified `VerifiedFileTargetSchema` value:
134
+ `{kind:'workspace',environmentId,path}` or `{kind:'thread-storage',threadId,path}`.
135
+ The graph is provider `recognition`, keys `{provider:'bb.file',identity}`, where
136
+ identity is SHA-256 of recognition `canonicalJson(['bb.file',kind,ownerId,path])`;
137
+ ownerId is environmentId for workspace and threadId for storage. No truncation.
138
+ `verifiedFileIdentityRecord` stores `{provider:'bb.file',verifiedFile:...}` in the
139
+ existing 16,384-byte mapping bound. It never stores a source-thread lexical ID
140
+ as the shared resource mapping. Original lexical identities remain per occurrence.
141
+
142
+ Paths are canonical slash-separated relative paths: reject empty/dot/parent
143
+ segments, leading slash, backslash, colon, percent, query/hash and controls.
144
+ Owner IDs use the existing BB ID alphabet/bound. Preserve exact Unicode/case and
145
+ authored symlink alias; do not normalize Unicode, case-fold or substitute realpath.
146
+ A leading `./` is already removed by the existing native recognition grammar.
147
+ The package validates/encodes data only; existence, regular-file and realpath
148
+ containment verification belongs to the consumer and shares its source deadline.
149
+
150
+ Workspace conversations in the same environment/path coalesce; different
151
+ environments, storage owners and alias paths stay distinct. Metadata preserves
152
+ future navigation/codec inputs, without claiming installation-local IDs are
153
+ portable. Phase-2 query and phase-3 Brief production must use this same codec and
154
+ frame rule. This helper adds no public wire method or v1 projection metadata
155
+ requirement; existing v1 producers remain unchanged.
156
+
157
+ ## Wire V2: stored mention evidence (0.3.0 reservation)
158
+
159
+ V1 methods, strict schemas and projection semantics remain unchanged. A host
160
+ advertises `[1,2]` at `crossReferences.describe`; the separate explicit V2 client
161
+ requires advertised2 and never substitutes a V1 read. Root remains data/pure;
162
+ `/bb` provides `createCrossReferencesV2Client` and `registerCrossReferencesV2`;
163
+ `/testing` provides read-only `runCrossReferencesV2Conformance` against actual
164
+ registered handlers and caller-prepared fixtures. No registry publication is
165
+ implied by this source reservation.
166
+
167
+ `crossReferencesV2ListMentions` input is recursively strict:
168
+
169
+ ```ts
170
+ {version:2,query:
171
+ | {kind:'resource',target:ResourceIdentity,relation:'self'|'github-pr-family'}
172
+ | {kind:'authored-url',href:string},
173
+ source?:ResourceIdentity,producerPluginId?:string,pageSize?:number,
174
+ cursor?:string,ifSnapshot?:string}
175
+ ```
176
+
177
+ Page size defaults25/max100; cursor<=4096 UTF8 bytes and conditional64hex are
178
+ exclusive. Source is exact and a missing source gives an empty result. Existing
179
+ V1 exact-key lookup is unchanged; general containment is deferred. Current GitHub
180
+ recognition collapses PR root/comment/review destinations into ONE primary root
181
+ identity, selected directly with no descendant enumeration ceiling. There are no
182
+ alias claims or derived posting graph. Supported explicit safe GitHub URL codec
183
+ `githubLookup` is exported for every consumer: owner/repo lowercase and positive
184
+ safe number map through the SAME recognition identity helper. A `/pull/N` route
185
+ has PR authority; issue URLs select self. Bare repo#N/opaque hashes alone do not
186
+ prove PR kind. Original descendant URL remains evidence, never root navigation.
187
+ Future separately identified descendants need a separately documented codec.
188
+
189
+ A page contains exact CURRENT retained matching location counts, confirmed and
190
+ unconfirmed counts, producerClaims, DISTINCT indexedSources,
191
+ **claimsWithoutLocations**, and excerptUnavailable. Repeated locations do not
192
+ inflate primary claims; legacy/other producers without matching locations take
193
+ one ordinary row slot. Counts describe known active producer/source/target facts,
194
+ not all-time totals or complete source discovery. In a literal authored URL query,
195
+ primary URL identity claims can appear with `matchBasis:'primary-url-identity'`
196
+ without asserting original spelling; unknown typed history is coverage only.
197
+ Claim reasons are `legacy`, `producer-no-evidence`, `not-yet-collected`.
198
+
199
+ Occurrence rows keep the complete original UTF16 span, actual user/assistant role,
200
+ threadId/messageId/messageSeq/anchorSeq, body-derived sourceContentRevision,
201
+ occurrenceKey, evidenceRevision, source/target/producer, original messageCreatedAt,
202
+ observedAt, original recognition provenance, URL-proof state and confirmation.
203
+ Cap state is uncapped/capped/unknown with retained limit100/null and separate
204
+ sourceHistoryUnknown. Absent producer evidence never means uncapped.
205
+
206
+ Ready excerpts are contiguous slices of admitted original text, <=320 Unicode
207
+ code points AND1280 UTF8 bytes, with original sourceSpan, relative nonempty
208
+ matchSpan, context/match clipping flags and codecVersion1. No sentence/paragraph
209
+ can bridge excluded code, inline code, raw HTML, standalone/linked image intervals.
210
+ No reconstruction of offsets from rendered Markdown. Ordinary/reference link
211
+ context remains eligible even though recognition excludes it from the prose pass.
212
+ An overlong indivisible matching word gives unavailable/indivisible-word with full
213
+ location/navigation retained; no eligible context gives no-eligible-context.
214
+ Absent valid child gives not-materialized. A missing excerpt remains an occurrence.
215
+ Original-slice proof is established while collection/commit has the body;
216
+ persisted reads validate stored text/ranges/revision/codec without fetching it.
217
+
218
+ Literal href lookup compares the original SAFE captured destination string,
219
+ including query/fragment/case/spelling; no redirect, canonical alias or typed-hash
220
+ reconstruction. Historical URL state is unknown until an ordinary existing scan
221
+ observes original spelling. No reader-triggered enqueue or re-observation campaign.
222
+ Unknown active locations under the same source/producer filters contribute to
223
+ independent authoredUrlCoverage, including outside literal matched rows.
224
+
225
+ Responses are page(snapshot,items,counts,coverage,nextCursor), not-modified
226
+ (snapshot,**current coverage**), restart(snapshot-changed,snapshot), or unavailable
227
+ (index-warming/read-budget,retryable). Direct storage needs no warming bootstrap.
228
+ Semantic tokens bind query/filter/page size, relevant active graph revision/payload/
229
+ presentation and evidence digest/revision/binding. They exclude observation-only
230
+ clocks and unrelated filtered-out sources/producers; a producer/source evidence
231
+ change may invalidate its other matching queries. The independent URL-unknown
232
+ watermark updates coverage without resetting unchanged item cursors.
233
+
234
+ Order is messageCreatedAt descending, binary canonical source digest, producer,
235
+ target digest, item kind, message ID, original span start, occurrence key; stable
236
+ claim sentinel time0. Cursor binds the complete query and semantic snapshot;
237
+ mismatch restarts instead of mixing pages. The one shared1MiB canonical JSON
238
+ UTF8 budget covers rows+counts+coverage+cursor; cursor advances only through the
239
+ last emitted row. Individual row ceiling128KiB. Output unknown fields share that
240
+ budget before tolerant decoding; parsed transport cannot bound pre-parse memory.
241
+ Nested evolving outputs tolerate additive fields; unknown item/locator/excerpt
242
+ enums safely preserve an unsupported item slot, required known fields still
243
+ validate. Reasons are <=32 safe codes of <=128 UTF8 bytes, with honest clipping/
244
+ unknown mapping; no raw errors. Direct counts/token/sort may scan all relevant
245
+ facts. Cooperative server checks use2s and return read-budget on exhaustion;
246
+ synchronous SQLite cannot be preempted by a JS timer. Client call budget<=5s.
247
+
248
+ `crossReferencesV2ResolveLookup` is mandatory for pasted referents:
249
+ `{version:2,text,mode:'recognize'|'exact-url',context?}`. Text1..4096 UTF16 units /
250
+ <=16384 UTF8 bytes; complete input<=64KiB; context is the strict public recognition
251
+ subset with <=16 safe unpositioned links and no caller attribution. Options<=8
252
+ contain query,label<=256 UTF8 bytes,inputSpan,basis(supplier/native/stored-codec),
253
+ reasons; overall state ready/ambiguous/unrecognized/incomplete. Exact-url mode stays
254
+ literal. Recognition uses the existing service-owned supplier snapshot, shared
255
+ arbitration and labelled pure codec fallback; <=8 suppliers share a1500ms stage.
256
+ Native thread verification may use bounded SDK metadata reads. No discovery per
257
+ reader, card/body/timeline/filesystem/network resolve, collection enqueue or graph
258
+ write. Lexical file text cannot invent verified file identity. One failed supplier
259
+ preserves healthy/native results with incompleteness disclosed.
260
+
261
+ V2 invalidation channel `cross-references-mentions-v2-changed` carries version2,
262
+ producerPluginId,sourceIdentityDigest,graphRevision,evidenceRevision(nullable),
263
+ <=512 affectedIdentityDigests,scopeListClipped. Publish once after a changed
264
+ committed source; old strict V1 signals are unchanged. Clipped/coarse wakes can
265
+ refresh mounted literal-URL coverage conditionally. No idle polling/factory SDK
266
+ subscription/new worker. Later consumers share lazy mounted queries, cancel on
267
+ teardown and retain rows/cursors when only coverage changes.
package/README.md CHANGED
@@ -40,3 +40,32 @@ client apply/get/backlinks acceptance and reports source conformance.
40
40
  Run `npm run build`, `npm run test`, `npm run typecheck` in the workspace.
41
41
  See [CONTRACT.md](./CONTRACT.md) for exports, bounds, wire compatibility,
42
42
  legacy describe fallback and proof limitations.
43
+
44
+ Package 0.2.0 exports `recognitionIdentity` and `recognitionIdentityRecord` for
45
+ recognition-backed consumers. Thread verification stays with the consumer;
46
+ typed opaque IDs use a bounded SHA-256 identity and a separate raw mapping.
47
+ See the [contract](CONTRACT.md#recognition-identity-adapter-package-020-wire-v1-unchanged).
48
+
49
+ Verified native files use `verifiedFileIdentity` and `verifiedFileIdentityRecord`
50
+ with `VerifiedFileTargetSchema`; the generic adapter rejects unverified `bb.file`.
51
+ Workspace owner is environment ID; storage owner is the owning thread ID.
52
+ Full frame/path survives separately from the bounded hashed graph key and
53
+ original lexical source IDs remain occurrence provenance. See the contract for
54
+ exact canonical tuple/path rules; consumers own bounded existence/containment.
55
+
56
+ ### Stored mention evidence, V2
57
+
58
+ The 0.3.0 contract reservation adds pure evidence schemas and the explicit
59
+ `createCrossReferencesV2Client(sdk, pluginId)` in `/bb`. Call `describe()` and use
60
+ `listMentions({version:2,query:{kind:'resource',target,relation:'self'}})` or literal
61
+ `{kind:'authored-url',href}`. `resolveLookup({version:2,text,mode:'recognize'})`
62
+ normalizes pasted PR URLs through shared recognition/pure labelled codec without
63
+ fetching cards or writing claims. `githubLookup` is the shared explicit GitHub
64
+ URL codec; issue/unknown-number input cannot silently become PR authority.
65
+
66
+ Pages carry bounded original-location evidence, exact counts for retained active
67
+ claims, clipping/cap/legacy/unknown-URL coverage and semantic cursors. Conditional
68
+ not-modified includes current coverage. Existing V1 clients stay unchanged. See
69
+ CONTRACT.md for strict inputs, tolerant bounded outputs, direct-query/time limits,
70
+ no-word-cut behavior and read-only conformance. Package source tests and private
71
+ emission are distinct from a published registry consumer or live host proof.