@cratis/pi 2.21.3 → 2.23.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/package/corpus/agents/backend-developer.md +6 -5
- package/package/corpus/agents/code-reviewer.md +7 -7
- package/package/corpus/agents/coordinator.md +5 -4
- package/package/corpus/agents/frontend-developer.md +34 -40
- package/package/corpus/agents/orchestrator.md +5 -4
- package/package/corpus/agents/performance-reviewer.md +5 -4
- package/package/corpus/agents/planner.md +5 -4
- package/package/corpus/agents/repository-investigation-reviewer.md +2 -1
- package/package/corpus/agents/repository-investigator.md +2 -1
- package/package/corpus/agents/security-reviewer.md +5 -4
- package/package/corpus/agents/slice-implementer.md +8 -2
- package/package/corpus/agents/spec-writer.md +6 -4
- package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +52 -7
- package/package/corpus/harnesses/pi/extensions/subagent/index.ts +14 -0
- package/package/corpus/hooks/README.md +29 -27
- package/package/corpus/hooks/agent-stop.md +1 -5
- package/package/corpus/hooks/scripts/cratis-patterns.json +1 -1
- package/package/corpus/hooks/scripts/validate-package-subpaths.sh +1 -2
- package/package/corpus/prompts/verify-ai-setup.prompt.md +17 -7
- package/package/corpus/rules/ai-distribution.md +58 -0
- package/package/corpus/rules/components.md +77 -44
- package/package/corpus/rules/dialogs.md +24 -20
- package/package/corpus/rules/efcore.md +35 -187
- package/package/corpus/rules/framework.md +1 -1
- package/package/corpus/rules/frontend-quality.md +1 -1
- package/package/corpus/rules/frontend-testing.md +4 -4
- package/package/corpus/rules/general.md +29 -105
- package/package/corpus/rules/new-repository-intake.md +34 -0
- package/package/corpus/rules/orleans.md +13 -27
- package/package/corpus/rules/react.md +12 -12
- package/package/corpus/rules/reactors.md +28 -5
- package/package/corpus/rules/specs.scenarios.csharp.md +18 -3
- package/package/corpus/rules/specs.typescript.md +1 -1
- package/package/corpus/rules/storybook.md +2 -2
- package/package/corpus/rules/typescript.md +1 -0
- package/package/corpus/rules/vertical-slices.md +20 -15
- package/package/corpus/rules/writing-correct-examples.md +1 -0
- package/package/corpus/skills/cratis-application-react-specifications/SKILL.md +4 -4
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +16 -8
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +6 -4
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +7 -4
- package/package/corpus/skills/cratis-arc-command/SKILL.md +9 -7
- package/package/corpus/skills/cratis-arc-command/references/command-result.md +1 -1
- package/package/corpus/skills/cratis-arc-command/references/handler-shapes.md +2 -2
- package/package/corpus/skills/cratis-arc-command/references/proxy-generation.md +6 -3
- package/package/corpus/skills/cratis-arc-command/references/read-model-injection.md +1 -1
- package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +12 -2
- package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +5 -3
- package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +7 -4
- package/package/corpus/skills/cratis-arc-observable-query-http/SKILL.md +10 -3
- package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +13 -8
- package/package/corpus/skills/cratis-arc-react-page/SKILL.md +27 -24
- package/package/corpus/skills/cratis-arc-react-page/references/data-page.md +15 -11
- package/package/corpus/skills/cratis-arc-react-page/references/data-tables.md +9 -2
- package/package/corpus/skills/cratis-arc-react-page/references/dialogs.md +11 -9
- package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +26 -2
- package/package/corpus/skills/cratis-chronicle-cli-operations/SKILL.md +19 -13
- package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +17 -15
- package/package/corpus/skills/cratis-chronicle-client-elixir/SKILL.md +24 -20
- package/package/corpus/skills/cratis-chronicle-client-kotlin/SKILL.md +26 -15
- package/package/corpus/skills/cratis-chronicle-client-typescript/SKILL.md +15 -11
- package/package/corpus/skills/cratis-chronicle-compliance/SKILL.md +14 -3
- package/package/corpus/skills/cratis-chronicle-event-constraints/SKILL.md +13 -6
- package/package/corpus/skills/cratis-chronicle-event-modeling/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +11 -5
- package/package/corpus/skills/cratis-chronicle-event-type-migration/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-projection/SKILL.md +23 -4
- package/package/corpus/skills/cratis-chronicle-projection/references/fluent-builder.md +1 -1
- package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +2 -2
- package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +22 -8
- package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +3 -1
- package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +1 -1
- package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +19 -11
- package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +11 -6
- package/package/corpus/skills/cratis-code-review/SKILL.md +8 -6
- package/package/corpus/skills/cratis-components-accessibility/SKILL.md +112 -82
- package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +12 -10
- package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +11 -12
- package/package/corpus/skills/cratis-components-styling/SKILL.md +204 -170
- package/package/corpus/skills/cratis-components-toolbar/SKILL.md +32 -26
- package/package/corpus/skills/cratis-event-model-diagram/SKILL.md +1 -1
- package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +2 -2
- package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +2 -2
- package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +4 -2
- package/package/corpus/skills/cratis-performance-review/SKILL.md +4 -2
- package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +15 -5
- package/package/corpus/skills/cratis-security-review/SKILL.md +20 -3
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +3 -3
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +12 -8
- package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +1 -1
- package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +7 -3
- package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +6 -3
- package/package/corpus/skills/cratis-specifications-typescript/references/typescript-patterns.md +21 -4
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +29 -17
- package/package.json +1 -1
|
@@ -10,226 +10,74 @@ profile: application
|
|
|
10
10
|
> **⚠️ APPLIES ONLY TO PROJECTS USING ENTITY FRAMEWORK CORE**
|
|
11
11
|
> If your project does not reference `Microsoft.EntityFrameworkCore` or any EF Core packages, **ignore this entire file**. These rules are irrelevant outside of EF Core contexts.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`Cratis.Arc.EntityFrameworkCore` gives an Arc application EF Core-backed read models: two `DbContext` base types, convention-based registration, provider selection from the connection string, cross-database column helpers for migrations, concept-aware value conversion, and live observation of a `DbSet`. **That is the whole of what Arc ships** — it has no migration runner, no table-name constant convention, no design-time factory and no prescribed project split. Where an application adds one of those, it is that application's local convention, not Cratis; keep such conventions in the repository's own instructions, never present them as framework. The step-by-step workflow, the exact signatures and the traps live in the **cratis-arc-ef-core-migration** skill; this rule states the invariants.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## DbContext base types **[contract]**
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|---------|----------------|
|
|
19
|
-
| `Database` | Migrations only – no entities, no DbContexts |
|
|
20
|
-
| `Core` | Entities and feature DbContexts (co-located with features) |
|
|
21
|
-
| `Infrastructure` | DbContext registration, migration runner, cross-cutting EF setup |
|
|
17
|
+
Always derive from one of Arc's base types — never directly from `DbContext`:
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
Core → Infrastructure → Database
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## DbContext Base Types
|
|
30
|
-
|
|
31
|
-
Always use the Cratis Arc base types — never inherit directly from `DbContext`:
|
|
32
|
-
|
|
33
|
-
- **`ReadOnlyDbContext`** — for all read model / projection contexts (the vast majority)
|
|
34
|
-
- **`BaseDbContext`** — only for writable contexts that own state (e.g. device state, infrastructure state)
|
|
19
|
+
- **`ReadOnlyDbContext`** — for every read model / projection context (the vast majority). Its save-changes interceptor **throws** on any `SaveChanges`, so a projection cannot be bypassed by accident.
|
|
20
|
+
- **`BaseDbContext`** — only for a writable context that genuinely owns state (device state, infrastructure state).
|
|
35
21
|
|
|
36
22
|
```csharp
|
|
37
|
-
// ✅ Read model context
|
|
38
23
|
public class StartupPhaseDbContext(DbContextOptions<StartupPhaseDbContext> options)
|
|
39
24
|
: ReadOnlyDbContext(options)
|
|
40
25
|
{
|
|
41
26
|
public DbSet<StartupPhase> StartupPhases => Set<StartupPhase>();
|
|
42
|
-
public DbSet<PersonnelAssignment> PersonnelAssignments => Set<PersonnelAssignment>();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ✅ Writable (state-owning) context
|
|
46
|
-
public class DeviceStateDbContext(DbContextOptions<DeviceStateDbContext> options)
|
|
47
|
-
: BaseDbContext(options)
|
|
48
|
-
{
|
|
49
|
-
public DbSet<DeviceState> DeviceStates => Set<DeviceState>();
|
|
50
27
|
}
|
|
51
28
|
```
|
|
52
29
|
|
|
53
|
-
Use the primary constructor
|
|
30
|
+
Use the primary constructor; expose each `DbSet<T>` as an expression-bodied property over `Set<T>()`. Co-locate the context with the feature whose read models it holds.
|
|
54
31
|
|
|
55
|
-
## Feature
|
|
32
|
+
## Feature contexts — not god contexts **[convention]**
|
|
56
33
|
|
|
57
|
-
|
|
34
|
+
One focused `DbContext` per feature or tightly related feature group. Never aggregate unrelated entities into a single context: a context's shape is a cohesion boundary, and a god context couples every feature's schema change to every other's.
|
|
58
35
|
|
|
59
|
-
|
|
60
|
-
// ❌ God context
|
|
61
|
-
public class AppDbContext : DbContext
|
|
62
|
-
{
|
|
63
|
-
public DbSet<Mission> Missions { get; set; }
|
|
64
|
-
public DbSet<User> Users { get; set; }
|
|
65
|
-
public DbSet<Station> Stations { get; set; }
|
|
66
|
-
// ... many more
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ✅ Focused feature context
|
|
70
|
-
public class StartupPhaseDbContext(DbContextOptions<StartupPhaseDbContext> options)
|
|
71
|
-
: ReadOnlyDbContext(options)
|
|
72
|
-
{
|
|
73
|
-
public DbSet<StartupPhase> StartupPhases => Set<StartupPhase>();
|
|
74
|
-
public DbSet<PersonnelAssignment> PersonnelAssignments => Set<PersonnelAssignment>();
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Co-locate the DbContext file with its feature:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
Missions/Ongoing/StartupPhase/
|
|
82
|
-
├── StartupPhase.cs
|
|
83
|
-
├── StartupPhaseDbContext.cs
|
|
84
|
-
└── ...
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## State Mutation — The Golden Rule
|
|
36
|
+
## State mutation — the golden rule **[convention]**
|
|
88
37
|
|
|
89
38
|
> **Never mutate state directly through a DbContext.**
|
|
90
39
|
|
|
91
|
-
All state changes
|
|
92
|
-
|
|
93
|
-
```csharp
|
|
94
|
-
// ❌ Direct mutation — forbidden
|
|
95
|
-
dbContext.StartupPhases.Add(new StartupPhase(...));
|
|
96
|
-
await dbContext.SaveChangesAsync();
|
|
97
|
-
|
|
98
|
-
// ✅ Correct: emit an event, let the projection handle writes
|
|
99
|
-
[Command]
|
|
100
|
-
public record UpdateStartupPhase(MissionId MissionId, ...) { ... }
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Only infrastructure projection code, the Chronicle event engine, and reference data sync may write through DbContexts.
|
|
40
|
+
All state changes flow through events and Chronicle projections; a direct write bypasses the event log and the audit trail. Only projection infrastructure, the Chronicle engine, and deliberate reference-data synchronization write through a context — and those are `BaseDbContext`s, never `ReadOnlyDbContext`s.
|
|
104
41
|
|
|
105
|
-
## Registration
|
|
106
|
-
|
|
107
|
-
Use the Cratis Arc `Cratis.Arc.EntityFrameworkCore` extension methods:
|
|
108
|
-
|
|
109
|
-
```csharp
|
|
110
|
-
// Register a single writable DbContext
|
|
111
|
-
services.AddDbContextWithConnectionString<DeviceStateDbContext>(connectionString, optionalConfigure);
|
|
112
|
-
|
|
113
|
-
// Auto-discover and register ALL ReadOnlyDbContext subtypes from given assemblies
|
|
114
|
-
services.AddReadModelDbContextsWithConnectionStringFromAssemblies(
|
|
115
|
-
connectionString,
|
|
116
|
-
configureOptions,
|
|
117
|
-
[Assembly.GetExecutingAssembly()]);
|
|
118
|
-
```
|
|
42
|
+
## Registration **[contract]**
|
|
119
43
|
|
|
120
|
-
|
|
44
|
+
Wire EF Core through the Arc builder and give it the connection string:
|
|
121
45
|
|
|
122
46
|
```csharp
|
|
123
|
-
|
|
47
|
+
builder.AddCratisArc(arc => arc.WithEntityFrameworkCore(
|
|
48
|
+
options => options.ConnectionString = connectionString));
|
|
124
49
|
```
|
|
125
50
|
|
|
126
|
-
|
|
51
|
+
With a non-empty connection string and `AutoDiscoverDbContexts` (the default), Arc discovers every public `BaseDbContext` subtype not marked `[IgnoreAutoRegistration]`, registering `ReadOnlyDbContext` subtypes read-only and the rest read-write. ⚠️ `WithEntityFrameworkCore()` with **no** connection string discovers nothing. Explicit registration remains available (`AddDbContextWithConnectionString<T>`, `AddReadOnlyDbContextWithConnectionString<T>`, `AddReadModelDbContextsFromAssemblies`, `AddReadModelDbContextsWithConnectionStringFromAssemblies`).
|
|
127
52
|
|
|
128
|
-
|
|
53
|
+
Select the provider with **`UseDatabaseFromConnectionString(connectionString)`** — never hard-code `UseSqlite` / `UseNpgsql` / `UseSqlServer`. It infers `DatabaseType` (`Sqlite`, `SqlServer`, `PostgreSql`) from the connection string, ensures a SQLite file's directory exists, and installs Arc's migrations SQL generator for that provider (which is what adds the JSON validation constraint for `[Json]` columns). An unsupported connection string throws `UnsupportedDatabaseType`.
|
|
129
54
|
|
|
130
|
-
|
|
55
|
+
## Migrations **[contract]/[convention]**
|
|
131
56
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
## Migrations
|
|
135
|
-
|
|
136
|
-
Migrations live exclusively in the **`Database`** project, never in `Core` or `Infrastructure`.
|
|
137
|
-
|
|
138
|
-
### Organization
|
|
139
|
-
|
|
140
|
-
Each entity category has its own folder with versioned migration files:
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
Database/
|
|
144
|
-
├── Missions/
|
|
145
|
-
│ ├── v1_0_0.cs
|
|
146
|
-
│ └── v1_1_0.cs
|
|
147
|
-
├── Users/
|
|
148
|
-
│ └── v1_0_0.cs
|
|
149
|
-
└── WellKnownTables.cs
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Naming
|
|
153
|
-
|
|
154
|
-
Version files using the pattern `v{major}_{minor}_{patch}.cs` and place them inside a namespace matching their folder:
|
|
155
|
-
|
|
156
|
-
```csharp
|
|
157
|
-
namespace Database.Missions;
|
|
158
|
-
|
|
159
|
-
public class v1_0_0 : Migration
|
|
160
|
-
{
|
|
161
|
-
protected override void Up(MigrationBuilder migrationBuilder) { ... }
|
|
162
|
-
protected override void Down(MigrationBuilder migrationBuilder) { ... }
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
The migration ID is composed as `{folder}_{ClassName}` (e.g. `Missions_v1_0_0`).
|
|
167
|
-
|
|
168
|
-
### Cross-Database Column Helpers
|
|
169
|
-
|
|
170
|
-
Always use the Cratis Arc `MigrationBuilder` extension helpers to define columns. These abstract over PostgreSQL and SQLite type differences:
|
|
57
|
+
Migrations are created and applied with the **standard EF Core tooling** (`dotnet ef migrations add`, `dotnet ef database update`, or `Database.Migrate()` at startup). Arc adds only the column helpers that keep one migration valid across all three providers — use them instead of raw `table.Column<T>()`:
|
|
171
58
|
|
|
172
59
|
| Helper | Use for |
|
|
173
|
-
|
|
174
|
-
| `table.StringColumn(migrationBuilder)` |
|
|
175
|
-
| `table.GuidColumn(migrationBuilder)` |
|
|
176
|
-
| `table.NumberColumn<T>(migrationBuilder)` |
|
|
177
|
-
| `table.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// ✅ Cross-database migration
|
|
183
|
-
migrationBuilder.CreateTable(
|
|
184
|
-
name: WellKnownTables.Missions,
|
|
185
|
-
columns: table => new
|
|
186
|
-
{
|
|
187
|
-
Id = table.StringColumn(migrationBuilder, nullable: false),
|
|
188
|
-
Title = table.StringColumn(migrationBuilder, maxLength: 200, nullable: false),
|
|
189
|
-
ResourceId = table.NumberColumn<int>(migrationBuilder, nullable: true),
|
|
190
|
-
DispatchTime = table.DateTimeOffsetColumn(migrationBuilder),
|
|
191
|
-
UrgencyId = table.GuidColumn(migrationBuilder)
|
|
192
|
-
},
|
|
193
|
-
constraints: table =>
|
|
194
|
-
{
|
|
195
|
-
table.PrimaryKey("PK_Missions", x => x.Id);
|
|
196
|
-
table.ForeignKey("FK_Missions_Urgency", x => x.UrgencyId,
|
|
197
|
-
WellKnownTables.MissionUrgencies, "Id", onDelete: ReferentialAction.SetNull);
|
|
198
|
-
});
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Table Names — WellKnownTables
|
|
202
|
-
|
|
203
|
-
Always reference table names from `WellKnownTables` constants. Never use magic strings directly in migrations.
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `table.StringColumn(migrationBuilder, …)` | text |
|
|
62
|
+
| `table.GuidColumn(migrationBuilder, …)` | GUID / UUID |
|
|
63
|
+
| `table.NumberColumn<T>(migrationBuilder, …)` | integers, longs, decimals |
|
|
64
|
+
| `table.BoolColumn(migrationBuilder, …)` | booleans |
|
|
65
|
+
| `table.DateTimeOffsetColumn(migrationBuilder, …)` | timestamps with offset |
|
|
66
|
+
| `table.AutoIncrementColumn(migrationBuilder, …)` | identity columns |
|
|
67
|
+
| `table.JsonColumn<TProperty>(migrationBuilder, …)` | a `[Json]`-mapped property |
|
|
68
|
+
| `migrationBuilder.Add{String,Guid,Number,Bool,DateTimeOffset,AutoIncrement,Json,Point,LineString,Polygon}Column(…)` | adding a column to an existing table |
|
|
204
69
|
|
|
205
|
-
|
|
206
|
-
// ❌ Magic string
|
|
207
|
-
migrationBuilder.CreateTable(name: "Missions", ...);
|
|
208
|
-
|
|
209
|
-
// ✅ Constant
|
|
210
|
-
migrationBuilder.CreateTable(name: WellKnownTables.Missions, ...);
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Add new table names to `Database/WellKnownTables.cs` before writing the migration.
|
|
70
|
+
Where a repository organizes its migrations (a dedicated project, a versioned file naming scheme, a table-name constants class) is its own convention: follow what the repository already does, and do not introduce one as if Arc required it.
|
|
214
71
|
|
|
215
|
-
|
|
72
|
+
## Concepts and JSON **[contract]**
|
|
216
73
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
```csharp
|
|
220
|
-
// ASP.NET mode
|
|
221
|
-
await app.ApplyAllMigrations(connectionString);
|
|
222
|
-
|
|
223
|
-
// MAUI / IServiceProvider mode
|
|
224
|
-
await services.ApplyAllMigrations(connectionString);
|
|
225
|
-
```
|
|
74
|
+
`ConceptAs<T>` properties map to their underlying primitive without per-property value converters: `BaseDbContext.OnModelCreating` applies the concept conversions, and every Arc registration path calls `AddConceptAsSupport()` so concepts also work inside LINQ predicates. (A context you register with plain EF `AddDbContext` must call `options.AddConceptAsSupport()` itself.) Mark a property `[Json]` to store it as a JSON column with the provider's validation constraint.
|
|
226
75
|
|
|
227
|
-
|
|
76
|
+
## Observation **[contract]**
|
|
228
77
|
|
|
229
|
-
|
|
78
|
+
An EF Core read model can back an observable query: `dbSet.Observe(...)`, `ObserveById(...)` and `ObserveSingle(...)` (extension methods declared in the `Microsoft.EntityFrameworkCore` namespace, so they are in scope wherever the `DbSet` is) push changes through the provider's change notifier — see the skill for what each provider supports.
|
|
230
79
|
|
|
231
|
-
|
|
80
|
+
## See also
|
|
232
81
|
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
- To isolate **writable** contexts, filter the discovered set on assignability — `types.Where(t => !typeof(ReadOnlyDbContext).IsAssignableFrom(t))` — rather than a dedicated extension.
|
|
82
|
+
- the **cratis-arc-ef-core-migration** skill — wiring, making an EF read model injectable into a command, writing a migration, observing, and specs.
|
|
83
|
+
- [efcore.specs.md](./efcore.specs.md) — `DbContext` specs with SQLite in-memory.
|
|
@@ -24,7 +24,7 @@ Each framework repo is organized by what it builds, not by feature slices:
|
|
|
24
24
|
- **Fundamentals** — the base library. `ConceptAs<T>`, type discovery (`IInstancesOf<T>` / `IImplementationsOf<T>`), serialization, common primitives. `Source/DotNET` (C#) + `Source/JavaScript` (`@cratis/fundamentals`) + the shared ESLint config.
|
|
25
25
|
- **Arc** — the CQRS + model-binding + proxy-generation engine. `Source/DotNET` (the command/query pipeline, validation, authorization, identity, the Roslyn **proxy generator**) + `Source/JavaScript` (`@cratis/arc`, `@cratis/arc.react`, `@cratis/arc.react.mvvm`). Arc.Core does **not** depend on Chronicle.
|
|
26
26
|
- **Chronicle** — the event-sourcing engine. `Source/Kernel` (the engine: **Orleans grains**, event sequences, observers/projections/reducers, storage providers — MongoDB and others), `Source/Clients` (the client SDKs incl. `DotNET` and `Testing`), `Infrastructure`, `Tools`, `Workbench`. The kernel is the deep, performance- and consistency-critical core.
|
|
27
|
-
- **Components** — the React component library
|
|
27
|
+
- **Components** — the React component library (Components-owned markup and styling contract; React Aria internally; optional PrimeReact/MUI presentation adapters under `Adapters/`). `Source/<Component>/` folder per component (`CommandDialog`, `DataPage`, `DataTables`, …) with Storybook stories; published as `@cratis/components`. (Application rules *consume* these components; here you *build* them.)
|
|
28
28
|
|
|
29
29
|
Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dual-stack libraries; `Kernel` vs `Clients` for Chronicle; a folder-per-component library layout for Components. Match the structure of the area you are editing — do not introduce app-style layouts.
|
|
30
30
|
|
|
@@ -29,7 +29,7 @@ Stop-and-fix signals during implementation and review:
|
|
|
29
29
|
|---|---|---|
|
|
30
30
|
| New component added without checking the shared component surface and `@cratis/components` | Duplicates fragment the design system | Reuse an existing primitive/wrapper, or document the missing one |
|
|
31
31
|
| Slice-local helper promoted to the shared component folder after one use | Freezes a one-off as a shared API | Keep it beside the slice until a second real consumer appears |
|
|
32
|
-
|
|
|
32
|
+
| A vendor UI control (any `primereact/*`, `@mui/*`, … import) where a Cratis component exists | Bypasses Arc binding, the overlay environment and validation; adds a second focus owner | Use the `@cratis/components` subpath component |
|
|
33
33
|
| Import from the `@cratis/components` root barrel in new code | Pulls optional-peer-heavy exports, hides intent | Import from subpaths (`CommandDialog`, `DataPage`, `DataTables`, `Dialogs`, `Dropdown`, `Toolbar`, `Common`) |
|
|
34
34
|
| Component API has many boolean visual flags (`primary`, `selected`, `muted`, …) | State combinations become undefined | One typed `variant`/`tone` union, or split components |
|
|
35
35
|
| A reusable component reaches into domain strings, generated proxies, identity, query, command, or navigation | It is no longer a primitive | Move it to the slice, or make it explicitly Cratis-aware and test/story it as such |
|
|
@@ -69,7 +69,7 @@ Behavior that can regress without TypeScript catching it:
|
|
|
69
69
|
- Command orchestration outside `CommandDialog`: handling of unauthorized / invalid / exception / success outcomes.
|
|
70
70
|
- React component rendering only when markup, wrapper behavior, disabled state, or integration with a wrapped component is the point.
|
|
71
71
|
|
|
72
|
-
**Do not test:** generated Cratis proxies; framework/
|
|
72
|
+
**Do not test:** generated Cratis proxies; framework/Cratis Components internals; CSS pixel-perfection; trivial presentational pass-throughs with no branch/derived behavior.
|
|
73
73
|
|
|
74
74
|
## View models
|
|
75
75
|
|
|
@@ -90,9 +90,9 @@ import React from 'react';
|
|
|
90
90
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
91
91
|
import { vi } from 'vitest';
|
|
92
92
|
|
|
93
|
-
vi.mock('
|
|
94
|
-
Dialog: (props: {
|
|
95
|
-
React.createElement('div', null, props.
|
|
93
|
+
vi.mock('@cratis/components/Dialogs', () => ({
|
|
94
|
+
Dialog: (props: { buttons?: React.ReactNode; children?: React.ReactNode }) =>
|
|
95
|
+
React.createElement('div', null, props.children, props.buttons),
|
|
96
96
|
}));
|
|
97
97
|
|
|
98
98
|
describe('when rendered while busy', () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Cratis repositories come in **two profiles**, and the rules are scoped to them. **Identify your profile first** — it decides which rules apply.
|
|
4
4
|
|
|
5
|
-
- **Application profile (default)** — you are *building an application on Cratis*: event-sourced CQRS with **Cratis Chronicle** + **Cratis Arc**, vertical slices, read models persisted to MongoDB/EF Core, and a React + Cratis Components (
|
|
5
|
+
- **Application profile (default)** — you are *building an application on Cratis*: event-sourced CQRS with **Cratis Chronicle** + **Cratis Arc**, vertical slices, read models persisted to MongoDB/EF Core, and a React + Cratis Components (4.x) frontend in MVVM. Most of this corpus targets this profile.
|
|
6
6
|
- **Framework profile** — you are *contributing to a Cratis framework repository itself* (Arc, Chronicle, Fundamentals, Components, …). These are **libraries** — source generators, the Chronicle kernel (Orleans grains + storage), client SDKs, a React component library — **not** vertical-slice event-sourced apps. The application-architecture rules here **do not apply**; follow **[framework.md](./framework.md)**.
|
|
7
7
|
|
|
8
8
|
**How to tell:** if the repo's own package is `Cratis.*` / `@cratis/*` and it *builds* the framework, you are in the framework profile. If it *consumes* Cratis to build a product, you are in the application profile.
|
|
@@ -76,66 +76,17 @@ immediately before acting and stop only when drift invalidates the authorized sc
|
|
|
76
76
|
or recovery plan. Git history rewrites remain prohibited unless the user explicitly
|
|
77
77
|
requests one.
|
|
78
78
|
|
|
79
|
-
## New Repository Strategy Intake
|
|
80
|
-
|
|
81
|
-
When a repository is created in the Cratis organization, prepare one transient,
|
|
82
|
-
no-effect Strategy intake proposal. Do not create, comment on, assign, mention,
|
|
83
|
-
link, or otherwise mutate a GitHub issue unless a current repository profile and
|
|
84
|
-
the exact operation are separately accepted. Tool access and a request to create
|
|
85
|
-
the repository do not supply that issue-effect authority.
|
|
86
|
-
|
|
87
|
-
The proposal should include only the bounded facts needed for Strategy triage:
|
|
88
|
-
|
|
89
|
-
- repository name, URL, visibility, and creation state;
|
|
90
|
-
- purpose, intended users, lifecycle, and whether it is canonical, generated,
|
|
91
|
-
experimental, operational, or scheduled for retirement;
|
|
92
|
-
- accountable owner or explicit vacancy and cross-repository boundaries;
|
|
93
|
-
- upstream/downstream dependencies and current owning records;
|
|
94
|
-
- release, distribution, credential, security, privacy, compliance, and data
|
|
95
|
-
expectations; and
|
|
96
|
-
- requested Strategy identity, portfolio, metadata, ownership, and local AI
|
|
97
|
-
context review.
|
|
98
|
-
|
|
99
|
-
First decide whether no record, an existing Strategy record, a bounded update
|
|
100
|
-
proposal, a new proposal, or a sensitive human route is appropriate. Treat the
|
|
101
|
-
result as Strategy intake, not strategic approval. Do not invent Strategy
|
|
102
|
-
metadata or copy private Strategy content into a public repository. Repository
|
|
103
|
-
creation does not require an issue URL; unresolved Strategy reconciliation is an
|
|
104
|
-
explicit next action for the authorized human/owning process.
|
|
105
|
-
|
|
106
79
|
## Shared AI Distribution
|
|
107
80
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
retirement evidence exists.
|
|
118
|
-
|
|
119
|
-
Shared public product and `engineering-*` packages contain only public-safe
|
|
120
|
-
Cratis behavior. The `engineering-` prefix identifies the maintainer audience;
|
|
121
|
-
it does not imply confidential package contents or a private registry.
|
|
122
|
-
|
|
123
|
-
The consuming repository owns its project facts, confidential behavior, local
|
|
124
|
-
skills, and minimal host bootstraps. Use repository-owned documentation as canonical
|
|
125
|
-
project context when that migration is active, `.agents/skills/` for private or
|
|
126
|
-
repository-specific local workflows, and repository-owned documentation only as the
|
|
127
|
-
documented legacy context fallback. Never merge, overwrite, or remove these
|
|
128
|
-
local files as a side effect of installing, updating, rolling back, or
|
|
129
|
-
uninstalling shared AI capabilities.
|
|
130
|
-
|
|
131
|
-
Keep confidential and repository-specific behavior local. Generalize and remove
|
|
132
|
-
private facts before proposing a reusable improvement to `Cratis/AI`; never
|
|
133
|
-
reverse-sync a private repository's AI tree or generated adapters.
|
|
134
|
-
|
|
135
|
-
Update shared AI by changing a version pin through the approved organization or
|
|
136
|
-
host mechanism. Canary the new version, observe its behavior and gates, and roll
|
|
137
|
-
back by version when needed. Never patch generated distribution bytes or
|
|
138
|
-
marketplace wrappers by hand.
|
|
81
|
+
Two invariants; the mechanics of every channel (`cratis ai install`, `@cratis/pi`,
|
|
82
|
+
the plugin marketplaces) are in [ai-distribution.md](./ai-distribution.md):
|
|
83
|
+
|
|
84
|
+
- Never copy or synchronize `.cratis/ai`, `.agents`, `.claude`, `.github`, or `.pi`
|
|
85
|
+
trees between repositories, and never patch managed files under `.cratis/ai/`
|
|
86
|
+
by hand — update through the channel that installed them.
|
|
87
|
+
- The consuming repository owns its project facts, confidential behavior, and
|
|
88
|
+
local skills; installing, updating, or uninstalling shared AI never merges,
|
|
89
|
+
overwrites, or removes them.
|
|
139
90
|
|
|
140
91
|
## Verification Discipline
|
|
141
92
|
|
|
@@ -154,25 +105,7 @@ A claim is only as good as the signal behind it — a build result, a test run,
|
|
|
154
105
|
|
|
155
106
|
## Project Layout (Cratis Application convention)
|
|
156
107
|
|
|
157
|
-
The framework discovers commands and read models by attributes and static methods — **the folder shape is a convention, not a requirement.** The house default
|
|
158
|
-
|
|
159
|
-
```
|
|
160
|
-
<AppSourceRoot>/ e.g. Source, Source/Core (app-defined)
|
|
161
|
-
├── Common/ shared ConceptAs<T> / EventSourceId<T> types
|
|
162
|
-
├── Identity/ Components/ ... cross-cutting / shared concerns, at the top level
|
|
163
|
-
└── <Module>/ top-level domain area — natural for most apps, NOT required
|
|
164
|
-
└── <Feature>/ grouping within the domain area
|
|
165
|
-
├── <Feature>.tsx pass-through layout (renders <Outlet/>)
|
|
166
|
-
├── <Concept>.cs feature-level concept types
|
|
167
|
-
└── <Slice>/ one folder per behavior — the invariant unit
|
|
168
|
-
├── <Slice>.cs backend artifacts for the slice in one file
|
|
169
|
-
├── *.tsx React component(s) for the slice
|
|
170
|
-
└── when_*/ spec folders
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**The slice is the invariant unit** — one behavior (command + events + projection + component + specs), created/renamed/deleted together. Features group related slices. A `<Module>` is the natural top-level domain grouping for larger areas (e.g. `Accounts`, `Admin`, `Requests`) but is **not required** — a feature may sit directly under the source root when no module grouping is natural; depth follows what fits the application. Cross-cutting concerns (shared concepts in `Common/`, shared components, identity) live at the top level. Namespace mirrors the path under `<AppSourceRoot>` (`<RootNamespace>.<Module>.<Feature>.<Slice>`, dropping any level that isn't present). Splitting the backend file is allowed when a slice grows large or shared concepts move upward; the single-file shape is the default, not a mandate.
|
|
174
|
-
|
|
175
|
-
> **No top-level `Features/` wrapper** — modules/features live directly under the app source root. The framework enforces no layout; this nested domain hierarchy is the chosen Cratis Application convention.
|
|
108
|
+
The framework discovers commands and read models by attributes and static methods — **the folder shape is a convention, not a requirement.** The house default: the domain hierarchy lives directly under the app source root (**no top-level `Features/` wrapper**), cross-cutting concerns (`Common/` concepts, `Identity/`, shared components) at the top level, and one folder per behavior — `<Module>/<Feature>/<Slice>/` holding `<Slice>.cs`, the slice's `.tsx`, and its `when_*/` specs. **The slice is the invariant unit** — created, renamed, and deleted as one. Namespace mirrors the path under the source root, dropping any level that isn't present. The full tree and the split rules are in [vertical-slices.md](./vertical-slices.md).
|
|
176
109
|
|
|
177
110
|
## Slice Types
|
|
178
111
|
|
|
@@ -195,7 +128,7 @@ Tagged **[contract]** (framework-enforced) or **[convention]** (house default).
|
|
|
195
128
|
|
|
196
129
|
1. **[contract] Model-bound — no controllers.** Commands are `[Command]` records with a public instance `Handle()` (Arc analyzers enforce this); queries are `static` methods on `[ReadModel]` records; projections/constraints/authorization use attributes. Arc generates the HTTP surface. Drop to fluent (`IProjectionFor<T>`, `IConstraint`) only when model-bound can't express the rule.
|
|
197
130
|
2. **[contract] Command validation & data flow.** Put command rejection in `CommandValidator<T>`, global value invariants in `ConceptValidator<T>`, and fetched/computed handler data in **`Provide()`** (runs after validation/authorization; may short-circuit with `ValidationResult.Error` / `Result<TProvided, ValidationResult>`). Keep `Handle()` focused on event construction. For a state-dependent rule that must hold **under concurrency**, inject the read model into `Handle()` and return a typed error via `Result<TEvent, ValidationResult>`. **Throwing from `Provide()`/`Handle()` is an exception (HTTP 500), not a validation rejection** — throw only for genuinely exceptional conditions, never for normal business rejection.
|
|
198
|
-
3. **[contract] Event-source id resolution
|
|
131
|
+
3. **[contract] Event-source id resolution:** `ICanProvideEventSourceId` first; else the first qualifying property in declaration order — an `EventSourceId`/`EventSourceId<T>`-derived value *or* a `[Key]` property (no priority between them; two candidates is `ARCCHR0002`); else Arc generates one. A value actually used as a Chronicle stream identity derives from `EventSourceId<T>` with the underlying `IComparable` primitive — never `ConceptAs<Guid>` for that stream identity. `NotSet`, `New()`, and primitive→derived-id operators are optional domain/API conveniences, not Chronicle requirements; typed empty/zero values are real specified stream IDs, not `EventSourceId.Unspecified`.
|
|
199
132
|
4. **[contract] Events never carry the event-source id** — it is implicit in the event context.
|
|
200
133
|
5. **[contract] `[Key]` / `[Subject]` are distinct.** `[Key]` is for event-source/read-model/projection key resolution; `[Subject]` is compliance identity only. Don't put either on an `EventSourceId<T>` value (it already is both); use them only for non-`EventSourceId<T>` values.
|
|
201
134
|
6. **[contract] Avoid nullable event properties** — Chronicle's analyzer warns on them. Model optional facts as a separate event; resolve nullable command inputs to a non-null sentinel before constructing the event.
|
|
@@ -206,21 +139,19 @@ Tagged **[contract]** (framework-enforced) or **[convention]** (house default).
|
|
|
206
139
|
11. **[contract] Projections consume events and event context — never other read models.** Default to model-bound attributes; use fluent `IProjectionFor<T>` for joins/nested/context/transforms; use a reducer when the model is "current state + event → next state" (a valid style, not a failure mode).
|
|
207
140
|
12. **[contract] Model-bound query custom paths use `[Path("...")]`** (`PathAttribute`), not ASP.NET `[Route]`. Reserve `[Route]` for controller-based endpoints (which this convention avoids).
|
|
208
141
|
13. **[convention] Cross-slice access is read-only through Chronicle** — inject another slice's read model or reference its events; never instantiate or DI another slice's command/handler/service.
|
|
209
|
-
14. **[contract] Never inject `IEventLog` into `Handle()`** — express appends through return types (`IEnumerable<object>` with `EventForEventSourceId` wrappers for cross-stream). In application reactors, return side-effect events or use `ICommandPipeline
|
|
142
|
+
14. **[contract] Never inject `IEventLog` into `Handle()`** — express appends through return types (`IEnumerable<object>` with `EventForEventSourceId` wrappers for cross-stream). In application reactors, return side-effect events or commands (or use `ICommandPipeline` and inspect the result); don't reach for `IEventLog` directly.
|
|
210
143
|
15. **[contract] Never edit a generated file** — proxies carry a `// @generated by Cratis` header. Fix the C# source and rebuild.
|
|
211
|
-
16. **[convention] Use the Cratis
|
|
144
|
+
16. **[convention] Use the Cratis dialogs** — `CommandDialog` from `@cratis/components/CommandDialog`, `Dialog` from `@cratis/components/Dialogs`; never a vendor or hand-rolled modal. The default frontend stack is Cratis Components **4.x** (Components-owned markup, `--cratis-*` tokens, `pt`/`data-cratis-part` parts; no PrimeReact dependency) — **not** Tailwind (Tailwind is one supported way to write the token-mapping CSS, not the generic default).
|
|
212
145
|
17. **[convention] One slice is one unit** — creating/renaming/moving/deleting a slice means doing the same to every artifact (the `.cs`, every `when_*/`, every `.tsx`, the composition import/JSX, the route).
|
|
213
146
|
|
|
214
147
|
## Implementation Workflow
|
|
215
148
|
|
|
216
|
-
- **Phase 0 — Model
|
|
217
|
-
- **Phase 1 — Backend.** Implement a coherent slice change. **Gate:**
|
|
218
|
-
- **Phase 2 — Specs.** Mandatory for every slice type, in-process scenario family first
|
|
219
|
-
- **Phase 3 — Frontend.**
|
|
149
|
+
- **Phase 0 — Model.** Confirm Module/Feature, slice name, slice type, domain rules; for new behavior or unclear event vocabulary run the **event-modeling** skill first.
|
|
150
|
+
- **Phase 1 — Backend.** Implement a coherent slice change. **Gate:** incremental Debug build of the affected project (regenerates proxies, compiles `#if DEBUG` spec code).
|
|
151
|
+
- **Phase 2 — Specs.** Mandatory for every slice type, in-process scenario family first (`CommandScenario<T>`, `EventScenario`, `ReadModelScenario<T>`, `ReactorScenario<T>`). **Gate:** tests pass.
|
|
152
|
+
- **Phase 3 — Frontend.** Build from the generated proxies, register in the composition page, wire routing. **Gate:** lint, conditional test, build.
|
|
220
153
|
|
|
221
|
-
**Backend before frontend, always** — the frontend depends on proxies that only
|
|
222
|
-
|
|
223
|
-
**Proxy generation runs on Debug, not Release.** `dotnet build -c Debug` is the canonical trigger for regenerating TypeScript proxies — it carries the fullest, most reliably-emitted PDB debug information the proxy generator relies on to place generated files. Generate proxies with a Debug build first; when you (or an agent) subsequently build Release purely to verify the app compiles in that configuration, skip proxy regeneration so the second build can't re-run the generator against a different compilation and touch already-correct generated files: `dotnet build -c Release -p:CratisProxiesOutputPath=`. The empty override clears the output path property the generator's MSBuild target is conditioned on, so the target no-ops for that invocation — no generated file is read or written.
|
|
154
|
+
**Backend before frontend, always** — the frontend depends on proxies that exist only after a successful build. Generate proxies from the **Debug** build (house convention); verify Release without re-running the generator: `dotnet build -c Release -p:CratisProxiesOutputPath=`. Why that property, and what to do when nothing is generated: the **cratis-arc-command** skill's proxy-generation reference.
|
|
224
155
|
|
|
225
156
|
## Quality Gates
|
|
226
157
|
|
|
@@ -235,7 +166,7 @@ Tagged **[contract]** (framework-enforced) or **[convention]** (house default).
|
|
|
235
166
|
|
|
236
167
|
Run affected-project incremental checks after a coherent change, then targeted regression tests for the changed behavior. Re-run a failed gate after a relevant fix. Reserve wider matrices and clean/Release builds for cross-cutting changes, demonstrated stale outputs, or required merge/release gates. Documentation/rule-only edits need relevant Markdown, frontmatter, link, and corpus checks, not an application build. Diagnose unrelated or environmental failures within a bounded attempt; report the evidence and blocker instead of broadening scope or retrying indefinitely. Required gates remain blocking until satisfied; never silently waive red CI.
|
|
237
168
|
|
|
238
|
-
Documentation-only changes
|
|
169
|
+
Documentation-only changes carry non-release intent and run the documentation checks, never a blanket exemption from red CI — see [pull-requests.md](./pull-requests.md).
|
|
239
170
|
|
|
240
171
|
---
|
|
241
172
|
|
|
@@ -258,7 +189,7 @@ Documentation-only changes use repository-supported non-release intent, ordinari
|
|
|
258
189
|
| For | Location |
|
|
259
190
|
| --- | --- |
|
|
260
191
|
| **AI Corpus Profiles** — what profiles exist and how to configure them | `profiles.md` |
|
|
261
|
-
| **Contributing to a Cratis framework repo** (framework profile) | `framework.md` |
|
|
192
|
+
| **Contributing to a Cratis framework repo** (framework profile) | `framework.md`; creating a repository in the Cratis organization: `new-repository-intake.md` |
|
|
262
193
|
| Slice anatomy (commands, `Provide()`, validators, events, projections, read models, reactors, constraints, compliance, cross-slice) | `vertical-slices.md` |
|
|
263
194
|
| C# / TypeScript style | `csharp.md`, `typescript.md` |
|
|
264
195
|
| Service lifetimes — why anything taking a scoped dependency is scoped or transient, never a singleton | `csharp.md` |
|
|
@@ -268,18 +199,18 @@ Documentation-only changes use repository-supported non-release intent, ordinari
|
|
|
268
199
|
| Spec patterns — the four `*Scenario` helpers (application only) | `specs.scenarios.csharp.md` |
|
|
269
200
|
| Strongly-typed values (`ConceptAs<T>`, `EventSourceId<T>`) | `concepts.md` |
|
|
270
201
|
| Shared term definitions (event, projection, reducer, reactor, observer, DCB, …) | `glossary.md` |
|
|
271
|
-
| Diagnosing a misbehaving slice
|
|
272
|
-
| Inspecting or operating a **running** Chronicle store (failed partitions, replays, browsing events) with the `cratis` CLI | the **
|
|
202
|
+
| Diagnosing a misbehaving slice | read model stale or startup crash: **cratis-chronicle-projection** (*Startup-crash traps*); reactor paused or quarantined: **cratis-chronicle-reactor** (*Failure behavior*); proxy missing: **cratis-arc-command** (*Generate the TypeScript proxy*) |
|
|
203
|
+
| Inspecting or operating a **running** Chronicle store (failed partitions, replays, browsing events) with the `cratis` CLI | the **cratis-chronicle-cli-operations** and **cratis-cli-terminal-workbench** skills |
|
|
273
204
|
| EF Core read models / migrations | `efcore.md`, `efcore.specs.md` |
|
|
274
205
|
| PRs / commits | `pull-requests.md`, `git-commits.md` |
|
|
275
|
-
| Reading, citing and superseding a decision record |
|
|
206
|
+
| Reading, citing and superseding a decision record | the **cratis-engineering-decision-record** skill |
|
|
276
207
|
| Whether you are allowed to do the thing you are able to do | `capability-is-not-authority.md` |
|
|
277
|
-
| What must stop and ask a human | `
|
|
208
|
+
| What must stop and ask a human | `capability-is-not-authority.md` (absent authority for a consequential effect: stop and ask) |
|
|
278
209
|
| What counts as evidence that something works | `verification-discipline.md` |
|
|
279
|
-
|
|
|
210
|
+
| Where session notes, plans and handovers may live | `local-work-artifacts.md` |
|
|
280
211
|
| Exit-code meaning and wrappers that lose a verdict | `exit-codes-and-wrappers.md` |
|
|
281
212
|
| Writing a scan, allowlist or destructive pass that cannot pass vacuously | `guards-and-fuses.md` |
|
|
282
|
-
|
|
|
213
|
+
| How the shared corpus is installed, updated and rolled back | `ai-distribution.md` |
|
|
283
214
|
| Event modeling / schema migration / calling commands from code / paging / cross-cutting metadata / multi-tenancy | the matching skills |
|
|
284
215
|
| Step-by-step recipes | `.cratis/ai/skills/` |
|
|
285
216
|
|
|
@@ -289,7 +220,7 @@ Documentation-only changes use repository-supported non-release intent, ordinari
|
|
|
289
220
|
- **Skills and rules are the authoritative answer.** If not answered there, ask. Don't infer Cratis behavior from package internals.
|
|
290
221
|
- Only make high-confidence suggestions.
|
|
291
222
|
- Don't change dependency manifests / lockfiles / `global.json` / NuGet config unless explicitly asked.
|
|
292
|
-
- When asked to commit, push, create a PR, ship, or land changes, use the **ship-changes**
|
|
223
|
+
- When asked to commit, push, create a PR, ship, or land changes, use the **ship-changes** prompt (`.cratis/ai/prompts/ship-changes.prompt.md`).
|
|
293
224
|
|
|
294
225
|
## General
|
|
295
226
|
|
|
@@ -305,11 +236,4 @@ Documentation-only changes use repository-supported non-release intent, ordinari
|
|
|
305
236
|
|
|
306
237
|
## Local AI work artifacts — `.ai-work/` only
|
|
307
238
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
- Create every such artifact inside **`.ai-work/`** at the repository root — never at the repository root itself, never under documentation folders, never anywhere else.
|
|
311
|
-
- `.ai-work/` is gitignored and must stay untracked. Never commit anything inside it, never `git add -f` anything inside it, and never remove the ignore entry.
|
|
312
|
-
- These artifacts must never enter git history or reach GitHub — not on any branch. If you find an unrelated tracked work record, report its path and obtain explicit authorization before moving it into `.ai-work/`, removing it from tracking, or making a dedicated cleanup commit. Discovery alone does not authorize unrelated changes or a commit.
|
|
313
|
-
- A genuine follow-up that must survive the session is **not** a work record — suggest opening a GitHub issue for it (or open one when asked) so future work is tracked where everyone can see it, instead of leaving a planning file behind.
|
|
314
|
-
- Knowledge that must outlive the session belongs in the repository's documentation structure through normal review, not in a work record.
|
|
315
|
-
- **A decision log is not a work record.** A decision — a durable choice with a decider and a date — is documentation: it lives in **`decisions/`** (or the repository's documented decisions folder) and is reviewed like any other documentation. A handover may summarize decisions; it never holds the only copy.
|
|
239
|
+
Plans, handovers, session notes, scratch analyses and research dumps are **work records, not documentation**: they live only in the gitignored `.ai-work/` at the repository root, never enter git history, and are never the only copy of a durable decision (those go in `decisions/`). A follow-up that must outlive the session is an issue, not a file. Full rule: [local-work-artifacts.md](./local-work-artifacts.md).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
profile: framework
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# New Repository Strategy Intake
|
|
7
|
+
|
|
8
|
+
This is Cratis organization process for maintainers creating repositories under the
|
|
9
|
+
Cratis organization. It does not apply to applications built on Cratis.
|
|
10
|
+
|
|
11
|
+
When a repository is created in the Cratis organization, prepare one transient,
|
|
12
|
+
no-effect Strategy intake proposal. Do not create, comment on, assign, mention,
|
|
13
|
+
link, or otherwise mutate a GitHub issue unless a current repository profile and
|
|
14
|
+
the exact operation are separately accepted. Tool access and a request to create
|
|
15
|
+
the repository do not supply that issue-effect authority.
|
|
16
|
+
|
|
17
|
+
The proposal should include only the bounded facts needed for Strategy triage:
|
|
18
|
+
|
|
19
|
+
- repository name, URL, visibility, and creation state;
|
|
20
|
+
- purpose, intended users, lifecycle, and whether it is canonical, generated,
|
|
21
|
+
experimental, operational, or scheduled for retirement;
|
|
22
|
+
- accountable owner or explicit vacancy and cross-repository boundaries;
|
|
23
|
+
- upstream/downstream dependencies and current owning records;
|
|
24
|
+
- release, distribution, credential, security, privacy, compliance, and data
|
|
25
|
+
expectations; and
|
|
26
|
+
- requested Strategy identity, portfolio, metadata, ownership, and local AI
|
|
27
|
+
context review.
|
|
28
|
+
|
|
29
|
+
First decide whether no record, an existing Strategy record, a bounded update
|
|
30
|
+
proposal, a new proposal, or a sensitive human route is appropriate. Treat the
|
|
31
|
+
result as Strategy intake, not strategic approval. Do not invent Strategy
|
|
32
|
+
metadata or copy private Strategy content into a public repository. Repository
|
|
33
|
+
creation does not require an issue URL; unresolved Strategy reconciliation is an
|
|
34
|
+
explicit next action for the authorized human/owning process.
|