Skip to content

Instantly share code, notes, and snippets.

@kspurgin
Last active October 1, 2026 01:36
Show Gist options
  • Select an option

  • Save kspurgin/fc882a10f66e166a06bcdd7305e5fa9b to your computer and use it in GitHub Desktop.

Select an option

Save kspurgin/fc882a10f66e166a06bcdd7305e5fa9b to your computer and use it in GitHub Desktop.
aspace_assessment_attribute.md

Testing creating an Assessment with an assessment_attribute note, but no rating (value) for the assessment_attribute.

Create Assessment record in UI

In the UI, create new assessment with NO RATING for Documentation quality AND a NOTE for Documentation quality:

image

JSON API output of this record

bin/console in aspace-data-tools:

c = ADT.client
a = c.get("/repositories/2/assessments/2")
a.parsed 
=> {"lock_version" => 1,
   "accession_report" => false,
   "appraisal" => false,
   "container_list" => false,
   "catalog_record" => false,
   "control_file" => false,
   "finding_aid_ead" => false,
   "finding_aid_paper" => false,
   "finding_aid_word" => false,
   "finding_aid_spreadsheet" => false,
   "review_required" => false,
   "sensitive_material" => false,
   "general_assessment_note" => "My general assessment note",
   "deed_of_gift" => false,
   "finding_aid_online" => false,
   "related_eac_records" => false,
   "survey_begin" => "2026-09-30",
   "inactive" => false,
   "created_by" => "admin",
   "last_modified_by" => "admin",
   "create_time" => "2026-09-30T20:22:36Z",
   "system_mtime" => "2026-09-30T20:26:48Z",
   "user_mtime" => "2026-09-30T20:26:48Z",
   "jsonmodel_type" => "assessment",
   "records" => [{"ref" => "/repositories/2/accessions/1"}],
   "surveyed_by" => [{"ref" => "/agents/people/26"}],
   "reviewer" => [],
   "formats" =>
    [{"global" => true, "label" => "Architectural Materials", "readonly" => false, "definition_id" => 9},
     {"global" => true, "label" => "Art Originals", "readonly" => false, "definition_id" => 10},
     {"global" => true, "label" => "Artifacts", "readonly" => false, "definition_id" => 11},
     {"global" => true, "label" => "Audio Materials", "readonly" => false, "definition_id" => 12},
     {"global" => true, "label" => "Biological Specimens", "readonly" => false, "definition_id" => 13},
     {"global" => true, "label" => "Botanical Specimens", "readonly" => false, "definition_id" => 14},
     {"global" => true, "label" => "Computer Storage Units", "readonly" => false, "definition_id" => 15},
     {"global" => true, "label" => "Film (negative, slide, or motion picture)", "readonly" => false, "definition_id" => 16},
     {"global" => true, "label" => "Glass", "readonly" => false, "definition_id" => 17},
     {"global" => true, "label" => "Photographs", "readonly" => false, "definition_id" => 18},
     {"global" => true, "label" => "Scrapbooks", "readonly" => false, "definition_id" => 19},
     {"global" => true, "label" => "Technical Drawings & Schematics", "readonly" => false, "definition_id" => 20},
     {"global" => true, "label" => "Textiles", "readonly" => false, "definition_id" => 21},
     {"global" => true, "label" => "Vellum & Parchment", "readonly" => false, "definition_id" => 22},
     {"global" => true, "label" => "Video Materials", "readonly" => false, "definition_id" => 23},
     {"global" => true, "label" => "Other", "readonly" => false, "definition_id" => 24}],
   "conservation_issues" =>
    [{"global" => true, "label" => "Potential Mold or Mold Damage", "readonly" => false, "definition_id" => 25},
     {"global" => true, "label" => "Recent Pest Damage", "readonly" => false, "definition_id" => 26},
     {"global" => true, "label" => "Deteriorating Film Base", "readonly" => false, "definition_id" => 27},
     {"global" => true, "label" => "Brittle Paper", "readonly" => false, "definition_id" => 28},
     {"global" => true, "label" => "Metal Fasteners", "readonly" => false, "definition_id" => 29},
     {"global" => true, "label" => "Newspaper", "readonly" => false, "definition_id" => 30},
     {"global" => true, "label" => "Tape", "readonly" => false, "definition_id" => 31},
     {"global" => true, "label" => "Heat-Sensitive Paper", "readonly" => false, "definition_id" => 32},
     {"global" => true, "label" => "Water Damage", "readonly" => false, "definition_id" => 33}],
   "ratings" =>
    [{"global" => true, "label" => "Reformatting Readiness", "readonly" => false, "definition_id" => 1},
     {"global" => true, "label" => "Housing Quality", "readonly" => false, "definition_id" => 2},
     {"global" => true, "label" => "Physical Condition", "readonly" => false, "definition_id" => 3},
     {"global" => true, "label" => "Physical Access (arrangement)", "readonly" => false, "definition_id" => 4},
     {"global" => true, "label" => "Intellectual Access (description)", "readonly" => false, "definition_id" => 5},
     {"global" => true, "label" => "Interest", "readonly" => false, "definition_id" => 6},
     {"global" => true, "label" => "Documentation Quality", "note" => "My documentation quality note", "readonly" => false, "definition_id" => 7},
     {"global" => true, "label" => "Research Value", "readonly" => true, "definition_id" => 8}],
   "external_documents" => [],
   "collections" => [],
   "uri" => "/repositories/2/assessments/2",
   "repository" => {"ref" => "/repositories/2"},
   "display_string" => "2"}

