@medicine-wheel/gap-analysis 0.5.3

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/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @medicine-wheel/gap-analysis
2
+
3
+ Problem-solving, built properly and without apology.
4
+
5
+ > [!WARNING]
6
+ > **Experimental alpha.** Part of the Medicine Wheel Developer Suite, which is
7
+ > under active development. APIs change between patch versions and all packages
8
+ > move in lockstep — pin exact versions. See
9
+ > [ALPHA.md](https://github.com/jgwill/medicine-wheel/blob/main/ALPHA.md).
10
+
11
+ ## Why it exists
12
+
13
+ Sometimes the forest is on fire. Digitally too. When something worked and
14
+ stopped working, closing the difference between the current state and the prior
15
+ one is the **right** move — oscillating back to a baseline is the goal when you
16
+ are below the baseline.
17
+
18
+ Work like that deserves a real instrument rather than a euphemism, so this
19
+ package is built as a first-class citizen of the suite and not smuggled in under
20
+ a nicer name.
21
+
22
+ ## The question at the door
23
+
24
+ Every analysis carries an orientation reading taken when it was opened, via
25
+ `@medicine-wheel/creative-orientation`. The question is always the same: *is a
26
+ prior state actually being restored?*
27
+
28
+ Opening an analysis **requires a baseline with evidence**. That requirement is
29
+ the whole point — it is the thing that separates a fire from a creating act, and
30
+ it cannot be satisfied by a feeling of urgency.
31
+
32
+ ```ts
33
+ import { openGapAnalysis, addStep, doorAdvice } from '@medicine-wheel/gap-analysis';
34
+
35
+ let analysis = openGapAnalysis(
36
+ { description: 'the published image matched the published packages',
37
+ evidence: 'true through 0.5.0, tagged 2026-07-17' },
38
+ { description: 'newest versioned image tag is 0.5.0; npm is at 0.5.2; 0.5.1 has no image',
39
+ source: 'Docker Hub tags API, read 2026-07-25' },
40
+ 'the image no longer tracks npm because building it depends on a human remembering a flag',
41
+ );
42
+
43
+ doorAdvice(analysis); // null — the situation and the instrument agree
44
+
45
+ analysis = addStep(analysis, {
46
+ action: 'build the image from the tag in CI rather than from release.sh',
47
+ verifiedBy: 'a v* tag push produces :app and :<version> without anyone running anything',
48
+ });
49
+ ```
50
+
51
+ ## It advises; it never refuses
52
+
53
+ If you open an analysis without evidence for the baseline, you get the analysis
54
+ **and** advice saying the routing rests on a feeling. You are not blocked. A
55
+ package that refuses is a package you learn to route around, and sometimes the
56
+ caller knows something the check does not.
57
+
58
+ ## Steps must be verifiable
59
+
60
+ `addStep` rejects a step with no `verifiedBy`. An elimination step you cannot
61
+ check is a wish; the fire is out only when something says so.
62
+
63
+ ## Where it sits
64
+
65
+ ```
66
+ creative-orientation ......... the gate
67
+ ├── gap-analysis ......... you are here — the fire path
68
+ └── structural-tension ... the advancing path
69
+ ```
70
+
71
+ Gap analysis is a borrowed instrument. It is genuinely available, and it is not
72
+ the foundation — the orientation question comes first, and this package reports
73
+ to it rather than the reverse.
74
+
75
+ ## Status
76
+
77
+ First release. Small on purpose.
78
+
79
+ ## License
80
+
81
+ MIT
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @medicine-wheel/gap-analysis
3
+ *
4
+ * The fire path, built properly and without apology.
5
+ *
6
+ * When something worked and stopped working, closing the difference between
7
+ * current and prior state is the correct move. Oscillation back to a baseline
8
+ * is the goal when you are below the baseline. This package exists so that
9
+ * work has a real instrument instead of a euphemism.
10
+ *
11
+ * It carries one question at its door — is a prior state actually being
12
+ * restored? — and asks it through `@medicine-wheel/creative-orientation`.
13
+ * It **advises and proceeds**. It never refuses. A package that blocks you is
14
+ * a package you learn to route around.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+ import { type OrientationReading } from '@medicine-wheel/creative-orientation';
19
+ export interface Baseline {
20
+ /** The state being restored, described concretely. */
21
+ description: string;
22
+ /** Evidence it existed — a date, a commit, a reading, a receipt. */
23
+ evidence: string;
24
+ }
25
+ export interface Observation {
26
+ /** What is true now, stated as measurement rather than interpretation. */
27
+ description: string;
28
+ /** Where this reading came from. */
29
+ source?: string;
30
+ }
31
+ export interface EliminationStep {
32
+ action: string;
33
+ /** How you will know this step worked. */
34
+ verifiedBy: string;
35
+ done?: boolean;
36
+ }
37
+ export interface GapAnalysis {
38
+ id: string;
39
+ baseline: Baseline;
40
+ current: Observation;
41
+ /** What is missing or wrong, derived from the two states above. */
42
+ difference: string;
43
+ rootCause?: string;
44
+ steps: EliminationStep[];
45
+ opened: string;
46
+ /**
47
+ * The orientation reading taken when this analysis was opened. Kept on the
48
+ * record so a later reader can see whether the instrument suited the
49
+ * situation, rather than having to reconstruct it.
50
+ */
51
+ orientation: OrientationReading;
52
+ }
53
+ export interface OpenGapOptions {
54
+ id?: string;
55
+ idFactory?: () => string;
56
+ timestamp?: string;
57
+ }
58
+ /**
59
+ * Open a gap analysis.
60
+ *
61
+ * A baseline with evidence is required, and that requirement is the whole
62
+ * point: it is the question that separates a fire from a creating act. If you
63
+ * cannot name a state that existed, the returned analysis carries advice
64
+ * saying so — and is still returned, because the caller may know something
65
+ * this check does not.
66
+ */
67
+ export declare function openGapAnalysis(baseline: Baseline, current: Observation, difference: string, options?: OpenGapOptions): GapAnalysis;
68
+ /** Add a step, with the check that makes it verifiable rather than hopeful. */
69
+ export declare function addStep(analysis: GapAnalysis, step: EliminationStep): GapAnalysis;
70
+ export declare function markDone(analysis: GapAnalysis, action: string): GapAnalysis;
71
+ /** Closed when every step is done. Says nothing about whether it was the right analysis. */
72
+ export declare function isClosed(analysis: GapAnalysis): boolean;
73
+ /**
74
+ * The advice to surface at the door, if any.
75
+ *
76
+ * Returns null when the situation and the instrument agree — advice on
77
+ * correctly-framed work is noise, and noise is how checks get switched off.
78
+ */
79
+ export declare function doorAdvice(analysis: GapAnalysis): string | null;
80
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,QAAQ;IACvB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,cAAmB,GAC3B,WAAW,CA0Bb;AAED,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,GAAG,WAAW,CAQjF;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAK3E;AAED,4FAA4F;AAC5F,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAE/D"}
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openGapAnalysis = openGapAnalysis;
4
+ exports.addStep = addStep;
5
+ exports.markDone = markDone;
6
+ exports.isClosed = isClosed;
7
+ exports.doorAdvice = doorAdvice;
8
+ /**
9
+ * @medicine-wheel/gap-analysis
10
+ *
11
+ * The fire path, built properly and without apology.
12
+ *
13
+ * When something worked and stopped working, closing the difference between
14
+ * current and prior state is the correct move. Oscillation back to a baseline
15
+ * is the goal when you are below the baseline. This package exists so that
16
+ * work has a real instrument instead of a euphemism.
17
+ *
18
+ * It carries one question at its door — is a prior state actually being
19
+ * restored? — and asks it through `@medicine-wheel/creative-orientation`.
20
+ * It **advises and proceeds**. It never refuses. A package that blocks you is
21
+ * a package you learn to route around.
22
+ *
23
+ * @packageDocumentation
24
+ */
25
+ const creative_orientation_1 = require("@medicine-wheel/creative-orientation");
26
+ function defaultId() {
27
+ return `gap:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
28
+ }
29
+ /**
30
+ * Open a gap analysis.
31
+ *
32
+ * A baseline with evidence is required, and that requirement is the whole
33
+ * point: it is the question that separates a fire from a creating act. If you
34
+ * cannot name a state that existed, the returned analysis carries advice
35
+ * saying so — and is still returned, because the caller may know something
36
+ * this check does not.
37
+ */
38
+ function openGapAnalysis(baseline, current, difference, options = {}) {
39
+ if (!baseline.description?.trim()) {
40
+ throw new Error('A gap analysis needs a baseline — the state you are restoring. Without one there is ' +
41
+ 'nothing to close toward, and the situation is a creating act rather than a repair.');
42
+ }
43
+ if (!current.description?.trim()) {
44
+ throw new Error('A gap analysis needs an observation of what is true now.');
45
+ }
46
+ const claim = {
47
+ outcome: difference,
48
+ restores: baseline.description,
49
+ evidence: baseline.evidence,
50
+ };
51
+ return {
52
+ id: options.id ?? (options.idFactory ? options.idFactory() : defaultId()),
53
+ baseline,
54
+ current,
55
+ difference,
56
+ steps: [],
57
+ opened: options.timestamp ?? new Date().toISOString(),
58
+ orientation: (0, creative_orientation_1.readOrientation)(claim),
59
+ };
60
+ }
61
+ /** Add a step, with the check that makes it verifiable rather than hopeful. */
62
+ function addStep(analysis, step) {
63
+ if (!step.verifiedBy?.trim()) {
64
+ throw new Error(`Step "${step.action}" has no verification. An elimination step you cannot check is a ` +
65
+ 'wish; the fire is out only when something says so.');
66
+ }
67
+ return { ...analysis, steps: [...analysis.steps, step] };
68
+ }
69
+ function markDone(analysis, action) {
70
+ return {
71
+ ...analysis,
72
+ steps: analysis.steps.map(s => (s.action === action ? { ...s, done: true } : s)),
73
+ };
74
+ }
75
+ /** Closed when every step is done. Says nothing about whether it was the right analysis. */
76
+ function isClosed(analysis) {
77
+ return analysis.steps.length > 0 && analysis.steps.every(s => s.done === true);
78
+ }
79
+ /**
80
+ * The advice to surface at the door, if any.
81
+ *
82
+ * Returns null when the situation and the instrument agree — advice on
83
+ * correctly-framed work is noise, and noise is how checks get switched off.
84
+ */
85
+ function doorAdvice(analysis) {
86
+ return (0, creative_orientation_1.worthSaying)(analysis.orientation) ? analysis.orientation.advice ?? null : null;
87
+ }
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAiFA,0CA+BC;AAGD,0BAQC;AAED,4BAKC;AAGD,4BAEC;AAQD,gCAEC;AAjJD;;;;;;;;;;;;;;;;GAgBG;AACH,+EAK8C;AA8C9C,SAAS,SAAS;IAChB,OAAO,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,eAAe,CAC7B,QAAkB,EAClB,OAAoB,EACpB,UAAkB,EAClB,UAA0B,EAAE;IAE5B,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACb,sFAAsF;YACpF,oFAAoF,CACvF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,KAAK,GAAmB;QAC5B,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,QAAQ,CAAC,WAAW;QAC9B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QACzE,QAAQ;QACR,OAAO;QACP,UAAU;QACV,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrD,WAAW,EAAE,IAAA,sCAAe,EAAC,KAAK,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,SAAgB,OAAO,CAAC,QAAqB,EAAE,IAAqB;IAClE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,SAAS,IAAI,CAAC,MAAM,mEAAmE;YACrF,oDAAoD,CACvD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAgB,QAAQ,CAAC,QAAqB,EAAE,MAAc;IAC5D,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACjF,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,SAAgB,QAAQ,CAAC,QAAqB;IAC5C,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACjF,CAAC;AAED;;;;;GAKG;AACH,SAAgB,UAAU,CAAC,QAAqB;IAC9C,OAAO,IAAA,kCAAW,EAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@medicine-wheel/gap-analysis",
3
+ "version": "0.5.3",
4
+ "description": "Problem-solving done properly — baseline, observation, difference, elimination steps — with the orientation question asked at its door rather than assumed.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "sideEffects": false,
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "clean": "rm -rf dist",
23
+ "prepublishOnly": "npm run clean && npm run build"
24
+ },
25
+ "keywords": [
26
+ "medicine-wheel",
27
+ "gap-analysis",
28
+ "problem-solving",
29
+ "root-cause",
30
+ "incident"
31
+ ],
32
+ "author": "jgwill",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/jgwill/medicine-wheel.git",
37
+ "directory": "src/gap-analysis"
38
+ },
39
+ "dependencies": {
40
+ "@medicine-wheel/creative-orientation": "^0.5.3"
41
+ },
42
+ "devDependencies": {
43
+ "typescript": "^5.7.0"
44
+ }
45
+ }