Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

However, it is unlikely that we can simply grant data providers the permission to assign AR as they see fit due to a conflicts of interest. Funding agencies are interested in sharing the data they fund as broadly as is ethically possible to maximize the return-on-investment. The researchers that receive the founding are typically only interested in sharing their data after they have extract all possible insights from it. It is common for funders to add sharing conditions to research they fund to encourage researcher to share. According to our governance team, it is typical for a researcher to select “true” for each question of the DUO questionnaire, in an effort to lock down their data. The assumption is they can claim to have shared the data while at the same time ensuring it is nearly impossible for anyone to actually access the data.

...

The goal for phase two will be to expand the use of DUO metadata to individual data files. We would also like to provide a system to “automatically” associate ARs with files base on their annotation values.

Background

As mentioned above, the Data Use Ontology (DUO) was develop to help standardize the data use nomenclature of biomedical data. Unfortunately, DUO was defined using Web Ontology Language (OWL), in a manner that allows broad interpretation of the definitions. For example, DUO does not actually define the expected keys or their corresponding values types. However, DUO does define 26 categories or data restrictions, with some comments about how each might be used.

...

We chose to implement each category as a separate JSON-schema, each consisting of at least one boolean property, using the ontology:shorthand as the key. For example, D0000007 use the key DS. In each case, the default value of each boolean is false. For some cases, when a value of “true” is provided, extra data is expected. For example, D0000024 which is labeled as: publication moratorium, with a key of MOR, include an extra field to capture the moratorium date: MOR_date, when MOR is set to true.

The next step is build a project specific JSON schema that defines how DUO should be applied. The following JSON schema is an examples of such schema that could be bound to the project from the main governance narrative:

...

languagejson

...

Next we want to setup some representative ARs that would be associated with the example project from the governance stories document. Let’s assume that a member of ACT has created the following ARs for this project:

access requirement ID

Name

Description

Expected Annotations

1

Cancer Research Requirement

Data under this AR can only be used for Cancer research.

RS = true

RS_research_type = Cancer

2

Ethics Approval Required

Data under this AR can only be accessed if the user has IRB approval.

IRB = true

3

Publication Moratorium

Data under this AR is under a publication moratorium that limits a download from publishing before this date.

MOR = true

MOR_date = 2022-05-20

4

Germany Geographical Restriction

Data under this AR has a geographical restriction stating that the data cannot leave Germany.

GS = true

GS_location = Germany

Access Requirements for the Project

Note: We will reference each of these ARs by their access requirement ID. The expected annotations column describes the expected DUO annotation key-value-pairs that would be any file that would under that AR.

The next step is to build a project specific JSON schema that defines how DUO should be applied. It is expected that the DUO specific elements and ARs in this schema would be the result of a collaboration between ACT and the Community Manager/Data Curator. The following JSON schema is an examples of such schema that could be bound to the project from the main governance narrative:

