Files
mission-synth/README.md
T
2026-09-28 14:45:34 -04:00

145 lines
6.2 KiB
Markdown

# MissionSynth
Checks that a mission concept holds together: requirements traced to needs in
both directions, verification criteria someone can decide, architecture
options that differ, and a TRL claim capped by evidence.
## What it does and why
MissionSynth does not write requirements. Turning a concept into candidate
requirements and architectures is generative work, done by people or by a
model. What decides whether that output survives a review is whether it holds
together, and that part can be checked:
- every requirement traces to a stated need, and every need to a requirement;
- every requirement names a verification method and a criterion someone could
decide;
- the architecture options differ on at least one stated criterion;
- the claimed TRL does not exceed what the evidence demonstrates.
It is pure: no clock, no I/O and no model calls. Reports use the
`@extant2000/evidence-record` format. The requirement id is the key a
downstream traceability tool can pick up.
## Derivation, checked both ways
The two defects a requirement set tends to have are opposites, and a check in
one direction finds only one of them.
| Defect | Typical of |
|---|---|
| Invented: traces to no stated need | A generated set. Producing plausible requirements is easy; producing only warranted ones is not. |
| Unaddressed need: no requirement covers it | A hand-written set. The needs that get forgotten are the ones nobody enjoys thinking about. |
A parent id that does not exist (`dangling-parent`) is its own defect. It is
the same as no parent, and it looks like traceability.
A requirement with no verification method fails, and so does one whose
criterion cannot be decided. A requirement nobody can fail passes every
review. `isMeasurable()` is a smell test, not a grammar. It catches the common
cases ("user-friendly", "acceptable", "intuitive"), but a criterion can be
unmeasurable without using any of those words, so a clean result does not
prove the criterion is good.
## TRL, capped by evidence
Technology Readiness Level is usually self-assessed, and it only goes wrong in
one direction: nobody claims a level below what they can show. The
definitions are specific, which is what makes this checkable. Each level names
the environment something was demonstrated in, and an environment is a fact.
```
TRL 4 component validated in a laboratory
TRL 5 component validated in a relevant environment
TRL 6 system or subsystem model demonstrated in a relevant environment
TRL 7 system prototype demonstrated in an operational environment
```
`EVIDENCE_CEILING` maps each kind of demonstration to the highest level it can
support. A bench test or a unit test (`lab-bench`) supports TRL 3, so a TRL 6
claim backed by one is capped at 3. The best evidence sets the ceiling:
having also written a paper does not drag down a system demonstration. No
evidence at all returns `null`, not TRL 1, because TRL 1 is itself a claim
that principles were observed and reported.
`maturationPath()` runs from the effective level, not the claimed one, and
each step names the demonstration that raises the number. A roadmap whose
steps produce no evidence is a schedule.
## A trade study with nothing to trade
- **One option** is a decision already made. It is reported as not assessed,
whatever the document is called.
- Options identical on every criterion fail at critical severity. The table is
full, the columns are populated, and the choice rests on something not
written down, which is why this passes a quick review.
- Criteria that are the same across all options are named as doing no work in
the decision. That is a note, not a fault.
- An option that satisfies a strict subset of another's requirements and adds
nothing of its own is flagged as dominated. It may still win on cost, but
carrying it unexamined makes the study look broader than it is.
- A requirement that no option satisfies fails.
## Usage
```ts
import { synthesize, formatSynthesis, type MissionConcept } from '@extant2000/mission-synth'
const concept: MissionConcept = {
name: 'deorbit module',
needs: [
{ id: 'N-1', statement: 'deorbit within 25 years of end of mission',
source: 'debris mitigation guideline', where: 'concept/needs.md' },
{ id: 'N-2', statement: 'survive launch loads', source: 'launch provider', where: 'concept/needs.md' },
],
requirements: [
{ id: 'SYS-001', statement: 'The system shall deorbit within 25 years', derivedFrom: ['N-1'],
verification: { method: 'analysis', criterion: 're-entry at less than 25 years' },
where: 'concept/requirements.md' },
{ id: 'SYS-002', statement: 'The system shall be easy to integrate', derivedFrom: [],
verification: { method: 'inspection', criterion: 'integration is intuitive' },
where: 'concept/requirements.md' },
],
options: [
{ id: 'A', name: 'drag sail', satisfies: ['SYS-001'], criteria: { mass: 'low', cost: 2 }, where: 'trade/a.md' },
{ id: 'B', name: 'propulsive', satisfies: ['SYS-001'], criteria: { mass: 'low', cost: 2 }, where: 'trade/b.md' },
],
claimedTrl: 6,
targetTrl: 7,
maturity: [{ evidence: 'lab-bench', description: 'deployment mechanism cycled on the bench', where: 'test/TR-12' }],
}
const report = synthesize(concept)
console.log(formatSynthesis(concept))
```
The finding lines from that output (header, notes and detail lines omitted):
```
✗ CRITICAL 1 requirement(s) satisfied by no option: SYS-002 [NOT MET]
✗ CRITICAL No criterion tells the 2 options apart [NOT MET]
✗ CRITICAL N-2 is stated and no requirement covers it [NOT MET]
✗ CRITICAL SYS-002: invented [NOT MET]
✗ CRITICAL TRL 6 claimed, evidence supports TRL 3 [NOT MET]
✗ HIGH SYS-002: immeasurable [NOT MET]
◦ info SYS-001 traces to N-1 and is verifiable by analysis [MET]
```
The notes also give the maturation path to TRL 7: four steps starting from
the effective TRL 3, not one step from the claimed TRL 6.
The building blocks are exported too: `requirementIssues()`,
`unaddressedNeeds()`, `isMeasurable()`, `nonDiscriminating()`,
`isUndiscriminated()`, `dominatedOptions()`, `uncoveredRequirements()`,
`supportedTrl()`, `assessTrl()` and `maturationPath()`.
## Install
```
npm install @extant2000/mission-synth
```
## License
MIT. See [LICENSE](LICENSE).