Try โ€‚โ€‰HackMD

2022-11-25 ssb-submissions design

Example Usage


// ssb
// artefactCrut // could come from ssb.artefact.create

ssb.submission.registerHandler(isArtefact, artefactCrut)

ssb.submission.create({ id, { date: '2022-04-XX' }, cb)
// looks up record
// finds type "artefact", sees we have a registered artefactCrut,
// so knows how to validate/ execute stuff

Problems:

  1. simulating a create/update
    • Some things let you do a dry run that show you what the output would be

Ideas:

  1. submitting a tombstone!

API

ssb.submission.registerHandler(crut)

register a handler for a message type

crut - crut instance (includes spec for record - has type and isRoot / isUpdate)

ssb.submission.proposeEdit(recordId, details, { comment }, cb)

  • recordId - id of a record you're wanting to edit. empty if you're proposing a new record

ssb.submission.proposeNew(type, details, { comment }, cb)

  • type - the type of the record being changed/created

  • details - Fields (that match the recordId) filled in with proposed changes

ssb.submission.read(id)

takes submission id, calls back with submission record

  • accepted or not, details etc

ssb.submission.showProposalResult(id, cb)

  • id : submission id

for when we want to see what would happen if you applied the edit.
- algorithm
- 1. read the current record state
- 2. "predict" the record state if this submission was applied
- 3. highlight diff (changing fields)

โ€‹โ€‹โ€‹โ€‹- 1. The recordId is null
โ€‹โ€‹โ€‹โ€‹- 2. "predict" what the new thing would look like
โ€‹โ€‹โ€‹โ€‹- 3. Wouldn't highlight diff

ssb.submission.accept(id, { comment }, cb)

  • id - submission id
  • cb - callback of signature (err, recordEditId)

ssb.submission.reject(id, { comment }, cb)

  • id - submission id
  • cb - callback of signature (err)

ssb.submission.tombstone

ssb.submission.list


Register handler pseudocode

const submissionCrut = new CRUT(ssb, submissionSpec)

const handlers = []
const findCrut = (content) => {
  const handler = handlers.find(h => h[0]({ type }))
  if (handler) return handler[1]
}

const API = {
  registerHandler (crut) {
    const isType = content => content.type === crut.spec.type
    
    handlers.push([isType, crut])
  },
  
  proposeNew (type, details, { comment }, cb) {
    const crut = findCrut({ type })
    if (!crut) return cb(new Error('unknown type: ' + type))
    
    const isValid = crut.isRoot
    // check it's a well formed
    
    if (!isValid(details)) return cb(new Error(isValid.errorString))
    
    const content = {
      id: null
      recordType: type,
      submission: details,
      comment
    }
    submissionCrut.create(content, cb)
    // publish message of type: submission/artefact
  },
    
  proposeEdit (recordId, details, { comment }, cb) {
      if(!recordId) return cb(new Error('Invalid recordId: ' + recordId))
      const targetRecord = lookUp(recordId) // is there something that can lookup a record of any type?
if(!targetRecord) // not found, tombstoned, etc
    return cb(new Error('Invalid record: ' + recordId))
      
     const crut = findCrut({ targetRecord.type }) // Is there a lookup that can get the crut of a record directly?
    if (!crut) return cb(new Error('unknown type: ' + targetRecord.type))
      
      
      if (!crut.isValid(details) || !crut.isValidNextStep(details)) return cb(new Error(isValid.errorString))
      
      const content = {
      id: recordId
      recordType: type,
      submission: details,
      comment
    }
      
      submissionCrut.create(content, cb)
      
  }
  
}


Test cases:

Simple:

  • - ProposeNew,Edit,Tombstone
  • - Accepting/rejecting proposal
  • - Proposing identity new/edit
  • - checking other proposal status: pending/invalid/obsolete/viewedโ€ฆ
  • - Kaitiaki creating submission
  • - Reading submission
    • - Details
    • - type
    • - status
    • - approvedBy
    • - Differences (similar to details but uses simulation)

RegisterHandler

  • - without crut,
  • - with incorrect crut,
  • - with multiple crut,
  • - with profile (not unique type)

Expect errors:

  • - Editing a profile that doesn't exist
  • - Editing a profile that hasn't been recieved by kaitiaki
  • - Editing a profile from a different group
  • - Editing null recordId
  • - Invalid details
  • - Invalid nextState
  • - Proposal that doesn't resolve conflict
  • - complex: kaitiaki having different tips compared to submitter
  • - Invalid type
  • - editing tombstoned profile
  • - Accepting a submission that has been tombstoned
  • - Accepting a submission that doesn't exist

Complex:

  • - Rejecting an already accepted proposal (and vis versa)
  • - crut with special isValidNextStep
  • - Multiple kaitiaki accepting/rejecting
  • - Non-kaitiaki accepting/declining
  • - Simultaneous accept+reject, i.e. multiple tips
  • - then merging tips
  • - Simulating/reading rejected/tombstoned/invalid submissions