Code Block
languagejson
{
	"$schema": "http://json-schema.org/draft-07/schema",
	"title": "Schema for Some Project",
	"$id": "some.project-main-1.3",
	"description": "This schema defines how DUO should be used with Some Project.",
	"allOf": [
		{
			"$ref": "org.sagebionetworks-repo.model.FileEntity-1.0.0"
		},
		{
			"$ref": "ebispot.duo-duo-1.0.1"
		},
		{
			"if": {
				"properties": {
					"patientLocation": {
						"const": "Germany"
					},
					"assayType": {
						"const": "genomic"
					}
				}
			},
			"then": {
				"properties": {
					"GS": {
						"title": "geographical restriction",
						"type": "boolean",
						"const": true
					},
					"GS_location": {
						"type": "string",
						"description": "This data cannot leave Germany",
						"const": "Germany"
					},
					"_accessRequirementIds": {
						"type": "array",
						"contains": {
							"const": 4
						}
					}
				},
				"required": [
					"GS_location"
				]
			}
		},
		{
			"if": {
				"properties": {
					"patientLocation": {
						"const": "USA"
					},
					"assayType": {
						"const": "genomic"
					}
				}
			},
			"then": {
				"properties": {
					"sourceGeography": {
						"const": "US"
					},
					"jurisdiction ": {
						"const": "HIPAA"
					},
					"dataLabel": {
						"const": "De-identified"
					}
				},
				"required": [
					"sourceGeography",
					"jurisdiction",
					"dataLabel"
				]
			}
		}
	],
	"properties": {
		"assayType": {
			"description": "Identifies they type of data for this files.",
			"type": "string",
			"enum": [
				"clinical",
				"assay",
				"imaging",
				"genomic"
			]
		},
		"patientLocation": {
			"description": "The location of the patient associated with the data",
			"type": "string",
			"enum": [
				"USA",
				"Germany"
			]
		},
		"RS": {
			"title": "research specific restrictions",
			"type": "boolean",
			"const": true
		},
		"RS_research_type": {
			"title": "Restricted to cancer research",
			"type": "string",
			"const": "cancer"
		},
		"IRB": {
			"title": "ethics approval required",
			"type": "boolean",
			"const": true
		},
		"MOR": {
			"title": "publication moratorium",
			"type": "boolean",
			"const": true
		},
		"MOR_date": {
			"title": "publication moratorium date",
			"type": "string",
			"format": "date",
			"const": "2022-05-20"
		},
	},
	"required_accessRequirmentIds": [{
			"assayTypetype",: 		"patientLocationarray",
			"NRESallOf",: [
				"HMB",
{
					"DScontains",: {
		"POA",
				"RSconst",: 1
			"NMDS",
		"GSO",}
		"NPUNCU",
		"PUB"},
		"COL",
		"IRB",{
			"GS",
		"MORcontains",: {
		"TS",
		"US",
		"PSconst",: 2
			"IS",
		"RTN",}
		"GRU",
		"CC"},
		"NPOA",
		"NPU",
		"NCU"
	]
}

DUO applied to a Project

Notice that line:8 indicates that this schema applies to FileEntities, while line:11 indicates that the schema “extends” the DUO schema. The first two properties of the schema: assayType (line:74) and patientLocation (line:84) are drivers that will determine what conditional properties must be applied to each file. There are two if/then blocks (line:14 to 71) that define what conditional properties should be applied based on assayType and patientLocation. The properties RS, RS_research_type, IRB, MOR, MOR_date, are all unconditional properties, with constant values that must be applied to all files in the project.

The following JSON is an example of what “valid” properties could be for syn1 from the example above:

Code Block
languagejson
{
	"name": "GermanGenomic.data",
	"description": "Genomic data from patients in Germany",
	"id": "syn1",
	"etag": "some-etag",
	"createdOn": "2020-05-20T20:20:39+00:00",
	"modifiedOn": "2020-05-20T20:20:39+00:00",
	"createdBy": "123456789",
	"modifiedBy": "123456789",
	"parentId": "syn444",
	"versionLabel": "one",
	"versionComment": "leaving blank",
	"versionNumber": 1,
	"dataFileHandleId": "98765",
	"fileNameOverride": "",
	"concreteType": "org.sagebionetworks.repo.model.FileEntity",
	"assayType": "genomic",
	"patientLocation": "Germany",
	"NRES": false,
	"HMB": false,
	"DS": false,
	"POA": false,
	"RS": true,
	"RS_research_type": "cancer",
	"NMDS": false,
	"GSO": false,
	"NPUNCU": false,
	"PUB": false,
	"COL": false,
	"IRB": true,
	"GS": true,
	"GS_location": "Germany",
	"MOR": true,
	"MOR_date": "2022-05-20",
	"TS": false,
	"US": false,
	"PS": false,
	"IS": false,
	"RTN": false,
	"GRU": false,
	"CC": false,
	"NPOA": false,
	"NPU": false,
	"NCU": false
}

syn1.json

Since syn1 includes "assayType": "genomic" and "patientLocation": "Germany", it must include "GS": true and "GS_location": "Germany" according to the rules of the first if/then. Most of the properties between lines: 19 to 44, are all constants based on this projects schema.

The following JSON is an example of what “valid” properties could be for syn4 from the example above:

Code Block
languagejson
{
	"name": "USGenomic.data",
	"description": "Genomic data from patients in USA",
	"id": "syn4",
	"etag": "some-etag",
	"createdOn": "2020-05-20T20:20:39+00:00",
	"modifiedOn": "2020-05-20T20:20:39+00:00",
	"createdBy": "123456789",
	"modifiedBy": "123456789",
	"parentId": "syn444",
	"versionLabel": "one",
	"versionComment": "leaving blank",
	"versionNumber": 1,
	"dataFileHandleId": "98765",
	"fileNameOverride": "",
	"concreteType": "org.sagebionetworks.repo.model.FileEntity",
	"assayType": "genomic",
	"patientLocation": "USA",
	"NRES": false,
	"HMB": false,
	"DS": false,
	"POA": false,
	"RS": true,
	"RS_research_type": "cancer",
	"NMDS": false,
	"GSO": false,
	"NPUNCU": false,
	"PUB": false,
	"COL": false,
	"IRB": true,
	"GS": false,
	"MOR": true,
	"MOR_date": "2022-05-20",
	"TS": false,
	"US": false,
	"PS": false,
	"IS": false,
	"RTN": false,
	"GRU": false,
	"CC": false,
	"NPOA": false,
	"NPU": false,
	"NCU": false,
	"sourceGeography":"US",
	"jurisdiction": "HIPAA",
	"dataLabel":"De-identified"
}

syn4.json

Since syn4 has "assayType": "genomic" and "patientLocation": "USA", according to the if/then statements it must also the following constant properties: "sourceGeography":"US", "jurisdiction": "HIPAA", "dataLabel":"De-identified". Note: For syn4 "GS": false because the patient location does not equal Germany.

Derived Annotations

The example above for both syn1 and syn4, indicates that all of the the governance specific metadata is derived from two sources:

  • Project specific constant - For example “publication moratorium” ("MOR": true & "MOR_date": "2022-05-20") apply to all files in the project, as defined by the schema ("$id": "some.project-main")

  • User Provided properties - For example, the if/then blocks define additional properties based on the values of the user provided: "assayType" and "patientLocation"

Note: For this phase we are glossing over the fact that the value of patientLocation is a transitive. Its value would be found by joining the patient table, with the treatment table, and then joining with the sampleIds of each file. We will attempt to address this in a later phase.

Given that there are 30+ governance annotations for this project, and all of then values can be derived, it does not seem reasonable to ask any user to provide these annotation values. Instead, it would be better if Synapse could “automatically” provided these value-key-pairs.

One of the governance narratives includes a case where the "patientLocation" value for a given file was mistakenly given the wrong value. For example, lets assume that syn4 was incorrectly given "patientLocation": "USA", as the patients location is actually Germany. Correcting this single value on syn4 would require that five other governance annotations would need to change. It might not even be obvious to the user making the correction that these additional changes are needed. Instead, it would be better if the Synapse could “automatically” re-derive the governance annotations.

It should be noted that a system that could automatically derive annotations could be useful for many external use cases. For example, one of the main JSON schema use cases involves setting annotations on files that are uploaded in bulk. For some of these use cases, a few key values provided by the upload might be enough to automatically derive the rest of the value-key pairs.

For this discussion we are defining the following terms:

  • Actual Annotation - This is a value-key-pair that is provided by user not the system.

  • Derived Annotation - This is a value-key-pair that is automatically provide by the system using a combination of JSON schema and actual annotations.

Derived Annotations Algorithm

Given a valid JSON schema, and a JSON representation of actual annotation value-key-pairs as input, calculate the list of derived annotation value-key-pairs as output. The algorithm must meet the following requirements:

  1. Only actual annotations are to be considered. In other words, a derived annotation value-key-pair cannot be used to derive another value-key-pair.

  2. Only JSON schema properties that are defined to have a constant value (for example :"const": "cancer") will be considered as derived annotation candidates.

    1. If an actual annotation exists with the same key, the candidate will be eliminated. This means that derived annotations will never “correct” invalid actual annotations.

    2. If the candidate is in an unreachable logic branch, then it will be eliminated. For example, if the candidate resides in a "then" block, that is unreachable because the corresponding "if" evaluates to “false”, then the candidate will be eliminated.

    3. Any candidate that is not eliminated will be added to the results as a derived annotation value-key-pair.

Derived Annotations API

Derived annotations are to be considered “transient” data. This means they are subject to be recalculated any time, either the input JSON schema changes or the actual annotations change. This implies that derived data will not be migrated between stacks, but instead, recalculated on each stack.

Derived annotations are to be considered separate from the actual annotation of a Entity. For example, an actual annotation is part of the persisted data of an Entity. While a derived annotation might be cached, it will not be part of the persisted data of an Entity.

JSON Schema Binding API Changes

Currently the API: PUT /entity/{id}/schema/binding is used to bind a JSON schema to a Entity. We propose extending the BindSchemaToEntityRequest object to include a new boolean property called “automaticallyIncludeDerivedAnnotations” with default value of “false”. With this value set to “false” Synapse will not attempt to calculate derived annotations for the Entities bound to this schema. However, when “automaticallyIncludeDerivedAnnotations=true”, Synapse will automatically, calculate the derived annotations for the Entities bound to this schema. Note: This new property value will be persisted with the JSON Schema’s binding data.

Entity Services API Changes

Currently there are three APIs for getting the annotations of an Entity:

Each API returns the annotations of the given entity id/(version). In order to get the derived annotations of an Entity, we propose extending each of these APIs to include a new boolean parameter named “includeDerivedAnnotations” with a default value of “false”. When the “includeDerivedAnnotations=true”, the results will include both the actual annotations, and the derived annotations.

Note: Each service currently returns the Entity’s “etag” in addition to the annotations. When a user wishes to update the annotations of an entity, they must include the provided “etag” with the update request. However, when “includeDerivedAnnotations=true” each service will not return the “etag”. This is done to prevent the user from accidentally updating the annotations of an Entity with the transient derived annotations.

Note: When “includeDerivedAnnotations=true”, the caller will not be able to distinguish the actual annotations from the derived annotations in the results.

Entity View API Changes

Currently, an EntityView is configured with a list of ColumnModels that define the schema of that view. Users will typically use the following asynchronous service to get the possible ColumnModels when setting the schema of their views: POST /column/view/scope/async/start. In order to create an EntityView that includes derived columns, we propose extending this API’s request object: ViewColumnModelRequest to include a boolean parameter named: “includeDerivedColumns“ with a default value of “false”. When this parameter is set to “true”, the services will include derived columns as possible results. In this way, users will be able to configure their views to include derived columns.

Entity Manifest Changes

Currently, when a user downloads a FileEntity via the packaging option of their download list (POST /download/list/package/async/start), the DownloadListPackageRequest include an option to include a manifest. When “includeManifest=true”, the package will include a CSV file contain all of the annotations for any FileEntity include in the download. We propose extending this manifest to automatically include all derived annotations.

AccessRequirement API Changes

...

		{
					"contains": {
						"const": 3
					}
				}
            ]
        }
	},
	"required": [
		"assayType",
		"patientLocation",
		"NRES",
		"HMB",
		"DS",
		"POA",
		"RS",
		"NMDS",
		"GSO",
		"NPUNCU",
		"PUB",
		"COL",
		"IRB",
		"GS",
		"MOR",
		"TS",
		"US",
		"PS",
		"IS",
		"RTN",
		"GRU",
		"CC",
		"NPOA",
		"NPU",
		"NCU"
	],
}

