@cratis/pi 7.70.0 → 7.71.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.
@@ -79,16 +79,23 @@ function originRepository(cwd) {
79
79
  return repositoryName(git(['remote', 'get-url', 'origin'], cwd));
80
80
  }
81
81
 
82
- function targetCallers(repository, cwd) {
82
+ function targetCallers(repository, cwd, warn) {
83
83
  if (cwd && repository?.toLowerCase() === originRepository(cwd)?.toLowerCase()) return callers(cwd);
84
- let files;
85
- try { files = JSON.parse(gh(['api', `repos/${repository}/contents/.github/workflows`])); }
86
- catch (error) {
87
- if (/HTTP 404/.test(error.message)) return [];
84
+ let listed = false;
85
+ try {
86
+ const files = JSON.parse(gh(['api', `repos/${repository}/contents/.github/workflows`]));
87
+ listed = true;
88
+ return files.filter(file => file.type === 'file' && /\.ya?ml$/.test(file.name)).flatMap(file =>
89
+ workflowCallers(gh(['api', '-H', 'Accept: application/vnd.github.raw', `repos/${repository}/contents/${file.path}`])));
90
+ } catch (error) {
91
+ // Only a missing workflows directory means no opt-in; a failed file fetch is an unknown.
92
+ if (!listed && /HTTP 404/.test(error.message)) return [];
93
+ if (/^Cratis\/[^/]+$/i.test(repository)) {
94
+ warn(`Could not determine release-workflow opt-in for ${repository} (${error.message}); checking against bundled reviewed rules`);
95
+ return [{ name: 'verify-release-notes', ref: reviewedRulesRef }];
96
+ }
88
97
  throw new Error(`Could not determine release-workflow opt-in for ${repository}: ${error.message}`);
89
98
  }
90
- return files.filter(file => file.type === 'file' && /\.ya?ml$/.test(file.name)).flatMap(file =>
91
- workflowCallers(gh(['api', '-H', 'Accept: application/vnd.github.raw', `repos/${repository}/contents/${file.path}`])));
92
99
  }
93
100
 
94
101
  function optedIn(cwd) {
@@ -126,7 +133,7 @@ function rules(warn, repositoryCallers) {
126
133
  renameSync(temporary, file);
127
134
  return file;
128
135
  } catch (error) {
129
- if (floating) {
136
+ if (floating || ref === reviewedRulesRef) {
130
137
  const bundled = fileURLToPath(new URL('./cratis-release-notes-reviewed.cjs', import.meta.url));
131
138
  new Script(readFileSync(bundled, 'utf8'));
132
139
  warn(`Could not fetch release-note rules at ${ref}; using bundled reviewed ${reviewedRulesRef}. ${error.message}`);
@@ -193,7 +200,7 @@ function check(argv, repositoryCallers, lookupOptions) {
193
200
  // The release-intent check above still applies to bot-authored pull requests.
194
201
  if (author === 'dependabot[bot]') return 0;
195
202
  const base = values.base || pull?.baseRefName || defaultBranch;
196
- const file = rules(warn, repositoryCallers || targetCallers(repository, process.cwd()));
203
+ const file = rules(warn, repositoryCallers || targetCallers(repository, process.cwd(), warn));
197
204
  if (!file) return 3;
198
205
  const env = { PATH: process.env.PATH, HOME: homedir(), LANG: 'C.UTF-8',
199
206
  PR_BODY: body, PR_LABELS: JSON.stringify([...labels]),
@@ -369,7 +376,7 @@ function hook() {
369
376
  throw new Error('Use a literal directory before gh pr create/edit.');
370
377
  }
371
378
  if (!/^Cratis\/[^/]+$/i.test(repository)) continue;
372
- const repositoryCallers = targetCallers(repository, knownDirectory ? cwd : undefined);
379
+ const repositoryCallers = targetCallers(repository, knownDirectory ? cwd : undefined, message => warning(`Warning: ${message}`));
373
380
  if (!repositoryCallers.length) continue;
374
381
  if (!knownDirectory) throw new Error('Use a literal directory before gh pr create/edit.');
375
382
  const args = [];
@@ -98,6 +98,23 @@ Execution orders authorization → property rules → required reads → derive/
98
98
  message `<ReadModel> '<key>' does not exist.` before evaluating requirements or
99
99
  mappings. Property-rule rejection therefore wins over absence.
100
100
 
101
+ A read key the event store refuses is the same outcome as missing state. Refused
102
+ shapes: empty, whitespace-only, exactly `*`, containing `#` anywhere, or with
103
+ leading or trailing whitespace. A composite key is refused when any part is. The
104
+ check runs before the world is consulted, so such a key rejects with
105
+ `<ReadModel> '<key>' does not exist.` even when an instance is stored at that key.
106
+ Only protected reads change: a command identifier or any other use of the same
107
+ value keeps its meaning. Model read keys as concepts with rules, or as generated
108
+ identifiers, so refused shapes cannot reach a protected read; a specification that
109
+ uses such a key expects the missing-state rejection.
110
+
111
+ Requires Screenplay 4.209.0 (`screenplay --version`) for this outcome in
112
+ `screenplay test`; older compilers answer missing state or, when an instance is
113
+ stored at the key, accept the read. A rendered Arc application or Stage host that
114
+ does not map the store's refusal answers an error response for such a key (a
115
+ server error, or a dependency failure for an empty key) instead of the rejection,
116
+ which is one more reason to keep refused shapes out of read keys.
117
+
101
118
  Decide records the unfiltered fact-log boundary, read key and handled event types.
102
119
  A matching fact after that boundary makes commit return Conflict /
103
120
  DecisionStateChanged with no command facts, including publications. Irrelevant
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/pi",
3
- "version": "7.70.0",
3
+ "version": "7.71.0",
4
4
  "description": "Configuration-aware Cratis AI integration for Pi",
5
5
  "type": "module",
6
6
  "files": [