@okfit/profiles 0.7.4 → 0.8.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/Provenance.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Derivation } from "./Derivation.js";
2
- import { Diagnostic, OkfitConfig, Timestamp } from "@okfit/core";
2
+ import { Diagnostic, DiagnosticRange, OkfitConfig, Timestamp } from "@okfit/core";
3
3
  import { DateTime, Effect, Path, Schema } from "effect";
4
4
 
5
5
  //#region src/Provenance.ts
@@ -27,8 +27,10 @@ const encodeAt = Schema.encodeSync(Timestamp);
27
27
  * The tier-2 fallback returns `[]` the moment a `NotARepositoryError`
28
28
  * surfaces: a bundle outside git has nothing to derive for any concept still
29
29
  * on tier 2, so the first occurrence short-circuits the whole walk, not just
30
- * the concept that triggered it (S-8). Emits no `range` (S-12, Judge note
31
- * 7): `Diagnostic.range` is `Schema.optionalKey` and is simply omitted.
30
+ * the concept that triggered it (S-8). Ranges at the `generated.at` value
31
+ * (phase 4 decision 2) via `DiagnosticRange.forFrontmatterPath`; omitted
32
+ * (`Diagnostic.range` is `Schema.optionalKey`) when the concept's document has
33
+ * no frontmatter block at all.
32
34
  *
33
35
  * `Provenance.lint` is total over severity (S-28, amending Judge note 3):
34
36
  * when `OkfitConfig.severityFor(config, "generated-at-drift")` resolves to
@@ -58,18 +60,23 @@ var Provenance = class {
58
60
  const skipGitTier = options?.skipGitTier === true;
59
61
  const path = yield* Path.Path;
60
62
  const diagnostics = [];
63
+ /** Pushes a `generated-at-drift` diagnostic, ranged at `generated.at`'s own value when found. */
64
+ const pushDrift = (file, message, range) => {
65
+ diagnostics.push(Diagnostic.make({
66
+ file,
67
+ code: "generated-at-drift",
68
+ severity,
69
+ message,
70
+ ...range === void 0 ? {} : { range }
71
+ }));
72
+ };
61
73
  for (const [, concept] of bundle.concepts) {
62
74
  if (concept.frontmatter.generated === void 0) continue;
63
75
  const recordedDigest = concept.frontmatter.generated.body_sha256;
64
76
  if (recordedDigest !== void 0) {
65
77
  const currentDigest = yield* Derivation.bodyDigest(concept.document.source);
66
78
  if (currentDigest === recordedDigest) continue;
67
- diagnostics.push(Diagnostic.make({
68
- file: concept.path,
69
- code: "generated-at-drift",
70
- severity,
71
- message: `the body has changed since generated.at was last stamped: generated.body_sha256 is ${recordedDigest}, the current body hashes to ${currentDigest}`
72
- }));
79
+ pushDrift(concept.path, `the body has changed since generated.at was last stamped: generated.body_sha256 is ${recordedDigest}, the current body hashes to ${currentDigest}`, DiagnosticRange.forFrontmatterPath(concept.document, ["generated", "at"]));
73
80
  continue;
74
81
  }
75
82
  if (skipGitTier) continue;
@@ -79,12 +86,7 @@ var Provenance = class {
79
86
  if (derived._tag === "uncommitted") continue;
80
87
  const recorded = concept.frontmatter.generated.at;
81
88
  if (recorded !== void 0 && DateTime.Equivalence(recorded, derived.at)) continue;
82
- diagnostics.push(Diagnostic.make({
83
- file: concept.path,
84
- code: "generated-at-drift",
85
- severity,
86
- message: `generated.at is ${recorded === void 0 ? "missing" : encodeAt(recorded)}; the last body change was ${encodeAt(derived.at)} (${derived.sha.slice(0, 7)})`
87
- }));
89
+ pushDrift(concept.path, `generated.at is ${recorded === void 0 ? "missing" : encodeAt(recorded)}; the last body change was ${encodeAt(derived.at)} (${derived.sha.slice(0, 7)})`, DiagnosticRange.forFrontmatterPath(concept.document, ["generated", "at"]));
88
90
  }
89
91
  return diagnostics;
90
92
  });
@@ -1,3 +1,5 @@
1
+ import { DiagnosticRange } from "@okfit/core";
2
+
1
3
  //#region src/SoftwareProject.ts
