@clossys/architect 0.1.8 → 0.1.9

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/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this package are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.9] - 2026-09-18
9
+
10
+ ### Added
11
+
12
+ - Documented installation against the public npm registry
13
+ (`https://registry.npmjs.org`) and that installing needs no authentication.
14
+ - Stated the charter close condition in the README: independent consumer
15
+ evidence of `architecture exception rate`, computed by
16
+ `assessArchitectureExceptions()`. No observed material changes is
17
+ indeterminate, never a zero rate. This package does not measure consumer
18
+ evidence and does not close the loop.
19
+ - Declared `foundry.assessment` against the mapped `architect-check` bin with
20
+ `invocation: "single-json-input"`, so first-day onboarding discovers this
21
+ role's assessment surface from the installed manifest instead of inferring
22
+ one. Advisor remains the only required first-day role.
23
+ - `architect-check assessment.json`: one JSON object with `topology`,
24
+ `observations`, and `maximumExceptionRate`. Prints the architecture
25
+ exception rate report and exits on the `0` / `1` / `2` ternary. The
26
+ existing `topology` and `exceptions` subcommands remain.
27
+
28
+ ### Notes
29
+
30
+ - This does not claim the position is closed. Qualification of `0.1.9` is
31
+ deferred under #833.
32
+
8
33
  ## [0.1.8] - 2026-09-16
9
34
 
10
35
  ### Note
package/README.md CHANGED
@@ -14,6 +14,39 @@ It performs no network I/O and has no runtime dependencies. Install it with:
14
14
  npm install @clossys/architect
15
15
  ```
16
16
 
17
+ This package is published to the public npm registry, `https://registry.npmjs.org`.
18
+ Installing it needs no authentication: no npm token, no `.npmrc` registry
19
+ override, and no GitHub credential of any kind.
20
+
21
+ ## Close condition
22
+
23
+ Independent consumer evidence shows the position's owned metric meets its
24
+ setpoint over the declared review cadence. The owned metric is `architecture
25
+ exception rate`, computed by `assessArchitectureExceptions()`. No observed
26
+ material changes means the rate is `indeterminate`, never zero. This package
27
+ does not measure consumer evidence and does not close the loop; a consumer
28
+ binds the condition against their own declared topology and independent
29
+ observations. A green run of this package's tests is not a close.
30
+
31
+ ```bash
32
+ architect-check assessment.json
33
+ ```
34
+
35
+ The command prints JSON and exits `0` for satisfied, `1` for violated, and
36
+ `2` for indeterminate, unreadable, or invalid input. The assessment file is
37
+ one JSON object with `topology`, `observations`, and `maximumExceptionRate`.
38
+
39
+ This package declares that command as its first-day assessment surface in
40
+ its own manifest:
41
+
42
+ ```json
43
+ "foundry": { "assessment": { "bin": "architect-check", "invocation": "single-json-input" } }
44
+ ```
45
+
46
+ Onboarding discovers that declaration from the installed manifest and never
47
+ infers a surface. Architect is not a required first-day role; Advisor
48
+ remains the only required first-day assessment.
49
+
17
50
  ## Job charter
18
51
 
19
52
  Architect operates in **optimize** mode. Its durable objective is to reduce
@@ -87,11 +120,16 @@ responsibilities implemented somewhere in the topology.
87
120
  ## CLI
88
121
 
89
122
  ```bash
123
+ architect-check assessment.json
90
124
  architect-check topology topology.json
91
125
  architect-check exceptions topology.json observations.json --maximum-exception-rate 0.05
92
126
  ```
93
127
 
94
- Both commands emit JSON. Exit codes are `0` satisfied, `1` violated, and `2`
128
+ `architect-check assessment.json` is the first-day assessment surface: one
129
+ JSON file containing `topology`, `observations`, and `maximumExceptionRate`.
130
+ The `topology` and `exceptions` subcommands remain for the two-file form.
131
+
132
+ All commands emit JSON. Exit codes are `0` satisfied, `1` violated, and `2`
95
133
  indeterminate or unable to run. Invalid topology is a violation for the
96
134
  `topology` conformance command. Invalid inputs make the exception rate
97
135
  indeterminate because no valid measurement can be computed.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAgBA,qBAAa,sBAAuB,SAAQ,KAAK;CAAG;AAwCpD,8FAA8F;AAC9F,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMpD"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAkBA,qBAAa,sBAAuB,SAAQ,KAAK;CAAG;AAqDpD,8FAA8F;AAC9F,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOpD"}
package/dist/cli.js CHANGED
@@ -4,16 +4,21 @@ import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { assessArchitectureExceptions } from "./assessment.js";
6
6
  import { validateOperatingTopology } from "./topology.js";
7
- const USAGE = `Usage: architect-check topology <topology-file>
7
+ const USAGE = `Usage: architect-check <assessment.json>
8
+ architect-check topology <topology-file>
8
9
  architect-check exceptions <topology-file> <observations-file> --maximum-exception-rate <rate>
9
10
 
10
11
  Commands:
11
- topology Validate a provider-neutral operating topology.
12
- exceptions Assess architecture exception rate from observed changes.
12
+ <assessment.json> Assess architecture exception rate from one JSON file containing topology, observations, and maximumExceptionRate.
13
+ topology Validate a provider-neutral operating topology.
14
+ exceptions Assess architecture exception rate from observed changes.
13
15
 