DUO applied to a Project

Notice that line:8 indicates that this schema applies to FileEntities, while line:11 indicates that the schema “extends” the DUO schema. The first two properties of the schema: assayType (line:80) and patientLocation (line:90) are drivers that will determine what conditional properties must be applied to each file. There are two if/then blocks (line:14 to 78) that define what conditional properties should be applied based on assayType and patientLocation. The properties RS, RS_research_type, IRB, MOR, MOR_date, are all unconditional properties, with constant values that must be applied to all files in the project.

Synapse would be expected to use the"_accessRequirementIds" properties for guidance to “automatically” associate files with ARs according to the rules defined in the schema. Specifically "const": 4 (line:39) indicates that ARid:4 should be applied to any file with the annotations: "assayType": "genomic" and "patientLocation": "Germany". While _accessRequirmentIds (line:124 - 144) indicates that ARids: 1,2,3 should be applied to all files in the project unconditionally.

We will also add derived annotations with with each of these keys and a value: true to each entity. This would allow a view designer to add these columns to a view, thus enabling end-users to query for files based on ARs.

Note: We will need to block users from adding or updating any annotations with the key "_accessRequirmentIds".

The following JSON is an example of what “valid” properties could be for syn1 from the example above:

Code Block
languagejson
{
	"name": "GermanGenomic.data",
	"description": "Genomic data from patients in Germany",
	"id": "syn1",
	"etag": "some-etag",
	"createdOn": "2020-05-20T20:20:39+00:00",
	"modifiedOn": "2020-05-20T20:20:39+00:00",
	"createdBy": "123456789",
	"modifiedBy": "123456789",
	"parentId": "syn444",
	"versionLabel": "one",
	"versionComment": "leaving blank",
	"versionNumber": 1,
	"dataFileHandleId": "98765",
	"fileNameOverride": "",
	"concreteType": "org.sagebionetworks.repo.model.FileEntity",
	"assayType": "genomic",
	"patientLocation": "Germany",
	"NRES": false,
	"HMB": false,
	"DS": false,
	"POA": false,
	"RS": true,
	"RS_research_type": "cancer",
	"NMDS": false,
	"GSO": false,
	"NPUNCU": false,
	"PUB": false,
	"COL": false,
	"IRB": true,
	"GS": true,
	"GS_location": "Germany",
	"MOR": true,
	"MOR_date": "2022-05-20",
	"TS": false,
	"US": false,
	"PS": false,
	"IS": false,
	"RTN": false,
	"GRU": false,
	"CC": false,
	"NPOA": false,
	"NPU": false,
	"NCU": false,
	"_accessRequirmentIds" : [1,2,3,4]
}