2
4
  /**
3
5
  * Hand-authored, typed `OkfitConfig` (P-25). Sets ONLY `concepts`, `types`,
@@ -258,11 +260,12 @@ const layout = {
258
260
  ]
259
261
  };
260
262
  const PROJECT_TYPE = "Project";
261
- const diagnostic = (file, code, message) => ({
263
+ const diagnostic = (file, code, message, range) => ({
262
264
  file,
263
265
  code,
264
266
  severity: "error",
265
- message
267
+ message,
268
+ ...range === void 0 ? {} : { range }
266
269
  });
267
270
  /** Plain code-unit order on `file` then `code` (decision 6); never locale-dependent. */
268
271
  const compare = (a, b) => {
@@ -277,7 +280,10 @@ const compare = (a, b) => {
277
280
  * (`CORE/Bundle.ts:98`; `Concept.type` `CORE/Concept.ts:27`). The rules are
278
281
  * independent: two Projects with one nested yield three diagnostics. The file
279
282
  * name `project.md` is layout guidance, not checked. Severity is always
280
- * `error`; no `range`. Output is sorted by `file` then `code`.
283
+ * `error`. `project-multiple` and `project-not-at-root` range at the
284
+ * misplaced concept's `type` value (phase 4 decision 2, via
285
+ * `DiagnosticRange.forFrontmatterPath`); `project-missing` is bundle-level
286
+ * (`file: ""`) and stays range-less. Output is sorted by `file` then `code`.
281
287
  */
282
288
  const check = (bundle) => {
283
289
  const projects = [...bundle.concepts.values()].filter((concept) => concept.frontmatter.type === PROJECT_TYPE);
@@ -285,9 +291,9 @@ const check = (bundle) => {
285
291
  if (projects.length === 0) out.push(diagnostic("", "project-missing", `No Project concept in the bundle; software-project expects exactly one at the bundle root (${layout.root.project})`));
286
292
  if (projects.length > 1) for (const project of projects) {
287
293
  const others = projects.filter((other) => other !== project).map((other) => other.path).sort();
288
- out.push(diagnostic(project.path, "project-multiple", `Project concept "${project.path}" is one of ${projects.length}; software-project expects exactly one (others: ${others.join(", ")})`));
294
+ out.push(diagnostic(project.path, "project-multiple", `Project concept "${project.path}" is one of ${projects.length}; software-project expects exactly one (others: ${others.join(", ")})`, DiagnosticRange.forFrontmatterPath(project.document, ["type"])));
289
295
  }
290
- for (const project of projects) if (project.path.includes("/")) out.push(diagnostic(project.path, "project-not-at-root", `Project concept "${project.path}" is below the bundle root; software-project expects it beside ${layout.root.index}`));
296
+ for (const project of projects) if (project.path.includes("/")) out.push(diagnostic(project.path, "project-not-at-root", `Project concept "${project.path}" is below the bundle root; software-project expects it beside ${layout.root.index}`, DiagnosticRange.forFrontmatterPath(project.document, ["type"])));
291
297
  return out.sort(compare);
292
298
  };
293
299
  /**
package/index.d.ts CHANGED
@@ -410,8 +410,10 @@ export declare class Profiles {
410
410
  * The tier-2 fallback returns `[]` the moment a `NotARepositoryError`
411
411
  * surfaces: a bundle outside git has nothing to derive for any concept still
412
412
  * on tier 2, so the first occurrence short-circuits the whole walk, not just
413
- * the concept that triggered it (S-8). Emits no `range` (S-12, Judge note
414
- * 7): `Diagnostic.range` is `Schema.optionalKey` and is simply omitted.
413
+ * the concept that triggered it (S-8). Ranges at the `generated.at` value
414
+ * (phase 4 decision 2) via `DiagnosticRange.forFrontmatterPath`; omitted
415
+ * (`Diagnostic.range` is `Schema.optionalKey`) when the concept's document has
416
+ * no frontmatter block at all.
415
417
  *
416
418
  * `Provenance.lint` is total over severity (S-28, amending Judge note 3):
417
419
  * when `OkfitConfig.severityFor(config, "generated-at-drift")` resolves to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okfit/profiles",
3
- "version": "0.7.4",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "Named OKF configuration profiles for okfit, starting with the software-project profile.",
6
6
  "keywords": [
@@ -35,10 +35,10 @@
35
35
  "./package.json": "./package.json"
36
36
  },
37
37
  "peerDependencies": {
38
- "@effected/git": "^0.16.0",
39
- "@effected/markdown": "^0.11.0",
40
- "@okfit/core": "^0.7.2",
41
- "effect": "4.0.0-rc.116"
38
+ "@effected/git": "^0.17.0",
39
+ "@effected/markdown": "^0.12.0",
40
+ "@okfit/core": "^0.8.0",
41
+ "effect": "4.0.0-rc.117"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=24.11.0"