User manual
Description
Annotated speech corpora circulate between tools. A corpus is transcribed in one software, aligned in another, analysed in a third, archived in a fourth. Each of these tools defines its own file format, and each format embodies a particular view of what an annotation is: a label on a point in time, a labelled interval, a hierarchy of tiers, a document carrying metadata. No format is a superset of the others. Moving annotations from one tool to another is therefore not a matter of translation, but of transposition: what the source expresses and the destination cannot hold has to be left behind.
This asymmetry is rarely visible to the people who depend on it. Annotation files are, for most of their users, opaque: opening one in a text editor reveals syntax, not structure. The user knows the corpus — the speakers, the tiers, the annotation scheme — but has no direct way to know whether the format they are exporting to is able to carry it. Conversion tools generally answer this by silence: either the operation succeeds, and the loss goes unnoticed, or it fails, and the reason belongs to the internals of the format rather than to anything the user can act upon.
The application "Convert" takes the opposite stance. Its purpose is not only to produce a file in another format, but to make the transposition itself intelligible. What a format is able to hold is stated before the conversion is launched, not discovered afterwards. What a format is unable to hold is expressed as a choice offered to the user, at the moment where the target format is selected, and applied uniformly to the whole set of files. What cannot be transposed at all is reported explicitly, file by file, with its cause.
This stance has a consequence on the shape of the tool. "Convert" operates on sets of files, heterogeneous in format and unknown in content at the time the user makes their decisions. It does not inspect a file in order to propose a tailored treatment; it lets the user state, once, how the annotations are to be written, and applies that decision to every file. The intelligibility "Convert" aims at is therefore not the intelligibility of a particular file, but of the destination format and of what reaching it costs.
"Convert" belongs to the SPPAS ecosystem and relies on its reading and writing capabilities, which cover a wide range of formats used in speech and multimodal annotation. It is available both as a page of the SPPAS Dashboard and as an online application, addressing the same need in two contexts of use: within a working session on a local corpus, or as an occasional service.
Accessibility is treated here as a functional requirement rather than an added quality: the information "Convert" exposes — supported properties, options, statuses — is of no use if it is not perceivable, and the tool is designed accordingly.
Defining the requirements
Problem statement and objectives
Converting annotation files raises a difficulty that is neither technical nor linguistic, but epistemic: the user must decide, before anything happens, what to do with information that the destination cannot receive. Formats differ in what they are able to express, and those differences are not documented anywhere the user is likely to look. The decision is therefore taken blindly, and its consequences appear only afterwards — as a file that fails to be written, or worse, as a file that is written and silently amputated.
The central problem addressed by "Convert" is thus:
how to let a user convert a set of annotation files to a chosen format, while making the cost of that choice knowable in advance and the outcome verifiable afterwards, without requiring any knowledge of how formats are internally organised.
This problem is sharpened by the conditions of use. Conversion is a batch operation: it applies to a set of files whose contents are not examined at the moment the user decides. It is also a directed operation: users convert because they are moving from one tool to another, with a definite destination in mind. Convert must therefore support decisions taken once, in ignorance of individual file contents, and applied uniformly — while remaining accountable for each file individually.
The objectives follow:
- to let the user select one destination format among those that can be written, and to expose what that format is able to hold at the moment of the choice;
- to let the user state, before conversion, how annotations are to be written when the destination cannot hold them as they are, these statements being attached to the format and not to any file;
- to apply the same decisions to every file of the batch, and to report the outcome of each file separately, an individual failure never interrupting the others;
- to give the user access to the converted files, in a manner adapted to the context of use;
- to guarantee accessibility, of the interface and of the information the tool exposes;
- to remain part of the SPPAS ecosystem, reusing its reading and writing capabilities without exposing them.
"Convert" does not aim to prepare files, to edit annotations, nor to correct a corpus. It aims to make one operation — writing annotations in another format — deliberate rather than accidental.
Expressing the requirements
Choosing a destination in full knowledge
A user selects a destination format because a tool downstream requires it, not because they know what that format can hold. The choice is therefore made under a constraint the user cannot evaluate. Convert answers this by presenting, alongside each writable format, the properties it supports — several tiers or one, metadata, hierarchies, controlled vocabularies, overlapping annotations, typed labels, and so on. This information is not documentation placed beside the tool; it is part of the act of choosing, available at the moment the decision is taken. Its presentation must make a comparison possible at a glance and remain legible to someone who has never opened an annotation file in an editor: the properties of a format are a technical matter, but understanding them must not require technical expertise.
Stating export options before reading anything
When a destination cannot hold what a source expresses, something must be decided. That decision belongs to the user, and it must be expressible without knowing which files will be affected: the batch is heterogeneous and its contents are not examined beforehand. Convert therefore attaches export options to the destination format itself. The options describe how to write, not what any file contains. Chosen once, they apply to the whole batch, and their meaning must be intelligible independently of any particular file.
Delimiting the set of files to convert
The files to be converted come from the working context, not from the tool: in a working session, they are the files currently selected in the workspace; in an occasional use, they are the files the user brings to the tool. The requirement is the same in both cases — the user delimits a set, Convert operates on that set, and the set is not silently altered. The two contexts differ only in their material constraints, an occasional use being bounded by what a service can reasonably receive.
Reporting each file individually
A batch is not an operation, but a series of operations sharing the same decisions. Some will succeed, some will not, for reasons belonging to the individual file rather than to the choices made. The user must be able to see, for every file, what happened to it: written, refused, or left untouched — and why. A refusal is stated in terms the user can act upon, and it never stops the files that follow. Reporting is therefore not a side effect of the conversion; it is what makes the operation verifiable.
Reaching the converted files
A conversion that produces files the user cannot find has not converted anything. In a working session, the produced files join the workspace and remain available to the following operations. In an occasional use, they are handed back to the user. The requirement is that the outcome be reachable without the user having to know where the tool put it.
Accessibility
Everything above rests on information being exposed: supported properties, available options, statuses, causes. This information is useless if it cannot be perceived. Contrast, legibility, text alternatives to any graphical encoding, keyboard operation, consistent terminology between the interface and the concepts it manipulates: these are conditions of the tool working at all, not qualities added to it. Convert exposes a technical subject to a non-technical audience; the burden of intelligibility lies entirely on the interface.
Modelling
Requirements
The previous sections state what users need and why; this section states what the system does to answer it, and what it manipulates in order to do so.
Two markers are used throughout. [API-OK] denotes what is achievable with the current SPPAS API. [API-EXT] denotes what requires an extension of that API. A requirement marked [API-EXT] is part of the model; it remains inactive until the API supports it.
Concepts manipulated by the application
The data dictionary of this application. Thirteen concepts, and the model below names no other.
- D1. Format
- A way of writing annotations on disk, identified by an extension and associated with a piece of software.
- D2. Format property
- A boolean characteristic of a format, stating what that format is able to hold. Properties belong to formats, never to files.
- D3. Destination format
- The single format, among those that can be written, into which the batch is converted.
- D4. Batch
- The set of files delimited by the user, heterogeneous in format, whose contents are unknown at the time decisions are taken.
- D5. Export option
- A question raised by what the destination format cannot hold, together with the answers available for it. Options are derived from properties, not written per format. An option covers one property where answering alters the annotations, and several where it does not.
- D6. Answer
- The user's decision for one option, applied to every file of the batch.
- D7. General option
- A decision independent of the destination format: overriding an existing output, detecting the format of an input whose extension is unknown.
- D8. Remediation
- A transformation applied to the annotations of one file, after reading and before writing, implementing the answer chosen for an option.
- D9. Structural loss
- Information not written because the destination format cannot hold it. Determined by the destination alone, identical for the whole batch, announced once.
- D10. Contingent loss
- Information not written, or content transformed, because of what one particular file contained. Determined at reading, reported for that file.
- D11. Status
- The outcome of one file: written, written with remarks, refused, or skipped.
- D12. Remark
- A contingent loss reported on one file.
- D13. Cause
- The explicit reason a file was refused.
Deriving the options from the destination format
The correspondence between an unsupported property, the question it raises, and the answers available for it is data of the model, not code. Adding a property to the API adds an entry to this table; it does not modify Convert.
The options are of two kinds, and the line between them is whether answering alters the annotations. Some unsupported properties concern what surrounds the annotations — metadata, controlled vocabularies, media declarations. Keeping them changes nothing of what was annotated. Others concern the annotations themselves, or the shape of the result: answering transforms the content, or the number of files produced. The first kind is decided once; the second, property by property.
Preservation: one decision
Where the destination cannot hold metadata, controlled vocabularies or media declarations, the user is not asked where to put them, but whether to keep them:
| Question raised | Answers | Properties covered |
|---|---|---|
| keep what the format cannot hold | yes / no | metadata, ctrl_vocab,
media |
Answering yes lets SPPAS write that information wherever the destination allows: as comments where the format holds them (a), in a tier otherwise (b). Answering no discards it. Where the destination allows neither, yes has the same effect as no, and the option is not offered.
The answer has a default no user has to look for: the setting of the
application, interoperability, true
[API-OK]. Maintaining interoperability is the
normal state; accepting the loss is a choice.
That setting is a default, not the decision. It is global — it weighs on the annotations as much as on the conversions — while its effect is seen here, on a page a user reaches without ever opening the settings. Convert therefore states the effective answer where it applies, and lets it be changed for this conversion alone. Online, where no setting is kept for a given user, the value of the page is the only one there is.
Where SPPAS writes what it preserves is a mechanism, not a decision. Users divide into those who want their file and care for nothing else, and those who want nothing lost; neither arbitrates between metadata and controlled vocabularies. Offering three answers for each of three properties would ask nine questions no one has.
Structure: one decision per property
The remaining options alter the annotations or the shape of the result. They are decided individually, because answering one says nothing of the others:
| Unsupported property | Question raised | Answers |
|---|---|---|
multi_tiers |
several tiers in the file | one file per tier / skip the file |
point |
tiers of points | convert into intervals / skip the tier |
alt_tag |
alternative labels | keep all / keep the best scored |
tag_types |
typed labels | convert into strings / skip the tier |
tag_geometry |
geometric labels | convert into strings / skip the tier |
alt_tag belongs here and not to preservation: discarding the
alternatives of a label, however poorly scored, alters the annotation. What is
written is no longer what was annotated, and that is a decision only the user
can take.
(a) The property accept_comments states it,
read by comments_support()
[API-OK]. The API was already writing metadata as
comments when the format allows it, and forgetting them otherwise; it now
exposes that capability.
(b) Writing metadata, controlled vocabularies and media as
a tier is done by create_unsupported_tier(), and read back by
parse_unsupported_tier()
[API-OK]. The tier is named
DoNotEdit; see the annex for what it holds.
Properties raising no question
The remaining unsupported properties raise no question, because nothing can be fabricated and no transformation preserves the content:
no_tiers— a file holding no tier at all cannot be written.empty_tier[API-OK] — a tier holding no annotation is removed where the destination refuses it, whichempty_tier_support()states beforehand; see 3.3.interval— intervals cannot be reduced to points. A file holding intervals is refused. The converse is remediable, hence thepointoption above.hierarchy,disjoint,alt_localization,radius,gaps,overlaps— cause a structural loss, announced once for the batch.
Extensions of the API required by this section
None: the three extensions this section was stating are available
[API-OK]. They are
empty_tier_support(), comments_support(), and the
pair create_unsupported_tier() /
parse_unsupported_tier(). The annex states what they do and what
they cost.
Remediation chaining
Remediations are not independent, and their order is not neutral. Removing empty tiers can leave a file with no tier, which the destination may refuse. Splitting a multi-tier file into one file per tier can produce a file whose single tier is empty. A remediation is therefore never final: it produces a new content, which is verified again against the properties of the destination.
A chain may end in a refusal. This is not a failure of the model: it means the content, once adapted as far as the destination allows, still exceeds what that destination can hold. The cause reported is the one that ended the chain, stated in terms of the user's data.
Conversion of one file
Anticipation comes first; the typed exceptions of the API act as a safety net for what anticipation did not catch.
- Read the file, applying the general option on format detection.
- Anticipate: compare the content read to the properties of the destination, apply the remediations chosen, chain and re-verify (3.3).
- Write.
- If writing fails on a typed exception identifying a remediable cause, remediate and write once more. One second pass only.
- If it fails again, or on a non-remediable cause, refuse the file and state the cause.
The failure of one file never interrupts the batch.
The typed exceptions of the current API relevant to writing are
AioMultiTiersError (1510), AioNoTiersError (1515),
AioEmptyTierError (1525) and AioLocationTypeError
(1530) [API-OK]. They identify refusals bound to
the properties of the destination, and are usable as causes as they
stand.
Requirements as specified
[010] Starting a conversion
- [011] The user can initiate a conversion of a set of annotation files.
- [012] The system initialises a conversion with no destination and no batch.
[020] Understanding the process
- [021] The user can identify what is required before a conversion can run.
- [022] The system states which decisions are missing.
[030] Controlled progression
- [031] The system allows a conversion to run only if a destination format is selected and the batch is not empty.
[100] Destination format
- [101] The user can select one destination format.
- [102] The system restricts the choice to the formats it is able to write.
- [103] The system presents, for each format, the properties it supports.
- [104] The system presents this information in a form comparable at a glance and intelligible without knowledge of file internals.
- [105] The user can select at most one destination format at a time.
- [106] The user can cancel the current selection.
[200] Batch
- [201] The user delimits the set of files to convert.
- [202] The system operates on that set and does not alter it.
- [203] The system reports when the set is empty.
[300] Export options
- [301] The system derives the options from the properties of the selected destination format.
- [302] The system presents an option for each unsupported property for which a remediation exists and answering alters the annotations, and a single option covering those for which it does not.
- [303] The user can choose one answer per option.
- [304] The system applies a default answer to any option left unanswered.
- [305] The answers apply to every file of the batch.
- [306] The options are stated before any file is read.
- [307] The system restricts the answers offered to those the destination format allows.
- [308] The system takes the answer of the preservation option from the settings of the application, states it on the page, and lets the user change it for this conversion without altering the settings.
[400] General options
- [401] The user can allow or forbid overriding an existing output file.
- [402] The user can allow or forbid detecting the format of an input file whose extension is unknown.
[500] Announcing structural loss
- [501] The system announces, once for the batch, what the destination format cannot hold.
- [502] The system does not report structural loss per file.
[600] Converting
- [601] The system reads each file of the batch.
- [602] The system applies the chosen remediations before writing.
- [603] The system re-verifies the content against the destination after each remediation.
- [604] The system writes each file in the destination format.
- [605] The system attempts a second write after remediating a typed failure.
- [606] The failure of one file never interrupts the batch.
[700] Reporting
- [701] The system reports a status for every file of the batch.
- [702] The system reports the remarks attached to a file.
- [703] The system states the cause of every refusal.
- [704] The system states the cause in terms of the user's data, not of the internals of the format.
[800] Reaching the results
- [801] The system makes the converted files reachable to the user.
- [802] The system makes them reachable without the user knowing where they were written.
[900] Restarting
- [901] The user can start a new conversion.
- [902] The system resets the decisions without resetting the batch.
[1000] UX and accessibility
- [1001] The system provides text alternatives to any graphical encoding of a property.
- [1002] The system uses consistent terminology between interface and concepts.
- [1003] The system is operable by keyboard and by screen reader.
- [1004] The system provides explicit messages at every decision point.
Conceptual model
Convert holds no persistent data. Everything it manipulates belongs to one conversion in progress, and is derived from a small number of user decisions. This section states who it exchanges with, which data exist, what produces them, what invalidates them, and on which event each treatment runs.
Conceptual model of communication
Four actors border Convert, and only one of them is a person. Three are neighbouring systems, and Convert writes into none of them.
Actors
- A1. The user — she chooses a destination format, answers the options it raises, sets the general options, runs the conversion, reads what happened to each file, reaches what was produced, and starts again.
- A2. The provider of files — it exposes a set of files, possibly empty, in both contexts of execution. It is the domain of the provision of files, and the batch is what it exposes.
- A3. The API of SPPAS — it says which formats can be written and what each of them holds, it reads annotations, it writes them, and it names the cause when it will not.
- A4. The settings of SPPAS — they hold
interoperability, which is the default answer of the preservation option and nothing more.
Flows
- F1. A1 → Convert — the destination chosen, or its cancellation [101], [106].
- F2. Convert → A1 — the formats which can be written, and what each of them holds, comparable at a glance [102], [103], [104].
- F3. Convert → A1 — the options that destination raises, the answers each offers, and the answer which holds if none is given [301], [302], [307], [308].
- F4. A1 → Convert — one answer for one option [303].
- F5. A1 → Convert — a general option [401], [402].
- F6. Convert → A1 — what the destination cannot hold, once for the batch [501].
- F7. Convert → A1 — what is still missing before a conversion can run [021], [022], [203].
- F8. A1 → Convert — run the conversion [031].
- F9. A1 → Convert — start a new conversion [901].
- F10. Convert → A1 — a status for every file, the remarks attached to it, and the cause of a refusal, stated in terms of her data [701] to [704].
- F11. Convert → A1 — the converted files, reached without her knowing where they were written [801], [802].
- F12. A2 → Convert — the batch: a set of files, possibly empty [201].
- F13. Convert → A3 — which formats can be written, and what each of them holds.
- F14. Convert → A3 — a file to read, and whether its format may be detected [402].
- F15. A3 → Convert — the annotations of that file, or a typed cause.
- F16. Convert → A3 — the annotations to write, in the destination format [604].
- F17. A3 → Convert — written, or a typed cause [605].
- F18. A4 → Convert — the value of
interoperability[308].
Two flows do not exist, and each of them is a requirement. Nothing goes from Convert to A2: the batch is read and never altered [202]. Nothing goes from Convert to A4: the answer is stated on the page and changed for one conversion, and the settings do not move [308].
A3 is the only neighbour which is written to, and what is written there is a file, never a state: Convert relies on the reading and writing capabilities of SPPAS and never exposes them.
Conceptual model of data
Nine classes. Three of them are the knowledge of formats, which is data of the model and not code; three belong to one conversion in progress; three belong to what it produced. Nothing here survives a conversion but the first three.
The classes of entities
| Class | Properties | What it is |
|---|---|---|
| FORMAT | # format, extension, software, can be written | A way of writing annotations on disk (D1). What it holds is R1, and it is read from the API |
| PROPERTY | # property | A boolean characteristic of a format, stating what that format is able to hold (D2). It belongs to formats, never to files |
| OPTION | # option, question, default answer, alters the annotations | The question raised by what a destination cannot hold (D5). It is the catalogue, and it is data of the model |
| ANSWER | # option, # answer, remediation | One of the answers an option offers (D6). It exists only inside its option, and names the remediation it asks for (D8) |
| CONVERSION | # conversion, destination, override, heuristic | One conversion in progress: the destination chosen and the two general options (D3, D7). It exists while it is decided upon |
| FILE | # file | One file of the batch (D4). It is exposed by A2, and this domain holds its identity and nothing else |
| CHOICE | # conversion, # option, # answer | The answer this conversion holds for one option. Absent, the default of the option is what holds [304] |
| RESULT | # conversion, # file, status, cause | What happened to one file of one batch: its status (D11) and, when it was refused, the cause (D13) |
| REMARK | # conversion, # file, # remark, what it says | A contingent loss reported on one file (D10, D12). There may be several, and there may be none |
The relations
| No. | Verb | Leg 1 | Leg 2 |
|---|---|---|---|
| R1 | supports | FORMAT (0,n) | PROPERTY (0,n) |
| R2 | covers | OPTION (1,n) | PROPERTY (0,1) |
| R3 | offers | ANSWER (1,1) | OPTION (1,n) |
| R4 | is converted by | FILE (0,n) | CONVERSION (0,n) |
| R5 | is decided in | CHOICE (1,1) | CONVERSION (0,n) |
| R6 | answers | CHOICE (1,1) | OPTION (1,n) |
| R7 | reports on | RESULT (1,1) | FILE (0,n) |
| R8 | belongs to | RESULT (1,1) | CONVERSION (0,n) |
| R9 | carries | REMARK (1,1) | RESULT (0,n) |
R2 is where the model is data and not code. An option covers one
property where answering alters the annotations, and several where it does
not: the preservation option covers metadata,
ctrl_vocab and media, which is why its leg reads
(1,n). A property covered by no option is (0,1) on its side, and it is
exactly what makes a structural loss. Adding a property to the API adds a row;
it modifies nothing.
R3 and R9 are aggregations: an answer is named inside the option which offers it, a remark inside the result which carries it, and neither has any existence outside it. R7 and R8 together identify a result: one file of one conversion has one result and no more.
A conversion holds no file. R4 is a relation and not a holding: the batch is exposed by A2, Convert reads it and never alters it [202]. What this domain knows of a file is its identity, which is what it takes to give it a result.
Computed, and never held
- The properties of the destination, which are R1 read for one format.
- The options raised, which are R2 read for the properties that format does not support, restricted to the answers that format allows [307].
- The structural loss, which is what the destination does not support and no option covers (D9). It depends on the destination alone, and is the same for every file of the batch.
- The answer which holds for an option, which is the choice when there is one and the default otherwise [304].
- The effective default of the preservation option, which is
interoperabilityread from A4 [308]. - What is still missing before a conversion can run, which is a destination and a batch which is not empty [031].
- The files produced, which stand where the API wrote them: one file of the batch may produce several, and none of them is held here.
What one conversion carries, in the words the code will use
destination— one format, among those that can be written.properties— the boolean characteristics ofdestination, stating what it is able to hold.options— the questions raised by the unsupported properties for which a remediation exists, each with its available answers.answers— one decision per option.general_options—override(boolean),heuristic(boolean).batch— a set of files, possibly empty.structural_loss— whatdestinationcannot hold.results— one result per file of the batch, each holding a status ∈ {written, written with remarks, refused, skipped}, the remarks attached to it, and the cause of a refusal.
Their dependencies, which the treatments below turn into events:
destination → propertiesproperties → optionsproperties → structural_lossoptions → answers(batch ∧ destination ∧ answers ∧ general_options) → results
What is not modelled, and why
- The annotations themselves, which are the API's: this domain reads them, transforms them through a remediation, and writes them back, holding none.
- The files of the batch beyond their identity, which are A2's [202].
- The settings, which are A4's and are read and never written [308].
- The remediations themselves (D8), which are what an answer names and what the API performs. The model says which answer asks for which; how it is done is not of this level.
Conceptual model of treatments
Eight treatments. Six are the decisions and the conversion; two were brought out by writing the events, three requirements having had no treatment to stand in. Each one says on which event it runs, what it does, and under which condition each of its results is emitted.
The events
| No. | Event | Kind | Comes from |
|---|---|---|---|
| E1 | The user chooses a destination format | external | F1 |
| E2 | The user cancels the destination | external | F1 |
| E3 | The user answers an option | external | F4 |
| E4 | The user sets a general option | external | F5 |
| E5 | The batch is exposed | external | F12 |
| E6 | The user asks for the conversion to run | external | F8 |
| E7 | The user asks for a new conversion | external | F9 |
| E8 | The destination is defined | internal | T01 |
| E9 | The options are known | internal | T02 |
| E10 | A decision has changed | internal | T01, T03, T04, T05 |
| E11 | The batch has been converted | internal | T06 |
E10 is the event this application turns on. Every treatment which takes a decision emits it, and two treatments listen: the results are invalidated, and what is still missing before a conversion can run is said again [021], [022]. No treatment is written for that announcement: it is a result of the four, because a decision which changed is the only moment at which what is missing can have changed.
Nothing here waits for two events. T06 is the only treatment with a condition on its synchronisation, and that condition is read on the data it already holds, not on a second event.
T01 — Set the destination format
- Event: E1 or E2.
- Purpose: define the format into which the batch is to be converted.
- Inputs: user choice (one format).
- Outputs:
destination. - Preconditions: none.
- Postconditions:
destinationis available to T02 and T06. - Rules:
- the format must be one the system is able to write;
- at most one destination is defined at a time;
- the destination may be cancelled, leaving it undefined;
- any change of destination invalidates
properties,options,answers,structural_lossandresults.
- Emission:
destinationand E8, when a format is chosen and it is one the system can write;destinationundefined and E10, when it is cancelled; F7, always; E10, always.
T02 — Derive the options and the structural loss
- Event: E8.
- Purpose: state what the destination cannot hold, and which of it can be decided upon.
- Inputs:
destination. - Outputs:
properties,options,structural_loss. - Preconditions:
destinationdefined. - Postconditions:
optionsare available to T03;structural_lossis available for announcement. - Rules:
- the correspondence between an unsupported property, the question it raises and the answers available is data of the model, not code;
- an unsupported property with no remediation produces no option and
contributes to
structural_loss; - the answers offered are restricted to those the destination allows, which may depend on other properties of that same destination;
structural_lossdepends on the destination alone: it is identical for every file of the batch;- this treatment reads no file.
- Emission:
properties,optionsand E9, always; F3, when at least one option is raised; F6, when the destination does not support a property no option covers.
T03 — Answer the options
- Event: E3, the options being known (E9).
- Purpose: decide how annotations are to be written when the destination cannot hold them as they are.
- Inputs:
options, user choices. - Outputs:
answers. - Preconditions:
optionsdefined. - Postconditions:
answersare available to T06. - Rules:
- one answer per option, chosen among the answers that option offers;
- an option left unanswered takes its default answer;
- the answers apply to every file of the batch;
- the answers are decided without any file being read;
- any change of an answer invalidates
results.
- Emission:
answers, always; E10, always. Nothing is emitted for an option left unanswered: its default is what holds [304].
T04 — Set the general options
- Event: E4.
- Purpose: decide what does not depend on the destination.
- Inputs: user choices.
- Outputs:
general_options. - Preconditions: none.
- Postconditions:
general_optionsare available to T06. - Rules:
overridestates whether an existing output file may be replaced;heuristicstates whether the format of an input file whose extension is unknown may be detected;- both default to false;
- any change invalidates
results.
- Emission:
general_options, always; E10, always.
T05 — Delimit the batch
- Event: E5.
- Purpose: define the set of files to convert.
- Inputs: the working context.
- Outputs:
batch. - Preconditions: none.
- Postconditions:
batchis available to T06. - Rules:
- the batch is delimited by the user, not by the system;
- the system does not alter the batch;
- the batch is heterogeneous in format and unknown in content;
- the batch may be empty, which forbids T06;
- any change of the batch invalidates
results.
- Emission:
batch, always; E10, always; F7 saying the set is empty, when it is [203].
T06 — Produce the results
- Event: E6, and a destination defined and a batch which is not empty [031].
- Purpose: write the annotations of every file of the batch in the destination format, and state what happened to each.
- Inputs:
batch,destination,answers,general_options. - Outputs:
results, converted files. - Preconditions:
destinationdefined;batchnot empty;answersdefined for every option. - Postconditions: every file of the batch holds a result; the converted files are reachable by the user.
- Rules:
- each file of the batch is treated independently; the failure of one never interrupts the others;
- a file is read first, applying
heuristic; - the content read is then compared to
properties, and the remediations stated byanswersare applied before writing; - a remediation produces a new content, which is verified again
against
properties; remediations therefore chain, and a chain may end in a refusal; - writing that fails on a typed cause for which a remediation exists is retried once, after that remediation; there is no further pass;
- a file that cannot be written is refused, with a cause stated in terms of the user's data;
- a file whose output already exists is skipped, unless
overrideallows it; - a remediation that transformed the content of one file produces a remark on that file;
- what
destinationcannot hold is not remarked per file: it belongs tostructural_loss, announced once; - one file may produce several converted files;
- this treatment does not alter the batch.
- Emission: One result per file, always; F10, always; E11, always. Nothing is emitted before the whole batch has been treated: a file which fails emits its result and never interrupts the others [606].
T07 — Start a new conversion
- Event: E7.
- Purpose: take the decisions back to what they were before any were taken, without taking the batch away.
- Inputs: user choice.
- Outputs:
destination,options,answers,general_options,structural_lossandresults, all undefined. - Preconditions: none.
- Postconditions: the conversion is in the state T01 finds it in at the beginning [012].
- Emission: F2, always; F7, always; E10, always.
- Rules:
- the batch is not reset: it was not decided here, and it is not this application which delimits it [902];
- the general options are decisions and are reset with the others;
- nothing of what was written on disk is undone: a new conversion is a new set of decisions, not the undoing of a conversion which ran.
T08 — Make the converted files reachable
- Event: E11.
- Purpose: that the user reaches what was produced without knowing where it was written.
- Inputs:
results, and the files the API wrote. - Outputs: the way each produced file is reached.
- Preconditions: the batch has been converted.
- Postconditions: every file which was written is reachable, and the user was told where none of them stands [801], [802].
- Emission: F11, for every file which was written; nothing at all for a file which was refused or skipped.
- Rules:
- one file of the batch may have produced several files, and each of them is reached;
- this application does not say where a file stands: where it was written is the business of what provided the files, and reaching it is asked of that one [802];
- this treatment writes nothing and moves nothing.
Organisational level
Organisational model of treatments
One procedure per treatment, numbered as it is. There are two contexts of execution and one organisation: what differs between the local server and uwsgi is who exposes the batch, and nothing of what is done. Convert is served identically by the two, which is why there is one table and not two.
| PF | What it does | Triggered by | In charge | Where | When | Nature |
|---|---|---|---|---|---|---|
| PF1 (T01) | Sets the destination format, or cancels it | E1, E2 | the user, and the server which restricts the choice | the browser, then the server | whenever she chooses or cancels | conversational |
| PF2 (T02) | Derives the options and the structural loss | E8 | the server | the server | as soon as a destination is defined | automated |
| PF3 (T03) | Answers an option | E3 | the user | the browser, then the server | whenever she answers one | conversational |
| PF4 (T04) | Sets a general option | E4 | the user | the browser, then the server | whenever she sets one | conversational |
| PF5 (T05) | Delimits the batch | E5 | the provider of files, and never Convert | outside this application | before Convert is reached locally; when the files are given, online | automated |
| PF6 (T06) | Produces the results | E6 | the server | the server | when she asks, and only then | automated |
| PF7 (T07) | Starts a new conversion | E7 | the server | the server | when she asks | automated |
| PF8 (T08) | Makes the converted files reachable | E11 | the provider of files | the server, then her machine | as soon as the batch has been converted, then when she follows | automated, then conversational |
Every procedure ends on the server, and none of them ends in the browser. Three are conversational, and in all three what the browser holds is the gesture: the format clicked, the answer chosen, the box ticked. What that gesture means — which options a format raises, which answers it allows, what is still missing — is knowledge of formats, and the client holds none of it. RO1
PF5 is in nobody's charge here. The batch is exposed by a neighbour in both contexts, and this application reads it. It appears in this table so that the one procedure Convert does not perform is written down, and not passed over in silence. RO5
PF6 is one request, and it is the only long one. The results replace what was shown when it ends; nothing is shown per file while it runs. A batch which takes minutes holds that request for minutes, and this level says so rather than leaving it to be discovered. What would show progress per file is not modelled, and it is the one thing this table leaves to be decided. RO6
What the user acts on
Client-side triggers
- Selecting the destination format
- Cancelling the selected destination format
- Answering an export option
- Setting a general option
- Requesting the conversion to run (triggers T06)
- Requesting a new conversion (resets the decisions)
Selecting a destination triggers T02 and produces the options and the structural loss. This is a server request: the correspondence between properties and options is data of the model, and the client holds no knowledge of formats.
Navigation
Convert is a single page. The conversion is not a pathway in the sense TextCueS gives that word: there are no successive steps, but decisions taken in any order, and one operation which requires them. The page shows the formats, the options derived from the selected one, the general options, and the results once the conversion has run.
From the page:
- one can select and cancel a destination without leaving it;
- one can run a conversion, which replaces the results shown;
- one can start a new conversion, which resets the decisions.
Rules of organisation
- RO1 — The client holds no knowledge of formats. Every derivation is a server request, the correspondence between properties and options being data of the model.
- RO2 — The two contexts of execution are one organisation. What differs is who exposes the batch, never what is done with it, and the two deployments are one implementation.
- RO3 — The decisions are taken in any order. None of them is a step, and none is a precondition of another: only the conversion requires them all.
- RO4 — A decision is never refused because another is missing. What is still missing is said [022], and running is forbidden until it is not [031].
- RO5 — The batch is exposed by a neighbour and read. Convert selects no file, in either context, and alters none [202].
- RO6 — The conversion is one request. The results replace what was shown when it ends, and the failure of one file never ends it [606].
- RO7 — A setting is read and never written. The answer which holds is carried by the page, for this conversion alone [308].
- RO8 — What one conversion has decided is carried between two requests by what the page transmits, and by nothing held on the server. Online, no setting and no session is kept for a given user, and a decision held on the server would be a decision belonging to somebody.
RO8 is what makes the two contexts one organisation: a conversion which keeps nothing on the server is served the same way by a server which knows the person and by one which does not. It is also what T07 rests on — starting again is transmitting nothing rather than undoing something.
Constraints
What the code holds to
Gathered from the rules of the treatments and from the requirements they answer, and written here once so that each of them has one place and one only. Nothing is added: what follows was already said, and what this chapter buys is that a constraint can be pointed at.
| No. | Constraint | Imposed by |
|---|---|---|
| C1 | At most one destination is defined at a time, and it may be cancelled, leaving none. | [105], [106], T01 |
| C2 | A destination is one of the formats the system is able to write. | [102], T01 |
| C3 | A decision which changes invalidates everything derived from it, which is then neither reused nor shown. | T01, T03, T04, T05, and E10 |
| C4 | The correspondence between an unsupported property, the question it raises and the answers available is data of the model, never code. | T02, and what adding a property to the API must cost |
| C5 | The answers offered for an option are restricted to those the destination allows. | [307], T02 |
| C6 | The structural loss depends on the destination alone: it is the same for every file, and it is announced once and never per file. | [501], [502], T02 |
| C7 | The options are stated before any file is read. | [306], T02, T03 |
| C8 | An option left unanswered takes its default answer, which reproduces what the API does today where it does something. | [304], T03 |
| C9 | An answer applies to every file of the batch. | [305], T03 |
| C10 | The general options default to false. | T04 |
| C11 | The batch is read and never altered, and no file is selected here. | [201], [202], T05, RO5 |
| C12 | A conversion runs only with a destination defined and a batch which is not empty. | [031], T06 |
| C13 | Each file is treated on its own, and the failure of one never interrupts the others. | [606], T06 |
| C14 | A remediation produces a new content, which is verified against the destination again. | [603], T06 |
| C15 | A remediation is applied at most once for one file, which is what ends the chain. | C14, and a loop needing a reason to stop |
| C16 | A write which fails on a typed cause for which a remediation exists is attempted once more, and there is no third attempt. | [605], T06 |
| C17 | A file whose output already exists is skipped, unless override allows replacing it. | T04, T06 |
| C18 | A cause is stated in terms of the user's data, and never of the internals of a format. | [704], T06 |
| C19 | One file of the batch may produce several converted files, and the report is not one line per file of the batch. | T06, T08 |
| C20 | The setting interoperability is read and never written: the answer which holds is carried by the page, for one conversion. | [308], RO7 |
| C21 | Nothing of a conversion is held on the server between two requests. | RO8, and a context where nothing is kept for a given user |
| C22 | Where a converted file stands is not said by this application. | [802], T08 |
| C23 | What a failed write left on the disk is not removed here. | The API, which writes; and C13, nothing being undone for the batch |
C4 is the one which decides the shape of the code. It is why the
correspondence is a file and not a branch, why a property added to the API costs
a row, and why ModelFormats is the only class to be read again that
day.
C15 and C21 were not in the dossier before the levels below the conceptual were written. The first is what makes the chain of C14 terminate; the second is what makes one implementation serve the two contexts of execution. Both are decisions, and they are written here rather than left to be discovered in the code.
Two constraints are refusals this application accepts rather than avoids. C13
says a batch is never undone, and C23 says what that costs: a file which was
refused may have left something where it was to be written, and
override is what the next conversion decides on.
Logical level
The tables
Each class of entities becomes a table, and its identifier becomes its key. Ten tables: five are the knowledge of formats and are permanent, five belong to one conversion and outlive nothing.
| Table | Columns | Comes from |
|---|---|---|
| FORMAT | format, extension, software, can be written | The class FORMAT |
| PROPERTY | property, option | The class PROPERTY, and R2 |
| SUPPORTS | format, property | R1, which is many to many |
| OPTION | option, question, default answer, alters the annotations | The class OPTION |
| ANSWER | option, answer, remediation | The class ANSWER, and R3 |
| CONVERSION | conversion, destination, override, heuristic | The class CONVERSION |
| BATCH | conversion, file | R4, which is many to many |
| CHOICE | conversion, option, answer | The class CHOICE, and R5 with R6 |
| RESULT | conversion, file, status, cause | The class RESULT, and R7 with R8 |
| REMARK | conversion, file, remark, what it says | The class REMARK, and R9 |
The structural loss is a column which is empty. R2 has its low cardinality on the side of PROPERTY, which is (0,1): the table takes the key of OPTION, and it may hold none. A property which a destination does not support and whose option is empty is exactly what that destination cannot hold and no answer can remedy (D9). Nothing counts it and no rule states it: it is read where it stands.
R3 and R9 are aggregations: the aggregated table takes the key of the aggregating one. An answer is named inside its option and two options offer an answer of one name without offering the same answer; a remark is named inside the result which carries it.
R5 and R6 both have their low cardinality on the side of CHOICE, which is (1,1): the table takes the two keys, and the two together identify it. One conversion answers one option once. The same holds of RESULT with R7 and R8: one file of one conversion has one result and no more.
Two tables are read and never written. SUPPORTS is what the API answers, and the table is the shape of that answer, not something this application keeps. BATCH is what the provider of files exposes, read at every request and altered by nothing here [202]. They are written down because the model needs their shape, not because anything of this domain holds them.
Not in the tables, and computed every time they are wanted: the properties of the destination, the options it raises, the structural loss, the answer which holds for an option, the effective default of the preservation option, what is still missing before a conversion can run, and the files which were produced. None of the seven would stay true if it were held, three decisions out of four invalidating them.
Physical level
Where each table stands
Here the machines are named, and not before. There is no database: three tables stand in the API of SPPAS, two in a file of this application, and five stand nowhere at all.
| Table | Where it stands | Between two requests | What the user sees |
|---|---|---|---|
| FORMAT | The API of SPPAS | Its own | The formats she may choose among, and what each of them holds |
| SUPPORTS | The API of SPPAS, read at every request | Its own | The same, read as a property supported or not |
| PROPERTY | The API for its identity, a file of this application for the option which covers it | The file | Nothing of a property by itself |
| OPTION | A file of this application, read and never written | The file | The question, and the answers it offers |
| ANSWER | The same file | The same | The answers of one option, restricted to those the destination allows |
| CONVERSION | What the page transmits | Nothing: it is rebuilt at every request | Her decisions, as she took them |
| BATCH | What the provider of files exposes | That domain's | The files she is converting |
| CHOICE | What the page transmits | Nothing | The answer standing for each option |
| RESULT | Made by the conversion and sent to the page | Nothing | A status, and a cause when it was refused |
| REMARK | The same | Nothing | What was transformed in her file |
Five tables stand nowhere between two requests, and that is RO8 written as a place. A conversion is rebuilt from what the page transmitted, used, and dropped. Nothing on the server belongs to anybody, which is what lets one implementation serve a context which knows the person and one which does not.
The correspondence is a file, and that is the whole of « data of the model, not code ». Adding a property to the API adds a row to that file: a property with an option and an answer becomes a question asked; a property with none becomes a structural loss announced. No treatment is written, no branch is added, and nothing of this application is read again.
The converted files stand where the API wrote them. This application does not say where that is, and does not have to: reaching them is asked of what provided them [802].
Operational model of treatments
The organisational level said by what and when; this says in what tasks, and what among them cannot be half done.
One request is one unit. Every request begins by rebuilding the conversion from what the page transmitted, runs the one treatment it was asked for, and sends back what is to be shown. Nothing is begun in one request and finished in another — T06 included, which is long and is one request all the same.
| PF | The tasks, in order | What cannot be half done |
|---|---|---|
| PF1 | Rebuild; read the writable formats from the API; verify the format chosen is one of them; hold it | Nothing: nothing is written |
| PF2 | Rebuild; read the properties of the destination; read the correspondence; raise the options and restrict their answers; gather what no option covers | Nothing: nothing is written |
| PF3, PF4 | Rebuild; hold the answer or the general option | Nothing |
| PF6 | Rebuild; verify a destination and a batch which is not empty; then, file by file: read, anticipate, write, and at most one second write | The result of one file. Not the batch, and not the writing itself |
| PF7 | Rebuild nothing: answer the page in the state T01 finds at the beginning | Nothing |
| PF8 | Ask the provider of files for the way each produced file is reached | Nothing |
One file is one unit, and the batch is not
The failure of one file never interrupts the others [606], so nothing here holds for the batch as a whole: there is no moment at which a conversion is half done and has to be undone. A file has its result, or it has not been reached yet.
What a failed write left on the disk is the API's, and this application
removes nothing. It states a refusal on what the API answered. A file which
was refused may therefore have left something where it was to be written, and the
general option override is what decides whether the next conversion
may replace it. That is a consequence of writing where the user asked, and not a
fault of the model.
The chain of remediations ends
A remediation produces a new content which is verified again, so the chain is a loop, and a loop needs a reason to stop. It is this: a remediation is applied at most once for one file. A content which, after every remediation its answers allow, still exceeds what the destination can hold is refused, and the cause reported is the one which ended the chain.
Without that rule, removing empty tiers and splitting a multi-tier file could ask for each other in turn. With it, the chain is as long as the number of options and no longer.
The second write is not a second chance
Anticipation comes first and the typed exceptions are a safety net. The second write happens only on a typed cause for which a remediation exists, and there is no third: a second failure is a refusal. What that costs is bounded — two writes per file at the worst — and what it buys is the file which anticipation did not catch.
Where the code goes
In sppas/ui/swapp/app_convert/. One module per kind of knowledge,
and every procedure has one module and one only. The separation this application
must keep is the one stated below, and these are its four lines.
| Module | What it does | Procedure |
|---|---|---|
| formats | Knows which formats can be written and what each holds, and derives from a destination the options, their answers and the structural loss. Reads no file | PF1, PF2 |
| remediation | Transforms annotations in memory: applies what the answers require, verifies the result again, chains, and says which transformation touched what. Reads and writes no file | What PF6 asks of it |
| conversion | Reads a file, calls the remediation, writes, retries once, and produces the result of that file | PF6 |
| provision | Reads the batch the provision of files exposes, and asks it by what each produced file is reached. Alters nothing of it | PF5, PF8 |
| decisions | Rebuilds a conversion from what the page transmitted, holds what was decided, reads the settings, and says what is still missing | PF3, PF4, PF7, and the beginning of every other |
| presentation | Renders the state, collects the decisions, triggers the events | The view of every procedure |
What each one promises, which is the reason for the cutting:
- The formats module is the only one which knows what a format holds, and it holds it as data. The day the API gains a property, it is the only one to read again — and what is read again is a file, not a branch.
- Remediation touches no disk: it is given a content and gives back a content. It is where the business logic of this application lies, and it is what can be tested with no file at all.
- The conversion module is the only one which reads and writes files, so it is the only one which meets a typed cause, and the only one to read again the day the API raises another.
- Provision is the only one which speaks to the neighbouring domain. It is given a batch and a way to reach a file, never a path, so there is nowhere here for the place of a converted file to be known.
- Decisions is the only one which knows what the page transmits. It holds no state of its own between two requests, and it is where the invalidation is done: what was derived from a decision which changed is not rebuilt.
- Presentation decides nothing. What it shows was decided before it was called, and the JavaScript it carries renders and nothing else.
This section states the principles retained for implementing Convert, in keeping with the requirements and the conceptual model, without prejudging detailed technical choices. Its purpose is to bind every implemented component to the requirement it satisfies.
Convert holds no persistent data of its own. Everything it manipulates belongs to one conversion in progress. The implementation is therefore organised around a chain of treatments, each producing clearly typed derived data, and each answering an identified requirement.
The implementation must keep a strict separation between:
- the handling of user decisions (destination, answers, general options);
- the knowledge of formats (properties, options, structural loss);
- the transformation and writing of annotations (remediation, chaining, writing, retry);
- the presentation of the interface and of the results.
Convert relies on the SPPAS reading and writing capabilities and never exposes them. It is served identically by the local SPPAS server and by uwsgi: the two deployments are one implementation, not two.
The batch is provided, not constituted
Convert does not select files. It receives a batch from its execution context and does not alter it. In a local session, that context is the SPPAS workspace, whose files are checked elsewhere, before Convert is reached: no file selection belongs to Convert. In an online use, the batch results from files brought by the user to the service.
Convert therefore depends on a provider of files, of which it requires only a contract:
- it exposes a set of files, possibly empty;
- Convert reads that set and never modifies it;
- it exists in both contexts of execution.
That component was not designed when this was written, and it is now: it is the provision of files, a service of swapp, and it has its own dossier. Convert is one of the apps it calls A2, and the contract above is what that dossier answers — a workspace holding the files to be treated and them only. What Convert receives is made for it, and the workspace of the person never leaves that domain.
Two things follow, and neither changes the model. What Convert reads is checked elsewhere, so no file selection belongs here [202]; and what it produces is given back to that same service, which is what makes it reachable without the user knowing where it stands [801], [802]. T05 still states a provided batch and not a constituted one, and T08 asks rather than answers.
Implementation model: MVC
- Model: knows the formats, performs T02 and T06, and is the only one which speaks to the provision of files — for the batch (T05) and for reaching what was produced (T08). It is a façade over the SPPAS reading and writing capabilities.
- Controller: identifies the task requested, checks its preconditions, chooses the treatment to run, invalidates the derived data, holds the transient state, calls the model, and prepares the data for display.
- View: renders the state, collects the decisions, triggers the events. No business logic; JavaScript is rendering and interaction support only.
What receives a request is not the controller. The WhakerPy response handles the URL, receives the GET or POST and the events it carries, instantiates the controller, calls it once for that request, and bakes the returned tree — either a full page or an update payload. The controller is called; it does not listen.
The task to run is carried by the request, as an event. The controller reads it and handles it. This holds because Convert has one controller; an application with several would have to dispatch, which is not the case here.
Model
The model is the functional core. It holds the knowledge of formats and the
transformation of annotations, and exposes neither to the rest of the
application. The façade ConvertModel exposes the single interface
the application expects and delegates to three specialised sub-models.
ModelFormats holds the knowledge of formats. It exposes the
formats that can be written, their properties, and derives from a destination
the options, their available answers, and the structural loss (T02). The
correspondence between an unsupported property, the question it raises and the
answers available is data it holds, not code it runs: adding a property to the
SPPAS API adds an entry, and modifies nothing else. This sub-model reads no
file.
ModelRemediation holds the transformations applied to
annotations. Given a content and the properties of a destination, it states
which remediations the answers require, applies them, and verifies the
resulting content against those properties again — a remediation producing a
new content, remediations chain, and a chain may end in a refusal. It also
states which remediations transformed the content, so that remarks can be
attached to the file. This sub-model reads and writes no file: it transforms
annotations in memory. It is the place where the business logic of Convert
lies, and it is testable on its own.
ModelConversion performs T06. For each file of the batch it
reads, calls ModelRemediation, writes, retries once after
remediating a typed failure, and produces the result of that file: its status,
its remarks, the cause of a refusal. It never interrupts the batch, and one
file may produce several converted files.
ModelProvision is the only class which speaks to the
provision of files. It exposes the batch that domain holds, and asks it by
what each produced file is reached (T08). It is given a way to reach a file
and never a path: where a converted file stands is not said by this
application C22. It alters nothing of the batch C11, and it is the only place
to be read again the day that domain changes.
This structure lets the knowledge of formats, the transformation of annotations, the conversion of files and the dependency on a neighbour evolve separately, behind one stable façade.
Controller
The controller is called once per request, in a stateless context. It
initialises an empty state, then rebuilds the current state exclusively from
the data transmitted to it. What carries that state is one object,
ConvertRecord: the view serialises it at each user action and the
controller parses it back, and neither of them holds it between two requests
C21. The controller identifies the task requested, checks its preconditions,
calls the model, and prepares the data for display.
The controller is also the only one which reads the settings of the
application. It takes interoperability from them, hands it to the
conversion as the default answer of the preservation option, and writes
nothing back: the value is changed for this conversion alone, on the page
[308] C20. The model knows no setting, and the view decides nothing.
The controller handles invalidation. Any change of an upstream datum invalidates the data derived from it, which are then neither reused nor displayed: a change of destination invalidates the properties, the options, the answers, the structural loss and the results; a change of an answer, of a general option or of the batch invalidates the results. This invalidation is implicit: only the data explicitly transmitted and recomputed during the current request are used.
Tasks:
- start — transmitted: nothing. Preconditions: none. Triggers: none. Produces: the page in its initial state, with the writable formats and no destination.
- destination — transmitted: the destination. Preconditions: the format can be written. Triggers: T02. Produces: the options, their answers, the structural loss.
- answer — transmitted: the destination, the answers taken so far, and the one just given. Preconditions: the option belongs to the destination, and the answer is one it offers. Triggers: T03. Produces: the answers, and the results invalidated.
- general — transmitted: everything decided so far, and the general option just set. Preconditions: none. Triggers: T04. Produces: the general options, and the results invalidated.
- convert — transmitted: the destination, the answers, the general options. Preconditions: destination defined; batch not empty; every option answered, defaults applying to those left unanswered. Triggers: T06. Produces: the results.
- reset — transmitted: nothing. Preconditions: none. Triggers: none. Produces: the page in its initial state. The batch is not reset: it belongs to the context, not to Convert.
Default answers
An option left unanswered takes a default. Two principles apply, in this order: the default reproduces the current behaviour of the SPPAS API where one exists; failing that, it takes no initiative.
| Option | Default | Reason |
|---|---|---|
| preservation | yes | current behaviour |
multi_tiers |
skip the file | no initiative |
point |
skip the tier | no initiative |
alt_tag |
keep all | current behaviour |
tag_types |
skip the tier | no initiative |
tag_geometry |
skip the tier | no initiative |
Preservation defaults to yes because that is what the API does today: it writes as comments what a format cannot hold, wherever comments are allowed. Where the destination allows neither comments nor a tier, the option is not offered and the information is lost — which is, again, the current behaviour.
Where a precondition is not satisfied, the controller runs no treatment and states which decision is missing. A decision is never refused because another is missing RO4.
Six tasks for eight treatments, and the two which have none have none for a reason: T02 is triggered by destination and never asked for on its own, and T08 follows the conversion in the same request. Every other treatment is one task, and every task is one request.
The controller is implemented by a single class
ConvertController, exposing one entry point
handle(request_data).
Views
As in TextCueS, the WhakerPy response builds the whole HTML tree and the
structural elements common to the application — head, header, nav, footer —
are factored there. The Convert views build only the content of
body > main, and of body > script where
support scripts are required. They create no structural element, handle no
navigation, take no functional decision and perform no linguistic
treatment.
Convert has one applicative view, ViewConvert, whose content
varies with the data the controller transmits. It is built from five
fragments, each with a defined scope.
The shape of these fragments follows from an observation about the users: they do not choose a destination format. They know it already — they are moving to Elan, to Praat, to subtitles — and they come to Convert to reach it. The properties of formats are therefore not there to help decide which format to pick; they are there to state what reaching the one already picked costs. The two are not served by the same presentation, and conflating them is what makes a matrix of formats by properties both indispensable and unreadable.
FragmentFormats presents the formats that can be written, and
lets one of them be selected or cancelled. It is a list of extensions, grouped
where grouping is possible: the extensions of one piece of software together,
the subtitle formats together, the rest as they come. The grouping is
heterogeneous by nature — Praat holds three extensions, some formats hold no
software at all — and it exists only to let the user find what they came for.
This fragment carries no property.
FragmentDestination presents what the selected format holds,
and is where the export options are answered. It is an
aside: consulting it is not leaving the list. It shows every
property, always, in the same order, whatever the format selected. What varies
from one format to the next is the state of each line, and whether a decision
appears on it. A property has three states, and no more: held; not held, with
nothing to decide; not held, with a decision to take. Preservation, covering
several properties at once, appears as one line among them.
The stability of that list is what makes it usable. Labels that do not move let the user click from one format to another and see what changed, without reading again. It also answers requirement [104] without hiding anything: a scientific application states its data. Some properties are widely understood — several tiers, media, metadata — and others are specificities that exist almost nowhere but in SPPAS. The latter are made discreet, not absent.
FragmentCompare presents the full matrix of formats by
properties, as a details element the user unfolds. This is the
one place where formats are compared to one another, which is a legitimate
thing to want and a poor way to choose a destination. Unfolded in place rather
than opened as a dialog, because comparing is consulting, not deciding: the
page stays where it is. Given the room a details element affords, the matrix
can here be what it never is when it drives the choice — readable.
FragmentGeneral presents the general options.
FragmentResults presents the result of every file of the
batch: its status, the remarks attached to it, and the cause of a refusal. It
exists only once a conversion has run. One file of the batch may produce
several converted files: the report is not a line per input file.
JavaScript is interface support. It handles local interactions — selecting a format, answering an option, refreshing the aside once a destination is known, refreshing the results — and transmits the state to the server. It holds no business logic and takes no decision on the treatments to run: it knows nothing of formats, of properties, or of what a remediation is. Which options a destination raises is derived by the model, server-side; the client displays what it is given.
The view serialises the current state at each user action. In a strictly stateless context, it transmits to the controller everything the requested treatment needs, without relying on any persistence, client-side or server-side.
The view carries the cross-cutting requirements: contrast, legibility, text alternatives to any graphical encoding, keyboard and screen-reader operation, consistent terminology between the interface and the concepts of the model, explicit messages at every decision point. Convert exposes a technical subject to a non-technical audience; the burden of intelligibility lies entirely here.
UML
The classes
Those which carry the data come from the tables; those which work come from the modules and from the MVC stated above. The names of the working classes are the ones that section fixed, and nothing is renamed here.
What carries the data
| Class | From | What it is |
|---|---|---|
Format | FORMAT, SUPPORTS | An extension, the software which reads it, and what it holds. Read from the API and kept by nobody |
Option | OPTION, ANSWER, PROPERTY | A question, the answers it offers, the answer which holds when none is given, and whether answering alters the annotations. It is read from the file which holds the correspondence |
Conversion | CONVERSION, CHOICE | What was decided: the destination, the two general options, and one answer per option. It is rebuilt at every request and held between none |
FileResult | RESULT, REMARK | What happened to one file: a status, the remarks attached to it, and the cause of a refusal |
ConvertRecord | — | What one request holds: the task it carries, the conversion it was given, and what is to be shown. It serialises itself for transport and parses itself back, and it is held by nobody between two requests |
| none | BATCH | The files are exposed by the provision of files, which names them already |
ConvertRecord is the class RO8 asks for and which no section
named. The view serialises the state at each action and the controller
rebuilds it: between the two there is an object, and it is better named than
implied. It is what makes the two contexts of execution one implementation.
What does the work
| Class | Module | What it is alone in knowing |
|---|---|---|
ConvertModel | — | The façade. It is what the controller sees, and it sees nothing behind it |
ModelFormats | formats | What a format holds, and what a destination raises as options and as structural loss. Reads no file |
ModelRemediation | remediation | How annotations are transformed, chained and verified again. Reads and writes no file |
ModelConversion | conversion | How a file is read, written, retried once and given a result. The only class which meets a typed cause |
ModelProvision | provision | How the provision of files is spoken to: the batch it exposes, and by what a produced file is reached |
ConvertController | decisions | What a request transmits, which task it carries, what a decision which changed invalidates, and what the settings say |
ViewConvert | presentation | What is shown, in five fragments, and nothing of what it means |
The four sub-models are what the façade holds, and the fourth is
ModelProvision: the batch and the way a produced file is reached are
asked of a neighbour, and one class is what asks it.
The five fragments — FragmentFormats,
FragmentDestination, FragmentCompare,
FragmentGeneral, FragmentResults — are classes of
the view and build each their own part of body > main. They
decide nothing, count nothing and refuse nothing.
What assembles
The response of WhakerPy handles the URL, builds the view and the controller,
calls the controller once for that request, and bakes the tree it was given. It
is named here ConvertResponseRecipe, and it is the only object of
this application anything outside it holds. The controller assembles
nothing: it is built, it is called once, and it is dropped.
The class diagram
/ marks what is derived and held by nobody. What the operations
promise is the chapter on the contracts; what they are called is a proposal, and
one pass renames them all.
| Class | Attributes | Operations |
|---|---|---|
Format | extension, software, properties | holds(property), can_be_written() |
Option | option, question, answers, default answer, alters | answers_allowed_by(format), default_for(settings) |
Conversion | destination, override, heuristic, answers, /what is missing | answer_of(option), what_is_missing(batch), invalidates() |
FileResult | file, status, cause, remarks | — |
ConvertRecord | task, conversion, to_be_shown | serialize(), parse(data) |
ConvertModel | — | writable_formats(), options_of(destination), structural_loss_of(destination), convert(batch, conversion) |
ModelFormats | — | writable_formats(), properties_of(format), options_of(format), structural_loss_of(format) |
ModelRemediation | — | remediate(content, properties, answers), what_was_transformed() |
ModelConversion | — | convert(batch, destination, answers, general_options), convert_one(file, …) |
ModelProvision | — | batch(), reached_by(file) |
ConvertController | record | handle(request_data), populate_view() |
ViewConvert | — | populate_tree_content(record) |
ConvertResponseRecipe | — | bake(), _process_events() |
Conversion.what_is_missing() is given the batch and does not hold
it: what is missing is a destination or a batch which is not empty [031], and
the batch belongs to a neighbour. A class which held it would hold what it is
forbidden to alter.
ModelRemediation is given a content and gives back a content. It
never sees a file, a path or a batch, which is what lets the business logic of
this application be tested with nothing installed.
What is tied to what
| Tie | Legs | What it is |
|---|---|---|
| holds | ConvertResponseRecipe 1 — 1 ViewConvert, 1 ConvertController | A composition: it builds them, and they go when it goes |
| holds | ConvertController 1 — 1 ConvertRecord | A composition: one record per request, made by the controller and kept by nobody |
| holds | ConvertRecord 1 — 1 Conversion | A composition: what was decided lives inside what one request carries |
| holds | ConvertModel 1 — 1 each of the four sub-models | A composition: the façade makes them, and nothing else reaches them |
| holds | ViewConvert 1 — 1 each of the five fragments | A composition: a fragment builds one part of one page and exists for it |
| uses | ConvertController → ConvertModel | A dependency: it calls the façade, once per request |
| uses | ConvertController → ViewConvert | A dependency: it hands it what to build from |
| uses | ViewConvert → ConvertRecord | A dependency: it is given it and builds from it |
| uses | ModelFormats → Format, Option | A dependency: it makes them from the API and from the correspondence, and keeps none |
| uses | ModelConversion → ModelRemediation, FileResult | A dependency: it asks for a content and gives back a result |
| uses | ModelConversion → the API of SPPAS | A dependency, and the only tie of this application to what reads and writes files |
| uses | ModelProvision → the provision of files | A dependency, and the only tie of this application to that domain |
| none | ModelRemediation | Tied to no file and to no neighbour: a content in, a content out |
In yUML
To be read at yuml.me, class diagram.
[ConvertResponseRecipe|bake();_process_events()]++1-1>[ConvertController|record|handle();populate_view()]
[ConvertResponseRecipe]++1-1>[ViewConvert|populate_tree_content()]
[ConvertController]++1-1>[ConvertRecord|task;conversion;to_be_shown|serialize();parse()]
[ConvertRecord]++1-1>[Conversion|destination;override;heuristic;answers;/missing|answer_of();what_is_missing();invalidates()]
[ConvertController]-.->[ConvertModel]
[ConvertController]-.->[ViewConvert]
[ViewConvert]-.->[ConvertRecord]
[ViewConvert]++1-1>[FragmentFormats]
[ViewConvert]++1-1>[FragmentDestination]
[ViewConvert]++1-1>[FragmentCompare]
[ViewConvert]++1-1>[FragmentGeneral]
[ViewConvert]++1-1>[FragmentResults]
[ConvertModel|writable_formats();options_of();structural_loss_of();convert()]++1-1>[ModelFormats|writable_formats();properties_of();options_of();structural_loss_of()]
[ConvertModel]++1-1>[ModelRemediation|remediate();what_was_transformed()]
[ConvertModel]++1-1>[ModelConversion|convert();convert_one()]
[ConvertModel]++1-1>[ModelProvision|batch();reached_by()]
[ModelFormats]-.->[Format|extension;software;properties|holds();can_be_written()]
[ModelFormats]-.->[Option|option;question;answers;default;alters|answers_allowed_by();default_for()]
[ModelConversion]-.->[ModelRemediation]
[ModelConversion]-.->[FileResult|file;status;cause;remarks]
The states
Two things have states in this application, and they are the two the user reads.
| State | When | What is shown |
|---|---|---|
| held | The destination supports it | The line, and no decision on it |
| not held, nothing to decide | It is not supported and no option covers it | The line, and it is a structural loss |
| not held, a decision to take | It is not supported and an option covers it | The line, and the answers that destination allows |
Three states and no more. The list of properties does not move from one format to the next: what moves is the state of each line, and that is what makes it readable.
| State | When |
|---|---|
| written | It was read, adapted where an answer asked for it, and written |
| written with remarks | The same, and a remediation transformed its content |
| refused | What it held exceeds what the destination can hold, after every remediation its answers allow |
| skipped | Its output already exists and override forbids replacing it |
A file has exactly one of the four. What is skipped was never read, and what is refused was: the two are told apart because the user can act on one of them and not on the other.
The sequence, from the first request to the results
- The page is asked for. The formats which can be written are read, and no destination is defined [012].
- The batch is read from the provision of files. It is empty, and what is missing is said [203].
- The user chooses a destination. The request carries it; the controller rebuilds a conversion which holds nothing else.
- The options that destination raises are derived, their answers restricted to what it allows, and what it cannot hold at all is announced once [501].
- She answers an option, or leaves it to its default; she sets a general option. Each is one task of its own — answer, general — one request, and each carries back everything decided so far.
- She asks for the conversion. The preconditions are read on what was transmitted: a destination, a batch which is not empty, an answer for every option.
- File by file: read, anticipate, write, and at most one second write. Each file has its result, and the failure of one ends nothing.
- The results replace what was shown: a status for each file, its remarks, and the cause of each refusal, in the words of her data.
- What was produced is reached, without her being told where it stands.
- She starts again: the decisions are gone and the batch is not.
Steps 3 to 6 happen in any order, and any of them may happen twice. There is no step which has to come before another, and the only thing which requires them all is step 7.
The error policy
| Level | What happens | What is done |
|---|---|---|
| 1 | A decision is missing: no destination, an empty batch | No treatment runs, and which decision is missing is said [022]. It is not an error and nothing is raised |
| 2 | One file is concerned: what it holds exceeds the destination, or its output exists and may not be replaced | That file is refused or skipped, the others are converted, and the cause is stated in terms of her data and not of the internals of a format [704] |
| 3 | Whoever runs the machine has to know: a file which cannot be read at all, a folder which cannot be written | Said where he reads it, and the file carries a refusal like any other so that the batch goes on |
What is raised is caught by the response which answers the request, and by nothing below it. A typed cause of the API is not an error of this application: it is an answer, and it is what the second write is decided on.
The contracts
How to read them
pre is what has to be true on the way in, and what the operation does not check; post is what the caller can count on without looking. The treatments state their preconditions for one treatment; these state them for one operation, and the two say the same thing at two levels.
What holds everywhere
- What is absent gives back an empty thing — an empty list, no destination, no remark — and never nothing at all.
- Nothing is held between two requests. Every operation is given what it works on and keeps none of it. C21
- Only
ModelConversionreads or writes a file of the user. No other class of this application touches a disk. - Only
ModelFormatsknows what a format holds, and it holds the correspondence as data. C4 - A view decides nothing: what it shows was decided before it was called.
- What is raised is caught by the response which answers the request, and no class below it writes a catch. A typed cause of the API is not raised to the caller: it is an answer.
Class by class
| Operation | Contract |
|---|---|
| Give the formats which can be written | pre: none. post: every format the system is able to write, with what each of them holds, and never one it cannot write. It reads no file of the user. C2 |
| Give the options of a destination | pre: the destination is a format which can be written. post: one option per unsupported property an option covers, with the answers that destination allows and the answer which holds if none is given. No file is read. C5, C7, C8 |
| Give the structural loss of a destination | pre: the same. post: the unsupported properties no option covers; it depends on the destination alone, and is the same for every file. C6 |
| Convert | pre: a destination, a batch which is not empty, and one answer standing for every option. post: one result per file of the batch, each holding a status, the remarks attached to it and the cause of a refusal; the batch is what it was. C11, C12 |
| Operation | Contract |
|---|---|
| Give the writable formats | pre: none. post: what the API answers, relayed; no list is written here |
| Give the properties of a format | pre: a format. post: what it holds, as the API says it. It belongs to the format and never to a file |
| Give the options of a format | pre: a format. post: read from the file which holds the correspondence, restricted to the answers that format allows. Adding a property to the API adds a row and changes nothing here. C4, C5 |
| Give the structural loss of a format | pre: a format. post: the unsupported properties whose option is empty. C6 |
It reads no file of the user and no content whatever. Every rule of what a destination raises is therefore verified with nothing installed but the API.
| Operation | Contract |
|---|---|
| Remediate a content | pre: a content, the properties of the destination, and one answer standing for every option. post: a content the destination holds, or the statement that it does not — every remediation the answers allow having been applied at most once, and the content verified again after each of them. C14, C15 |
| Say what was transformed | pre: a content was remediated. post: the remediations which changed it, which is what a remark is made of; empty when none did |
It is given a content and gives back a content: no file, no path, no batch. It is where the business logic of this application lies, and it is what can be tested with nothing at all.
| Operation | Contract |
|---|---|
| Convert a batch | pre: the preconditions of the conversion are verified. post: one result per file, in the order of the batch; the failure of one is a result and never an interruption; nothing of the batch is altered. C11, C13 |
| Convert one file | pre: a file of the batch. post: written, written with remarks, refused with a cause, or skipped — one of the four and no other; at most two writes were attempted; the cause is stated in terms of the user's data. C16, C17, C18 |
It is the only class which meets a typed cause of the API, and the only one to be read again the day that API raises another. What a failed write left on the disk is not removed by it. C23
| Operation | Contract |
|---|---|
| Give the batch | pre: none. post: the set of files that domain exposes, possibly empty; read at every request and altered by nothing here. C11 |
| Say by what a file is reached | pre: the file was produced by the conversion. post: the way it is reached, as that domain gives it — never a path, and never a place of the machine. C22 |
It is the only class which speaks to that domain, so it is the only one to be read again the day it changes. It is also where C22 stands: nothing here is ever given a path, so no code of this application can show one.
| Operation | Contract |
|---|---|
| Give the answer of an option | pre: none. post: the answer which was chosen, or the default of that option; never nothing. C8 |
| Say what is missing | pre: a batch is given to it. post: a destination when none is defined, the batch when it is empty, nothing when the conversion may run. It holds no batch: what it is forbidden to alter, it does not keep. C12 |
| Say what a change invalidates | pre: none. post: a change of destination invalidates the properties, the options, the answers, the structural loss and the results; a change of an answer, of a general option or of the batch invalidates the results. C3 |
| Serialise a record | pre: none. post: everything a next request needs in order to rebuild this conversion, and nothing of the machine |
| Parse a record | pre: what a page transmitted. post: the conversion as it was, or an empty conversion when nothing was transmitted. Parsed twice, it gives the same conversion. C21 |
| Operation | Contract |
|---|---|
| Handle a request | pre: called once for that request, and never twice. post: the record is rebuilt from what was transmitted, the task is identified, its preconditions are read; the treatment ran, or no treatment ran and the missing decision is stated. Nothing derived from a decision which changed is reused. C3, RO4 |
| Populate the view | pre: the request was handled. post: the view has the record; nothing is decided here and nothing is read back but a tree |
It assembles nothing: it is built by the response, called once, and dropped. A decision is never refused because another is missing.
| Operation | Contract |
|---|---|
| Populate the tree | pre: a record. post: a tree holding what that record says and nothing more — no refusal it invented, no total it counted. It reaches no disk and no neighbour |
FragmentFormats | post: the formats which can be written, grouped so that one is found, and carrying no property |
FragmentDestination | post: every property, always, in the same order, whatever the destination; what varies is the state of each line, which is one of three |
FragmentCompare | post: the matrix of formats by properties, unfolded in place; it decides nothing and the page stays where it is |
FragmentGeneral | post: the two general options, false when nothing was transmitted. C10 |
FragmentResults | post: one entry per file of the batch, with its status, its remarks and its cause; it exists only once a conversion has run, and it is not one line per file produced. C19 |
| Operation | Contract |
|---|---|
| Bake | pre: a request, carrying a task or carrying none. post: the tree of the page, or the payload of an update. The view and the controller were built, the controller was called once, and neither of them outlives the request |
Where each constraint is held
One place each. A constraint held in two would be a constraint held in neither.
| No. | Held by |
|---|---|
| C1 | Conversion, which holds one destination or none |
| C2 | ModelFormats, which is what says a format can be written; the façade reads it before holding a destination |
| C3 | Conversion, which says what a change invalidates, and ConvertController, which rebuilds only what was transmitted |
| C4 | ModelFormats, reading the file which holds the correspondence |
| C5 | ModelFormats, giving the options of a format |
| C6 | ModelFormats, giving the structural loss of a format |
| C7 | ModelFormats, which reads no file: the options exist before anything is read |
| C8 | Conversion, giving the answer of an option |
| C9 | ModelConversion, which is given one set of answers for the whole batch and reads no other |
| C10 | Conversion, whose general options are false when nothing was transmitted |
| C11 | ModelProvision, which is what reads the batch, and ModelConversion, which writes nothing into it |
| C12 | Conversion, saying what is missing, read by ConvertController before it runs anything |
| C13 | ModelConversion, converting a batch |
| C14 | ModelRemediation, which verifies again after each remediation |
| C15 | ModelRemediation, which applies each remediation at most once for one file |
| C16 | ModelConversion, converting one file |
| C17 | ModelConversion, converting one file |
| C18 | ModelConversion, which names the cause; the view shows it as it was given and writes none of its own |
| C19 | FragmentResults |
| C20 | Conversion, which is given the setting as a default and never writes it |
| C21 | ConvertRecord, and ConvertController, which keeps nothing after the request |
| C22 | ModelProvision, which is given a way to reach a file and never a path. It is held by what that operation is not given: nothing else of this application ever sees one, so there is nowhere for it to be broken |
| C23 | ModelConversion, which removes nothing |
C22 is held by what one operation is not given, which is the strongest way to hold a rule: no code can break it, because no code is handed what it would take to break it. Every one of the twenty-three names exactly one place, C11 excepted, which names two — and they are two halves of one thing: one class reads the batch, another writes nothing into it, and neither can do the other's half.
What is tested, and where
The models
Twenty-five tests for the four sub-models and the façade. The controller, the view and its fragments are not covered here and are owed.
ModelRemediation, with nothing installed
It is given a content and gives back a content: no file, no path, no batch, and no API to read a format with. It is the business logic of this application, and it is the cheapest thing here to test.
| No. | What is checked | What it holds |
|---|---|---|
| TE1 | A content the destination already holds comes back as it was, and nothing was transformed | The contract of remediating |
| TE2 | An answer which asks for a transformation transforms the content, and what was transformed is named — which is what a remark is made of | T06, D12 |
| TE3 | The content is verified against the destination again after each remediation | C14 |
| TE4 | A remediation is applied at most once for one file: a chain which would ask for it twice ends instead | C15 |
| TE5 | A chain which cannot reach a content the destination holds ends in a refusal, and the cause is the one which ended it | T06 |
| TE6 | Nothing appears on the disk, whatever it is given | Its own promise, and what makes it testable |
TE4 is the one which would have been forgotten. Nothing in the conceptual model asks for it: it was the operational level which found that a chain needs a reason to stop, and this is that reason checked.
ModelFormats, with the API and no file
| No. | What is checked | What it holds |
|---|---|---|
| TE7 | The formats offered are those the API says can be written, and one which cannot is not among them | C2 |
| TE8 | The properties of a format are what the API answers, relayed and not decided here | D2 |
| TE9 | The options are read from the file which holds the correspondence: a row added there becomes a question asked, and no code is touched | C4 |
| TE10 | The answers offered are restricted to those the destination allows | C5 |
| TE11 | An unsupported property no option covers is a structural loss, and it is the same whatever the files are | C6 |
| TE12 | The preservation option appears once, covering the three properties it covers, and not three times | R2 |
| TE13 | No file of the user is read: every answer is given before anything is opened | C7 |
TE9 is C4 made checkable. A row is added to the correspondence and an option appears; nothing else in the test changes. The day that assertion has to be rewritten, the correspondence has become code again.
ModelConversion, with a disk
| No. | What is checked | What it holds |
|---|---|---|
| TE14 | One result per file of the batch, in the order of the batch | T06 |
| TE15 | The failure of one file never interrupts the others: the files after it have their results | C13 |
| TE16 | The batch is what it was: not one file added, removed or rewritten | C11 |
| TE17 | A file whose output exists is skipped; with override it is written | C17 |
| TE18 | A write which fails on a typed cause is attempted once more, and never a third time | C16 |
| TE19 | A refused file carries a cause, and that cause names what was in her file and not what is in the format | C18 |
| TE20 | What a failed write left on the disk is still there afterwards | C23 |
| TE21 | One file of the batch may produce several converted files, and it has one result all the same | C19 |
TE20 asserts that something is left behind. It is written that way on purpose: C23 is a renouncement, and a renouncement which is not tested becomes, six months later, a bug somebody fixes.
ModelProvision, against the neighbour
| No. | What is checked | What it holds |
|---|---|---|
| TE22 | The batch is what that domain exposes, empty when it exposes nothing, and nothing is written into it | C11 |
| TE23 | What is given for a produced file is a way to reach it, and never a path of the machine | C22 |
ConvertModel, the façade
| No. | What is checked | What it holds |
|---|---|---|
| TE24 | It converts only with a destination, a batch which is not empty, and an answer standing for every option | C12 |
| TE25 | The options and the structural loss are given with no file read, and the same answer is given whatever the batch holds | C7, C6 |
What no test covers, and where they stand
- The controller, the view and its fragments. They are owed, and they are what will check that a decision which changed invalidates what was derived from it, that a record parsed twice gives the same conversion, and that a view shows what its record says and nothing more.
- What the API does with the annotations it writes. It is established, it has its own tests or it has not, and this application is answerable for what it asked of it.
- The mockup and the wording. Of the interface, decided against the markup and not against an assertion.
Thirteen of the twenty-five need nothing but the API, six need a disk, two need the neighbouring domain. The cutting into sub-models is what makes that count possible, and the count is what says whether the cutting was worth anything.
They stand beside the code, in the folder of this application.
Annexes
Annex: Extensions of the SPPAS API
The model of Convert stated three requirements the SPPAS API did not
cover. All three are available: they were added to
sppas.src.anndata, and this annex now states what they are, what
they hold, and what they cost. Nothing of the model is left waiting for the
API.
E1 — accept_comments [API-OK]
| What | A boolean property of formats, stating whether a format is able to hold comments. |
|---|---|
| Why | The API already writes metadata as comments where the format allows it, and forgets them otherwise. That capability is internal and not exposed. Convert cannot know whether preserving is possible, and therefore whether the option is worth offering. |
| Bound to | The preservation option — section 3.2. Requirement [307]. |
| Available as | comments_support() of any reader-writer. The formats
holding comments are txt, ctm,
stm, arff and tdf; every other
one answers False. |
E2 — accept_empty_tier [API-OK]
| What | A boolean property of formats, stating whether a format is able to hold a tier carrying no annotation. |
|---|---|
| Why | The API raises AioEmptyTierError (1525) when a format
refuses an empty tier, but nothing states beforehand which formats do.
The refusal is knowable only by attempting to write. |
| Bound to | Anticipation and chaining — sections 3.3, 4.3 (T06). Requirements [602], [603]. |
| Available as | empty_tier_support() of any reader-writer. The formats
holding an empty tier are the ones declaring their tiers apart from
their annotations: xra, eaf,
antx, ant, tei,
mrk, and TextGrid — which writes such a tier
as one interval with no text, adding an empty annotation rather than
removing the tier. |
| Note | Not to be confused with no_tiers, which states whether
a format accepts a file holding no tier at all. Removing empty tiers can
produce such a file: the two properties interact, which is why chaining
re-verifies. |
E3 — Writing metadata, controlled vocabularies and media as a tier [API-OK]
| What | The ability to write, into a tier of the output, what a format cannot hold as metadata, as a controlled vocabulary, or as a media declaration. |
|---|---|
| Why | Where a destination holds neither the information nor comments, that information is currently lost. A tier is the one container every format holds by definition. |
| Bound to | The preservation option — section 3.2. |
| Available as | create_unsupported_tier() and
parse_unsupported_tier(), with
unsupported_entries() and
fill_unsupported_entry() underneath — a reader holding the
information its own way, as a comment for instance, fills the objects
with the latter. Written by TextGrid, csv and
mrk: the formats holding several tiers but neither
metadata nor comments. |
| What it holds | A tier named DoNotEdit, whose first annotation holds the
keyword Metadata, then one annotation per key: the key, the
value, the nature — metadata, ctrl_vocab or media — and the name of the
tier it belongs to, one in each of its labels. The whole time span of the
transcription is shared into intervals of equal duration. Reading it
assigns the entries back to their object and removes the tier: it is a
way to write, not data. |
| Decided by | The settings of the application give the default:
interoperability of sppasAppConfig, true. Each
reader-writer takes it when created and holds it as its own, so a caller
writing one file decides for that file only, with
set_preserve_unsupported() — of the format, or of
sppasTrsRW, which passes it on. The settings are left
untouched. The tier is written only when there is something to preserve:
what SPPAS assigns to any object it creates does not count. |
| What it costs | csv and mrk write the labels of an
annotation separated by a whitespace, so the whitespaces of the entries
are turned into underscores and stay so when read back: an assumed loss,
stated in the docstring of both. The descriptions of a controlled
vocabulary and of its tags are not preserved. |
What the current API already provides
For contrast, and to bound the extensions above, the following are available and require nothing:
- the list of formats and, for each, whether it can be read and written;
- the boolean properties of formats, which Convert derives its options from;
- typed and numbered exceptions on writing —
AioMultiTiersError(1510),AioNoTiersError(1515),AioEmptyTierError(1525),AioLocationTypeError(1530) — usable as causes of a refusal as they stand; - overriding an existing output, and detecting the format of an input whose extension is unknown.
Annex: Mockup of the interface
This annex is not a picture of the page. It is the page — the fragment below is HTML, styled by Whakerexa, rendered here by the same stylesheets that will render the application. What is unreadable here will be unreadable there.
It shows one state: the destination TextGrid selected, on a
batch of four files, after a conversion has run. Interactions are inert; the
structure, the labels and the wording are not.
Convert
Write into
Compare the formats
The full matrix of formats by properties. It is here because comparing formats is a legitimate thing to want, and a poor way to choose a destination. Unfolded in place: the page stays where it is.
| Format | Several tiers | Metadata | Hierarchy | Overlaps | Ctrl. vocab. |
|---|---|---|---|---|---|
| xra | yes | yes | yes | yes | yes |
| TextGrid | yes | no | no | no | no |
| eaf | yes | yes | yes | no | yes |
| srt | no | no | no | no | no |
… and the remaining formats and properties.
Options
Results
| File | Status | Remarks |
|---|---|---|
| interview-01.xra | written | — |
| interview-02.xra | written, with remarks | An empty tier was removed: Comments. |
| gestures.eaf | refused | The file holds a tier of geometric labels, and you chose to skip such tiers. Nothing was left to write. |
| notes.TextGrid | skipped | The output file already exists. |
What the mockup settles, and what it does not
The labels of the aside do not move. Selecting another format changes what is said of each property, never the property said. Clicking from TextGrid to eaf and back shows what differs without anything being read twice.
The properties are a list, not a table. There is one format here: a table would assert a second dimension that does not exist, and would weigh on the page as though every line had to be analysed rather than read. The full matrix, which does have two dimensions, remains a table — in the details element, where it belongs.
Every property is on the same footing. This is a scientific application: it states its data. Some properties exist almost nowhere but in SPPAS, and a user who wants to know what vagueness is has the right to find it — in the same list, in the same order, as the ones everybody knows.
Two things are shown here and are not settled: the wording of the properties in plain language, and the wording of the causes of refusal. They are interface questions, and they are decided against this markup rather than in the abstract.
A third was open when this markup was drawn and is now settled elsewhere: the results replace what was shown, because a conversion is one request and its results are what that request answers. The organisational level says it and the sequence repeats it; the mockup is read with that settled.
Annex: Legal notices
- Author: Brigitte Bigi
- Document License: GNU Free Documentation License (GFDL) 1.3
- Copyright (C) 2026 Brigitte Bigi, CNRS
- Creation Date: 2026-07-16
- Last update: 2026-09-17