syn1.json

Since syn1 includes "assayType": "genomic" and "patientLocation": "Germany", it must include "GS": true and "GS_location": "Germany" according to the rules of the first if/then. Most of the properties between lines: 19 to 44, are all constants based on this projects schema.

The following JSON is an example of what “valid” properties could be for syn4 from the example above:

Code Block
languagejson
{
	"name": "USGenomic.data",
	"description": "Genomic data from patients in USA",
	"id": "syn4",
	"etag": "some-etag",
	"createdOn": "2020-05-20T20:20:39+00:00",
	"modifiedOn": "2020-05-20T20:20:39+00:00",
	"createdBy": "123456789",
	"modifiedBy": "123456789",
	"parentId": "syn444",
	"versionLabel": "one",
	"versionComment": "leaving blank",
	"versionNumber": 1,
	"dataFileHandleId": "98765",
	"fileNameOverride": "",
	"concreteType": "org.sagebionetworks.repo.model.FileEntity",
	"assayType": "genomic",
	"patientLocation": "USA",
	"NRES": false,
	"HMB": false,
	"DS": false,
	"POA": false,
	"RS": true,
	"RS_research_type": "cancer",
	"NMDS": false,
	"GSO": false,
	"NPUNCU": false,
	"PUB": false,
	"COL": false,
	"IRB": true,
	"GS": false,
	"MOR": true,
	"MOR_date": "2022-05-20",
	"TS": false,
	"US": false,
	"PS": false,
	"IS": false,
	"RTN": false,
	"GRU": false,
	"CC": false,
	"NPOA": false,
	"NPU": false,
	"NCU": false,
	"sourceGeography":"US",
	"jurisdiction": "HIPAA",
	"dataLabel":"De-identified",
	"_accessRequirmentIds" : [1,2,3]
}

