@phosphorco/bb-cross-references 0.1.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/CONTRACT.md CHANGED
@@ -107,3 +107,266 @@ 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.
268
+
269
+ ## Producer ingress reservation (0.4, wire family1)
270
+
271
+ The separately negotiated producer family has four methods:
272
+ `crossReferencesProducer.describe`, `crossReferencesProducerV1GetState`,
273
+ `crossReferencesProducerV1Apply`, and `crossReferencesProducerV1ReportStatus`.
274
+ Use the exported schemas/client/registration helpers. Inputs are strict; outputs
275
+ admit bounded additive object fields. The existing V1 graph methods, digests,
276
+ claim uniqueness and counts retain their meaning. These source additions do not
277
+ establish registry availability of0.4 or compatibility with an older advertised SDK.
278
+
279
+ The first source kind is `thread-brief`, producer `thread-brief`, fixed verified
280
+ thread-storage `BRIEF.md`. One complete replacement contains the V1 projection,
281
+ its full primary evidence and an independently computed evidence digest. Existing
282
+ V1 resource/presentation validation remains authoritative. Limits are1MiB total,
283
+ 256 targets/256KiB V1 payload,512 locations/100 per target and256UTF8 bytes per
284
+ named heading. Presentation limits remain256/1024/2048UTF8 bytes and4096 JSON
285
+ bytes. The preflight returns the actual closed hit codes; it never truncates,
286
+ splits, silently withholds an overlong safe presentation or partially installs.
287
+
288
+ Let G be current graph revision and S retained blocked attempt; high-water is
289
+ max(G,S). A prospective producer Apply must exceed that high-water and satisfy
290
+ unchanged graph CAS. Exact current bound graph/evidence replay is nonmutating,
291
+ ignores stale CAS like V1 duplicate/equal, and exposes rather than clears newer
292
+ status. Same graph payload with different/unbound evidence cannot graft evidence.
293
+ `currentRevision` always means G. Apply commits graph, evidence, mappings and
294
+ superseded status deletion atomically, before any invalidation. Status-only
295
+ writes create no graph resources/claims/evidence, including a first-ever source.
296
+
297
+ ReportStatus precedence is exact stored attempt+digest replay; nonreplay<=G
298
+ stale; lower prior status stale/same attempt different content conflict; then
299
+ expectedRevision graph CAS. Its digest excludes attempt/CAS/clocks. Unknown
300
+ write outcomes require exact GetState reconciliation, never an automatic retry.
301
+ Ordinary V1 writes remain compatible and unfenced by S: retained evidence can
302
+ become unconfirmed and retained status can become superseded-by-graph. There
303
+ is one prospective V1 allocator, not a separate evidence/status revision clock.
304
+
305
+ Blocked states are `over-limit` (actual hit codes) and `identity-unrepresentable`
306
+ (fixed identity codes and any actual limit hits). UI text is exactly “brief
307
+ references not updated: over limit” or “brief references not updated: identity
308
+ cannot be represented safely”. Neither status transports raw errors or metadata.
309
+
310
+ ### Display safety and original locations
311
+
312
+ `classifyBriefDisplayTextV1` and `classifyBriefDisplayFieldsV1` are one pure bounded
313
+ lexical display-policy implementation, independent of recognition and Markdown.
314
+ They reuse existing safe URL/credential parameter policy, inspect raw plus at
315
+ most three strict security decode views, and return safe, unsafe or unclassified
316
+ with fixed reasons/work counters. URL userinfo, query/fragment parameters and
317
+ query-shaped sensitive-name assignments are covered. Percent UTF8, textual JSON
318
+ escapes and the closed numeric/ASCII HTML entity set are security views only.
319
+ Unknown, ambiguous, deep, malformed, control or budget-limited data is never safe.
320
+ No host/provider/resource discovery/parser call or cross-acceptance cache exists.
321
+ Bulk work admits required identities first, memoizes exact final values across
322
+ roles, and has fixed8192-field/4096-distinct/2MiB-original/8MiB-work limits.
323
+
324
+ Explicit B slots distinguish exact safe data, absent data and withheld digest plus
325
+ fixed generic display. Intro is null; named-empty is still a named heading.
326
+ Withheld digest is SHA256 of canonical `['brief-withheld',1,role,originalKnownValue]`.
327
+ Raw withheld values are never transported/stored. CR independently classifies
328
+ received safe/available fields; it cannot attest unseen originals behind digests.
329
+ Unsafe required identity rejects the whole revision. Optional unsafe metadata
330
+ keeps safe primary claims/counts/locations with explicit withholding; withheld
331
+ codec metadata supplies no new raw mapping/family authority. Exact authored URL
332
+ proof is separate from canonical identity and uses only safe original spelling.
333
+ Withheld/unknown URL proof contributes conservative coverage, never reconstruction.
334
+
335
+ Brief V2 rows are `brief-occurrence` with original ref-N, raw SHA/frame/bodyBase,
336
+ B section, original line/span and producer-attested/retained-unconfirmed binding.
337
+ They have no invented conversation role/messageSeq/time, and excerpts are only
338
+ unavailable/not-materialized. Direct active full producer/source/target joins,
339
+ query-relevant semantic tokens, keysets/counts/shared1MiB response admission and
340
+ independent coverage-on-not-modified remain. No derived postings or bootstrap.
341
+
342
+ ### Navigation provider seam
343
+
344
+ `registerBriefNavigation` and `createBriefNavigationClient` negotiate the separate
345
+ Thread Brief provider. A strict request pins the fixed file, raw revision, full
346
+ UTF16/BOM/bodyBase/native-line frame and explicit section/original line. A ready
347
+ proof must match all of them and the same complete accepted revision. Otherwise
348
+ open only fixed BRIEF top with a bounded note. FileLink alone is not freshness.
349
+
350
+ The TB adopter must implement one fresh bounded contained RAW read/hash per
351
+ explicit primary click, bypass stat/idle caches, and reuse accepted section/native
352
+ facts only after source/raw/frame equality. No hidden parse/recognition/model
353
+ construction or newer-heading relocation. Intro needs explicit same-pass intro
354
+ facts. Source/service generation guards are independent of viewer teardown. BOM
355
+ and LF/CRLF/loneCR mapping require actual adopter proof; unknown means top.
356
+
357
+ One mounted CR surface owns pending proof and dispatch entitlement across all
358
+ rows. New modifier/defaultPrevented/download/nonprimary/aux/context-menu intent
359
+ cancels prior proof before native top dispatch, without interception/new read.
360
+ Identical in-flight primary shares one read AND open. Primary prevents default
361
+ synchronously; current validated continuation opens once, with no automatic retry.
362
+ The public provider/accessor repairs and exact published0.4 TB adoption remain
363
+ separate work; source schemas do not claim that provider is already installed.
364
+
365
+ PR-family membership requires authority on each admitted record, recomputed to
366
+ the same canonical target. A PR sibling never promotes issue/kindless/withheld
367
+ siblings. An own available typed descriptor can support the real claim sentinel
368
+ when no admitted family location exists. Resource-level kindless mappings are
369
+ insufficient. Missing authority is independently scoped partial coverage using
370
+ `pr-family-authority-unknown`, including an all-unknown empty result; known issue
371
+ alone is excluded without fabricated unknown. Exact-self/literal semantics stay
372
+ unchanged, and no parser/secondary graph edge/target enumeration is added.
package/README.md CHANGED
@@ -40,3 +40,44 @@ 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.
72
+
73
+ The unreleased0.4 producer additions are exported through existing root, `/bb`
74
+ and `/testing` entries. Use `createCrossReferencesProducerClient` for complete
75
+ Brief graph/evidence replacement and status/readback, and
76
+ `runCrossReferencesProducerConformance` against an adopter's real registered
77
+ handlers. `runBriefNavigationConformance` requires an actual accepted-reader
78
+ fixture; it never supplies a fake freshness proof. Explicitly compile
79
+ `test/public-producer-types.mts`; ordinary test discovery does not compile it.
80
+ `tools/packed-producer-consumer.mjs` checks actual independent installed native
81
+ ESM imports and physical roots; resolver fixtures are not package/registry proof.
82
+ See CONTRACT.md for display withholding, bounds, revision fencing and the still
83
+ separate TB raw-reader/public navigation adoption duties.