Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update must, could, should based on proposed MVP values #284

Open
wants to merge 8 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions requirements/specifications/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Firebolt Requirements

Document Status: Working Draft

See [Firebolt Requirements Governance](../governance.md) for more info.

| Contributor | Organization |
| -------------- | -------------- |
| Jeremy LaCivita | Comcast |

## 1. Overview
All of the documents in this `/requirements/` directory comprise the collected set of requirements for this Firebolt version.

This document covers the Firebolt Specification JSON, [./firebolt-specification.json](./firebolt-specification.json), which is a JSON document outlining all Firebolt Capabilities and whether they MUST, SHOULD, or COULD be supported.

This document is written using the [IETF Best Common Practice 14](https://www.rfc-editor.org/rfc/rfc2119.txt) and should include the following summary in the Overview section:

The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in [BCP 14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

## 2. Table of Contents
- [1. Overview](#1-overview)
- [2. Table of Contents](#2-table-of-contents)
- [3. Capabilities](#3-capabilities)
- [3.1. Capability Level](#31-capability-level)
- [3.1.1. Should vs Could](#311-should-vs-could)
- [3.1.2. Supported Capability](#312-supported-capability)

## 3. Capabilities
All Firebolt APIs are assigned a capability by either using it, managing it, or providing it.

See [Capabilities](./general/capabilities/capabilities.md) for more info.

### 3.1. Capability Level
In the Firebolt Specification JSON, every capability is given a `level` of either:

- `"must"`
- `"should"`
- `"could"`

A capability with the level set to `"must"` **MUST** be supported or the implementation in question is not a certified Firebolt implementation.

A capability with the level set to `"should"` **SHOULD** be supported, especially if the implementation supports similar requirements in a non-Firebolt interface.

A capability with the level set to `"could"` **COULD** be supported at the implementations discretion.

#### 3.1.1. Should vs Could
This section is non-normative and does not denote any requiements.

"Should" means that not supporting a capability has a detremental impact on a Firebolt platform, and care should be taken when deciding not to support a `"should"` capability.

For example, a capability supporting HDMI outputs would likely be assigned a level of `"should"`, since most STB devices have HDMI outputs, while most TV devices do not.

If a capability has a level of `"should"` and the device exposes the functionality in question through hardware or software, then it should either be treated as a `"must"` or a really good reason should exist for why it was not implemented.

If a device has HDMI output ports, then it probably should implement this capability. While a device w/out HDMI output ports does not need to.

"Could" means that this API is truly optional, for example a capability to expose the postal code of the device might be assigned a `level` of `"could"` since Firebolt platforms can justifiably opt not to support this.

#### 3.1.2. Supported Capability
A supported capability **MUST** have all of its `x-uses` APIs surfaced, supported, and passing Firebolt Compliance tests.

A supported capability **MUST** have all of its `x-provides` APIs surfaced, supported, and passing Firebolt Compliance tests.

A supported capability **MUST** either:

> have all of its `x-manages` APIs surfaced, supported, and passing Firebolt Compliance tests.
>
> **OR**
>
> have a Firebolt Certification translation layer that translates all of its `x-manages` APIs into local, non-firebolt APIs so that certification can run.
44 changes: 24 additions & 20 deletions src/js/github.io/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -116,32 +116,36 @@ const capabilities = () => {
}
})

let manifest = '\n'
Object.entries(specification.capabilities).forEach( ([c, v]) => {
capabilities[c].level = v.level
})

let manifest = '\n## Capailities\n| Capability | Level | Uses | Provides | Manages |\n|-|-|-|-|-|\n'

const linkify = (method) => `[${method}](./${corerpc.methods.find(m => m.name === method) ? 'core' : 'manage'}/${method.split('.').shift()}/#${method.match(/\.on[A-Z]/) ? method.split('.').pop().charAt(2).toLowerCase() + method.split('.').pop().substring(3).toLowerCase() : method.split('.').pop().toLowerCase()})`
Object.keys(capabilities).sort().forEach(c => {
manifest += `### \`${c}\`\n`
const use = capabilities[c].uses.length ? `<details><summary>${capabilities[c].uses.length}</summary>${capabilities[c].uses.map(linkify).join('<br/>')}</details>` : ''
const man = capabilities[c].manages.length ? `<details><summary>${capabilities[c].manages.length}</summary>${capabilities[c].manages.map(linkify).join('<br/>')}</details>` : ''
const pro = capabilities[c].provides.length ? `<details><summary>${capabilities[c].provides.length}</summary>${capabilities[c].provides.map(linkify).join('<br/>')}</details>` : ''

if (capabilities[c].uses.length) {
manifest += '\n| Uses |\n'
manifest += '| ---- |\n'
manifest += `| ${capabilities[c].uses.map(linkify).join('<br/>')} |\n`
manifest += '\n\n'
}
manifest += `| \`${c}\` | **${capabilities[c].level.toUpperCase()}** | ${use} | ${pro} | ${man} |\n`
})

if (capabilities[c].manages.length) {
manifest += '\n| Manages |\n'
manifest += '| ------- |\n'
manifest += `| ${capabilities[c].manages.map(linkify).join('<br/>')} |\n`
manifest += '\n\n'
}

if (capabilities[c].provides.length) {
manifest += '\n| Provides |\n'
manifest += '| -------- |\n'
manifest += `| ${capabilities[c].provides.map(linkify).join('<br/>')} |\n`
manifest += '\n\n'
}
manifest += '\n## Methods\nCapability prefix `xrn:firebolt:capability` let off for readability.\n| Method | Level | Uses | Provides | Manages |\n|-|-|-|-|-|\n'

openrpc.methods.forEach(method => {
let uses = Object.entries(capabilities).filter( ([c, v]) => v.uses.includes(method.name)).map(([c, v]) => c)
let mans = Object.entries(capabilities).filter( ([c, v]) => v.manages.includes(method.name)).map(([c, v]) => c)
let pros = Object.entries(capabilities).filter( ([c, v]) => v.provides.includes(method.name)).map(([c, v]) => c)
let level = Array.from(new Set(uses.concat(mans).concat(pros).map(c => capabilities[c].level))).join(', ')

uses = uses.map(c => c.split(':').slice(3, 5).join(':')).map(c => `\`${c}\``).join(', ')
pros = pros.map(c => c.split(':').slice(3, 5).join(':')).map(c => `\`${c}\``).join(', ')
mans = mans.map(c => c.split(':').slice(3, 5).join(':')).map(c => `\`${c}\``).join(', ')
level = level.includes('must') ? 'must' : level.includes('should') ? 'should' : 'could'

manifest += `| ${linkify(method.name)} | **${level.toUpperCase()}** | ${uses} | ${pros} | ${mans} |\n`

})

Expand Down
2 changes: 1 addition & 1 deletion src/js/version-specification/capabilities.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const doImport = (source, target, clear=false, report=false) => {
logSuccess(`${report ? 'Missing' : 'Adding'} capability ${capability}.`)
}
result.capabilities[capability] = Object.assign({
level: 'must',
level: 'could',
use: {
public: uses.includes(capability),
negotiable: true && uses.includes(capability)
Expand Down
Loading
Loading