In database

My assessment record is stored:

image

The assessment attribute note is stored:

image

PERHAPS IMPORTANT: No rows for any attributes are written to the assessment_attribute table:

image

Create new Assessment record via API

I created a new asmt.json (attached as separate file) file based off the result of my api call.

Back in aspace-data-tools console:

json = JSON.load_file(File.join(Bundler.root, "asmt.json"))
=> (a big JSON output)

result = c.post("/repositories/2/assessments", json)
=> #<ArchivesSpace::Response:0x0000000124c544d0
 @body="{\"status\":\"Created\",\"id\":3,\"lock_version\":0,\"stale\":null,\"uri\":\"/repositories/2/assessments/3\",\"warnings\":[]}\n",
 @headers=
  {"connection" => ["close"],
   "date" => ["Wed, 30 Sep 2026 21:01:52 GMT"],
   "content-type" => ["application/json"],
   "cache-control" => ["private, must-revalidate, max-age=0"],
   "x-content-type-options" => ["nosniff"],
   "content-length" => ["110"],
   "server" => ["Jetty(9.4.44.v20210927)"]},
 @parsed={"status" => "Created", "id" => 3, "lock_version" => 0, "stale" => nil, "uri" => "/repositories/2/assessments/3", "warnings" => []},
 @result={"status" => "Created", "id" => 3, "lock_version" => 0, "stale" => nil, "uri" => "/repositories/2/assessments/3", "warnings" => []},
 @status=#<Net::HTTPOK 200 OK readbody=true>,
 @status_code=200>

This record in database

New assessment row with id = 3 created.

Documentation quality note created exactly as for assessment 2

No assessment_attribute rows create for this record

In UI

IN UI, record looks like I expect it to:

image

Via Assessments CSV import background job

Leaving the non-note column for the assessment attribute empty works:

basic,basic,basic,basic,rating,rating
record,record,surveyed_by,survey_begin,Reformatting Readiness,Reformatting Readiness_note
accession_1,,admin,2017-07-04,,test

This gets the error: Errors: #<JSONModel::ModelNotFound: JSONModel not found for rating_reformatting_readiness>:

basic,basic,basic,basic,rating
record,record,surveyed_by,survey_begin,Reformatting Readiness_note
accession_1,,admin,2017-07-04,test

Debugging this crap

AssessmentConverter.configure does not itself throw this error. [src]