14
16
  Exit codes: 0 = satisfied, 1 = violated, 2 = indeterminate or could not run.`;
15
17
  export class ArchitectCliInputError extends Error {
16
18
  }
19
+ function isRecord(value) {
20
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21
+ }
17
22
  function readJson(path, label) {
18
23
  const resolved = resolve(path);
19
24
  if (!existsSync(resolved))
@@ -34,6 +39,15 @@ function readJson(path, label) {
34
39
  throw new ArchitectCliInputError(`${label} "${path}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
35
40
  }
36
41
  }
42
+ function assessmentCommand(path) {
43
+ const value = readJson(path, "assessment file");
44
+ if (!isRecord(value))
45
+ throw new ArchitectCliInputError("assessment file must be a JSON object");
46
+ const maximumExceptionRate = typeof value.maximumExceptionRate === "number" ? value.maximumExceptionRate : Number(value.maximumExceptionRate);
47
+ const report = assessArchitectureExceptions(value.topology, value.observations, { maximumExceptionRate });
48
+ console.log(JSON.stringify({ ...report, proposedPositions: [] }, null, 2));
49
+ return report.state === "satisfied" ? 0 : report.state === "violated" ? 1 : 2;
50
+ }
37
51
  function topologyCommand(argv) {
38
52
  if (argv.length !== 1)
39
53
  throw new ArchitectCliInputError("topology requires exactly one topology-file");
@@ -80,7 +94,9 @@ export function main(argv) {
80
94
  return topologyCommand(rest);
81
95
  if (command === "exceptions")
82
96
  return exceptionsCommand(rest);
83
- throw new ArchitectCliInputError(command === undefined ? "a command is required" : `unknown command "${command}"`);
97
+ if (command !== undefined && rest.length === 0)
98
+ return assessmentCommand(command);
99
+ throw new ArchitectCliInputError(command === undefined ? "a command or assessment.json file is required" : `unknown command "${command}"`);
84
100
  }
85
101
  function run() {
86
102
  try {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clossys/architect",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,6 +29,12 @@
29
29
  "LICENSE"
30
30
  ],
31
31
  "sideEffects": false,
32
+ "foundry": {
33
+ "assessment": {
34
+ "bin": "architect-check",
35
+ "invocation": "single-json-input"
36
+ }
37
+ },
32
38
  "description": "The architect role: provider-neutral operating topology, ontology, authority and interface contracts, plus evidence-based architecture exception assessment.",
33
39
  "keywords": [
34
40
  "architecture",
package/src/cli.ts CHANGED
@@ -5,17 +5,23 @@ import { fileURLToPath } from "node:url";
5
5
  import { assessArchitectureExceptions } from "./assessment.js";
6
6
  import { validateOperatingTopology } from "./topology.js";
7
7
 
8
- const USAGE = `Usage: architect-check topology <topology-file>
8
+ const USAGE = `Usage: architect-check <assessment.json>
9
+ architect-check topology <topology-file>
9
10
  architect-check exceptions <topology-file> <observations-file> --maximum-exception-rate <rate>
10
11
 
11
12
  Commands:
12
- topology Validate a provider-neutral operating topology.
13
- exceptions Assess architecture exception rate from observed changes.
13
+ <assessment.json> Assess architecture exception rate from one JSON file containing topology, observations, and maximumExceptionRate.
14
+ topology Validate a provider-neutral operating topology.
15
+ exceptions Assess architecture exception rate from observed changes.
14
16
 
15
17
  Exit codes: 0 = satisfied, 1 = violated, 2 = indeterminate or could not run.`;
16
18
 
17
19
  export class ArchitectCliInputError extends Error {}
18
20
 
21
+ function isRecord(value: unknown): value is Record<string, unknown> {
22
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23
+ }
24
+
19
25
  function readJson(path: string, label: string): unknown {
20
26
  const resolved = resolve(path);
21
27
  if (!existsSync(resolved)) throw new ArchitectCliInputError(`${label} "${path}" does not exist`);
@@ -25,6 +31,15 @@ function readJson(path: string, label: string): unknown {
25
31
  catch (error) { throw new ArchitectCliInputError(`${label} "${path}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`); }
26
32
  }
27
33
 
34
+ function assessmentCommand(path: string): number {
35
+ const value = readJson(path, "assessment file");
36
+ if (!isRecord(value)) throw new ArchitectCliInputError("assessment file must be a JSON object");
37
+ const maximumExceptionRate = typeof value.maximumExceptionRate === "number" ? value.maximumExceptionRate : Number(value.maximumExceptionRate);
38
+ const report = assessArchitectureExceptions(value.topology, value.observations, { maximumExceptionRate });
39
+ console.log(JSON.stringify({ ...report, proposedPositions: [] }, null, 2));
40
+ return report.state === "satisfied" ? 0 : report.state === "violated" ? 1 : 2;
41
+ }
42
+
28
43
  function topologyCommand(argv: readonly string[]): number {
29
44
  if (argv.length !== 1) throw new ArchitectCliInputError("topology requires exactly one topology-file");
30
45
  const findings = validateOperatingTopology(readJson(argv[0] as string, "topology-file"));
@@ -60,7 +75,8 @@ export function main(argv: readonly string[]): number {
60
75
  const [command, ...rest] = argv;
61
76
  if (command === "topology") return topologyCommand(rest);
62
77
  if (command === "exceptions") return exceptionsCommand(rest);
63
- throw new ArchitectCliInputError(command === undefined ? "a command is required" : `unknown command "${command}"`);
78
+ if (command !== undefined && rest.length === 0) return assessmentCommand(command);
79
+ throw new ArchitectCliInputError(command === undefined ? "a command or assessment.json file is required" : `unknown command "${command}"`);
64
80
  }
65
81
 
66
82
  function run(): void {