@@ -468,10 +468,6 @@ function followPointer<S extends BaseMemoryAddress>(
468468 const target : BaseMemoryAddress = ( link . id !== undefined )
469469 ? { id : link . id , type : "application/json" }
470470 : doc . address ;
471- const targetDoc = {
472- address : doc . address ,
473- value : doc . value ,
474- } ;
475471 if ( selector !== undefined ) {
476472 // We'll need to re-root the selector for the target doc
477473 // Remove the portions of doc.path from selector.path, limiting schema if
@@ -492,43 +488,47 @@ function followPointer<S extends BaseMemoryAddress>(
492488 // Cycle detected - treat this as notFound to avoid traversal
493489 return [ notFound ( doc . address ) , selector ] ;
494490 }
491+ // We may access portions of the doc outside what we have in our doc
492+ // attestation, so reload the top level doc from the manager.
493+ const valueEntry = manager . load ( target ) ;
494+ if ( valueEntry === null ) {
495+ return [ notFound ( doc . address ) , selector ] ;
496+ }
495497 if ( link . id !== undefined ) {
496- // We have a reference to a different cell , so track the dependency
498+ // We have a reference to a different doc , so track the dependency
497499 // and update our targetDoc
498- const valueEntry = manager . load ( target ) ;
499- if ( valueEntry === null ) {
500- return [ notFound ( doc . address ) , selector ] ;
501- }
502500 if ( schemaTracker !== undefined && selector !== undefined ) {
503501 schemaTracker . add ( manager . toKey ( target ) , selector ) ;
504502 }
505- // If the object we're pointing to is a retracted fact, just return undefined.
506- // We can't do a better match, but we do want to include the result so we watch this doc
507- if ( valueEntry . value === undefined ) {
508- return [ notFound ( target ) , selector ] ;
503+ // Load the sources/recipes recursively unless we're a retracted fact.
504+ if ( valueEntry . value !== undefined ) {
505+ loadSource (
506+ manager ,
507+ valueEntry ,
508+ new Set < string > ( ) ,
509+ schemaTracker ,
510+ ) ;
509511 }
510- // Otherwise, we can continue with the target.
511- // an assertion fact.is will be an object with a value property, and
512- // that's what our schema is relative to.
513- targetDoc . address = { ...target , path : [ "value" ] } ;
514- targetDoc . value = ( valueEntry . value as Immutable < JSONObject > ) [ "value" ] ;
515- // Load any sources (recursively) if they exist and any linked recipes
516- loadSource (
517- manager ,
518- valueEntry ,
519- new Set < string > ( ) ,
520- schemaTracker ,
521- ) ;
522512 }
513+ // If the object we're pointing to is a retracted fact, just return undefined.
514+ // We can't do a better match, but we do want to include the result so we watch this doc
515+ if ( valueEntry . value === undefined ) {
516+ return [ notFound ( target ) , selector ] ;
517+ }
518+ // We can continue with the target, but provide the top level target doc
519+ // to getAtPath.
520+ // An assertion fact.is will be an object with a value property, and
521+ // that's what our schema is relative to, so we'll grab the value part.
522+ const targetDoc = {
523+ address : { ...target , path : [ "value" ] } ,
524+ value : ( valueEntry . value as Immutable < JSONObject > ) [ "value" ] ,
525+ } ;
523526
524527 // We've loaded the linked doc, so walk the path to get to the right part of that doc (or whatever doc that path leads to),
525528 // then the provided path from the arguments.
526529 return getAtPath (
527530 manager ,
528- {
529- address : targetDoc . address ,
530- value : targetDoc . value ,
531- } ,
531+ targetDoc ,
532532 [ ...link . path , ...path ] as string [ ] ,
533533 tracker ,
534534 schemaTracker ,
0 commit comments