syn4.json

Since syn4 has "assayType": "genomic" and "patientLocation": "USA", according to the if/then statements it must also the following constant properties: "sourceGeography":"US", "jurisdiction": "HIPAA", "dataLabel":"De-identified". Note: For syn4 "GS": false because the patient location does not equal Germany.

In both of these examples (syn1 & syn4) we included annotations for "_accessRequirementIds". Both files have [1,2,3] for AR IDs 1-3, since they are unconditional. Syn1 has [1,2,3,4], indicating it requires that the three unconditional ARs (1-3) and the conditional AR 4.

Derived Annotations

The example above for both syn1 and syn4, indicates that all of the the governance specific metadata is derived from two sources:

  • Project specific constant - For example “publication moratorium” ("MOR": true & "MOR_date": "2022-05-20") apply to all files in the project, as defined by the schema ("$id": "some.project-main")

  • User Provided properties - For example, the if/then blocks define additional properties based on the values of the user provided: "assayType" and "patientLocation"

Note: For this phase we are glossing over the fact that the value of patientLocation is a transitive. Its value would be found by joining the patient table, with the treatment table, and then joining with the sampleIds of each file. We will attempt to address this in a later phase.

Given that there are 30+ governance annotations for this project, and all of then values can be derived, it does not seem reasonable to ask any user to provide these annotation values. Instead, it would be better if Synapse could “automatically” provided these value-key-pairs.