It produces the following config Hash:

     [java] => {:records_1=>
     [java]   {:record_type=>#<Proc:0x55fdf5fa /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:87>,
     [java]    :on_row_complete=>#<Proc:0x552d5a7 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:90>},
     [java]  "basic_record_1"=>[#<Proc:0x136a0854 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:266>, "records_1.uri"],
     [java]  :records_2=>
     [java]   {:record_type=>#<Proc:0x2cbb0969 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:87>,
     [java]    :on_row_complete=>#<Proc:0x3c6bfa74 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:90>},
     [java]  "basic_record_2"=>[#<Proc:0x136a0854 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:266>, "records_2.uri"],
     [java]  :agents_1=>
     [java]   {:record_type=>#<Proc:0x749b6e76 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:108>,
     [java]    :on_row_complete=>#<Proc:0x1e3a139a /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:111>},
     [java]  "basic_surveyed_by_1"=>[#<Proc:0x1b51b0bd /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:287>, "agents_1.uri"],
     [java]  "basic_survey_begin"=>[#<Proc:0x503b8e11 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:236>, "assessment.survey_begin"],
     [java]  "rating_reformatting_readiness_note"=>[nil, "rating_reformatting_readiness.note"]}

I have no idea what this is supposed to look like, so I pulled it for the job that works:

     [java] => {:records_1=>
     [java]   {:record_type=>#<Proc:0x101d40e5 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:87>,
     [java]    :on_row_complete=>#<Proc:0xf760b83 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:90>},
     [java]  "basic_record_1"=>[#<Proc:0x136a0854 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:266>, "records_1.uri"],
     [java]  :records_2=>
     [java]   {:record_type=>#<Proc:0x64424277 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:87>,
     [java]    :on_row_complete=>#<Proc:0x7eed3131 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:90>},
     [java]  "basic_record_2"=>[#<Proc:0x136a0854 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:266>, "records_2.uri"],
     [java]  :agents_1=>
     [java]   {:record_type=>#<Proc:0x1a952014 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:108>,
     [java]    :on_row_complete=>#<Proc:0x14f216dd /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:111>},
     [java]  "basic_surveyed_by_1"=>[#<Proc:0x1b51b0bd /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:287>, "agents_1.uri"],
     [java]  "basic_survey_begin"=>[#<Proc:0x503b8e11 /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:236>, "assessment.survey_begin"],
     [java]  :rating_reformatting_readiness=>{:record_type=>"assessment_attribute", :on_row_complete=>#<Proc:0x1cf20e3f /Users/kristina/code/as/archivesspace/backend/app/converters/assessment_converter.rb:170>},
     [java]  "rating_reformatting_readiness"=>[nil, "rating_reformatting_readiness.value"],
     [java]  "rating_reformatting_readiness_note"=>[nil, "rating_reformatting_readiness.note"]}

So the presence of the Reformatting Readiness column causes the following to be added before the two rating fields:

:rating_reformatting_readiness => {:record_type=>"assessment_attribute", :on_row_complete=>#<Proc...>}

It made me itchy that the following key in this Hash is the same, but as a String instead of a Symbol!:

"rating_reformatting_readiness"=>[nil, "rating_reformatting_readiness.value"]

This is the eventual cause of the error, which doesn't get triggered until all of this is sent through CsvConverter.parse_row to RecordProxy.spawn, which attempts to create a JSONModel without the necessary data to do so, eg. the :record_type=>"assessment_attribute" in the missing Hash value for the Symbol :rating_reformatting_readiness.

Mitigating assessments that got created with unwanted ratings

Example in UI:

image

Via DB

Deleting the assessment_attribute rows with funky values resets the display to:

image
{
"accession_report": false,
"appraisal": false,
"container_list": false,
"catalog_record": false,
"control_file": false,
"finding_aid_ead": false,
"finding_aid_paper": false,
"finding_aid_word": false,
"finding_aid_spreadsheet": false,
"review_required": false,
"sensitive_material": false,
"general_assessment_note": "My general assessment note",
"deed_of_gift": false,
"finding_aid_online": false,
"related_eac_records": false,
"survey_begin": "2026-09-30",
"inactive": false,
"jsonmodel_type": "assessment",
"records": [
{
"ref": "/repositories/2/accessions/1"
}
],
"surveyed_by": [
{
"ref": "/agents/people/26"
}
],
"reviewer": [],
"formats": [
{
"global": true,
"label": "Architectural Materials",
"readonly": false,
"definition_id": 9
},
{
"global": true,
"label": "Art Originals",
"readonly": false,
"definition_id": 10
},
{
"global": true,
"label": "Artifacts",
"readonly": false,
"definition_id": 11
},
{
"global": true,
"label": "Audio Materials",
"readonly": false,
"definition_id": 12
},
{
"global": true,
"label": "Biological Specimens",
"readonly": false,
"definition_id": 13
},
{
"global": true,
"label": "Botanical Specimens",
"readonly": false,
"definition_id": 14
},
{
"global": true,
"label": "Computer Storage Units",
"readonly": false,
"definition_id": 15
},
{
"global": true,
"label": "Film (negative, slide, or motion picture)",
"readonly": false,
"definition_id": 16
},
{
"global": true,
"label": "Glass",
"readonly": false,
"definition_id": 17
},
{
"global": true,
"label": "Photographs",
"readonly": false,
"definition_id": 18
},
{
"global": true,
"label": "Scrapbooks",
"readonly": false,
"definition_id": 19
},
{
"global": true,
"label": "Technical Drawings & Schematics",
"readonly": false,
"definition_id": 20
},
{
"global": true,
"label": "Textiles",
"readonly": false,
"definition_id": 21
},
{
"global": true,
"label": "Vellum & Parchment",
"readonly": false,
"definition_id": 22
},
{
"global": true,
"label": "Video Materials",
"readonly": false,
"definition_id": 23
},
{
"global": true,
"label": "Other",
"readonly": false,
"definition_id": 24
}
],
"conservation_issues": [
{
"global": true,
"label": "Potential Mold or Mold Damage",
"readonly": false,
"definition_id": 25
},
{
"global": true,
"label": "Recent Pest Damage",
"readonly": false,
"definition_id": 26
},
{
"global": true,
"label": "Deteriorating Film Base",
"readonly": false,
"definition_id": 27
},
{
"global": true,
"label": "Brittle Paper",
"readonly": false,
"definition_id": 28
},
{
"global": true,
"label": "Metal Fasteners",
"readonly": false,
"definition_id": 29
},
{
"global": true,
"label": "Newspaper",
"readonly": false,
"definition_id": 30
},
{
"global": true,
"label": "Tape",
"readonly": false,
"definition_id": 31
},
{
"global": true,
"label": "Heat-Sensitive Paper",
"readonly": false,
"definition_id": 32
},
{
"global": true,
"label": "Water Damage",
"readonly": false,
"definition_id": 33
}
],
"ratings": [
{
"global": true,
"label": "Reformatting Readiness",
"readonly": false,
"definition_id": 1
},
{
"global": true,
"label": "Housing Quality",
"readonly": false,
"definition_id": 2
},
{
"global": true,
"label": "Physical Condition",
"readonly": false,
"definition_id": 3
},
{
"global": true,
"label": "Physical Access (arrangement)",
"readonly": false,
"definition_id": 4
},
{
"global": true,
"label": "Intellectual Access (description)",
"readonly": false,
"definition_id": 5
},
{
"global": true,
"label": "Interest",
"readonly": false,
"definition_id": 6
},
{
"global": true,
"label": "Documentation Quality",
"note": "My documentation quality note",
"readonly": false,
"definition_id": 7
},
{
"global": true,
"label": "Research Value",
"readonly": true,
"definition_id": 8
}
],
"external_documents": [],
"collections": []
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment