@ogygie/generate 0.0.0-stage → 0.19.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -2
  3. package/dist/behavior-binding.d.ts +47 -0
  4. package/dist/behavior-grammar.d.ts +53 -0
  5. package/dist/check-spec.d.ts +53 -0
  6. package/dist/chunk-WVFHAPGC.js +10992 -0
  7. package/dist/cli/check-command.d.ts +3 -0
  8. package/dist/cli/fill-command.d.ts +39 -0
  9. package/dist/cli/generate-command.d.ts +8 -0
  10. package/dist/cli/generate-screen-command.d.ts +6 -0
  11. package/dist/cli/output.d.ts +9 -0
  12. package/dist/cli/preview-command.d.ts +19 -0
  13. package/dist/cli/project.d.ts +97 -0
  14. package/dist/cli/run.d.ts +13 -0
  15. package/dist/cli/run.js +1127 -0
  16. package/dist/cli/schemas-command.d.ts +31 -0
  17. package/dist/cli/verify-command.d.ts +3 -0
  18. package/dist/consumed-feature.d.ts +32 -0
  19. package/dist/emit/db.d.ts +27 -0
  20. package/dist/emit/factories.d.ts +14 -0
  21. package/dist/emit/hole-doc.d.ts +18 -0
  22. package/dist/emit/hole-tests.d.ts +28 -0
  23. package/dist/emit/manifest-entry.d.ts +44 -0
  24. package/dist/emit/mssql/migration.d.ts +2 -0
  25. package/dist/emit/mssql/repository.d.ts +17 -0
  26. package/dist/emit/mssql/sql-types.d.ts +23 -0
  27. package/dist/emit/mssql/statements.d.ts +55 -0
  28. package/dist/emit/mssql/stub.d.ts +17 -0
  29. package/dist/emit/names.d.ts +34 -0
  30. package/dist/emit/plan.d.ts +428 -0
  31. package/dist/emit/repository.d.ts +16 -0
  32. package/dist/emit/routes.d.ts +22 -0
  33. package/dist/emit/runtime.d.ts +47 -0
  34. package/dist/emit/screen/container.d.ts +17 -0
  35. package/dist/emit/screen/fixtures.d.ts +14 -0
  36. package/dist/emit/screen/hole-doc.d.ts +2 -0
  37. package/dist/emit/screen/previews.d.ts +24 -0
  38. package/dist/emit/screen/queries.d.ts +10 -0
  39. package/dist/emit/screen/shared.d.ts +35 -0
  40. package/dist/emit/screen/spec-contracts.d.ts +10 -0
  41. package/dist/emit/screen/tests-static.d.ts +21 -0
  42. package/dist/emit/screen/tests.d.ts +19 -0
  43. package/dist/emit/screen/views.d.ts +10 -0
  44. package/dist/emit/screen/writes.d.ts +9 -0
  45. package/dist/emit/screen-plan.d.ts +187 -0
  46. package/dist/emit/service.d.ts +18 -0
  47. package/dist/emit/spec-contracts.d.ts +27 -0
  48. package/dist/emit/tests.d.ts +3 -0
  49. package/dist/fill/body.d.ts +26 -0
  50. package/dist/fill/fill.d.ts +97 -0
  51. package/dist/fill/model-draw.d.ts +25 -0
  52. package/dist/generate-feature.d.ts +23 -0
  53. package/dist/generate-screen.d.ts +19 -0
  54. package/dist/generation-block.schema.d.ts +1279 -0
  55. package/dist/hole-shape.d.ts +100 -0
  56. package/dist/index.d.ts +45 -0
  57. package/dist/index.js +401 -0
  58. package/dist/manifest-generation.schema.d.ts +239 -0
  59. package/dist/motif-catalog.d.ts +175 -0
  60. package/dist/package-root.d.ts +5 -0
  61. package/dist/prompt-card.d.ts +3 -0
  62. package/dist/schema-checks.d.ts +32 -0
  63. package/dist/schemas/draft.d.ts +111 -0
  64. package/dist/screen-block.schema.d.ts +146 -0
  65. package/dist/screen-checks.d.ts +34 -0
  66. package/dist/screen-grammar.d.ts +36 -0
  67. package/dist/screen-vocabulary.d.ts +47 -0
  68. package/dist/spec-sections.d.ts +51 -0
  69. package/dist/verify-generation.d.ts +93 -0
  70. package/dist/vocabulary.d.ts +39 -0
  71. package/dist/zod-introspection.d.ts +119 -0
  72. package/holes-library/27560e1760bb184c.json +28 -0
  73. package/holes-library/2c26136fc6bff99a.json +30 -0
  74. package/holes-library/43a27770407bb38a.json +27 -0
  75. package/holes-library/46e67880a81012bc.json +27 -0
  76. package/holes-library/48dc5c44dc2cf3b7.json +32 -0
  77. package/holes-library/63d0825a61f6f5d3.json +27 -0
  78. package/holes-library/6784ed6c8e353dac.json +27 -0
  79. package/holes-library/8b4e4c8f04a5fc6a.json +31 -0
  80. package/holes-library/README.md +33 -0
  81. package/holes-library/d3597f50c265ba0c.json +27 -0
  82. package/holes-library/e48695e16221ff1a.json +32 -0
  83. package/package.json +59 -3