One of the governance narratives includes a case where the "patientLocation" value for a given file was mistakenly given the wrong value. For example, lets assume that syn4 was incorrectly given "patientLocation": "USA", as the patients location is actually Germany. Correcting this single value on syn4 would require that five other governance annotations would need to change. It might not even be obvious to the user making the correction that these additional changes are needed. Instead, it would be better if the Synapse could “automatically” re-derive the governance annotations.

It should be noted that a system that could automatically derive annotations would be useful for many external use cases. For example, one of the main JSON schema use cases involves setting annotations on files that are uploaded in bulk. For some of these use cases, a few key values provided by the uploader might be enough to automatically derive the rest of the value-key pairs.

For this discussion we are defining the following terms:

  • Actual Annotation - This is a value-key-pair that is provided by user not the system.

  • Derived Annotation - This is a value-key-pair that is automatically provide by the system using a combination of JSON schema and actual annotations.

Derived Annotations Algorithm

Given a valid JSON schema, and a JSON representation of actual annotation value-key-pairs as input, calculate the list of derived annotation value-key-pairs as output. The algorithm must meet the following requirements:

  1. Only actual annotations are to be considered. In other words, a derived annotation value-key-pair cannot be used to derive another value-key-pair.

  2. Only JSON schema properties that are defined to have a constant or default value will be considered as derived annotation candidates.

    1. If an actual annotation exists with the same key, the candidate will be eliminated. This means that derived annotations will never “correct” invalid actual annotations.

    2. If the candidate is in an unreachable logic branch, then it will be eliminated. For example, if the candidate resides in a "then" block, that is unreachable because the corresponding "if" evaluates to “false”, then the candidate will be eliminated.

    3. Default values will only be used if there are no overriding “const” for the same key.

    4. Any candidate that is not eliminated will be added to the results as a derived annotation value-key-pair.

Derived Annotations API

Derived annotations are to be considered “transient” data. This means they are subject to be recalculated any time, either the input JSON schema changes or the actual annotations change. This implies that derived data will not be migrated between stacks, but instead, recalculated on each stack.

Derived annotations are to be considered separate from the actual annotation of a Entity. For example, an actual annotation is part of the persisted data of an Entity. While a derived annotation might be cached, it will not be part of the persisted data of an Entity.

JSON Schema Binding API Changes

Currently the API: PUT /entity/{id}/schema/binding is used to bind a JSON schema to a Entity. We propose extending the BindSchemaToEntityRequest object to include a new boolean property called “automaticallyIncludeDerivedAnnotations” with default value of “false”. With this value set to “false” Synapse will not attempt to calculate derived annotations for the Entities bound to this schema. However, when “automaticallyIncludeDerivedAnnotations=true”, Synapse will automatically, calculate the derived annotations for the Entities bound to this schema. Note: This new property value will be persisted with the JSON Schema’s binding data.

Entity Services API Changes

Currently there are three APIs for getting the annotations of an Entity:

Each API returns the annotations of the given entity id/(version). In order to get the derived annotations of an Entity, we propose extending each of these APIs to include a new boolean parameter named “includeDerivedAnnotations” with a default value of “false”. When the “includeDerivedAnnotations=true”, the results will include both the actual annotations, and the derived annotations.

We will need to provide a service that would list the derived keys for a given entity id:

Response

API

Description

List<Strings> derivedKeys

GET /entity/{id}/derivedKeys

Get the derived keys for the given Entity ID

Entity View API Changes

Currently, an EntityView is configured with a list of ColumnModels that define the schema of that view. Users will typically use the following asynchronous service to get the possible ColumnModels when setting the schema of their views: POST /column/view/scope/async/start. In order to create an EntityView that includes derived columns, we propose extending this API’s request object: ViewColumnModelRequest to include a boolean parameter named: “includeDerivedColumns“ with a default value of “false”. When this parameter is set to “true”, the services will include derived columns as possible results. In this way, users will be able to configure their views to include derived columns.

Entity Manifest Changes

