truecourse 0.6.0-next.12 → 0.6.0-next.13

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.
Files changed (3) hide show
  1. package/cli.mjs +67 -13
  2. package/package.json +1 -1
  3. package/server.mjs +46 -8
package/cli.mjs CHANGED
@@ -129397,7 +129397,7 @@ function readToolVersion() {
129397
129397
  if (cachedVersion)
129398
129398
  return cachedVersion;
129399
129399
  if (true) {
129400
- cachedVersion = "0.6.0-next.12";
129400
+ cachedVersion = "0.6.0";
129401
129401
  return cachedVersion;
129402
129402
  }
129403
129403
  try {
@@ -143905,14 +143905,20 @@ Use sensible defaults when the spec doesn't spell them out:
143905
143905
  on-violation {
143906
143906
  status 401
143907
143907
  error-code unauthenticated
143908
- body ErrorEnvelope:error.envelope.standard
143909
143908
  }
143910
143909
  }
143911
143910
 
143912
- Default \`on-violation\` is **always** status 401, error-code \`unauthenticated\`,
143913
- body \`ErrorEnvelope:error.envelope.standard\` when the spec doesn't specify
143914
- otherwise. Default selector is \`path-glob "/api/**"\` when the spec says "all
143915
- /api/* endpoints" without naming a more specific pattern.
143911
+ Default \`on-violation\` is status 401, error-code \`unauthenticated\`. Add a
143912
+ \`body ErrorEnvelope:error.envelope.standard\` line ONLY when the spec/corpus
143913
+ actually establishes a standard error envelope \u2014 a dedicated errors /
143914
+ error-response section, an error-code catalog, or another slice that describes
143915
+ the error body shape. When the spec is SILENT about the error response body
143916
+ (common for terse auth docs that only state the scheme), OMIT the \`body\` line:
143917
+ a \`body\` reference to an envelope nothing defines is a dangling cross-reference
143918
+ that fails the validation gate, while an omitted body is faithful. See
143919
+ "Error-envelope references must be grounded" below. Default selector is
143920
+ \`path-glob "/api/**"\` when the spec says "all /api/* endpoints" without naming a
143921
+ more specific pattern.
143916
143922
 
143917
143923
  When a spec describes role-based auth ("admin only", "moderators can \u2026"), produce
143918
143924
  a SEPARATE \`auth-requirement\` with \`required-role <role>\`, identity
@@ -143947,7 +143953,8 @@ is the correct fallback when the slice lacks operation context.
143947
143953
  on-violation {
143948
143954
  status 403
143949
143955
  error-code forbidden
143950
- body ErrorEnvelope:error.envelope.standard
143956
+ // body ErrorEnvelope:error.envelope.standard only when that envelope is
143957
+ // defined in the corpus \u2014 see "Error-envelope references must be grounded".
143951
143958
  }
143952
143959
  }
143953
143960
 
@@ -144494,6 +144501,37 @@ response as a literal:
144494
144501
  - Only declare a literal \`response 401/403 on \u2026\` when the spec describes the
144495
144502
  response as standalone, NOT delegated to a rule.
144496
144503
 
144504
+ # Error-envelope references must be grounded
144505
+
144506
+ \`ErrorEnvelope:error.envelope.standard\` is a CROSS-REFERENCE, not a literal \u2014 it
144507
+ only resolves if a matching \`error-envelope error.envelope.standard { \u2026 }\`
144508
+ artifact exists somewhere in the corpus. Emitting the reference with nothing
144509
+ defining it produces a dangling cross-reference that fails the validation gate,
144510
+ exactly like referencing an undefined \`Enum:\`. This is the same prime-directive
144511
+ rule as enums ("never reference an enum without defining it"), applied to error
144512
+ bodies.
144513
+
144514
+ The rule applies EVERYWHERE an envelope can appear:
144515
+ \`on-violation { \u2026 body ErrorEnvelope:\u2026 }\` on auth-requirements and
144516
+ authorization-rules, and \`response \u2026 { body envelope ErrorEnvelope:\u2026 { \u2026 } }\`
144517
+ on operations.
144518
+
144519
+ - Reference \`ErrorEnvelope:error.envelope.standard\` ONLY when the spec actually
144520
+ establishes a standard error envelope: a dedicated errors / error-response
144521
+ section, an error-code catalog, or prose that names "the standard error
144522
+ envelope". In a multi-doc corpus the defining section may live in ANOTHER
144523
+ slice \u2014 that's fine, just like an \`Enum:\` defined in a sibling slice.
144524
+ - When you reference it AND the slice in front of you is the one that describes
144525
+ the envelope, ALSO emit the \`error-envelope error.envelope.standard { \u2026 }\`
144526
+ artifact \u2014 mirroring the described shape; never invent fields the spec does
144527
+ not list.
144528
+ - When the spec is SILENT about the error response body \u2014 no error section, no
144529
+ envelope, no error codes \u2014 do NOT emit the reference at all. Omit the \`body\`
144530
+ line from \`on-violation\`; on an operation response use a plain \`body \u2026\` only
144531
+ if the spec gives a shape, otherwise omit it. Faithful under-specification
144532
+ beats a dangling reference: never conjure a standard envelope just to fill the
144533
+ slot.
144534
+
144497
144535
  # Naming conventions for artifact identities
144498
144536
 
144499
144537
  Use these canonical identity formats:
@@ -148874,7 +148912,7 @@ function rulesFor(a) {
148874
148912
  }
148875
148913
  if (a.kind === "auth-requirement") {
148876
148914
  if (!/\bon-violation\s*\{/.test(src)) {
148877
- out.push("missing `on-violation { status ... error-code ... body ErrorEnvelope:... }`.");
148915
+ out.push("missing `on-violation { status ... error-code ... }` (add `body ErrorEnvelope:error.envelope.standard` only when that envelope is defined in the corpus).");
148878
148916
  }
148879
148917
  if (/\brequired-role\b/.test(src)) {
148880
148918
  const hasBroadGlob = /selector\s+path-glob\s+"\/api\/(\*\*|\*)"/.test(src);
@@ -150497,11 +150535,27 @@ async function runContractsGenerate(options = {}) {
150497
150535
  if (f2.run?.error) console.log(` \u2192 ${f2.run.error}`);
150498
150536
  }
150499
150537
  }
150500
- if (result.validationIssues.length > 0) {
150501
- O2.error(`Validation gate failed (${result.validationIssues.length} issue${result.validationIssues.length === 1 ? "" : "s"}):`);
150502
- for (const issue of result.validationIssues) {
150503
- console.log(` ${issue.artifactKey}: ${issue.message}`);
150538
+ const hardIssues = result.validationIssues.filter((i) => i.severity === "hard");
150539
+ const softIssues = result.validationIssues.filter((i) => i.severity === "soft");
150540
+ if (softIssues.length > 0) {
150541
+ const counts = /* @__PURE__ */ new Map();
150542
+ for (const issue of softIssues) {
150543
+ const line = `${issue.artifactKey}: ${issue.message}`;
150544
+ counts.set(line, (counts.get(line) ?? 0) + 1);
150504
150545
  }
150546
+ O2.warn(
150547
+ `${counts.size} unresolved cross-reference${counts.size === 1 ? "" : "s"} (non-blocking \u2014 the referenced artifact wasn't generated; \`truecourse verify\` will flag any real drift):`
150548
+ );
150549
+ for (const [line, n] of counts) console.log(` ${line}${n > 1 ? ` (\xD7${n})` : ""}`);
150550
+ }
150551
+ if (hardIssues.length > 0) {
150552
+ O2.error(
150553
+ `${hardIssues.length} artifact${hardIssues.length === 1 ? " was" : "s were"} dropped (invalid \`.tc\` \u2014 parse error or duplicate identity):`
150554
+ );
150555
+ for (const issue of hardIssues) console.log(` ${issue.artifactKey}: ${issue.message}`);
150556
+ }
150557
+ const produced = options.diff ? result.write.proposed.length : result.write.written.length;
150558
+ if (produced === 0 && result.validationIssues.length > 0) {
150505
150559
  gt("No contracts were written. Edit the spec or re-run after fixing.");
150506
150560
  process.exit(1);
150507
150561
  }