@@ -0,0 +1,146 @@
1
+ /**
2
+ * @intent Zod schema AND parser of the `# Génération` block of a SCREEN spec
3
+ * (DECISIONS.md D41): one fenced YAML block, three keys — `consumes` (the API
4
+ * features and the operations the screen uses), `views` (`list`, `form`,
5
+ * `custom`, each on ONE operation) and `holes` (the custom views: what they
6
+ * receive, which writes they may trigger, what their render must show) — plus
7
+ * an OPTIONAL `route`, the path the screen mounts on. What the shape alone
8
+ * cannot check — do the operations exist in the consumed blocks, are the
9
+ * fields of the output or the input — is `screen-checks.ts`, which needs the
10
+ * consumed features; this module checks the block against itself and refuses
11
+ * at its path (`OGYGIE_GENERATION_BLOCK_INVALID`, `details.path`), as the
12
+ * feature block does.
13
+ */
14
+ import { z } from "zod";
15
+ import type { OgygieError } from "@ogygie/core/errors";
16
+ import { type BlockLocation } from "./generation-block.schema.js";
17
+ export declare const SCREEN_BLOCK_KEYS: readonly ["route", "consumes", "views", "holes"];
18
+ /** A feature id of the map, kebab-case (French ids allowed, as everywhere). */
19
+ export declare const FeatureIdSchema: z.ZodString;
20
+ /** A front path: `/`, `/rates`, `/settings/archetypes` — no parameter in M1. */
21
+ export declare const ScreenRouteSchema: z.ZodString;
22
+ export declare const ConsumedFeatureSchema: z.ZodObject<{
23
+ feature: z.ZodString;
24
+ operations: z.ZodArray<z.ZodString>;
25
+ }, z.core.$strict>;
26
+ export type ConsumedFeature = z.infer<typeof ConsumedFeatureSchema>;
27
+ /** A DataTable over the collection a read serves: its element's fields, in order. */
28
+ export declare const ListViewSchema: z.ZodObject<{
29
+ kind: z.ZodLiteral<"list">;
30
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
31
+ sort: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodEnum<{
32
+ asc: "asc";
33
+ desc: "desc";
34
+ }>], null>>;
35
+ id: z.ZodString;
36
+ operation: z.ZodString;
37
+ }, z.core.$strict>;
38
+ /** A ContractForm over the input a write expects, calling its mutation. */
39
+ export declare const FormViewSchema: z.ZodObject<{
40
+ kind: z.ZodLiteral<"form">;
41
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
42
+ multiline: z.ZodOptional<z.ZodArray<z.ZodString>>;
43
+ id: z.ZodString;
44
+ operation: z.ZodString;
45
+ }, z.core.$strict>;
46
+ /** A view that is thought: a component with a hole, fed by a read's output. */
47
+ export declare const CustomViewSchema: z.ZodObject<{
48
+ kind: z.ZodLiteral<"custom">;
49
+ hole: z.ZodString;
50
+ id: z.ZodString;
51
+ operation: z.ZodString;
52
+ }, z.core.$strict>;
53
+ export declare const ViewSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
54
+ kind: z.ZodLiteral<"list">;
55
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
56
+ sort: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodEnum<{
57
+ asc: "asc";
58
+ desc: "desc";
59
+ }>], null>>;
60
+ id: z.ZodString;
61
+ operation: z.ZodString;
62
+ }, z.core.$strict>, z.ZodObject<{
63
+ kind: z.ZodLiteral<"form">;
64
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
65
+ multiline: z.ZodOptional<z.ZodArray<z.ZodString>>;
66
+ id: z.ZodString;
67
+ operation: z.ZodString;
68
+ }, z.core.$strict>, z.ZodObject<{
69
+ kind: z.ZodLiteral<"custom">;
70
+ hole: z.ZodString;
71
+ id: z.ZodString;
72
+ operation: z.ZodString;
73
+ }, z.core.$strict>], "kind">;
74
+ export type View = z.infer<typeof ViewSchema>;
75
+ export type ListView = Extract<View, {
76
+ kind: "list";
77
+ }>;
78
+ export type FormView = Extract<View, {
79
+ kind: "form";
80
+ }>;
81
+ export type CustomView = Extract<View, {
82
+ kind: "custom";
83
+ }>;
84
+ export declare const ScreenHoleSchema: z.ZodObject<{
85
+ id: z.ZodString;
86
+ receives: z.ZodArray<z.ZodString>;
87
+ actions: z.ZodDefault<z.ZodArray<z.ZodString>>;
88
+ examples: z.ZodObject<{
89
+ input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
90
+ renders: z.ZodArray<z.ZodString>;
91
+ }, z.core.$strict>;
92
+ }, z.core.$strict>;
93
+ export type ScreenHole = z.infer<typeof ScreenHoleSchema>;
94
+ export declare const ScreenBlockSchema: z.ZodObject<{
95
+ route: z.ZodOptional<z.ZodString>;
96
+ consumes: z.ZodArray<z.ZodObject<{
97
+ feature: z.ZodString;
98
+ operations: z.ZodArray<z.ZodString>;
99
+ }, z.core.$strict>>;
100
+ views: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
101
+ kind: z.ZodLiteral<"list">;
102
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
103
+ sort: z.ZodOptional<z.ZodTuple<[z.ZodString, z.ZodEnum<{
104
+ asc: "asc";
105
+ desc: "desc";
106
+ }>], null>>;
107
+ id: z.ZodString;
108
+ operation: z.ZodString;
109
+ }, z.core.$strict>, z.ZodObject<{
110
+ kind: z.ZodLiteral<"form">;
111
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
112
+ multiline: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ id: z.ZodString;
114
+ operation: z.ZodString;
115
+ }, z.core.$strict>, z.ZodObject<{
116
+ kind: z.ZodLiteral<"custom">;
117
+ hole: z.ZodString;
118
+ id: z.ZodString;
119
+ operation: z.ZodString;
120
+ }, z.core.$strict>], "kind">>;
121
+ holes: z.ZodDefault<z.ZodArray<z.ZodObject<{
122
+ id: z.ZodString;
123
+ receives: z.ZodArray<z.ZodString>;
124
+ actions: z.ZodDefault<z.ZodArray<z.ZodString>>;
125
+ examples: z.ZodObject<{
126
+ input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
127
+ renders: z.ZodArray<z.ZodString>;
128
+ }, z.core.$strict>;
129
+ }, z.core.$strict>>>;
130
+ }, z.core.$strict>;
131
+ export type ScreenBlock = z.infer<typeof ScreenBlockSchema>;
132
+ export type ScreenBlockParse = {
133
+ ok: true;
134
+ block: ScreenBlock;
135
+ } | {
136
+ ok: false;
137
+ problems: OgygieError[];
138
+ };
139
+ /** Validates an already-parsed screen block value. */
140
+ export declare function validateScreenBlock(raw: unknown, location: BlockLocation): ScreenBlockParse;
141
+ /** Reads the YAML text of a screen block, then validates it. */
142
+ export declare function parseScreenBlock(yamlText: string, location: BlockLocation): ScreenBlockParse;
143
+ /** The consumed feature an operation belongs to, or null when the block does not consume it. */
144
+ export declare function consumerOf(block: ScreenBlock, operationId: string): ConsumedFeature | null;
145
+ /** The read whose output the screen's ScreenState waits for: the first list or custom view (D40). */
146
+ export declare function primaryViewOf(block: ScreenBlock): ListView | CustomView | null;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @intent What a screen block cannot check against itself (D41): that every
3
+ * consumed feature is on the map — with a `# Génération` block, or, without
4
+ * one, with GET routes the screen may read (precision of lot 4 M3) — that every
5
+ * consumed operation is one the feature offers, that a `list` or
6
+ * `custom` view serves a read whose output carries a collection, that a `form`
7
+ * serves a write — a create or an import in this lot: a form on a keyed write
8
+ * needs the row it addresses, which is a custom view — and that every field a
9
+ * view shows or receives exists in the output's element or the input. Each
10
+ * refusal names its path, like the block's own checks.
11
+ */
12
+ import { type OgygieError } from "@ogygie/core/errors";
13
+ import { type ConsumedRoute } from "./consumed-feature.js";
14
+ import { type GenerationBlock } from "./generation-block.schema.js";
15
+ import type { ScreenBlock } from "./screen-block.schema.js";
16
+ import type { FieldModel, SchemaModels } from "./zod-introspection.js";
17
+ export interface ConsumedFeatureCheckInput {
18
+ featureId: string;
19
+ /** Null when the feature is on the map but its spec carries no block, or its block does not parse. */
20
+ block: GenerationBlock | null;
21
+ /** Null when the feature's schemas module could not be loaded. */
22
+ schemas: SchemaModels | null;
23
+ /** The feature's routes as the map declares them: what a feature without a block offers to read (D41 precision). */
24
+ routes: readonly ConsumedRoute[];
25
+ }
26
+ export interface ScreenCheckInput {
27
+ block: ScreenBlock;
28
+ specPath: string;
29
+ /** The consumed features, as the project resolved them — absent when the map does not know the feature. */
30
+ consumed: ReadonlyMap<string, ConsumedFeatureCheckInput>;
31
+ }
32
+ /** The element fields of a read output — the one array of objects it carries. */
33
+ export declare function elementFieldsOf(outputModel: FieldModel | undefined): string[] | null;
34
+ export declare function checkScreenBlock(input: ScreenCheckInput): OgygieError[];
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @intent The parser of the closed SCREEN behavior grammar (DECISIONS.md D20,
3
+ * precision of lot 4 M1):
4
+ *
5
+ * ÉTANT DONNÉ <vue> avec <état>[, [avec|sans] <état>]* ALORS <rendu>[, <rendu>]* [[hole:<id>]]
6
+ *
7
+ * Pure text in, structure out — the binder (screen-vocabulary.ts) says
8
+ * whether the view exists and the words are in its vocabulary. No status: a
9
+ * screen does not answer, it renders. `<vue>` is a view id of the block or
10
+ * the word « écran » (the whole screen, its primary read). The keywords are
11
+ * French (a spec is for the humans of the project); the identifiers a line
12
+ * cites — view ids, operation ids, field names — are the code's.
13
+ */
14
+ export declare const SCREEN_SUBJECT = "\u00E9cran";
15
+ export interface ScreenCase {
16
+ polarity: "with" | "without";
17
+ phrase: string;
18
+ }
19
+ export interface ParsedScreenBehavior {
20
+ raw: string;
21
+ /** A view id, or `écran`. */
22
+ view: string;
23
+ cases: ScreenCase[];
24
+ renders: string[];
25
+ hole: string | null;
26
+ }
27
+ export type ScreenParseResult = {
28
+ ok: true;
29
+ behavior: ParsedScreenBehavior;
30
+ } | {
31
+ ok: false;
32
+ raw: string;
33
+ hole: string | null;
34
+ reason: string;
35
+ };
36
+ export declare function parseScreenBehavior(input: string): ScreenParseResult;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @intent The vocabulary of ONE view of a screen (DECISIONS.md D20, precision
3
+ * of lot 4 M1) and the binder of a screen behavior line. A read view (`list`,
4
+ * `custom`, or the whole screen « écran ») speaks of its states — loading,
5
+ * error, access denied, rows, no row — and of what it renders — the skeleton,
6
+ * the error banner, the access explanation, the empty state, the rows, their
7
+ * order; a `form` view speaks of a valid or invalid form, of a refused write,
8
+ * and renders the write it triggers, the error sentences, or nothing written.
9
+ * A line whose every word is in here is derived without a model; a word
10
+ * outside it needs a hole — a custom view.
11
+ */
12
+ import { type OgygieError } from "@ogygie/core/errors";
13
+ import { type ScreenParseResult } from "./screen-grammar.js";
14
+ import { type ScreenBlock, type View } from "./screen-block.schema.js";
15
+ export interface ScreenVocabulary {
16
+ /** Normalized state keys: `with:<phrase>` / `without:<phrase>`. */
17
+ states: ReadonlySet<string>;
18
+ renders: ReadonlySet<string>;
19
+ }
20
+ export declare const READ_STATES: readonly ["with:chargement", "with:erreur", "with:accès refusé", "with:lignes", "without:ligne"];
21
+ export declare const READ_RENDERS: readonly ["squelette", "bandeau d'erreur", "explication d'accès", "état vide", "lignes"];
22
+ export declare const FORM_STATES: readonly ["with:formulaire valide", "with:formulaire invalide", "with:écriture refusée"];
23
+ export declare const FORM_RENDERS: readonly ["phrases d'erreur", "rien n'est écrit", "bandeau d'erreur"];
24
+ export declare function screenCaseKey(polarity: "with" | "without", phrase: string): string;
25
+ /** What a line may say of a view — the whole screen speaks like its primary read view. */
26
+ export declare function screenVocabularyOf(view: View | null, block: ScreenBlock, sortableFields?: readonly string[]): ScreenVocabulary;
27
+ export interface ScreenBindingContext {
28
+ block: ScreenBlock;
29
+ /** The fields a list view may order by when it declares none: the element fields of its operation's output, when known. */
30
+ sortableFieldsOf?: (view: View) => readonly string[];
31
+ specPath: string;
32
+ line: number;
33
+ }
34
+ export type ScreenBindingOutcome = {
35
+ ok: true;
36
+ status: "derivable";
37
+ view: View | null;
38
+ } | {
39
+ ok: true;
40
+ status: "hole";
41
+ hole: string;
42
+ view: View | null;
43
+ } | {
44
+ ok: false;
45
+ error: OgygieError;
46
+ };
47
+ export declare function bindScreenBehavior(parse: ScreenParseResult, context: ScreenBindingContext): ScreenBindingOutcome;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @intent Reads the two parts of a spec the generator needs, and nothing
3
+ * else: the single fenced YAML block of the `# Génération` section (D18) and
4
+ * the behavior paragraphs of `# Comportements` (D20), re-joined when wrapped
5
+ * over several lines of the file. Top-level sections are split on `# ` lines
6
+ * OUTSIDE fenced blocks and after the frontmatter — a `#` inside a YAML or
7
+ * TypeScript fence is not a heading.
8
+ *
9
+ * Nothing is dropped in silence: a paragraph opening with the formula
10
+ * without its accents, or in the three-line QUAND format, is returned as a
11
+ * paragraph for the grammar to refuse — the gate says why, it never ignores.
12
+ */
13
+ export interface SectionLine {
14
+ text: string;
15
+ /** 1-based line number in the spec file. */
16
+ line: number;
17
+ }
18
+ export interface SpecSection {
19
+ title: string;
20
+ headingLine: number;
21
+ lines: SectionLine[];
22
+ }
23
+ export declare function splitTopLevelSections(markdown: string): SpecSection[];
24
+ export declare function findSection(markdown: string, title: string): SpecSection | undefined;
25
+ export declare const GENERATION_SECTION_TITLE = "G\u00E9n\u00E9ration";
26
+ export declare const BEHAVIORS_SECTION_TITLE = "Comportements";
27
+ export type GenerationSectionLookup = {
28
+ kind: "absent";
29
+ } | {
30
+ kind: "block";
31
+ yaml: string;
32
+ line: number;
33
+ } | {
34
+ kind: "invalid";
35
+ cause: string;
36
+ details: Record<string, unknown>;
37
+ };
38
+ /** The ONE yaml block of `# Génération`, or why there is none to read. */
39
+ export declare function extractGenerationSection(markdown: string): GenerationSectionLookup;
40
+ export interface BehaviorParagraph {
41
+ /** The whole behavior, wrapped lines re-joined with single spaces. */
42
+ raw: string;
43
+ /** 1-based line where it starts in the spec file. */
44
+ line: number;
45
+ }
46
+ /**
47
+ * Every paragraph of `# Comportements` that opens with (something like) the
48
+ * formula. A paragraph starts at a line opening with it — bulleted or not —
49
+ * and runs until a blank line, a heading, a fence or the next opening.
50
+ */
51
+ export declare function extractBehaviorParagraphs(markdown: string): BehaviorParagraph[];
@@ -0,0 +1,93 @@
1
+ import { type OgygieError } from "@ogygie/core/errors";
2
+ import type { RepoAdapter } from "@ogygie/core/repo-adapter";
3
+ import { type ParsedBehavior } from "./behavior-grammar.js";
4
+ import { checkSpec, type CheckTally } from "./check-spec.js";
5
+ import type { HoleLibraryEntry } from "./hole-shape.js";
6
+ import { type ManifestGeneration } from "./manifest-generation.schema.js";
7
+ import { type DeclaredManifestEntry } from "./emit/manifest-entry.js";
8
+ import type { SchemaModels } from "./zod-introspection.js";
9
+ import type { ScreenBlock } from "./screen-block.schema.js";
10
+ import type { ConsumedFeatureCheckInput } from "./screen-checks.js";
11
+ import { type ParsedScreenBehavior } from "./screen-grammar.js";
12
+ export declare const GENERATED_DRIFT = "OGYGIE_GENERATED_DRIFT";
13
+ /** The version every emitted header carries — the package's own, so a bump of the lockstep is a drift every product regenerates (D27). */
14
+ export declare const GENERATOR_VERSION: string;
15
+ /**
16
+ * The repo has no formatter; this is the whole of « after the formatter »
17
+ * (D21, D27): line endings and trailing whitespace are not a drift, every
18
+ * other byte is.
19
+ */
20
+ export declare function normalizeForComparison(text: string): string;
21
+ /** The header every generated file carries on its LINE 1 (D21), with the generator version. */
22
+ export declare const GENERATED_HEADER: RegExp;
23
+ /** A feature of the map that owns a spec: where its code lives. */
24
+ export interface SpecOwnerFolder {
25
+ specPath: string;
26
+ /** Folder of the feature, relative to the repo root. */
27
+ folder: string;
28
+ /** The map's entry for the feature — its two generated fields, as declared (B3); absent, they are not compared. */
29
+ declared?: DeclaredManifestEntry;
30
+ /** The app carrying the feature (D40): a screen lives under a front app and regenerates through the screen pipeline. */
31
+ appPath?: string;
32
+ appType?: "api" | "front" | "gateway";
33
+ }
34
+ /** A consumed feature as `verify` needs it to regenerate a screen: what `check` reads of it, its routes on the map included. */
35
+ export type LoadedConsumedForVerify = ConsumedFeatureCheckInput;
36
+ export interface VerifyGenerationInput {
37
+ repo: RepoAdapter;
38
+ /** SQL tenant column of the product (`tenancy.column`); required to regenerate a feature. */
39
+ tenantColumn?: string;
40
+ /** The holes library, for the neighbours section of every holes/<id>.gen.md. */
41
+ library?: readonly HoleLibraryEntry[];
42
+ /** Folder of the specs, as the manifest declares it (`conventions.specsFolder`). */
43
+ specsFolder: string;
44
+ /** Folders walked for generated files — the apps and packages the manifest declares. */
45
+ scanDirs: readonly string[];
46
+ /** The manifest's `generation` block, null when the product declares none. */
47
+ generation: ManifestGeneration | null;
48
+ /** Spec → feature folder, from the manifest; a generated spec without one cannot be checked against its module. */
49
+ features?: readonly SpecOwnerFolder[];
50
+ /** Loads and introspects a schemas module (path relative to the repo root); null when the file is absent. */
51
+ loadSchemaModels?: (modulePath: string) => Promise<SchemaModels | null>;
52
+ /** Path of the API app, relative to the repo root — where guard modules live. */
53
+ apiAppPath?: string;
54
+ /** D41: resolves the features a screen block consumes (their block, schemas and routes); absent, no screen is regenerated. */
55
+ loadConsumed?: (block: ScreenBlock) => Promise<ReadonlyMap<string, LoadedConsumedForVerify>>;
56
+ }
57
+ export interface VerifiedSpec {
58
+ specPath: string;
59
+ generated: boolean;
60
+ tally: CheckTally;
61
+ }
62
+ export interface GeneratedFileClaim {
63
+ path: string;
64
+ /** Version read on line 1, null for a `*.gen.*` file without the header there. */
65
+ generatorVersion: string | null;
66
+ }
67
+ export interface VerifyGenerationReport {
68
+ ok: boolean;
69
+ specs: VerifiedSpec[];
70
+ generatedFiles: GeneratedFileClaim[];
71
+ problems: OgygieError[];
72
+ /** What was examined, and what this version cannot see (D12). */
73
+ perimeter: {
74
+ specsFolder: string;
75
+ scanDirs: readonly string[];
76
+ outOfScope: readonly string[];
77
+ };
78
+ }
79
+ /** The folder of the generator's own golden files: regenerated and compared by the package's tests, never by verify (D33, M2). */
80
+ export declare const GOLDEN_DIRECTORY = "__golden__";
81
+ /** The behaviors `check` bound, in the shape the plan takes — unbound ones never reach here (check refused). */
82
+ export declare function boundBehaviorsOf(behaviors: ReturnType<typeof checkSpec>["behaviors"]): Array<{
83
+ behavior: ParsedBehavior;
84
+ status: "derivable" | "hole";
85
+ }>;
86
+ /** The screen behaviors `check` bound, in the shape the screen plan takes (D20 for screens). */
87
+ export declare function boundScreenBehaviorsOf(behaviors: ReturnType<typeof checkSpec>["behaviors"]): Array<{
88
+ behavior: ParsedScreenBehavior;
89
+ status: "derivable" | "hole";
90
+ }>;
91
+ /** `export function name` or `export const name` — what a declared export must look like in its module. */
92
+ export declare function exportsName(source: string, name: string): boolean;
93
+ export declare function verifyGeneration(input: VerifyGenerationInput): Promise<VerifyGenerationReport>;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @intent The vocabulary of ONE operation (DECISIONS.md D20, D28 to D31,
3
+ * D34): every case a behavior line may open with, every named value and
4
+ * phrase an expectation may use, and every error code the operation can
5
+ * answer with its status — assembled from the generic words of this package,
6
+ * the guard of the operation (manifest `generation.guards`: its valid case,
7
+ * its variants, one case per declared refusal with its status and code — the
8
+ * `perFeature` one at the operation's `guardDeniedCode`), the operation itself
9
+ * (its kind: a plain read's rows, a keyed write's unknown key, a slot's
10
+ * words, `respondsWith`, `range`, `orderBy`, `limit`), the motif it uses, the
11
+ * implicit `signedWrite`, and the holes it carries (a derive's « <field>
12
+ * dérivé », every refusal code). A line whose every word is in here is derived
13
+ * without a model; a word outside it needs a hole.
14
+ */
15
+ import { type GuardRegistry } from "./manifest-generation.schema.js";
16
+ import { type GenerationBlock, type HttpOperation } from "./generation-block.schema.js";
17
+ /** The code the API answers when a request violates its input contract. */
18
+ export declare const CONTRACT_VALIDATION_FAILED = "CONTRACT_VALIDATION_FAILED";
19
+ export interface OperationVocabulary {
20
+ /** Normalized case keys: `with:<phrase>` / `without:<phrase>`. */
21
+ cases: ReadonlySet<string>;
22
+ namedValues: ReadonlySet<string>;
23
+ phrases: ReadonlySet<string>;
24
+ /** Error code → the status it comes back with. */
25
+ codes: ReadonlyMap<string, number>;
26
+ successStatus: number;
27
+ }
28
+ /** `entrée invalide` is a STRUCTURAL violation — a required field missing — never a near-miss. */
29
+ export declare const GENERIC_CASES: readonly ["with:entrée valide", "with:entrée invalide"];
30
+ export declare const GENERIC_PHRASES: readonly ["rien n'est écrit"];
31
+ export declare function caseKey(polarity: "with" | "without", phrase: string): string;
32
+ /** The code a guard refusal answers for this operation: the operation's `guardDeniedCode` on a `perFeature` refusal, the guard's otherwise (D34). */
33
+ export declare function deniedCodeOf(operation: {
34
+ guardDeniedCode?: string | null | undefined;
35
+ }, denial: {
36
+ code: string;
37
+ perFeature?: boolean | undefined;
38
+ }): string;
39
+ export declare function vocabularyOf(operation: HttpOperation, block: GenerationBlock, guards?: GuardRegistry, contractViolationCode?: string): OperationVocabulary;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @intent Zod v4 introspection (DECISIONS.md D19): the generator derives
3
+ * columns, factories and output mappings from the schemas MODULE itself —
4
+ * never from a copy. It walks the public core definition of each schema
5
+ * (`schema._zod.def`, the `zod/v4/core` contract library authors build on)
6
+ * into a small, serializable FieldModel: what the STRUCTURE says (kind, format,
7
+ * enum values, optional/nullable, bounds) and whether the structure alone can
8
+ * populate a sample (`derivable`). A regex, a `refine`, a `transform` are not
9
+ * derivable: such a field carries its example in the schema
10
+ * (`.meta({ examples })`, D23), read here through the global registry and
11
+ * checked against the schema (`rejectedExamples`).
12
+ *
13
+ * Samples are deterministic by construction: first enum value, the declared
14
+ * example, dates and uuids of fixed shape — the same module always yields the
15
+ * same factories, which is what byte-identical regeneration rests on (D21).
16
+ */
17
+ import * as core from "zod/v4/core";
18
+ interface ModelBase {
19
+ optional: boolean;
20
+ nullable: boolean;
21
+ /** Declared through `.meta({ examples })`, first wins as THE sample. */
22
+ examples: unknown[];
23
+ /** Declared examples the schema itself rejects — a refusal of `check`. */
24
+ rejectedExamples: unknown[];
25
+ /** Can the structure alone yield a valid sample? */
26
+ derivable: boolean;
27
+ }
28
+ export type FieldModel = ModelBase & ({
29
+ kind: "string";
30
+ format: string | null;
31
+ pattern: string | null;
32
+ minLength: number | null;
33
+ maxLength: number | null;
34
+ /** `.refine()` and friends: constraints no structure describes. */
35
+ customChecks: number;
36
+ } | {
37
+ kind: "number";
38
+ integer: boolean;
39
+ minimum: number | null;
40
+ maximum: number | null;
41
+ customChecks: number;
42
+ } | {
43
+ kind: "boolean";
44
+ } | {
45
+ kind: "enum";
46
+ values: Array<string | number>;
47
+ } | {
48
+ kind: "literal";
49
+ value: unknown;
50
+ } | {
51
+ kind: "array";
52
+ element: FieldModel;
53
+ } | {
54
+ kind: "object";
55
+ fields: Record<string, FieldModel>;
56
+ }
57
+ /** `z.record(key, value)`: keys the key model admits, every value of one shape — a map, not a row (lot 4 M3). */
58
+ | {
59
+ kind: "record";
60
+ key: FieldModel;
61
+ value: FieldModel;
62
+ }
63
+ /** `z.union([...])` of anything but literals alone: the first option is the shape a sample takes (lot 4 M3). A union of literals is an enum. */
64
+ | {
65
+ kind: "union";
66
+ options: FieldModel[];
67
+ }
68
+ /** `z.tuple([...])`: a fixed list of positioned shapes (lot 4 M3). */
69
+ | {
70
+ kind: "tuple";
71
+ items: FieldModel[];
72
+ } | {
73
+ kind: "unknown";
74
+ typeName: string;
75
+ });
76
+ export interface SchemaModel {
77
+ /** Export name in the module, e.g. `CreateRateInputSchema`. */
78
+ name: string;
79
+ model: FieldModel;
80
+ }
81
+ /** Every `*Schema` export of a module, by export name. */
82
+ export type SchemaModels = Record<string, SchemaModel>;
83
+ export declare function modelOf(schema: core.$ZodType): FieldModel;
84
+ /** The `*Schema` exports of an imported module, modelled. Non-schema exports are ignored. */
85
+ export declare function modelsOfModule(moduleExports: Record<string, unknown>): SchemaModels;
86
+ export type SampleResult = {
87
+ ok: true;
88
+ value: unknown;
89
+ } | {
90
+ ok: false;
91
+ reason: string;
92
+ path: string[];
93
+ };
94
+ /**
95
+ * A VALID sample of the model, deterministic: the declared example wins,
96
+ * then the structure. Fails — never guesses — when neither can answer.
97
+ * `variant` picks another declared example or enum value when there is one
98
+ * (« d'une autre <k> »), falling back to the first.
99
+ */
100
+ export declare function sampleOf(model: FieldModel, path?: string[], variant?: number): SampleResult;
101
+ export type InvalidSampleResult = {
102
+ ok: true;
103
+ value: Record<string, unknown>;
104
+ removedField: string;
105
+ } | {
106
+ ok: false;
107
+ reason: string;
108
+ };
109
+ /**
110
+ * A STRUCTURALLY invalid sample: the valid one without its first required
111
+ * field — never a near-miss (D23 amendment). Impossible for a schema with no
112
+ * required field, and said so.
113
+ */
114
+ export declare function invalidSampleOf(model: FieldModel): InvalidSampleResult;
115
+ /** Field names of an object model, in declaration order; empty for anything else. */
116
+ export declare function fieldNamesOf(model: FieldModel): string[];
117
+ /** Does `model` describe the same object shape as `resource` (same field names)? */
118
+ export declare function hasSameFieldsAs(model: FieldModel, resource: FieldModel): boolean;
119
+ export {};
@@ -0,0 +1,28 @@
1
+ {
2
+ "hole": "assertPublicationAfterEffective",
3
+ "signature": "export function assertPublicationAfterEffective(\n input: Pick<CreateRateInput, \"effectiveDate\" | \"publicationDate\">,\n): HoleResult<void, \"RATE_PUBLICATION_DATE_BEFORE_EFFECTIVE\"> {",
4
+ "signatureHash": "27560e1760bb184c",
5
+ "shape": {
6
+ "kind": "validate",
7
+ "reads": [
8
+ "string:date",
9
+ "string:date"
10
+ ],
11
+ "columns": [],
12
+ "codeRole": "operation-refusal",
13
+ "returns": "void"
14
+ },
15
+ "shapeHash": "05fa33d36c5f6172",
16
+ "errorCode": "RATE_PUBLICATION_DATE_BEFORE_EFFECTIVE",
17
+ "bodyTemplate": " // ISO dates compare lexicographically; publishing on the effective date itself is allowed.\n if (input.{{read:1}} >= input.{{read:0}}) return accept(undefined);\n return refuse(\n \"{{code}}\",\n `{{read:1}}=${input.{{read:1}}} is before {{read:0}}=${input.{{read:0}}}`,\n \"Publish on or after the effective date.\",\n );",
18
+ "provenance": [
19
+ {
20
+ "hole": "assertPublicationAfterEffective",
21
+ "repo": "julienTeam/Ogygie",
22
+ "feature": "publication-de-taux",
23
+ "path": "human",
24
+ "model": null,
25
+ "date": "2026-10-17"
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "hole": "projectForCaller",
3
+ "signature": "export function projectForCaller(context: Pick<ProjectionContext, \"role\">, output: ListGradesOutput): ListGradesOutput {",
4
+ "signatureHash": "2c26136fc6bff99a",
5
+ "shape": {
6
+ "kind": "project",
7
+ "reads": [
8
+ "context"
9
+ ],
10
+ "columns": [
11
+ "grades[].holderCount",
12
+ "canManage"
13
+ ],
14
+ "codeRole": "none",
15
+ "returns": "output"
16
+ },
17
+ "shapeHash": "1a61c3f4a779177f",
18
+ "errorCode": "",
19
+ "bodyTemplate": " const manages = context.role === \"owner\";\n return {\n ...output,\n canManage: manages,\n grades: output.grades.map((grade) => ({ ...grade, holderCount: manages ? grade.holderCount : null })),\n };",
20
+ "provenance": [
21
+ {
22
+ "hole": "projectForCaller",
23
+ "repo": "julienTeam/Ogygie",
24
+ "feature": "referentiel-de-paliers",
25
+ "path": "human",
26
+ "model": null,
27
+ "date": "2026-10-17"
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "hole": "deriveGradeCode",
3
+ "signature": "export function deriveGradeCode(\n input: Pick<CreateGradeInput, \"label\">,\n): HoleResult<string, \"GRADE_LABEL_INVALID\"> {",
4
+ "signatureHash": "43a27770407bb38a",
5
+ "shape": {
6
+ "kind": "derive",
7
+ "reads": [
8
+ "string"
9
+ ],
10
+ "columns": [],
11
+ "codeRole": "operation-refusal",
12
+ "returns": "string:regex"
13
+ },
14
+ "shapeHash": "5a010bdc51bf4608",
15
+ "errorCode": "GRADE_LABEL_INVALID",
16
+ "bodyTemplate": " const slug = input.{{read:0}}\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/gu, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/gu, \"-\")\n .replace(/^-+|-+$/gu, \"\")\n .slice(0, 32)\n .replace(/-+$/u, \"\");\n if (slug === \"\") {\n return refuse(\n \"{{code}}\",\n `{{read:0}} ${JSON.stringify(input.{{read:0}})} has no letter nor digit to derive a code from`,\n \"Give the grade a {{read:0}} with at least one letter or digit.\",\n );\n }\n return accept(slug);",
17
+ "provenance": [
18
+ {
19
+ "hole": "deriveGradeCode",
20
+ "repo": "julienTeam/Ogygie",
21
+ "feature": "referentiel-de-paliers",
22
+ "path": "human",
23
+ "model": null,
24
+ "date": "2026-10-17"
25
+ }
26
+ ]
27
+ }