Currently, when a user downloads a FileEntity via the packaging option of their download list (POST /download/list/package/async/start), the DownloadListPackageRequest include an option to include a manifest. When “includeManifest=true”, the package will include a CSV file contain all of the annotations for any FileEntity include in the download. We propose extending this manifest to automatically include all derived annotations.

AccessRequirement API Changes

New AccessRequirement Types

Currently, AccessRequirement (AR) include a list of “subjectIds” that define what Entities (or Teams) the AR applies too. There are currently six types of ARs:

Currently all six AR’s include a subjectIds list within the actual AR. Subjects are added/removed from these ARs by updating the actual AR object using either the CREATE or UPDATE services. We will likely need to continue to maintain each of these ARs types for the foreseeable future.

With this design, we are proposing a new system for assigning the subjects to ARs. Rather than explicitly modifying the subjects of each AR, the new system will allow subjects to be “automatically” bound to ARs based on the new derived _accessRequirementIds annotations on Entities. We will likely need to apply this new system to three of the six AR types: SelfSignAccessRequirement, TermsOfUseAccessRequirement, & ManagedACTAccessRequirement. Rather than define multiple new AR types, we proposed extending all ARs by adding the following property:

Code Block
languagejson
	"properties": {
...
		"subjectsDefinedByAnnotations": {
			"type": "boolean",
			"description": "Defaults to 'false'.  When 'true', the subjects controlled by this AR are defined by the the'_accessRequirementIds' annotations on individual entities.  This property is mutually exclusive with 'subjectIds'.  If this is set to 'true' then 'subjectIds' must be excluded."
		},
...
		"subjectIds": {
			"type": "array",
			"description": "The IDs of the items controlled by this Access Requirement.  Required when creating or updating.",
			"transient": true,
			"items": {
        		"type":"object",
				"$ref":"org.sagebionetworks.repo.model.RestrictableObjectDescriptor"
			}
		}
...
	}

This new boolean will allow for the configuration of an AR to be either define by either the ‘subjectIds’ list or _accessRequirementIds annotation.

The GET /accessRequirement/{requirementId} API returns the full list of ‘subjectIds’ for existing ARs. This means that the entire subject list must fit in both client-side and server-side memory. Considering that existing ARs are managed by hand, it is reasonable to assume that the full list will be small enough to prevent memory problems. In fact, it is common for the ‘subjectIds’ to be container IDs (Projects & Folders), to minimize the micromanagement required to maintain an AR. As a result, a short ‘subjectIds’ list can restrict thousands of Entites, since a container can contain up to 40K children. This type of data compression is not likely to extend to new ARs with subjectsDefinedByAnnotations = true. While it will be possible to bind _accessRequirementIds annotations to containers, it is far more likely that these annotations will be bound to individual files. After all, the new derived annotations features make it easy to apply annotation to millions of entities with only a few lines of schema code. This means we must assume that the subjects of ARs with subjectsDefinedByAnnotations = true might not fit in memory. Therefore, we cannot return all of the subject’s for such ARs for calls that GET the AR. However, since the subjects of such ARs are controlled by JSON schemas, it is not clear that listing the subject will even be needed. If we find that we do need to provide all of the subjects of these new ARs then we will need to add a new API that provides a paginated list of subjectIds to avoid out-of-memory problems.

The _accessRequirementIds annotation Lifecycle

The above examples demonstrate the need for _accessRequirementIds annotation as derived annotations. We will be able to use these derived annotations to bind ARs to entities and to filter Entity data in views that include the _accessRequirementIds column. We do not currently have a use case for users to directly create or update _accessRequirementIds annotations on entities. Therefore, we will block all users from directly creating or updating _accessRequirementIds annotations.

Invalid Annotations

Currently, derived annotations are reevaluated for any type of Entity change event. This includes JSON schema binding change events, and annotation changes events. We will need to check the AR binding of an Entity each time the derived annotations are reevaluated. However, what happens if a change puts an entity into an invalid state? For such a case, we would not be able to to determine what the correct derived annotations should be. By extension we would not be able to determine the correct AR bindings of an invalid Entity. It seems wrong to allow users to download a file with no ARs simply becuase the file’s annotations are invalid. To prevent this cases, we will automatically add an invalid-metadata-access-restriction to any file that has invalid annotations and is bound to a JSON schema that includes _accessRequirementIds. This invalid-metadata AR will function similarly to the existing LockAccessRequirement.