yarramate 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/visual/session-server.js +27 -1
- package/dist/adapters/visual/workspace-model.d.ts +16 -3
- package/dist/adapters/visual/workspace-model.js +12 -5
- package/dist/ask-command.js +25 -16
- package/dist/catalogue-sources.d.ts +20 -0
- package/dist/catalogue-sources.js +39 -0
- package/dist/check-command.js +38 -9
- package/dist/cli-support.d.ts +7 -0
- package/dist/cli-support.js +4 -0
- package/dist/design-command.js +21 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interrogate-command.d.ts +82 -1
- package/dist/interrogate-command.js +195 -29
- package/dist/interrogation-entry.d.ts +1 -1
- package/dist/interrogation-entry.js +1 -1
- package/dist/projection.d.ts +47 -0
- package/dist/projection.js +126 -0
- package/dist/visual-app-lib/editor.js +26771 -26713
- package/dist/visual-app-lib/types/adapters/visual/workspace-model.d.ts +16 -3
- package/dist/visual-app-lib/types/interrogate-command.d.ts +82 -1
- package/dist/visual-app-lib/types/projection.d.ts +47 -0
- package/dist/visual-app-lib/types/workspace.d.ts +15 -0
- package/dist/workbook-import-entry.d.ts +30 -0
- package/dist/workbook-import-entry.js +30 -0
- package/dist/workbook.js +15 -0
- package/dist/workspace.d.ts +15 -0
- package/dist/workspace.js +1 -0
- package/docs/CONSUMING-YARRAMATE.md +63 -0
- package/package.json +5 -1
- package/schema/yarramate-interrogation-report.schema.json +9 -0
- package/schema/yarramate-question-catalogue.schema.json +2 -3
- package/schema/yarramate-workspace.schema.json +4 -0
|
@@ -57,10 +57,20 @@ export interface DismissedQuestion {
|
|
|
57
57
|
export declare const interrogationOverlayOf: (compiled: {
|
|
58
58
|
readonly graph: SemanticGraph;
|
|
59
59
|
readonly profileContext: ResolvedProfileContext;
|
|
60
|
-
},
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* The catalogue, or the composed SET a workspace carries (#345, ADR 0129).
|
|
63
|
+
* A set rather than one document so the pane asks the same interview the
|
|
64
|
+
* CLI does over the same workspace: an editor showing fewer questions than
|
|
65
|
+
* `design` does over the same files is a disagreement with no symptom.
|
|
66
|
+
*/
|
|
67
|
+
catalogue: {
|
|
61
68
|
readonly path: string;
|
|
62
69
|
readonly source: string;
|
|
63
|
-
}
|
|
70
|
+
} | readonly {
|
|
71
|
+
readonly path: string;
|
|
72
|
+
readonly source: string;
|
|
73
|
+
}[],
|
|
64
74
|
/**
|
|
65
75
|
* What the host has already dealt with (#328). Evaluation is unchanged and
|
|
66
76
|
* the model is untouched: this decides only what the pane draws, because a
|
|
@@ -83,7 +93,10 @@ export declare const renderedWorkspaceOf: (compiled: {
|
|
|
83
93
|
}, views: readonly VisualViewSummary[], metadata: Omit<VisualRenderedModel, "graph" | "vocabulary" | "interrogation">, catalogue?: {
|
|
84
94
|
readonly path: string;
|
|
85
95
|
readonly source: string;
|
|
86
|
-
}
|
|
96
|
+
} | readonly {
|
|
97
|
+
readonly path: string;
|
|
98
|
+
readonly source: string;
|
|
99
|
+
}[], dismissed?: readonly DismissedQuestion[]) => {
|
|
87
100
|
readonly model: VisualRenderedModel;
|
|
88
101
|
readonly views: readonly VisualViewSummary[];
|
|
89
102
|
};
|
|
@@ -188,14 +188,29 @@ export interface InterrogationSummary {
|
|
|
188
188
|
export interface InterrogationReport {
|
|
189
189
|
readonly format: 'yarramate/interrogation-report/v1';
|
|
190
190
|
readonly workspace: string;
|
|
191
|
+
/** The BASE catalogue, `id@version`. Unchanged in shape by composition. */
|
|
191
192
|
readonly catalogue: string;
|
|
193
|
+
/**
|
|
194
|
+
* Every contributing catalogue as `id@version`, base first, when more than
|
|
195
|
+
* one contributed (#345, ADR 0129). Optional so that adding it breaks no
|
|
196
|
+
* constructor, and `catalogue` keeps its value shape so it breaks no reader.
|
|
197
|
+
*/
|
|
198
|
+
readonly catalogues?: readonly string[];
|
|
192
199
|
/** {@link INTERROGATION_SEMANTICS_VERSION} at the time of evaluation. */
|
|
193
200
|
readonly semantics: string;
|
|
194
201
|
readonly summary: InterrogationSummary;
|
|
195
202
|
readonly waves: readonly ReportWave[];
|
|
196
203
|
}
|
|
197
204
|
export declare const renderQuestion: (template: string, subjectId: string, subjectName: string | undefined, counterparts?: readonly string[]) => string;
|
|
198
|
-
export declare function evaluateCatalogue(catalogue: QuestionCatalogue, graph: SemanticGraph, profileContext?: ResolvedProfileContext, evidence?: readonly CatalogueEvidenceObservation[]
|
|
205
|
+
export declare function evaluateCatalogue(catalogue: QuestionCatalogue, graph: SemanticGraph, profileContext?: ResolvedProfileContext, evidence?: readonly CatalogueEvidenceObservation[],
|
|
206
|
+
/**
|
|
207
|
+
* Contributing catalogues, from {@link composeCatalogues}. Composition
|
|
208
|
+
* happens BEFORE evaluation and hands this function an ordinary catalogue,
|
|
209
|
+
* so the only thing evaluation learns about composition is what to name in
|
|
210
|
+
* the report. A fifth optional parameter rather than an options object,
|
|
211
|
+
* because this signature is published and a consumer already calls it.
|
|
212
|
+
*/
|
|
213
|
+
catalogues?: readonly string[]): Omit<InterrogationReport, 'workspace'>;
|
|
199
214
|
export type CatalogueLoadResult = {
|
|
200
215
|
readonly ok: true;
|
|
201
216
|
readonly catalogue: QuestionCatalogue;
|
|
@@ -203,5 +218,71 @@ export type CatalogueLoadResult = {
|
|
|
203
218
|
readonly ok: false;
|
|
204
219
|
readonly diagnostics: readonly Diagnostic[];
|
|
205
220
|
};
|
|
221
|
+
/**
|
|
222
|
+
* A catalogue is qualified on the way OUT, never in what an author writes.
|
|
223
|
+
*
|
|
224
|
+
* The authored schema keeps ids local (`^[a-z][a-z0-9-]*$`) and that does not
|
|
225
|
+
* change; a consultant writes `regulator-signoff`, not
|
|
226
|
+
* `consulting#regulator-signoff`. The engine qualifies when it composes, which
|
|
227
|
+
* is the only moment two catalogues can be confused for each other.
|
|
228
|
+
*
|
|
229
|
+
* NO VERSION, and that is the decision rather than an omission (ADR 0129).
|
|
230
|
+
* `core-enrichment` went 1.0 to 1.3 in a single day renaming nothing; a
|
|
231
|
+
* versioned identity would have stranded every stored dismissal in every
|
|
232
|
+
* adopter's database three times that day, for changes that removed no
|
|
233
|
+
* question. Versioned identity is safe for things that are AUTHORED - a
|
|
234
|
+
* document keeps naming the version it was written against and an author
|
|
235
|
+
* updates it deliberately - and unsafe for things that are STORED, because a
|
|
236
|
+
* row in someone's database has no author to update it.
|
|
237
|
+
*/
|
|
238
|
+
export declare const qualifiedQuestionId: (catalogueId: string, questionId: string) => string;
|
|
239
|
+
export interface ComposedCatalogue {
|
|
240
|
+
/**
|
|
241
|
+
* The composed catalogue, ready for `evaluateCatalogue`. Structurally a
|
|
242
|
+
* `QuestionCatalogue`, but its question ids are QUALIFIED, so it is a
|
|
243
|
+
* composition result rather than something an author could have written and
|
|
244
|
+
* must never be validated against the authored schema again.
|
|
245
|
+
*/
|
|
246
|
+
readonly catalogue: QuestionCatalogue;
|
|
247
|
+
/** Every contributing catalogue as `id@version`, base first. */
|
|
248
|
+
readonly catalogues: readonly string[];
|
|
249
|
+
}
|
|
250
|
+
export type CatalogueCompositionResult = {
|
|
251
|
+
readonly ok: true;
|
|
252
|
+
readonly composed: ComposedCatalogue;
|
|
253
|
+
} | {
|
|
254
|
+
readonly ok: false;
|
|
255
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Compose a base catalogue with the ones a workspace carries (#345, ADR 0129).
|
|
259
|
+
*
|
|
260
|
+
* ADDITIVE. `--catalogue` and `MountOptions.catalogue` replace the base; this
|
|
261
|
+
* adds to it, which is what lets a consultant author a question at any point
|
|
262
|
+
* in an engagement with no product release.
|
|
263
|
+
*
|
|
264
|
+
* A WAVE IS DECLARED EXACTLY ONCE across the resolved set, and any catalogue
|
|
265
|
+
* may contribute questions to a wave it did not declare. That one rule settles
|
|
266
|
+
* three questions composition would otherwise raise. Wave identity: a project
|
|
267
|
+
* catalogue joins a declared wave rather than colliding with it. Ordering:
|
|
268
|
+
* only a declaration places a wave, so the base's order is untouched and new
|
|
269
|
+
* waves append. And the `opensWhen` precedence ADR 0125 made load-bearing does
|
|
270
|
+
* not arise at all, because there is only ever one declarer to ask.
|
|
271
|
+
*
|
|
272
|
+
* QUALIFICATION IS A PROPERTY OF COMPOSITION, NOT OF EVALUATION. A caller
|
|
273
|
+
* that hands `evaluateCatalogue` a catalogue directly still gets local ids,
|
|
274
|
+
* exactly as before this existed. Route through here even for ONE catalogue -
|
|
275
|
+
* which is what every CLI verb does - and ids are qualified from the start, so
|
|
276
|
+
* they do not change later when a workspace first carries a question of its
|
|
277
|
+
* own. That transition is the one thing an adopter keying stored judgments on
|
|
278
|
+
* a question id must not experience, and composing unconditionally is how it
|
|
279
|
+
* is avoided.
|
|
280
|
+
*
|
|
281
|
+
* ID COLLISIONS DISSOLVE rather than being resolved. Two catalogues may both
|
|
282
|
+
* carry `outcome-missing`; qualified, they are two different questions. There
|
|
283
|
+
* is no merge rule, no last-wins and no refusal, because there is nothing to
|
|
284
|
+
* merge.
|
|
285
|
+
*/
|
|
286
|
+
export declare function composeCatalogues(sources: readonly WorkspaceSource[], profileContext?: ResolvedProfileContext): CatalogueCompositionResult;
|
|
206
287
|
export declare function loadQuestionCatalogue(catalogueSource: WorkspaceSource, profileContext?: ResolvedProfileContext): CatalogueLoadResult;
|
|
207
288
|
export declare function renderInterrogationReport(report: InterrogationReport): string;
|
|
@@ -108,6 +108,53 @@ export interface ProjectionExclusion {
|
|
|
108
108
|
readonly id: string;
|
|
109
109
|
readonly facet: ConceptFacet;
|
|
110
110
|
}
|
|
111
|
+
/** A query facet naming something the model does not have. */
|
|
112
|
+
export interface UnmatchedSelector {
|
|
113
|
+
readonly facet: string;
|
|
114
|
+
readonly value: string;
|
|
115
|
+
/** The closest name the facet does offer, when one is close enough to be a likely typo. */
|
|
116
|
+
readonly nearest?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Every value in a projection query that names nothing.
|
|
120
|
+
*
|
|
121
|
+
* A projection is a DOCUMENT, and a query holds references the same way a
|
|
122
|
+
* relationship does. YarraMate refuses a relationship pointing at a concept
|
|
123
|
+
* that does not exist; it did not refuse a query naming a state that does not
|
|
124
|
+
* exist, and the symptom is silent. `states: [target-stat]` selects no state,
|
|
125
|
+
* which selects no subject, which exports a clean empty artifact with exit 0.
|
|
126
|
+
* Someone hands that to a client.
|
|
127
|
+
*
|
|
128
|
+
* Checked at `check`, not at `export`, because the typo is in a file rather
|
|
129
|
+
* than in an invocation: CI catches it, and every verb over the same
|
|
130
|
+
* projection inherits the guard instead of each growing its own.
|
|
131
|
+
*
|
|
132
|
+
* ONLY FACETS WITH A CLOSED NAMESPACE ARE CHECKED. `statuses` and
|
|
133
|
+
* `excludeStatuses` are schema enums, refused upstream before this runs.
|
|
134
|
+
* Everything else names something: `owners` and `constraints` are REFS to
|
|
135
|
+
* concepts, which the compiler itself proves by refusing an unresolved owner
|
|
136
|
+
* with YM304, so their namespace is the subject list like `subjects`.
|
|
137
|
+
*
|
|
138
|
+
* Each namespace is derived the way the FILTER derives it, so the check cannot
|
|
139
|
+
* drift from what it guards: `documents` reads the same provenance the
|
|
140
|
+
* `documents` facet compares against, and `states` is the same
|
|
141
|
+
* `yarramate/state/type` scan `conceptSelector` runs.
|
|
142
|
+
*
|
|
143
|
+
* A kind whose profile is not loaded is DORMANT rather than wrong, the same
|
|
144
|
+
* distinction #351 drew for question catalogues, so the kind facets are
|
|
145
|
+
* checked only when a profile context is present.
|
|
146
|
+
*
|
|
147
|
+
* An empty RESULT is not reported here and must not be. A query whose every
|
|
148
|
+
* name resolves and which selects nothing is a real answer to a real question:
|
|
149
|
+
* a target state nobody has populated yet is empty, correctly.
|
|
150
|
+
*/
|
|
151
|
+
export declare function unmatchedSelectors(graph: SemanticGraph, projection: ProjectionDefinition, profileContext?: ResolvedProfileContext): readonly UnmatchedSelector[];
|
|
152
|
+
/**
|
|
153
|
+
* {@link unmatchedSelectors} as diagnostics, built HERE rather than at each
|
|
154
|
+
* caller so `check`, and anything that adopts this later, refuse in identical
|
|
155
|
+
* words with an identical code.
|
|
156
|
+
*/
|
|
157
|
+
export declare function projectionReferenceDiagnostics(source: WorkspaceSource, projection: ProjectionDefinition, graph: SemanticGraph, profileContext?: ResolvedProfileContext): readonly Diagnostic[];
|
|
111
158
|
/**
|
|
112
159
|
* Every concept a query leaves out, and the facet that left it out.
|
|
113
160
|
*
|
|
@@ -7,6 +7,7 @@ export interface WorkspaceManifest {
|
|
|
7
7
|
readonly projections: readonly string[];
|
|
8
8
|
readonly adapterMappings: readonly string[];
|
|
9
9
|
readonly patterns?: readonly string[];
|
|
10
|
+
readonly questions?: readonly string[];
|
|
10
11
|
readonly evidence?: readonly string[];
|
|
11
12
|
readonly contracts?: readonly string[];
|
|
12
13
|
}
|
|
@@ -17,6 +18,20 @@ export interface ResolvedWorkspace {
|
|
|
17
18
|
readonly projections: readonly string[];
|
|
18
19
|
readonly adapterMappings: readonly string[];
|
|
19
20
|
readonly patterns: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* Question catalogues the workspace itself carries (#345, ADR 0129).
|
|
23
|
+
* ADDITIVE to the shipped catalogue: `--catalogue` replaces the base, this
|
|
24
|
+
* adds to it, which is what lets a consultant author a question mid
|
|
25
|
+
* engagement without a product release.
|
|
26
|
+
*
|
|
27
|
+
* OPTIONAL in the type although `loadWorkspaceManifest` always populates it,
|
|
28
|
+
* and that is deliberate. `ResolvedWorkspace` is published, and adding
|
|
29
|
+
* `patterns` to it as a required field broke a consumer's production module:
|
|
30
|
+
* a required field is free for readers and a break for CONSTRUCTORS. Six
|
|
31
|
+
* fixtures in this repository construct one, which is the same signal from
|
|
32
|
+
* inside. Read it as `workspace.questions ?? []`.
|
|
33
|
+
*/
|
|
34
|
+
readonly questions?: readonly string[];
|
|
20
35
|
readonly evidence: readonly string[];
|
|
21
36
|
readonly contracts: readonly string[];
|
|
22
37
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yarramate/workbook/import` — reading an edited workbook back, for a host
|
|
3
|
+
* that has no Node.
|
|
4
|
+
*
|
|
5
|
+
* A SEPARATE subpath from `yarramate/workbook` rather than more exports on it,
|
|
6
|
+
* because the package declares no `sideEffects` field and a bundler must
|
|
7
|
+
* therefore assume every module might have one. A Worker that only GENERATES
|
|
8
|
+
* workbooks would otherwise carry the reader, the merge and the operations
|
|
9
|
+
* emitter it never calls, and small bundles are the reason the xlsx container
|
|
10
|
+
* is hand-written in the first place (#355).
|
|
11
|
+
*
|
|
12
|
+
* Held to the same bar as `./workbook` and `./interrogation` by
|
|
13
|
+
* `test/export-purity.test.ts`: no Node builtins, no `ws`, no session server,
|
|
14
|
+
* no runtime import of the compiler. `workbook-read.ts` imports nothing at
|
|
15
|
+
* all; inflation uses `DecompressionStream('deflate-raw')`, which Workers,
|
|
16
|
+
* browsers and Node 18+ all have.
|
|
17
|
+
*
|
|
18
|
+
* The reader is ASYNC and the writer is not, deliberately. A workbook this
|
|
19
|
+
* package wrote has stored entries and inline strings, but one a person saved
|
|
20
|
+
* from Excel comes back deflated and shared-stringed, and inflation is only
|
|
21
|
+
* offered as a stream.
|
|
22
|
+
*
|
|
23
|
+
* What a host still owns: reading the bytes, evaluating the projection that
|
|
24
|
+
* says what the workbook SHOULD hold now, and applying the operations. This
|
|
25
|
+
* entry turns bytes into sheets, sheets into a merge report, and a merge
|
|
26
|
+
* report into `yarramate/operations/v1`.
|
|
27
|
+
*/
|
|
28
|
+
export { readWorkbook, unzipEntries, columnIndexOf, decodeXmlText, type WorkbookRead, type ZipReadFailure, } from './workbook-read.js';
|
|
29
|
+
export { mergeWorkbook, mergeSheet, keySheet, baselineSheets, isDerivedColumn, type KeyedSheet, type CellChange, type Conflict, type MergeReport, } from './workbook-merge.js';
|
|
30
|
+
export { operationsFrom, operationsDocument, type OperationsResult, } from './workbook-operations.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yarramate/workbook/import` — reading an edited workbook back, for a host
|
|
3
|
+
* that has no Node.
|
|
4
|
+
*
|
|
5
|
+
* A SEPARATE subpath from `yarramate/workbook` rather than more exports on it,
|
|
6
|
+
* because the package declares no `sideEffects` field and a bundler must
|
|
7
|
+
* therefore assume every module might have one. A Worker that only GENERATES
|
|
8
|
+
* workbooks would otherwise carry the reader, the merge and the operations
|
|
9
|
+
* emitter it never calls, and small bundles are the reason the xlsx container
|
|
10
|
+
* is hand-written in the first place (#355).
|
|
11
|
+
*
|
|
12
|
+
* Held to the same bar as `./workbook` and `./interrogation` by
|
|
13
|
+
* `test/export-purity.test.ts`: no Node builtins, no `ws`, no session server,
|
|
14
|
+
* no runtime import of the compiler. `workbook-read.ts` imports nothing at
|
|
15
|
+
* all; inflation uses `DecompressionStream('deflate-raw')`, which Workers,
|
|
16
|
+
* browsers and Node 18+ all have.
|
|
17
|
+
*
|
|
18
|
+
* The reader is ASYNC and the writer is not, deliberately. A workbook this
|
|
19
|
+
* package wrote has stored entries and inline strings, but one a person saved
|
|
20
|
+
* from Excel comes back deflated and shared-stringed, and inflation is only
|
|
21
|
+
* offered as a stream.
|
|
22
|
+
*
|
|
23
|
+
* What a host still owns: reading the bytes, evaluating the projection that
|
|
24
|
+
* says what the workbook SHOULD hold now, and applying the operations. This
|
|
25
|
+
* entry turns bytes into sheets, sheets into a merge report, and a merge
|
|
26
|
+
* report into `yarramate/operations/v1`.
|
|
27
|
+
*/
|
|
28
|
+
export { readWorkbook, unzipEntries, columnIndexOf, decodeXmlText, } from './workbook-read.js';
|
|
29
|
+
export { mergeWorkbook, mergeSheet, keySheet, baselineSheets, isDerivedColumn, } from './workbook-merge.js';
|
|
30
|
+
export { operationsFrom, operationsDocument, } from './workbook-operations.js';
|
package/dist/workbook.js
CHANGED
|
@@ -239,6 +239,21 @@ export const buildWorkbookSheets = (result, provenance) => {
|
|
|
239
239
|
['4.', 'Deleting a row does NOT delete anything. Removals are reported, never applied.'],
|
|
240
240
|
['5.', 'Send the file back and import it. Your edits are merged; only a field changed on both sides is refused.'],
|
|
241
241
|
[],
|
|
242
|
+
[],
|
|
243
|
+
['What this holds, and what it does not'],
|
|
244
|
+
[
|
|
245
|
+
'',
|
|
246
|
+
`A projection is a QUERY, so this workbook is the slice it names: ${conceptRows.length - 1} concepts and ${relationshipRows.length - 1} relationships.`,
|
|
247
|
+
],
|
|
248
|
+
[
|
|
249
|
+
'',
|
|
250
|
+
'Everything the model knows about a subject that IS here is here, including anything these columns do not model, on 07 Other Facts.',
|
|
251
|
+
],
|
|
252
|
+
[
|
|
253
|
+
'',
|
|
254
|
+
'A subject outside the slice has no row, and importing this file cannot change it. A narrow workbook is safe against a wide model.',
|
|
255
|
+
],
|
|
256
|
+
[],
|
|
242
257
|
['Sheets beginning ~ are machinery. Do not edit them.'],
|
|
243
258
|
];
|
|
244
259
|
const listColumns = [
|
package/dist/workspace.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface WorkspaceManifest {
|
|
|
7
7
|
readonly projections: readonly string[];
|
|
8
8
|
readonly adapterMappings: readonly string[];
|
|
9
9
|
readonly patterns?: readonly string[];
|
|
10
|
+
readonly questions?: readonly string[];
|
|
10
11
|
readonly evidence?: readonly string[];
|
|
11
12
|
readonly contracts?: readonly string[];
|
|
12
13
|
}
|
|
@@ -17,6 +18,20 @@ export interface ResolvedWorkspace {
|
|
|
17
18
|
readonly projections: readonly string[];
|
|
18
19
|
readonly adapterMappings: readonly string[];
|
|
19
20
|
readonly patterns: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* Question catalogues the workspace itself carries (#345, ADR 0129).
|
|
23
|
+
* ADDITIVE to the shipped catalogue: `--catalogue` replaces the base, this
|
|
24
|
+
* adds to it, which is what lets a consultant author a question mid
|
|
25
|
+
* engagement without a product release.
|
|
26
|
+
*
|
|
27
|
+
* OPTIONAL in the type although `loadWorkspaceManifest` always populates it,
|
|
28
|
+
* and that is deliberate. `ResolvedWorkspace` is published, and adding
|
|
29
|
+
* `patterns` to it as a required field broke a consumer's production module:
|
|
30
|
+
* a required field is free for readers and a break for CONSTRUCTORS. Six
|
|
31
|
+
* fixtures in this repository construct one, which is the same signal from
|
|
32
|
+
* inside. Read it as `workspace.questions ?? []`.
|
|
33
|
+
*/
|
|
34
|
+
readonly questions?: readonly string[];
|
|
20
35
|
readonly evidence: readonly string[];
|
|
21
36
|
readonly contracts: readonly string[];
|
|
22
37
|
}
|
package/dist/workspace.js
CHANGED
|
@@ -107,6 +107,7 @@ export function loadWorkspaceManifest(source, cwd) {
|
|
|
107
107
|
projections: expand('projections', 'projection', value.projections),
|
|
108
108
|
adapterMappings: expand('adapterMappings', 'adapter mapping', value.adapterMappings),
|
|
109
109
|
patterns: expand('patterns', 'pattern', value.patterns ?? []),
|
|
110
|
+
questions: expand('questions', 'question catalogue', value.questions ?? []),
|
|
110
111
|
evidence: expand('evidence', 'evidence', value.evidence ?? []),
|
|
111
112
|
contracts: expand('contracts', 'Core contract', value.contracts ?? []),
|
|
112
113
|
};
|
|
@@ -444,6 +444,18 @@ query:
|
|
|
444
444
|
- target-state
|
|
445
445
|
```
|
|
446
446
|
|
|
447
|
+
**Which makes a workbook a SLICE, and it is worth being plain about that.** An
|
|
448
|
+
omitted facet imposes no constraint, so `query: {}` exports the whole model,
|
|
449
|
+
and every facet you name narrows it. For a subject the query selected, nothing
|
|
450
|
+
is dropped: the projection filters claims by subject membership rather than by
|
|
451
|
+
predicate, so every fact about an included subject arrives, and `07 Other
|
|
452
|
+
Facts` catches whatever the named columns do not model. For a subject it did
|
|
453
|
+
not select, there is simply no row, and a missing row is never a deletion, so
|
|
454
|
+
**a narrow workbook cannot damage a wide model on the way back in**. The
|
|
455
|
+
`00 Read Me` sheet says all of this and reports the counts the slice actually
|
|
456
|
+
has, because an FDE handed a filtered workbook with no note will read it as
|
|
457
|
+
the model.
|
|
458
|
+
|
|
447
459
|
**Reading the sheets.** Column A is always the id and is what the model is
|
|
448
460
|
keyed on. A column headed `↳ … (auto)` is derived for readability and is
|
|
449
461
|
ignored on the way back. Kind and status columns are drawn from the compiled
|
|
@@ -472,6 +484,57 @@ did not touch merges even if the repository moved on; only a field changed on
|
|
|
472
484
|
is reported and never treated as a deletion, and a new row needs its `Document`
|
|
473
485
|
column filled in.
|
|
474
486
|
|
|
487
|
+
**On a host with no Node**, `yarramate/workbook/import` publishes the same
|
|
488
|
+
three steps the CLI runs, so ingesting a workbook is not CLI-only:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
import {
|
|
492
|
+
readWorkbook,
|
|
493
|
+
baselineSheets,
|
|
494
|
+
mergeWorkbook,
|
|
495
|
+
operationsFrom,
|
|
496
|
+
operationsDocument,
|
|
497
|
+
} from 'yarramate/workbook/import'
|
|
498
|
+
|
|
499
|
+
const read = await readWorkbook(bytes)
|
|
500
|
+
if (!read.ok) return refuse(read.reason)
|
|
501
|
+
|
|
502
|
+
const ancestor = read.sheets.get('~Baseline')
|
|
503
|
+
if (ancestor === undefined) return refuse('not produced by yarramate export xlsx')
|
|
504
|
+
|
|
505
|
+
const report = mergeWorkbook(
|
|
506
|
+
read.sheets,
|
|
507
|
+
baselineSheets(ancestor),
|
|
508
|
+
buildWorkbookSheets(currentResult, provenance),
|
|
509
|
+
)
|
|
510
|
+
if (report.conflicts.length > 0) return refuse(report.conflicts)
|
|
511
|
+
|
|
512
|
+
const { operations, refusals } = operationsFrom(report, read.sheets)
|
|
513
|
+
await apply(operationsDocument(operations))
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
`readWorkbook` is **async** while the writer is synchronous, and deliberately
|
|
517
|
+
so: a workbook this package wrote has stored entries and inline strings, but
|
|
518
|
+
one a person saved from Excel comes back deflated and shared-stringed, and
|
|
519
|
+
inflation is only offered as a stream (`DecompressionStream('deflate-raw')`,
|
|
520
|
+
present on Workers, in browsers and in Node 18+). Keeping the writer
|
|
521
|
+
synchronous is what stops it infecting a synchronous store on the host side.
|
|
522
|
+
|
|
523
|
+
It is a **separate subpath** from `yarramate/workbook` on purpose. The package
|
|
524
|
+
declares no `sideEffects` field, so a bundler must assume every module might
|
|
525
|
+
have one and cannot shake an unused re-export away; a host that only generates
|
|
526
|
+
workbooks would otherwise carry the reader, the merge and the operations
|
|
527
|
+
emitter it never calls. `test/export-purity.test.ts` holds the two entries
|
|
528
|
+
disjoint as well as pure.
|
|
529
|
+
|
|
530
|
+
The host keeps three jobs: reading the bytes, evaluating the projection that
|
|
531
|
+
says what the model holds **now** (the third argument to `mergeWorkbook`, which
|
|
532
|
+
is what measures repo drift in the same terms the author edited in), and
|
|
533
|
+
applying the operations. Refusal wording is the host's too. The `Conflict`
|
|
534
|
+
values name the sheet, row, column, what the author wrote, what the workspace
|
|
535
|
+
now holds and their common ancestor, which reads like a merge tool rather than
|
|
536
|
+
like something you hand a consultant.
|
|
537
|
+
|
|
475
538
|
## MCP server for agent harnesses
|
|
476
539
|
|
|
477
540
|
Harnesses that load MCP servers can connect the bundled read-only adapter:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yarramate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Tool-neutral semantic architecture engine and guided methodology",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"types": "./dist/workbook-entry.d.ts",
|
|
63
63
|
"import": "./dist/workbook-entry.js"
|
|
64
64
|
},
|
|
65
|
+
"./workbook/import": {
|
|
66
|
+
"types": "./dist/workbook-import-entry.d.ts",
|
|
67
|
+
"import": "./dist/workbook-import-entry.js"
|
|
68
|
+
},
|
|
65
69
|
"./visual-app": {
|
|
66
70
|
"types": "./dist/visual-app-lib/editor.d.ts",
|
|
67
71
|
"import": "./dist/visual-app-lib/editor.js"
|
|
@@ -24,6 +24,15 @@
|
|
|
24
24
|
"type": "string",
|
|
25
25
|
"minLength": 1
|
|
26
26
|
},
|
|
27
|
+
"catalogues": {
|
|
28
|
+
"description": "Every catalogue that contributed, as id@version, base first (#345, ADR 0129). Present only when more than one did. OPTIONAL, and `catalogue` keeps naming the base with its existing value shape, because turning that field into an array would break every reader: an optional additive field is free for readers and does not force constructors. Question ids in this report are qualified as catalogue#question and carry NO version, so a catalogue version bump strands no stored judgment keyed on them; the versions live here instead.",
|
|
29
|
+
"type": "array",
|
|
30
|
+
"minItems": 1,
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1
|
|
34
|
+
}
|
|
35
|
+
},
|
|
27
36
|
"semantics": {
|
|
28
37
|
"type": "string",
|
|
29
38
|
"minLength": 1,
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"waves": {
|
|
47
|
-
"description": "Ordered interview phases. Array order is interview order. The wave taxonomy is catalogue opinion, not engine semantics.",
|
|
47
|
+
"description": "Ordered interview phases. Array order is interview order. The wave taxonomy is catalogue opinion, not engine semantics. MAY BE EMPTY (#345, ADR 0129): a catalogue that only contributes questions to waves ANOTHER catalogue declared is the ordinary shape of a project catalogue, and requiring a wave here would force it to declare one it does not want - which is refused as a duplicate the moment two catalogues do it. Evaluated alone, a catalogue with no waves and a question naming one is YM911, correctly: nothing declares it.",
|
|
48
48
|
"type": "array",
|
|
49
|
-
"minItems":
|
|
49
|
+
"minItems": 0,
|
|
50
50
|
"items": {
|
|
51
51
|
"type": "object",
|
|
52
52
|
"additionalProperties": false,
|
|
@@ -112,7 +112,6 @@
|
|
|
112
112
|
"description": "Which subjects a subject-scope question applies to. Field vocabulary mirrors the projection query selector (ADR 0017).",
|
|
113
113
|
"type": "object",
|
|
114
114
|
"additionalProperties": false,
|
|
115
|
-
|
|
116
115
|
"properties": {
|
|
117
116
|
"kinds": {
|
|
118
117
|
"type": "array",
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"description": "yarramate/pattern/v1 documents: the shape a concept kind promises, and the wiring the compiler mints between an instance and the parts it binds (ADR 0123). Structure, where profiles declare vocabulary. Optional, like evidence and contracts.",
|
|
33
33
|
"$ref": "#/$defs/patterns"
|
|
34
34
|
},
|
|
35
|
+
"questions": {
|
|
36
|
+
"description": "yarramate/question-catalogue/v1 documents the WORKSPACE carries: questions true of this engagement and nowhere else (#345, ADR 0129). ADDITIVE to the shipped catalogue rather than replacing it, which is what --catalogue and MountOptions.catalogue do. Question ids are qualified as catalogue#question on the way out, so two catalogues may carry the same local id. A wave is declared exactly once across the resolved set, and any catalogue may contribute questions to a wave it did not declare. Optional, like patterns, evidence and contracts.",
|
|
37
|
+
"$ref": "#/$defs/patterns"
|
|
38
|
+
},
|
|
35
39
|
"adapterMappings": {
|
|
36
40
|
"$ref": "#/$defs/patterns"
|
|
37
41
|
},
|