@@ -154293,7 +154347,7 @@ async function runHooksRun() {
154293
154347
 
154294
154348
  // tools/cli/src/index.ts
154295
154349
  var program2 = new Command();
154296
- program2.name("truecourse").version("0.6.0-next.12").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
154350
+ program2.name("truecourse").version("0.6.0").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
154297
154351
  var dashboardCmd = program2.command("dashboard").description("Start the TrueCourse dashboard and open it in your browser").option("--reconfigure", "Re-prompt for console vs background service mode").option("--service", "Run as a background service (skips mode prompt)").option("--console", "Run in this terminal (skips mode prompt)").action(async (options) => {
154298
154352
  if (options.service && options.console) {
154299
154353
  console.error("error: --service and --console are mutually exclusive");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "truecourse",
3
- "version": "0.6.0-next.12",
3
+ "version": "0.6.0-next.13",
4
4
  "description": "Visualize your codebase architecture as an interactive graph",
5
5
  "type": "module",
6
6
  "bin": {
package/server.mjs CHANGED
@@ -158105,7 +158105,7 @@ function readToolVersion() {
158105
158105
  if (cachedVersion)
158106
158106
  return cachedVersion;
158107
158107
  if (true) {
158108
- cachedVersion = "0.6.0-next.12";
158108
+ cachedVersion = "0.6.0";
158109
158109
  return cachedVersion;
158110
158110
  }
158111
158111
  try {
@@ -164240,14 +164240,20 @@ Use sensible defaults when the spec doesn't spell them out:
164240
164240
  on-violation {
164241
164241
  status 401
164242
164242
  error-code unauthenticated
164243
- body ErrorEnvelope:error.envelope.standard
164244
164243
  }
164245
164244
  }
164246
164245
 
164247
- Default \`on-violation\` is **always** status 401, error-code \`unauthenticated\`,
164248
- body \`ErrorEnvelope:error.envelope.standard\` when the spec doesn't specify
164249
- otherwise. Default selector is \`path-glob "/api/**"\` when the spec says "all
164250
- /api/* endpoints" without naming a more specific pattern.
164246
+ Default \`on-violation\` is status 401, error-code \`unauthenticated\`. Add a
164247
+ \`body ErrorEnvelope:error.envelope.standard\` line ONLY when the spec/corpus
164248
+ actually establishes a standard error envelope \u2014 a dedicated errors /
164249
+ error-response section, an error-code catalog, or another slice that describes
164250
+ the error body shape. When the spec is SILENT about the error response body
164251
+ (common for terse auth docs that only state the scheme), OMIT the \`body\` line:
164252
+ a \`body\` reference to an envelope nothing defines is a dangling cross-reference
164253
+ that fails the validation gate, while an omitted body is faithful. See
164254
+ "Error-envelope references must be grounded" below. Default selector is
164255
+ \`path-glob "/api/**"\` when the spec says "all /api/* endpoints" without naming a
164256
+ more specific pattern.
164251
164257
 
164252
164258
  When a spec describes role-based auth ("admin only", "moderators can \u2026"), produce
164253
164259
  a SEPARATE \`auth-requirement\` with \`required-role <role>\`, identity
@@ -164282,7 +164288,8 @@ is the correct fallback when the slice lacks operation context.
164282
164288
  on-violation {
164283
164289
  status 403
164284
164290
  error-code forbidden
164285
- body ErrorEnvelope:error.envelope.standard
164291
+ // body ErrorEnvelope:error.envelope.standard only when that envelope is
164292
+ // defined in the corpus \u2014 see "Error-envelope references must be grounded".
164286
164293
  }
164287
164294
  }
164288
164295
 
@@ -164829,6 +164836,37 @@ response as a literal:
164829
164836
  - Only declare a literal \`response 401/403 on \u2026\` when the spec describes the
164830
164837
  response as standalone, NOT delegated to a rule.
164831
164838
 
164839
+ # Error-envelope references must be grounded
164840
+
164841
+ \`ErrorEnvelope:error.envelope.standard\` is a CROSS-REFERENCE, not a literal \u2014 it
164842
+ only resolves if a matching \`error-envelope error.envelope.standard { \u2026 }\`
164843
+ artifact exists somewhere in the corpus. Emitting the reference with nothing
164844
+ defining it produces a dangling cross-reference that fails the validation gate,
164845
+ exactly like referencing an undefined \`Enum:\`. This is the same prime-directive
164846
+ rule as enums ("never reference an enum without defining it"), applied to error
164847
+ bodies.
164848
+
164849
+ The rule applies EVERYWHERE an envelope can appear:
164850
+ \`on-violation { \u2026 body ErrorEnvelope:\u2026 }\` on auth-requirements and
164851
+ authorization-rules, and \`response \u2026 { body envelope ErrorEnvelope:\u2026 { \u2026 } }\`
164852
+ on operations.
164853
+
164854
+ - Reference \`ErrorEnvelope:error.envelope.standard\` ONLY when the spec actually
164855
+ establishes a standard error envelope: a dedicated errors / error-response
164856
+ section, an error-code catalog, or prose that names "the standard error
164857
+ envelope". In a multi-doc corpus the defining section may live in ANOTHER
164858
+ slice \u2014 that's fine, just like an \`Enum:\` defined in a sibling slice.
164859
+ - When you reference it AND the slice in front of you is the one that describes
164860
+ the envelope, ALSO emit the \`error-envelope error.envelope.standard { \u2026 }\`
164861
+ artifact \u2014 mirroring the described shape; never invent fields the spec does
164862
+ not list.
164863
+ - When the spec is SILENT about the error response body \u2014 no error section, no
164864
+ envelope, no error codes \u2014 do NOT emit the reference at all. Omit the \`body\`
164865
+ line from \`on-violation\`; on an operation response use a plain \`body \u2026\` only
164866
+ if the spec gives a shape, otherwise omit it. Faithful under-specification
164867
+ beats a dangling reference: never conjure a standard envelope just to fill the
164868
+ slot.
164869
+
164832
164870
  # Naming conventions for artifact identities
164833
164871
 
164834
164872
  Use these canonical identity formats:
@@ -165581,7 +165619,7 @@ function rulesFor(a) {
165581
165619
  }
165582
165620
  if (a.kind === "auth-requirement") {
165583
165621
  if (!/\bon-violation\s*\{/.test(src)) {
165584
- out.push("missing `on-violation { status ... error-code ... body ErrorEnvelope:... }`.");
165622
+ out.push("missing `on-violation { status ... error-code ... }` (add `body ErrorEnvelope:error.envelope.standard` only when that envelope is defined in the corpus).");
165585
165623
  }
165586
165624
  if (/\brequired-role\b/.test(src)) {
165587
165625
  const hasBroadGlob = /selector\s+path-glob\s+"\/api\/(\*\*|\*)"/.test(src);